From 11a1e0ed7908f04c896e69d0eb65e478c12f8519 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 7 Oct 2016 11:41:13 -0300 Subject: [media] dvb-usb: warn if return value for USB read/write routines is not checked the return values for dvb_usb_generic_rw() and dvb_usb_generic_write() should be checked, as otherwise the drivers won't be doing the right thing in the case of errors. So, add __must_check to both declarations. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dvb-usb.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb/dvb-usb.h b/drivers/media/usb/dvb-usb/dvb-usb.h index 639c4678c65b..1448c3d27ea2 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb.h +++ b/drivers/media/usb/dvb-usb/dvb-usb.h @@ -462,8 +462,10 @@ extern int dvb_usb_device_init(struct usb_interface *, extern void dvb_usb_device_exit(struct usb_interface *); /* the generic read/write method for device control */ -extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int); -extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); +extern int __must_check +dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16, int); +extern int __must_check +dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); /* commonly used remote control parsing */ extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); -- cgit v1.2.3 From 7126bc2e8d60c2a00539bf96b1005f3015be87a5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 15 Oct 2016 19:09:13 -0400 Subject: lustre: switch to use of ->d_init() Signed-off-by: Al Viro --- drivers/staging/lustre/lustre/llite/dcache.c | 33 +++++----------------- .../staging/lustre/lustre/llite/llite_internal.h | 17 ++--------- drivers/staging/lustre/lustre/llite/llite_nfs.c | 22 ++++----------- drivers/staging/lustre/lustre/llite/namei.c | 13 +-------- drivers/staging/lustre/lustre/llite/statahead.c | 4 +-- 5 files changed, 18 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c index 0e45d8fc4d7c..65bf0c401b44 100644 --- a/drivers/staging/lustre/lustre/llite/dcache.c +++ b/drivers/staging/lustre/lustre/llite/dcache.c @@ -57,9 +57,6 @@ static void ll_release(struct dentry *de) LASSERT(de); lld = ll_d2d(de); - if (!lld) /* NFS copies the de->d_op methods (bug 4655) */ - return; - if (lld->lld_it) { ll_intent_release(lld->lld_it); kfree(lld->lld_it); @@ -126,30 +123,13 @@ static int ll_ddelete(const struct dentry *de) return 0; } -int ll_d_init(struct dentry *de) +static int ll_d_init(struct dentry *de) { - CDEBUG(D_DENTRY, "ldd on dentry %pd (%p) parent %p inode %p refc %d\n", - de, de, de->d_parent, d_inode(de), d_count(de)); - - if (!de->d_fsdata) { - struct ll_dentry_data *lld; - - lld = kzalloc(sizeof(*lld), GFP_NOFS); - if (likely(lld)) { - spin_lock(&de->d_lock); - if (likely(!de->d_fsdata)) { - de->d_fsdata = lld; - __d_lustre_invalidate(de); - } else { - kfree(lld); - } - spin_unlock(&de->d_lock); - } else { - return -ENOMEM; - } - } - LASSERT(de->d_op == &ll_d_ops); - + struct ll_dentry_data *lld = kzalloc(sizeof(*lld), GFP_KERNEL); + if (unlikely(!lld)) + return -ENOMEM; + lld->lld_invalid = 1; + de->d_fsdata = lld; return 0; } @@ -300,6 +280,7 @@ static int ll_revalidate_nd(struct dentry *dentry, unsigned int flags) } const struct dentry_operations ll_d_ops = { + .d_init = ll_d_init, .d_revalidate = ll_revalidate_nd, .d_release = ll_release, .d_delete = ll_ddelete, diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h index 4bc551279aa4..507c6039b7a9 100644 --- a/drivers/staging/lustre/lustre/llite/llite_internal.h +++ b/drivers/staging/lustre/lustre/llite/llite_internal.h @@ -801,7 +801,6 @@ int ll_hsm_release(struct inode *inode); /* llite/dcache.c */ -int ll_d_init(struct dentry *de); extern const struct dentry_operations ll_d_ops; void ll_intent_drop_lock(struct lookup_intent *); void ll_intent_release(struct lookup_intent *); @@ -1189,7 +1188,7 @@ dentry_may_statahead(struct inode *dir, struct dentry *dentry) * 'lld_sa_generation == lli->lli_sa_generation'. */ ldd = ll_d2d(dentry); - if (ldd && ldd->lld_sa_generation == lli->lli_sa_generation) + if (ldd->lld_sa_generation == lli->lli_sa_generation) return false; return true; @@ -1317,17 +1316,7 @@ static inline void ll_set_lock_data(struct obd_export *exp, struct inode *inode, static inline int d_lustre_invalid(const struct dentry *dentry) { - struct ll_dentry_data *lld = ll_d2d(dentry); - - return !lld || lld->lld_invalid; -} - -static inline void __d_lustre_invalidate(struct dentry *dentry) -{ - struct ll_dentry_data *lld = ll_d2d(dentry); - - if (lld) - lld->lld_invalid = 1; + return ll_d2d(dentry)->lld_invalid; } /* @@ -1343,7 +1332,7 @@ static inline void d_lustre_invalidate(struct dentry *dentry, int nested) spin_lock_nested(&dentry->d_lock, nested ? DENTRY_D_LOCK_NESTED : DENTRY_D_LOCK_NORMAL); - __d_lustre_invalidate(dentry); + ll_d2d(dentry)->lld_invalid = 1; /* * We should be careful about dentries created by d_obtain_alias(). * These dentries are not put in the dentry tree, instead they are diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c index 709230571b4b..2ad9dc2665f3 100644 --- a/drivers/staging/lustre/lustre/llite/llite_nfs.c +++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c @@ -169,22 +169,12 @@ ll_iget_for_nfs(struct super_block *sb, struct lu_fid *fid, struct lu_fid *paren /* N.B. d_obtain_alias() drops inode ref on error */ result = d_obtain_alias(inode); if (!IS_ERR(result)) { - int rc; - - rc = ll_d_init(result); - if (rc < 0) { - dput(result); - result = ERR_PTR(rc); - } else { - struct ll_dentry_data *ldd = ll_d2d(result); - - /* - * Need to signal to the ll_intent_file_open that - * we came from NFS and so opencache needs to be - * enabled for this one - */ - ldd->lld_nfs_dentry = 1; - } + /* + * Need to signal to the ll_intent_file_open that + * we came from NFS and so opencache needs to be + * enabled for this one + */ + ll_d2d(result)->lld_nfs_dentry = 1; } return result; diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c index 180f35e3afd9..31a771319cbc 100644 --- a/drivers/staging/lustre/lustre/llite/namei.c +++ b/drivers/staging/lustre/lustre/llite/namei.c @@ -395,17 +395,9 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry) */ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) { - struct dentry *new; - int rc; - if (inode) { - new = ll_find_alias(inode, de); + struct dentry *new = ll_find_alias(inode, de); if (new) { - rc = ll_d_init(new); - if (rc < 0) { - dput(new); - return ERR_PTR(rc); - } d_move(new, de); iput(inode); CDEBUG(D_DENTRY, @@ -414,9 +406,6 @@ struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de) return new; } } - rc = ll_d_init(de); - if (rc < 0) - return ERR_PTR(rc); d_add(de, inode); CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n", de, d_inode(de), d_count(de), de->d_flags); diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c index 0677513476ec..166323fddc44 100644 --- a/drivers/staging/lustre/lustre/llite/statahead.c +++ b/drivers/staging/lustre/lustre/llite/statahead.c @@ -1513,9 +1513,7 @@ out_unplug: */ ldd = ll_d2d(*dentryp); lli = ll_i2info(dir); - /* ldd can be NULL if llite lookup failed. */ - if (ldd) - ldd->lld_sa_generation = lli->lli_sa_generation; + ldd->lld_sa_generation = lli->lli_sa_generation; sa_put(sai, entry); return rc; } -- cgit v1.2.3 From 3f2fe461c7548153dec239f44ff2aebafc8e7fdf Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 18 Aug 2016 11:56:01 -0700 Subject: soc: rockchip: power-domain: Don't (incorrectly) set rk3399 up/down counts On rk3288 it was important that powerdown and powerup counts for the CPU/GPU in the kernel because: * The power on default was crazy long. * We couldn't rely on the firmware to set this up because really this wasn't the firmware's job--the kernel was the only one that really cared about bringing up / down CPUs and the GPU and doing suspend / resume (which involves bringing up / down CPUs). On newer ARM systems (like rk3399) ARM Trusted Firmware is in charge of bringing up and down the CPUs and it really should be in charge of setting all these counts right. After all ATF is in charge of suspend / resume and CPU up / down. Let's get out of the way and let ATF do its job. A few other motivations for doing this: * Depending on another configuration (PMU_24M_EN_CFG) these counts can be either in 24M or 32k cycles. Thus, though ATF isn't really so involved in bringing up the GPU, ATF should probably manage the counts for everything so it can also manage the 24M / 32k choice. * It turns out that (right now) 24M mode is broken on rk3399 and not being used. That means that the count the kernel was programming in (24) was not 1 us (which it seems was intended) but was actually .75 ms * On rk3399 there are actually 2 separate registers for setting CPU up/down time plus 1 register for GPU up/down time. The curent kernel code actually was putting the register for the "little" cores in the "CPU" slot and the register for the "big" cores in the "GPU" slot. It was never initting the GPU counts. Note: this change assumes that ATF will actually set these values at boot, as I'm proposing in . Signed-off-by: Douglas Anderson [ATF change has landed] Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 7acd1517dd37..5f106b16e622 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -597,10 +597,12 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) * Configure power up and down transition delays for CORE * and GPU domains. */ - rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset, - pmu_info->core_power_transition_time); - rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset, - pmu_info->gpu_power_transition_time); + if (pmu_info->core_power_transition_time) + rockchip_configure_pd_cnt(pmu, pmu_info->core_pwrcnt_offset, + pmu_info->core_power_transition_time); + if (pmu_info->gpu_pwrcnt_offset) + rockchip_configure_pd_cnt(pmu, pmu_info->gpu_pwrcnt_offset, + pmu_info->gpu_power_transition_time); error = -ENODEV; @@ -722,11 +724,7 @@ static const struct rockchip_pmu_info rk3399_pmu = { .idle_offset = 0x64, .ack_offset = 0x68, - .core_pwrcnt_offset = 0x9c, - .gpu_pwrcnt_offset = 0xa4, - - .core_power_transition_time = 24, - .gpu_power_transition_time = 24, + /* ARM Trusted Firmware manages power transition times */ .num_domains = ARRAY_SIZE(rk3399_pm_domains), .domain_info = rk3399_pm_domains, -- cgit v1.2.3 From 603311ba979fa5bbbf6a8961e5f7a27deafce1b4 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Wed, 5 Oct 2016 14:35:01 -0700 Subject: soc: renesas: rcar-sysc: add R8A7743 support Add support for RZ/G1M (R8A7743) SoC power areas to the R-Car SYSC driver. Based on the original (and large) patch by Dmitry Shifrin . Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- .../bindings/power/renesas,rcar-sysc.txt | 7 +++-- drivers/soc/renesas/Makefile | 1 + drivers/soc/renesas/r8a7743-sysc.c | 32 ++++++++++++++++++++++ drivers/soc/renesas/rcar-sysc.c | 3 ++ drivers/soc/renesas/rcar-sysc.h | 1 + 5 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 drivers/soc/renesas/r8a7743-sysc.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt index 0725fb37a973..c16ec1866ac4 100644 --- a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt +++ b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt @@ -1,12 +1,13 @@ -DT bindings for the Renesas R-Car System Controller +DT bindings for the Renesas R-Car (RZ/G) System Controller == System Controller Node == -The R-Car System Controller provides power management for the CPU cores and -various coprocessors. +The R-Car (RZ/G) System Controller provides power management for the CPU cores +and various coprocessors. Required properties: - compatible: Must contain exactly one of the following: + - "renesas,r8a7743-sysc" (RZ/G1M) - "renesas,r8a7779-sysc" (R-Car H1) - "renesas,r8a7790-sysc" (R-Car H2) - "renesas,r8a7791-sysc" (R-Car M2-W) diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 623039c3514c..9e0bb329594c 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_ARCH_R8A7743) += rcar-sysc.o r8a7743-sysc.o obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o diff --git a/drivers/soc/renesas/r8a7743-sysc.c b/drivers/soc/renesas/r8a7743-sysc.c new file mode 100644 index 000000000000..9583a327d90c --- /dev/null +++ b/drivers/soc/renesas/r8a7743-sysc.c @@ -0,0 +1,32 @@ +/* + * Renesas RZ/G1M System Controller + * + * Copyright (C) 2016 Cogent Embedded Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; of the License. + */ + +#include +#include + +#include + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7743_areas[] __initconst = { + { "always-on", 0, 0, R8A7743_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca15-scu", 0x180, 0, R8A7743_PD_CA15_SCU, R8A7743_PD_ALWAYS_ON, + PD_SCU }, + { "ca15-cpu0", 0x40, 0, R8A7743_PD_CA15_CPU0, R8A7743_PD_CA15_SCU, + PD_CPU_NOCR }, + { "ca15-cpu1", 0x40, 1, R8A7743_PD_CA15_CPU1, R8A7743_PD_CA15_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A7743_PD_SGX, R8A7743_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7743_sysc_info __initconst = { + .areas = r8a7743_areas, + .num_areas = ARRAY_SIZE(r8a7743_areas), +}; diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 65c8e1eb90c0..71acd45b13f0 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -275,6 +275,9 @@ finalize: } static const struct of_device_id rcar_sysc_matches[] = { +#ifdef CONFIG_ARCH_R8A7743 + { .compatible = "renesas,r8a7743-sysc", .data = &r8a7743_sysc_info }, +#endif #ifdef CONFIG_ARCH_R8A7779 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, #endif diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h index 77dbe861473f..8ab9ca8a825a 100644 --- a/drivers/soc/renesas/rcar-sysc.h +++ b/drivers/soc/renesas/rcar-sysc.h @@ -50,6 +50,7 @@ struct rcar_sysc_info { unsigned int num_areas; }; +extern const struct rcar_sysc_info r8a7743_sysc_info; extern const struct rcar_sysc_info r8a7779_sysc_info; extern const struct rcar_sysc_info r8a7790_sysc_info; extern const struct rcar_sysc_info r8a7791_sysc_info; -- cgit v1.2.3 From 761d0efee839cf8cf0710f61f43f77026e5a77d8 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 5 Oct 2016 09:33:27 +0200 Subject: firmware: arm_scpi: add command indirection to support legacy commands Since the legacy SCPI and the SCPI v1.0 differ in the command values, it's better to create some sort of command indirection in the driver to avoid repeated version check at multiple places. This patch adds the indirection command table to allow different values of the command across SCPI versions. [narmstrong@baylibre.com: added cmd check in scpi_send_message] Signed-off-by: Neil Armstrong Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scpi.c | 71 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index ce2bc2a38101..9e9b022450eb 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -99,6 +99,7 @@ enum scpi_error_codes { SCPI_ERR_MAX }; +/* SCPI Standard commands */ enum scpi_std_cmd { SCPI_CMD_INVALID = 0x00, SCPI_CMD_SCPI_READY = 0x01, @@ -132,6 +133,38 @@ enum scpi_std_cmd { SCPI_CMD_COUNT }; +/* List of all commands used by this driver, used as indices */ +enum scpi_drv_cmds { + CMD_SCPI_CAPABILITIES = 0, + CMD_GET_CLOCK_INFO, + CMD_GET_CLOCK_VALUE, + CMD_SET_CLOCK_VALUE, + CMD_GET_DVFS, + CMD_SET_DVFS, + CMD_GET_DVFS_INFO, + CMD_SENSOR_CAPABILITIES, + CMD_SENSOR_INFO, + CMD_SENSOR_VALUE, + CMD_SET_DEVICE_PWR_STATE, + CMD_GET_DEVICE_PWR_STATE, + CMD_MAX_COUNT, +}; + +static int scpi_std_commands[CMD_MAX_COUNT] = { + SCPI_CMD_SCPI_CAPABILITIES, + SCPI_CMD_GET_CLOCK_INFO, + SCPI_CMD_GET_CLOCK_VALUE, + SCPI_CMD_SET_CLOCK_VALUE, + SCPI_CMD_GET_DVFS, + SCPI_CMD_SET_DVFS, + SCPI_CMD_GET_DVFS_INFO, + SCPI_CMD_SENSOR_CAPABILITIES, + SCPI_CMD_SENSOR_INFO, + SCPI_CMD_SENSOR_VALUE, + SCPI_CMD_SET_DEVICE_PWR_STATE, + SCPI_CMD_GET_DEVICE_PWR_STATE, +}; + struct scpi_xfer { u32 slot; /* has to be first element */ u32 cmd; @@ -161,6 +194,7 @@ struct scpi_drvinfo { u32 protocol_version; u32 firmware_version; int num_chans; + int *commands; atomic_t next_chan; struct scpi_ops *scpi_ops; struct scpi_chan *channels; @@ -344,14 +378,20 @@ static void put_scpi_xfer(struct scpi_xfer *t, struct scpi_chan *ch) mutex_unlock(&ch->xfers_lock); } -static int scpi_send_message(u8 cmd, void *tx_buf, unsigned int tx_len, +static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len, void *rx_buf, unsigned int rx_len) { int ret; u8 chan; + u8 cmd; struct scpi_xfer *msg; struct scpi_chan *scpi_chan; + if (scpi_info->commands[idx] < 0) + return -EOPNOTSUPP; + + cmd = scpi_info->commands[idx]; + chan = atomic_inc_return(&scpi_info->next_chan) % scpi_info->num_chans; scpi_chan = scpi_info->channels + chan; @@ -397,7 +437,7 @@ scpi_clk_get_range(u16 clk_id, unsigned long *min, unsigned long *max) struct clk_get_info clk; __le16 le_clk_id = cpu_to_le16(clk_id); - ret = scpi_send_message(SCPI_CMD_GET_CLOCK_INFO, &le_clk_id, + ret = scpi_send_message(CMD_GET_CLOCK_INFO, &le_clk_id, sizeof(le_clk_id), &clk, sizeof(clk)); if (!ret) { *min = le32_to_cpu(clk.min_rate); @@ -412,8 +452,9 @@ static unsigned long scpi_clk_get_val(u16 clk_id) struct clk_get_value clk; __le16 le_clk_id = cpu_to_le16(clk_id); - ret = scpi_send_message(SCPI_CMD_GET_CLOCK_VALUE, &le_clk_id, + ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id, sizeof(le_clk_id), &clk, sizeof(clk)); + return ret ? ret : le32_to_cpu(clk.rate); } @@ -425,7 +466,7 @@ static int scpi_clk_set_val(u16 clk_id, unsigned long rate) .rate = cpu_to_le32(rate) }; - return scpi_send_message(SCPI_CMD_SET_CLOCK_VALUE, &clk, sizeof(clk), + return scpi_send_message(CMD_SET_CLOCK_VALUE, &clk, sizeof(clk), &stat, sizeof(stat)); } @@ -434,8 +475,9 @@ static int scpi_dvfs_get_idx(u8 domain) int ret; u8 dvfs_idx; - ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain), + ret = scpi_send_message(CMD_GET_DVFS, &domain, sizeof(domain), &dvfs_idx, sizeof(dvfs_idx)); + return ret ? ret : dvfs_idx; } @@ -444,7 +486,7 @@ static int scpi_dvfs_set_idx(u8 domain, u8 index) int stat; struct dvfs_set dvfs = {domain, index}; - return scpi_send_message(SCPI_CMD_SET_DVFS, &dvfs, sizeof(dvfs), + return scpi_send_message(CMD_SET_DVFS, &dvfs, sizeof(dvfs), &stat, sizeof(stat)); } @@ -468,9 +510,8 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain) if (scpi_info->dvfs[domain]) /* data already populated */ return scpi_info->dvfs[domain]; - ret = scpi_send_message(SCPI_CMD_GET_DVFS_INFO, &domain, sizeof(domain), + ret = scpi_send_message(CMD_GET_DVFS_INFO, &domain, sizeof(domain), &buf, sizeof(buf)); - if (ret) return ERR_PTR(ret); @@ -503,7 +544,7 @@ static int scpi_sensor_get_capability(u16 *sensors) struct sensor_capabilities cap_buf; int ret; - ret = scpi_send_message(SCPI_CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf, + ret = scpi_send_message(CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf, sizeof(cap_buf)); if (!ret) *sensors = le16_to_cpu(cap_buf.sensors); @@ -517,7 +558,7 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info) struct _scpi_sensor_info _info; int ret; - ret = scpi_send_message(SCPI_CMD_SENSOR_INFO, &id, sizeof(id), + ret = scpi_send_message(CMD_SENSOR_INFO, &id, sizeof(id), &_info, sizeof(_info)); if (!ret) { memcpy(info, &_info, sizeof(*info)); @@ -533,7 +574,7 @@ static int scpi_sensor_get_value(u16 sensor, u64 *val) struct sensor_value buf; int ret; - ret = scpi_send_message(SCPI_CMD_SENSOR_VALUE, &id, sizeof(id), + ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id), &buf, sizeof(buf)); if (!ret) *val = (u64)le32_to_cpu(buf.hi_val) << 32 | @@ -548,7 +589,7 @@ static int scpi_device_get_power_state(u16 dev_id) u8 pstate; __le16 id = cpu_to_le16(dev_id); - ret = scpi_send_message(SCPI_CMD_GET_DEVICE_PWR_STATE, &id, + ret = scpi_send_message(CMD_GET_DEVICE_PWR_STATE, &id, sizeof(id), &pstate, sizeof(pstate)); return ret ? ret : pstate; } @@ -561,7 +602,7 @@ static int scpi_device_set_power_state(u16 dev_id, u8 pstate) .pstate = pstate, }; - return scpi_send_message(SCPI_CMD_SET_DEVICE_PWR_STATE, &dev_set, + return scpi_send_message(CMD_SET_DEVICE_PWR_STATE, &dev_set, sizeof(dev_set), &stat, sizeof(stat)); } @@ -591,7 +632,7 @@ static int scpi_init_versions(struct scpi_drvinfo *info) int ret; struct scp_capabilities caps; - ret = scpi_send_message(SCPI_CMD_SCPI_CAPABILITIES, NULL, 0, + ret = scpi_send_message(CMD_SCPI_CAPABILITIES, NULL, 0, &caps, sizeof(caps)); if (!ret) { info->protocol_version = le32_to_cpu(caps.protocol_version); @@ -755,6 +796,8 @@ err: scpi_info->channels = scpi_chan; scpi_info->num_chans = count; + scpi_info->commands = scpi_std_commands; + platform_set_drvdata(pdev, scpi_info); ret = scpi_init_versions(scpi_info); -- cgit v1.2.3 From 801f33be8e902d8cea75cb7ac056d07c4fdd25f8 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Fri, 23 Sep 2016 14:09:07 +0100 Subject: drivers: cci: add missing CCI port availability firmware check The CCI ports programming interface is available to the kernel only when booted in secure mode (or when firmware enables non-secure access to override CCI ports control). In both cases, firmware reports the CCI ports availability through the device tree CCI ports nodes, which must be parsed and their status checked by the kernel probing path. This check is currently missing and may cause the kernel to erroneously believe it is free to take control of CCI ports where in practice CCI ports control is forbidden. Add the missing CCI port availability check to the CCI driver in order to guarantee sane CCI usage. Cc: Liviu Dudau Cc: Suzuki K Poulose Cc: Marc Zyngier Acked-by: Nicolas Pitre Signed-off-by: Lorenzo Pieralisi Signed-off-by: Sudeep Holla --- drivers/bus/arm-cci.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c index 890082315054..231633328dfa 100644 --- a/drivers/bus/arm-cci.c +++ b/drivers/bus/arm-cci.c @@ -2190,6 +2190,9 @@ static int cci_probe_ports(struct device_node *np) if (!of_match_node(arm_cci_ctrl_if_matches, cp)) continue; + if (!of_device_is_available(cp)) + continue; + i = nb_ace + nb_ace_lite; if (i >= nb_cci_ports) @@ -2232,6 +2235,13 @@ static int cci_probe_ports(struct device_node *np) ports[i].dn = cp; } + /* + * If there is no CCI port that is under kernel control + * return early and report probe status. + */ + if (!nb_ace && !nb_ace_lite) + return -ENODEV; + /* initialize a stashed array of ACE ports to speed-up look-up */ cci_ace_init_ports(); -- cgit v1.2.3 From 43ea43b9d8b27b7acd443ec59319faa3cdb8a616 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 08:21:43 -0300 Subject: [media] radio-bcm2048: don't ignore errors Remove this warning: drivers/staging/media/bcm2048/radio-bcm2048.c: In function 'bcm2048_set_rds_no_lock': drivers/staging/media/bcm2048/radio-bcm2048.c:467:6: warning: variable 'err' set but not used [-Wunused-but-set-variable] int err; ^~~ By returning the error code. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index ea15cc638097..4d9bd02ede47 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -482,6 +482,8 @@ static int bcm2048_set_rds_no_lock(struct bcm2048_device *bdev, u8 rds_on) flags); memset(&bdev->rds_info, 0, sizeof(bdev->rds_info)); } + if (err) + return err; return bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, bdev->cache_fm_rds_system); -- cgit v1.2.3 From 396a3529800af0817c6af2eb65c542588a1f7fb7 Mon Sep 17 00:00:00 2001 From: Gerd Hoffmann Date: Mon, 19 Sep 2016 10:43:17 +0200 Subject: pinctrl: bcm2835: add pull defines to dt bindings Also delete (unused) private enum from driver. The pull defines can be used instead if needed. Signed-off-by: Gerd Hoffmann Signed-off-by: Eric Anholt Acked-by: Linus Walleij Acked-by: Stefan Wahren --- drivers/pinctrl/bcm/pinctrl-bcm2835.c | 6 ------ include/dt-bindings/pinctrl/bcm2835.h | 5 +++++ 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c index fa77165fab2c..4cf612bcfdfa 100644 --- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c +++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c @@ -76,12 +76,6 @@ enum bcm2835_pinconf_param { BCM2835_PINCONF_PARAM_PULL, }; -enum bcm2835_pinconf_pull { - BCM2835_PINCONFIG_PULL_NONE, - BCM2835_PINCONFIG_PULL_DOWN, - BCM2835_PINCONFIG_PULL_UP, -}; - #define BCM2835_PINCONF_PACK(_param_, _arg_) ((_param_) << 16 | (_arg_)) #define BCM2835_PINCONF_UNPACK_PARAM(_conf_) ((_conf_) >> 16) #define BCM2835_PINCONF_UNPACK_ARG(_conf_) ((_conf_) & 0xffff) diff --git a/include/dt-bindings/pinctrl/bcm2835.h b/include/dt-bindings/pinctrl/bcm2835.h index 6f0bc37af39c..e4e4fdf5d38f 100644 --- a/include/dt-bindings/pinctrl/bcm2835.h +++ b/include/dt-bindings/pinctrl/bcm2835.h @@ -24,4 +24,9 @@ #define BCM2835_FSEL_ALT2 6 #define BCM2835_FSEL_ALT3 7 +/* brcm,pull property */ +#define BCM2835_PUD_OFF 0 +#define BCM2835_PUD_DOWN 1 +#define BCM2835_PUD_UP 2 + #endif /* __DT_BINDINGS_PINCTRL_BCM2835_H__ */ -- cgit v1.2.3 From b156b7f2169bb4d963a2432ff03319fe7d64b823 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 13:19:37 -0300 Subject: mtd: nand: omap2: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/mtd/nand/omap2_nand.ko | grep alias alias: platform:omap2-nand After this patch: $ modinfo drivers/mtd/nand/omap2_nand.ko | grep alias alias: platform:omap2-nand alias: of:N*T*Cti,omap2-nandC* alias: of:N*T*Cti,omap2-nand Signed-off-by: Javier Martinez Canillas Signed-off-by: Boris Brezillon --- drivers/mtd/nand/omap2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 5513bfd9cdc9..0934c3b3f70e 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -2197,6 +2197,7 @@ static const struct of_device_id omap_nand_ids[] = { { .compatible = "ti,omap2-nand", }, {}, }; +MODULE_DEVICE_TABLE(of, omap_nand_ids); static struct platform_driver omap_nand_driver = { .probe = omap_nand_probe, -- cgit v1.2.3 From 29676833df1d9207cb665fe9869f6778a96045b9 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Wed, 28 Sep 2016 16:30:56 +0100 Subject: power: reset: Add Intel PIIX4 poweroff driver Add a driver which allows powering off the system via an Intel PIIX4 southbridge, by entering the PIIX4 SOff state. This is useful on the MIPS Malta development board, where it will power down the FPGA based board until its ON/NMI button is pressed, or the QEMU implementation of the MIPS Malta board where it will cause QEMU to exit. Signed-off-by: Paul Burton Cc: Sebastian Reichel Cc: Dmitry Eremin-Solenikov Cc: David Woodhouse Cc: linux-pm@vger.kernel.org Signed-off-by: Sebastian Reichel --- drivers/power/reset/Kconfig | 10 ++++ drivers/power/reset/Makefile | 1 + drivers/power/reset/piix4-poweroff.c | 113 +++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+) create mode 100644 drivers/power/reset/piix4-poweroff.c (limited to 'drivers') diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index c74c3f67b8da..abeb77217a21 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -104,6 +104,16 @@ config POWER_RESET_MSM help Power off and restart support for Qualcomm boards. +config POWER_RESET_PIIX4_POWEROFF + tristate "Intel PIIX4 power-off driver" + depends on PCI + depends on MIPS || COMPILE_TEST + help + This driver supports powering off a system using the Intel PIIX4 + southbridge, for example the MIPS Malta development board. The + southbridge SOff state is entered in response to a request to + power off the system. + config POWER_RESET_LTC2952 bool "LTC2952 PowerPath power-off driver" depends on OF_GPIO diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 1be307c7fc25..11dae3b56ff9 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o +obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o diff --git a/drivers/power/reset/piix4-poweroff.c b/drivers/power/reset/piix4-poweroff.c new file mode 100644 index 000000000000..bacfc95783f0 --- /dev/null +++ b/drivers/power/reset/piix4-poweroff.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2016 Imagination Technologies + * Author: Paul Burton + * + * 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 + +static struct pci_dev *pm_dev; +static resource_size_t io_offset; + +enum piix4_pm_io_reg { + PIIX4_FUNC3IO_PMSTS = 0x00, +#define PIIX4_FUNC3IO_PMSTS_PWRBTN_STS BIT(8) + PIIX4_FUNC3IO_PMCNTRL = 0x04, +#define PIIX4_FUNC3IO_PMCNTRL_SUS_EN BIT(13) +#define PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF (0x0 << 10) +}; + +#define PIIX4_SUSPEND_MAGIC 0x00120002 + +static const int piix4_pm_io_region = PCI_BRIDGE_RESOURCES; + +static void piix4_poweroff(void) +{ + int spec_devid; + u16 sts; + + /* Ensure the power button status is clear */ + while (1) { + sts = inw(io_offset + PIIX4_FUNC3IO_PMSTS); + if (!(sts & PIIX4_FUNC3IO_PMSTS_PWRBTN_STS)) + break; + outw(sts, io_offset + PIIX4_FUNC3IO_PMSTS); + } + + /* Enable entry to suspend */ + outw(PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF | PIIX4_FUNC3IO_PMCNTRL_SUS_EN, + io_offset + PIIX4_FUNC3IO_PMCNTRL); + + /* If the special cycle occurs too soon this doesn't work... */ + mdelay(10); + + /* + * The PIIX4 will enter the suspend state only after seeing a special + * cycle with the correct magic data on the PCI bus. Generate that + * cycle now. + */ + spec_devid = PCI_DEVID(0, PCI_DEVFN(0x1f, 0x7)); + pci_bus_write_config_dword(pm_dev->bus, spec_devid, 0, + PIIX4_SUSPEND_MAGIC); + + /* Give the system some time to power down, then error */ + mdelay(1000); + pr_emerg("Unable to poweroff system\n"); +} + +static int piix4_poweroff_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + int res; + + if (pm_dev) + return -EINVAL; + + /* Request access to the PIIX4 PM IO registers */ + res = pci_request_region(dev, piix4_pm_io_region, + "PIIX4 PM IO registers"); + if (res) { + dev_err(&dev->dev, "failed to request PM IO registers: %d\n", + res); + return res; + } + + pm_dev = dev; + io_offset = pci_resource_start(dev, piix4_pm_io_region); + pm_power_off = piix4_poweroff; + + return 0; +} + +static void piix4_poweroff_remove(struct pci_dev *dev) +{ + if (pm_power_off == piix4_poweroff) + pm_power_off = NULL; + + pci_release_region(dev, piix4_pm_io_region); + pm_dev = NULL; +} + +static const struct pci_device_id piix4_poweroff_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) }, + { 0 }, +}; + +static struct pci_driver piix4_poweroff_driver = { + .name = "piix4-poweroff", + .id_table = piix4_poweroff_ids, + .probe = piix4_poweroff_probe, + .remove = piix4_poweroff_remove, +}; + +module_pci_driver(piix4_poweroff_driver); +MODULE_AUTHOR("Paul Burton "); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From a758c9b93f5c4e826b3c0849c96c630b1cce8f8d Mon Sep 17 00:00:00 2001 From: Russell King - ARM Linux Date: Mon, 19 Sep 2016 21:12:12 +0200 Subject: clk: pxa25x: OSTIMER0 clocks from the main oscillator The OSTIMER0 clock ticks at the main oscillator rate, not the 32kHz oscillator rate. Ensure that it is parented to the main oscillator. Signed-off-by: Russell King Acked-by: Stephen Boyd Tested-by: Robert Jarzmik Signed-off-by: Robert Jarzmik --- drivers/clk/pxa/clk-pxa25x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/clk/pxa/clk-pxa25x.c b/drivers/clk/pxa/clk-pxa25x.c index a98b98e2a9e4..56b0a6027e38 100644 --- a/drivers/clk/pxa/clk-pxa25x.c +++ b/drivers/clk/pxa/clk-pxa25x.c @@ -230,7 +230,7 @@ static struct dummy_clk dummy_clks[] __initdata = { DUMMY_CLK("GPIO11_CLK", NULL, "osc_3_6864mhz"), DUMMY_CLK("GPIO12_CLK", NULL, "osc_32_768khz"), DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"), - DUMMY_CLK("OSTIMER0", NULL, "osc_32_768khz"), + DUMMY_CLK("OSTIMER0", NULL, "osc_3_6864mhz"), DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"), }; -- cgit v1.2.3 From f4e14edf25661f32c9e7323d8a482b8632a6f47f Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 19 Sep 2016 21:12:13 +0200 Subject: ARM: sa11x0/pxa: acquire timer rate from the clock rate As both pxa and sa1100 provide a clock to the timer, the rate can be inferred from the clock rather than hard encoded in a functional call. This patch changes the pxa timer to have a mandatory clock which is used as the timer rate. Signed-off-by: Robert Jarzmik Acked-by: Daniel Lezcano Acked-by: Russell King --- arch/arm/mach-pxa/generic.c | 3 +-- arch/arm/mach-sa1100/generic.c | 2 +- drivers/clocksource/pxa_timer.c | 11 +++++------ include/clocksource/pxa.h | 3 +-- 4 files changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c index ec510ecf8370..2a9297991d74 100644 --- a/arch/arm/mach-pxa/generic.c +++ b/arch/arm/mach-pxa/generic.c @@ -69,8 +69,7 @@ void __init pxa_timer_init(void) pxa27x_clocks_init(); if (cpu_is_pxa3xx()) pxa3xx_clocks_init(); - pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000), - get_clock_tick_rate()); + pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x40a00000)); } /* diff --git a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c index 3e09beddb6e8..2eb00691b07d 100644 --- a/arch/arm/mach-sa1100/generic.c +++ b/arch/arm/mach-sa1100/generic.c @@ -378,7 +378,7 @@ void __init sa1100_map_io(void) void __init sa1100_timer_init(void) { - pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000), 3686400); + pxa_timer_nodt_init(IRQ_OST0, io_p2v(0x90000000)); } static struct resource irq_resource = diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c index 3e1cb512f3ce..9cae38eebec2 100644 --- a/drivers/clocksource/pxa_timer.c +++ b/drivers/clocksource/pxa_timer.c @@ -220,17 +220,16 @@ CLOCKSOURCE_OF_DECLARE(pxa_timer, "marvell,pxa-timer", pxa_timer_dt_init); /* * Legacy timer init for non device-tree boards. */ -void __init pxa_timer_nodt_init(int irq, void __iomem *base, - unsigned long clock_tick_rate) +void __init pxa_timer_nodt_init(int irq, void __iomem *base) { struct clk *clk; timer_base = base; clk = clk_get(NULL, "OSTIMER0"); - if (clk && !IS_ERR(clk)) + if (clk && !IS_ERR(clk)) { clk_prepare_enable(clk); - else + pxa_timer_common_init(irq, clk_get_rate(clk)); + } else { pr_crit("%s: unable to get clk\n", __func__); - - pxa_timer_common_init(irq, clock_tick_rate); + } } diff --git a/include/clocksource/pxa.h b/include/clocksource/pxa.h index 1efbe5a66958..a9a0f03024a4 100644 --- a/include/clocksource/pxa.h +++ b/include/clocksource/pxa.h @@ -12,7 +12,6 @@ #ifndef _CLOCKSOURCE_PXA_H #define _CLOCKSOURCE_PXA_H -extern void pxa_timer_nodt_init(int irq, void __iomem *base, - unsigned long clock_tick_rate); +extern void pxa_timer_nodt_init(int irq, void __iomem *base); #endif -- cgit v1.2.3 From 6924089c488e9deab2ecc43a263a09a2d8a3f4cb Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Mon, 19 Sep 2016 21:12:14 +0200 Subject: watchdog: sa11x0/pxa: get rid of get_clock_tick_rate The OS timer rate used for the watchdog can now be fetched from the standard clock API. This will remove the last user of get_clock_tick_rate() in both pxa and sa11x0 architectures. Signed-off-by: Robert Jarzmik Acked-by: Daniel Lezcano Reviewed-by: Guenter Roeck Tested-by: Guenter Roeck Acked-by: Russell King Acked-by: Wim Van Sebroeck --- drivers/watchdog/sa1100_wdt.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/sa1100_wdt.c b/drivers/watchdog/sa1100_wdt.c index e1d39a1e9628..8965e3f536c3 100644 --- a/drivers/watchdog/sa1100_wdt.c +++ b/drivers/watchdog/sa1100_wdt.c @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -155,12 +156,27 @@ static struct miscdevice sa1100dog_miscdev = { }; static int margin __initdata = 60; /* (secs) Default is 1 minute */ +static struct clk *clk; static int __init sa1100dog_init(void) { int ret; - oscr_freq = get_clock_tick_rate(); + clk = clk_get(NULL, "OSTIMER0"); + if (IS_ERR(clk)) { + pr_err("SA1100/PXA2xx Watchdog Timer: clock not found: %d\n", + (int) PTR_ERR(clk)); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("SA1100/PXA2xx Watchdog Timer: clock failed to prepare+enable: %d\n", + ret); + goto err; + } + + oscr_freq = clk_get_rate(clk); /* * Read the reset status, and save it for later. If @@ -176,11 +192,17 @@ static int __init sa1100dog_init(void) pr_info("SA1100/PXA2xx Watchdog Timer: timer margin %d sec\n", margin); return ret; +err: + clk_disable_unprepare(clk); + clk_put(clk); + return ret; } static void __exit sa1100dog_exit(void) { misc_deregister(&sa1100dog_miscdev); + clk_disable_unprepare(clk); + clk_put(clk); } module_init(sa1100dog_init); -- cgit v1.2.3 From 556195f492a15f27f2389acf6e99ae8e5a1bf3d9 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Tue, 18 Oct 2016 08:46:32 +0200 Subject: Revert "dmaengine: pxa_dma: add support for legacy transition" This reverts commit c91134d9194478144ba579ca6efeddf628055650. The conversion of the pxa architecture is now finished for all drivers, so this functions has fullfilled its purpose and can now be removed. Signed-off-by: Robert Jarzmik Acked-by: Arnd Bergmann Signed-off-by: Vinod Koul --- drivers/dma/pxa_dma.c | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pxa_dma.c b/drivers/dma/pxa_dma.c index 3f56f9ca4482..b53fb618bbf6 100644 --- a/drivers/dma/pxa_dma.c +++ b/drivers/dma/pxa_dma.c @@ -413,15 +413,6 @@ static inline void pxad_init_debugfs(struct pxad_device *pdev) {} static inline void pxad_cleanup_debugfs(struct pxad_device *pdev) {} #endif -/* - * In the transition phase where legacy pxa handling is done at the same time as - * mmp_dma, the DMA physical channel split between the 2 DMA providers is done - * through legacy_reserved. Legacy code reserves DMA channels by settings - * corresponding bits in legacy_reserved. - */ -static u32 legacy_reserved; -static u32 legacy_unavailable; - static struct pxad_phy *lookup_phy(struct pxad_chan *pchan) { int prio, i; @@ -442,14 +433,10 @@ static struct pxad_phy *lookup_phy(struct pxad_chan *pchan) for (i = 0; i < pdev->nr_chans; i++) { if (prio != (i & 0xf) >> 2) continue; - if ((i < 32) && (legacy_reserved & BIT(i))) - continue; phy = &pdev->phys[i]; if (!phy->vchan) { phy->vchan = pchan; found = phy; - if (i < 32) - legacy_unavailable |= BIT(i); goto out_unlock; } } @@ -469,7 +456,6 @@ static void pxad_free_phy(struct pxad_chan *chan) struct pxad_device *pdev = to_pxad_dev(chan->vc.chan.device); unsigned long flags; u32 reg; - int i; dev_dbg(&chan->vc.chan.dev->device, "%s(): freeing\n", __func__); @@ -483,9 +469,6 @@ static void pxad_free_phy(struct pxad_chan *chan) } spin_lock_irqsave(&pdev->phy_lock, flags); - for (i = 0; i < 32; i++) - if (chan->phy == &pdev->phys[i]) - legacy_unavailable &= ~BIT(i); chan->phy->vchan = NULL; chan->phy = NULL; spin_unlock_irqrestore(&pdev->phy_lock, flags); @@ -739,8 +722,6 @@ static irqreturn_t pxad_int_handler(int irq, void *dev_id) i = __ffs(dint); dint &= (dint - 1); phy = &pdev->phys[i]; - if ((i < 32) && (legacy_reserved & BIT(i))) - continue; if (pxad_chan_handler(irq, phy) == IRQ_HANDLED) ret = IRQ_HANDLED; } @@ -1522,15 +1503,6 @@ bool pxad_filter_fn(struct dma_chan *chan, void *param) } EXPORT_SYMBOL_GPL(pxad_filter_fn); -int pxad_toggle_reserved_channel(int legacy_channel) -{ - if (legacy_unavailable & (BIT(legacy_channel))) - return -EBUSY; - legacy_reserved ^= BIT(legacy_channel); - return 0; -} -EXPORT_SYMBOL_GPL(pxad_toggle_reserved_channel); - module_platform_driver(pxad_driver); MODULE_DESCRIPTION("Marvell PXA Peripheral DMA Driver"); -- cgit v1.2.3 From 9934075471dcc6de9bdce1f3c1e16f1afbd711a8 Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Fri, 14 Oct 2016 10:30:47 +0530 Subject: dmaengine: omap-dma: add support for pause of non-cyclic transfers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This DMA driver is used by 8250-omap on DRA7-evm. There is one requirement that is to pause a transfer. This is currently used on the RX side. It is possible that the UART HW aborted the RX (UART's RX-timeout) but the DMA controller starts the transfer shortly after. Before we can manually purge the FIFO we need to pause the transfer, check how many bytes it already received and terminate the transfer without it making any progress. From testing on the TX side it seems that it is possible that we invoke pause once the transfer has completed which is indicated by the missing CCR_ENABLE bit but before the interrupt has been noticed. In that case the interrupt will come even after disabling it. The AM572x manual says that we have to wait for the CCR_RD_ACTIVE & CCR_WR_ACTIVE bits to be gone before programming it again here is the drain loop. Also it looks like without the drain the TX-transfer makes sometimes progress. One note: The pause + resume combo is broken because after resume the the complete transfer will be programmed again. That means the already transferred bytes (until the pause event) will be sent again. This is currently not important for my UART user because it does only pause + terminate. v3…v4: - update subject line. v2…v3: - rephrase the comment based on Russell's information / feedback. v1…v2: - move the drain loop into omap_dma_drain_chan() instead of having it twice. - allow pause only for DMA_DEV_TO_MEM transfers if non-cyclic. Add a comment why DMA_MEM_TO_DEV not allowed. - clear pause on terminate_all. Otherwise pause() + terminate_all() will keep the pause bit set and we can't pause the following transfer. Signed-off-by: Sebastian Andrzej Siewior [vigneshr@ti.com: drain channel only when buffering is on, rebase to v4.8] Signed-off-by: Vignesh R Acked-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/omap-dma.c | 124 +++++++++++++++++++++++++++++++++++-------------- 1 file changed, 89 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 7ca27d4b1c54..fd6b9e6834ad 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -422,7 +422,30 @@ static void omap_dma_start(struct omap_chan *c, struct omap_desc *d) c->running = true; } -static void omap_dma_stop(struct omap_chan *c) +static void omap_dma_drain_chan(struct omap_chan *c) +{ + int i; + u32 val; + + /* Wait for sDMA FIFO to drain */ + for (i = 0; ; i++) { + val = omap_dma_chan_read(c, CCR); + if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))) + break; + + if (i > 100) + break; + + udelay(5); + } + + if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)) + dev_err(c->vc.chan.device->dev, + "DMA drain did not complete on lch %d\n", + c->dma_ch); +} + +static int omap_dma_stop(struct omap_chan *c) { struct omap_dmadev *od = to_omap_dma_dev(c->vc.chan.device); uint32_t val; @@ -435,7 +458,6 @@ static void omap_dma_stop(struct omap_chan *c) val = omap_dma_chan_read(c, CCR); if (od->plat->errata & DMA_ERRATA_i541 && val & CCR_TRIGGER_SRC) { uint32_t sysconfig; - unsigned i; sysconfig = omap_dma_glbl_read(od, OCP_SYSCONFIG); val = sysconfig & ~DMA_SYSCONFIG_MIDLEMODE_MASK; @@ -446,27 +468,19 @@ static void omap_dma_stop(struct omap_chan *c) val &= ~CCR_ENABLE; omap_dma_chan_write(c, CCR, val); - /* Wait for sDMA FIFO to drain */ - for (i = 0; ; i++) { - val = omap_dma_chan_read(c, CCR); - if (!(val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE))) - break; - - if (i > 100) - break; - - udelay(5); - } - - if (val & (CCR_RD_ACTIVE | CCR_WR_ACTIVE)) - dev_err(c->vc.chan.device->dev, - "DMA drain did not complete on lch %d\n", - c->dma_ch); + if (!(c->ccr & CCR_BUFFERING_DISABLE)) + omap_dma_drain_chan(c); omap_dma_glbl_write(od, OCP_SYSCONFIG, sysconfig); } else { + if (!(val & CCR_ENABLE)) + return -EINVAL; + val &= ~CCR_ENABLE; omap_dma_chan_write(c, CCR, val); + + if (!(c->ccr & CCR_BUFFERING_DISABLE)) + omap_dma_drain_chan(c); } mb(); @@ -481,8 +495,8 @@ static void omap_dma_stop(struct omap_chan *c) omap_dma_chan_write(c, CLNK_CTRL, val); } - c->running = false; + return 0; } static void omap_dma_start_sg(struct omap_chan *c, struct omap_desc *d) @@ -836,6 +850,8 @@ static enum dma_status omap_dma_tx_status(struct dma_chan *chan, } else { txstate->residue = 0; } + if (ret == DMA_IN_PROGRESS && c->paused) + ret = DMA_PAUSED; spin_unlock_irqrestore(&c->vc.lock, flags); return ret; @@ -1247,10 +1263,8 @@ static int omap_dma_terminate_all(struct dma_chan *chan) omap_dma_stop(c); } - if (c->cyclic) { - c->cyclic = false; - c->paused = false; - } + c->cyclic = false; + c->paused = false; vchan_get_all_descriptors(&c->vc, &head); spin_unlock_irqrestore(&c->vc.lock, flags); @@ -1269,28 +1283,66 @@ static void omap_dma_synchronize(struct dma_chan *chan) static int omap_dma_pause(struct dma_chan *chan) { struct omap_chan *c = to_omap_dma_chan(chan); + struct omap_dmadev *od = to_omap_dma_dev(chan->device); + unsigned long flags; + int ret = -EINVAL; + bool can_pause; - /* Pause/Resume only allowed with cyclic mode */ - if (!c->cyclic) - return -EINVAL; + spin_lock_irqsave(&od->irq_lock, flags); - if (!c->paused) { - omap_dma_stop(c); - c->paused = true; + if (!c->desc) + goto out; + + if (c->cyclic) + can_pause = true; + + /* + * We do not allow DMA_MEM_TO_DEV transfers to be paused. + * From the AM572x TRM, 16.1.4.18 Disabling a Channel During Transfer: + * "When a channel is disabled during a transfer, the channel undergoes + * an abort, unless it is hardware-source-synchronized …". + * A source-synchronised channel is one where the fetching of data is + * under control of the device. In other words, a device-to-memory + * transfer. So, a destination-synchronised channel (which would be a + * memory-to-device transfer) undergoes an abort if the the CCR_ENABLE + * bit is cleared. + * From 16.1.4.20.4.6.2 Abort: "If an abort trigger occurs, the channel + * aborts immediately after completion of current read/write + * transactions and then the FIFO is cleaned up." The term "cleaned up" + * is not defined. TI recommends to check that RD_ACTIVE and WR_ACTIVE + * are both clear _before_ disabling the channel, otherwise data loss + * will occur. + * The problem is that if the channel is active, then device activity + * can result in DMA activity starting between reading those as both + * clear and the write to DMA_CCR to clear the enable bit hitting the + * hardware. If the DMA hardware can't drain the data in its FIFO to the + * destination, then data loss "might" occur (say if we write to an UART + * and the UART is not accepting any further data). + */ + else if (c->desc->dir == DMA_DEV_TO_MEM) + can_pause = true; + + if (can_pause && !c->paused) { + ret = omap_dma_stop(c); + if (!ret) + c->paused = true; } +out: + spin_unlock_irqrestore(&od->irq_lock, flags); - return 0; + return ret; } static int omap_dma_resume(struct dma_chan *chan) { struct omap_chan *c = to_omap_dma_chan(chan); + struct omap_dmadev *od = to_omap_dma_dev(chan->device); + unsigned long flags; + int ret = -EINVAL; - /* Pause/Resume only allowed with cyclic mode */ - if (!c->cyclic) - return -EINVAL; + spin_lock_irqsave(&od->irq_lock, flags); - if (c->paused) { + if (c->paused && c->desc) { mb(); /* Restore channel link register */ @@ -1298,9 +1350,11 @@ static int omap_dma_resume(struct dma_chan *chan) omap_dma_start(c, c->desc); c->paused = false; + ret = 0; } + spin_unlock_irqrestore(&od->irq_lock, flags); - return 0; + return ret; } static int omap_dma_chan_init(struct omap_dmadev *od) -- cgit v1.2.3 From 7dcec7577ddbc5677deb5204a8cb8837c32a68cf Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Thu, 6 Oct 2016 15:33:14 -0400 Subject: dmaengine: qcom_hidma: prevent disable in error When an error is observed, we try to disable the channel and prevent further accesses from the client. Depending on the type of error, transitioning into disabled state might not be possible. Adding a check to make sure that HW is in enabled/running state before the disable transition happens. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_ll.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 3224f24c577b..c3a66c9b0ab7 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -564,19 +564,8 @@ int hidma_ll_disable(struct hidma_lldev *lldev) u32 val; int ret; - val = readl(lldev->evca + HIDMA_EVCA_CTRLSTS_REG); - lldev->evch_state = HIDMA_CH_STATE(val); - val = readl(lldev->trca + HIDMA_TRCA_CTRLSTS_REG); - lldev->trch_state = HIDMA_CH_STATE(val); - - /* already suspended by this OS */ - if ((lldev->trch_state == HIDMA_CH_SUSPENDED) || - (lldev->evch_state == HIDMA_CH_SUSPENDED)) - return 0; - - /* already stopped by the manager */ - if ((lldev->trch_state == HIDMA_CH_STOPPED) || - (lldev->evch_state == HIDMA_CH_STOPPED)) + /* The channel needs to be in working state */ + if (!hidma_ll_isenabled(lldev)) return 0; val = readl(lldev->trca + HIDMA_TRCA_CTRLSTS_REG); -- cgit v1.2.3 From 32c52eff6a27798706487e042fae7bac6dd73576 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Oct 2016 21:46:25 +0200 Subject: power: supply: improve function-level documentation In drivers/power/supply/ab8500_fg.c, fix two typos and adjust the function name in two cases to correspond to the names of the defined functions. In drivers/power/supply/power_supply_core.c, change two variable names to the names of the corresponding parameters. Issue detected using Coccinelle (http://coccinelle.lip6.fr/) Signed-off-by: Julia Lawall Signed-off-by: Sebastian Reichel --- drivers/power/supply/ab8500_fg.c | 8 ++++---- drivers/power/supply/power_supply_core.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c index 2199f673118c..c569f82a0071 100644 --- a/drivers/power/supply/ab8500_fg.c +++ b/drivers/power/supply/ab8500_fg.c @@ -1900,7 +1900,7 @@ static void ab8500_fg_low_bat_work(struct work_struct *work) * ab8500_fg_battok_calc - calculate the bit pattern corresponding * to the target voltage. * @di: pointer to the ab8500_fg structure - * @target target voltage + * @target: target voltage * * Returns bit pattern closest to the target voltage * valid return values are 0-14. (0-BATT_OK_MAX_NR_INCREMENTS) @@ -2391,7 +2391,7 @@ static void ab8500_fg_external_power_changed(struct power_supply *psy) } /** - * abab8500_fg_reinit_work() - work to reset the FG algorithm + * ab8500_fg_reinit_work() - work to reset the FG algorithm * @work: pointer to the work_struct structure * * Used to reset the current battery capacity to be able to @@ -2528,7 +2528,7 @@ static struct kobj_type ab8500_fg_ktype = { }; /** - * ab8500_chargalg_sysfs_exit() - de-init of sysfs entry + * ab8500_fg_sysfs_exit() - de-init of sysfs entry * @di: pointer to the struct ab8500_chargalg * * This function removes the entry in sysfs. @@ -2539,7 +2539,7 @@ static void ab8500_fg_sysfs_exit(struct ab8500_fg *di) } /** - * ab8500_chargalg_sysfs_init() - init of sysfs entry + * ab8500_fg_sysfs_init() - init of sysfs entry * @di: pointer to the struct ab8500_chargalg * * This function adds an entry in sysfs. diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index a74d8ca383a1..1e0960b646e8 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -413,7 +413,7 @@ static int power_supply_match_device_node(struct device *dev, const void *data) /** * power_supply_get_by_phandle() - Search for a power supply and returns its ref * @np: Pointer to device node holding phandle property - * @phandle_name: Name of property holding a power supply name + * @property: Name of property holding a power supply name * * If power supply was found, it increases reference count for the * internal power supply's device. The user should power_supply_put() @@ -458,7 +458,7 @@ static void devm_power_supply_put(struct device *dev, void *res) * devm_power_supply_get_by_phandle() - Resource managed version of * power_supply_get_by_phandle() * @dev: Pointer to device holding phandle property - * @phandle_name: Name of property holding a power supply phandle + * @property: Name of property holding a power supply phandle * * Return: On success returns a reference to a power supply with * matching name equals to value under @property, NULL or ERR_PTR otherwise. -- cgit v1.2.3 From 950b6c2d110e8df65b9d2704cc7039f3d0d9f7b2 Mon Sep 17 00:00:00 2001 From: Matt Ranostay Date: Fri, 30 Sep 2016 21:45:30 -0700 Subject: power: supply: bq27xxx_battery: don't update poll_interval param if same To avoid canceling the delayed workqueue needlessly, and scheduling an immediate polling. Check if the new poll_interval value is different than the previous setting. Cc: Tony Lindgren Cc: Sebastian Reichel Signed-off-by: Matt Ranostay Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 3b0dbc689d72..0c343a0c941e 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -397,10 +397,11 @@ static LIST_HEAD(bq27xxx_battery_devices); static int poll_interval_param_set(const char *val, const struct kernel_param *kp) { struct bq27xxx_device_info *di; + unsigned int prev_val = *(unsigned int *) kp->arg; int ret; ret = param_set_uint(val, kp); - if (ret < 0) + if (ret < 0 || prev_val == *(unsigned int *) kp->arg) return ret; mutex_lock(&bq27xxx_list_lock); -- cgit v1.2.3 From 14d60bdd1ef58e3e0913f049c88daeed91a43387 Mon Sep 17 00:00:00 2001 From: Liu Xiang Date: Wed, 21 Sep 2016 22:17:34 +0800 Subject: power: supply: max17040: Change register transaction length from 8 bits to 16 bits According to the datasheet, MAX17040 has six 16-bit registers. Register reads and writes are only valid if all 16 bits are transferred. Any write command that is terminated early is ignored. So it's better to change register transacton length from 8 bits to 16 bits. Signed-off-by: Liu Xiang Signed-off-by: Sebastian Reichel --- drivers/power/supply/max17040_battery.c | 52 +++++++++++++-------------------- 1 file changed, 20 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/max17040_battery.c b/drivers/power/supply/max17040_battery.c index 8689c80202b5..e7c3649b31a0 100644 --- a/drivers/power/supply/max17040_battery.c +++ b/drivers/power/supply/max17040_battery.c @@ -21,18 +21,13 @@ #include #include -#define MAX17040_VCELL_MSB 0x02 -#define MAX17040_VCELL_LSB 0x03 -#define MAX17040_SOC_MSB 0x04 -#define MAX17040_SOC_LSB 0x05 -#define MAX17040_MODE_MSB 0x06 -#define MAX17040_MODE_LSB 0x07 -#define MAX17040_VER_MSB 0x08 -#define MAX17040_VER_LSB 0x09 -#define MAX17040_RCOMP_MSB 0x0C -#define MAX17040_RCOMP_LSB 0x0D -#define MAX17040_CMD_MSB 0xFE -#define MAX17040_CMD_LSB 0xFF +#define MAX17040_VCELL 0x02 +#define MAX17040_SOC 0x04 +#define MAX17040_MODE 0x06 +#define MAX17040_VER 0x08 +#define MAX17040_RCOMP 0x0C +#define MAX17040_CMD 0xFE + #define MAX17040_DELAY 1000 #define MAX17040_BATTERY_FULL 95 @@ -78,11 +73,11 @@ static int max17040_get_property(struct power_supply *psy, return 0; } -static int max17040_write_reg(struct i2c_client *client, int reg, u8 value) +static int max17040_write_reg(struct i2c_client *client, int reg, u16 value) { int ret; - ret = i2c_smbus_write_byte_data(client, reg, value); + ret = i2c_smbus_write_word_swapped(client, reg, value); if (ret < 0) dev_err(&client->dev, "%s: err %d\n", __func__, ret); @@ -94,7 +89,7 @@ static int max17040_read_reg(struct i2c_client *client, int reg) { int ret; - ret = i2c_smbus_read_byte_data(client, reg); + ret = i2c_smbus_read_word_swapped(client, reg); if (ret < 0) dev_err(&client->dev, "%s: err %d\n", __func__, ret); @@ -104,43 +99,36 @@ static int max17040_read_reg(struct i2c_client *client, int reg) static void max17040_reset(struct i2c_client *client) { - max17040_write_reg(client, MAX17040_CMD_MSB, 0x54); - max17040_write_reg(client, MAX17040_CMD_LSB, 0x00); + max17040_write_reg(client, MAX17040_CMD, 0x0054); } static void max17040_get_vcell(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u16 vcell; - msb = max17040_read_reg(client, MAX17040_VCELL_MSB); - lsb = max17040_read_reg(client, MAX17040_VCELL_LSB); + vcell = max17040_read_reg(client, MAX17040_VCELL); - chip->vcell = (msb << 4) + (lsb >> 4); + chip->vcell = vcell; } static void max17040_get_soc(struct i2c_client *client) { struct max17040_chip *chip = i2c_get_clientdata(client); - u8 msb; - u8 lsb; + u16 soc; - msb = max17040_read_reg(client, MAX17040_SOC_MSB); - lsb = max17040_read_reg(client, MAX17040_SOC_LSB); + soc = max17040_read_reg(client, MAX17040_SOC); - chip->soc = msb; + chip->soc = (soc >> 8); } static void max17040_get_version(struct i2c_client *client) { - u8 msb; - u8 lsb; + u16 version; - msb = max17040_read_reg(client, MAX17040_VER_MSB); - lsb = max17040_read_reg(client, MAX17040_VER_LSB); + version = max17040_read_reg(client, MAX17040_VER); - dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver %d%d\n", msb, lsb); + dev_info(&client->dev, "MAX17040 Fuel-Gauge Ver 0x%x\n", version); } static void max17040_get_online(struct i2c_client *client) -- cgit v1.2.3 From a5a8539927b840502d706c8c56423d203437d9c6 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 16:13:35 -0300 Subject: power: supply: max8997_charger: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/power/supply/max8997_charger.ko | grep alias $ After this patch: $ modinfo drivers/power/supply/max8997_charger.ko | grep alias alias: platform:max8997-battery Signed-off-by: Javier Martinez Canillas Signed-off-by: Sebastian Reichel --- drivers/power/supply/max8997_charger.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/supply/max8997_charger.c b/drivers/power/supply/max8997_charger.c index 0b2eab571528..290ddc12b040 100644 --- a/drivers/power/supply/max8997_charger.c +++ b/drivers/power/supply/max8997_charger.c @@ -184,6 +184,7 @@ static const struct platform_device_id max8997_battery_id[] = { { "max8997-battery", 0 }, { } }; +MODULE_DEVICE_TABLE(platform, max8997_battery_id); static struct platform_driver max8997_battery_driver = { .driver = { -- cgit v1.2.3 From 99e33fbdffc6d98ff8966b6a13a8fa53253a2974 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 16:13:36 -0300 Subject: power: supply: axp288_fuel_gauge: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/power/supply/axp288_fuel_gauge.ko | grep alias $ After this patch: $ modinfo drivers/power/supply/axp288_fuel_gauge.ko | grep alias alias: platform:axp288_fuel_gauge Signed-off-by: Javier Martinez Canillas Signed-off-by: Sebastian Reichel --- drivers/power/supply/axp288_fuel_gauge.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/supply/axp288_fuel_gauge.c b/drivers/power/supply/axp288_fuel_gauge.c index 5bdde692f724..539eb41504bb 100644 --- a/drivers/power/supply/axp288_fuel_gauge.c +++ b/drivers/power/supply/axp288_fuel_gauge.c @@ -1120,6 +1120,7 @@ static const struct platform_device_id axp288_fg_id_table[] = { { .name = DEV_NAME }, {}, }; +MODULE_DEVICE_TABLE(platform, axp288_fg_id_table); static int axp288_fuel_gauge_remove(struct platform_device *pdev) { -- cgit v1.2.3 From 991de440363d294bee06bfaf484a3843f3f3fd81 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 15:36:12 -0300 Subject: power: reset: at91-reset: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/power/reset/at91-reset.ko | grep alias $ After this patch: $ modinfo drivers/power/reset/at91-reset.ko | grep alias alias: of:N*T*Catmel,sama5d3-rstcC* alias: of:N*T*Catmel,sama5d3-rstc alias: of:N*T*Catmel,at91sam9g45-rstcC* alias: of:N*T*Catmel,at91sam9g45-rstc alias: of:N*T*Catmel,at91sam9260-rstcC* alias: of:N*T*Catmel,at91sam9260-rstc alias: platform:at91-sam9g45-reset alias: platform:at91-sam9260-reset Signed-off-by: Javier Martinez Canillas Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-reset.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c index 1b5d450586d1..568580cf0655 100644 --- a/drivers/power/reset/at91-reset.c +++ b/drivers/power/reset/at91-reset.c @@ -175,6 +175,7 @@ static const struct of_device_id at91_reset_of_match[] = { { .compatible = "atmel,sama5d3-rstc", .data = sama5d3_restart }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, at91_reset_of_match); static struct notifier_block at91_restart_nb = { .priority = 192, @@ -242,6 +243,7 @@ static const struct platform_device_id at91_reset_plat_match[] = { { "at91-sam9g45-reset", (unsigned long)at91sam9g45_restart }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(platform, at91_reset_plat_match); static struct platform_driver at91_reset_driver = { .remove = __exit_p(at91_reset_remove), -- cgit v1.2.3 From c9ba9b77631d7bb81c953b83e17f6924380c09e1 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 15:36:13 -0300 Subject: power: reset: at91-poweroff: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/power/reset/at91-poweroff.ko | grep alias $ After this patch: $ modinfo drivers/power/reset/at91-poweroff.ko | grep alias alias: of:N*T*Catmel,at91sam9x5-shdwcC* alias: of:N*T*Catmel,at91sam9x5-shdwc alias: of:N*T*Catmel,at91sam9rl-shdwcC* alias: of:N*T*Catmel,at91sam9rl-shdwc alias: of:N*T*Catmel,at91sam9260-shdwcC* alias: of:N*T*Catmel,at91sam9260-shdwc Signed-off-by: Javier Martinez Canillas Signed-off-by: Sebastian Reichel --- drivers/power/reset/at91-poweroff.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c index e9e24df35f26..a85dd4d233af 100644 --- a/drivers/power/reset/at91-poweroff.c +++ b/drivers/power/reset/at91-poweroff.c @@ -169,6 +169,7 @@ static const struct of_device_id at91_poweroff_of_match[] = { { .compatible = "atmel,at91sam9x5-shdwc", }, { /*sentinel*/ } }; +MODULE_DEVICE_TABLE(of, at91_poweroff_of_match); static struct platform_driver at91_poweroff_driver = { .remove = __exit_p(at91_poweroff_remove), -- cgit v1.2.3 From 0a27aa9c316ea36c299bfe552da8297e15d16fd4 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 15:36:14 -0300 Subject: power: reset: syscon-reboot-mode: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/power/reset/syscon-reboot-mode.ko | grep alias $ After this patch: $ modinfo drivers/power/reset/syscon-reboot-mode.ko | grep alias alias: of:N*T*Csyscon-reboot-modeC* alias: of:N*T*Csyscon-reboot-mode Signed-off-by: Javier Martinez Canillas Signed-off-by: Sebastian Reichel --- drivers/power/reset/syscon-reboot-mode.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/reset/syscon-reboot-mode.c b/drivers/power/reset/syscon-reboot-mode.c index 1ecb51d67149..c8c371b285b1 100644 --- a/drivers/power/reset/syscon-reboot-mode.c +++ b/drivers/power/reset/syscon-reboot-mode.c @@ -74,6 +74,7 @@ static const struct of_device_id syscon_reboot_mode_of_match[] = { { .compatible = "syscon-reboot-mode" }, {} }; +MODULE_DEVICE_TABLE(of, syscon_reboot_mode_of_match); static struct platform_driver syscon_reboot_mode_driver = { .probe = syscon_reboot_mode_probe, -- cgit v1.2.3 From 93f7c27b4dc56f144b954424031baae0f6a0e808 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 15:36:15 -0300 Subject: power: reset: zx-reboot: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/power/reset/zx-reboot.ko | grep alias $ After this patch: $ modinfo drivers/power/reset/zx-reboot.ko | grep alias alias: of:N*T*Czte,sysctrlC* alias: of:N*T*Czte,sysctrl Signed-off-by: Javier Martinez Canillas Signed-off-by: Sebastian Reichel --- drivers/power/reset/zx-reboot.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/power/reset/zx-reboot.c b/drivers/power/reset/zx-reboot.c index b0b1eb3a78c2..7549c7f74a3c 100644 --- a/drivers/power/reset/zx-reboot.c +++ b/drivers/power/reset/zx-reboot.c @@ -72,6 +72,7 @@ static const struct of_device_id zx_reboot_of_match[] = { { .compatible = "zte,sysctrl" }, {} }; +MODULE_DEVICE_TABLE(of, zx_reboot_of_match); static struct platform_driver zx_reboot_driver = { .probe = zx_reboot_probe, -- cgit v1.2.3 From 44fccac4ff17371054f795f89e23f0b60bb516c1 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Oct 2016 10:33:28 +0300 Subject: power: supply: lp8788: remove an unneeded NULL check We checked that "pdata->chg_params" is non-NULL earlier in this function so when we add "i" to it, it's still non-NULL. Signed-off-by: Dan Carpenter Acked-by: Milo Kim Signed-off-by: Sebastian Reichel --- drivers/power/supply/lp8788-charger.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/lp8788-charger.c b/drivers/power/supply/lp8788-charger.c index 7321b727d484..509e2b341bd6 100644 --- a/drivers/power/supply/lp8788-charger.c +++ b/drivers/power/supply/lp8788-charger.c @@ -384,9 +384,6 @@ static int lp8788_update_charger_params(struct platform_device *pdev, for (i = 0; i < pdata->num_chg_params; i++) { param = pdata->chg_params + i; - if (!param) - continue; - if (lp8788_is_valid_charger_register(param->addr)) { ret = lp8788_write_byte(lp, param->addr, param->val); if (ret) -- cgit v1.2.3 From 6a6af3d04435adfdaab363624ec569a9b5d3973c Mon Sep 17 00:00:00 2001 From: Gabriele Mazzotta Date: Tue, 4 Oct 2016 00:50:28 +0200 Subject: rtc: cmos: Reject unsupported alarm values Some platforms allows to specify the month and day of the month in which an alarm should go off, some others the day of the month and some others just the time. Currently any given value is accepted by the driver and only the supported fields are used to program the hardware. As consequence, alarms are potentially programmed to go off in the wrong moment. Fix this by rejecting any unsupported value. Signed-off-by: Gabriele Mazzotta Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index dd3d59806ffa..903a82ae83f0 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -325,14 +325,86 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask) cmos_checkintr(cmos, rtc_control); } +static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + struct rtc_time now; + + cmos_read_time(dev, &now); + + if (!cmos->day_alrm) { + time64_t t_max_date; + time64_t t_alrm; + + t_max_date = rtc_tm_to_time64(&now); + t_max_date += 24 * 60 * 60 - 1; + t_alrm = rtc_tm_to_time64(&t->time); + if (t_alrm > t_max_date) { + dev_err(dev, + "Alarms can be up to one day in the future\n"); + return -EINVAL; + } + } else if (!cmos->mon_alrm) { + struct rtc_time max_date = now; + time64_t t_max_date; + time64_t t_alrm; + int max_mday; + + if (max_date.tm_mon == 11) { + max_date.tm_mon = 0; + max_date.tm_year += 1; + } else { + max_date.tm_mon += 1; + } + max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year); + if (max_date.tm_mday > max_mday) + max_date.tm_mday = max_mday; + + t_max_date = rtc_tm_to_time64(&max_date); + t_max_date -= 1; + t_alrm = rtc_tm_to_time64(&t->time); + if (t_alrm > t_max_date) { + dev_err(dev, + "Alarms can be up to one month in the future\n"); + return -EINVAL; + } + } else { + struct rtc_time max_date = now; + time64_t t_max_date; + time64_t t_alrm; + int max_mday; + + max_date.tm_year += 1; + max_mday = rtc_month_days(max_date.tm_mon, max_date.tm_year); + if (max_date.tm_mday > max_mday) + max_date.tm_mday = max_mday; + + t_max_date = rtc_tm_to_time64(&max_date); + t_max_date -= 1; + t_alrm = rtc_tm_to_time64(&t->time); + if (t_alrm > t_max_date) { + dev_err(dev, + "Alarms can be up to one year in the future\n"); + return -EINVAL; + } + } + + return 0; +} + static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct cmos_rtc *cmos = dev_get_drvdata(dev); unsigned char mon, mday, hrs, min, sec, rtc_control; + int ret; if (!is_valid_irq(cmos->irq)) return -EIO; + ret = cmos_validate_alarm(dev, t); + if (ret < 0) + return ret; + mon = t->time.tm_mon + 1; mday = t->time.tm_mday; hrs = t->time.tm_hour; -- cgit v1.2.3 From 290cd0f07f0c55f4071aee47b5d4cc3c83da588c Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 12 Oct 2016 15:30:53 +0200 Subject: rtc: cmos: don't refer to asm-generic/rtc.h That header has been gone for a while. I've fixed up the Kconfig comment, but the one in rtc-cmos.c doesn't make any sense to me even looking at its history. Signed-off-by: Christoph Hellwig Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 4 ++-- drivers/rtc/rtc-cmos.c | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e859d148aba9..4cbea34e6003 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -820,8 +820,8 @@ config RTC_DRV_RV3029_HWMON comment "Platform RTC drivers" -# this 'CMOS' RTC driver is arch dependent because -# requires defining CMOS_READ/CMOS_WRITE, and a +# this 'CMOS' RTC driver is arch dependent because it requires +# defining CMOS_READ/CMOS_WRITE, and a # global rtc_lock ... it's not yet just another platform_device. config RTC_DRV_CMOS diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 903a82ae83f0..390172bac39b 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -772,9 +772,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) spin_unlock_irq(&rtc_lock); - /* FIXME: - * doesn't know 12-hour mode either. - */ if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) { dev_warn(dev, "only 24-hr supported\n"); retval = -ENXIO; -- cgit v1.2.3 From 0741b819246029a7e53b8edcc5693debd7c00c8f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 19 Oct 2016 12:05:53 +0100 Subject: dmaengine: omap-dma: initialize can_pause to false can_pause is not initialized so it contains garbage. Fix this by setting it to false. Found using static analysis with cppcheck. Signed-off-by: Colin Ian King Signed-off-by: Vinod Koul --- drivers/dma/omap-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index fd6b9e6834ad..15eb8024666b 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -1286,7 +1286,7 @@ static int omap_dma_pause(struct dma_chan *chan) struct omap_dmadev *od = to_omap_dma_dev(chan->device); unsigned long flags; int ret = -EINVAL; - bool can_pause; + bool can_pause = false; spin_lock_irqsave(&od->irq_lock, flags); -- cgit v1.2.3 From b5b809532e7b070374d98c90f8f423c63f3655f5 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Thu, 6 Oct 2016 18:21:29 -0400 Subject: dmaengine: qcom_hidma: remove useless debugfs file removal Since 'commit acc29fb8f792 ("debugfs: ->d_parent is never NULL or negative")', HIDMA object removal is no longer working. This is due to redundant debugfs remove call in hidma_debug_uninit. debugfs_remove_recursive(dmadev->debugfs); debugfs_remove_recursive(dmadev->stats); The first remove is for the directory. Second remove is for the file under the directory. The directory remove makes file remove invalid. Unable to handle kernel NULL pointer dereference at virtual address [] down_write+0x18/0x68 [] debugfs_remove_recursive+0x50/0x1c0 [] hidma_debug_uninit+0x20/0x30 [] hidma_remove+0x48/0x98 [] platform_drv_remove+0x24/0x68 [] __device_release_driver+0x80/0x118 [] device_release_driver+0x24/0x38 [] unbind_store+0xe8/0x110 [] drv_attr_store+0x20/0x30 [] sysfs_kf_write+0x48/0x58 [] kernfs_fop_write+0xb0/0x1d8 [] __vfs_write+0x1c/0x110 [] vfs_write+0xa0/0x1b8 [] SyS_write+0x44/0xa0 [] el0_svc_naked+0x24/0x28 Removing the second line. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_dbg.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_dbg.c b/drivers/dma/qcom/hidma_dbg.c index fa827e5ffd68..3d83b9962220 100644 --- a/drivers/dma/qcom/hidma_dbg.c +++ b/drivers/dma/qcom/hidma_dbg.c @@ -164,7 +164,6 @@ static const struct file_operations hidma_dma_fops = { void hidma_debug_uninit(struct hidma_dev *dmadev) { debugfs_remove_recursive(dmadev->debugfs); - debugfs_remove_recursive(dmadev->stats); } int hidma_debug_init(struct hidma_dev *dmadev) -- cgit v1.2.3 From 5282c181662c4cef4823cc16b4641d147c52144f Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 7 Oct 2016 01:25:08 -0400 Subject: of: irq: make of_msi_configure accessible from modules The of_msi_configure routine is only accessible by the built-in kernel drivers. Export this function so that modules can use it too. This function is useful for configuring MSI on child device tree nodes on hierarchical objects. Acked-by: Rob Herring Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/of/irq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/of/irq.c b/drivers/of/irq.c index 393fea85eb4e..3fda9a32defb 100644 --- a/drivers/of/irq.c +++ b/drivers/of/irq.c @@ -697,3 +697,4 @@ void of_msi_configure(struct device *dev, struct device_node *np) dev_set_msi_domain(dev, of_msi_get_domain(dev, np, DOMAIN_BUS_PLATFORM_MSI)); } +EXPORT_SYMBOL_GPL(of_msi_configure); -- cgit v1.2.3 From 9da0be80be6e7855385ec519c7c13576dfed84c0 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 7 Oct 2016 01:25:09 -0400 Subject: dmaengine: qcom_hidma: configure DMA and MSI for OF Configure the DMA bindings for the device tree based firmware. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_mgmt.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 82f36e466083..185d29c77c22 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -375,8 +375,15 @@ static int __init hidma_mgmt_of_populate_channels(struct device_node *np) ret = PTR_ERR(new_pdev); goto out; } + of_node_get(child); + new_pdev->dev.of_node = child; of_dma_configure(&new_pdev->dev, child); - + /* + * It is assumed that calling of_msi_configure is safe on + * platforms with or without MSI support. + */ + of_msi_configure(&new_pdev->dev, child); + of_node_put(child); kfree(res); res = NULL; } -- cgit v1.2.3 From d3eab504d44803147d94de8f8e1baf3f6f5645f1 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 7 Oct 2016 01:25:12 -0400 Subject: dmaengine: qcom_hidma: add a common API to setup the interrupt Introducing the hidma_ll_setup_irq function to set up the interrupt type externally from the OS interface. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.h | 2 ++ drivers/dma/qcom/hidma_ll.c | 27 +++++++++++++++++++++++---- 2 files changed, 25 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h index e52e20716303..de6176497524 100644 --- a/drivers/dma/qcom/hidma.h +++ b/drivers/dma/qcom/hidma.h @@ -46,6 +46,7 @@ struct hidma_tre { }; struct hidma_lldev { + bool msi_support; /* flag indicating MSI support */ bool initialized; /* initialized flag */ u8 trch_state; /* trch_state of the device */ u8 evch_state; /* evch_state of the device */ @@ -145,6 +146,7 @@ int hidma_ll_disable(struct hidma_lldev *lldev); int hidma_ll_enable(struct hidma_lldev *llhndl); void hidma_ll_set_transfer_params(struct hidma_lldev *llhndl, u32 tre_ch, dma_addr_t src, dma_addr_t dest, u32 len, u32 flags); +void hidma_ll_setup_irq(struct hidma_lldev *lldev, bool msi); int hidma_ll_setup(struct hidma_lldev *lldev); struct hidma_lldev *hidma_ll_init(struct device *dev, u32 max_channels, void __iomem *trca, void __iomem *evca, diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index c3a66c9b0ab7..132d29eb9a63 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -680,17 +680,36 @@ int hidma_ll_setup(struct hidma_lldev *lldev) writel(HIDMA_EVRE_SIZE * nr_tres, lldev->evca + HIDMA_EVCA_RING_LEN_REG); - /* support IRQ only for now */ + /* configure interrupts */ + hidma_ll_setup_irq(lldev, lldev->msi_support); + + rc = hidma_ll_enable(lldev); + if (rc) + return rc; + + return rc; +} + +void hidma_ll_setup_irq(struct hidma_lldev *lldev, bool msi) +{ + u32 val; + + lldev->msi_support = msi; + + /* disable interrupts again after reset */ + writel(0, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); + writel(0, lldev->evca + HIDMA_EVCA_IRQ_EN_REG); + + /* support IRQ by default */ val = readl(lldev->evca + HIDMA_EVCA_INTCTRL_REG); val &= ~0xF; - val |= 0x1; + if (!lldev->msi_support) + val = val | 0x1; writel(val, lldev->evca + HIDMA_EVCA_INTCTRL_REG); /* clear all pending interrupts and enable them */ writel(ENABLE_IRQS, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); writel(ENABLE_IRQS, lldev->evca + HIDMA_EVCA_IRQ_EN_REG); - - return hidma_ll_enable(lldev); } struct hidma_lldev *hidma_ll_init(struct device *dev, u32 nr_tres, -- cgit v1.2.3 From fc737969f645c1cbb1d167604eb7082fe18809c4 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 7 Oct 2016 01:25:14 -0400 Subject: dmaengine: qcom_hidma: break completion processing on error We try to consume as much successful transfers as possible. Now that we support MSI interrupts, an error interrupt might be observed by another processor while we are finishing the successful ones. Try to abort successful processing if this is the case. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_ll.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 132d29eb9a63..e605c9096545 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -291,6 +291,13 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev) evre_write_off = readl_relaxed(lldev->evca + HIDMA_EVCA_WRITE_PTR_REG); num_completed++; + + /* + * An error interrupt might have arrived while we are processing + * the completed interrupt. + */ + if (!hidma_ll_isenabled(lldev)) + break; } if (num_completed) { -- cgit v1.2.3 From 1b7794163ab35a06b32b04ff558819ebb684b1c2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sun, 16 Oct 2016 13:25:47 +0100 Subject: dmaengine: ioatdma: loop for number elements in array chanerr_str Just iterate over the number of elements in array chanerr_str rather than for all 32 bits. This removes the need for a NULL chanerr_str[i] check which could possibly overrun if the upper bits (28..31) of chanerr are set and 27th bit in chanerr is zero. This simplifies the code by removing an if statement and a break. Signed-off-by: Colin Ian King Signed-off-by: Vinod Koul --- drivers/dma/ioat/dma.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 49386ce04bf5..42ff3073d89d 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -66,7 +66,6 @@ static char *chanerr_str[] = { "Result Guard Tag verification Error", "Result Application Tag verification Error", "Result Reference Tag verification Error", - NULL }; static void ioat_eh(struct ioatdma_chan *ioat_chan); @@ -75,13 +74,10 @@ static void ioat_print_chanerrs(struct ioatdma_chan *ioat_chan, u32 chanerr) { int i; - for (i = 0; i < 32; i++) { + for (i = 0; i < ARRAY_SIZE(chanerr_str); i++) { if ((chanerr >> i) & 1) { - if (chanerr_str[i]) { - dev_err(to_dev(ioat_chan), "Err(%d): %s\n", - i, chanerr_str[i]); - } else - break; + dev_err(to_dev(ioat_chan), "Err(%d): %s\n", + i, chanerr_str[i]); } } } -- cgit v1.2.3 From 8d7c22ac0c036978a072b7e13c607b5402c474e0 Mon Sep 17 00:00:00 2001 From: Toshi Kani Date: Wed, 19 Oct 2016 08:19:44 -0600 Subject: libnvdimm: use generic iostat interfaces nd_iostat_start() and nd_iostat_end() implement the same functionality that generic_start_io_acct() and generic_end_io_acct() already provide. Change nd_iostat_start() and nd_iostat_end() to call the generic iostat interfaces. There is no change in the nd interfaces. Signed-off-by: Toshi Kani Cc: Andrew Morton Cc: Alexander Viro Cc: Dave Chinner Cc: Ross Zwisler Signed-off-by: Dan Williams --- drivers/nvdimm/core.c | 29 ----------------------------- drivers/nvdimm/nd.h | 11 +++++++++-- 2 files changed, 9 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/core.c b/drivers/nvdimm/core.c index 7ceba08774b6..9303cfeb8bee 100644 --- a/drivers/nvdimm/core.c +++ b/drivers/nvdimm/core.c @@ -317,35 +317,6 @@ ssize_t nd_sector_size_store(struct device *dev, const char *buf, } } -void __nd_iostat_start(struct bio *bio, unsigned long *start) -{ - struct gendisk *disk = bio->bi_bdev->bd_disk; - const int rw = bio_data_dir(bio); - int cpu = part_stat_lock(); - - *start = jiffies; - part_round_stats(cpu, &disk->part0); - part_stat_inc(cpu, &disk->part0, ios[rw]); - part_stat_add(cpu, &disk->part0, sectors[rw], bio_sectors(bio)); - part_inc_in_flight(&disk->part0, rw); - part_stat_unlock(); -} -EXPORT_SYMBOL(__nd_iostat_start); - -void nd_iostat_end(struct bio *bio, unsigned long start) -{ - struct gendisk *disk = bio->bi_bdev->bd_disk; - unsigned long duration = jiffies - start; - const int rw = bio_data_dir(bio); - int cpu = part_stat_lock(); - - part_stat_add(cpu, &disk->part0, ticks[rw], duration); - part_round_stats(cpu, &disk->part0); - part_dec_in_flight(&disk->part0, rw); - part_stat_unlock(); -} -EXPORT_SYMBOL(nd_iostat_end); - static ssize_t commands_show(struct device *dev, struct device_attribute *attr, char *buf) { diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index d3b2fca8deec..065abf1b8f32 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -377,10 +377,17 @@ static inline bool nd_iostat_start(struct bio *bio, unsigned long *start) if (!blk_queue_io_stat(disk->queue)) return false; - __nd_iostat_start(bio, start); + *start = jiffies; + generic_start_io_acct(bio_data_dir(bio), + bio_sectors(bio), &disk->part0); return true; } -void nd_iostat_end(struct bio *bio, unsigned long start); +static inline void nd_iostat_end(struct bio *bio, unsigned long start) +{ + struct gendisk *disk = bio->bi_bdev->bd_disk; + + generic_end_io_acct(bio_data_dir(bio), &disk->part0, start); +} static inline bool is_bad_pmem(struct badblocks *bb, sector_t sector, unsigned int len) { -- cgit v1.2.3 From 42237e393f64d619ed56e17fbf8fd27526485695 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 15 Oct 2016 15:33:52 -0700 Subject: libnvdimm: allow a platform to force enable label support Platforms like QEMU-KVM implement an NFIT table and label DSMs. However, since that environment does not define an aliased configuration, the labels are currently ignored and the kernel registers a single full-sized pmem-namespace per region. Now that the kernel supports sub-divisions of pmem regions the labels have a purpose. Arrange for the labels to be honored when we find an existing / valid namespace index block. Cc: Cc: Haozhong Zhang Cc: Xiao Guangrong Signed-off-by: Dan Williams --- drivers/nvdimm/dimm.c | 2 ++ drivers/nvdimm/dimm_devs.c | 7 +++++++ drivers/nvdimm/nd.h | 1 + 3 files changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/nvdimm/dimm.c b/drivers/nvdimm/dimm.c index 619834e144d1..ee0b412827bf 100644 --- a/drivers/nvdimm/dimm.c +++ b/drivers/nvdimm/dimm.c @@ -64,6 +64,8 @@ static int nvdimm_probe(struct device *dev) nd_label_copy(ndd, to_next_namespace_index(ndd), to_current_namespace_index(ndd)); rc = nd_label_reserve_dpa(ndd); + if (ndd->ns_current >= 0) + nvdimm_set_aliasing(dev); nvdimm_bus_unlock(dev); if (rc) diff --git a/drivers/nvdimm/dimm_devs.c b/drivers/nvdimm/dimm_devs.c index d614493ad5ac..0eedc49e0d47 100644 --- a/drivers/nvdimm/dimm_devs.c +++ b/drivers/nvdimm/dimm_devs.c @@ -184,6 +184,13 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, return rc; } +void nvdimm_set_aliasing(struct device *dev) +{ + struct nvdimm *nvdimm = to_nvdimm(dev); + + nvdimm->flags |= NDD_ALIASING; +} + static void nvdimm_release(struct device *dev) { struct nvdimm *nvdimm = to_nvdimm(dev); diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 065abf1b8f32..35dd75057e16 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -238,6 +238,7 @@ int nvdimm_set_config_data(struct nvdimm_drvdata *ndd, size_t offset, void *buf, size_t len); long nvdimm_clear_poison(struct device *dev, phys_addr_t phys, unsigned int len); +void nvdimm_set_aliasing(struct device *dev); struct nd_btt *to_nd_btt(struct device *dev); struct nd_gen_sb { -- cgit v1.2.3 From 64933513e4610c90d84104a4988a328c934a3e7b Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Wed, 14 Sep 2016 14:27:53 +0100 Subject: reset: sti: Remove STiH415/6 reset support Support for STiH415/6 SoCs is being removed from the kernel because the platforms are obsolete. This patch removes the reset drivers for these SoC's. Signed-off-by: Peter Griffin Signed-off-by: Philipp Zabel --- arch/arm/mach-sti/Kconfig | 2 - drivers/reset/sti/Kconfig | 8 --- drivers/reset/sti/Makefile | 2 - drivers/reset/sti/reset-stih415.c | 112 ----------------------------- drivers/reset/sti/reset-stih416.c | 143 -------------------------------------- 5 files changed, 267 deletions(-) delete mode 100644 drivers/reset/sti/reset-stih415.c delete mode 100644 drivers/reset/sti/reset-stih416.c (limited to 'drivers') diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig index 119e1108b1f8..f8eeeffddaff 100644 --- a/arch/arm/mach-sti/Kconfig +++ b/arch/arm/mach-sti/Kconfig @@ -28,7 +28,6 @@ if ARCH_STI config SOC_STIH415 bool "STiH415 STMicroelectronics Consumer Electronics family" default y - select STIH415_RESET help This enables support for STMicroelectronics Digital Consumer Electronics family StiH415 parts, primarily targeted at set-top-box @@ -38,7 +37,6 @@ config SOC_STIH415 config SOC_STIH416 bool "STiH416 STMicroelectronics Consumer Electronics family" default y - select STIH416_RESET help This enables support for STMicroelectronics Digital Consumer Electronics family StiH416 parts, primarily targeted at set-top-box diff --git a/drivers/reset/sti/Kconfig b/drivers/reset/sti/Kconfig index 613178553612..71592b5bfd14 100644 --- a/drivers/reset/sti/Kconfig +++ b/drivers/reset/sti/Kconfig @@ -3,14 +3,6 @@ if ARCH_STI config STI_RESET_SYSCFG bool -config STIH415_RESET - bool - select STI_RESET_SYSCFG - -config STIH416_RESET - bool - select STI_RESET_SYSCFG - config STIH407_RESET bool select STI_RESET_SYSCFG diff --git a/drivers/reset/sti/Makefile b/drivers/reset/sti/Makefile index dc85dfbe56a9..f9d82411f29e 100644 --- a/drivers/reset/sti/Makefile +++ b/drivers/reset/sti/Makefile @@ -1,5 +1,3 @@ obj-$(CONFIG_STI_RESET_SYSCFG) += reset-syscfg.o -obj-$(CONFIG_STIH415_RESET) += reset-stih415.o -obj-$(CONFIG_STIH416_RESET) += reset-stih416.o obj-$(CONFIG_STIH407_RESET) += reset-stih407.o diff --git a/drivers/reset/sti/reset-stih415.c b/drivers/reset/sti/reset-stih415.c deleted file mode 100644 index 6f220cdbef46..000000000000 --- a/drivers/reset/sti/reset-stih415.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2013 STMicroelectronics (R&D) Limited - * Author: Stephen Gallimore - * Author: Srinivas Kandagatla - * - * 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 "reset-syscfg.h" - -/* - * STiH415 Peripheral powerdown definitions. - */ -static const char stih415_front[] = "st,stih415-front-syscfg"; -static const char stih415_rear[] = "st,stih415-rear-syscfg"; -static const char stih415_sbc[] = "st,stih415-sbc-syscfg"; -static const char stih415_lpm[] = "st,stih415-lpm-syscfg"; - -#define STIH415_PDN_FRONT(_bit) \ - _SYSCFG_RST_CH(stih415_front, SYSCFG_114, _bit, SYSSTAT_187, _bit) - -#define STIH415_PDN_REAR(_cntl, _stat) \ - _SYSCFG_RST_CH(stih415_rear, SYSCFG_336, _cntl, SYSSTAT_384, _stat) - -#define STIH415_SRST_REAR(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih415_rear, _reg, _bit) - -#define STIH415_SRST_SBC(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih415_sbc, _reg, _bit) - -#define STIH415_SRST_FRONT(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih415_front, _reg, _bit) - -#define STIH415_SRST_LPM(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih415_lpm, _reg, _bit) - -#define SYSCFG_114 0x38 /* Powerdown request EMI/NAND/Keyscan */ -#define SYSSTAT_187 0x15c /* Powerdown status EMI/NAND/Keyscan */ - -#define SYSCFG_336 0x90 /* Powerdown request USB/SATA/PCIe */ -#define SYSSTAT_384 0x150 /* Powerdown status USB/SATA/PCIe */ - -#define SYSCFG_376 0x130 /* Reset generator 0 control 0 */ -#define SYSCFG_166 0x108 /* Softreset Ethernet 0 */ -#define SYSCFG_31 0x7c /* Softreset Ethernet 1 */ -#define LPM_SYSCFG_1 0x4 /* Softreset IRB */ - -static const struct syscfg_reset_channel_data stih415_powerdowns[] = { - [STIH415_EMISS_POWERDOWN] = STIH415_PDN_FRONT(0), - [STIH415_NAND_POWERDOWN] = STIH415_PDN_FRONT(1), - [STIH415_KEYSCAN_POWERDOWN] = STIH415_PDN_FRONT(2), - [STIH415_USB0_POWERDOWN] = STIH415_PDN_REAR(0, 0), - [STIH415_USB1_POWERDOWN] = STIH415_PDN_REAR(1, 1), - [STIH415_USB2_POWERDOWN] = STIH415_PDN_REAR(2, 2), - [STIH415_SATA0_POWERDOWN] = STIH415_PDN_REAR(3, 3), - [STIH415_SATA1_POWERDOWN] = STIH415_PDN_REAR(4, 4), - [STIH415_PCIE_POWERDOWN] = STIH415_PDN_REAR(5, 8), -}; - -static const struct syscfg_reset_channel_data stih415_softresets[] = { - [STIH415_ETH0_SOFTRESET] = STIH415_SRST_FRONT(SYSCFG_166, 0), - [STIH415_ETH1_SOFTRESET] = STIH415_SRST_SBC(SYSCFG_31, 0), - [STIH415_IRB_SOFTRESET] = STIH415_SRST_LPM(LPM_SYSCFG_1, 6), - [STIH415_USB0_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 9), - [STIH415_USB1_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 10), - [STIH415_USB2_SOFTRESET] = STIH415_SRST_REAR(SYSCFG_376, 11), - [STIH415_KEYSCAN_SOFTRESET] = STIH415_SRST_LPM(LPM_SYSCFG_1, 8), -}; - -static struct syscfg_reset_controller_data stih415_powerdown_controller = { - .wait_for_ack = true, - .nr_channels = ARRAY_SIZE(stih415_powerdowns), - .channels = stih415_powerdowns, -}; - -static struct syscfg_reset_controller_data stih415_softreset_controller = { - .wait_for_ack = false, - .active_low = true, - .nr_channels = ARRAY_SIZE(stih415_softresets), - .channels = stih415_softresets, -}; - -static const struct of_device_id stih415_reset_match[] = { - { .compatible = "st,stih415-powerdown", - .data = &stih415_powerdown_controller, }, - { .compatible = "st,stih415-softreset", - .data = &stih415_softreset_controller, }, - {}, -}; - -static struct platform_driver stih415_reset_driver = { - .probe = syscfg_reset_probe, - .driver = { - .name = "reset-stih415", - .of_match_table = stih415_reset_match, - }, -}; - -static int __init stih415_reset_init(void) -{ - return platform_driver_register(&stih415_reset_driver); -} -arch_initcall(stih415_reset_init); diff --git a/drivers/reset/sti/reset-stih416.c b/drivers/reset/sti/reset-stih416.c deleted file mode 100644 index c581d606ef0f..000000000000 --- a/drivers/reset/sti/reset-stih416.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (C) 2013 STMicroelectronics (R&D) Limited - * Author: Stephen Gallimore - * Author: Srinivas Kandagatla - * - * 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 "reset-syscfg.h" - -/* - * STiH416 Peripheral powerdown definitions. - */ -static const char stih416_front[] = "st,stih416-front-syscfg"; -static const char stih416_rear[] = "st,stih416-rear-syscfg"; -static const char stih416_sbc[] = "st,stih416-sbc-syscfg"; -static const char stih416_lpm[] = "st,stih416-lpm-syscfg"; -static const char stih416_cpu[] = "st,stih416-cpu-syscfg"; - -#define STIH416_PDN_FRONT(_bit) \ - _SYSCFG_RST_CH(stih416_front, SYSCFG_1500, _bit, SYSSTAT_1578, _bit) - -#define STIH416_PDN_REAR(_cntl, _stat) \ - _SYSCFG_RST_CH(stih416_rear, SYSCFG_2525, _cntl, SYSSTAT_2583, _stat) - -#define SYSCFG_1500 0x7d0 /* Powerdown request EMI/NAND/Keyscan */ -#define SYSSTAT_1578 0x908 /* Powerdown status EMI/NAND/Keyscan */ - -#define SYSCFG_2525 0x834 /* Powerdown request USB/SATA/PCIe */ -#define SYSSTAT_2583 0x91c /* Powerdown status USB/SATA/PCIe */ - -#define SYSCFG_2552 0x8A0 /* Reset Generator control 0 */ -#define SYSCFG_1539 0x86c /* Softreset Ethernet 0 */ -#define SYSCFG_510 0x7f8 /* Softreset Ethernet 1 */ -#define LPM_SYSCFG_1 0x4 /* Softreset IRB */ -#define SYSCFG_2553 0x8a4 /* Softreset SATA0/1, PCIE0/1 */ -#define SYSCFG_7563 0x8cc /* MPE softresets 0 */ -#define SYSCFG_7564 0x8d0 /* MPE softresets 1 */ - -#define STIH416_SRST_CPU(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih416_cpu, _reg, _bit) - -#define STIH416_SRST_FRONT(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih416_front, _reg, _bit) - -#define STIH416_SRST_REAR(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih416_rear, _reg, _bit) - -#define STIH416_SRST_LPM(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih416_lpm, _reg, _bit) - -#define STIH416_SRST_SBC(_reg, _bit) \ - _SYSCFG_RST_CH_NO_ACK(stih416_sbc, _reg, _bit) - -static const struct syscfg_reset_channel_data stih416_powerdowns[] = { - [STIH416_EMISS_POWERDOWN] = STIH416_PDN_FRONT(0), - [STIH416_NAND_POWERDOWN] = STIH416_PDN_FRONT(1), - [STIH416_KEYSCAN_POWERDOWN] = STIH416_PDN_FRONT(2), - [STIH416_USB0_POWERDOWN] = STIH416_PDN_REAR(0, 0), - [STIH416_USB1_POWERDOWN] = STIH416_PDN_REAR(1, 1), - [STIH416_USB2_POWERDOWN] = STIH416_PDN_REAR(2, 2), - [STIH416_USB3_POWERDOWN] = STIH416_PDN_REAR(6, 5), - [STIH416_SATA0_POWERDOWN] = STIH416_PDN_REAR(3, 3), - [STIH416_SATA1_POWERDOWN] = STIH416_PDN_REAR(4, 4), - [STIH416_PCIE0_POWERDOWN] = STIH416_PDN_REAR(7, 9), - [STIH416_PCIE1_POWERDOWN] = STIH416_PDN_REAR(5, 8), -}; - -static const struct syscfg_reset_channel_data stih416_softresets[] = { - [STIH416_ETH0_SOFTRESET] = STIH416_SRST_FRONT(SYSCFG_1539, 0), - [STIH416_ETH1_SOFTRESET] = STIH416_SRST_SBC(SYSCFG_510, 0), - [STIH416_IRB_SOFTRESET] = STIH416_SRST_LPM(LPM_SYSCFG_1, 6), - [STIH416_USB0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 9), - [STIH416_USB1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 10), - [STIH416_USB2_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 11), - [STIH416_USB3_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 28), - [STIH416_SATA0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 7), - [STIH416_SATA1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 3), - [STIH416_PCIE0_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 15), - [STIH416_PCIE1_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 2), - [STIH416_AUD_DAC_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 14), - [STIH416_HDTVOUT_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 5), - [STIH416_VTAC_M_RX_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 25), - [STIH416_VTAC_A_RX_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2552, 26), - [STIH416_SYNC_HD_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 5), - [STIH416_SYNC_SD_SOFTRESET] = STIH416_SRST_REAR(SYSCFG_2553, 6), - [STIH416_BLITTER_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 10), - [STIH416_GPU_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 11), - [STIH416_VTAC_M_TX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 18), - [STIH416_VTAC_A_TX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 19), - [STIH416_VTG_AUX_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 21), - [STIH416_JPEG_DEC_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7563, 23), - [STIH416_HVA_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 2), - [STIH416_COMPO_M_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 3), - [STIH416_COMPO_A_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 4), - [STIH416_VP8_DEC_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 10), - [STIH416_VTG_MAIN_SOFTRESET] = STIH416_SRST_CPU(SYSCFG_7564, 16), - [STIH416_KEYSCAN_SOFTRESET] = STIH416_SRST_LPM(LPM_SYSCFG_1, 8), -}; - -static struct syscfg_reset_controller_data stih416_powerdown_controller = { - .wait_for_ack = true, - .nr_channels = ARRAY_SIZE(stih416_powerdowns), - .channels = stih416_powerdowns, -}; - -static struct syscfg_reset_controller_data stih416_softreset_controller = { - .wait_for_ack = false, - .active_low = true, - .nr_channels = ARRAY_SIZE(stih416_softresets), - .channels = stih416_softresets, -}; - -static const struct of_device_id stih416_reset_match[] = { - { .compatible = "st,stih416-powerdown", - .data = &stih416_powerdown_controller, }, - { .compatible = "st,stih416-softreset", - .data = &stih416_softreset_controller, }, - {}, -}; - -static struct platform_driver stih416_reset_driver = { - .probe = syscfg_reset_probe, - .driver = { - .name = "reset-stih416", - .of_match_table = stih416_reset_match, - }, -}; - -static int __init stih416_reset_init(void) -{ - return platform_driver_register(&stih416_reset_driver); -} -arch_initcall(stih416_reset_init); -- cgit v1.2.3 From a68262bb1e0cd21870a404a7b6323500e9b5c004 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Oct 2016 17:27:08 +0200 Subject: reset: oxnas: Add OX820 support In order to support the Oxford Semiconductor OX820 SoC, add a new compatible string. Signed-off-by: Neil Armstrong Signed-off-by: Philipp Zabel --- drivers/reset/reset-oxnas.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/reset/reset-oxnas.c b/drivers/reset/reset-oxnas.c index 944980572f79..0d9036dea010 100644 --- a/drivers/reset/reset-oxnas.c +++ b/drivers/reset/reset-oxnas.c @@ -80,6 +80,7 @@ static const struct reset_control_ops oxnas_reset_ops = { static const struct of_device_id oxnas_reset_dt_ids[] = { { .compatible = "oxsemi,ox810se-reset", }, + { .compatible = "oxsemi,ox820-reset", }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, oxnas_reset_dt_ids); -- cgit v1.2.3 From ecc2d430fadfba408b1d453d82128a696fa73fe0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 16 Sep 2016 13:03:47 +0000 Subject: memory: atmel-ebi: fix return value check in at91_ebi_dev_disable() Fix the retrn value check which testing the wrong variable in at91_ebi_dev_disable(). Signed-off-by: Wei Yongjun Signed-off-by: Alexandre Belloni --- drivers/memory/atmel-ebi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/memory/atmel-ebi.c b/drivers/memory/atmel-ebi.c index b5ed3bd082b5..047d6fcdcec2 100644 --- a/drivers/memory/atmel-ebi.c +++ b/drivers/memory/atmel-ebi.c @@ -657,7 +657,7 @@ static int at91_ebi_dev_disable(struct at91_ebi *ebi, struct device_node *np) return -ENOMEM; newprop->value = devm_kstrdup(dev, "disabled", GFP_KERNEL); - if (!newprop->name) + if (!newprop->value) return -ENOMEM; newprop->length = sizeof("disabled"); -- cgit v1.2.3 From af692400608857f7d7c3189c150c0b1d6b0ffad0 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 16 Sep 2016 13:05:10 +0000 Subject: memory: atmel-sdramc: use builtin_platform_driver to simplify the code Use the builtin_platform_driver() macro to make the code simpler. Signed-off-by: Wei Yongjun Signed-off-by: Alexandre Belloni --- drivers/memory/atmel-sdramc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/atmel-sdramc.c b/drivers/memory/atmel-sdramc.c index 12080b05e3e6..b418b39af180 100644 --- a/drivers/memory/atmel-sdramc.c +++ b/drivers/memory/atmel-sdramc.c @@ -85,8 +85,4 @@ static struct platform_driver atmel_ramc_driver = { }, }; -static int __init atmel_ramc_init(void) -{ - return platform_driver_register(&atmel_ramc_driver); -} -device_initcall(atmel_ramc_init); +builtin_platform_driver(atmel_ramc_driver); -- cgit v1.2.3 From 69eb4d0190eab9e32fccbe1ec64dec1cfa7fb01a Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 16 Sep 2016 12:08:51 +0200 Subject: hwrng: omap - Switch to non-obsolete read API implementation The ".data_present" and ".data_read" operations are marked as OBSOLETE in the hwrng API. We have to use the ".read" operation instead. It makes the driver simpler and moves the busy loop, that waits until enough data is generated, to the read function. We simplify this step by only checking the status of the engine, if there is data, we copy the data to the output buffer and the amout of copied data is returned to the caller, otherwise zero is returned. The hwrng core will re-call the read operation as many times as required until enough data has been copied. Signed-off-by: Romain Perier Signed-off-by: Herbert Xu --- drivers/char/hw_random/omap-rng.c | 41 ++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index f5c26a5f6875..6ba0794e1c5a 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -140,41 +140,35 @@ static inline void omap_rng_write(struct omap_rng_dev *priv, u16 reg, __raw_writel(val, priv->base + priv->pdata->regs[reg]); } -static int omap_rng_data_present(struct hwrng *rng, int wait) + +static int omap_rng_do_read(struct hwrng *rng, void *data, size_t max, + bool wait) { struct omap_rng_dev *priv; - int data, i; + int i, present; priv = (struct omap_rng_dev *)rng->priv; + if (max < priv->pdata->data_size) + return 0; + for (i = 0; i < 20; i++) { - data = priv->pdata->data_present(priv); - if (data || !wait) + present = priv->pdata->data_present(priv); + if (present || !wait) break; - /* RNG produces data fast enough (2+ MBit/sec, even - * during "rngtest" loads, that these delays don't - * seem to trigger. We *could* use the RNG IRQ, but - * that'd be higher overhead ... so why bother? - */ + udelay(10); } - return data; -} - -static int omap_rng_data_read(struct hwrng *rng, u32 *data) -{ - struct omap_rng_dev *priv; - u32 data_size, i; - - priv = (struct omap_rng_dev *)rng->priv; - data_size = priv->pdata->data_size; + if (!present) + return 0; - for (i = 0; i < data_size / sizeof(u32); i++) - data[i] = omap_rng_read(priv, RNG_OUTPUT_L_REG + i); + memcpy_fromio(data, priv->base + priv->pdata->regs[RNG_OUTPUT_L_REG], + priv->pdata->data_size); if (priv->pdata->regs[RNG_INTACK_REG]) omap_rng_write(priv, RNG_INTACK_REG, RNG_REG_INTACK_RDY_MASK); - return data_size; + + return priv->pdata->data_size; } static int omap_rng_init(struct hwrng *rng) @@ -195,8 +189,7 @@ static void omap_rng_cleanup(struct hwrng *rng) static struct hwrng omap_rng_ops = { .name = "omap", - .data_present = omap_rng_data_present, - .data_read = omap_rng_data_read, + .read = omap_rng_do_read, .init = omap_rng_init, .cleanup = omap_rng_cleanup, }; -- cgit v1.2.3 From b23d2d92ce34a487436dba8549a302729c5a40a2 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 16 Sep 2016 12:08:52 +0200 Subject: hwrng: omap - Remove global definition of hwrng The omap-rng driver currently assumes that there will only ever be a single instance of an RNG device. For this reason, there is a statically allocated struct hwrng, with a fixed name. However, registering two struct hwrng with the same isn't accepted by the RNG framework, so we need to switch to a dynamically allocated struct hwrng, each using a different name. Then, we define the name of this hwrng to "dev_name(dev)", so the name of the data structure is unique per device. Signed-off-by: Romain Perier Signed-off-by: Herbert Xu --- drivers/char/hw_random/omap-rng.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 6ba0794e1c5a..e4f71c8147f9 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -127,6 +127,7 @@ struct omap_rng_dev { void __iomem *base; struct device *dev; const struct omap_rng_pdata *pdata; + struct hwrng rng; }; static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg) @@ -187,12 +188,6 @@ static void omap_rng_cleanup(struct hwrng *rng) priv->pdata->cleanup(priv); } -static struct hwrng omap_rng_ops = { - .name = "omap", - .read = omap_rng_do_read, - .init = omap_rng_init, - .cleanup = omap_rng_cleanup, -}; static inline u32 omap2_rng_data_present(struct omap_rng_dev *priv) { @@ -365,7 +360,11 @@ static int omap_rng_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - omap_rng_ops.priv = (unsigned long)priv; + priv->rng.read = omap_rng_do_read; + priv->rng.init = omap_rng_init; + priv->rng.cleanup = omap_rng_cleanup; + + priv->rng.priv = (unsigned long)priv; platform_set_drvdata(pdev, priv); priv->dev = dev; @@ -376,6 +375,12 @@ static int omap_rng_probe(struct platform_device *pdev) goto err_ioremap; } + priv->rng.name = devm_kstrdup(dev, dev_name(dev), GFP_KERNEL); + if (!priv->rng.name) { + ret = -ENOMEM; + goto err_ioremap; + } + pm_runtime_enable(&pdev->dev); ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) { @@ -389,7 +394,7 @@ static int omap_rng_probe(struct platform_device *pdev) if (ret) goto err_ioremap; - ret = hwrng_register(&omap_rng_ops); + ret = hwrng_register(&priv->rng); if (ret) goto err_register; @@ -410,7 +415,7 @@ static int omap_rng_remove(struct platform_device *pdev) { struct omap_rng_dev *priv = platform_get_drvdata(pdev); - hwrng_unregister(&omap_rng_ops); + hwrng_unregister(&priv->rng); priv->pdata->cleanup(priv); -- cgit v1.2.3 From e54feeb0db9c6fc5d6b75cc045c9e4578534ec2e Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 16 Sep 2016 12:08:53 +0200 Subject: hwrng: omap - Add support for 128-bit output of data So far, this driver only supports up to 64 bits of output data generated by an RNG. Some IP blocks, like the SafeXcel IP-76 supports up to 128 bits of output data. This commits renames registers descriptions OUTPUT_L_REG and OUTPUT_H_REG to OUTPUT_0_REG and OUPUT_1_REG, respectively. It also adds two new values to the enumeration of existing registers: OUTPUT_2_REG and OUTPUT_3_REG. Signed-off-by: Romain Perier Signed-off-by: Herbert Xu --- drivers/char/hw_random/omap-rng.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index e4f71c8147f9..6c18540c8b43 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -65,8 +65,10 @@ #define OMAP4_RNG_OUTPUT_SIZE 0x8 enum { - RNG_OUTPUT_L_REG = 0, - RNG_OUTPUT_H_REG, + RNG_OUTPUT_0_REG = 0, + RNG_OUTPUT_1_REG, + RNG_OUTPUT_2_REG, + RNG_OUTPUT_3_REG, RNG_STATUS_REG, RNG_INTMASK_REG, RNG_INTACK_REG, @@ -82,7 +84,7 @@ enum { }; static const u16 reg_map_omap2[] = { - [RNG_OUTPUT_L_REG] = 0x0, + [RNG_OUTPUT_0_REG] = 0x0, [RNG_STATUS_REG] = 0x4, [RNG_CONFIG_REG] = 0x28, [RNG_REV_REG] = 0x3c, @@ -90,8 +92,8 @@ static const u16 reg_map_omap2[] = { }; static const u16 reg_map_omap4[] = { - [RNG_OUTPUT_L_REG] = 0x0, - [RNG_OUTPUT_H_REG] = 0x4, + [RNG_OUTPUT_0_REG] = 0x0, + [RNG_OUTPUT_1_REG] = 0x4, [RNG_STATUS_REG] = 0x8, [RNG_INTMASK_REG] = 0xc, [RNG_INTACK_REG] = 0x10, @@ -163,7 +165,7 @@ static int omap_rng_do_read(struct hwrng *rng, void *data, size_t max, if (!present) return 0; - memcpy_fromio(data, priv->base + priv->pdata->regs[RNG_OUTPUT_L_REG], + memcpy_fromio(data, priv->base + priv->pdata->regs[RNG_OUTPUT_0_REG], priv->pdata->data_size); if (priv->pdata->regs[RNG_INTACK_REG]) -- cgit v1.2.3 From f0d5a11200ca7071273d4b55b3c1d2a6f24f567b Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 16 Sep 2016 12:08:54 +0200 Subject: hwrng: omap - Don't prefix the probe message with OMAP So far, this driver was only used for OMAP SoCs. However, if a device variant is added for an IP block that has nothing to do with the OMAP platform, the message "OMAP Random Number Generator Ver" is displayed anyway. Instead of hardcoding "OMAP" into this message, we decide to only display "Random Number Generator". As dev_info is already pre-pending the message with the name of the device, we have enough informations. Signed-off-by: Romain Perier Signed-off-by: Herbert Xu --- drivers/char/hw_random/omap-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index 6c18540c8b43..c64a0990feb7 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -400,7 +400,7 @@ static int omap_rng_probe(struct platform_device *pdev) if (ret) goto err_register; - dev_info(&pdev->dev, "OMAP Random Number Generator ver. %02x\n", + dev_info(&pdev->dev, "Random Number Generator ver. %02x\n", omap_rng_read(priv, RNG_REV_REG)); return 0; -- cgit v1.2.3 From 383212425c926f3648fd760b2b674f1b7fac0d1d Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Fri, 16 Sep 2016 12:08:55 +0200 Subject: hwrng: omap - Add device variant for SafeXcel IP-76 found in Armada 8K This commits adds a device variant for Safexcel,EIP76 found in Marvell Armada 8k. It defines registers mapping with the good offset and add a specific initialization function. Signed-off-by: Romain Perier Signed-off-by: Herbert Xu --- drivers/char/hw_random/Kconfig | 2 +- drivers/char/hw_random/omap-rng.c | 86 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 200dab5136a7..ceff2fc524b1 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig @@ -168,7 +168,7 @@ config HW_RANDOM_IXP4XX config HW_RANDOM_OMAP tristate "OMAP Random Number Generator support" - depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS + depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS || ARCH_MVEBU default HW_RANDOM ---help--- This driver provides kernel-side support for the Random Number diff --git a/drivers/char/hw_random/omap-rng.c b/drivers/char/hw_random/omap-rng.c index c64a0990feb7..3ad86fdf954e 100644 --- a/drivers/char/hw_random/omap-rng.c +++ b/drivers/char/hw_random/omap-rng.c @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -63,6 +64,7 @@ #define OMAP2_RNG_OUTPUT_SIZE 0x4 #define OMAP4_RNG_OUTPUT_SIZE 0x8 +#define EIP76_RNG_OUTPUT_SIZE 0x10 enum { RNG_OUTPUT_0_REG = 0, @@ -108,6 +110,23 @@ static const u16 reg_map_omap4[] = { [RNG_SYSCONFIG_REG] = 0x1FE4, }; +static const u16 reg_map_eip76[] = { + [RNG_OUTPUT_0_REG] = 0x0, + [RNG_OUTPUT_1_REG] = 0x4, + [RNG_OUTPUT_2_REG] = 0x8, + [RNG_OUTPUT_3_REG] = 0xc, + [RNG_STATUS_REG] = 0x10, + [RNG_INTACK_REG] = 0x10, + [RNG_CONTROL_REG] = 0x14, + [RNG_CONFIG_REG] = 0x18, + [RNG_ALARMCNT_REG] = 0x1c, + [RNG_FROENABLE_REG] = 0x20, + [RNG_FRODETUNE_REG] = 0x24, + [RNG_ALARMMASK_REG] = 0x28, + [RNG_ALARMSTOP_REG] = 0x2c, + [RNG_REV_REG] = 0x7c, +}; + struct omap_rng_dev; /** * struct omap_rng_pdata - RNG IP block-specific data @@ -130,6 +149,7 @@ struct omap_rng_dev { struct device *dev; const struct omap_rng_pdata *pdata; struct hwrng rng; + struct clk *clk; }; static inline u32 omap_rng_read(struct omap_rng_dev *priv, u16 reg) @@ -221,6 +241,38 @@ static inline u32 omap4_rng_data_present(struct omap_rng_dev *priv) return omap_rng_read(priv, RNG_STATUS_REG) & RNG_REG_STATUS_RDY; } +static int eip76_rng_init(struct omap_rng_dev *priv) +{ + u32 val; + + /* Return if RNG is already running. */ + if (omap_rng_read(priv, RNG_CONTROL_REG) & RNG_CONTROL_ENABLE_TRNG_MASK) + return 0; + + /* Number of 512 bit blocks of raw Noise Source output data that must + * be processed by either the Conditioning Function or the + * SP 800-90 DRBG ‘BC_DF’ functionality to yield a ‘full entropy’ + * output value. + */ + val = 0x5 << RNG_CONFIG_MIN_REFIL_CYCLES_SHIFT; + + /* Number of FRO samples that are XOR-ed together into one bit to be + * shifted into the main shift register + */ + val |= RNG_CONFIG_MAX_REFIL_CYCLES << RNG_CONFIG_MAX_REFIL_CYCLES_SHIFT; + omap_rng_write(priv, RNG_CONFIG_REG, val); + + /* Enable all available FROs */ + omap_rng_write(priv, RNG_FRODETUNE_REG, 0x0); + omap_rng_write(priv, RNG_FROENABLE_REG, RNG_REG_FROENABLE_MASK); + + /* Enable TRNG */ + val = RNG_CONTROL_ENABLE_TRNG_MASK; + omap_rng_write(priv, RNG_CONTROL_REG, val); + + return 0; +} + static int omap4_rng_init(struct omap_rng_dev *priv) { u32 val; @@ -290,6 +342,14 @@ static struct omap_rng_pdata omap4_rng_pdata = { .cleanup = omap4_rng_cleanup, }; +static struct omap_rng_pdata eip76_rng_pdata = { + .regs = (u16 *)reg_map_eip76, + .data_size = EIP76_RNG_OUTPUT_SIZE, + .data_present = omap4_rng_data_present, + .init = eip76_rng_init, + .cleanup = omap4_rng_cleanup, +}; + static const struct of_device_id omap_rng_of_match[] = { { .compatible = "ti,omap2-rng", @@ -299,6 +359,10 @@ static const struct of_device_id omap_rng_of_match[] = { .compatible = "ti,omap4-rng", .data = &omap4_rng_pdata, }, + { + .compatible = "inside-secure,safexcel-eip76", + .data = &eip76_rng_pdata, + }, {}, }; MODULE_DEVICE_TABLE(of, omap_rng_of_match); @@ -317,7 +381,8 @@ static int of_get_omap_rng_device_details(struct omap_rng_dev *priv, } priv->pdata = match->data; - if (of_device_is_compatible(dev->of_node, "ti,omap4-rng")) { + if (of_device_is_compatible(dev->of_node, "ti,omap4-rng") || + of_device_is_compatible(dev->of_node, "inside-secure,safexcel-eip76")) { irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(dev, "%s: error getting IRQ resource - %d\n", @@ -333,6 +398,16 @@ static int of_get_omap_rng_device_details(struct omap_rng_dev *priv, return err; } omap_rng_write(priv, RNG_INTMASK_REG, RNG_SHUTDOWN_OFLO_MASK); + + priv->clk = of_clk_get(pdev->dev.of_node, 0); + if (IS_ERR(priv->clk) && PTR_ERR(priv->clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + if (!IS_ERR(priv->clk)) { + err = clk_prepare_enable(priv->clk); + if (err) + dev_err(&pdev->dev, "unable to enable the clk, " + "err = %d\n", err); + } } return 0; } @@ -394,7 +469,7 @@ static int omap_rng_probe(struct platform_device *pdev) ret = (dev->of_node) ? of_get_omap_rng_device_details(priv, pdev) : get_omap_rng_device_details(priv); if (ret) - goto err_ioremap; + goto err_register; ret = hwrng_register(&priv->rng); if (ret) @@ -407,7 +482,11 @@ static int omap_rng_probe(struct platform_device *pdev) err_register: priv->base = NULL; + pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); err_ioremap: dev_err(dev, "initialization failed.\n"); return ret; @@ -424,6 +503,9 @@ static int omap_rng_remove(struct platform_device *pdev) pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); + if (!IS_ERR(priv->clk)) + clk_disable_unprepare(priv->clk); + return 0; } -- cgit v1.2.3 From f709dc86bc4f9d8c320ceb9a12ac304756129dd5 Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Thu, 29 Sep 2016 18:46:57 +0200 Subject: crypto: atmel-aes - fix compiler error when VERBOSE_DEBUG is defined This patch fixes a compiler error when VERBOSE_DEBUG is defined. Indeed, in atmel_aes_write(), the 3rd argument of atmel_aes_reg_name() was missing. Signed-off-by: Cyrille Pitchen Reported-by: Levent Demir Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index e3d40a8dfffb..1d9e7bd3f377 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -317,7 +317,7 @@ static inline void atmel_aes_write(struct atmel_aes_dev *dd, char tmp[16]; dev_vdbg(dd->dev, "write 0x%08x into %s\n", value, - atmel_aes_reg_name(offset, tmp)); + atmel_aes_reg_name(offset, tmp, sizeof(tmp))); } #endif /* VERBOSE_DEBUG */ -- cgit v1.2.3 From d52db5188a87dcdf8e5bf024f45543b362a1a85f Mon Sep 17 00:00:00 2001 From: Cyrille Pitchen Date: Mon, 3 Oct 2016 14:33:16 +0200 Subject: crypto: atmel-aes - add support to the XTS mode This patch adds the xts(aes) algorithm, which is supported from hardware version 0x500 and above (sama5d2x). Signed-off-by: Cyrille Pitchen Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes-regs.h | 4 + drivers/crypto/atmel-aes.c | 185 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 183 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/atmel-aes-regs.h b/drivers/crypto/atmel-aes-regs.h index 6c2951bb70b1..0ec04407b533 100644 --- a/drivers/crypto/atmel-aes-regs.h +++ b/drivers/crypto/atmel-aes-regs.h @@ -28,6 +28,7 @@ #define AES_MR_OPMOD_CFB (0x3 << 12) #define AES_MR_OPMOD_CTR (0x4 << 12) #define AES_MR_OPMOD_GCM (0x5 << 12) +#define AES_MR_OPMOD_XTS (0x6 << 12) #define AES_MR_LOD (0x1 << 15) #define AES_MR_CFBS_MASK (0x7 << 16) #define AES_MR_CFBS_128b (0x0 << 16) @@ -67,6 +68,9 @@ #define AES_CTRR 0x98 #define AES_GCMHR(x) (0x9c + ((x) * 0x04)) +#define AES_TWR(x) (0xc0 + ((x) * 0x04)) +#define AES_ALPHAR(x) (0xd0 + ((x) * 0x04)) + #define AES_HW_VERSION 0xFC #endif /* __ATMEL_AES_REGS_H__ */ diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 1d9e7bd3f377..6b656f4a9378 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +69,7 @@ #define AES_FLAGS_CFB8 (AES_MR_OPMOD_CFB | AES_MR_CFBS_8b) #define AES_FLAGS_CTR AES_MR_OPMOD_CTR #define AES_FLAGS_GCM AES_MR_OPMOD_GCM +#define AES_FLAGS_XTS AES_MR_OPMOD_XTS #define AES_FLAGS_MODE_MASK (AES_FLAGS_OPMODE_MASK | \ AES_FLAGS_ENCRYPT | \ @@ -89,6 +91,7 @@ struct atmel_aes_caps { bool has_cfb64; bool has_ctr32; bool has_gcm; + bool has_xts; u32 max_burst_size; }; @@ -135,6 +138,12 @@ struct atmel_aes_gcm_ctx { atmel_aes_fn_t ghash_resume; }; +struct atmel_aes_xts_ctx { + struct atmel_aes_base_ctx base; + + u32 key2[AES_KEYSIZE_256 / sizeof(u32)]; +}; + struct atmel_aes_reqctx { unsigned long mode; }; @@ -282,6 +291,20 @@ static const char *atmel_aes_reg_name(u32 offset, char *tmp, size_t sz) snprintf(tmp, sz, "GCMHR[%u]", (offset - AES_GCMHR(0)) >> 2); break; + case AES_TWR(0): + case AES_TWR(1): + case AES_TWR(2): + case AES_TWR(3): + snprintf(tmp, sz, "TWR[%u]", (offset - AES_TWR(0)) >> 2); + break; + + case AES_ALPHAR(0): + case AES_ALPHAR(1): + case AES_ALPHAR(2): + case AES_ALPHAR(3): + snprintf(tmp, sz, "ALPHAR[%u]", (offset - AES_ALPHAR(0)) >> 2); + break; + default: snprintf(tmp, sz, "0x%02x", offset); break; @@ -453,15 +476,15 @@ static inline int atmel_aes_complete(struct atmel_aes_dev *dd, int err) return err; } -static void atmel_aes_write_ctrl(struct atmel_aes_dev *dd, bool use_dma, - const u32 *iv) +static void atmel_aes_write_ctrl_key(struct atmel_aes_dev *dd, bool use_dma, + const u32 *iv, const u32 *key, int keylen) { u32 valmr = 0; /* MR register must be set before IV registers */ - if (dd->ctx->keylen == AES_KEYSIZE_128) + if (keylen == AES_KEYSIZE_128) valmr |= AES_MR_KEYSIZE_128; - else if (dd->ctx->keylen == AES_KEYSIZE_192) + else if (keylen == AES_KEYSIZE_192) valmr |= AES_MR_KEYSIZE_192; else valmr |= AES_MR_KEYSIZE_256; @@ -478,13 +501,19 @@ static void atmel_aes_write_ctrl(struct atmel_aes_dev *dd, bool use_dma, atmel_aes_write(dd, AES_MR, valmr); - atmel_aes_write_n(dd, AES_KEYWR(0), dd->ctx->key, - SIZE_IN_WORDS(dd->ctx->keylen)); + atmel_aes_write_n(dd, AES_KEYWR(0), key, SIZE_IN_WORDS(keylen)); if (iv && (valmr & AES_MR_OPMOD_MASK) != AES_MR_OPMOD_ECB) atmel_aes_write_block(dd, AES_IVR(0), iv); } +static inline void atmel_aes_write_ctrl(struct atmel_aes_dev *dd, bool use_dma, + const u32 *iv) + +{ + atmel_aes_write_ctrl_key(dd, use_dma, iv, + dd->ctx->key, dd->ctx->keylen); +} /* CPU transfer */ @@ -1769,6 +1798,137 @@ static struct aead_alg aes_gcm_alg = { }; +/* xts functions */ + +static inline struct atmel_aes_xts_ctx * +atmel_aes_xts_ctx_cast(struct atmel_aes_base_ctx *ctx) +{ + return container_of(ctx, struct atmel_aes_xts_ctx, base); +} + +static int atmel_aes_xts_process_data(struct atmel_aes_dev *dd); + +static int atmel_aes_xts_start(struct atmel_aes_dev *dd) +{ + struct atmel_aes_xts_ctx *ctx = atmel_aes_xts_ctx_cast(dd->ctx); + struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq); + struct atmel_aes_reqctx *rctx = ablkcipher_request_ctx(req); + unsigned long flags; + int err; + + atmel_aes_set_mode(dd, rctx); + + err = atmel_aes_hw_init(dd); + if (err) + return atmel_aes_complete(dd, err); + + /* Compute the tweak value from req->info with ecb(aes). */ + flags = dd->flags; + dd->flags &= ~AES_FLAGS_MODE_MASK; + dd->flags |= (AES_FLAGS_ECB | AES_FLAGS_ENCRYPT); + atmel_aes_write_ctrl_key(dd, false, NULL, + ctx->key2, ctx->base.keylen); + dd->flags = flags; + + atmel_aes_write_block(dd, AES_IDATAR(0), req->info); + return atmel_aes_wait_for_data_ready(dd, atmel_aes_xts_process_data); +} + +static int atmel_aes_xts_process_data(struct atmel_aes_dev *dd) +{ + struct ablkcipher_request *req = ablkcipher_request_cast(dd->areq); + bool use_dma = (req->nbytes >= ATMEL_AES_DMA_THRESHOLD); + u32 tweak[AES_BLOCK_SIZE / sizeof(u32)]; + static const u32 one[AES_BLOCK_SIZE / sizeof(u32)] = {cpu_to_le32(1), }; + u8 *tweak_bytes = (u8 *)tweak; + int i; + + /* Read the computed ciphered tweak value. */ + atmel_aes_read_block(dd, AES_ODATAR(0), tweak); + /* + * Hardware quirk: + * the order of the ciphered tweak bytes need to be reversed before + * writing them into the ODATARx registers. + */ + for (i = 0; i < AES_BLOCK_SIZE/2; ++i) { + u8 tmp = tweak_bytes[AES_BLOCK_SIZE - 1 - i]; + + tweak_bytes[AES_BLOCK_SIZE - 1 - i] = tweak_bytes[i]; + tweak_bytes[i] = tmp; + } + + /* Process the data. */ + atmel_aes_write_ctrl(dd, use_dma, NULL); + atmel_aes_write_block(dd, AES_TWR(0), tweak); + atmel_aes_write_block(dd, AES_ALPHAR(0), one); + if (use_dma) + return atmel_aes_dma_start(dd, req->src, req->dst, req->nbytes, + atmel_aes_transfer_complete); + + return atmel_aes_cpu_start(dd, req->src, req->dst, req->nbytes, + atmel_aes_transfer_complete); +} + +static int atmel_aes_xts_setkey(struct crypto_ablkcipher *tfm, const u8 *key, + unsigned int keylen) +{ + struct atmel_aes_xts_ctx *ctx = crypto_ablkcipher_ctx(tfm); + int err; + + err = xts_check_key(crypto_ablkcipher_tfm(tfm), key, keylen); + if (err) + return err; + + memcpy(ctx->base.key, key, keylen/2); + memcpy(ctx->key2, key + keylen/2, keylen/2); + ctx->base.keylen = keylen/2; + + return 0; +} + +static int atmel_aes_xts_encrypt(struct ablkcipher_request *req) +{ + return atmel_aes_crypt(req, AES_FLAGS_XTS | AES_FLAGS_ENCRYPT); +} + +static int atmel_aes_xts_decrypt(struct ablkcipher_request *req) +{ + return atmel_aes_crypt(req, AES_FLAGS_XTS); +} + +static int atmel_aes_xts_cra_init(struct crypto_tfm *tfm) +{ + struct atmel_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm); + + tfm->crt_ablkcipher.reqsize = sizeof(struct atmel_aes_reqctx); + ctx->base.start = atmel_aes_xts_start; + + return 0; +} + +static struct crypto_alg aes_xts_alg = { + .cra_name = "xts(aes)", + .cra_driver_name = "atmel-xts-aes", + .cra_priority = ATMEL_AES_PRIORITY, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct atmel_aes_xts_ctx), + .cra_alignmask = 0xf, + .cra_type = &crypto_ablkcipher_type, + .cra_module = THIS_MODULE, + .cra_init = atmel_aes_xts_cra_init, + .cra_exit = atmel_aes_cra_exit, + .cra_u.ablkcipher = { + .min_keysize = 2 * AES_MIN_KEY_SIZE, + .max_keysize = 2 * AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + .setkey = atmel_aes_xts_setkey, + .encrypt = atmel_aes_xts_encrypt, + .decrypt = atmel_aes_xts_decrypt, + } +}; + + /* Probe functions */ static int atmel_aes_buff_init(struct atmel_aes_dev *dd) @@ -1877,6 +2037,9 @@ static void atmel_aes_unregister_algs(struct atmel_aes_dev *dd) { int i; + if (dd->caps.has_xts) + crypto_unregister_alg(&aes_xts_alg); + if (dd->caps.has_gcm) crypto_unregister_aead(&aes_gcm_alg); @@ -1909,8 +2072,16 @@ static int atmel_aes_register_algs(struct atmel_aes_dev *dd) goto err_aes_gcm_alg; } + if (dd->caps.has_xts) { + err = crypto_register_alg(&aes_xts_alg); + if (err) + goto err_aes_xts_alg; + } + return 0; +err_aes_xts_alg: + crypto_unregister_aead(&aes_gcm_alg); err_aes_gcm_alg: crypto_unregister_alg(&aes_cfb64_alg); err_aes_cfb64_alg: @@ -1928,6 +2099,7 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) dd->caps.has_cfb64 = 0; dd->caps.has_ctr32 = 0; dd->caps.has_gcm = 0; + dd->caps.has_xts = 0; dd->caps.max_burst_size = 1; /* keep only major version number */ @@ -1937,6 +2109,7 @@ static void atmel_aes_get_cap(struct atmel_aes_dev *dd) dd->caps.has_cfb64 = 1; dd->caps.has_ctr32 = 1; dd->caps.has_gcm = 1; + dd->caps.has_xts = 1; dd->caps.max_burst_size = 4; break; case 0x200: -- cgit v1.2.3 From 0c99620f0ac13a51f2f78cf62e6b551a09f8b1f1 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 5 Oct 2016 09:56:32 +0200 Subject: crypto: marvell - Use an unique pool to copy results of requests So far, we used a dedicated dma pool to copy the result of outer IV for cipher requests. Instead of using a dma pool per outer data, we prefer use the op dma pool that contains all part of the request from the SRAM. Then, the outer data that is likely to be used by the 'complete' operation, is copied later. In this way, any type of result can be retrieved by DMA for cipher or ahash requests. Signed-off-by: Romain Perier Acked-by: Boris Brezillon Signed-off-by: Herbert Xu --- drivers/crypto/marvell/cesa.c | 4 ---- drivers/crypto/marvell/cesa.h | 5 ++--- drivers/crypto/marvell/cipher.c | 8 +++++--- drivers/crypto/marvell/tdma.c | 33 +++++++++++++++++++-------------- 4 files changed, 26 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/marvell/cesa.c b/drivers/crypto/marvell/cesa.c index 37dadb2a4feb..6e7a5c77a00a 100644 --- a/drivers/crypto/marvell/cesa.c +++ b/drivers/crypto/marvell/cesa.c @@ -375,10 +375,6 @@ static int mv_cesa_dev_dma_init(struct mv_cesa_dev *cesa) if (!dma->padding_pool) return -ENOMEM; - dma->iv_pool = dmam_pool_create("cesa_iv", dev, 16, 1, 0); - if (!dma->iv_pool) - return -ENOMEM; - cesa->dma = dma; return 0; diff --git a/drivers/crypto/marvell/cesa.h b/drivers/crypto/marvell/cesa.h index e423d33decd4..a768da7138a1 100644 --- a/drivers/crypto/marvell/cesa.h +++ b/drivers/crypto/marvell/cesa.h @@ -277,7 +277,7 @@ struct mv_cesa_op_ctx { #define CESA_TDMA_DUMMY 0 #define CESA_TDMA_DATA 1 #define CESA_TDMA_OP 2 -#define CESA_TDMA_IV 3 +#define CESA_TDMA_RESULT 3 /** * struct mv_cesa_tdma_desc - TDMA descriptor @@ -393,7 +393,6 @@ struct mv_cesa_dev_dma { struct dma_pool *op_pool; struct dma_pool *cache_pool; struct dma_pool *padding_pool; - struct dma_pool *iv_pool; }; /** @@ -839,7 +838,7 @@ mv_cesa_tdma_desc_iter_init(struct mv_cesa_tdma_chain *chain) memset(chain, 0, sizeof(*chain)); } -int mv_cesa_dma_add_iv_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src, +int mv_cesa_dma_add_result_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src, u32 size, u32 flags, gfp_t gfp_flags); struct mv_cesa_op_ctx *mv_cesa_dma_add_op(struct mv_cesa_tdma_chain *chain, diff --git a/drivers/crypto/marvell/cipher.c b/drivers/crypto/marvell/cipher.c index d19dc9614e6e..098871a22a54 100644 --- a/drivers/crypto/marvell/cipher.c +++ b/drivers/crypto/marvell/cipher.c @@ -212,7 +212,8 @@ mv_cesa_ablkcipher_complete(struct crypto_async_request *req) struct mv_cesa_req *basereq; basereq = &creq->base; - memcpy(ablkreq->info, basereq->chain.last->data, ivsize); + memcpy(ablkreq->info, basereq->chain.last->op->ctx.blkcipher.iv, + ivsize); } else { memcpy_fromio(ablkreq->info, engine->sram + CESA_SA_CRYPT_IV_SRAM_OFFSET, @@ -373,8 +374,9 @@ static int mv_cesa_ablkcipher_dma_req_init(struct ablkcipher_request *req, /* Add output data for IV */ ivsize = crypto_ablkcipher_ivsize(crypto_ablkcipher_reqtfm(req)); - ret = mv_cesa_dma_add_iv_op(&basereq->chain, CESA_SA_CRYPT_IV_SRAM_OFFSET, - ivsize, CESA_TDMA_SRC_IN_SRAM, flags); + ret = mv_cesa_dma_add_result_op(&basereq->chain, CESA_SA_CFG_SRAM_OFFSET, + CESA_SA_DATA_SRAM_OFFSET, + CESA_TDMA_SRC_IN_SRAM, flags); if (ret) goto err_free_tdma; diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c index 9fd7a5fbaa1b..4416b88eca70 100644 --- a/drivers/crypto/marvell/tdma.c +++ b/drivers/crypto/marvell/tdma.c @@ -69,9 +69,6 @@ void mv_cesa_dma_cleanup(struct mv_cesa_req *dreq) if (type == CESA_TDMA_OP) dma_pool_free(cesa_dev->dma->op_pool, tdma->op, le32_to_cpu(tdma->src)); - else if (type == CESA_TDMA_IV) - dma_pool_free(cesa_dev->dma->iv_pool, tdma->data, - le32_to_cpu(tdma->dst)); tdma = tdma->next; dma_pool_free(cesa_dev->dma->tdma_desc_pool, old_tdma, @@ -209,29 +206,37 @@ mv_cesa_dma_add_desc(struct mv_cesa_tdma_chain *chain, gfp_t flags) return new_tdma; } -int mv_cesa_dma_add_iv_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src, +int mv_cesa_dma_add_result_op(struct mv_cesa_tdma_chain *chain, dma_addr_t src, u32 size, u32 flags, gfp_t gfp_flags) { - - struct mv_cesa_tdma_desc *tdma; - u8 *iv; - dma_addr_t dma_handle; + struct mv_cesa_tdma_desc *tdma, *op_desc; tdma = mv_cesa_dma_add_desc(chain, gfp_flags); if (IS_ERR(tdma)) return PTR_ERR(tdma); - iv = dma_pool_alloc(cesa_dev->dma->iv_pool, gfp_flags, &dma_handle); - if (!iv) - return -ENOMEM; + /* We re-use an existing op_desc object to retrieve the context + * and result instead of allocating a new one. + * There is at least one object of this type in a CESA crypto + * req, just pick the first one in the chain. + */ + for (op_desc = chain->first; op_desc; op_desc = op_desc->next) { + u32 type = op_desc->flags & CESA_TDMA_TYPE_MSK; + + if (type == CESA_TDMA_OP) + break; + } + + if (!op_desc) + return -EIO; tdma->byte_cnt = cpu_to_le32(size | BIT(31)); tdma->src = src; - tdma->dst = cpu_to_le32(dma_handle); - tdma->data = iv; + tdma->dst = op_desc->src; + tdma->op = op_desc->op; flags &= (CESA_TDMA_DST_IN_SRAM | CESA_TDMA_SRC_IN_SRAM); - tdma->flags = flags | CESA_TDMA_IV; + tdma->flags = flags | CESA_TDMA_RESULT; return 0; } -- cgit v1.2.3 From f34dad1721642989336283c9e6c3b8f6b23fa67c Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 5 Oct 2016 09:56:33 +0200 Subject: crypto: marvell - Don't break chain for computable last ahash requests Currently, the driver breaks chain for all kind of hash requests in order to don't override intermediate states of partial ahash updates. However, some final ahash requests can be directly processed by the engine, and so without intermediate state. This is typically the case for most for the HMAC requests processed via IPSec. This commits adds a TDMA descriptor to copy context for these of requests into the "op" dma pool, then it allow to chain these requests at the DMA level. The 'complete' operation is also updated to retrieve the MAC digest from the right location. Signed-off-by: Romain Perier Acked-by: Boris Brezillon Signed-off-by: Herbert Xu --- drivers/crypto/marvell/hash.c | 65 ++++++++++++++++++++++++++++++++----------- 1 file changed, 49 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index 9f284682c091..2a9260559654 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -312,24 +312,40 @@ static void mv_cesa_ahash_complete(struct crypto_async_request *req) int i; digsize = crypto_ahash_digestsize(crypto_ahash_reqtfm(ahashreq)); - for (i = 0; i < digsize / 4; i++) - creq->state[i] = readl_relaxed(engine->regs + CESA_IVDIG(i)); - if (creq->last_req) { + if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ && + (creq->base.chain.last->flags & CESA_TDMA_TYPE_MSK) == CESA_TDMA_RESULT) { + __le32 *data = NULL; + /* - * Hardware's MD5 digest is in little endian format, but - * SHA in big endian format + * Result is already in the correct endianess when the SA is + * used */ - if (creq->algo_le) { - __le32 *result = (void *)ahashreq->result; + data = creq->base.chain.last->op->ctx.hash.hash; + for (i = 0; i < digsize / 4; i++) + creq->state[i] = cpu_to_le32(data[i]); - for (i = 0; i < digsize / 4; i++) - result[i] = cpu_to_le32(creq->state[i]); - } else { - __be32 *result = (void *)ahashreq->result; + memcpy(ahashreq->result, data, digsize); + } else { + for (i = 0; i < digsize / 4; i++) + creq->state[i] = readl_relaxed(engine->regs + + CESA_IVDIG(i)); + if (creq->last_req) { + /* + * Hardware's MD5 digest is in little endian format, but + * SHA in big endian format + */ + if (creq->algo_le) { + __le32 *result = (void *)ahashreq->result; + + for (i = 0; i < digsize / 4; i++) + result[i] = cpu_to_le32(creq->state[i]); + } else { + __be32 *result = (void *)ahashreq->result; - for (i = 0; i < digsize / 4; i++) - result[i] = cpu_to_be32(creq->state[i]); + for (i = 0; i < digsize / 4; i++) + result[i] = cpu_to_be32(creq->state[i]); + } } } @@ -504,6 +520,12 @@ mv_cesa_ahash_dma_last_req(struct mv_cesa_tdma_chain *chain, CESA_SA_DESC_CFG_LAST_FRAG, CESA_SA_DESC_CFG_FRAG_MSK); + ret = mv_cesa_dma_add_result_op(chain, + CESA_SA_CFG_SRAM_OFFSET, + CESA_SA_DATA_SRAM_OFFSET, + CESA_TDMA_SRC_IN_SRAM, flags); + if (ret) + return ERR_PTR(-ENOMEM); return op; } @@ -564,6 +586,7 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) struct mv_cesa_op_ctx *op = NULL; unsigned int frag_len; int ret; + u32 type; basereq->chain.first = NULL; basereq->chain.last = NULL; @@ -635,7 +658,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) goto err_free_tdma; } - if (op) { + /* + * If results are copied via DMA, this means that this + * request can be directly processed by the engine, + * without partial updates. So we can chain it at the + * DMA level with other requests. + */ + type = basereq->chain.last->flags & CESA_TDMA_TYPE_MSK; + + if (op && type != CESA_TDMA_RESULT) { /* Add dummy desc to wait for crypto operation end */ ret = mv_cesa_dma_add_dummy_end(&basereq->chain, flags); if (ret) @@ -648,8 +679,10 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) else creq->cache_ptr = 0; - basereq->chain.last->flags |= (CESA_TDMA_END_OF_REQ | - CESA_TDMA_BREAK_CHAIN); + basereq->chain.last->flags |= CESA_TDMA_END_OF_REQ; + + if (type != CESA_TDMA_RESULT) + basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN; return 0; -- cgit v1.2.3 From 4c36941aee7f9bb3a1183ba89aa15b86622c8668 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Fri, 7 Oct 2016 22:36:20 +0200 Subject: crypto: crypto4xx - Fix size used in dma_free_coherent() The size used in 'dma_free_coherent()' looks un-initialized here. ctx->sa_len is set a few lines below and is apparently not set by the caller. So use 'size' as in the corresponding 'dma_alloc_coherent()' a few lines above. This has been spotted with coccinelle, using the following script: //////////////////// @r@ expression x0, x1, y0, y1, z0, z1, t0, t1, ret; @@ * ret = dma_alloc_coherent(x0, y0, z0, t0); ... * dma_free_coherent(x1, y1, ret, t1); @script:python@ y0 << r.y0; y1 << r.y1; @@ if y1.find(y0) == -1: print "WARNING: sizes look different: '%s' vs '%s'" % (y0, y1) //////////////////// Signed-off-by: Christophe JAILLET Signed-off-by: Herbert Xu --- drivers/crypto/amcc/crypto4xx_core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/amcc/crypto4xx_core.c b/drivers/crypto/amcc/crypto4xx_core.c index dae1e39139e9..d10b4ae5e0da 100644 --- a/drivers/crypto/amcc/crypto4xx_core.c +++ b/drivers/crypto/amcc/crypto4xx_core.c @@ -135,8 +135,7 @@ int crypto4xx_alloc_sa(struct crypto4xx_ctx *ctx, u32 size) ctx->sa_out = dma_alloc_coherent(ctx->dev->core_dev->device, size * 4, &ctx->sa_out_dma_addr, GFP_ATOMIC); if (ctx->sa_out == NULL) { - dma_free_coherent(ctx->dev->core_dev->device, - ctx->sa_len * 4, + dma_free_coherent(ctx->dev->core_dev->device, size * 4, ctx->sa_in, ctx->sa_in_dma_addr); return -ENOMEM; } -- cgit v1.2.3 From 3cf799680d2612a21d50ed554848dd37241672c8 Mon Sep 17 00:00:00 2001 From: Gary R Hook Date: Wed, 12 Oct 2016 08:47:03 -0500 Subject: crypto: ccp - change type of struct member lsb to signed The lsb field uses a value of -1 to indicate that it is unassigned. Therefore type must be a signed int. Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index da5f4a678083..5afaa53672b3 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -278,7 +278,7 @@ struct ccp_cmd_queue { /* Private LSB that is assigned to this queue, or -1 if none. * Bitmap for my private LSB, unused otherwise */ - unsigned int lsb; + int lsb; DECLARE_BITMAP(lsbmap, PLSB_MAP_SIZE); /* Queue processing thread */ -- cgit v1.2.3 From 58d5b693637d9963018bcb92fecf858e6899ed49 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 19 Oct 2016 16:49:59 -0300 Subject: pwm: meson: Remove unneeded platform MODULE_ALIAS The Amlogic Meson is a DT-only platform, which means the devices are registered via OF and not using the legacy platform devices support. So there's no need to have a MODULE_ALIAS("platform:meson-pwm") since the reported uevent MODALIAS to user-space will always be the OF one. Signed-off-by: Javier Martinez Canillas Acked-by: Kevin Hilman Signed-off-by: Thierry Reding --- drivers/pwm/pwm-meson.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pwm/pwm-meson.c b/drivers/pwm/pwm-meson.c index 381871b2bb46..5678092cad4b 100644 --- a/drivers/pwm/pwm-meson.c +++ b/drivers/pwm/pwm-meson.c @@ -523,7 +523,6 @@ static struct platform_driver meson_pwm_driver = { }; module_platform_driver(meson_pwm_driver); -MODULE_ALIAS("platform:meson-pwm"); MODULE_DESCRIPTION("Amlogic Meson PWM Generator driver"); MODULE_AUTHOR("Neil Armstrong "); MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 15c8ffc41a1559e37e3ec7106b261f5706490f1e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 06:50:34 -0300 Subject: [media] tuner-xc2028: mark printk continuation lines as such This driver has a lot of printk continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner-xc2028.c | 93 +++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 317ef63ee789..55f6c858b9c3 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -179,67 +179,67 @@ static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val) static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq) { if (type & BASE) - printk("BASE "); + printk(KERN_CONT "BASE "); if (type & INIT1) - printk("INIT1 "); + printk(KERN_CONT "INIT1 "); if (type & F8MHZ) - printk("F8MHZ "); + printk(KERN_CONT "F8MHZ "); if (type & MTS) - printk("MTS "); + printk(KERN_CONT "MTS "); if (type & D2620) - printk("D2620 "); + printk(KERN_CONT "D2620 "); if (type & D2633) - printk("D2633 "); + printk(KERN_CONT "D2633 "); if (type & DTV6) - printk("DTV6 "); + printk(KERN_CONT "DTV6 "); if (type & QAM) - printk("QAM "); + printk(KERN_CONT "QAM "); if (type & DTV7) - printk("DTV7 "); + printk(KERN_CONT "DTV7 "); if (type & DTV78) - printk("DTV78 "); + printk(KERN_CONT "DTV78 "); if (type & DTV8) - printk("DTV8 "); + printk(KERN_CONT "DTV8 "); if (type & FM) - printk("FM "); + printk(KERN_CONT "FM "); if (type & INPUT1) - printk("INPUT1 "); + printk(KERN_CONT "INPUT1 "); if (type & LCD) - printk("LCD "); + printk(KERN_CONT "LCD "); if (type & NOGD) - printk("NOGD "); + printk(KERN_CONT "NOGD "); if (type & MONO) - printk("MONO "); + printk(KERN_CONT "MONO "); if (type & ATSC) - printk("ATSC "); + printk(KERN_CONT "ATSC "); if (type & IF) - printk("IF "); + printk(KERN_CONT "IF "); if (type & LG60) - printk("LG60 "); + printk(KERN_CONT "LG60 "); if (type & ATI638) - printk("ATI638 "); + printk(KERN_CONT "ATI638 "); if (type & OREN538) - printk("OREN538 "); + printk(KERN_CONT "OREN538 "); if (type & OREN36) - printk("OREN36 "); + printk(KERN_CONT "OREN36 "); if (type & TOYOTA388) - printk("TOYOTA388 "); + printk(KERN_CONT "TOYOTA388 "); if (type & TOYOTA794) - printk("TOYOTA794 "); + printk(KERN_CONT "TOYOTA794 "); if (type & DIBCOM52) - printk("DIBCOM52 "); + printk(KERN_CONT "DIBCOM52 "); if (type & ZARLINK456) - printk("ZARLINK456 "); + printk(KERN_CONT "ZARLINK456 "); if (type & CHINA) - printk("CHINA "); + printk(KERN_CONT "CHINA "); if (type & F6MHZ) - printk("F6MHZ "); + printk(KERN_CONT "F6MHZ "); if (type & INPUT2) - printk("INPUT2 "); + printk(KERN_CONT "INPUT2 "); if (type & SCODE) - printk("SCODE "); + printk(KERN_CONT "SCODE "); if (type & HAS_IF) - printk("HAS_IF_%d ", int_freq); + printk(KERN_CONT "HAS_IF_%d ", int_freq); } static v4l2_std_id parse_audio_std_option(void) @@ -374,8 +374,8 @@ static int load_all_firmwares(struct dvb_frontend *fe, if (!size || size > endp - p) { tuner_err("Firmware type "); dump_firm_type(type); - printk("(%x), id %llx is corrupted " - "(size=%d, expected %d)\n", + printk(KERN_CONT + "(%x), id %llx is corrupted (size=%d, expected %d)\n", type, (unsigned long long)id, (unsigned)(endp - p), size); goto corrupt; @@ -390,7 +390,7 @@ static int load_all_firmwares(struct dvb_frontend *fe, tuner_dbg("Reading firmware type "); if (debug) { dump_firm_type_and_int_freq(type, int_freq); - printk("(%x), id %llx, size=%d.\n", + printk(KERN_CONT "(%x), id %llx, size=%d.\n", type, (unsigned long long)id, size); } @@ -439,7 +439,8 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, tuner_dbg("%s called, want type=", __func__); if (debug) { dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + printk(KERN_CONT "(%x), id %016llx.\n", + type, (unsigned long long)*id); } if (!priv->firm) { @@ -498,7 +499,8 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, tuner_dbg("Selecting best matching firmware (%d bits) for " "type=", best_nr_matches); dump_firm_type(type); - printk("(%x), id %016llx:\n", type, (unsigned long long)*id); + printk(KERN_CONT + "(%x), id %016llx:\n", type, (unsigned long long)*id); i = best_i; goto found; } @@ -515,7 +517,8 @@ ret: tuner_dbg("%s firmware for type=", (i < 0) ? "Can't find" : "Found"); if (debug) { dump_firm_type(type); - printk("(%x), id %016llx.\n", type, (unsigned long long)*id); + printk(KERN_CONT "(%x), id %016llx.\n", + type, (unsigned long long)*id); } return i; } @@ -555,8 +558,8 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type, tuner_info("Loading firmware for type="); dump_firm_type(priv->firm[pos].type); - printk("(%x), id %016llx.\n", priv->firm[pos].type, - (unsigned long long)*id); + printk(KERN_CONT "(%x), id %016llx.\n", + priv->firm[pos].type, (unsigned long long)*id); p = priv->firm[pos].ptr; endp = p + priv->firm[pos].size; @@ -689,7 +692,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type, tuner_info("Loading SCODE for type="); dump_firm_type_and_int_freq(priv->firm[pos].type, priv->firm[pos].int_freq); - printk("(%x), id %016llx.\n", priv->firm[pos].type, + printk(KERN_CONT "(%x), id %016llx.\n", priv->firm[pos].type, (unsigned long long)*id); if (priv->firm_version < 0x0202) @@ -741,15 +744,15 @@ retry: tuner_dbg("checking firmware, user requested type="); if (debug) { dump_firm_type(new_fw.type); - printk("(%x), id %016llx, ", new_fw.type, + printk(KERN_CONT "(%x), id %016llx, ", new_fw.type, (unsigned long long)new_fw.std_req); if (!int_freq) { - printk("scode_tbl "); + printk(KERN_CONT "scode_tbl "); dump_firm_type(priv->ctrl.scode_table); - printk("(%x), ", priv->ctrl.scode_table); + printk(KERN_CONT "(%x), ", priv->ctrl.scode_table); } else - printk("int_freq %d, ", new_fw.int_freq); - printk("scode_nr %d\n", new_fw.scode_nr); + printk(KERN_CONT "int_freq %d, ", new_fw.int_freq); + printk(KERN_CONT "scode_nr %d\n", new_fw.scode_nr); } /* -- cgit v1.2.3 From 2af3eb647e9b90f679265a45a8fbb78048ba8889 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 06:59:16 -0300 Subject: [media] tuner-xc2028: don't break long lines Due to the 80-cols checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. So, join those continuation lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/tuner-xc2028.c | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index 55f6c858b9c3..e07c5fb59cc6 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -56,8 +56,7 @@ MODULE_PARM_DESC(no_poweroff, "0 (default) powers device off when not used.\n" static char audio_std[8]; module_param_string(audio_std, audio_std, sizeof(audio_std), 0); MODULE_PARM_DESC(audio_std, - "Audio standard. XC3028 audio decoder explicitly " - "needs to know what audio\n" + "Audio standard. XC3028 audio decoder explicitly needs to know what audio\n" "standard is needed for some video standards with audio A2 or NICAM.\n" "The valid values are:\n" "A2\n" @@ -69,8 +68,8 @@ MODULE_PARM_DESC(audio_std, static char firmware_name[30]; module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); -MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " - "default firmware name\n"); +MODULE_PARM_DESC(firmware_name, + "Firmware file name. Allows overriding the default firmware name\n"); static LIST_HEAD(hybrid_tuner_instance_list); static DEFINE_MUTEX(xc2028_list_mutex); @@ -346,8 +345,7 @@ static int load_all_firmwares(struct dvb_frontend *fe, n++; if (n >= n_array) { - tuner_err("More firmware images in file than " - "were expected!\n"); + tuner_err("More firmware images in file than were expected!\n"); goto corrupt; } @@ -496,8 +494,8 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, } if (best_nr_matches > 0) { - tuner_dbg("Selecting best matching firmware (%d bits) for " - "type=", best_nr_matches); + tuner_dbg("Selecting best matching firmware (%d bits) for type=", + best_nr_matches); dump_firm_type(type); printk(KERN_CONT "(%x), id %016llx:\n", type, (unsigned long long)*id); @@ -840,8 +838,7 @@ check_device: goto fail; } - tuner_dbg("Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", + tuner_dbg("Device is Xceive %d version %d.%d, firmware version %d.%d\n", hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8, (version & 0xf0) >> 4, version & 0xf); @@ -855,8 +852,7 @@ check_device: tuner_err("Incorrect readback of firmware version.\n"); goto fail; } else { - tuner_err("Returned an incorrect version. However, " - "read is not reliable enough. Ignoring it.\n"); + tuner_err("Returned an incorrect version. However, read is not reliable enough. Ignoring it.\n"); hwmodel = 3028; } } @@ -867,8 +863,7 @@ check_device: priv->hwvers = version & 0xff00; } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || priv->hwvers != (version & 0xff00)) { - tuner_err("Read invalid device hardware information - tuner " - "hung?\n"); + tuner_err("Read invalid device hardware information - tuner hung?\n"); goto fail; } -- cgit v1.2.3 From 5ccb197de29269ba854066c4f1a92eb71974e126 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 07:05:48 -0300 Subject: [media] em28xx: don't break long lines Due to the 80-cols checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. So, join those continuation lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 10 +++---- drivers/media/usb/em28xx/em28xx-cards.c | 51 ++++++++++++--------------------- drivers/media/usb/em28xx/em28xx-core.c | 11 ++++--- drivers/media/usb/em28xx/em28xx-dvb.c | 6 ++-- drivers/media/usb/em28xx/em28xx-input.c | 3 +- drivers/media/usb/em28xx/em28xx-video.c | 6 ++-- 6 files changed, 33 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index e11fe46a547c..2a3975b1aea5 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -3,7 +3,7 @@ * * Copyright (C) 2006 Markus Rechberger * - * Copyright (C) 2007-2014 Mauro Carvalho Chehab + * Copyright (C) 2007-2016 Mauro Carvalho Chehab * - Port to work with the in-kernel driver * - Cleanups, fixes, alsa-controls, etc. * @@ -254,8 +254,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) int nonblock, ret = 0; if (!dev) { - em28xx_err("BUG: em28xx can't find device struct." - " Can't proceed with open\n"); + em28xx_err("BUG: em28xx can't find device struct. Can't proceed with open\n"); return -ENODEV; } @@ -902,10 +901,9 @@ static int em28xx_audio_init(struct em28xx *dev) kref_get(&dev->ref); - printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus " - "Rechberger\n"); + printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); printk(KERN_INFO - "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n"); + "em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n"); err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio", THIS_MODULE, 0, &card); diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index e397f544f108..bed41c1b4817 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2832,13 +2832,10 @@ static int em28xx_hint_board(struct em28xx *dev) dev->tuner_type = em28xx_eeprom_hash[i].tuner; em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on eeprom hash.\n"); + em28xx_errdev("A hint were successfully done, based on eeprom hash.\n"); em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " \n"); + em28xx_errdev("If the board were missdetected, please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List \n"); em28xx_errdev("Board detected as %s\n", em28xx_boards[dev->model].name); @@ -2864,13 +2861,10 @@ static int em28xx_hint_board(struct em28xx *dev) dev->model = em28xx_i2c_hash[i].model; dev->tuner_type = em28xx_i2c_hash[i].tuner; em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, " - "based on i2c devicelist hash.\n"); + em28xx_errdev("A hint were successfully done, based on i2c devicelist hash.\n"); em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, " - "please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List " - " \n"); + em28xx_errdev("If the board were missdetected, please email this log to:\n"); + em28xx_errdev("\tV4L Mailing List \n"); em28xx_errdev("Board detected as %s\n", em28xx_boards[dev->model].name); @@ -2878,17 +2872,14 @@ static int em28xx_hint_board(struct em28xx *dev) } } - em28xx_errdev("Your board has no unique USB ID and thus need a " - "hint to be detected.\n"); - em28xx_errdev("You may try to use card= insmod option to " - "workaround that.\n"); + em28xx_errdev("Your board has no unique USB ID and thus need a hint to be detected.\n"); + em28xx_errdev("You may try to use card= insmod option to workaround that.\n"); em28xx_errdev("Please send an email with this log to:\n"); em28xx_errdev("\tV4L Mailing List \n"); em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); - em28xx_errdev("Here is a list of valid choices for the card=" - " insmod option:\n"); + em28xx_errdev("Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < em28xx_bcount; i++) { em28xx_errdev(" card=%d -> %s\n", i, em28xx_boards[i].name); @@ -3035,11 +3026,9 @@ static void em28xx_card_setup(struct em28xx *dev) if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) { em28xx_errdev("\n\n"); - em28xx_errdev("The support for this board weren't " - "valid yet.\n"); + em28xx_errdev("The support for this board weren't valid yet.\n"); em28xx_errdev("Please send a report of having this working\n"); - em28xx_errdev("not to V4L mailing list (and/or to other " - "addresses)\n\n"); + em28xx_errdev("not to V4L mailing list (and/or to other addresses)\n\n"); } /* Free eeprom data memory */ @@ -3360,8 +3349,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, /* Resets I2C speed */ retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { - em28xx_errdev("%s: em28xx_write_reg failed!" - " retval [%d]\n", + em28xx_errdev("%s: em28xx_write_reg failed! retval [%d]\n", __func__, retval); return retval; } @@ -3429,7 +3417,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ - printk(DRIVER_NAME ": Supports only %i em28xx boards.\n", + printk(DRIVER_NAME + ": Supports only %i em28xx boards.\n", EM28XX_MAXBOARDS); retval = -ENOMEM; goto err_no_slot; @@ -3438,8 +3427,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - em28xx_err(DRIVER_NAME " audio device (%04x:%04x): " - "interface %i, class %i\n", + em28xx_err(DRIVER_NAME + " audio device (%04x:%04x): interface %i, class %i\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), ifnum, @@ -3502,7 +3491,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, has_vendor_audio = true; } else { printk(KERN_INFO DRIVER_NAME - ": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); + ": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); } break; case 0x84: @@ -3576,8 +3565,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, } printk(KERN_INFO DRIVER_NAME - ": New device %s %s @ %s Mbps " - "(%04x:%04x, interface %d, class %d)\n", + ": New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", udev->manufacturer ? udev->manufacturer : "", udev->product ? udev->product : "", speed, @@ -3593,8 +3581,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, */ if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { printk(DRIVER_NAME ": Device initialization failed.\n"); - printk(DRIVER_NAME ": Device must be connected to a high-speed" - " USB 2.0 port.\n"); + printk(DRIVER_NAME ": Device must be connected to a high-speed USB 2.0 port.\n"); retval = -ENODEV; goto err_free; } diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index eebd5d7088d0..a73e853e876e 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -87,8 +87,8 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, return -EINVAL; if (reg_debug) { - printk(KERN_DEBUG "(pipe 0x%08x): " - "IN: %02x %02x %02x %02x %02x %02x %02x %02x ", + printk(KERN_DEBUG + "(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x ", pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, req, 0, 0, @@ -165,8 +165,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, if (reg_debug) { int byte; - printk(KERN_DEBUG "(pipe 0x%08x): " - "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", + printk(KERN_DEBUG + "(pipe 0x%08x): OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", pipe, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, req, 0, 0, @@ -942,8 +942,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!usb_bufs->transfer_buffer[i]) { - em28xx_err("unable to allocate %i bytes for transfer" - " buffer %i%s\n", + em28xx_err("unable to allocate %i bytes for transfer buffer %i%s\n", sb_size, i, in_interrupt() ? " while in int" : ""); em28xx_uninit_usb_xfer(dev, mode); diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 8cedef0daae4..488c70e5ebde 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -934,8 +934,7 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) cfg.ctrl = &ctl; if (!dev->dvb->fe[0]) { - em28xx_errdev("/2: dvb frontend not attached. " - "Can't attach xc3028\n"); + em28xx_errdev("/2: dvb frontend not attached. Can't attach xc3028\n"); return -EINVAL; } @@ -1937,8 +1936,7 @@ static int em28xx_dvb_init(struct em28xx *dev) } break; default: - em28xx_errdev("/2: The frontend of your DVB/ATSC card" - " isn't supported yet\n"); + em28xx_errdev("/2: The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if (NULL == dvb->fe[0]) { diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 4007356d991d..580f3853505d 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -703,8 +703,7 @@ static int em28xx_ir_init(struct em28xx *dev) if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) { /* No remote control support */ - em28xx_warn("Remote control support is not available for " - "this card.\n"); + em28xx_warn("Remote control support is not available for this card.\n"); return 0; } diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 1f7fa059eb34..119877bb8a1e 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -505,8 +505,7 @@ static void em28xx_copy_video(struct em28xx *dev, if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) { - em28xx_isocdbg("Overflow of %zu bytes past buffer end" - "(2)\n", + em28xx_isocdbg("Overflow of %zu bytes past buffer end(2)\n", ((char *)startwrite + lencopy) - ((char *)buf->vb_buf + buf->length)); lencopy = remain = (char *)buf->vb_buf + buf->length - @@ -2204,8 +2203,7 @@ static int em28xx_v4l2_close(struct file *filp) em28xx_videodbg("setting alternate 0\n"); errCode = usb_set_interface(dev->udev, 0, 0); if (errCode < 0) { - em28xx_errdev("cannot change alternate number to " - "0 (error=%i)\n", errCode); + em28xx_errdev("cannot change alternate number to 0 (error=%i)\n", errCode); } } -- cgit v1.2.3 From 3e7974169a826fe20381302bddd7d531b30646ef Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 07:10:10 -0300 Subject: [media] em28xx: mark printk continuation lines as such This driver has a lot of printk continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-core.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index a73e853e876e..06bee2d67273 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -102,7 +102,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { if (reg_debug) - printk(" failed!\n"); + printk(KERN_CONT " failed!\n"); mutex_unlock(&dev->ctrl_urb_lock); return usb_translate_errors(ret); } @@ -115,10 +115,10 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, if (reg_debug) { int byte; - printk("<<<"); + printk(KERN_CONT "<<<"); for (byte = 0; byte < len; byte++) - printk(" %02x", (unsigned char)buf[byte]); - printk("\n"); + printk(KERN_CONT " %02x", (unsigned char)buf[byte]); + printk(KERN_CONT "\n"); } return ret; @@ -174,8 +174,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, len & 0xff, len >> 8); for (byte = 0; byte < len; byte++) - printk(" %02x", (unsigned char)buf[byte]); - printk("\n"); + printk(KERN_CONT " %02x", (unsigned char)buf[byte]); + printk(KERN_CONT "\n"); } mutex_lock(&dev->ctrl_urb_lock); -- cgit v1.2.3 From 8314d40233f3790e4cfa704087bb2a43c18144d7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 07:26:47 -0300 Subject: [media] em28xx: use pr_foo instead of em28xx-specific printk macros There's no reason to keep using em28xx-specific printk macros here. Just use pr_foo(). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 31 ++++----- drivers/media/usb/em28xx/em28xx-camera.c | 34 +++++----- drivers/media/usb/em28xx/em28xx-cards.c | 77 +++++++++++----------- drivers/media/usb/em28xx/em28xx-core.c | 51 +++++++-------- drivers/media/usb/em28xx/em28xx-dvb.c | 42 ++++++------ drivers/media/usb/em28xx/em28xx-i2c.c | 109 ++++++++++++++++--------------- drivers/media/usb/em28xx/em28xx-input.c | 26 ++++---- drivers/media/usb/em28xx/em28xx-video.c | 57 ++++++++-------- drivers/media/usb/em28xx/em28xx.h | 18 +---- 9 files changed, 215 insertions(+), 230 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 2a3975b1aea5..b5f35a25d870 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -25,6 +25,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "em28xx.h" + #include #include #include @@ -44,7 +46,6 @@ #include #include #include -#include "em28xx.h" static int debug; module_param(debug, int, 0644); @@ -164,7 +165,7 @@ static void em28xx_audio_isocirq(struct urb *urb) status = usb_submit_urb(urb, GFP_ATOMIC); if (status < 0) - em28xx_errdev("resubmit of audio urb failed (error=%i)\n", + pr_err("resubmit of audio urb failed (error=%i)\n", status); return; } @@ -182,7 +183,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { - em28xx_errdev("submit of audio urb failed (error=%i)\n", + pr_err("submit of audio urb failed (error=%i)\n", errCode); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); @@ -254,7 +255,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) int nonblock, ret = 0; if (!dev) { - em28xx_err("BUG: em28xx can't find device struct. Can't proceed with open\n"); + pr_err("BUG: em28xx can't find device struct. Can't proceed with open\n"); return -ENODEV; } @@ -317,7 +318,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) err: mutex_unlock(&dev->lock); - em28xx_err("Error while configuring em28xx mixer\n"); + pr_err("Error while configuring em28xx mixer\n"); return ret; } @@ -755,7 +756,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) intf = usb_ifnum_to_if(dev->udev, dev->ifnum); if (intf->num_altsetting <= alt) { - em28xx_errdev("alt %d doesn't exist on interface %d\n", + pr_err("alt %d doesn't exist on interface %d\n", dev->ifnum, alt); return -ENODEV; } @@ -771,14 +772,14 @@ static int em28xx_audio_urb_init(struct em28xx *dev) } if (!ep) { - em28xx_errdev("Couldn't find an audio endpoint"); + pr_err("Couldn't find an audio endpoint"); return -ENODEV; } ep_size = em28xx_audio_ep_packet_size(dev->udev, ep); interval = 1 << (ep->bInterval - 1); - em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", + pr_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed), dev->ifnum, alt, interval, @@ -819,7 +820,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) if (urb_size > ep_size * npackets) npackets = DIV_ROUND_UP(urb_size, ep_size); - em28xx_info("Number of URBs: %d, with %d packets and %d size\n", + pr_info("Number of URBs: %d, with %d packets and %d size\n", num_urb, npackets, urb_size); /* Estimate the bytes per period */ @@ -857,7 +858,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC, &urb->transfer_dma); if (!buf) { - em28xx_errdev("usb_alloc_coherent failed!\n"); + pr_err("usb_alloc_coherent failed!\n"); em28xx_audio_free_urb(dev); return -ENOMEM; } @@ -897,7 +898,7 @@ static int em28xx_audio_init(struct em28xx *dev) return 0; } - em28xx_info("Binding audio extension\n"); + pr_info("Binding audio extension\n"); kref_get(&dev->ref); @@ -953,7 +954,7 @@ static int em28xx_audio_init(struct em28xx *dev) if (err < 0) goto urb_free; - em28xx_info("Audio extension successfully initialized\n"); + pr_info("Audio extension successfully initialized\n"); return 0; urb_free: @@ -978,7 +979,7 @@ static int em28xx_audio_fini(struct em28xx *dev) return 0; } - em28xx_info("Closing audio extension\n"); + pr_info("Closing audio extension\n"); if (dev->adev.sndcard) { snd_card_disconnect(dev->adev.sndcard); @@ -1002,7 +1003,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - em28xx_info("Suspending audio extension\n"); + pr_info("Suspending audio extension\n"); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); return 0; @@ -1016,7 +1017,7 @@ static int em28xx_audio_resume(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - em28xx_info("Resuming audio extension\n"); + pr_info("Resuming audio extension\n"); /* Nothing to do other than schedule_work() ?? */ schedule_work(&dev->adev.wq_trigger); return 0; diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 72f3f4d50253..bc07166e7df0 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -19,14 +19,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "em28xx.h" + #include #include #include #include #include -#include "em28xx.h" - /* Possible i2c addresses of Micron sensors */ static unsigned short micron_sensor_addrs[] = { 0xb8 >> 1, /* MT9V111, MT9V403 */ @@ -120,13 +120,13 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) ret = i2c_master_send(&client, ®, 1); if (ret < 0) { if (ret != -ENXIO) - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } @@ -135,13 +135,13 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) reg = 0xff; ret = i2c_master_send(&client, ®, 1); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } @@ -180,15 +180,15 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) dev->em28xx_sensor = EM28XX_MT9M001; break; default: - em28xx_info("unknown Micron sensor detected: 0x%04x\n", + pr_info("unknown Micron sensor detected: 0x%04x\n", id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - em28xx_info("unsupported sensor detected: %s\n", name); + pr_info("unsupported sensor detected: %s\n", name); else - em28xx_info("sensor %s detected\n", name); + pr_info("sensor %s detected\n", name); dev->i2c_client[dev->def_i2c_bus].addr = client.addr; return 0; @@ -218,7 +218,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { if (ret != -ENXIO) - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } @@ -226,7 +226,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x1d; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } @@ -238,7 +238,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x0a; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } @@ -246,7 +246,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x0b; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - em28xx_errdev("couldn't read from i2c device 0x%02x: error %i\n", + pr_err("couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } @@ -285,15 +285,15 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) name = "OV9655"; break; default: - em28xx_info("unknown OmniVision sensor detected: 0x%04x\n", + pr_info("unknown OmniVision sensor detected: 0x%04x\n", id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - em28xx_info("unsupported sensor detected: %s\n", name); + pr_info("unsupported sensor detected: %s\n", name); else - em28xx_info("sensor %s detected\n", name); + pr_info("sensor %s detected\n", name); dev->i2c_client[dev->def_i2c_bus].addr = client.addr; return 0; @@ -317,7 +317,7 @@ int em28xx_detect_sensor(struct em28xx *dev) */ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { - em28xx_info("No sensor detected\n"); + pr_info("No sensor detected\n"); return -ENODEV; } diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index bed41c1b4817..c73cf2012bf5 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -23,6 +23,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "em28xx.h" + #include #include #include @@ -39,7 +41,6 @@ #include #include -#include "em28xx.h" #define DRIVER_NAME "em28xx" @@ -2677,7 +2678,7 @@ static int em28xx_wait_until_ac97_features_equals(struct em28xx *dev, msleep(50); } - em28xx_warn("AC97 registers access is not reliable !\n"); + pr_warn("AC97 registers access is not reliable !\n"); return -ETIMEDOUT; } @@ -2831,12 +2832,12 @@ static int em28xx_hint_board(struct em28xx *dev) dev->model = em28xx_eeprom_hash[i].model; dev->tuner_type = em28xx_eeprom_hash[i].tuner; - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, based on eeprom hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List \n"); - em28xx_errdev("Board detected as %s\n", + pr_err("Your board has no unique USB ID.\n"); + pr_err("A hint were successfully done, based on eeprom hash.\n"); + pr_err("This method is not 100%% failproof.\n"); + pr_err("If the board were missdetected, please email this log to:\n"); + pr_err("\tV4L Mailing List \n"); + pr_err("Board detected as %s\n", em28xx_boards[dev->model].name); return 0; @@ -2860,28 +2861,28 @@ static int em28xx_hint_board(struct em28xx *dev) if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { dev->model = em28xx_i2c_hash[i].model; dev->tuner_type = em28xx_i2c_hash[i].tuner; - em28xx_errdev("Your board has no unique USB ID.\n"); - em28xx_errdev("A hint were successfully done, based on i2c devicelist hash.\n"); - em28xx_errdev("This method is not 100%% failproof.\n"); - em28xx_errdev("If the board were missdetected, please email this log to:\n"); - em28xx_errdev("\tV4L Mailing List \n"); - em28xx_errdev("Board detected as %s\n", + pr_err("Your board has no unique USB ID.\n"); + pr_err("A hint were successfully done, based on i2c devicelist hash.\n"); + pr_err("This method is not 100%% failproof.\n"); + pr_err("If the board were missdetected, please email this log to:\n"); + pr_err("\tV4L Mailing List \n"); + pr_err("Board detected as %s\n", em28xx_boards[dev->model].name); return 0; } } - em28xx_errdev("Your board has no unique USB ID and thus need a hint to be detected.\n"); - em28xx_errdev("You may try to use card= insmod option to workaround that.\n"); - em28xx_errdev("Please send an email with this log to:\n"); - em28xx_errdev("\tV4L Mailing List \n"); - em28xx_errdev("Board eeprom hash is 0x%08lx\n", dev->hash); - em28xx_errdev("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); + pr_err("Your board has no unique USB ID and thus need a hint to be detected.\n"); + pr_err("You may try to use card= insmod option to workaround that.\n"); + pr_err("Please send an email with this log to:\n"); + pr_err("\tV4L Mailing List \n"); + pr_err("Board eeprom hash is 0x%08lx\n", dev->hash); + pr_err("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); - em28xx_errdev("Here is a list of valid choices for the card= insmod option:\n"); + pr_err("Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < em28xx_bcount; i++) { - em28xx_errdev(" card=%d -> %s\n", + pr_err(" card=%d -> %s\n", i, em28xx_boards[i].name); } return -1; @@ -2916,7 +2917,7 @@ static void em28xx_card_setup(struct em28xx *dev) * hash identities which has not been determined as yet. */ if (em28xx_hint_board(dev) < 0) - em28xx_errdev("Board not discovered\n"); + pr_err("Board not discovered\n"); else { em28xx_set_model(dev); em28xx_pre_card_setup(dev); @@ -2926,7 +2927,7 @@ static void em28xx_card_setup(struct em28xx *dev) em28xx_set_model(dev); } - em28xx_info("Identified as %s (card=%d)\n", + pr_info("Identified as %s (card=%d)\n", dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; @@ -3025,10 +3026,10 @@ static void em28xx_card_setup(struct em28xx *dev) } if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) { - em28xx_errdev("\n\n"); - em28xx_errdev("The support for this board weren't valid yet.\n"); - em28xx_errdev("Please send a report of having this working\n"); - em28xx_errdev("not to V4L mailing list (and/or to other addresses)\n\n"); + pr_err("\n\n"); + pr_err("The support for this board weren't valid yet.\n"); + pr_err("Please send a report of having this working\n"); + pr_err("not to V4L mailing list (and/or to other addresses)\n\n"); } /* Free eeprom data memory */ @@ -3211,7 +3212,7 @@ void em28xx_free_device(struct kref *ref) { struct em28xx *dev = kref_to_dev(ref); - em28xx_info("Freeing device\n"); + pr_info("Freeing device\n"); if (!dev->disconnected) em28xx_release_resources(dev); @@ -3349,7 +3350,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, /* Resets I2C speed */ retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { - em28xx_errdev("%s: em28xx_write_reg failed! retval [%d]\n", + pr_err("%s: em28xx_write_reg failed! retval [%d]\n", __func__, retval); return retval; } @@ -3363,7 +3364,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, else retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { - em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n", + pr_err("%s: em28xx_i2c_register bus 0 - error [%d]!\n", __func__, retval); return retval; } @@ -3377,7 +3378,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, retval = em28xx_i2c_register(dev, 1, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { - em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n", + pr_err("%s: em28xx_i2c_register bus 1 - error [%d]!\n", __func__, retval); em28xx_i2c_unregister(dev, 0); @@ -3427,7 +3428,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - em28xx_err(DRIVER_NAME + pr_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), @@ -3441,7 +3442,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); if (dev == NULL) { - em28xx_err(DRIVER_NAME ": out of memory!\n"); retval = -ENOMEM; goto err; } @@ -3451,7 +3451,6 @@ static int em28xx_usb_probe(struct usb_interface *interface, kmalloc(sizeof(dev->alt_max_pkt_size_isoc[0]) * interface->num_altsetting, GFP_KERNEL); if (dev->alt_max_pkt_size_isoc == NULL) { - em28xx_errdev("out of memory!\n"); kfree(dev); retval = -ENOMEM; goto err; @@ -3604,7 +3603,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { if (has_vendor_audio) - em28xx_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n" + pr_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n" "\t\tThe vendor interface will be ignored. Please contact the developers \n"); dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; break; @@ -3661,13 +3660,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video) { if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) dev->analog_xfer_bulk = 1; - em28xx_info("analog set to %s mode.\n", + pr_info("analog set to %s mode.\n", dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) dev->dvb_xfer_bulk = 1; - em28xx_info("dvb set to %s mode.\n", + pr_info("dvb set to %s mode.\n", dev->dvb_xfer_bulk ? "bulk" : "isoc"); } @@ -3715,7 +3714,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) dev->disconnected = 1; - em28xx_info("Disconnecting %s\n", dev->name); + pr_info("Disconnecting %s\n", dev->name); flush_request_modules(dev); diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 06bee2d67273..8897cde9894b 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -22,6 +22,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "em28xx.h" + #include #include #include @@ -32,8 +34,6 @@ #include #include -#include "em28xx.h" - #define DRIVER_AUTHOR "Ludovico Cavedon , " \ "Markus Rechberger , " \ "Mauro Carvalho Chehab , " \ @@ -267,7 +267,7 @@ static int em28xx_is_ac97_ready(struct em28xx *dev) msleep(5); } - em28xx_warn("AC97 command still being executed: not handled properly!\n"); + pr_warn("AC97 command still being executed: not handled properly!\n"); return -EBUSY; } @@ -360,7 +360,7 @@ static int set_ac97_input(struct em28xx *dev) ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); if (ret < 0) - em28xx_warn("couldn't setup AC97 register %d\n", + pr_warn("couldn't setup AC97 register %d\n", inputs[i].reg); } return 0; @@ -444,7 +444,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) for (i = 0; i < ARRAY_SIZE(outputs); i++) { ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000); if (ret < 0) - em28xx_warn("couldn't setup AC97 register %d\n", + pr_warn("couldn't setup AC97 register %d\n", outputs[i].reg); } } @@ -482,7 +482,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) ret = em28xx_write_ac97(dev, outputs[i].reg, vol); if (ret < 0) - em28xx_warn("couldn't setup AC97 register %d\n", + pr_warn("couldn't setup AC97 register %d\n", outputs[i].reg); } @@ -519,7 +519,7 @@ int em28xx_audio_setup(struct em28xx *dev) /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); - em28xx_info("Config register raw data: 0x%02x\n", cfg); + pr_info("Config register raw data: 0x%02x\n", cfg); if (cfg < 0) { /* Register read error */ /* Be conservative */ dev->int_audio_type = EM28XX_INT_AUDIO_AC97; @@ -540,7 +540,7 @@ int em28xx_audio_setup(struct em28xx *dev) i2s_samplerates = 5; else i2s_samplerates = 3; - em28xx_info("I2S Audio (%d sample rate(s))\n", + pr_info("I2S Audio (%d sample rate(s))\n", i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; @@ -558,7 +558,7 @@ int em28xx_audio_setup(struct em28xx *dev) * Note: (some) em2800 devices without eeprom reports 0x91 on * CHIPCFG register, even not having an AC97 chip */ - em28xx_warn("AC97 chip type couldn't be determined\n"); + pr_warn("AC97 chip type couldn't be determined\n"); dev->audio_mode.ac97 = EM28XX_NO_AC97; if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR) dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; @@ -571,13 +571,13 @@ int em28xx_audio_setup(struct em28xx *dev) goto init_audio; vid = vid1 << 16 | vid2; - em28xx_warn("AC97 vendor ID = 0x%08x\n", vid); + pr_warn("AC97 vendor ID = 0x%08x\n", vid); feat = em28xx_read_ac97(dev, AC97_RESET); if (feat < 0) goto init_audio; - em28xx_warn("AC97 features = 0x%04x\n", feat); + pr_warn("AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90)) @@ -589,17 +589,17 @@ init_audio: /* Reports detected AC97 processor */ switch (dev->audio_mode.ac97) { case EM28XX_NO_AC97: - em28xx_info("No AC97 audio processor\n"); + pr_info("No AC97 audio processor\n"); break; case EM28XX_AC97_EM202: - em28xx_info("Empia 202 AC97 audio processor detected\n"); + pr_info("Empia 202 AC97 audio processor detected\n"); break; case EM28XX_AC97_SIGMATEL: - em28xx_info("Sigmatel audio processor detected (stac 97%02x)\n", + pr_info("Sigmatel audio processor detected (stac 97%02x)\n", vid & 0xff); break; case EM28XX_AC97_OTHER: - em28xx_warn("Unknown AC97 audio processor detected!\n"); + pr_warn("Unknown AC97 audio processor detected!\n"); break; default: break; @@ -883,7 +883,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, if (mode == EM28XX_DIGITAL_MODE) { if ((xfer_bulk && !dev->dvb_ep_bulk) || (!xfer_bulk && !dev->dvb_ep_isoc)) { - em28xx_errdev("no endpoint for DVB mode and transfer type %d\n", + pr_err("no endpoint for DVB mode and transfer type %d\n", xfer_bulk > 0); return -EINVAL; } @@ -891,13 +891,13 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, } else if (mode == EM28XX_ANALOG_MODE) { if ((xfer_bulk && !dev->analog_ep_bulk) || (!xfer_bulk && !dev->analog_ep_isoc)) { - em28xx_errdev("no endpoint for analog mode and transfer type %d\n", + pr_err("no endpoint for analog mode and transfer type %d\n", xfer_bulk > 0); return -EINVAL; } usb_bufs = &dev->usb_ctl.analog_bufs; } else { - em28xx_errdev("invalid mode selected\n"); + pr_err("invalid mode selected\n"); return -EINVAL; } @@ -907,15 +907,12 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->num_bufs = num_bufs; usb_bufs->urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); - if (!usb_bufs->urb) { - em28xx_errdev("cannot alloc memory for usb buffers\n"); + if (!usb_bufs->urb) return -ENOMEM; - } usb_bufs->transfer_buffer = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL); if (!usb_bufs->transfer_buffer) { - em28xx_errdev("cannot allocate memory for usb transfer\n"); kfree(usb_bufs->urb); return -ENOMEM; } @@ -942,7 +939,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!usb_bufs->transfer_buffer[i]) { - em28xx_err("unable to allocate %i bytes for transfer buffer %i%s\n", + pr_err("unable to allocate %i bytes for transfer buffer %i%s\n", sb_size, i, in_interrupt() ? " while in int" : ""); em28xx_uninit_usb_xfer(dev, mode); @@ -1024,7 +1021,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, if (xfer_bulk) { rc = usb_clear_halt(dev->udev, usb_bufs->urb[0]->pipe); if (rc < 0) { - em28xx_err("failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", + pr_err("failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", rc); em28xx_uninit_usb_xfer(dev, mode); return rc; @@ -1040,7 +1037,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, for (i = 0; i < usb_bufs->num_bufs; i++) { rc = usb_submit_urb(usb_bufs->urb[i], GFP_ATOMIC); if (rc) { - em28xx_err("submit of urb %i failed (error=%i)\n", i, + pr_err("submit of urb %i failed (error=%i)\n", i, rc); em28xx_uninit_usb_xfer(dev, mode); return rc; @@ -1123,7 +1120,7 @@ int em28xx_suspend_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - em28xx_info("Suspending extensions\n"); + pr_info("Suspending extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) @@ -1137,7 +1134,7 @@ int em28xx_resume_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - em28xx_info("Resuming extensions\n"); + pr_info("Resuming extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 488c70e5ebde..cbece65899b5 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -21,11 +21,12 @@ the Free Software Foundation; either version 2 of the License. */ +#include "em28xx.h" + #include #include #include -#include "em28xx.h" #include #include #include @@ -734,7 +735,7 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) ret = gpio_request_one(dvb->lna_gpio, flags, NULL); if (ret) - em28xx_errdev("gpio request failed %d\n", ret); + pr_err("gpio request failed %d\n", ret); else gpio_free(dvb->lna_gpio); @@ -934,19 +935,19 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) cfg.ctrl = &ctl; if (!dev->dvb->fe[0]) { - em28xx_errdev("/2: dvb frontend not attached. Can't attach xc3028\n"); + pr_err("/2: dvb frontend not attached. Can't attach xc3028\n"); return -EINVAL; } fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg); if (!fe) { - em28xx_errdev("/2: xc3028 attach failed\n"); + pr_err("/2: xc3028 attach failed\n"); dvb_frontend_detach(dev->dvb->fe[0]); dev->dvb->fe[0] = NULL; return -EINVAL; } - em28xx_info("%s/2: xc3028 attached\n", dev->name); + pr_info("%s/2: xc3028 attached\n", dev->name); return 0; } @@ -1116,13 +1117,12 @@ static int em28xx_dvb_init(struct em28xx *dev) return 0; } - em28xx_info("Binding DVB extension\n"); + pr_info("Binding DVB extension\n"); dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); - if (dvb == NULL) { - em28xx_info("em28xx_dvb: memory allocation failed\n"); + if (!dvb) return -ENOMEM; - } + dev->dvb = dvb; dvb->fe[0] = dvb->fe[1] = NULL; @@ -1141,7 +1141,7 @@ static int em28xx_dvb_init(struct em28xx *dev) EM28XX_DVB_NUM_ISOC_PACKETS); } if (result) { - em28xx_errdev("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n"); + pr_err("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n"); kfree(dvb); dev->dvb = NULL; return result; @@ -1320,7 +1320,7 @@ static int em28xx_dvb_init(struct em28xx *dev) result = gpio_request_one(dvb->lna_gpio, GPIOF_OUT_INIT_LOW, NULL); if (result) - em28xx_errdev("gpio request failed %d\n", + pr_err("gpio request failed %d\n", result); else gpio_free(dvb->lna_gpio); @@ -1936,11 +1936,11 @@ static int em28xx_dvb_init(struct em28xx *dev) } break; default: - em28xx_errdev("/2: The frontend of your DVB/ATSC card isn't supported yet\n"); + pr_err("/2: The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if (NULL == dvb->fe[0]) { - em28xx_errdev("/2: frontend initialization failed\n"); + pr_err("/2: frontend initialization failed\n"); result = -EINVAL; goto out_free; } @@ -1955,7 +1955,7 @@ static int em28xx_dvb_init(struct em28xx *dev) if (result < 0) goto out_free; - em28xx_info("DVB extension successfully initialized\n"); + pr_info("DVB extension successfully initialized\n"); kref_get(&dev->ref); @@ -1995,7 +1995,7 @@ static int em28xx_dvb_fini(struct em28xx *dev) if (!dev->dvb) return 0; - em28xx_info("Closing DVB extension\n"); + pr_info("Closing DVB extension\n"); dvb = dev->dvb; @@ -2053,17 +2053,17 @@ static int em28xx_dvb_suspend(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - em28xx_info("Suspending DVB extension\n"); + pr_info("Suspending DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_suspend(dvb->fe[0]); - em28xx_info("fe0 suspend %d\n", ret); + pr_info("fe0 suspend %d\n", ret); } if (dvb->fe[1]) { dvb_frontend_suspend(dvb->fe[1]); - em28xx_info("fe1 suspend %d\n", ret); + pr_info("fe1 suspend %d\n", ret); } } @@ -2080,18 +2080,18 @@ static int em28xx_dvb_resume(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - em28xx_info("Resuming DVB extension\n"); + pr_info("Resuming DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_resume(dvb->fe[0]); - em28xx_info("fe0 resume %d\n", ret); + pr_info("fe0 resume %d\n", ret); } if (dvb->fe[1]) { ret = dvb_frontend_resume(dvb->fe[1]); - em28xx_info("fe1 resume %d\n", ret); + pr_info("fe1 resume %d\n", ret); } } diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 8b690ac908a4..5185fed9fbf0 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -22,13 +22,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "em28xx.h" + #include #include #include #include #include -#include "em28xx.h" #include "tuner-xc2028.h" #include #include @@ -70,7 +71,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) /* trigger write */ ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); if (ret != 2 + len) { - em28xx_warn("failed to trigger write to i2c address 0x%x (error=%i)\n", + pr_warn("failed to trigger write to i2c address 0x%x (error=%i)\n", addr, ret); return (ret < 0) ? ret : -EIO; } @@ -81,19 +82,19 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) return len; if (ret == 0x94 + len - 1) { if (i2c_debug == 1) - em28xx_warn("R05 returned 0x%02x: I2C ACK error\n", + pr_warn("R05 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } if (ret < 0) { - em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } msleep(5); } if (i2c_debug) - em28xx_warn("write to i2c device at 0x%x timed out\n", addr); + pr_warn("write to i2c device at 0x%x timed out\n", addr); return -ETIMEDOUT; } @@ -116,7 +117,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) buf2[0] = addr; ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2); if (ret != 2) { - em28xx_warn("failed to trigger read from i2c address 0x%x (error=%i)\n", + pr_warn("failed to trigger read from i2c address 0x%x (error=%i)\n", addr, ret); return (ret < 0) ? ret : -EIO; } @@ -128,12 +129,12 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) break; if (ret == 0x94 + len - 1) { if (i2c_debug == 1) - em28xx_warn("R05 returned 0x%02x: I2C ACK error\n", + pr_warn("R05 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } if (ret < 0) { - em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } @@ -141,14 +142,14 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) } if (ret != 0x84 + len - 1) { if (i2c_debug) - em28xx_warn("read from i2c device at 0x%x timed out\n", + pr_warn("read from i2c device at 0x%x timed out\n", addr); } /* get the received message */ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); if (ret != len) { - em28xx_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", + pr_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", addr, ret); return (ret < 0) ? ret : -EIO; } @@ -193,11 +194,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); if (ret != len) { if (ret < 0) { - em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n", + pr_warn("writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; } else { - em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + pr_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", len, addr, ret); return -EIO; } @@ -210,12 +211,12 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, return len; if (ret == 0x10) { if (i2c_debug == 1) - em28xx_warn("I2C ACK error on writing to addr 0x%02x\n", + pr_warn("I2C ACK error on writing to addr 0x%02x\n", addr); return -ENXIO; } if (ret < 0) { - em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } @@ -230,12 +231,12 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (ret == 0x02 || ret == 0x04) { /* NOTE: these errors seem to be related to clock stretching */ if (i2c_debug) - em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", + pr_warn("write to i2c device at 0x%x timed out (status=%i)\n", addr, ret); return -ETIMEDOUT; } - em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", + pr_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", addr, ret); return -EIO; } @@ -258,7 +259,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) /* Read data from i2c device */ ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); if (ret < 0) { - em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n", + pr_warn("reading from i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; } @@ -276,13 +277,13 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) if (ret == 0) /* success */ return len; if (ret < 0) { - em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } if (ret == 0x10) { if (i2c_debug == 1) - em28xx_warn("I2C ACK error on writing to addr 0x%02x\n", + pr_warn("I2C ACK error on writing to addr 0x%02x\n", addr); return -ENXIO; } @@ -290,12 +291,12 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) if (ret == 0x02 || ret == 0x04) { /* NOTE: these errors seem to be related to clock stretching */ if (i2c_debug) - em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n", + pr_warn("write to i2c device at 0x%x timed out (status=%i)\n", addr, ret); return -ETIMEDOUT; } - em28xx_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", + pr_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", addr, ret); return -EIO; } @@ -335,11 +336,11 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len); if (ret != len) { if (ret < 0) { - em28xx_warn("writing to i2c device at 0x%x failed (error=%i)\n", + pr_warn("writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; } else { - em28xx_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + pr_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", len, addr, ret); return -EIO; } @@ -354,7 +355,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, return len; else if (ret > 0) { if (i2c_debug == 1) - em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", + pr_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -386,7 +387,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, /* Read value */ ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len); if (ret < 0) { - em28xx_warn("reading from i2c device at 0x%x failed (error=%i)\n", + pr_warn("reading from i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; } @@ -409,7 +410,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, return len; else if (ret > 0) { if (i2c_debug == 1) - em28xx_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", + pr_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -672,7 +673,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, /* Check if board has eeprom */ err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0); if (err < 0) { - em28xx_info("board has no eeprom\n"); + pr_info("board has no eeprom\n"); return -ENODEV; } @@ -685,7 +686,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, dev->eeprom_addrwidth_16bit, len, data); if (err != len) { - em28xx_errdev("failed to read eeprom (err=%d)\n", err); + pr_err("failed to read eeprom (err=%d)\n", err); goto error; } @@ -695,7 +696,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, 16, 1, data, len, true); if (dev->eeprom_addrwidth_16bit) - em28xx_info("eeprom %06x: ... (skipped)\n", 256); + pr_info("eeprom %06x: ... (skipped)\n", 256); } if (dev->eeprom_addrwidth_16bit && @@ -707,10 +708,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, dev->hash = em28xx_hash_mem(data, len, 32); mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ - em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", + pr_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", data[0], data[1], data[2], data[3], dev->hash); - em28xx_info("EEPROM info:\n"); - em28xx_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", + pr_info("EEPROM info:\n"); + pr_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", mc_start, data[2]); /* * boot configuration (address 0x0002): @@ -729,7 +730,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2, data); if (err != 2) { - em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n", + pr_err("failed to read hardware configuration data from eeprom (err=%d)\n", err); goto error; } @@ -747,7 +748,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len, data); if (err != len) { - em28xx_errdev("failed to read hardware configuration data from eeprom (err=%d)\n", + pr_err("failed to read hardware configuration data from eeprom (err=%d)\n", err); goto error; } @@ -756,7 +757,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, /* NOTE: not all devices provide this type of dataset */ if (data[0] != 0x1a || data[1] != 0xeb || data[2] != 0x67 || data[3] != 0x95) { - em28xx_info("\tno hardware configuration dataset found in eeprom\n"); + pr_info("\tno hardware configuration dataset found in eeprom\n"); kfree(data); return 0; } @@ -767,11 +768,11 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data[0] == 0x1a && data[1] == 0xeb && data[2] == 0x67 && data[3] == 0x95) { dev->hash = em28xx_hash_mem(data, len, 32); - em28xx_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", + pr_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", data[0], data[1], data[2], data[3], dev->hash); - em28xx_info("EEPROM info:\n"); + pr_info("EEPROM info:\n"); } else { - em28xx_info("unknown eeprom format or eeprom corrupted !\n"); + pr_info("unknown eeprom format or eeprom corrupted !\n"); err = -ENODEV; goto error; } @@ -782,46 +783,46 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) { case 0: - em28xx_info("\tNo audio on board.\n"); + pr_info("\tNo audio on board.\n"); break; case 1: - em28xx_info("\tAC97 audio (5 sample rates)\n"); + pr_info("\tAC97 audio (5 sample rates)\n"); break; case 2: if (dev->chip_id < CHIP_ID_EM2860) - em28xx_info("\tI2S audio, sample rate=32k\n"); + pr_info("\tI2S audio, sample rate=32k\n"); else - em28xx_info("\tI2S audio, 3 sample rates\n"); + pr_info("\tI2S audio, 3 sample rates\n"); break; case 3: if (dev->chip_id < CHIP_ID_EM2860) - em28xx_info("\tI2S audio, 3 sample rates\n"); + pr_info("\tI2S audio, 3 sample rates\n"); else - em28xx_info("\tI2S audio, 5 sample rates\n"); + pr_info("\tI2S audio, 5 sample rates\n"); break; } if (le16_to_cpu(dev_config->chip_conf) & 1 << 3) - em28xx_info("\tUSB Remote wakeup capable\n"); + pr_info("\tUSB Remote wakeup capable\n"); if (le16_to_cpu(dev_config->chip_conf) & 1 << 2) - em28xx_info("\tUSB Self power capable\n"); + pr_info("\tUSB Self power capable\n"); switch (le16_to_cpu(dev_config->chip_conf) & 0x3) { case 0: - em28xx_info("\t500mA max power\n"); + pr_info("\t500mA max power\n"); break; case 1: - em28xx_info("\t400mA max power\n"); + pr_info("\t400mA max power\n"); break; case 2: - em28xx_info("\t300mA max power\n"); + pr_info("\t300mA max power\n"); break; case 3: - em28xx_info("\t200mA max power\n"); + pr_info("\t200mA max power\n"); break; } - em28xx_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", + pr_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", dev_config->string_idx_table, le16_to_cpu(dev_config->string1), le16_to_cpu(dev_config->string2), @@ -914,7 +915,7 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) if (rc < 0) continue; i2c_devicelist[i] = i; - em28xx_info("found i2c device @ 0x%x on bus %d [%s]\n", + pr_info("found i2c device @ 0x%x on bus %d [%s]\n", i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???"); } @@ -949,7 +950,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, retval = i2c_add_adapter(&dev->i2c_adap[bus]); if (retval < 0) { - em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n", + pr_err("%s: i2c_add_adapter failed! retval [%d]\n", __func__, retval); return retval; } @@ -961,7 +962,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, if (!bus) { retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len); if ((retval < 0) && (retval != -ENODEV)) { - em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n", + pr_err("%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); return retval; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 580f3853505d..e8e1f768d45e 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "em28xx.h" + #include #include #include @@ -29,8 +31,6 @@ #include #include -#include "em28xx.h" - #define EM28XX_SNAPSHOT_KEY KEY_CAMERA #define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL 500 /* [ms] */ #define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL 100 /* [ms] */ @@ -567,7 +567,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) struct input_dev *input_dev; int err; - em28xx_info("Registering snapshot button...\n"); + pr_info("Registering snapshot button...\n"); input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; @@ -591,7 +591,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) err = input_register_device(input_dev); if (err) { - em28xx_errdev("input_register_device failed\n"); + pr_err("input_register_device failed\n"); input_free_device(input_dev); return err; } @@ -631,7 +631,7 @@ static void em28xx_init_buttons(struct em28xx *dev) } else if (button->role == EM28XX_BUTTON_ILLUMINATION) { /* Check sanity */ if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) { - em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n"); + pr_err("BUG: illumination button defined, but no illumination LED.\n"); goto next_button; } } @@ -667,7 +667,7 @@ static void em28xx_shutdown_buttons(struct em28xx *dev) dev->num_button_polling_addresses = 0; /* Deregister input devices */ if (dev->sbutton_input_dev != NULL) { - em28xx_info("Deregistering snapshot button\n"); + pr_info("Deregistering snapshot button\n"); input_unregister_device(dev->sbutton_input_dev); dev->sbutton_input_dev = NULL; } @@ -696,18 +696,18 @@ static int em28xx_ir_init(struct em28xx *dev) i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev); if (!i2c_rc_dev_addr) { dev->board.has_ir_i2c = 0; - em28xx_warn("No i2c IR remote control device found.\n"); + pr_warn("No i2c IR remote control device found.\n"); return -ENODEV; } } if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) { /* No remote control support */ - em28xx_warn("Remote control support is not available for this card.\n"); + pr_warn("Remote control support is not available for this card.\n"); return 0; } - em28xx_info("Registering input extension\n"); + pr_info("Registering input extension\n"); ir = kzalloc(sizeof(*ir), GFP_KERNEL); if (!ir) @@ -810,7 +810,7 @@ static int em28xx_ir_init(struct em28xx *dev) if (err) goto error; - em28xx_info("Input extension successfully initalized\n"); + pr_info("Input extension successfully initalized\n"); return 0; @@ -831,7 +831,7 @@ static int em28xx_ir_fini(struct em28xx *dev) return 0; } - em28xx_info("Closing input extension\n"); + pr_info("Closing input extension\n"); em28xx_shutdown_buttons(dev); @@ -860,7 +860,7 @@ static int em28xx_ir_suspend(struct em28xx *dev) if (dev->is_audio_only) return 0; - em28xx_info("Suspending input extension\n"); + pr_info("Suspending input extension\n"); if (ir) cancel_delayed_work_sync(&ir->work); cancel_delayed_work_sync(&dev->buttons_query_work); @@ -877,7 +877,7 @@ static int em28xx_ir_resume(struct em28xx *dev) if (dev->is_audio_only) return 0; - em28xx_info("Resuming input extension\n"); + pr_info("Resuming input extension\n"); /* if suspend calls ir_raw_event_unregister(), the should call ir_raw_event_register() */ if (ir) diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 119877bb8a1e..3efabc19bfe9 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -26,6 +26,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "em28xx.h" + #include #include #include @@ -37,7 +39,6 @@ #include #include -#include "em28xx.h" #include "em28xx-v4l.h" #include #include @@ -413,7 +414,7 @@ set_alt: dev->alt, dev->max_pkt_size); errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); if (errCode < 0) { - em28xx_errdev("cannot change alternate number to %d (error=%i)\n", + pr_err("cannot change alternate number to %d (error=%i)\n", dev->alt, errCode); return errCode; } @@ -2047,7 +2048,7 @@ static int em28xx_v4l2_open(struct file *filp) ret = v4l2_fh_open(filp); if (ret) { - em28xx_errdev("%s: v4l2_fh_open() returned error %d\n", + pr_err("%s: v4l2_fh_open() returned error %d\n", __func__, ret); mutex_unlock(&dev->lock); return ret; @@ -2102,7 +2103,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (v4l2 == NULL) return 0; - em28xx_info("Closing video extension\n"); + pr_info("Closing video extension\n"); mutex_lock(&dev->lock); @@ -2113,17 +2114,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev) em28xx_v4l2_media_release(dev); if (video_is_registered(&v4l2->radio_dev)) { - em28xx_info("V4L2 device %s deregistered\n", + pr_info("V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { - em28xx_info("V4L2 device %s deregistered\n", + pr_info("V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { - em28xx_info("V4L2 device %s deregistered\n", + pr_info("V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } @@ -2153,7 +2154,7 @@ static int em28xx_v4l2_suspend(struct em28xx *dev) if (!dev->has_video) return 0; - em28xx_info("Suspending video extension\n"); + pr_info("Suspending video extension\n"); em28xx_stop_urbs(dev); return 0; } @@ -2166,7 +2167,7 @@ static int em28xx_v4l2_resume(struct em28xx *dev) if (!dev->has_video) return 0; - em28xx_info("Resuming video extension\n"); + pr_info("Resuming video extension\n"); /* what do we do here */ return 0; } @@ -2203,7 +2204,8 @@ static int em28xx_v4l2_close(struct file *filp) em28xx_videodbg("setting alternate 0\n"); errCode = usb_set_interface(dev->udev, 0, 0); if (errCode < 0) { - em28xx_errdev("cannot change alternate number to 0 (error=%i)\n", errCode); + pr_err("cannot change alternate number to 0 (error=%i)\n", + errCode); } } @@ -2420,13 +2422,12 @@ static int em28xx_v4l2_init(struct em28xx *dev) return 0; } - em28xx_info("Registering V4L2 extension\n"); + pr_info("Registering V4L2 extension\n"); mutex_lock(&dev->lock); v4l2 = kzalloc(sizeof(struct em28xx_v4l2), GFP_KERNEL); - if (v4l2 == NULL) { - em28xx_info("em28xx_v4l: memory allocation failed\n"); + if (!v4l2) { mutex_unlock(&dev->lock); return -ENOMEM; } @@ -2439,7 +2440,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) #endif ret = v4l2_device_register(&dev->udev->dev, &v4l2->v4l2_dev); if (ret < 0) { - em28xx_errdev("Call to v4l2_device_register() failed!\n"); + pr_err("Call to v4l2_device_register() failed!\n"); goto err; } @@ -2523,7 +2524,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Configure audio */ ret = em28xx_audio_setup(dev); if (ret < 0) { - em28xx_errdev("%s: Error while setting audio - error [%d]!\n", + pr_err("%s: Error while setting audio - error [%d]!\n", __func__, ret); goto unregister_dev; } @@ -2551,7 +2552,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Send a reset to other chips via gpio */ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); if (ret < 0) { - em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", + pr_err("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", __func__, ret); goto unregister_dev; } @@ -2559,7 +2560,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); if (ret < 0) { - em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", + pr_err("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", __func__, ret); goto unregister_dev; } @@ -2661,7 +2662,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); if (ret) { - em28xx_errdev("unable to register video device (error=%i).\n", + pr_err("unable to register video device (error=%i).\n", ret); goto unregister_dev; } @@ -2691,7 +2692,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); if (ret < 0) { - em28xx_errdev("unable to register vbi device\n"); + pr_err("unable to register vbi device\n"); goto unregister_dev; } } @@ -2702,10 +2703,10 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { - em28xx_errdev("can't register radio device\n"); + pr_err("can't register radio device\n"); goto unregister_dev; } - em28xx_info("Registered radio device as %s\n", + pr_info("Registered radio device as %s\n", video_device_node_name(&v4l2->radio_dev)); } @@ -2715,17 +2716,17 @@ static int em28xx_v4l2_init(struct em28xx *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = v4l2_mc_create_media_graph(dev->media_dev); if (ret) { - em28xx_errdev("failed to create media graph\n"); + pr_err("failed to create media graph\n"); em28xx_v4l2_media_release(dev); goto unregister_dev; } #endif - em28xx_info("V4L2 video device registered as %s\n", + pr_info("V4L2 video device registered as %s\n", video_device_node_name(&v4l2->vdev)); if (video_is_registered(&v4l2->vbi_dev)) - em28xx_info("V4L2 VBI device registered as %s\n", + pr_info("V4L2 VBI device registered as %s\n", video_device_node_name(&v4l2->vbi_dev)); /* Save some power by putting tuner to sleep */ @@ -2734,7 +2735,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* initialize videobuf2 stuff */ em28xx_vb2_setup(dev); - em28xx_info("V4L2 extension successfully initialized\n"); + pr_info("V4L2 extension successfully initialized\n"); kref_get(&dev->ref); @@ -2743,17 +2744,17 @@ static int em28xx_v4l2_init(struct em28xx *dev) unregister_dev: if (video_is_registered(&v4l2->radio_dev)) { - em28xx_info("V4L2 device %s deregistered\n", + pr_info("V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { - em28xx_info("V4L2 device %s deregistered\n", + pr_info("V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { - em28xx_info("V4L2 device %s deregistered\n", + pr_info("V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index d148463b22c1..0f6830f5078b 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -29,6 +29,8 @@ #define EM28XX_VERSION "0.2.2" #define DRIVER_DESC "Empia em28xx device driver" +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -797,20 +799,4 @@ void em28xx_free_device(struct kref *ref); int em28xx_detect_sensor(struct em28xx *dev); int em28xx_init_camera(struct em28xx *dev); -/* printk macros */ - -#define em28xx_err(fmt, arg...) do {\ - printk(KERN_ERR fmt , ##arg); } while (0) - -#define em28xx_errdev(fmt, arg...) do {\ - printk(KERN_ERR "%s: "fmt,\ - dev->name , ##arg); } while (0) - -#define em28xx_info(fmt, arg...) do {\ - printk(KERN_INFO "%s: "fmt,\ - dev->name , ##arg); } while (0) -#define em28xx_warn(fmt, arg...) do {\ - printk(KERN_WARNING "%s: "fmt,\ - dev->name , ##arg); } while (0) - #endif -- cgit v1.2.3 From 2a96f60e89b9af8396fe06dc361909b5e3a9b4f0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 07:32:23 -0300 Subject: [media] em28xx: convert the remaining printks to pr_foo There are still several places with printk's called directly. Convert them to pr_foo() macros, except for the debug printk's, as those are enabled via modprobe vars. While here, realign the pr_foo() arguments to match the recommended CodingStyle. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 10 ++--- drivers/media/usb/em28xx/em28xx-camera.c | 21 +++++---- drivers/media/usb/em28xx/em28xx-cards.c | 67 ++++++++++++----------------- drivers/media/usb/em28xx/em28xx-core.c | 47 ++++++++++---------- drivers/media/usb/em28xx/em28xx-dvb.c | 39 ++++++++--------- drivers/media/usb/em28xx/em28xx-i2c.c | 74 ++++++++++++++++---------------- drivers/media/usb/em28xx/em28xx-input.c | 2 +- drivers/media/usb/em28xx/em28xx-vbi.c | 7 +-- drivers/media/usb/em28xx/em28xx-video.c | 46 +++++++++----------- 9 files changed, 146 insertions(+), 167 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index b5f35a25d870..06e495615296 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -56,9 +56,8 @@ MODULE_PARM_DESC(debug, "activates debug info"); #define dprintk(fmt, arg...) do { \ if (debug) \ - printk(KERN_INFO "em28xx-audio %s: " fmt, \ - __func__, ##arg); \ - } while (0) + printk(KERN_DEBUG pr_fmt("audio: %s: " fmt), \ + __func__, ##arg); } while (0) static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -902,9 +901,8 @@ static int em28xx_audio_init(struct em28xx *dev) kref_get(&dev->ref); - printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); - printk(KERN_INFO - "em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n"); + pr_info("em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); + pr_info("em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n"); err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio", THIS_MODULE, 0, &card); diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index bc07166e7df0..a24695474212 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -121,13 +121,13 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) if (ret < 0) { if (ret != -ENXIO) pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } id = be16_to_cpu(id_be); @@ -136,13 +136,13 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) ret = i2c_master_send(&client, ®, 1); if (ret < 0) { pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } /* Validate chip ID to be sure we have a Micron device */ @@ -180,8 +180,7 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) dev->em28xx_sensor = EM28XX_MT9M001; break; default: - pr_info("unknown Micron sensor detected: 0x%04x\n", - id); + pr_info("unknown Micron sensor detected: 0x%04x\n", id); return 0; } @@ -219,7 +218,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) if (ret < 0) { if (ret != -ENXIO) pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } id = ret << 8; @@ -227,7 +226,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } id += ret; @@ -239,7 +238,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } id = ret << 8; @@ -247,7 +246,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + client.addr << 1, ret); continue; } id += ret; @@ -286,7 +285,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) break; default: pr_info("unknown OmniVision sensor detected: 0x%04x\n", - id); + id); return 0; } diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index c73cf2012bf5..bcd6ac61d9f8 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2838,7 +2838,7 @@ static int em28xx_hint_board(struct em28xx *dev) pr_err("If the board were missdetected, please email this log to:\n"); pr_err("\tV4L Mailing List \n"); pr_err("Board detected as %s\n", - em28xx_boards[dev->model].name); + em28xx_boards[dev->model].name); return 0; } @@ -2867,7 +2867,7 @@ static int em28xx_hint_board(struct em28xx *dev) pr_err("If the board were missdetected, please email this log to:\n"); pr_err("\tV4L Mailing List \n"); pr_err("Board detected as %s\n", - em28xx_boards[dev->model].name); + em28xx_boards[dev->model].name); return 0; } @@ -2882,8 +2882,7 @@ static int em28xx_hint_board(struct em28xx *dev) pr_err("Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < em28xx_bcount; i++) { - pr_err(" card=%d -> %s\n", - i, em28xx_boards[i].name); + pr_err(" card=%d -> %s\n", i, em28xx_boards[i].name); } return -1; } @@ -2928,7 +2927,7 @@ static void em28xx_card_setup(struct em28xx *dev) } pr_info("Identified as %s (card=%d)\n", - dev->board.name, dev->model); + dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; @@ -3318,14 +3317,12 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, dev->eeprom_addrwidth_16bit = 1; break; default: - printk(KERN_INFO DRIVER_NAME - ": unknown em28xx chip ID (%d)\n", dev->chip_id); + pr_info("unknown em28xx chip ID (%d)\n", dev->chip_id); } } if (chip_name != default_chip_name) - printk(KERN_INFO DRIVER_NAME - ": chip ID is %s\n", chip_name); + pr_info("chip ID is %s\n", chip_name); /* * For em2820/em2710, the name may change latter, after checking @@ -3351,7 +3348,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { pr_err("%s: em28xx_write_reg failed! retval [%d]\n", - __func__, retval); + __func__, retval); return retval; } } @@ -3365,7 +3362,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { pr_err("%s: em28xx_i2c_register bus 0 - error [%d]!\n", - __func__, retval); + __func__, retval); return retval; } @@ -3379,7 +3376,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { pr_err("%s: em28xx_i2c_register bus 1 - error [%d]!\n", - __func__, retval); + __func__, retval); em28xx_i2c_unregister(dev, 0); @@ -3418,8 +3415,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ - printk(DRIVER_NAME - ": Supports only %i em28xx boards.\n", + pr_err("Driver supports up to %i em28xx boards.\n", EM28XX_MAXBOARDS); retval = -ENOMEM; goto err_no_slot; @@ -3428,8 +3424,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - pr_err(DRIVER_NAME - " audio device (%04x:%04x): interface %i, class %i\n", + pr_err("audio device (%04x:%04x): interface %i, class %i\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), ifnum, @@ -3489,8 +3484,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (usb_endpoint_xfer_isoc(e)) { has_vendor_audio = true; } else { - printk(KERN_INFO DRIVER_NAME - ": error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); + pr_err("error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); } break; case 0x84: @@ -3563,8 +3557,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, speed = "unknown"; } - printk(KERN_INFO DRIVER_NAME - ": New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", + pr_info("New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", udev->manufacturer ? udev->manufacturer : "", udev->product ? udev->product : "", speed, @@ -3579,8 +3572,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - printk(DRIVER_NAME ": Device initialization failed.\n"); - printk(DRIVER_NAME ": Device must be connected to a high-speed USB 2.0 port.\n"); + pr_err("Device initialization failed.\n"); + pr_err("Device must be connected to a high-speed USB 2.0 port.\n"); retval = -ENODEV; goto err_free; } @@ -3593,8 +3586,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->ifnum = ifnum; if (has_vendor_audio) { - printk(KERN_INFO DRIVER_NAME ": Audio interface %i found %s\n", - ifnum, "(Vendor Class)"); + pr_info("Audio interface %i found (Vendor Class)\n", ifnum); dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR; } /* Checks if audio is provided by a USB Audio Class interface */ @@ -3604,24 +3596,22 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { if (has_vendor_audio) pr_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n" - "\t\tThe vendor interface will be ignored. Please contact the developers \n"); + "\t\tThe vendor interface will be ignored. Please contact the developers \n"); dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; break; } } if (has_video) - printk(KERN_INFO DRIVER_NAME - ": Video interface %i found:%s%s\n", - ifnum, - dev->analog_ep_bulk ? " bulk" : "", - dev->analog_ep_isoc ? " isoc" : ""); + pr_info("Video interface %i found:%s%s\n", + ifnum, + dev->analog_ep_bulk ? " bulk" : "", + dev->analog_ep_isoc ? " isoc" : ""); if (has_dvb) - printk(KERN_INFO DRIVER_NAME - ": DVB interface %i found:%s%s\n", - ifnum, - dev->dvb_ep_bulk ? " bulk" : "", - dev->dvb_ep_isoc ? " isoc" : ""); + pr_info("DVB interface %i found:%s%s\n", + ifnum, + dev->dvb_ep_bulk ? " bulk" : "", + dev->dvb_ep_isoc ? " isoc" : ""); dev->num_alt = interface->num_altsetting; @@ -3650,8 +3640,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Disable V4L2 if the device doesn't have a decoder */ if (has_video && dev->board.decoder == EM28XX_NODECODER && !dev->board.is_webcam) { - printk(DRIVER_NAME - ": Currently, V4L2 is not supported on this model\n"); + pr_err("Currently, V4L2 is not supported on this model\n"); has_video = false; dev->has_video = false; } @@ -3661,13 +3650,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) dev->analog_xfer_bulk = 1; pr_info("analog set to %s mode.\n", - dev->analog_xfer_bulk ? "bulk" : "isoc"); + dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) dev->dvb_xfer_bulk = 1; pr_info("dvb set to %s mode.\n", - dev->dvb_xfer_bulk ? "bulk" : "isoc"); + dev->dvb_xfer_bulk ? "bulk" : "isoc"); } kref_init(&dev->ref); diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 8897cde9894b..a413ff7c30d7 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -48,12 +48,12 @@ MODULE_VERSION(EM28XX_VERSION); static unsigned int core_debug; module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); +MODULE_PARM_DESC(core_debug, "enable debug messages [core and isoc]"); #define em28xx_coredbg(fmt, arg...) do {\ if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) + printk(KERN_DEBUG pr_fmt("core: %s: " fmt), \ + __func__, ##arg); } while (0) static unsigned int reg_debug; module_param(reg_debug, int, 0644); @@ -61,14 +61,14 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); #define em28xx_regdbg(fmt, arg...) do {\ if (reg_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) + printk(KERN_DEBUG pr_fmt("reg: %s: " fmt), \ + __func__, ##arg); } while (0) /* FIXME */ #define em28xx_isocdbg(fmt, arg...) do {\ if (core_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) + printk(KERN_DEBUG pr_fmt("isoc: %s: " fmt), \ + __func__, ##arg); } while (0) /* * em28xx_read_reg_req() @@ -102,7 +102,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { if (reg_debug) - printk(KERN_CONT " failed!\n"); + pr_cont(" failed!\n"); mutex_unlock(&dev->ctrl_urb_lock); return usb_translate_errors(ret); } @@ -115,10 +115,10 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, if (reg_debug) { int byte; - printk(KERN_CONT "<<<"); + pr_cont("<<<"); for (byte = 0; byte < len; byte++) - printk(KERN_CONT " %02x", (unsigned char)buf[byte]); - printk(KERN_CONT "\n"); + pr_cont(" %02x", (unsigned char)buf[byte]); + pr_cont("\n"); } return ret; @@ -174,8 +174,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, len & 0xff, len >> 8); for (byte = 0; byte < len; byte++) - printk(KERN_CONT " %02x", (unsigned char)buf[byte]); - printk(KERN_CONT "\n"); + pr_cont(" %02x", (unsigned char)buf[byte]); + pr_cont("\n"); } mutex_lock(&dev->ctrl_urb_lock); @@ -541,7 +541,7 @@ int em28xx_audio_setup(struct em28xx *dev) else i2s_samplerates = 3; pr_info("I2S Audio (%d sample rate(s))\n", - i2s_samplerates); + i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; goto init_audio; @@ -596,7 +596,7 @@ init_audio: break; case EM28XX_AC97_SIGMATEL: pr_info("Sigmatel audio processor detected (stac 97%02x)\n", - vid & 0xff); + vid & 0xff); break; case EM28XX_AC97_OTHER: pr_warn("Unknown AC97 audio processor detected!\n"); @@ -884,7 +884,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, if ((xfer_bulk && !dev->dvb_ep_bulk) || (!xfer_bulk && !dev->dvb_ep_isoc)) { pr_err("no endpoint for DVB mode and transfer type %d\n", - xfer_bulk > 0); + xfer_bulk > 0); return -EINVAL; } usb_bufs = &dev->usb_ctl.digital_bufs; @@ -892,7 +892,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, if ((xfer_bulk && !dev->analog_ep_bulk) || (!xfer_bulk && !dev->analog_ep_isoc)) { pr_err("no endpoint for analog mode and transfer type %d\n", - xfer_bulk > 0); + xfer_bulk > 0); return -EINVAL; } usb_bufs = &dev->usb_ctl.analog_bufs; @@ -940,8 +940,8 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!usb_bufs->transfer_buffer[i]) { pr_err("unable to allocate %i bytes for transfer buffer %i%s\n", - sb_size, i, - in_interrupt() ? " while in int" : ""); + sb_size, i, + in_interrupt() ? " while in int" : ""); em28xx_uninit_usb_xfer(dev, mode); return -ENOMEM; } @@ -1022,7 +1022,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, rc = usb_clear_halt(dev->udev, usb_bufs->urb[0]->pipe); if (rc < 0) { pr_err("failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", - rc); + rc); em28xx_uninit_usb_xfer(dev, mode); return rc; } @@ -1037,8 +1037,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, for (i = 0; i < usb_bufs->num_bufs; i++) { rc = usb_submit_urb(usb_bufs->urb[i], GFP_ATOMIC); if (rc) { - pr_err("submit of urb %i failed (error=%i)\n", i, - rc); + pr_err("submit of urb %i failed (error=%i)\n", i, rc); em28xx_uninit_usb_xfer(dev, mode); return rc; } @@ -1071,7 +1070,7 @@ int em28xx_register_extension(struct em28xx_ops *ops) ops->init(dev); } mutex_unlock(&em28xx_devlist_mutex); - printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name); + pr_info("em28xx: Registered (%s) extension\n", ops->name); return 0; } EXPORT_SYMBOL(em28xx_register_extension); @@ -1086,7 +1085,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) } list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); - printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name); + pr_info("Em28xx: Removed (%s) extension\n", ops->name); } EXPORT_SYMBOL(em28xx_unregister_extension); diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index cbece65899b5..6feb0e416eac 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -935,19 +935,19 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) cfg.ctrl = &ctl; if (!dev->dvb->fe[0]) { - pr_err("/2: dvb frontend not attached. Can't attach xc3028\n"); + pr_err("dvb frontend not attached. Can't attach xc3028\n"); return -EINVAL; } fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg); if (!fe) { - pr_err("/2: xc3028 attach failed\n"); + pr_err("xc3028 attach failed\n"); dvb_frontend_detach(dev->dvb->fe[0]); dev->dvb->fe[0] = NULL; return -EINVAL; } - pr_info("%s/2: xc3028 attached\n", dev->name); + pr_info("xc3028 attached\n"); return 0; } @@ -966,8 +966,8 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, adapter_nr); if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n", - dev->name, result); + pr_warn("dvb_register_adapter failed (errno = %d)\n", + result); goto fail_adapter; } #ifdef CONFIG_MEDIA_CONTROLLER_DVB @@ -984,8 +984,8 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, /* register frontend */ result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]); if (result < 0) { - printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n", - dev->name, result); + pr_warn("dvb_register_frontend failed (errno = %d)\n", + result); goto fail_frontend0; } @@ -993,8 +993,8 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, if (dvb->fe[1]) { result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]); if (result < 0) { - printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n", - dev->name, result); + pr_warn("2nd dvb_register_frontend failed (errno = %d)\n", + result); goto fail_frontend1; } } @@ -1011,8 +1011,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, result = dvb_dmx_init(&dvb->demux); if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n", - dev->name, result); + pr_warn("dvb_dmx_init failed (errno = %d)\n", result); goto fail_dmx; } @@ -1021,31 +1020,29 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, dvb->dmxdev.capabilities = 0; result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); if (result < 0) { - printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n", - dev->name, result); + pr_warn("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_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - dev->name, result); + pr_warn("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_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - dev->name, result); + pr_warn("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_WARNING "%s: connect_frontend failed (errno = %d)\n", - dev->name, result); + pr_warn("connect_frontend failed (errno = %d)\n", result); goto fail_fe_conn; } @@ -1936,11 +1933,11 @@ static int em28xx_dvb_init(struct em28xx *dev) } break; default: - pr_err("/2: The frontend of your DVB/ATSC card isn't supported yet\n"); + pr_err("The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if (NULL == dvb->fe[0]) { - pr_err("/2: frontend initialization failed\n"); + pr_err("frontend initialization failed\n"); result = -EINVAL; goto out_free; } diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 5185fed9fbf0..b7a5b4c5ceff 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -83,12 +83,12 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) if (ret == 0x94 + len - 1) { if (i2c_debug == 1) pr_warn("R05 returned 0x%02x: I2C ACK error\n", - ret); + ret); return -ENXIO; } if (ret < 0) { pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); + ret); return ret; } msleep(5); @@ -118,7 +118,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2); if (ret != 2) { pr_warn("failed to trigger read from i2c address 0x%x (error=%i)\n", - addr, ret); + addr, ret); return (ret < 0) ? ret : -EIO; } @@ -130,12 +130,12 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) if (ret == 0x94 + len - 1) { if (i2c_debug == 1) pr_warn("R05 returned 0x%02x: I2C ACK error\n", - ret); + ret); return -ENXIO; } if (ret < 0) { pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); + ret); return ret; } msleep(5); @@ -143,14 +143,14 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) if (ret != 0x84 + len - 1) { if (i2c_debug) pr_warn("read from i2c device at 0x%x timed out\n", - addr); + addr); } /* get the received message */ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); if (ret != len) { pr_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", - addr, ret); + addr, ret); return (ret < 0) ? ret : -EIO; } for (i = 0; i < len; i++) @@ -195,11 +195,11 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (ret != len) { if (ret < 0) { pr_warn("writing to i2c device at 0x%x failed (error=%i)\n", - addr, ret); + addr, ret); return ret; } else { pr_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); + len, addr, ret); return -EIO; } } @@ -212,12 +212,12 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (ret == 0x10) { if (i2c_debug == 1) pr_warn("I2C ACK error on writing to addr 0x%02x\n", - addr); + addr); return -ENXIO; } if (ret < 0) { pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); + ret); return ret; } msleep(5); @@ -232,12 +232,12 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, /* NOTE: these errors seem to be related to clock stretching */ if (i2c_debug) pr_warn("write to i2c device at 0x%x timed out (status=%i)\n", - addr, ret); + addr, ret); return -ETIMEDOUT; } pr_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", - addr, ret); + addr, ret); return -EIO; } @@ -260,7 +260,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); if (ret < 0) { pr_warn("reading from i2c device at 0x%x failed (error=%i)\n", - addr, ret); + addr, ret); return ret; } /* @@ -278,13 +278,13 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) return len; if (ret < 0) { pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); + ret); return ret; } if (ret == 0x10) { if (i2c_debug == 1) pr_warn("I2C ACK error on writing to addr 0x%02x\n", - addr); + addr); return -ENXIO; } @@ -292,12 +292,12 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) /* NOTE: these errors seem to be related to clock stretching */ if (i2c_debug) pr_warn("write to i2c device at 0x%x timed out (status=%i)\n", - addr, ret); + addr, ret); return -ETIMEDOUT; } pr_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", - addr, ret); + addr, ret); return -EIO; } @@ -337,11 +337,11 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (ret != len) { if (ret < 0) { pr_warn("writing to i2c device at 0x%x failed (error=%i)\n", - addr, ret); + addr, ret); return ret; } else { pr_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); + len, addr, ret); return -EIO; } } @@ -356,7 +356,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, else if (ret > 0) { if (i2c_debug == 1) pr_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", - ret); + ret); return -ENXIO; } @@ -388,7 +388,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len); if (ret < 0) { pr_warn("reading from i2c device at 0x%x failed (error=%i)\n", - addr, ret); + addr, ret); return ret; } /* @@ -411,7 +411,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, else if (ret > 0) { if (i2c_debug == 1) pr_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", - ret); + ret); return -ENXIO; } @@ -544,11 +544,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, if (rc < 0) { if (rc == -ENXIO) { if (i2c_debug > 1) - printk(KERN_CONT " no device\n"); + pr_cont(" no device\n"); rc = -ENODEV; } else { if (i2c_debug > 1) - printk(KERN_CONT " ERROR: %i\n", rc); + pr_cont(" ERROR: %i\n", rc); } rt_mutex_unlock(&dev->i2c_bus_lock); return rc; @@ -558,11 +558,11 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, rc = i2c_recv_bytes(i2c_bus, msgs[i]); if (i2c_debug > 1 && rc >= 0) - printk(KERN_CONT " %*ph", + pr_cont(" %*ph", msgs[i].len, msgs[i].buf); } else { if (i2c_debug > 1) - printk(KERN_CONT " %*ph", + pr_cont(" %*ph", msgs[i].len, msgs[i].buf); /* write bytes */ @@ -570,12 +570,12 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, } if (rc < 0) { if (i2c_debug > 1) - printk(KERN_CONT " ERROR: %i\n", rc); + pr_cont(" ERROR: %i\n", rc); rt_mutex_unlock(&dev->i2c_bus_lock); return rc; } if (i2c_debug > 1) - printk(KERN_CONT "\n"); + pr_cont("\n"); } rt_mutex_unlock(&dev->i2c_bus_lock); @@ -709,10 +709,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ pr_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); + data[0], data[1], data[2], data[3], dev->hash); pr_info("EEPROM info:\n"); pr_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", - mc_start, data[2]); + mc_start, data[2]); /* * boot configuration (address 0x0002): * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz @@ -731,7 +731,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data); if (err != 2) { pr_err("failed to read hardware configuration data from eeprom (err=%d)\n", - err); + err); goto error; } @@ -749,7 +749,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data); if (err != len) { pr_err("failed to read hardware configuration data from eeprom (err=%d)\n", - err); + err); goto error; } @@ -769,7 +769,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data[2] == 0x67 && data[3] == 0x95) { dev->hash = em28xx_hash_mem(data, len, 32); pr_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); + data[0], data[1], data[2], data[3], dev->hash); pr_info("EEPROM info:\n"); } else { pr_info("unknown eeprom format or eeprom corrupted !\n"); @@ -916,7 +916,7 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) continue; i2c_devicelist[i] = i; pr_info("found i2c device @ 0x%x on bus %d [%s]\n", - i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???"); + i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???"); } if (bus == dev->def_i2c_bus) @@ -951,7 +951,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, retval = i2c_add_adapter(&dev->i2c_adap[bus]); if (retval < 0) { pr_err("%s: i2c_add_adapter failed! retval [%d]\n", - __func__, retval); + __func__, retval); return retval; } @@ -963,7 +963,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len); if ((retval < 0) && (retval != -ENODEV)) { pr_err("%s: em28xx_i2_eeprom failed! retval [%d]\n", - __func__, retval); + __func__, retval); return retval; } diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index e8e1f768d45e..0e23e65eff15 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -458,7 +458,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) case CHIP_ID_EM28178: return em2874_ir_change_protocol(rc_dev, rc_type); default: - printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n", + pr_err("Unrecognized em28xx chip id 0x%02x: IR not supported\n", dev->chip_id); return -EINVAL; } diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 836c6b53b16c..744b3300b153 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -21,12 +21,13 @@ 02110-1301, USA. */ +#include "em28xx.h" + #include #include #include #include -#include "em28xx.h" #include "em28xx-v4l.h" /* ------------------------------------------------------------------ */ @@ -63,8 +64,8 @@ static int vbi_buffer_prepare(struct vb2_buffer *vb) size = v4l2->vbi_width * v4l2->vbi_height * 2; if (vb2_plane_size(vb, 0) < size) { - printk(KERN_INFO "%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), size); + pr_info("%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); return -EINVAL; } vb2_set_plane_payload(vb, 0, size); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 3efabc19bfe9..8b5e13bbfb07 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -66,16 +66,13 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); #define em28xx_videodbg(fmt, arg...) do {\ if (video_debug) \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); } while (0) + printk(KERN_DEBUG pr_fmt("video: %s: " fmt), \ + __func__, ##arg); } while (0) -#define em28xx_isocdbg(fmt, arg...) \ -do {\ - if (isoc_debug) { \ - printk(KERN_INFO "%s %s :"fmt, \ - dev->name, __func__ , ##arg); \ - } \ - } while (0) +#define em28xx_isocdbg(fmt, arg...) do {\ + if (isoc_debug) \ + printk(KERN_DEBUG pr_fmt("isoc: %s: " fmt), \ + __func__, ##arg); } while (0) MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface"); @@ -415,7 +412,7 @@ set_alt: errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); if (errCode < 0) { pr_err("cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); + dev->alt, errCode); return errCode; } return 0; @@ -2049,7 +2046,7 @@ static int em28xx_v4l2_open(struct file *filp) ret = v4l2_fh_open(filp); if (ret) { pr_err("%s: v4l2_fh_open() returned error %d\n", - __func__, ret); + __func__, ret); mutex_unlock(&dev->lock); return ret; } @@ -2115,17 +2112,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (video_is_registered(&v4l2->radio_dev)) { pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->radio_dev)); + video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vbi_dev)); + video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vdev)); + video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } @@ -2525,7 +2522,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = em28xx_audio_setup(dev); if (ret < 0) { pr_err("%s: Error while setting audio - error [%d]!\n", - __func__, ret); + __func__, ret); goto unregister_dev; } if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { @@ -2553,7 +2550,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); if (ret < 0) { pr_err("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", - __func__, ret); + __func__, ret); goto unregister_dev; } msleep(3); @@ -2561,7 +2558,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); if (ret < 0) { pr_err("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", - __func__, ret); + __func__, ret); goto unregister_dev; } msleep(3); @@ -2662,8 +2659,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); if (ret) { - pr_err("unable to register video device (error=%i).\n", - ret); + pr_err("unable to register video device (error=%i).\n", ret); goto unregister_dev; } @@ -2707,7 +2703,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) goto unregister_dev; } pr_info("Registered radio device as %s\n", - video_device_node_name(&v4l2->radio_dev)); + video_device_node_name(&v4l2->radio_dev)); } /* Init entities at the Media Controller */ @@ -2723,11 +2719,11 @@ static int em28xx_v4l2_init(struct em28xx *dev) #endif pr_info("V4L2 video device registered as %s\n", - video_device_node_name(&v4l2->vdev)); + video_device_node_name(&v4l2->vdev)); if (video_is_registered(&v4l2->vbi_dev)) pr_info("V4L2 VBI device registered as %s\n", - video_device_node_name(&v4l2->vbi_dev)); + video_device_node_name(&v4l2->vbi_dev)); /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); @@ -2745,17 +2741,17 @@ static int em28xx_v4l2_init(struct em28xx *dev) unregister_dev: if (video_is_registered(&v4l2->radio_dev)) { pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->radio_dev)); + video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vbi_dev)); + video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vdev)); + video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } -- cgit v1.2.3 From 0a93dc1c18fd86f936bcb44f72dc044c0ea826a8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 08:11:16 -0300 Subject: [media] dvb-core: don't break long lines Due to the 80-cols checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. So, join those continuation lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index a0cf7b0d03e8..280716f1cc46 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -426,8 +426,7 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) } if (buf[1] & 0x80) { - dprintk_tscheck("TEI detected. " - "PID=0x%x data1=0x%x\n", + dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", pid, buf[1]); /* data in this packet can't be trusted - drop it unless * module option dvb_demux_feed_err_pkts is set */ -- cgit v1.2.3 From 0919f3a04b5e7ea019ef393dee892454f054fe16 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 08:18:35 -0300 Subject: [media] tuner-core: don't break long lines Due to the 80-cols checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. So, join those continuation lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index 731487be5baa..e2613ecb7605 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -503,8 +503,7 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd, set_type(c, tun_setup->type, tun_setup->mode_mask, tun_setup->config, tun_setup->tuner_callback); } else - tuner_dbg("set addr discarded for type %i, mask %x. " - "Asked to change tuner at addr 0x%02x, with mask %x\n", + tuner_dbg("set addr discarded for type %i, mask %x. Asked to change tuner at addr 0x%02x, with mask %x\n", t->type, t->mode_mask, tun_setup->addr, tun_setup->mode_mask); @@ -809,8 +808,8 @@ static int set_mode(struct tuner *t, enum v4l2_tuner_type mode) if (mode != t->mode) { if (check_mode(t, mode) == -EINVAL) { - tuner_dbg("Tuner doesn't support mode %d. " - "Putting tuner to sleep\n", mode); + tuner_dbg("Tuner doesn't support mode %d. Putting tuner to sleep\n", + mode); t->standby = true; if (analog_ops->standby) analog_ops->standby(&t->fe); -- cgit v1.2.3 From e428744a9fa18a3e114fcd420d8263f8a3e274b3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 12 Oct 2016 08:19:27 -0300 Subject: [media] tuner-core: use %&ph for small buffer dumps This driver has a printk with a continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups'"), this won't work anymore. We might be using KERNEL_CONT, but it is better to just use a single printk line using %*ph for buffer dump. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index e2613ecb7605..d3a6236b6b02 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -617,14 +617,12 @@ static int tuner_probe(struct i2c_client *client, if (show_i2c) { unsigned char buffer[16]; - int i, rc; + int rc; memset(buffer, 0, sizeof(buffer)); rc = i2c_master_recv(client, buffer, sizeof(buffer)); - tuner_info("I2C RECV = "); - for (i = 0; i < rc; i++) - printk(KERN_CONT "%02x ", buffer[i]); - printk("\n"); + if (rc >= 0) + tuner_info("I2C RECV = %*ph\n", rc, buffer); } /* autodetection code based on the i2c addr */ -- cgit v1.2.3 From b3ad24d2e0b039834db28d06727dc9a675aa0396 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 06:47:54 -0300 Subject: [media] dvb-core: use pr_foo() instead of printk() The dvb-core directly calls printk() without using the modern printk macros, or using the proper printk levels. Change it to use pr_foo(). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dmxdev.c | 24 ++++++---- drivers/media/dvb-core/dvb_ca_en50221.c | 57 ++++++++++++++--------- drivers/media/dvb-core/dvb_demux.c | 46 ++++++++++-------- drivers/media/dvb-core/dvb_frontend.c | 12 +++-- drivers/media/dvb-core/dvb_net.c | 82 ++++++++++++++++++--------------- drivers/media/dvb-core/dvbdev.c | 25 ++++++---- 6 files changed, 146 insertions(+), 100 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 7b67e1dd97fd..1e96a6f1b6f0 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -20,6 +20,8 @@ * */ +#define pr_fmt(fmt) "dmxdev: " fmt + #include #include #include @@ -36,7 +38,11 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); -#define dprintk if (debug) printk +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, const u8 *src, size_t len) @@ -50,7 +56,7 @@ static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, free = dvb_ringbuffer_free(buf); if (len > free) { - dprintk("dmxdev: buffer overflow\n"); + dprintk("buffer overflow\n"); return -EOVERFLOW; } @@ -126,7 +132,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; - dprintk("function : %s\n", __func__); + dprintk("%s\n", __func__); if (mutex_lock_interruptible(&dmxdev->mutex)) return -ERESTARTSYS; @@ -258,7 +264,7 @@ static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, void *newmem; void *oldmem; - dprintk("function : %s\n", __func__); + dprintk("%s\n", __func__); if (buf->size == size) return 0; @@ -367,7 +373,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, return 0; } del_timer(&dmxdevfilter->timer); - dprintk("dmxdev: section callback %*ph\n", 6, buffer1); + dprintk("section callback %*ph\n", 6, buffer1); ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); if (ret == buffer1_len) { @@ -655,7 +661,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) secfeed, dvb_dmxdev_section_callback); if (ret < 0) { - printk("DVB (%s): could not alloc feed\n", + pr_err("DVB (%s): could not alloc feed\n", __func__); return ret; } @@ -663,7 +669,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) ret = (*secfeed)->set(*secfeed, para->pid, 32768, (para->flags & DMX_CHECK_CRC) ? 1 : 0); if (ret < 0) { - printk("DVB (%s): could not set feed\n", + pr_err("DVB (%s): could not set feed\n", __func__); dvb_dmxdev_feed_restart(filter); return ret; @@ -844,7 +850,7 @@ static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_sct_filter_params *params) { - dprintk("function : %s, PID=0x%04x, flags=%02x, timeout=%d\n", + dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n", __func__, params->pid, params->flags, params->timeout); dvb_dmxdev_filter_stop(dmxdevfilter); @@ -1184,7 +1190,7 @@ static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) struct dmxdev *dmxdev = dvbdev->priv; unsigned int mask = 0; - dprintk("function : %s\n", __func__); + dprintk("%s\n", __func__); if (dmxdev->exit) return POLLERR; diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index b5b5b195ea7f..262a492e7c08 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -28,6 +28,8 @@ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html */ +#define pr_fmt(fmt) "dvb_ca_en50221: " fmt + #include #include #include @@ -46,7 +48,10 @@ static int dvb_ca_en50221_debug; module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644); MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); -#define dprintk if (dvb_ca_en50221_debug) printk +#define dprintk(fmt, arg...) do { \ + if (dvb_ca_en50221_debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg);\ +} while (0) #define INIT_TIMEOUT_SECS 10 @@ -298,7 +303,8 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, /* if we got the flags, it was successful! */ if (res & waitfor) { - dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start); + dprintk("%s succeeded timeout:%lu\n", + __func__, jiffies - start); return 0; } @@ -519,8 +525,9 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) /* is it a version we support? */ if (strncmp(dvb_str + 8, "1.00", 4)) { - printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n", - ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]); + pr_err("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n", + ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], + dvb_str[10], dvb_str[11]); return -EINVAL; } @@ -557,8 +564,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) break; default: /* Unknown tuple type - just skip this tuple and move to the next one */ - dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, - tupleLength); + dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", + tupleType, tupleLength); break; } } @@ -567,7 +574,8 @@ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) return -EINVAL; dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", - manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); + manfid, devid, ca->slot_info[slot].config_base, + ca->slot_info[slot].config_option); // success! return 0; @@ -661,14 +669,15 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb /* check it will fit */ if (ebuf == NULL) { if (bytes_read > ca->slot_info[slot].link_buf_size) { - printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", - ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size); + pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", + ca->dvbdev->adapter->num, bytes_read, + ca->slot_info[slot].link_buf_size); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; goto exit; } if (bytes_read < 2) { - printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", + pr_err("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; status = -EIO; @@ -676,7 +685,7 @@ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * eb } } else { if (bytes_read > ecount) { - printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", + pr_err("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", ca->dvbdev->adapter->num); status = -EIO; goto exit; @@ -1062,7 +1071,7 @@ static int dvb_ca_en50221_thread(void *data) case DVB_CA_SLOTSTATE_WAITREADY: if (time_after(jiffies, ca->slot_info[slot].timeout)) { - printk("dvb_ca adaptor %d: PC card did not respond :(\n", + pr_err("dvb_ca adaptor %d: PC card did not respond :(\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); @@ -1084,14 +1093,14 @@ static int dvb_ca_en50221_thread(void *data) } } - printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", + pr_err("dvb_ca adapter %d: Invalid PC card inserted :(\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; } if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { - printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", + pr_err("dvb_ca adapter %d: Unable to initialise CAM :(\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); @@ -1099,7 +1108,7 @@ static int dvb_ca_en50221_thread(void *data) } if (ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, CMDREG_RS) != 0) { - printk("dvb_ca adapter %d: Unable to reset CAM IF\n", + pr_err("dvb_ca adapter %d: Unable to reset CAM IF\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); @@ -1114,7 +1123,7 @@ static int dvb_ca_en50221_thread(void *data) case DVB_CA_SLOTSTATE_WAITFR: if (time_after(jiffies, ca->slot_info[slot].timeout)) { - printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", + pr_err("dvb_ca adapter %d: DVB CAM did not respond :(\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); @@ -1141,7 +1150,8 @@ static int dvb_ca_en50221_thread(void *data) } } - printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num); + pr_err("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; @@ -1150,7 +1160,8 @@ static int dvb_ca_en50221_thread(void *data) if (ca->slot_info[slot].rx_buffer.data == NULL) { rxbuf = vmalloc(RX_BUFFER_SIZE); if (rxbuf == NULL) { - printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); + pr_err("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", + ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); break; @@ -1161,7 +1172,8 @@ static int dvb_ca_en50221_thread(void *data) ca->pub->slot_ts_enable(ca->pub, slot); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; dvb_ca_en50221_thread_update_delay(ca); - printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num); + pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", + ca->dvbdev->adapter->num); break; case DVB_CA_SLOTSTATE_RUNNING: @@ -1497,7 +1509,8 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, pktlen = 2; do { if (idx == -1) { - printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num); + pr_err("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", + ca->dvbdev->adapter->num); status = -EIO; goto exit; } @@ -1755,8 +1768,8 @@ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, ca->dvbdev->adapter->num, ca->dvbdev->id); if (IS_ERR(ca->thread)) { ret = PTR_ERR(ca->thread); - printk("dvb_ca_init: failed to start kernel_thread (%d)\n", - ret); + pr_err("dvb_ca_init: failed to start kernel_thread (%d)\n", + ret); goto unregister_device; } return 0; diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 280716f1cc46..a0a1f8456c54 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -21,6 +21,8 @@ * */ +#define pr_fmt(fmt) "dvb_demux: " fmt + #include #include #include @@ -55,10 +57,13 @@ module_param(dvb_demux_feed_err_pkts, int, 0644); MODULE_PARM_DESC(dvb_demux_feed_err_pkts, "when set to 0, drop packets with the TEI bit set (1 by default)"); -#define dprintk_tscheck(x...) do { \ - if (dvb_demux_tscheck && printk_ratelimit()) \ - printk(x); \ - } while (0) +#define dprintk(fmt, arg...) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg) + +#define dprintk_tscheck(x...) do { \ + if (dvb_demux_tscheck && printk_ratelimit()) \ + dprintk(x); \ +} while (0) /****************************************************************************** * static inlined helper functions @@ -122,7 +127,7 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, ccok = ((feed->cc + 1) & 0x0f) == cc; feed->cc = cc; if (!ccok) - printk("missed packet!\n"); + dprintk("missed packet!\n"); */ if (buf[1] & 0x40) // PUSI ? @@ -199,12 +204,12 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) * but just first and last. */ if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { - printk("dvb_demux.c section ts padding loss: %d/%d\n", + dprintk("dvb_demux.c section ts padding loss: %d/%d\n", n, sec->tsfeedp); - printk("dvb_demux.c pad data:"); + dprintk("dvb_demux.c pad data:"); for (i = 0; i < n; i++) - printk(" %02x", sec->secbuf[i]); - printk("\n"); + pr_cont(" %02x", sec->secbuf[i]); + pr_cont("\n"); } } #endif @@ -243,7 +248,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { #ifdef DVB_DEMUX_SECTION_LOSS_LOG - printk("dvb_demux.c section buffer full loss: %d/%d\n", + dprintk("dvb_demux.c section buffer full loss: %d/%d\n", sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE); #endif @@ -278,7 +283,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, dvb_dmx_swfilter_section_feed(feed); #ifdef DVB_DEMUX_SECTION_LOSS_LOG else - printk("dvb_demux.c pusi not seen, discarding section data\n"); + dprintk("dvb_demux.c pusi not seen, discarding section data\n"); #endif sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ @@ -313,8 +318,8 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, if (!ccok || dc_i) { #ifdef DVB_DEMUX_SECTION_LOSS_LOG - printk("dvb_demux.c discontinuity detected %d bytes lost\n", - count); + dprintk("dvb_demux.c discontinuity detected %d bytes lost\n", + count); /* * those bytes under sume circumstances will again be reported * in the following dvb_dmx_swfilter_section_new @@ -346,7 +351,8 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, } #ifdef DVB_DEMUX_SECTION_LOSS_LOG else if (count > 0) - printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); + dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n", + count); #endif } else { /* PUSI=0 (is not set), no section boundary */ @@ -415,9 +421,9 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) 1024); speed_timedelta = ktime_ms_delta(cur_time, demux->speed_last_time); - printk(KERN_INFO "TS speed %llu Kbits/sec \n", - div64_u64(speed_bytes, - speed_timedelta)); + dprintk("TS speed %llu Kbits/sec \n", + div64_u64(speed_bytes, + speed_timedelta)); } demux->speed_last_time = cur_time; @@ -634,7 +640,7 @@ static void dvb_demux_feed_add(struct dvb_demux_feed *feed) { spin_lock_irq(&feed->demux->lock); if (dvb_demux_feed_find(feed)) { - printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", + pr_err("%s: feed already in list (type=%x state=%x pid=%x)\n", __func__, feed->type, feed->state, feed->pid); goto out; } @@ -648,7 +654,7 @@ static void dvb_demux_feed_del(struct dvb_demux_feed *feed) { spin_lock_irq(&feed->demux->lock); if (!(dvb_demux_feed_find(feed))) { - printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", + pr_err("%s: feed not in list (type=%x state=%x pid=%x)\n", __func__, feed->type, feed->state, feed->pid); goto out; } @@ -1267,7 +1273,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); if (!dvbdemux->cnt_storage) - printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); + pr_warn("Couldn't allocate memory for TS/TEI check. Disabling it\n"); INIT_LIST_HEAD(&dvbdemux->frontend_list); diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 01511e5a5566..98edf46b22d0 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -28,6 +28,8 @@ /* Enables DVBv3 compatibility bits at the headers */ #define __DVB_CORE__ +#define pr_fmt(fmt) "dvb_frontend: " fmt + #include #include #include @@ -67,6 +69,9 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volt module_param(dvb_mfe_wait_time, int, 0644); MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to seconds on open() for multi-frontend to become available (default:5 seconds)"); +#define dprintk(fmt, arg...) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg) + #define FESTATE_IDLE 1 #define FESTATE_RETUNE 2 #define FESTATE_TUNING_FAST 4 @@ -2356,7 +2361,8 @@ static int dvb_frontend_ioctl_legacy(struct file *file, int i; u8 last = 1; if (dvb_frontend_debug) - printk("%s switch command: 0x%04lx\n", __func__, swcmd); + dprintk("%s switch command: 0x%04lx\n", + __func__, swcmd); nexttime = ktime_get_boottime(); if (dvb_frontend_debug) tv[0] = nexttime; @@ -2379,10 +2385,10 @@ static int dvb_frontend_ioctl_legacy(struct file *file, dvb_frontend_sleep_until(&nexttime, 8000); } if (dvb_frontend_debug) { - printk("%s(%d): switch delay (should be 32k followed by all 8k\n", + dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n", __func__, fe->dvb->num); for (i = 1; i < 10; i++) - printk("%d: %d\n", i, + pr_info("%d: %d\n", i, (int) ktime_us_delta(tv[i], tv[i-1])); } err = 0; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 9914f69a4a02..063f63563919 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -54,6 +54,8 @@ * */ +#define pr_fmt(fmt) "dvb_net: " fmt + #include #include #include @@ -344,7 +346,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */ if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) { - printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", + pr_warn("%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", priv->ts_count, ts[0], (ts[1] & TS_TEI) >> 7, (ts[3] & TS_SC) >> 6); @@ -376,8 +378,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) priv->tscc = ts[3] & 0x0F; /* There is a pointer field here. */ if (ts[4] > ts_remain) { - printk(KERN_ERR "%lu: Invalid ULE packet " - "(pointer field %d)\n", priv->ts_count, ts[4]); + pr_err("%lu: Invalid ULE packet (pointer field %d)\n", + priv->ts_count, ts[4]); ts += TS_SZ; priv->ts_count++; continue; @@ -400,8 +402,9 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) priv->tscc = (priv->tscc + 1) & 0x0F; else { /* TS discontinuity handling: */ - printk(KERN_WARNING "%lu: TS discontinuity: got %#x, " - "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc); + pr_warn("%lu: TS discontinuity: got %#x, expected %#x.\n", + priv->ts_count, ts[3] & 0x0F, + priv->tscc); /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); @@ -423,8 +426,9 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (! priv->need_pusi) { if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) { /* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */ - printk(KERN_WARNING "%lu: Invalid pointer " - "field: %u.\n", priv->ts_count, *from_where); + pr_warn("%lu: Invalid pointer field: %u.\n", + priv->ts_count, + *from_where); /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { @@ -454,9 +458,10 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * current TS cell. */ dev->stats.rx_errors++; dev->stats.rx_length_errors++; - printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " - "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", - priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); + pr_warn("%lu: Expected %d more SNDU bytes, but got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", + priv->ts_count, + priv->ule_sndu_remain, + ts[4], ts_remain); dev_kfree_skb(priv->ule_skb); /* Prepare for next SNDU. */ reset_ule(priv); @@ -475,8 +480,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * TS. * Check ts_remain has to be >= 2 here. */ if (ts_remain < 2) { - printk(KERN_WARNING "Invalid payload packing: only %d " - "bytes left in TS. Resyncing.\n", ts_remain); + pr_warn("Invalid payload packing: only %d bytes left in TS. Resyncing.\n", + ts_remain); priv->ule_sndu_len = 0; priv->need_pusi = 1; ts += TS_SZ; @@ -494,8 +499,9 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) priv->ule_dbit = 0; if (priv->ule_sndu_len < 5) { - printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " - "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); + pr_warn("%lu: Invalid ULE SNDU length %u. Resyncing.\n", + priv->ts_count, + priv->ule_sndu_len); dev->stats.rx_errors++; dev->stats.rx_length_errors++; priv->ule_sndu_len = 0; @@ -550,8 +556,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */ priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN ); if (priv->ule_skb == NULL) { - printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", - dev->name); + pr_notice("%s: Memory squeeze, dropping packet.\n", + dev->name); dev->stats.rx_dropped++; return; } @@ -595,8 +601,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) *(tail - 2) << 8 | *(tail - 1); if (ule_crc != expected_crc) { - printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", - priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0); + pr_warn("%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", + priv->ts_count, ule_crc, expected_crc, + priv->ule_sndu_len, priv->ule_sndu_type, + ts_remain, + ts_remain > 2 ? *(unsigned short *)from_where : 0); #ifdef ULE_DEBUG hexdump( iov[0].iov_base, iov[0].iov_len ); @@ -687,7 +696,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) int l = handle_ule_extensions(priv); if (l < 0) { /* Mandatory extension header unknown or TEST SNDU. Drop it. */ - // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" ); + // pr_warn("Dropping SNDU, extension headers.\n" ); dev_kfree_skb(priv->ule_skb); goto sndu_done; } @@ -741,10 +750,10 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) priv->ule_skb = NULL; priv->ule_sndu_type_1 = 0; priv->ule_sndu_len = 0; - // printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n", + // pr_warn("More data in current TS: [%#x %#x %#x %#x]\n", // *(from_where + 0), *(from_where + 1), // *(from_where + 2), *(from_where + 3)); - // printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0); + // pr_warn("ts @ %p, stopped @ %p:\n", ts, from_where + 0); // hexdump(ts, 188); } else { new_ts = 1; @@ -766,10 +775,10 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, struct net_device *dev = feed->priv; if (buffer2) - printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2); + pr_warn("buffer2 not NULL: %p.\n", buffer2); if (buffer1_len > 32768) - printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len); - /* printk("TS callback: %u bytes, %u TS cells @ %p.\n", + pr_warn("length > 32k: %zu.\n", buffer1_len); + /* pr_info("TS callback: %u bytes, %u TS cells @ %p.\n", buffer1_len, buffer1_len / TS_SZ, buffer1); */ dvb_net_ule(dev, buffer1, buffer1_len); return 0; @@ -786,7 +795,7 @@ static void dvb_net_sec(struct net_device *dev, /* note: pkt_len includes a 32bit checksum */ if (pkt_len < 16) { - printk("%s: IP/MPE packet length = %d too small.\n", + pr_warn("%s: IP/MPE packet length = %d too small.\n", dev->name, pkt_len); stats->rx_errors++; stats->rx_length_errors++; @@ -824,7 +833,7 @@ static void dvb_net_sec(struct net_device *dev, * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP */ if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) { - //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); + //pr_notice("%s: Memory squeeze, dropping packet.\n", dev->name); stats->rx_dropped++; return; } @@ -903,7 +912,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, *secfilter=NULL; ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter); if (ret<0) { - printk("%s: could not get filter\n", dev->name); + pr_err("%s: could not get filter\n", dev->name); return ret; } @@ -944,7 +953,7 @@ static int dvb_net_feed_start(struct net_device *dev) netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode); mutex_lock(&priv->mutex); if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) - printk("%s: BUG %d\n", __func__, __LINE__); + pr_err("%s: BUG %d\n", __func__, __LINE__); priv->secfeed=NULL; priv->secfilter=NULL; @@ -955,14 +964,15 @@ static int dvb_net_feed_start(struct net_device *dev) ret=demux->allocate_section_feed(demux, &priv->secfeed, dvb_net_sec_callback); if (ret<0) { - printk("%s: could not allocate section feed\n", dev->name); + pr_err("%s: could not allocate section feed\n", + dev->name); goto error; } ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); if (ret<0) { - printk("%s: could not set section feed\n", dev->name); + pr_err("%s: could not set section feed\n", dev->name); priv->demux->release_section_feed(priv->demux, priv->secfeed); priv->secfeed=NULL; goto error; @@ -1003,7 +1013,7 @@ static int dvb_net_feed_start(struct net_device *dev) netdev_dbg(dev, "alloc tsfeed\n"); ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); if (ret < 0) { - printk("%s: could not allocate ts feed\n", dev->name); + pr_err("%s: could not allocate ts feed\n", dev->name); goto error; } @@ -1018,7 +1028,7 @@ static int dvb_net_feed_start(struct net_device *dev) ); if (ret < 0) { - printk("%s: could not set ts feed\n", dev->name); + pr_err("%s: could not set ts feed\n", dev->name); priv->demux->release_ts_feed(priv->demux, priv->tsfeed); priv->tsfeed = NULL; goto error; @@ -1067,7 +1077,7 @@ static int dvb_net_feed_stop(struct net_device *dev) priv->demux->release_section_feed(priv->demux, priv->secfeed); priv->secfeed = NULL; } else - printk("%s: no feed to stop\n", dev->name); + pr_err("%s: no feed to stop\n", dev->name); } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { if (priv->tsfeed) { if (priv->tsfeed->is_filtering) { @@ -1078,7 +1088,7 @@ static int dvb_net_feed_stop(struct net_device *dev) priv->tsfeed = NULL; } else - printk("%s: no ts feed to stop\n", dev->name); + pr_err("%s: no ts feed to stop\n", dev->name); } else ret = -EINVAL; mutex_unlock(&priv->mutex); @@ -1279,7 +1289,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) free_netdev(net); return result; } - printk("dvb_net: created network interface %s\n", net->name); + pr_info("created network interface %s\n", net->name); return if_num; } @@ -1298,7 +1308,7 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) dvb_net_stop(net); flush_work(&priv->set_multicast_list_wq); flush_work(&priv->restart_net_feed_wq); - printk("dvb_net: removed network interface %s\n", net->name); + pr_info("removed network interface %s\n", net->name); unregister_netdev(net); dvbnet->state[num]=0; dvbnet->device[num] = NULL; diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 75a3f4b57fd4..0694d1d53c67 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -21,6 +21,8 @@ * */ +#define pr_fmt(fmt) "dvbdev: " fmt + #include #include #include @@ -43,7 +45,11 @@ static int dvbdev_debug; module_param(dvbdev_debug, int, 0644); MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); -#define dprintk if (dvbdev_debug) printk +#define dprintk(fmt, arg...) do { \ + if (dvbdev_debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) static LIST_HEAD(dvb_adapter_list); static DEFINE_MUTEX(dvbdev_register_lock); @@ -354,7 +360,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev, if (ret) return ret; - printk(KERN_DEBUG "%s: media entity '%s' registered.\n", + pr_info("%s: media entity '%s' registered.\n", __func__, dvbdev->entity->name); return 0; @@ -438,7 +444,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, if ((id = dvbdev_get_free_id (adap, type)) < 0){ mutex_unlock(&dvbdev_register_lock); *pdvbdev = NULL; - printk(KERN_ERR "%s: couldn't find free device id\n", __func__); + pr_err("%s: couldn't find free device id\n", __func__); return -ENFILE; } @@ -493,8 +499,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, ret = dvb_register_media_device(dvbdev, type, minor, demux_sink_pads); if (ret) { - printk(KERN_ERR - "%s: dvb_register_media_device failed to create the mediagraph\n", + pr_err("%s: dvb_register_media_device failed to create the mediagraph\n", __func__); dvb_media_device_free(dvbdev); @@ -511,11 +516,11 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, MKDEV(DVB_MAJOR, minor), dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); if (IS_ERR(clsdev)) { - printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", + pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); return PTR_ERR(clsdev); } - dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", + dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, minor, minor); return 0; @@ -808,7 +813,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, memset (adap, 0, sizeof(struct dvb_adapter)); INIT_LIST_HEAD (&adap->device_list); - printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); + pr_info("DVB: registering new adapter (%s)\n", name); adap->num = num; adap->name = name; @@ -926,13 +931,13 @@ static int __init init_dvbdev(void) dev_t dev = MKDEV(DVB_MAJOR, 0); if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { - printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); + pr_err("dvb-core: unable to get major %d\n", DVB_MAJOR); return retval; } cdev_init(&dvb_device_cdev, &dvb_device_fops); if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { - printk(KERN_ERR "dvb-core: unable register character device\n"); + pr_err("dvb-core: unable register character device\n"); goto error; } -- cgit v1.2.3 From bbd02f6aa9fb4c1c951fe52629b722f79c70883f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 06:57:47 -0300 Subject: [media] dvb_demux: convert an internal ifdef into a Kconfig option There are some ifdefs inside the dvb_demux that are meant to enable advanced debug capabilities, at the cost of being very verbose. Keeping those as internal ifdefs is a very bad idea, as it doesn't make easy to check if the code there was broken by some patch. So, let's add an explicit Kconfig option for it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/Kconfig | 13 +++++++++++++ drivers/media/dvb-core/dvb_demux.c | 14 +++++--------- 2 files changed, 18 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig index fa7a2490ed5f..8964f1d3cf57 100644 --- a/drivers/media/dvb-core/Kconfig +++ b/drivers/media/dvb-core/Kconfig @@ -27,3 +27,16 @@ config DVB_DYNAMIC_MINORS will be required to manage the device nodes. If you are unsure about this, say N here. + +config DVB_DEMUX_SECTION_LOSS_LOG + bool "Enable DVB demux section packet loss log" + depends on DVB_CORE + default n + help + Enable extra log messages meant to detect packet loss + inside the Kernel. + + Should not be enabled on normal cases, as logs can + be very verbose. + + If you are unsure about this, say N here. diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index a0a1f8456c54..5a69b0bda4bb 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -37,10 +37,6 @@ #include "dvb_demux.h" #define NOBUFS -/* -** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog -*/ -// #define DVB_DEMUX_SECTION_LOSS_LOG static int dvb_demux_tscheck; module_param(dvb_demux_tscheck, int, 0644); @@ -194,7 +190,7 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { struct dmx_section_feed *sec = &feed->feed.sec; -#ifdef DVB_DEMUX_SECTION_LOSS_LOG +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG if (sec->secbufp < sec->tsfeedp) { int i, n = sec->tsfeedp - sec->secbufp; @@ -247,7 +243,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, return 0; if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { -#ifdef DVB_DEMUX_SECTION_LOSS_LOG +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG dprintk("dvb_demux.c section buffer full loss: %d/%d\n", sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE); @@ -281,7 +277,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, /* dump [secbuf .. secbuf+seclen) */ if (feed->pusi_seen) dvb_dmx_swfilter_section_feed(feed); -#ifdef DVB_DEMUX_SECTION_LOSS_LOG +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG else dprintk("dvb_demux.c pusi not seen, discarding section data\n"); #endif @@ -317,7 +313,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, } if (!ccok || dc_i) { -#ifdef DVB_DEMUX_SECTION_LOSS_LOG +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG dprintk("dvb_demux.c discontinuity detected %d bytes lost\n", count); /* @@ -349,7 +345,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); } -#ifdef DVB_DEMUX_SECTION_LOSS_LOG +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG else if (count > 0) dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); -- cgit v1.2.3 From 801edd6bb9b223390028dc7f565904a2833d20e1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 07:19:55 -0300 Subject: [media] dvb_demux: uncomment a packet loss check code There is a commented code that also detects packet loss. Uncomment it and put into the DVB_DEMUX_SECTION_LOSS_LOG debug Kconfig option. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_demux.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 5a69b0bda4bb..51bf5eb2df49 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -110,21 +110,23 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, { int count = payload(buf); int p; - //int ccok; - //u8 cc; +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG + int ccok; + u8 cc; +#endif if (count == 0) return -1; p = 188 - count; - /* +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; feed->cc = cc; if (!ccok) dprintk("missed packet!\n"); - */ +#endif if (buf[1] & 0x40) // PUSI ? feed->peslen = 0xfffa; -- cgit v1.2.3 From dd79d27e1bbded7366ade6d25fbfde305e33fad8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 07:14:38 -0300 Subject: [media] dvb-core: get rid of demux optional circular buffer There is a provision at the dvb_demux.c to use a vmalloc'ed circular buffer, enabled via an extra #ifdef option that it is not at Kconfig. Enabling it will only make the Kernel to allocate/deallocate such buffer, but no code would actually use it. So, no practical effect, except for sparing some memory without any good reason. So, get rid of such dead code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/demux.h | 5 +---- drivers/media/dvb-core/dmxdev.c | 4 ++-- drivers/media/dvb-core/dvb_demux.c | 42 ++------------------------------------ drivers/media/dvb-core/dvb_demux.h | 2 -- drivers/media/dvb-core/dvb_net.c | 3 +-- 5 files changed, 6 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h index aeda2b64931c..f8adf4506a45 100644 --- a/drivers/media/dvb-core/demux.h +++ b/drivers/media/dvb-core/demux.h @@ -103,7 +103,6 @@ struct dmx_ts_feed { u16 pid, int type, enum dmx_ts_pes pes_type, - size_t circular_buffer_size, ktime_t timeout); int (*start_filtering)(struct dmx_ts_feed *feed); int (*stop_filtering)(struct dmx_ts_feed *feed); @@ -181,7 +180,6 @@ struct dmx_section_feed { /* public: */ int (*set)(struct dmx_section_feed *feed, u16 pid, - size_t circular_buffer_size, int check_crc); int (*allocate_filter)(struct dmx_section_feed *feed, struct dmx_section_filter **filter); @@ -206,8 +204,7 @@ struct dmx_section_feed { * the &dmx_demux. * Any TS packets that match the filter settings are copied to a circular * buffer. The filtered TS packets are delivered to the client using this - * callback function. The size of the circular buffer is controlled by the - * circular_buffer_size parameter of the &dmx_ts_feed.@set function. + * callback function. * It is expected that the @buffer1 and @buffer2 callback parameters point to * addresses within the circular buffer, but other implementations are also * possible. Note that the called party should not try to free the memory diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 1e96a6f1b6f0..efe55a3e80d0 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -595,7 +595,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, tsfeed = feed->ts; tsfeed->priv = filter; - ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout); + ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout); if (ret < 0) { dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); return ret; @@ -666,7 +666,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) return ret; } - ret = (*secfeed)->set(*secfeed, para->pid, 32768, + ret = (*secfeed)->set(*secfeed, para->pid, (para->flags & DMX_CHECK_CRC) ? 1 : 0); if (ret < 0) { pr_err("DVB (%s): could not set feed\n", diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 51bf5eb2df49..3ad0b2cd26b1 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -36,8 +36,6 @@ #include "dvb_demux.h" -#define NOBUFS - static int dvb_demux_tscheck; module_param(dvb_demux_tscheck, int, 0644); MODULE_PARM_DESC(dvb_demux_tscheck, @@ -663,8 +661,7 @@ out: } static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, - enum dmx_ts_pes pes_type, - size_t circular_buffer_size, ktime_t timeout) + enum dmx_ts_pes pes_type, ktime_t timeout) { struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; struct dvb_demux *demux = feed->demux; @@ -694,23 +691,10 @@ static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, dvb_demux_feed_add(feed); feed->pid = pid; - feed->buffer_size = circular_buffer_size; feed->timeout = timeout; feed->ts_type = ts_type; feed->pes_type = pes_type; - if (feed->buffer_size) { -#ifdef NOBUFS - feed->buffer = NULL; -#else - feed->buffer = vmalloc(feed->buffer_size); - if (!feed->buffer) { - mutex_unlock(&demux->mutex); - return -ENOMEM; - } -#endif - } - feed->state = DMX_STATE_READY; mutex_unlock(&demux->mutex); @@ -799,7 +783,6 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, feed->demux = demux; feed->pid = 0xffff; feed->peslen = 0xfffa; - feed->buffer = NULL; (*ts_feed) = &feed->feed.ts; (*ts_feed)->parent = dmx; @@ -836,10 +819,6 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, mutex_unlock(&demux->mutex); return -EINVAL; } -#ifndef NOBUFS - vfree(feed->buffer); - feed->buffer = NULL; -#endif feed->state = DMX_STATE_FREE; feed->filter->state = DMX_STATE_FREE; @@ -891,8 +870,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, } static int dmx_section_feed_set(struct dmx_section_feed *feed, - u16 pid, size_t circular_buffer_size, - int check_crc) + u16 pid, int check_crc) { struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; struct dvb_demux *dvbdmx = dvbdmxfeed->demux; @@ -906,19 +884,8 @@ static int dmx_section_feed_set(struct dmx_section_feed *feed, dvb_demux_feed_add(dvbdmxfeed); dvbdmxfeed->pid = pid; - dvbdmxfeed->buffer_size = circular_buffer_size; dvbdmxfeed->feed.sec.check_crc = check_crc; -#ifdef NOBUFS - dvbdmxfeed->buffer = NULL; -#else - dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); - if (!dvbdmxfeed->buffer) { - mutex_unlock(&dvbdmx->mutex); - return -ENOMEM; - } -#endif - dvbdmxfeed->state = DMX_STATE_READY; mutex_unlock(&dvbdmx->mutex); return 0; @@ -1077,7 +1044,6 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.tsfeedp = 0; dvbdmxfeed->filter = NULL; - dvbdmxfeed->buffer = NULL; (*feed) = &dvbdmxfeed->feed.sec; (*feed)->is_filtering = 0; @@ -1106,10 +1072,6 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux, mutex_unlock(&dvbdmx->mutex); return -EINVAL; } -#ifndef NOBUFS - vfree(dvbdmxfeed->buffer); - dvbdmxfeed->buffer = NULL; -#endif dvbdmxfeed->state = DMX_STATE_FREE; dvb_demux_feed_del(dvbdmxfeed); diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h index 5ed3cab4ad28..9235b008ea0a 100644 --- a/drivers/media/dvb-core/dvb_demux.h +++ b/drivers/media/dvb-core/dvb_demux.h @@ -80,8 +80,6 @@ struct dvb_demux_feed { int type; int state; u16 pid; - u8 *buffer; - int buffer_size; ktime_t timeout; struct dvb_demux_filter *filter; diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 063f63563919..b9a46d5a1bb5 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -969,7 +969,7 @@ static int dvb_net_feed_start(struct net_device *dev) goto error; } - ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); + ret = priv->secfeed->set(priv->secfeed, priv->pid, 1); if (ret<0) { pr_err("%s: could not set section feed\n", dev->name); @@ -1023,7 +1023,6 @@ static int dvb_net_feed_start(struct net_device *dev) priv->pid, /* pid */ TS_PACKET, /* type */ DMX_PES_OTHER, /* pes type */ - 32768, /* circular buffer size */ timeout /* timeout */ ); -- cgit v1.2.3 From b676e7316ae9b4e6424dc0beb16dbaf71c659a18 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 07:41:38 -0300 Subject: [media] dvb-core: move dvb_filter out of the DVB core The dvb_filter.c can hardly be considered as part of the DVB core. More than half of the code there is commented out by av7110 and ttusb_dec. On the latter, just two small helper functions and a struct definition is used. Being part of the core means that it would require an amount of work to fix issues in it, like bad printk's on it, and to document it on some future, like other kAPI headers. It simply not worth the effort for something that seems to be deprecated, as no new drivers use it. So, move it out of the core, by moving it to pci/ttpci directory, where av7110 driver is kept, and copy the two routines used by ttyusb_dec directly into its code. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/b2c2/flexcop-common.h | 1 - drivers/media/dvb-core/Makefile | 2 +- drivers/media/dvb-core/dvb_filter.c | 603 ----------------------------- drivers/media/dvb-core/dvb_filter.h | 246 ------------ drivers/media/pci/ttpci/Makefile | 2 +- drivers/media/pci/ttpci/dvb_filter.c | 600 ++++++++++++++++++++++++++++ drivers/media/pci/ttpci/dvb_filter.h | 246 ++++++++++++ drivers/media/usb/ttusb-dec/ttusb_dec.c | 58 ++- 8 files changed, 905 insertions(+), 853 deletions(-) delete mode 100644 drivers/media/dvb-core/dvb_filter.c delete mode 100644 drivers/media/dvb-core/dvb_filter.h create mode 100644 drivers/media/pci/ttpci/dvb_filter.c create mode 100644 drivers/media/pci/ttpci/dvb_filter.h (limited to 'drivers') diff --git a/drivers/media/common/b2c2/flexcop-common.h b/drivers/media/common/b2c2/flexcop-common.h index 2b2460e9e6b4..2533574c0cf4 100644 --- a/drivers/media/common/b2c2/flexcop-common.h +++ b/drivers/media/common/b2c2/flexcop-common.h @@ -14,7 +14,6 @@ #include "dmxdev.h" #include "dvb_demux.h" -#include "dvb_filter.h" #include "dvb_net.h" #include "dvb_frontend.h" diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile index 8f22bcd7c1f9..281bc89576e6 100644 --- a/drivers/media/dvb-core/Makefile +++ b/drivers/media/dvb-core/Makefile @@ -4,7 +4,7 @@ dvb-net-$(CONFIG_DVB_NET) := dvb_net.o -dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ +dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ dvb_ca_en50221.o dvb_frontend.o \ $(dvb-net-y) dvb_ringbuffer.o dvb_math.o diff --git a/drivers/media/dvb-core/dvb_filter.c b/drivers/media/dvb-core/dvb_filter.c deleted file mode 100644 index 772003fb1821..000000000000 --- a/drivers/media/dvb-core/dvb_filter.c +++ /dev/null @@ -1,603 +0,0 @@ -#include -#include -#include -#include "dvb_filter.h" - -#if 0 -static unsigned int bitrates[3][16] = -{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, - {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, - {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; -#endif - -static u32 freq[4] = {480, 441, 320, 0}; - -static unsigned int ac3_bitrates[32] = - {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, - 0,0,0,0,0,0,0,0,0,0,0,0,0}; - -static u32 ac3_frames[3][32] = - {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, - 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, - 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, - {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, - 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; - - - -#if 0 -static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, - void (*pes_write)(u8 *buf, int count, void *data), - void *priv) -{ - dvb_filter_ipack_init(pa, IPACKS, pes_write); - dvb_filter_ipack_init(pv, IPACKS, pes_write); - pa->pid = pida; - pv->pid = pidv; - pa->data = priv; - pv->data = priv; -} -#endif - -#if 0 -static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) -{ - u8 off = 0; - - if (!buf || !p ){ - printk("NULL POINTER IDIOT\n"); - return; - } - if (buf[1]&PAY_START) { - if (p->plength == MMAX_PLENGTH-6 && p->found>6){ - p->plength = p->found-6; - p->found = 0; - send_ipack(p); - dvb_filter_ipack_reset(p); - } - } - if (buf[3] & ADAPT_FIELD) { // adaptation field? - off = buf[4] + 1; - if (off+4 > 187) return; - } - dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p); -} -#endif - -#if 0 -/* needs 5 byte input, returns picture coding type*/ -static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr) -{ - u8 pct; - - if (pr) printk( "Pic header: "); - pic->temporal_reference[field] = (( headr[0] << 2 ) | - (headr[1] & 0x03) )& 0x03ff; - if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); - - pct = ( headr[1] >> 2 ) & 0x07; - pic->picture_coding_type[field] = pct; - if (pr) { - switch(pct){ - case I_FRAME: - printk( " I-FRAME"); - break; - case B_FRAME: - printk( " B-FRAME"); - break; - case P_FRAME: - printk( " P-FRAME"); - break; - } - } - - - pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | - ( (headr[3] & 0x1F) << 11) ) & 0xffff; - - if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); - - pic->picture_header_parameter = ( headr[3] & 0xe0 ) | - ((headr[4] & 0x80) >> 3); - - if ( pct == B_FRAME ){ - pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; - } - if (pr) printk( " pic head param: 0x%x", - pic->picture_header_parameter); - - return pct; -} -#endif - -#if 0 -/* needs 4 byte input */ -static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr) -{ - if (pr) printk("GOP header: "); - - pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | - ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; - - if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, - ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), - ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); - - if ( ( headr[3] & 0x40 ) != 0 ){ - pic->closed_gop = 1; - } else { - pic->closed_gop = 0; - } - if (pr) printk("closed: %d", pic->closed_gop); - - if ( ( headr[3] & 0x20 ) != 0 ){ - pic->broken_link = 1; - } else { - pic->broken_link = 0; - } - if (pr) printk(" broken: %d\n", pic->broken_link); - - return 0; -} -#endif - -#if 0 -/* needs 8 byte input */ -static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr) -{ - int sw; - int form = -1; - - if (pr) printk("Reading sequence header\n"); - - vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); - vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); - - sw = (int)((headr[3]&0xF0) >> 4) ; - - switch( sw ){ - case 1: - if (pr) - printk("Videostream: ASPECT: 1:1"); - vi->aspect_ratio = 100; - break; - case 2: - if (pr) - printk("Videostream: ASPECT: 4:3"); - vi->aspect_ratio = 133; - break; - case 3: - if (pr) - printk("Videostream: ASPECT: 16:9"); - vi->aspect_ratio = 177; - break; - case 4: - if (pr) - printk("Videostream: ASPECT: 2.21:1"); - vi->aspect_ratio = 221; - break; - - case 5 ... 15: - if (pr) - printk("Videostream: ASPECT: reserved"); - vi->aspect_ratio = 0; - break; - - default: - vi->aspect_ratio = 0; - return -1; - } - - if (pr) - printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); - - sw = (int)(headr[3]&0x0F); - - switch ( sw ) { - case 1: - if (pr) - printk(" FRate: 23.976 fps"); - vi->framerate = 23976; - form = -1; - break; - case 2: - if (pr) - printk(" FRate: 24 fps"); - vi->framerate = 24000; - form = -1; - break; - case 3: - if (pr) - printk(" FRate: 25 fps"); - vi->framerate = 25000; - form = VIDEO_MODE_PAL; - break; - case 4: - if (pr) - printk(" FRate: 29.97 fps"); - vi->framerate = 29970; - form = VIDEO_MODE_NTSC; - break; - case 5: - if (pr) - printk(" FRate: 30 fps"); - vi->framerate = 30000; - form = VIDEO_MODE_NTSC; - break; - case 6: - if (pr) - printk(" FRate: 50 fps"); - vi->framerate = 50000; - form = VIDEO_MODE_PAL; - break; - case 7: - if (pr) - printk(" FRate: 60 fps"); - vi->framerate = 60000; - form = VIDEO_MODE_NTSC; - break; - } - - vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); - - vi->vbv_buffer_size - = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); - - if (pr){ - printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); - printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); - printk("\n"); - } - - vi->video_format = form; - - return 0; -} -#endif - - -#if 0 -static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - - while (found < 4 && c+4 < count){ - u8 *b; - - b = mbuf+c; - if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 - && b[3] == 0xb3) found = 4; - else { - c++; - } - } - - if (! found) return -1; - c += 4; - if (c+12 >= count) return -1; - headr = mbuf+c; - if (read_sequence_header(headr, vi, pr) < 0) return -1; - vi->off = c-4; - return 0; -} -#endif - - -#if 0 -static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - int fr = 0; - - while (found < 2 && c < count){ - u8 b[2]; - memcpy( b, mbuf+c, 2); - - if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) - found = 2; - else { - c++; - } - } - - if (!found) return -1; - - if (c+3 >= count) return -1; - headr = mbuf+c; - - ai->layer = (headr[1] & 0x06) >> 1; - - if (pr) - printk("Audiostream: Layer: %d", 4-ai->layer); - - - ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; - - if (pr){ - if (ai->bit_rate == 0) - printk(" Bit rate: free"); - else if (ai->bit_rate == 0xf) - printk(" BRate: reserved"); - else - printk(" BRate: %d kb/s", ai->bit_rate/1000); - } - - fr = (headr[2] & 0x0c ) >> 2; - ai->frequency = freq[fr]*100; - if (pr){ - if (ai->frequency == 3) - printk(" Freq: reserved\n"); - else - printk(" Freq: %d kHz\n",ai->frequency); - - } - ai->off = c; - return 0; -} -#endif - - -int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - u8 frame = 0; - int fr = 0; - - while ( !found && c < count){ - u8 *b = mbuf+c; - - if ( b[0] == 0x0b && b[1] == 0x77 ) - found = 1; - else { - c++; - } - } - - if (!found) return -1; - if (pr) - printk("Audiostream: AC3"); - - ai->off = c; - if (c+5 >= count) return -1; - - ai->layer = 0; // 0 for AC3 - headr = mbuf+c+2; - - frame = (headr[2]&0x3f); - ai->bit_rate = ac3_bitrates[frame >> 1]*1000; - - if (pr) - printk(" BRate: %d kb/s", (int) ai->bit_rate/1000); - - ai->frequency = (headr[2] & 0xc0 ) >> 6; - fr = (headr[2] & 0xc0 ) >> 6; - ai->frequency = freq[fr]*100; - if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency); - - - ai->framesize = ac3_frames[fr][frame >> 1]; - if ((frame & 1) && (fr == 1)) ai->framesize++; - ai->framesize = ai->framesize << 1; - if (pr) printk (" Framesize %d\n",(int) ai->framesize); - - - return 0; -} -EXPORT_SYMBOL(dvb_filter_get_ac3info); - - -#if 0 -static u8 *skip_pes_header(u8 **bufp) -{ - u8 *inbuf = *bufp; - u8 *buf = inbuf; - u8 *pts = NULL; - int skip = 0; - - static const int mpeg1_skip_table[16] = { - 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff - }; - - - if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ - if (buf[7] & PTS_ONLY) - pts = buf+9; - else pts = NULL; - buf = inbuf + 9 + inbuf[8]; - } else { /* mpeg1 */ - for (buf = inbuf + 6; *buf == 0xff; buf++) - if (buf == inbuf + 6 + 16) { - break; - } - if ((*buf & 0xc0) == 0x40) - buf += 2; - skip = mpeg1_skip_table [*buf >> 4]; - if (skip == 5 || skip == 10) pts = buf; - else pts = NULL; - - buf += mpeg1_skip_table [*buf >> 4]; - } - - *bufp = buf; - return pts; -} -#endif - -#if 0 -static void initialize_quant_matrix( u32 *matrix ) -{ - int i; - - matrix[0] = 0x08101013; - matrix[1] = 0x10131616; - matrix[2] = 0x16161616; - matrix[3] = 0x1a181a1b; - matrix[4] = 0x1b1b1a1a; - matrix[5] = 0x1a1a1b1b; - matrix[6] = 0x1b1d1d1d; - matrix[7] = 0x2222221d; - matrix[8] = 0x1d1d1b1b; - matrix[9] = 0x1d1d2020; - matrix[10] = 0x22222526; - matrix[11] = 0x25232322; - matrix[12] = 0x23262628; - matrix[13] = 0x28283030; - matrix[14] = 0x2e2e3838; - matrix[15] = 0x3a454553; - - for ( i = 16 ; i < 32 ; i++ ) - matrix[i] = 0x10101010; -} -#endif - -#if 0 -static void initialize_mpg_picture(struct mpg_picture *pic) -{ - int i; - - /* set MPEG1 */ - pic->mpeg1_flag = 1; - pic->profile_and_level = 0x4A ; /* MP@LL */ - pic->progressive_sequence = 1; - pic->low_delay = 0; - - pic->sequence_display_extension_flag = 0; - for ( i = 0 ; i < 4 ; i++ ){ - pic->frame_centre_horizontal_offset[i] = 0; - pic->frame_centre_vertical_offset[i] = 0; - } - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - - pic->picture_display_extension_flag[0] = 0; - pic->picture_display_extension_flag[1] = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; -} -#endif - -#if 0 -static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic ) -{ - int16_t last_h_offset; - int16_t last_v_offset; - - int16_t *p_h_offset; - int16_t *p_v_offset; - - if ( pic->mpeg1_flag ){ - pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; - pic->top_field_first = 0; - pic->repeat_first_field = 0; - pic->progressive_frame = 1; - pic->picture_coding_parameter = 0x000010; - } - - /* Reset flag */ - pic->picture_display_extension_flag[field_type] = 0; - - last_h_offset = pic->last_frame_centre_horizontal_offset; - last_v_offset = pic->last_frame_centre_vertical_offset; - if ( field_type == FIRST_FIELD ){ - p_h_offset = pic->frame_centre_horizontal_offset; - p_v_offset = pic->frame_centre_vertical_offset; - *p_h_offset = last_h_offset; - *(p_h_offset + 1) = last_h_offset; - *(p_h_offset + 2) = last_h_offset; - *p_v_offset = last_v_offset; - *(p_v_offset + 1) = last_v_offset; - *(p_v_offset + 2) = last_v_offset; - } else { - pic->frame_centre_horizontal_offset[3] = last_h_offset; - pic->frame_centre_vertical_offset[3] = last_v_offset; - } -} -#endif - -#if 0 -static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type) -{ - pic->picture_header = 0; - pic->sequence_header_data - = ( INIT_HORIZONTAL_SIZE << 20 ) - | ( INIT_VERTICAL_SIZE << 8 ) - | ( INIT_ASPECT_RATIO << 4 ) - | ( INIT_FRAME_RATE ); - pic->mpeg1_flag = 0; - pic->vinfo.horizontal_size - = INIT_DISP_HORIZONTAL_SIZE; - pic->vinfo.vertical_size - = INIT_DISP_VERTICAL_SIZE; - pic->picture_display_extension_flag[field_type] - = 0; - pic->pts_flag[field_type] = 0; - - pic->sequence_gop_header = 0; - pic->picture_header = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; - pic->sequence_display_extension_flag = 0; - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - pic->channel = chan; -} -#endif - -void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, - dvb_filter_pes2ts_cb_t *cb, void *priv) -{ - unsigned char *buf=p2ts->buf; - - buf[0]=0x47; - buf[1]=(pid>>8); - buf[2]=pid&0xff; - p2ts->cc=0; - p2ts->cb=cb; - p2ts->priv=priv; -} -EXPORT_SYMBOL(dvb_filter_pes2ts_init); - -int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, - int len, int payload_start) -{ - unsigned char *buf=p2ts->buf; - int ret=0, rest; - - //len=6+((pes[4]<<8)|pes[5]); - - if (payload_start) - buf[1]|=0x40; - else - buf[1]&=~0x40; - while (len>=184) { - buf[3]=0x10|((p2ts->cc++)&0x0f); - memcpy(buf+4, pes, 184); - if ((ret=p2ts->cb(p2ts->priv, buf))) - return ret; - len-=184; pes+=184; - buf[1]&=~0x40; - } - if (!len) - return 0; - buf[3]=0x30|((p2ts->cc++)&0x0f); - rest=183-len; - if (rest) { - buf[5]=0x00; - if (rest-1) - memset(buf+6, 0xff, rest-1); - } - buf[4]=rest; - memcpy(buf+5+rest, pes, len); - return p2ts->cb(p2ts->priv, buf); -} -EXPORT_SYMBOL(dvb_filter_pes2ts); diff --git a/drivers/media/dvb-core/dvb_filter.h b/drivers/media/dvb-core/dvb_filter.h deleted file mode 100644 index 375e3be184b1..000000000000 --- a/drivers/media/dvb-core/dvb_filter.h +++ /dev/null @@ -1,246 +0,0 @@ -/* - * dvb_filter.h - * - * Copyright (C) 2003 Convergence GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ - -#ifndef _DVB_FILTER_H_ -#define _DVB_FILTER_H_ - -#include - -#include "demux.h" - -typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); - -struct dvb_filter_pes2ts { - unsigned char buf[188]; - unsigned char cc; - dvb_filter_pes2ts_cb_t *cb; - void *priv; -}; - -void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, - dvb_filter_pes2ts_cb_t *cb, void *priv); - -int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, - int len, int payload_start); - - -#define PROG_STREAM_MAP 0xBC -#define PRIVATE_STREAM1 0xBD -#define PADDING_STREAM 0xBE -#define PRIVATE_STREAM2 0xBF -#define AUDIO_STREAM_S 0xC0 -#define AUDIO_STREAM_E 0xDF -#define VIDEO_STREAM_S 0xE0 -#define VIDEO_STREAM_E 0xEF -#define ECM_STREAM 0xF0 -#define EMM_STREAM 0xF1 -#define DSM_CC_STREAM 0xF2 -#define ISO13522_STREAM 0xF3 -#define PROG_STREAM_DIR 0xFF - -#define DVB_PICTURE_START 0x00 -#define DVB_USER_START 0xb2 -#define DVB_SEQUENCE_HEADER 0xb3 -#define DVB_SEQUENCE_ERROR 0xb4 -#define DVB_EXTENSION_START 0xb5 -#define DVB_SEQUENCE_END 0xb7 -#define DVB_GOP_START 0xb8 -#define DVB_EXCEPT_SLICE 0xb0 - -#define SEQUENCE_EXTENSION 0x01 -#define SEQUENCE_DISPLAY_EXTENSION 0x02 -#define PICTURE_CODING_EXTENSION 0x08 -#define QUANT_MATRIX_EXTENSION 0x03 -#define PICTURE_DISPLAY_EXTENSION 0x07 - -#define I_FRAME 0x01 -#define B_FRAME 0x02 -#define P_FRAME 0x03 - -/* Initialize sequence_data */ -#define INIT_HORIZONTAL_SIZE 720 -#define INIT_VERTICAL_SIZE 576 -#define INIT_ASPECT_RATIO 0x02 -#define INIT_FRAME_RATE 0x03 -#define INIT_DISP_HORIZONTAL_SIZE 540 -#define INIT_DISP_VERTICAL_SIZE 576 - - -//flags2 -#define PTS_DTS_FLAGS 0xC0 -#define ESCR_FLAG 0x20 -#define ES_RATE_FLAG 0x10 -#define DSM_TRICK_FLAG 0x08 -#define ADD_CPY_FLAG 0x04 -#define PES_CRC_FLAG 0x02 -#define PES_EXT_FLAG 0x01 - -//pts_dts flags -#define PTS_ONLY 0x80 -#define PTS_DTS 0xC0 - -#define TS_SIZE 188 -#define TRANS_ERROR 0x80 -#define PAY_START 0x40 -#define TRANS_PRIO 0x20 -#define PID_MASK_HI 0x1F -//flags -#define TRANS_SCRMBL1 0x80 -#define TRANS_SCRMBL2 0x40 -#define ADAPT_FIELD 0x20 -#define PAYLOAD 0x10 -#define COUNT_MASK 0x0F - -// adaptation flags -#define DISCON_IND 0x80 -#define RAND_ACC_IND 0x40 -#define ES_PRI_IND 0x20 -#define PCR_FLAG 0x10 -#define OPCR_FLAG 0x08 -#define SPLICE_FLAG 0x04 -#define TRANS_PRIV 0x02 -#define ADAP_EXT_FLAG 0x01 - -// adaptation extension flags -#define LTW_FLAG 0x80 -#define PIECE_RATE 0x40 -#define SEAM_SPLICE 0x20 - - -#define MAX_PLENGTH 0xFFFF -#define MMAX_PLENGTH (256*MAX_PLENGTH) - -#ifndef IPACKS -#define IPACKS 2048 -#endif - -struct ipack { - int size; - int found; - u8 *buf; - u8 cid; - u32 plength; - u8 plen[2]; - u8 flag1; - u8 flag2; - u8 hlength; - u8 pts[5]; - u16 *pid; - int mpeg; - u8 check; - int which; - int done; - void *data; - void (*func)(u8 *buf, int size, void *priv); - int count; - int repack_subids; -}; - -struct dvb_video_info { - u32 horizontal_size; - u32 vertical_size; - u32 aspect_ratio; - u32 framerate; - u32 video_format; - u32 bit_rate; - u32 comp_bit_rate; - u32 vbv_buffer_size; - s16 vbv_delay; - u32 CSPF; - u32 off; -}; - -#define OFF_SIZE 4 -#define FIRST_FIELD 0 -#define SECOND_FIELD 1 -#define VIDEO_FRAME_PICTURE 0x03 - -struct mpg_picture { - int channel; - struct dvb_video_info vinfo; - u32 *sequence_gop_header; - u32 *picture_header; - s32 time_code; - int low_delay; - int closed_gop; - int broken_link; - int sequence_header_flag; - int gop_flag; - int sequence_end_flag; - - u8 profile_and_level; - s32 picture_coding_parameter; - u32 matrix[32]; - s8 matrix_change_flag; - - u8 picture_header_parameter; - /* bit 0 - 2: bwd f code - bit 3 : fpb vector - bit 4 - 6: fwd f code - bit 7 : fpf vector */ - - int mpeg1_flag; - int progressive_sequence; - int sequence_display_extension_flag; - u32 sequence_header_data; - s16 last_frame_centre_horizontal_offset; - s16 last_frame_centre_vertical_offset; - - u32 pts[2]; /* [0] 1st field, [1] 2nd field */ - int top_field_first; - int repeat_first_field; - int progressive_frame; - int bank; - int forward_bank; - int backward_bank; - int compress; - s16 frame_centre_horizontal_offset[OFF_SIZE]; - /* [0-2] 1st field, [3] 2nd field */ - s16 frame_centre_vertical_offset[OFF_SIZE]; - /* [0-2] 1st field, [3] 2nd field */ - s16 temporal_reference[2]; - /* [0] 1st field, [1] 2nd field */ - - s8 picture_coding_type[2]; - /* [0] 1st field, [1] 2nd field */ - s8 picture_structure[2]; - /* [0] 1st field, [1] 2nd field */ - s8 picture_display_extension_flag[2]; - /* [0] 1st field, [1] 2nd field */ - /* picture_display_extenion() 0:no 1:exit*/ - s8 pts_flag[2]; - /* [0] 1st field, [1] 2nd field */ -}; - -struct dvb_audio_info { - int layer; - u32 bit_rate; - u32 frequency; - u32 mode; - u32 mode_extension ; - u32 emphasis; - u32 framesize; - u32 off; -}; - -int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr); - - -#endif diff --git a/drivers/media/pci/ttpci/Makefile b/drivers/media/pci/ttpci/Makefile index 49f71b1eaf14..3cf617737f7c 100644 --- a/drivers/media/pci/ttpci/Makefile +++ b/drivers/media/pci/ttpci/Makefile @@ -3,7 +3,7 @@ # and the AV7110 DVB device driver # -dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o +dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o dvb_filter.o ifdef CONFIG_DVB_AV7110_IR dvb-ttpci-objs += av7110_ir.o diff --git a/drivers/media/pci/ttpci/dvb_filter.c b/drivers/media/pci/ttpci/dvb_filter.c new file mode 100644 index 000000000000..6395812ed1f1 --- /dev/null +++ b/drivers/media/pci/ttpci/dvb_filter.c @@ -0,0 +1,600 @@ +#include +#include +#include +#include "dvb_filter.h" + +#if 0 +static unsigned int bitrates[3][16] = +{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, + {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, + {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; +#endif + +static u32 freq[4] = {480, 441, 320, 0}; + +static unsigned int ac3_bitrates[32] = + {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, + 0,0,0,0,0,0,0,0,0,0,0,0,0}; + +static u32 ac3_frames[3][32] = + {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, + 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, + 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, + {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, + 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + + + +#if 0 +static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, + void (*pes_write)(u8 *buf, int count, void *data), + void *priv) +{ + dvb_filter_ipack_init(pa, IPACKS, pes_write); + dvb_filter_ipack_init(pv, IPACKS, pes_write); + pa->pid = pida; + pv->pid = pidv; + pa->data = priv; + pv->data = priv; +} +#endif + +#if 0 +static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) +{ + u8 off = 0; + + if (!buf || !p ){ + printk("NULL POINTER IDIOT\n"); + return; + } + if (buf[1]&PAY_START) { + if (p->plength == MMAX_PLENGTH-6 && p->found>6){ + p->plength = p->found-6; + p->found = 0; + send_ipack(p); + dvb_filter_ipack_reset(p); + } + } + if (buf[3] & ADAPT_FIELD) { // adaptation field? + off = buf[4] + 1; + if (off+4 > 187) return; + } + dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p); +} +#endif + +#if 0 +/* needs 5 byte input, returns picture coding type*/ +static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr) +{ + u8 pct; + + if (pr) printk( "Pic header: "); + pic->temporal_reference[field] = (( headr[0] << 2 ) | + (headr[1] & 0x03) )& 0x03ff; + if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); + + pct = ( headr[1] >> 2 ) & 0x07; + pic->picture_coding_type[field] = pct; + if (pr) { + switch(pct){ + case I_FRAME: + printk( " I-FRAME"); + break; + case B_FRAME: + printk( " B-FRAME"); + break; + case P_FRAME: + printk( " P-FRAME"); + break; + } + } + + + pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | + ( (headr[3] & 0x1F) << 11) ) & 0xffff; + + if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); + + pic->picture_header_parameter = ( headr[3] & 0xe0 ) | + ((headr[4] & 0x80) >> 3); + + if ( pct == B_FRAME ){ + pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; + } + if (pr) printk( " pic head param: 0x%x", + pic->picture_header_parameter); + + return pct; +} +#endif + +#if 0 +/* needs 4 byte input */ +static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr) +{ + if (pr) printk("GOP header: "); + + pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | + ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; + + if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, + ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), + ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); + + if ( ( headr[3] & 0x40 ) != 0 ){ + pic->closed_gop = 1; + } else { + pic->closed_gop = 0; + } + if (pr) printk("closed: %d", pic->closed_gop); + + if ( ( headr[3] & 0x20 ) != 0 ){ + pic->broken_link = 1; + } else { + pic->broken_link = 0; + } + if (pr) printk(" broken: %d\n", pic->broken_link); + + return 0; +} +#endif + +#if 0 +/* needs 8 byte input */ +static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr) +{ + int sw; + int form = -1; + + if (pr) printk("Reading sequence header\n"); + + vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); + vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); + + sw = (int)((headr[3]&0xF0) >> 4) ; + + switch( sw ){ + case 1: + if (pr) + printk("Videostream: ASPECT: 1:1"); + vi->aspect_ratio = 100; + break; + case 2: + if (pr) + printk("Videostream: ASPECT: 4:3"); + vi->aspect_ratio = 133; + break; + case 3: + if (pr) + printk("Videostream: ASPECT: 16:9"); + vi->aspect_ratio = 177; + break; + case 4: + if (pr) + printk("Videostream: ASPECT: 2.21:1"); + vi->aspect_ratio = 221; + break; + + case 5 ... 15: + if (pr) + printk("Videostream: ASPECT: reserved"); + vi->aspect_ratio = 0; + break; + + default: + vi->aspect_ratio = 0; + return -1; + } + + if (pr) + printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); + + sw = (int)(headr[3]&0x0F); + + switch ( sw ) { + case 1: + if (pr) + printk(" FRate: 23.976 fps"); + vi->framerate = 23976; + form = -1; + break; + case 2: + if (pr) + printk(" FRate: 24 fps"); + vi->framerate = 24000; + form = -1; + break; + case 3: + if (pr) + printk(" FRate: 25 fps"); + vi->framerate = 25000; + form = VIDEO_MODE_PAL; + break; + case 4: + if (pr) + printk(" FRate: 29.97 fps"); + vi->framerate = 29970; + form = VIDEO_MODE_NTSC; + break; + case 5: + if (pr) + printk(" FRate: 30 fps"); + vi->framerate = 30000; + form = VIDEO_MODE_NTSC; + break; + case 6: + if (pr) + printk(" FRate: 50 fps"); + vi->framerate = 50000; + form = VIDEO_MODE_PAL; + break; + case 7: + if (pr) + printk(" FRate: 60 fps"); + vi->framerate = 60000; + form = VIDEO_MODE_NTSC; + break; + } + + vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); + + vi->vbv_buffer_size + = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); + + if (pr){ + printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); + printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); + printk("\n"); + } + + vi->video_format = form; + + return 0; +} +#endif + + +#if 0 +static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr) +{ + u8 *headr; + int found = 0; + int c = 0; + + while (found < 4 && c+4 < count){ + u8 *b; + + b = mbuf+c; + if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 + && b[3] == 0xb3) found = 4; + else { + c++; + } + } + + if (! found) return -1; + c += 4; + if (c+12 >= count) return -1; + headr = mbuf+c; + if (read_sequence_header(headr, vi, pr) < 0) return -1; + vi->off = c-4; + return 0; +} +#endif + + +#if 0 +static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) +{ + u8 *headr; + int found = 0; + int c = 0; + int fr = 0; + + while (found < 2 && c < count){ + u8 b[2]; + memcpy( b, mbuf+c, 2); + + if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) + found = 2; + else { + c++; + } + } + + if (!found) return -1; + + if (c+3 >= count) return -1; + headr = mbuf+c; + + ai->layer = (headr[1] & 0x06) >> 1; + + if (pr) + printk("Audiostream: Layer: %d", 4-ai->layer); + + + ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; + + if (pr){ + if (ai->bit_rate == 0) + printk(" Bit rate: free"); + else if (ai->bit_rate == 0xf) + printk(" BRate: reserved"); + else + printk(" BRate: %d kb/s", ai->bit_rate/1000); + } + + fr = (headr[2] & 0x0c ) >> 2; + ai->frequency = freq[fr]*100; + if (pr){ + if (ai->frequency == 3) + printk(" Freq: reserved\n"); + else + printk(" Freq: %d kHz\n",ai->frequency); + + } + ai->off = c; + return 0; +} +#endif + + +int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) +{ + u8 *headr; + int found = 0; + int c = 0; + u8 frame = 0; + int fr = 0; + + while ( !found && c < count){ + u8 *b = mbuf+c; + + if ( b[0] == 0x0b && b[1] == 0x77 ) + found = 1; + else { + c++; + } + } + + if (!found) return -1; + if (pr) + printk("Audiostream: AC3"); + + ai->off = c; + if (c+5 >= count) return -1; + + ai->layer = 0; // 0 for AC3 + headr = mbuf+c+2; + + frame = (headr[2]&0x3f); + ai->bit_rate = ac3_bitrates[frame >> 1]*1000; + + if (pr) + printk(" BRate: %d kb/s", (int) ai->bit_rate/1000); + + ai->frequency = (headr[2] & 0xc0 ) >> 6; + fr = (headr[2] & 0xc0 ) >> 6; + ai->frequency = freq[fr]*100; + if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency); + + + ai->framesize = ac3_frames[fr][frame >> 1]; + if ((frame & 1) && (fr == 1)) ai->framesize++; + ai->framesize = ai->framesize << 1; + if (pr) printk (" Framesize %d\n",(int) ai->framesize); + + + return 0; +} + + +#if 0 +static u8 *skip_pes_header(u8 **bufp) +{ + u8 *inbuf = *bufp; + u8 *buf = inbuf; + u8 *pts = NULL; + int skip = 0; + + static const int mpeg1_skip_table[16] = { + 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, + 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff + }; + + + if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ + if (buf[7] & PTS_ONLY) + pts = buf+9; + else pts = NULL; + buf = inbuf + 9 + inbuf[8]; + } else { /* mpeg1 */ + for (buf = inbuf + 6; *buf == 0xff; buf++) + if (buf == inbuf + 6 + 16) { + break; + } + if ((*buf & 0xc0) == 0x40) + buf += 2; + skip = mpeg1_skip_table [*buf >> 4]; + if (skip == 5 || skip == 10) pts = buf; + else pts = NULL; + + buf += mpeg1_skip_table [*buf >> 4]; + } + + *bufp = buf; + return pts; +} +#endif + +#if 0 +static void initialize_quant_matrix( u32 *matrix ) +{ + int i; + + matrix[0] = 0x08101013; + matrix[1] = 0x10131616; + matrix[2] = 0x16161616; + matrix[3] = 0x1a181a1b; + matrix[4] = 0x1b1b1a1a; + matrix[5] = 0x1a1a1b1b; + matrix[6] = 0x1b1d1d1d; + matrix[7] = 0x2222221d; + matrix[8] = 0x1d1d1b1b; + matrix[9] = 0x1d1d2020; + matrix[10] = 0x22222526; + matrix[11] = 0x25232322; + matrix[12] = 0x23262628; + matrix[13] = 0x28283030; + matrix[14] = 0x2e2e3838; + matrix[15] = 0x3a454553; + + for ( i = 16 ; i < 32 ; i++ ) + matrix[i] = 0x10101010; +} +#endif + +#if 0 +static void initialize_mpg_picture(struct mpg_picture *pic) +{ + int i; + + /* set MPEG1 */ + pic->mpeg1_flag = 1; + pic->profile_and_level = 0x4A ; /* MP@LL */ + pic->progressive_sequence = 1; + pic->low_delay = 0; + + pic->sequence_display_extension_flag = 0; + for ( i = 0 ; i < 4 ; i++ ){ + pic->frame_centre_horizontal_offset[i] = 0; + pic->frame_centre_vertical_offset[i] = 0; + } + pic->last_frame_centre_horizontal_offset = 0; + pic->last_frame_centre_vertical_offset = 0; + + pic->picture_display_extension_flag[0] = 0; + pic->picture_display_extension_flag[1] = 0; + pic->sequence_header_flag = 0; + pic->gop_flag = 0; + pic->sequence_end_flag = 0; +} +#endif + +#if 0 +static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic ) +{ + int16_t last_h_offset; + int16_t last_v_offset; + + int16_t *p_h_offset; + int16_t *p_v_offset; + + if ( pic->mpeg1_flag ){ + pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; + pic->top_field_first = 0; + pic->repeat_first_field = 0; + pic->progressive_frame = 1; + pic->picture_coding_parameter = 0x000010; + } + + /* Reset flag */ + pic->picture_display_extension_flag[field_type] = 0; + + last_h_offset = pic->last_frame_centre_horizontal_offset; + last_v_offset = pic->last_frame_centre_vertical_offset; + if ( field_type == FIRST_FIELD ){ + p_h_offset = pic->frame_centre_horizontal_offset; + p_v_offset = pic->frame_centre_vertical_offset; + *p_h_offset = last_h_offset; + *(p_h_offset + 1) = last_h_offset; + *(p_h_offset + 2) = last_h_offset; + *p_v_offset = last_v_offset; + *(p_v_offset + 1) = last_v_offset; + *(p_v_offset + 2) = last_v_offset; + } else { + pic->frame_centre_horizontal_offset[3] = last_h_offset; + pic->frame_centre_vertical_offset[3] = last_v_offset; + } +} +#endif + +#if 0 +static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type) +{ + pic->picture_header = 0; + pic->sequence_header_data + = ( INIT_HORIZONTAL_SIZE << 20 ) + | ( INIT_VERTICAL_SIZE << 8 ) + | ( INIT_ASPECT_RATIO << 4 ) + | ( INIT_FRAME_RATE ); + pic->mpeg1_flag = 0; + pic->vinfo.horizontal_size + = INIT_DISP_HORIZONTAL_SIZE; + pic->vinfo.vertical_size + = INIT_DISP_VERTICAL_SIZE; + pic->picture_display_extension_flag[field_type] + = 0; + pic->pts_flag[field_type] = 0; + + pic->sequence_gop_header = 0; + pic->picture_header = 0; + pic->sequence_header_flag = 0; + pic->gop_flag = 0; + pic->sequence_end_flag = 0; + pic->sequence_display_extension_flag = 0; + pic->last_frame_centre_horizontal_offset = 0; + pic->last_frame_centre_vertical_offset = 0; + pic->channel = chan; +} +#endif + +void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv) +{ + unsigned char *buf=p2ts->buf; + + buf[0]=0x47; + buf[1]=(pid>>8); + buf[2]=pid&0xff; + p2ts->cc=0; + p2ts->cb=cb; + p2ts->priv=priv; +} + +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start) +{ + unsigned char *buf=p2ts->buf; + int ret=0, rest; + + //len=6+((pes[4]<<8)|pes[5]); + + if (payload_start) + buf[1]|=0x40; + else + buf[1]&=~0x40; + while (len>=184) { + buf[3]=0x10|((p2ts->cc++)&0x0f); + memcpy(buf+4, pes, 184); + if ((ret=p2ts->cb(p2ts->priv, buf))) + return ret; + len-=184; pes+=184; + buf[1]&=~0x40; + } + if (!len) + return 0; + buf[3]=0x30|((p2ts->cc++)&0x0f); + rest=183-len; + if (rest) { + buf[5]=0x00; + if (rest-1) + memset(buf+6, 0xff, rest-1); + } + buf[4]=rest; + memcpy(buf+5+rest, pes, len); + return p2ts->cb(p2ts->priv, buf); +} diff --git a/drivers/media/pci/ttpci/dvb_filter.h b/drivers/media/pci/ttpci/dvb_filter.h new file mode 100644 index 000000000000..375e3be184b1 --- /dev/null +++ b/drivers/media/pci/ttpci/dvb_filter.h @@ -0,0 +1,246 @@ +/* + * dvb_filter.h + * + * Copyright (C) 2003 Convergence GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _DVB_FILTER_H_ +#define _DVB_FILTER_H_ + +#include + +#include "demux.h" + +typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); + +struct dvb_filter_pes2ts { + unsigned char buf[188]; + unsigned char cc; + dvb_filter_pes2ts_cb_t *cb; + void *priv; +}; + +void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv); + +int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, + int len, int payload_start); + + +#define PROG_STREAM_MAP 0xBC +#define PRIVATE_STREAM1 0xBD +#define PADDING_STREAM 0xBE +#define PRIVATE_STREAM2 0xBF +#define AUDIO_STREAM_S 0xC0 +#define AUDIO_STREAM_E 0xDF +#define VIDEO_STREAM_S 0xE0 +#define VIDEO_STREAM_E 0xEF +#define ECM_STREAM 0xF0 +#define EMM_STREAM 0xF1 +#define DSM_CC_STREAM 0xF2 +#define ISO13522_STREAM 0xF3 +#define PROG_STREAM_DIR 0xFF + +#define DVB_PICTURE_START 0x00 +#define DVB_USER_START 0xb2 +#define DVB_SEQUENCE_HEADER 0xb3 +#define DVB_SEQUENCE_ERROR 0xb4 +#define DVB_EXTENSION_START 0xb5 +#define DVB_SEQUENCE_END 0xb7 +#define DVB_GOP_START 0xb8 +#define DVB_EXCEPT_SLICE 0xb0 + +#define SEQUENCE_EXTENSION 0x01 +#define SEQUENCE_DISPLAY_EXTENSION 0x02 +#define PICTURE_CODING_EXTENSION 0x08 +#define QUANT_MATRIX_EXTENSION 0x03 +#define PICTURE_DISPLAY_EXTENSION 0x07 + +#define I_FRAME 0x01 +#define B_FRAME 0x02 +#define P_FRAME 0x03 + +/* Initialize sequence_data */ +#define INIT_HORIZONTAL_SIZE 720 +#define INIT_VERTICAL_SIZE 576 +#define INIT_ASPECT_RATIO 0x02 +#define INIT_FRAME_RATE 0x03 +#define INIT_DISP_HORIZONTAL_SIZE 540 +#define INIT_DISP_VERTICAL_SIZE 576 + + +//flags2 +#define PTS_DTS_FLAGS 0xC0 +#define ESCR_FLAG 0x20 +#define ES_RATE_FLAG 0x10 +#define DSM_TRICK_FLAG 0x08 +#define ADD_CPY_FLAG 0x04 +#define PES_CRC_FLAG 0x02 +#define PES_EXT_FLAG 0x01 + +//pts_dts flags +#define PTS_ONLY 0x80 +#define PTS_DTS 0xC0 + +#define TS_SIZE 188 +#define TRANS_ERROR 0x80 +#define PAY_START 0x40 +#define TRANS_PRIO 0x20 +#define PID_MASK_HI 0x1F +//flags +#define TRANS_SCRMBL1 0x80 +#define TRANS_SCRMBL2 0x40 +#define ADAPT_FIELD 0x20 +#define PAYLOAD 0x10 +#define COUNT_MASK 0x0F + +// adaptation flags +#define DISCON_IND 0x80 +#define RAND_ACC_IND 0x40 +#define ES_PRI_IND 0x20 +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 +#define SPLICE_FLAG 0x04 +#define TRANS_PRIV 0x02 +#define ADAP_EXT_FLAG 0x01 + +// adaptation extension flags +#define LTW_FLAG 0x80 +#define PIECE_RATE 0x40 +#define SEAM_SPLICE 0x20 + + +#define MAX_PLENGTH 0xFFFF +#define MMAX_PLENGTH (256*MAX_PLENGTH) + +#ifndef IPACKS +#define IPACKS 2048 +#endif + +struct ipack { + int size; + int found; + u8 *buf; + u8 cid; + u32 plength; + u8 plen[2]; + u8 flag1; + u8 flag2; + u8 hlength; + u8 pts[5]; + u16 *pid; + int mpeg; + u8 check; + int which; + int done; + void *data; + void (*func)(u8 *buf, int size, void *priv); + int count; + int repack_subids; +}; + +struct dvb_video_info { + u32 horizontal_size; + u32 vertical_size; + u32 aspect_ratio; + u32 framerate; + u32 video_format; + u32 bit_rate; + u32 comp_bit_rate; + u32 vbv_buffer_size; + s16 vbv_delay; + u32 CSPF; + u32 off; +}; + +#define OFF_SIZE 4 +#define FIRST_FIELD 0 +#define SECOND_FIELD 1 +#define VIDEO_FRAME_PICTURE 0x03 + +struct mpg_picture { + int channel; + struct dvb_video_info vinfo; + u32 *sequence_gop_header; + u32 *picture_header; + s32 time_code; + int low_delay; + int closed_gop; + int broken_link; + int sequence_header_flag; + int gop_flag; + int sequence_end_flag; + + u8 profile_and_level; + s32 picture_coding_parameter; + u32 matrix[32]; + s8 matrix_change_flag; + + u8 picture_header_parameter; + /* bit 0 - 2: bwd f code + bit 3 : fpb vector + bit 4 - 6: fwd f code + bit 7 : fpf vector */ + + int mpeg1_flag; + int progressive_sequence; + int sequence_display_extension_flag; + u32 sequence_header_data; + s16 last_frame_centre_horizontal_offset; + s16 last_frame_centre_vertical_offset; + + u32 pts[2]; /* [0] 1st field, [1] 2nd field */ + int top_field_first; + int repeat_first_field; + int progressive_frame; + int bank; + int forward_bank; + int backward_bank; + int compress; + s16 frame_centre_horizontal_offset[OFF_SIZE]; + /* [0-2] 1st field, [3] 2nd field */ + s16 frame_centre_vertical_offset[OFF_SIZE]; + /* [0-2] 1st field, [3] 2nd field */ + s16 temporal_reference[2]; + /* [0] 1st field, [1] 2nd field */ + + s8 picture_coding_type[2]; + /* [0] 1st field, [1] 2nd field */ + s8 picture_structure[2]; + /* [0] 1st field, [1] 2nd field */ + s8 picture_display_extension_flag[2]; + /* [0] 1st field, [1] 2nd field */ + /* picture_display_extenion() 0:no 1:exit*/ + s8 pts_flag[2]; + /* [0] 1st field, [1] 2nd field */ +}; + +struct dvb_audio_info { + int layer; + u32 bit_rate; + u32 frequency; + u32 mode; + u32 mode_extension ; + u32 emphasis; + u32 framesize; + u32 off; +}; + +int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr); + + +#endif diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 4e7671a3a1e4..35d5003ff809 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -36,7 +36,6 @@ #include "dmxdev.h" #include "dvb_demux.h" -#include "dvb_filter.h" #include "dvb_frontend.h" #include "dvb_net.h" #include "ttusbdecfe.h" @@ -92,6 +91,15 @@ enum ttusb_dec_interface { TTUSB_DEC_INTERFACE_OUT }; +typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); + +struct dvb_filter_pes2ts { + unsigned char buf[188]; + unsigned char cc; + dvb_filter_pes2ts_cb_t *cb; + void *priv; +}; + struct ttusb_dec { enum ttusb_dec_model model; char *model_name; @@ -201,6 +209,54 @@ static u16 rc_keys[] = { KEY_RADIO }; +static void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, + unsigned short pid, + dvb_filter_pes2ts_cb_t *cb, void *priv) +{ + unsigned char *buf=p2ts->buf; + + buf[0]=0x47; + buf[1]=(pid>>8); + buf[2]=pid&0xff; + p2ts->cc=0; + p2ts->cb=cb; + p2ts->priv=priv; +} + +static int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, + unsigned char *pes, int len, int payload_start) +{ + unsigned char *buf=p2ts->buf; + int ret=0, rest; + + //len=6+((pes[4]<<8)|pes[5]); + + if (payload_start) + buf[1]|=0x40; + else + buf[1]&=~0x40; + while (len>=184) { + buf[3]=0x10|((p2ts->cc++)&0x0f); + memcpy(buf+4, pes, 184); + if ((ret=p2ts->cb(p2ts->priv, buf))) + return ret; + len-=184; pes+=184; + buf[1]&=~0x40; + } + if (!len) + return 0; + buf[3]=0x30|((p2ts->cc++)&0x0f); + rest=183-len; + if (rest) { + buf[5]=0x00; + if (rest-1) + memset(buf+6, 0xff, rest-1); + } + buf[4]=rest; + memcpy(buf+5+rest, pes, len); + return p2ts->cb(p2ts->priv, buf); +} + static void ttusb_dec_set_model(struct ttusb_dec *dec, enum ttusb_dec_model model); -- cgit v1.2.3 From 54e0443b47bba8a4700273abc261c73ec1d358f7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:03:48 -0300 Subject: [media] dvb_filter: get rid of dead code There are lots of stuff here commented out for a really long time. Get rid of them. If one wants it again, it could always use git log. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/dvb_filter.c | 485 ----------------------------------- 1 file changed, 485 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ttpci/dvb_filter.c b/drivers/media/pci/ttpci/dvb_filter.c index 6395812ed1f1..227f93e2ef10 100644 --- a/drivers/media/pci/ttpci/dvb_filter.c +++ b/drivers/media/pci/ttpci/dvb_filter.c @@ -3,13 +3,6 @@ #include #include "dvb_filter.h" -#if 0 -static unsigned int bitrates[3][16] = -{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, - {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, - {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; -#endif - static u32 freq[4] = {480, 441, 320, 0}; static unsigned int ac3_bitrates[32] = @@ -25,323 +18,6 @@ static u32 ac3_frames[3][32] = 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; - -#if 0 -static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, - void (*pes_write)(u8 *buf, int count, void *data), - void *priv) -{ - dvb_filter_ipack_init(pa, IPACKS, pes_write); - dvb_filter_ipack_init(pv, IPACKS, pes_write); - pa->pid = pida; - pv->pid = pidv; - pa->data = priv; - pv->data = priv; -} -#endif - -#if 0 -static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) -{ - u8 off = 0; - - if (!buf || !p ){ - printk("NULL POINTER IDIOT\n"); - return; - } - if (buf[1]&PAY_START) { - if (p->plength == MMAX_PLENGTH-6 && p->found>6){ - p->plength = p->found-6; - p->found = 0; - send_ipack(p); - dvb_filter_ipack_reset(p); - } - } - if (buf[3] & ADAPT_FIELD) { // adaptation field? - off = buf[4] + 1; - if (off+4 > 187) return; - } - dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p); -} -#endif - -#if 0 -/* needs 5 byte input, returns picture coding type*/ -static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr) -{ - u8 pct; - - if (pr) printk( "Pic header: "); - pic->temporal_reference[field] = (( headr[0] << 2 ) | - (headr[1] & 0x03) )& 0x03ff; - if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); - - pct = ( headr[1] >> 2 ) & 0x07; - pic->picture_coding_type[field] = pct; - if (pr) { - switch(pct){ - case I_FRAME: - printk( " I-FRAME"); - break; - case B_FRAME: - printk( " B-FRAME"); - break; - case P_FRAME: - printk( " P-FRAME"); - break; - } - } - - - pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | - ( (headr[3] & 0x1F) << 11) ) & 0xffff; - - if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); - - pic->picture_header_parameter = ( headr[3] & 0xe0 ) | - ((headr[4] & 0x80) >> 3); - - if ( pct == B_FRAME ){ - pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; - } - if (pr) printk( " pic head param: 0x%x", - pic->picture_header_parameter); - - return pct; -} -#endif - -#if 0 -/* needs 4 byte input */ -static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr) -{ - if (pr) printk("GOP header: "); - - pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | - ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; - - if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, - ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), - ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); - - if ( ( headr[3] & 0x40 ) != 0 ){ - pic->closed_gop = 1; - } else { - pic->closed_gop = 0; - } - if (pr) printk("closed: %d", pic->closed_gop); - - if ( ( headr[3] & 0x20 ) != 0 ){ - pic->broken_link = 1; - } else { - pic->broken_link = 0; - } - if (pr) printk(" broken: %d\n", pic->broken_link); - - return 0; -} -#endif - -#if 0 -/* needs 8 byte input */ -static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr) -{ - int sw; - int form = -1; - - if (pr) printk("Reading sequence header\n"); - - vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); - vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); - - sw = (int)((headr[3]&0xF0) >> 4) ; - - switch( sw ){ - case 1: - if (pr) - printk("Videostream: ASPECT: 1:1"); - vi->aspect_ratio = 100; - break; - case 2: - if (pr) - printk("Videostream: ASPECT: 4:3"); - vi->aspect_ratio = 133; - break; - case 3: - if (pr) - printk("Videostream: ASPECT: 16:9"); - vi->aspect_ratio = 177; - break; - case 4: - if (pr) - printk("Videostream: ASPECT: 2.21:1"); - vi->aspect_ratio = 221; - break; - - case 5 ... 15: - if (pr) - printk("Videostream: ASPECT: reserved"); - vi->aspect_ratio = 0; - break; - - default: - vi->aspect_ratio = 0; - return -1; - } - - if (pr) - printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); - - sw = (int)(headr[3]&0x0F); - - switch ( sw ) { - case 1: - if (pr) - printk(" FRate: 23.976 fps"); - vi->framerate = 23976; - form = -1; - break; - case 2: - if (pr) - printk(" FRate: 24 fps"); - vi->framerate = 24000; - form = -1; - break; - case 3: - if (pr) - printk(" FRate: 25 fps"); - vi->framerate = 25000; - form = VIDEO_MODE_PAL; - break; - case 4: - if (pr) - printk(" FRate: 29.97 fps"); - vi->framerate = 29970; - form = VIDEO_MODE_NTSC; - break; - case 5: - if (pr) - printk(" FRate: 30 fps"); - vi->framerate = 30000; - form = VIDEO_MODE_NTSC; - break; - case 6: - if (pr) - printk(" FRate: 50 fps"); - vi->framerate = 50000; - form = VIDEO_MODE_PAL; - break; - case 7: - if (pr) - printk(" FRate: 60 fps"); - vi->framerate = 60000; - form = VIDEO_MODE_NTSC; - break; - } - - vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); - - vi->vbv_buffer_size - = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); - - if (pr){ - printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); - printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); - printk("\n"); - } - - vi->video_format = form; - - return 0; -} -#endif - - -#if 0 -static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - - while (found < 4 && c+4 < count){ - u8 *b; - - b = mbuf+c; - if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 - && b[3] == 0xb3) found = 4; - else { - c++; - } - } - - if (! found) return -1; - c += 4; - if (c+12 >= count) return -1; - headr = mbuf+c; - if (read_sequence_header(headr, vi, pr) < 0) return -1; - vi->off = c-4; - return 0; -} -#endif - - -#if 0 -static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) -{ - u8 *headr; - int found = 0; - int c = 0; - int fr = 0; - - while (found < 2 && c < count){ - u8 b[2]; - memcpy( b, mbuf+c, 2); - - if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) - found = 2; - else { - c++; - } - } - - if (!found) return -1; - - if (c+3 >= count) return -1; - headr = mbuf+c; - - ai->layer = (headr[1] & 0x06) >> 1; - - if (pr) - printk("Audiostream: Layer: %d", 4-ai->layer); - - - ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; - - if (pr){ - if (ai->bit_rate == 0) - printk(" Bit rate: free"); - else if (ai->bit_rate == 0xf) - printk(" BRate: reserved"); - else - printk(" BRate: %d kb/s", ai->bit_rate/1000); - } - - fr = (headr[2] & 0x0c ) >> 2; - ai->frequency = freq[fr]*100; - if (pr){ - if (ai->frequency == 3) - printk(" Freq: reserved\n"); - else - printk(" Freq: %d kHz\n",ai->frequency); - - } - ai->off = c; - return 0; -} -#endif - - int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) { u8 *headr; @@ -391,167 +67,6 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p return 0; } - -#if 0 -static u8 *skip_pes_header(u8 **bufp) -{ - u8 *inbuf = *bufp; - u8 *buf = inbuf; - u8 *pts = NULL; - int skip = 0; - - static const int mpeg1_skip_table[16] = { - 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, - 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff - }; - - - if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ - if (buf[7] & PTS_ONLY) - pts = buf+9; - else pts = NULL; - buf = inbuf + 9 + inbuf[8]; - } else { /* mpeg1 */ - for (buf = inbuf + 6; *buf == 0xff; buf++) - if (buf == inbuf + 6 + 16) { - break; - } - if ((*buf & 0xc0) == 0x40) - buf += 2; - skip = mpeg1_skip_table [*buf >> 4]; - if (skip == 5 || skip == 10) pts = buf; - else pts = NULL; - - buf += mpeg1_skip_table [*buf >> 4]; - } - - *bufp = buf; - return pts; -} -#endif - -#if 0 -static void initialize_quant_matrix( u32 *matrix ) -{ - int i; - - matrix[0] = 0x08101013; - matrix[1] = 0x10131616; - matrix[2] = 0x16161616; - matrix[3] = 0x1a181a1b; - matrix[4] = 0x1b1b1a1a; - matrix[5] = 0x1a1a1b1b; - matrix[6] = 0x1b1d1d1d; - matrix[7] = 0x2222221d; - matrix[8] = 0x1d1d1b1b; - matrix[9] = 0x1d1d2020; - matrix[10] = 0x22222526; - matrix[11] = 0x25232322; - matrix[12] = 0x23262628; - matrix[13] = 0x28283030; - matrix[14] = 0x2e2e3838; - matrix[15] = 0x3a454553; - - for ( i = 16 ; i < 32 ; i++ ) - matrix[i] = 0x10101010; -} -#endif - -#if 0 -static void initialize_mpg_picture(struct mpg_picture *pic) -{ - int i; - - /* set MPEG1 */ - pic->mpeg1_flag = 1; - pic->profile_and_level = 0x4A ; /* MP@LL */ - pic->progressive_sequence = 1; - pic->low_delay = 0; - - pic->sequence_display_extension_flag = 0; - for ( i = 0 ; i < 4 ; i++ ){ - pic->frame_centre_horizontal_offset[i] = 0; - pic->frame_centre_vertical_offset[i] = 0; - } - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - - pic->picture_display_extension_flag[0] = 0; - pic->picture_display_extension_flag[1] = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; -} -#endif - -#if 0 -static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic ) -{ - int16_t last_h_offset; - int16_t last_v_offset; - - int16_t *p_h_offset; - int16_t *p_v_offset; - - if ( pic->mpeg1_flag ){ - pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; - pic->top_field_first = 0; - pic->repeat_first_field = 0; - pic->progressive_frame = 1; - pic->picture_coding_parameter = 0x000010; - } - - /* Reset flag */ - pic->picture_display_extension_flag[field_type] = 0; - - last_h_offset = pic->last_frame_centre_horizontal_offset; - last_v_offset = pic->last_frame_centre_vertical_offset; - if ( field_type == FIRST_FIELD ){ - p_h_offset = pic->frame_centre_horizontal_offset; - p_v_offset = pic->frame_centre_vertical_offset; - *p_h_offset = last_h_offset; - *(p_h_offset + 1) = last_h_offset; - *(p_h_offset + 2) = last_h_offset; - *p_v_offset = last_v_offset; - *(p_v_offset + 1) = last_v_offset; - *(p_v_offset + 2) = last_v_offset; - } else { - pic->frame_centre_horizontal_offset[3] = last_h_offset; - pic->frame_centre_vertical_offset[3] = last_v_offset; - } -} -#endif - -#if 0 -static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type) -{ - pic->picture_header = 0; - pic->sequence_header_data - = ( INIT_HORIZONTAL_SIZE << 20 ) - | ( INIT_VERTICAL_SIZE << 8 ) - | ( INIT_ASPECT_RATIO << 4 ) - | ( INIT_FRAME_RATE ); - pic->mpeg1_flag = 0; - pic->vinfo.horizontal_size - = INIT_DISP_HORIZONTAL_SIZE; - pic->vinfo.vertical_size - = INIT_DISP_VERTICAL_SIZE; - pic->picture_display_extension_flag[field_type] - = 0; - pic->pts_flag[field_type] = 0; - - pic->sequence_gop_header = 0; - pic->picture_header = 0; - pic->sequence_header_flag = 0; - pic->gop_flag = 0; - pic->sequence_end_flag = 0; - pic->sequence_display_extension_flag = 0; - pic->last_frame_centre_horizontal_offset = 0; - pic->last_frame_centre_vertical_offset = 0; - pic->channel = chan; -} -#endif - void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, dvb_filter_pes2ts_cb_t *cb, void *priv) { -- cgit v1.2.3 From 9a9689cf6d4dfb8b105946e20846ec20ea403bf9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:11:07 -0300 Subject: [media] dvb_filter: use KERN_CONT where needed Some continuation messages are not using KERN_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. While here, add missing log level annotations. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/dvb_filter.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ttpci/dvb_filter.c b/drivers/media/pci/ttpci/dvb_filter.c index 227f93e2ef10..b67127b67d4e 100644 --- a/drivers/media/pci/ttpci/dvb_filter.c +++ b/drivers/media/pci/ttpci/dvb_filter.c @@ -17,7 +17,6 @@ static u32 ac3_frames[3][32] = {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; - int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) { u8 *headr; @@ -38,7 +37,7 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p if (!found) return -1; if (pr) - printk("Audiostream: AC3"); + printk(KERN_DEBUG "Audiostream: AC3"); ai->off = c; if (c+5 >= count) return -1; @@ -50,19 +49,19 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p ai->bit_rate = ac3_bitrates[frame >> 1]*1000; if (pr) - printk(" BRate: %d kb/s", (int) ai->bit_rate/1000); + printk(KERN_CONT " BRate: %d kb/s", (int) ai->bit_rate/1000); ai->frequency = (headr[2] & 0xc0 ) >> 6; fr = (headr[2] & 0xc0 ) >> 6; ai->frequency = freq[fr]*100; - if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency); - + if (pr) + printk(KERN_CONT " Freq: %d Hz\n", (int) ai->frequency); ai->framesize = ac3_frames[fr][frame >> 1]; if ((frame & 1) && (fr == 1)) ai->framesize++; ai->framesize = ai->framesize << 1; - if (pr) printk (" Framesize %d\n",(int) ai->framesize); - + if (pr) + printk(KERN_DEBUG " Framesize %d\n", (int) ai->framesize); return 0; } -- cgit v1.2.3 From 69396c4e2a985091ca6f8d246913fb21ace060ca Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:23:29 -0300 Subject: [media] uvc_driver: use KERN_CONT where needed Some continuation messages are not using KERN_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Laurent Pinchart --- drivers/media/usb/uvc/uvc_driver.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 302e284a95eb..9c4b56b4a9c6 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1309,7 +1309,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, switch (UVC_ENTITY_TYPE(entity)) { case UVC_VC_EXTENSION_UNIT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- XU %d", entity->id); + printk(KERN_CONT " <- XU %d", entity->id); if (entity->bNrInPins != 1) { uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more " @@ -1321,7 +1321,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_VC_PROCESSING_UNIT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- PU %d", entity->id); + printk(KERN_CONT " <- PU %d", entity->id); if (chain->processing != NULL) { uvc_trace(UVC_TRACE_DESCR, "Found multiple " @@ -1334,7 +1334,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_VC_SELECTOR_UNIT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- SU %d", entity->id); + printk(KERN_CONT " <- SU %d", entity->id); /* Single-input selector units are ignored. */ if (entity->bNrInPins == 1) @@ -1353,7 +1353,7 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_ITT_CAMERA: case UVC_ITT_MEDIA_TRANSPORT_INPUT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT %d\n", entity->id); + printk(KERN_CONT " <- IT %d\n", entity->id); break; @@ -1361,17 +1361,17 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, case UVC_OTT_DISPLAY: case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" OT %d", entity->id); + printk(KERN_CONT " OT %d", entity->id); break; case UVC_TT_STREAMING: if (UVC_ENTITY_IS_ITERM(entity)) { if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT %d\n", entity->id); + printk(KERN_CONT " <- IT %d\n", entity->id); } else { if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" OT %d", entity->id); + printk(KERN_CONT " OT %d", entity->id); } break; @@ -1416,9 +1416,9 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, list_add_tail(&forward->chain, &chain->entities); if (uvc_trace_param & UVC_TRACE_PROBE) { if (!found) - printk(" (->"); + printk(KERN_CONT " (->"); - printk(" XU %d", forward->id); + printk(KERN_CONT " XU %d", forward->id); found = 1; } break; @@ -1436,16 +1436,16 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, list_add_tail(&forward->chain, &chain->entities); if (uvc_trace_param & UVC_TRACE_PROBE) { if (!found) - printk(" (->"); + printk(KERN_CONT " (->"); - printk(" OT %d", forward->id); + printk(KERN_CONT " OT %d", forward->id); found = 1; } break; } } if (found) - printk(")"); + printk(KERN_CONT ")"); return 0; } @@ -1471,7 +1471,7 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, } if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" <- IT"); + printk(KERN_CONT " <- IT"); chain->selector = entity; for (i = 0; i < entity->bNrInPins; ++i) { @@ -1485,14 +1485,14 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, } if (uvc_trace_param & UVC_TRACE_PROBE) - printk(" %d", term->id); + printk(KERN_CONT " %d", term->id); list_add_tail(&term->chain, &chain->entities); uvc_scan_chain_forward(chain, term, entity); } if (uvc_trace_param & UVC_TRACE_PROBE) - printk("\n"); + printk(KERN_CONT "\n"); id = 0; break; -- cgit v1.2.3 From 832d40c028cfc7049ceff79155f87ccb5e6a3582 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:48:35 -0300 Subject: [media] imon: use %*ph to do small hexa dumps Since commit 563873318d32 ("Merge branch 'printk-cleanups"), continuation lines require KERN_CONT. Instead, let's just use %*ph to print the buffer. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index 86cc70fe2534..d62b1f38292c 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -1593,7 +1593,6 @@ static void imon_incoming_packet(struct imon_context *ictx, struct device *dev = ictx->dev; unsigned long flags; u32 kc; - int i; u64 scancode; int press_type = 0; int msec; @@ -1664,10 +1663,8 @@ static void imon_incoming_packet(struct imon_context *ictx, } if (debug) { - printk(KERN_INFO "intf%d decoded packet: ", intf); - for (i = 0; i < len; ++i) - printk("%02x ", buf[i]); - printk("\n"); + printk(KERN_INFO "intf%d decoded packet: %*ph\n", + intf, len, buf); } press_type = imon_parse_press_type(ictx, buf, ktype); -- cgit v1.2.3 From c5bac2e75270b10ff5a5675bebad4df2106506f1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 10:37:48 -0300 Subject: [media] mt20xx: use %*ph to do small hexa dumps Since commit 563873318d32 ("Merge branch 'printk-cleanups"), continuation lines require KERN_CONT. Instead, let's just use %*ph to print the buffer. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/mt20xx.c | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c index 52da4671b0e0..29dadd171b31 100644 --- a/drivers/media/tuners/mt20xx.c +++ b/drivers/media/tuners/mt20xx.c @@ -487,13 +487,8 @@ static void mt2050_set_if_freq(struct dvb_frontend *fe,unsigned int freq, unsign buf[5]=div2a; if(num2!=0) buf[5]=buf[5]|0x40; - if (debug > 1) { - int i; - tuner_dbg("bufs is: "); - for(i=0;i<6;i++) - printk("%x ",buf[i]); - printk("\n"); - } + if (debug > 1) + tuner_dbg("bufs is: %*ph\n", 6, buf); ret=tuner_i2c_xfer_send(&priv->i2c_props,buf,6); if (ret!=6) @@ -619,15 +614,9 @@ struct dvb_frontend *microtune_attach(struct dvb_frontend *fe, tuner_i2c_xfer_send(&priv->i2c_props,buf,1); tuner_i2c_xfer_recv(&priv->i2c_props,buf,21); - if (debug) { - int i; - tuner_dbg("MT20xx hexdump:"); - for(i=0;i<21;i++) { - printk(" %02x",buf[i]); - if(((i+1)%8)==0) printk(" "); - } - printk("\n"); - } + if (debug) + tuner_dbg("MT20xx hexdump: %*ph\n", 21, buf); + company_code = buf[0x11] << 8 | buf[0x12]; tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n", company_code,buf[0x13],buf[0x14]); -- cgit v1.2.3 From 178991e03c43db6a45ecf3d28fee6165fc66b250 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 14:02:21 -0300 Subject: [media] tvaudio: mark printk continuation lines as such This driver has printk continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups'"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvaudio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c index 42d1e26e581c..ce86534450ac 100644 --- a/drivers/media/i2c/tvaudio.c +++ b/drivers/media/i2c/tvaudio.c @@ -1894,8 +1894,9 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id * printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n"); printk(KERN_INFO "tvaudio: known chips: "); for (desc = chiplist; desc->name != NULL; desc++) - printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name); - printk("\n"); + printk(KERN_CONT "%s%s", + (desc == chiplist) ? "" : ", ", desc->name); + printk(KERN_CONT "\n"); } chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); -- cgit v1.2.3 From 7887d3710b6eac7c980f4e7b4b86bd383695ae80 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 15:23:12 -0300 Subject: [media] flexcop-i2c: mark printk continuation lines as such This driver has printk continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups'"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/b2c2/flexcop-i2c.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c index 965d5eb33752..e41cd23f8e45 100644 --- a/drivers/media/common/b2c2/flexcop-i2c.c +++ b/drivers/media/common/b2c2/flexcop-i2c.c @@ -124,10 +124,10 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, #ifdef DUMP_I2C_MESSAGES printk(KERN_DEBUG "%d ", i2c->port); if (op == FC_READ) - printk("rd("); + printk(KERN_CONT "rd("); else - printk("wr("); - printk("%02x): %02x ", chipaddr, addr); + printk(KERN_CONT "wr("); + printk(KERN_CONT "%02x): %02x ", chipaddr, addr); #endif /* in that case addr is the only value -> @@ -151,7 +151,7 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, #ifdef DUMP_I2C_MESSAGES for (i = 0; i < bytes_to_transfer; i++) - printk("%02x ", buf[i]); + printk(KERN_CONT "%02x ", buf[i]); #endif if (ret < 0) @@ -163,7 +163,7 @@ int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c, } #ifdef DUMP_I2C_MESSAGES - printk("\n"); + printk(KERN_CONT "\n"); #endif return 0; -- cgit v1.2.3 From 6dd23d4c952f4ccf4dd9454c8464557c5151f2be Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 15:27:35 -0300 Subject: [media] cx2341x: mark printk continuation lines as such This driver has printk continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups'"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/cx2341x.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c index 5e4afa0131e6..2725702eda7b 100644 --- a/drivers/media/common/cx2341x.c +++ b/drivers/media/common/cx2341x.c @@ -1190,8 +1190,8 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_TYPE)); if (p->stream_insert_nav_packets) - printk(" (with navigation packets)"); - printk("\n"); + printk(KERN_CONT " (with navigation packets)"); + printk(KERN_CONT "\n"); printk(KERN_INFO "%s: VBI Format: %s\n", prefix, cx2341x_menu_item(p, V4L2_CID_MPEG_STREAM_VBI_FMT)); @@ -1209,8 +1209,8 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_VIDEO_BITRATE_MODE), p->video_bitrate); if (p->video_bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) - printk(", Peak %d", p->video_bitrate_peak); - printk("\n"); + printk(KERN_CONT ", Peak %d", p->video_bitrate_peak); + printk(KERN_CONT "\n"); printk(KERN_INFO "%s: Video: GOP Size %d, %d B-Frames, %sGOP Closure\n", prefix, @@ -1232,9 +1232,9 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix) cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE), p->audio_mute ? " (muted)" : ""); if (p->audio_mode == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO) - printk(", %s", cx2341x_menu_item(p, + printk(KERN_CONT ", %s", cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_MODE_EXTENSION)); - printk(", %s, %s\n", + printk(KERN_CONT ", %s, %s\n", cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_EMPHASIS), cx2341x_menu_item(p, V4L2_CID_MPEG_AUDIO_CRC)); -- cgit v1.2.3 From 5479a582deb57e9f4804fc001fa41b3f07eb9334 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 15:32:32 -0300 Subject: [media] dvb-pll: use pr_foo() macros instead of printk() Replace printk() macros by their pr_foo() counterparts. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dvb-pll.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 735a96662022..b6d199196b83 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -18,6 +18,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -25,6 +27,9 @@ #include "dvb-pll.h" +#define dprintk(fmt, arg...) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg) + struct dvb_pll_priv { /* pll number */ int nr; @@ -362,7 +367,7 @@ static void opera1_bw(struct dvb_frontend *fe, u8 *buf) result = i2c_transfer(priv->i2c, &msg, 1); if (result != 1) - printk(KERN_ERR "%s: i2c_transfer failed:%d", + pr_err("%s: i2c_transfer failed:%d", __func__, result); if (b_w <= 10000) @@ -432,7 +437,7 @@ static void samsung_dtos403ih102a_set(struct dvb_frontend *fe, u8 *buf) result = i2c_transfer(priv->i2c, &msg, 1); if (result != 1) - printk(KERN_ERR "%s: i2c_transfer failed:%d", + pr_err("%s: i2c_transfer failed:%d", __func__, result); buf[2] = 0x9e; @@ -578,7 +583,7 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, } if (debug) - printk("pll: %s: freq=%d | i=%d/%d\n", desc->name, + dprintk("pll: %s: freq=%d | i=%d/%d\n", desc->name, frequency, i, desc->count); if (i == desc->count) return -EINVAL; @@ -594,7 +599,7 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, desc->set(fe, buf); if (debug) - printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", + dprintk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n", desc->name, div, buf[0], buf[1], buf[2], buf[3]); // calculate the frequency we set it to @@ -803,10 +808,10 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, fe->tuner_priv = priv; if ((debug) || (id[priv->nr] == pll_desc_id)) { - printk("dvb-pll[%d]", priv->nr); + dprintk("dvb-pll[%d]", priv->nr); if (i2c != NULL) - printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr); - printk(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, + pr_cont(" %d-%04x", i2c_adapter_id(i2c), pll_addr); + pr_cont(": id# %d (%s) attached, %s\n", pll_desc_id, desc->name, id[priv->nr] == pll_desc_id ? "insmod option" : "autodetected"); } -- cgit v1.2.3 From cc5ad2b659d2c37c8b264a72621653cbbd2a7c06 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 15:37:40 -0300 Subject: [media] nxt6000: use pr_foo() macros instead of printk() Replace printk() macros by their pr_foo() counterparts and use pr_cont() for the continuation lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/nxt6000.c | 136 +++++++++++++++++++--------------- 1 file changed, 76 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/nxt6000.c b/drivers/media/dvb-frontends/nxt6000.c index 73f9505367ac..1545d898b125 100644 --- a/drivers/media/dvb-frontends/nxt6000.c +++ b/drivers/media/dvb-frontends/nxt6000.c @@ -19,6 +19,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -39,7 +41,11 @@ struct nxt6000_state { }; static int debug; -#define dprintk if (debug) printk +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data) { @@ -215,119 +221,129 @@ static void nxt6000_dump_status(struct nxt6000_state *state) { u8 val; -/* - printk("RS_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, RS_COR_STAT)); - printk("VIT_SYNC_STATUS: 0x%02X\n", nxt6000_readreg(fe, VIT_SYNC_STATUS)); - printk("OFDM_COR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_COR_STAT)); - printk("OFDM_SYR_STAT: 0x%02X\n", nxt6000_readreg(fe, OFDM_SYR_STAT)); - printk("OFDM_TPS_RCVD_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_1)); - printk("OFDM_TPS_RCVD_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_2)); - printk("OFDM_TPS_RCVD_3: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_3)); - printk("OFDM_TPS_RCVD_4: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RCVD_4)); - printk("OFDM_TPS_RESERVED_1: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_1)); - printk("OFDM_TPS_RESERVED_2: 0x%02X\n", nxt6000_readreg(fe, OFDM_TPS_RESERVED_2)); -*/ - printk("NXT6000 status:"); +#if 0 + pr_info("RS_COR_STAT: 0x%02X\n", + nxt6000_readreg(fe, RS_COR_STAT)); + pr_info("VIT_SYNC_STATUS: 0x%02X\n", + nxt6000_readreg(fe, VIT_SYNC_STATUS)); + pr_info("OFDM_COR_STAT: 0x%02X\n", + nxt6000_readreg(fe, OFDM_COR_STAT)); + pr_info("OFDM_SYR_STAT: 0x%02X\n", + nxt6000_readreg(fe, OFDM_SYR_STAT)); + pr_info("OFDM_TPS_RCVD_1: 0x%02X\n", + nxt6000_readreg(fe, OFDM_TPS_RCVD_1)); + pr_info("OFDM_TPS_RCVD_2: 0x%02X\n", + nxt6000_readreg(fe, OFDM_TPS_RCVD_2)); + pr_info("OFDM_TPS_RCVD_3: 0x%02X\n", + nxt6000_readreg(fe, OFDM_TPS_RCVD_3)); + pr_info("OFDM_TPS_RCVD_4: 0x%02X\n", + nxt6000_readreg(fe, OFDM_TPS_RCVD_4)); + pr_info("OFDM_TPS_RESERVED_1: 0x%02X\n", + nxt6000_readreg(fe, OFDM_TPS_RESERVED_1)); + pr_info("OFDM_TPS_RESERVED_2: 0x%02X\n", + nxt6000_readreg(fe, OFDM_TPS_RESERVED_2)); +#endif + pr_info("NXT6000 status:"); val = nxt6000_readreg(state, RS_COR_STAT); - printk(" DATA DESCR LOCK: %d,", val & 0x01); - printk(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01); + pr_cont(" DATA DESCR LOCK: %d,", val & 0x01); + pr_cont(" DATA SYNC LOCK: %d,", (val >> 1) & 0x01); val = nxt6000_readreg(state, VIT_SYNC_STATUS); - printk(" VITERBI LOCK: %d,", (val >> 7) & 0x01); + pr_cont(" VITERBI LOCK: %d,", (val >> 7) & 0x01); switch ((val >> 4) & 0x07) { case 0x00: - printk(" VITERBI CODERATE: 1/2,"); + pr_cont(" VITERBI CODERATE: 1/2,"); break; case 0x01: - printk(" VITERBI CODERATE: 2/3,"); + pr_cont(" VITERBI CODERATE: 2/3,"); break; case 0x02: - printk(" VITERBI CODERATE: 3/4,"); + pr_cont(" VITERBI CODERATE: 3/4,"); break; case 0x03: - printk(" VITERBI CODERATE: 5/6,"); + pr_cont(" VITERBI CODERATE: 5/6,"); break; case 0x04: - printk(" VITERBI CODERATE: 7/8,"); + pr_cont(" VITERBI CODERATE: 7/8,"); break; default: - printk(" VITERBI CODERATE: Reserved,"); + pr_cont(" VITERBI CODERATE: Reserved,"); } val = nxt6000_readreg(state, OFDM_COR_STAT); - printk(" CHCTrack: %d,", (val >> 7) & 0x01); - printk(" TPSLock: %d,", (val >> 6) & 0x01); - printk(" SYRLock: %d,", (val >> 5) & 0x01); - printk(" AGCLock: %d,", (val >> 4) & 0x01); + pr_cont(" CHCTrack: %d,", (val >> 7) & 0x01); + pr_cont(" TPSLock: %d,", (val >> 6) & 0x01); + pr_cont(" SYRLock: %d,", (val >> 5) & 0x01); + pr_cont(" AGCLock: %d,", (val >> 4) & 0x01); switch (val & 0x0F) { case 0x00: - printk(" CoreState: IDLE,"); + pr_cont(" CoreState: IDLE,"); break; case 0x02: - printk(" CoreState: WAIT_AGC,"); + pr_cont(" CoreState: WAIT_AGC,"); break; case 0x03: - printk(" CoreState: WAIT_SYR,"); + pr_cont(" CoreState: WAIT_SYR,"); break; case 0x04: - printk(" CoreState: WAIT_PPM,"); + pr_cont(" CoreState: WAIT_PPM,"); break; case 0x01: - printk(" CoreState: WAIT_TRL,"); + pr_cont(" CoreState: WAIT_TRL,"); break; case 0x05: - printk(" CoreState: WAIT_TPS,"); + pr_cont(" CoreState: WAIT_TPS,"); break; case 0x06: - printk(" CoreState: MONITOR_TPS,"); + pr_cont(" CoreState: MONITOR_TPS,"); break; default: - printk(" CoreState: Reserved,"); + pr_cont(" CoreState: Reserved,"); } val = nxt6000_readreg(state, OFDM_SYR_STAT); - printk(" SYRLock: %d,", (val >> 4) & 0x01); - printk(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K"); + pr_cont(" SYRLock: %d,", (val >> 4) & 0x01); + pr_cont(" SYRMode: %s,", (val >> 2) & 0x01 ? "8K" : "2K"); switch ((val >> 4) & 0x03) { case 0x00: - printk(" SYRGuard: 1/32,"); + pr_cont(" SYRGuard: 1/32,"); break; case 0x01: - printk(" SYRGuard: 1/16,"); + pr_cont(" SYRGuard: 1/16,"); break; case 0x02: - printk(" SYRGuard: 1/8,"); + pr_cont(" SYRGuard: 1/8,"); break; case 0x03: - printk(" SYRGuard: 1/4,"); + pr_cont(" SYRGuard: 1/4,"); break; } @@ -336,77 +352,77 @@ static void nxt6000_dump_status(struct nxt6000_state *state) switch ((val >> 4) & 0x07) { case 0x00: - printk(" TPSLP: 1/2,"); + pr_cont(" TPSLP: 1/2,"); break; case 0x01: - printk(" TPSLP: 2/3,"); + pr_cont(" TPSLP: 2/3,"); break; case 0x02: - printk(" TPSLP: 3/4,"); + pr_cont(" TPSLP: 3/4,"); break; case 0x03: - printk(" TPSLP: 5/6,"); + pr_cont(" TPSLP: 5/6,"); break; case 0x04: - printk(" TPSLP: 7/8,"); + pr_cont(" TPSLP: 7/8,"); break; default: - printk(" TPSLP: Reserved,"); + pr_cont(" TPSLP: Reserved,"); } switch (val & 0x07) { case 0x00: - printk(" TPSHP: 1/2,"); + pr_cont(" TPSHP: 1/2,"); break; case 0x01: - printk(" TPSHP: 2/3,"); + pr_cont(" TPSHP: 2/3,"); break; case 0x02: - printk(" TPSHP: 3/4,"); + pr_cont(" TPSHP: 3/4,"); break; case 0x03: - printk(" TPSHP: 5/6,"); + pr_cont(" TPSHP: 5/6,"); break; case 0x04: - printk(" TPSHP: 7/8,"); + pr_cont(" TPSHP: 7/8,"); break; default: - printk(" TPSHP: Reserved,"); + pr_cont(" TPSHP: Reserved,"); } val = nxt6000_readreg(state, OFDM_TPS_RCVD_4); - printk(" TPSMode: %s,", val & 0x01 ? "8K" : "2K"); + pr_cont(" TPSMode: %s,", val & 0x01 ? "8K" : "2K"); switch ((val >> 4) & 0x03) { case 0x00: - printk(" TPSGuard: 1/32,"); + pr_cont(" TPSGuard: 1/32,"); break; case 0x01: - printk(" TPSGuard: 1/16,"); + pr_cont(" TPSGuard: 1/16,"); break; case 0x02: - printk(" TPSGuard: 1/8,"); + pr_cont(" TPSGuard: 1/8,"); break; case 0x03: - printk(" TPSGuard: 1/4,"); + pr_cont(" TPSGuard: 1/4,"); break; } @@ -416,8 +432,8 @@ static void nxt6000_dump_status(struct nxt6000_state *state) val = nxt6000_readreg(state, RF_AGC_STATUS); val = nxt6000_readreg(state, RF_AGC_STATUS); - printk(" RF AGC LOCK: %d,", (val >> 4) & 0x01); - printk("\n"); + pr_cont(" RF AGC LOCK: %d,", (val >> 4) & 0x01); + pr_cont("\n"); } static int nxt6000_read_status(struct dvb_frontend *fe, enum fe_status *status) -- cgit v1.2.3 From d9942ad0228a7e1a46a24f7962cb790443042da3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:00 -0200 Subject: [media] b2c2: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/b2c2/flexcop-eeprom.c | 3 +-- drivers/media/common/b2c2/flexcop-i2c.c | 4 ++-- drivers/media/common/b2c2/flexcop-misc.c | 9 +++------ drivers/media/common/b2c2/flexcop.c | 3 +-- 4 files changed, 7 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/b2c2/flexcop-eeprom.c b/drivers/media/common/b2c2/flexcop-eeprom.c index a25373a9bd84..844c7836c2a6 100644 --- a/drivers/media/common/b2c2/flexcop-eeprom.c +++ b/drivers/media/common/b2c2/flexcop-eeprom.c @@ -136,8 +136,7 @@ int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended) if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) { if (extended != 0) { - err("TODO: extended (EUI64) MAC addresses aren't " - "completely supported yet"); + err("TODO: extended (EUI64) MAC addresses aren't completely supported yet"); ret = -EINVAL; } else memcpy(fc->dvb_adapter.proposed_mac,buf,6); diff --git a/drivers/media/common/b2c2/flexcop-i2c.c b/drivers/media/common/b2c2/flexcop-i2c.c index e41cd23f8e45..58d39a59fc09 100644 --- a/drivers/media/common/b2c2/flexcop-i2c.c +++ b/drivers/media/common/b2c2/flexcop-i2c.c @@ -33,8 +33,8 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, return -EREMOTEIO; } } - deb_i2c("tried %d times i2c operation, " - "never finished or too many ack errors.\n", i); + deb_i2c("tried %d times i2c operation, never finished or too many ack errors.\n", + i); return -EREMOTEIO; } diff --git a/drivers/media/common/b2c2/flexcop-misc.c b/drivers/media/common/b2c2/flexcop-misc.c index b8eff235367d..bb0d95fe64f9 100644 --- a/drivers/media/common/b2c2/flexcop-misc.c +++ b/drivers/media/common/b2c2/flexcop-misc.c @@ -23,18 +23,15 @@ void flexcop_determine_revision(struct flexcop_device *fc) fc->rev = FLEXCOP_III; break; default: - err("unknown FlexCop Revision: %x. Please report this to " - "linux-dvb@linuxtv.org.", + err("unknown FlexCop Revision: %x. Please report this to linux-dvb@linuxtv.org.", v.misc_204.Rev_N_sig_revision_hi); break; } if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps)) - deb_info("this FlexCop has " - "the additional 32 hardware pid filter.\n"); + deb_info("this FlexCop has the additional 32 hardware pid filter.\n"); else - deb_info("this FlexCop has " - "the 6 basic main hardware pid filter.\n"); + deb_info("this FlexCop has the 6 basic main hardware pid filter.\n"); /* bus parts have to decide if hw pid filtering is used or not. */ } diff --git a/drivers/media/common/b2c2/flexcop.c b/drivers/media/common/b2c2/flexcop.c index 0f5114d406f8..4338ab0043b4 100644 --- a/drivers/media/common/b2c2/flexcop.c +++ b/drivers/media/common/b2c2/flexcop.c @@ -46,8 +46,7 @@ int b2c2_flexcop_debug; EXPORT_SYMBOL_GPL(b2c2_flexcop_debug); module_param_named(debug, b2c2_flexcop_debug, int, 0644); MODULE_PARM_DESC(debug, - "set debug level (1=info,2=tuner,4=i2c,8=ts," - "16=sram,32=reg (|-able))." + "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS); #undef DEBSTATUS -- cgit v1.2.3 From 72cc0671b0fad38891f134afa069f38dc74f39b9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:01 -0200 Subject: [media] cx25840: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/cx25840/cx25840-core.c | 11 +++-------- drivers/media/i2c/cx25840/cx25840-ir.c | 7 +++---- 2 files changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c index 142ae28803bb..0dcf450052ac 100644 --- a/drivers/media/i2c/cx25840/cx25840-core.c +++ b/drivers/media/i2c/cx25840/cx25840-core.c @@ -873,10 +873,7 @@ void cx25840_std_setup(struct i2c_client *client) "Chroma sub-carrier freq = %d.%06d MHz\n", fsc / 1000000, fsc % 1000000); - v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, " - "vblank %i, vactive %i, vblank656 %i, src_dec %i, " - "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, " - "sc 0x%06x\n", + v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n", hblank, hactive, vblank, vactive, vblank656, src_decimation, burst, luma_lpf, uv_lpf, comb, sc); } @@ -5169,11 +5166,9 @@ static int cx25840_probe(struct i2c_client *client, id = CX2310X_AV; } else if ((device_id & 0xff) == (device_id >> 8)) { v4l_err(client, - "likely a confused/unresponsive cx2388[578] A/V decoder" - " found @ 0x%x (%s)\n", + "likely a confused/unresponsive cx2388[578] A/V decoder found @ 0x%x (%s)\n", client->addr << 1, client->adapter->name); - v4l_err(client, "A method to reset it from the cx25840 driver" - " software is not known at this time\n"); + v4l_err(client, "A method to reset it from the cx25840 driver software is not known at this time\n"); return -ENODEV; } else { v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n"); diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c index 4b782012cadc..15fbd9607cee 100644 --- a/drivers/media/i2c/cx25840/cx25840-ir.c +++ b/drivers/media/i2c/cx25840/cx25840-ir.c @@ -1113,8 +1113,8 @@ int cx25840_ir_log_status(struct v4l2_subdev *sd) j = 0; break; } - v4l2_info(sd, "\tNext carrier edge window: 16 clocks " - "-%1d/+%1d, %u to %u Hz\n", i, j, + v4l2_info(sd, "\tNext carrier edge window: 16 clocks -%1d/+%1d, %u to %u Hz\n", + i, j, clock_divider_to_freq(rxclk, 16 + j), clock_divider_to_freq(rxclk, 16 - i)); } @@ -1124,8 +1124,7 @@ int cx25840_ir_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "\tLow pass filter: %s\n", filtr ? "enabled" : "disabled"); if (filtr) - v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " - "%u ns\n", + v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, %u ns\n", lpf_count_to_us(filtr), lpf_count_to_ns(filtr)); v4l2_info(sd, "\tPulse width timer timed-out: %s\n", -- cgit v1.2.3 From 4b68f05e4d607c596288d2c81bdf196a4950ce6c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:01 -0200 Subject: [media] smiapp: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Acked-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-regs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c index 1e501c06d18c..d6779e35d36f 100644 --- a/drivers/media/i2c/smiapp/smiapp-regs.c +++ b/drivers/media/i2c/smiapp/smiapp-regs.c @@ -268,8 +268,8 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val) if (r == 1) { if (retries) dev_err(&client->dev, - "sensor i2c stall encountered. " - "retries: %d\n", retries); + "sensor i2c stall encountered. retries: %d\n", + retries); return 0; } -- cgit v1.2.3 From 8f44c3925139fc2fc1ccae6b2a9dcd51215fb16b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:01 -0200 Subject: [media] soc_camera: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/soc_camera/ov772x.c | 3 +-- drivers/media/i2c/soc_camera/ov9740.c | 3 +-- drivers/media/i2c/soc_camera/tw9910.c | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c index 7e68762b3a4b..985a3672b243 100644 --- a/drivers/media/i2c/soc_camera/ov772x.c +++ b/drivers/media/i2c/soc_camera/ov772x.c @@ -1064,8 +1064,7 @@ static int ov772x_probe(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&adapter->dev, - "I2C-Adapter doesn't support " - "I2C_FUNC_SMBUS_BYTE_DATA\n"); + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n"); return -EIO; } diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c index 0da632d7d33a..f11f76cdacad 100644 --- a/drivers/media/i2c/soc_camera/ov9740.c +++ b/drivers/media/i2c/soc_camera/ov9740.c @@ -881,8 +881,7 @@ static int ov9740_video_probe(struct i2c_client *client) goto done; } - dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, " - "Manufacturer 0x%02x, SMIA Version 0x%02x\n", + dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, Manufacturer 0x%02x, SMIA Version 0x%02x\n", priv->model, priv->revision, priv->manid, priv->smiaver); ret = v4l2_ctrl_handler_setup(&priv->hdl); diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c index 4002c07f3857..c9c49ed707b8 100644 --- a/drivers/media/i2c/soc_camera/tw9910.c +++ b/drivers/media/i2c/soc_camera/tw9910.c @@ -947,8 +947,7 @@ static int tw9910_probe(struct i2c_client *client, if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { dev_err(&client->dev, - "I2C-Adapter doesn't support " - "I2C_FUNC_SMBUS_BYTE_DATA\n"); + "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n"); return -EIO; } -- cgit v1.2.3 From d6376f0e64b19e55a6c7f3e5bd6648fd1f87e1f2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:02 -0200 Subject: [media] b2c2: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/b2c2/flexcop-dma.c | 6 ++---- drivers/media/pci/b2c2/flexcop-pci.c | 7 +++---- 2 files changed, 5 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/b2c2/flexcop-dma.c b/drivers/media/pci/b2c2/flexcop-dma.c index 2881e0d956ad..913dc97f8b49 100644 --- a/drivers/media/pci/b2c2/flexcop-dma.c +++ b/drivers/media/pci/b2c2/flexcop-dma.c @@ -57,8 +57,7 @@ int flexcop_dma_config(struct flexcop_device *fc, fc->write_ibi_reg(fc,dma2_014,v0x4); fc->write_ibi_reg(fc,dma2_01c,v0xc); } else { - err("either DMA1 or DMA2 can be configured within one " - "flexcop_dma_config call."); + err("either DMA1 or DMA2 can be configured within one flexcop_dma_config call."); return -EINVAL; } @@ -82,8 +81,7 @@ int flexcop_dma_xfer_control(struct flexcop_device *fc, r0x0 = dma2_010; r0xc = dma2_01c; } else { - err("either transfer DMA1 or DMA2 can be started within one " - "flexcop_dma_xfer_control call."); + err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call."); return -EINVAL; } diff --git a/drivers/media/pci/b2c2/flexcop-pci.c b/drivers/media/pci/b2c2/flexcop-pci.c index 4cac1fc233f2..99ce28442a75 100644 --- a/drivers/media/pci/b2c2/flexcop-pci.c +++ b/drivers/media/pci/b2c2/flexcop-pci.c @@ -185,8 +185,7 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2; u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0; - deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, " - "last_cur_pos: %08x ", + deb_irq("%u irq: %08x cur_addr: %llx: cur_pos: %08x, last_cur_pos: %08x ", jiffies_to_usecs(jiffies - fc_pci->last_irq), v.raw, (unsigned long long)cur_addr, cur_pos, fc_pci->last_dma1_cur_pos); @@ -220,8 +219,8 @@ static irqreturn_t flexcop_pci_isr(int irq, void *dev_id) fc_pci->last_dma1_cur_pos = cur_pos; fc_pci->count++; } else { - deb_irq("isr for flexcop called, " - "apparently without reason (%08x)\n", v.raw); + deb_irq("isr for flexcop called, apparently without reason (%08x)\n", + v.raw); ret = IRQ_NONE; } -- cgit v1.2.3 From 652fd6eaebc7ff2b268ca905e6aec5bd001b1b16 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:02 -0200 Subject: [media] bt8xx: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/bttv-cards.c | 9 +++------ drivers/media/pci/bt8xx/bttv-driver.c | 6 ++---- drivers/media/pci/bt8xx/bttv-i2c.c | 6 ++---- drivers/media/pci/bt8xx/bttv-input.c | 4 ++-- 4 files changed, 9 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c index 8a17cc0bfa07..a1b0f3193bc0 100644 --- a/drivers/media/pci/bt8xx/bttv-cards.c +++ b/drivers/media/pci/bt8xx/bttv-cards.c @@ -125,10 +125,8 @@ module_param_array(remote, int, NULL, 0444); module_param_array(audiodev, int, NULL, 0444); module_param_array(audiomux, int, NULL, 0444); -MODULE_PARM_DESC(triton1,"set ETBF pci config bit " - "[enable bug compatibility for triton1 + others]"); -MODULE_PARM_DESC(vsfx,"set VSFX pci config bit " - "[yet another chipset flaw workaround]"); +MODULE_PARM_DESC(triton1, "set ETBF pci config bit [enable bug compatibility for triton1 + others]"); +MODULE_PARM_DESC(vsfx, "set VSFX pci config bit [yet another chipset flaw workaround]"); MODULE_PARM_DESC(latency,"pci latency timer"); MODULE_PARM_DESC(card,"specify TV/grabber card model, see CARDLIST file for a list"); MODULE_PARM_DESC(pll, "specify installed crystal (0=none, 28=28 MHz, 35=35 MHz, 14=14 MHz)"); @@ -141,8 +139,7 @@ MODULE_PARM_DESC(audiodev, "specify audio device:\n" "\t\t 2 = tda7432\n" "\t\t 3 = tvaudio"); MODULE_PARM_DESC(saa6588, "if 1, then load the saa6588 RDS module, default (0) is to use the card definition."); -MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" - " [some VIA/SIS chipsets are known to have problem with overlay]"); +MODULE_PARM_DESC(no_overlay, "allow override overlay default (0 disables, 1 enables) [some VIA/SIS chipsets are known to have problem with overlay]"); /* ----------------------------------------------------------------------- */ /* list of card IDs for bt878+ cards */ diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c index 97b91a9f9fa9..fb4aefbcc8f8 100644 --- a/drivers/media/pci/bt8xx/bttv-driver.c +++ b/drivers/media/pci/bt8xx/bttv-driver.c @@ -148,8 +148,7 @@ MODULE_PARM_DESC(irq_debug, "irq handler debug messages, default is 0 (no)"); MODULE_PARM_DESC(disable_ir, "disable infrared remote support"); MODULE_PARM_DESC(gbuffers, "number of capture buffers. range 2-32, default 8"); MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 0x208000"); -MODULE_PARM_DESC(reset_crop, "reset cropping parameters at open(), default " - "is 1 (yes) for compatibility with older applications"); +MODULE_PARM_DESC(reset_crop, "reset cropping parameters at open(), default is 1 (yes) for compatibility with older applications"); MODULE_PARM_DESC(automute, "mute audio on bad/missing video signal, default is 1 (yes)"); MODULE_PARM_DESC(chroma_agc, "enables the AGC of chroma signal, default is 0 (no)"); MODULE_PARM_DESC(agc_crush, "enables the luminance AGC crush, default is 1 (yes)"); @@ -3506,8 +3505,7 @@ static void bttv_irq_debug_low_latency(struct bttv *btv, u32 rc) (unsigned long)rc); if (0 == (btread(BT848_DSTATUS) & BT848_DSTATUS_HLOC)) { - pr_notice("%d: Oh, there (temporarily?) is no input signal. " - "Ok, then this is harmless, don't worry ;)\n", + pr_notice("%d: Oh, there (temporarily?) is no input signal. Ok, then this is harmless, don't worry ;)\n", btv->c.nr); return; } diff --git a/drivers/media/pci/bt8xx/bttv-i2c.c b/drivers/media/pci/bt8xx/bttv-i2c.c index d43911deb617..274fd036b306 100644 --- a/drivers/media/pci/bt8xx/bttv-i2c.c +++ b/drivers/media/pci/bt8xx/bttv-i2c.c @@ -44,15 +44,13 @@ static int i2c_scan; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "configure i2c debug level"); module_param(i2c_hw, int, 0444); -MODULE_PARM_DESC(i2c_hw,"force use of hardware i2c support, " - "instead of software bitbang"); +MODULE_PARM_DESC(i2c_hw, "force use of hardware i2c support, instead of software bitbang"); module_param(i2c_scan, int, 0444); MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); static unsigned int i2c_udelay = 5; module_param(i2c_udelay, int, 0444); -MODULE_PARM_DESC(i2c_udelay,"soft i2c delay at insmod time, in usecs " - "(should be 5 or higher). Lower value means higher bus speed."); +MODULE_PARM_DESC(i2c_udelay, "soft i2c delay at insmod time, in usecs (should be 5 or higher). Lower value means higher bus speed."); /* ----------------------------------------------------------------------- */ /* I2C functions - bitbanging adapter (software i2c) */ diff --git a/drivers/media/pci/bt8xx/bttv-input.c b/drivers/media/pci/bt8xx/bttv-input.c index a75c53da224a..4da720e4867e 100644 --- a/drivers/media/pci/bt8xx/bttv-input.c +++ b/drivers/media/pci/bt8xx/bttv-input.c @@ -185,8 +185,8 @@ static u32 bttv_rc5_decode(unsigned int code) return 0; } } - dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, " - "instr=%x\n", rc5, org_code, RC5_START(rc5), + dprintk("code=%x, rc5=%x, start=%x, toggle=%x, address=%x, instr=%x\n", + rc5, org_code, RC5_START(rc5), RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5)); return rc5; } -- cgit v1.2.3 From 6beb1388a0b5730337360818d9385808e50aa870 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:03 -0200 Subject: [media] cx18: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx18/cx18-alsa-main.c | 8 +++---- drivers/media/pci/cx18/cx18-av-core.c | 17 ++++++-------- drivers/media/pci/cx18/cx18-av-firmware.c | 3 +-- drivers/media/pci/cx18/cx18-controls.c | 9 +++---- drivers/media/pci/cx18/cx18-driver.c | 35 ++++++++++++--------------- drivers/media/pci/cx18/cx18-dvb.c | 6 ++--- drivers/media/pci/cx18/cx18-fileops.c | 6 ++--- drivers/media/pci/cx18/cx18-ioctl.c | 6 ++--- drivers/media/pci/cx18/cx18-irq.c | 4 ++-- drivers/media/pci/cx18/cx18-mailbox.c | 39 +++++++++++-------------------- drivers/media/pci/cx18/cx18-queue.c | 8 +++---- drivers/media/pci/cx18/cx18-streams.c | 7 +++--- 12 files changed, 58 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c index 0b0e8015ad34..9fb7f5978c8b 100644 --- a/drivers/media/pci/cx18/cx18-alsa-main.c +++ b/drivers/media/pci/cx18/cx18-alsa-main.c @@ -217,8 +217,8 @@ static int cx18_alsa_load(struct cx18 *cx) s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; if (s->video_dev.v4l2_dev == NULL) { - CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " - "skipping\n", __func__); + CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - skipping\n", + __func__); return 0; } @@ -232,8 +232,8 @@ static int cx18_alsa_load(struct cx18 *cx) CX18_ALSA_ERR("%s: failed to create struct snd_cx18_card\n", __func__); } else { - CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance " - "\n", __func__); + CX18_DEBUG_ALSA_INFO("%s: created cx18 ALSA interface instance\n", + __func__); } return 0; } diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c index 30bbe8d1ea55..7f7306fd9a7f 100644 --- a/drivers/media/pci/cx18/cx18-av-core.c +++ b/drivers/media/pci/cx18/cx18-av-core.c @@ -468,21 +468,19 @@ void cx18_av_std_setup(struct cx18 *cx) CX18_DEBUG_INFO_DEV(sd, "Pixel rate = %d.%06d Mpixel/sec\n", pll / 8000000, (pll / 8) % 1000000); - CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio " - "= %d.%03d\n", src_decimation / 256, + CX18_DEBUG_INFO_DEV(sd, "ADC XTAL/pixel clock decimation ratio = %d.%03d\n", + src_decimation / 256, ((src_decimation % 256) * 1000) / 256); tmp = 28636360 * (u64) sc; do_div(tmp, src_decimation); fsc = tmp >> 13; CX18_DEBUG_INFO_DEV(sd, - "Chroma sub-carrier initial freq = %d.%06d " - "MHz\n", fsc / 1000000, fsc % 1000000); + "Chroma sub-carrier initial freq = %d.%06d MHz\n", + fsc / 1000000, fsc % 1000000); - CX18_DEBUG_INFO_DEV(sd, "hblank %i, hactive %i, vblank %i, " - "vactive %i, vblank656 %i, src_dec %i, " - "burst 0x%02x, luma_lpf %i, uv_lpf %i, " - "comb 0x%02x, sc 0x%06x\n", + CX18_DEBUG_INFO_DEV(sd, + "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n", hblank, hactive, vblank, vactive, vblank656, src_decimation, burst, luma_lpf, uv_lpf, comb, sc); @@ -1069,8 +1067,7 @@ static void log_video_status(struct cx18 *cx) CX18_INFO_DEV(sd, "Specified video input: Composite %d\n", vid_input - CX18_AV_COMPOSITE1 + 1); } else { - CX18_INFO_DEV(sd, "Specified video input: " - "S-Video (Luma In%d, Chroma In%d)\n", + CX18_INFO_DEV(sd, "Specified video input: S-Video (Luma In%d, Chroma In%d)\n", (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8); } diff --git a/drivers/media/pci/cx18/cx18-av-firmware.c b/drivers/media/pci/cx18/cx18-av-firmware.c index a34fd082b76e..160e2e53383f 100644 --- a/drivers/media/pci/cx18/cx18-av-firmware.c +++ b/drivers/media/pci/cx18/cx18-av-firmware.c @@ -61,8 +61,7 @@ static int cx18_av_verifyfw(struct cx18 *cx, const struct firmware *fw) dl_control &= 0xffff3fff; /* ignore top 2 bits of address */ expected = 0x0f000000 | ((u32)data[addr] << 16) | addr; if (expected != dl_control) { - CX18_ERR_DEV(sd, "verification of %s firmware load " - "failed: expected %#010x got %#010x\n", + CX18_ERR_DEV(sd, "verification of %s firmware load failed: expected %#010x got %#010x\n", FWFILE, expected, dl_control); ret = -EIO; break; diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c index adb5a8c72c06..812a2507945a 100644 --- a/drivers/media/pci/cx18/cx18-controls.c +++ b/drivers/media/pci/cx18/cx18-controls.c @@ -44,8 +44,7 @@ static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) type == V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD)) { /* Only IVTV fmt VBI insertion & only MPEG-2 PS type streams */ cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; - CX18_DEBUG_INFO("disabled insertion of sliced VBI data into " - "the MPEG stream\n"); + CX18_DEBUG_INFO("disabled insertion of sliced VBI data into the MPEG stream\n"); return 0; } @@ -63,16 +62,14 @@ static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt) } cx->vbi.insert_mpeg = V4L2_MPEG_STREAM_VBI_FMT_NONE; - CX18_WARN("Unable to allocate buffers for " - "sliced VBI data insertion\n"); + CX18_WARN("Unable to allocate buffers for sliced VBI data insertion\n"); return -ENOMEM; } } } cx->vbi.insert_mpeg = fmt; - CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS," - "when sliced VBI is enabled\n"); + CX18_DEBUG_INFO("enabled insertion of sliced VBI data into the MPEG PS,when sliced VBI is enabled\n"); /* * If our current settings have no lines set for capture, store a valid, diff --git a/drivers/media/pci/cx18/cx18-driver.c b/drivers/media/pci/cx18/cx18-driver.c index 2f23b26b16c0..b8eedbe51c8f 100644 --- a/drivers/media/pci/cx18/cx18-driver.c +++ b/drivers/media/pci/cx18/cx18-driver.c @@ -405,8 +405,8 @@ static void cx18_process_eeprom(struct cx18 *cx) CX18_ERR("Invalid EEPROM\n"); return; default: - CX18_ERR("Unknown model %d, defaulting to original HVR-1600 " - "(cardtype=1)\n", tv.model); + CX18_ERR("Unknown model %d, defaulting to original HVR-1600 (cardtype=1)\n", + tv.model); cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT); break; } @@ -635,8 +635,8 @@ static void cx18_process_options(struct cx18 *cx) /* convert from kB to bytes */ cx->stream_buf_size[i] *= 1024; } - CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, " - "%d bytes\n", i, cx->options.megabytes[i], + CX18_DEBUG_INFO("Stream type %d options: %d MB, %d buffers, %d bytes\n", + i, cx->options.megabytes[i], cx->stream_buffers[i], cx->stream_buf_size[i]); } @@ -838,14 +838,13 @@ static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *pci_dev, pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 64 && cx18_pci_latency) { - CX18_INFO("Unreasonably low latency timer, " - "setting to 64 (was %d)\n", pci_latency); + CX18_INFO("Unreasonably low latency timer, setting to 64 (was %d)\n", + pci_latency); pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, 64); pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &pci_latency); } - CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, " - "irq: %d, latency: %d, memory: 0x%llx\n", + CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, irq: %d, latency: %d, memory: 0x%llx\n", cx->pci_dev->device, cx->card_rev, pci_dev->bus->number, PCI_SLOT(pci_dev->devfn), PCI_FUNC(pci_dev->devfn), cx->pci_dev->irq, pci_latency, (u64)cx->base_addr); @@ -910,8 +909,8 @@ static int cx18_probe(struct pci_dev *pci_dev, /* FIXME - module parameter arrays constrain max instances */ i = atomic_inc_return(&cx18_instance) - 1; if (i >= CX18_MAX_CARDS) { - printk(KERN_ERR "cx18: cannot manage card %d, driver has a " - "limit of 0 - %d\n", i, CX18_MAX_CARDS - 1); + printk(KERN_ERR "cx18: cannot manage card %d, driver has a limit of 0 - %d\n", + i, CX18_MAX_CARDS - 1); return -ENOMEM; } @@ -926,8 +925,8 @@ static int cx18_probe(struct pci_dev *pci_dev, retval = v4l2_device_register(&pci_dev->dev, &cx->v4l2_dev); if (retval) { - printk(KERN_ERR "cx18: v4l2_device_register of card %d failed" - "\n", cx->instance); + printk(KERN_ERR "cx18: v4l2_device_register of card %d failed\n", + cx->instance); kfree(cx); return retval; } @@ -958,13 +957,10 @@ static int cx18_probe(struct pci_dev *pci_dev, cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE); if (!cx->enc_mem) { - CX18_ERR("ioremap failed. Can't get a window into CX23418 " - "memory and register space\n"); - CX18_ERR("Each capture card with a CX23418 needs 64 MB of " - "vmalloc address space for the window\n"); + CX18_ERR("ioremap failed. Can't get a window into CX23418 memory and register space\n"); + CX18_ERR("Each capture card with a CX23418 needs 64 MB of vmalloc address space for the window\n"); CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); - CX18_ERR("Use the vmalloc= kernel command line option to set " - "VmallocTotal to a larger value\n"); + CX18_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); retval = -ENOMEM; goto free_mem; } @@ -1000,8 +996,7 @@ static int cx18_probe(struct pci_dev *pci_dev, /* Initialize GPIO Reset Controller to do chip resets during i2c init */ if (cx->card->hw_all & CX18_HW_GPIO_RESET_CTRL) { if (cx18_gpio_register(cx, CX18_HW_GPIO_RESET_CTRL) != 0) - CX18_WARN("Could not register GPIO reset controller" - "subdevice; proceeding anyway.\n"); + CX18_WARN("Could not register GPIO reset controllersubdevice; proceeding anyway.\n"); else cx->hw_flags |= CX18_HW_GPIO_RESET_CTRL; } diff --git a/drivers/media/pci/cx18/cx18-dvb.c b/drivers/media/pci/cx18/cx18-dvb.c index 3eac59c51231..03d0478170a7 100644 --- a/drivers/media/pci/cx18/cx18-dvb.c +++ b/drivers/media/pci/cx18/cx18-dvb.c @@ -155,10 +155,8 @@ static int yuan_mpc718_mt352_reqfw(struct cx18_stream *stream, } if (ret) { - CX18_ERR("The MPC718 board variant with the MT352 DVB-T" - "demodualtor will not work without it\n"); - CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware " - "mpc718' if you need the firmware\n"); + CX18_ERR("The MPC718 board variant with the MT352 DVB-Tdemodualtor will not work without it\n"); + CX18_ERR("Run 'linux/Documentation/dvb/get_dvb_firmware mpc718' if you need the firmware\n"); } return ret; } diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index df837408efd5..78b399b8613e 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -49,8 +49,7 @@ int cx18_claim_stream(struct cx18_open_id *id, int type) /* Nothing should ever try to directly claim the IDX stream */ if (type == CX18_ENC_STREAM_TYPE_IDX) { - CX18_WARN("MPEG Index stream cannot be claimed " - "directly, but something tried.\n"); + CX18_WARN("MPEG Index stream cannot be claimed directly, but something tried.\n"); return -EINVAL; } @@ -728,8 +727,7 @@ void cx18_stop_capture(struct cx18_open_id *id, int gop_end) /* Stop internal use associated VBI and IDX streams */ if (test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) && !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) { - CX18_DEBUG_INFO("close stopping embedded VBI " - "capture\n"); + CX18_DEBUG_INFO("close stopping embedded VBI capture\n"); cx18_stop_v4l2_encode_stream(s_vbi, 0); } if (test_bit(CX18_F_S_STREAMING, &s_idx->s_flags)) { diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index fecca2a63891..0faeb979ceb9 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -951,8 +951,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh, return 0; h = cx18_find_handle(cx); if (h == CX18_INVALID_TASK_HANDLE) { - CX18_ERR("Can't find valid task handle for " - "V4L2_ENC_CMD_PAUSE\n"); + CX18_ERR("Can't find valid task handle for V4L2_ENC_CMD_PAUSE\n"); return -EBADFD; } cx18_mute(cx); @@ -968,8 +967,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh, return 0; h = cx18_find_handle(cx); if (h == CX18_INVALID_TASK_HANDLE) { - CX18_ERR("Can't find valid task handle for " - "V4L2_ENC_CMD_RESUME\n"); + CX18_ERR("Can't find valid task handle for V4L2_ENC_CMD_RESUME\n"); return -EBADFD; } cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, h); diff --git a/drivers/media/pci/cx18/cx18-irq.c b/drivers/media/pci/cx18/cx18-irq.c index 80edfe93a3d8..361426485e98 100644 --- a/drivers/media/pci/cx18/cx18-irq.c +++ b/drivers/media/pci/cx18/cx18-irq.c @@ -59,8 +59,8 @@ irqreturn_t cx18_irq_handler(int irq, void *dev_id) cx18_write_reg_expect(cx, hw2, HW2_INT_CLR_STATUS, ~hw2, hw2); if (sw1 || sw2 || hw2) - CX18_DEBUG_HI_IRQ("received interrupts " - "SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2); + CX18_DEBUG_HI_IRQ("received interrupts SW1: %x SW2: %x HW2: %x\n", + sw1, sw2, hw2); /* * SW1 responses have to happen first. The sending XPU times out the diff --git a/drivers/media/pci/cx18/cx18-mailbox.c b/drivers/media/pci/cx18/cx18-mailbox.c index 1f8aa9a749a1..d3cf3588879f 100644 --- a/drivers/media/pci/cx18/cx18-mailbox.c +++ b/drivers/media/pci/cx18/cx18-mailbox.c @@ -123,8 +123,8 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name) if (!(cx18_debug & CX18_DBGFLG_API)) return; - CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s" - "\n", name, mb->request, mb->ack, mb->cmd, mb->error, + CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s\n", + name, mb->request, mb->ack, mb->cmd, mb->error, u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); } @@ -255,8 +255,8 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) s = cx18_handle_to_stream(cx, handle); if (s == NULL) { - CX18_WARN("Got DMA done notification for unknown/inactive" - " handle %d, %s mailbox seq no %d\n", handle, + CX18_WARN("Got DMA done notification for unknown/inactive handle %d, %s mailbox seq no %d\n", + handle, (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? "stale" : "good", mb->request); return; @@ -290,9 +290,8 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order) if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && !(id >= s->mdl_base_idx && id < (s->mdl_base_idx + s->buffers))) { - CX18_WARN("Fell behind! Ignoring stale mailbox with " - " inconsistent data. Lost MDL for mailbox " - "seq no %d\n", mb->request); + CX18_WARN("Fell behind! Ignoring stale mailbox with inconsistent data. Lost MDL for mailbox seq no %d\n", + mb->request); break; } mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); @@ -418,9 +417,7 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order) /* Don't ack if the RPU has gotten impatient and timed us out */ if (req != cx18_readl(cx, &ack_mb->request) || req == cx18_readl(cx, &ack_mb->ack)) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u) " - "while processing\n", + CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our incoming %s to EPU mailbox (sequence no. %u) while processing\n", rpu_str[order->rpu], rpu_str[order->rpu], req); order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; return; @@ -555,8 +552,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) order = alloc_in_work_order_irq(cx); if (order == NULL) { - CX18_WARN("Unable to find blank work order form to schedule " - "incoming mailbox command processing\n"); + CX18_WARN("Unable to find blank work order form to schedule incoming mailbox command processing\n"); return; } @@ -573,9 +569,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu) (&order_mb->request)[i] = cx18_readl(cx, &mb->request + i); if (order_mb->request == order_mb->ack) { - CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our " - "incoming %s to EPU mailbox (sequence no. %u)" - "\n", + CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our incoming %s to EPU mailbox (sequence no. %u)\n", rpu_str[rpu], rpu_str[rpu], order_mb->request); if (cx18_debug & CX18_DBGFLG_WARN) dump_mb(cx, order_mb, "incoming"); @@ -663,8 +657,8 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) if (req != ack) { /* waited long enough, make the mbox "not busy" from our end */ cx18_writel(cx, req, &mb->ack); - CX18_ERR("mbox was found stuck busy when setting up for %s; " - "clearing busy and trying to proceed\n", info->name); + CX18_ERR("mbox was found stuck busy when setting up for %s; clearing busy and trying to proceed\n", + info->name); } else if (ret != timeout) CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", jiffies_to_msecs(timeout-ret)); @@ -707,14 +701,10 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) mutex_unlock(mb_lock); if (ret >= timeout) { /* Timed out */ - CX18_DEBUG_WARN("sending %s timed out waiting %d msecs " - "for RPU acknowledgement\n", + CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU acknowledgment\n", info->name, jiffies_to_msecs(ret)); } else { - CX18_DEBUG_WARN("woken up before mailbox ack was ready " - "after submitting %s to RPU. only " - "waited %d msecs on req %u but awakened" - " with unmatched ack %u\n", + CX18_DEBUG_WARN("woken up before mailbox ack was ready after submitting %s to RPU. only waited %d msecs on req %u but awakened with unmatched ack %u\n", info->name, jiffies_to_msecs(ret), req, ack); @@ -723,8 +713,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) } if (ret >= timeout) - CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment " - "sending %s; timed out waiting %d msecs\n", + CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment sending %s; timed out waiting %d msecs\n", info->name, jiffies_to_msecs(ret)); else CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", diff --git a/drivers/media/pci/cx18/cx18-queue.c b/drivers/media/pci/cx18/cx18-queue.c index 2a247d264b87..13e96d6055eb 100644 --- a/drivers/media/pci/cx18/cx18-queue.c +++ b/drivers/media/pci/cx18/cx18-queue.c @@ -164,9 +164,8 @@ struct cx18_mdl *cx18_queue_get_mdl(struct cx18_stream *s, u32 id, mdl->skipped++; if (mdl->skipped >= atomic_read(&s->q_busy.depth)-1) { /* mdl must have fallen out of rotation */ - CX18_WARN("Skipped %s, MDL %d, %d " - "times - it must have dropped out of " - "rotation\n", s->name, mdl->id, + CX18_WARN("Skipped %s, MDL %d, %d times - it must have dropped out of rotation\n", + s->name, mdl->id, mdl->skipped); /* Sweep it up to put it back into rotation */ list_move_tail(&mdl->list, &sweep_up); @@ -352,8 +351,7 @@ int cx18_stream_alloc(struct cx18_stream *s) if (s->buffers == 0) return 0; - CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers " - "(%d.%02d kB total)\n", + CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%d.%02d kB total)\n", s->name, s->buffers, s->buf_size, s->buffers * s->buf_size / 1024, (s->buffers * s->buf_size * 100 / 1024) % 100); diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index f3802ec1b383..7f699f0ee76c 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -353,8 +353,8 @@ static int cx18_prep_dev(struct cx18 *cx, int type) if (cx->card->hw_all & CX18_HW_DVB) { s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL); if (s->dvb == NULL) { - CX18_ERR("Couldn't allocate cx18_dvb structure" - " for %s\n", s->name); + CX18_ERR("Couldn't allocate cx18_dvb structure for %s\n", + s->name); return -ENOMEM; } } else { @@ -462,8 +462,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type) case VFL_TYPE_VBI: if (cx->stream_buffers[type]) - CX18_INFO("Registered device %s for %s " - "(%d x %d bytes)\n", + CX18_INFO("Registered device %s for %s (%d x %d bytes)\n", name, s->name, cx->stream_buffers[type], cx->stream_buf_size[type]); else -- cgit v1.2.3 From 07ab29e11696cf05c3563479bfc838c28a03d606 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:03 -0200 Subject: [media] cx23885: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cimax2.c | 7 ++----- drivers/media/pci/cx23885/cx23885-417.c | 18 +++++++----------- drivers/media/pci/cx23885/cx23885-alsa.c | 15 +++++++-------- drivers/media/pci/cx23885/cx23885-cards.c | 8 +++----- drivers/media/pci/cx23885/cx23885-core.c | 15 +++++++-------- drivers/media/pci/cx23885/cx23885-dvb.c | 3 +-- drivers/media/pci/cx23885/cx23885-video.c | 3 +-- drivers/media/pci/cx23885/cx23888-ir.c | 7 +++---- 8 files changed, 31 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index 631e4f24aea6..d644c65622e2 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -365,11 +365,8 @@ static void netup_read_ci_status(struct work_struct *work) if (ret != 0) return; - ci_dbg_print("%s: Slot Status Addr=[0x%04x], " - "Reg=[0x%02x], data=%02x, " - "TS config = %02x\n", __func__, - state->ci_i2c_addr, 0, buf[0], - buf[0]); + ci_dbg_print("%s: Slot Status Addr=[0x%04x], Reg=[0x%02x], data=%02x, TS config = %02x\n", + __func__, state->ci_i2c_addr, 0, buf[0], buf[0]); if (buf[0] & 1) diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index da892f3e3c29..0c122585a1f0 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -770,9 +770,8 @@ static int cx23885_mbox_func(void *priv, mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); if (value != 0x12345678) { printk(KERN_ERR - "Firmware and/or mailbox pointer not initialized " - "or corrupted, signature = 0x%x, cmd = %s\n", value, - cmd_to_str(command)); + "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n", + value, cmd_to_str(command)); return -1; } @@ -781,8 +780,8 @@ static int cx23885_mbox_func(void *priv, */ mc417_memory_read(dev, dev->cx23417_mailbox, &flag); if (flag) { - printk(KERN_ERR "ERROR: Mailbox appears to be in use " - "(%x), cmd = %s\n", flag, cmd_to_str(command)); + printk(KERN_ERR "ERROR: Mailbox appears to be in use (%x), cmd = %s\n", + flag, cmd_to_str(command)); return -1; } @@ -935,14 +934,12 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) printk(KERN_ERR "ERROR: Hotplug firmware request failed (%s).\n", CX23885_FIRM_IMAGE_NAME); - printk(KERN_ERR "Please fix your hotplug setup, the board will " - "not work without firmware loaded!\n"); + printk(KERN_ERR "Please fix your hotplug setup, the board will not work without firmware loaded!\n"); return -1; } if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { - printk(KERN_ERR "ERROR: Firmware size mismatch " - "(have %zu, expected %d)\n", + printk(KERN_ERR "ERROR: Firmware size mismatch (have %zu, expected %d)\n", firmware->size, CX23885_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; @@ -1077,8 +1074,7 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version); if (retval < 0) { - printk(KERN_ERR "ERROR: cx23417 firmware get encoder :" - "version failed!\n"); + printk(KERN_ERR "ERROR: cx23417 firmware get encoder :version failed!\n"); return -1; } dprintk(1, "cx23417 firmware version is 0x%08x\n", version); diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 6115d4e148ba..9d2a4e2dc54f 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -186,8 +186,8 @@ static int cx23885_start_audio_dma(struct cx23885_audio_dev *chip) cx_write(AUD_INT_A_GPCNT_CTL, GP_COUNT_CONTROL_RESET); atomic_set(&chip->count, 0); - dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " - "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start+12)>>1, + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d byte buffer\n", + buf->bpl, cx_read(audio_ch->cmds_start+12)>>1, chip->num_periods, buf->bpl * chip->num_periods); /* Enables corresponding bits at AUD_INT_STAT */ @@ -327,8 +327,7 @@ static int snd_cx23885_pcm_open(struct snd_pcm_substream *substream) int err; if (!chip) { - printk(KERN_ERR "BUG: cx23885 can't find device struct." - " Can't proceed with open\n"); + printk(KERN_ERR "BUG: cx23885 can't find device struct. Can't proceed with open\n"); return -ENODEV; } @@ -555,8 +554,8 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) return NULL; if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) { - printk(KERN_WARNING "%s(): Missing SRAM channel configuration " - "for analog TV Audio\n", __func__); + printk(KERN_WARNING "%s(): Missing SRAM channel configuration for analog TV Audio\n", + __func__); return NULL; } @@ -590,8 +589,8 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) error: snd_card_free(card); - printk(KERN_ERR "%s(): Failed to register analog " - "audio adapter\n", __func__); + printk(KERN_ERR "%s(): Failed to register analog audio adapter\n", + __func__); return NULL; } diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index 99ba8d6328f0..e2c4edbfbdb7 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -1304,8 +1304,7 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) */ break; default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", + printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); break; } @@ -2342,9 +2341,8 @@ void cx23885_card_setup(struct cx23885_dev *dev) ret = request_firmware(&fw, filename, &dev->pci->dev); if (ret != 0) - printk(KERN_ERR "did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details " - "on firmware-problems.", filename); + printk(KERN_ERR "did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems.", + filename); else altera_init(&netup_config, fw); diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index c86b1093ab99..5020a60a4f1f 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -915,8 +915,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_init_tsport(dev, &dev->ts2, 2); if (get_resources(dev) < 0) { - printk(KERN_ERR "CORE %s No more PCIe resources for " - "subsystem: %04x:%04x\n", + printk(KERN_ERR "CORE %s No more PCIe resources for subsystem: %04x:%04x\n", dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device); @@ -980,8 +979,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { if (cx23885_video_register(dev) < 0) { - printk(KERN_ERR "%s() Failed to register analog " - "video adapters on VID_A\n", __func__); + printk(KERN_ERR "%s() Failed to register analog video adapters on VID_A\n", + __func__); } } @@ -1579,8 +1578,8 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status) (status & VID_B_MSK_VBI_SYNC) || (status & VID_B_MSK_OF) || (status & VID_B_MSK_VBI_OF)) { - printk(KERN_ERR "%s: V4L mpeg risc op code error, status " - "= 0x%x\n", dev->name, status); + printk(KERN_ERR "%s: V4L mpeg risc op code error, status = 0x%x\n", + dev->name, status); if (status & VID_B_MSK_BAD_PKT) dprintk(1, " VID_B_MSK_BAD_PKT\n"); if (status & VID_B_MSK_OPC_ERR) @@ -1995,8 +1994,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev, 0)); diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 818f3c2fc98d..42413fa423b4 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -2482,8 +2482,7 @@ static int dvb_register(struct cx23885_tsport *port) break; default: - printk(KERN_INFO "%s: The frontend of your DVB/ATSC card " - " isn't supported yet\n", + printk(KERN_INFO "%s: The frontend of your DVB/ATSC card isn't supported yet\n", dev->name); break; } diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 33d168ef278d..92ff452e5886 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -1065,8 +1065,7 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) } if (status & VID_BC_MSK_SYNC) - dprintk(7, " (VID_BC_MSK_SYNC 0x%08x) " - "video lines miss-match\n", + dprintk(7, " (VID_BC_MSK_SYNC 0x%08x) video lines miss-match\n", VID_BC_MSK_SYNC); if (status & VID_BC_MSK_OF) diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index c1aa888af705..3115cfddab95 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -1015,8 +1015,8 @@ static int cx23888_ir_log_status(struct v4l2_subdev *sd) j = 0; break; } - v4l2_info(sd, "\tNext carrier edge window: 16 clocks " - "-%1d/+%1d, %u to %u Hz\n", i, j, + v4l2_info(sd, "\tNext carrier edge window: 16 clocks -%1d/+%1d, %u to %u Hz\n", + i, j, clock_divider_to_freq(rxclk, 16 + j), clock_divider_to_freq(rxclk, 16 - i)); } @@ -1026,8 +1026,7 @@ static int cx23888_ir_log_status(struct v4l2_subdev *sd) v4l2_info(sd, "\tLow pass filter: %s\n", filtr ? "enabled" : "disabled"); if (filtr) - v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, " - "%u ns\n", + v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, %u ns\n", lpf_count_to_us(filtr), lpf_count_to_ns(filtr)); v4l2_info(sd, "\tPulse width timer timed-out: %s\n", -- cgit v1.2.3 From e318e584f70f60170809dd975bbd480fc06cc5e4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:04 -0200 Subject: [media] cx88: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-alsa.c | 15 ++++++--------- drivers/media/pci/cx88/cx88-cards.c | 14 ++++++-------- drivers/media/pci/cx88/cx88-dsp.c | 12 ++++++------ drivers/media/pci/cx88/cx88-dvb.c | 6 ++---- drivers/media/pci/cx88/cx88-i2c.c | 3 +-- drivers/media/pci/cx88/cx88-mpeg.c | 15 +++++++-------- drivers/media/pci/cx88/cx88-tvaudio.c | 6 ++---- drivers/media/pci/cx88/cx88-video.c | 4 ++-- 8 files changed, 32 insertions(+), 43 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 723f06462104..495f9a0569e0 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -120,9 +120,7 @@ MODULE_AUTHOR("Mauro Carvalho Chehab "); MODULE_LICENSE("GPL"); MODULE_VERSION(CX88_VERSION); -MODULE_SUPPORTED_DEVICE("{{Conexant,23881}," - "{{Conexant,23882}," - "{{Conexant,23883}"); +MODULE_SUPPORTED_DEVICE("{{Conexant,23881},{{Conexant,23882},{{Conexant,23883}"); static unsigned int debug; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages"); @@ -154,8 +152,8 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); atomic_set(&chip->count, 0); - dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d " - "byte buffer\n", buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d byte buffer\n", + buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, chip->num_periods, buf->bpl * chip->num_periods); /* Enables corresponding bits at AUD_INT_STAT */ @@ -425,8 +423,7 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) int err; if (!chip) { - printk(KERN_ERR "BUG: cx88 can't find device struct." - " Can't proceed with open\n"); + printk(KERN_ERR "BUG: cx88 can't find device struct. Can't proceed with open\n"); return -ENODEV; } @@ -914,8 +911,8 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, /* print pci info */ pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat); - dprintk(1,"ALSA %s/%i: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", core->name, devno, + dprintk(1, "ALSA %s/%i: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + core->name, devno, pci_name(pci), pci->revision, pci->irq, pci_lat, (unsigned long long)pci_resource_start(pci,0)); diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 8f2556ec3971..31295b36dafc 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -2847,8 +2847,7 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) break; } - info_printk(core, "Leadtek Winfast 2000XP Expert config: " - "tuner=%d, eeprom[0]=0x%02x\n", + info_printk(core, "Leadtek Winfast 2000XP Expert config: tuner=%d, eeprom[0]=0x%02x\n", core->board.tuner_type, eeprom_data[0]); } @@ -3107,8 +3106,8 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) msg.len = (i != 12 ? 5 : 2); err = i2c_transfer(&core->i2c_adap, &msg, 1); if (err != 1) { - warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d " - "failed (err = %d)!\n", i, err); + warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", + i, err); return; } } @@ -3284,8 +3283,7 @@ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) "%s: version might help as well.\n", core->name,core->name,core->name,core->name); } - err_printk(core, "Here is a list of valid choices for the card= " - "insmod option:\n"); + err_printk(core, "Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) printk(KERN_ERR "%s: card=%d -> %s\n", core->name, i, cx88_boards[i].name); @@ -3510,8 +3508,8 @@ static void cx88_card_setup(struct cx88_core *core) for (i = 0; i < ARRAY_SIZE(buffer); i++) if (2 != i2c_master_send(&core->i2c_client, buffer[i],2)) - warn_printk(core, "Unable to enable " - "tuner(%i).\n", i); + warn_printk(core, "Unable to enable tuner(%i).\n", + i); } break; case CX88_BOARD_MSI_TVANYWHERE_MASTER: diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index a9907265ff66..7fafd132ccaf 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -186,8 +186,8 @@ static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) dual = freq_magnitude(x, N, dual_freq); noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END); - dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, " - "noise=%d\n", carrier, stereo, dual, noise); + dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, noise=%d\n", + carrier, stereo, dual, noise); if (stereo > dual) ret = V4L2_TUNER_SUB_STEREO; @@ -222,8 +222,8 @@ static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N) s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP); s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF); s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL); - dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d" - "\n", dual_ref, dual, sap_ref, sap); + dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d\n", + dual_ref, dual, sap_ref, sap); /* FIXME: Currently not supported */ return UNSET; } @@ -241,8 +241,8 @@ static s16 *read_rds_samples(struct cx88_core *core, u32 *N) u32 current_address = cx_read(srch->ptr1_reg); u32 offset = (current_address - srch->fifo_start + bpl); - dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), " - "sample_count=%d, aud_intstat=%08x\n", current_address, + dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), sample_count=%d, aud_intstat=%08x\n", + current_address, current_address - srch->fifo_start, sample_count, cx_read(MO_AUD_INTSTAT)); diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index ac2392d8887a..fe5fd2a4650b 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -625,8 +625,7 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) return -EINVAL; if (!fe0->dvb.frontend) { - printk(KERN_ERR "%s/2: dvb frontend not attached. " - "Can't attach xc3028\n", + printk(KERN_ERR "%s/2: dvb frontend not attached. Can't attach xc3028\n", dev->core->name); return -EINVAL; } @@ -665,8 +664,7 @@ static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg) return -EINVAL; if (!fe0->dvb.frontend) { - printk(KERN_ERR "%s/2: dvb frontend not attached. " - "Can't attach xc4000\n", + printk(KERN_ERR "%s/2: dvb frontend not attached. Can't attach xc4000\n", dev->core->name); return -EINVAL; } diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c index cf2d69615838..804f7417d19f 100644 --- a/drivers/media/pci/cx88/cx88-i2c.c +++ b/drivers/media/pci/cx88/cx88-i2c.c @@ -45,8 +45,7 @@ MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); static unsigned int i2c_udelay = 5; module_param(i2c_udelay, int, 0644); -MODULE_PARM_DESC(i2c_udelay,"i2c delay at insmod time, in usecs " - "(should be 5 or higher). Lower value means higher bus speed."); +MODULE_PARM_DESC(i2c_udelay, "i2c delay at insmod time, in usecs (should be 5 or higher). Lower value means higher bus speed."); #define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 245357adbc25..86b46b62d985 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -401,8 +401,8 @@ static int cx8802_init_common(struct cx8802_dev *dev) dev->pci_rev = dev->pci->revision; pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->core->name, + printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->core->name, pci_name(dev->pci), dev->pci_rev, dev->pci->irq, dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0)); @@ -690,8 +690,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) list_del(&d->drvlist); kfree(d); } else - printk(KERN_ERR "%s/2: cx8802 driver remove " - "failed (%d)\n", dev->core->name, err); + printk(KERN_ERR "%s/2: cx8802 driver remove failed (%d)\n", + dev->core->name, err); } mutex_unlock(&dev->core->lock); @@ -768,8 +768,7 @@ static void cx8802_remove(struct pci_dev *pci_dev) struct cx8802_driver *drv, *tmp; int err; - printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver " - "while cx8802 sub-drivers still loaded?!\n", + printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver while cx8802 sub-drivers still loaded?!\n", dev->core->name); list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) { @@ -777,8 +776,8 @@ static void cx8802_remove(struct pci_dev *pci_dev) if (err == 0) { list_del(&drv->drvlist); } else - printk(KERN_ERR "%s/2: cx8802 driver remove " - "failed (%d)\n", dev->core->name, err); + printk(KERN_ERR "%s/2: cx8802 driver remove failed (%d)\n", + dev->core->name, err); kfree(drv); } } diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index 6bbce6ad6295..dd8e6f324204 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -62,8 +62,7 @@ MODULE_PARM_DESC(always_analog,"force analog audio out"); static unsigned int radio_deemphasis; module_param(radio_deemphasis,int,0644); -MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, " - "0=None, 1=50us (elsewhere), 2=75us (USA)"); +MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, 0=None, 1=50us (elsewhere), 2=75us (USA)"); #define dprintk(fmt, arg...) if (audio_debug) \ printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) @@ -976,8 +975,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) } if (UNSET != ctl) { - dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x " - "[status=0x%x,ctl=0x%x,vol=0x%x]\n", + dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x [status=0x%x,ctl=0x%x,vol=0x%x]\n", mask, ctl, cx_read(AUD_STATUS), cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); cx_andor(AUD_CTL, mask, ctl); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index d83eb3b10f54..418e2db40b39 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -1307,8 +1307,8 @@ static int cx8800_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", core->name, + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + core->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); -- cgit v1.2.3 From 935747ff180594471b27e3bc776ab0cf93e525cf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:04 -0200 Subject: [media] ddbridge: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ddbridge/ddbridge-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c index 18e3a4deee64..a6c9fe235974 100644 --- a/drivers/media/pci/ddbridge/ddbridge-core.c +++ b/drivers/media/pci/ddbridge/ddbridge-core.c @@ -824,8 +824,7 @@ static int dvb_input_attach(struct ddb_input *input) &input->port->dev->pdev->dev, adapter_nr); if (ret < 0) { - printk(KERN_ERR "ddbridge: Could not register adapter." - "Check if you enabled enough adapters in dvb-core!\n"); + printk(KERN_ERR "ddbridge: Could not register adapter.Check if you enabled enough adapters in dvb-core!\n"); return ret; } input->attached = 1; @@ -1730,8 +1729,7 @@ static __init int module_init_ddbridge(void) { int ret; - printk(KERN_INFO "Digital Devices PCIE bridge driver, " - "Copyright (C) 2010-11 Digital Devices GmbH\n"); + printk(KERN_INFO "Digital Devices PCIE bridge driver, Copyright (C) 2010-11 Digital Devices GmbH\n"); ret = ddb_class_create(); if (ret < 0) -- cgit v1.2.3 From 0e8aebb52d38298720229d2a77476be23188a208 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:04 -0200 Subject: [media] dm1105: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/dm1105/dm1105.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/dm1105/dm1105.c b/drivers/media/pci/dm1105/dm1105.c index 5dd504741b12..a589aa78d1d9 100644 --- a/drivers/media/pci/dm1105/dm1105.c +++ b/drivers/media/pci/dm1105/dm1105.c @@ -315,8 +315,7 @@ static void dm1105_card_list(struct pci_dev *pci) "dm1105: Updating to the latest version might help\n" "dm1105: as well.\n"); } - printk(KERN_ERR "Here is a list of valid choices for the card= " - "insmod option:\n"); + printk(KERN_ERR "Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < ARRAY_SIZE(dm1105_boards); i++) printk(KERN_ERR "dm1105: card=%d -> %s\n", i, dm1105_boards[i].name); -- cgit v1.2.3 From 67ccf860a0181e0af627fa873990fa98a6c4036d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:05 -0200 Subject: [media] ivtv: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ivtv/ivtv-alsa-main.c | 12 +++++------ drivers/media/pci/ivtv/ivtv-driver.c | 37 ++++++++++++--------------------- drivers/media/pci/ivtv/ivtv-firmware.c | 4 ++-- drivers/media/pci/ivtv/ivtv-yuv.c | 8 +++---- drivers/media/pci/ivtv/ivtvfb.c | 3 +-- 5 files changed, 26 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ivtv/ivtv-alsa-main.c b/drivers/media/pci/ivtv/ivtv-alsa-main.c index 8a86b61a896d..374f45f81ab3 100644 --- a/drivers/media/pci/ivtv/ivtv-alsa-main.c +++ b/drivers/media/pci/ivtv/ivtv-alsa-main.c @@ -177,8 +177,8 @@ static int snd_ivtv_init(struct v4l2_device *v4l2_dev) #if 0 ret = snd_ivtv_mixer_create(itvsc); if (ret) { - IVTV_ALSA_WARN("%s: snd_ivtv_mixer_create() failed with err %d:" - " proceeding anyway\n", __func__, ret); + IVTV_ALSA_WARN("%s: snd_ivtv_mixer_create() failed with err %d: proceeding anyway\n", + __func__, ret); } #endif @@ -235,8 +235,8 @@ static int ivtv_alsa_load(struct ivtv *itv) s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM]; if (s->vdev.v4l2_dev == NULL) { - IVTV_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " - "skipping\n", __func__); + IVTV_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - skipping\n", + __func__); return 0; } @@ -250,8 +250,8 @@ static int ivtv_alsa_load(struct ivtv *itv) IVTV_ALSA_ERR("%s: failed to create struct snd_ivtv_card\n", __func__); } else { - IVTV_DEBUG_ALSA_INFO("%s: created ivtv ALSA interface instance " - "\n", __func__); + IVTV_DEBUG_ALSA_INFO("%s: created ivtv ALSA interface instance \n", + __func__); } return 0; } diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c index ee48c3e09de4..0a3b80a4bd69 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.c +++ b/drivers/media/pci/ivtv/ivtv-driver.c @@ -885,8 +885,8 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); if (pci_latency < 64 && ivtv_pci_latency) { - IVTV_INFO("Unreasonably low latency timer, " - "setting to 64 (was %d)\n", pci_latency); + IVTV_INFO("Unreasonably low latency timer, setting to 64 (was %d)\n", + pci_latency); pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 64); pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); } @@ -896,8 +896,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, these problems. */ pci_write_config_dword(pdev, 0x40, 0xffff); - IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, " - "irq: %d, latency: %d, memory: 0x%llx\n", + IVTV_DEBUG_INFO("%d (rev %d) at %02x:%02x.%x, irq: %d, latency: %d, memory: 0x%llx\n", pdev->device, pdev->revision, pdev->bus->number, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev->irq, pci_latency, (u64)itv->base_addr); @@ -1047,13 +1046,10 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); if (!itv->enc_mem) { - IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 " - "encoder memory\n"); - IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of " - "vmalloc address space for this window\n"); + IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 encoder memory\n"); + IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of vmalloc address space for this window\n"); IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); - IVTV_ERR("Use the vmalloc= kernel command line option to set " - "VmallocTotal to a larger value\n"); + IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); retval = -ENOMEM; goto free_mem; } @@ -1064,14 +1060,10 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); if (!itv->dec_mem) { - IVTV_ERR("ioremap failed. Can't get a window into " - "CX23415 decoder memory\n"); - IVTV_ERR("Each capture card with a CX23415 needs 8 MB " - "of vmalloc address space for this window\n"); - IVTV_ERR("Check the output of 'grep Vmalloc " - "/proc/meminfo'\n"); - IVTV_ERR("Use the vmalloc= kernel command line option " - "to set VmallocTotal to a larger value\n"); + IVTV_ERR("ioremap failed. Can't get a window into CX23415 decoder memory\n"); + IVTV_ERR("Each capture card with a CX23415 needs 8 MB of vmalloc address space for this window\n"); + IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); + IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); retval = -ENOMEM; goto free_mem; } @@ -1086,13 +1078,10 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) itv->reg_mem = ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); if (!itv->reg_mem) { - IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 " - "register space\n"); - IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of " - "vmalloc address space for this window\n"); + IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 register space\n"); + IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of vmalloc address space for this window\n"); IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); - IVTV_ERR("Use the vmalloc= kernel command line option to set " - "VmallocTotal to a larger value\n"); + IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); retval = -ENOMEM; goto free_io; } diff --git a/drivers/media/pci/ivtv/ivtv-firmware.c b/drivers/media/pci/ivtv/ivtv-firmware.c index 5b3095f65dce..ba279fdb3df8 100644 --- a/drivers/media/pci/ivtv/ivtv-firmware.c +++ b/drivers/media/pci/ivtv/ivtv-firmware.c @@ -376,8 +376,8 @@ int ivtv_firmware_check(struct ivtv *itv, char *where) /* If something failed & currently idle, try to reload */ if (res && !atomic_read(&itv->capturing) && !atomic_read(&itv->decoding)) { - IVTV_INFO("Detected in %s that firmware had failed - " - "Reloading\n", where); + IVTV_INFO("Detected in %s that firmware had failed - Reloading\n", + where); res = ivtv_firmware_restart(itv); /* * Even if restarted ok, still signal a problem had occurred. diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c index b094054cda6e..a61f63234e1f 100644 --- a/drivers/media/pci/ivtv/ivtv-yuv.c +++ b/drivers/media/pci/ivtv/ivtv-yuv.c @@ -88,8 +88,8 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, if (y_pages == y_dma.page_count) { IVTV_DEBUG_WARN - ("failed to map uv user pages, returned %d " - "expecting %d\n", uv_pages, uv_dma.page_count); + ("failed to map uv user pages, returned %d expecting %d\n", + uv_pages, uv_dma.page_count); if (uv_pages >= 0) { for (i = 0; i < uv_pages; i++) @@ -100,8 +100,8 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, } } else { IVTV_DEBUG_WARN - ("failed to map y user pages, returned %d " - "expecting %d\n", y_pages, y_dma.page_count); + ("failed to map y user pages, returned %d expecting %d\n", + y_pages, y_dma.page_count); } if (y_pages >= 0) { for (i = 0; i < y_pages; i++) diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c index 8b95eefb610b..612a8402cf4d 100644 --- a/drivers/media/pci/ivtv/ivtvfb.c +++ b/drivers/media/pci/ivtv/ivtvfb.c @@ -293,8 +293,7 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv, /* Map User DMA */ if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { mutex_unlock(&itv->udma.lock); - IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, " - "Error with get_user_pages: %d bytes, %d pages returned\n", + IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, Error with get_user_pages: %d bytes, %d pages returned\n", size_in_bytes, itv->udma.page_count); /* get_user_pages must have failed completely */ -- cgit v1.2.3 From f8a3dcb5a927141610e30d01e5782ba4a4516980 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:05 -0200 Subject: [media] meye: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/meye/meye.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index ba887e8e1b17..11d81389ab1e 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -60,8 +60,7 @@ MODULE_PARM_DESC(gbuffers, "number of capture buffers, default is 2 (32 max)"); /* size of a grab buffer */ static unsigned int gbufsize = MEYE_MAX_BUFSIZE; module_param(gbufsize, int, 0444); -MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400" - " (will be rounded up to a page multiple)"); +MODULE_PARM_DESC(gbufsize, "size of the capture buffers, default is 614400 (will be rounded up to a page multiple)"); /* /dev/videoX registration number */ static int video_nr = -1; @@ -1261,8 +1260,7 @@ static int vidioc_reqbufs(struct file *file, void *fh, meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize); if (!meye.grab_fbuffer) { - printk(KERN_ERR "meye: v4l framebuffer allocation" - " failed\n"); + printk(KERN_ERR "meye: v4l framebuffer allocation failed\n"); mutex_unlock(&meye.lock); return -ENOMEM; } @@ -1659,8 +1657,7 @@ static int meye_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) ret = -EIO; if ((ret = sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERA, 1))) { v4l2_err(v4l2_dev, "meye: unable to power on the camera\n"); - v4l2_err(v4l2_dev, "meye: did you enable the camera in " - "sonypi using the module options ?\n"); + v4l2_err(v4l2_dev, "meye: did you enable the camera in sonypi using the module options ?\n"); goto outsonypienable; } @@ -1834,8 +1831,7 @@ static int __init meye_init(void) if (gbufsize > MEYE_MAX_BUFSIZE) gbufsize = MEYE_MAX_BUFSIZE; gbufsize = PAGE_ALIGN(gbufsize); - printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) " - "for capture\n", + printk(KERN_INFO "meye: using %d buffers with %dk (%dk total) for capture\n", gbuffers, gbufsize / 1024, gbuffers * gbufsize / 1024); return pci_register_driver(&meye_driver); -- cgit v1.2.3 From 2d96b44f0abfd429816d66148b75bad84a625f3b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:06 -0200 Subject: [media] pt1: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/pt1/pt1.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c index e7e4428109c3..d5ee82aee9e8 100644 --- a/drivers/media/pci/pt1/pt1.c +++ b/drivers/media/pci/pt1/pt1.c @@ -282,13 +282,12 @@ static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page) continue; if (upacket >> 24 & 1) - printk_ratelimited(KERN_INFO "earth-pt1: device " - "buffer overflowing. table[%d] buf[%d]\n", + printk_ratelimited(KERN_INFO "earth-pt1: device buffer overflowing. table[%d] buf[%d]\n", pt1->table_index, pt1->buf_index); sc = upacket >> 26 & 0x7; if (adap->st_count != -1 && sc != ((adap->st_count + 1) & 0x7)) - printk_ratelimited(KERN_INFO "earth-pt1: data loss" - " in streamID(adapter)[%d]\n", index); + printk_ratelimited(KERN_INFO "earth-pt1: data loss in streamID(adapter)[%d]\n", + index); adap->st_count = sc; buf = adap->buf; -- cgit v1.2.3 From 395eff951a9dc6d6d08d9afe27f2aa975bc23c39 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:06 -0200 Subject: [media] saa7134: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-alsa.c | 3 +-- drivers/media/pci/saa7134/saa7134-cards.c | 8 +++---- drivers/media/pci/saa7134/saa7134-core.c | 39 ++++++++++++++----------------- drivers/media/pci/saa7134/saa7134-dvb.c | 32 ++++++++++++------------- drivers/media/pci/saa7134/saa7134-input.c | 13 ++++------- 5 files changed, 43 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c index dc0e2fc5f68b..8a35ecfb75e3 100644 --- a/drivers/media/pci/saa7134/saa7134-alsa.c +++ b/drivers/media/pci/saa7134/saa7134-alsa.c @@ -813,8 +813,7 @@ static int snd_card_saa7134_capture_open(struct snd_pcm_substream * substream) int amux, err; if (!saa7134) { - pr_err("BUG: saa7134 can't find device struct." - " Can't proceed with open\n"); + pr_err("BUG: saa7134 can't find device struct. Can't proceed with open\n"); return -ENODEV; } dev = saa7134->dev; diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c index c480a7e87593..2b60af493de4 100644 --- a/drivers/media/pci/saa7134/saa7134-cards.c +++ b/drivers/media/pci/saa7134/saa7134-cards.c @@ -7341,8 +7341,8 @@ static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data) case 67659: /* WinTV-HVR1110 (OEM, no IR, hybrid, FM, SVid/Comp, RCA aud) */ break; default: - pr_warn("%s: warning: " - "unknown hauppauge model #%d\n", dev->name, tv.model); + pr_warn("%s: warning: unknown hauppauge model #%d\n", + dev->name, tv.model); break; } @@ -7920,8 +7920,8 @@ int saa7134_board_init2(struct saa7134_dev *dev) msg.addr = 0x0b; msg.len = 1; if (1 != i2c_transfer(&dev->i2c_adap, &msg, 1)) { - pr_warn("%s: send wake up byte to pic16C505" - "(IR chip) failed\n", dev->name); + pr_warn("%s: send wake up byte to pic16C505(IR chip) failed\n", + dev->name); } else { msg.flags = I2C_M_RD; rc = i2c_transfer(&dev->i2c_adap, &msg, 1); diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c index ffb66a9ae23e..7d6bb5c9343f 100644 --- a/drivers/media/pci/saa7134/saa7134-core.c +++ b/drivers/media/pci/saa7134/saa7134-core.c @@ -66,8 +66,7 @@ MODULE_PARM_DESC(latency,"pci latency timer"); int saa7134_no_overlay=-1; module_param_named(no_overlay, saa7134_no_overlay, int, 0444); -MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" - " [some VIA/SIS chipsets are known to have problem with overlay]"); +MODULE_PARM_DESC(no_overlay, "allow override overlay default (0 disables, 1 enables) [some VIA/SIS chipsets are known to have problem with overlay]"); bool saa7134_userptr; module_param(saa7134_userptr, bool, 0644); @@ -619,25 +618,25 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id) print_irqstatus(dev,loop,report,status); if (report & SAA7134_IRQ_REPORT_PE) { /* disable all parity error */ - pr_warn("%s/irq: looping -- " - "clearing PE (parity error!) enable bit\n",dev->name); + pr_warn("%s/irq: looping -- clearing PE (parity error!) enable bit\n", + dev->name); saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE); } else if (report & SAA7134_IRQ_REPORT_GPIO16) { /* disable gpio16 IRQ */ - pr_warn("%s/irq: looping -- " - "clearing GPIO16 enable bit\n",dev->name); + pr_warn("%s/irq: looping -- clearing GPIO16 enable bit\n", + dev->name); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_P); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16_N); } else if (report & SAA7134_IRQ_REPORT_GPIO18) { /* disable gpio18 IRQs */ - pr_warn("%s/irq: looping -- " - "clearing GPIO18 enable bit\n",dev->name); + pr_warn("%s/irq: looping -- clearing GPIO18 enable bit\n", + dev->name); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P); saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_N); } else { /* disable all irqs */ - pr_warn("%s/irq: looping -- " - "clearing all enable bits\n",dev->name); + pr_warn("%s/irq: looping -- clearing all enable bits\n", + dev->name); saa_writel(SAA7134_IRQ1,0); saa_writel(SAA7134_IRQ2,0); } @@ -1081,18 +1080,14 @@ static int saa7134_initdev(struct pci_dev *pci_dev, } #endif if (pci_pci_problems & (PCIPCI_FAIL|PCIAGP_FAIL)) { - pr_info("%s: quirk: this driver and your " - "chipset may not work together" - " in overlay mode.\n",dev->name); + pr_info("%s: quirk: this driver and your chipset may not work together in overlay mode.\n", + dev->name); if (!saa7134_no_overlay) { - pr_info("%s: quirk: overlay " - "mode will be disabled.\n", + pr_info("%s: quirk: overlay mode will be disabled.\n", dev->name); saa7134_no_overlay = 1; } else { - pr_info("%s: quirk: overlay " - "mode will be forced. Use this" - " option at your own risk.\n", + pr_info("%s: quirk: overlay mode will be forced. Use this option at your own risk.\n", dev->name); } } @@ -1106,10 +1101,10 @@ static int saa7134_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - pr_info("%s: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, - dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); + pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, + (unsigned long long)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); if (err) { diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c index 59a4b5f7724e..598b8bbfe726 100644 --- a/drivers/media/pci/saa7134/saa7134-dvb.c +++ b/drivers/media/pci/saa7134/saa7134-dvb.c @@ -1449,8 +1449,8 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - pr_warn("%s: Medion Quadro, no tda826x " - "found !\n", __func__); + pr_warn("%s: Medion Quadro, no tda826x found !\n", + __func__); goto detach_frontend; } if (dev_id != 0x08) { @@ -1458,8 +1458,8 @@ static int dvb_init(struct saa7134_dev *dev) fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - pr_warn("%s: Medion Quadro, no ISL6405 " - "found !\n", __func__); + pr_warn("%s: Medion Quadro, no ISL6405 found !\n", + __func__); goto detach_frontend; } if (dev_id == 0x07) { @@ -1629,8 +1629,8 @@ static int dvb_init(struct saa7134_dev *dev) struct dvb_frontend *fe; if (dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL) { - pr_warn("%s: MD7134 DVB-S, no SD1878 " - "found !\n", __func__); + pr_warn("%s: MD7134 DVB-S, no SD1878 found !\n", + __func__); goto detach_frontend; } /* we need to open the i2c gate (we know it exists) */ @@ -1638,8 +1638,8 @@ static int dvb_init(struct saa7134_dev *dev) fe->ops.i2c_gate_ctrl(fe, 1); if (dvb_attach(isl6405_attach, fe, &dev->i2c_adap, 0x08, 0, 0) == NULL) { - pr_warn("%s: MD7134 DVB-S, no ISL6405 " - "found !\n", __func__); + pr_warn("%s: MD7134 DVB-S, no ISL6405 found !\n", + __func__); goto detach_frontend; } fe->ops.i2c_gate_ctrl(fe, 0); @@ -1670,14 +1670,14 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - pr_warn("%s: Asus Tiger 3in1, no " - "tda826x found!\n", __func__); + pr_warn("%s: Asus Tiger 3in1, no tda826x found!\n", + __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - pr_warn("%s: Asus Tiger 3in1, no lnbp21" - " found!\n", __func__); + pr_warn("%s: Asus Tiger 3in1, no lnbp21 found!\n", + __func__); goto detach_frontend; } } @@ -1695,14 +1695,14 @@ static int dvb_init(struct saa7134_dev *dev) if (dvb_attach(tda826x_attach, fe0->dvb.frontend, 0x60, &dev->i2c_adap, 0) == NULL) { - pr_warn("%s: Asus My Cinema PS3-100, no " - "tda826x found!\n", __func__); + pr_warn("%s: Asus My Cinema PS3-100, no tda826x found!\n", + __func__); goto detach_frontend; } if (dvb_attach(lnbp21_attach, fe0->dvb.frontend, &dev->i2c_adap, 0, 0) == NULL) { - pr_warn("%s: Asus My Cinema PS3-100, no lnbp21" - " found!\n", __func__); + pr_warn("%s: Asus My Cinema PS3-100, no lnbp21 found!\n", + __func__); goto detach_frontend; } } diff --git a/drivers/media/pci/saa7134/saa7134-input.c b/drivers/media/pci/saa7134/saa7134-input.c index eff52bbbfd66..823b75ed47e1 100644 --- a/drivers/media/pci/saa7134/saa7134-input.c +++ b/drivers/media/pci/saa7134/saa7134-input.c @@ -123,8 +123,7 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - ir_dbg(ir, "get_key_flydvb_trio: " - "ir->c->adapter->algo_data is NULL!\n"); + ir_dbg(ir, "get_key_flydvb_trio: ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -150,8 +149,8 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, enum rc_type *protocol, msleep(10); continue; } - ir_dbg(ir, "send wake up byte to pic16C505 (IR chip)" - "failed %dx\n", attempt); + ir_dbg(ir, "send wake up byte to pic16C505 (IR chip)failed %dx\n", + attempt); return -EIO; } if (1 != i2c_master_recv(ir->c, &b, 1)) { @@ -174,8 +173,7 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, enum rc_type *protocol /* is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - ir_dbg(ir, "get_key_msi_tvanywhere_plus: " - "ir->c->adapter->algo_data is NULL!\n"); + ir_dbg(ir, "get_key_msi_tvanywhere_plus: ir->c->adapter->algo_data is NULL!\n"); return -EIO; } @@ -223,8 +221,7 @@ static int get_key_kworld_pc150u(struct IR_i2c *ir, enum rc_type *protocol, /* is needed to access GPIO. Used by the saa_readl macro. */ struct saa7134_dev *dev = ir->c->adapter->algo_data; if (dev == NULL) { - ir_dbg(ir, "get_key_kworld_pc150u: " - "ir->c->adapter->algo_data is NULL!\n"); + ir_dbg(ir, "get_key_kworld_pc150u: ir->c->adapter->algo_data is NULL!\n"); return -EIO; } -- cgit v1.2.3 From 24f711c135a71fd2afbb1f6dc2235d470f083880 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:07 -0200 Subject: [media] saa7164: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7164/saa7164-buffer.c | 3 +- drivers/media/pci/saa7164/saa7164-bus.c | 4 +- drivers/media/pci/saa7164/saa7164-cards.c | 4 +- drivers/media/pci/saa7164/saa7164-cmd.c | 12 +++--- drivers/media/pci/saa7164/saa7164-core.c | 66 ++++++++++++----------------- drivers/media/pci/saa7164/saa7164-dvb.c | 34 +++++++-------- drivers/media/pci/saa7164/saa7164-encoder.c | 18 ++++---- drivers/media/pci/saa7164/saa7164-fw.c | 10 ++--- drivers/media/pci/saa7164/saa7164-vbi.c | 14 +++--- 9 files changed, 72 insertions(+), 93 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c index f30758e24f5d..62c34504199d 100644 --- a/drivers/media/pci/saa7164/saa7164-buffer.c +++ b/drivers/media/pci/saa7164/saa7164-buffer.c @@ -218,8 +218,7 @@ int saa7164_buffer_activate(struct saa7164_buffer *buf, int i) saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma); saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0); - dprintk(DBGLVL_BUF, " buf[%d] offset 0x%llx (0x%x) " - "buf 0x%llx/%llx (0x%x/%x) nr=%d\n", + dprintk(DBGLVL_BUF, " buf[%d] offset 0x%llx (0x%x) buf 0x%llx/%llx (0x%x/%x) nr=%d\n", buf->idx, (u64)port->bufoffset + (i * sizeof(u32)), saa7164_readl(port->bufoffset + (sizeof(u32) * i)), diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c index a18fe5d47238..e305c02f9dc9 100644 --- a/drivers/media/pci/saa7164/saa7164-bus.c +++ b/drivers/media/pci/saa7164/saa7164-bus.c @@ -427,8 +427,8 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg, write_distance = curr_gwp + bus->m_dwSizeGetRing - curr_grp; if (bytes_to_read > write_distance) { - printk(KERN_ERR "%s() Invalid bus state, missing msg " - "or mangled ring, faulty H/W / bad code?\n", __func__); + printk(KERN_ERR "%s() Invalid bus state, missing msg or mangled ring, faulty H/W / bad code?\n", + __func__); ret = SAA_ERR_INVALID_COMMAND; goto out; } diff --git a/drivers/media/pci/saa7164/saa7164-cards.c b/drivers/media/pci/saa7164/saa7164-cards.c index c2b738227f58..15a98c638c55 100644 --- a/drivers/media/pci/saa7164/saa7164-cards.c +++ b/drivers/media/pci/saa7164/saa7164-cards.c @@ -726,8 +726,8 @@ void saa7164_card_list(struct saa7164_dev *dev) dev->name, dev->name, dev->name, dev->name); } - printk(KERN_ERR "%s: Here are valid choices for the card= insmod " - "option:\n", dev->name); + printk(KERN_ERR "%s: Here are valid choices for the card= insmod option:\n", + dev->name); for (i = 0; i < saa7164_bcount; i++) printk(KERN_ERR "%s: card=%d -> %s\n", diff --git a/drivers/media/pci/saa7164/saa7164-cmd.c b/drivers/media/pci/saa7164/saa7164-cmd.c index 3285c37b4583..45951b3cc251 100644 --- a/drivers/media/pci/saa7164/saa7164-cmd.c +++ b/drivers/media/pci/saa7164/saa7164-cmd.c @@ -301,8 +301,8 @@ static int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno) else saa7164_cmd_timeout_seqno(dev, seqno); - dprintk(DBGLVL_CMD, "%s(seqno=%d) Waiting res = %d " - "(signalled=%d)\n", __func__, seqno, r, + dprintk(DBGLVL_CMD, "%s(seqno=%d) Waiting res = %d (signalled=%d)\n", + __func__, seqno, r, dev->cmds[seqno].signalled); } else ret = SAA_OK; @@ -353,8 +353,8 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, int ret; int safety = 0; - dprintk(DBGLVL_CMD, "%s(unitid = %s (%d) , command = 0x%x, " - "sel = 0x%x)\n", __func__, saa7164_unitid_name(dev, id), id, + dprintk(DBGLVL_CMD, "%s(unitid = %s (%d) , command = 0x%x, sel = 0x%x)\n", + __func__, saa7164_unitid_name(dev, id), id, command, controlselector); if ((size == 0) || (buf == NULL)) { @@ -452,9 +452,7 @@ int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command, if (presponse_t->seqno != pcommand_t->seqno) { dprintk(DBGLVL_CMD, - "wrong event: seqno = %d, " - "expected seqno = %d, " - "will dequeue regardless\n", + "wrong event: seqno = %d, expected seqno = %d, will dequeue regardless\n", presponse_t->seqno, pcommand_t->seqno); ret = saa7164_cmd_dequeue(dev); diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c index 8bbd092fbe1d..03a1511a92be 100644 --- a/drivers/media/pci/saa7164/saa7164-core.c +++ b/drivers/media/pci/saa7164/saa7164-core.c @@ -710,9 +710,7 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id) } else { /* Find the function */ dprintk(DBGLVL_IRQ, - "%s() unhandled interrupt " - "reg 0x%x bit 0x%x " - "intid = 0x%x\n", + "%s() unhandled interrupt reg 0x%x bit 0x%x intid = 0x%x\n", __func__, i, bit, intid); } } @@ -767,13 +765,11 @@ void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr) { int i; - dprintk(1, "--------------------> " - "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); + dprintk(1, "--------------------> 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n"); for (i = 0; i < 0x100; i += 16) - dprintk(1, "region0[0x%08x] = " - "%02x %02x %02x %02x %02x %02x %02x %02x" - " %02x %02x %02x %02x %02x %02x %02x %02x\n", i, + dprintk(1, "region0[0x%08x] = %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n", + i, (u8)saa7164_readb(addr + i + 0), (u8)saa7164_readb(addr + i + 1), (u8)saa7164_readb(addr + i + 2), @@ -825,8 +821,7 @@ static void saa7164_dump_hwdesc(struct saa7164_dev *dev) static void saa7164_dump_intfdesc(struct saa7164_dev *dev) { - dprintk(1, "@0x%p intfdesc " - "sizeof(struct tmComResInterfaceDescr) = %d bytes\n", + dprintk(1, "@0x%p intfdesc sizeof(struct tmComResInterfaceDescr) = %d bytes\n", &dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr)); dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength); @@ -1011,8 +1006,7 @@ static int saa7164_dev_setup(struct saa7164_dev *dev) saa7164_port_init(dev, SAA7164_PORT_VBI2); if (get_resources(dev) < 0) { - printk(KERN_ERR "CORE %s No more PCIe resources for " - "subsystem: %04x:%04x\n", + printk(KERN_ERR "CORE %s No more PCIe resources for subsystem: %04x:%04x\n", dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device); @@ -1204,8 +1198,8 @@ static bool saa7164_enable_msi(struct pci_dev *pci_dev, struct saa7164_dev *dev) err = pci_enable_msi(pci_dev); if (err) { - printk(KERN_ERR "%s() Failed to enable MSI interrupt." - " Falling back to a shared IRQ\n", __func__); + printk(KERN_ERR "%s() Failed to enable MSI interrupt. Falling back to a shared IRQ\n", + __func__); return false; } @@ -1215,8 +1209,8 @@ static bool saa7164_enable_msi(struct pci_dev *pci_dev, struct saa7164_dev *dev) if (err) { /* fall back to legacy interrupt */ - printk(KERN_ERR "%s() Failed to get an MSI interrupt." - " Falling back to a shared IRQ\n", __func__); + printk(KERN_ERR "%s() Failed to get an MSI interrupt. Falling back to a shared IRQ\n", + __func__); pci_disable_msi(pci_dev); return false; } @@ -1256,8 +1250,8 @@ static int saa7164_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, + printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev, 0)); @@ -1307,8 +1301,7 @@ static int saa7164_initdev(struct pci_dev *pci_dev, err = saa7164_downloadfirmware(dev); if (err < 0) { printk(KERN_ERR - "Failed to boot firmware, no features " - "registered\n"); + "Failed to boot firmware, no features registered\n"); goto fail_fw; } @@ -1327,8 +1320,7 @@ static int saa7164_initdev(struct pci_dev *pci_dev, */ version = 0; if (saa7164_api_get_fw_version(dev, &version) == SAA_OK) - dprintk(1, "Bus is operating correctly using " - "version %d.%d.%d.%d (0x%x)\n", + dprintk(1, "Bus is operating correctly using version %d.%d.%d.%d (0x%x)\n", (version & 0x0000fc00) >> 10, (version & 0x000003e0) >> 5, (version & 0x0000001f), @@ -1356,45 +1348,43 @@ static int saa7164_initdev(struct pci_dev *pci_dev, /* Begin to create the video sub-systems and register funcs */ if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) { if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) { - printk(KERN_ERR "%s() Failed to register " - "dvb adapters on porta\n", + printk(KERN_ERR "%s() Failed to register dvb adapters on porta\n", __func__); } } if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) { if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "dvb adapters on portb\n", + printk(KERN_ERR"%s() Failed to register dvb adapters on portb\n", __func__); } } if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) { if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "mpeg encoder\n", __func__); + printk(KERN_ERR"%s() Failed to register mpeg encoder\n", + __func__); } } if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) { if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "mpeg encoder\n", __func__); + printk(KERN_ERR"%s() Failed to register mpeg encoder\n", + __func__); } } if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) { if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "vbi device\n", __func__); + printk(KERN_ERR"%s() Failed to register vbi device\n", + __func__); } } if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) { if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) { - printk(KERN_ERR"%s() Failed to register " - "vbi device\n", __func__); + printk(KERN_ERR"%s() Failed to register vbi device\n", + __func__); } } saa7164_api_set_debug(dev, fw_debug); @@ -1404,15 +1394,15 @@ static int saa7164_initdev(struct pci_dev *pci_dev, "saa7164 debug"); if (IS_ERR(dev->kthread)) { dev->kthread = NULL; - printk(KERN_ERR "%s() Failed to create " - "debug kernel thread\n", __func__); + printk(KERN_ERR "%s() Failed to create debug kernel thread\n", + __func__); } } } /* != BOARD_UNKNOWN */ else - printk(KERN_ERR "%s() Unsupported board detected, " - "registering without firmware\n", __func__); + printk(KERN_ERR "%s() Unsupported board detected, registering without firmware\n", + __func__); dprintk(1, "%s() parameter debug = %d\n", __func__, saa_debug); dprintk(1, "%s() parameter waitsecs = %d\n", __func__, waitsecs); diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c index e9a783b71b45..cd3eeda5250b 100644 --- a/drivers/media/pci/saa7164/saa7164-dvb.c +++ b/drivers/media/pci/saa7164/saa7164-dvb.c @@ -244,8 +244,8 @@ static int saa7164_dvb_start_port(struct saa7164_port *port) /* Stop the hardware, regardless */ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() acquire/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; goto out; @@ -261,8 +261,8 @@ static int saa7164_dvb_start_port(struct saa7164_port *port) /* Stop the hardware, regardless */ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() pause/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; @@ -279,8 +279,8 @@ static int saa7164_dvb_start_port(struct saa7164_port *port) /* Stop the hardware, regardless */ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() run/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; @@ -357,8 +357,7 @@ static int dvb_register(struct saa7164_port *port) /* Sanity check that the PCI configuration space is active */ if (port->hwcfg.BARLocation == 0) { result = -ENOMEM; - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d), NO PCI configuration\n", + printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d), NO PCI configuration\n", DRIVER_NAME, result); goto fail_adapter; } @@ -386,8 +385,7 @@ static int dvb_register(struct saa7164_port *port) if (!buf) { result = -ENOMEM; - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d), unable to allocate buffers\n", + printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d), unable to allocate buffers\n", DRIVER_NAME, result); goto fail_adapter; } @@ -401,8 +399,8 @@ static int dvb_register(struct saa7164_port *port) result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE, &dev->pci->dev, adapter_nr); if (result < 0) { - printk(KERN_ERR "%s: dvb_register_adapter failed " - "(errno = %d)\n", DRIVER_NAME, result); + printk(KERN_ERR "%s: dvb_register_adapter failed (errno = %d)\n", + DRIVER_NAME, result); goto fail_adapter; } dvb->adapter.priv = port; @@ -410,8 +408,8 @@ static int dvb_register(struct saa7164_port *port) /* 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); + printk(KERN_ERR "%s: dvb_register_frontend failed (errno = %d)\n", + DRIVER_NAME, result); goto fail_frontend; } @@ -444,16 +442,16 @@ static int dvb_register(struct saa7164_port *port) 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); + printk(KERN_ERR "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", + DRIVER_NAME, 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); + printk(KERN_ERR "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", + DRIVER_NAME, result); goto fail_fe_mem; } diff --git a/drivers/media/pci/saa7164/saa7164-encoder.c b/drivers/media/pci/saa7164/saa7164-encoder.c index 32a353d162e7..68124ce7ebc3 100644 --- a/drivers/media/pci/saa7164/saa7164-encoder.c +++ b/drivers/media/pci/saa7164/saa7164-encoder.c @@ -157,8 +157,7 @@ static int saa7164_encoder_buffers_alloc(struct saa7164_port *port) params->pitch); if (!buf) { - printk(KERN_ERR "%s() failed " - "(errno = %d), unable to allocate buffer\n", + printk(KERN_ERR "%s() failed (errno = %d), unable to allocate buffer\n", __func__, result); result = -ENOMEM; goto failed; @@ -681,8 +680,8 @@ static int saa7164_encoder_start_streaming(struct saa7164_port *port) /* Stop the hardware, regardless */ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() acquire/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() acquire/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; goto out; @@ -698,8 +697,8 @@ static int saa7164_encoder_start_streaming(struct saa7164_port *port) /* Stop the hardware, regardless */ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() pause/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() pause/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; @@ -716,8 +715,8 @@ static int saa7164_encoder_start_streaming(struct saa7164_port *port) /* Stop the hardware, regardless */ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP); if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) { - printk(KERN_ERR "%s() run/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() run/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; @@ -1026,8 +1025,7 @@ int saa7164_encoder_register(struct saa7164_port *port) /* Sanity check that the PCI configuration space is active */ if (port->hwcfg.BARLocation == 0) { - printk(KERN_ERR "%s() failed " - "(errno = %d), NO PCI configuration\n", + printk(KERN_ERR "%s() failed (errno = %d), NO PCI configuration\n", __func__, result); result = -ENOMEM; goto failed; diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c index 269e0782c7b6..8568adfd7ece 100644 --- a/drivers/media/pci/saa7164/saa7164-fw.c +++ b/drivers/media/pci/saa7164/saa7164-fw.c @@ -421,8 +421,8 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) ret = request_firmware(&fw, fwname, &dev->pci->dev); if (ret) { - printk(KERN_ERR "%s() Upload failed. " - "(file not found?)\n", __func__); + printk(KERN_ERR "%s() Upload failed. (file not found?)\n", + __func__); return -ENOMEM; } @@ -478,15 +478,13 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev) 0x03) && (saa7164_readl(SAA_DATAREADY_FLAG_ACK) == 0x00) && (version == 0x00)) { - dprintk(DBGLVL_FW, "BootLoader version in " - "rom %d.%d.%d.%d\n", + dprintk(DBGLVL_FW, "BootLoader version in rom %d.%d.%d.%d\n", (bootloaderversion & 0x0000fc00) >> 10, (bootloaderversion & 0x000003e0) >> 5, (bootloaderversion & 0x0000001f), (bootloaderversion & 0xffff0000) >> 16 ); - dprintk(DBGLVL_FW, "BootLoader version " - "in file %d.%d.%d.%d\n", + dprintk(DBGLVL_FW, "BootLoader version in file %d.%d.%d.%d\n", (boothdr->version & 0x0000fc00) >> 10, (boothdr->version & 0x000003e0) >> 5, (boothdr->version & 0x0000001f), diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c index ee54491459a6..e5dcb81029d3 100644 --- a/drivers/media/pci/saa7164/saa7164-vbi.c +++ b/drivers/media/pci/saa7164/saa7164-vbi.c @@ -110,8 +110,7 @@ static int saa7164_vbi_buffers_alloc(struct saa7164_port *port) params->pitch); if (!buf) { - printk(KERN_ERR "%s() failed " - "(errno = %d), unable to allocate buffer\n", + printk(KERN_ERR "%s() failed (errno = %d), unable to allocate buffer\n", __func__, result); result = -ENOMEM; goto failed; @@ -384,8 +383,8 @@ static int saa7164_vbi_start_streaming(struct saa7164_port *port) /* Stop the hardware, regardless */ result = saa7164_vbi_stop_port(port); if (result != SAA_OK) { - printk(KERN_ERR "%s() pause/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() pause/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; @@ -403,8 +402,8 @@ static int saa7164_vbi_start_streaming(struct saa7164_port *port) result = saa7164_vbi_acquire_port(port); result = saa7164_vbi_stop_port(port); if (result != SAA_OK) { - printk(KERN_ERR "%s() run/forced stop transition " - "failed, res = 0x%x\n", __func__, result); + printk(KERN_ERR "%s() run/forced stop transition failed, res = 0x%x\n", + __func__, result); } ret = -EIO; @@ -728,8 +727,7 @@ int saa7164_vbi_register(struct saa7164_port *port) /* Sanity check that the PCI configuration space is active */ if (port->hwcfg.BARLocation == 0) { - printk(KERN_ERR "%s() failed " - "(errno = %d), NO PCI configuration\n", + printk(KERN_ERR "%s() failed (errno = %d), NO PCI configuration\n", __func__, result); result = -ENOMEM; goto failed; -- cgit v1.2.3 From 3d160041dccefcb79874a06009493de55cc11914 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:07 -0200 Subject: [media] solo6x10: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10-v4l2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c index b4be47969b6b..896bec6627aa 100644 --- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c +++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c @@ -702,8 +702,8 @@ int solo_v4l2_init(struct solo_dev *solo_dev, unsigned nr) snprintf(solo_dev->vfd->name, sizeof(solo_dev->vfd->name), "%s (%i)", SOLO6X10_NAME, solo_dev->vfd->num); - dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with " - "%d inputs (%d extended)\n", solo_dev->vfd->num, + dev_info(&solo_dev->pdev->dev, "Display as /dev/video%d with %d inputs (%d extended)\n", + solo_dev->vfd->num, solo_dev->nr_chans, solo_dev->nr_ext); return 0; -- cgit v1.2.3 From 008e6ff9b9bf57a22b49643923bfa4dcaa792fa9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:07 -0200 Subject: [media] ttpci: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/av7110.c | 30 ++++++++++++------------------ drivers/media/pci/ttpci/av7110_hw.c | 12 ++++-------- drivers/media/pci/ttpci/budget-av.c | 3 +-- drivers/media/pci/ttpci/budget-ci.c | 4 +--- drivers/media/pci/ttpci/budget-patch.c | 3 +-- drivers/media/pci/ttpci/budget.c | 3 +-- drivers/media/pci/ttpci/ttpci-eeprom.c | 3 +-- 7 files changed, 21 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 382caf200ba1..fbcc2e5c9414 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -100,8 +100,7 @@ MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetect module_param(hw_sections, int, 0444); MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware"); module_param(rgb_on, int, 0444); -MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control" - " signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); +MODULE_PARM_DESC(rgb_on, "For Siemens DVB-C cards only: Enable RGB control signal on SCART pin 16 to switch SCART video mode from CVBS to RGB"); module_param(volume, int, 0444); MODULE_PARM_DESC(volume, "initial volume: default 255 (range 0-255)"); module_param(budgetpatch, int, 0444); @@ -833,8 +832,7 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter) ret = av7110_fw_request(av7110, buf, 20, &handle, 1); if (ret != 0 || handle >= 32) { - printk("dvb-ttpci: %s error buf %04x %04x %04x %04x " - "ret %d handle %04x\n", + printk(KERN_ERR "dvb-ttpci: %s error buf %04x %04x %04x %04x ret %d handle %04x\n", __func__, buf[0], buf[1], buf[2], buf[3], ret, handle); dvbdmxfilter->hw_handle = 0xffff; @@ -876,8 +874,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter) buf[2] = handle; ret = av7110_fw_request(av7110, buf, 3, answ, 2); if (ret != 0 || answ[1] != handle) { - printk("dvb-ttpci: %s error cmd %04x %04x %04x ret %x " - "resp %04x %04x pid %d\n", + printk(KERN_ERR "dvb-ttpci: %s error cmd %04x %04x %04x ret %x resp %04x %04x pid %d\n", __func__, buf[0], buf[1], buf[2], ret, answ[0], answ[1], dvbdmxfilter->feed->pid); if (!ret) @@ -1532,15 +1529,12 @@ static int get_firmware(struct av7110* av7110) ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev); if (ret) { if (ret == -ENOENT) { - printk(KERN_ERR "dvb-ttpci: could not load firmware," - " file not found: dvb-ttpci-01.fw\n"); - printk(KERN_ERR "dvb-ttpci: usually this should be in " - "/usr/lib/hotplug/firmware or /lib/firmware\n"); - printk(KERN_ERR "dvb-ttpci: and can be downloaded from" - " https://linuxtv.org/download/dvb/firmware/\n"); + printk(KERN_ERR "dvb-ttpci: could not load firmware, file not found: dvb-ttpci-01.fw\n"); + printk(KERN_ERR "dvb-ttpci: usually this should be in /usr/lib/hotplug/firmware or /lib/firmware\n"); + printk(KERN_ERR "dvb-ttpci: and can be downloaded from https://linuxtv.org/download/dvb/firmware/\n"); } else - printk(KERN_ERR "dvb-ttpci: cannot request firmware" - " (error %i)\n", ret); + printk(KERN_ERR "dvb-ttpci: cannot request firmware (error %i)\n", + ret); return -EINVAL; } @@ -2700,8 +2694,9 @@ static int av7110_attach(struct saa7146_dev* dev, goto err_stop_arm_9; if (FW_VERSION(av7110->arm_app)<0x2501) - printk ("dvb-ttpci: Warning, firmware version 0x%04x is too old. " - "System might be unstable!\n", FW_VERSION(av7110->arm_app)); + printk(KERN_WARNING + "dvb-ttpci: Warning, firmware version 0x%04x is too old. System might be unstable!\n", + FW_VERSION(av7110->arm_app)); thread = kthread_run(arm_thread, (void *) av7110, "arm_mon"); if (IS_ERR(thread)) { @@ -2944,7 +2939,6 @@ static void __exit av7110_exit(void) module_init(av7110_init); module_exit(av7110_exit); -MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by " - "Siemens, Technotrend, Hauppauge"); +MODULE_DESCRIPTION("driver for the SAA7146 based AV110 PCI DVB cards by Siemens, Technotrend, Hauppauge"); MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/pci/ttpci/av7110_hw.c b/drivers/media/pci/ttpci/av7110_hw.c index 0583d56ef5ef..520414cbe087 100644 --- a/drivers/media/pci/ttpci/av7110_hw.c +++ b/drivers/media/pci/ttpci/av7110_hw.c @@ -235,8 +235,7 @@ int av7110_bootarm(struct av7110 *av7110) iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4); if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) { - printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: " - "%08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", + printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n", ret, 0x10325476); return -1; } @@ -262,8 +261,7 @@ int av7110_bootarm(struct av7110 *av7110) iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2); if (saa7146_wait_for_debi_done(av7110->dev, 1)) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "saa7146_wait_for_debi_done() timed out\n"); + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out\n"); return -ETIMEDOUT; } saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); @@ -271,8 +269,7 @@ int av7110_bootarm(struct av7110 *av7110) dprintk(1, "load dram code\n"); if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "load_dram() failed\n"); + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): load_dram() failed\n"); return -1; } @@ -283,8 +280,7 @@ int av7110_bootarm(struct av7110 *av7110) mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram); if (saa7146_wait_for_debi_done(av7110->dev, 1)) { - printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): " - "saa7146_wait_for_debi_done() timed out after loading DRAM\n"); + printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out after loading DRAM\n"); return -ETIMEDOUT; } saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI); diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c index 6f0d0161970e..896c66d4b3ae 100644 --- a/drivers/media/pci/ttpci/budget-av.c +++ b/drivers/media/pci/ttpci/budget-av.c @@ -1636,5 +1636,4 @@ module_exit(budget_av_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB w/ analog input and CI-module (e.g. the KNC cards)"); diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c index 7b27af4d9658..20ad93bf0f54 100644 --- a/drivers/media/pci/ttpci/budget-ci.c +++ b/drivers/media/pci/ttpci/budget-ci.c @@ -1586,6 +1586,4 @@ module_exit(budget_ci_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michael Hunold, Jack Thomasson, Andrew de Quincey, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB cards w/ CI-module produced by " - "Siemens, Technotrend, Hauppauge"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards w/ CI-module produced by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/pci/ttpci/budget-patch.c b/drivers/media/pci/ttpci/budget-patch.c index 591dbdfa2a13..f152eda0123a 100644 --- a/drivers/media/pci/ttpci/budget-patch.c +++ b/drivers/media/pci/ttpci/budget-patch.c @@ -679,5 +679,4 @@ module_exit(budget_patch_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); -MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 " - "based so-called Budget Patch cards"); +MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 based so-called Budget Patch cards"); diff --git a/drivers/media/pci/ttpci/budget.c b/drivers/media/pci/ttpci/budget.c index fb8ede5a1531..3091b480ce22 100644 --- a/drivers/media/pci/ttpci/budget.c +++ b/drivers/media/pci/ttpci/budget.c @@ -897,5 +897,4 @@ module_exit(budget_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others"); -MODULE_DESCRIPTION("driver for the SAA7146 based so-called " - "budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); +MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards by Siemens, Technotrend, Hauppauge"); diff --git a/drivers/media/pci/ttpci/ttpci-eeprom.c b/drivers/media/pci/ttpci/ttpci-eeprom.c index 079ee098b7e3..9534f29c1ffd 100644 --- a/drivers/media/pci/ttpci/ttpci-eeprom.c +++ b/drivers/media/pci/ttpci/ttpci-eeprom.c @@ -171,5 +171,4 @@ EXPORT_SYMBOL(ttpci_eeprom_parse_mac); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, others"); -MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards " - "made by Siemens, Technotrend, Hauppauge"); +MODULE_DESCRIPTION("Decode dvb_net MAC address from EEPROM of PCI DVB cards made by Siemens, Technotrend, Hauppauge"); -- cgit v1.2.3 From db6d8d5fdf9537641c76ba7f32e02b4bcc600972 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:08 -0200 Subject: [media] tw68: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw68/tw68-video.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c index a45e02367321..58c4dd75bfa1 100644 --- a/drivers/media/pci/tw68/tw68-video.c +++ b/drivers/media/pci/tw68/tw68-video.c @@ -279,9 +279,8 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, height /= 2; /* we must set for 1-frame */ pr_debug("%s: width=%d, height=%d, both=%d\n" - " tvnorm h_delay=%d, h_start=%d, h_stop=%d, " - "v_delay=%d, v_start=%d, v_stop=%d\n" , __func__, - width, height, V4L2_FIELD_HAS_BOTH(field), + " tvnorm h_delay=%d, h_start=%d, h_stop=%d, v_delay=%d, v_start=%d, v_stop=%d\n", + __func__, width, height, V4L2_FIELD_HAS_BOTH(field), norm->h_delay, norm->h_start, norm->h_stop, norm->v_delay, norm->video_v_start, norm->video_v_stop); @@ -309,16 +308,15 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, V4L2_FIELD_HAS_TOP(field) ? "T" : "", V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", v4l2_norm_to_name(dev->tvnorm->id)); - pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; " - "vactive=%d, vdelay=%d, vscale=%d\n", __func__, + pr_debug("%s: hactive=%d, hdelay=%d, hscale=%d; vactive=%d, vdelay=%d, vscale=%d\n", + __func__, hactive, hdelay, hscale, vactive, vdelay, vscale); comb = ((vdelay & 0x300) >> 2) | ((vactive & 0x300) >> 4) | ((hdelay & 0x300) >> 6) | ((hactive & 0x300) >> 8); - pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, " - "VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", + pr_debug("%s: setting CROP_HI=%02x, VDELAY_LO=%02x, VACTIVE_LO=%02x, HDELAY_LO=%02x, HACTIVE_LO=%02x\n", __func__, comb, vdelay, vactive, hdelay, hactive); tw_writeb(TW68_CROP_HI, comb); tw_writeb(TW68_VDELAY_LO, vdelay & 0xff); @@ -327,8 +325,8 @@ static int tw68_set_scale(struct tw68_dev *dev, unsigned int width, tw_writeb(TW68_HACTIVE_LO, hactive & 0xff); comb = ((vscale & 0xf00) >> 4) | ((hscale & 0xf00) >> 8); - pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, " - "HSCALE_LO=%02x\n", __func__, comb, vscale, hscale); + pr_debug("%s: setting SCALE_HI=%02x, VSCALE_LO=%02x, HSCALE_LO=%02x\n", + __func__, comb, vscale, hscale); tw_writeb(TW68_SCALE_HI, comb); tw_writeb(TW68_VSCALE_LO, vscale); tw_writeb(TW68_HSCALE_LO, hscale); -- cgit v1.2.3 From ded026e0805fd4aa772716be4ca8e2751d3a7de7 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:08 -0200 Subject: [media] davinci: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Acked-by: Lad, Prabhakar Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/dm355_ccdc.c | 4 ++-- drivers/media/platform/davinci/dm644x_ccdc.c | 4 ++-- drivers/media/platform/davinci/vpbe.c | 15 +++++---------- drivers/media/platform/davinci/vpfe_capture.c | 6 ++---- drivers/media/platform/davinci/vpif_capture.c | 9 ++------- drivers/media/platform/davinci/vpif_display.c | 9 ++------- drivers/media/platform/davinci/vpss.c | 7 +++---- 7 files changed, 18 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/dm355_ccdc.c b/drivers/media/platform/davinci/dm355_ccdc.c index c90b9a4f0c24..65c2973167c6 100644 --- a/drivers/media/platform/davinci/dm355_ccdc.c +++ b/drivers/media/platform/davinci/dm355_ccdc.c @@ -334,8 +334,8 @@ static int ccdc_set_params(void __user *params) x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); if (x) { - dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdc" - "params, %d\n", x); + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying ccdcparams, %d\n", + x); return -EFAULT; } diff --git a/drivers/media/platform/davinci/dm644x_ccdc.c b/drivers/media/platform/davinci/dm644x_ccdc.c index 6fba32bec974..c7523a7e0594 100644 --- a/drivers/media/platform/davinci/dm644x_ccdc.c +++ b/drivers/media/platform/davinci/dm644x_ccdc.c @@ -354,8 +354,8 @@ static int ccdc_set_params(void __user *params) x = copy_from_user(&ccdc_raw_params, params, sizeof(ccdc_raw_params)); if (x) { - dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copying" - "ccdc params, %d\n", x); + dev_dbg(ccdc_cfg.dev, "ccdc_set_params: error in copyingccdc params, %d\n", + x); return -EFAULT; } diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 9a6c2cc38acb..7d2670732805 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -705,15 +705,13 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) "v4l2 sub device %s registered\n", enc_info->module_name); else { - v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s" - " failed to register", + v4l2_err(&vpbe_dev->v4l2_dev, "encoder %s failed to register", enc_info->module_name); ret = -ENODEV; goto fail_kfree_encoders; } } else - v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders" - " currently not supported"); + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c encoders currently not supported"); } /* Add amplifier subdevice for dm365 */ if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) && @@ -735,8 +733,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) amp_info->module_name); } else { vpbe_dev->amp = NULL; - v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers" - " currently not supported"); + v4l2_warn(&vpbe_dev->v4l2_dev, "non-i2c amplifiers currently not supported"); } } else { vpbe_dev->amp = NULL; @@ -835,15 +832,13 @@ static int vpbe_probe(struct platform_device *pdev) if (!cfg->module_name[0] || !cfg->osd.module_name[0] || !cfg->venc.module_name[0]) { - v4l2_err(pdev->dev.driver, "vpbe display module names not" - " defined\n"); + v4l2_err(pdev->dev.driver, "vpbe display module names not defined\n"); return ret; } vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); if (vpbe_dev == NULL) { - v4l2_err(pdev->dev.driver, "Unable to allocate memory" - " for vpbe_device\n"); + v4l2_err(pdev->dev.driver, "Unable to allocate memory for vpbe_device\n"); return -ENOMEM; } vpbe_dev->cfg = cfg; diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 6efb2f1631c4..ca22c3493f55 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -919,8 +919,7 @@ static const struct vpfe_pixel_format * else pixfmt->sizeimage = pixfmt->bytesperline * pixfmt->height; - v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height =" - " %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", + v4l2_info(&vpfe_dev->v4l2_dev, "adjusted width = %d, height = %d, bpp = %d, bytesperline = %d, sizeimage = %d\n", pixfmt->width, pixfmt->height, vpfe_pix_fmt->bpp, pixfmt->bytesperline, pixfmt->sizeimage); return vpfe_pix_fmt; @@ -1088,8 +1087,7 @@ static int vpfe_enum_input(struct file *file, void *priv, &subdev, &index, inp->index) < 0) { - v4l2_err(&vpfe_dev->v4l2_dev, "input information not found" - " for the subdev\n"); + v4l2_err(&vpfe_dev->v4l2_dev, "input information not found for the subdev\n"); return -EINVAL; } sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 5104cc0ee40e..c6a3a904afc8 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1152,11 +1152,7 @@ static int vpif_s_dv_timings(struct file *file, void *priv, timings->bt.vfrontporch && (timings->bt.vbackporch || timings->bt.vsync))) { - vpif_dbg(2, debug, "Timings for width, height, " - "horizontal back porch, horizontal sync, " - "horizontal front porch, vertical back porch, " - "vertical sync and vertical back porch " - "must be defined\n"); + vpif_dbg(2, debug, "Timings for width, height, horizontal back porch, horizontal sync, horizontal front porch, vertical back porch, vertical sync and vertical back porch must be defined\n"); return -EINVAL; } @@ -1181,8 +1177,7 @@ static int vpif_s_dv_timings(struct file *file, void *priv, std_info->l11 = std_info->vsize - (bt->il_vfrontporch - 1); } else { - vpif_dbg(2, debug, "Required timing values for " - "interlaced BT format missing\n"); + vpif_dbg(2, debug, "Required timing values for interlaced BT format missing\n"); return -EINVAL; } } else { diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 75b27233ec2f..6b3ea1e8e97f 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -954,11 +954,7 @@ static int vpif_s_dv_timings(struct file *file, void *priv, timings->bt.vfrontporch && (timings->bt.vbackporch || timings->bt.vsync))) { - vpif_dbg(2, debug, "Timings for width, height, " - "horizontal back porch, horizontal sync, " - "horizontal front porch, vertical back porch, " - "vertical sync and vertical back porch " - "must be defined\n"); + vpif_dbg(2, debug, "Timings for width, height, horizontal back porch, horizontal sync, horizontal front porch, vertical back porch, vertical sync and vertical back porch must be defined\n"); return -EINVAL; } @@ -983,8 +979,7 @@ static int vpif_s_dv_timings(struct file *file, void *priv, std_info->l11 = std_info->vsize - (bt->il_vfrontporch - 1); } else { - vpif_dbg(2, debug, "Required timing values for " - "interlaced BT format missing\n"); + vpif_dbg(2, debug, "Required timing values for interlaced BT format missing\n"); return -EINVAL; } } else { diff --git a/drivers/media/platform/davinci/vpss.c b/drivers/media/platform/davinci/vpss.c index fce86f17dffc..373b796132f2 100644 --- a/drivers/media/platform/davinci/vpss.c +++ b/drivers/media/platform/davinci/vpss.c @@ -261,8 +261,8 @@ static int dm355_enable_clock(enum vpss_clock_sel clock_sel, int en) shift = 6; break; default: - printk(KERN_ERR "dm355_enable_clock:" - " Invalid selector: %d\n", clock_sel); + printk(KERN_ERR "dm355_enable_clock: Invalid selector: %d\n", + clock_sel); return -EINVAL; } @@ -421,8 +421,7 @@ static int vpss_probe(struct platform_device *pdev) else if (!strcmp(platform_name, "dm644x_vpss")) oper_cfg.platform = DM644X; else { - dev_err(&pdev->dev, "vpss driver not supported on" - " this platform\n"); + dev_err(&pdev->dev, "vpss driver not supported on this platform\n"); return -ENODEV; } -- cgit v1.2.3 From 57425dc76d8174e7bfe94a11d089d3feeebb474c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:09 -0200 Subject: [media] exynos4-is: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/media-dev.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c index 1a1154a9dfa4..e3a8709138fa 100644 --- a/drivers/media/platform/exynos4-is/media-dev.c +++ b/drivers/media/platform/exynos4-is/media-dev.c @@ -938,8 +938,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) csis = fmd->csis[pdata->mux_id].sd; if (WARN(csis == NULL, - "MIPI-CSI interface specified " - "but s5p-csis module is not loaded!\n")) + "MIPI-CSI interface specified but s5p-csis module is not loaded!\n")) return -EINVAL; pad = sensor->entity.num_pads - 1; -- cgit v1.2.3 From a4585c31c5018578b4abf699ddfdff719dd1c313 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:09 -0200 Subject: [media] marvell-ccic: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/marvell-ccic/mcam-core.c | 26 +++++++------------------ 1 file changed, 7 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c index af59bf4dca2d..a8bda6679422 100644 --- a/drivers/media/platform/marvell-ccic/mcam-core.c +++ b/drivers/media/platform/marvell-ccic/mcam-core.c @@ -49,24 +49,17 @@ static bool alloc_bufs_at_read; module_param(alloc_bufs_at_read, bool, 0444); MODULE_PARM_DESC(alloc_bufs_at_read, - "Non-zero value causes DMA buffers to be allocated when the " - "video capture device is read, rather than at module load " - "time. This saves memory, but decreases the chances of " - "successfully getting those buffers. This parameter is " - "only used in the vmalloc buffer mode"); + "Non-zero value causes DMA buffers to be allocated when the video capture device is read, rather than at module load time. This saves memory, but decreases the chances of successfully getting those buffers. This parameter is only used in the vmalloc buffer mode"); static int n_dma_bufs = 3; module_param(n_dma_bufs, uint, 0644); MODULE_PARM_DESC(n_dma_bufs, - "The number of DMA buffers to allocate. Can be either two " - "(saves memory, makes timing tighter) or three."); + "The number of DMA buffers to allocate. Can be either two (saves memory, makes timing tighter) or three."); static int dma_buf_size = VGA_WIDTH * VGA_HEIGHT * 2; /* Worst case */ module_param(dma_buf_size, uint, 0444); MODULE_PARM_DESC(dma_buf_size, - "The size of the allocated DMA buffers. If actual operating " - "parameters require larger buffers, an attempt to reallocate " - "will be made."); + "The size of the allocated DMA buffers. If actual operating parameters require larger buffers, an attempt to reallocate will be made."); #else /* MCAM_MODE_VMALLOC */ static const bool alloc_bufs_at_read; static const int n_dma_bufs = 3; /* Used by S/G_PARM */ @@ -75,15 +68,12 @@ static const int n_dma_bufs = 3; /* Used by S/G_PARM */ static bool flip; module_param(flip, bool, 0444); MODULE_PARM_DESC(flip, - "If set, the sensor will be instructed to flip the image " - "vertically."); + "If set, the sensor will be instructed to flip the image vertically."); static int buffer_mode = -1; module_param(buffer_mode, int, 0444); MODULE_PARM_DESC(buffer_mode, - "Set the buffer mode to be used; default is to go with what " - "the platform driver asks for. Set to 0 for vmalloc, 1 for " - "DMA contiguous."); + "Set the buffer mode to be used; default is to go with what the platform driver asks for. Set to 0 for vmalloc, 1 for DMA contiguous."); /* * Status flags. Always manipulated with bit operations. @@ -1759,8 +1749,7 @@ int mccic_register(struct mcam_camera *cam) cam->buffer_mode = buffer_mode; if (cam->buffer_mode == B_DMA_sg && cam->chip_id == MCAM_CAFE) { - printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, " - "attempting vmalloc mode instead\n"); + printk(KERN_ERR "marvell-cam: Cafe can't do S/G I/O, attempting vmalloc mode instead\n"); cam->buffer_mode = B_vmalloc; } if (!mcam_buffer_mode_supported(cam->buffer_mode)) { @@ -1828,8 +1817,7 @@ int mccic_register(struct mcam_camera *cam) */ if (cam->buffer_mode == B_vmalloc && !alloc_bufs_at_read) { if (mcam_alloc_dma_bufs(cam, 1)) - cam_warn(cam, "Unable to alloc DMA buffers at load" - " will try again later."); + cam_warn(cam, "Unable to alloc DMA buffers at load will try again later."); } mutex_unlock(&cam->s_mutex); -- cgit v1.2.3 From bc39030bb2d49cf197bf9714d71ea3fc4a970e60 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:10 -0200 Subject: [media] omap: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap/omap_vout.c | 24 +++++++++++++----------- drivers/media/platform/omap/omap_vout_vrfb.c | 5 +++-- 2 files changed, 16 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c index e668dde6d857..c39b5463e0b3 100644 --- a/drivers/media/platform/omap/omap_vout.c +++ b/drivers/media/platform/omap/omap_vout.c @@ -408,8 +408,8 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout, v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "%s enable=%d addr=%pad width=%d\n height=%d color_mode=%d\n" "rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n" - "out_height=%d rotation_type=%d screen_width=%d\n", - __func__, ovl->is_enabled(ovl), &info.paddr, info.width, info.height, + "out_height=%d rotation_type=%d screen_width=%d\n", __func__, + ovl->is_enabled(ovl), &info.paddr, info.width, info.height, info.color_mode, info.rotation, info.mirror, info.pos_x, info.pos_y, info.out_width, info.out_height, info.rotation_type, info.screen_width); @@ -791,7 +791,8 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q, dma_addr = dma_map_single(vout->vid_dev->v4l2_dev.dev, (void *) addr, size, DMA_TO_DEVICE); if (dma_mapping_error(vout->vid_dev->v4l2_dev.dev, dma_addr)) - v4l2_err(&vout->vid_dev->v4l2_dev, "dma_map_single failed\n"); + v4l2_err(&vout->vid_dev->v4l2_dev, + "dma_map_single failed\n"); vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i]; } @@ -1657,8 +1658,8 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) /* Turn of the pipeline */ ret = omapvid_apply_changes(vout); if (ret) - v4l2_err(&vout->vid_dev->v4l2_dev, "failed to change mode in" - " streamoff\n"); + v4l2_err(&vout->vid_dev->v4l2_dev, + "failed to change mode in streamoff\n"); INIT_LIST_HEAD(&vout->dma_queue); ret = videobuf_streamoff(&vout->vbq); @@ -1858,8 +1859,8 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout) vfd = vout->vfd = video_device_alloc(); if (!vfd) { - printk(KERN_ERR VOUT_NAME ": could not allocate" - " video device struct\n"); + printk(KERN_ERR VOUT_NAME + ": could not allocate video device struct\n"); v4l2_ctrl_handler_free(hdl); return -ENOMEM; } @@ -1984,16 +1985,17 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev) */ vfd = vout->vfd; if (video_register_device(vfd, VFL_TYPE_GRABBER, -1) < 0) { - dev_err(&pdev->dev, ": Could not register " - "Video for Linux device\n"); + dev_err(&pdev->dev, + ": Could not register Video for Linux device\n"); vfd->minor = -1; ret = -ENODEV; goto error2; } video_set_drvdata(vfd, vout); - dev_info(&pdev->dev, ": registered and initialized" - " video device %d\n", vfd->minor); + dev_info(&pdev->dev, + ": registered and initialized video device %d\n", + vfd->minor); if (k == (pdev->num_resources - 1)) return 0; diff --git a/drivers/media/platform/omap/omap_vout_vrfb.c b/drivers/media/platform/omap/omap_vout_vrfb.c index b8638e4e1627..92c4e1826356 100644 --- a/drivers/media/platform/omap/omap_vout_vrfb.c +++ b/drivers/media/platform/omap/omap_vout_vrfb.c @@ -139,8 +139,9 @@ int omap_vout_setup_vrfb_bufs(struct platform_device *pdev, int vid_num, (void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch); if (ret < 0) { vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED; - dev_info(&pdev->dev, ": failed to allocate DMA Channel for" - " video%d\n", vfd->minor); + dev_info(&pdev->dev, + ": failed to allocate DMA Channel for video%d\n", + vfd->minor); } init_waitqueue_head(&vout->vrfb_dma_tx.wait); -- cgit v1.2.3 From d26da99058869a5a655820ea43b86f246bf6874a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:10 -0200 Subject: [media] omap3isp: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 4 +- drivers/media/platform/omap3isp/ispccdc.c | 9 +++-- drivers/media/platform/omap3isp/ispcsi2.c | 13 ++---- drivers/media/platform/omap3isp/ispcsiphy.c | 4 +- drivers/media/platform/omap3isp/isph3a_aewb.c | 8 ++-- drivers/media/platform/omap3isp/isph3a_af.c | 8 ++-- drivers/media/platform/omap3isp/ispstat.c | 58 +++++++++++++++------------ 7 files changed, 54 insertions(+), 50 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 0321d84addc7..2e1b17ef82a3 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -480,8 +480,8 @@ void omap3isp_hist_dma_done(struct isp_device *isp) omap3isp_stat_pcr_busy(&isp->isp_hist)) { /* Histogram cannot be enabled in this frame anymore */ atomic_set(&isp->isp_hist.buf_err, 1); - dev_dbg(isp->dev, "hist: Out of synchronization with " - "CCDC. Ignoring next buffer.\n"); + dev_dbg(isp->dev, + "hist: Out of synchronization with CCDC. Ignoring next buffer.\n"); } } diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c index 882310eb45cc..7207558d722c 100644 --- a/drivers/media/platform/omap3isp/ispccdc.c +++ b/drivers/media/platform/omap3isp/ispccdc.c @@ -151,8 +151,8 @@ static int ccdc_lsc_validate_config(struct isp_ccdc_device *ccdc, } if (lsc_cfg->offset & 3) { - dev_dbg(isp->dev, "CCDC: LSC: Offset must be a multiple of " - "4\n"); + dev_dbg(isp->dev, + "CCDC: LSC: Offset must be a multiple of 4\n"); return -EINVAL; } @@ -416,8 +416,9 @@ static int ccdc_lsc_config(struct isp_ccdc_device *ccdc, return 0; if (update != (OMAP3ISP_CCDC_CONFIG_LSC | OMAP3ISP_CCDC_TBL_LSC)) { - dev_dbg(to_device(ccdc), "%s: Both LSC configuration and table " - "need to be supplied\n", __func__); + dev_dbg(to_device(ccdc), + "%s: Both LSC configuration and table need to be supplied\n", + __func__); return -EINVAL; } diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c index f75a1be29d84..7dae2fe0d42d 100644 --- a/drivers/media/platform/omap3isp/ispcsi2.c +++ b/drivers/media/platform/omap3isp/ispcsi2.c @@ -753,8 +753,8 @@ void omap3isp_csi2_isr(struct isp_csi2_device *csi2) ISPCSI2_PHY_IRQSTATUS); isp_reg_writel(isp, cpxio1_irqstatus, csi2->regs1, ISPCSI2_PHY_IRQSTATUS); - dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ " - "%x\n", cpxio1_irqstatus); + dev_dbg(isp->dev, "CSI2: ComplexIO Error IRQ %x\n", + cpxio1_irqstatus); pipe->error = true; } @@ -763,13 +763,8 @@ void omap3isp_csi2_isr(struct isp_csi2_device *csi2) ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ | ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ | ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) { - dev_dbg(isp->dev, "CSI2 Err:" - " OCP:%d," - " Short_pack:%d," - " ECC:%d," - " CPXIO2:%d," - " FIFO_OVF:%d," - "\n", + dev_dbg(isp->dev, + "CSI2 Err: OCP:%d, Short_pack:%d, ECC:%d, CPXIO2:%d, FIFO_OVF:%d,\n", (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0, (csi2_irqstatus & diff --git a/drivers/media/platform/omap3isp/ispcsiphy.c b/drivers/media/platform/omap3isp/ispcsiphy.c index 495447d66cfd..871d4fe09c7f 100644 --- a/drivers/media/platform/omap3isp/ispcsiphy.c +++ b/drivers/media/platform/omap3isp/ispcsiphy.c @@ -267,8 +267,8 @@ int omap3isp_csiphy_acquire(struct isp_csiphy *phy) int rval; if (phy->vdd == NULL) { - dev_err(phy->isp->dev, "Power regulator for CSI PHY not " - "available\n"); + dev_err(phy->isp->dev, + "Power regulator for CSI PHY not available\n"); return -ENODEV; } diff --git a/drivers/media/platform/omap3isp/isph3a_aewb.c b/drivers/media/platform/omap3isp/isph3a_aewb.c index ccaf92f39236..d44626f20ac6 100644 --- a/drivers/media/platform/omap3isp/isph3a_aewb.c +++ b/drivers/media/platform/omap3isp/isph3a_aewb.c @@ -304,8 +304,8 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) aewb_recover_cfg = devm_kzalloc(isp->dev, sizeof(*aewb_recover_cfg), GFP_KERNEL); if (!aewb_recover_cfg) { - dev_err(aewb->isp->dev, "AEWB: cannot allocate memory for " - "recover configuration.\n"); + dev_err(aewb->isp->dev, + "AEWB: cannot allocate memory for recover configuration.\n"); return -ENOMEM; } @@ -321,8 +321,8 @@ int omap3isp_h3a_aewb_init(struct isp_device *isp) aewb_recover_cfg->subsample_hor_inc = OMAP3ISP_AEWB_MIN_SUB_INC; if (h3a_aewb_validate_params(aewb, aewb_recover_cfg)) { - dev_err(aewb->isp->dev, "AEWB: recover configuration is " - "invalid.\n"); + dev_err(aewb->isp->dev, + "AEWB: recover configuration is invalid.\n"); return -EINVAL; } diff --git a/drivers/media/platform/omap3isp/isph3a_af.c b/drivers/media/platform/omap3isp/isph3a_af.c index 92937f7eecef..99bd6cc21d86 100644 --- a/drivers/media/platform/omap3isp/isph3a_af.c +++ b/drivers/media/platform/omap3isp/isph3a_af.c @@ -367,8 +367,8 @@ int omap3isp_h3a_af_init(struct isp_device *isp) af_recover_cfg = devm_kzalloc(isp->dev, sizeof(*af_recover_cfg), GFP_KERNEL); if (!af_recover_cfg) { - dev_err(af->isp->dev, "AF: cannot allocate memory for recover " - "configuration.\n"); + dev_err(af->isp->dev, + "AF: cannot allocate memory for recover configuration.\n"); return -ENOMEM; } @@ -379,8 +379,8 @@ int omap3isp_h3a_af_init(struct isp_device *isp) af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN; af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN; if (h3a_af_validate_params(af, af_recover_cfg)) { - dev_err(af->isp->dev, "AF: recover configuration is " - "invalid.\n"); + dev_err(af->isp->dev, + "AF: recover configuration is invalid.\n"); return -EINVAL; } diff --git a/drivers/media/platform/omap3isp/ispstat.c b/drivers/media/platform/omap3isp/ispstat.c index 1b9217d3b1b6..47cbc7e3d825 100644 --- a/drivers/media/platform/omap3isp/ispstat.c +++ b/drivers/media/platform/omap3isp/ispstat.c @@ -113,8 +113,9 @@ static int isp_stat_buf_check_magic(struct ispstat *stat, ret = 0; if (ret) { - dev_dbg(stat->isp->dev, "%s: beginning magic check does not " - "match.\n", stat->subdev.name); + dev_dbg(stat->isp->dev, + "%s: beginning magic check does not match.\n", + stat->subdev.name); return ret; } @@ -122,8 +123,9 @@ static int isp_stat_buf_check_magic(struct ispstat *stat, for (w = buf->virt_addr + buf_size, end = w + MAGIC_SIZE; w < end; w++) { if (unlikely(*w != MAGIC_NUM)) { - dev_dbg(stat->isp->dev, "%s: ending magic check does " - "not match.\n", stat->subdev.name); + dev_dbg(stat->isp->dev, + "%s: ending magic check does not match.\n", + stat->subdev.name); return -EINVAL; } } @@ -256,9 +258,9 @@ static void isp_stat_buf_next(struct ispstat *stat) { if (unlikely(stat->active_buf)) /* Overwriting unused active buffer */ - dev_dbg(stat->isp->dev, "%s: new buffer requested without " - "queuing active one.\n", - stat->subdev.name); + dev_dbg(stat->isp->dev, + "%s: new buffer requested without queuing active one.\n", + stat->subdev.name); else stat->active_buf = isp_stat_buf_find_oldest_or_empty(stat); } @@ -292,8 +294,9 @@ static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat, return ERR_PTR(-EBUSY); } if (isp_stat_buf_check_magic(stat, buf)) { - dev_dbg(stat->isp->dev, "%s: current buffer has " - "corrupted data\n.", stat->subdev.name); + dev_dbg(stat->isp->dev, + "%s: current buffer has corrupted data\n.", + stat->subdev.name); /* Mark empty because it doesn't have valid data. */ buf->empty = 1; } else { @@ -307,8 +310,9 @@ static struct ispstat_buffer *isp_stat_buf_get(struct ispstat *stat, spin_unlock_irqrestore(&stat->isp->stat_lock, flags); if (buf->buf_size > data->buf_size) { - dev_warn(stat->isp->dev, "%s: userspace's buffer size is " - "not enough.\n", stat->subdev.name); + dev_warn(stat->isp->dev, + "%s: userspace's buffer size is not enough.\n", + stat->subdev.name); isp_stat_buf_release(stat); return ERR_PTR(-EINVAL); } @@ -531,20 +535,22 @@ int omap3isp_stat_config(struct ispstat *stat, void *new_conf) mutex_lock(&stat->ioctl_lock); - dev_dbg(stat->isp->dev, "%s: configuring module with buffer " - "size=0x%08lx\n", stat->subdev.name, (unsigned long)buf_size); + dev_dbg(stat->isp->dev, + "%s: configuring module with buffer size=0x%08lx\n", + stat->subdev.name, (unsigned long)buf_size); ret = stat->ops->validate_params(stat, new_conf); if (ret) { mutex_unlock(&stat->ioctl_lock); - dev_dbg(stat->isp->dev, "%s: configuration values are " - "invalid.\n", stat->subdev.name); + dev_dbg(stat->isp->dev, "%s: configuration values are invalid.\n", + stat->subdev.name); return ret; } if (buf_size != user_cfg->buf_size) - dev_dbg(stat->isp->dev, "%s: driver has corrected buffer size " - "request to 0x%08lx\n", stat->subdev.name, + dev_dbg(stat->isp->dev, + "%s: driver has corrected buffer size request to 0x%08lx\n", + stat->subdev.name, (unsigned long)user_cfg->buf_size); /* @@ -595,8 +601,9 @@ int omap3isp_stat_config(struct ispstat *stat, void *new_conf) /* Module has a valid configuration. */ stat->configured = 1; - dev_dbg(stat->isp->dev, "%s: module has been successfully " - "configured.\n", stat->subdev.name); + dev_dbg(stat->isp->dev, + "%s: module has been successfully configured.\n", + stat->subdev.name); mutex_unlock(&stat->ioctl_lock); @@ -762,8 +769,8 @@ int omap3isp_stat_enable(struct ispstat *stat, u8 enable) if (!stat->configured && enable) { spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); mutex_unlock(&stat->ioctl_lock); - dev_dbg(stat->isp->dev, "%s: cannot enable module as it's " - "never been successfully configured so far.\n", + dev_dbg(stat->isp->dev, + "%s: cannot enable module as it's never been successfully configured so far.\n", stat->subdev.name); return -EINVAL; } @@ -859,8 +866,8 @@ static void __stat_isr(struct ispstat *stat, int from_dma) if (stat->state == ISPSTAT_ENABLED) { spin_unlock_irqrestore(&stat->isp->stat_lock, irqflags); dev_err(stat->isp->dev, - "%s: interrupt occurred when module was still " - "processing a buffer.\n", stat->subdev.name); + "%s: interrupt occurred when module was still processing a buffer.\n", + stat->subdev.name); ret = STAT_NO_BUF; goto out; } else { @@ -964,8 +971,9 @@ static void __stat_isr(struct ispstat *stat, int from_dma) atomic_set(&stat->buf_err, 1); ret = STAT_NO_BUF; - dev_dbg(stat->isp->dev, "%s: cannot process buffer, " - "device is busy.\n", stat->subdev.name); + dev_dbg(stat->isp->dev, + "%s: cannot process buffer, device is busy.\n", + stat->subdev.name); } out: -- cgit v1.2.3 From c12a5cc61637e8aa87db591be9b1d6dba3f15616 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:10 -0200 Subject: [media] s5p-mfc: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 13 ++++++------- drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c | 7 ++----- 2 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index 52081ddc9bf2..cf787eae11b7 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -793,18 +793,17 @@ static int vidioc_g_crop(struct file *file, void *priv, cr->c.top = top; cr->c.width = ctx->img_width - left - right; cr->c.height = ctx->img_height - top - bottom; - mfc_debug(2, "Cropping info [h264]: l=%d t=%d " - "w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", left, top, - cr->c.width, cr->c.height, right, bottom, - ctx->buf_width, ctx->buf_height); + mfc_debug(2, "Cropping info [h264]: l=%d t=%d w=%d h=%d (r=%d b=%d fw=%d fh=%d\n", + left, top, cr->c.width, cr->c.height, right, bottom, + ctx->buf_width, ctx->buf_height); } else { cr->c.left = 0; cr->c.top = 0; cr->c.width = ctx->img_width; cr->c.height = ctx->img_height; - mfc_debug(2, "Cropping info: w=%d h=%d fw=%d " - "fh=%d\n", cr->c.width, cr->c.height, ctx->buf_width, - ctx->buf_height); + mfc_debug(2, "Cropping info: w=%d h=%d fw=%d fh=%d\n", + cr->c.width, cr->c.height, ctx->buf_width, + ctx->buf_height); } return 0; } 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 81e1e4ce6c24..f4301d5bbd32 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c @@ -1293,14 +1293,11 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx) * First set the output frame buffers */ if (ctx->capture_state != QUEUE_BUFS_MMAPED) { - mfc_err("It seems that not all destionation buffers were " - "mmaped\nMFC requires that all destination are mmaped " - "before starting processing\n"); + mfc_err("It seems that not all destionation buffers were mmaped\nMFC requires that all destination are mmaped before starting processing\n"); return -EAGAIN; } if (list_empty(&ctx->src_queue)) { - mfc_err("Header has been deallocated in the middle of" - " initialization\n"); + mfc_err("Header has been deallocated in the middle of initialization\n"); return -EIO; } temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list); -- cgit v1.2.3 From 7152c88e556bcbee525689063c260cd296f295a8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:11 -0200 Subject: [media] c8sectpfe: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Acked-by: Peter Griffin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 30c148b9d65e..42b123ff2953 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -112,8 +112,7 @@ static void channel_swdemux_tsklet(unsigned long data) buf = (u8 *) channel->back_buffer_aligned; dev_dbg(fei->dev, - "chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\t" - "rp=0x%lx, wp=0x%lx\n", + "chan=%d channel=%p num_packets = %d, buf = %p, pos = 0x%x\n\trp=0x%lx, wp=0x%lx\n", channel->tsin_id, channel, num_packets, buf, pos, rp, wp); for (n = 0; n < num_packets; n++) { @@ -789,8 +788,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) /* sanity check value */ if (tsin->tsin_id > fei->hw_stats.num_ib) { dev_err(&pdev->dev, - "tsin-num %d specified greater than number\n\t" - "of input block hw in SoC! (%d)", + "tsin-num %d specified greater than number\n\tof input block hw in SoC! (%d)", tsin->tsin_id, fei->hw_stats.num_ib); ret = -EINVAL; goto err_clk_disable; @@ -855,8 +853,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) tsin->demux_mapping = index; dev_dbg(fei->dev, - "channel=%p n=%d tsin_num=%d, invert-ts-clk=%d\n\t" - "serial-not-parallel=%d pkt-clk-valid=%d dvb-card=%d\n", + "channel=%p n=%d tsin_num=%d, invert-ts-clk=%d\n\tserial-not-parallel=%d pkt-clk-valid=%d dvb-card=%d\n", fei->channel_data[index], index, tsin->tsin_id, tsin->invert_ts_clk, tsin->serial_not_parallel, tsin->async_not_sync, @@ -1045,8 +1042,8 @@ static void load_imem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr, */ dev_dbg(fei->dev, - "Loading IMEM segment %d 0x%08x\n\t" - " (0x%x bytes) -> 0x%p (0x%x bytes)\n", seg_num, + "Loading IMEM segment %d 0x%08x\n\t (0x%x bytes) -> 0x%p (0x%x bytes)\n", +seg_num, phdr->p_paddr, phdr->p_filesz, dest, phdr->p_memsz + phdr->p_memsz / 3); @@ -1075,8 +1072,7 @@ static void load_dmem_segment(struct c8sectpfei *fei, Elf32_Phdr *phdr, */ dev_dbg(fei->dev, - "Loading DMEM segment %d 0x%08x\n\t" - "(0x%x bytes) -> 0x%p (0x%x bytes)\n", + "Loading DMEM segment %d 0x%08x\n\t(0x%x bytes) -> 0x%p (0x%x bytes)\n", seg_num, phdr->p_paddr, phdr->p_filesz, dst, phdr->p_memsz); -- cgit v1.2.3 From 637d5ac51380b7021c711e183052b81afb89d160 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:11 -0200 Subject: [media] ti-vpe: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Acked-by: Benoit Parrot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 22 ++++++++++------------ drivers/media/platform/ti-vpe/vpe.c | 3 +-- 2 files changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 3e2e3a33e6ed..4aff05915051 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -466,10 +466,10 @@ static void dump_cfd(struct vpdma_cfd *cfd) pr_debug("word2: payload_addr = 0x%08x\n", cfd->payload_addr); - pr_debug("word3: pkt_type = %d, direct = %d, class = %d, dest = %d, " - "payload_len = %d\n", cfd_get_pkt_type(cfd), - cfd_get_direct(cfd), class, cfd_get_dest(cfd), - cfd_get_payload_len(cfd)); + pr_debug("word3: pkt_type = %d, direct = %d, class = %d, dest = %d, payload_len = %d\n", + cfd_get_pkt_type(cfd), + cfd_get_direct(cfd), class, cfd_get_dest(cfd), + cfd_get_payload_len(cfd)); } /* @@ -574,8 +574,7 @@ static void dump_dtd(struct vpdma_dtd *dtd) pr_debug("%s data transfer descriptor for channel %d\n", dir == DTD_DIR_OUT ? "outbound" : "inbound", chan); - pr_debug("word0: data_type = %d, notify = %d, field = %d, 1D = %d, " - "even_ln_skp = %d, odd_ln_skp = %d, line_stride = %d\n", + pr_debug("word0: data_type = %d, notify = %d, field = %d, 1D = %d, even_ln_skp = %d, odd_ln_skp = %d, line_stride = %d\n", dtd_get_data_type(dtd), dtd_get_notify(dtd), dtd_get_field(dtd), dtd_get_1d(dtd), dtd_get_even_line_skip(dtd), dtd_get_odd_line_skip(dtd), dtd_get_line_stride(dtd)); @@ -586,17 +585,16 @@ static void dump_dtd(struct vpdma_dtd *dtd) 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), - dtd_get_mode(dtd), dir, chan, dtd_get_priority(dtd), - dtd_get_next_chan(dtd)); + pr_debug("word3: pkt_type = %d, mode = %d, dir = %d, chan = %d, pri = %d, next_chan = %d\n", + dtd_get_pkt_type(dtd), + dtd_get_mode(dtd), dir, chan, dtd_get_priority(dtd), + dtd_get_next_chan(dtd)); if (dir == DTD_DIR_IN) pr_debug("word4: frame_width = %d, frame_height = %d\n", dtd_get_frame_width(dtd), dtd_get_frame_height(dtd)); else - pr_debug("word4: desc_write_addr = 0x%08x, write_desc = %d, " - "drp_data = %d, use_desc_reg = %d\n", + pr_debug("word4: desc_write_addr = 0x%08x, write_desc = %d, drp_data = %d, use_desc_reg = %d\n", dtd_get_desc_write_addr(dtd), dtd_get_write_desc(dtd), dtd_get_drop_data(dtd), dtd_get_use_desc(dtd)); diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 0189f7f7cb03..1cf4a4c1b899 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1263,8 +1263,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) } if (irqst0 | irqst1) { - dev_warn(dev->v4l2_dev.dev, "Unexpected interrupt: " - "INT0_STATUS0 = 0x%08x, INT0_STATUS1 = 0x%08x\n", + dev_warn(dev->v4l2_dev.dev, "Unexpected interrupt: INT0_STATUS0 = 0x%08x, INT0_STATUS1 = 0x%08x\n", irqst0, irqst1); } -- cgit v1.2.3 From cbfc90809862859a1df6a8b48c7b3c2ac48fdbcd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:12 -0200 Subject: [media] si470x: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si470x/radio-si470x-i2c.c | 7 +++---- drivers/media/radio/si470x/radio-si470x-usb.c | 15 +++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c index ee0470a3196b..9b81969d76b5 100644 --- a/drivers/media/radio/si470x/radio-si470x-i2c.c +++ b/drivers/media/radio/si470x/radio-si470x-i2c.c @@ -387,8 +387,8 @@ static int si470x_i2c_probe(struct i2c_client *client, radio->registers[DEVICEID], radio->registers[SI_CHIPID]); if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&client->dev, - "This driver is known to work with " - "firmware version %hu,\n", RADIO_FW_VERSION); + "This driver is known to work with firmware version %hu,\n", + RADIO_FW_VERSION); dev_warn(&client->dev, "but the device has firmware version %hu.\n", radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE); @@ -400,8 +400,7 @@ static int si470x_i2c_probe(struct i2c_client *client, dev_warn(&client->dev, "If you have some trouble using this driver,\n"); dev_warn(&client->dev, - "please report to V4L ML at " - "linux-media@vger.kernel.org\n"); + "please report to V4L ML at linux-media@vger.kernel.org\n"); } /* set initial frequency */ diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c index 4b132c29f290..1add136d37a3 100644 --- a/drivers/media/radio/si470x/radio-si470x-usb.c +++ b/drivers/media/radio/si470x/radio-si470x-usb.c @@ -351,8 +351,8 @@ static int si470x_get_scratch_page_versions(struct si470x_device *radio) retval = si470x_get_report(radio, radio->usb_buf, SCRATCH_REPORT_SIZE); if (retval < 0) - dev_warn(&radio->intf->dev, "si470x_get_scratch: " - "si470x_get_report returned %d\n", retval); + dev_warn(&radio->intf->dev, "si470x_get_scratch: si470x_get_report returned %d\n", + retval); else { radio->software_version = radio->usb_buf[1]; radio->hardware_version = radio->usb_buf[2]; @@ -688,8 +688,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->registers[DEVICEID], radio->registers[SI_CHIPID]); if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) { dev_warn(&intf->dev, - "This driver is known to work with " - "firmware version %hu,\n", RADIO_FW_VERSION); + "This driver is known to work with firmware version %hu,\n", + RADIO_FW_VERSION); dev_warn(&intf->dev, "but the device has firmware version %hu.\n", radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE); @@ -705,8 +705,8 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->software_version, radio->hardware_version); if (radio->hardware_version < RADIO_HW_VERSION) { dev_warn(&intf->dev, - "This driver is known to work with " - "hardware version %hu,\n", RADIO_HW_VERSION); + "This driver is known to work with hardware version %hu,\n", + RADIO_HW_VERSION); dev_warn(&intf->dev, "but the device has hardware version %hu.\n", radio->hardware_version); @@ -718,8 +718,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, dev_warn(&intf->dev, "If you have some trouble using this driver,\n"); dev_warn(&intf->dev, - "please report to V4L ML at " - "linux-media@vger.kernel.org\n"); + "please report to V4L ML at linux-media@vger.kernel.org\n"); } /* set led to connect state */ -- cgit v1.2.3 From 3c1e300966d7edc380e405b3ab70b6e3c813a121 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:12 -0200 Subject: [media] si4713: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/si4713/si4713.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c index 0b04b56571da..bc2a8b5442ae 100644 --- a/drivers/media/radio/si4713/si4713.c +++ b/drivers/media/radio/si4713/si4713.c @@ -716,9 +716,9 @@ static int si4713_tx_tune_status(struct si4713_device *sdev, u8 intack, *power = val[5]; *antcap = val[6]; *noise = val[7]; - v4l2_dbg(1, debug, &sdev->sd, "%s: response: %d x 10 kHz " - "(power %d, antcap %d, rnl %d)\n", __func__, - *frequency, *power, *antcap, *noise); + v4l2_dbg(1, debug, &sdev->sd, + "%s: response: %d x 10 kHz (power %d, antcap %d, rnl %d)\n", + __func__, *frequency, *power, *antcap, *noise); } return err; @@ -758,10 +758,9 @@ static int si4713_tx_rds_buff(struct si4713_device *sdev, u8 mode, u16 rdsb, v4l2_dbg(1, debug, &sdev->sd, "%s: status=0x%02x\n", __func__, val[0]); *cbleft = (s8)val[2] - val[3]; - v4l2_dbg(1, debug, &sdev->sd, "%s: response: interrupts" - " 0x%02x cb avail: %d cb used %d fifo avail" - " %d fifo used %d\n", __func__, val[1], - val[2], val[3], val[4], val[5]); + v4l2_dbg(1, debug, &sdev->sd, + "%s: response: interrupts 0x%02x cb avail: %d cb used %d fifo avail %d fifo used %d\n", + __func__, val[1], val[2], val[3], val[4], val[5]); } return err; -- cgit v1.2.3 From e84541f0fbf354e989caec58990ac9d543251433 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:12 -0200 Subject: [media] wl128x: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 30 +++++++++++++----------------- drivers/media/radio/wl128x/fmdrv_rx.c | 8 ++++---- 2 files changed, 17 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 642b89c66bcb..6f254e80ffa6 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -230,10 +230,10 @@ inline void dump_rx_skb_data(struct sk_buff *skb) struct fm_event_msg_hdr *evt_hdr; evt_hdr = (struct fm_event_msg_hdr *)skb->data; - printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x " - "opcode:%02x type:%s dlen:%02x", evt_hdr->hdr, evt_hdr->len, - evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op, - (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen); + printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x opcode:%02x type:%s dlen:%02x", + evt_hdr->hdr, evt_hdr->len, + evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->op, + (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen); len_org = skb->len - FM_EVT_MSG_HDR_SIZE; if (len_org > 0) { @@ -271,9 +271,9 @@ static void recv_tasklet(unsigned long arg) /* Process all packets in the RX queue */ while ((skb = skb_dequeue(&fmdev->rx_q))) { if (skb->len < sizeof(struct fm_event_msg_hdr)) { - fmerr("skb(%p) has only %d bytes, " - "at least need %zu bytes to decode\n", skb, - skb->len, sizeof(struct fm_event_msg_hdr)); + fmerr("skb(%p) has only %d bytes, at least need %zu bytes to decode\n", + skb, + skb->len, sizeof(struct fm_event_msg_hdr)); kfree_skb(skb); continue; } @@ -472,8 +472,7 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload, if (!wait_for_completion_timeout(&fmdev->maintask_comp, FM_DRV_TX_TIMEOUT)) { - fmerr("Timeout(%d sec),didn't get reg" - "completion signal from RX tasklet\n", + fmerr("Timeout(%d sec),didn't get regcompletion signal from RX tasklet\n", jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000); return -ETIMEDOUT; } @@ -523,8 +522,7 @@ static inline int check_cmdresp_status(struct fmdev *fmdev, fm_evt_hdr = (void *)(*skb)->data; if (fm_evt_hdr->status != 0) { - fmerr("irq: opcode %x response status is not zero " - "Initiating irq recovery process\n", + fmerr("irq: opcode %x response status is not zero Initiating irq recovery process\n", fm_evt_hdr->op); mod_timer(&fmdev->irq_info.timer, jiffies + FM_DRV_TX_TIMEOUT); @@ -564,8 +562,7 @@ static void int_timeout_handler(unsigned long data) * reset stage index & retry count values */ fmirq->stage = 0; fmirq->retry = 0; - fmerr("Recovery action failed during" - "irq processing, max retry reached\n"); + fmerr("Recovery action failed duringirq processing, max retry reached\n"); return; } fm_irq_call_stage(fmdev, FM_SEND_INTMSK_CMD_IDX); @@ -1516,14 +1513,13 @@ int fmc_prepare(struct fmdev *fmdev) if (!wait_for_completion_timeout(&wait_for_fmdrv_reg_comp, FM_ST_REG_TIMEOUT)) { - fmerr("Timeout(%d sec), didn't get reg " - "completion signal from ST\n", + fmerr("Timeout(%d sec), didn't get reg completion signal from ST\n", jiffies_to_msecs(FM_ST_REG_TIMEOUT) / 1000); return -ETIMEDOUT; } if (fmdev->streg_cbdata != 0) { - fmerr("ST reg comp CB called with error " - "status %d\n", fmdev->streg_cbdata); + fmerr("ST reg comp CB called with error status %d\n", + fmdev->streg_cbdata); return -EAGAIN; } diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c index cfaeb2417fbb..e7455f82fadc 100644 --- a/drivers/media/radio/wl128x/fmdrv_rx.c +++ b/drivers/media/radio/wl128x/fmdrv_rx.c @@ -120,8 +120,8 @@ int fm_rx_set_freq(struct fmdev *fmdev, u32 freq) curr_frq_in_khz = (fmdev->rx.region.bot_freq + ((u32)curr_frq * FM_FREQ_MUL)); if (curr_frq_in_khz != freq) { - pr_info("Frequency is set to (%d) but " - "requested freq is (%d)\n", curr_frq_in_khz, freq); + pr_info("Frequency is set to (%d) but requested freq is (%d)\n", + curr_frq_in_khz, freq); } /* Update local cache */ @@ -390,8 +390,8 @@ int fm_rx_set_region(struct fmdev *fmdev, u8 region_to_set) new_frq = fmdev->rx.region.top_freq; if (new_frq) { - fmdbg("Current freq is not within band limit boundary," - "switching to %d KHz\n", new_frq); + fmdbg("Current freq is not within band limit boundary,switching to %d KHz\n", + new_frq); /* Current RX frequency is not in range. So, update it */ ret = fm_rx_set_freq(fmdev, new_frq); } -- cgit v1.2.3 From 22990690b1881fc2ae2b2c54f042b323a039d741 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:13 -0200 Subject: [media] au0828: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/au0828/au0828-video.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 85dd9a8e83ff..7a10eaa38f67 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -253,8 +253,7 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets, dev->isoc_ctl.transfer_buffer[i] = usb_alloc_coherent(dev->usbdev, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!dev->isoc_ctl.transfer_buffer[i]) { - printk("unable to allocate %i bytes for transfer" - " buffer %i%s\n", + printk("unable to allocate %i bytes for transfer buffer %i%s\n", sb_size, i, in_interrupt() ? " while in int" : ""); au0828_uninit_isoc(dev); -- cgit v1.2.3 From 4a58d39075e1e2bc5ca8b379278659d95f072363 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:13 -0200 Subject: [media] b2c2: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/b2c2/flexcop-usb.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c index 52bc42da8a4c..788c73803138 100644 --- a/drivers/media/usb/b2c2/flexcop-usb.c +++ b/drivers/media/usb/b2c2/flexcop-usb.c @@ -33,8 +33,7 @@ static int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2," - "ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); +MODULE_PARM_DESC(debug, "set debugging level (1=info,ts=2,ctrl=4,i2c=8,v8mem=16 (or-able))." DEBSTATUS); #undef DEBSTATUS #define deb_info(args...) dprintk(0x01, args) @@ -433,8 +432,8 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) frame_size, i, j, ret; int buffer_offset = 0; - deb_ts("creating %d iso-urbs with %d frames " - "each of %d bytes size = %d.\n", B2C2_USB_NUM_ISO_URB, + deb_ts("creating %d iso-urbs with %d frames each of %d bytes size = %d.\n", + B2C2_USB_NUM_ISO_URB, B2C2_USB_FRAMES_PER_ISO, frame_size, bufsize); fc_usb->iso_buffer = usb_alloc_coherent(fc_usb->udev, @@ -459,8 +458,8 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) for (i = 0; i < B2C2_USB_NUM_ISO_URB; i++) { int frame_offset = 0; struct urb *urb = fc_usb->iso_urb[i]; - deb_ts("initializing and submitting urb no. %d " - "(buf_offset: %d).\n", i, buffer_offset); + deb_ts("initializing and submitting urb no. %d (buf_offset: %d).\n", + i, buffer_offset); urb->dev = fc_usb->udev; urb->context = fc_usb; -- cgit v1.2.3 From ca852dcd88bed6c6139362432e12bfd8526ccd56 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:14 -0200 Subject: [media] cpia2: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cpia2/cpia2_usb.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/cpia2/cpia2_usb.c b/drivers/media/usb/cpia2/cpia2_usb.c index e9100a235831..37f9b30b0abc 100644 --- a/drivers/media/usb/cpia2/cpia2_usb.c +++ b/drivers/media/usb/cpia2/cpia2_usb.c @@ -759,9 +759,7 @@ int cpia2_usb_stream_start(struct camera_data *cam, unsigned int alternate) cam->params.camera_state.stream_mode = old_alt; ret2 = set_alternate(cam, USBIF_CMDONLY); if (ret2 < 0) { - ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already " - "failed. Then tried to call " - "set_alternate(USBIF_CMDONLY) = %d.\n", + ERR("cpia2_usb_change_streaming_alternate(%d) =%d has already failed. Then tried to call set_alternate(USBIF_CMDONLY) = %d.\n", alternate, ret, ret2); } } else { -- cgit v1.2.3 From ba1da97e0a9de6dee40f30dd2e2d72e3ebbc99e2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:14 -0200 Subject: [media] cx231xx: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/cx231xx/cx231xx-core.c | 10 ++++------ drivers/media/usb/cx231xx/cx231xx-dvb.c | 4 ++-- 2 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c index 8b099fe1d592..550ec932f931 100644 --- a/drivers/media/usb/cx231xx/cx231xx-core.c +++ b/drivers/media/usb/cx231xx/cx231xx-core.c @@ -241,8 +241,7 @@ static int __usb_control_msg(struct cx231xx *dev, unsigned int pipe, int rc, i; if (reg_debug) { - printk(KERN_DEBUG "%s: (pipe 0x%08x): " - "%s: %02x %02x %02x %02x %02x %02x %02x %02x ", + printk(KERN_DEBUG "%s: (pipe 0x%08x): %s: %02x %02x %02x %02x %02x %02x %02x %02x ", dev->name, pipe, (requesttype & USB_DIR_IN) ? "IN" : "OUT", @@ -441,8 +440,7 @@ int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, char *buf, if (reg_debug) { int byte; - cx231xx_isocdbg("(pipe 0x%08x): " - "OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", + cx231xx_isocdbg("(pipe 0x%08x): OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", pipe, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, req, 0, val, reg & 0xff, @@ -600,8 +598,8 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt) return -1; } - cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u," - "Interface = %d\n", alt, max_pkt_size, + cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u,Interface = %d\n", + alt, max_pkt_size, usb_interface_index); if (usb_interface_index > 0) { diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c index 1417515d30eb..2868546999ca 100644 --- a/drivers/media/usb/cx231xx/cx231xx-dvb.c +++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c @@ -377,8 +377,8 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev) cfg.i2c_addr = addr; if (!dev->dvb->frontend) { - dev_err(dev->dev, "%s/2: dvb frontend not attached. " - "Can't attach xc5000\n", dev->name); + dev_err(dev->dev, "%s/2: dvb frontend not attached. Can't attach xc5000\n", + dev->name); return -EINVAL; } -- cgit v1.2.3 From f319ed911cc8a64ea4a4ddb53633ec1964729108 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:15 -0200 Subject: [media] dvb-usb: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cinergyT2-core.c | 6 ++---- drivers/media/usb/dvb-usb/dib0700_core.c | 5 +---- drivers/media/usb/dvb-usb/dib0700_devices.c | 3 +-- drivers/media/usb/dvb-usb/dvb-usb-dvb.c | 3 +-- drivers/media/usb/dvb-usb/dvb-usb-firmware.c | 6 ++---- drivers/media/usb/dvb-usb/dw2102.c | 10 ++-------- drivers/media/usb/dvb-usb/friio.c | 4 ++-- drivers/media/usb/dvb-usb/gp8psk.c | 3 +-- drivers/media/usb/dvb-usb/opera1.c | 3 +-- drivers/media/usb/dvb-usb/technisat-usb2.c | 3 +-- 10 files changed, 14 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb/cinergyT2-core.c b/drivers/media/usb/dvb-usb/cinergyT2-core.c index 8ac825413d5a..1a198d07e30e 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-core.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-core.c @@ -34,8 +34,7 @@ int dvb_usb_cinergyt2_debug; module_param_named(debug, dvb_usb_cinergyt2_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 " - "(or-able))."); +MODULE_PARM_DESC(debug, "set debugging level (1=info, xfer=2, rc=4 (or-able))."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -94,8 +93,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap) ret = dvb_usb_generic_rw(d, st->data, 1, st->data, 3, 0); if (ret < 0) { - deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep " - "state info\n"); + deb_rc("cinergyt2_power_ctrl() Failed to retrieve sleep state info\n"); } mutex_unlock(&st->data_mutex); diff --git a/drivers/media/usb/dvb-usb/dib0700_core.c b/drivers/media/usb/dvb-usb/dib0700_core.c index 92d5408684ac..47df7135e960 100644 --- a/drivers/media/usb/dvb-usb/dib0700_core.c +++ b/drivers/media/usb/dvb-usb/dib0700_core.c @@ -16,10 +16,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-ab static int nb_packet_buffer_size = 21; module_param(nb_packet_buffer_size, int, 0644); MODULE_PARM_DESC(nb_packet_buffer_size, - "Set the dib0700 driver data buffer size. This parameter " - "corresponds to the number of TS packets. The actual size of " - "the data buffer corresponds to this parameter " - "multiplied by 188 (default: 21)"); + "Set the dib0700 driver data buffer size. This parameter corresponds to the number of TS packets. The actual size of the data buffer corresponds to this parameter multiplied by 188 (default: 21)"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index ef1b8ee75c57..b29d4894c2f1 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -26,8 +26,7 @@ static int force_lna_activation; module_param(force_lna_activation, int, 0644); -MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), " - "if applicable for the device (default: 0=automatic/off)."); +MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplifyer(s) (LNA), if applicable for the device (default: 0=automatic/off)."); struct dib0700_adapter_state { int (*set_param_save) (struct dvb_frontend *); diff --git a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c index a04c0a250625..e5675da286cb 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-dvb.c @@ -277,8 +277,7 @@ int dvb_usb_adapter_frontend_init(struct dvb_usb_adapter *adap) for (i = 0; i < adap->props.num_frontends; i++) { if (adap->props.fe[i].frontend_attach == NULL) { - err("strange: '%s' #%d,%d " - "doesn't want to attach a frontend.", + err("strange: '%s' #%d,%d doesn't want to attach a frontend.", adap->dev->desc->name, adap->id, i); return 0; diff --git a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c index dd048a7c461c..f0023dbb7276 100644 --- a/drivers/media/usb/dvb-usb/dvb-usb-firmware.c +++ b/drivers/media/usb/dvb-usb/dvb-usb-firmware.c @@ -49,8 +49,7 @@ int usb_cypress_load_firmware(struct usb_device *udev, const struct firmware *fw ret = usb_cypress_writemem(udev,hx.addr,hx.data,hx.len); if (ret != hx.len) { - err("error while transferring firmware " - "(transferred size: %d, block size: %d)", + err("error while transferring firmware (transferred size: %d, block size: %d)", ret,hx.len); ret = -EINVAL; break; @@ -81,8 +80,7 @@ int dvb_usb_download_firmware(struct usb_device *udev, struct dvb_usb_device_pro const struct firmware *fw = NULL; if ((ret = request_firmware(&fw, props->firmware, &udev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + err("did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", props->firmware,ret); return ret; } diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 2c720cb2fb00..38794ab8874e 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -86,8 +86,7 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))." /* demod probe */ static int demod_probe = 1; module_param_named(demod, demod_probe, int, 0644); -MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 " - "4=stv0903+stb6100(or-able))."); +MODULE_PARM_DESC(demod, "demod to probe (1=cx24116 2=stv0903+stv6110 4=stv0903+stb6100(or-able))."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); @@ -2343,12 +2342,7 @@ static struct usb_driver dw2102_driver = { module_usb_driver(dw2102_driver); MODULE_AUTHOR("Igor M. Liplianin (c) liplianin@me.by"); -MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104," - " DVB-C 3101 USB2.0," - " TeVii S421, S480, S482, S600, S630, S632, S650," - " TeVii S660, S662, Prof 1100, 7500 USB2.0," - " Geniatech SU3000, T220," - " TechnoTrend S2-4600, Terratec Cinergy S2 devices"); +MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101 USB2.0, TeVii S421, S480, S482, S600, S630, S632, S650, TeVii S660, S662, Prof 1100, 7500 USB2.0, Geniatech SU3000, T220, TechnoTrend S2-4600, Terratec Cinergy S2 devices"); MODULE_VERSION("0.1"); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(DW2101_FIRMWARE); diff --git a/drivers/media/usb/dvb-usb/friio.c b/drivers/media/usb/dvb-usb/friio.c index 474a17e4db0c..62abe6c43a32 100644 --- a/drivers/media/usb/dvb-usb/friio.c +++ b/drivers/media/usb/dvb-usb/friio.c @@ -320,8 +320,8 @@ restart: */ if (rbuf[0] & 0x80) { /* still in PowerOnReset state? */ if (++retry > 3) { - deb_info("failed to get the correct" - " FE demod status:0x%02x\n", rbuf[0]); + deb_info("failed to get the correct FE demod status:0x%02x\n", + rbuf[0]); goto error; } msleep(100); diff --git a/drivers/media/usb/dvb-usb/gp8psk.c b/drivers/media/usb/dvb-usb/gp8psk.c index adfd76491451..db9e9a9721a0 100644 --- a/drivers/media/usb/dvb-usb/gp8psk.c +++ b/drivers/media/usb/dvb-usb/gp8psk.c @@ -131,8 +131,7 @@ static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) u8 *buf; if ((ret = request_firmware(&fw, bcm4500_firmware, &d->udev->dev)) != 0) { - err("did not find the bcm4500 firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + err("did not find the bcm4500 firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", bcm4500_firmware,ret); return ret; } diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c index 2566d2f1c2ad..946a5ccc8f1a 100644 --- a/drivers/media/usb/dvb-usb/opera1.c +++ b/drivers/media/usb/dvb-usb/opera1.c @@ -453,8 +453,7 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev, info("start downloading fpga firmware %s",filename); if ((ret = request_firmware(&fw, filename, &dev->dev)) != 0) { - err("did not find the firmware file. (%s) " - "Please see linux/Documentation/dvb/ for more details on firmware-problems.", + err("did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems.", filename); return ret; } else { diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index 4706628a3ed5..02c3bee6f83b 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -50,8 +50,7 @@ MODULE_PARM_DESC(debug, static int disable_led_control; module_param(disable_led_control, int, 0444); MODULE_PARM_DESC(disable_led_control, - "disable LED control of the device " - "(default: 0 - LED control is active)."); + "disable LED control of the device (default: 0 - LED control is active)."); /* device private data */ struct technisat_usb2_state { -- cgit v1.2.3 From 4ab3200608760981c0d64c42d85edf34eb2659dd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:15 -0200 Subject: [media] dvb-usb-v2: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c | 12 +++++------- drivers/media/usb/dvb-usb-v2/mxl111sf.c | 10 ++++------ 2 files changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c index 283495c84ba3..6427137a09ef 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c @@ -666,8 +666,8 @@ static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, if (rd_status[i] == 0x04) { if (i < 7) { - mxl_i2c("i2c fifo empty!" - " @ %d", i); + mxl_i2c("i2c fifo empty! @ %d", + i); msg->buf[(index*8)+i] = i2c_r_data[(i*3)+1]; /* read again */ @@ -692,8 +692,7 @@ static int mxl111sf_i2c_hw_xfer_msg(struct mxl111sf_state *state, } goto stop_copy; } else { - mxl_i2c("readagain " - "ERROR!"); + mxl_i2c("readagain ERROR!"); } } else { msg->buf[(index*8)+i] = @@ -827,9 +826,8 @@ int mxl111sf_i2c_xfer(struct i2c_adapter *adap, mxl111sf_i2c_hw_xfer_msg(state, &msg[i]) : mxl111sf_i2c_sw_xfer_msg(state, &msg[i]); if (mxl_fail(ret)) { - mxl_debug_adv("failed with error %d on i2c " - "transaction %d of %d, %sing %d bytes " - "to/from 0x%02x", ret, i+1, num, + mxl_debug_adv("failed with error %d on i2c transaction %d of %d, %sing %d bytes to/from 0x%02x", + ret, i+1, num, (msg[i].flags & I2C_M_RD) ? "read" : "writ", msg[i].len, msg[i].addr); diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index 5d676b533a3a..80c635980526 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -29,8 +29,7 @@ int dvb_usb_mxl111sf_debug; module_param_named(debug, dvb_usb_mxl111sf_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debugging level " - "(1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); +MODULE_PARM_DESC(debug, "set debugging level (1=info, 2=xfer, 4=i2c, 8=reg, 16=adv (or-able))."); static int dvb_usb_mxl111sf_isoc; module_param_named(isoc, dvb_usb_mxl111sf_isoc, int, 0644); @@ -137,8 +136,8 @@ int mxl111sf_write_reg_mask(struct mxl111sf_state *state, #if 1 /* dont know why this usually errors out on the first try */ if (mxl_fail(ret)) - pr_err("error writing addr: 0x%02x, mask: 0x%02x, " - "data: 0x%02x, retrying...", addr, mask, data); + pr_err("error writing addr: 0x%02x, mask: 0x%02x, data: 0x%02x, retrying...", + addr, mask, data); ret = mxl111sf_read_reg(state, addr, &val); #endif @@ -946,8 +945,7 @@ static int mxl111sf_init(struct dvb_usb_device *d) case 138001: break; default: - printk(KERN_WARNING "%s: warning: " - "unknown hauppauge model #%d\n", + printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n", __func__, state->tv.model); } #endif -- cgit v1.2.3 From c558d13c216d3baff033025a9ddc6c70a1767031 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:15 -0200 Subject: [media] em28xx: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index bcd6ac61d9f8..898fab136534 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -1561,8 +1561,7 @@ struct em28xx_board em28xx_boards[] = { } }, }, [EM2820_BOARD_PINNACLE_DVC_90] = { - .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker " - "/ Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U", + .name = "Pinnacle Dazzle DVC 90/100/101/107 / Kaiser Baas Video to DVD maker / Kworld DVD Maker 2 / Plextor ConvertX PX-AV100U", .tuner_type = TUNER_ABSENT, /* capture only board */ .decoder = EM28XX_SAA711X, .input = { { -- cgit v1.2.3 From 1ddc9f75a4c95dd284cd33783b72ed0ae4709a09 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:16 -0200 Subject: [media] gspca: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/gspca.c | 3 +-- drivers/media/usb/gspca/m5602/m5602_core.c | 11 ++++------- drivers/media/usb/gspca/mr97310a.c | 3 +-- drivers/media/usb/gspca/ov519.c | 3 +-- drivers/media/usb/gspca/pac207.c | 4 ++-- drivers/media/usb/gspca/pac7302.c | 3 +-- drivers/media/usb/gspca/sn9c20x.c | 6 ++---- drivers/media/usb/gspca/sq905.c | 3 +-- drivers/media/usb/gspca/sq905c.c | 4 ++-- drivers/media/usb/gspca/stv06xx/stv06xx.c | 9 +++------ drivers/media/usb/gspca/sunplus.c | 3 +-- drivers/media/usb/gspca/topro.c | 3 +-- drivers/media/usb/gspca/zc3xx.c | 3 +-- 13 files changed, 21 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index af2395a76d8b..fa2cbb981905 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -201,8 +201,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev, buffer_len = le16_to_cpu(ep->wMaxPacketSize); interval = ep->bInterval; - PDEBUG(D_CONF, "found int in endpoint: 0x%x, " - "buffer_len=%u, interval=%u", + PDEBUG(D_CONF, "found int in endpoint: 0x%x, buffer_len=%u, interval=%u", ep->bEndpointAddress, buffer_len, interval); dev = gspca_dev->dev; diff --git a/drivers/media/usb/gspca/m5602/m5602_core.c b/drivers/media/usb/gspca/m5602/m5602_core.c index e4a0658e3f83..f1dcd9021983 100644 --- a/drivers/media/usb/gspca/m5602/m5602_core.c +++ b/drivers/media/usb/gspca/m5602/m5602_core.c @@ -154,8 +154,8 @@ int m5602_read_sensor(struct sd *sd, const u8 address, err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i])); - PDEBUG(D_CONF, "Reading sensor register " - "0x%x containing 0x%x ", address, *i2c_data); + PDEBUG(D_CONF, "Reading sensor register 0x%x containing 0x%x ", + address, *i2c_data); } return err; } @@ -441,13 +441,10 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); module_param(force_sensor, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(force_sensor, - "forces detection of a sensor, " - "1 = OV9650, 2 = S5K83A, 3 = S5K4AA, " - "4 = MT9M111, 5 = PO1030, 6 = OV7660"); + "forces detection of a sensor, 1 = OV9650, 2 = S5K83A, 3 = S5K4AA, 4 = MT9M111, 5 = PO1030, 6 = OV7660"); module_param(dump_bridge, bool, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(dump_bridge, "Dumps all usb bridge registers at startup"); module_param(dump_sensor, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers " - "at startup providing a sensor is found"); +MODULE_PARM_DESC(dump_sensor, "Dumps all usb sensor registers at startup providing a sensor is found"); diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c index f006e29ca019..6dfb364094ec 100644 --- a/drivers/media/usb/gspca/mr97310a.c +++ b/drivers/media/usb/gspca/mr97310a.c @@ -72,8 +72,7 @@ #define MR97310A_MIN_CLOCKDIV_MAX 8 #define MR97310A_MIN_CLOCKDIV_DEFAULT 3 -MODULE_AUTHOR("Kyle Guinn ," - "Theodore Kilgore "); +MODULE_AUTHOR("Kyle Guinn ,Theodore Kilgore "); MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c index 965372a5ff2f..4dbca54cf2a8 100644 --- a/drivers/media/usb/gspca/ov519.c +++ b/drivers/media/usb/gspca/ov519.c @@ -4326,8 +4326,7 @@ static void ov511_pkt_scan(struct gspca_dev *gspca_dev, /* Frame end */ if ((in[9] + 1) * 8 != gspca_dev->pixfmt.width || (in[10] + 1) * 8 != gspca_dev->pixfmt.height) { - PERR("Invalid frame size, got: %dx%d," - " requested: %dx%d\n", + PERR("Invalid frame size, got: %dx%d, requested: %dx%d\n", (in[9] + 1) * 8, (in[10] + 1) * 8, gspca_dev->pixfmt.width, gspca_dev->pixfmt.height); diff --git a/drivers/media/usb/gspca/pac207.c b/drivers/media/usb/gspca/pac207.c index 07529e5a0c56..51e11248bbb8 100644 --- a/drivers/media/usb/gspca/pac207.c +++ b/drivers/media/usb/gspca/pac207.c @@ -179,8 +179,8 @@ static int sd_config(struct gspca_dev *gspca_dev, } PDEBUG(D_PROBE, - "Pixart PAC207BCA Image Processor and Control Chip detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "Pixart PAC207BCA Image Processor and Control Chip detected (vid/pid 0x%04X:0x%04X)", + id->idVendor, id->idProduct); cam = &gspca_dev->cam; cam->cam_mode = sif_mode; diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index 8b08bd0172f4..be07a24c4518 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -105,8 +105,7 @@ #define PAC7302_EXPOSURE_DEFAULT 66 /* 33 ms / 30 fps */ #define PAC7302_EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ -MODULE_AUTHOR("Jean-Francois Moine , " - "Thomas Kaiser thomas@kaiser-linux.li"); +MODULE_AUTHOR("Jean-Francois Moine , Thomas Kaiser thomas@kaiser-linux.li"); MODULE_DESCRIPTION("Pixart PAC7302"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c index 10269dad9d20..e7430b06526a 100644 --- a/drivers/media/usb/gspca/sn9c20x.c +++ b/drivers/media/usb/gspca/sn9c20x.c @@ -29,8 +29,7 @@ #include -MODULE_AUTHOR("Brian Johnson , " - "microdia project "); +MODULE_AUTHOR("Brian Johnson , microdia project "); MODULE_DESCRIPTION("GSPCA/SN9C20X USB Camera Driver"); MODULE_LICENSE("GPL"); @@ -1948,8 +1947,7 @@ static int sd_isoc_init(struct gspca_dev *gspca_dev) intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface); if (intf->num_altsetting != 9) { - pr_warn("sn9c20x camera with unknown number of alt " - "settings (%d), please report!\n", + pr_warn("sn9c20x camera with unknown number of alt settings (%d), please report!\n", intf->num_altsetting); gspca_dev->alt = intf->num_altsetting; return 0; diff --git a/drivers/media/usb/gspca/sq905.c b/drivers/media/usb/gspca/sq905.c index a7ae0ec9fa91..9424c33f0ddb 100644 --- a/drivers/media/usb/gspca/sq905.c +++ b/drivers/media/usb/gspca/sq905.c @@ -41,8 +41,7 @@ #include #include "gspca.h" -MODULE_AUTHOR("Adam Baker , " - "Theodore Kilgore "); +MODULE_AUTHOR("Adam Baker , Theodore Kilgore "); MODULE_DESCRIPTION("GSPCA/SQ905 USB Camera Driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c index aa21edc9502d..e02b8c1d06a2 100644 --- a/drivers/media/usb/gspca/sq905c.c +++ b/drivers/media/usb/gspca/sq905c.c @@ -210,8 +210,8 @@ static int sd_config(struct gspca_dev *gspca_dev, int ret; PDEBUG(D_PROBE, - "SQ9050 camera detected" - " (vid/pid 0x%04X:0x%04X)", id->idVendor, id->idProduct); + "SQ9050 camera detected (vid/pid 0x%04X:0x%04X)", + id->idVendor, id->idProduct); ret = sq905c_command(gspca_dev, SQ905C_GET_ID, 0); if (ret < 0) { diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index 6ac93d8db427..562ddb050cfd 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -412,8 +412,7 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev, len -= 4; if (len < chunk_len) { - PERR("URB packet length is smaller" - " than the specified chunk length"); + PERR("URB packet length is smaller than the specified chunk length"); gspca_dev->last_packet_type = DISCARD_PACKET; return; } @@ -455,8 +454,7 @@ frame_data: sd->to_skip = gspca_dev->pixfmt.width * 4; if (chunk_len) - PERR("Chunk length is " - "non-zero on a SOF"); + PERR("Chunk length is non-zero on a SOF"); break; case 0x8002: @@ -469,8 +467,7 @@ frame_data: NULL, 0); if (chunk_len) - PERR("Chunk length is " - "non-zero on a EOF"); + PERR("Chunk length is non-zero on a EOF"); break; case 0x0005: diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c index 46c9f2229a18..38dc9e7aa313 100644 --- a/drivers/media/usb/gspca/sunplus.c +++ b/drivers/media/usb/gspca/sunplus.c @@ -368,8 +368,7 @@ static void spca504_read_info(struct gspca_dev *gspca_dev) info[i] = gspca_dev->usb_buf[0]; } PDEBUG(D_STREAM, - "Read info: %d %d %d %d %d %d." - " Should be 1,0,2,2,0,0", + "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0", info[0], info[1], info[2], info[3], info[4], info[5]); } diff --git a/drivers/media/usb/gspca/topro.c b/drivers/media/usb/gspca/topro.c index 15eb069ab60b..983fc6b500af 100644 --- a/drivers/media/usb/gspca/topro.c +++ b/drivers/media/usb/gspca/topro.c @@ -24,8 +24,7 @@ #include "gspca.h" MODULE_DESCRIPTION("Topro TP6800/6810 gspca webcam driver"); -MODULE_AUTHOR("Jean-Francois Moine , " - "Anders Blomdell "); +MODULE_AUTHOR("Jean-Francois Moine , Anders Blomdell "); MODULE_LICENSE("GPL"); static int force_sensor = -1; diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c index 5f7254d2bc9a..d5d8c7e81762 100644 --- a/drivers/media/usb/gspca/zc3xx.c +++ b/drivers/media/usb/gspca/zc3xx.c @@ -25,8 +25,7 @@ #include "gspca.h" #include "jpeg.h" -MODULE_AUTHOR("Jean-Francois Moine , " - "Serge A. Suchkov "); +MODULE_AUTHOR("Jean-Francois Moine , Serge A. Suchkov "); MODULE_DESCRIPTION("GSPCA ZC03xx/VC3xx USB Camera Driver"); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4d5ded751e8651707d5b6b59bcd45576c1b04bff Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:17 -0200 Subject: [media] hdpvr: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-core.c | 9 +++------ drivers/media/usb/hdpvr/hdpvr-i2c.c | 7 +++---- drivers/media/usb/hdpvr/hdpvr-video.c | 4 +--- 3 files changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/hdpvr/hdpvr-core.c b/drivers/media/usb/hdpvr/hdpvr-core.c index a61d8fd63c12..15f016ad5b89 100644 --- a/drivers/media/usb/hdpvr/hdpvr-core.c +++ b/drivers/media/usb/hdpvr/hdpvr-core.c @@ -41,13 +41,11 @@ MODULE_PARM_DESC(hdpvr_debug, "enable debugging output"); static uint default_video_input = HDPVR_VIDEO_INPUTS; module_param(default_video_input, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / " - "1=S-Video / 2=Composite"); +MODULE_PARM_DESC(default_video_input, "default video input: 0=Component / 1=S-Video / 2=Composite"); static uint default_audio_input = HDPVR_AUDIO_INPUTS; module_param(default_audio_input, uint, S_IRUGO|S_IWUSR); -MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / " - "1=RCA front / 2=S/PDIF"); +MODULE_PARM_DESC(default_audio_input, "default audio input: 0=RCA back / 1=RCA front / 2=S/PDIF"); static bool boost_audio; module_param(boost_audio, bool, S_IRUGO|S_IWUSR); @@ -165,8 +163,7 @@ static int device_authorization(struct hdpvr_device *dev) dev->flags |= HDPVR_FLAG_AC3_CAP; break; default: - v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might" - " not work.\n"); + v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might not work.\n"); if (dev->fw_ver >= HDPVR_FIRMWARE_VERSION_AC3) dev->flags |= HDPVR_FLAG_AC3_CAP; else diff --git a/drivers/media/usb/hdpvr/hdpvr-i2c.c b/drivers/media/usb/hdpvr/hdpvr-i2c.c index 9b641c4d4431..fcab55038d99 100644 --- a/drivers/media/usb/hdpvr/hdpvr-i2c.c +++ b/drivers/media/usb/hdpvr/hdpvr-i2c.c @@ -145,15 +145,14 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs, msgs[0].len); } else if (num == 2) { if (msgs[0].addr != msgs[1].addr) { - v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer " - "with conflicting target addresses\n"); + v4l2_warn(&dev->v4l2_dev, "refusing 2-phase i2c xfer with conflicting target addresses\n"); retval = -EINVAL; goto out; } if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD)) { - v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with " - "r0=%d, r1=%d\n", msgs[0].flags & I2C_M_RD, + v4l2_warn(&dev->v4l2_dev, "refusing complex xfer with r0=%d, r1=%d\n", + msgs[0].flags & I2C_M_RD, msgs[1].flags & I2C_M_RD); retval = -EINVAL; goto out; diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 474c11e1d495..e3e7682d0f0e 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -336,9 +336,7 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev) buf = kmalloc(dev->bulk_in_size, GFP_KERNEL); if (!buf) - v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer " - "for emptying the internal device buffer. " - "Next capture start will be slow\n"); + v4l2_err(&dev->v4l2_dev, "failed to allocate temporary buffer for emptying the internal device buffer. Next capture start will be slow\n"); dev->status = STATUS_SHUTTING_DOWN; hdpvr_config_call(dev, CTRL_STOP_STREAMING_VALUE, 0x00); -- cgit v1.2.3 From 96292c89cf1fa700ba086fd7c0e431ac90adba10 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:18 -0200 Subject: [media] pvrusb2: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-audio.c | 4 +- drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c | 4 +- drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c | 4 +- drivers/media/usb/pvrusb2/pvrusb2-debugifc.c | 4 +- drivers/media/usb/pvrusb2/pvrusb2-eeprom.c | 7 +- drivers/media/usb/pvrusb2/pvrusb2-encoder.c | 29 ++-- drivers/media/usb/pvrusb2/pvrusb2-hdw.c | 181 ++++++++---------------- drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c | 33 ++--- drivers/media/usb/pvrusb2/pvrusb2-io.c | 35 ++--- drivers/media/usb/pvrusb2/pvrusb2-ioread.c | 36 ++--- drivers/media/usb/pvrusb2/pvrusb2-std.c | 3 +- drivers/media/usb/pvrusb2/pvrusb2-v4l2.c | 10 +- drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c | 4 +- drivers/media/usb/pvrusb2/pvrusb2-wm8775.c | 3 +- 14 files changed, 118 insertions(+), 239 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c index 5f953d837bf1..3bac50a248d4 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c @@ -74,9 +74,7 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) input = sp->def[hdw->input_val]; } else { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev msp3400 set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", + "*** WARNING *** subdev msp3400 set_input: Invalid routing scheme (%u) and/or input (%d)", sid, hdw->input_val); return; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c index f82f0f0f2c04..7f29a0464f36 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c @@ -72,9 +72,7 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) (hdw->input_val < 0) || (hdw->input_val >= sp->cnt)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev v4l2 set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", + "*** WARNING *** subdev v4l2 set_input: Invalid routing scheme (%u) and/or input (%d)", sid, hdw->input_val); return; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c index 7d675fae1846..30eef97ef2ef 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c @@ -137,9 +137,7 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) (hdw->input_val < 0) || (hdw->input_val >= sp->cnt)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev cx2584x set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", + "*** WARNING *** subdev cx2584x set_input: Invalid routing scheme (%u) and/or input (%d)", sid, hdw->input_val); return; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c index e4022bcb155b..58ec706ebdb3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c @@ -176,9 +176,7 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw, pvr2_stream_get_stats(sp, &stats, 0); ccnt = scnprintf( buf,acnt, - "Bytes streamed=%u" - " URBs: queued=%u idle=%u ready=%u" - " processed=%u failed=%u\n", + "Bytes streamed=%u URBs: queued=%u idle=%u ready=%u processed=%u failed=%u\n", stats.bytes_processed, stats.buffers_in_queue, stats.buffers_in_idle, diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c index e1907cd0c3b7..276b17fb9aad 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c @@ -56,8 +56,7 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); if (!eeprom) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to allocate memory" - " required to read eeprom"); + "Failed to allocate memory required to read eeprom"); return NULL; } @@ -74,8 +73,8 @@ static u8 *pvr2_eeprom_fetch(struct pvr2_hdw *hdw) strange but it's what they do) */ mode16 = (addr & 1); eepromSize = (mode16 ? 4096 : 256); - trace_eeprom("Examining %d byte eeprom at location 0x%x" - " using %d bit addressing",eepromSize,addr, + trace_eeprom("Examining %d byte eeprom at location 0x%x using %d bit addressing", + eepromSize, addr, mode16 ? 16 : 8); msg[0].addr = addr; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c index 593b3e9b6bfd..f0483621d2a3 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c @@ -188,9 +188,7 @@ static int pvr2_encoder_cmd(void *ctxt, if (arg_cnt_send > (ARRAY_SIZE(wrData) - 4)) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Failed to write cx23416 command" - " - too many input arguments" - " (was given %u limit %lu)", + "Failed to write cx23416 command - too many input arguments (was given %u limit %lu)", arg_cnt_send, (long unsigned) ARRAY_SIZE(wrData) - 4); return -EINVAL; } @@ -198,9 +196,7 @@ static int pvr2_encoder_cmd(void *ctxt, if (arg_cnt_recv > (ARRAY_SIZE(rdData) - 4)) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Failed to write cx23416 command" - " - too many return arguments" - " (was given %u limit %lu)", + "Failed to write cx23416 command - too many return arguments (was given %u limit %lu)", arg_cnt_recv, (long unsigned) ARRAY_SIZE(rdData) - 4); return -EINVAL; } @@ -248,14 +244,12 @@ static int pvr2_encoder_cmd(void *ctxt, retry_flag = !0; pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Encoder timed out waiting for us" - "; arranging to retry"); + "Encoder timed out waiting for us; arranging to retry"); } else { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "***WARNING*** device's encoder" - " appears to be stuck" - " (status=0x%08x)",rdData[0]); + "***WARNING*** device's encoder appears to be stuck (status=0x%08x)", +rdData[0]); } pvr2_trace( PVR2_TRACE_ERROR_LEGS, @@ -293,11 +287,7 @@ static int pvr2_encoder_cmd(void *ctxt, } pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Giving up on command." - " This is normally recovered via a firmware" - " reload and re-initialization; concern" - " is only warranted if this happens repeatedly" - " and rapidly."); + "Giving up on command. This is normally recovered via a firmware reload and re-initialization; concern is only warranted if this happens repeatedly and rapidly."); break; } wrData[0] = 0x7; @@ -325,9 +315,7 @@ static int pvr2_encoder_vcmd(struct pvr2_hdw *hdw, int cmd, if (args > ARRAY_SIZE(data)) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Failed to write cx23416 command" - " - too many arguments" - " (was given %u limit %lu)", + "Failed to write cx23416 command - too many arguments (was given %u limit %lu)", args, (long unsigned) ARRAY_SIZE(data)); return -EINVAL; } @@ -433,8 +421,7 @@ int pvr2_encoder_configure(struct pvr2_hdw *hdw) { int ret; int val; - pvr2_trace(PVR2_TRACE_ENCODER,"pvr2_encoder_configure" - " (cx2341x module)"); + pvr2_trace(PVR2_TRACE_ENCODER, "pvr2_encoder_configure (cx2341x module)"); hdw->enc_ctl_state.port = CX2341X_PORT_STREAMING; hdw->enc_ctl_state.width = hdw->res_hor_val; hdw->enc_ctl_state.height = hdw->res_ver_val; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c index 1eb4f7ba2967..e3ed8ffee9f7 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c @@ -1371,8 +1371,7 @@ static int pvr2_locate_firmware(struct pvr2_hdw *hdw, fwnames[idx], &hdw->usb_dev->dev); if (!ret) { - trace_firmware("Located %s firmware: %s;" - " uploading...", + trace_firmware("Located %s firmware: %s; uploading...", fwtypename, fwnames[idx]); return idx; @@ -1383,21 +1382,17 @@ static int pvr2_locate_firmware(struct pvr2_hdw *hdw, return ret; } pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "***WARNING***" - " Device %s firmware" - " seems to be missing.", + "***WARNING*** Device %s firmware seems to be missing.", fwtypename); pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Did you install the pvrusb2 firmware files" - " in their proper location?"); + "Did you install the pvrusb2 firmware files in their proper location?"); if (fwcount == 1) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, "request_firmware unable to locate %s file %s", fwtypename,fwnames[0]); } else { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "request_firmware unable to locate" - " one of the following %s files:", + "request_firmware unable to locate one of the following %s files:", fwtypename); for (idx = 0; idx < fwcount; idx++) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, @@ -1431,8 +1426,7 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) if (!hdw->hdw_desc->fx2_firmware.cnt) { hdw->fw1_state = FW1_STATE_OK; pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Connected device type defines" - " no firmware to upload; ignoring firmware"); + "Connected device type defines no firmware to upload; ignoring firmware"); return -ENOTTY; } @@ -1457,13 +1451,11 @@ static int pvr2_upload_firmware1(struct pvr2_hdw *hdw) (!(hdw->hdw_desc->flag_fx2_16kb && (fwsize == 0x4000)))) { if (hdw->hdw_desc->flag_fx2_16kb) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Wrong fx2 firmware size" - " (expected 8192 or 16384, got %u)", + "Wrong fx2 firmware size (expected 8192 or 16384, got %u)", fwsize); } else { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Wrong fx2 firmware size" - " (expected 8192, got %u)", + "Wrong fx2 firmware size (expected 8192, got %u)", fwsize); } release_firmware(fw_entry); @@ -1585,8 +1577,7 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw) if (fw_len % sizeof(u32)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "size of %s firmware" - " must be a multiple of %zu bytes", + "size of %s firmware must be a multiple of %zu bytes", fw_files[fwidx],sizeof(u32)); release_firmware(fw_entry); ret = -EINVAL; @@ -1887,8 +1878,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) bcnt = pvr2_std_id_to_str(buf,sizeof(buf),hdw->std_mask_eeprom); pvr2_trace(PVR2_TRACE_STD, - "Supported video standard(s) reported available" - " in hardware: %.*s", + "Supported video standard(s) reported available in hardware: %.*s", bcnt,buf); hdw->std_mask_avail = hdw->std_mask_eeprom; @@ -1897,8 +1887,7 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) if (std2) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std2); pvr2_trace(PVR2_TRACE_STD, - "Expanding supported video standards" - " to include: %.*s", + "Expanding supported video standards to include: %.*s", bcnt,buf); hdw->std_mask_avail |= std2; } @@ -1917,8 +1906,8 @@ static void pvr2_hdw_setup_std(struct pvr2_hdw *hdw) if (std3) { bcnt = pvr2_std_id_to_str(buf,sizeof(buf),std3); pvr2_trace(PVR2_TRACE_STD, - "Initial video standard" - " (determined by device type): %.*s",bcnt,buf); + "Initial video standard (determined by device type): %.*s", + bcnt, buf); hdw->std_mask_cur = std3; hdw->std_dirty = !0; return; @@ -1980,8 +1969,7 @@ static void pvr2_hdw_cx25840_vbi_hack(struct pvr2_hdw *hdw) } pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Executing cx25840 VBI hack", + "Module ID %u: Executing cx25840 VBI hack", hdw->decoder_client_id); memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE; @@ -2007,8 +1995,7 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, fname = (mid < ARRAY_SIZE(module_names)) ? module_names[mid] : NULL; if (!fname) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Module ID %u for device %s has no name?" - " The driver might have a configuration problem.", + "Module ID %u for device %s has no name? The driver might have a configuration problem.", mid, hdw->hdw_desc->description); return -EINVAL; @@ -2027,32 +2014,27 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, ARRAY_SIZE(i2caddr)); if (i2ccnt) { pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Using default i2c address list", + "Module ID %u: Using default i2c address list", mid); } } if (!i2ccnt) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Module ID %u (%s) for device %s:" - " No i2c addresses." - " The driver might have a configuration problem.", + "Module ID %u (%s) for device %s: No i2c addresses. The driver might have a configuration problem.", mid, fname, hdw->hdw_desc->description); return -EINVAL; } if (i2ccnt == 1) { pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Setting up with specified i2c address 0x%x", + "Module ID %u: Setting up with specified i2c address 0x%x", mid, i2caddr[0]); sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, fname, i2caddr[0], NULL); } else { pvr2_trace(PVR2_TRACE_INIT, - "Module ID %u:" - " Setting up with address probe list", + "Module ID %u: Setting up with address probe list", mid); sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap, fname, 0, i2caddr); @@ -2060,9 +2042,7 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw, if (!sd) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Module ID %u (%s) for device %s failed to load." - " Possible missing sub-device kernel module or" - " initialization failure within module.", + "Module ID %u (%s) for device %s failed to load. Possible missing sub-device kernel module or initialization failure within module.", mid, fname, hdw->hdw_desc->description); return -EIO; } @@ -2124,18 +2104,14 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) == 0); if (reloadFl) { pvr2_trace(PVR2_TRACE_INIT, - "USB endpoint config looks strange" - "; possibly firmware needs to be" - " loaded"); + "USB endpoint config looks strange; possibly firmware needs to be loaded"); } } if (!reloadFl) { reloadFl = !pvr2_hdw_check_firmware(hdw); if (reloadFl) { pvr2_trace(PVR2_TRACE_INIT, - "Check for FX2 firmware failed" - "; possibly firmware needs to be" - " loaded"); + "Check for FX2 firmware failed; possibly firmware needs to be loaded"); } } if (reloadFl) { @@ -2200,8 +2176,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) if (!pvr2_hdw_dev_ok(hdw)) return; if (ret < 0) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Unable to determine location of eeprom," - " skipping"); + "Unable to determine location of eeprom, skipping"); } else { hdw->eeprom_addr = ret; pvr2_eeprom_analyze(hdw); @@ -2254,8 +2229,7 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw) idx = get_default_error_tolerance(hdw); if (idx) { pvr2_trace(PVR2_TRACE_INIT, - "pvr2_hdw_setup: video stream %p" - " setting tolerance %u", + "pvr2_hdw_setup: video stream %p setting tolerance %u", hdw->vid_stream,idx); } pvr2_stream_setup(hdw->vid_stream,hdw->usb_dev, @@ -2285,16 +2259,13 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw) if (hdw->flag_init_ok) { pvr2_trace( PVR2_TRACE_INFO, - "Device initialization" - " completed successfully."); + "Device initialization completed successfully."); break; } if (hdw->fw1_state == FW1_STATE_RELOAD) { pvr2_trace( PVR2_TRACE_INFO, - "Device microcontroller firmware" - " (re)loaded; it should now reset" - " and reconnect."); + "Device microcontroller firmware (re)loaded; it should now reset and reconnect."); break; } pvr2_trace( @@ -2303,48 +2274,35 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw) if (hdw->fw1_state == FW1_STATE_MISSING) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Giving up since device" - " microcontroller firmware" - " appears to be missing."); + "Giving up since device microcontroller firmware appears to be missing."); break; } } if (hdw->flag_modulefail) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "***WARNING*** pvrusb2 driver initialization" - " failed due to the failure of one or more" - " sub-device kernel modules."); + "***WARNING*** pvrusb2 driver initialization failed due to the failure of one or more sub-device kernel modules."); pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "You need to resolve the failing condition" - " before this driver can function. There" - " should be some earlier messages giving more" - " information about the problem."); + "You need to resolve the failing condition before this driver can function. There should be some earlier messages giving more information about the problem."); break; } if (procreload) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Attempting pvrusb2 recovery by reloading" - " primary firmware."); + "Attempting pvrusb2 recovery by reloading primary firmware."); pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "If this works, device should disconnect" - " and reconnect in a sane state."); + "If this works, device should disconnect and reconnect in a sane state."); hdw->fw1_state = FW1_STATE_UNKNOWN; pvr2_upload_firmware1(hdw); } else { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "***WARNING*** pvrusb2 device hardware" - " appears to be jammed" - " and I can't clear it."); + "***WARNING*** pvrusb2 device hardware appears to be jammed and I can't clear it."); pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "You might need to power cycle" - " the pvrusb2 device" - " in order to recover."); + "You might need to power cycle the pvrusb2 device in order to recover."); } } while (0); pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_setup(hdw=%p) end",hdw); @@ -2396,12 +2354,8 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, hdw_desc = (const struct pvr2_device_desc *)(devid->driver_info); if (hdw_desc == NULL) { - pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create:" - " No device description pointer," - " unable to continue."); - pvr2_trace(PVR2_TRACE_INIT, "If you have a new device type," - " please contact Mike Isely " - " to get it included in the driver\n"); + pvr2_trace(PVR2_TRACE_INIT, "pvr2_hdw_create: No device description pointer, unable to continue."); + pvr2_trace(PVR2_TRACE_INIT, "If you have a new device type, please contact Mike Isely to get it included in the driver\n"); goto fail; } @@ -2413,14 +2367,12 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, if (hdw_desc->flag_is_experimental) { pvr2_trace(PVR2_TRACE_INFO, "**********"); pvr2_trace(PVR2_TRACE_INFO, - "WARNING: Support for this device (%s) is" - " experimental.", hdw_desc->description); + "WARNING: Support for this device (%s) is experimental.", + hdw_desc->description); pvr2_trace(PVR2_TRACE_INFO, - "Important functionality might not be" - " entirely working."); + "Important functionality might not be entirely working."); pvr2_trace(PVR2_TRACE_INFO, - "Please consider contacting the driver author to" - " help with further stabilization of the driver."); + "Please consider contacting the driver author to help with further stabilization of the driver."); pvr2_trace(PVR2_TRACE_INFO, "**********"); } if (!hdw) goto fail; @@ -3375,8 +3327,7 @@ static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) eeprom = kmalloc(EEPROM_SIZE,GFP_KERNEL); if (!eeprom) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to allocate memory" - " required to read eeprom"); + "Failed to allocate memory required to read eeprom"); return NULL; } @@ -3393,8 +3344,8 @@ static u8 *pvr2_full_eeprom_fetch(struct pvr2_hdw *hdw) strange but it's what they do) */ mode16 = (addr & 1); eepromSize = (mode16 ? EEPROM_SIZE : 256); - trace_eeprom("Examining %d byte eeprom at location 0x%x" - " using %d bit addressing",eepromSize,addr, + trace_eeprom("Examining %d byte eeprom at location 0x%x using %d bit addressing", + eepromSize, addr, mode16 ? 16 : 8); msg[0].addr = addr; @@ -3461,8 +3412,8 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw, if (hdw->fw_cpu_flag) { hdw->fw_size = (mode == 1) ? 0x4000 : 0x2000; pvr2_trace(PVR2_TRACE_FIRMWARE, - "Preparing to suck out CPU firmware" - " (size=%u)", hdw->fw_size); + "Preparing to suck out CPU firmware (size=%u)", + hdw->fw_size); hdw->fw_buffer = kzalloc(hdw->fw_size,GFP_KERNEL); if (!hdw->fw_buffer) { hdw->fw_size = 0; @@ -3620,21 +3571,18 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, struct timer_list timer; if (!hdw->ctl_lock_held) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " without lock!!"); + "Attempted to execute control transfer without lock!!"); return -EDEADLK; } if (!hdw->flag_ok && !probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " when device not ok"); + "Attempted to execute control transfer when device not ok"); return -EIO; } if (!(hdw->ctl_read_urb && hdw->ctl_write_urb)) { if (!probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Attempted to execute control transfer" - " when USB is disconnected"); + "Attempted to execute control transfer when USB is disconnected"); } return -ENOTTY; } @@ -3645,16 +3593,14 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, if (write_len > PVR2_CTL_BUFFSIZE) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Attempted to execute %d byte" - " control-write transfer (limit=%d)", + "Attempted to execute %d byte control-write transfer (limit=%d)", write_len,PVR2_CTL_BUFFSIZE); return -EINVAL; } if (read_len > PVR2_CTL_BUFFSIZE) { pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "Attempted to execute %d byte" - " control-read transfer (limit=%d)", + "Attempted to execute %d byte control-read transfer (limit=%d)", write_len,PVR2_CTL_BUFFSIZE); return -EINVAL; } @@ -3703,8 +3649,8 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, status = usb_submit_urb(hdw->ctl_write_urb,GFP_KERNEL); if (status < 0) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to submit write-control" - " URB status=%d",status); + "Failed to submit write-control URB status=%d", +status); hdw->ctl_write_pend_flag = 0; goto done; } @@ -3727,8 +3673,8 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, status = usb_submit_urb(hdw->ctl_read_urb,GFP_KERNEL); if (status < 0) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Failed to submit read-control" - " URB status=%d",status); + "Failed to submit read-control URB status=%d", +status); hdw->ctl_read_pend_flag = 0; goto done; } @@ -3770,8 +3716,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, status = hdw->ctl_write_urb->status; if (!probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB failure," - " status=%d", + "control-write URB failure, status=%d", status); } goto done; @@ -3781,8 +3726,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, status = -EIO; if (!probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-write URB short," - " expected=%d got=%d", + "control-write URB short, expected=%d got=%d", write_len, hdw->ctl_write_urb->actual_length); } @@ -3800,8 +3744,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, status = hdw->ctl_read_urb->status; if (!probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB failure," - " status=%d", + "control-read URB failure, status=%d", status); } goto done; @@ -3811,8 +3754,7 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw, status = -EIO; if (!probe_fl) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "control-read URB short," - " expected=%d got=%d", + "control-read URB short, expected=%d got=%d", read_len, hdw->ctl_read_urb->actual_length); } @@ -4799,9 +4741,7 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, 0); return scnprintf( buf,acnt, - "Bytes streamed=%u" - " URBs: queued=%u idle=%u ready=%u" - " processed=%u failed=%u", + "Bytes streamed=%u URBs: queued=%u idle=%u ready=%u processed=%u failed=%u", stats.bytes_processed, stats.buffers_in_queue, stats.buffers_in_idle, @@ -5013,8 +4953,7 @@ int pvr2_hdw_gpio_chg_dir(struct pvr2_hdw *hdw,u32 msk,u32 val) if (ret) return ret; nval = (cval & ~msk) | (val & msk); pvr2_trace(PVR2_TRACE_GPIO, - "GPIO direction changing 0x%x:0x%x" - " from 0x%x to 0x%x", + "GPIO direction changing 0x%x:0x%x from 0x%x to 0x%x", msk,val,cval,nval); } else { nval = val; @@ -5057,9 +4996,7 @@ void pvr2_hdw_status_poll(struct pvr2_hdw *hdw) now. (Of course, no sub-drivers seem to implement it either. But now it's a a chicken and egg problem...) */ v4l2_device_call_all(&hdw->v4l2_dev, 0, tuner, g_tuner, vtp); - pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll" - " type=%u strength=%u audio=0x%x cap=0x%x" - " low=%u hi=%u", + pvr2_trace(PVR2_TRACE_CHIPS, "subdev status poll type=%u strength=%u audio=0x%x cap=0x%x low=%u hi=%u", vtp->type, vtp->signal, vtp->rxsubchans, vtp->capability, vtp->rangelow, vtp->rangehigh); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 6da5fb544817..48d837e39a9c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -62,8 +62,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ if (!data) length = 0; if (length > (sizeof(hdw->cmd_buffer) - 3)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Killing an I2C write to %u that is too large" - " (desired=%u limit=%u)", + "Killing an I2C write to %u that is too large (desired=%u limit=%u)", i2c_addr, length,(unsigned int)(sizeof(hdw->cmd_buffer) - 3)); return -ENOTSUPP; @@ -90,8 +89,7 @@ static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */ if (hdw->cmd_buffer[0] != 8) { ret = -EIO; if (hdw->cmd_buffer[0] != 7) { - trace_i2c("unexpected status" - " from i2_write[%d]: %d", + trace_i2c("unexpected status from i2_write[%d]: %d", i2c_addr,hdw->cmd_buffer[0]); } } @@ -116,16 +114,14 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */ if (!data) dlen = 0; if (dlen > (sizeof(hdw->cmd_buffer) - 4)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Killing an I2C read to %u that has wlen too large" - " (desired=%u limit=%u)", + "Killing an I2C read to %u that has wlen too large (desired=%u limit=%u)", i2c_addr, dlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 4)); return -ENOTSUPP; } if (res && (rlen > (sizeof(hdw->cmd_buffer) - 1))) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "Killing an I2C read to %u that has rlen too large" - " (desired=%u limit=%u)", + "Killing an I2C read to %u that has rlen too large (desired=%u limit=%u)", i2c_addr, rlen,(unsigned int)(sizeof(hdw->cmd_buffer) - 1)); return -ENOTSUPP; @@ -154,8 +150,7 @@ static int pvr2_i2c_read(struct pvr2_hdw *hdw, /* Context */ if (hdw->cmd_buffer[0] != 8) { ret = -EIO; if (hdw->cmd_buffer[0] != 7) { - trace_i2c("unexpected status" - " from i2_read[%d]: %d", + trace_i2c("unexpected status from i2_read[%d]: %d", i2c_addr,hdw->cmd_buffer[0]); } } @@ -352,13 +347,11 @@ static int i2c_hack_cx25840(struct pvr2_hdw *hdw, if ((ret != 0) || (*rdata == 0x04) || (*rdata == 0x0a)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Detected a wedged cx25840 chip;" - " the device will not work."); + "WARNING: Detected a wedged cx25840 chip; the device will not work."); pvr2_trace(PVR2_TRACE_ERROR_LEGS, "WARNING: Try power cycling the pvrusb2 device."); pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "WARNING: Disabling further access to the device" - " to prevent other foul-ups."); + "WARNING: Disabling further access to the device to prevent other foul-ups."); // This blocks all further communication with the part. hdw->i2c_func[0x44] = NULL; pvr2_hdw_render_useless(hdw); @@ -444,8 +437,7 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, } } else if (num == 2) { if (msgs[0].addr != msgs[1].addr) { - trace_i2c("i2c refusing 2 phase transfer with" - " conflicting target addresses"); + trace_i2c("i2c refusing 2 phase transfer with conflicting target addresses"); ret = -ENOTSUPP; goto done; } @@ -477,8 +469,7 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, ret = 2; goto done; } else { - trace_i2c("i2c refusing complex transfer" - " read0=%d read1=%d", + trace_i2c("i2c refusing complex transfer read0=%d read1=%d", (msgs[0].flags & I2C_M_RD), (msgs[1].flags & I2C_M_RD)); } @@ -492,8 +483,7 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, for (idx = 0; idx < num; idx++) { cnt = msgs[idx].len; printk(KERN_INFO - "pvrusb2 i2c xfer %u/%u:" - " addr=0x%x len=%d %s", + "pvrusb2 i2c xfer %u/%u: addr=0x%x len=%d %s", idx+1,num, msgs[idx].addr, cnt, @@ -668,8 +658,7 @@ void pvr2_i2c_core_init(struct pvr2_hdw *hdw) the emulated IR receiver. */ if (do_i2c_probe(hdw, 0x71)) { pvr2_trace(PVR2_TRACE_INFO, - "Device has newer IR hardware;" - " disabling unneeded virtual IR device"); + "Device has newer IR hardware; disabling unneeded virtual IR device"); hdw->i2c_func[0x18] = NULL; /* Remember that this is a different device... */ hdw->ir_scheme_active = PVR2_IR_SCHEME_24XXX_MCE; diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c index e68ce24f27e3..e3103ecd4828 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-io.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c @@ -113,8 +113,7 @@ static const char *pvr2_buffer_state_decode(enum pvr2_buffer_state st) static void pvr2_buffer_describe(struct pvr2_buffer *bp,const char *msg) { pvr2_trace(PVR2_TRACE_INFO, - "buffer%s%s %p state=%s id=%d status=%d" - " stream=%p purb=%p sig=0x%x", + "buffer%s%s %p state=%s id=%d status=%d stream=%p purb=%p sig=0x%x", (msg ? " " : ""), (msg ? msg : ""), bp, @@ -156,8 +155,7 @@ static void pvr2_buffer_remove(struct pvr2_buffer *bp) (*cnt)--; (*bcnt) -= ccnt; pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s dec cap=%07d cnt=%02d", + "/*---TRACE_FLOW---*/ bufferPool %8s dec cap=%07d cnt=%02d", pvr2_buffer_state_decode(bp->state),*bcnt,*cnt); bp->state = pvr2_buffer_state_none; } @@ -198,8 +196,7 @@ static int pvr2_buffer_set_ready(struct pvr2_buffer *bp) (sp->r_count)++; sp->r_bcount += bp->used_count; pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s inc cap=%07d cnt=%02d", + "/*---TRACE_FLOW---*/ bufferPool %8s inc cap=%07d cnt=%02d", pvr2_buffer_state_decode(bp->state), sp->r_bcount,sp->r_count); spin_unlock_irqrestore(&sp->list_lock,irq_flags); @@ -224,8 +221,7 @@ static void pvr2_buffer_set_idle(struct pvr2_buffer *bp) (sp->i_count)++; sp->i_bcount += bp->max_count; pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s inc cap=%07d cnt=%02d", + "/*---TRACE_FLOW---*/ bufferPool %8s inc cap=%07d cnt=%02d", pvr2_buffer_state_decode(bp->state), sp->i_bcount,sp->i_count); spin_unlock_irqrestore(&sp->list_lock,irq_flags); @@ -249,8 +245,7 @@ static void pvr2_buffer_set_queued(struct pvr2_buffer *bp) (sp->q_count)++; sp->q_bcount += bp->max_count; pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/" - " bufferPool %8s inc cap=%07d cnt=%02d", + "/*---TRACE_FLOW---*/ bufferPool %8s inc cap=%07d cnt=%02d", pvr2_buffer_state_decode(bp->state), sp->q_bcount,sp->q_count); spin_unlock_irqrestore(&sp->list_lock,irq_flags); @@ -293,8 +288,8 @@ static void pvr2_buffer_done(struct pvr2_buffer *bp) bp->signature = 0; bp->stream = NULL; usb_free_urb(bp->purb); - pvr2_trace(PVR2_TRACE_BUF_POOL,"/*---TRACE_FLOW---*/" - " bufferDone %p",bp); + pvr2_trace(PVR2_TRACE_BUF_POOL, "/*---TRACE_FLOW---*/ bufferDone %p", + bp); } static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt) @@ -306,8 +301,7 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp,unsigned int cnt) if (cnt == sp->buffer_total_count) return 0; pvr2_trace(PVR2_TRACE_BUF_POOL, - "/*---TRACE_FLOW---*/ poolResize " - " stream=%p cur=%d adj=%+d", + "/*---TRACE_FLOW---*/ poolResize stream=%p cur=%d adj=%+d", sp, sp->buffer_total_count, cnt-sp->buffer_total_count); @@ -374,8 +368,7 @@ static int pvr2_stream_achieve_buffer_count(struct pvr2_stream *sp) if (sp->buffer_total_count == sp->buffer_target_count) return 0; pvr2_trace(PVR2_TRACE_BUF_POOL, - "/*---TRACE_FLOW---*/" - " poolCheck stream=%p cur=%d tgt=%d", + "/*---TRACE_FLOW---*/ poolCheck stream=%p cur=%d tgt=%d", sp,sp->buffer_total_count,sp->buffer_target_count); if (sp->buffer_total_count < sp->buffer_target_count) { @@ -454,8 +447,8 @@ static void buffer_complete(struct urb *urb) bp->used_count = urb->actual_length; if (sp->fail_count) { pvr2_trace(PVR2_TRACE_TOLERANCE, - "stream %p transfer ok" - " - fail count reset",sp); + "stream %p transfer ok - fail count reset", + sp); sp->fail_count = 0; } } else if (sp->fail_count < sp->fail_tolerance) { @@ -464,8 +457,7 @@ static void buffer_complete(struct urb *urb) (sp->fail_count)++; (sp->buffers_failed)++; pvr2_trace(PVR2_TRACE_TOLERANCE, - "stream %p ignoring error %d" - " - fail count increased to %u", + "stream %p ignoring error %d - fail count increased to %u", sp,urb->status,sp->fail_count); } else { (sp->buffers_failed)++; @@ -666,8 +658,7 @@ int pvr2_buffer_set_buffer(struct pvr2_buffer *bp,void *ptr,unsigned int cnt) bp->max_count = cnt; bp->stream->i_bcount += bp->max_count; pvr2_trace(PVR2_TRACE_BUF_FLOW, - "/*---TRACE_FLOW---*/ bufferPool " - " %8s cap cap=%07d cnt=%02d", + "/*---TRACE_FLOW---*/ bufferPool %8s cap cap=%07d cnt=%02d", pvr2_buffer_state_decode( pvr2_buffer_state_idle), bp->stream->i_bcount,bp->stream->i_count); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c index 614d55767a4e..70b8a052eb5b 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c @@ -169,9 +169,7 @@ static int pvr2_ioread_start(struct pvr2_ioread *cp) stat = pvr2_buffer_queue(bp); if (stat < 0) { pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " pvr2_ioread_start id=%p" - " error=%d", + "/*---TRACE_READ---*/ pvr2_ioread_start id=%p error=%d", cp,stat); pvr2_ioread_stop(cp); return stat; @@ -209,8 +207,8 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) do { if (cp->stream) { pvr2_trace(PVR2_TRACE_START_STOP, - "/*---TRACE_READ---*/" - " pvr2_ioread_setup (tear-down) id=%p",cp); + "/*---TRACE_READ---*/ pvr2_ioread_setup (tear-down) id=%p", + cp); pvr2_ioread_stop(cp); pvr2_stream_kill(cp->stream); if (pvr2_stream_get_buffer_count(cp->stream)) { @@ -220,8 +218,8 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp) } if (sp) { pvr2_trace(PVR2_TRACE_START_STOP, - "/*---TRACE_READ---*/" - " pvr2_ioread_setup (setup) id=%p",cp); + "/*---TRACE_READ---*/ pvr2_ioread_setup (setup) id=%p", + cp); pvr2_stream_kill(sp); ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT); if (ret < 0) { @@ -270,9 +268,7 @@ static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) if (stat < 0) { // Streaming error... pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " pvr2_ioread_read id=%p" - " queue_error=%d", + "/*---TRACE_READ---*/ pvr2_ioread_read id=%p queue_error=%d", cp,stat); pvr2_ioread_stop(cp); return 0; @@ -292,9 +288,7 @@ static int pvr2_ioread_get_buffer(struct pvr2_ioread *cp) if (stat < 0) { // Streaming error... pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " pvr2_ioread_read id=%p" - " buffer_error=%d", + "/*---TRACE_READ---*/ pvr2_ioread_read id=%p buffer_error=%d", cp,stat); pvr2_ioread_stop(cp); // Give up. @@ -347,8 +341,7 @@ static void pvr2_ioread_filter(struct pvr2_ioread *cp) if (cp->sync_buf_offs >= cp->sync_key_len) { cp->sync_trashed_count -= cp->sync_key_len; pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " sync_state <== 2 (skipped %u bytes)", + "/*---TRACE_READ---*/ sync_state <== 2 (skipped %u bytes)", cp->sync_trashed_count); cp->sync_state = 2; cp->sync_buf_offs = 0; @@ -358,8 +351,7 @@ static void pvr2_ioread_filter(struct pvr2_ioread *cp) if (cp->c_data_offs < cp->c_data_len) { // Sanity check - should NEVER get here pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "ERROR: pvr2_ioread filter sync problem" - " len=%u offs=%u", + "ERROR: pvr2_ioread filter sync problem len=%u offs=%u", cp->c_data_len,cp->c_data_offs); // Get out so we don't get stuck in an infinite // loop. @@ -418,8 +410,8 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) if (!cnt) { pvr2_trace(PVR2_TRACE_TRAP, - "/*---TRACE_READ---*/ pvr2_ioread_read id=%p" - " ZERO Request? Returning zero.",cp); + "/*---TRACE_READ---*/ pvr2_ioread_read id=%p ZERO Request? Returning zero.", +cp); return 0; } @@ -477,8 +469,7 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) // Consumed entire key; switch mode // to normal. pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/" - " sync_state <== 0"); + "/*---TRACE_READ---*/ sync_state <== 0"); cp->sync_state = 0; } } else { @@ -502,8 +493,7 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt) } pvr2_trace(PVR2_TRACE_DATA_FLOW, - "/*---TRACE_READ---*/ pvr2_ioread_read" - " id=%p request=%d result=%d", + "/*---TRACE_READ---*/ pvr2_ioread_read id=%p request=%d result=%d", cp,req_cnt,ret); return ret; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c index 9a596a3a4c27..cd7bc18a1ba2 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-std.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c @@ -357,8 +357,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr, bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk); pvr2_trace( PVR2_TRACE_ERROR_LEGS, - "WARNING:" - " Failed to classify the following standard(s): %.*s", + "WARNING: Failed to classify the following standard(s): %.*s", bcnt,buf); } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 2cc4d2b6f810..bbbe18d5275a 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -949,8 +949,8 @@ static long pvr2_v4l2_ioctl(struct file *file, if (ret < 0) { if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { pvr2_trace(PVR2_TRACE_V4LIOCTL, - "pvr2_v4l2_do_ioctl failure, ret=%ld" - " command was:", ret); + "pvr2_v4l2_do_ioctl failure, ret=%ld command was:", +ret); v4l_printk_ioctl(pvr2_hdw_get_driver_name(hdw), cmd); } } else { @@ -1254,8 +1254,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, nr_ptr = video_nr; if (!dip->stream) { pr_err(KBUILD_MODNAME - ": Failed to set up pvrusb2 v4l video dev" - " due to missing stream instance\n"); + ": Failed to set up pvrusb2 v4l video dev due to missing stream instance\n"); return; } break; @@ -1272,8 +1271,7 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, break; default: /* Bail out (this should be impossible) */ - pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev" - " due to unrecognized config\n"); + pr_err(KBUILD_MODNAME ": Failed to set up pvrusb2 v4l dev due to unrecognized config\n"); return; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c index 105123ab36aa..6fee367139aa 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c @@ -91,9 +91,7 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) (hdw->input_val < 0) || (hdw->input_val >= sp->cnt)) { pvr2_trace(PVR2_TRACE_ERROR_LEGS, - "*** WARNING *** subdev v4l2 set_input:" - " Invalid routing scheme (%u)" - " and/or input (%d)", + "*** WARNING *** subdev v4l2 set_input: Invalid routing scheme (%u) and/or input (%d)", sid, hdw->input_val); return; } diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c index f1df94a2436f..7993983de5a6 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c @@ -49,8 +49,7 @@ void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd) input = 2; break; } - pvr2_trace(PVR2_TRACE_CHIPS, "subdev wm8775" - " set_input(val=%d route=0x%x)", + pvr2_trace(PVR2_TRACE_CHIPS, "subdev wm8775 set_input(val=%d route=0x%x)", hdw->input_val, input); sd->ops->audio->s_routing(sd, input, 0, 0); -- cgit v1.2.3 From c91e42f5efea7f2828d6f24165ada97f65f9e7e5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:18 -0200 Subject: [media] pwc: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pwc/pwc-if.c | 4 ++-- drivers/media/usb/pwc/pwc-v4l.c | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index ff657644b6b3..22420c14ac98 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -238,8 +238,8 @@ static void pwc_frame_complete(struct pwc_device *pdev) } else { /* Check for underflow first */ if (fbuf->filled < pdev->frame_total_size) { - PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);" - " discarded.\n", fbuf->filled); + PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes); discarded.\n", + fbuf->filled); } else { fbuf->vb.field = V4L2_FIELD_NONE; fbuf->vb.sequence = pdev->vframe_count; diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c index 3d987984602f..92f04db6bbae 100644 --- a/drivers/media/usb/pwc/pwc-v4l.c +++ b/drivers/media/usb/pwc/pwc-v4l.c @@ -406,8 +406,7 @@ static void pwc_vidioc_fill_fmt(struct v4l2_format *f, f->fmt.pix.bytesperline = f->fmt.pix.width; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.width * 3 / 2; f->fmt.pix.colorspace = V4L2_COLORSPACE_SRGB; - PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() " - "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", + PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.bytesperline, @@ -473,8 +472,7 @@ static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) pixelformat = f->fmt.pix.pixelformat; - PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d " - "format=%c%c%c%c\n", + PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d format=%c%c%c%c\n", f->fmt.pix.width, f->fmt.pix.height, pdev->vframes, (pixelformat)&255, (pixelformat>>8)&255, -- cgit v1.2.3 From 67390d21fe8fefbf961395274f8d67a071306d9a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:19 -0200 Subject: [media] siano: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/siano/smsusb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c index c2e25876e93b..a4dcaec31d02 100644 --- a/drivers/media/usb/siano/smsusb.c +++ b/drivers/media/usb/siano/smsusb.c @@ -604,8 +604,8 @@ static int smsusb_resume(struct usb_interface *intf) intf->cur_altsetting->desc. bInterfaceNumber, 0); if (rc < 0) { - printk(KERN_INFO "%s usb_set_interface failed, " - "rc %d\n", __func__, rc); + printk(KERN_INFO "%s usb_set_interface failed, rc %d\n", + __func__, rc); return rc; } } -- cgit v1.2.3 From b4b3f99c8d77e2edd02fdfc791c194641f3e9fc3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:19 -0200 Subject: [media] stkwebcam: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-sensor.c | 4 ++-- drivers/media/usb/stkwebcam/stk-webcam.c | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/stkwebcam/stk-sensor.c b/drivers/media/usb/stkwebcam/stk-sensor.c index e546b014d7ad..13ad8fdf05bb 100644 --- a/drivers/media/usb/stkwebcam/stk-sensor.c +++ b/drivers/media/usb/stkwebcam/stk-sensor.c @@ -391,8 +391,8 @@ int stk_sensor_init(struct stk_camera *dev) } stk_sensor_write_regvals(dev, ov_initvals); msleep(10); - STK_INFO("OmniVision sensor detected, id %02X%02X" - " at address %x\n", idh, idl, SENSOR_ADDRESS); + STK_INFO("OmniVision sensor detected, id %02X%02X at address %x\n", + idh, idl, SENSOR_ADDRESS); return 0; } diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index 22a9aae16291..e2e7d0f7a43c 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -372,8 +372,7 @@ static void stk_isoc_handler(struct urb *urb) if (fb->v4lbuf.bytesused != 0 && fb->v4lbuf.bytesused != dev->frame_size) { (void) (printk_ratelimit() && - STK_ERROR("frame %d, " - "bytesused=%d, skipping\n", + STK_ERROR("frame %d, bytesused=%d, skipping\n", i, fb->v4lbuf.bytesused)); fb->v4lbuf.bytesused = 0; fill = fb->buffer; -- cgit v1.2.3 From 68616504573945c24fe8f21466967b0d8a5cabf0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:19 -0200 Subject: [media] tm6000: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/tm6000/tm6000-alsa.c | 4 +--- drivers/media/usb/tm6000/tm6000-core.c | 14 ++++++-------- drivers/media/usb/tm6000/tm6000-dvb.c | 16 +++++----------- drivers/media/usb/tm6000/tm6000-i2c.c | 3 +-- drivers/media/usb/tm6000/tm6000-stds.c | 3 +-- drivers/media/usb/tm6000/tm6000-video.c | 18 ++++++++---------- 6 files changed, 22 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c index f16fbd1f9f51..422322541af6 100644 --- a/drivers/media/usb/tm6000/tm6000-alsa.c +++ b/drivers/media/usb/tm6000/tm6000-alsa.c @@ -58,9 +58,7 @@ MODULE_PARM_DESC(index, "Index value for tm6000x capture interface(s)."); MODULE_DESCRIPTION("ALSA driver module for tm5600/tm6000/tm6010 based TV cards"); MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Trident,tm5600}," - "{{Trident,tm6000}," - "{{Trident,tm6010}"); +MODULE_SUPPORTED_DEVICE("{{Trident,tm5600},{{Trident,tm6000},{{Trident,tm6010}"); static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); diff --git a/drivers/media/usb/tm6000/tm6000-core.c b/drivers/media/usb/tm6000/tm6000-core.c index 7c32353c59db..8d104e5c4be3 100644 --- a/drivers/media/usb/tm6000/tm6000-core.c +++ b/drivers/media/usb/tm6000/tm6000-core.c @@ -602,8 +602,8 @@ int tm6000_init(struct tm6000_core *dev) for (i = 0; i < size; i++) { rc = tm6000_set_reg(dev, tab[i].req, tab[i].reg, tab[i].val); if (rc < 0) { - printk(KERN_ERR "Error %i while setting req %d, " - "reg %d to value %d\n", rc, + printk(KERN_ERR "Error %i while setting req %d, reg %d to value %d\n", + rc, tab[i].req, tab[i].reg, tab[i].val); return rc; } @@ -761,9 +761,8 @@ int tm6000_tvaudio_set_mute(struct tm6000_core *dev, u8 mute) if (dev->dev_type == TM6010) tm6010_set_mute_sif(dev, mute); else { - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" - " SIF audio inputs. Please check the %s" - " configuration.\n", dev->name); + printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has SIF audio inputs. Please check the %s configuration.\n", + dev->name); return -EINVAL; } break; @@ -822,9 +821,8 @@ void tm6000_set_volume(struct tm6000_core *dev, int vol) if (dev->dev_type == TM6010) tm6010_set_volume_sif(dev, vol); else - printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has" - " SIF audio inputs. Please check the %s" - " configuration.\n", dev->name); + printk(KERN_INFO "ERROR: TM5600 and TM6000 don't has SIF audio inputs. Please check the %s configuration.\n", + dev->name); break; case TM6000_AMUX_ADC1: case TM6000_AMUX_ADC2: diff --git a/drivers/media/usb/tm6000/tm6000-dvb.c b/drivers/media/usb/tm6000/tm6000-dvb.c index 0426b210383b..70dbaec1219e 100644 --- a/drivers/media/usb/tm6000/tm6000-dvb.c +++ b/drivers/media/usb/tm6000/tm6000-dvb.c @@ -35,9 +35,7 @@ MODULE_DESCRIPTION("DVB driver extension module for tm5600/6000/6010 based TV ca MODULE_AUTHOR("Mauro Carvalho Chehab"); MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("{{Trident, tm5600}," - "{{Trident, tm6000}," - "{{Trident, tm6010}"); +MODULE_SUPPORTED_DEVICE("{{Trident, tm5600},{{Trident, tm6000},{{Trident, tm6010}"); static int debug; @@ -292,13 +290,11 @@ static int register_dvb(struct tm6000_core *dev) } if (!dvb_attach(xc2028_attach, dvb->frontend, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc3028)\n"); + printk(KERN_ERR "tm6000: couldn't register frontend (xc3028)\n"); ret = -EINVAL; goto frontend_err; } - printk(KERN_INFO "tm6000: XC2028/3028 asked to be " - "attached to frontend!\n"); + printk(KERN_INFO "tm6000: XC2028/3028 asked to be attached to frontend!\n"); break; } case TUNER_XC5000: { @@ -315,13 +311,11 @@ static int register_dvb(struct tm6000_core *dev) } if (!dvb_attach(xc5000_attach, dvb->frontend, &dev->i2c_adap, &cfg)) { - printk(KERN_ERR "tm6000: couldn't register " - "frontend (xc5000)\n"); + printk(KERN_ERR "tm6000: couldn't register frontend (xc5000)\n"); ret = -EINVAL; goto frontend_err; } - printk(KERN_INFO "tm6000: XC5000 asked to be " - "attached to frontend!\n"); + printk(KERN_INFO "tm6000: XC5000 asked to be attached to frontend!\n"); break; } } diff --git a/drivers/media/usb/tm6000/tm6000-i2c.c b/drivers/media/usb/tm6000/tm6000-i2c.c index c7e23e3dd75e..b01d3ee56e77 100644 --- a/drivers/media/usb/tm6000/tm6000-i2c.c +++ b/drivers/media/usb/tm6000/tm6000-i2c.c @@ -173,8 +173,7 @@ static int tm6000_i2c_xfer(struct i2c_adapter *i2c_adap, * immediately after a 1 or 2 byte write to select * a register. We cannot fulfil this request. */ - i2c_dprintk(2, " read without preceding write not" - " supported"); + i2c_dprintk(2, " read without preceding write not supported"); rc = -EOPNOTSUPP; goto err; } else if (i + 1 < num && msgs[i].len <= 2 && diff --git a/drivers/media/usb/tm6000/tm6000-stds.c b/drivers/media/usb/tm6000/tm6000-stds.c index 93a4b2434b6e..4064a5e8fae1 100644 --- a/drivers/media/usb/tm6000/tm6000-stds.c +++ b/drivers/media/usb/tm6000/tm6000-stds.c @@ -464,8 +464,7 @@ static int tm6000_load_std(struct tm6000_core *dev, struct tm6000_reg_settings * for (i = 0; set[i].req; i++) { rc = tm6000_set_reg(dev, set[i].req, set[i].reg, set[i].value); if (rc < 0) { - printk(KERN_ERR "Error %i while setting " - "req %d, reg %d to value %d\n", + printk(KERN_ERR "Error %i while setting req %d, reg %d to value %d\n", rc, set[i].req, set[i].reg, set[i].value); return rc; } diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index dee7e7d3d47d..d9f3fa5db8dd 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -615,8 +615,7 @@ static int tm6000_prepare_isoc(struct tm6000_core *dev) return -ENOMEM; } - dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets" - " (%d bytes) of %d bytes each to handle %u size\n", + dprintk(dev, V4L2_DEBUG_QUEUE, "Allocating %d x %d packets (%d bytes) of %d bytes each to handle %u size\n", max_packets, num_bufs, sb_size, dev->isoc_in.maxsize, size); @@ -939,8 +938,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, fmt = format_by_fourcc(f->fmt.pix.pixelformat); if (NULL == fmt) { - dprintk(dev, 2, "Fourcc format (0x%08x)" - " invalid.\n", f->fmt.pix.pixelformat); + dprintk(dev, 2, "Fourcc format (0x%08x) invalid.\n", + f->fmt.pix.pixelformat); return -EINVAL; } @@ -1366,14 +1365,13 @@ static int __tm6000_open(struct file *file) fh->width = dev->width; fh->height = dev->height; - dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, " - "dev->vidq=0x%08lx\n", + dprintk(dev, V4L2_DEBUG_OPEN, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n", (unsigned long)fh, (unsigned long)dev, (unsigned long)&dev->vidq); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " - "queued=%d\n", list_empty(&dev->vidq.queued)); - dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty " - "active=%d\n", list_empty(&dev->vidq.active)); + dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty queued=%d\n", + list_empty(&dev->vidq.queued)); + dprintk(dev, V4L2_DEBUG_OPEN, "Open: list_empty active=%d\n", + list_empty(&dev->vidq.active)); /* initialize hardware on analog mode */ rc = tm6000_init_analog_mode(dev); -- cgit v1.2.3 From 80ebec68ec02a1d03e1dd64248978a91bc93f504 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:20 -0200 Subject: [media] ttusb-budget: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c index d52d4a8d39ad..361e40b56045 100644 --- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c @@ -767,8 +767,7 @@ static void ttusb_iso_irq(struct urb *urb) for (i = 0; i < urb->number_of_packets; ++i) { numpkt++; if (time_after_eq(jiffies, lastj + HZ)) { - dprintk("frames/s: %lu (ts: %d, stuff %d, " - "sec: %d, invalid: %d, all: %d)\n", + dprintk("frames/s: %lu (ts: %d, stuff %d, sec: %d, invalid: %d, all: %d)\n", numpkt * HZ / (jiffies - lastj), numts, numstuff, numsec, numinvalid, numts + numstuff + numsec + numinvalid); -- cgit v1.2.3 From bf769a4e68d1d56674171ab601c23d2db46c6f7a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:20 -0200 Subject: [media] ttusb-dec: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/ttusb-dec/ttusb_dec.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 35d5003ff809..559c823a4fe8 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -708,8 +708,8 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b, dec->packet_payload_length = 2; dec->packet_state = 7; } else { - printk("%s: unknown packet type: " - "%02x%02x\n", __func__, + printk("%s: unknown packet type: %02x%02x\n", + __func__, dec->packet[0], dec->packet[1]); dec->packet_state = 0; } @@ -961,8 +961,8 @@ static int ttusb_dec_start_iso_xfer(struct ttusb_dec *dec) for (i = 0; i < ISO_BUF_COUNT; i++) { if ((result = usb_submit_urb(dec->iso_urb[i], GFP_ATOMIC))) { - printk("%s: failed urb submission %d: " - "error %d\n", __func__, i, result); + printk("%s: failed urb submission %d: error %d\n", + __func__, i, result); while (i) { usb_kill_urb(dec->iso_urb[i - 1]); @@ -1375,8 +1375,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) memcpy(&tmp, &firmware[56], 4); crc32_check = ntohl(tmp); if (crc32_csum != crc32_check) { - printk("%s: crc32 check of DSP code failed (calculated " - "0x%08x != 0x%08x in file), file invalid.\n", + printk("%s: crc32 check of DSP code failed (calculated 0x%08x != 0x%08x in file), file invalid.\n", __func__, crc32_csum, crc32_check); release_firmware(fw_entry); return -ENOENT; @@ -1453,11 +1452,9 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) if (!mode) { if (version == 0xABCDEFAB) - printk(KERN_INFO "ttusb_dec: no version " - "info in Firmware\n"); + printk(KERN_INFO "ttusb_dec: no version info in Firmware\n"); else - printk(KERN_INFO "ttusb_dec: Firmware " - "%x.%02x%c%c\n", + printk(KERN_INFO "ttusb_dec: Firmware %x.%02x%c%c\n", version >> 24, (version >> 16) & 0xff, (version >> 8) & 0xff, version & 0xff); @@ -1481,8 +1478,7 @@ static int ttusb_dec_init_stb(struct ttusb_dec *dec) ttusb_dec_set_model(dec, TTUSB_DEC2540T); break; default: - printk(KERN_ERR "%s: unknown model returned " - "by firmware (%08x) - please report\n", + printk(KERN_ERR "%s: unknown model returned by firmware (%08x) - please report\n", __func__, model); return -ENOENT; } -- cgit v1.2.3 From 02c539d3ea2f5eedf8e15750d924c2430c587111 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:21 -0200 Subject: [media] usbvision: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbvision/usbvision-core.c | 20 ++++++++++---------- drivers/media/usb/usbvision/usbvision-video.c | 4 ++-- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index c23bf73a68ea..bf041a9e69db 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -1656,8 +1656,8 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma (__u16) USBVISION_FILT_CONT, value, 2, HZ); if (rc < 0) { - printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); + printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - reconnect or reload driver.\n", + proc, rc); } usbvision->isoc_mode = format; return rc; @@ -1890,8 +1890,8 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision) (__u16) USBVISION_INTRA_CYC, value, 5, HZ); if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - reconnect or reload driver.\n", + proc, rc); return rc; } @@ -1921,8 +1921,8 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision) (__u16) USBVISION_PCM_THR1, value, 6, HZ); if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - reconnect or reload driver.\n", + proc, rc); } return rc; } @@ -1960,8 +1960,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) rc = usbvision_write_reg(usbvision, USBVISION_VIN_REG1, value[0]); if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - reconnect or reload driver.\n", + proc, rc); return rc; } @@ -2026,8 +2026,8 @@ int usbvision_set_input(struct usb_usbvision *usbvision) USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT, 0, (__u16) USBVISION_LXSIZE_I, value, 8, HZ); if (rc < 0) { - printk(KERN_ERR "%sERROR=%d. USBVISION stopped - " - "reconnect or reload driver.\n", proc, rc); + printk(KERN_ERR "%sERROR=%d. USBVISION stopped - reconnect or reload driver.\n", + proc, rc); return rc; } diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index c8b4eb2ee7a2..a7529196c327 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -1456,8 +1456,8 @@ static int usbvision_probe(struct usb_interface *intf, } if (interface->desc.bNumEndpoints < 2) { - dev_err(&intf->dev, "interface %d has %d endpoints, but must" - " have minimum 2\n", ifnum, interface->desc.bNumEndpoints); + dev_err(&intf->dev, "interface %d has %d endpoints, but must have minimum 2\n", + ifnum, interface->desc.bNumEndpoints); ret = -ENODEV; goto err_usb; } -- cgit v1.2.3 From 3a611875d9719610668d99b9e79c716fd4488cd1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:22 -0200 Subject: [media] zr364xx: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/zr364xx/zr364xx.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index cc128db85723..3950708cbb32 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -633,8 +633,7 @@ static int zr364xx_read_video_callback(struct zr364xx_camera *cam, } else { if (frm->cur_size + purb->actual_length > MAX_FRAME_SIZE) { dev_info(&cam->udev->dev, - "%s: buffer (%d bytes) too small to hold " - "frame data. Discarding frame data.\n", + "%s: buffer (%d bytes) too small to hold frame data. Discarding frame data.\n", __func__, MAX_FRAME_SIZE); } else { pdest += frm->cur_size; @@ -1373,8 +1372,7 @@ static int zr364xx_board_init(struct zr364xx_camera *cam) &cam->buffer.frame[i], i, cam->buffer.frame[i].lpvbits); if (cam->buffer.frame[i].lpvbits == NULL) { - printk(KERN_INFO KBUILD_MODNAME ": out of memory. " - "Using less frames\n"); + printk(KERN_INFO KBUILD_MODNAME ": out of memory. Using less frames\n"); break; } } -- cgit v1.2.3 From 8720427c198b6d36be26d5cd45a487bf7bb49478 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:22 -0200 Subject: [media] v4l2-core: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 91 +++++++++-------------------- drivers/media/v4l2-core/videobuf-core.c | 3 +- drivers/media/v4l2-core/videobuf2-core.c | 25 ++++---- drivers/media/v4l2-core/videobuf2-v4l2.c | 10 ++-- drivers/media/v4l2-core/videobuf2-vmalloc.c | 3 +- 5 files changed, 43 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index c52d94c018bb..26fe7aef1196 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -174,8 +174,7 @@ static void v4l_print_querycap(const void *arg, bool write_only) { const struct v4l2_capability *p = arg; - pr_cont("driver=%.*s, card=%.*s, bus=%.*s, version=0x%08x, " - "capabilities=0x%08x, device_caps=0x%08x\n", + pr_cont("driver=%.*s, card=%.*s, bus=%.*s, version=0x%08x, capabilities=0x%08x, device_caps=0x%08x\n", (int)sizeof(p->driver), p->driver, (int)sizeof(p->card), p->card, (int)sizeof(p->bus_info), p->bus_info, @@ -186,8 +185,7 @@ static void v4l_print_enuminput(const void *arg, bool write_only) { const struct v4l2_input *p = arg; - pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, tuner=%u, " - "std=0x%08Lx, status=0x%x, capabilities=0x%x\n", + pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, tuner=%u, std=0x%08Lx, status=0x%x, capabilities=0x%x\n", p->index, (int)sizeof(p->name), p->name, p->type, p->audioset, p->tuner, (unsigned long long)p->std, p->status, p->capabilities); @@ -197,8 +195,7 @@ static void v4l_print_enumoutput(const void *arg, bool write_only) { const struct v4l2_output *p = arg; - pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, " - "modulator=%u, std=0x%08Lx, capabilities=0x%x\n", + pr_cont("index=%u, name=%.*s, type=%u, audioset=0x%x, modulator=%u, std=0x%08Lx, capabilities=0x%x\n", p->index, (int)sizeof(p->name), p->name, p->type, p->audioset, p->modulator, (unsigned long long)p->std, p->capabilities); } @@ -256,11 +253,7 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_VIDEO_CAPTURE: case V4L2_BUF_TYPE_VIDEO_OUTPUT: pix = &p->fmt.pix; - pr_cont(", width=%u, height=%u, " - "pixelformat=%c%c%c%c, field=%s, " - "bytesperline=%u, sizeimage=%u, colorspace=%d, " - "flags=0x%x, ycbcr_enc=%u, quantization=%u, " - "xfer_func=%u\n", + pr_cont(", width=%u, height=%u, pixelformat=%c%c%c%c, field=%s, bytesperline=%u, sizeimage=%u, colorspace=%d, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", pix->width, pix->height, (pix->pixelformat & 0xff), (pix->pixelformat >> 8) & 0xff, @@ -274,10 +267,7 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: mp = &p->fmt.pix_mp; - pr_cont(", width=%u, height=%u, " - "format=%c%c%c%c, field=%s, " - "colorspace=%d, num_planes=%u, flags=0x%x, " - "ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", + pr_cont(", width=%u, height=%u, format=%c%c%c%c, field=%s, colorspace=%d, num_planes=%u, flags=0x%x, ycbcr_enc=%u, quantization=%u, xfer_func=%u\n", mp->width, mp->height, (mp->pixelformat & 0xff), (mp->pixelformat >> 8) & 0xff, @@ -306,8 +296,7 @@ static void v4l_print_format(const void *arg, bool write_only) case V4L2_BUF_TYPE_VBI_CAPTURE: case V4L2_BUF_TYPE_VBI_OUTPUT: vbi = &p->fmt.vbi; - pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, " - "sample_format=%c%c%c%c, start=%u,%u, count=%u,%u\n", + pr_cont(", sampling_rate=%u, offset=%u, samples_per_line=%u, sample_format=%c%c%c%c, start=%u,%u, count=%u,%u\n", vbi->sampling_rate, vbi->offset, vbi->samples_per_line, (vbi->sample_format & 0xff), @@ -343,9 +332,7 @@ static void v4l_print_framebuffer(const void *arg, bool write_only) { const struct v4l2_framebuffer *p = arg; - pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, " - "height=%u, pixelformat=%c%c%c%c, " - "bytesperline=%u, sizeimage=%u, colorspace=%d\n", + pr_cont("capability=0x%x, flags=0x%x, base=0x%p, width=%u, height=%u, pixelformat=%c%c%c%c, bytesperline=%u, sizeimage=%u, colorspace=%d\n", p->capability, p->flags, p->base, p->fmt.width, p->fmt.height, (p->fmt.pixelformat & 0xff), @@ -368,8 +355,7 @@ static void v4l_print_modulator(const void *arg, bool write_only) if (write_only) pr_cont("index=%u, txsubchans=0x%x\n", p->index, p->txsubchans); else - pr_cont("index=%u, name=%.*s, capability=0x%x, " - "rangelow=%u, rangehigh=%u, txsubchans=0x%x\n", + pr_cont("index=%u, name=%.*s, capability=0x%x, rangelow=%u, rangehigh=%u, txsubchans=0x%x\n", p->index, (int)sizeof(p->name), p->name, p->capability, p->rangelow, p->rangehigh, p->txsubchans); } @@ -381,9 +367,7 @@ static void v4l_print_tuner(const void *arg, bool write_only) if (write_only) pr_cont("index=%u, audmode=%u\n", p->index, p->audmode); else - pr_cont("index=%u, name=%.*s, type=%u, capability=0x%x, " - "rangelow=%u, rangehigh=%u, signal=%u, afc=%d, " - "rxsubchans=0x%x, audmode=%u\n", + pr_cont("index=%u, name=%.*s, type=%u, capability=0x%x, rangelow=%u, rangehigh=%u, signal=%u, afc=%d, rxsubchans=0x%x, audmode=%u\n", p->index, (int)sizeof(p->name), p->name, p->type, p->capability, p->rangelow, p->rangehigh, p->signal, p->afc, @@ -402,8 +386,8 @@ static void v4l_print_standard(const void *arg, bool write_only) { const struct v4l2_standard *p = arg; - pr_cont("index=%u, id=0x%Lx, name=%.*s, fps=%u/%u, " - "framelines=%u\n", p->index, + pr_cont("index=%u, id=0x%Lx, name=%.*s, fps=%u/%u, framelines=%u\n", + p->index, (unsigned long long)p->id, (int)sizeof(p->name), p->name, p->frameperiod.numerator, p->frameperiod.denominator, @@ -419,8 +403,7 @@ static void v4l_print_hw_freq_seek(const void *arg, bool write_only) { const struct v4l2_hw_freq_seek *p = arg; - pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u, " - "rangelow=%u, rangehigh=%u\n", + pr_cont("tuner=%u, type=%u, seek_upward=%u, wrap_around=%u, spacing=%u, rangelow=%u, rangehigh=%u\n", p->tuner, p->type, p->seek_upward, p->wrap_around, p->spacing, p->rangelow, p->rangehigh); } @@ -442,8 +425,7 @@ static void v4l_print_buffer(const void *arg, bool write_only) const struct v4l2_plane *plane; int i; - pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, " - "flags=0x%08x, field=%s, sequence=%d, memory=%s", + pr_cont("%02ld:%02d:%02d.%08ld index=%d, type=%s, flags=0x%08x, field=%s, sequence=%d, memory=%s", p->timestamp.tv_sec / 3600, (int)(p->timestamp.tv_sec / 60) % 60, (int)(p->timestamp.tv_sec % 60), @@ -458,8 +440,7 @@ static void v4l_print_buffer(const void *arg, bool write_only) for (i = 0; i < p->length; ++i) { plane = &p->m.planes[i]; printk(KERN_DEBUG - "plane %d: bytesused=%d, data_offset=0x%08x, " - "offset/userptr=0x%lx, length=%d\n", + "plane %d: bytesused=%d, data_offset=0x%08x, offset/userptr=0x%lx, length=%d\n", i, plane->bytesused, plane->data_offset, plane->m.userptr, plane->length); } @@ -468,8 +449,7 @@ static void v4l_print_buffer(const void *arg, bool write_only) p->bytesused, p->m.userptr, p->length); } - printk(KERN_DEBUG "timecode=%02d:%02d:%02d type=%d, " - "flags=0x%08x, frames=%d, userbits=0x%08x\n", + printk(KERN_DEBUG "timecode=%02d:%02d:%02d type=%d, flags=0x%08x, frames=%d, userbits=0x%08x\n", tc->hours, tc->minutes, tc->seconds, tc->type, tc->flags, tc->frames, *(__u32 *)tc->userbits); } @@ -503,8 +483,7 @@ static void v4l_print_streamparm(const void *arg, bool write_only) p->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { const struct v4l2_captureparm *c = &p->parm.capture; - pr_cont(", capability=0x%x, capturemode=0x%x, timeperframe=%d/%d, " - "extendedmode=%d, readbuffers=%d\n", + pr_cont(", capability=0x%x, capturemode=0x%x, timeperframe=%d/%d, extendedmode=%d, readbuffers=%d\n", c->capability, c->capturemode, c->timeperframe.numerator, c->timeperframe.denominator, c->extendedmode, c->readbuffers); @@ -512,8 +491,7 @@ static void v4l_print_streamparm(const void *arg, bool write_only) p->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { const struct v4l2_outputparm *c = &p->parm.output; - pr_cont(", capability=0x%x, outputmode=0x%x, timeperframe=%d/%d, " - "extendedmode=%d, writebuffers=%d\n", + pr_cont(", capability=0x%x, outputmode=0x%x, timeperframe=%d/%d, extendedmode=%d, writebuffers=%d\n", c->capability, c->outputmode, c->timeperframe.numerator, c->timeperframe.denominator, c->extendedmode, c->writebuffers); @@ -526,8 +504,7 @@ static void v4l_print_queryctrl(const void *arg, bool write_only) { const struct v4l2_queryctrl *p = arg; - pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%d/%d, " - "step=%d, default=%d, flags=0x%08x\n", + pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%d/%d, step=%d, default=%d, flags=0x%08x\n", p->id, p->type, (int)sizeof(p->name), p->name, p->minimum, p->maximum, p->step, p->default_value, p->flags); @@ -537,9 +514,7 @@ static void v4l_print_query_ext_ctrl(const void *arg, bool write_only) { const struct v4l2_query_ext_ctrl *p = arg; - pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%lld/%lld, " - "step=%lld, default=%lld, flags=0x%08x, elem_size=%u, elems=%u, " - "nr_of_dims=%u, dims=%u,%u,%u,%u\n", + pr_cont("id=0x%x, type=%d, name=%.*s, min/max=%lld/%lld, step=%lld, default=%lld, flags=0x%08x, elem_size=%u, elems=%u, nr_of_dims=%u, dims=%u,%u,%u,%u\n", p->id, p->type, (int)sizeof(p->name), p->name, p->minimum, p->maximum, p->step, p->default_value, p->flags, @@ -583,9 +558,7 @@ static void v4l_print_cropcap(const void *arg, bool write_only) { const struct v4l2_cropcap *p = arg; - pr_cont("type=%s, bounds wxh=%dx%d, x,y=%d,%d, " - "defrect wxh=%dx%d, x,y=%d,%d, " - "pixelaspect %d/%d\n", + pr_cont("type=%s, bounds wxh=%dx%d, x,y=%d,%d, defrect wxh=%dx%d, x,y=%d,%d, pixelaspect %d/%d\n", prt_names(p->type, v4l2_type_names), p->bounds.width, p->bounds.height, p->bounds.left, p->bounds.top, @@ -618,8 +591,7 @@ static void v4l_print_jpegcompression(const void *arg, bool write_only) { const struct v4l2_jpegcompression *p = arg; - pr_cont("quality=%d, APPn=%d, APP_len=%d, " - "COM_len=%d, jpeg_markers=0x%x\n", + pr_cont("quality=%d, APPn=%d, APP_len=%d, COM_len=%d, jpeg_markers=0x%x\n", p->quality, p->APPn, p->APP_len, p->COM_len, p->jpeg_markers); } @@ -686,14 +658,7 @@ static void v4l_print_dv_timings(const void *arg, bool write_only) switch (p->type) { case V4L2_DV_BT_656_1120: - pr_cont("type=bt-656/1120, interlaced=%u, " - "pixelclock=%llu, " - "width=%u, height=%u, polarities=0x%x, " - "hfrontporch=%u, hsync=%u, " - "hbackporch=%u, vfrontporch=%u, " - "vsync=%u, vbackporch=%u, " - "il_vfrontporch=%u, il_vsync=%u, " - "il_vbackporch=%u, standards=0x%x, flags=0x%x\n", + pr_cont("type=bt-656/1120, interlaced=%u, pixelclock=%llu, width=%u, height=%u, polarities=0x%x, hfrontporch=%u, hsync=%u, hbackporch=%u, vfrontporch=%u, vsync=%u, vbackporch=%u, il_vfrontporch=%u, il_vsync=%u, il_vbackporch=%u, standards=0x%x, flags=0x%x\n", p->bt.interlaced, p->bt.pixelclock, p->bt.width, p->bt.height, p->bt.polarities, p->bt.hfrontporch, @@ -723,8 +688,7 @@ static void v4l_print_dv_timings_cap(const void *arg, bool write_only) switch (p->type) { case V4L2_DV_BT_656_1120: - pr_cont("type=bt-656/1120, width=%u-%u, height=%u-%u, " - "pixelclock=%llu-%llu, standards=0x%x, capabilities=0x%x\n", + pr_cont("type=bt-656/1120, width=%u-%u, height=%u-%u, pixelclock=%llu-%llu, standards=0x%x, capabilities=0x%x\n", p->bt.min_width, p->bt.max_width, p->bt.min_height, p->bt.max_height, p->bt.min_pixelclock, p->bt.max_pixelclock, @@ -805,8 +769,7 @@ static void v4l_print_event(const void *arg, bool write_only) const struct v4l2_event *p = arg; const struct v4l2_event_ctrl *c; - pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, " - "timestamp=%lu.%9.9lu\n", + pr_cont("type=0x%x, pending=%u, sequence=%u, id=%u, timestamp=%lu.%9.9lu\n", p->type, p->pending, p->sequence, p->id, p->timestamp.tv_sec, p->timestamp.tv_nsec); switch (p->type) { @@ -822,8 +785,7 @@ static void v4l_print_event(const void *arg, bool write_only) pr_cont("value64=%lld, ", c->value64); else pr_cont("value=%d, ", c->value); - pr_cont("flags=0x%x, minimum=%d, maximum=%d, step=%d, " - "default_value=%d\n", + pr_cont("flags=0x%x, minimum=%d, maximum=%d, step=%d, default_value=%d\n", c->flags, c->minimum, c->maximum, c->step, c->default_value); break; @@ -859,8 +821,7 @@ static void v4l_print_freq_band(const void *arg, bool write_only) { const struct v4l2_frequency_band *p = arg; - pr_cont("tuner=%u, type=%u, index=%u, capability=0x%x, " - "rangelow=%u, rangehigh=%u, modulation=0x%x\n", + pr_cont("tuner=%u, type=%u, index=%u, capability=0x%x, rangelow=%u, rangehigh=%u, modulation=0x%x\n", p->tuner, p->type, p->index, p->capability, p->rangelow, p->rangehigh, p->modulation); diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c index def84753c4c3..1dbf6f7785bb 100644 --- a/drivers/media/v4l2-core/videobuf-core.c +++ b/drivers/media/v4l2-core/videobuf-core.c @@ -572,8 +572,7 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b) switch (b->memory) { case V4L2_MEMORY_MMAP: if (0 == buf->baddr) { - dprintk(1, "qbuf: mmap requested " - "but buffer addr is zero!\n"); + dprintk(1, "qbuf: mmap requested but buffer addr is zero!\n"); goto done; } if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c index 21900202ff83..7c1d390ea438 100644 --- a/drivers/media/v4l2-core/videobuf2-core.c +++ b/drivers/media/v4l2-core/videobuf2-core.c @@ -358,8 +358,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, if (memory == VB2_MEMORY_MMAP) { ret = __vb2_buf_mem_alloc(vb); if (ret) { - dprintk(1, "failed allocating memory for " - "buffer %d\n", buffer); + dprintk(1, "failed allocating memory for buffer %d\n", + buffer); q->bufs[vb->index] = NULL; kfree(vb); break; @@ -372,8 +372,8 @@ static int __vb2_queue_alloc(struct vb2_queue *q, enum vb2_memory memory, */ ret = call_vb_qop(vb, buf_init, vb); if (ret) { - dprintk(1, "buffer %d %p initialization" - " failed\n", buffer, vb); + dprintk(1, "buffer %d %p initialization failed\n", + buffer, vb); __vb2_buf_mem_free(vb); q->bufs[vb->index] = NULL; kfree(vb); @@ -997,13 +997,12 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) && vb->planes[plane].length == planes[plane].length) continue; - dprintk(3, "userspace address for plane %d changed, " - "reacquiring memory\n", plane); + dprintk(3, "userspace address for plane %d changed, reacquiring memory\n", + plane); /* Check if the provided plane buffer is large enough */ if (planes[plane].length < vb->planes[plane].min_length) { - dprintk(1, "provided buffer size %u is less than " - "setup size %u for plane %d\n", + dprintk(1, "provided buffer size %u is less than setup size %u for plane %d\n", planes[plane].length, vb->planes[plane].min_length, plane); @@ -1032,8 +1031,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const void *pb) planes[plane].m.userptr, planes[plane].length, dma_dir); if (IS_ERR(mem_priv)) { - dprintk(1, "failed acquiring userspace " - "memory for plane %d\n", plane); + dprintk(1, "failed acquiring userspace memory for plane %d\n", + plane); ret = PTR_ERR(mem_priv); goto err; } @@ -1123,8 +1122,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const void *pb) planes[plane].length = dbuf->size; if (planes[plane].length < vb->planes[plane].min_length) { - dprintk(1, "invalid dmabuf length %u for plane %d, " - "minimum length %u\n", + dprintk(1, "invalid dmabuf length %u for plane %d, minimum length %u\n", planes[plane].length, plane, vb->planes[plane].min_length); dma_buf_put(dbuf); @@ -1472,8 +1470,7 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking) } if (nonblocking) { - dprintk(1, "nonblocking and no buffers to dequeue, " - "will not wait\n"); + dprintk(1, "nonblocking and no buffers to dequeue, will not wait\n"); return -EAGAIN; } diff --git a/drivers/media/v4l2-core/videobuf2-v4l2.c b/drivers/media/v4l2-core/videobuf2-v4l2.c index 52ef8833f6b6..3529849d2218 100644 --- a/drivers/media/v4l2-core/videobuf2-v4l2.c +++ b/drivers/media/v4l2-core/videobuf2-v4l2.c @@ -60,14 +60,13 @@ static int __verify_planes_array(struct vb2_buffer *vb, const struct v4l2_buffer /* Is memory for copying plane information present? */ if (b->m.planes == NULL) { - dprintk(1, "multi-planar buffer passed but " - "planes array not provided\n"); + dprintk(1, "multi-planar buffer passed but planes array not provided\n"); return -EINVAL; } if (b->length < vb->num_planes || b->length > VB2_MAX_PLANES) { - dprintk(1, "incorrect planes array length, " - "expected %d, got %d\n", vb->num_planes, b->length); + dprintk(1, "incorrect planes array length, expected %d, got %d\n", + vb->num_planes, b->length); return -EINVAL; } @@ -316,8 +315,7 @@ static int __fill_vb2_buffer(struct vb2_buffer *vb, * that just says that it is either a top or a bottom field, * but not which of the two it is. */ - dprintk(1, "the field is incorrectly set to ALTERNATE " - "for an output buffer\n"); + dprintk(1, "the field is incorrectly set to ALTERNATE for an output buffer\n"); return -EINVAL; } vb->timestamp = 0; diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c index ab3227b75c84..3f778147cdef 100644 --- a/drivers/media/v4l2-core/videobuf2-vmalloc.c +++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c @@ -151,8 +151,7 @@ static void *vb2_vmalloc_vaddr(void *buf_priv) struct vb2_vmalloc_buf *buf = buf_priv; if (!buf->vaddr) { - pr_err("Address of an unallocated plane requested " - "or cannot map user pointer\n"); + pr_err("Address of an unallocated plane requested or cannot map user pointer\n"); return NULL; } -- cgit v1.2.3 From 4bd69e7b9c1b8c1a5b6cfc50a126ae0a1d926e57 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:22 -0200 Subject: [media] dvb-frontends: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/au8522_common.c | 4 ++-- drivers/media/dvb-frontends/cx24110.c | 4 ++-- drivers/media/dvb-frontends/cx24113.c | 4 ++-- drivers/media/dvb-frontends/cx24116.c | 8 ++++---- drivers/media/dvb-frontends/cx24117.c | 4 ++-- drivers/media/dvb-frontends/cx24123.c | 4 ++-- drivers/media/dvb-frontends/ds3000.c | 15 +++++++-------- drivers/media/dvb-frontends/lgdt330x.c | 3 +-- drivers/media/dvb-frontends/m88rs2000.c | 11 +++++------ drivers/media/dvb-frontends/mt312.c | 7 +++---- drivers/media/dvb-frontends/nxt200x.c | 11 +++++------ drivers/media/dvb-frontends/or51132.c | 6 ++---- drivers/media/dvb-frontends/or51211.c | 3 +-- drivers/media/dvb-frontends/s5h1409.c | 4 ++-- drivers/media/dvb-frontends/s5h1411.c | 4 ++-- drivers/media/dvb-frontends/s5h1432.c | 4 ++-- drivers/media/dvb-frontends/s921.c | 4 ++-- drivers/media/dvb-frontends/si21xx.c | 8 ++++---- drivers/media/dvb-frontends/sp887x.c | 3 +-- drivers/media/dvb-frontends/stv0288.c | 11 +++++------ drivers/media/dvb-frontends/stv0297.c | 4 ++-- drivers/media/dvb-frontends/stv0299.c | 7 +++---- drivers/media/dvb-frontends/stv0900_sw.c | 3 +-- drivers/media/dvb-frontends/tda10021.c | 3 +-- drivers/media/dvb-frontends/tda10023.c | 6 ++---- drivers/media/dvb-frontends/tda10048.c | 12 ++++-------- drivers/media/dvb-frontends/ves1820.c | 8 ++++---- drivers/media/dvb-frontends/zl10036.c | 4 ++-- drivers/media/dvb-frontends/zl10039.c | 3 +-- 29 files changed, 76 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/au8522_common.c b/drivers/media/dvb-frontends/au8522_common.c index f135126bc373..cf4ac240a01f 100644 --- a/drivers/media/dvb-frontends/au8522_common.c +++ b/drivers/media/dvb-frontends/au8522_common.c @@ -50,8 +50,8 @@ int au8522_writereg(struct au8522_state *state, u16 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, " - "ret == %i)\n", __func__, reg, data, ret); + printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -1 : 0; } diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c index 6cb81ec12847..92a08c7bf794 100644 --- a/drivers/media/dvb-frontends/cx24110.c +++ b/drivers/media/dvb-frontends/cx24110.c @@ -120,8 +120,8 @@ static int cx24110_writereg (struct cx24110_state* state, int reg, int data) int err; if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - dprintk ("%s: writereg error (err == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, err, reg, data); + dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", + __func__, err, reg, data); return -EREMOTEIO; } diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 3883c3b31aef..3812ef8cac08 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -108,8 +108,8 @@ static int cx24113_writereg(struct cx24113_state *state, int reg, int data) .flags = 0, .buf = buf, .len = 2 }; int err = i2c_transfer(state->i2c, &msg, 1); if (err != 1) { - printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, err, reg, data); + printk(KERN_DEBUG "%s: writereg error(err == %i, reg == 0x%02x, data == 0x%02x)\n", + __func__, err, reg, data); return err; } diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index 8814f36d53fb..ae5a7f9f5a72 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -209,8 +209,8 @@ static int cx24116_writereg(struct cx24116_state *state, int reg, int data) err = i2c_transfer(state->i2c, &msg, 1); if (err != 1) { - printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," - " value == 0x%02x)\n", __func__, err, reg, data); + printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n", + __func__, err, reg, data); return -EREMOTEIO; } @@ -498,8 +498,8 @@ static int cx24116_firmware_ondemand(struct dvb_frontend *fe) printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); if (ret) { - printk(KERN_ERR "%s: No firmware uploaded " - "(timeout or file not found?)\n", __func__); + printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n", + __func__); return ret; } diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index a3f7eb4e609d..bc3cd698303f 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -474,8 +474,8 @@ static int cx24117_firmware_ondemand(struct dvb_frontend *fe) "%s: Waiting for firmware upload(2)...\n", __func__); if (ret) { dev_err(&state->priv->i2c->dev, - "%s: No firmware uploaded " - "(timeout or file not found?)\n", __func__); + "%s: No firmware uploaded (timeout or file not found?)\n", +__func__); return ret; } diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index 113b0949408a..b1287de98e86 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -255,8 +255,8 @@ static int cx24123_i2c_writereg(struct cx24123_state *state, err = i2c_transfer(state->i2c, &msg, 1); if (err != 1) { - printk("%s: writereg error(err == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, err, reg, data); + printk("%s: writereg error(err == %i, reg == 0x%02x, data == 0x%02x)\n", + __func__, err, reg, data); return err; } diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 447b518e287a..6dc79d4528c2 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -248,8 +248,8 @@ static int ds3000_writereg(struct ds3000_state *state, int reg, int data) err = i2c_transfer(state->i2c, &msg, 1); if (err != 1) { - printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x," - " value == 0x%02x)\n", __func__, err, reg, data); + printk(KERN_ERR "%s: writereg error(err == %i, reg == 0x%02x, value == 0x%02x)\n", + __func__, err, reg, data); return -EREMOTEIO; } @@ -296,8 +296,8 @@ static int ds3000_writeFW(struct ds3000_state *state, int reg, ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) { - printk(KERN_ERR "%s: write error(err == %i, " - "reg == 0x%02x\n", __func__, ret, reg); + printk(KERN_ERR "%s: write error(err == %i, reg == 0x%02x\n", + __func__, ret, reg); ret = -EREMOTEIO; goto error; } @@ -364,8 +364,8 @@ static int ds3000_firmware_ondemand(struct dvb_frontend *fe) state->i2c->dev.parent); printk(KERN_INFO "%s: Waiting for firmware upload(2)...\n", __func__); if (ret) { - printk(KERN_ERR "%s: No firmware uploaded (timeout or file not " - "found?)\n", __func__); + printk(KERN_ERR "%s: No firmware uploaded (timeout or file not found?)\n", + __func__); return ret; } @@ -1144,8 +1144,7 @@ static struct dvb_frontend_ops ds3000_ops = { module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)"); -MODULE_DESCRIPTION("DVB Frontend module for Montage Technology " - "DS3000 hardware"); +MODULE_DESCRIPTION("DVB Frontend module for Montage Technology DS3000 hardware"); MODULE_AUTHOR("Konstantin Dimitrov "); MODULE_LICENSE("GPL"); MODULE_FIRMWARE(DS3000_DEFAULT_FIRMWARE); diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index 96bf254da21e..8cb6c56d220a 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -405,8 +405,7 @@ static int lgdt330x_set_parameters(struct dvb_frontend *fe) return -1; } if (err < 0) - printk(KERN_WARNING "lgdt330x: %s: error blasting " - "bytes to lgdt3303 for modulation type(%d)\n", + printk(KERN_WARNING "lgdt330x: %s: error blasting bytes to lgdt3303 for modulation type(%d)\n", __func__, p->modulation); /* diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c index ef79a4ec31e2..3669c906ba01 100644 --- a/drivers/media/dvb-frontends/m88rs2000.c +++ b/drivers/media/dvb-frontends/m88rs2000.c @@ -75,8 +75,8 @@ static int m88rs2000_writereg(struct m88rs2000_state *state, ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); + deb_info("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; } @@ -618,10 +618,9 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) state->no_lock_count = 0; if (c->delivery_system != SYS_DVBS) { - deb_info("%s: unsupported delivery " - "system selected (%d)\n", - __func__, c->delivery_system); - return -EOPNOTSUPP; + deb_info("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; } /* Set Tuner */ diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index fc08429c99b7..fdee75b1b99a 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -457,8 +457,8 @@ static int mt312_read_status(struct dvb_frontend *fe, enum fe_status *s) if (ret < 0) return ret; - dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x," - " FEC_STATUS: 0x%02x\n", status[0], status[1], status[2]); + dprintk("QPSK_STAT_H: 0x%02x, QPSK_STAT_L: 0x%02x, FEC_STATUS: 0x%02x\n", + status[0], status[1], status[2]); if (status[0] & 0xc0) *s |= FE_HAS_SIGNAL; /* signal noise ratio */ @@ -827,8 +827,7 @@ struct dvb_frontend *mt312_attach(const struct mt312_config *config, state->freq_mult = 9; break; default: - printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313" - " are supported chips.\n"); + printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313 are supported chips.\n"); goto error; } diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c index 79c3040912ab..7c23f0499f23 100644 --- a/drivers/media/dvb-frontends/nxt200x.c +++ b/drivers/media/dvb-frontends/nxt200x.c @@ -289,8 +289,7 @@ static void nxt200x_microcontroller_stop (struct nxt200x_state* state) counter++; } - pr_warn("Timeout waiting for nxt200x to stop. This is ok after " - "firmware upload.\n"); + pr_warn("Timeout waiting for nxt200x to stop. This is ok after firmware upload.\n"); return; } @@ -893,8 +892,8 @@ static int nxt2002_init(struct dvb_frontend* fe) state->i2c->dev.parent); pr_debug("%s: Waiting for firmware upload(2)...\n", __func__); if (ret) { - pr_err("%s: No firmware uploaded (timeout or file not found?)" - "\n", __func__); + pr_err("%s: No firmware uploaded (timeout or file not found?)\n", + __func__); return ret; } @@ -960,8 +959,8 @@ static int nxt2004_init(struct dvb_frontend* fe) state->i2c->dev.parent); pr_debug("%s: Waiting for firmware upload(2)...\n", __func__); if (ret) { - pr_err("%s: No firmware uploaded (timeout or file not found?)" - "\n", __func__); + pr_err("%s: No firmware uploaded (timeout or file not found?)\n", + __func__); return ret; } diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c index a165af990672..bacea20822ea 100644 --- a/drivers/media/dvb-frontends/or51132.c +++ b/drivers/media/dvb-frontends/or51132.c @@ -342,15 +342,13 @@ static int or51132_set_parameters(struct dvb_frontend *fe) fwname); ret = request_firmware(&fw, fwname, state->i2c->dev.parent); if (ret) { - printk(KERN_WARNING "or51132: No firmware up" - "loaded(timeout or file not found?)\n"); + printk(KERN_WARNING "or51132: No firmware uploaded(timeout or file not found?)\n"); return ret; } ret = or51132_load_firmware(fe, fw); release_firmware(fw); if (ret) { - printk(KERN_WARNING "or51132: Writing firmware to " - "device failed!\n"); + printk(KERN_WARNING "or51132: Writing firmware to device failed!\n"); return ret; } printk("or51132: Firmware upload complete.\n"); diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index e82413b975e6..839479eab3b3 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -377,8 +377,7 @@ static int or51211_init(struct dvb_frontend* fe) OR51211_DEFAULT_FIRMWARE); pr_info("Got Hotplug firmware\n"); if (ret) { - pr_warn("No firmware uploaded " - "(timeout or file not found?)\n"); + pr_warn("No firmware uploaded (timeout or file not found?)\n"); return ret; } diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index c68965ad97c0..56c3fb442d6c 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -321,8 +321,8 @@ static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, " - "ret == %i)\n", __func__, reg, data, ret); + printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -1 : 0; } diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index 90f86e82b087..a861854981b7 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -350,8 +350,8 @@ static int s5h1411_writereg(struct s5h1411_state *state, ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, " - "ret == %i)\n", __func__, addr, reg, data, ret); + printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, ret == %i)\n", + __func__, addr, reg, data, ret); return (ret != 1) ? -1 : 0; } diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c index 4215652f8eb7..5de79739cf63 100644 --- a/drivers/media/dvb-frontends/s5h1432.c +++ b/drivers/media/dvb-frontends/s5h1432.c @@ -63,8 +63,8 @@ static int s5h1432_writereg(struct s5h1432_state *state, ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, " - "ret == %i)\n", __func__, addr, reg, data, ret); + printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, ret == %i)\n", + __func__, addr, reg, data, ret); return (ret != 1) ? -1 : 0; } diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c index b5e3d90eba5e..98cceb149b91 100644 --- a/drivers/media/dvb-frontends/s921.c +++ b/drivers/media/dvb-frontends/s921.c @@ -214,8 +214,8 @@ static int s921_i2c_writereg(struct s921_state *state, rc = i2c_transfer(state->i2c, &msg, 1); if (rc != 1) { - printk("%s: writereg rcor(rc == %i, reg == 0x%02x," - " data == 0x%02x)\n", __func__, rc, reg, data); + printk("%s: writereg rcor(rc == %i, reg == 0x%02x, data == 0x%02x)\n", + __func__, rc, reg, data); return rc; } diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index 62ad7a7be9f8..32ebfb78bfdd 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -245,8 +245,8 @@ static int si21_writeregs(struct si21xx_state *state, u8 reg1, ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, " - "ret == %i)\n", __func__, reg1, data[0], ret); + dprintk("%s: writereg error (reg1 == 0x%02x, data == 0x%02x, ret == %i)\n", + __func__, reg1, data[0], ret); return (ret != 1) ? -EREMOTEIO : 0; } @@ -265,8 +265,8 @@ static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); + dprintk("%s: writereg error (reg == 0x%02x, data == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; } diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index 4378fe1b978e..f9194b7b7fec 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -63,8 +63,7 @@ static int sp887x_writereg (struct sp887x_state* state, u16 reg, u16 data) if (!(reg == 0xf1a && data == 0x000 && (ret == -EREMOTEIO || ret == -EFAULT))) { - printk("%s: writereg error " - "(reg %03x, data %03x, ret == %i)\n", + printk("%s: writereg error (reg %03x, data %03x, ret == %i)\n", __func__, reg & 0xffff, data & 0xffff, ret); return ret; } diff --git a/drivers/media/dvb-frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c index c93d9a45f7f7..12f6a4205e3e 100644 --- a/drivers/media/dvb-frontends/stv0288.c +++ b/drivers/media/dvb-frontends/stv0288.c @@ -74,8 +74,8 @@ static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; } @@ -465,10 +465,9 @@ static int stv0288_set_frontend(struct dvb_frontend *fe) dprintk("%s : FE_SET_FRONTEND\n", __func__); if (c->delivery_system != SYS_DVBS) { - dprintk("%s: unsupported delivery " - "system selected (%d)\n", - __func__, c->delivery_system); - return -EOPNOTSUPP; + dprintk("%s: unsupported delivery system selected (%d)\n", + __func__, c->delivery_system); + return -EOPNOTSUPP; } if (state->config->set_ts_params) diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c index 81b27b7c0c96..73b4d4243b74 100644 --- a/drivers/media/dvb-frontends/stv0297.c +++ b/drivers/media/dvb-frontends/stv0297.c @@ -57,8 +57,8 @@ static int stv0297_writereg(struct stv0297_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -1 : 0; } diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c index 7927fa925f2f..a9b28ceb80d8 100644 --- a/drivers/media/dvb-frontends/stv0299.c +++ b/drivers/media/dvb-frontends/stv0299.c @@ -88,8 +88,8 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data) ret = i2c_transfer (state->i2c, &msg, 1); if (ret != 1) - dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, " - "ret == %i)\n", __func__, reg, data, ret); + dprintk("%s: writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; } @@ -761,8 +761,7 @@ module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); -MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " - "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); +MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(stv0299_attach); diff --git a/drivers/media/dvb-frontends/stv0900_sw.c b/drivers/media/dvb-frontends/stv0900_sw.c index fa63a9e929ce..bded82774f4b 100644 --- a/drivers/media/dvb-frontends/stv0900_sw.c +++ b/drivers/media/dvb-frontends/stv0900_sw.c @@ -1485,8 +1485,7 @@ static u32 stv0900_search_srate_coarse(struct dvb_frontend *fe) current_step++; direction *= -1; - dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started." - " tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n", + dprintk("lock: I2C_DEMOD_MODE_FIELD =0. Search started. tuner freq=%d agc2=0x%x srate_coarse=%d tmg_cpt=%d\n", tuner_freq, agc2_integr, coarse_srate, timingcpt); if ((timingcpt >= 5) && diff --git a/drivers/media/dvb-frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c index 806c56691ca5..4c514e6bffda 100644 --- a/drivers/media/dvb-frontends/tda10021.c +++ b/drivers/media/dvb-frontends/tda10021.c @@ -77,8 +77,7 @@ static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data) ret = i2c_transfer (state->i2c, &msg, 1); if (ret != 1) - printk("DVB: TDA10021(%d): %s, writereg error " - "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", + printk("DVB: TDA10021(%d): %s, writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", state->frontend.dvb->num, __func__, reg, data, ret); msleep(10); diff --git a/drivers/media/dvb-frontends/tda10023.c b/drivers/media/dvb-frontends/tda10023.c index 3b8c7e499d0d..0c416be76d65 100644 --- a/drivers/media/dvb-frontends/tda10023.c +++ b/drivers/media/dvb-frontends/tda10023.c @@ -72,8 +72,7 @@ static u8 tda10023_readreg (struct tda10023_state* state, u8 reg) ret = i2c_transfer (state->i2c, msg, 2); if (ret != 2) { int num = state->frontend.dvb ? state->frontend.dvb->num : -1; - printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error " - "(reg == 0x%02x, ret == %i)\n", + printk(KERN_ERR "DVB: TDA10023(%d): %s: readreg error (reg == 0x%02x, ret == %i)\n", num, __func__, reg, ret); } return b1[0]; @@ -88,8 +87,7 @@ static int tda10023_writereg (struct tda10023_state* state, u8 reg, u8 data) ret = i2c_transfer (state->i2c, &msg, 1); if (ret != 1) { int num = state->frontend.dvb ? state->frontend.dvb->num : -1; - printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error " - "(reg == 0x%02x, val == 0x%02x, ret == %i)\n", + printk(KERN_ERR "DVB: TDA10023(%d): %s, writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", num, __func__, reg, data, ret); } return (ret != 1) ? -EREMOTEIO : 0; diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c index c2bf89d0b0b0..7cb23f89a03b 100644 --- a/drivers/media/dvb-frontends/tda10048.c +++ b/drivers/media/dvb-frontends/tda10048.c @@ -1063,32 +1063,28 @@ static void tda10048_establish_defaults(struct dvb_frontend *fe) /* Validate/default the config */ if (config->dtv6_if_freq_khz == 0) { config->dtv6_if_freq_khz = TDA10048_IF_4300; - printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz " - "is not set (defaulting to %d)\n", + printk(KERN_WARNING "%s() tda10048_config.dtv6_if_freq_khz is not set (defaulting to %d)\n", __func__, config->dtv6_if_freq_khz); } if (config->dtv7_if_freq_khz == 0) { config->dtv7_if_freq_khz = TDA10048_IF_4300; - printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz " - "is not set (defaulting to %d)\n", + printk(KERN_WARNING "%s() tda10048_config.dtv7_if_freq_khz is not set (defaulting to %d)\n", __func__, config->dtv7_if_freq_khz); } if (config->dtv8_if_freq_khz == 0) { config->dtv8_if_freq_khz = TDA10048_IF_4300; - printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz " - "is not set (defaulting to %d)\n", + printk(KERN_WARNING "%s() tda10048_config.dtv8_if_freq_khz is not set (defaulting to %d)\n", __func__, config->dtv8_if_freq_khz); } if (config->clk_freq_khz == 0) { config->clk_freq_khz = TDA10048_CLK_16000; - printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz " - "is not set (defaulting to %d)\n", + printk(KERN_WARNING "%s() tda10048_config.clk_freq_khz is not set (defaulting to %d)\n", __func__, config->clk_freq_khz); } diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c index b09fe88c40f8..24ac54b3b967 100644 --- a/drivers/media/dvb-frontends/ves1820.c +++ b/drivers/media/dvb-frontends/ves1820.c @@ -65,8 +65,8 @@ static int ves1820_writereg(struct ves1820_state *state, u8 reg, u8 data) ret = i2c_transfer(state->i2c, &msg, 1); if (ret != 1) - printk("ves1820: %s(): writereg error (reg == 0x%02x, " - "val == 0x%02x, ret == %i)\n", __func__, reg, data, ret); + printk("ves1820: %s(): writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n", + __func__, reg, data, ret); return (ret != 1) ? -EREMOTEIO : 0; } @@ -84,8 +84,8 @@ static u8 ves1820_readreg(struct ves1820_state *state, u8 reg) ret = i2c_transfer(state->i2c, msg, 2); if (ret != 2) - printk("ves1820: %s(): readreg error (reg == 0x%02x, " - "ret == %i)\n", __func__, reg, ret); + printk("ves1820: %s(): readreg error (reg == 0x%02x, ret == %i)\n", + __func__, reg, ret); return b1[0]; } diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c index 7ed81315965f..df5d0fe24687 100644 --- a/drivers/media/dvb-frontends/zl10036.c +++ b/drivers/media/dvb-frontends/zl10036.c @@ -85,8 +85,8 @@ static int zl10036_read_status_reg(struct zl10036_state *state) deb_i2c("R(status): %02x [FL=%d]\n", status, (status & STATUS_FL) ? 1 : 0); if (status & STATUS_POR) - deb_info("%s: Power-On-Reset bit enabled - " - "need to initialize the tuner\n", __func__); + deb_info("%s: Power-On-Reset bit enabled - need to initialize the tuner\n", + __func__); return status; } diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c index f8c271be196c..d6ded11fee49 100644 --- a/drivers/media/dvb-frontends/zl10039.c +++ b/drivers/media/dvb-frontends/zl10039.c @@ -152,8 +152,7 @@ static int zl10039_init(struct dvb_frontend *fe) /* Reset logic */ ret = zl10039_writereg(state, GENERAL, 0x40); if (ret < 0) { - dprintk("Note: i2c write error normal when resetting the " - "tuner\n"); + dprintk("Note: i2c write error normal when resetting the tuner\n"); } /* Wake up */ ret = zl10039_writereg(state, GENERAL, 0x01); -- cgit v1.2.3 From 2a3edc5d55c23ee7e2c7fa662ac76cc41863c7a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:23 -0200 Subject: [media] common: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tveeprom.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c index 47da0378cad8..e0e2cb706087 100644 --- a/drivers/media/common/tveeprom.c +++ b/drivers/media/common/tveeprom.c @@ -510,8 +510,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, len = eeprom_data[i] & 0x07; ++i; } else { - tveeprom_warn("Encountered bad packet header [%02x]. " - "Corrupt or not a Hauppauge eeprom.\n", + tveeprom_warn("Encountered bad packet header [%02x]. Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); return; } -- cgit v1.2.3 From f96cffd77b014944fd0d855cf56b2b5724fafb0d Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Tue, 18 Oct 2016 20:53:35 -0200 Subject: [media] firewire: use dev_dbg() instead of printk() A structure for firedtv (struct firedtv) has a member for a pointer to struct device. In this case, we can use dev_dbg() for debug printing. This is more preferrable behaviour in device driver development. Signed-off-by: Takashi Sakamoto Acked-by: Stefan Richter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/firewire/firedtv-rc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/firewire/firedtv-rc.c b/drivers/media/firewire/firedtv-rc.c index f82d4a93feb3..04dea2aac583 100644 --- a/drivers/media/firewire/firedtv-rc.c +++ b/drivers/media/firewire/firedtv-rc.c @@ -184,8 +184,9 @@ void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) else if (code >= 0x4540 && code <= 0x4542) code = oldtable[code - 0x4521]; else { - printk(KERN_DEBUG "firedtv: invalid key code 0x%04x " - "from remote control\n", code); + dev_dbg(fdtv->device, + "invalid key code 0x%04x from remote control\n", + code); return; } -- cgit v1.2.3 From 4c481739afeb806f7ecfbfb2087f8c2afba00e74 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:23 -0200 Subject: [media] firewire: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Reviewed-by: Takashi Sakamoto Acked-by: Stefan Richter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/firewire/firedtv-avc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/firewire/firedtv-avc.c b/drivers/media/firewire/firedtv-avc.c index 251a556112a9..5bde6c209cd7 100644 --- a/drivers/media/firewire/firedtv-avc.c +++ b/drivers/media/firewire/firedtv-avc.c @@ -1181,8 +1181,8 @@ int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length) if (es_info_length > 0) { pmt_cmd_id = msg[read_pos++]; if (pmt_cmd_id != 1 && pmt_cmd_id != 4) - dev_err(fdtv->device, "invalid pmt_cmd_id %d " - "at stream level\n", pmt_cmd_id); + dev_err(fdtv->device, "invalid pmt_cmd_id %d at stream level\n", + pmt_cmd_id); if (es_info_length > sizeof(c->operand) - 4 - write_pos) { -- cgit v1.2.3 From 759a4ed4d8e068dd5dd38aa2f4f8651c5c205056 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:24 -0200 Subject: [media] platform: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Acked-by: Robert Jarzmik Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mx2_emmaprp.c | 10 +++++----- drivers/media/platform/pxa_camera.c | 6 ++---- drivers/media/platform/via-camera.c | 7 ++----- 3 files changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c index e68d271b10af..03e47e0f778d 100644 --- a/drivers/media/platform/mx2_emmaprp.c +++ b/drivers/media/platform/mx2_emmaprp.c @@ -724,10 +724,10 @@ static int emmaprp_buf_prepare(struct vb2_buffer *vb) q_data = get_q_data(ctx, vb->vb2_queue->type); if (vb2_plane_size(vb, 0) < q_data->sizeimage) { - dprintk(ctx->dev, "%s data will not fit into plane" - "(%lu < %lu)\n", __func__, - vb2_plane_size(vb, 0), - (long)q_data->sizeimage); + dprintk(ctx->dev, + "%s data will not fit into plane(%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), + (long)q_data->sizeimage); return -EINVAL; } @@ -937,7 +937,7 @@ static int emmaprp_probe(struct platform_device *pdev) snprintf(vfd->name, sizeof(vfd->name), "%s", emmaprp_videodev.name); pcdev->vfd = vfd; v4l2_info(&pcdev->v4l2_dev, EMMAPRP_MODULE_NAME - " Device registered as /dev/video%d\n", vfd->num); + " Device registered as /dev/video%d\n", vfd->num); platform_set_drvdata(pdev, pcdev); diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index c12209c701d3..bcdac4932fb1 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2347,8 +2347,7 @@ static int pxa_camera_probe(struct platform_device *pdev) * Platform hasn't set available data widths. This is bad. * Warn and use a default. */ - dev_warn(&pdev->dev, "WARNING! Platform hasn't set available " - "data widths, using default 10 bit\n"); + dev_warn(&pdev->dev, "WARNING! Platform hasn't set available data widths, using default 10 bit\n"); pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10; } if (pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8) @@ -2359,8 +2358,7 @@ static int pxa_camera_probe(struct platform_device *pdev) pcdev->width_flags |= 1 << 9; if (!pcdev->mclk) { dev_warn(&pdev->dev, - "mclk == 0! Please, fix your platform data. " - "Using default 20MHz\n"); + "mclk == 0! Please, fix your platform data. Using default 20MHz\n"); pcdev->mclk = 20000000; } diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c index 7ca12deba89c..e16f70a5df1d 100644 --- a/drivers/media/platform/via-camera.c +++ b/drivers/media/platform/via-camera.c @@ -39,15 +39,12 @@ MODULE_LICENSE("GPL"); static bool flip_image; module_param(flip_image, bool, 0444); MODULE_PARM_DESC(flip_image, - "If set, the sensor will be instructed to flip the image " - "vertically."); + "If set, the sensor will be instructed to flip the image vertically."); static bool override_serial; module_param(override_serial, bool, 0444); MODULE_PARM_DESC(override_serial, - "The camera driver will normally refuse to load if " - "the XO 1.5 serial port is enabled. Set this option " - "to force-enable the camera."); + "The camera driver will normally refuse to load if the XO 1.5 serial port is enabled. Set this option to force-enable the camera."); /* * The structure describing our camera. -- cgit v1.2.3 From 547633def7f5eb6deebf83400f61341b31eb7018 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:25 -0200 Subject: [media] radio: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/radio-gemtek.c | 8 ++------ drivers/media/radio/radio-wl1273.c | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index cff1eb144a5c..ca051ccbc3e4 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -67,14 +67,10 @@ module_param(probe, bool, 0444); MODULE_PARM_DESC(probe, "Enable automatic device probing."); module_param(hardmute, bool, 0644); -MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may " - "reduce static noise."); +MODULE_PARM_DESC(hardmute, "Enable 'hard muting' by shutting down PLL, may reduce static noise."); module_param_array(io, int, NULL, 0444); -MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic " - "probing is disabled or fails. The most common I/O ports are: 0x20c " - "0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to " - "work for the combined sound/radiocard)."); +MODULE_PARM_DESC(io, "Force I/O ports for the GemTek Radio card if automatic probing is disabled or fails. The most common I/O ports are: 0x20c 0x30c, 0x24c or 0x34c (0x20c, 0x248 and 0x28c have been reported to work for the combined sound/radiocard)."); module_param_array(radio_nr, int, NULL, 0444); MODULE_PARM_DESC(radio_nr, "Radio device numbers"); diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c index a93f681aa9d6..9ce4b12299b4 100644 --- a/drivers/media/radio/radio-wl1273.c +++ b/drivers/media/radio/radio-wl1273.c @@ -2068,8 +2068,7 @@ static int wl1273_fm_radio_probe(struct platform_device *pdev) goto err_request_irq; } } else { - dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ" - " not configured"); + dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ not configured"); r = -EINVAL; goto pdata_err; } -- cgit v1.2.3 From 25ec587c02c3008ead4046a998eb412ce41c72ec Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:25 -0200 Subject: [media] rc: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ati_remote.c | 3 +-- drivers/media/rc/ene_ir.c | 3 +-- drivers/media/rc/imon.c | 48 +++++++++++++++++------------------------- drivers/media/rc/ite-cir.c | 9 +++----- drivers/media/rc/mceusb.c | 4 +--- drivers/media/rc/rc-main.c | 3 +-- drivers/media/rc/redrat3.c | 18 ++++++---------- drivers/media/rc/streamzap.c | 11 +++++----- drivers/media/rc/winbond-cir.c | 9 +++----- 9 files changed, 40 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c index 9f5b59706741..0884b7dc0e71 100644 --- a/drivers/media/rc/ati_remote.c +++ b/drivers/media/rc/ati_remote.c @@ -527,8 +527,7 @@ static void ati_remote_input_report(struct urb *urb) remote_num = (data[3] >> 4) & 0x0f; if (channel_mask & (1 << (remote_num + 1))) { dbginfo(&ati_remote->interface->dev, - "Masked input from channel 0x%02x: data %02x, " - "mask= 0x%02lx\n", + "Masked input from channel 0x%02x: data %02x, mask= 0x%02lx\n", remote_num, data[2], channel_mask); return; } diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c index d1c61cd035f6..bd5512e64aea 100644 --- a/drivers/media/rc/ene_ir.c +++ b/drivers/media/rc/ene_ir.c @@ -1210,8 +1210,7 @@ MODULE_PARM_DESC(txsim, MODULE_DEVICE_TABLE(pnp, ene_ids); MODULE_DESCRIPTION - ("Infrared input driver for KB3926B/C/D/E/F " - "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port"); + ("Infrared input driver for KB3926B/C/D/E/F (aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port"); MODULE_AUTHOR("Maxim Levitsky"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index d62b1f38292c..bd807fa4cb9f 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -441,13 +441,11 @@ MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)"); /* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */ static int display_type; module_param(display_type, int, S_IRUGO); -MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, " - "1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); +MODULE_PARM_DESC(display_type, "Type of attached display. 0=autodetect, 1=vfd, 2=lcd, 3=vga, 4=none (default: autodetect)"); static int pad_stabilize = 1; module_param(pad_stabilize, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD " - "presses in arrow key mode. 0=disable, 1=enable (default)."); +MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD presses in arrow key mode. 0=disable, 1=enable (default)."); /* * In certain use cases, mouse mode isn't really helpful, and could actually @@ -455,14 +453,12 @@ MODULE_PARM_DESC(pad_stabilize, "Apply stabilization algorithm to iMON PAD " */ static bool nomouse; module_param(nomouse, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is " - "open. 0=don't disable, 1=disable. (default: don't disable)"); +MODULE_PARM_DESC(nomouse, "Disable mouse input device mode when IR device is open. 0=don't disable, 1=disable. (default: don't disable)"); /* threshold at which a pad push registers as an arrow key in kbd mode */ static int pad_thresh; module_param(pad_thresh, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an " - "arrow key in kbd mode (default: 28)"); +MODULE_PARM_DESC(pad_thresh, "Threshold at which a pad push registers as an arrow key in kbd mode (default: 28)"); static void free_imon_context(struct imon_context *ictx) @@ -785,9 +781,7 @@ static ssize_t show_associate_remote(struct device *d, else strcpy(buf, "closed\n"); - dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for " - "instructions on how to associate your iMON 2.4G DT/LT " - "remote\n"); + dev_info(d, "Visit http://www.lirc.org/html/imon-24g.html for instructions on how to associate your iMON 2.4G DT/LT remote\n"); mutex_unlock(&ictx->lock); return strlen(buf); } @@ -1115,8 +1109,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 }; if (*rc_type && !(*rc_type & rc->allowed_protocols)) - dev_warn(dev, "Looks like you're trying to use an IR protocol " - "this device does not support\n"); + dev_warn(dev, "Looks like you're trying to use an IR protocol this device does not support\n"); if (*rc_type & RC_BIT_RC6_MCE) { dev_dbg(dev, "Configuring IR receiver for MCE protocol\n"); @@ -1129,8 +1122,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_type) /* ir_proto_packet[0] = 0x00; // already the default */ *rc_type = RC_BIT_OTHER; } else { - dev_warn(dev, "Unsupported IR protocol specified, overriding " - "to iMON IR protocol\n"); + dev_warn(dev, "Unsupported IR protocol specified, overriding to iMON IR protocol\n"); if (!pad_stabilize) dev_dbg(dev, "PAD stabilize functionality disabled\n"); /* ir_proto_packet[0] = 0x00; // already the default */ @@ -1719,8 +1711,8 @@ static void imon_incoming_packet(struct imon_context *ictx, not_input_data: if (len != 8) { - dev_warn(dev, "imon %s: invalid incoming packet " - "size (len = %d, intf%d)\n", __func__, len, intf); + dev_warn(dev, "imon %s: invalid incoming packet size (len = %d, intf%d)\n", + __func__, len, intf); return; } @@ -1876,8 +1868,7 @@ static void imon_get_ffdc_type(struct imon_context *ictx) allowed_protos = RC_BIT_RC6_MCE; break; default: - dev_info(ictx->dev, "Unknown 0xffdc device, " - "defaulting to VFD and iMON IR"); + dev_info(ictx->dev, "Unknown 0xffdc device, defaulting to VFD and iMON IR"); detected_display_type = IMON_DISPLAY_TYPE_VFD; /* We don't know which one it is, allow user to set the * RC6 one from userspace if OTHER wasn't correct. */ @@ -1934,8 +1925,8 @@ static void imon_set_display_type(struct imon_context *ictx) ictx->display_supported = false; else ictx->display_supported = true; - dev_info(ictx->dev, "%s: overriding display type to %d via " - "modparam\n", __func__, display_type); + dev_info(ictx->dev, "%s: overriding display type to %d via modparam\n", + __func__, display_type); } ictx->display_type = configured_display_type; @@ -2156,8 +2147,8 @@ static bool imon_find_endpoints(struct imon_context *ictx, if (!display_ep_found) { tx_control = true; display_ep_found = true; - dev_dbg(ictx->dev, "%s: device uses control endpoint, not " - "interface OUT endpoint\n", __func__); + dev_dbg(ictx->dev, "%s: device uses control endpoint, not interface OUT endpoint\n", + __func__); } /* @@ -2366,8 +2357,8 @@ static void imon_init_display(struct imon_context *ictx, /* set up sysfs entry for built-in clock */ ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group); if (ret) - dev_err(ictx->dev, "Could not create display sysfs " - "entries(%d)", ret); + dev_err(ictx->dev, "Could not create display sysfs entries(%d)", + ret); if (ictx->display_type == IMON_DISPLAY_TYPE_LCD) ret = usb_register_dev(intf, &imon_lcd_class); @@ -2375,8 +2366,7 @@ static void imon_init_display(struct imon_context *ictx, ret = usb_register_dev(intf, &imon_vfd_class); if (ret) /* Not a fatal error, so ignore */ - dev_info(ictx->dev, "could not get a minor number for " - "display\n"); + dev_info(ictx->dev, "could not get a minor number for display\n"); } @@ -2456,8 +2446,8 @@ static int imon_probe(struct usb_interface *interface, mutex_unlock(&ictx->lock); } - dev_info(dev, "iMON device (%04x:%04x, intf%d) on " - "usb<%d:%d> initialized\n", vendor, product, ifnum, + dev_info(dev, "iMON device (%04x:%04x, intf%d) on usb<%d:%d> initialized\n", + vendor, product, ifnum, usbdev->bus->busnum, usbdev->devnum); mutex_unlock(&driver_lock); diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index 0f301903aa6f..c5e8e3885766 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -55,14 +55,12 @@ MODULE_PARM_DESC(debug, "Enable debugging output"); /* low limit for RX carrier freq, Hz, 0 for no RX demodulation */ static int rx_low_carrier_freq; module_param(rx_low_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, " - "0 for no RX demodulation"); +MODULE_PARM_DESC(rx_low_carrier_freq, "Override low RX carrier frequency, Hz, 0 for no RX demodulation"); /* high limit for RX carrier freq, Hz, 0 for no RX demodulation */ static int rx_high_carrier_freq; module_param(rx_high_carrier_freq, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, " - "Hz, 0 for no RX demodulation"); +MODULE_PARM_DESC(rx_high_carrier_freq, "Override high RX carrier frequency, Hz, 0 for no RX demodulation"); /* override tx carrier frequency */ static int tx_carrier_freq; @@ -1484,8 +1482,7 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id if (model_number >= 0 && model_number < ARRAY_SIZE(ite_dev_descs)) { model_no = model_number; - ite_pr(KERN_NOTICE, "The model has been fixed by a module " - "parameter."); + ite_pr(KERN_NOTICE, "The model has been fixed by a module parameter."); } ite_pr(KERN_NOTICE, "Using model: %s\n", ite_dev_descs[model_no].model); diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 4f8c7effdcee..f813b77c595d 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -604,9 +604,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf, break; case MCE_RSP_EQWAKEVERSION: if (!out) - dev_dbg(dev, "Wake version, proto: 0x%02x, " - "payload: 0x%02x, address: 0x%02x, " - "version: 0x%02x", + dev_dbg(dev, "Wake version, proto: 0x%02x, payload: 0x%02x, address: 0x%02x, version: 0x%02x", data1, data2, data3, data4); break; case MCE_RSP_GETPORTSTATUS: diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index d9c1f2ff7119..b241e5f569ef 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -660,8 +660,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_type protocol, dev->last_toggle = toggle; dev->last_keycode = keycode; - IR_dprintk(1, "%s: key down event, " - "key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", + IR_dprintk(1, "%s: key down event, key 0x%04x, protocol 0x%04x, scancode 0x%08x\n", dev->input_name, keycode, protocol, scancode); input_report_key(dev->input_dev, keycode, 1); diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 05ba47bc0b61..3b0ed1c3f2d8 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -265,8 +265,7 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) /* Codes 0x20 through 0x2f are IR Firmware Errors */ case 0x20: - pr_cont("Initial signal pulse not long enough " - "to measure carrier frequency\n"); + pr_cont("Initial signal pulse not long enough to measure carrier frequency\n"); break; case 0x21: pr_cont("Not enough length values allocated for signal\n"); @@ -278,18 +277,15 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) pr_cont("Too many signal repeats\n"); break; case 0x28: - pr_cont("Insufficient memory available for IR signal " - "data memory allocation\n"); + pr_cont("Insufficient memory available for IR signal data memory allocation\n"); break; case 0x29: - pr_cont("Insufficient memory available " - "for IrDa signal data memory allocation\n"); + pr_cont("Insufficient memory available for IrDa signal data memory allocation\n"); break; /* Codes 0x30 through 0x3f are USB Firmware Errors */ case 0x30: - pr_cont("Insufficient memory available for bulk " - "transfer structure\n"); + pr_cont("Insufficient memory available for bulk transfer structure\n"); break; /* @@ -301,8 +297,7 @@ static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) pr_cont("Signal capture has been terminated\n"); break; case 0x41: - pr_cont("Attempt to set/get and unknown signal I/O " - "algorithm parameter\n"); + pr_cont("Attempt to set/get and unknown signal I/O algorithm parameter\n"); break; case 0x42: pr_cont("Signal capture already started\n"); @@ -917,8 +912,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) goto out; } - snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s " - "Infrared Remote Transceiver (%04x:%04x)", + snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s Infrared Remote Transceiver (%04x:%04x)", prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "", le16_to_cpu(rr3->udev->descriptor.idVendor), prod); diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c index 4004260a7c69..53f9b0af358a 100644 --- a/drivers/media/rc/streamzap.c +++ b/drivers/media/rc/streamzap.c @@ -297,8 +297,7 @@ static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz) goto out; } - snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared " - "Receiver (%04x:%04x)", + snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared Receiver (%04x:%04x)", le16_to_cpu(sz->usbdev->descriptor.idVendor), le16_to_cpu(sz->usbdev->descriptor.idProduct)); usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys)); @@ -364,15 +363,15 @@ static int streamzap_probe(struct usb_interface *intf, sz->endpoint = &(iface_host->endpoint[0].desc); if (!usb_endpoint_dir_in(sz->endpoint)) { - dev_err(&intf->dev, "%s: endpoint doesn't match input device " - "02%02x\n", __func__, sz->endpoint->bEndpointAddress); + dev_err(&intf->dev, "%s: endpoint doesn't match input device 02%02x\n", + __func__, sz->endpoint->bEndpointAddress); retval = -ENODEV; goto free_sz; } if (!usb_endpoint_xfer_int(sz->endpoint)) { - dev_err(&intf->dev, "%s: endpoint attributes don't match xfer " - "02%02x\n", __func__, sz->endpoint->bmAttributes); + dev_err(&intf->dev, "%s: endpoint attributes don't match xfer 02%02x\n", + __func__, sz->endpoint->bmAttributes); retval = -ENODEV; goto free_sz; } diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 95ae60e659a1..cdcd6e38b295 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -227,8 +227,7 @@ struct wbcir_data { static enum wbcir_protocol protocol = IR_PROTOCOL_RC6; module_param(protocol, uint, 0444); -MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command " - "(0 = RC5, 1 = NEC, 2 = RC6A, default)"); +MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command (0 = RC5, 1 = NEC, 2 = RC6A, default)"); static bool invert; /* default = 0 */ module_param(invert, bool, 0444); @@ -244,8 +243,7 @@ MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command"); static unsigned int wake_rc6mode = 6; module_param(wake_rc6mode, uint, 0644); -MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command " - "(0 = 0, 6 = 6A, default)"); +MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command (0 = 0, 6 = 6A, default)"); @@ -1050,8 +1048,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) goto exit_free_data; } - dev_dbg(&device->dev, "Found device " - "(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", + dev_dbg(&device->dev, "Found device (w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n", data->wbase, data->ebase, data->sbase, data->irq); data->led.name = "cir::activity"; -- cgit v1.2.3 From 8ca2e927eb29cdfb67439b5894307e7d3872f2ee Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 18 Oct 2016 17:44:26 -0200 Subject: [media] tuners: don't break long lines Due to the 80-cols restrictions, and latter due to checkpatch warnings, several strings were broken into multiple lines. This is not considered a good practice anymore, as it makes harder to grep for strings at the source code. As we're right now fixing other drivers due to KERN_CONT, we need to be able to identify what printk strings don't end with a "\n". It is a way easier to detect those if we don't break long lines. So, join those continuation lines. The patch was generated via the script below, and manually adjusted if needed. use Text::Tabs; while (<>) { if ($next ne "") { $c=$_; if ($c =~ /^\s+\"(.*)/) { $c2=$1; $next =~ s/\"\n$//; $n = expand($next); $funpos = index($n, '('); $pos = index($c2, '",'); if ($funpos && $pos > 0) { $s1 = substr $c2, 0, $pos + 2; $s2 = ' ' x ($funpos + 1) . substr $c2, $pos + 2; $s2 =~ s/^\s+//; $s2 = ' ' x ($funpos + 1) . $s2 if ($s2 ne ""); print unexpand("$next$s1\n"); print unexpand("$s2\n") if ($s2 ne ""); } else { print "$next$c2\n"; } $next=""; next; } else { print $next; } $next=""; } else { if (m/\"$/) { if (!m/\\n\"$/) { $next=$_; next; } } } print $_; } Signed-off-by: Mauro Carvalho Chehab --- drivers/media/tuners/fc0011.c | 7 ++---- drivers/media/tuners/mc44s803.c | 4 +-- drivers/media/tuners/tda18271-common.c | 4 +-- drivers/media/tuners/tda18271-fe.c | 3 +-- drivers/media/tuners/tda18271-maps.c | 6 +---- drivers/media/tuners/tda8290.c | 4 +-- drivers/media/tuners/tea5761.c | 6 ++--- drivers/media/tuners/tuner-simple.c | 45 ++++++++++++++-------------------- drivers/media/tuners/xc4000.c | 25 ++++++------------- 9 files changed, 39 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c index 3932aa81e18c..2dda8d993c14 100644 --- a/drivers/media/tuners/fc0011.c +++ b/drivers/media/tuners/fc0011.c @@ -262,8 +262,7 @@ static int fc0011_set_params(struct dvb_frontend *fe) regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW7M; break; default: - dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. " - "Using 6000 kHz.\n", + dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. Using 6000 kHz.\n", bandwidth); bandwidth = 6000; /* fallthrough */ @@ -435,9 +434,7 @@ static int fc0011_set_params(struct dvb_frontend *fe) if (err) return err; - dev_dbg(&priv->i2c->dev, "Tuned to " - "fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X " - "vcocal=%02X(%u) bw=%u\n", + dev_dbg(&priv->i2c->dev, "Tuned to fa=%02X fp=%02X xin=%02X%02X vco=%02X vcosel=%02X vcocal=%02X(%u) bw=%u\n", (unsigned int)regs[FC11_REG_FA], (unsigned int)regs[FC11_REG_FP], (unsigned int)regs[FC11_REG_XINHI], diff --git a/drivers/media/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c index f1b764074661..d5681669d3cd 100644 --- a/drivers/media/tuners/mc44s803.c +++ b/drivers/media/tuners/mc44s803.c @@ -349,8 +349,8 @@ struct dvb_frontend *mc44s803_attach(struct dvb_frontend *fe, id = MC44S803_REG_MS(reg, MC44S803_ID); if (id != 0x14) { - mc_printk(KERN_ERR, "unsupported ID " - "(%x should be 0x14)\n", id); + mc_printk(KERN_ERR, "unsupported ID (%x should be 0x14)\n", + id); goto error; } diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c index a26bb33102b8..7e81cd887c13 100644 --- a/drivers/media/tuners/tda18271-common.c +++ b/drivers/media/tuners/tda18271-common.c @@ -251,8 +251,8 @@ static int __tda18271_write_regs(struct dvb_frontend *fe, int idx, int len, } if (ret != 1) - tda_err("ERROR: idx = 0x%x, len = %d, " - "i2c_transfer returned: %d\n", idx, max, ret); + tda_err("ERROR: idx = 0x%x, len = %d, i2c_transfer returned: %d\n", + idx, max, ret); return (ret == 1 ? 0 : ret); } diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index 2d50e8b1dce1..a4730610c0c6 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -26,8 +26,7 @@ int tda18271_debug; module_param_named(debug, tda18271_debug, int, 0644); -MODULE_PARM_DESC(debug, "set debug level " - "(info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); +MODULE_PARM_DESC(debug, "set debug level (info=1, map=2, reg=4, adv=8, cal=16 (or-able))"); static int tda18271_cal_on_startup = -1; module_param_named(cal, tda18271_cal_on_startup, int, 0644); diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c index 1e89dd93c4bb..7d114677b4ca 100644 --- a/drivers/media/tuners/tda18271-maps.c +++ b/drivers/media/tuners/tda18271-maps.c @@ -1024,11 +1024,7 @@ int tda18271_lookup_rf_band(struct dvb_frontend *fe, u32 *freq, u8 *rf_band) while ((map[i].rfmax * 1000) < *freq) { if (tda18271_debug & DBG_ADV) - tda_map("(%d) rfmax = %d < freq = %d, " - "rf1_def = %d, rf2_def = %d, rf3_def = %d, " - "rf1 = %d, rf2 = %d, rf3 = %d, " - "rf_a1 = %d, rf_a2 = %d, " - "rf_b1 = %d, rf_b2 = %d\n", + tda_map("(%d) rfmax = %d < freq = %d, rf1_def = %d, rf2_def = %d, rf3_def = %d, rf1 = %d, rf2 = %d, rf3 = %d, rf_a1 = %d, rf_a2 = %d, rf_b1 = %d, rf_b2 = %d\n", i, map[i].rfmax * 1000, *freq, map[i].rf1_def, map[i].rf2_def, map[i].rf3_def, map[i].rf1, map[i].rf2, map[i].rf3, diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index 998e82bba9c0..6b75415b75a5 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -617,8 +617,8 @@ static int tda829x_find_tuner(struct dvb_frontend *fe) if (tuner_addrs == 0) { tuner_addrs = 0x60; - tuner_info("could not clearly identify tuner address, " - "defaulting to %x\n", tuner_addrs); + tuner_info("could not clearly identify tuner address, defaulting to %x\n", + tuner_addrs); } else { tuner_addrs = tuner_addrs & 0xff; tuner_info("setting tuner address to %x\n", tuner_addrs); diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c index 36b0b1e1d05b..12347aa95de3 100644 --- a/drivers/media/tuners/tea5761.c +++ b/drivers/media/tuners/tea5761.c @@ -274,13 +274,11 @@ int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) } if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) { - printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x." - " It is not a TEA5761\n", + printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n", buffer[13], buffer[14], buffer[15]); return -EINVAL; } - printk(KERN_WARNING "tea5761: TEA%02x%02x detected. " - "Manufacturer ID= 0x%02x\n", + printk(KERN_WARNING "tea5761: TEA%02x%02x detected. Manufacturer ID= 0x%02x\n", buffer[14], buffer[15], buffer[13]); return 0; diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index 9ba9582e7765..315f45cd0778 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c @@ -275,8 +275,7 @@ static int simple_config_lookup(struct dvb_frontend *fe, *config = t_params->ranges[i].config; *cb = t_params->ranges[i].cb; - tuner_dbg("freq = %d.%02d (%d), range = %d, " - "config = 0x%02x, cb = 0x%02x\n", + tuner_dbg("freq = %d.%02d (%d), range = %d, config = 0x%02x, cb = 0x%02x\n", *frequency / 16, *frequency % 16 * 100 / 16, *frequency, i, *config, *cb); @@ -404,12 +403,12 @@ static int simple_std_setup(struct dvb_frontend *fe, i2c.addr = 0x0a; rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2); if (2 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 2)\n", rc); + tuner_warn("i2c i/o error: rc == %d (should be 2)\n", + rc); rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2); if (2 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 2)\n", rc); + tuner_warn("i2c i/o error: rc == %d (should be 2)\n", + rc); break; } } @@ -463,8 +462,8 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, rc = tuner_i2c_xfer_recv(&priv->i2c_props, &status_byte, 1); if (1 != rc) { - tuner_warn("i2c i/o read error: rc == %d " - "(should be 1)\n", rc); + tuner_warn("i2c i/o read error: rc == %d (should be 1)\n", + rc); break; } if (status_byte & TUNER_PLL_LOCKED) @@ -483,8 +482,8 @@ static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer, rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4); if (4 != rc) - tuner_warn("i2c i/o error: rc == %d " - "(should be 4)\n", rc); + tuner_warn("i2c i/o error: rc == %d (should be 4)\n", + rc); break; } } @@ -499,8 +498,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer) switch (priv->type) { case TUNER_TENA_9533_DI: case TUNER_YMEC_TVF_5533MF: - tuner_dbg("This tuner doesn't have FM. " - "Most cards have a TEA5767 for FM\n"); + tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n"); return 0; case TUNER_PHILIPS_FM1216ME_MK3: case TUNER_PHILIPS_FM1236_MK3: @@ -586,8 +584,7 @@ static int simple_set_tv_freq(struct dvb_frontend *fe, div = params->frequency + IFPCoff + offset; - tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, " - "Offset=%d.%02d MHz, div=%0d\n", + tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n", params->frequency / 16, params->frequency % 16 * 100 / 16, IFPCoff / 16, IFPCoff % 16 * 100 / 16, offset / 16, offset % 16 * 100 / 16, div); @@ -858,8 +855,7 @@ static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf, if (!tun->stepsize) { /* tuner-core was loaded before the digital tuner was * configured and somehow picked the wrong tuner type */ - tuner_err("attempt to treat tuner %d (%s) as digital tuner " - "without stepsize defined.\n", + tuner_err("attempt to treat tuner %d (%s) as digital tuner without stepsize defined.\n", priv->type, priv->tun->name); return 0; /* failure */ } @@ -1077,8 +1073,7 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, fe->ops.i2c_gate_ctrl(fe, 1); if (1 != i2c_transfer(i2c_adap, &msg, 1)) - printk(KERN_WARNING "tuner-simple %d-%04x: " - "unable to probe %s, proceeding anyway.", + printk(KERN_WARNING "tuner-simple %d-%04x: unable to probe %s, proceeding anyway.", i2c_adapter_id(i2c_adap), i2c_addr, tuners[type].name); @@ -1123,18 +1118,16 @@ struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe, if ((debug) || ((atv_input[priv->nr] > 0) || (dtv_input[priv->nr] > 0))) { if (0 == atv_input[priv->nr]) - tuner_info("tuner %d atv rf input will be " - "autoselected\n", priv->nr); + tuner_info("tuner %d atv rf input will be autoselected\n", + priv->nr); else - tuner_info("tuner %d atv rf input will be " - "set to input %d (insmod option)\n", + tuner_info("tuner %d atv rf input will be set to input %d (insmod option)\n", priv->nr, atv_input[priv->nr]); if (0 == dtv_input[priv->nr]) - tuner_info("tuner %d dtv rf input will be " - "autoselected\n", priv->nr); + tuner_info("tuner %d dtv rf input will be autoselected\n", + priv->nr); else - tuner_info("tuner %d dtv rf input will be " - "set to input %d (insmod option)\n", + tuner_info("tuner %d dtv rf input will be set to input %d (insmod option)\n", priv->nr, dtv_input[priv->nr]); } diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index d95c7e082ccf..ac98dea985c8 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -43,14 +43,11 @@ MODULE_PARM_DESC(debug, "Debugging level (0 to 2, default: 0 (off))."); static int no_poweroff; module_param(no_poweroff, int, 0644); -MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, " - "0 (default): use device-specific default mode)."); +MODULE_PARM_DESC(no_poweroff, "Power management (1: disabled, 2: enabled, 0 (default): use device-specific default mode)."); static int audio_std; module_param(audio_std, int, 0644); -MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " - "needs to know what audio standard is needed for some video standards " - "with audio A2 or NICAM. The valid settings are a sum of:\n" +MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly needs to know what audio standard is needed for some video standards with audio A2 or NICAM. The valid settings are a sum of:\n" " 1: use NICAM/B or A2/B instead of NICAM/A or A2/A\n" " 2: use A2 instead of NICAM or BTSC\n" " 4: use SECAM/K3 instead of K1\n" @@ -60,8 +57,7 @@ MODULE_PARM_DESC(audio_std, "Audio standard. XC4000 audio decoder explicitly " static char firmware_name[30]; module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0); -MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the " - "default firmware name."); +MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the default firmware name."); static DEFINE_MUTEX(xc4000_list_mutex); static LIST_HEAD(hybrid_tuner_instance_list); @@ -290,8 +286,7 @@ static int xc4000_tuner_reset(struct dvb_frontend *fe) return -EREMOTEIO; } } else { - printk(KERN_ERR "xc4000: no tuner reset callback function, " - "fatal\n"); + printk(KERN_ERR "xc4000: no tuner reset callback function, fatal\n"); return -EINVAL; } return 0; @@ -679,8 +674,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type, if (best_nr_diffs > 0U) { printk(KERN_WARNING - "Selecting best matching firmware (%u bits differ) for " - "type=(%x), id %016llx:\n", + "Selecting best matching firmware (%u bits differ) for type=(%x), id %016llx:\n", best_nr_diffs, type, (unsigned long long)*id); i = best_i; } @@ -800,8 +794,7 @@ static int xc4000_fwupload(struct dvb_frontend *fe) n++; if (n >= n_array) { - printk(KERN_ERR "More firmware images in file than " - "were expected!\n"); + printk(KERN_ERR "More firmware images in file than were expected!\n"); goto corrupt; } @@ -1055,8 +1048,7 @@ check_device: goto fail; } - dprintk(1, "Device is Xceive %d version %d.%d, " - "firmware version %d.%d\n", + dprintk(1, "Device is Xceive %d version %d.%d, firmware version %d.%d\n", hwmodel, hw_major, hw_minor, fw_major, fw_minor); /* Check firmware version against what we downloaded. */ @@ -1076,8 +1068,7 @@ check_device: } else if (priv->hwmodel == 0 || priv->hwmodel != hwmodel || priv->hwvers != ((hw_major << 8) | hw_minor)) { printk(KERN_WARNING - "Read invalid device hardware information - tuner " - "hung?\n"); + "Read invalid device hardware information - tuner hung?\n"); goto fail; } -- cgit v1.2.3 From 7cda4c5bae46ffca3abeadc4c1882d9325ee3102 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 10:51:20 -0300 Subject: [media] tveeprom: use dev_foo() for printk messages Instead of calling a V4L-specific macro, do the right thing and use the dev_foo() macros. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tveeprom.c | 76 +++++++++++++---------------------------- 1 file changed, 24 insertions(+), 52 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c index e0e2cb706087..e7d0d86f19aa 100644 --- a/drivers/media/common/tveeprom.c +++ b/drivers/media/common/tveeprom.c @@ -28,7 +28,6 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - #include #include #include @@ -45,22 +44,9 @@ MODULE_DESCRIPTION("i2c Hauppauge eeprom decoder driver"); MODULE_AUTHOR("John Klar"); MODULE_LICENSE("GPL"); -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "Debug level (0-1)"); - #define STRM(array, i) \ (i < sizeof(array) / sizeof(char *) ? array[i] : "unknown") -#define tveeprom_info(fmt, arg...) \ - v4l_printk(KERN_INFO, "tveeprom", c->adapter, c->addr, fmt , ## arg) -#define tveeprom_warn(fmt, arg...) \ - v4l_printk(KERN_WARNING, "tveeprom", c->adapter, c->addr, fmt , ## arg) -#define tveeprom_dbg(fmt, arg...) do { \ - if (debug) \ - v4l_printk(KERN_DEBUG, "tveeprom", \ - c->adapter, c->addr, fmt , ## arg); \ - } while (0) /* * The Hauppauge eeprom uses an 8bit field to determine which @@ -510,18 +496,13 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, len = eeprom_data[i] & 0x07; ++i; } else { - tveeprom_warn("Encountered bad packet header [%02x]. Corrupt or not a Hauppauge eeprom.\n", + dev_warn(&c->dev, "Encountered bad packet header [%02x]. Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); return; } - if (debug) { - tveeprom_info("Tag [%02x] + %d bytes:", - eeprom_data[i], len - 1); - for (j = 1; j < len; j++) - printk(KERN_CONT " %02x", eeprom_data[i + j]); - printk(KERN_CONT "\n"); - } + dev_dbg(&c->dev, "Tag [%02x] + %d bytes: %*ph\n", + eeprom_data[i], len - 1, len, &eeprom_data[i]); /* process by tag */ tag = eeprom_data[i]; @@ -661,14 +642,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, /* case 0x12: tag 'InfoBits' */ default: - tveeprom_dbg("Not sure what to do with tag [%02x]\n", + dev_dbg(&c->dev, "Not sure what to do with tag [%02x]\n", tag); /* dump the rest of the packet? */ } } if (!done) { - tveeprom_warn("Ran out of data!\n"); + dev_warn(&c->dev, "Ran out of data!\n"); return; } @@ -681,8 +662,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, } if (hasRadioTuner(tuner1) && !tvee->has_radio) { - tveeprom_info("The eeprom says no radio is present, but the tuner type\n"); - tveeprom_info("indicates otherwise. I will assume that radio is present.\n"); + dev_info(&c->dev, "The eeprom says no radio is present, but the tuner type\n"); + dev_info(&c->dev, "indicates otherwise. I will assume that radio is present.\n"); tvee->has_radio = 1; } @@ -717,46 +698,46 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, } } - tveeprom_info("Hauppauge model %d, rev %s, serial# %u\n", + dev_info(&c->dev, "Hauppauge model %d, rev %s, serial# %u\n", tvee->model, tvee->rev_str, tvee->serial_number); if (tvee->has_MAC_address == 1) - tveeprom_info("MAC address is %pM\n", tvee->MAC_address); - tveeprom_info("tuner model is %s (idx %d, type %d)\n", + dev_info(&c->dev, "MAC address is %pM\n", tvee->MAC_address); + dev_info(&c->dev, "tuner model is %s (idx %d, type %d)\n", t_name1, tuner1, tvee->tuner_type); - tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + dev_info(&c->dev, "TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], t_format1); if (tuner2) - tveeprom_info("second tuner model is %s (idx %d, type %d)\n", + dev_info(&c->dev, "second tuner model is %s (idx %d, type %d)\n", t_name2, tuner2, tvee->tuner2_type); if (t_format2) - tveeprom_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + dev_info(&c->dev, "TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], t_format2); if (audioic < 0) { - tveeprom_info("audio processor is unknown (no idx)\n"); + dev_info(&c->dev, "audio processor is unknown (no idx)\n"); tvee->audio_processor = TVEEPROM_AUDPROC_OTHER; } else { if (audioic < ARRAY_SIZE(audio_ic)) - tveeprom_info("audio processor is %s (idx %d)\n", + dev_info(&c->dev, "audio processor is %s (idx %d)\n", audio_ic[audioic].name, audioic); else - tveeprom_info("audio processor is unknown (idx %d)\n", + dev_info(&c->dev, "audio processor is unknown (idx %d)\n", audioic); } if (tvee->decoder_processor) - tveeprom_info("decoder processor is %s (idx %d)\n", + dev_info(&c->dev, "decoder processor is %s (idx %d)\n", STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); if (tvee->has_ir) - tveeprom_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", + dev_info(&c->dev, "has %sradio, has %sIR receiver, has %sIR transmitter\n", tvee->has_radio ? "" : "no ", (tvee->has_ir & 2) ? "" : "no ", (tvee->has_ir & 4) ? "" : "no "); else - tveeprom_info("has %sradio\n", + dev_info(&c->dev, "has %sradio\n", tvee->has_radio ? "" : "no "); } EXPORT_SYMBOL(tveeprom_hauppauge_analog); @@ -772,26 +753,17 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) buf = 0; err = i2c_master_send(c, &buf, 1); if (err != 1) { - tveeprom_info("Huh, no eeprom present (err=%d)?\n", err); + dev_info(&c->dev, "Huh, no eeprom present (err=%d)?\n", err); return -1; } err = i2c_master_recv(c, eedata, len); if (err != len) { - tveeprom_warn("i2c eeprom read error (err=%d)\n", err); + dev_warn(&c->dev, "i2c eeprom read error (err=%d)\n", err); return -1; } - if (debug) { - int i; - - tveeprom_info("full 256-byte eeprom dump:\n"); - for (i = 0; i < len; i++) { - if (0 == (i % 16)) - tveeprom_info("%02x:", i); - printk(KERN_CONT " %02x", eedata[i]); - if (15 == (i % 16)) - printk(KERN_CONT "\n"); - } - } + + print_hex_dump_debug("full 256-byte eeprom dump:", DUMP_PREFIX_NONE, + 16, 1, eedata, len, true); return 0; } EXPORT_SYMBOL(tveeprom_read); -- cgit v1.2.3 From 3467c9a7e7f9209a9ecd8f9db65b04a323a13932 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Fri, 16 Sep 2016 03:14:33 -0300 Subject: [media] s5p-mfc: fix failure path of s5p_mfc_alloc_memdev() s5p_mfc_alloc_memdev() function lacks proper releasing of allocated device in case of reserved memory initialization failure. This results in NULL pointer dereference: [ 2.828457] Unable to handle kernel NULL pointer dereference at virtual address 00000001 [ 2.835089] pgd = c0004000 [ 2.837752] [00000001] *pgd=00000000 [ 2.844696] Internal error: Oops: 5 [#1] PREEMPT SMP ARM [ 2.848680] Modules linked in: [ 2.851722] CPU: 1 PID: 1 Comm: swapper/0 Not tainted 4.8.0-rc6-00002-gafa1b97 #878 [ 2.859357] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 2.865433] task: ef080000 task.stack: ef06c000 [ 2.869952] PC is at strcmp+0x0/0x30 [ 2.873508] LR is at platform_match+0x84/0xac [ 2.877847] pc : [] lr : [] psr: 20000013 [ 2.877847] sp : ef06dea0 ip : 00000000 fp : 00000000 [ 2.889303] r10: 00000000 r9 : c0b34848 r8 : c0b1e968 [ 2.894511] r7 : 00000000 r6 : 00000001 r5 : c086e7fc r4 : eeb8e010 [ 2.901021] r3 : 0000006d r2 : 00000000 r1 : c086e7fc r0 : 00000001 [ 2.907533] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 2.914649] Control: 10c5387d Table: 4000404a DAC: 00000051 [ 2.920378] Process swapper/0 (pid: 1, stack limit = 0xef06c210) [ 2.926367] Stack: (0xef06dea0 to 0xef06e000) [ 2.930711] dea0: eeb8e010 c0c2d91c c03f4a6c c03f4a8c 00000000 c0c2d91c c03f4a6c c03f2fc8 [ 2.938870] dec0: ef003274 ef10c4c0 c0c2d91c ef10cc80 c0c21270 c03f3fa4 c09c1be8 c0c2d91c [ 2.947028] dee0: 00000006 c0c2d91c 00000006 c0b3483c c0c47000 c03f5314 c0c2d908 c0b5fed8 [ 2.955188] df00: 00000006 c010178c 60000013 c0a4ef14 00000000 c06feaa0 ef080000 60000013 [ 2.963347] df20: 00000000 c0c095c8 efffca76 c0816b8c 000000d5 c0134098 c0b34848 c09d6cdc [ 2.971506] df40: c0a4de70 00000000 00000006 00000006 c0c09568 efffca40 c0b5fed8 00000006 [ 2.979665] df60: c0b3483c c0c47000 000000d5 c0b34848 c0b005a4 c0b00d84 00000006 00000006 [ 2.987824] df80: 00000000 c0b005a4 00000000 c06fb4d8 00000000 00000000 00000000 00000000 [ 2.995983] dfa0: 00000000 c06fb4e0 00000000 c01079b8 00000000 00000000 00000000 00000000 [ 3.004142] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 3.012302] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 ffffffff ffffffff [ 3.020469] [] (strcmp) from [] (platform_match+0x84/0xac) [ 3.027672] [] (platform_match) from [] (__driver_attach+0x20/0xb0) [ 3.035654] [] (__driver_attach) from [] (bus_for_each_dev+0x54/0x88) [ 3.043812] [] (bus_for_each_dev) from [] (bus_add_driver+0xe8/0x1f4) [ 3.051971] [] (bus_add_driver) from [] (driver_register+0x78/0xf4) [ 3.059958] [] (driver_register) from [] (do_one_initcall+0x3c/0x16c) [ 3.068123] [] (do_one_initcall) from [] (kernel_init_freeable+0x120/0x1ec) [ 3.076802] [] (kernel_init_freeable) from [] (kernel_init+0x8/0x118) [ 3.084958] [] (kernel_init) from [] (ret_from_fork+0x14/0x3c) [ 3.092506] Code: 1afffffb e12fff1e e1a03000 eafffff7 (e4d03001) [ 3.098618] ---[ end trace 511bf9d750810709 ]--- [ 3.103207] Kernel panic - not syncing: Attempted to kill init! exitcode=0x0000000b This patch fixes this issue. Fixes: c79667dd93b084fe412bcfe7fbf0ba43f7dec520 ("media: s5p-mfc: replace custom reserved memory handling code with generic one") CC: stable@vger.kernel.org # v4.7+ Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 0a5b8f5e011e..3436eda58855 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1082,6 +1082,7 @@ static struct device *s5p_mfc_alloc_memdev(struct device *dev, idx); if (ret == 0) return child; + device_del(child); } put_device(child); -- cgit v1.2.3 From e2818a59f7ca42e896869903239575cd36f52119 Mon Sep 17 00:00:00 2001 From: Andrew-CT Chen Date: Fri, 2 Sep 2016 09:19:52 -0300 Subject: [media] VPU: mediatek: Add decode support VPU driver add decode support [mchehab@s-opensource.org: fix a kernel-doc markup] Signed-off-by: Andrew-CT Chen Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.c | 12 +++++++++ drivers/media/platform/mtk-vpu/mtk_vpu.h | 43 ++++++++++++++++++++++++++------ 2 files changed, 47 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index c9bf58c97878..63510de0147c 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -134,6 +134,8 @@ struct vpu_wdt { * * @signaled: the signal of vpu initialization completed * @fw_ver: VPU firmware version + * @dec_capability: decoder capability which is not used for now and + * the value is reserved for future use * @enc_capability: encoder capability which is not used for now and * the value is reserved for future use * @wq: wait queue for VPU initialization status @@ -141,6 +143,7 @@ struct vpu_wdt { struct vpu_run { u32 signaled; char fw_ver[VPU_FW_VER_LEN]; + unsigned int dec_capability; unsigned int enc_capability; wait_queue_head_t wq; }; @@ -415,6 +418,14 @@ int vpu_wdt_reg_handler(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(vpu_wdt_reg_handler); +unsigned int vpu_get_vdec_hw_capa(struct platform_device *pdev) +{ + struct mtk_vpu *vpu = platform_get_drvdata(pdev); + + return vpu->run.dec_capability; +} +EXPORT_SYMBOL_GPL(vpu_get_vdec_hw_capa); + unsigned int vpu_get_venc_hw_capa(struct platform_device *pdev) { struct mtk_vpu *vpu = platform_get_drvdata(pdev); @@ -600,6 +611,7 @@ static void vpu_init_ipi_handler(void *data, unsigned int len, void *priv) vpu->run.signaled = run->signaled; strncpy(vpu->run.fw_ver, run->fw_ver, VPU_FW_VER_LEN); + vpu->run.dec_capability = run->dec_capability; vpu->run.enc_capability = run->enc_capability; wake_up_interruptible(&vpu->run.wq); } diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.h b/drivers/media/platform/mtk-vpu/mtk_vpu.h index 5ab37f04bdfd..69da501afffa 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.h +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.h @@ -31,21 +31,36 @@ typedef void (*ipi_handler_t) (void *data, * enum ipi_id - the id of inter-processor interrupt * * @IPI_VPU_INIT: The interrupt from vpu is to notfiy kernel - VPU initialization completed. - IPI_VPU_INIT is sent from VPU when firmware is - loaded. AP doesn't need to send IPI_VPU_INIT - command to VPU. - For other IPI below, AP should send the request - to VPU to trigger the interrupt. + * VPU initialization completed. + * IPI_VPU_INIT is sent from VPU when firmware is + * loaded. AP doesn't need to send IPI_VPU_INIT + * command to VPU. + * For other IPI below, AP should send the request + * to VPU to trigger the interrupt. + * @IPI_VDEC_H264: The interrupt from vpu is to notify kernel to + * handle H264 vidoe decoder job, and vice versa. + * Decode output format is always MT21 no matter what + * the input format is. + * @IPI_VDEC_VP8: The interrupt from is to notify kernel to + * handle VP8 video decoder job, and vice versa. + * Decode output format is always MT21 no matter what + * the input format is. + * @IPI_VDEC_VP9: The interrupt from vpu is to notify kernel to + * handle VP9 video decoder job, and vice versa. + * Decode output format is always MT21 no matter what + * the input format is. * @IPI_VENC_H264: The interrupt from vpu is to notify kernel to - handle H264 video encoder job, and vice versa. + * handle H264 video encoder job, and vice versa. * @IPI_VENC_VP8: The interrupt fro vpu is to notify kernel to - handle VP8 video encoder job,, and vice versa. + * handle VP8 video encoder job,, and vice versa. * @IPI_MAX: The maximum IPI number */ enum ipi_id { IPI_VPU_INIT = 0, + IPI_VDEC_H264, + IPI_VDEC_VP8, + IPI_VDEC_VP9, IPI_VENC_H264, IPI_VENC_VP8, IPI_MAX, @@ -55,10 +70,12 @@ enum ipi_id { * enum rst_id - reset id to register reset function for VPU watchdog timeout * * @VPU_RST_ENC: encoder reset id + * @VPU_RST_DEC: decoder reset id * @VPU_RST_MAX: maximum reset id */ enum rst_id { VPU_RST_ENC, + VPU_RST_DEC, VPU_RST_MAX, }; @@ -125,6 +142,16 @@ struct platform_device *vpu_get_plat_device(struct platform_device *pdev); int vpu_wdt_reg_handler(struct platform_device *pdev, void vpu_wdt_reset_func(void *), void *priv, enum rst_id id); + +/** + * vpu_get_vdec_hw_capa - get video decoder hardware capability + * + * @pdev: VPU platform device + * + * Return: video decoder hardware capability + **/ +unsigned int vpu_get_vdec_hw_capa(struct platform_device *pdev); + /** * vpu_get_venc_hw_capa - get video encoder hardware capability * -- cgit v1.2.3 From 590577a4e5257ac3ed72999a94666ad6ba8f24bc Mon Sep 17 00:00:00 2001 From: Tiffany Lin Date: Fri, 2 Sep 2016 09:19:54 -0300 Subject: [media] vcodec: mediatek: Add Mediatek V4L2 Video Decoder Driver Add v4l2 layer decoder driver for MT8173 [mchehab@s-opensource.com: make checkpatch.pl happy] Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/Makefile | 12 +- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 1432 ++++++++++++++++++++ drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h | 88 ++ .../media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 394 ++++++ .../media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 204 +++ .../media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h | 28 + drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h | 62 +- .../media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c | 8 +- .../media/platform/mtk-vcodec/mtk_vcodec_intr.c | 3 +- .../media/platform/mtk-vcodec/mtk_vcodec_util.c | 33 +- .../media/platform/mtk-vcodec/mtk_vcodec_util.h | 5 + drivers/media/platform/mtk-vcodec/vdec_drv_base.h | 55 + drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 112 ++ drivers/media/platform/mtk-vcodec/vdec_drv_if.h | 101 ++ drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h | 103 ++ drivers/media/platform/mtk-vcodec/vdec_vpu_if.c | 170 +++ drivers/media/platform/mtk-vcodec/vdec_vpu_if.h | 96 ++ 17 files changed, 2884 insertions(+), 22 deletions(-) create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c create mode 100644 drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_base.h create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_if.c create mode 100644 drivers/media/platform/mtk-vcodec/vdec_drv_if.h create mode 100644 drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h create mode 100644 drivers/media/platform/mtk-vcodec/vdec_vpu_if.c create mode 100644 drivers/media/platform/mtk-vcodec/vdec_vpu_if.h (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index dc5cb006d600..b54e82372b4c 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -1,7 +1,13 @@ - -obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-enc.o mtk-vcodec-common.o - +obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ + mtk-vcodec-enc.o \ + mtk-vcodec-common.o + +mtk-vcodec-dec-y := mtk_vcodec_dec_drv.o \ + vdec_drv_if.o \ + vdec_vpu_if.o \ + mtk_vcodec_dec.o \ + mtk_vcodec_dec_pm.o \ mtk-vcodec-enc-y := venc/venc_vp8_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c new file mode 100644 index 000000000000..7f7464a570cb --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -0,0 +1,1432 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * Tiffany Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_dec.h" +#include "mtk_vcodec_intr.h" +#include "mtk_vcodec_util.h" +#include "vdec_drv_if.h" +#include "mtk_vcodec_dec_pm.h" + +#define OUT_FMT_IDX 0 +#define CAP_FMT_IDX 0 + +#define MTK_VDEC_MIN_W 64U +#define MTK_VDEC_MIN_H 64U +#define DFT_CFG_WIDTH MTK_VDEC_MIN_W +#define DFT_CFG_HEIGHT MTK_VDEC_MIN_H + +static struct mtk_video_fmt mtk_video_formats[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .type = MTK_FMT_DEC, + .num_planes = 1, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .type = MTK_FMT_DEC, + .num_planes = 1, + }, +}; + +static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { + { + .fourcc = V4L2_PIX_FMT_H264, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, +}; + +#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) +#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats) + +static struct mtk_video_fmt *mtk_vdec_find_format(struct v4l2_format *f) +{ + struct mtk_video_fmt *fmt; + unsigned int k; + + for (k = 0; k < NUM_FORMATS; k++) { + fmt = &mtk_video_formats[k]; + if (fmt->fourcc == f->fmt.pix_mp.pixelformat) + return fmt; + } + + return NULL; +} + +static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return &ctx->q_data[MTK_Q_DATA_SRC]; + + return &ctx->q_data[MTK_Q_DATA_DST]; +} + +/* + * This function tries to clean all display buffers, the buffers will return + * in display order. + * Note the buffers returned from codec driver may still be in driver's + * reference list. + */ +static struct vb2_buffer *get_display_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct vdec_fb *disp_frame_buffer = NULL; + struct mtk_video_dec_buf *dstbuf; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + if (vdec_if_get_param(ctx, + GET_PARAM_DISP_FRAME_BUFFER, + &disp_frame_buffer)) { + mtk_v4l2_err("[%d]Cannot get param : GET_PARAM_DISP_FRAME_BUFFER", + ctx->id); + return NULL; + } + + if (disp_frame_buffer == NULL) { + mtk_v4l2_debug(3, "No display frame buffer"); + return NULL; + } + + dstbuf = container_of(disp_frame_buffer, struct mtk_video_dec_buf, + frame_buffer); + mutex_lock(&ctx->lock); + if (dstbuf->used) { + vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 0, + ctx->picinfo.y_bs_sz); + vb2_set_plane_payload(&dstbuf->vb.vb2_buf, 1, + ctx->picinfo.c_bs_sz); + + dstbuf->ready_to_display = true; + + mtk_v4l2_debug(2, + "[%d]status=%x queue id=%d to done_list %d", + ctx->id, disp_frame_buffer->status, + dstbuf->vb.vb2_buf.index, + dstbuf->queued_in_vb2); + + v4l2_m2m_buf_done(&dstbuf->vb, VB2_BUF_STATE_DONE); + ctx->decoded_frame_cnt++; + } + mutex_unlock(&ctx->lock); + return &dstbuf->vb.vb2_buf; +} + +/* + * This function tries to clean all capture buffers that are not used as + * reference buffers by codec driver any more + * In this case, we need re-queue buffer to vb2 buffer if user space + * already returns this buffer to v4l2 or this buffer is just the output of + * previous sps/pps/resolution change decode, or do nothing if user + * space still owns this buffer + */ +static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct mtk_video_dec_buf *dstbuf; + struct vdec_fb *free_frame_buffer = NULL; + + if (vdec_if_get_param(ctx, + GET_PARAM_FREE_FRAME_BUFFER, + &free_frame_buffer)) { + mtk_v4l2_err("[%d] Error!! Cannot get param", ctx->id); + return NULL; + } + if (free_frame_buffer == NULL) { + mtk_v4l2_debug(3, " No free frame buffer"); + return NULL; + } + + mtk_v4l2_debug(3, "[%d] tmp_frame_addr = 0x%p", + ctx->id, free_frame_buffer); + + dstbuf = container_of(free_frame_buffer, struct mtk_video_dec_buf, + frame_buffer); + + mutex_lock(&ctx->lock); + if (dstbuf->used) { + if ((dstbuf->queued_in_vb2) && + (dstbuf->queued_in_v4l2) && + (free_frame_buffer->status == FB_ST_FREE)) { + /* + * After decode sps/pps or non-display buffer, we don't + * need to return capture buffer to user space, but + * just re-queue this capture buffer to vb2 queue. + * This reduce overheads that dq/q unused capture + * buffer. In this case, queued_in_vb2 = true. + */ + mtk_v4l2_debug(2, + "[%d]status=%x queue id=%d to rdy_queue %d", + ctx->id, free_frame_buffer->status, + dstbuf->vb.vb2_buf.index, + dstbuf->queued_in_vb2); + v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb); + } else if ((dstbuf->queued_in_vb2 == false) && + (dstbuf->queued_in_v4l2 == true)) { + /* + * If buffer in v4l2 driver but not in vb2 queue yet, + * and we get this buffer from free_list, it means + * that codec driver do not use this buffer as + * reference buffer anymore. We should q buffer to vb2 + * queue, so later work thread could get this buffer + * for decode. In this case, queued_in_vb2 = false + * means this buffer is not from previous decode + * output. + */ + mtk_v4l2_debug(2, + "[%d]status=%x queue id=%d to rdy_queue", + ctx->id, free_frame_buffer->status, + dstbuf->vb.vb2_buf.index); + v4l2_m2m_buf_queue(ctx->m2m_ctx, &dstbuf->vb); + dstbuf->queued_in_vb2 = true; + } else { + /* + * Codec driver do not need to reference this capture + * buffer and this buffer is not in v4l2 driver. + * Then we don't need to do any thing, just add log when + * we need to debug buffer flow. + * When this buffer q from user space, it could + * directly q to vb2 buffer + */ + mtk_v4l2_debug(3, "[%d]status=%x err queue id=%d %d %d", + ctx->id, free_frame_buffer->status, + dstbuf->vb.vb2_buf.index, + dstbuf->queued_in_vb2, + dstbuf->queued_in_v4l2); + } + dstbuf->used = false; + } + mutex_unlock(&ctx->lock); + return &dstbuf->vb.vb2_buf; +} + +static void clean_display_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct vb2_buffer *framptr; + + do { + framptr = get_display_buffer(ctx); + } while (framptr); +} + +static void clean_free_buffer(struct mtk_vcodec_ctx *ctx) +{ + struct vb2_buffer *framptr; + + do { + framptr = get_free_buffer(ctx); + } while (framptr); +} + +static void mtk_vdec_queue_res_chg_event(struct mtk_vcodec_ctx *ctx) +{ + static const struct v4l2_event ev_src_ch = { + .type = V4L2_EVENT_SOURCE_CHANGE, + .u.src_change.changes = + V4L2_EVENT_SRC_CH_RESOLUTION, + }; + + mtk_v4l2_debug(1, "[%d]", ctx->id); + v4l2_event_queue_fh(&ctx->fh, &ev_src_ch); +} + +static void mtk_vdec_flush_decoder(struct mtk_vcodec_ctx *ctx) +{ + bool res_chg; + int ret = 0; + + ret = vdec_if_decode(ctx, NULL, NULL, &res_chg); + if (ret) + mtk_v4l2_err("DecodeFinal failed, ret=%d", ret); + + clean_display_buffer(ctx); + clean_free_buffer(ctx); +} + +static void mtk_vdec_pic_info_update(struct mtk_vcodec_ctx *ctx) +{ + unsigned int dpbsize = 0; + int ret; + + if (vdec_if_get_param(ctx, + GET_PARAM_PIC_INFO, + &ctx->last_decoded_picinfo)) { + mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", + ctx->id); + return; + } + + if (ctx->last_decoded_picinfo.pic_w == 0 || + ctx->last_decoded_picinfo.pic_h == 0 || + ctx->last_decoded_picinfo.buf_w == 0 || + ctx->last_decoded_picinfo.buf_h == 0) { + mtk_v4l2_err("Cannot get correct pic info"); + return; + } + + if ((ctx->last_decoded_picinfo.pic_w == ctx->picinfo.pic_w) || + (ctx->last_decoded_picinfo.pic_h == ctx->picinfo.pic_h)) + return; + + mtk_v4l2_debug(1, + "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", + ctx->id, ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->last_decoded_picinfo.buf_w, + ctx->last_decoded_picinfo.buf_h); + + ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); + if (dpbsize == 0) + mtk_v4l2_err("Incorrect dpb size, ret=%d", ret); + + ctx->dpb_size = dpbsize; +} + +static void mtk_vdec_worker(struct work_struct *work) +{ + struct mtk_vcodec_ctx *ctx = container_of(work, struct mtk_vcodec_ctx, + decode_work); + struct mtk_vcodec_dev *dev = ctx->dev; + struct vb2_buffer *src_buf, *dst_buf; + struct mtk_vcodec_mem buf; + struct vdec_fb *pfb; + bool res_chg = false; + int ret; + struct mtk_video_dec_buf *dst_buf_info, *src_buf_info; + struct vb2_v4l2_buffer *dst_vb2_v4l2, *src_vb2_v4l2; + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (src_buf == NULL) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] src_buf empty!!", ctx->id); + return; + } + + dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + if (dst_buf == NULL) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_debug(1, "[%d] dst_buf empty!!", ctx->id); + return; + } + + src_vb2_v4l2 = container_of(src_buf, struct vb2_v4l2_buffer, vb2_buf); + src_buf_info = container_of(src_vb2_v4l2, struct mtk_video_dec_buf, vb); + + dst_vb2_v4l2 = container_of(dst_buf, struct vb2_v4l2_buffer, vb2_buf); + dst_buf_info = container_of(dst_vb2_v4l2, struct mtk_video_dec_buf, vb); + + buf.va = vb2_plane_vaddr(src_buf, 0); + buf.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + buf.size = (size_t)src_buf->planes[0].bytesused; + if (!buf.va) { + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + mtk_v4l2_err("[%d] id=%d src_addr is NULL!!", + ctx->id, src_buf->index); + return; + } + + pfb = &dst_buf_info->frame_buffer; + pfb->base_y.va = vb2_plane_vaddr(dst_buf, 0); + pfb->base_y.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0); + pfb->base_y.size = ctx->picinfo.y_bs_sz + ctx->picinfo.y_len_sz; + + pfb->base_c.va = vb2_plane_vaddr(dst_buf, 1); + pfb->base_c.dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 1); + pfb->base_c.size = ctx->picinfo.c_bs_sz + ctx->picinfo.c_len_sz; + pfb->status = 0; + mtk_v4l2_debug(3, "===>[%d] vdec_if_decode() ===>", ctx->id); + mtk_v4l2_debug(3, "[%d] Bitstream VA=%p DMA=%pad Size=%zx vb=%p", + ctx->id, buf.va, &buf.dma_addr, buf.size, src_buf); + + mtk_v4l2_debug(3, + "id=%d Framebuf pfb=%p VA=%p Y_DMA=%pad C_DMA=%pad Size=%zx", + dst_buf->index, pfb, + pfb->base_y.va, &pfb->base_y.dma_addr, + &pfb->base_c.dma_addr, pfb->base_y.size); + + if (src_buf_info->lastframe) { + /* update src buf status */ + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + src_buf_info->lastframe = false; + v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE); + + /* update dst buf status */ + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + dst_buf_info->used = false; + + vdec_if_decode(ctx, NULL, NULL, &res_chg); + clean_display_buffer(ctx); + vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 0, 0); + vb2_set_plane_payload(&dst_buf_info->vb.vb2_buf, 1, 0); + v4l2_m2m_buf_done(&dst_buf_info->vb, VB2_BUF_STATE_DONE); + clean_free_buffer(ctx); + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); + return; + } + dst_buf_info->vb.vb2_buf.timestamp + = src_buf_info->vb.vb2_buf.timestamp; + dst_buf_info->vb.timecode + = src_buf_info->vb.timecode; + mutex_lock(&ctx->lock); + dst_buf_info->used = true; + mutex_unlock(&ctx->lock); + src_buf_info->used = true; + + ret = vdec_if_decode(ctx, &buf, pfb, &res_chg); + + if (ret) { + mtk_v4l2_err( + " <===[%d], src_buf[%d]%d sz=0x%zx pts=%llu dst_buf[%d] vdec_if_decode() ret=%d res_chg=%d===>", + ctx->id, + src_buf->index, + src_buf_info->lastframe, + buf.size, + src_buf_info->vb.vb2_buf.timestamp, + dst_buf->index, + ret, res_chg); + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_ERROR); + } else if (res_chg == false) { + /* + * we only return src buffer with VB2_BUF_STATE_DONE + * when decode success without resolution change + */ + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(&src_buf_info->vb, VB2_BUF_STATE_DONE); + } + + dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + clean_display_buffer(ctx); + clean_free_buffer(ctx); + + if (!ret && res_chg) { + mtk_vdec_pic_info_update(ctx); + /* + * On encountering a resolution change in the stream. + * The driver must first process and decode all + * remaining buffers from before the resolution change + * point, so call flush decode here + */ + mtk_vdec_flush_decoder(ctx); + /* + * After all buffers containing decoded frames from + * before the resolution change point ready to be + * dequeued on the CAPTURE queue, the driver sends a + * V4L2_EVENT_SOURCE_CHANGE event for source change + * type V4L2_EVENT_SRC_CH_RESOLUTION + */ + mtk_vdec_queue_res_chg_event(ctx); + } + v4l2_m2m_job_finish(dev->m2m_dev_dec, ctx->m2m_ctx); +} + +void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx) +{ + mutex_unlock(&ctx->dev->dec_mutex); +} + +void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx) +{ + mutex_lock(&ctx->dev->dec_mutex); +} + +void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx) +{ + vdec_if_deinit(ctx); + ctx->state = MTK_STATE_FREE; +} + +void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx) +{ + struct mtk_q_data *q_data; + + ctx->m2m_ctx->q_lock = &ctx->dev->dev_mutex; + ctx->fh.m2m_ctx = ctx->m2m_ctx; + ctx->fh.ctrl_handler = &ctx->ctrl_hdl; + INIT_WORK(&ctx->decode_work, mtk_vdec_worker); + ctx->colorspace = V4L2_COLORSPACE_REC709; + ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + ctx->quantization = V4L2_QUANTIZATION_DEFAULT; + ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT; + + q_data = &ctx->q_data[MTK_Q_DATA_SRC]; + memset(q_data, 0, sizeof(struct mtk_q_data)); + q_data->visible_width = DFT_CFG_WIDTH; + q_data->visible_height = DFT_CFG_HEIGHT; + q_data->fmt = &mtk_video_formats[OUT_FMT_IDX]; + q_data->field = V4L2_FIELD_NONE; + + q_data->sizeimage[0] = DFT_CFG_WIDTH * DFT_CFG_HEIGHT; + q_data->bytesperline[0] = 0; + + q_data = &ctx->q_data[MTK_Q_DATA_DST]; + memset(q_data, 0, sizeof(struct mtk_q_data)); + q_data->visible_width = DFT_CFG_WIDTH; + q_data->visible_height = DFT_CFG_HEIGHT; + q_data->coded_width = DFT_CFG_WIDTH; + q_data->coded_height = DFT_CFG_HEIGHT; + q_data->fmt = &mtk_video_formats[CAP_FMT_IDX]; + q_data->field = V4L2_FIELD_NONE; + + v4l_bound_align_image(&q_data->coded_width, + MTK_VDEC_MIN_W, + MTK_VDEC_MAX_W, 4, + &q_data->coded_height, + MTK_VDEC_MIN_H, + MTK_VDEC_MAX_H, 5, 6); + + q_data->sizeimage[0] = q_data->coded_width * q_data->coded_height; + q_data->bytesperline[0] = q_data->coded_width; + q_data->sizeimage[1] = q_data->sizeimage[0] / 2; + q_data->bytesperline[1] = q_data->coded_width; +} + +static int vidioc_vdec_qbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct vb2_queue *vq; + struct vb2_buffer *vb; + struct mtk_video_dec_buf *mtkbuf; + struct vb2_v4l2_buffer *vb2_v4l2; + + if (ctx->state == MTK_STATE_ABORT) { + mtk_v4l2_err("[%d] Call on QBUF after unrecoverable error", + ctx->id); + return -EIO; + } + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type); + vb = vq->bufs[buf->index]; + vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb); + + if ((buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && + (buf->m.planes[0].bytesused == 0)) { + mtkbuf->lastframe = true; + mtk_v4l2_debug(1, "[%d] (%d) id=%d lastframe=%d (%d,%d, %d) vb=%p", + ctx->id, buf->type, buf->index, + mtkbuf->lastframe, buf->bytesused, + buf->m.planes[0].bytesused, buf->length, + vb); + } + + return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_vdec_dqbuf(struct file *file, void *priv, + struct v4l2_buffer *buf) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + + if (ctx->state == MTK_STATE_ABORT) { + mtk_v4l2_err("[%d] Call on DQBUF after unrecoverable error", + ctx->id); + return -EIO; + } + + return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf); +} + +static int vidioc_vdec_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strlcpy(cap->driver, MTK_VCODEC_DEC_NAME, sizeof(cap->driver)); + strlcpy(cap->bus_info, MTK_PLATFORM_STR, sizeof(cap->bus_info)); + strlcpy(cap->card, MTK_PLATFORM_STR, sizeof(cap->card)); + + return 0; +} + +static int vidioc_vdec_subscribe_evt(struct v4l2_fh *fh, + const struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 2, NULL); + case V4L2_EVENT_SOURCE_CHANGE: + return v4l2_src_change_event_subscribe(fh, sub); + default: + return v4l2_ctrl_subscribe_event(fh, sub); + } +} + +static int vidioc_try_fmt(struct v4l2_format *f, struct mtk_video_fmt *fmt) +{ + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + int i; + + pix_fmt_mp->field = V4L2_FIELD_NONE; + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + pix_fmt_mp->num_planes = 1; + pix_fmt_mp->plane_fmt[0].bytesperline = 0; + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + int tmp_w, tmp_h; + + pix_fmt_mp->height = clamp(pix_fmt_mp->height, + MTK_VDEC_MIN_H, + MTK_VDEC_MAX_H); + pix_fmt_mp->width = clamp(pix_fmt_mp->width, + MTK_VDEC_MIN_W, + MTK_VDEC_MAX_W); + + /* + * Find next closer width align 64, heign align 64, size align + * 64 rectangle + * Note: This only get default value, the real HW needed value + * only available when ctx in MTK_STATE_HEADER state + */ + tmp_w = pix_fmt_mp->width; + tmp_h = pix_fmt_mp->height; + v4l_bound_align_image(&pix_fmt_mp->width, + MTK_VDEC_MIN_W, + MTK_VDEC_MAX_W, 6, + &pix_fmt_mp->height, + MTK_VDEC_MIN_H, + MTK_VDEC_MAX_H, 6, 9); + + if (pix_fmt_mp->width < tmp_w && + (pix_fmt_mp->width + 64) <= MTK_VDEC_MAX_W) + pix_fmt_mp->width += 64; + if (pix_fmt_mp->height < tmp_h && + (pix_fmt_mp->height + 64) <= MTK_VDEC_MAX_H) + pix_fmt_mp->height += 64; + + mtk_v4l2_debug(0, + "before resize width=%d, height=%d, after resize width=%d, height=%d, sizeimage=%d", + tmp_w, tmp_h, pix_fmt_mp->width, + pix_fmt_mp->height, + pix_fmt_mp->width * pix_fmt_mp->height); + + pix_fmt_mp->num_planes = fmt->num_planes; + pix_fmt_mp->plane_fmt[0].sizeimage = + pix_fmt_mp->width * pix_fmt_mp->height; + pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width; + + if (pix_fmt_mp->num_planes == 2) { + pix_fmt_mp->plane_fmt[1].sizeimage = + (pix_fmt_mp->width * pix_fmt_mp->height) / 2; + pix_fmt_mp->plane_fmt[1].bytesperline = + pix_fmt_mp->width; + } + } + + for (i = 0; i < pix_fmt_mp->num_planes; i++) + memset(&(pix_fmt_mp->plane_fmt[i].reserved[0]), 0x0, + sizeof(pix_fmt_mp->plane_fmt[0].reserved)); + + pix_fmt_mp->flags = 0; + memset(&pix_fmt_mp->reserved, 0x0, sizeof(pix_fmt_mp->reserved)); + return 0; +} + +static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mtk_video_fmt *fmt; + + fmt = mtk_vdec_find_format(f); + if (!fmt) { + f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc; + fmt = mtk_vdec_find_format(f); + } + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; + struct mtk_video_fmt *fmt; + + fmt = mtk_vdec_find_format(f); + if (!fmt) { + f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc; + fmt = mtk_vdec_find_format(f); + } + + if (pix_fmt_mp->plane_fmt[0].sizeimage == 0) { + mtk_v4l2_err("sizeimage of output format must be given"); + return -EINVAL; + } + + return vidioc_try_fmt(f, fmt); +} + +static int vidioc_vdec_g_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct mtk_q_data *q_data; + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + q_data = &ctx->q_data[MTK_Q_DATA_DST]; + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + s->r.left = 0; + s->r.top = 0; + s->r.width = ctx->picinfo.pic_w; + s->r.height = ctx->picinfo.pic_h; + break; + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + s->r.left = 0; + s->r.top = 0; + s->r.width = ctx->picinfo.buf_w; + s->r.height = ctx->picinfo.buf_h; + break; + case V4L2_SEL_TGT_COMPOSE: + if (vdec_if_get_param(ctx, GET_PARAM_CROP_INFO, &(s->r))) { + /* set to default value if header info not ready yet*/ + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->visible_width; + s->r.height = q_data->visible_height; + } + break; + default: + return -EINVAL; + } + + if (ctx->state < MTK_STATE_HEADER) { + /* set to default value if header info not ready yet*/ + s->r.left = 0; + s->r.top = 0; + s->r.width = q_data->visible_width; + s->r.height = q_data->visible_height; + return 0; + } + + return 0; +} + +static int vidioc_vdec_s_selection(struct file *file, void *priv, + struct v4l2_selection *s) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + + if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE: + s->r.left = 0; + s->r.top = 0; + s->r.width = ctx->picinfo.pic_w; + s->r.height = ctx->picinfo.pic_h; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int vidioc_vdec_s_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_mp; + struct mtk_q_data *q_data; + int ret = 0; + struct mtk_video_fmt *fmt; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + + q_data = mtk_vdec_get_q_data(ctx, f->type); + if (!q_data) + return -EINVAL; + + pix_mp = &f->fmt.pix_mp; + if ((f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) && + vb2_is_busy(&ctx->m2m_ctx->out_q_ctx.q)) { + mtk_v4l2_err("out_q_ctx buffers already requested"); + ret = -EBUSY; + } + + if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && + vb2_is_busy(&ctx->m2m_ctx->cap_q_ctx.q)) { + mtk_v4l2_err("cap_q_ctx buffers already requested"); + ret = -EBUSY; + } + + fmt = mtk_vdec_find_format(f); + if (fmt == NULL) { + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + f->fmt.pix.pixelformat = + mtk_video_formats[OUT_FMT_IDX].fourcc; + fmt = mtk_vdec_find_format(f); + } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + f->fmt.pix.pixelformat = + mtk_video_formats[CAP_FMT_IDX].fourcc; + fmt = mtk_vdec_find_format(f); + } + } + + q_data->fmt = fmt; + vidioc_try_fmt(f, q_data->fmt); + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + q_data->sizeimage[0] = pix_mp->plane_fmt[0].sizeimage; + q_data->coded_width = pix_mp->width; + q_data->coded_height = pix_mp->height; + + ctx->colorspace = f->fmt.pix_mp.colorspace; + ctx->ycbcr_enc = f->fmt.pix_mp.ycbcr_enc; + ctx->quantization = f->fmt.pix_mp.quantization; + ctx->xfer_func = f->fmt.pix_mp.xfer_func; + + if (ctx->state == MTK_STATE_FREE) { + ret = vdec_if_init(ctx, q_data->fmt->fourcc); + if (ret) { + mtk_v4l2_err("[%d]: vdec_if_init() fail ret=%d", + ctx->id, ret); + return -EINVAL; + } + ctx->state = MTK_STATE_INIT; + } + } + + return 0; +} + +static int vidioc_enum_framesizes(struct file *file, void *priv, + struct v4l2_frmsizeenum *fsize) +{ + int i = 0; + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + + if (fsize->index != 0) + return -EINVAL; + + for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) { + if (fsize->pixel_format != mtk_vdec_framesizes[i].fourcc) + continue; + + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; + fsize->stepwise = mtk_vdec_framesizes[i].stepwise; + if (!(ctx->dev->dec_capability & + VCODEC_CAPABILITY_4K_DISABLED)) { + mtk_v4l2_debug(3, "4K is enabled"); + fsize->stepwise.max_width = + VCODEC_DEC_4K_CODED_WIDTH; + fsize->stepwise.max_height = + VCODEC_DEC_4K_CODED_HEIGHT; + } + mtk_v4l2_debug(1, "%x, %d %d %d %d %d %d", + ctx->dev->dec_capability, + fsize->stepwise.min_width, + fsize->stepwise.max_width, + fsize->stepwise.step_width, + fsize->stepwise.min_height, + fsize->stepwise.max_height, + fsize->stepwise.step_height); + return 0; + } + + return -EINVAL; +} + +static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue) +{ + struct mtk_video_fmt *fmt; + int i, j = 0; + + for (i = 0; i < NUM_FORMATS; i++) { + if (output_queue && (mtk_video_formats[i].type != MTK_FMT_DEC)) + continue; + if (!output_queue && + (mtk_video_formats[i].type != MTK_FMT_FRAME)) + continue; + + if (j == f->index) + break; + ++j; + } + + if (i == NUM_FORMATS) + return -EINVAL; + + fmt = &mtk_video_formats[i]; + f->pixelformat = fmt->fourcc; + + return 0; +} + +static int vidioc_vdec_enum_fmt_vid_cap_mplane(struct file *file, void *pirv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(f, false); +} + +static int vidioc_vdec_enum_fmt_vid_out_mplane(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return vidioc_enum_fmt(f, true); +} + +static int vidioc_vdec_g_fmt(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv); + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + struct vb2_queue *vq; + struct mtk_q_data *q_data; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (!vq) { + mtk_v4l2_err("no vb2 queue for type=%d", f->type); + return -EINVAL; + } + + q_data = mtk_vdec_get_q_data(ctx, f->type); + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->colorspace = ctx->colorspace; + pix_mp->ycbcr_enc = ctx->ycbcr_enc; + pix_mp->quantization = ctx->quantization; + pix_mp->xfer_func = ctx->xfer_func; + + if ((f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) && + (ctx->state >= MTK_STATE_HEADER)) { + /* Until STREAMOFF is called on the CAPTURE queue + * (acknowledging the event), the driver operates as if + * the resolution hasn't changed yet. + * So we just return picinfo yet, and update picinfo in + * stop_streaming hook function + */ + q_data->sizeimage[0] = ctx->picinfo.y_bs_sz + + ctx->picinfo.y_len_sz; + q_data->sizeimage[1] = ctx->picinfo.c_bs_sz + + ctx->picinfo.c_len_sz; + q_data->bytesperline[0] = ctx->last_decoded_picinfo.buf_w; + q_data->bytesperline[1] = ctx->last_decoded_picinfo.buf_w; + q_data->coded_width = ctx->picinfo.buf_w; + q_data->coded_height = ctx->picinfo.buf_h; + + /* + * Width and height are set to the dimensions + * of the movie, the buffer is bigger and + * further processing stages should crop to this + * rectangle. + */ + pix_mp->width = q_data->coded_width; + pix_mp->height = q_data->coded_height; + + /* + * Set pixelformat to the format in which mt vcodec + * outputs the decoded frame + */ + pix_mp->num_planes = q_data->fmt->num_planes; + pix_mp->pixelformat = q_data->fmt->fourcc; + pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; + pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; + pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1]; + pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1]; + + } else if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + /* + * This is run on OUTPUT + * The buffer contains compressed image + * so width and height have no meaning. + * Assign value here to pass v4l2-compliance test + */ + pix_mp->width = q_data->visible_width; + pix_mp->height = q_data->visible_height; + pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; + pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; + pix_mp->pixelformat = q_data->fmt->fourcc; + pix_mp->num_planes = q_data->fmt->num_planes; + } else { + pix_mp->width = q_data->coded_width; + pix_mp->height = q_data->coded_height; + pix_mp->num_planes = q_data->fmt->num_planes; + pix_mp->pixelformat = q_data->fmt->fourcc; + pix_mp->plane_fmt[0].bytesperline = q_data->bytesperline[0]; + pix_mp->plane_fmt[0].sizeimage = q_data->sizeimage[0]; + pix_mp->plane_fmt[1].bytesperline = q_data->bytesperline[1]; + pix_mp->plane_fmt[1].sizeimage = q_data->sizeimage[1]; + + mtk_v4l2_debug(1, "[%d] type=%d state=%d Format information could not be read, not ready yet!", + ctx->id, f->type, ctx->state); + } + + return 0; +} + +static int vb2ops_vdec_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, + unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vq); + struct mtk_q_data *q_data; + unsigned int i; + + q_data = mtk_vdec_get_q_data(ctx, vq->type); + + if (q_data == NULL) { + mtk_v4l2_err("vq->type=%d err\n", vq->type); + return -EINVAL; + } + + if (*nplanes) { + for (i = 0; i < *nplanes; i++) { + if (sizes[i] < q_data->sizeimage[i]) + return -EINVAL; + } + } else { + if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + *nplanes = 2; + else + *nplanes = 1; + + for (i = 0; i < *nplanes; i++) + sizes[i] = q_data->sizeimage[i]; + } + + mtk_v4l2_debug(1, + "[%d]\t type = %d, get %d plane(s), %d buffer(s) of size 0x%x 0x%x ", + ctx->id, vq->type, *nplanes, *nbuffers, + sizes[0], sizes[1]); + + return 0; +} + +static int vb2ops_vdec_buf_prepare(struct vb2_buffer *vb) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct mtk_q_data *q_data; + int i; + + mtk_v4l2_debug(3, "[%d] (%d) id=%d", + ctx->id, vb->vb2_queue->type, vb->index); + + q_data = mtk_vdec_get_q_data(ctx, vb->vb2_queue->type); + + for (i = 0; i < q_data->fmt->num_planes; i++) { + if (vb2_plane_size(vb, i) < q_data->sizeimage[i]) { + mtk_v4l2_err("data will not fit into plane %d (%lu < %d)", + i, vb2_plane_size(vb, i), + q_data->sizeimage[i]); + } + } + + return 0; +} + +static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_buffer *src_buf; + struct mtk_vcodec_mem src_mem; + bool res_chg = false; + int ret = 0; + unsigned int dpbsize = 1; + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb, + struct vb2_v4l2_buffer, vb2_buf); + struct mtk_video_dec_buf *buf = container_of(vb2_v4l2, + struct mtk_video_dec_buf, vb); + + mtk_v4l2_debug(3, "[%d] (%d) id=%d, vb=%p", + ctx->id, vb->vb2_queue->type, + vb->index, vb); + /* + * check if this buffer is ready to be used after decode + */ + if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + mutex_lock(&ctx->lock); + if (buf->used == false) { + v4l2_m2m_buf_queue(ctx->m2m_ctx, + to_vb2_v4l2_buffer(vb)); + buf->queued_in_vb2 = true; + buf->queued_in_v4l2 = true; + buf->ready_to_display = false; + } else { + buf->queued_in_vb2 = false; + buf->queued_in_v4l2 = true; + buf->ready_to_display = false; + } + mutex_unlock(&ctx->lock); + return; + } + + v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2); + + if (ctx->state != MTK_STATE_INIT) { + mtk_v4l2_debug(3, "[%d] already init driver %d", + ctx->id, ctx->state); + return; + } + + src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + if (!src_buf) { + mtk_v4l2_err("No src buffer"); + return; + } + + src_mem.va = vb2_plane_vaddr(src_buf, 0); + src_mem.dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0); + src_mem.size = (size_t)src_buf->planes[0].bytesused; + mtk_v4l2_debug(2, + "[%d] buf id=%d va=%p dma=%pad size=%zx", + ctx->id, src_buf->index, + src_mem.va, &src_mem.dma_addr, + src_mem.size); + + ret = vdec_if_decode(ctx, &src_mem, NULL, &res_chg); + if (ret || !res_chg) { + /* + * fb == NULL menas to parse SPS/PPS header or + * resolution info in src_mem. Decode can fail + * if there is no SPS header or picture info + * in bs + */ + int log_level = ret ? 0 : 1; + + src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), + VB2_BUF_STATE_DONE); + mtk_v4l2_debug(log_level, + "[%d] vdec_if_decode() src_buf=%d, size=%zu, fail=%d, res_chg=%d", + ctx->id, src_buf->index, + src_mem.size, ret, res_chg); + return; + } + + if (vdec_if_get_param(ctx, GET_PARAM_PIC_INFO, &ctx->picinfo)) { + mtk_v4l2_err("[%d]Error!! Cannot get param : GET_PARAM_PICTURE_INFO ERR", + ctx->id); + return; + } + + ctx->last_decoded_picinfo = ctx->picinfo; + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] = + ctx->picinfo.y_bs_sz + + ctx->picinfo.y_len_sz; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = + ctx->picinfo.buf_w; + ctx->q_data[MTK_Q_DATA_DST].sizeimage[1] = + ctx->picinfo.c_bs_sz + + ctx->picinfo.c_len_sz; + ctx->q_data[MTK_Q_DATA_DST].bytesperline[1] = ctx->picinfo.buf_w; + mtk_v4l2_debug(2, "[%d] vdec_if_init() OK wxh=%dx%d pic wxh=%dx%d sz[0]=0x%x sz[1]=0x%x", + ctx->id, + ctx->picinfo.buf_w, ctx->picinfo.buf_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->q_data[MTK_Q_DATA_DST].sizeimage[0], + ctx->q_data[MTK_Q_DATA_DST].sizeimage[1]); + + ret = vdec_if_get_param(ctx, GET_PARAM_DPB_SIZE, &dpbsize); + if (dpbsize == 0) + mtk_v4l2_err("[%d] GET_PARAM_DPB_SIZE fail=%d", ctx->id, ret); + + ctx->dpb_size = dpbsize; + ctx->state = MTK_STATE_HEADER; + mtk_v4l2_debug(1, "[%d] dpbsize=%d", ctx->id, ctx->dpb_size); +} + +static void vb2ops_vdec_buf_finish(struct vb2_buffer *vb) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct vb2_v4l2_buffer *vb2_v4l2; + struct mtk_video_dec_buf *buf; + + if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) + return; + + vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); + buf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb); + mutex_lock(&ctx->lock); + buf->queued_in_v4l2 = false; + buf->queued_in_vb2 = false; + mutex_unlock(&ctx->lock); +} + +static int vb2ops_vdec_buf_init(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vb2_v4l2 = container_of(vb, + struct vb2_v4l2_buffer, vb2_buf); + struct mtk_video_dec_buf *buf = container_of(vb2_v4l2, + struct mtk_video_dec_buf, vb); + + if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { + buf->used = false; + buf->ready_to_display = false; + buf->queued_in_v4l2 = false; + } else { + buf->lastframe = false; + } + + return 0; +} + +static int vb2ops_vdec_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); + + if (ctx->state == MTK_STATE_FLUSH) + ctx->state = MTK_STATE_HEADER; + + return 0; +} + +static void vb2ops_vdec_stop_streaming(struct vb2_queue *q) +{ + struct vb2_buffer *src_buf = NULL, *dst_buf = NULL; + struct mtk_vcodec_ctx *ctx = vb2_get_drv_priv(q); + + mtk_v4l2_debug(3, "[%d] (%d) state=(%x) ctx->decoded_frame_cnt=%d", + ctx->id, q->type, ctx->state, ctx->decoded_frame_cnt); + + if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + while ((src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx))) + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), + VB2_BUF_STATE_ERROR); + return; + } + + if (ctx->state >= MTK_STATE_HEADER) { + + /* Until STREAMOFF is called on the CAPTURE queue + * (acknowledging the event), the driver operates + * as if the resolution hasn't changed yet, i.e. + * VIDIOC_G_FMT< etc. return previous resolution. + * So we update picinfo here + */ + ctx->picinfo = ctx->last_decoded_picinfo; + + mtk_v4l2_debug(2, + "[%d]-> new(%d,%d), old(%d,%d), real(%d,%d)", + ctx->id, ctx->last_decoded_picinfo.pic_w, + ctx->last_decoded_picinfo.pic_h, + ctx->picinfo.pic_w, ctx->picinfo.pic_h, + ctx->last_decoded_picinfo.buf_w, + ctx->last_decoded_picinfo.buf_h); + + mtk_vdec_flush_decoder(ctx); + } + ctx->state = MTK_STATE_FLUSH; + + while ((dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx))) { + vb2_set_plane_payload(dst_buf, 0, 0); + vb2_set_plane_payload(dst_buf, 1, 0); + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), + VB2_BUF_STATE_ERROR); + } + +} + +static void m2mops_vdec_device_run(void *priv) +{ + struct mtk_vcodec_ctx *ctx = priv; + struct mtk_vcodec_dev *dev = ctx->dev; + + queue_work(dev->decode_workqueue, &ctx->decode_work); +} + +static int m2mops_vdec_job_ready(void *m2m_priv) +{ + struct mtk_vcodec_ctx *ctx = m2m_priv; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + + if (ctx->state == MTK_STATE_ABORT) + return 0; + + if ((ctx->last_decoded_picinfo.pic_w != ctx->picinfo.pic_w) || + (ctx->last_decoded_picinfo.pic_h != ctx->picinfo.pic_h)) + return 0; + + if (ctx->state != MTK_STATE_HEADER) + return 0; + + return 1; +} + +static void m2mops_vdec_job_abort(void *priv) +{ + struct mtk_vcodec_ctx *ctx = priv; + + ctx->state = MTK_STATE_ABORT; +} + +static int mtk_vdec_g_v_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_vcodec_ctx *ctx = ctrl_to_ctx(ctrl); + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + if (ctx->state >= MTK_STATE_HEADER) { + ctrl->val = ctx->dpb_size; + } else { + mtk_v4l2_debug(0, "Seqinfo not ready"); + ctrl->val = 0; + } + break; + default: + ret = -EINVAL; + } + return ret; +} + +static const struct v4l2_ctrl_ops mtk_vcodec_dec_ctrl_ops = { + .g_volatile_ctrl = mtk_vdec_g_v_ctrl, +}; + +int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx) +{ + struct v4l2_ctrl *ctrl; + + v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 1); + + ctrl = v4l2_ctrl_new_std(&ctx->ctrl_hdl, + &mtk_vcodec_dec_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, + 0, 32, 1, 1); + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + if (ctx->ctrl_hdl.error) { + mtk_v4l2_err("Adding control failed %d", + ctx->ctrl_hdl.error); + return ctx->ctrl_hdl.error; + } + + v4l2_ctrl_handler_setup(&ctx->ctrl_hdl); + return 0; +} + +static void m2mops_vdec_lock(void *m2m_priv) +{ + struct mtk_vcodec_ctx *ctx = m2m_priv; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + mutex_lock(&ctx->dev->dev_mutex); +} + +static void m2mops_vdec_unlock(void *m2m_priv) +{ + struct mtk_vcodec_ctx *ctx = m2m_priv; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + mutex_unlock(&ctx->dev->dev_mutex); +} + +const struct v4l2_m2m_ops mtk_vdec_m2m_ops = { + .device_run = m2mops_vdec_device_run, + .job_ready = m2mops_vdec_job_ready, + .job_abort = m2mops_vdec_job_abort, + .lock = m2mops_vdec_lock, + .unlock = m2mops_vdec_unlock, +}; + +static const struct vb2_ops mtk_vdec_vb2_ops = { + .queue_setup = vb2ops_vdec_queue_setup, + .buf_prepare = vb2ops_vdec_buf_prepare, + .buf_queue = vb2ops_vdec_buf_queue, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + .buf_init = vb2ops_vdec_buf_init, + .buf_finish = vb2ops_vdec_buf_finish, + .start_streaming = vb2ops_vdec_start_streaming, + .stop_streaming = vb2ops_vdec_stop_streaming, +}; + +const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops = { + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_qbuf = vidioc_vdec_qbuf, + .vidioc_dqbuf = vidioc_vdec_dqbuf, + + .vidioc_try_fmt_vid_cap_mplane = vidioc_try_fmt_vid_cap_mplane, + .vidioc_try_fmt_vid_out_mplane = vidioc_try_fmt_vid_out_mplane, + + .vidioc_s_fmt_vid_cap_mplane = vidioc_vdec_s_fmt, + .vidioc_s_fmt_vid_out_mplane = vidioc_vdec_s_fmt, + .vidioc_g_fmt_vid_cap_mplane = vidioc_vdec_g_fmt, + .vidioc_g_fmt_vid_out_mplane = vidioc_vdec_g_fmt, + + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + + .vidioc_enum_fmt_vid_cap_mplane = vidioc_vdec_enum_fmt_vid_cap_mplane, + .vidioc_enum_fmt_vid_out_mplane = vidioc_vdec_enum_fmt_vid_out_mplane, + .vidioc_enum_framesizes = vidioc_enum_framesizes, + + .vidioc_querycap = vidioc_vdec_querycap, + .vidioc_subscribe_event = vidioc_vdec_subscribe_evt, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_selection = vidioc_vdec_g_selection, + .vidioc_s_selection = vidioc_vdec_s_selection, +}; + +int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct mtk_vcodec_ctx *ctx = priv; + int ret = 0; + + mtk_v4l2_debug(3, "[%d]", ctx->id); + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_DMABUF | VB2_MMAP; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf); + src_vq->ops = &mtk_vdec_vb2_ops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->dev->dev_mutex; + src_vq->dev = &ctx->dev->plat_dev->dev; + + ret = vb2_queue_init(src_vq); + if (ret) { + mtk_v4l2_err("Failed to initialize videobuf2 queue(output)"); + return ret; + } + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_DMABUF | VB2_MMAP; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct mtk_video_dec_buf); + dst_vq->ops = &mtk_vdec_vb2_ops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->dev->dev_mutex; + dst_vq->dev = &ctx->dev->plat_dev->dev; + + ret = vb2_queue_init(dst_vq); + if (ret) { + vb2_queue_release(src_vq); + mtk_v4l2_err("Failed to initialize videobuf2 queue(capture)"); + } + + return ret; +} diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h new file mode 100644 index 000000000000..362f5a85762e --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.h @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * Tiffany Lin + * + * 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 _MTK_VCODEC_DEC_H_ +#define _MTK_VCODEC_DEC_H_ + +#include +#include + +#define VCODEC_CAPABILITY_4K_DISABLED 0x10 +#define VCODEC_DEC_4K_CODED_WIDTH 4096U +#define VCODEC_DEC_4K_CODED_HEIGHT 2304U +#define MTK_VDEC_MAX_W 2048U +#define MTK_VDEC_MAX_H 1088U + +#define MTK_VDEC_IRQ_STATUS_DEC_SUCCESS 0x10000 + +/** + * struct vdec_fb - decoder frame buffer + * @base_y : Y plane memory info + * @base_c : C plane memory info + * @status : frame buffer status (vdec_fb_status) + */ +struct vdec_fb { + struct mtk_vcodec_mem base_y; + struct mtk_vcodec_mem base_c; + unsigned int status; +}; + +/** + * struct mtk_video_dec_buf - Private data related to each VB2 buffer. + * @b: VB2 buffer + * @list: link list + * @used: Capture buffer contain decoded frame data and keep in + * codec data structure + * @ready_to_display: Capture buffer not display yet + * @queued_in_vb2: Capture buffer is queue in vb2 + * @queued_in_v4l2: Capture buffer is in v4l2 driver, but not in vb2 + * queue yet + * @lastframe: Intput buffer is last buffer - EOS + * @frame_buffer: Decode status, and buffer information of Capture buffer + * + * Note : These status information help us track and debug buffer state + */ +struct mtk_video_dec_buf { + struct vb2_v4l2_buffer vb; + struct list_head list; + + bool used; + bool ready_to_display; + bool queued_in_vb2; + bool queued_in_v4l2; + bool lastframe; + struct vdec_fb frame_buffer; +}; + +extern const struct v4l2_ioctl_ops mtk_vdec_ioctl_ops; +extern const struct v4l2_m2m_ops mtk_vdec_m2m_ops; + + +/* + * mtk_vdec_lock/mtk_vdec_unlock are for ctx instance to + * get/release lock before/after access decoder hw. + * mtk_vdec_lock get decoder hw lock and set curr_ctx + * to ctx instance that get lock + */ +void mtk_vdec_unlock(struct mtk_vcodec_ctx *ctx); +void mtk_vdec_lock(struct mtk_vcodec_ctx *ctx); +int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq); +void mtk_vcodec_dec_set_default_params(struct mtk_vcodec_ctx *ctx); +void mtk_vcodec_dec_release(struct mtk_vcodec_ctx *ctx); +int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_ctx *ctx); + + +#endif /* _MTK_VCODEC_DEC_H_ */ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c new file mode 100644 index 000000000000..70aa99329ce5 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * Tiffany Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_dec.h" +#include "mtk_vcodec_dec_pm.h" +#include "mtk_vcodec_intr.h" +#include "mtk_vcodec_util.h" +#include "mtk_vpu.h" + +#define VDEC_HW_ACTIVE 0x10 +#define VDEC_IRQ_CFG 0x11 +#define VDEC_IRQ_CLR 0x10 +#define VDEC_IRQ_CFG_REG 0xa4 + +module_param(mtk_v4l2_dbg_level, int, 0644); +module_param(mtk_vcodec_dbg, bool, 0644); + +/* Wake up context wait_queue */ +static void wake_up_ctx(struct mtk_vcodec_ctx *ctx) +{ + ctx->int_cond = 1; + wake_up_interruptible(&ctx->queue); +} + +static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv) +{ + struct mtk_vcodec_dev *dev = priv; + struct mtk_vcodec_ctx *ctx; + u32 cg_status = 0; + unsigned int dec_done_status = 0; + void __iomem *vdec_misc_addr = dev->reg_base[VDEC_MISC] + + VDEC_IRQ_CFG_REG; + + ctx = mtk_vcodec_get_curr_ctx(dev); + + /* check if HW active or not */ + cg_status = readl(dev->reg_base[0]); + if ((cg_status & VDEC_HW_ACTIVE) != 0) { + mtk_v4l2_err("DEC ISR, VDEC active is not 0x0 (0x%08x)", + cg_status); + return IRQ_HANDLED; + } + + dec_done_status = readl(vdec_misc_addr); + ctx->irq_status = dec_done_status; + if ((dec_done_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) != + MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) + return IRQ_HANDLED; + + /* clear interrupt */ + writel((readl(vdec_misc_addr) | VDEC_IRQ_CFG), + dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG); + writel((readl(vdec_misc_addr) & ~VDEC_IRQ_CLR), + dev->reg_base[VDEC_MISC] + VDEC_IRQ_CFG_REG); + + wake_up_ctx(ctx); + + mtk_v4l2_debug(3, + "mtk_vcodec_dec_irq_handler :wake up ctx %d, dec_done_status=%x", + ctx->id, dec_done_status); + + return IRQ_HANDLED; +} + +static void mtk_vcodec_dec_reset_handler(void *priv) +{ + struct mtk_vcodec_dev *dev = priv; + struct mtk_vcodec_ctx *ctx; + + mtk_v4l2_err("Watchdog timeout!!"); + + mutex_lock(&dev->dev_mutex); + list_for_each_entry(ctx, &dev->ctx_list, list) { + ctx->state = MTK_STATE_ABORT; + mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ERROR", + ctx->id); + } + mutex_unlock(&dev->dev_mutex); +} + +static int fops_vcodec_open(struct file *file) +{ + struct mtk_vcodec_dev *dev = video_drvdata(file); + struct mtk_vcodec_ctx *ctx = NULL; + int ret = 0; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + mutex_lock(&dev->dev_mutex); + ctx->id = dev->id_counter++; + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + v4l2_fh_add(&ctx->fh); + INIT_LIST_HEAD(&ctx->list); + ctx->dev = dev; + init_waitqueue_head(&ctx->queue); + mutex_init(&ctx->lock); + + ctx->type = MTK_INST_DECODER; + ret = mtk_vcodec_dec_ctrls_setup(ctx); + if (ret) { + mtk_v4l2_err("Failed to setup mt vcodec controls"); + goto err_ctrls_setup; + } + ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev_dec, ctx, + &mtk_vcodec_dec_queue_init); + if (IS_ERR((__force void *)ctx->m2m_ctx)) { + ret = PTR_ERR((__force void *)ctx->m2m_ctx); + mtk_v4l2_err("Failed to v4l2_m2m_ctx_init() (%d)", + ret); + goto err_m2m_ctx_init; + } + mtk_vcodec_dec_set_default_params(ctx); + + if (v4l2_fh_is_singular(&ctx->fh)) { + mtk_vcodec_dec_pw_on(&dev->pm); + /* + * vpu_load_firmware checks if it was loaded already and + * does nothing in that case + */ + ret = vpu_load_firmware(dev->vpu_plat_dev); + if (ret < 0) { + /* + * Return 0 if downloading firmware successfully, + * otherwise it is failed + */ + mtk_v4l2_err("vpu_load_firmware failed!"); + goto err_load_fw; + } + + dev->dec_capability = + vpu_get_vdec_hw_capa(dev->vpu_plat_dev); + mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability); + } + + list_add(&ctx->list, &dev->ctx_list); + + mutex_unlock(&dev->dev_mutex); + mtk_v4l2_debug(0, "%s decoder [%d]", dev_name(&dev->plat_dev->dev), + ctx->id); + return ret; + + /* Deinit when failure occurred */ +err_load_fw: + v4l2_m2m_ctx_release(ctx->m2m_ctx); +err_m2m_ctx_init: + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); +err_ctrls_setup: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + + return ret; +} + +static int fops_vcodec_release(struct file *file) +{ + struct mtk_vcodec_dev *dev = video_drvdata(file); + struct mtk_vcodec_ctx *ctx = fh_to_ctx(file->private_data); + + mtk_v4l2_debug(0, "[%d] decoder", ctx->id); + mutex_lock(&dev->dev_mutex); + + /* + * Call v4l2_m2m_ctx_release before mtk_vcodec_dec_release. First, it + * makes sure the worker thread is not running after vdec_if_deinit. + * Second, the decoder will be flushed and all the buffers will be + * returned in stop_streaming. + */ + v4l2_m2m_ctx_release(ctx->m2m_ctx); + mtk_vcodec_dec_release(ctx); + + if (v4l2_fh_is_singular(&ctx->fh)) + mtk_vcodec_dec_pw_off(&dev->pm); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + + list_del_init(&ctx->list); + kfree(ctx); + mutex_unlock(&dev->dev_mutex); + return 0; +} + +static const struct v4l2_file_operations mtk_vcodec_fops = { + .owner = THIS_MODULE, + .open = fops_vcodec_open, + .release = fops_vcodec_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static int mtk_vcodec_probe(struct platform_device *pdev) +{ + struct mtk_vcodec_dev *dev; + struct video_device *vfd_dec; + struct resource *res; + int i, ret; + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + INIT_LIST_HEAD(&dev->ctx_list); + dev->plat_dev = pdev; + + dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev); + if (dev->vpu_plat_dev == NULL) { + mtk_v4l2_err("[VPU] vpu device in not ready"); + return -EPROBE_DEFER; + } + + vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_dec_reset_handler, + dev, VPU_RST_DEC); + + ret = mtk_vcodec_init_dec_pm(dev); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to get mt vcodec clock source"); + return ret; + } + + for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) { + res = platform_get_resource(pdev, IORESOURCE_MEM, i); + if (res == NULL) { + dev_err(&pdev->dev, "get memory resource failed."); + ret = -ENXIO; + goto err_res; + } + dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR((__force void *)dev->reg_base[i])) { + ret = PTR_ERR((__force void *)dev->reg_base); + goto err_res; + } + mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]); + } + + res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + if (res == NULL) { + dev_err(&pdev->dev, "failed to get irq resource"); + ret = -ENOENT; + goto err_res; + } + + dev->dec_irq = platform_get_irq(pdev, 0); + ret = devm_request_irq(&pdev->dev, dev->dec_irq, + mtk_vcodec_dec_irq_handler, 0, pdev->name, dev); + if (ret) { + dev_err(&pdev->dev, "Failed to install dev->dec_irq %d (%d)", + dev->dec_irq, + ret); + goto err_res; + } + + disable_irq(dev->dec_irq); + mutex_init(&dev->dec_mutex); + mutex_init(&dev->dev_mutex); + spin_lock_init(&dev->irqlock); + + snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name), "%s", + "[/MTK_V4L2_VDEC]"); + + ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev); + if (ret) { + mtk_v4l2_err("v4l2_device_register err=%d", ret); + goto err_res; + } + + init_waitqueue_head(&dev->queue); + + vfd_dec = video_device_alloc(); + if (!vfd_dec) { + mtk_v4l2_err("Failed to allocate video device"); + ret = -ENOMEM; + goto err_dec_alloc; + } + vfd_dec->fops = &mtk_vcodec_fops; + vfd_dec->ioctl_ops = &mtk_vdec_ioctl_ops; + vfd_dec->release = video_device_release; + vfd_dec->lock = &dev->dev_mutex; + vfd_dec->v4l2_dev = &dev->v4l2_dev; + vfd_dec->vfl_dir = VFL_DIR_M2M; + vfd_dec->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | + V4L2_CAP_STREAMING; + + snprintf(vfd_dec->name, sizeof(vfd_dec->name), "%s", + MTK_VCODEC_DEC_NAME); + video_set_drvdata(vfd_dec, dev); + dev->vfd_dec = vfd_dec; + platform_set_drvdata(pdev, dev); + + dev->m2m_dev_dec = v4l2_m2m_init(&mtk_vdec_m2m_ops); + if (IS_ERR((__force void *)dev->m2m_dev_dec)) { + mtk_v4l2_err("Failed to init mem2mem dec device"); + ret = PTR_ERR((__force void *)dev->m2m_dev_dec); + goto err_dec_mem_init; + } + + dev->decode_workqueue = + alloc_ordered_workqueue(MTK_VCODEC_DEC_NAME, + WQ_MEM_RECLAIM | WQ_FREEZABLE); + if (!dev->decode_workqueue) { + mtk_v4l2_err("Failed to create decode workqueue"); + ret = -EINVAL; + goto err_event_workq; + } + + ret = video_register_device(vfd_dec, VFL_TYPE_GRABBER, 0); + if (ret) { + mtk_v4l2_err("Failed to register video device"); + goto err_dec_reg; + } + + mtk_v4l2_debug(0, "decoder registered as /dev/video%d", + vfd_dec->num); + + return 0; + +err_dec_reg: + destroy_workqueue(dev->decode_workqueue); +err_event_workq: + v4l2_m2m_release(dev->m2m_dev_dec); +err_dec_mem_init: + video_unregister_device(vfd_dec); +err_dec_alloc: + v4l2_device_unregister(&dev->v4l2_dev); +err_res: + mtk_vcodec_release_dec_pm(dev); + return ret; +} + +static const struct of_device_id mtk_vcodec_match[] = { + {.compatible = "mediatek,mt8173-vcodec-dec",}, + {}, +}; + +MODULE_DEVICE_TABLE(of, mtk_vcodec_match); + +static int mtk_vcodec_dec_remove(struct platform_device *pdev) +{ + struct mtk_vcodec_dev *dev = platform_get_drvdata(pdev); + + flush_workqueue(dev->decode_workqueue); + destroy_workqueue(dev->decode_workqueue); + if (dev->m2m_dev_dec) + v4l2_m2m_release(dev->m2m_dev_dec); + + if (dev->vfd_dec) + video_unregister_device(dev->vfd_dec); + + v4l2_device_unregister(&dev->v4l2_dev); + mtk_vcodec_release_dec_pm(dev); + return 0; +} + +static struct platform_driver mtk_vcodec_dec_driver = { + .probe = mtk_vcodec_probe, + .remove = mtk_vcodec_dec_remove, + .driver = { + .name = MTK_VCODEC_DEC_NAME, + .of_match_table = mtk_vcodec_match, + }, +}; + +module_platform_driver(mtk_vcodec_dec_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Mediatek video codec V4L2 decoder driver"); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c new file mode 100644 index 000000000000..18182f5676d8 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Tiffany Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "mtk_vcodec_dec_pm.h" +#include "mtk_vcodec_util.h" +#include "mtk_vpu.h" + +int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) +{ + struct device_node *node; + struct platform_device *pdev; + struct device *dev; + struct mtk_vcodec_pm *pm; + int ret = 0; + + pdev = mtkdev->plat_dev; + pm = &mtkdev->pm; + pm->mtkdev = mtkdev; + dev = &pdev->dev; + node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0); + if (!node) { + mtk_v4l2_err("of_parse_phandle mediatek,larb fail!"); + return -1; + } + + pdev = of_find_device_by_node(node); + if (WARN_ON(!pdev)) { + of_node_put(node); + return -1; + } + pm->larbvdec = &pdev->dev; + pdev = mtkdev->plat_dev; + pm->dev = &pdev->dev; + + pm->vcodecpll = devm_clk_get(&pdev->dev, "vcodecpll"); + if (IS_ERR(pm->vcodecpll)) { + mtk_v4l2_err("devm_clk_get vcodecpll fail"); + ret = PTR_ERR(pm->vcodecpll); + } + + pm->univpll_d2 = devm_clk_get(&pdev->dev, "univpll_d2"); + if (IS_ERR(pm->univpll_d2)) { + mtk_v4l2_err("devm_clk_get univpll_d2 fail"); + ret = PTR_ERR(pm->univpll_d2); + } + + pm->clk_cci400_sel = devm_clk_get(&pdev->dev, "clk_cci400_sel"); + if (IS_ERR(pm->clk_cci400_sel)) { + mtk_v4l2_err("devm_clk_get clk_cci400_sel fail"); + ret = PTR_ERR(pm->clk_cci400_sel); + } + + pm->vdec_sel = devm_clk_get(&pdev->dev, "vdec_sel"); + if (IS_ERR(pm->vdec_sel)) { + mtk_v4l2_err("devm_clk_get vdec_sel fail"); + ret = PTR_ERR(pm->vdec_sel); + } + + pm->vdecpll = devm_clk_get(&pdev->dev, "vdecpll"); + if (IS_ERR(pm->vdecpll)) { + mtk_v4l2_err("devm_clk_get vdecpll fail"); + ret = PTR_ERR(pm->vdecpll); + } + + pm->vencpll = devm_clk_get(&pdev->dev, "vencpll"); + if (IS_ERR(pm->vencpll)) { + mtk_v4l2_err("devm_clk_get vencpll fail"); + ret = PTR_ERR(pm->vencpll); + } + + pm->venc_lt_sel = devm_clk_get(&pdev->dev, "venc_lt_sel"); + if (IS_ERR(pm->venc_lt_sel)) { + mtk_v4l2_err("devm_clk_get venc_lt_sel fail"); + ret = PTR_ERR(pm->venc_lt_sel); + } + + pm->vdec_bus_clk_src = devm_clk_get(&pdev->dev, "vdec_bus_clk_src"); + if (IS_ERR(pm->vdec_bus_clk_src)) { + mtk_v4l2_err("devm_clk_get vdec_bus_clk_src"); + ret = PTR_ERR(pm->vdec_bus_clk_src); + } + + pm_runtime_enable(&pdev->dev); + + return ret; +} + +void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev) +{ + pm_runtime_disable(dev->pm.dev); +} + +void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm) +{ + int ret; + + ret = pm_runtime_get_sync(pm->dev); + if (ret) + mtk_v4l2_err("pm_runtime_get_sync fail %d", ret); +} + +void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm) +{ + int ret; + + ret = pm_runtime_put_sync(pm->dev); + if (ret) + mtk_v4l2_err("pm_runtime_put_sync fail %d", ret); +} + +void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm) +{ + int ret; + + ret = clk_set_rate(pm->vcodecpll, 1482 * 1000000); + if (ret) + mtk_v4l2_err("clk_set_rate vcodecpll fail %d", ret); + + ret = clk_set_rate(pm->vencpll, 800 * 1000000); + if (ret) + mtk_v4l2_err("clk_set_rate vencpll fail %d", ret); + + ret = clk_prepare_enable(pm->vcodecpll); + if (ret) + mtk_v4l2_err("clk_prepare_enable vcodecpll fail %d", ret); + + ret = clk_prepare_enable(pm->vencpll); + if (ret) + mtk_v4l2_err("clk_prepare_enable vencpll fail %d", ret); + + ret = clk_prepare_enable(pm->vdec_bus_clk_src); + if (ret) + mtk_v4l2_err("clk_prepare_enable vdec_bus_clk_src fail %d", + ret); + + ret = clk_prepare_enable(pm->venc_lt_sel); + if (ret) + mtk_v4l2_err("clk_prepare_enable venc_lt_sel fail %d", ret); + + ret = clk_set_parent(pm->venc_lt_sel, pm->vdec_bus_clk_src); + if (ret) + mtk_v4l2_err("clk_set_parent venc_lt_sel vdec_bus_clk_src fail %d", + ret); + + ret = clk_prepare_enable(pm->univpll_d2); + if (ret) + mtk_v4l2_err("clk_prepare_enable univpll_d2 fail %d", ret); + + ret = clk_prepare_enable(pm->clk_cci400_sel); + if (ret) + mtk_v4l2_err("clk_prepare_enable clk_cci400_sel fail %d", ret); + + ret = clk_set_parent(pm->clk_cci400_sel, pm->univpll_d2); + if (ret) + mtk_v4l2_err("clk_set_parent clk_cci400_sel univpll_d2 fail %d", + ret); + + ret = clk_prepare_enable(pm->vdecpll); + if (ret) + mtk_v4l2_err("clk_prepare_enable vdecpll fail %d", ret); + + ret = clk_prepare_enable(pm->vdec_sel); + if (ret) + mtk_v4l2_err("clk_prepare_enable vdec_sel fail %d", ret); + + ret = clk_set_parent(pm->vdec_sel, pm->vdecpll); + if (ret) + mtk_v4l2_err("clk_set_parent vdec_sel vdecpll fail %d", ret); + + ret = mtk_smi_larb_get(pm->larbvdec); + if (ret) + mtk_v4l2_err("mtk_smi_larb_get larbvdec fail %d", ret); + +} + +void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm) +{ + mtk_smi_larb_put(pm->larbvdec); + clk_disable_unprepare(pm->vdec_sel); + clk_disable_unprepare(pm->vdecpll); + clk_disable_unprepare(pm->univpll_d2); + clk_disable_unprepare(pm->clk_cci400_sel); + clk_disable_unprepare(pm->venc_lt_sel); + clk_disable_unprepare(pm->vdec_bus_clk_src); + clk_disable_unprepare(pm->vencpll); + clk_disable_unprepare(pm->vcodecpll); +} diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h new file mode 100644 index 000000000000..86a7825353e3 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Tiffany Lin + * + * 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 _MTK_VCODEC_DEC_PM_H_ +#define _MTK_VCODEC_DEC_PM_H_ + +#include "mtk_vcodec_drv.h" + +int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *dev); +void mtk_vcodec_release_dec_pm(struct mtk_vcodec_dev *dev); + +void mtk_vcodec_dec_pw_on(struct mtk_vcodec_pm *pm); +void mtk_vcodec_dec_pw_off(struct mtk_vcodec_pm *pm); +void mtk_vcodec_dec_clock_on(struct mtk_vcodec_pm *pm); +void mtk_vcodec_dec_clock_off(struct mtk_vcodec_pm *pm); + +#endif /* _MTK_VCODEC_DEC_PM_H_ */ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h index c8eaa41c00e6..d7eb8ef855d2 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h @@ -22,13 +22,13 @@ #include #include #include - +#include "mtk_vcodec_util.h" #define MTK_VCODEC_DRV_NAME "mtk_vcodec_drv" +#define MTK_VCODEC_DEC_NAME "mtk-vcodec-dec" #define MTK_VCODEC_ENC_NAME "mtk-vcodec-enc" #define MTK_PLATFORM_STR "platform:mt8173" - #define MTK_VCODEC_MAX_PLANES 3 #define MTK_V4L2_BENCHMARK 0 #define WAIT_INTR_TIMEOUT_MS 1000 @@ -179,6 +179,9 @@ struct mtk_enc_params { * struct mtk_vcodec_pm - Power management data structure */ struct mtk_vcodec_pm { + struct clk *vdec_bus_clk_src; + struct clk *vencpll; + struct clk *vcodecpll; struct clk *univpll_d2; struct clk *clk_cci400_sel; @@ -195,6 +198,32 @@ struct mtk_vcodec_pm { struct mtk_vcodec_dev *mtkdev; }; +/** + * struct vdec_pic_info - picture size information + * @pic_w: picture width + * @pic_h: picture height + * @buf_w: picture buffer width (64 aligned up from pic_w) + * @buf_h: picture buffer heiht (64 aligned up from pic_h) + * @y_bs_sz: Y bitstream size + * @c_bs_sz: CbCr bitstream size + * @y_len_sz: additional size required to store decompress information for y + * plane + * @c_len_sz: additional size required to store decompress information for cbcr + * plane + * E.g. suppose picture size is 176x144, + * buffer size will be aligned to 176x160. + */ +struct vdec_pic_info { + unsigned int pic_w; + unsigned int pic_h; + unsigned int buf_w; + unsigned int buf_h; + unsigned int y_bs_sz; + unsigned int c_bs_sz; + unsigned int y_len_sz; + unsigned int c_len_sz; +}; + /** * struct mtk_vcodec_ctx - Context (instance) private data. * @@ -209,9 +238,12 @@ struct mtk_vcodec_pm { * @state: state of the context * @param_change: indicate encode parameter type * @enc_params: encoding parameters + * @dec_if: hooked decoder driver interface * @enc_if: hoooked encoder driver interface * @drv_handle: driver handle for specific decode/encode instance * + * @picinfo: store picture info after header parsing + * @dpb_size: store dpb count after header parsing * @int_cond: variable used by the waitqueue * @int_type: type of the last interrupt * @queue: waitqueue that can be used to wait for this context to @@ -219,12 +251,16 @@ struct mtk_vcodec_pm { * @irq_status: irq status * * @ctrl_hdl: handler for v4l2 framework + * @decode_work: worker for the decoding * @encode_work: worker for the encoding + * @last_decoded_picinfo: pic information get from latest decode * * @colorspace: enum v4l2_colorspace; supplemental to pixelformat * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding * @quantization: enum v4l2_quantization, colorspace quantization * @xfer_func: enum v4l2_xfer_func, colorspace transfer function + * @lock: protect variables accessed by V4L2 threads and worker thread such as + * mtk_video_dec_buf. */ struct mtk_vcodec_ctx { enum mtk_instance_type type; @@ -239,28 +275,40 @@ struct mtk_vcodec_ctx { enum mtk_encode_param param_change; struct mtk_enc_params enc_params; + const struct vdec_common_if *dec_if; const struct venc_common_if *enc_if; unsigned long drv_handle; + struct vdec_pic_info picinfo; + int dpb_size; + int int_cond; int int_type; wait_queue_head_t queue; unsigned int irq_status; struct v4l2_ctrl_handler ctrl_hdl; + struct work_struct decode_work; struct work_struct encode_work; + struct vdec_pic_info last_decoded_picinfo; enum v4l2_colorspace colorspace; enum v4l2_ycbcr_encoding ycbcr_enc; enum v4l2_quantization quantization; enum v4l2_xfer_func xfer_func; + + int decoded_frame_cnt; + struct mutex lock; + }; /** * struct mtk_vcodec_dev - driver data * @v4l2_dev: V4L2 device to register video devices for. + * @vfd_dec: Video device for decoder * @vfd_enc: Video device for encoder. * + * @m2m_dev_dec: m2m device for decoder * @m2m_dev_enc: m2m device for encoder. * @plat_dev: platform device * @vpu_plat_dev: mtk vpu platform device @@ -271,7 +319,6 @@ struct mtk_vcodec_ctx { * @reg_base: Mapped address of MTK Vcodec registers. * * @id_counter: used to identify current opened instance - * @num_instances: counter of active MTK Vcodec instances * * @encode_workqueue: encode work queue * @@ -280,9 +327,11 @@ struct mtk_vcodec_ctx { * @dev_mutex: video_device lock * @queue: waitqueue for waiting for completion of device commands * + * @dec_irq: decoder irq resource * @enc_irq: h264 encoder irq resource * @enc_lt_irq: vp8 encoder irq resource * + * @dec_mutex: decoder hardware lock * @enc_mutex: encoder hardware lock. * * @pm: power management control @@ -291,8 +340,10 @@ struct mtk_vcodec_ctx { */ struct mtk_vcodec_dev { struct v4l2_device v4l2_dev; + struct video_device *vfd_dec; struct video_device *vfd_enc; + struct v4l2_m2m_dev *m2m_dev_dec; struct v4l2_m2m_dev *m2m_dev_enc; struct platform_device *plat_dev; struct platform_device *vpu_plat_dev; @@ -302,18 +353,19 @@ struct mtk_vcodec_dev { void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE]; unsigned long id_counter; - int num_instances; + struct workqueue_struct *decode_workqueue; struct workqueue_struct *encode_workqueue; - int int_cond; int int_type; struct mutex dev_mutex; wait_queue_head_t queue; + int dec_irq; int enc_irq; int enc_lt_irq; + struct mutex dec_mutex; struct mutex enc_mutex; struct mtk_vcodec_pm pm; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c index 5cd2151431bf..aa81f3ce9463 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c @@ -188,7 +188,6 @@ static int fops_vcodec_open(struct file *file) mtk_v4l2_debug(2, "Create instance [%d]@%p m2m_ctx=%p ", ctx->id, ctx, ctx->m2m_ctx); - dev->num_instances++; list_add(&ctx->list, &dev->ctx_list); mutex_unlock(&dev->dev_mutex); @@ -218,18 +217,13 @@ static int fops_vcodec_release(struct file *file) mtk_v4l2_debug(1, "[%d] encoder", ctx->id); mutex_lock(&dev->dev_mutex); - /* - * Call v4l2_m2m_ctx_release to make sure the worker thread is not - * running after venc_if_deinit. - */ - v4l2_m2m_ctx_release(ctx->m2m_ctx); mtk_vcodec_enc_release(ctx); v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->ctrl_hdl); + v4l2_m2m_ctx_release(ctx->m2m_ctx); list_del_init(&ctx->list); - dev->num_instances--; kfree(ctx); mutex_unlock(&dev->dev_mutex); return 0; diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c index 52e7e5c9afa0..113b2097f061 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_intr.c @@ -30,8 +30,7 @@ int mtk_vcodec_wait_for_done_ctx(struct mtk_vcodec_ctx *ctx, int command, timeout_jiff = msecs_to_jiffies(timeout_ms); ret = wait_event_interruptible_timeout(*waitqueue, - (ctx->int_cond && - (ctx->int_type == command)), + ctx->int_cond, timeout_jiff); if (!ret) { diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c index 5e3651372a3c..46768c056193 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c @@ -81,14 +81,37 @@ void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data, return; } - dma_free_coherent(dev, size, mem->va, mem->dma_addr); - mem->va = NULL; - mem->dma_addr = 0; - mem->size = 0; - mtk_v4l2_debug(3, "[%d] - va = %p", ctx->id, mem->va); mtk_v4l2_debug(3, "[%d] - dma = 0x%lx", ctx->id, (unsigned long)mem->dma_addr); mtk_v4l2_debug(3, "[%d] size = 0x%lx", ctx->id, size); + + dma_free_coherent(dev, size, mem->va, mem->dma_addr); + mem->va = NULL; + mem->dma_addr = 0; + mem->size = 0; } EXPORT_SYMBOL(mtk_vcodec_mem_free); + +void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev, + struct mtk_vcodec_ctx *ctx) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->irqlock, flags); + dev->curr_ctx = ctx; + spin_unlock_irqrestore(&dev->irqlock, flags); +} +EXPORT_SYMBOL(mtk_vcodec_set_curr_ctx); + +struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev) +{ + unsigned long flags; + struct mtk_vcodec_ctx *ctx; + + spin_lock_irqsave(&dev->irqlock, flags); + ctx = dev->curr_ctx; + spin_unlock_irqrestore(&dev->irqlock, flags); + return ctx; +} +EXPORT_SYMBOL(mtk_vcodec_get_curr_ctx); diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h index d6345fc04840..7d55975d3185 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.h @@ -26,6 +26,7 @@ struct mtk_vcodec_mem { }; struct mtk_vcodec_ctx; +struct mtk_vcodec_dev; extern int mtk_v4l2_dbg_level; extern bool mtk_vcodec_dbg; @@ -84,4 +85,8 @@ int mtk_vcodec_mem_alloc(struct mtk_vcodec_ctx *data, struct mtk_vcodec_mem *mem); void mtk_vcodec_mem_free(struct mtk_vcodec_ctx *data, struct mtk_vcodec_mem *mem); +void mtk_vcodec_set_curr_ctx(struct mtk_vcodec_dev *dev, + struct mtk_vcodec_ctx *ctx); +struct mtk_vcodec_ctx *mtk_vcodec_get_curr_ctx(struct mtk_vcodec_dev *dev); + #endif /* _MTK_VCODEC_UTIL_H_ */ diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h new file mode 100644 index 000000000000..ca022e3300d7 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VDEC_DRV_BASE_ +#define _VDEC_DRV_BASE_ + +#include "mtk_vcodec_drv.h" + + +struct vdec_common_if { + /** + * (*init)() - initialize decode driver + * @ctx : [in] mtk v4l2 context + * @h_vdec : [out] driver handle + */ + int (*init)(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec); + + /** + * (*decode)() - trigger decode + * @h_vdec : [in] driver handle + * @bs : [in] input bitstream + * @fb : [in] frame buffer to store decoded frame + * @res_chg : [out] resolution change happen + */ + int (*decode)(unsigned long h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg); + + /** + * (*get_param)() - get driver's parameter + * @h_vdec : [in] driver handle + * @type : [in] input parameter type + * @out : [out] buffer to store query result + */ + int (*get_param)(unsigned long h_vdec, enum vdec_get_param_type type, + void *out); + + /** + * (*deinit)() - deinitialize driver. + * @h_vdec : [in] driver handle to be deinit + */ + void (*deinit)(unsigned long h_vdec); +}; + +#endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c new file mode 100644 index 000000000000..3cb04ef45144 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * Tiffany Lin + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include + +#include "vdec_drv_if.h" +#include "mtk_vcodec_dec.h" +#include "vdec_drv_base.h" +#include "mtk_vcodec_dec_pm.h" +#include "mtk_vpu.h" + + +int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) +{ + int ret = 0; + + switch (fourcc) { + case V4L2_PIX_FMT_H264: + case V4L2_PIX_FMT_VP8: + default: + return -EINVAL; + } + + mtk_vdec_lock(ctx); + mtk_vcodec_dec_clock_on(&ctx->dev->pm); + ret = ctx->dec_if->init(ctx, &ctx->drv_handle); + mtk_vcodec_dec_clock_off(&ctx->dev->pm); + mtk_vdec_unlock(ctx); + + return ret; +} + +int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + int ret = 0; + + if (bs) { + if ((bs->dma_addr & 63) != 0) { + mtk_v4l2_err("bs dma_addr should 64 byte align"); + return -EINVAL; + } + } + + if (fb) { + if (((fb->base_y.dma_addr & 511) != 0) || + ((fb->base_c.dma_addr & 511) != 0)) { + mtk_v4l2_err("frame buffer dma_addr should 512 byte align"); + return -EINVAL; + } + } + + if (ctx->drv_handle == 0) + return -EIO; + + mtk_vdec_lock(ctx); + + mtk_vcodec_set_curr_ctx(ctx->dev, ctx); + mtk_vcodec_dec_clock_on(&ctx->dev->pm); + enable_irq(ctx->dev->dec_irq); + ret = ctx->dec_if->decode(ctx->drv_handle, bs, fb, res_chg); + disable_irq(ctx->dev->dec_irq); + mtk_vcodec_dec_clock_off(&ctx->dev->pm); + mtk_vcodec_set_curr_ctx(ctx->dev, NULL); + + mtk_vdec_unlock(ctx); + + return ret; +} + +int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type, + void *out) +{ + int ret = 0; + + if (ctx->drv_handle == 0) + return -EIO; + + mtk_vdec_lock(ctx); + ret = ctx->dec_if->get_param(ctx->drv_handle, type, out); + mtk_vdec_unlock(ctx); + + return ret; +} + +void vdec_if_deinit(struct mtk_vcodec_ctx *ctx) +{ + if (ctx->drv_handle == 0) + return; + + mtk_vdec_lock(ctx); + mtk_vcodec_dec_clock_on(&ctx->dev->pm); + ctx->dec_if->deinit(ctx->drv_handle); + mtk_vcodec_dec_clock_off(&ctx->dev->pm); + mtk_vdec_unlock(ctx); + + ctx->drv_handle = 0; +} diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.h b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h new file mode 100644 index 000000000000..db6b5205ffb1 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * Tiffany Lin + * + * 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 _VDEC_DRV_IF_H_ +#define _VDEC_DRV_IF_H_ + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_dec.h" +#include "mtk_vcodec_util.h" + + +/** + * struct vdec_fb_status - decoder frame buffer status + * @FB_ST_NORMAL : initial state + * @FB_ST_DISPLAY : frmae buffer is ready to be displayed + * @FB_ST_FREE : frame buffer is not used by decoder any more + */ +enum vdec_fb_status { + FB_ST_NORMAL = 0, + FB_ST_DISPLAY = (1 << 0), + FB_ST_FREE = (1 << 1) +}; + +/* For GET_PARAM_DISP_FRAME_BUFFER and GET_PARAM_FREE_FRAME_BUFFER, + * the caller does not own the returned buffer. The buffer will not be + * released before vdec_if_deinit. + * GET_PARAM_DISP_FRAME_BUFFER : get next displayable frame buffer, + * struct vdec_fb** + * GET_PARAM_FREE_FRAME_BUFFER : get non-referenced framebuffer, vdec_fb** + * GET_PARAM_PIC_INFO : get picture info, struct vdec_pic_info* + * GET_PARAM_CROP_INFO : get crop info, struct v4l2_crop* + * GET_PARAM_DPB_SIZE : get dpb size, unsigned int* + */ +enum vdec_get_param_type { + GET_PARAM_DISP_FRAME_BUFFER, + GET_PARAM_FREE_FRAME_BUFFER, + GET_PARAM_PIC_INFO, + GET_PARAM_CROP_INFO, + GET_PARAM_DPB_SIZE +}; + +/** + * struct vdec_fb_node - decoder frame buffer node + * @list : list to hold this node + * @fb : point to frame buffer (vdec_fb), fb could point to frame buffer and + * working buffer this is for maintain buffers in different state + */ +struct vdec_fb_node { + struct list_head list; + struct vdec_fb *fb; +}; + +/** + * vdec_if_init() - initialize decode driver + * @ctx : [in] v4l2 context + * @fourcc : [in] video format fourcc, V4L2_PIX_FMT_H264/VP8/VP9.. + */ +int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc); + +/** + * vdec_if_deinit() - deinitialize decode driver + * @ctx : [in] v4l2 context + * + */ +void vdec_if_deinit(struct mtk_vcodec_ctx *ctx); + +/** + * vdec_if_decode() - trigger decode + * @ctx : [in] v4l2 context + * @bs : [in] input bitstream + * @fb : [in] frame buffer to store decoded frame, when null menas parse + * header only + * @res_chg : [out] resolution change happens if current bs have different + * picture width/height + * Note: To flush the decoder when reaching EOF, set input bitstream as NULL. + */ +int vdec_if_decode(struct mtk_vcodec_ctx *ctx, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg); + +/** + * vdec_if_get_param() - get driver's parameter + * @ctx : [in] v4l2 context + * @type : [in] input parameter type + * @out : [out] buffer to store query result + */ +int vdec_if_get_param(struct mtk_vcodec_ctx *ctx, enum vdec_get_param_type type, + void *out); + +#endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h new file mode 100644 index 000000000000..5a8a629f4ac9 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec_ipi_msg.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * + * This program is free software; you can redistribute it and/or + * modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VDEC_IPI_MSG_H_ +#define _VDEC_IPI_MSG_H_ + +/** + * enum vdec_ipi_msgid - message id between AP and VPU + * @AP_IPIMSG_XXX : AP to VPU cmd message id + * @VPU_IPIMSG_XXX_ACK : VPU ack AP cmd message id + */ +enum vdec_ipi_msgid { + AP_IPIMSG_DEC_INIT = 0xA000, + AP_IPIMSG_DEC_START = 0xA001, + AP_IPIMSG_DEC_END = 0xA002, + AP_IPIMSG_DEC_DEINIT = 0xA003, + AP_IPIMSG_DEC_RESET = 0xA004, + + VPU_IPIMSG_DEC_INIT_ACK = 0xB000, + VPU_IPIMSG_DEC_START_ACK = 0xB001, + VPU_IPIMSG_DEC_END_ACK = 0xB002, + VPU_IPIMSG_DEC_DEINIT_ACK = 0xB003, + VPU_IPIMSG_DEC_RESET_ACK = 0xB004, +}; + +/** + * struct vdec_ap_ipi_cmd - generic AP to VPU ipi command format + * @msg_id : vdec_ipi_msgid + * @vpu_inst_addr : VPU decoder instance address + */ +struct vdec_ap_ipi_cmd { + uint32_t msg_id; + uint32_t vpu_inst_addr; +}; + +/** + * struct vdec_vpu_ipi_ack - generic VPU to AP ipi command format + * @msg_id : vdec_ipi_msgid + * @status : VPU exeuction result + * @ap_inst_addr : AP video decoder instance address + */ +struct vdec_vpu_ipi_ack { + uint32_t msg_id; + int32_t status; + uint64_t ap_inst_addr; +}; + +/** + * struct vdec_ap_ipi_init - for AP_IPIMSG_DEC_INIT + * @msg_id : AP_IPIMSG_DEC_INIT + * @reserved : Reserved field + * @ap_inst_addr : AP video decoder instance address + */ +struct vdec_ap_ipi_init { + uint32_t msg_id; + uint32_t reserved; + uint64_t ap_inst_addr; +}; + +/** + * struct vdec_ap_ipi_dec_start - for AP_IPIMSG_DEC_START + * @msg_id : AP_IPIMSG_DEC_START + * @vpu_inst_addr : VPU decoder instance address + * @data : Header info + * H264 decoder [0]:buf_sz [1]:nal_start + * VP8 decoder [0]:width/height + * VP9 decoder [0]:profile, [1][2] width/height + * @reserved : Reserved field + */ +struct vdec_ap_ipi_dec_start { + uint32_t msg_id; + uint32_t vpu_inst_addr; + uint32_t data[3]; + uint32_t reserved; +}; + +/** + * struct vdec_vpu_ipi_init_ack - for VPU_IPIMSG_DEC_INIT_ACK + * @msg_id : VPU_IPIMSG_DEC_INIT_ACK + * @status : VPU exeuction result + * @ap_inst_addr : AP vcodec_vpu_inst instance address + * @vpu_inst_addr : VPU decoder instance address + */ +struct vdec_vpu_ipi_init_ack { + uint32_t msg_id; + int32_t status; + uint64_t ap_inst_addr; + uint32_t vpu_inst_addr; +}; + +#endif diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c new file mode 100644 index 000000000000..5a24c51aebb7 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mtk_vcodec_drv.h" +#include "mtk_vcodec_util.h" +#include "vdec_ipi_msg.h" +#include "vdec_vpu_if.h" + +static void handle_init_ack_msg(struct vdec_vpu_ipi_init_ack *msg) +{ + struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) + (unsigned long)msg->ap_inst_addr; + + mtk_vcodec_debug(vpu, "+ ap_inst_addr = 0x%llx", msg->ap_inst_addr); + + /* mapping VPU address to kernel virtual address */ + /* the content in vsi is initialized to 0 in VPU */ + vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr); + vpu->inst_addr = msg->vpu_inst_addr; + + mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr); +} + +/* + * This function runs in interrupt context and it means there's an IPI MSG + * from VPU. + */ +void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv) +{ + struct vdec_vpu_ipi_ack *msg = data; + struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *) + (unsigned long)msg->ap_inst_addr; + + mtk_vcodec_debug(vpu, "+ id=%X", msg->msg_id); + + if (msg->status == 0) { + switch (msg->msg_id) { + case VPU_IPIMSG_DEC_INIT_ACK: + handle_init_ack_msg(data); + break; + + case VPU_IPIMSG_DEC_START_ACK: + case VPU_IPIMSG_DEC_END_ACK: + case VPU_IPIMSG_DEC_DEINIT_ACK: + case VPU_IPIMSG_DEC_RESET_ACK: + break; + + default: + mtk_vcodec_err(vpu, "invalid msg=%X", msg->msg_id); + break; + } + } + + mtk_vcodec_debug(vpu, "- id=%X", msg->msg_id); + vpu->failure = msg->status; + vpu->signaled = 1; +} + +static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len) +{ + int err; + uint32_t msg_id = *(uint32_t *)msg; + + mtk_vcodec_debug(vpu, "id=%X", msg_id); + + vpu->failure = 0; + vpu->signaled = 0; + + err = vpu_ipi_send(vpu->dev, vpu->id, msg, len); + if (err) { + mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d", + vpu->id, msg_id, err); + return err; + } + + return vpu->failure; +} + +static int vcodec_send_ap_ipi(struct vdec_vpu_inst *vpu, unsigned int msg_id) +{ + struct vdec_ap_ipi_cmd msg; + int err = 0; + + mtk_vcodec_debug(vpu, "+ id=%X", msg_id); + + memset(&msg, 0, sizeof(msg)); + msg.msg_id = msg_id; + msg.vpu_inst_addr = vpu->inst_addr; + + err = vcodec_vpu_send_msg(vpu, &msg, sizeof(msg)); + mtk_vcodec_debug(vpu, "- id=%X ret=%d", msg_id, err); + return err; +} + +int vpu_dec_init(struct vdec_vpu_inst *vpu) +{ + struct vdec_ap_ipi_init msg; + int err; + + mtk_vcodec_debug_enter(vpu); + + init_waitqueue_head(&vpu->wq); + + err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, "vdec", NULL); + if (err != 0) { + mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err); + return err; + } + + memset(&msg, 0, sizeof(msg)); + msg.msg_id = AP_IPIMSG_DEC_INIT; + msg.ap_inst_addr = (unsigned long)vpu; + + mtk_vcodec_debug(vpu, "vdec_inst=%p", vpu); + + err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg)); + mtk_vcodec_debug(vpu, "- ret=%d", err); + return err; +} + +int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len) +{ + struct vdec_ap_ipi_dec_start msg; + int i; + int err = 0; + + mtk_vcodec_debug_enter(vpu); + + if (len > ARRAY_SIZE(msg.data)) { + mtk_vcodec_err(vpu, "invalid len = %d\n", len); + return -EINVAL; + } + + memset(&msg, 0, sizeof(msg)); + msg.msg_id = AP_IPIMSG_DEC_START; + msg.vpu_inst_addr = vpu->inst_addr; + + for (i = 0; i < len; i++) + msg.data[i] = data[i]; + + err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg)); + mtk_vcodec_debug(vpu, "- ret=%d", err); + return err; +} + +int vpu_dec_end(struct vdec_vpu_inst *vpu) +{ + return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_END); +} + +int vpu_dec_deinit(struct vdec_vpu_inst *vpu) +{ + return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_DEINIT); +} + +int vpu_dec_reset(struct vdec_vpu_inst *vpu) +{ + return vcodec_send_ap_ipi(vpu, AP_IPIMSG_DEC_RESET); +} diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h new file mode 100644 index 000000000000..0dc9ed01fffe --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _VDEC_VPU_IF_H_ +#define _VDEC_VPU_IF_H_ + +#include "mtk_vpu.h" + +/** + * struct vdec_vpu_inst - VPU instance for video codec + * @ipi_id : ipi id for each decoder + * @vsi : driver structure allocated by VPU side and shared to AP side + * for control and info share + * @failure : VPU execution result status, 0: success, others: fail + * @inst_addr : VPU decoder instance address + * @signaled : 1 - Host has received ack message from VPU, 0 - not received + * @ctx : context for v4l2 layer integration + * @dev : platform device of VPU + * @wq : wait queue to wait VPU message ack + * @handler : ipi handler for each decoder + */ +struct vdec_vpu_inst { + enum ipi_id id; + void *vsi; + int32_t failure; + uint32_t inst_addr; + unsigned int signaled; + struct mtk_vcodec_ctx *ctx; + struct platform_device *dev; + wait_queue_head_t wq; + ipi_handler_t handler; +}; + +/** + * vpu_dec_init - init decoder instance and allocate required resource in VPU. + * + * @vpu: instance for vdec_vpu_inst + */ +int vpu_dec_init(struct vdec_vpu_inst *vpu); + +/** + * vpu_dec_start - start decoding, basically the function will be invoked once + * every frame. + * + * @vpu : instance for vdec_vpu_inst + * @data: meta data to pass bitstream info to VPU decoder + * @len : meta data length + */ +int vpu_dec_start(struct vdec_vpu_inst *vpu, uint32_t *data, unsigned int len); + +/** + * vpu_dec_end - end decoding, basically the function will be invoked once + * when HW decoding done interrupt received successfully. The + * decoder in VPU will continute to do referene frame management + * and check if there is a new decoded frame available to display. + * + * @vpu : instance for vdec_vpu_inst + */ +int vpu_dec_end(struct vdec_vpu_inst *vpu); + +/** + * vpu_dec_deinit - deinit decoder instance and resource freed in VPU. + * + * @vpu: instance for vdec_vpu_inst + */ +int vpu_dec_deinit(struct vdec_vpu_inst *vpu); + +/** + * vpu_dec_reset - reset decoder, use for flush decoder when end of stream or + * seek. Remainig non displayed frame will be pushed to display. + * + * @vpu: instance for vdec_vpu_inst + */ +int vpu_dec_reset(struct vdec_vpu_inst *vpu); + +/** + * vpu_dec_ipi_handler - Handler for VPU ipi message. + * + * @data: ipi message + * @len : length of ipi message + * @priv: callback private data which is passed by decoder when register. + */ +void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv); + +#endif -- cgit v1.2.3 From 487a4c51c1e99ea1949520af565c0d29bf3164f6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 21 Oct 2016 10:55:52 -0200 Subject: [media] mtk-vcodec: fix some smatch warnings Fix this bug: drivers/media/platform/mtk-vcodec/vdec_drv_if.c:38 vdec_if_init() info: ignoring unreachable code. With is indeed a real problem that prevents the driver to work! While here, also remove an used var, as reported by smatch: drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c: In function 'mtk_vcodec_init_dec_pm': drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c:29:17: warning: variable 'dev' set but not used [-Wunused-but-set-variable] struct device *dev; ^~~ Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c | 2 -- drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c index 18182f5676d8..79ca03ac449c 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c @@ -26,14 +26,12 @@ int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev) { struct device_node *node; struct platform_device *pdev; - struct device *dev; struct mtk_vcodec_pm *pm; int ret = 0; pdev = mtkdev->plat_dev; pm = &mtkdev->pm; pm->mtkdev = mtkdev; - dev = &pdev->dev; node = of_parse_phandle(pdev->dev.of_node, "mediatek,larb", 0); if (!node) { mtk_v4l2_err("of_parse_phandle mediatek,larb fail!"); diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 3cb04ef45144..9813b2ffd5fa 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -31,6 +31,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) switch (fourcc) { case V4L2_PIX_FMT_H264: case V4L2_PIX_FMT_VP8: + break; default: return -EINVAL; } -- cgit v1.2.3 From a7b131751cd364a85ec115cb0a1898db6663ee8e Mon Sep 17 00:00:00 2001 From: Tiffany Lin Date: Fri, 2 Sep 2016 09:19:55 -0300 Subject: [media] vcodec: mediatek: Add Mediatek H264 Video Decoder Drive Add h264 decoder driver for MT8173 Signed-off-by: PC Chen Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/Makefile | 3 +- .../media/platform/mtk-vcodec/vdec/vdec_h264_if.c | 507 +++++++++++++++++++++ drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 3 + 3 files changed, 512 insertions(+), 1 deletion(-) create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index b54e82372b4c..58243edb3865 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -3,7 +3,8 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ mtk-vcodec-enc.o \ mtk-vcodec-common.o -mtk-vcodec-dec-y := mtk_vcodec_dec_drv.o \ +mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ + mtk_vcodec_dec_drv.o \ vdec_drv_if.o \ vdec_vpu_if.o \ mtk_vcodec_dec.o \ diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c new file mode 100644 index 000000000000..57a842ff3097 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: PC Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#include "../vdec_drv_if.h" +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_vpu_if.h" +#include "../vdec_drv_base.h" + +#define NAL_NON_IDR_SLICE 0x01 +#define NAL_IDR_SLICE 0x05 +#define NAL_H264_PPS 0x08 +#define NAL_TYPE(value) ((value) & 0x1F) + +#define BUF_PREDICTION_SZ (32 * 1024) + +#define MB_UNIT_LEN 16 + +/* motion vector size (bytes) for every macro block */ +#define HW_MB_STORE_SZ 64 + +#define H264_MAX_FB_NUM 17 +#define HDR_PARSING_BUF_SZ 1024 + +/** + * struct h264_fb - h264 decode frame buffer information + * @vdec_fb_va : virtual address of struct vdec_fb + * @y_fb_dma : dma address of Y frame buffer (luma) + * @c_fb_dma : dma address of C frame buffer (chroma) + * @poc : picture order count of frame buffer + * @reserved : for 8 bytes alignment + */ +struct h264_fb { + uint64_t vdec_fb_va; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + int32_t poc; + uint32_t reserved; +}; + +/** + * struct h264_ring_fb_list - ring frame buffer list + * @fb_list : frame buffer arrary + * @read_idx : read index + * @write_idx : write index + * @count : buffer count in list + */ +struct h264_ring_fb_list { + struct h264_fb fb_list[H264_MAX_FB_NUM]; + unsigned int read_idx; + unsigned int write_idx; + unsigned int count; + unsigned int reserved; +}; + +/** + * struct vdec_h264_dec_info - decode information + * @dpb_sz : decoding picture buffer size + * @resolution_changed : resoltion change happen + * @realloc_mv_buf : flag to notify driver to re-allocate mv buffer + * @reserved : for 8 bytes alignment + * @bs_dma : Input bit-stream buffer dma address + * @y_fb_dma : Y frame buffer dma address + * @c_fb_dma : C frame buffer dma address + * @vdec_fb_va : VDEC frame buffer struct virtual address + */ +struct vdec_h264_dec_info { + uint32_t dpb_sz; + uint32_t resolution_changed; + uint32_t realloc_mv_buf; + uint32_t reserved; + uint64_t bs_dma; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + uint64_t vdec_fb_va; +}; + +/** + * struct vdec_h264_vsi - shared memory for decode information exchange + * between VPU and Host. + * The memory is allocated by VPU then mapping to Host + * in vpu_dec_init() and freed in vpu_dec_deinit() + * by VPU. + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @hdr_buf : Header parsing buffer (AP-W, VPU-R) + * @pred_buf_dma : HW working predication buffer dma address (AP-W, VPU-R) + * @mv_buf_dma : HW working motion vector buffer dma address (AP-W, VPU-R) + * @list_free : free frame buffer ring list (AP-W/R, VPU-W) + * @list_disp : display frame buffer ring list (AP-R, VPU-W) + * @dec : decode information (AP-R, VPU-W) + * @pic : picture information (AP-R, VPU-W) + * @crop : crop information (AP-R, VPU-W) + */ +struct vdec_h264_vsi { + unsigned char hdr_buf[HDR_PARSING_BUF_SZ]; + uint64_t pred_buf_dma; + uint64_t mv_buf_dma[H264_MAX_FB_NUM]; + struct h264_ring_fb_list list_free; + struct h264_ring_fb_list list_disp; + struct vdec_h264_dec_info dec; + struct vdec_pic_info pic; + struct v4l2_rect crop; +}; + +/** + * struct vdec_h264_inst - h264 decoder instance + * @num_nalu : how many nalus be decoded + * @ctx : point to mtk_vcodec_ctx + * @pred_buf : HW working predication buffer + * @mv_buf : HW working motion vector buffer + * @vpu : VPU instance + * @vsi : VPU shared information + */ +struct vdec_h264_inst { + unsigned int num_nalu; + struct mtk_vcodec_ctx *ctx; + struct mtk_vcodec_mem pred_buf; + struct mtk_vcodec_mem mv_buf[H264_MAX_FB_NUM]; + struct vdec_vpu_inst vpu; + struct vdec_h264_vsi *vsi; +}; + +static unsigned int get_mv_buf_size(unsigned int width, unsigned int height) +{ + return HW_MB_STORE_SZ * (width/MB_UNIT_LEN) * (height/MB_UNIT_LEN); +} + +static int allocate_predication_buf(struct vdec_h264_inst *inst) +{ + int err = 0; + + inst->pred_buf.size = BUF_PREDICTION_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, &inst->pred_buf); + if (err) { + mtk_vcodec_err(inst, "failed to allocate ppl buf"); + return err; + } + + inst->vsi->pred_buf_dma = inst->pred_buf.dma_addr; + return 0; +} + +static void free_predication_buf(struct vdec_h264_inst *inst) +{ + struct mtk_vcodec_mem *mem = NULL; + + mtk_vcodec_debug_enter(inst); + + inst->vsi->pred_buf_dma = 0; + mem = &inst->pred_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); +} + +static int alloc_mv_buf(struct vdec_h264_inst *inst, struct vdec_pic_info *pic) +{ + int i; + int err; + struct mtk_vcodec_mem *mem = NULL; + unsigned int buf_sz = get_mv_buf_size(pic->buf_w, pic->buf_h); + + for (i = 0; i < H264_MAX_FB_NUM; i++) { + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + mem->size = buf_sz; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "failed to allocate mv buf"); + return err; + } + inst->vsi->mv_buf_dma[i] = mem->dma_addr; + } + + return 0; +} + +static void free_mv_buf(struct vdec_h264_inst *inst) +{ + int i; + struct mtk_vcodec_mem *mem = NULL; + + for (i = 0; i < H264_MAX_FB_NUM; i++) { + inst->vsi->mv_buf_dma[i] = 0; + mem = &inst->mv_buf[i]; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + } +} + +static int check_list_validity(struct vdec_h264_inst *inst, bool disp_list) +{ + struct h264_ring_fb_list *list; + + list = disp_list ? &inst->vsi->list_disp : &inst->vsi->list_free; + + if (list->count > H264_MAX_FB_NUM || + list->read_idx >= H264_MAX_FB_NUM || + list->write_idx >= H264_MAX_FB_NUM) { + mtk_vcodec_err(inst, "%s list err: cnt=%d r_idx=%d w_idx=%d", + disp_list ? "disp" : "free", list->count, + list->read_idx, list->write_idx); + return -EINVAL; + } + + return 0; +} + +static void put_fb_to_free(struct vdec_h264_inst *inst, struct vdec_fb *fb) +{ + struct h264_ring_fb_list *list; + + if (fb) { + if (check_list_validity(inst, false)) + return; + + list = &inst->vsi->list_free; + if (list->count == H264_MAX_FB_NUM) { + mtk_vcodec_err(inst, "[FB] put fb free_list full"); + return; + } + + mtk_vcodec_debug(inst, "[FB] put fb into free_list @(%p, %llx)", + fb->base_y.va, (u64)fb->base_y.dma_addr); + + list->fb_list[list->write_idx].vdec_fb_va = (u64)(uintptr_t)fb; + list->write_idx = (list->write_idx == H264_MAX_FB_NUM - 1) ? + 0 : list->write_idx + 1; + list->count++; + } +} + +static void get_pic_info(struct vdec_h264_inst *inst, + struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); + mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, + pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); +} + +static void get_crop_info(struct vdec_h264_inst *inst, struct v4l2_rect *cr) +{ + cr->left = inst->vsi->crop.left; + cr->top = inst->vsi->crop.top; + cr->width = inst->vsi->crop.width; + cr->height = inst->vsi->crop.height; + + mtk_vcodec_debug(inst, "l=%d, t=%d, w=%d, h=%d", + cr->left, cr->top, cr->width, cr->height); +} + +static void get_dpb_size(struct vdec_h264_inst *inst, unsigned int *dpb_sz) +{ + *dpb_sz = inst->vsi->dec.dpb_sz; + mtk_vcodec_debug(inst, "sz=%d", *dpb_sz); +} + +static int vdec_h264_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_h264_inst *inst = NULL; + int err; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = IPI_VDEC_H264; + inst->vpu.dev = ctx->dev->vpu_plat_dev; + inst->vpu.ctx = ctx; + inst->vpu.handler = vpu_dec_ipi_handler; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_h264 init err=%d", err); + goto error_free_inst; + } + + inst->vsi = (struct vdec_h264_vsi *)inst->vpu.vsi; + err = allocate_predication_buf(inst); + if (err) + goto error_deinit; + + mtk_vcodec_debug(inst, "H264 Instance >> %p", inst); + + *h_vdec = (unsigned long)inst; + return 0; + +error_deinit: + vpu_dec_deinit(&inst->vpu); + +error_free_inst: + kfree(inst); + return err; +} + +static void vdec_h264_deinit(unsigned long h_vdec) +{ + struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + free_predication_buf(inst); + free_mv_buf(inst); + + kfree(inst); +} + +static int find_start_code(unsigned char *data, unsigned int data_sz) +{ + if (data_sz > 3 && data[0] == 0 && data[1] == 0 && data[2] == 1) + return 3; + + if (data_sz > 4 && data[0] == 0 && data[1] == 0 && data[2] == 0 && + data[3] == 1) + return 4; + + return -1; +} + +static int vdec_h264_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; + struct vdec_vpu_inst *vpu = &inst->vpu; + int nal_start_idx = 0; + int err = 0; + unsigned int nal_start; + unsigned int nal_type; + unsigned char *buf; + unsigned int buf_sz; + unsigned int data[2]; + uint64_t vdec_fb_va = (u64)(uintptr_t)fb; + uint64_t y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + uint64_t c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + + mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx va=%p", + ++inst->num_nalu, y_fb_dma, c_fb_dma, fb); + + /* bs NULL means flush decoder */ + if (bs == NULL) + return vpu_dec_reset(vpu); + + buf = (unsigned char *)bs->va; + buf_sz = bs->size; + nal_start_idx = find_start_code(buf, buf_sz); + if (nal_start_idx < 0) + goto err_free_fb_out; + + nal_start = buf[nal_start_idx]; + nal_type = NAL_TYPE(buf[nal_start_idx]); + mtk_vcodec_debug(inst, "\n + NALU[%d] type %d +\n", inst->num_nalu, + nal_type); + + if (nal_type == NAL_H264_PPS) { + buf_sz -= nal_start_idx; + if (buf_sz > HDR_PARSING_BUF_SZ) { + err = -EILSEQ; + goto err_free_fb_out; + } + memcpy(inst->vsi->hdr_buf, buf + nal_start_idx, buf_sz); + } + + inst->vsi->dec.bs_dma = (uint64_t)bs->dma_addr; + inst->vsi->dec.y_fb_dma = y_fb_dma; + inst->vsi->dec.c_fb_dma = c_fb_dma; + inst->vsi->dec.vdec_fb_va = vdec_fb_va; + + data[0] = buf_sz; + data[1] = nal_start; + err = vpu_dec_start(vpu, data, 2); + if (err) + goto err_free_fb_out; + + *res_chg = inst->vsi->dec.resolution_changed; + if (*res_chg) { + struct vdec_pic_info pic; + + mtk_vcodec_debug(inst, "- resolution changed -"); + get_pic_info(inst, &pic); + + if (inst->vsi->dec.realloc_mv_buf) { + err = alloc_mv_buf(inst, &pic); + if (err) + goto err_free_fb_out; + } + } + + if (nal_type == NAL_NON_IDR_SLICE || nal_type == NAL_IDR_SLICE) { + /* wait decoder done interrupt */ + err = mtk_vcodec_wait_for_done_ctx(inst->ctx, + MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS); + if (err) + goto err_free_fb_out; + + vpu_dec_end(vpu); + } + + mtk_vcodec_debug(inst, "\n - NALU[%d] type=%d -\n", inst->num_nalu, + nal_type); + return 0; + +err_free_fb_out: + put_fb_to_free(inst, fb); + mtk_vcodec_err(inst, "\n - NALU[%d] err=%d -\n", inst->num_nalu, err); + return err; +} + +static void vdec_h264_get_fb(struct vdec_h264_inst *inst, + struct h264_ring_fb_list *list, + bool disp_list, struct vdec_fb **out_fb) +{ + struct vdec_fb *fb; + + if (check_list_validity(inst, disp_list)) + return; + + if (list->count == 0) { + mtk_vcodec_debug(inst, "[FB] there is no %s fb", + disp_list ? "disp" : "free"); + *out_fb = NULL; + return; + } + + fb = (struct vdec_fb *) + (uintptr_t)list->fb_list[list->read_idx].vdec_fb_va; + fb->status |= (disp_list ? FB_ST_DISPLAY : FB_ST_FREE); + + *out_fb = fb; + mtk_vcodec_debug(inst, "[FB] get %s fb st=%d poc=%d %llx", + disp_list ? "disp" : "free", + fb->status, list->fb_list[list->read_idx].poc, + list->fb_list[list->read_idx].vdec_fb_va); + + list->read_idx = (list->read_idx == H264_MAX_FB_NUM - 1) ? + 0 : list->read_idx + 1; + list->count--; +} + +static int vdec_h264_get_param(unsigned long h_vdec, + enum vdec_get_param_type type, void *out) +{ + struct vdec_h264_inst *inst = (struct vdec_h264_inst *)h_vdec; + + switch (type) { + case GET_PARAM_DISP_FRAME_BUFFER: + vdec_h264_get_fb(inst, &inst->vsi->list_disp, true, out); + break; + + case GET_PARAM_FREE_FRAME_BUFFER: + vdec_h264_get_fb(inst, &inst->vsi->list_free, false, out); + break; + + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + get_dpb_size(inst, out); + break; + + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + + return 0; +} + +static struct vdec_common_if vdec_h264_if = { + vdec_h264_init, + vdec_h264_decode, + vdec_h264_get_param, + vdec_h264_deinit, +}; + +struct vdec_common_if *get_h264_dec_comm_if(void); + +struct vdec_common_if *get_h264_dec_comm_if(void) +{ + return &vdec_h264_if; +} diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 9813b2ffd5fa..e03f126eb51f 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -23,6 +23,7 @@ #include "mtk_vcodec_dec_pm.h" #include "mtk_vpu.h" +const struct vdec_common_if *get_h264_dec_comm_if(void); int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { @@ -30,6 +31,8 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) switch (fourcc) { case V4L2_PIX_FMT_H264: + ctx->dec_if = get_h264_dec_comm_if(); + break; case V4L2_PIX_FMT_VP8: break; default: -- cgit v1.2.3 From d1fad85f5af329650d101069ae8f78e3043b8f2b Mon Sep 17 00:00:00 2001 From: Tiffany Lin Date: Fri, 2 Sep 2016 09:19:56 -0300 Subject: [media] vcodec: mediatek: Add Mediatek VP8 Video Decoder Driver Add vp8 decoder driver for MT8173 [mchehab@s-opensource.org: make checkpatch.pl happy] Signed-off-by: PC Chen Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/Makefile | 1 + .../media/platform/mtk-vcodec/vdec/vdec_vp8_if.c | 634 +++++++++++++++++++++ drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 2 + 3 files changed, 637 insertions(+) create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 58243edb3865..7743c81346a8 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -4,6 +4,7 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ mtk-vcodec-common.o mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ + vdec/vdec_vp8_if.o \ mtk_vcodec_dec_drv.o \ vdec_drv_if.o \ vdec_vpu_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c new file mode 100644 index 000000000000..6e7a62ae0842 --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c @@ -0,0 +1,634 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Jungchang Tsao + * PC Chen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "../vdec_drv_if.h" +#include "../mtk_vcodec_util.h" +#include "../mtk_vcodec_dec.h" +#include "../mtk_vcodec_intr.h" +#include "../vdec_vpu_if.h" +#include "../vdec_drv_base.h" + +/* Decoding picture buffer size (3 reference frames plus current frame) */ +#define VP8_DPB_SIZE 4 + +/* HW working buffer size (bytes) */ +#define VP8_WORKING_BUF_SZ (45 * 4096) + +/* HW control register address */ +#define VP8_SEGID_DRAM_ADDR 0x3c +#define VP8_HW_VLD_ADDR 0x93C +#define VP8_HW_VLD_VALUE 0x940 +#define VP8_BSASET 0x100 +#define VP8_BSDSET 0x104 +#define VP8_RW_CKEN_SET 0x0 +#define VP8_RW_DCM_CON 0x18 +#define VP8_WO_VLD_SRST 0x108 +#define VP8_RW_MISC_SYS_SEL 0x84 +#define VP8_RW_MISC_SPEC_CON 0xC8 +#define VP8_WO_VLD_SRST 0x108 +#define VP8_RW_VP8_CTRL 0xA4 +#define VP8_RW_MISC_DCM_CON 0xEC +#define VP8_RW_MISC_SRST 0xF4 +#define VP8_RW_MISC_FUNC_CON 0xCC + +#define VP8_MAX_FRM_BUF_NUM 5 +#define VP8_MAX_FRM_BUF_NODE_NUM (VP8_MAX_FRM_BUF_NUM * 2) + +/* required buffer size (bytes) to store decode information */ +#define VP8_HW_SEGMENT_DATA_SZ 272 +#define VP8_HW_SEGMENT_UINT 4 + +#define VP8_DEC_TABLE_PROC_LOOP 96 +#define VP8_DEC_TABLE_UNIT 3 +#define VP8_DEC_TABLE_SZ 300 +#define VP8_DEC_TABLE_OFFSET 2 +#define VP8_DEC_TABLE_RW_UNIT 4 + +/** + * struct vdec_vp8_dec_info - decode misc information + * @working_buf_dma : working buffer dma address + * @prev_y_dma : previous decoded frame buffer Y plane address + * @cur_y_fb_dma : current plane Y frame buffer dma address + * @cur_c_fb_dma : current plane C frame buffer dma address + * @bs_dma : bitstream dma address + * @bs_sz : bitstream size + * @resolution_changed: resolution change flag 1 - changed, 0 - not change + * @show_frame : display this frame or not + * @wait_key_frame : wait key frame coming + */ +struct vdec_vp8_dec_info { + uint64_t working_buf_dma; + uint64_t prev_y_dma; + uint64_t cur_y_fb_dma; + uint64_t cur_c_fb_dma; + uint64_t bs_dma; + uint32_t bs_sz; + uint32_t resolution_changed; + uint32_t show_frame; + uint32_t wait_key_frame; +}; + +/** + * struct vdec_vp8_vsi - VPU shared information + * @dec : decoding information + * @pic : picture information + * @dec_table : decoder coefficient table + * @segment_buf : segmentation buffer + * @load_data : flag to indicate reload decode data + */ +struct vdec_vp8_vsi { + struct vdec_vp8_dec_info dec; + struct vdec_pic_info pic; + uint32_t dec_table[VP8_DEC_TABLE_SZ]; + uint32_t segment_buf[VP8_HW_SEGMENT_DATA_SZ][VP8_HW_SEGMENT_UINT]; + uint32_t load_data; +}; + +/** + * struct vdec_vp8_hw_reg_base - HW register base + * @sys : base address for sys + * @misc : base address for misc + * @ld : base address for ld + * @top : base address for top + * @cm : base address for cm + * @hwd : base address for hwd + * @hwb : base address for hwb + */ +struct vdec_vp8_hw_reg_base { + void __iomem *sys; + void __iomem *misc; + void __iomem *ld; + void __iomem *top; + void __iomem *cm; + void __iomem *hwd; + void __iomem *hwb; +}; + +/** + * struct vdec_vp8_vpu_inst - VPU instance for VP8 decode + * @wq_hd : Wait queue to wait VPU message ack + * @signaled : 1 - Host has received ack message from VPU, 0 - not recevie + * @failure : VPU execution result status 0 - success, others - fail + * @inst_addr : VPU decoder instance address + */ +struct vdec_vp8_vpu_inst { + wait_queue_head_t wq_hd; + int signaled; + int failure; + uint32_t inst_addr; +}; + +/* frame buffer (fb) list + * [available_fb_node_list] - decode fb are initialized to 0 and populated in + * [fb_use_list] - fb is set after decode and is moved to this list + * [fb_free_list] - fb is not needed for reference will be moved from + * [fb_use_list] to [fb_free_list] and + * once user remove fb from [fb_free_list], + * it is circulated back to [available_fb_node_list] + * [fb_disp_list] - fb is set after decode and is moved to this list + * once user remove fb from [fb_disp_list] it is + * circulated back to [available_fb_node_list] + */ + +/** + * struct vdec_vp8_inst - VP8 decoder instance + * @cur_fb : current frame buffer + * @dec_fb : decode frame buffer node + * @available_fb_node_list : list to store available frame buffer node + * @fb_use_list : list to store frame buffer in use + * @fb_free_list : list to store free frame buffer + * @fb_disp_list : list to store display ready frame buffer + * @working_buf : HW decoder working buffer + * @reg_base : HW register base address + * @frm_cnt : decode frame count + * @ctx : V4L2 context + * @dev : platform device + * @vpu : VPU instance for decoder + * @vsi : VPU share information + */ +struct vdec_vp8_inst { + struct vdec_fb *cur_fb; + struct vdec_fb_node dec_fb[VP8_MAX_FRM_BUF_NODE_NUM]; + struct list_head available_fb_node_list; + struct list_head fb_use_list; + struct list_head fb_free_list; + struct list_head fb_disp_list; + struct mtk_vcodec_mem working_buf; + struct vdec_vp8_hw_reg_base reg_base; + unsigned int frm_cnt; + struct mtk_vcodec_ctx *ctx; + struct vdec_vpu_inst vpu; + struct vdec_vp8_vsi *vsi; +}; + +static void get_hw_reg_base(struct vdec_vp8_inst *inst) +{ + inst->reg_base.top = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_TOP); + inst->reg_base.cm = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_CM); + inst->reg_base.hwd = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWD); + inst->reg_base.sys = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_SYS); + inst->reg_base.misc = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_MISC); + inst->reg_base.ld = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_LD); + inst->reg_base.hwb = mtk_vcodec_get_reg_addr(inst->ctx, VDEC_HWB); +} + +static void write_hw_segmentation_data(struct vdec_vp8_inst *inst) +{ + int i, j; + u32 seg_id_addr; + u32 val; + void __iomem *cm = inst->reg_base.cm; + struct vdec_vp8_vsi *vsi = inst->vsi; + + seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4; + + for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) { + for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) { + val = (1 << 16) + ((seg_id_addr + i) << 2) + j; + writel(val, cm + VP8_HW_VLD_ADDR); + + val = vsi->segment_buf[i][j]; + writel(val, cm + VP8_HW_VLD_VALUE); + } + } +} + +static void read_hw_segmentation_data(struct vdec_vp8_inst *inst) +{ + int i, j; + u32 seg_id_addr; + u32 val; + void __iomem *cm = inst->reg_base.cm; + struct vdec_vp8_vsi *vsi = inst->vsi; + + seg_id_addr = readl(inst->reg_base.top + VP8_SEGID_DRAM_ADDR) >> 4; + + for (i = 0; i < ARRAY_SIZE(vsi->segment_buf); i++) { + for (j = ARRAY_SIZE(vsi->segment_buf[i]) - 1; j >= 0; j--) { + val = ((seg_id_addr + i) << 2) + j; + writel(val, cm + VP8_HW_VLD_ADDR); + + val = readl(cm + VP8_HW_VLD_VALUE); + vsi->segment_buf[i][j] = val; + } + } +} + +/* reset HW and enable HW read/write data function */ +static void enable_hw_rw_function(struct vdec_vp8_inst *inst) +{ + u32 val = 0; + void __iomem *sys = inst->reg_base.sys; + void __iomem *misc = inst->reg_base.misc; + void __iomem *ld = inst->reg_base.ld; + void __iomem *hwb = inst->reg_base.hwb; + void __iomem *hwd = inst->reg_base.hwd; + + writel(0x1, sys + VP8_RW_CKEN_SET); + writel(0x101, ld + VP8_WO_VLD_SRST); + writel(0x101, hwb + VP8_WO_VLD_SRST); + + writel(1, sys); + val = readl(misc + VP8_RW_MISC_SRST); + writel((val & 0xFFFFFFFE), misc + VP8_RW_MISC_SRST); + + writel(0x1, misc + VP8_RW_MISC_SYS_SEL); + writel(0x17F, misc + VP8_RW_MISC_SPEC_CON); + writel(0x71201100, misc + VP8_RW_MISC_FUNC_CON); + writel(0x0, ld + VP8_WO_VLD_SRST); + writel(0x0, hwb + VP8_WO_VLD_SRST); + writel(0x1, sys + VP8_RW_DCM_CON); + writel(0x1, misc + VP8_RW_MISC_DCM_CON); + writel(0x1, hwd + VP8_RW_VP8_CTRL); +} + +static void store_dec_table(struct vdec_vp8_inst *inst) +{ + int i, j; + u32 addr = 0, val = 0; + void __iomem *hwd = inst->reg_base.hwd; + u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET]; + + for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) { + writel(addr, hwd + VP8_BSASET); + for (j = 0; j < VP8_DEC_TABLE_UNIT ; j++) { + val = *p++; + writel(val, hwd + VP8_BSDSET); + } + addr += VP8_DEC_TABLE_RW_UNIT; + } +} + +static void load_dec_table(struct vdec_vp8_inst *inst) +{ + int i; + u32 addr = 0; + u32 *p = &inst->vsi->dec_table[VP8_DEC_TABLE_OFFSET]; + void __iomem *hwd = inst->reg_base.hwd; + + for (i = 0; i < VP8_DEC_TABLE_PROC_LOOP; i++) { + writel(addr, hwd + VP8_BSASET); + /* read total 11 bytes */ + *p++ = readl(hwd + VP8_BSDSET); + *p++ = readl(hwd + VP8_BSDSET); + *p++ = readl(hwd + VP8_BSDSET) & 0xFFFFFF; + addr += VP8_DEC_TABLE_RW_UNIT; + } +} + +static void get_pic_info(struct vdec_vp8_inst *inst, struct vdec_pic_info *pic) +{ + *pic = inst->vsi->pic; + + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); + mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, + pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); +} + +static void vp8_dec_finish(struct vdec_vp8_inst *inst) +{ + struct vdec_fb_node *node; + uint64_t prev_y_dma = inst->vsi->dec.prev_y_dma; + + mtk_vcodec_debug(inst, "prev fb base dma=%llx", prev_y_dma); + + /* put last decode ok frame to fb_free_list */ + if (prev_y_dma != 0) { + list_for_each_entry(node, &inst->fb_use_list, list) { + struct vdec_fb *fb = (struct vdec_fb *)node->fb; + + if (prev_y_dma == (uint64_t)fb->base_y.dma_addr) { + list_move_tail(&node->list, + &inst->fb_free_list); + break; + } + } + } + + /* available_fb_node_list -> fb_use_list */ + node = list_first_entry(&inst->available_fb_node_list, + struct vdec_fb_node, list); + node->fb = inst->cur_fb; + list_move_tail(&node->list, &inst->fb_use_list); + + /* available_fb_node_list -> fb_disp_list */ + if (inst->vsi->dec.show_frame) { + node = list_first_entry(&inst->available_fb_node_list, + struct vdec_fb_node, list); + node->fb = inst->cur_fb; + list_move_tail(&node->list, &inst->fb_disp_list); + } +} + +static void move_fb_list_use_to_free(struct vdec_vp8_inst *inst) +{ + struct vdec_fb_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, &inst->fb_use_list, list) + list_move_tail(&node->list, &inst->fb_free_list); +} + +static void init_list(struct vdec_vp8_inst *inst) +{ + int i; + + INIT_LIST_HEAD(&inst->available_fb_node_list); + INIT_LIST_HEAD(&inst->fb_use_list); + INIT_LIST_HEAD(&inst->fb_free_list); + INIT_LIST_HEAD(&inst->fb_disp_list); + + for (i = 0; i < ARRAY_SIZE(inst->dec_fb); i++) { + INIT_LIST_HEAD(&inst->dec_fb[i].list); + inst->dec_fb[i].fb = NULL; + list_add_tail(&inst->dec_fb[i].list, + &inst->available_fb_node_list); + } +} + +static void add_fb_to_free_list(struct vdec_vp8_inst *inst, void *fb) +{ + struct vdec_fb_node *node; + + if (fb) { + node = list_first_entry(&inst->available_fb_node_list, + struct vdec_fb_node, list); + node->fb = fb; + list_move_tail(&node->list, &inst->fb_free_list); + } +} + +static int alloc_working_buf(struct vdec_vp8_inst *inst) +{ + int err; + struct mtk_vcodec_mem *mem = &inst->working_buf; + + mem->size = VP8_WORKING_BUF_SZ; + err = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (err) { + mtk_vcodec_err(inst, "Cannot allocate working buffer"); + return err; + } + + inst->vsi->dec.working_buf_dma = (uint64_t)mem->dma_addr; + return 0; +} + +static void free_working_buf(struct vdec_vp8_inst *inst) +{ + struct mtk_vcodec_mem *mem = &inst->working_buf; + + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + + inst->vsi->dec.working_buf_dma = 0; +} + +static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_vp8_inst *inst; + int err; + + inst = kzalloc(sizeof(*inst), GFP_KERNEL); + if (!inst) + return -ENOMEM; + + inst->ctx = ctx; + + inst->vpu.id = IPI_VDEC_VP8; + inst->vpu.dev = ctx->dev->vpu_plat_dev; + inst->vpu.ctx = ctx; + inst->vpu.handler = vpu_dec_ipi_handler; + + err = vpu_dec_init(&inst->vpu); + if (err) { + mtk_vcodec_err(inst, "vdec_vp8 init err=%d", err); + goto error_free_inst; + } + + inst->vsi = (struct vdec_vp8_vsi *)inst->vpu.vsi; + init_list(inst); + err = alloc_working_buf(inst); + if (err) + goto error_deinit; + + get_hw_reg_base(inst); + mtk_vcodec_debug(inst, "VP8 Instance >> %p", inst); + + *h_vdec = (unsigned long)inst; + return 0; + +error_deinit: + vpu_dec_deinit(&inst->vpu); +error_free_inst: + kfree(inst); + return err; +} + +static int vdec_vp8_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; + struct vdec_vp8_dec_info *dec = &inst->vsi->dec; + struct vdec_vpu_inst *vpu = &inst->vpu; + unsigned char *bs_va; + unsigned int data; + int err = 0; + uint64_t y_fb_dma; + uint64_t c_fb_dma; + + /* bs NULL means flush decoder */ + if (bs == NULL) { + move_fb_list_use_to_free(inst); + return vpu_dec_reset(vpu); + } + + y_fb_dma = fb ? (u64)fb->base_y.dma_addr : 0; + c_fb_dma = fb ? (u64)fb->base_c.dma_addr : 0; + + mtk_vcodec_debug(inst, "+ [%d] FB y_dma=%llx c_dma=%llx fb=%p", + inst->frm_cnt, y_fb_dma, c_fb_dma, fb); + + inst->cur_fb = fb; + dec->bs_dma = (unsigned long)bs->dma_addr; + dec->bs_sz = bs->size; + dec->cur_y_fb_dma = y_fb_dma; + dec->cur_c_fb_dma = c_fb_dma; + + mtk_vcodec_debug(inst, "\n + FRAME[%d] +\n", inst->frm_cnt); + + write_hw_segmentation_data(inst); + enable_hw_rw_function(inst); + store_dec_table(inst); + + bs_va = (unsigned char *)bs->va; + + /* retrieve width/hight and scale info from header */ + data = (*(bs_va + 9) << 24) | (*(bs_va + 8) << 16) | + (*(bs_va + 7) << 8) | *(bs_va + 6); + err = vpu_dec_start(vpu, &data, 1); + if (err) { + add_fb_to_free_list(inst, fb); + if (dec->wait_key_frame) { + mtk_vcodec_debug(inst, "wait key frame !"); + return 0; + } + + goto error; + } + + if (dec->resolution_changed) { + mtk_vcodec_debug(inst, "- resolution_changed -"); + *res_chg = true; + add_fb_to_free_list(inst, fb); + return 0; + } + + /* wait decoder done interrupt */ + mtk_vcodec_wait_for_done_ctx(inst->ctx, MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS); + + if (inst->vsi->load_data) + load_dec_table(inst); + + vp8_dec_finish(inst); + read_hw_segmentation_data(inst); + + err = vpu_dec_end(vpu); + if (err) + goto error; + + mtk_vcodec_debug(inst, "\n - FRAME[%d] - show=%d\n", inst->frm_cnt, + dec->show_frame); + inst->frm_cnt++; + *res_chg = false; + return 0; + +error: + mtk_vcodec_err(inst, "\n - FRAME[%d] - err=%d\n", inst->frm_cnt, err); + return err; +} + +static void get_disp_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb) +{ + struct vdec_fb_node *node; + struct vdec_fb *fb; + + node = list_first_entry_or_null(&inst->fb_disp_list, + struct vdec_fb_node, list); + if (node) { + list_move_tail(&node->list, &inst->available_fb_node_list); + fb = (struct vdec_fb *)node->fb; + fb->status |= FB_ST_DISPLAY; + mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d", + node->fb, fb->status); + } else { + fb = NULL; + mtk_vcodec_debug(inst, "[FB] there is no disp fb"); + } + + *out_fb = fb; +} + +static void get_free_fb(struct vdec_vp8_inst *inst, struct vdec_fb **out_fb) +{ + struct vdec_fb_node *node; + struct vdec_fb *fb; + + node = list_first_entry_or_null(&inst->fb_free_list, + struct vdec_fb_node, list); + if (node) { + list_move_tail(&node->list, &inst->available_fb_node_list); + fb = (struct vdec_fb *)node->fb; + fb->status |= FB_ST_FREE; + mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d", + node->fb, fb->status); + } else { + fb = NULL; + mtk_vcodec_debug(inst, "[FB] there is no free fb"); + } + + *out_fb = fb; +} + +static void get_crop_info(struct vdec_vp8_inst *inst, struct v4l2_rect *cr) +{ + cr->left = 0; + cr->top = 0; + cr->width = inst->vsi->pic.pic_w; + cr->height = inst->vsi->pic.pic_h; + mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d", + cr->left, cr->top, cr->width, cr->height); +} + +static int vdec_vp8_get_param(unsigned long h_vdec, + enum vdec_get_param_type type, void *out) +{ + struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; + + switch (type) { + case GET_PARAM_DISP_FRAME_BUFFER: + get_disp_fb(inst, out); + break; + + case GET_PARAM_FREE_FRAME_BUFFER: + get_free_fb(inst, out); + break; + + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + + case GET_PARAM_DPB_SIZE: + *((unsigned int *)out) = VP8_DPB_SIZE; + break; + + default: + mtk_vcodec_err(inst, "invalid get parameter type=%d", type); + return -EINVAL; + } + + return 0; +} + +static void vdec_vp8_deinit(unsigned long h_vdec) +{ + struct vdec_vp8_inst *inst = (struct vdec_vp8_inst *)h_vdec; + + mtk_vcodec_debug_enter(inst); + + vpu_dec_deinit(&inst->vpu); + free_working_buf(inst); + kfree(inst); +} + +static struct vdec_common_if vdec_vp8_if = { + vdec_vp8_init, + vdec_vp8_decode, + vdec_vp8_get_param, + vdec_vp8_deinit, +}; + +struct vdec_common_if *get_vp8_dec_comm_if(void); + +struct vdec_common_if *get_vp8_dec_comm_if(void) +{ + return &vdec_vp8_if; +} diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index e03f126eb51f..25c7cb96b716 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -24,6 +24,7 @@ #include "mtk_vpu.h" const struct vdec_common_if *get_h264_dec_comm_if(void); +const struct vdec_common_if *get_vp8_dec_comm_if(void); int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { @@ -34,6 +35,7 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) ctx->dec_if = get_h264_dec_comm_if(); break; case V4L2_PIX_FMT_VP8: + ctx->dec_if = get_vp8_dec_comm_if(); break; default: return -EINVAL; -- cgit v1.2.3 From fa14a56475ff3690efcda3b6b90f3502db0aa10b Mon Sep 17 00:00:00 2001 From: Wu-Cheng Li Date: Fri, 2 Sep 2016 09:19:58 -0300 Subject: [media] v4l2-ioctl: add VP9 format description VP9 is a video coding format and a successor to VP8. Signed-off-by: Wu-Cheng Li Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 26fe7aef1196..a4b5d360fc96 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1230,6 +1230,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_VC1_ANNEX_G: descr = "VC-1 (SMPTE 412M Annex G)"; break; case V4L2_PIX_FMT_VC1_ANNEX_L: descr = "VC-1 (SMPTE 412M Annex L)"; break; case V4L2_PIX_FMT_VP8: descr = "VP8"; break; + case V4L2_PIX_FMT_VP9: descr = "VP9"; break; case V4L2_PIX_FMT_CPIA1: descr = "GSPCA CPiA YUV"; break; case V4L2_PIX_FMT_WNVA: descr = "WNVA"; break; case V4L2_PIX_FMT_SN9C10X: descr = "GSPCA SN9C10X"; break; -- cgit v1.2.3 From f77e89854b3e1ce2ca647963bd5bf0320a54a357 Mon Sep 17 00:00:00 2001 From: Tiffany Lin Date: Fri, 2 Sep 2016 09:20:00 -0300 Subject: [media] vcodec: mediatek: Add Mediatek VP9 Video Decoder Driver Add vp9 decoder driver for MT8173 [mchehab@s-opensource.org: make checkpatch.pl happy] Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/Makefile | 1 + drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 10 + .../media/platform/mtk-vcodec/vdec/vdec_vp9_if.c | 967 +++++++++++++++++++++ drivers/media/platform/mtk-vcodec/vdec_drv_base.h | 1 + drivers/media/platform/mtk-vcodec/vdec_drv_if.c | 4 + 5 files changed, 983 insertions(+) create mode 100644 drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile index 7743c81346a8..852d9697ccfa 100644 --- a/drivers/media/platform/mtk-vcodec/Makefile +++ b/drivers/media/platform/mtk-vcodec/Makefile @@ -5,6 +5,7 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec-dec.o \ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \ vdec/vdec_vp8_if.o \ + vdec/vdec_vp9_if.o \ mtk_vcodec_dec_drv.o \ vdec_drv_if.o \ vdec_vpu_if.o \ diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 7f7464a570cb..5823bccfac3e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -43,6 +43,11 @@ static struct mtk_video_fmt mtk_video_formats[] = { .type = MTK_FMT_DEC, .num_planes = 1, }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .type = MTK_FMT_DEC, + .num_planes = 1, + }, }; static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { @@ -56,6 +61,11 @@ static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, }, + { + .fourcc = V4L2_PIX_FMT_VP9, + .stepwise = { MTK_VDEC_MIN_W, MTK_VDEC_MAX_W, 16, + MTK_VDEC_MIN_H, MTK_VDEC_MAX_H, 16 }, + }, }; #define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_vdec_framesizes) diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c new file mode 100644 index 000000000000..e91a3b425b0c --- /dev/null +++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c @@ -0,0 +1,967 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Daniel Hsiao + * Kai-Sean Yang + * Tiffany Lin + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include + +#include "../mtk_vcodec_intr.h" +#include "../vdec_drv_base.h" +#include "../vdec_vpu_if.h" + +#define VP9_SUPER_FRAME_BS_SZ 64 +#define MAX_VP9_DPB_SIZE 9 + +#define REFS_PER_FRAME 3 +#define MAX_NUM_REF_FRAMES 8 +#define VP9_MAX_FRM_BUF_NUM 9 +#define VP9_MAX_FRM_BUF_NODE_NUM (VP9_MAX_FRM_BUF_NUM * 2) + +/** + * struct vp9_dram_buf - contains buffer info for vpu + * @va : cpu address + * @pa : iova address + * @sz : buffer size + * @padding : for 64 bytes alignment + */ +struct vp9_dram_buf { + unsigned long va; + unsigned long pa; + unsigned int sz; + unsigned int padding; +}; + +/** + * struct vp9_fb_info - contains frame buffer info + * @fb : frmae buffer + * @reserved : reserved field used by vpu + */ +struct vp9_fb_info { + struct vdec_fb *fb; + unsigned int reserved[32]; +}; + +/** + * struct vp9_ref_cnt_buf - contains reference buffer information + * @buf : referenced frame buffer + * @ref_cnt : referenced frame buffer's reference count. + * When reference count=0, remove it from reference list + */ +struct vp9_ref_cnt_buf { + struct vp9_fb_info buf; + unsigned int ref_cnt; +}; + +/** + * struct vp9_fb_info - contains current frame's reference buffer information + * @buf : reference buffer + * @idx : reference buffer index to frm_bufs + * @reserved : reserved field used by vpu + */ +struct vp9_ref_buf { + struct vp9_fb_info *buf; + unsigned int idx; + unsigned int reserved[6]; +}; + +/** + * struct vp9_fb_info - contains frame buffer info + * @fb : super frame reference frame buffer + * @used : this reference frame info entry is used + * @padding : for 64 bytes size align + */ +struct vp9_sf_ref_fb { + struct vdec_fb fb; + int used; + int padding; +}; + +/* + * struct vdec_vp9_vsi - shared buffer between host and VPU firmware + * AP-W/R : AP is writer/reader on this item + * VPU-W/R: VPU is write/reader on this item + * @sf_bs_buf : super frame backup buffer (AP-W, VPU-R) + * @sf_ref_fb : record supoer frame reference buffer information + * (AP-R/W, VPU-R/W) + * @sf_next_ref_fb_idx : next available super frame (AP-W, VPU-R) + * @sf_frm_cnt : super frame count, filled by vpu (AP-R, VPU-W) + * @sf_frm_offset : super frame offset, filled by vpu (AP-R, VPU-W) + * @sf_frm_sz : super frame size, filled by vpu (AP-R, VPU-W) + * @sf_frm_idx : current super frame (AP-R, VPU-W) + * @sf_init : inform super frame info already parsed by vpu (AP-R, VPU-W) + * @fb : capture buffer (AP-W, VPU-R) + * @bs : bs buffer (AP-W, VPU-R) + * @cur_fb : current show capture buffer (AP-R/W, VPU-R/W) + * @pic_w : picture width (AP-R, VPU-W) + * @pic_h : picture height (AP-R, VPU-W) + * @buf_w : codec width (AP-R, VPU-W) + * @buf_h : coded height (AP-R, VPU-W) + * @buf_sz_y_bs : ufo compressed y plane size (AP-R, VPU-W) + * @buf_sz_c_bs : ufo compressed cbcr plane size (AP-R, VPU-W) + * @buf_len_sz_y : size used to store y plane ufo info (AP-R, VPU-W) + * @buf_len_sz_c : size used to store cbcr plane ufo info (AP-R, VPU-W) + + * @profile : profile sparsed from vpu (AP-R, VPU-W) + * @show_frame : display this frame or not (AP-R, VPU-W) + * @show_existing_frame : inform this frame is show existing frame + * (AP-R, VPU-W) + * @frm_to_show_idx : index to show frame (AP-R, VPU-W) + + * @refresh_frm_flags : indicate when frame need to refine reference count + * (AP-R, VPU-W) + * @resolution_changed : resolution change in this frame (AP-R, VPU-W) + + * @frm_bufs : maintain reference buffer info (AP-R/W, VPU-R/W) + * @ref_frm_map : maintain reference buffer map info (AP-R/W, VPU-R/W) + * @new_fb_idx : index to frm_bufs array (AP-R, VPU-W) + * @frm_num : decoded frame number, include sub-frame count (AP-R, VPU-W) + * @mv_buf : motion vector working buffer (AP-W, VPU-R) + * @frm_refs : maintain three reference buffer info (AP-R/W, VPU-R/W) + */ +struct vdec_vp9_vsi { + unsigned char sf_bs_buf[VP9_SUPER_FRAME_BS_SZ]; + struct vp9_sf_ref_fb sf_ref_fb[VP9_MAX_FRM_BUF_NUM-1]; + int sf_next_ref_fb_idx; + unsigned int sf_frm_cnt; + unsigned int sf_frm_offset[VP9_MAX_FRM_BUF_NUM-1]; + unsigned int sf_frm_sz[VP9_MAX_FRM_BUF_NUM-1]; + unsigned int sf_frm_idx; + unsigned int sf_init; + struct vdec_fb fb; + struct mtk_vcodec_mem bs; + struct vdec_fb cur_fb; + unsigned int pic_w; + unsigned int pic_h; + unsigned int buf_w; + unsigned int buf_h; + unsigned int buf_sz_y_bs; + unsigned int buf_sz_c_bs; + unsigned int buf_len_sz_y; + unsigned int buf_len_sz_c; + unsigned int profile; + unsigned int show_frame; + unsigned int show_existing_frame; + unsigned int frm_to_show_idx; + unsigned int refresh_frm_flags; + unsigned int resolution_changed; + + struct vp9_ref_cnt_buf frm_bufs[VP9_MAX_FRM_BUF_NUM]; + int ref_frm_map[MAX_NUM_REF_FRAMES]; + unsigned int new_fb_idx; + unsigned int frm_num; + struct vp9_dram_buf mv_buf; + + struct vp9_ref_buf frm_refs[REFS_PER_FRAME]; +}; + +/* + * struct vdec_vp9_inst - vp9 decode instance + * @mv_buf : working buffer for mv + * @dec_fb : vdec_fb node to link fb to different fb_xxx_list + * @available_fb_node_list : current available vdec_fb node + * @fb_use_list : current used or referenced vdec_fb + * @fb_free_list : current available to free vdec_fb + * @fb_disp_list : current available to display vdec_fb + * @cur_fb : current frame buffer + * @ctx : current decode context + * @vpu : vpu instance information + * @vsi : shared buffer between host and VPU firmware + * @total_frm_cnt : total frame count, it do not include sub-frames in super + * frame + * @mem : instance memory information + */ +struct vdec_vp9_inst { + struct mtk_vcodec_mem mv_buf; + + struct vdec_fb_node dec_fb[VP9_MAX_FRM_BUF_NODE_NUM]; + struct list_head available_fb_node_list; + struct list_head fb_use_list; + struct list_head fb_free_list; + struct list_head fb_disp_list; + struct vdec_fb *cur_fb; + struct mtk_vcodec_ctx *ctx; + struct vdec_vpu_inst vpu; + struct vdec_vp9_vsi *vsi; + unsigned int total_frm_cnt; + struct mtk_vcodec_mem mem; +}; + +static bool vp9_is_sf_ref_fb(struct vdec_vp9_inst *inst, struct vdec_fb *fb) +{ + int i; + struct vdec_vp9_vsi *vsi = inst->vsi; + + for (i = 0; i < ARRAY_SIZE(vsi->sf_ref_fb); i++) { + if (fb == &vsi->sf_ref_fb[i].fb) + return true; + } + return false; +} + +static struct vdec_fb *vp9_rm_from_fb_use_list(struct vdec_vp9_inst + *inst, void *addr) +{ + struct vdec_fb *fb = NULL; + struct vdec_fb_node *node; + + list_for_each_entry(node, &inst->fb_use_list, list) { + fb = (struct vdec_fb *)node->fb; + if (fb->base_y.va == addr) { + list_move_tail(&node->list, + &inst->available_fb_node_list); + break; + } + } + return fb; +} + +static void vp9_add_to_fb_free_list(struct vdec_vp9_inst *inst, + struct vdec_fb *fb) +{ + struct vdec_fb_node *node; + + if (fb) { + node = list_first_entry_or_null(&inst->available_fb_node_list, + struct vdec_fb_node, list); + + if (node) { + node->fb = fb; + list_move_tail(&node->list, &inst->fb_free_list); + } + } else { + mtk_vcodec_debug(inst, "No free fb node"); + } +} + +static void vp9_free_sf_ref_fb(struct vdec_fb *fb) +{ + struct vp9_sf_ref_fb *sf_ref_fb = + container_of(fb, struct vp9_sf_ref_fb, fb); + + sf_ref_fb->used = 0; +} + +static void vp9_ref_cnt_fb(struct vdec_vp9_inst *inst, int *idx, + int new_idx) +{ + struct vdec_vp9_vsi *vsi = inst->vsi; + int ref_idx = *idx; + + if (ref_idx >= 0 && vsi->frm_bufs[ref_idx].ref_cnt > 0) { + vsi->frm_bufs[ref_idx].ref_cnt--; + + if (vsi->frm_bufs[ref_idx].ref_cnt == 0) { + if (!vp9_is_sf_ref_fb(inst, + vsi->frm_bufs[ref_idx].buf.fb)) { + struct vdec_fb *fb; + + fb = vp9_rm_from_fb_use_list(inst, + vsi->frm_bufs[ref_idx].buf.fb->base_y.va); + vp9_add_to_fb_free_list(inst, fb); + } else + vp9_free_sf_ref_fb( + vsi->frm_bufs[ref_idx].buf.fb); + } + } + + *idx = new_idx; + vsi->frm_bufs[new_idx].ref_cnt++; +} + +static void vp9_free_all_sf_ref_fb(struct vdec_vp9_inst *inst) +{ + int i; + struct vdec_vp9_vsi *vsi = inst->vsi; + + for (i = 0; i < ARRAY_SIZE(vsi->sf_ref_fb); i++) { + if (vsi->sf_ref_fb[i].fb.base_y.va) { + mtk_vcodec_mem_free(inst->ctx, + &vsi->sf_ref_fb[i].fb.base_y); + mtk_vcodec_mem_free(inst->ctx, + &vsi->sf_ref_fb[i].fb.base_c); + vsi->sf_ref_fb[i].used = 0; + } + } +} + +/* For each sub-frame except the last one, the driver will dynamically + * allocate reference buffer by calling vp9_get_sf_ref_fb() + * The last sub-frame will use the original fb provided by the + * vp9_dec_decode() interface + */ +static int vp9_get_sf_ref_fb(struct vdec_vp9_inst *inst) +{ + int idx; + struct mtk_vcodec_mem *mem_basy_y; + struct mtk_vcodec_mem *mem_basy_c; + struct vdec_vp9_vsi *vsi = inst->vsi; + + for (idx = 0; + idx < ARRAY_SIZE(vsi->sf_ref_fb); + idx++) { + if (vsi->sf_ref_fb[idx].fb.base_y.va && + vsi->sf_ref_fb[idx].used == 0) { + return idx; + } + } + + for (idx = 0; + idx < ARRAY_SIZE(vsi->sf_ref_fb); + idx++) { + if (vsi->sf_ref_fb[idx].fb.base_y.va == NULL) + break; + } + + if (idx == ARRAY_SIZE(vsi->sf_ref_fb)) { + mtk_vcodec_err(inst, "List Full"); + return -1; + } + + mem_basy_y = &vsi->sf_ref_fb[idx].fb.base_y; + mem_basy_y->size = vsi->buf_sz_y_bs + + vsi->buf_len_sz_y; + + if (mtk_vcodec_mem_alloc(inst->ctx, mem_basy_y)) { + mtk_vcodec_err(inst, "Cannot allocate sf_ref_buf y_buf"); + return -1; + } + + mem_basy_c = &vsi->sf_ref_fb[idx].fb.base_c; + mem_basy_c->size = vsi->buf_sz_c_bs + + vsi->buf_len_sz_c; + + if (mtk_vcodec_mem_alloc(inst->ctx, mem_basy_c)) { + mtk_vcodec_err(inst, "Cannot allocate sf_ref_fb c_buf"); + return -1; + } + vsi->sf_ref_fb[idx].used = 0; + + return idx; +} + +static bool vp9_alloc_work_buf(struct vdec_vp9_inst *inst) +{ + struct vdec_vp9_vsi *vsi = inst->vsi; + int result; + struct mtk_vcodec_mem *mem; + + unsigned int max_pic_w; + unsigned int max_pic_h; + + + if (!(inst->ctx->dev->dec_capability & + VCODEC_CAPABILITY_4K_DISABLED)) { + max_pic_w = VCODEC_DEC_4K_CODED_WIDTH; + max_pic_h = VCODEC_DEC_4K_CODED_HEIGHT; + } else { + max_pic_w = MTK_VDEC_MAX_W; + max_pic_h = MTK_VDEC_MAX_H; + } + + if ((vsi->pic_w > max_pic_w) || + (vsi->pic_h > max_pic_h)) { + mtk_vcodec_err(inst, "Invalid w/h %d/%d", + vsi->pic_w, vsi->pic_h); + return false; + } + + mtk_vcodec_debug(inst, "BUF CHG(%d): w/h/sb_w/sb_h=%d/%d/%d/%d", + vsi->resolution_changed, + vsi->pic_w, + vsi->pic_h, + vsi->buf_w, + vsi->buf_h); + + mem = &inst->mv_buf; + + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + + mem->size = ((vsi->buf_w / 64) * + (vsi->buf_h / 64) + 2) * 36 * 16; + + result = mtk_vcodec_mem_alloc(inst->ctx, mem); + if (result) { + mem->size = 0; + mtk_vcodec_err(inst, "Cannot allocate mv_buf"); + return false; + } + /* Set the va again */ + vsi->mv_buf.va = (unsigned long)mem->va; + vsi->mv_buf.pa = (unsigned long)mem->dma_addr; + vsi->mv_buf.sz = (unsigned int)mem->size; + + vp9_free_all_sf_ref_fb(inst); + vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst); + + return true; +} + +static bool vp9_add_to_fb_disp_list(struct vdec_vp9_inst *inst, + struct vdec_fb *fb) +{ + struct vdec_fb_node *node; + + if (!fb) { + mtk_vcodec_err(inst, "fb == NULL"); + return false; + } + + node = list_first_entry_or_null(&inst->available_fb_node_list, + struct vdec_fb_node, list); + if (node) { + node->fb = fb; + list_move_tail(&node->list, &inst->fb_disp_list); + } else { + mtk_vcodec_err(inst, "No available fb node"); + return false; + } + + return true; +} + +/* If any buffer updating is signaled it should be done here. */ +static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst) +{ + struct vdec_vp9_vsi *vsi = inst->vsi; + struct vp9_fb_info *frm_to_show; + int ref_index = 0, mask; + + for (mask = vsi->refresh_frm_flags; mask; mask >>= 1) { + if (mask & 1) + vp9_ref_cnt_fb(inst, &vsi->ref_frm_map[ref_index], + vsi->new_fb_idx); + ++ref_index; + } + + frm_to_show = &vsi->frm_bufs[vsi->new_fb_idx].buf; + vsi->frm_bufs[vsi->new_fb_idx].ref_cnt--; + + if (frm_to_show->fb != inst->cur_fb) { + /* This frame is show exist frame and no decode output + * copy frame data from frm_to_show to current CAPTURE + * buffer + */ + if ((frm_to_show->fb != NULL) && + (inst->cur_fb->base_y.size >= + frm_to_show->fb->base_y.size)) { + memcpy((void *)inst->cur_fb->base_y.va, + (void *)frm_to_show->fb->base_y.va, + vsi->buf_w * + vsi->buf_h); + memcpy((void *)inst->cur_fb->base_c.va, + (void *)frm_to_show->fb->base_c.va, + vsi->buf_w * + vsi->buf_h / 2); + } else { + /* After resolution change case, current CAPTURE buffer + * may have less buffer size than frm_to_show buffer + * size + */ + if (frm_to_show->fb != NULL) + mtk_vcodec_err(inst, + "inst->cur_fb->base_y.size=%zu, frm_to_show->fb.base_y.size=%zu", + inst->cur_fb->base_y.size, + frm_to_show->fb->base_y.size); + } + if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) { + if (vsi->show_frame) + vp9_add_to_fb_disp_list(inst, inst->cur_fb); + } + } else { + if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) { + if (vsi->show_frame) + vp9_add_to_fb_disp_list(inst, frm_to_show->fb); + } + } + + /* when ref_cnt ==0, move this fb to fb_free_list. v4l2 driver will + * clean fb_free_list + */ + if (vsi->frm_bufs[vsi->new_fb_idx].ref_cnt == 0) { + if (!vp9_is_sf_ref_fb( + inst, vsi->frm_bufs[vsi->new_fb_idx].buf.fb)) { + struct vdec_fb *fb; + + fb = vp9_rm_from_fb_use_list(inst, + vsi->frm_bufs[vsi->new_fb_idx].buf.fb->base_y.va); + + vp9_add_to_fb_free_list(inst, fb); + } else { + vp9_free_sf_ref_fb( + vsi->frm_bufs[vsi->new_fb_idx].buf.fb); + } + } + + /* if this super frame and it is not last sub-frame, get next fb for + * sub-frame decode + */ + if (vsi->sf_frm_cnt > 0 && vsi->sf_frm_idx != vsi->sf_frm_cnt - 1) + vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst); +} + +static bool vp9_wait_dec_end(struct vdec_vp9_inst *inst) +{ + struct mtk_vcodec_ctx *ctx = inst->ctx; + + mtk_vcodec_wait_for_done_ctx(inst->ctx, + MTK_INST_IRQ_RECEIVED, + WAIT_INTR_TIMEOUT_MS); + + if (ctx->irq_status & MTK_VDEC_IRQ_STATUS_DEC_SUCCESS) + return true; + else + return false; +} + +static struct vdec_vp9_inst *vp9_alloc_inst(struct mtk_vcodec_ctx *ctx) +{ + int result; + struct mtk_vcodec_mem mem; + struct vdec_vp9_inst *inst; + + memset(&mem, 0, sizeof(mem)); + mem.size = sizeof(struct vdec_vp9_inst); + result = mtk_vcodec_mem_alloc(ctx, &mem); + if (result) + return NULL; + + inst = mem.va; + inst->mem = mem; + + return inst; +} + +static void vp9_free_inst(struct vdec_vp9_inst *inst) +{ + struct mtk_vcodec_mem mem; + + mem = inst->mem; + if (mem.va) + mtk_vcodec_mem_free(inst->ctx, &mem); +} + +static bool vp9_decode_end_proc(struct vdec_vp9_inst *inst) +{ + struct vdec_vp9_vsi *vsi = inst->vsi; + bool ret = false; + + if (!vsi->show_existing_frame) { + ret = vp9_wait_dec_end(inst); + if (!ret) { + mtk_vcodec_err(inst, "Decode failed, Decode Timeout @[%d]", + vsi->frm_num); + return false; + } + + if (vpu_dec_end(&inst->vpu)) { + mtk_vcodec_err(inst, "vp9_dec_vpu_end failed"); + return false; + } + mtk_vcodec_debug(inst, "Decode Ok @%d (%d/%d)", vsi->frm_num, + vsi->pic_w, vsi->pic_h); + } else { + mtk_vcodec_debug(inst, "Decode Ok @%d (show_existing_frame)", + vsi->frm_num); + } + + vp9_swap_frm_bufs(inst); + vsi->frm_num++; + return true; +} + +static bool vp9_is_last_sub_frm(struct vdec_vp9_inst *inst) +{ + struct vdec_vp9_vsi *vsi = inst->vsi; + + if (vsi->sf_frm_cnt <= 0 || vsi->sf_frm_idx == vsi->sf_frm_cnt) + return true; + + return false; +} + +static struct vdec_fb *vp9_rm_from_fb_disp_list(struct vdec_vp9_inst *inst) +{ + struct vdec_fb_node *node; + struct vdec_fb *fb = NULL; + + node = list_first_entry_or_null(&inst->fb_disp_list, + struct vdec_fb_node, list); + if (node) { + fb = (struct vdec_fb *)node->fb; + fb->status |= FB_ST_DISPLAY; + list_move_tail(&node->list, &inst->available_fb_node_list); + mtk_vcodec_debug(inst, "[FB] get disp fb %p st=%d", + node->fb, fb->status); + } else + mtk_vcodec_debug(inst, "[FB] there is no disp fb"); + + return fb; +} + +static bool vp9_add_to_fb_use_list(struct vdec_vp9_inst *inst, + struct vdec_fb *fb) +{ + struct vdec_fb_node *node; + + if (!fb) { + mtk_vcodec_debug(inst, "fb == NULL"); + return false; + } + + node = list_first_entry_or_null(&inst->available_fb_node_list, + struct vdec_fb_node, list); + if (node) { + node->fb = fb; + list_move_tail(&node->list, &inst->fb_use_list); + } else { + mtk_vcodec_err(inst, "No free fb node"); + return false; + } + return true; +} + +static void vp9_reset(struct vdec_vp9_inst *inst) +{ + struct vdec_fb_node *node, *tmp; + + list_for_each_entry_safe(node, tmp, &inst->fb_use_list, list) + list_move_tail(&node->list, &inst->fb_free_list); + + vp9_free_all_sf_ref_fb(inst); + inst->vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst); + + if (vpu_dec_reset(&inst->vpu)) + mtk_vcodec_err(inst, "vp9_dec_vpu_reset failed"); + + /* Set the va again, since vpu_dec_reset will clear mv_buf in vpu */ + inst->vsi->mv_buf.va = (unsigned long)inst->mv_buf.va; + inst->vsi->mv_buf.pa = (unsigned long)inst->mv_buf.dma_addr; + inst->vsi->mv_buf.sz = (unsigned long)inst->mv_buf.size; +} + +static void init_all_fb_lists(struct vdec_vp9_inst *inst) +{ + int i; + + INIT_LIST_HEAD(&inst->available_fb_node_list); + INIT_LIST_HEAD(&inst->fb_use_list); + INIT_LIST_HEAD(&inst->fb_free_list); + INIT_LIST_HEAD(&inst->fb_disp_list); + + for (i = 0; i < ARRAY_SIZE(inst->dec_fb); i++) { + INIT_LIST_HEAD(&inst->dec_fb[i].list); + inst->dec_fb[i].fb = NULL; + list_add_tail(&inst->dec_fb[i].list, + &inst->available_fb_node_list); + } +} + +static void get_pic_info(struct vdec_vp9_inst *inst, struct vdec_pic_info *pic) +{ + pic->y_bs_sz = inst->vsi->buf_sz_y_bs; + pic->c_bs_sz = inst->vsi->buf_sz_c_bs; + pic->y_len_sz = inst->vsi->buf_len_sz_y; + pic->c_len_sz = inst->vsi->buf_len_sz_c; + + pic->pic_w = inst->vsi->pic_w; + pic->pic_h = inst->vsi->pic_h; + pic->buf_w = inst->vsi->buf_w; + pic->buf_h = inst->vsi->buf_h; + + mtk_vcodec_debug(inst, "pic(%d, %d), buf(%d, %d)", + pic->pic_w, pic->pic_h, pic->buf_w, pic->buf_h); + mtk_vcodec_debug(inst, "Y(%d, %d), C(%d, %d)", pic->y_bs_sz, + pic->y_len_sz, pic->c_bs_sz, pic->c_len_sz); +} + +static void get_disp_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb) +{ + + *out_fb = vp9_rm_from_fb_disp_list(inst); + if (*out_fb) + (*out_fb)->status |= FB_ST_DISPLAY; +} + +static void get_free_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb) +{ + struct vdec_fb_node *node; + struct vdec_fb *fb = NULL; + + node = list_first_entry_or_null(&inst->fb_free_list, + struct vdec_fb_node, list); + if (node) { + list_move_tail(&node->list, &inst->available_fb_node_list); + fb = (struct vdec_fb *)node->fb; + fb->status |= FB_ST_FREE; + mtk_vcodec_debug(inst, "[FB] get free fb %p st=%d", + node->fb, fb->status); + } else { + mtk_vcodec_debug(inst, "[FB] there is no free fb"); + } + + *out_fb = fb; +} + +static void vdec_vp9_deinit(unsigned long h_vdec) +{ + struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; + struct mtk_vcodec_mem *mem; + int ret = 0; + + ret = vpu_dec_deinit(&inst->vpu); + if (ret) + mtk_vcodec_err(inst, "vpu_dec_deinit failed"); + + mem = &inst->mv_buf; + if (mem->va) + mtk_vcodec_mem_free(inst->ctx, mem); + + vp9_free_all_sf_ref_fb(inst); + vp9_free_inst(inst); +} + +static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx, unsigned long *h_vdec) +{ + struct vdec_vp9_inst *inst; + + inst = vp9_alloc_inst(ctx); + if (!inst) + return -ENOMEM; + + inst->total_frm_cnt = 0; + inst->ctx = ctx; + + inst->vpu.id = IPI_VDEC_VP9; + inst->vpu.dev = ctx->dev->vpu_plat_dev; + inst->vpu.ctx = ctx; + inst->vpu.handler = vpu_dec_ipi_handler; + + if (vpu_dec_init(&inst->vpu)) { + mtk_vcodec_err(inst, "vp9_dec_vpu_init failed"); + goto err_deinit_inst; + } + + inst->vsi = (struct vdec_vp9_vsi *)inst->vpu.vsi; + init_all_fb_lists(inst); + + (*h_vdec) = (unsigned long)inst; + return 0; + +err_deinit_inst: + vp9_free_inst(inst); + + return -EINVAL; +} + +static int vdec_vp9_decode(unsigned long h_vdec, struct mtk_vcodec_mem *bs, + struct vdec_fb *fb, bool *res_chg) +{ + int ret = 0; + struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; + struct vdec_vp9_vsi *vsi = inst->vsi; + u32 data[3]; + int i; + + *res_chg = false; + + if ((bs == NULL) && (fb == NULL)) { + mtk_vcodec_debug(inst, "[EOS]"); + vp9_reset(inst); + return ret; + } + + if (bs == NULL) { + mtk_vcodec_err(inst, "bs == NULL"); + return -EINVAL; + } + + mtk_vcodec_debug(inst, "Input BS Size = %zu", bs->size); + + while (1) { + struct vdec_fb *cur_fb = NULL; + + data[0] = *((unsigned int *)bs->va); + data[1] = *((unsigned int *)(bs->va + 4)); + data[2] = *((unsigned int *)(bs->va + 8)); + + vsi->bs = *bs; + + if (fb) + vsi->fb = *fb; + + if (!vsi->sf_init) { + unsigned int sf_bs_sz; + unsigned int sf_bs_off; + unsigned char *sf_bs_src; + unsigned char *sf_bs_dst; + + sf_bs_sz = bs->size > VP9_SUPER_FRAME_BS_SZ ? + VP9_SUPER_FRAME_BS_SZ : bs->size; + sf_bs_off = VP9_SUPER_FRAME_BS_SZ - sf_bs_sz; + sf_bs_src = bs->va + bs->size - sf_bs_sz; + sf_bs_dst = vsi->sf_bs_buf + sf_bs_off; + memcpy(sf_bs_dst, sf_bs_src, sf_bs_sz); + } else { + if ((vsi->sf_frm_cnt > 0) && + (vsi->sf_frm_idx < vsi->sf_frm_cnt)) { + unsigned int idx = vsi->sf_frm_idx; + + memcpy((void *)bs->va, + (void *)(bs->va + + vsi->sf_frm_offset[idx]), + vsi->sf_frm_sz[idx]); + } + } + ret = vpu_dec_start(&inst->vpu, data, 3); + if (ret) { + mtk_vcodec_err(inst, "vpu_dec_start failed"); + goto DECODE_ERROR; + } + + if (vsi->resolution_changed) { + if (!vp9_alloc_work_buf(inst)) { + ret = -EINVAL; + goto DECODE_ERROR; + } + } + + if (vsi->sf_frm_cnt > 0) { + cur_fb = &vsi->sf_ref_fb[vsi->sf_next_ref_fb_idx].fb; + + if (vsi->sf_frm_idx < vsi->sf_frm_cnt) + inst->cur_fb = cur_fb; + else + inst->cur_fb = fb; + } else { + inst->cur_fb = fb; + } + + vsi->frm_bufs[vsi->new_fb_idx].buf.fb = inst->cur_fb; + if (!vp9_is_sf_ref_fb(inst, inst->cur_fb)) + vp9_add_to_fb_use_list(inst, inst->cur_fb); + + mtk_vcodec_debug(inst, "[#pic %d]", vsi->frm_num); + + if (vsi->show_existing_frame) + mtk_vcodec_debug(inst, + "drv->new_fb_idx=%d, drv->frm_to_show_idx=%d", + vsi->new_fb_idx, vsi->frm_to_show_idx); + + if (vsi->show_existing_frame && (vsi->frm_to_show_idx < + VP9_MAX_FRM_BUF_NUM)) { + mtk_vcodec_err(inst, + "Skip Decode drv->new_fb_idx=%d, drv->frm_to_show_idx=%d", + vsi->new_fb_idx, vsi->frm_to_show_idx); + + vp9_ref_cnt_fb(inst, &vsi->new_fb_idx, + vsi->frm_to_show_idx); + ret = -EINVAL; + goto DECODE_ERROR; + } + + /* VPU assign the buffer pointer in its address space, + * reassign here + */ + for (i = 0; i < ARRAY_SIZE(vsi->frm_refs); i++) { + unsigned int idx = vsi->frm_refs[i].idx; + + vsi->frm_refs[i].buf = &vsi->frm_bufs[idx].buf; + } + + if (vsi->resolution_changed) { + *res_chg = true; + mtk_vcodec_debug(inst, "VDEC_ST_RESOLUTION_CHANGED"); + + ret = 0; + goto DECODE_ERROR; + } + + if (vp9_decode_end_proc(inst) != true) { + mtk_vcodec_err(inst, "vp9_decode_end_proc"); + ret = -EINVAL; + goto DECODE_ERROR; + } + + if (vp9_is_last_sub_frm(inst)) + break; + + } + inst->total_frm_cnt++; + +DECODE_ERROR: + if (ret < 0) + vp9_add_to_fb_free_list(inst, fb); + + return ret; +} + +static void get_crop_info(struct vdec_vp9_inst *inst, struct v4l2_rect *cr) +{ + cr->left = 0; + cr->top = 0; + cr->width = inst->vsi->pic_w; + cr->height = inst->vsi->pic_h; + mtk_vcodec_debug(inst, "get crop info l=%d, t=%d, w=%d, h=%d\n", + cr->left, cr->top, cr->width, cr->height); +} + +static int vdec_vp9_get_param(unsigned long h_vdec, + enum vdec_get_param_type type, void *out) +{ + struct vdec_vp9_inst *inst = (struct vdec_vp9_inst *)h_vdec; + int ret = 0; + + switch (type) { + case GET_PARAM_DISP_FRAME_BUFFER: + get_disp_fb(inst, out); + break; + case GET_PARAM_FREE_FRAME_BUFFER: + get_free_fb(inst, out); + break; + case GET_PARAM_PIC_INFO: + get_pic_info(inst, out); + break; + case GET_PARAM_DPB_SIZE: + *((unsigned int *)out) = MAX_VP9_DPB_SIZE; + break; + case GET_PARAM_CROP_INFO: + get_crop_info(inst, out); + break; + default: + mtk_vcodec_err(inst, "not supported param type %d", type); + ret = -EINVAL; + break; + } + + return ret; +} + +static struct vdec_common_if vdec_vp9_if = { + vdec_vp9_init, + vdec_vp9_decode, + vdec_vp9_get_param, + vdec_vp9_deinit, +}; + +struct vdec_common_if *get_vp9_dec_comm_if(void); + +struct vdec_common_if *get_vp9_dec_comm_if(void) +{ + return &vdec_vp9_if; +} diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h index ca022e3300d7..7e4c1a92bbd8 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h @@ -17,6 +17,7 @@ #include "mtk_vcodec_drv.h" +#include "vdec_drv_if.h" struct vdec_common_if { /** diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c index 25c7cb96b716..5ffc468dd910 100644 --- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c +++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c @@ -25,6 +25,7 @@ const struct vdec_common_if *get_h264_dec_comm_if(void); const struct vdec_common_if *get_vp8_dec_comm_if(void); +const struct vdec_common_if *get_vp9_dec_comm_if(void); int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) { @@ -37,6 +38,9 @@ int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc) case V4L2_PIX_FMT_VP8: ctx->dec_if = get_vp8_dec_comm_if(); break; + case V4L2_PIX_FMT_VP9: + ctx->dec_if = get_vp9_dec_comm_if(); + break; default: return -EINVAL; } -- cgit v1.2.3 From fa44d3b9e785327eef8182eae5ae7d463b9cbcba Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 6 Sep 2016 11:51:15 -0300 Subject: [media] vcodec: mediatek: fix odd_ptr_err.cocci warnings PTR_ERR should access the value just tested by IS_ERR Generated by: scripts/coccinelle/tests/odd_ptr_err.cocci CC: Tiffany Lin Signed-off-by: Julia Lawall Signed-off-by: Fengguang Wu Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c index 70aa99329ce5..d48287c727f4 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c @@ -255,7 +255,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev) } dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR((__force void *)dev->reg_base[i])) { - ret = PTR_ERR((__force void *)dev->reg_base); + ret = PTR_ERR((__force void *)dev->reg_base[i]); goto err_res; } mtk_v4l2_debug(2, "reg[%d] base=%p", i, dev->reg_base[i]); -- cgit v1.2.3 From 211eba9e791e6f6f4c5945b7fabc1dba150075e4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 7 Sep 2016 14:10:27 -0300 Subject: [media] VPU: mediatek: fix null pointer dereference on pdev pdev is being null checked, however, prior to that it is being dereferenced by platform_get_drvdata. Move the assignments of vpu and run to after the pdev null check to avoid a potential null pointer dereference. Signed-off-by: Colin Ian King Reviewed-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index 63510de0147c..c3643d929167 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -534,9 +534,9 @@ static int load_requested_vpu(struct mtk_vpu *vpu, int vpu_load_firmware(struct platform_device *pdev) { - struct mtk_vpu *vpu = platform_get_drvdata(pdev); + struct mtk_vpu *vpu; struct device *dev = &pdev->dev; - struct vpu_run *run = &vpu->run; + struct vpu_run *run; const struct firmware *vpu_fw = NULL; int ret; @@ -545,6 +545,9 @@ int vpu_load_firmware(struct platform_device *pdev) return -EINVAL; } + vpu = platform_get_drvdata(pdev); + run = &vpu->run; + mutex_lock(&vpu->vpu_mutex); if (vpu->fw_loaded) { mutex_unlock(&vpu->vpu_mutex); -- cgit v1.2.3 From d4de663458bd00a579742e966c2db0d86352358b Mon Sep 17 00:00:00 2001 From: Tiffany Lin Date: Fri, 9 Sep 2016 12:48:04 -0300 Subject: [media] v4l: add Mediatek compressed video block format Add V4L2_PIX_FMT_MT21C format used on MT8173 driver. It is compressed format and need MT8173 MDP driver to transfer to other standard format. Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 1 + include/uapi/linux/videodev2.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index a4b5d360fc96..39e19b4222be 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1249,6 +1249,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_JPGL: descr = "JPEG Lite"; break; case V4L2_PIX_FMT_SE401: descr = "GSPCA SE401"; break; case V4L2_PIX_FMT_S5C_UYVY_JPG: descr = "S5C73MX interleaved UYVY/JPEG"; break; + case V4L2_PIX_FMT_MT21C: descr = "Mediatek Compressed Format"; break; default: WARN(1, "Unknown pixelformat 0x%08x\n", fmt->pixelformat); if (fmt->description[0]) diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index ad206de8eada..2da477c04479 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -635,6 +635,7 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_Y8I v4l2_fourcc('Y', '8', 'I', ' ') /* Greyscale 8-bit L/R interleaved */ #define V4L2_PIX_FMT_Y12I v4l2_fourcc('Y', '1', '2', 'I') /* Greyscale 12-bit L/R interleaved */ #define V4L2_PIX_FMT_Z16 v4l2_fourcc('Z', '1', '6', ' ') /* Depth data 16-bit */ +#define V4L2_PIX_FMT_MT21C v4l2_fourcc('M', 'T', '2', '1') /* Mediatek compressed block mode */ /* SDR formats - used only for Software Defined Radio devices */ #define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */ -- cgit v1.2.3 From 86082512625cab8755970105098a4a8818e3f954 Mon Sep 17 00:00:00 2001 From: Tiffany Lin Date: Fri, 9 Sep 2016 12:48:06 -0300 Subject: [media] vcodec: mediatek: Add V4L2_PIX_FMT_MT21C support for v4l2 decoder Add V4L2_PIX_FMT_MT21C support Signed-off-by: Tiffany Lin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 5823bccfac3e..05209193ff7e 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -25,7 +25,7 @@ #include "mtk_vcodec_dec_pm.h" #define OUT_FMT_IDX 0 -#define CAP_FMT_IDX 0 +#define CAP_FMT_IDX 3 #define MTK_VDEC_MIN_W 64U #define MTK_VDEC_MIN_H 64U @@ -48,6 +48,11 @@ static struct mtk_video_fmt mtk_video_formats[] = { .type = MTK_FMT_DEC, .num_planes = 1, }, + { + .fourcc = V4L2_PIX_FMT_MT21C, + .type = MTK_FMT_FRAME, + .num_planes = 2, + }, }; static const struct mtk_codec_framesizes mtk_vdec_framesizes[] = { -- cgit v1.2.3 From 737ea6cfd2263127e6cb00e607135b1087468d60 Mon Sep 17 00:00:00 2001 From: Minghsiu Tsai Date: Thu, 8 Sep 2016 10:09:01 -0300 Subject: [media] VPU: mediatek: Add mdp support VPU driver add mdp support [mchehab@s-opensource.com: fix a merge conflict and make checkpatch happy] Signed-off-by: Minghsiu Tsai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.h b/drivers/media/platform/mtk-vpu/mtk_vpu.h index 69da501afffa..aec0268be3d0 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.h +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.h @@ -53,6 +53,8 @@ typedef void (*ipi_handler_t) (void *data, * handle H264 video encoder job, and vice versa. * @IPI_VENC_VP8: The interrupt fro vpu is to notify kernel to * handle VP8 video encoder job,, and vice versa. + * @IPI_MDP: The interrupt from vpu is to notify kernel to + * handle MDP (Media Data Path) job, and vice versa. * @IPI_MAX: The maximum IPI number */ @@ -63,6 +65,7 @@ enum ipi_id { IPI_VDEC_VP9, IPI_VENC_H264, IPI_VENC_VP8, + IPI_MDP, IPI_MAX, }; @@ -71,11 +74,13 @@ enum ipi_id { * * @VPU_RST_ENC: encoder reset id * @VPU_RST_DEC: decoder reset id + * @VPU_RST_MDP: MDP (Media Data Path) reset id * @VPU_RST_MAX: maximum reset id */ enum rst_id { VPU_RST_ENC, VPU_RST_DEC, + VPU_RST_MDP, VPU_RST_MAX, }; -- cgit v1.2.3 From c8eb2d7e8202fd9cb912f5d33cc34ede66dcb24a Mon Sep 17 00:00:00 2001 From: Minghsiu Tsai Date: Thu, 8 Sep 2016 10:09:03 -0300 Subject: [media] media: Add Mediatek MDP Driver Add MDP driver for MT8173 Signed-off-by: Minghsiu Tsai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 17 + drivers/media/platform/Makefile | 2 + drivers/media/platform/mtk-mdp/Makefile | 9 + drivers/media/platform/mtk-mdp/mtk_mdp_comp.c | 159 ++++ drivers/media/platform/mtk-mdp/mtk_mdp_comp.h | 72 ++ drivers/media/platform/mtk-mdp/mtk_mdp_core.c | 294 ++++++ drivers/media/platform/mtk-mdp/mtk_mdp_core.h | 260 +++++ drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h | 126 +++ drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 1270 +++++++++++++++++++++++++ drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h | 22 + drivers/media/platform/mtk-mdp/mtk_mdp_regs.c | 152 +++ drivers/media/platform/mtk-mdp/mtk_mdp_regs.h | 31 + drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c | 145 +++ drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h | 41 + 14 files changed, 2600 insertions(+) create mode 100644 drivers/media/platform/mtk-mdp/Makefile create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.c create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_comp.h create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.c create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_core.h create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.c create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_regs.h create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c create mode 100644 drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index ce4a96fccc43..8d00a3fdcf96 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -175,6 +175,23 @@ config VIDEO_MEDIATEK_VPU To compile this driver as a module, choose M here: the module will be called mtk-vpu. +config VIDEO_MEDIATEK_MDP + tristate "Mediatek MDP driver" + depends on MTK_IOMMU || COMPILE_TEST + depends on VIDEO_DEV && VIDEO_V4L2 + depends on ARCH_MEDIATEK || COMPILE_TEST + depends on HAS_DMA + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + select VIDEO_MEDIATEK_VPU + default n + ---help--- + It is a v4l2 driver and present in Mediatek MT8173 SoCs. + The driver supports for scaling and color space conversion. + + To compile this driver as a module, choose M here: the + module will be called mtk-mdp. + config VIDEO_MEDIATEK_VCODEC tristate "Mediatek Video Codec driver" depends on MTK_IOMMU || COMPILE_TEST diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index 40b18d12726e..f842933d17de 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -66,3 +66,5 @@ ccflags-y += -I$(srctree)/drivers/media/i2c obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/ + +obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/ diff --git a/drivers/media/platform/mtk-mdp/Makefile b/drivers/media/platform/mtk-mdp/Makefile new file mode 100644 index 000000000000..f8025699af99 --- /dev/null +++ b/drivers/media/platform/mtk-mdp/Makefile @@ -0,0 +1,9 @@ +mtk-mdp-y += mtk_mdp_core.o +mtk-mdp-y += mtk_mdp_comp.o +mtk-mdp-y += mtk_mdp_m2m.o +mtk-mdp-y += mtk_mdp_regs.o +mtk-mdp-y += mtk_mdp_vpu.o + +obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp.o + +ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c new file mode 100644 index 000000000000..aa8f9fd1f1a2 --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.c @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Ming Hsiu Tsai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + +#include "mtk_mdp_comp.h" + + +static const char * const mtk_mdp_comp_stem[MTK_MDP_COMP_TYPE_MAX] = { + "mdp_rdma", + "mdp_rsz", + "mdp_wdma", + "mdp_wrot", +}; + +struct mtk_mdp_comp_match { + enum mtk_mdp_comp_type type; + int alias_id; +}; + +static const struct mtk_mdp_comp_match mtk_mdp_matches[MTK_MDP_COMP_ID_MAX] = { + { MTK_MDP_RDMA, 0 }, + { MTK_MDP_RDMA, 1 }, + { MTK_MDP_RSZ, 0 }, + { MTK_MDP_RSZ, 1 }, + { MTK_MDP_RSZ, 2 }, + { MTK_MDP_WDMA, 0 }, + { MTK_MDP_WROT, 0 }, + { MTK_MDP_WROT, 1 }, +}; + +int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node, + enum mtk_mdp_comp_type comp_type) +{ + int id = of_alias_get_id(node, mtk_mdp_comp_stem[comp_type]); + int i; + + for (i = 0; i < ARRAY_SIZE(mtk_mdp_matches); i++) { + if (comp_type == mtk_mdp_matches[i].type && + id == mtk_mdp_matches[i].alias_id) + return i; + } + + dev_err(dev, "Failed to get id. type: %d, id: %d\n", comp_type, id); + + return -EINVAL; +} + +void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp) +{ + int i, err; + + if (comp->larb_dev) { + err = mtk_smi_larb_get(comp->larb_dev); + if (err) + dev_err(dev, + "failed to get larb, err %d. type:%d id:%d\n", + err, comp->type, comp->id); + } + + for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { + if (!comp->clk[i]) + continue; + err = clk_prepare_enable(comp->clk[i]); + if (err) + dev_err(dev, + "failed to enable clock, err %d. type:%d id:%d i:%d\n", + err, comp->type, comp->id, i); + } +} + +void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { + if (!comp->clk[i]) + continue; + clk_disable_unprepare(comp->clk[i]); + } + + if (comp->larb_dev) + mtk_smi_larb_put(comp->larb_dev); +} + +int mtk_mdp_comp_init(struct device *dev, struct device_node *node, + struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id) +{ + struct device_node *larb_node; + struct platform_device *larb_pdev; + int i; + + if (comp_id < 0 || comp_id >= MTK_MDP_COMP_ID_MAX) { + dev_err(dev, "Invalid comp_id %d\n", comp_id); + return -EINVAL; + } + + comp->dev_node = of_node_get(node); + comp->id = comp_id; + comp->type = mtk_mdp_matches[comp_id].type; + comp->regs = of_iomap(node, 0); + + for (i = 0; i < ARRAY_SIZE(comp->clk); i++) { + comp->clk[i] = of_clk_get(node, i); + + /* Only RDMA needs two clocks */ + if (comp->type != MTK_MDP_RDMA) + break; + } + + /* Only DMA capable components need the LARB property */ + comp->larb_dev = NULL; + if (comp->type != MTK_MDP_RDMA && + comp->type != MTK_MDP_WDMA && + comp->type != MTK_MDP_WROT) + return 0; + + larb_node = of_parse_phandle(node, "mediatek,larb", 0); + if (!larb_node) { + dev_err(dev, + "Missing mediadek,larb phandle in %s node\n", + node->full_name); + return -EINVAL; + } + + larb_pdev = of_find_device_by_node(larb_node); + if (!larb_pdev) { + dev_warn(dev, "Waiting for larb device %s\n", + larb_node->full_name); + of_node_put(larb_node); + return -EPROBE_DEFER; + } + of_node_put(larb_node); + + comp->larb_dev = &larb_pdev->dev; + + return 0; +} + +void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp) +{ + of_node_put(comp->dev_node); +} diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h new file mode 100644 index 000000000000..63b3983ef1a4 --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_comp.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Ming Hsiu Tsai + * + * 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 __MTK_MDP_COMP_H__ +#define __MTK_MDP_COMP_H__ + +/** + * enum mtk_mdp_comp_type - the MDP component + * @MTK_MDP_RDMA: Read DMA + * @MTK_MDP_RSZ: Riszer + * @MTK_MDP_WDMA: Write DMA + * @MTK_MDP_WROT: Write DMA with rotation + */ +enum mtk_mdp_comp_type { + MTK_MDP_RDMA, + MTK_MDP_RSZ, + MTK_MDP_WDMA, + MTK_MDP_WROT, + MTK_MDP_COMP_TYPE_MAX, +}; + +enum mtk_mdp_comp_id { + MTK_MDP_COMP_RDMA0, + MTK_MDP_COMP_RDMA1, + MTK_MDP_COMP_RSZ0, + MTK_MDP_COMP_RSZ1, + MTK_MDP_COMP_RSZ2, + MTK_MDP_COMP_WDMA, + MTK_MDP_COMP_WROT0, + MTK_MDP_COMP_WROT1, + MTK_MDP_COMP_ID_MAX, +}; + +/** + * struct mtk_mdp_comp - the MDP's function component data + * @dev_node: component device node + * @clk: clocks required for component + * @regs: Mapped address of component registers. + * @larb_dev: SMI device required for component + * @type: component type + * @id: component ID + */ +struct mtk_mdp_comp { + struct device_node *dev_node; + struct clk *clk[2]; + void __iomem *regs; + struct device *larb_dev; + enum mtk_mdp_comp_type type; + enum mtk_mdp_comp_id id; +}; + +int mtk_mdp_comp_init(struct device *dev, struct device_node *node, + struct mtk_mdp_comp *comp, enum mtk_mdp_comp_id comp_id); +void mtk_mdp_comp_deinit(struct device *dev, struct mtk_mdp_comp *comp); +int mtk_mdp_comp_get_id(struct device *dev, struct device_node *node, + enum mtk_mdp_comp_type comp_type); +void mtk_mdp_comp_clock_on(struct device *dev, struct mtk_mdp_comp *comp); +void mtk_mdp_comp_clock_off(struct device *dev, struct mtk_mdp_comp *comp); + + +#endif /* __MTK_MDP_COMP_H__ */ diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c new file mode 100644 index 000000000000..7e35235d82e2 --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2015-2016 MediaTek Inc. + * Author: Houlong Wei + * Ming Hsiu Tsai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_mdp_core.h" +#include "mtk_mdp_m2m.h" +#include "mtk_vpu.h" + +/* MDP debug log level (0-3). 3 shows all the logs. */ +int mtk_mdp_dbg_level; +EXPORT_SYMBOL(mtk_mdp_dbg_level); + +module_param(mtk_mdp_dbg_level, int, 0644); + +static const struct of_device_id mtk_mdp_comp_dt_ids[] = { + { + .compatible = "mediatek,mt8173-mdp-rdma", + .data = (void *)MTK_MDP_RDMA + }, { + .compatible = "mediatek,mt8173-mdp-rsz", + .data = (void *)MTK_MDP_RSZ + }, { + .compatible = "mediatek,mt8173-mdp-wdma", + .data = (void *)MTK_MDP_WDMA + }, { + .compatible = "mediatek,mt8173-mdp-wrot", + .data = (void *)MTK_MDP_WROT + } +}; + +static const struct of_device_id mtk_mdp_of_ids[] = { + { .compatible = "mediatek,mt8173-mdp", }, + { }, +}; +MODULE_DEVICE_TABLE(of, mtk_mdp_of_ids); + +static void mtk_mdp_clock_on(struct mtk_mdp_dev *mdp) +{ + struct device *dev = &mdp->pdev->dev; + int i; + + for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) + mtk_mdp_comp_clock_on(dev, mdp->comp[i]); +} + +static void mtk_mdp_clock_off(struct mtk_mdp_dev *mdp) +{ + struct device *dev = &mdp->pdev->dev; + int i; + + for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) + mtk_mdp_comp_clock_off(dev, mdp->comp[i]); +} + +static void mtk_mdp_wdt_worker(struct work_struct *work) +{ + struct mtk_mdp_dev *mdp = + container_of(work, struct mtk_mdp_dev, wdt_work); + struct mtk_mdp_ctx *ctx; + + mtk_mdp_err("Watchdog timeout"); + + list_for_each_entry(ctx, &mdp->ctx_list, list) { + mtk_mdp_dbg(0, "[%d] Change as state error", ctx->id); + mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_CTX_ERROR); + } +} + +static void mtk_mdp_reset_handler(void *priv) +{ + struct mtk_mdp_dev *mdp = priv; + + queue_work(mdp->wdt_wq, &mdp->wdt_work); +} + +static int mtk_mdp_probe(struct platform_device *pdev) +{ + struct mtk_mdp_dev *mdp; + struct device *dev = &pdev->dev; + struct device_node *node; + int i, ret = 0; + + mdp = devm_kzalloc(dev, sizeof(*mdp), GFP_KERNEL); + if (!mdp) + return -ENOMEM; + + mdp->id = pdev->id; + mdp->pdev = pdev; + INIT_LIST_HEAD(&mdp->ctx_list); + + mutex_init(&mdp->lock); + mutex_init(&mdp->vpulock); + + /* Iterate over sibling MDP function blocks */ + for_each_child_of_node(dev->of_node, node) { + const struct of_device_id *of_id; + enum mtk_mdp_comp_type comp_type; + int comp_id; + struct mtk_mdp_comp *comp; + + of_id = of_match_node(mtk_mdp_comp_dt_ids, node); + if (!of_id) + continue; + + if (!of_device_is_available(node)) { + dev_err(dev, "Skipping disabled component %s\n", + node->full_name); + continue; + } + + comp_type = (enum mtk_mdp_comp_type)of_id->data; + comp_id = mtk_mdp_comp_get_id(dev, node, comp_type); + if (comp_id < 0) { + dev_warn(dev, "Skipping unknown component %s\n", + node->full_name); + continue; + } + + comp = devm_kzalloc(dev, sizeof(*comp), GFP_KERNEL); + if (!comp) { + ret = -ENOMEM; + goto err_comp; + } + mdp->comp[comp_id] = comp; + + ret = mtk_mdp_comp_init(dev, node, comp, comp_id); + if (ret) + goto err_comp; + } + + mdp->job_wq = create_singlethread_workqueue(MTK_MDP_MODULE_NAME); + if (!mdp->job_wq) { + dev_err(&pdev->dev, "unable to alloc job workqueue\n"); + ret = -ENOMEM; + goto err_alloc_job_wq; + } + + mdp->wdt_wq = create_singlethread_workqueue("mdp_wdt_wq"); + if (!mdp->wdt_wq) { + dev_err(&pdev->dev, "unable to alloc wdt workqueue\n"); + ret = -ENOMEM; + goto err_alloc_wdt_wq; + } + INIT_WORK(&mdp->wdt_work, mtk_mdp_wdt_worker); + + ret = v4l2_device_register(dev, &mdp->v4l2_dev); + if (ret) { + dev_err(&pdev->dev, "Failed to register v4l2 device\n"); + ret = -EINVAL; + goto err_dev_register; + } + + ret = mtk_mdp_register_m2m_device(mdp); + if (ret) { + v4l2_err(&mdp->v4l2_dev, "Failed to init mem2mem device\n"); + goto err_m2m_register; + } + + mdp->vpu_dev = vpu_get_plat_device(pdev); + vpu_wdt_reg_handler(mdp->vpu_dev, mtk_mdp_reset_handler, mdp, + VPU_RST_MDP); + + platform_set_drvdata(pdev, mdp); + + vb2_dma_contig_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32)); + + pm_runtime_enable(dev); + dev_dbg(dev, "mdp-%d registered successfully\n", mdp->id); + + return 0; + +err_m2m_register: + v4l2_device_unregister(&mdp->v4l2_dev); + +err_dev_register: + destroy_workqueue(mdp->wdt_wq); + +err_alloc_wdt_wq: + destroy_workqueue(mdp->job_wq); + +err_alloc_job_wq: + +err_comp: + for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) + mtk_mdp_comp_deinit(dev, mdp->comp[i]); + + dev_dbg(dev, "err %d\n", ret); + return ret; +} + +static int mtk_mdp_remove(struct platform_device *pdev) +{ + struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev); + int i; + + pm_runtime_disable(&pdev->dev); + vb2_dma_contig_clear_max_seg_size(&pdev->dev); + mtk_mdp_unregister_m2m_device(mdp); + v4l2_device_unregister(&mdp->v4l2_dev); + + flush_workqueue(mdp->job_wq); + destroy_workqueue(mdp->job_wq); + + for (i = 0; i < ARRAY_SIZE(mdp->comp); i++) + mtk_mdp_comp_deinit(&pdev->dev, mdp->comp[i]); + + dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); + return 0; +} + +#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP) +static int mtk_mdp_pm_suspend(struct device *dev) +{ + struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); + + mtk_mdp_clock_off(mdp); + + return 0; +} + +static int mtk_mdp_pm_resume(struct device *dev) +{ + struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); + + mtk_mdp_clock_on(mdp); + + return 0; +} +#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */ + +#ifdef CONFIG_PM_SLEEP +static int mtk_mdp_suspend(struct device *dev) +{ + if (pm_runtime_suspended(dev)) + return 0; + + return mtk_mdp_pm_suspend(dev); +} + +static int mtk_mdp_resume(struct device *dev) +{ + if (pm_runtime_suspended(dev)) + return 0; + + return mtk_mdp_pm_resume(dev); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops mtk_mdp_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume) + SET_RUNTIME_PM_OPS(mtk_mdp_pm_suspend, mtk_mdp_pm_resume, NULL) +}; + +static struct platform_driver mtk_mdp_driver = { + .probe = mtk_mdp_probe, + .remove = mtk_mdp_remove, + .driver = { + .name = MTK_MDP_MODULE_NAME, + .owner = THIS_MODULE, + .pm = &mtk_mdp_pm_ops, + .of_match_table = mtk_mdp_of_ids, + } +}; + +module_platform_driver(mtk_mdp_driver); + +MODULE_AUTHOR("Houlong Wei "); +MODULE_DESCRIPTION("Mediatek image processor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h new file mode 100644 index 000000000000..2e979f97d1df --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2015-2016 MediaTek Inc. + * Author: Houlong Wei + * Ming Hsiu Tsai + * + * 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 __MTK_MDP_CORE_H__ +#define __MTK_MDP_CORE_H__ + +#include +#include +#include +#include +#include +#include + +#include "mtk_mdp_vpu.h" +#include "mtk_mdp_comp.h" + + +#define MTK_MDP_MODULE_NAME "mtk-mdp" + +#define MTK_MDP_SHUTDOWN_TIMEOUT ((100*HZ)/1000) /* 100ms */ +#define MTK_MDP_MAX_CTRL_NUM 10 + +#define MTK_MDP_FMT_FLAG_OUTPUT BIT(0) +#define MTK_MDP_FMT_FLAG_CAPTURE BIT(1) + +#define MTK_MDP_VPU_INIT BIT(0) +#define MTK_MDP_SRC_FMT BIT(1) +#define MTK_MDP_DST_FMT BIT(2) +#define MTK_MDP_CTX_ERROR BIT(5) + +/** + * struct mtk_mdp_pix_align - alignement of image + * @org_w: source alignment of width + * @org_h: source alignment of height + * @target_w: dst alignment of width + * @target_h: dst alignment of height + */ +struct mtk_mdp_pix_align { + u16 org_w; + u16 org_h; + u16 target_w; + u16 target_h; +}; + +/** + * struct mtk_mdp_fmt - the driver's internal color format data + * @pixelformat: the fourcc code for this format, 0 if not applicable + * @num_planes: number of physically non-contiguous data planes + * @num_comp: number of logical data planes + * @depth: per plane driver's private 'number of bits per pixel' + * @row_depth: per plane driver's private 'number of bits per pixel per row' + * @flags: flags indicating which operation mode format applies to + MTK_MDP_FMT_FLAG_OUTPUT is used in OUTPUT stream + MTK_MDP_FMT_FLAG_CAPTURE is used in CAPTURE stream + * @align: pointer to a pixel alignment struct, NULL if using default value + */ +struct mtk_mdp_fmt { + u32 pixelformat; + u16 num_planes; + u16 num_comp; + u8 depth[VIDEO_MAX_PLANES]; + u8 row_depth[VIDEO_MAX_PLANES]; + u32 flags; + struct mtk_mdp_pix_align *align; +}; + +/** + * struct mtk_mdp_addr - the image processor physical address set + * @addr: address of planes + */ +struct mtk_mdp_addr { + dma_addr_t addr[MTK_MDP_MAX_NUM_PLANE]; +}; + +/* struct mtk_mdp_ctrls - the image processor control set + * @rotate: rotation degree + * @hflip: horizontal flip + * @vflip: vertical flip + * @global_alpha: the alpha value of current frame + */ +struct mtk_mdp_ctrls { + struct v4l2_ctrl *rotate; + struct v4l2_ctrl *hflip; + struct v4l2_ctrl *vflip; + struct v4l2_ctrl *global_alpha; +}; + +/** + * struct mtk_mdp_frame - source/target frame properties + * @width: SRC : SRCIMG_WIDTH, DST : OUTPUTDMA_WHOLE_IMG_WIDTH + * @height: SRC : SRCIMG_HEIGHT, DST : OUTPUTDMA_WHOLE_IMG_HEIGHT + * @crop: cropped(source)/scaled(destination) size + * @payload: image size in bytes (w x h x bpp) + * @pitch: bytes per line of image in memory + * @addr: image frame buffer physical addresses + * @fmt: color format pointer + * @alpha: frame's alpha value + */ +struct mtk_mdp_frame { + u32 width; + u32 height; + struct v4l2_rect crop; + unsigned long payload[VIDEO_MAX_PLANES]; + unsigned int pitch[VIDEO_MAX_PLANES]; + struct mtk_mdp_addr addr; + const struct mtk_mdp_fmt *fmt; + u8 alpha; +}; + +/** + * struct mtk_mdp_variant - image processor variant information + * @pix_max: maximum limit of image size + * @pix_min: minimun limit of image size + * @pix_align: alignement of image + * @h_scale_up_max: maximum scale-up in horizontal + * @v_scale_up_max: maximum scale-up in vertical + * @h_scale_down_max: maximum scale-down in horizontal + * @v_scale_down_max: maximum scale-down in vertical + */ +struct mtk_mdp_variant { + struct mtk_mdp_pix_limit *pix_max; + struct mtk_mdp_pix_limit *pix_min; + struct mtk_mdp_pix_align *pix_align; + u16 h_scale_up_max; + u16 v_scale_up_max; + u16 h_scale_down_max; + u16 v_scale_down_max; +}; + +/** + * struct mtk_mdp_dev - abstraction for image processor entity + * @lock: the mutex protecting this data structure + * @vpulock: the mutex protecting the communication with VPU + * @pdev: pointer to the image processor platform device + * @variant: the IP variant information + * @id: image processor device index (0..MTK_MDP_MAX_DEVS) + * @comp: MDP function components + * @m2m_dev: v4l2 memory-to-memory device data + * @ctx_list: list of struct mtk_mdp_ctx + * @vdev: video device for image processor driver + * @v4l2_dev: V4L2 device to register video devices for. + * @job_wq: processor work queue + * @vpu_dev: VPU platform device + * @ctx_num: counter of active MTK MDP context + * @id_counter: An integer id given to the next opened context + * @wdt_wq: work queue for VPU watchdog + * @wdt_work: worker for VPU watchdog + */ +struct mtk_mdp_dev { + struct mutex lock; + struct mutex vpulock; + struct platform_device *pdev; + struct mtk_mdp_variant *variant; + u16 id; + struct mtk_mdp_comp *comp[MTK_MDP_COMP_ID_MAX]; + struct v4l2_m2m_dev *m2m_dev; + struct list_head ctx_list; + struct video_device vdev; + struct v4l2_device v4l2_dev; + struct workqueue_struct *job_wq; + struct platform_device *vpu_dev; + int ctx_num; + unsigned long id_counter; + struct workqueue_struct *wdt_wq; + struct work_struct wdt_work; +}; + +/** + * mtk_mdp_ctx - the device context data + * @list: link to ctx_list of mtk_mdp_dev + * @s_frame: source frame properties + * @d_frame: destination frame properties + * @id: index of the context that this structure describes + * @flags: additional flags for image conversion + * @state: flags to keep track of user configuration + Protected by slock + * @rotation: rotates the image by specified angle + * @hflip: mirror the picture horizontally + * @vflip: mirror the picture vertically + * @mdp_dev: the image processor device this context applies to + * @m2m_ctx: memory-to-memory device context + * @fh: v4l2 file handle + * @ctrl_handler: v4l2 controls handler + * @ctrls image processor control set + * @ctrls_rdy: true if the control handler is initialized + * @colorspace: enum v4l2_colorspace; supplemental to pixelformat + * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding + * @xfer_func: enum v4l2_xfer_func, colorspace transfer function + * @quant: enum v4l2_quantization, colorspace quantization + * @vpu: VPU instance + * @slock: the mutex protecting mtp_mdp_ctx.state + * @work: worker for image processing + */ +struct mtk_mdp_ctx { + struct list_head list; + struct mtk_mdp_frame s_frame; + struct mtk_mdp_frame d_frame; + u32 flags; + u32 state; + int id; + int rotation; + u32 hflip:1; + u32 vflip:1; + struct mtk_mdp_dev *mdp_dev; + struct v4l2_m2m_ctx *m2m_ctx; + struct v4l2_fh fh; + struct v4l2_ctrl_handler ctrl_handler; + struct mtk_mdp_ctrls ctrls; + bool ctrls_rdy; + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_xfer_func xfer_func; + enum v4l2_quantization quant; + + struct mtk_mdp_vpu vpu; + struct mutex slock; + struct work_struct work; +}; + +extern int mtk_mdp_dbg_level; + +#if defined(DEBUG) + +#define mtk_mdp_dbg(level, fmt, args...) \ + do { \ + if (mtk_mdp_dbg_level >= level) \ + pr_info("[MTK_MDP] level=%d %s(),%d: " fmt "\n", \ + level, __func__, __LINE__, ##args); \ + } while (0) + +#define mtk_mdp_err(fmt, args...) \ + pr_err("[MTK_MDP][ERROR] %s:%d: " fmt "\n", __func__, __LINE__, \ + ##args) + + +#define mtk_mdp_dbg_enter() mtk_mdp_dbg(3, "+") +#define mtk_mdp_dbg_leave() mtk_mdp_dbg(3, "-") + +#else + +#define mtk_mdp_dbg(level, fmt, args...) +#define mtk_mdp_err(fmt, args...) +#define mtk_mdp_dbg_enter() +#define mtk_mdp_dbg_leave() + +#endif + +#endif /* __MTK_MDP_CORE_H__ */ diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h new file mode 100644 index 000000000000..78e2cc0dead1 --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_ipi.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2015-2016 MediaTek Inc. + * Author: Houlong Wei + * Ming Hsiu Tsai + * + * 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 __MTK_MDP_IPI_H__ +#define __MTK_MDP_IPI_H__ + +#define MTK_MDP_MAX_NUM_PLANE 3 + +enum mdp_ipi_msgid { + AP_MDP_INIT = 0xd000, + AP_MDP_DEINIT = 0xd001, + AP_MDP_PROCESS = 0xd002, + + VPU_MDP_INIT_ACK = 0xe000, + VPU_MDP_DEINIT_ACK = 0xe001, + VPU_MDP_PROCESS_ACK = 0xe002 +}; + +#pragma pack(push, 4) + +/** + * struct mdp_ipi_init - for AP_MDP_INIT + * @msg_id : AP_MDP_INIT + * @ipi_id : IPI_MDP + * @ap_inst : AP mtk_mdp_vpu address + */ +struct mdp_ipi_init { + uint32_t msg_id; + uint32_t ipi_id; + uint64_t ap_inst; +}; + +/** + * struct mdp_ipi_comm - for AP_MDP_PROCESS, AP_MDP_DEINIT + * @msg_id : AP_MDP_PROCESS, AP_MDP_DEINIT + * @ipi_id : IPI_MDP + * @ap_inst : AP mtk_mdp_vpu address + * @vpu_inst_addr : VPU MDP instance address + */ +struct mdp_ipi_comm { + uint32_t msg_id; + uint32_t ipi_id; + uint64_t ap_inst; + uint32_t vpu_inst_addr; +}; + +/** + * struct mdp_ipi_comm_ack - for VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK + * @msg_id : VPU_MDP_DEINIT_ACK, VPU_MDP_PROCESS_ACK + * @ipi_id : IPI_MDP + * @ap_inst : AP mtk_mdp_vpu address + * @vpu_inst_addr : VPU MDP instance address + * @status : VPU exeuction result + */ +struct mdp_ipi_comm_ack { + uint32_t msg_id; + uint32_t ipi_id; + uint64_t ap_inst; + uint32_t vpu_inst_addr; + int32_t status; +}; + +/** + * struct mdp_config - configured for source/destination image + * @x : left + * @y : top + * @w : width + * @h : height + * @w_stride : bytes in horizontal + * @h_stride : bytes in vertical + * @crop_x : cropped left + * @crop_y : cropped top + * @crop_w : cropped width + * @crop_h : cropped height + * @format : color format + */ +struct mdp_config { + int32_t x; + int32_t y; + int32_t w; + int32_t h; + int32_t w_stride; + int32_t h_stride; + int32_t crop_x; + int32_t crop_y; + int32_t crop_w; + int32_t crop_h; + int32_t format; +}; + +struct mdp_buffer { + uint64_t addr_mva[MTK_MDP_MAX_NUM_PLANE]; + int32_t plane_size[MTK_MDP_MAX_NUM_PLANE]; + int32_t plane_num; +}; + +struct mdp_config_misc { + int32_t orientation; /* 0, 90, 180, 270 */ + int32_t hflip; /* 1 will enable the flip */ + int32_t vflip; /* 1 will enable the flip */ + int32_t alpha; /* global alpha */ +}; + +struct mdp_process_vsi { + struct mdp_config src_config; + struct mdp_buffer src_buffer; + struct mdp_config dst_config; + struct mdp_buffer dst_buffer; + struct mdp_config_misc misc; +}; + +#pragma pack(pop) + +#endif /* __MTK_MDP_IPI_H__ */ diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c new file mode 100644 index 000000000000..065502757133 --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -0,0 +1,1270 @@ +/* + * Copyright (c) 2015-2016 MediaTek Inc. + * Author: Houlong Wei + * Ming Hsiu Tsai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_mdp_core.h" +#include "mtk_mdp_m2m.h" +#include "mtk_mdp_regs.h" +#include "mtk_vpu.h" + + +/** + * struct mtk_mdp_pix_limit - image pixel size limits + * @org_w: source pixel width + * @org_h: source pixel height + * @target_rot_dis_w: pixel dst scaled width with the rotator is off + * @target_rot_dis_h: pixel dst scaled height with the rotator is off + * @target_rot_en_w: pixel dst scaled width with the rotator is on + * @target_rot_en_h: pixel dst scaled height with the rotator is on + */ +struct mtk_mdp_pix_limit { + u16 org_w; + u16 org_h; + u16 target_rot_dis_w; + u16 target_rot_dis_h; + u16 target_rot_en_w; + u16 target_rot_en_h; +}; + +static struct mtk_mdp_pix_align mtk_mdp_size_align = { + .org_w = 16, + .org_h = 16, + .target_w = 2, + .target_h = 2, +}; + +static const struct mtk_mdp_fmt mtk_mdp_formats[] = { + { + .pixelformat = V4L2_PIX_FMT_NV12M, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .num_comp = 2, + .flags = MTK_MDP_FMT_FLAG_OUTPUT | + MTK_MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YUV420M, + .depth = { 8, 2, 2 }, + .row_depth = { 8, 4, 4 }, + .num_planes = 3, + .num_comp = 3, + .flags = MTK_MDP_FMT_FLAG_OUTPUT | + MTK_MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVU420, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .num_comp = 3, + .flags = MTK_MDP_FMT_FLAG_OUTPUT | + MTK_MDP_FMT_FLAG_CAPTURE, + } +}; + +static struct mtk_mdp_pix_limit mtk_mdp_size_max = { + .target_rot_dis_w = 4096, + .target_rot_dis_h = 4096, + .target_rot_en_w = 4096, + .target_rot_en_h = 4096, +}; + +static struct mtk_mdp_pix_limit mtk_mdp_size_min = { + .org_w = 16, + .org_h = 16, + .target_rot_dis_w = 16, + .target_rot_dis_h = 16, + .target_rot_en_w = 16, + .target_rot_en_h = 16, +}; + +/* align size for normal raster scan pixel format */ +static struct mtk_mdp_pix_align mtk_mdp_rs_align = { + .org_w = 2, + .org_h = 2, + .target_w = 2, + .target_h = 2, +}; + +static struct mtk_mdp_variant mtk_mdp_default_variant = { + .pix_max = &mtk_mdp_size_max, + .pix_min = &mtk_mdp_size_min, + .pix_align = &mtk_mdp_rs_align, + .h_scale_up_max = 32, + .v_scale_up_max = 32, + .h_scale_down_max = 32, + .v_scale_down_max = 128, +}; + +static const struct mtk_mdp_fmt *mtk_mdp_find_fmt(u32 pixelformat, u32 type) +{ + u32 i, flag; + + flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT : + MTK_MDP_FMT_FLAG_CAPTURE; + + for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) { + if (!(mtk_mdp_formats[i].flags & flag)) + continue; + if (mtk_mdp_formats[i].pixelformat == pixelformat) + return &mtk_mdp_formats[i]; + } + return NULL; +} + +static const struct mtk_mdp_fmt *mtk_mdp_find_fmt_by_index(u32 index, u32 type) +{ + u32 i, flag, num = 0; + + flag = V4L2_TYPE_IS_OUTPUT(type) ? MTK_MDP_FMT_FLAG_OUTPUT : + MTK_MDP_FMT_FLAG_CAPTURE; + + for (i = 0; i < ARRAY_SIZE(mtk_mdp_formats); ++i) { + if (!(mtk_mdp_formats[i].flags & flag)) + continue; + if (index == num) + return &mtk_mdp_formats[i]; + num++; + } + return NULL; +} + +static void mtk_mdp_bound_align_image(u32 *w, unsigned int wmin, + unsigned int wmax, unsigned int align_w, + u32 *h, unsigned int hmin, + unsigned int hmax, unsigned int align_h) +{ + int org_w, org_h, step_w, step_h; + int walign, halign; + + org_w = *w; + org_h = *h; + walign = ffs(align_w) - 1; + halign = ffs(align_h) - 1; + v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0); + + step_w = 1 << walign; + step_h = 1 << halign; + if (*w < org_w && (*w + step_w) <= wmax) + *w += step_w; + if (*h < org_h && (*h + step_h) <= hmax) + *h += step_h; +} + +static const struct mtk_mdp_fmt *mtk_mdp_try_fmt_mplane(struct mtk_mdp_ctx *ctx, + struct v4l2_format *f) +{ + struct mtk_mdp_dev *mdp = ctx->mdp_dev; + struct mtk_mdp_variant *variant = mdp->variant; + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; + const struct mtk_mdp_fmt *fmt; + u32 max_w, max_h, align_w, align_h; + u32 min_w, min_h, org_w, org_h; + int i; + + fmt = mtk_mdp_find_fmt(pix_mp->pixelformat, f->type); + if (!fmt) + fmt = mtk_mdp_find_fmt_by_index(0, f->type); + if (!fmt) { + dev_dbg(&ctx->mdp_dev->pdev->dev, + "pixelformat format 0x%X invalid\n", + pix_mp->pixelformat); + return NULL; + } + + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->pixelformat = fmt->pixelformat; + if (!V4L2_TYPE_IS_OUTPUT(f->type)) { + pix_mp->colorspace = ctx->colorspace; + pix_mp->xfer_func = ctx->xfer_func; + pix_mp->ycbcr_enc = ctx->ycbcr_enc; + pix_mp->quantization = ctx->quant; + } + memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); + + max_w = variant->pix_max->target_rot_dis_w; + max_h = variant->pix_max->target_rot_dis_h; + + if (fmt->align == NULL) { + /* use default alignment */ + align_w = variant->pix_align->org_w; + align_h = variant->pix_align->org_h; + } else { + align_w = fmt->align->org_w; + align_h = fmt->align->org_h; + } + + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + min_w = variant->pix_min->org_w; + min_h = variant->pix_min->org_h; + } else { + min_w = variant->pix_min->target_rot_dis_w; + min_h = variant->pix_min->target_rot_dis_h; + } + + mtk_mdp_dbg(2, "[%d] type:%d, wxh:%ux%u, align:%ux%u, max:%ux%u", + ctx->id, f->type, pix_mp->width, pix_mp->height, + align_w, align_h, max_w, max_h); + /* + * To check if image size is modified to adjust parameter against + * hardware abilities + */ + org_w = pix_mp->width; + org_h = pix_mp->height; + + mtk_mdp_bound_align_image(&pix_mp->width, min_w, max_w, align_w, + &pix_mp->height, min_h, max_h, align_h); + + if (org_w != pix_mp->width || org_h != pix_mp->height) + mtk_mdp_dbg(1, "[%d] size change:%ux%u to %ux%u", ctx->id, + org_w, org_h, pix_mp->width, pix_mp->height); + pix_mp->num_planes = fmt->num_planes; + + for (i = 0; i < pix_mp->num_planes; ++i) { + int bpl = (pix_mp->width * fmt->row_depth[i]) / 8; + int sizeimage = (pix_mp->width * pix_mp->height * + fmt->depth[i]) / 8; + + pix_mp->plane_fmt[i].bytesperline = bpl; + if (pix_mp->plane_fmt[i].sizeimage < sizeimage) + pix_mp->plane_fmt[i].sizeimage = sizeimage; + memset(pix_mp->plane_fmt[i].reserved, 0, + sizeof(pix_mp->plane_fmt[i].reserved)); + mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%u (%u)", ctx->id, + i, bpl, pix_mp->plane_fmt[i].sizeimage, sizeimage); + } + + return fmt; +} + +static struct mtk_mdp_frame *mtk_mdp_ctx_get_frame(struct mtk_mdp_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return &ctx->s_frame; + return &ctx->d_frame; +} + +static void mtk_mdp_check_crop_change(u32 new_w, u32 new_h, u32 *w, u32 *h) +{ + if (new_w != *w || new_h != *h) { + mtk_mdp_dbg(1, "size change:%dx%d to %dx%d", + *w, *h, new_w, new_h); + + *w = new_w; + *h = new_h; + } +} + +static int mtk_mdp_try_crop(struct mtk_mdp_ctx *ctx, u32 type, + struct v4l2_rect *r) +{ + struct mtk_mdp_frame *frame; + struct mtk_mdp_dev *mdp = ctx->mdp_dev; + struct mtk_mdp_variant *variant = mdp->variant; + u32 align_w, align_h, new_w, new_h; + u32 min_w, min_h, max_w, max_h; + + if (r->top < 0 || r->left < 0) { + dev_err(&ctx->mdp_dev->pdev->dev, + "doesn't support negative values for top & left\n"); + return -EINVAL; + } + + mtk_mdp_dbg(2, "[%d] type:%d, set wxh:%dx%d", ctx->id, type, + r->width, r->height); + + frame = mtk_mdp_ctx_get_frame(ctx, type); + max_w = frame->width; + max_h = frame->height; + new_w = r->width; + new_h = r->height; + + if (V4L2_TYPE_IS_OUTPUT(type)) { + align_w = 1; + align_h = 1; + min_w = 64; + min_h = 32; + } else { + align_w = variant->pix_align->target_w; + align_h = variant->pix_align->target_h; + if (ctx->ctrls.rotate->val == 90 || + ctx->ctrls.rotate->val == 270) { + max_w = frame->height; + max_h = frame->width; + min_w = variant->pix_min->target_rot_en_w; + min_h = variant->pix_min->target_rot_en_h; + new_w = r->height; + new_h = r->width; + } else { + min_w = variant->pix_min->target_rot_dis_w; + min_h = variant->pix_min->target_rot_dis_h; + } + } + + mtk_mdp_dbg(2, "[%d] align:%dx%d, min:%dx%d, new:%dx%d", ctx->id, + align_w, align_h, min_w, min_h, new_w, new_h); + + mtk_mdp_bound_align_image(&new_w, min_w, max_w, align_w, + &new_h, min_h, max_h, align_h); + + if (!V4L2_TYPE_IS_OUTPUT(type) && + (ctx->ctrls.rotate->val == 90 || + ctx->ctrls.rotate->val == 270)) + mtk_mdp_check_crop_change(new_h, new_w, + &r->width, &r->height); + else + mtk_mdp_check_crop_change(new_w, new_h, + &r->width, &r->height); + + /* adjust left/top if cropping rectangle is out of bounds */ + /* Need to add code to algin left value with 2's multiple */ + if (r->left + new_w > max_w) + r->left = max_w - new_w; + if (r->top + new_h > max_h) + r->top = max_h - new_h; + + if (r->left & 1) + r->left -= 1; + + mtk_mdp_dbg(2, "[%d] crop l,t,w,h:%d,%d,%d,%d, max:%dx%d", ctx->id, + r->left, r->top, r->width, + r->height, max_w, max_h); + return 0; +} + +static inline struct mtk_mdp_ctx *fh_to_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct mtk_mdp_ctx, fh); +} + +static inline struct mtk_mdp_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl) +{ + return container_of(ctrl->handler, struct mtk_mdp_ctx, ctrl_handler); +} + +void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state) +{ + mutex_lock(&ctx->slock); + ctx->state |= state; + mutex_unlock(&ctx->slock); +} + +static void mtk_mdp_ctx_state_lock_clear(struct mtk_mdp_ctx *ctx, u32 state) +{ + mutex_lock(&ctx->slock); + ctx->state &= ~state; + mutex_unlock(&ctx->slock); +} + +static bool mtk_mdp_ctx_state_is_set(struct mtk_mdp_ctx *ctx, u32 mask) +{ + bool ret; + + mutex_lock(&ctx->slock); + ret = (ctx->state & mask) == mask; + mutex_unlock(&ctx->slock); + return ret; +} + +static void mtk_mdp_ctx_lock(struct vb2_queue *vq) +{ + struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq); + + mutex_lock(&ctx->mdp_dev->lock); +} + +static void mtk_mdp_ctx_unlock(struct vb2_queue *vq) +{ + struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq); + + mutex_unlock(&ctx->mdp_dev->lock); +} + +static void mtk_mdp_set_frame_size(struct mtk_mdp_frame *frame, int width, + int height) +{ + frame->width = width; + frame->height = height; + frame->crop.width = width; + frame->crop.height = height; + frame->crop.left = 0; + frame->crop.top = 0; +} + +static int mtk_mdp_m2m_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct mtk_mdp_ctx *ctx = q->drv_priv; + int ret; + + ret = pm_runtime_get_sync(&ctx->mdp_dev->pdev->dev); + if (ret < 0) + mtk_mdp_dbg(1, "[%d] pm_runtime_get_sync failed:%d", + ctx->id, ret); + + return 0; +} + +static void *mtk_mdp_m2m_buf_remove(struct mtk_mdp_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + else + return v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); +} + +static void mtk_mdp_m2m_stop_streaming(struct vb2_queue *q) +{ + struct mtk_mdp_ctx *ctx = q->drv_priv; + struct vb2_buffer *vb; + + vb = mtk_mdp_m2m_buf_remove(ctx, q->type); + while (vb != NULL) { + v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR); + vb = mtk_mdp_m2m_buf_remove(ctx, q->type); + } + + pm_runtime_put(&ctx->mdp_dev->pdev->dev); +} + +static void mtk_mdp_m2m_job_abort(void *priv) +{ +} + +/* The color format (num_planes) must be already configured. */ +static void mtk_mdp_prepare_addr(struct mtk_mdp_ctx *ctx, + struct vb2_buffer *vb, + struct mtk_mdp_frame *frame, + struct mtk_mdp_addr *addr) +{ + u32 pix_size, planes, i; + + pix_size = frame->width * frame->height; + planes = min_t(u32, frame->fmt->num_planes, ARRAY_SIZE(addr->addr)); + for (i = 0; i < planes; i++) + addr->addr[i] = vb2_dma_contig_plane_dma_addr(vb, i); + + if (planes == 1) { + if (frame->fmt->pixelformat == V4L2_PIX_FMT_YVU420) { + addr->addr[1] = (dma_addr_t)(addr->addr[0] + pix_size); + addr->addr[2] = (dma_addr_t)(addr->addr[1] + + (pix_size >> 2)); + } else { + dev_err(&ctx->mdp_dev->pdev->dev, + "Invalid pixelformat:0x%x\n", + frame->fmt->pixelformat); + } + } + mtk_mdp_dbg(3, "[%d] planes:%d, size:%d, addr:%p,%p,%p", + ctx->id, planes, pix_size, (void *)addr->addr[0], + (void *)addr->addr[1], (void *)addr->addr[2]); +} + +static void mtk_mdp_m2m_get_bufs(struct mtk_mdp_ctx *ctx) +{ + struct mtk_mdp_frame *s_frame, *d_frame; + struct vb2_buffer *src_vb, *dst_vb; + struct vb2_v4l2_buffer *src_vbuf, *dst_vbuf; + + s_frame = &ctx->s_frame; + d_frame = &ctx->d_frame; + + src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx); + mtk_mdp_prepare_addr(ctx, src_vb, s_frame, &s_frame->addr); + + dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); + mtk_mdp_prepare_addr(ctx, dst_vb, d_frame, &d_frame->addr); + + src_vbuf = to_vb2_v4l2_buffer(src_vb); + dst_vbuf = to_vb2_v4l2_buffer(dst_vb); + dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp; +} + +static void mtk_mdp_process_done(void *priv, int vb_state) +{ + struct mtk_mdp_dev *mdp = priv; + struct mtk_mdp_ctx *ctx; + struct vb2_buffer *src_vb, *dst_vb; + struct vb2_v4l2_buffer *src_vbuf = NULL, *dst_vbuf = NULL; + + ctx = v4l2_m2m_get_curr_priv(mdp->m2m_dev); + if (!ctx) + return; + + src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + src_vbuf = to_vb2_v4l2_buffer(src_vb); + dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + dst_vbuf = to_vb2_v4l2_buffer(dst_vb); + + dst_vbuf->vb2_buf.timestamp = src_vbuf->vb2_buf.timestamp; + dst_vbuf->timecode = src_vbuf->timecode; + dst_vbuf->flags &= ~V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + dst_vbuf->flags |= src_vbuf->flags & V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + + v4l2_m2m_buf_done(src_vbuf, vb_state); + v4l2_m2m_buf_done(dst_vbuf, vb_state); + v4l2_m2m_job_finish(ctx->mdp_dev->m2m_dev, ctx->m2m_ctx); +} + +static void mtk_mdp_m2m_worker(struct work_struct *work) +{ + struct mtk_mdp_ctx *ctx = + container_of(work, struct mtk_mdp_ctx, work); + struct mtk_mdp_dev *mdp = ctx->mdp_dev; + enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR; + int ret; + + if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_CTX_ERROR)) { + dev_err(&mdp->pdev->dev, "ctx is in error state"); + goto worker_end; + } + + mtk_mdp_m2m_get_bufs(ctx); + + mtk_mdp_hw_set_input_addr(ctx, &ctx->s_frame.addr); + mtk_mdp_hw_set_output_addr(ctx, &ctx->d_frame.addr); + + mtk_mdp_hw_set_in_size(ctx); + mtk_mdp_hw_set_in_image_format(ctx); + + mtk_mdp_hw_set_out_size(ctx); + mtk_mdp_hw_set_out_image_format(ctx); + + mtk_mdp_hw_set_rotation(ctx); + mtk_mdp_hw_set_global_alpha(ctx); + + ret = mtk_mdp_vpu_process(&ctx->vpu); + if (ret) { + dev_err(&mdp->pdev->dev, "processing failed: %d", ret); + goto worker_end; + } + + buf_state = VB2_BUF_STATE_DONE; + +worker_end: + mtk_mdp_process_done(mdp, buf_state); +} + +static void mtk_mdp_m2m_device_run(void *priv) +{ + struct mtk_mdp_ctx *ctx = priv; + + queue_work(ctx->mdp_dev->job_wq, &ctx->work); +} + +static int mtk_mdp_m2m_queue_setup(struct vb2_queue *vq, + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) +{ + struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vq); + struct mtk_mdp_frame *frame; + int i; + + frame = mtk_mdp_ctx_get_frame(ctx, vq->type); + *num_planes = frame->fmt->num_planes; + for (i = 0; i < frame->fmt->num_planes; i++) + sizes[i] = frame->payload[i]; + mtk_mdp_dbg(2, "[%d] type:%d, planes:%d, buffers:%d, size:%u,%u", + ctx->id, vq->type, *num_planes, *num_buffers, + sizes[0], sizes[1]); + return 0; +} + +static int mtk_mdp_m2m_buf_prepare(struct vb2_buffer *vb) +{ + struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct mtk_mdp_frame *frame; + int i; + + frame = mtk_mdp_ctx_get_frame(ctx, vb->vb2_queue->type); + + if (!V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + for (i = 0; i < frame->fmt->num_planes; i++) + vb2_set_plane_payload(vb, i, frame->payload[i]); + } + + return 0; +} + +static void mtk_mdp_m2m_buf_queue(struct vb2_buffer *vb) +{ + struct mtk_mdp_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->m2m_ctx, to_vb2_v4l2_buffer(vb)); +} + +static struct vb2_ops mtk_mdp_m2m_qops = { + .queue_setup = mtk_mdp_m2m_queue_setup, + .buf_prepare = mtk_mdp_m2m_buf_prepare, + .buf_queue = mtk_mdp_m2m_buf_queue, + .wait_prepare = mtk_mdp_ctx_unlock, + .wait_finish = mtk_mdp_ctx_lock, + .stop_streaming = mtk_mdp_m2m_stop_streaming, + .start_streaming = mtk_mdp_m2m_start_streaming, +}; + +static int mtk_mdp_m2m_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_dev *mdp = ctx->mdp_dev; + + strlcpy(cap->driver, MTK_MDP_MODULE_NAME, sizeof(cap->driver)); + strlcpy(cap->card, mdp->pdev->name, sizeof(cap->card)); + strlcpy(cap->bus_info, "platform:mt8173", sizeof(cap->bus_info)); + + return 0; +} + +static int mtk_mdp_enum_fmt_mplane(struct v4l2_fmtdesc *f, u32 type) +{ + const struct mtk_mdp_fmt *fmt; + + fmt = mtk_mdp_find_fmt_by_index(f->index, type); + if (!fmt) + return -EINVAL; + + f->pixelformat = fmt->pixelformat; + + return 0; +} + +static int mtk_mdp_m2m_enum_fmt_mplane_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); +} + +static int mtk_mdp_m2m_enum_fmt_mplane_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return mtk_mdp_enum_fmt_mplane(f, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); +} + +static int mtk_mdp_m2m_g_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct mtk_mdp_frame *frame; + struct v4l2_pix_format_mplane *pix_mp; + int i; + + mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type); + + frame = mtk_mdp_ctx_get_frame(ctx, f->type); + pix_mp = &f->fmt.pix_mp; + + pix_mp->width = frame->width; + pix_mp->height = frame->height; + pix_mp->field = V4L2_FIELD_NONE; + pix_mp->pixelformat = frame->fmt->pixelformat; + pix_mp->num_planes = frame->fmt->num_planes; + pix_mp->colorspace = ctx->colorspace; + pix_mp->xfer_func = ctx->xfer_func; + pix_mp->ycbcr_enc = ctx->ycbcr_enc; + pix_mp->quantization = ctx->quant; + mtk_mdp_dbg(2, "[%d] wxh:%dx%d", ctx->id, + pix_mp->width, pix_mp->height); + + for (i = 0; i < pix_mp->num_planes; ++i) { + pix_mp->plane_fmt[i].bytesperline = (frame->width * + frame->fmt->row_depth[i]) / 8; + pix_mp->plane_fmt[i].sizeimage = (frame->width * + frame->height * frame->fmt->depth[i]) / 8; + + mtk_mdp_dbg(2, "[%d] p%d, bpl:%d, sizeimage:%d", ctx->id, i, + pix_mp->plane_fmt[i].bytesperline, + pix_mp->plane_fmt[i].sizeimage); + } + + return 0; +} + +static int mtk_mdp_m2m_try_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + + if (!mtk_mdp_try_fmt_mplane(ctx, f)) + return -EINVAL; + return 0; +} + +static int mtk_mdp_m2m_s_fmt_mplane(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct vb2_queue *vq; + struct mtk_mdp_frame *frame; + struct v4l2_pix_format_mplane *pix_mp; + const struct mtk_mdp_fmt *fmt; + int i; + + mtk_mdp_dbg(2, "[%d] type:%d", ctx->id, f->type); + + frame = mtk_mdp_ctx_get_frame(ctx, f->type); + fmt = mtk_mdp_try_fmt_mplane(ctx, f); + if (!fmt) { + mtk_mdp_err("[%d] try_fmt failed, type:%d", ctx->id, f->type); + return -EINVAL; + } + frame->fmt = fmt; + + vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type); + if (vb2_is_streaming(vq)) { + dev_info(&ctx->mdp_dev->pdev->dev, "queue %d busy", f->type); + return -EBUSY; + } + + pix_mp = &f->fmt.pix_mp; + for (i = 0; i < frame->fmt->num_planes; i++) { + frame->payload[i] = pix_mp->plane_fmt[i].sizeimage; + frame->pitch[i] = pix_mp->plane_fmt[i].bytesperline; + } + + mtk_mdp_set_frame_size(frame, pix_mp->width, pix_mp->height); + if (V4L2_TYPE_IS_OUTPUT(f->type)) { + ctx->colorspace = pix_mp->colorspace; + ctx->xfer_func = pix_mp->xfer_func; + ctx->ycbcr_enc = pix_mp->ycbcr_enc; + ctx->quant = pix_mp->quantization; + } + + if (V4L2_TYPE_IS_OUTPUT(f->type)) + mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_SRC_FMT); + else + mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_DST_FMT); + + mtk_mdp_dbg(2, "[%d] type:%d, frame:%dx%d", ctx->id, f->type, + frame->width, frame->height); + + return 0; +} + +static int mtk_mdp_m2m_reqbufs(struct file *file, void *fh, + struct v4l2_requestbuffers *reqbufs) +{ + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + + if (reqbufs->count == 0) { + if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_SRC_FMT); + else + mtk_mdp_ctx_state_lock_clear(ctx, MTK_MDP_DST_FMT); + } + + return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); +} + +static int mtk_mdp_m2m_streamon(struct file *file, void *fh, + enum v4l2_buf_type type) +{ + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + int ret; + + /* The source and target color format need to be set */ + if (V4L2_TYPE_IS_OUTPUT(type)) { + if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_SRC_FMT)) + return -EINVAL; + } else if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT)) { + return -EINVAL; + } + + if (!mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_VPU_INIT)) { + ret = mtk_mdp_vpu_init(&ctx->vpu); + if (ret < 0) { + dev_err(&ctx->mdp_dev->pdev->dev, + "vpu init failed %d\n", + ret); + return -EINVAL; + } + mtk_mdp_ctx_state_lock_set(ctx, MTK_MDP_VPU_INIT); + } + + return v4l2_m2m_streamon(file, ctx->m2m_ctx, type); +} + +static inline bool mtk_mdp_is_target_compose(u32 target) +{ + if (target == V4L2_SEL_TGT_COMPOSE_DEFAULT + || target == V4L2_SEL_TGT_COMPOSE_BOUNDS + || target == V4L2_SEL_TGT_COMPOSE) + return true; + return false; +} + +static inline bool mtk_mdp_is_target_crop(u32 target) +{ + if (target == V4L2_SEL_TGT_CROP_DEFAULT + || target == V4L2_SEL_TGT_CROP_BOUNDS + || target == V4L2_SEL_TGT_CROP) + return true; + return false; +} + +static int mtk_mdp_m2m_g_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct mtk_mdp_frame *frame; + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + bool valid = false; + + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (mtk_mdp_is_target_compose(s->target)) + valid = true; + } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (mtk_mdp_is_target_crop(s->target)) + valid = true; + } + if (!valid) { + mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx->id, s->type, + s->target); + return -EINVAL; + } + + frame = mtk_mdp_ctx_get_frame(ctx, s->type); + + switch (s->target) { + case V4L2_SEL_TGT_COMPOSE_DEFAULT: + case V4L2_SEL_TGT_COMPOSE_BOUNDS: + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + s->r.left = 0; + s->r.top = 0; + s->r.width = frame->width; + s->r.height = frame->height; + return 0; + + case V4L2_SEL_TGT_COMPOSE: + case V4L2_SEL_TGT_CROP: + s->r.left = frame->crop.left; + s->r.top = frame->crop.top; + s->r.width = frame->crop.width; + s->r.height = frame->crop.height; + return 0; + } + + return -EINVAL; +} + +static int mtk_mdp_check_scaler_ratio(struct mtk_mdp_variant *var, int src_w, + int src_h, int dst_w, int dst_h, int rot) +{ + int tmp_w, tmp_h; + + if (rot == 90 || rot == 270) { + tmp_w = dst_h; + tmp_h = dst_w; + } else { + tmp_w = dst_w; + tmp_h = dst_h; + } + + if ((src_w / tmp_w) > var->h_scale_down_max || + (src_h / tmp_h) > var->v_scale_down_max || + (tmp_w / src_w) > var->h_scale_up_max || + (tmp_h / src_h) > var->v_scale_up_max) + return -EINVAL; + + return 0; +} + +static int mtk_mdp_m2m_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct mtk_mdp_frame *frame; + struct mtk_mdp_ctx *ctx = fh_to_ctx(fh); + struct v4l2_rect new_r; + struct mtk_mdp_variant *variant = ctx->mdp_dev->variant; + int ret; + bool valid = false; + + if (s->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (s->target == V4L2_SEL_TGT_COMPOSE) + valid = true; + } else if (s->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) { + if (s->target == V4L2_SEL_TGT_CROP) + valid = true; + } + if (!valid) { + mtk_mdp_dbg(1, "[%d] invalid type:%d,%u", ctx->id, s->type, + s->target); + return -EINVAL; + } + + new_r = s->r; + ret = mtk_mdp_try_crop(ctx, s->type, &new_r); + if (ret) + return ret; + + if (mtk_mdp_is_target_crop(s->target)) + frame = &ctx->s_frame; + else + frame = &ctx->d_frame; + + /* Check to see if scaling ratio is within supported range */ + if (mtk_mdp_ctx_state_is_set(ctx, MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT)) { + if (V4L2_TYPE_IS_OUTPUT(s->type)) { + ret = mtk_mdp_check_scaler_ratio(variant, new_r.width, + new_r.height, ctx->d_frame.crop.width, + ctx->d_frame.crop.height, + ctx->ctrls.rotate->val); + } else { + ret = mtk_mdp_check_scaler_ratio(variant, + ctx->s_frame.crop.width, + ctx->s_frame.crop.height, new_r.width, + new_r.height, ctx->ctrls.rotate->val); + } + + if (ret) { + dev_info(&ctx->mdp_dev->pdev->dev, + "Out of scaler range"); + return -EINVAL; + } + } + + s->r = new_r; + frame->crop = new_r; + + return 0; +} + +static const struct v4l2_ioctl_ops mtk_mdp_m2m_ioctl_ops = { + .vidioc_querycap = mtk_mdp_m2m_querycap, + .vidioc_enum_fmt_vid_cap_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_cap, + .vidioc_enum_fmt_vid_out_mplane = mtk_mdp_m2m_enum_fmt_mplane_vid_out, + .vidioc_g_fmt_vid_cap_mplane = mtk_mdp_m2m_g_fmt_mplane, + .vidioc_g_fmt_vid_out_mplane = mtk_mdp_m2m_g_fmt_mplane, + .vidioc_try_fmt_vid_cap_mplane = mtk_mdp_m2m_try_fmt_mplane, + .vidioc_try_fmt_vid_out_mplane = mtk_mdp_m2m_try_fmt_mplane, + .vidioc_s_fmt_vid_cap_mplane = mtk_mdp_m2m_s_fmt_mplane, + .vidioc_s_fmt_vid_out_mplane = mtk_mdp_m2m_s_fmt_mplane, + .vidioc_reqbufs = mtk_mdp_m2m_reqbufs, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_streamon = mtk_mdp_m2m_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + .vidioc_g_selection = mtk_mdp_m2m_g_selection, + .vidioc_s_selection = mtk_mdp_m2m_s_selection +}; + +static int mtk_mdp_m2m_queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct mtk_mdp_ctx *ctx = priv; + int ret; + + memset(src_vq, 0, sizeof(*src_vq)); + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->ops = &mtk_mdp_m2m_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->dev = &ctx->mdp_dev->pdev->dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + memset(dst_vq, 0, sizeof(*dst_vq)); + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->ops = &mtk_mdp_m2m_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer); + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->dev = &ctx->mdp_dev->pdev->dev; + + return vb2_queue_init(dst_vq); +} + +static int mtk_mdp_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_mdp_ctx *ctx = ctrl_to_ctx(ctrl); + struct mtk_mdp_dev *mdp = ctx->mdp_dev; + struct mtk_mdp_variant *variant = mdp->variant; + u32 state = MTK_MDP_DST_FMT | MTK_MDP_SRC_FMT; + int ret = 0; + + if (ctrl->flags & V4L2_CTRL_FLAG_INACTIVE) + return 0; + + switch (ctrl->id) { + case V4L2_CID_HFLIP: + ctx->hflip = ctrl->val; + break; + case V4L2_CID_VFLIP: + ctx->vflip = ctrl->val; + break; + case V4L2_CID_ROTATE: + if (mtk_mdp_ctx_state_is_set(ctx, state)) { + ret = mtk_mdp_check_scaler_ratio(variant, + ctx->s_frame.crop.width, + ctx->s_frame.crop.height, + ctx->d_frame.crop.width, + ctx->d_frame.crop.height, + ctx->ctrls.rotate->val); + + if (ret) + return -EINVAL; + } + + ctx->rotation = ctrl->val; + break; + case V4L2_CID_ALPHA_COMPONENT: + ctx->d_frame.alpha = ctrl->val; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops mtk_mdp_ctrl_ops = { + .s_ctrl = mtk_mdp_s_ctrl, +}; + +static int mtk_mdp_ctrls_create(struct mtk_mdp_ctx *ctx) +{ + v4l2_ctrl_handler_init(&ctx->ctrl_handler, MTK_MDP_MAX_CTRL_NUM); + + ctx->ctrls.rotate = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &mtk_mdp_ctrl_ops, V4L2_CID_ROTATE, 0, 270, 90, 0); + ctx->ctrls.hflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &mtk_mdp_ctrl_ops, + V4L2_CID_HFLIP, + 0, 1, 1, 0); + ctx->ctrls.vflip = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &mtk_mdp_ctrl_ops, + V4L2_CID_VFLIP, + 0, 1, 1, 0); + ctx->ctrls.global_alpha = v4l2_ctrl_new_std(&ctx->ctrl_handler, + &mtk_mdp_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, + 0, 255, 1, 0); + ctx->ctrls_rdy = ctx->ctrl_handler.error == 0; + + if (ctx->ctrl_handler.error) { + int err = ctx->ctrl_handler.error; + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + dev_err(&ctx->mdp_dev->pdev->dev, + "Failed to create control handlers\n"); + return err; + } + + return 0; +} + +static void mtk_mdp_set_default_params(struct mtk_mdp_ctx *ctx) +{ + struct mtk_mdp_dev *mdp = ctx->mdp_dev; + struct mtk_mdp_frame *frame; + + frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + frame->fmt = mtk_mdp_find_fmt_by_index(0, + V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + frame->width = mdp->variant->pix_min->org_w; + frame->height = mdp->variant->pix_min->org_h; + frame->payload[0] = frame->width * frame->height; + frame->payload[1] = frame->payload[0] / 2; + + frame = mtk_mdp_ctx_get_frame(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + frame->fmt = mtk_mdp_find_fmt_by_index(0, + V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + frame->width = mdp->variant->pix_min->target_rot_dis_w; + frame->height = mdp->variant->pix_min->target_rot_dis_h; + frame->payload[0] = frame->width * frame->height; + frame->payload[1] = frame->payload[0] / 2; + +} + +static int mtk_mdp_m2m_open(struct file *file) +{ + struct mtk_mdp_dev *mdp = video_drvdata(file); + struct video_device *vfd = video_devdata(file); + struct mtk_mdp_ctx *ctx = NULL; + int ret; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + if (mutex_lock_interruptible(&mdp->lock)) { + ret = -ERESTARTSYS; + goto err_lock; + } + + mutex_init(&ctx->slock); + ctx->id = mdp->id_counter++; + v4l2_fh_init(&ctx->fh, vfd); + file->private_data = &ctx->fh; + ret = mtk_mdp_ctrls_create(ctx); + if (ret) + goto error_ctrls; + + /* Use separate control handler per file handle */ + ctx->fh.ctrl_handler = &ctx->ctrl_handler; + v4l2_fh_add(&ctx->fh); + INIT_LIST_HEAD(&ctx->list); + + ctx->mdp_dev = mdp; + mtk_mdp_set_default_params(ctx); + + INIT_WORK(&ctx->work, mtk_mdp_m2m_worker); + ctx->m2m_ctx = v4l2_m2m_ctx_init(mdp->m2m_dev, ctx, + mtk_mdp_m2m_queue_init); + if (IS_ERR(ctx->m2m_ctx)) { + dev_err(&mdp->pdev->dev, "Failed to initialize m2m context"); + ret = PTR_ERR(ctx->m2m_ctx); + goto error_m2m_ctx; + } + ctx->fh.m2m_ctx = ctx->m2m_ctx; + if (mdp->ctx_num++ == 0) { + ret = vpu_load_firmware(mdp->vpu_dev); + if (ret < 0) { + dev_err(&mdp->pdev->dev, + "vpu_load_firmware failed %d\n", ret); + goto err_load_vpu; + } + + ret = mtk_mdp_vpu_register(mdp->pdev); + if (ret < 0) { + dev_err(&mdp->pdev->dev, + "mdp_vpu register failed %d\n", ret); + goto err_load_vpu; + } + } + + list_add(&ctx->list, &mdp->ctx_list); + mutex_unlock(&mdp->lock); + + mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id); + + return 0; + +err_load_vpu: + mdp->ctx_num--; + v4l2_m2m_ctx_release(ctx->m2m_ctx); +error_m2m_ctx: + v4l2_ctrl_handler_free(&ctx->ctrl_handler); +error_ctrls: + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + mutex_unlock(&mdp->lock); +err_lock: + kfree(ctx); + + return ret; +} + +static int mtk_mdp_m2m_release(struct file *file) +{ + struct mtk_mdp_ctx *ctx = fh_to_ctx(file->private_data); + struct mtk_mdp_dev *mdp = ctx->mdp_dev; + + flush_workqueue(mdp->job_wq); + mutex_lock(&mdp->lock); + v4l2_m2m_ctx_release(ctx->m2m_ctx); + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + mtk_mdp_vpu_deinit(&ctx->vpu); + mdp->ctx_num--; + list_del_init(&ctx->list); + + mtk_mdp_dbg(0, "%s [%d]", dev_name(&mdp->pdev->dev), ctx->id); + + mutex_unlock(&mdp->lock); + kfree(ctx); + + return 0; +} + +static const struct v4l2_file_operations mtk_mdp_m2m_fops = { + .owner = THIS_MODULE, + .open = mtk_mdp_m2m_open, + .release = mtk_mdp_m2m_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static struct v4l2_m2m_ops mtk_mdp_m2m_ops = { + .device_run = mtk_mdp_m2m_device_run, + .job_abort = mtk_mdp_m2m_job_abort, +}; + +int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp) +{ + struct device *dev = &mdp->pdev->dev; + int ret; + + mdp->variant = &mtk_mdp_default_variant; + mdp->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + mdp->vdev.fops = &mtk_mdp_m2m_fops; + mdp->vdev.ioctl_ops = &mtk_mdp_m2m_ioctl_ops; + mdp->vdev.release = video_device_release_empty; + mdp->vdev.lock = &mdp->lock; + mdp->vdev.vfl_dir = VFL_DIR_M2M; + mdp->vdev.v4l2_dev = &mdp->v4l2_dev; + snprintf(mdp->vdev.name, sizeof(mdp->vdev.name), "%s:m2m", + MTK_MDP_MODULE_NAME); + video_set_drvdata(&mdp->vdev, mdp); + + mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops); + if (IS_ERR(mdp->m2m_dev)) { + dev_err(dev, "failed to initialize v4l2-m2m device\n"); + ret = PTR_ERR(mdp->m2m_dev); + goto err_m2m_init; + } + + ret = video_register_device(&mdp->vdev, VFL_TYPE_GRABBER, 2); + if (ret) { + dev_err(dev, "failed to register video device\n"); + goto err_vdev_register; + } + + v4l2_info(&mdp->v4l2_dev, "driver registered as /dev/video%d", + mdp->vdev.num); + return 0; + +err_vdev_register: + v4l2_m2m_release(mdp->m2m_dev); +err_m2m_init: + video_device_release(&mdp->vdev); + + return ret; +} + +void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp) +{ + video_device_release(&mdp->vdev); + v4l2_m2m_release(mdp->m2m_dev); +} diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h new file mode 100644 index 000000000000..45afd3655817 --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Ming Hsiu Tsai + * + * 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 __MTK_MDP_M2M_H__ +#define __MTK_MDP_M2M_H__ + +void mtk_mdp_ctx_state_lock_set(struct mtk_mdp_ctx *ctx, u32 state); +int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp); +void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp); + +#endif /* __MTK_MDP_M2M_H__ */ diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c new file mode 100644 index 000000000000..a5601e1a238c --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2015-2016 MediaTek Inc. + * Author: Houlong Wei + * Ming Hsiu Tsai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include "mtk_mdp_core.h" +#include "mtk_mdp_regs.h" + + +#define MDP_COLORFMT_PACK(VIDEO, PLANE, COPLANE, HF, VF, BITS, GROUP, SWAP, ID)\ + (((VIDEO) << 27) | ((PLANE) << 24) | ((COPLANE) << 22) |\ + ((HF) << 20) | ((VF) << 18) | ((BITS) << 8) | ((GROUP) << 6) |\ + ((SWAP) << 5) | ((ID) << 0)) + +enum MDP_COLOR_ENUM { + MDP_COLOR_UNKNOWN = 0, + MDP_COLOR_NV12 = MDP_COLORFMT_PACK(0, 2, 1, 1, 1, 8, 1, 0, 12), + MDP_COLOR_I420 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 0, 8), + MDP_COLOR_YV12 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 1, 8), +}; + +static int32_t mtk_mdp_map_color_format(int v4l2_format) +{ + switch (v4l2_format) { + case V4L2_PIX_FMT_NV12M: + case V4L2_PIX_FMT_NV12: + return MDP_COLOR_NV12; + case V4L2_PIX_FMT_YUV420M: + case V4L2_PIX_FMT_YUV420: + return MDP_COLOR_I420; + case V4L2_PIX_FMT_YVU420: + return MDP_COLOR_YV12; + } + + mtk_mdp_err("Unknown format 0x%x", v4l2_format); + + return MDP_COLOR_UNKNOWN; +} + +void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx, + struct mtk_mdp_addr *addr) +{ + struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer; + int i; + + for (i = 0; i < ARRAY_SIZE(addr->addr); i++) + src_buf->addr_mva[i] = (uint64_t)addr->addr[i]; +} + +void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx, + struct mtk_mdp_addr *addr) +{ + struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer; + int i; + + for (i = 0; i < ARRAY_SIZE(addr->addr); i++) + dst_buf->addr_mva[i] = (uint64_t)addr->addr[i]; +} + +void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx) +{ + struct mtk_mdp_frame *frame = &ctx->s_frame; + struct mdp_config *config = &ctx->vpu.vsi->src_config; + + /* Set input pixel offset */ + config->crop_x = frame->crop.left; + config->crop_y = frame->crop.top; + + /* Set input cropped size */ + config->crop_w = frame->crop.width; + config->crop_h = frame->crop.height; + + /* Set input original size */ + config->x = 0; + config->y = 0; + config->w = frame->width; + config->h = frame->height; +} + +void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx) +{ + unsigned int i; + struct mtk_mdp_frame *frame = &ctx->s_frame; + struct mdp_config *config = &ctx->vpu.vsi->src_config; + struct mdp_buffer *src_buf = &ctx->vpu.vsi->src_buffer; + + src_buf->plane_num = frame->fmt->num_comp; + config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat); + config->w_stride = 0; /* MDP will calculate it by color format. */ + config->h_stride = 0; /* MDP will calculate it by color format. */ + + for (i = 0; i < src_buf->plane_num; i++) + src_buf->plane_size[i] = frame->payload[i]; +} + +void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx) +{ + struct mtk_mdp_frame *frame = &ctx->d_frame; + struct mdp_config *config = &ctx->vpu.vsi->dst_config; + + config->crop_x = frame->crop.left; + config->crop_y = frame->crop.top; + config->crop_w = frame->crop.width; + config->crop_h = frame->crop.height; + config->x = 0; + config->y = 0; + config->w = frame->width; + config->h = frame->height; +} + +void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx) +{ + unsigned int i; + struct mtk_mdp_frame *frame = &ctx->d_frame; + struct mdp_config *config = &ctx->vpu.vsi->dst_config; + struct mdp_buffer *dst_buf = &ctx->vpu.vsi->dst_buffer; + + dst_buf->plane_num = frame->fmt->num_comp; + config->format = mtk_mdp_map_color_format(frame->fmt->pixelformat); + config->w_stride = 0; /* MDP will calculate it by color format. */ + config->h_stride = 0; /* MDP will calculate it by color format. */ + for (i = 0; i < dst_buf->plane_num; i++) + dst_buf->plane_size[i] = frame->payload[i]; +} + +void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx) +{ + struct mdp_config_misc *misc = &ctx->vpu.vsi->misc; + + misc->orientation = ctx->ctrls.rotate->val; + misc->hflip = ctx->ctrls.hflip->val; + misc->vflip = ctx->ctrls.vflip->val; +} + +void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx) +{ + struct mdp_config_misc *misc = &ctx->vpu.vsi->misc; + + misc->alpha = ctx->ctrls.global_alpha->val; +} diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h new file mode 100644 index 000000000000..42bd057e76cc --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016 MediaTek Inc. + * Author: Ming Hsiu Tsai + * + * 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 __MTK_MDP_REGS_H__ +#define __MTK_MDP_REGS_H__ + + +void mtk_mdp_hw_set_input_addr(struct mtk_mdp_ctx *ctx, + struct mtk_mdp_addr *addr); +void mtk_mdp_hw_set_output_addr(struct mtk_mdp_ctx *ctx, + struct mtk_mdp_addr *addr); +void mtk_mdp_hw_set_in_size(struct mtk_mdp_ctx *ctx); +void mtk_mdp_hw_set_in_image_format(struct mtk_mdp_ctx *ctx); +void mtk_mdp_hw_set_out_size(struct mtk_mdp_ctx *ctx); +void mtk_mdp_hw_set_out_image_format(struct mtk_mdp_ctx *ctx); +void mtk_mdp_hw_set_rotation(struct mtk_mdp_ctx *ctx); +void mtk_mdp_hw_set_global_alpha(struct mtk_mdp_ctx *ctx); + + +#endif /* __MTK_MDP_REGS_H__ */ diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c new file mode 100644 index 000000000000..fb07bf3dbd8b --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2015-2016 MediaTek Inc. + * Author: Houlong Wei + * Ming Hsiu Tsai + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "mtk_mdp_core.h" +#include "mtk_mdp_vpu.h" +#include "mtk_vpu.h" + + +static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu) +{ + return container_of(vpu, struct mtk_mdp_ctx, vpu); +} + +static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg) +{ + struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst; + + /* mapping VPU address to kernel virtual address */ + vpu->vsi = (struct mdp_process_vsi *) + vpu_mapping_dm_addr(vpu->pdev, msg->vpu_inst_addr); + vpu->inst_addr = msg->vpu_inst_addr; +} + +static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv) +{ + unsigned int msg_id = *(unsigned int *)data; + struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data; + struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst; + struct mtk_mdp_ctx *ctx; + + vpu->failure = msg->status; + if (!vpu->failure) { + switch (msg_id) { + case VPU_MDP_INIT_ACK: + mtk_mdp_vpu_handle_init_ack(data); + break; + case VPU_MDP_DEINIT_ACK: + case VPU_MDP_PROCESS_ACK: + break; + default: + ctx = vpu_to_ctx(vpu); + dev_err(&ctx->mdp_dev->pdev->dev, + "handle unknown ipi msg:0x%x\n", + msg_id); + break; + } + } else { + ctx = vpu_to_ctx(vpu); + mtk_mdp_dbg(0, "[%d]:msg 0x%x, failure:%d", ctx->id, + msg_id, vpu->failure); + } +} + +int mtk_mdp_vpu_register(struct platform_device *pdev) +{ + struct mtk_mdp_dev *mdp = platform_get_drvdata(pdev); + int err; + + err = vpu_ipi_register(mdp->vpu_dev, IPI_MDP, + mtk_mdp_vpu_ipi_handler, "mdp_vpu", NULL); + if (err) + dev_err(&mdp->pdev->dev, + "vpu_ipi_registration fail status=%d\n", err); + + return err; +} + +static int mtk_mdp_vpu_send_msg(void *msg, int len, struct mtk_mdp_vpu *vpu, + int id) +{ + struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu); + int err; + + if (!vpu->pdev) { + mtk_mdp_dbg(1, "[%d]:vpu pdev is NULL", ctx->id); + return -EINVAL; + } + + mutex_lock(&ctx->mdp_dev->vpulock); + err = vpu_ipi_send(vpu->pdev, (enum ipi_id)id, msg, len); + if (err) { + mutex_unlock(&ctx->mdp_dev->vpulock); + dev_err(&ctx->mdp_dev->pdev->dev, + "vpu_ipi_send fail status %d\n", err); + } + mutex_unlock(&ctx->mdp_dev->vpulock); + + return err; +} + +static int mtk_mdp_vpu_send_ap_ipi(struct mtk_mdp_vpu *vpu, uint32_t msg_id) +{ + int err; + struct mdp_ipi_comm msg; + + msg.msg_id = msg_id; + msg.ipi_id = IPI_MDP; + msg.vpu_inst_addr = vpu->inst_addr; + msg.ap_inst = (uint64_t)vpu; + err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP); + if (!err && vpu->failure) + err = -EINVAL; + + return err; +} + +int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu) +{ + int err; + struct mdp_ipi_init msg; + struct mtk_mdp_ctx *ctx = vpu_to_ctx(vpu); + + vpu->pdev = ctx->mdp_dev->vpu_dev; + + msg.msg_id = AP_MDP_INIT; + msg.ipi_id = IPI_MDP; + msg.ap_inst = (uint64_t)vpu; + err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP); + if (!err && vpu->failure) + err = -EINVAL; + + return err; +} + +int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu) +{ + return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_DEINIT); +} + +int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu) +{ + return mtk_mdp_vpu_send_ap_ipi(vpu, AP_MDP_PROCESS); +} diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h new file mode 100644 index 000000000000..df4bddaa438e --- /dev/null +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2015-2016 MediaTek Inc. + * Author: Houlong Wei + * Ming Hsiu Tsai + * + * 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 __MTK_MDP_VPU_H__ +#define __MTK_MDP_VPU_H__ + +#include "mtk_mdp_ipi.h" + + +/** + * struct mtk_mdp_vpu - VPU instance for MDP + * @pdev : pointer to the VPU platform device + * @inst_addr : VPU MDP instance address + * @failure : VPU execution result status + * @vsi : VPU shared information + */ +struct mtk_mdp_vpu { + struct platform_device *pdev; + uint32_t inst_addr; + int32_t failure; + struct mdp_process_vsi *vsi; +}; + +int mtk_mdp_vpu_register(struct platform_device *pdev); +int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu); +int mtk_mdp_vpu_deinit(struct mtk_mdp_vpu *vpu); +int mtk_mdp_vpu_process(struct mtk_mdp_vpu *vpu); + +#endif /* __MTK_MDP_VPU_H__ */ -- cgit v1.2.3 From 004b93b9e9a7d9e8590de8c864b909ca363deba5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 21 Oct 2016 11:56:43 -0200 Subject: [media] mtk-mdp: fix compilation warnings if !DEBUG MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mtk_mdp_dbg() is empty if !DEBUG. This causes the following warnings: drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c: In function ‘mtk_mdp_try_fmt_mplane’: drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c:231:52: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body] org_w, org_h, pix_mp->width, pix_mp->height); ^ drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c: In function ‘mtk_mdp_m2m_start_streaming’: drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c:414:21: warning: suggest braces around empty body in an ‘if’ statement [-Wempty-body] ctx->id, ret); ^ With could actually make the code to do something wrong. So, add an empty block to make it be parsed ok. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_core.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h index 2e979f97d1df..848569d4ab90 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h @@ -250,7 +250,7 @@ extern int mtk_mdp_dbg_level; #else -#define mtk_mdp_dbg(level, fmt, args...) +#define mtk_mdp_dbg(level, fmt, args...) {} #define mtk_mdp_err(fmt, args...) #define mtk_mdp_dbg_enter() #define mtk_mdp_dbg_leave() -- cgit v1.2.3 From 859b5e407d83e79f42dad08c50bdfc2bb17766cb Mon Sep 17 00:00:00 2001 From: Minghsiu Tsai Date: Thu, 8 Sep 2016 10:09:05 -0300 Subject: [media] media: mtk-mdp: support pixelformat V4L2_PIX_FMT_MT21C Add V4L2_PIX_FMT_MT21C in format list. [mchehab@s-opensource.org: re-add mtk_mdp_size_align] Signed-off-by: Minghsiu Tsai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 8 ++++++++ drivers/media/platform/mtk-mdp/mtk_mdp_regs.c | 4 ++++ 2 files changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c index 065502757133..a90972efec5c 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -54,6 +54,14 @@ static struct mtk_mdp_pix_align mtk_mdp_size_align = { static const struct mtk_mdp_fmt mtk_mdp_formats[] = { { + .pixelformat = V4L2_PIX_FMT_MT21C, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .num_comp = 2, + .align = &mtk_mdp_size_align, + .flags = MTK_MDP_FMT_FLAG_OUTPUT, + }, { .pixelformat = V4L2_PIX_FMT_NV12M, .depth = { 8, 4 }, .row_depth = { 8, 8 }, diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c index a5601e1a238c..86d57f380c97 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_regs.c @@ -29,6 +29,8 @@ enum MDP_COLOR_ENUM { MDP_COLOR_NV12 = MDP_COLORFMT_PACK(0, 2, 1, 1, 1, 8, 1, 0, 12), MDP_COLOR_I420 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 0, 8), MDP_COLOR_YV12 = MDP_COLORFMT_PACK(0, 3, 0, 1, 1, 8, 1, 1, 8), + /* Mediatek proprietary format */ + MDP_COLOR_420_MT21 = MDP_COLORFMT_PACK(5, 2, 1, 1, 1, 256, 1, 0, 12), }; static int32_t mtk_mdp_map_color_format(int v4l2_format) @@ -37,6 +39,8 @@ static int32_t mtk_mdp_map_color_format(int v4l2_format) case V4L2_PIX_FMT_NV12M: case V4L2_PIX_FMT_NV12: return MDP_COLOR_NV12; + case V4L2_PIX_FMT_MT21C: + return MDP_COLOR_420_MT21; case V4L2_PIX_FMT_YUV420M: case V4L2_PIX_FMT_YUV420: return MDP_COLOR_I420; -- cgit v1.2.3 From 37bf7e34ecc817ce6b8278588aeb22aab5635e1c Mon Sep 17 00:00:00 2001 From: Minghsiu Tsai Date: Mon, 19 Sep 2016 03:34:42 -0300 Subject: [media] media: mtk-mdp: fix build warning in arch x86 This patch fix build warning in arch x86 Signed-off-by: Minghsiu Tsai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 1 + drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c index a90972efec5c..9a747e7321cc 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c index fb07bf3dbd8b..39188e5e46d0 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c @@ -25,7 +25,8 @@ static inline struct mtk_mdp_ctx *vpu_to_ctx(struct mtk_mdp_vpu *vpu) static void mtk_mdp_vpu_handle_init_ack(struct mdp_ipi_comm_ack *msg) { - struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst; + struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *) + (unsigned long)msg->ap_inst; /* mapping VPU address to kernel virtual address */ vpu->vsi = (struct mdp_process_vsi *) @@ -37,7 +38,8 @@ static void mtk_mdp_vpu_ipi_handler(void *data, unsigned int len, void *priv) { unsigned int msg_id = *(unsigned int *)data; struct mdp_ipi_comm_ack *msg = (struct mdp_ipi_comm_ack *)data; - struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *)msg->ap_inst; + struct mtk_mdp_vpu *vpu = (struct mtk_mdp_vpu *) + (unsigned long)msg->ap_inst; struct mtk_mdp_ctx *ctx; vpu->failure = msg->status; @@ -108,7 +110,7 @@ static int mtk_mdp_vpu_send_ap_ipi(struct mtk_mdp_vpu *vpu, uint32_t msg_id) msg.msg_id = msg_id; msg.ipi_id = IPI_MDP; msg.vpu_inst_addr = vpu->inst_addr; - msg.ap_inst = (uint64_t)vpu; + msg.ap_inst = (unsigned long)vpu; err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP); if (!err && vpu->failure) err = -EINVAL; @@ -126,7 +128,7 @@ int mtk_mdp_vpu_init(struct mtk_mdp_vpu *vpu) msg.msg_id = AP_MDP_INIT; msg.ipi_id = IPI_MDP; - msg.ap_inst = (uint64_t)vpu; + msg.ap_inst = (unsigned long)vpu; err = mtk_mdp_vpu_send_msg((void *)&msg, sizeof(msg), vpu, IPI_MDP); if (!err && vpu->failure) err = -EINVAL; -- cgit v1.2.3 From 1b06fcf56aa65299203c876de5dd69d4f46e55a8 Mon Sep 17 00:00:00 2001 From: Minghsiu Tsai Date: Mon, 19 Sep 2016 03:34:43 -0300 Subject: [media] media: mtk-mdp: fix build error This patch fix build error without CONFIG_PM_RUNTIME and CONFIG_PM_SLEEP Signed-off-by: Minghsiu Tsai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index 7e35235d82e2..40a229d8a1f5 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -233,7 +233,7 @@ static int mtk_mdp_remove(struct platform_device *pdev) return 0; } -#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP) +#ifdef CONFIG_PM static int mtk_mdp_pm_suspend(struct device *dev) { struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); @@ -251,7 +251,7 @@ static int mtk_mdp_pm_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */ +#endif /* CONFIG_PM */ #ifdef CONFIG_PM_SLEEP static int mtk_mdp_suspend(struct device *dev) -- cgit v1.2.3 From 669c6141ea78dff885b5bf025456c7dffb669a61 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 19 Sep 2016 05:00:34 -0300 Subject: [media] mtk-mdp: fix double mutex_unlock Fix smatch error: media-git/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c:100 mtk_mdp_vpu_send_msg() error: double unlock 'mutex:&ctx->mdp_dev->vpulock' Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c index 39188e5e46d0..4893825aa5dd 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_vpu.c @@ -92,11 +92,9 @@ static int mtk_mdp_vpu_send_msg(void *msg, int len, struct mtk_mdp_vpu *vpu, mutex_lock(&ctx->mdp_dev->vpulock); err = vpu_ipi_send(vpu->pdev, (enum ipi_id)id, msg, len); - if (err) { - mutex_unlock(&ctx->mdp_dev->vpulock); + if (err) dev_err(&ctx->mdp_dev->pdev->dev, "vpu_ipi_send fail status %d\n", err); - } mutex_unlock(&ctx->mdp_dev->vpulock); return err; -- cgit v1.2.3 From f59dab8d9e8f37f7042ba05bfbab748b1312e73e Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 20 Oct 2016 10:12:42 +0200 Subject: mtd: nand: sunxi: fix support for 512bytes ECC chunks The driver is incorrectly assuming that the ECC block size is always 1k which is not always true. Also take the other cases into account. Signed-off-by: Boris Brezillon Signed-off-by: Maxime Ripard --- drivers/mtd/nand/sunxi_nand.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c index 8b8470c4e6d0..e40482a65de6 100644 --- a/drivers/mtd/nand/sunxi_nand.c +++ b/drivers/mtd/nand/sunxi_nand.c @@ -145,6 +145,7 @@ #define NFC_ECC_PIPELINE BIT(3) #define NFC_ECC_EXCEPTION BIT(4) #define NFC_ECC_BLOCK_SIZE_MSK BIT(5) +#define NFC_ECC_BLOCK_512 BIT(5) #define NFC_RANDOM_EN BIT(9) #define NFC_RANDOM_DIRECTION BIT(10) #define NFC_ECC_MODE_MSK GENMASK(15, 12) @@ -817,6 +818,9 @@ static void sunxi_nfc_hw_ecc_enable(struct mtd_info *mtd) ecc_ctl |= NFC_ECC_EN | NFC_ECC_MODE(data->mode) | NFC_ECC_EXCEPTION | NFC_ECC_PIPELINE; + if (nand->ecc.size == 512) + ecc_ctl |= NFC_ECC_BLOCK_512; + writel(ecc_ctl, nfc->regs + NFC_REG_ECC_CTL); } -- cgit v1.2.3 From 6ac18a4859b3a7d55874bed2ebe6d704b7926a10 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 20 Oct 2016 10:12:43 +0200 Subject: mtd: nand: add support for the TC58NVG2S0H chip Add the description of the Toshiba TC58NVG2S0H SLC nand to the nand_ids table so we can use the NAND ECC infos and the ONFI timings. Signed-off-by: Boris Brezillon Signed-off-by: Maxime Ripard --- drivers/mtd/nand/nand_ids.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c index 2af9869a115e..b3a332f37e14 100644 --- a/drivers/mtd/nand/nand_ids.c +++ b/drivers/mtd/nand/nand_ids.c @@ -36,6 +36,9 @@ struct nand_flash_dev nand_flash_ids[] = { {"TC58NVG2S0F 4G 3.3V 8-bit", { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x15, 0x01, 0x08} }, SZ_4K, SZ_512, SZ_256K, 0, 8, 224, NAND_ECC_INFO(4, SZ_512) }, + {"TC58NVG2S0H 4G 3.3V 8-bit", + { .id = {0x98, 0xdc, 0x90, 0x26, 0x76, 0x16, 0x08, 0x00} }, + SZ_4K, SZ_512, SZ_256K, 0, 8, 256, NAND_ECC_INFO(8, SZ_512) }, {"TC58NVG3S0F 8G 3.3V 8-bit", { .id = {0x98, 0xd3, 0x90, 0x26, 0x76, 0x15, 0x02, 0x08} }, SZ_4K, SZ_1K, SZ_256K, 0, 8, 232, NAND_ECC_INFO(4, SZ_512) }, -- cgit v1.2.3 From b7547ef8670057b1143e9a47a300180db97a0e5b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Sep 2016 09:39:45 -0300 Subject: [media] smiapp: Move sub-device initialisation into a separate function Simplify smiapp_init() by moving the initialisation of individual sub-devices to a separate function. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 110 +++++++++++++++------------------ 1 file changed, 51 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 44f8c7e10a35..957e37e1c25f 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2535,11 +2535,58 @@ static void smiapp_cleanup(struct smiapp_sensor *sensor) smiapp_free_controls(sensor); } +static void smiapp_create_subdev(struct smiapp_sensor *sensor, + struct smiapp_subdev *ssd, const char *name) +{ + struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + + if (!ssd) + return; + + if (ssd != sensor->src) + v4l2_subdev_init(&ssd->sd, &smiapp_ops); + + ssd->sensor = sensor; + + if (ssd == sensor->pixel_array) { + ssd->npads = 1; + } else { + ssd->npads = 2; + ssd->source_pad = 1; + } + + snprintf(ssd->sd.name, + sizeof(ssd->sd.name), "%s %s %d-%4.4x", sensor->minfo.name, + name, i2c_adapter_id(client->adapter), client->addr); + + ssd->sink_fmt.width = + sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; + ssd->sink_fmt.height = + sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; + ssd->compose.width = ssd->sink_fmt.width; + ssd->compose.height = ssd->sink_fmt.height; + ssd->crop[ssd->source_pad] = ssd->compose; + ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE; + if (ssd != sensor->pixel_array) { + ssd->crop[ssd->sink_pad] = ssd->compose; + ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK; + } + + ssd->sd.entity.ops = &smiapp_entity_ops; + + if (ssd == sensor->src) + return; + + ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + ssd->sd.internal_ops = &smiapp_internal_ops; + ssd->sd.owner = THIS_MODULE; + v4l2_set_subdevdata(&ssd->sd, client); +} + static int smiapp_init(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_pll *pll = &sensor->pll; - struct smiapp_subdev *last = NULL; unsigned int i; int rval; @@ -2700,64 +2747,9 @@ static int smiapp_init(struct smiapp_sensor *sensor) if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - for (i = 0; i < SMIAPP_SUBDEVS; i++) { - struct { - struct smiapp_subdev *ssd; - char *name; - } const __this[] = { - { sensor->scaler, "scaler", }, - { sensor->binner, "binner", }, - { sensor->pixel_array, "pixel array", }, - }, *_this = &__this[i]; - struct smiapp_subdev *this = _this->ssd; - - if (!this) - continue; - - if (this != sensor->src) - v4l2_subdev_init(&this->sd, &smiapp_ops); - - this->sensor = sensor; - - if (this == sensor->pixel_array) { - this->npads = 1; - } else { - this->npads = 2; - this->source_pad = 1; - } - - snprintf(this->sd.name, - sizeof(this->sd.name), "%s %s %d-%4.4x", - sensor->minfo.name, _this->name, - i2c_adapter_id(client->adapter), client->addr); - - this->sink_fmt.width = - sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; - this->sink_fmt.height = - sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; - this->compose.width = this->sink_fmt.width; - this->compose.height = this->sink_fmt.height; - this->crop[this->source_pad] = this->compose; - this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE; - if (this != sensor->pixel_array) { - this->crop[this->sink_pad] = this->compose; - this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK; - } - - this->sd.entity.ops = &smiapp_entity_ops; - - if (last == NULL) { - last = this; - continue; - } - - this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - this->sd.internal_ops = &smiapp_internal_ops; - this->sd.owner = THIS_MODULE; - v4l2_set_subdevdata(&this->sd, client); - - last = this; - } + smiapp_create_subdev(sensor, sensor->scaler, "scaler"); + smiapp_create_subdev(sensor, sensor->binner, "binner"); + smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array"); dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); -- cgit v1.2.3 From cc1488a1fcdcf8fee3ca12c82f5a48745b7fa45d Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Sep 2016 10:02:09 -0300 Subject: [media] smiapp: Explicitly define number of pads in initialisation Define the number of pads explicitly in initialising the sub-devices. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 957e37e1c25f..2090b7f2b9aa 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2536,7 +2536,8 @@ static void smiapp_cleanup(struct smiapp_sensor *sensor) } static void smiapp_create_subdev(struct smiapp_sensor *sensor, - struct smiapp_subdev *ssd, const char *name) + struct smiapp_subdev *ssd, const char *name, + unsigned short num_pads) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); @@ -2548,12 +2549,8 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor, ssd->sensor = sensor; - if (ssd == sensor->pixel_array) { - ssd->npads = 1; - } else { - ssd->npads = 2; - ssd->source_pad = 1; - } + ssd->npads = num_pads; + ssd->source_pad = num_pads - 1; snprintf(ssd->sd.name, sizeof(ssd->sd.name), "%s %s %d-%4.4x", sensor->minfo.name, @@ -2747,9 +2744,9 @@ static int smiapp_init(struct smiapp_sensor *sensor) if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - smiapp_create_subdev(sensor, sensor->scaler, "scaler"); - smiapp_create_subdev(sensor, sensor->binner, "binner"); - smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array"); + smiapp_create_subdev(sensor, sensor->scaler, "scaler", 2); + smiapp_create_subdev(sensor, sensor->binner, "binner", 2); + smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array", 1); dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); -- cgit v1.2.3 From 6d8d61fe661aa6466ed709e5459cd3255dea87b9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Sep 2016 10:04:52 -0300 Subject: [media] smiapp: Initialise media entity after sensor init This allows determining the number of pads in the entity based on the sensor. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 2090b7f2b9aa..4f9750324150 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -3058,12 +3058,7 @@ static int smiapp_probe(struct i2c_client *client, sensor->src->sd.internal_ops = &smiapp_internal_src_ops; sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; sensor->src->sensor = sensor; - sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; - rval = media_entity_pads_init(&sensor->src->sd.entity, 2, - sensor->src->pads); - if (rval < 0) - return rval; if (client->dev.of_node) { rval = smiapp_init(sensor); @@ -3071,6 +3066,11 @@ static int smiapp_probe(struct i2c_client *client, goto out_media_entity_cleanup; } + rval = media_entity_pads_init(&sensor->src->sd.entity, 2, + sensor->src->pads); + if (rval < 0) + goto out_media_entity_cleanup; + rval = v4l2_async_register_subdev(&sensor->src->sd); if (rval < 0) goto out_media_entity_cleanup; -- cgit v1.2.3 From 2fca9ca0d6fb172ab4c01f506fc864f2881b6f80 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Sep 2016 10:21:10 -0300 Subject: [media] smiapp: Split off sub-device registration into two Remove the loop in sub-device registration and create each sub-device explicitly instead. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 82 +++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 4f9750324150..86c0d7c6bf83 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2475,54 +2475,62 @@ static const struct v4l2_subdev_ops smiapp_ops; static const struct v4l2_subdev_internal_ops smiapp_internal_ops; static const struct media_entity_operations smiapp_entity_ops; -static int smiapp_register_subdevs(struct smiapp_sensor *sensor) +static int smiapp_register_subdev(struct smiapp_sensor *sensor, + struct smiapp_subdev *ssd, + struct smiapp_subdev *sink_ssd, + u16 source_pad, u16 sink_pad, u32 link_flags) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_subdev *ssds[] = { - sensor->scaler, - sensor->binner, - sensor->pixel_array, - }; - unsigned int i; int rval; - for (i = 0; i < SMIAPP_SUBDEVS - 1; i++) { - struct smiapp_subdev *this = ssds[i + 1]; - struct smiapp_subdev *last = ssds[i]; + if (!sink_ssd) + return 0; - if (!last) - continue; + rval = media_entity_pads_init(&ssd->sd.entity, + ssd->npads, ssd->pads); + if (rval) { + dev_err(&client->dev, + "media_entity_pads_init failed\n"); + return rval; + } - rval = media_entity_pads_init(&this->sd.entity, - this->npads, this->pads); - if (rval) { - dev_err(&client->dev, - "media_entity_pads_init failed\n"); - return rval; - } + rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, + &ssd->sd); + if (rval) { + dev_err(&client->dev, + "v4l2_device_register_subdev failed\n"); + return rval; + } - rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, - &this->sd); - if (rval) { - dev_err(&client->dev, - "v4l2_device_register_subdev failed\n"); - return rval; - } + rval = media_create_pad_link(&ssd->sd.entity, source_pad, + &sink_ssd->sd.entity, sink_pad, + link_flags); + if (rval) { + dev_err(&client->dev, + "media_create_pad_link failed\n"); + return rval; + } - rval = media_create_pad_link(&this->sd.entity, - this->source_pad, - &last->sd.entity, - last->sink_pad, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); - if (rval) { - dev_err(&client->dev, - "media_create_pad_link failed\n"); + return 0; +} + +static int smiapp_register_subdevs(struct smiapp_sensor *sensor) +{ + int rval; + + if (sensor->scaler) { + rval = smiapp_register_subdev( + sensor, sensor->binner, sensor->scaler, + SMIAPP_PAD_SRC, SMIAPP_PAD_SINK, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (rval < 0) return rval; - } } - return 0; + return smiapp_register_subdev( + sensor, sensor->pixel_array, sensor->binner, + SMIAPP_PA_PAD_SRC, SMIAPP_PAD_SINK, + MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); } static void smiapp_cleanup(struct smiapp_sensor *sensor) -- cgit v1.2.3 From 6c5ff7c8e8800c95be96c59f02ea31b8860ad745 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Sep 2016 12:15:15 -0300 Subject: [media] smiapp: Provide a common function to obtain native pixel array size The same pixel array size is required for the active format of each sub-device sink pad and try format of each sink pad of each opened file handle as well as for the native size rectangle. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 39 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 86c0d7c6bf83..e5d458420922 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2161,6 +2161,15 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, return 0; } +static void smiapp_get_native_size(struct smiapp_subdev *ssd, + struct v4l2_rect *r) +{ + r->top = 0; + r->left = 0; + r->width = ssd->sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; + r->height = ssd->sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; +} + static int __smiapp_get_selection(struct v4l2_subdev *subdev, struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_selection *sel) @@ -2192,17 +2201,12 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev, switch (sel->target) { case V4L2_SEL_TGT_CROP_BOUNDS: case V4L2_SEL_TGT_NATIVE_SIZE: - if (ssd == sensor->pixel_array) { - sel->r.left = sel->r.top = 0; - sel->r.width = - sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; - sel->r.height = - sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; - } else if (sel->pad == ssd->sink_pad) { + if (ssd == sensor->pixel_array) + smiapp_get_native_size(ssd, &sel->r); + else if (sel->pad == ssd->sink_pad) sel->r = sink_fmt; - } else { + else sel->r = *comp; - } break; case V4L2_SEL_TGT_CROP: case V4L2_SEL_TGT_COMPOSE_BOUNDS: @@ -2564,10 +2568,8 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor, sizeof(ssd->sd.name), "%s %s %d-%4.4x", sensor->minfo.name, name, i2c_adapter_id(client->adapter), client->addr); - ssd->sink_fmt.width = - sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; - ssd->sink_fmt.height = - sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; + smiapp_get_native_size(ssd, &ssd->sink_fmt); + ssd->compose.width = ssd->sink_fmt.width; ssd->compose.height = ssd->sink_fmt.height; ssd->crop[ssd->source_pad] = ssd->compose; @@ -2840,16 +2842,13 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, i); struct v4l2_rect *try_comp; - try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; - try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; + smiapp_get_native_size(ssd, try_crop); + + try_fmt->width = try_crop->width; + try_fmt->height = try_crop->height; try_fmt->code = mbus_code; try_fmt->field = V4L2_FIELD_NONE; - try_crop->top = 0; - try_crop->left = 0; - try_crop->width = try_fmt->width; - try_crop->height = try_fmt->height; - if (ssd != sensor->pixel_array) continue; -- cgit v1.2.3 From 624e9896c5bffee146ebb05b9366f8dc3f8b54aa Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 6 Sep 2016 09:51:17 -0300 Subject: [media] smiapp: Remove unnecessary BUG_ON()'s Instead, calculate how much is needed and then allocate the memory dynamically. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 24 ++++++++++++++++++------ drivers/media/i2c/smiapp/smiapp.h | 8 ++------ 2 files changed, 20 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index e5d458420922..9873b3d764db 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -621,7 +621,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor) static int smiapp_init_late_controls(struct smiapp_sensor *sensor) { unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ - sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE]; + sensor->csi_format->compressed - sensor->compressed_min_bpp]; unsigned int max, i; for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) { @@ -754,6 +754,7 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) { struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct smiapp_pll *pll = &sensor->pll; + u8 compressed_max_bpp = 0; unsigned int type, n; unsigned int i, pixel_order; int rval; @@ -825,17 +826,28 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) pll->binning_vertical = 1; pll->scale_m = sensor->scale_m; + for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { + sensor->compressed_min_bpp = + min(smiapp_csi_data_formats[i].compressed, + sensor->compressed_min_bpp); + compressed_max_bpp = + max(smiapp_csi_data_formats[i].compressed, + compressed_max_bpp); + } + + sensor->valid_link_freqs = devm_kcalloc( + &client->dev, + compressed_max_bpp - sensor->compressed_min_bpp + 1, + sizeof(*sensor->valid_link_freqs), GFP_KERNEL); + for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { const struct smiapp_csi_data_format *f = &smiapp_csi_data_formats[i]; unsigned long *valid_link_freqs = &sensor->valid_link_freqs[ - f->compressed - SMIAPP_COMPRESSED_BASE]; + f->compressed - sensor->compressed_min_bpp]; unsigned int j; - BUG_ON(f->compressed < SMIAPP_COMPRESSED_BASE); - BUG_ON(f->compressed > SMIAPP_COMPRESSED_MAX); - if (!(sensor->default_mbus_frame_fmts & 1 << i)) continue; @@ -1769,7 +1781,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev, valid_link_freqs = &sensor->valid_link_freqs[sensor->csi_format->compressed - - SMIAPP_COMPRESSED_BASE]; + - sensor->compressed_min_bpp]; __v4l2_ctrl_modify_range( sensor->link_freq, 0, diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index aae72bc87bf7..e71271ef764b 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -150,11 +150,6 @@ struct smiapp_csi_data_format { #define SMIAPP_PAD_SRC 1 #define SMIAPP_PADS 2 -#define SMIAPP_COMPRESSED_BASE 8 -#define SMIAPP_COMPRESSED_MAX 16 -#define SMIAPP_NR_OF_COMPRESSED (SMIAPP_COMPRESSED_MAX - \ - SMIAPP_COMPRESSED_BASE + 1) - struct smiapp_binning_subtype { u8 horizontal:4; u8 vertical:4; @@ -224,6 +219,7 @@ struct smiapp_sensor { bool streaming; bool dev_init_done; + u8 compressed_min_bpp; u8 *nvm; /* nvm memory buffer */ unsigned int nvm_size; /* bytes */ @@ -233,7 +229,7 @@ struct smiapp_sensor { struct smiapp_pll pll; /* Is a default format supported for a given BPP? */ - unsigned long valid_link_freqs[SMIAPP_NR_OF_COMPRESSED]; + unsigned long *valid_link_freqs; /* Pixel array controls */ struct v4l2_ctrl *analog_gain; -- cgit v1.2.3 From 231d1a014aeb8c2288316572f2fe876c5145b91c Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 7 Sep 2016 06:40:13 -0300 Subject: [media] smiapp: Always initialise the sensor in probe Initialise the sensor in probe. The reason why it wasn't previously done in case of platform data was that the probe() of the driver that provided the clock through the set_xclk() callback would need to finish before the probe() function of the smiapp driver. The set_xclk() callback no longer exists. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 30 +++++------------------------- 1 file changed, 5 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 9873b3d764db..8a58c641bc47 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2530,8 +2530,9 @@ static int smiapp_register_subdev(struct smiapp_sensor *sensor, return 0; } -static int smiapp_register_subdevs(struct smiapp_sensor *sensor) +static int smiapp_registered(struct v4l2_subdev *subdev) { + struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); int rval; if (sensor->scaler) { @@ -2819,25 +2820,6 @@ out_power_off: return rval; } -static int smiapp_registered(struct v4l2_subdev *subdev) -{ - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - struct i2c_client *client = v4l2_get_subdevdata(subdev); - int rval; - - if (!client->dev.of_node) { - rval = smiapp_init(sensor); - if (rval) - return rval; - } - - rval = smiapp_register_subdevs(sensor); - if (rval) - smiapp_cleanup(sensor); - - return rval; -} - static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct smiapp_subdev *ssd = to_smiapp_subdev(sd); @@ -3079,11 +3061,9 @@ static int smiapp_probe(struct i2c_client *client, sensor->src->sensor = sensor; sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; - if (client->dev.of_node) { - rval = smiapp_init(sensor); - if (rval) - goto out_media_entity_cleanup; - } + rval = smiapp_init(sensor); + if (rval) + goto out_media_entity_cleanup; rval = media_entity_pads_init(&sensor->src->sd.entity, 2, sensor->src->pads); -- cgit v1.2.3 From 997695407512c3d0a7bf2f5e589ab288ac6d0f6b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 19 Sep 2016 18:41:14 -0300 Subject: [media] smiapp: Fix resource management in registration failure If the registered() callback failed, resources were left unaccounted for. Fix this, as well as add unregistering the sub-devices in driver unregistered() callback. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 8a58c641bc47..9d7af8b2ae8e 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2524,12 +2524,22 @@ static int smiapp_register_subdev(struct smiapp_sensor *sensor, if (rval) { dev_err(&client->dev, "media_create_pad_link failed\n"); + v4l2_device_unregister_subdev(&ssd->sd); return rval; } return 0; } +static void smiapp_unregistered(struct v4l2_subdev *subdev) +{ + struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); + unsigned int i; + + for (i = 1; i < sensor->ssds_used; i++) + v4l2_device_unregister_subdev(&sensor->ssds[i].sd); +} + static int smiapp_registered(struct v4l2_subdev *subdev) { struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); @@ -2544,10 +2554,19 @@ static int smiapp_registered(struct v4l2_subdev *subdev) return rval; } - return smiapp_register_subdev( + rval = smiapp_register_subdev( sensor, sensor->pixel_array, sensor->binner, SMIAPP_PA_PAD_SRC, SMIAPP_PAD_SINK, MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE); + if (rval) + goto out_err; + + return 0; + +out_err: + smiapp_unregistered(subdev); + + return rval; } static void smiapp_cleanup(struct smiapp_sensor *sensor) @@ -2894,6 +2913,7 @@ static const struct media_entity_operations smiapp_entity_ops = { static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = { .registered = smiapp_registered, + .unregistered = smiapp_unregistered, .open = smiapp_open, .close = smiapp_close, }; -- cgit v1.2.3 From 3ecb86641b20c98f01df31ee0e22d36cc28660aa Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 12 Sep 2016 06:44:35 -0300 Subject: [media] smiapp: Merge smiapp_init() with smiapp_probe() The smiapp_probe() is the sole caller of smiapp_init(). Unify the two. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 423 ++++++++++++++++----------------- 1 file changed, 204 insertions(+), 219 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 9d7af8b2ae8e..384a13b9733b 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2622,223 +2622,6 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor, v4l2_set_subdevdata(&ssd->sd, client); } -static int smiapp_init(struct smiapp_sensor *sensor) -{ - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); - struct smiapp_pll *pll = &sensor->pll; - unsigned int i; - int rval; - - sensor->vana = devm_regulator_get(&client->dev, "vana"); - if (IS_ERR(sensor->vana)) { - dev_err(&client->dev, "could not get regulator for vana\n"); - return PTR_ERR(sensor->vana); - } - - sensor->ext_clk = devm_clk_get(&client->dev, NULL); - if (IS_ERR(sensor->ext_clk)) { - dev_err(&client->dev, "could not get clock (%ld)\n", - PTR_ERR(sensor->ext_clk)); - return -EPROBE_DEFER; - } - - rval = clk_set_rate(sensor->ext_clk, - sensor->hwcfg->ext_clk); - if (rval < 0) { - dev_err(&client->dev, - "unable to set clock freq to %u\n", - sensor->hwcfg->ext_clk); - return rval; - } - - sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", - GPIOD_OUT_LOW); - if (IS_ERR(sensor->xshutdown)) - return PTR_ERR(sensor->xshutdown); - - rval = smiapp_power_on(sensor); - if (rval) - return -ENODEV; - - rval = smiapp_identify_module(sensor); - if (rval) { - rval = -ENODEV; - goto out_power_off; - } - - rval = smiapp_get_all_limits(sensor); - if (rval) { - rval = -ENODEV; - goto out_power_off; - } - - /* - * Handle Sensor Module orientation on the board. - * - * The application of H-FLIP and V-FLIP on the sensor is modified by - * the sensor orientation on the board. - * - * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set - * both H-FLIP and V-FLIP for normal operation which also implies - * that a set/unset operation for user space HFLIP and VFLIP v4l2 - * controls will need to be internally inverted. - * - * Rotation also changes the bayer pattern. - */ - if (sensor->hwcfg->module_board_orient == - SMIAPP_MODULE_BOARD_ORIENT_180) - sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP | - SMIAPP_IMAGE_ORIENTATION_VFLIP; - - rval = smiapp_call_quirk(sensor, limits); - if (rval) { - dev_err(&client->dev, "limits quirks failed\n"); - goto out_power_off; - } - - if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) { - u32 val; - - rval = smiapp_read(sensor, - SMIAPP_REG_U8_BINNING_SUBTYPES, &val); - if (rval < 0) { - rval = -ENODEV; - goto out_power_off; - } - sensor->nbinning_subtypes = min_t(u8, val, - SMIAPP_BINNING_SUBTYPES); - - for (i = 0; i < sensor->nbinning_subtypes; i++) { - rval = smiapp_read( - sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val); - if (rval < 0) { - rval = -ENODEV; - goto out_power_off; - } - sensor->binning_subtypes[i] = - *(struct smiapp_binning_subtype *)&val; - - dev_dbg(&client->dev, "binning %xx%x\n", - sensor->binning_subtypes[i].horizontal, - sensor->binning_subtypes[i].vertical); - } - } - sensor->binning_horizontal = 1; - sensor->binning_vertical = 1; - - if (device_create_file(&client->dev, &dev_attr_ident) != 0) { - dev_err(&client->dev, "sysfs ident entry creation failed\n"); - rval = -ENOENT; - goto out_power_off; - } - /* SMIA++ NVM initialization - it will be read from the sensor - * when it is first requested by userspace. - */ - if (sensor->minfo.smiapp_version && sensor->hwcfg->nvm_size) { - sensor->nvm = devm_kzalloc(&client->dev, - sensor->hwcfg->nvm_size, GFP_KERNEL); - if (sensor->nvm == NULL) { - dev_err(&client->dev, "nvm buf allocation failed\n"); - rval = -ENOMEM; - goto out_cleanup; - } - - if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { - dev_err(&client->dev, "sysfs nvm entry failed\n"); - rval = -EBUSY; - goto out_cleanup; - } - } - - /* We consider this as profile 0 sensor if any of these are zero. */ - if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] || - !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] || - !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] || - !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) { - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; - } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] - != SMIAPP_SCALING_CAPABILITY_NONE) { - if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] - == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; - else - sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; - sensor->scaler = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] - == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { - sensor->scaler = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - } - sensor->binner = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; - sensor->ssds_used++; - - sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; - - /* prepare PLL configuration input values */ - pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; - pll->csi2.lanes = sensor->hwcfg->lanes; - pll->ext_clk_freq_hz = sensor->hwcfg->ext_clk; - pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; - /* Profile 0 sensors have no separate OP clock branch. */ - if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) - pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; - - smiapp_create_subdev(sensor, sensor->scaler, "scaler", 2); - smiapp_create_subdev(sensor, sensor->binner, "binner", 2); - smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array", 1); - - dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); - - sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - - /* final steps */ - smiapp_read_frame_fmt(sensor); - rval = smiapp_init_controls(sensor); - if (rval < 0) - goto out_cleanup; - - rval = smiapp_call_quirk(sensor, init); - if (rval) - goto out_cleanup; - - rval = smiapp_get_mbus_formats(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - - rval = smiapp_init_late_controls(sensor); - if (rval) { - rval = -ENODEV; - goto out_cleanup; - } - - mutex_lock(&sensor->mutex); - rval = smiapp_update_mode(sensor); - mutex_unlock(&sensor->mutex); - if (rval) { - dev_err(&client->dev, "update mode failed\n"); - goto out_cleanup; - } - - sensor->streaming = false; - sensor->dev_init_done = true; - - smiapp_power_off(sensor); - - return 0; - -out_cleanup: - smiapp_cleanup(sensor); - -out_power_off: - smiapp_power_off(sensor); - return rval; -} - static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct smiapp_subdev *ssd = to_smiapp_subdev(sd); @@ -3061,6 +2844,7 @@ static int smiapp_probe(struct i2c_client *client, { struct smiapp_sensor *sensor; struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev); + unsigned int i; int rval; if (hwcfg == NULL) @@ -3081,9 +2865,205 @@ static int smiapp_probe(struct i2c_client *client, sensor->src->sensor = sensor; sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; - rval = smiapp_init(sensor); + sensor->vana = devm_regulator_get(&client->dev, "vana"); + if (IS_ERR(sensor->vana)) { + dev_err(&client->dev, "could not get regulator for vana\n"); + return PTR_ERR(sensor->vana); + } + + sensor->ext_clk = devm_clk_get(&client->dev, NULL); + if (IS_ERR(sensor->ext_clk)) { + dev_err(&client->dev, "could not get clock (%ld)\n", + PTR_ERR(sensor->ext_clk)); + return -EPROBE_DEFER; + } + + rval = clk_set_rate(sensor->ext_clk, + sensor->hwcfg->ext_clk); + if (rval < 0) { + dev_err(&client->dev, + "unable to set clock freq to %u\n", + sensor->hwcfg->ext_clk); + return rval; + } + + sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown", + GPIOD_OUT_LOW); + if (IS_ERR(sensor->xshutdown)) + return PTR_ERR(sensor->xshutdown); + + rval = smiapp_power_on(sensor); if (rval) - goto out_media_entity_cleanup; + return -ENODEV; + + rval = smiapp_identify_module(sensor); + if (rval) { + rval = -ENODEV; + goto out_power_off; + } + + rval = smiapp_get_all_limits(sensor); + if (rval) { + rval = -ENODEV; + goto out_power_off; + } + + /* + * Handle Sensor Module orientation on the board. + * + * The application of H-FLIP and V-FLIP on the sensor is modified by + * the sensor orientation on the board. + * + * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set + * both H-FLIP and V-FLIP for normal operation which also implies + * that a set/unset operation for user space HFLIP and VFLIP v4l2 + * controls will need to be internally inverted. + * + * Rotation also changes the bayer pattern. + */ + if (sensor->hwcfg->module_board_orient == + SMIAPP_MODULE_BOARD_ORIENT_180) + sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP | + SMIAPP_IMAGE_ORIENTATION_VFLIP; + + rval = smiapp_call_quirk(sensor, limits); + if (rval) { + dev_err(&client->dev, "limits quirks failed\n"); + goto out_power_off; + } + + if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) { + u32 val; + + rval = smiapp_read(sensor, + SMIAPP_REG_U8_BINNING_SUBTYPES, &val); + if (rval < 0) { + rval = -ENODEV; + goto out_power_off; + } + sensor->nbinning_subtypes = min_t(u8, val, + SMIAPP_BINNING_SUBTYPES); + + for (i = 0; i < sensor->nbinning_subtypes; i++) { + rval = smiapp_read( + sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val); + if (rval < 0) { + rval = -ENODEV; + goto out_power_off; + } + sensor->binning_subtypes[i] = + *(struct smiapp_binning_subtype *)&val; + + dev_dbg(&client->dev, "binning %xx%x\n", + sensor->binning_subtypes[i].horizontal, + sensor->binning_subtypes[i].vertical); + } + } + sensor->binning_horizontal = 1; + sensor->binning_vertical = 1; + + if (device_create_file(&client->dev, &dev_attr_ident) != 0) { + dev_err(&client->dev, "sysfs ident entry creation failed\n"); + rval = -ENOENT; + goto out_power_off; + } + /* SMIA++ NVM initialization - it will be read from the sensor + * when it is first requested by userspace. + */ + if (sensor->minfo.smiapp_version && sensor->hwcfg->nvm_size) { + sensor->nvm = devm_kzalloc(&client->dev, + sensor->hwcfg->nvm_size, GFP_KERNEL); + if (sensor->nvm == NULL) { + dev_err(&client->dev, "nvm buf allocation failed\n"); + rval = -ENOMEM; + goto out_cleanup; + } + + if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { + dev_err(&client->dev, "sysfs nvm entry failed\n"); + rval = -EBUSY; + goto out_cleanup; + } + } + + /* We consider this as profile 0 sensor if any of these are zero. */ + if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] || + !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] || + !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] || + !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) { + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; + } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] + != SMIAPP_SCALING_CAPABILITY_NONE) { + if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] + == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; + else + sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; + sensor->scaler = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] + == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { + sensor->scaler = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + } + sensor->binner = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; + sensor->ssds_used++; + + sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; + + /* prepare PLL configuration input values */ + sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2; + sensor->pll.csi2.lanes = sensor->hwcfg->lanes; + sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk; + sensor->pll.scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; + /* Profile 0 sensors have no separate OP clock branch. */ + if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) + sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; + + smiapp_create_subdev(sensor, sensor->scaler, "scaler", 2); + smiapp_create_subdev(sensor, sensor->binner, "binner", 2); + smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array", 1); + + dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); + + sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; + + /* final steps */ + smiapp_read_frame_fmt(sensor); + rval = smiapp_init_controls(sensor); + if (rval < 0) + goto out_cleanup; + + rval = smiapp_call_quirk(sensor, init); + if (rval) + goto out_cleanup; + + rval = smiapp_get_mbus_formats(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + rval = smiapp_init_late_controls(sensor); + if (rval) { + rval = -ENODEV; + goto out_cleanup; + } + + mutex_lock(&sensor->mutex); + rval = smiapp_update_mode(sensor); + mutex_unlock(&sensor->mutex); + if (rval) { + dev_err(&client->dev, "update mode failed\n"); + goto out_cleanup; + } + + sensor->streaming = false; + sensor->dev_init_done = true; + + smiapp_power_off(sensor); rval = media_entity_pads_init(&sensor->src->sd.entity, 2, sensor->src->pads); @@ -3099,6 +3079,11 @@ static int smiapp_probe(struct i2c_client *client, out_media_entity_cleanup: media_entity_cleanup(&sensor->src->sd.entity); +out_cleanup: + smiapp_cleanup(sensor); + +out_power_off: + smiapp_power_off(sensor); return rval; } -- cgit v1.2.3 From 1344bf74c93b87fdc5c8d4f1612470b4c3c2906f Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 7 Sep 2016 07:37:47 -0300 Subject: [media] smiapp: Read frame format earlier The information gathered during frame format reading will be required earlier in the initialisation when it was available. Also return an error if frame format cannot be obtained. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 384a13b9733b..6ec17eab70ac 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2908,6 +2908,12 @@ static int smiapp_probe(struct i2c_client *client, goto out_power_off; } + rval = smiapp_read_frame_fmt(sensor); + if (rval) { + rval = -ENODEV; + goto out_power_off; + } + /* * Handle Sensor Module orientation on the board. * @@ -3030,8 +3036,6 @@ static int smiapp_probe(struct i2c_client *client, sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; - /* final steps */ - smiapp_read_frame_fmt(sensor); rval = smiapp_init_controls(sensor); if (rval < 0) goto out_cleanup; -- cgit v1.2.3 From a118e61edc3e54bd727a6f6d7193e40270cd3711 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 7 Sep 2016 08:55:34 -0300 Subject: [media] smiapp: Unify setting up sub-devices The initialisation of the source sub-device is somewhat different as it's not created by the smiapp driver itself. Remove redundancy in initialising the two kind of sub-devices. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 6ec17eab70ac..7ac0d4e0cc89 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2591,6 +2591,7 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor, if (ssd != sensor->src) v4l2_subdev_init(&ssd->sd, &smiapp_ops); + ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ssd->sensor = sensor; ssd->npads = num_pads; @@ -2616,7 +2617,6 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor, if (ssd == sensor->src) return; - ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; ssd->sd.internal_ops = &smiapp_internal_ops; ssd->sd.owner = THIS_MODULE; v4l2_set_subdevdata(&ssd->sd, client); @@ -2861,9 +2861,6 @@ static int smiapp_probe(struct i2c_client *client, v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops); sensor->src->sd.internal_ops = &smiapp_internal_src_ops; - sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; - sensor->src->sensor = sensor; - sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; sensor->vana = devm_regulator_get(&client->dev, "vana"); if (IS_ERR(sensor->vana)) { -- cgit v1.2.3 From df0e40339b48e149f25da9010bc92a39afbf5e66 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 7 Sep 2016 08:39:52 -0300 Subject: [media] smiapp: Use SMIAPP_PADS when referring to number of pads Replace plain value 2 with SMIAPP_PADS when referring to the number of pads. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index e71271ef764b..f9febe0a056d 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -157,9 +157,9 @@ struct smiapp_binning_subtype { struct smiapp_subdev { struct v4l2_subdev sd; - struct media_pad pads[2]; + struct media_pad pads[SMIAPP_PADS]; struct v4l2_rect sink_fmt; - struct v4l2_rect crop[2]; + struct v4l2_rect crop[SMIAPP_PADS]; struct v4l2_rect compose; /* compose on sink */ unsigned short sink_pad; unsigned short source_pad; -- cgit v1.2.3 From 3fc34b7beb89472b61f919ec0f8699e2a3b46d94 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 5 Sep 2016 08:18:34 -0300 Subject: [media] smiapp: Obtain frame layout from the frame descriptor Besides the image data, SMIA++ compliant sensors also provide embedded data in form of registers used to capture the image. Store this information for later use in frame descriptor and routing. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 46 +++++++++++++++++++--------------- drivers/media/i2c/smiapp/smiapp.h | 5 +++- 2 files changed, 30 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 7ac0d4e0cc89..a7afcea5a5c5 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -68,10 +68,9 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; unsigned int i; - int rval; + int pixel_count = 0; int line_count = 0; - int embedded_start = -1, embedded_end = -1; - int image_start = 0; + int rval; rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE, &fmt_model_type); @@ -166,33 +165,40 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) dev_dbg(&client->dev, "%s pixels: %d %s\n", what, pixels, which); - if (i < ncol_desc) + if (i < ncol_desc) { + if (pixelcode == + SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE) + sensor->visible_pixel_start = pixel_count; + pixel_count += pixels; continue; + } /* Handle row descriptors */ - if (pixelcode - == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) { - embedded_start = line_count; - } else { - if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE - || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2) - image_start = line_count; - if (embedded_start != -1 && embedded_end == -1) - embedded_end = line_count; + switch (pixelcode) { + case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED: + if (sensor->embedded_end) + break; + sensor->embedded_start = line_count; + sensor->embedded_end = line_count + pixels; + break; + case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE: + sensor->image_start = line_count; + break; } line_count += pixels; } - if (embedded_start == -1 || embedded_end == -1) { - embedded_start = 0; - embedded_end = 0; + if (sensor->embedded_end > sensor->image_start) { + dev_dbg(&client->dev, + "adjusting image start line to %u (was %u)\n", + sensor->embedded_end, sensor->image_start); + sensor->image_start = sensor->embedded_end; } - sensor->image_start = image_start; - dev_dbg(&client->dev, "embedded data from lines %d to %d\n", - embedded_start, embedded_end); - dev_dbg(&client->dev, "image data starts at line %d\n", image_start); + sensor->embedded_start, sensor->embedded_end); + dev_dbg(&client->dev, "image data starts at line %d\n", + sensor->image_start); return 0; } diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index f9febe0a056d..d7b52a61af4f 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -213,7 +213,10 @@ struct smiapp_sensor { u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ u8 frame_skip; - u16 image_start; /* Offset to first line after metadata lines */ + u16 embedded_start; /* embedded data start line */ + u16 embedded_end; + u16 image_start; /* image data start line */ + u16 visible_pixel_start; /* start pixel of the visible image */ int power_count; -- cgit v1.2.3 From e43665a9d7b41b4b35069e7d3cf29e8a8a40d554 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 7 Sep 2016 09:53:42 -0300 Subject: [media] smiapp: Improve debug messages from frame layout reading Provide more debugging information on reading the frame layout. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index a7afcea5a5c5..1337b22e2380 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -100,12 +100,11 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) u32 pixels; char *which; char *what; + u32 reg; if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) { - rval = smiapp_read( - sensor, - SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i), - &desc); + reg = SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i); + rval = smiapp_read(sensor, reg, &desc); if (rval) return rval; @@ -116,10 +115,8 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK; } else if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) { - rval = smiapp_read( - sensor, - SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i), - &desc); + reg = SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i); + rval = smiapp_read(sensor, reg, &desc); if (rval) return rval; @@ -158,12 +155,12 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) break; default: what = "invalid"; - dev_dbg(&client->dev, "pixelcode %d\n", pixelcode); break; } - dev_dbg(&client->dev, "%s pixels: %d %s\n", - what, pixels, which); + dev_dbg(&client->dev, + "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg, + what, pixels, which, pixelcode); if (i < ncol_desc) { if (pixelcode == -- cgit v1.2.3 From 2aa8e838a303c7c9ed4b2761eb8ffe0930320d24 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Sep 2016 05:46:47 -0300 Subject: [media] smiapp: Remove useless newlines and other small cleanups The code probably has been unindented at some point but rewrapping has not been done. Do it now. Also remove a useless memory allocation failure message. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 1337b22e2380..2e8b7bf32c87 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -446,8 +446,7 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP; orient ^= sensor->hvflip_inv_mask; - rval = smiapp_write(sensor, - SMIAPP_REG_U8_IMAGE_ORIENTATION, + rval = smiapp_write(sensor, SMIAPP_REG_U8_IMAGE_ORIENTATION, orient); if (rval < 0) return rval; @@ -462,10 +461,8 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) __smiapp_update_exposure_limits(sensor); if (exposure > sensor->exposure->maximum) { - sensor->exposure->val = - sensor->exposure->maximum; - rval = smiapp_set_ctrl( - sensor->exposure); + sensor->exposure->val = sensor->exposure->maximum; + rval = smiapp_set_ctrl(sensor->exposure); if (rval < 0) return rval; } @@ -1322,8 +1319,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) if (!sensor->pixel_array) return 0; - rval = v4l2_ctrl_handler_setup( - &sensor->pixel_array->ctrl_handler); + rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler); if (rval) goto out_cci_addr_fail; @@ -1629,7 +1625,8 @@ static int __smiapp_get_format(struct v4l2_subdev *subdev, struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, + fmt->pad); } else { struct v4l2_rect *r; @@ -1729,7 +1726,6 @@ static void smiapp_propagate(struct v4l2_subdev *subdev, static const struct smiapp_csi_data_format *smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code) { - const struct smiapp_csi_data_format *csi_format = sensor->csi_format; unsigned int i; for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { @@ -1738,7 +1734,7 @@ static const struct smiapp_csi_data_format return &smiapp_csi_data_formats[i]; } - return csi_format; + return sensor->csi_format; } static int smiapp_set_format_source(struct v4l2_subdev *subdev, @@ -2072,8 +2068,7 @@ static int smiapp_set_compose(struct v4l2_subdev *subdev, smiapp_set_compose_scaler(subdev, cfg, sel, crops, comp); *comp = sel->r; - smiapp_propagate(subdev, cfg, sel->which, - V4L2_SEL_TGT_COMPOSE); + smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE); if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) return smiapp_update_mode(sensor); @@ -2150,9 +2145,8 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev, ->height; src_size = &_r; } else { - src_size = - v4l2_subdev_get_try_compose( - subdev, cfg, ssd->sink_pad); + src_size = v4l2_subdev_get_try_compose( + subdev, cfg, ssd->sink_pad); } } @@ -2638,7 +2632,8 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) for (i = 0; i < ssd->npads; i++) { struct v4l2_mbus_framefmt *try_fmt = v4l2_subdev_get_try_format(sd, fh->pad, i); - struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, i); + struct v4l2_rect *try_crop = + v4l2_subdev_get_try_crop(sd, fh->pad, i); struct v4l2_rect *try_comp; smiapp_get_native_size(ssd, try_crop); @@ -2878,8 +2873,7 @@ static int smiapp_probe(struct i2c_client *client, return -EPROBE_DEFER; } - rval = clk_set_rate(sensor->ext_clk, - sensor->hwcfg->ext_clk); + rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk); if (rval < 0) { dev_err(&client->dev, "unable to set clock freq to %u\n", @@ -2980,7 +2974,6 @@ static int smiapp_probe(struct i2c_client *client, sensor->nvm = devm_kzalloc(&client->dev, sensor->hwcfg->nvm_size, GFP_KERNEL); if (sensor->nvm == NULL) { - dev_err(&client->dev, "nvm buf allocation failed\n"); rval = -ENOMEM; goto out_cleanup; } -- cgit v1.2.3 From 1b81717ed7be8a88345dde1e0cffcc31a7693d81 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Sep 2016 05:49:27 -0300 Subject: [media] smiapp: Obtain correct media bus code for try format The media bus code obtained for try format may have been a code that the sensor did not even support. Use a supported code with the current pixel order. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 2e8b7bf32c87..5f4680d9d822 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2623,8 +2623,6 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { struct smiapp_subdev *ssd = to_smiapp_subdev(sd); struct smiapp_sensor *sensor = ssd->sensor; - u32 mbus_code = - smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code; unsigned int i; mutex_lock(&sensor->mutex); @@ -2640,7 +2638,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) try_fmt->width = try_crop->width; try_fmt->height = try_crop->height; - try_fmt->code = mbus_code; + try_fmt->code = sensor->internal_csi_format->code; try_fmt->field = V4L2_FIELD_NONE; if (ssd != sensor->pixel_array) -- cgit v1.2.3 From fbffb28f0337801d284d13c3a559e85697726afb Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Sep 2016 09:08:26 -0300 Subject: [media] smiapp: Drop a debug print on frame size and bit depth The first time the sensor is powered on, the information is not yet available. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 5f4680d9d822..8f9690e375bf 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -926,12 +926,6 @@ static int smiapp_update_mode(struct smiapp_sensor *sensor) unsigned int binning_mode; int rval; - dev_dbg(&client->dev, "frame size: %dx%d\n", - sensor->src->crop[SMIAPP_PAD_SRC].width, - sensor->src->crop[SMIAPP_PAD_SRC].height); - dev_dbg(&client->dev, "csi format width: %d\n", - sensor->csi_format->width); - /* Binning has to be set up here; it affects limits */ if (sensor->binning_horizontal == 1 && sensor->binning_vertical == 1) { -- cgit v1.2.3 From b08726bf2ea03d1eabf8908c70a3518fa502313b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Thu, 8 Sep 2016 10:50:07 -0300 Subject: [media] smiapp-pll: Don't complain aloud about failing PLL calculation Don't complain about a failure to compute the pre_pll divisor. The function is used to determine whether a particular combination of bits per sample value and a link frequency can be used, in which case there are lots of unnecessary driver messages. During normal operation the failure generally does not happen. Use dev_dbg() instead. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp-pll.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c index e3348db56c46..771db56332b2 100644 --- a/drivers/media/i2c/smiapp-pll.c +++ b/drivers/media/i2c/smiapp-pll.c @@ -479,7 +479,8 @@ int smiapp_pll_calculate(struct device *dev, return 0; } - dev_info(dev, "unable to compute pre_pll divisor\n"); + dev_dbg(dev, "unable to compute pre_pll divisor\n"); + return rval; } EXPORT_SYMBOL_GPL(smiapp_pll_calculate); -- cgit v1.2.3 From 88b3e311b52679a5c81af6bb0495d2c45049bb07 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Sep 2016 11:25:42 -0300 Subject: [media] smiapp: Drop BUG_ON() in suspend path Checking that the mutex is not acquired is unnecessary for user processes are stopped by this point. Drop the check. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 8f9690e375bf..1891c28ca6a4 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2709,8 +2709,6 @@ static int smiapp_suspend(struct device *dev) struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); bool streaming; - BUG_ON(mutex_is_locked(&sensor->mutex)); - if (sensor->power_count == 0) return 0; -- cgit v1.2.3 From df77542ede76774cfbdc852d0e09b6f800941be1 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Sep 2016 19:16:32 -0300 Subject: [media] smiapp: Set device for pixel array and binner The dev field of the v4l2_subdev was left NULL for the pixel array and binner sub-devices. Fix this. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 1891c28ca6a4..3ea4f12ecee2 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -2610,6 +2610,7 @@ static void smiapp_create_subdev(struct smiapp_sensor *sensor, ssd->sd.internal_ops = &smiapp_internal_ops; ssd->sd.owner = THIS_MODULE; + ssd->sd.dev = &client->dev; v4l2_set_subdevdata(&ssd->sd, client); } -- cgit v1.2.3 From 4ecc2d75c0c5fc959d207ef90da19df7771d01c9 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 14 Sep 2016 11:58:17 -0300 Subject: [media] smiapp: Set use suspend and resume ops for other functions Use the suspend and resume ops for freeze, thaw, poweroff and restore callbacks as well. Signed-off-by: Sakari Ailus Reviewed-by: Sebastian Reichel Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 3ea4f12ecee2..88ad4b97ba85 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -3111,8 +3111,7 @@ static const struct i2c_device_id smiapp_id_table[] = { MODULE_DEVICE_TABLE(i2c, smiapp_id_table); static const struct dev_pm_ops smiapp_pm_ops = { - .suspend = smiapp_suspend, - .resume = smiapp_resume, + SET_SYSTEM_SLEEP_PM_OPS(smiapp_suspend, smiapp_resume) }; static struct i2c_driver smiapp_i2c_driver = { -- cgit v1.2.3 From cbba45d43631d0414266d7e79827da3f491f1b1e Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 13 Sep 2016 10:01:03 -0300 Subject: [media] smiapp: Use runtime PM Switch to runtime PM in sensor power management. The internal power count is thus removed. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 131 +++++++++++++++++++++------------ drivers/media/i2c/smiapp/smiapp.h | 11 +-- 2 files changed, 83 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 88ad4b97ba85..68adc1b28985 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -1202,9 +1203,17 @@ out: * Power management */ -static int smiapp_power_on(struct smiapp_sensor *sensor) +static int smiapp_power_on(struct device *dev) { - struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); + /* + * The sub-device related to the I2C device is always the + * source one, i.e. ssds[0]. + */ + struct smiapp_sensor *sensor = + container_of(ssd, struct smiapp_sensor, ssds[0]); unsigned int sleep; int rval; @@ -1330,16 +1339,24 @@ static int smiapp_power_on(struct smiapp_sensor *sensor) return 0; out_cci_addr_fail: + gpiod_set_value(sensor->xshutdown, 0); clk_disable_unprepare(sensor->ext_clk); out_xclk_fail: regulator_disable(sensor->vana); + return rval; } -static void smiapp_power_off(struct smiapp_sensor *sensor) +static int smiapp_power_off(struct device *dev) { + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *subdev = i2c_get_clientdata(client); + struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); + struct smiapp_sensor *sensor = + container_of(ssd, struct smiapp_sensor, ssds[0]); + /* * Currently power/clock to lens are enable/disabled separately * but they are essentially the same signals. So if the sensor is @@ -1357,31 +1374,26 @@ static void smiapp_power_off(struct smiapp_sensor *sensor) usleep_range(5000, 5000); regulator_disable(sensor->vana); sensor->streaming = false; + + return 0; } static int smiapp_set_power(struct v4l2_subdev *subdev, int on) { - struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int ret = 0; + int rval = 0; - mutex_lock(&sensor->power_mutex); + if (on) { + rval = pm_runtime_get_sync(subdev->dev); + if (rval >= 0) + return 0; - if (on && !sensor->power_count) { - /* Power on and perform initialisation. */ - ret = smiapp_power_on(sensor); - if (ret < 0) - goto out; - } else if (!on && sensor->power_count == 1) { - smiapp_power_off(sensor); + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(subdev->dev); } - /* Update the power count. */ - sensor->power_count += on ? 1 : -1; - WARN_ON(sensor->power_count < 0); + pm_runtime_put(subdev->dev); -out: - mutex_unlock(&sensor->power_mutex); - return ret; + return rval; } /* ----------------------------------------------------------------------------- @@ -2310,15 +2322,25 @@ smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, return -EBUSY; if (!sensor->nvm_size) { + int rval; + /* NVM not read yet - read it now */ sensor->nvm_size = sensor->hwcfg->nvm_size; - if (smiapp_set_power(subdev, 1) < 0) + + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put(&client->dev); return -ENODEV; + } + if (smiapp_read_nvm(sensor, sensor->nvm)) { dev_err(&client->dev, "nvm read failed\n"); return -ENODEV; } - smiapp_set_power(subdev, 0); + + pm_runtime_put(&client->dev); } /* * NVM is still way below a PAGE_SIZE, so we can safely @@ -2619,6 +2641,7 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) struct smiapp_subdev *ssd = to_smiapp_subdev(sd); struct smiapp_sensor *sensor = ssd->sensor; unsigned int i; + int rval; mutex_lock(&sensor->mutex); @@ -2645,12 +2668,22 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) mutex_unlock(&sensor->mutex); - return smiapp_set_power(sd, 1); + rval = pm_runtime_get_sync(sd->dev); + if (rval >= 0) + return 0; + + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(sd->dev); + pm_runtime_put(sd->dev); + + return rval; } static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - return smiapp_set_power(sd, 0); + pm_runtime_put(sd->dev); + + return 0; } static const struct v4l2_subdev_video_ops smiapp_video_ops = { @@ -2708,18 +2741,20 @@ static int smiapp_suspend(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *subdev = i2c_get_clientdata(client); struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - bool streaming; + bool streaming = sensor->streaming; + int rval; - if (sensor->power_count == 0) - return 0; + rval = pm_runtime_get_sync(dev); + if (rval < 0) { + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(&client->dev); + pm_runtime_put(dev); + return -EAGAIN; + } if (sensor->streaming) smiapp_stop_streaming(sensor); - streaming = sensor->streaming; - - smiapp_power_off(sensor); - /* save state for resume */ sensor->streaming = streaming; @@ -2731,14 +2766,9 @@ static int smiapp_resume(struct device *dev) struct i2c_client *client = to_i2c_client(dev); struct v4l2_subdev *subdev = i2c_get_clientdata(client); struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); - int rval; - - if (sensor->power_count == 0) - return 0; + int rval = 0; - rval = smiapp_power_on(sensor); - if (rval) - return rval; + pm_runtime_put(dev); if (sensor->streaming) rval = smiapp_start_streaming(sensor); @@ -2845,7 +2875,6 @@ static int smiapp_probe(struct i2c_client *client, sensor->hwcfg = hwcfg; mutex_init(&sensor->mutex); - mutex_init(&sensor->power_mutex); sensor->src = &sensor->ssds[sensor->ssds_used]; v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops); @@ -2877,9 +2906,13 @@ static int smiapp_probe(struct i2c_client *client, if (IS_ERR(sensor->xshutdown)) return PTR_ERR(sensor->xshutdown); - rval = smiapp_power_on(sensor); - if (rval) - return -ENODEV; + pm_runtime_enable(&client->dev); + + rval = pm_runtime_get_sync(&client->dev); + if (rval < 0) { + rval = -ENODEV; + goto out_power_off; + } rval = smiapp_identify_module(sensor); if (rval) { @@ -3051,8 +3084,6 @@ static int smiapp_probe(struct i2c_client *client, sensor->streaming = false; sensor->dev_init_done = true; - smiapp_power_off(sensor); - rval = media_entity_pads_init(&sensor->src->sd.entity, 2, sensor->src->pads); if (rval < 0) @@ -3062,6 +3093,8 @@ static int smiapp_probe(struct i2c_client *client, if (rval < 0) goto out_media_entity_cleanup; + pm_runtime_put(&client->dev); + return 0; out_media_entity_cleanup: @@ -3071,7 +3104,9 @@ out_cleanup: smiapp_cleanup(sensor); out_power_off: - smiapp_power_off(sensor); + pm_runtime_put(&client->dev); + pm_runtime_disable(&client->dev); + return rval; } @@ -3083,11 +3118,8 @@ static int smiapp_remove(struct i2c_client *client) v4l2_async_unregister_subdev(subdev); - if (sensor->power_count) { - gpiod_set_value(sensor->xshutdown, 0); - clk_disable_unprepare(sensor->ext_clk); - sensor->power_count = 0; - } + pm_runtime_suspend(&client->dev); + pm_runtime_disable(&client->dev); for (i = 0; i < sensor->ssds_used; i++) { v4l2_device_unregister_subdev(&sensor->ssds[i].sd); @@ -3112,6 +3144,7 @@ MODULE_DEVICE_TABLE(i2c, smiapp_id_table); static const struct dev_pm_ops smiapp_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(smiapp_suspend, smiapp_resume) + SET_RUNTIME_PM_OPS(smiapp_power_off, smiapp_power_on, NULL) }; static struct i2c_driver smiapp_i2c_driver = { diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h index d7b52a61af4f..f74d695018b9 100644 --- a/drivers/media/i2c/smiapp/smiapp.h +++ b/drivers/media/i2c/smiapp/smiapp.h @@ -176,16 +176,9 @@ struct smiapp_sensor { * "mutex" is used to serialise access to all fields here * except v4l2_ctrls at the end of the struct. "mutex" is also * used to serialise access to file handle specific - * information. The exception to this rule is the power_mutex - * below. + * information. */ struct mutex mutex; - /* - * power_mutex is used to serialise power management related - * activities. Acquiring "mutex" at that time isn't necessary - * since there are no other users anyway. - */ - struct mutex power_mutex; struct smiapp_subdev ssds[SMIAPP_SUBDEVS]; u32 ssds_used; struct smiapp_subdev *src; @@ -218,8 +211,6 @@ struct smiapp_sensor { u16 image_start; /* image data start line */ u16 visible_pixel_start; /* start pixel of the visible image */ - int power_count; - bool streaming; bool dev_init_done; u8 compressed_min_bpp; -- cgit v1.2.3 From 93bef23024983d707248c25a849f5860119cd5e4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 14 Sep 2016 12:29:23 -0300 Subject: [media] smiapp: Implement support for autosuspend Delay suspending the device by 1000 ms by default. This is done on explicit power off through s_power() callback, through releasing the file descriptor, NVM read or when the probe finishes. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/smiapp/smiapp-core.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c index 68adc1b28985..59872b31f832 100644 --- a/drivers/media/i2c/smiapp/smiapp-core.c +++ b/drivers/media/i2c/smiapp/smiapp-core.c @@ -1380,17 +1380,22 @@ static int smiapp_power_off(struct device *dev) static int smiapp_set_power(struct v4l2_subdev *subdev, int on) { - int rval = 0; + int rval; - if (on) { - rval = pm_runtime_get_sync(subdev->dev); - if (rval >= 0) - return 0; + if (!on) { + pm_runtime_mark_last_busy(subdev->dev); + pm_runtime_put_autosuspend(subdev->dev); - if (rval != -EBUSY && rval != -EAGAIN) - pm_runtime_set_active(subdev->dev); + return 0; } + rval = pm_runtime_get_sync(subdev->dev); + if (rval >= 0) + return 0; + + if (rval != -EBUSY && rval != -EAGAIN) + pm_runtime_set_active(subdev->dev); + pm_runtime_put(subdev->dev); return rval; @@ -2340,7 +2345,8 @@ smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, return -ENODEV; } - pm_runtime_put(&client->dev); + pm_runtime_mark_last_busy(&client->dev); + pm_runtime_put_autosuspend(&client->dev); } /* * NVM is still way below a PAGE_SIZE, so we can safely @@ -2681,7 +2687,8 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { - pm_runtime_put(sd->dev); + pm_runtime_mark_last_busy(sd->dev); + pm_runtime_put_autosuspend(sd->dev); return 0; } @@ -3093,7 +3100,9 @@ static int smiapp_probe(struct i2c_client *client, if (rval < 0) goto out_media_entity_cleanup; - pm_runtime_put(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, 1000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put_autosuspend(&client->dev); return 0; -- cgit v1.2.3 From 66b2ab271afc0888b87a44dc946cc68067ba0985 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Thu, 18 Aug 2016 11:33:27 -0300 Subject: [media] videodev2.h Add HSV formats These formats store the color information of the image in a geometrical representation. The colors are mapped into a cylinder, where the angle is the HUE, the height is the VALUE and the distance to the center is the SATURATION. This is a very useful format for image segmentation algorithms. Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 2 ++ include/uapi/linux/videodev2.h | 4 ++++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 39e19b4222be..181381d1dc77 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1200,6 +1200,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_TM6000: descr = "A/V + VBI Mux Packet"; break; case V4L2_PIX_FMT_CIT_YYVYUY: descr = "GSPCA CIT YYVYUY"; break; case V4L2_PIX_FMT_KONICA420: descr = "GSPCA KONICA420"; break; + case V4L2_PIX_FMT_HSV24: descr = "24-bit HSV 8-8-8"; break; + case V4L2_PIX_FMT_HSV32: descr = "32-bit XHSV 8-8-8-8"; break; case V4L2_SDR_FMT_CU8: descr = "Complex U8"; break; case V4L2_SDR_FMT_CU16LE: descr = "Complex U16LE"; break; case V4L2_SDR_FMT_CS8: descr = "Complex S8"; break; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index 2da477c04479..6b480c91778e 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -587,6 +587,10 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ +/* HSV formats */ +#define V4L2_PIX_FMT_HSV24 v4l2_fourcc('H', 'S', 'V', '3') +#define V4L2_PIX_FMT_HSV32 v4l2_fourcc('H', 'S', 'V', '4') + /* compressed formats */ #define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M', 'J', 'P', 'G') /* Motion-JPEG */ #define V4L2_PIX_FMT_JPEG v4l2_fourcc('J', 'P', 'E', 'G') /* JFIF JPEG */ -- cgit v1.2.3 From 646895e9361af5ea501d0325f9b0251080a32854 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Fri, 15 Jul 2016 06:09:47 -0300 Subject: [media] vivid: Code refactor for color encoding Replace is_yuv with color_enc Which can be used by other color encodings such us HSV. This change should ease the review of the following patches. Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 49 +++++++++++++++-------- drivers/media/platform/vivid/vivid-core.h | 2 +- drivers/media/platform/vivid/vivid-vid-common.c | 52 ++++++++++++------------- include/media/v4l2-tpg.h | 7 +++- 4 files changed, 66 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 1684810cab83..c4153307bfc5 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -237,13 +237,13 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: - tpg->is_yuv = false; + tpg->color_enc = TGP_COLOR_ENC_RGB; break; case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_YUV565: case V4L2_PIX_FMT_YUV32: - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV420M: case V4L2_PIX_FMT_YVU420M: @@ -256,7 +256,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->hdownsampling[1] = 2; tpg->hdownsampling[2] = 2; tpg->planes = 3; - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV422M: case V4L2_PIX_FMT_YVU422M: @@ -268,7 +268,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->hdownsampling[1] = 2; tpg->hdownsampling[2] = 2; tpg->planes = 3; - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_NV16M: case V4L2_PIX_FMT_NV61M: @@ -280,7 +280,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->hdownsampling[1] = 1; tpg->hmask[1] = ~1; tpg->planes = 2; - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_NV12M: case V4L2_PIX_FMT_NV21M: @@ -292,7 +292,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->hdownsampling[1] = 1; tpg->hmask[1] = ~1; tpg->planes = 2; - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUV444M: case V4L2_PIX_FMT_YVU444M: @@ -302,21 +302,21 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->vdownsampling[2] = 1; tpg->hdownsampling[1] = 1; tpg->hdownsampling[2] = 1; - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_NV24: case V4L2_PIX_FMT_NV42: tpg->vdownsampling[1] = 1; tpg->hdownsampling[1] = 1; tpg->planes = 2; - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_VYUY: tpg->hmask[0] = ~1; - tpg->is_yuv = true; + tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; default: return false; @@ -775,7 +775,8 @@ static void precalculate_color(struct tpg_data *tpg, int k) * Remember that r, g and b are still in the 0 - 0xff0 range. */ if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED && - tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL && !tpg->is_yuv) { + tpg->rgb_range == V4L2_DV_RGB_RANGE_FULL && + tpg->color_enc == TGP_COLOR_ENC_RGB) { /* * Convert from full range (which is what r, g and b are) * to limited range (which is the 'real' RGB range), which @@ -785,7 +786,9 @@ static void precalculate_color(struct tpg_data *tpg, int k) g = (g * 219) / 255 + (16 << 4); b = (b * 219) / 255 + (16 << 4); } else if (tpg->real_rgb_range != V4L2_DV_RGB_RANGE_LIMITED && - tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED && !tpg->is_yuv) { + tpg->rgb_range == V4L2_DV_RGB_RANGE_LIMITED && + tpg->color_enc == TGP_COLOR_ENC_RGB) { + /* * Clamp r, g and b to the limited range and convert to full * range since that's what we deliver. @@ -818,7 +821,7 @@ static void precalculate_color(struct tpg_data *tpg, int k) cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128); cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128); - if (tpg->is_yuv) { + if (tpg->color_enc == TGP_COLOR_ENC_YCBCR) { tpg->colors[k][0] = clamp(y >> 4, 1, 254); tpg->colors[k][1] = clamp(cb >> 4, 1, 254); tpg->colors[k][2] = clamp(cr >> 4, 1, 254); @@ -827,7 +830,7 @@ static void precalculate_color(struct tpg_data *tpg, int k) ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b); } - if (tpg->is_yuv) { + if (tpg->color_enc == TGP_COLOR_ENC_YCBCR) { /* Convert to YCbCr */ int y, cb, cr; @@ -1840,7 +1843,8 @@ static void tpg_recalc(struct tpg_data *tpg) if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) tpg->real_quantization = - V4L2_MAP_QUANTIZATION_DEFAULT(!tpg->is_yuv, + V4L2_MAP_QUANTIZATION_DEFAULT( + tpg->color_enc != TGP_COLOR_ENC_YCBCR, tpg->colorspace, tpg->real_ycbcr_enc); tpg_precalculate_colors(tpg); @@ -1887,11 +1891,24 @@ static int tpg_pattern_avg(const struct tpg_data *tpg, return -1; } +static const char *tpg_color_enc_str(enum tgp_color_enc + color_enc) +{ + switch (color_enc) { + case TGP_COLOR_ENC_YCBCR: + return "Y'CbCr"; + case TGP_COLOR_ENC_RGB: + default: + return "R'G'B"; + + } +} + void tpg_log_status(struct tpg_data *tpg) { pr_info("tpg source WxH: %ux%u (%s)\n", - tpg->src_width, tpg->src_height, - tpg->is_yuv ? "YCbCr" : "RGB"); + tpg->src_width, tpg->src_height, + tpg_color_enc_str(tpg->color_enc)); pr_info("tpg field: %u\n", tpg->field); pr_info("tpg crop: %ux%u@%dx%d\n", tpg->crop.width, tpg->crop.height, tpg->crop.left, tpg->crop.top); diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index a7daa40d0a49..b59b49456d45 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -80,7 +80,7 @@ extern unsigned vivid_debug; struct vivid_fmt { u32 fourcc; /* v4l2 format id */ - bool is_yuv; + enum tgp_color_enc color_enc; bool can_do_overlay; u8 vdownsampling[TPG_MAX_PLANES]; u32 alpha_mask; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index fcda3ae4e6b0..f4c35ba5f070 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -48,7 +48,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YUYV, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 1, .buffers = 1, .data_offset = { PLANE0_DATA_OFFSET }, @@ -57,7 +57,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_UYVY, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 1, .buffers = 1, }, @@ -65,7 +65,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YVYU, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 1, .buffers = 1, }, @@ -73,7 +73,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_VYUY, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 1, .buffers = 1, }, @@ -81,7 +81,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YUV422P, .vdownsampling = { 1, 1, 1 }, .bit_depth = { 8, 4, 4 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 1, }, @@ -89,7 +89,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YUV420, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 1, }, @@ -97,7 +97,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YVU420, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 1, }, @@ -105,7 +105,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV12, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 1, }, @@ -113,7 +113,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV21, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 1, }, @@ -121,7 +121,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV16, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 1, }, @@ -129,7 +129,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV61, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 1, }, @@ -137,7 +137,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV24, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 1, }, @@ -145,7 +145,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV42, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 1, }, @@ -184,7 +184,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_GREY, .vdownsampling = { 1 }, .bit_depth = { 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 1, .buffers = 1, }, @@ -192,7 +192,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_Y16, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 1, .buffers = 1, }, @@ -200,7 +200,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_Y16_BE, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 1, .buffers = 1, }, @@ -452,7 +452,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV16M, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 2, .data_offset = { PLANE0_DATA_OFFSET, 0 }, @@ -461,7 +461,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV61M, .vdownsampling = { 1, 1 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 2, .data_offset = { 0, PLANE0_DATA_OFFSET }, @@ -470,7 +470,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YUV420M, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 3, }, @@ -478,7 +478,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YVU420M, .vdownsampling = { 1, 2, 2 }, .bit_depth = { 8, 4, 4 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 3, }, @@ -486,7 +486,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV12M, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 2, }, @@ -494,7 +494,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_NV21M, .vdownsampling = { 1, 2 }, .bit_depth = { 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 2, .buffers = 2, }, @@ -502,7 +502,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YUV422M, .vdownsampling = { 1, 1, 1 }, .bit_depth = { 8, 4, 4 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 3, }, @@ -510,7 +510,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YVU422M, .vdownsampling = { 1, 1, 1 }, .bit_depth = { 8, 4, 4 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 3, }, @@ -518,7 +518,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YUV444M, .vdownsampling = { 1, 1, 1 }, .bit_depth = { 8, 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 3, }, @@ -526,7 +526,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_YVU444M, .vdownsampling = { 1, 1, 1 }, .bit_depth = { 8, 8, 8 }, - .is_yuv = true, + .color_enc = TGP_COLOR_ENC_YCBCR, .planes = 3, .buffers = 3, }, diff --git a/include/media/v4l2-tpg.h b/include/media/v4l2-tpg.h index 329bebfa930c..b4cb8f34cd87 100644 --- a/include/media/v4l2-tpg.h +++ b/include/media/v4l2-tpg.h @@ -87,6 +87,11 @@ enum tpg_move_mode { TPG_MOVE_POS_FAST, }; +enum tgp_color_enc { + TGP_COLOR_ENC_RGB, + TGP_COLOR_ENC_YCBCR, +}; + extern const char * const tpg_aspect_strings[]; #define TPG_MAX_PLANES 3 @@ -119,7 +124,7 @@ struct tpg_data { u8 saturation; s16 hue; u32 fourcc; - bool is_yuv; + enum tgp_color_enc color_enc; u32 colorspace; u32 xfer_func; u32 ycbcr_enc; -- cgit v1.2.3 From 54fb15348385a1acf5a7bc1417bdd94c9d5115bb Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Fri, 15 Jul 2016 10:20:08 -0300 Subject: [media] vivid: Add support for HSV formats This patch adds support for V4L2_PIX_FMT_HSV24 and V4L2_PIX_FMT_HSV32. Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 93 +++++++++++++++++++++++-- drivers/media/platform/vivid/vivid-vid-common.c | 14 ++++ include/media/v4l2-tpg.h | 1 + 3 files changed, 104 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index c4153307bfc5..67e0aaf067b7 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -318,6 +318,10 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) tpg->hmask[0] = ~1; tpg->color_enc = TGP_COLOR_ENC_YCBCR; break; + case V4L2_PIX_FMT_HSV24: + case V4L2_PIX_FMT_HSV32: + tpg->color_enc = TGP_COLOR_ENC_HSV; + break; default: return false; } @@ -351,6 +355,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) break; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_HSV24: tpg->twopixelsize[0] = 2 * 3; break; case V4L2_PIX_FMT_BGR666: @@ -361,6 +366,7 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: case V4L2_PIX_FMT_YUV32: + case V4L2_PIX_FMT_HSV32: tpg->twopixelsize[0] = 2 * 4; break; case V4L2_PIX_FMT_NV12: @@ -490,6 +496,64 @@ static inline int linear_to_rec709(int v) return tpg_linear_to_rec709[v]; } +static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b, + int *h, int *s, int *v) +{ + int max_rgb, min_rgb, diff_rgb; + int aux; + int third; + + r >>= 4; + g >>= 4; + b >>= 4; + + /* Value */ + max_rgb = max3(r, g, b); + *v = max_rgb; + if (!max_rgb) { + *h = 0; + *s = 0; + return; + } + + /* Saturation */ + min_rgb = min3(r, g, b); + diff_rgb = max_rgb - min_rgb; + aux = 255 * diff_rgb; + aux += max_rgb / 2; + aux /= max_rgb; + *s = aux; + if (!aux) { + *h = 0; + return; + } + + /* Hue */ + if (max_rgb == r) { + aux = g - b; + third = 0; + } else if (max_rgb == g) { + aux = b - r; + third = 60; + } else { + aux = r - g; + third = 120; + } + + aux *= 30; + aux += diff_rgb / 2; + aux /= diff_rgb; + aux += third; + + /* Clamp Hue */ + if (aux < 0) + aux += 180; + else if (aux > 180) + aux -= 180; + *h = aux; + +} + static void rgb2ycbcr(const int m[3][3], int r, int g, int b, int y_offset, int *y, int *cb, int *cr) { @@ -830,7 +894,19 @@ static void precalculate_color(struct tpg_data *tpg, int k) ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b); } - if (tpg->color_enc == TGP_COLOR_ENC_YCBCR) { + switch (tpg->color_enc) { + case TGP_COLOR_ENC_HSV: + { + int h, s, v; + + color_to_hsv(tpg, r, g, b, &h, &s, &v); + tpg->colors[k][0] = h; + tpg->colors[k][1] = s; + tpg->colors[k][2] = v; + break; + } + case TGP_COLOR_ENC_YCBCR: + { /* Convert to YCbCr */ int y, cb, cr; @@ -864,7 +940,10 @@ static void precalculate_color(struct tpg_data *tpg, int k) tpg->colors[k][0] = y; tpg->colors[k][1] = cb; tpg->colors[k][2] = cr; - } else { + break; + } + case TGP_COLOR_ENC_RGB: + { if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { r = (r * 219) / 255 + (16 << 4); g = (g * 219) / 255 + (16 << 4); @@ -914,6 +993,8 @@ static void precalculate_color(struct tpg_data *tpg, int k) tpg->colors[k][0] = r; tpg->colors[k][1] = g; tpg->colors[k][2] = b; + break; + } } } @@ -939,8 +1020,8 @@ static void gen_twopix(struct tpg_data *tpg, alpha = 0; if (color == TPG_COLOR_RANDOM) precalculate_color(tpg, color); - r_y = tpg->colors[color][0]; /* R or precalculated Y */ - g_u = tpg->colors[color][1]; /* G or precalculated U */ + r_y = tpg->colors[color][0]; /* R or precalculated Y, H */ + g_u = tpg->colors[color][1]; /* G or precalculated U, V */ b_v = tpg->colors[color][2]; /* B or precalculated V */ switch (tpg->fourcc) { @@ -1122,6 +1203,7 @@ static void gen_twopix(struct tpg_data *tpg, buf[0][offset + 1] = (g_u << 5) | b_v; break; case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_HSV24: buf[0][offset] = r_y; buf[0][offset + 1] = g_u; buf[0][offset + 2] = b_v; @@ -1139,6 +1221,7 @@ static void gen_twopix(struct tpg_data *tpg, break; case V4L2_PIX_FMT_RGB32: case V4L2_PIX_FMT_XRGB32: + case V4L2_PIX_FMT_HSV32: alpha = 0; /* fall through */ case V4L2_PIX_FMT_YUV32: @@ -1895,6 +1978,8 @@ static const char *tpg_color_enc_str(enum tgp_color_enc color_enc) { switch (color_enc) { + case TGP_COLOR_ENC_HSV: + return "HSV"; case TGP_COLOR_ENC_YCBCR: return "Y'CbCr"; case TGP_COLOR_ENC_RGB: diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index f4c35ba5f070..20822b5111b3 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -445,6 +445,20 @@ struct vivid_fmt vivid_formats[] = { .planes = 1, .buffers = 1, }, + { + .fourcc = V4L2_PIX_FMT_HSV24, /* HSV 24bits */ + .vdownsampling = { 1 }, + .bit_depth = { 24 }, + .planes = 1, + .buffers = 1, + }, + { + .fourcc = V4L2_PIX_FMT_HSV32, /* HSV 32bits */ + .vdownsampling = { 1 }, + .bit_depth = { 32 }, + .planes = 1, + .buffers = 1, + }, /* Multiplanar formats */ diff --git a/include/media/v4l2-tpg.h b/include/media/v4l2-tpg.h index b4cb8f34cd87..4a40f9b79053 100644 --- a/include/media/v4l2-tpg.h +++ b/include/media/v4l2-tpg.h @@ -90,6 +90,7 @@ enum tpg_move_mode { enum tgp_color_enc { TGP_COLOR_ENC_RGB, TGP_COLOR_ENC_YCBCR, + TGP_COLOR_ENC_HSV, }; extern const char * const tpg_aspect_strings[]; -- cgit v1.2.3 From 25e90073497b94c3469f083cc0c66563c18c0788 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Fri, 15 Jul 2016 10:21:46 -0300 Subject: [media] vivid: Rename variable r_y and g_u now also contain the H and V components on the HSV formats. Rename the variables to reflect this. Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 209 +++++++++++++------------- 1 file changed, 105 insertions(+), 104 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 67e0aaf067b7..0aeabe92ff32 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -1012,7 +1012,7 @@ static void gen_twopix(struct tpg_data *tpg, { unsigned offset = odd * tpg->twopixelsize[0] / 2; u8 alpha = tpg->alpha_component; - u8 r_y, g_u, b_v; + u8 r_y_h, g_u_s, b_v; if (tpg->alpha_red_only && color != TPG_COLOR_CSC_RED && color != TPG_COLOR_100_RED && @@ -1020,161 +1020,161 @@ static void gen_twopix(struct tpg_data *tpg, alpha = 0; if (color == TPG_COLOR_RANDOM) precalculate_color(tpg, color); - r_y = tpg->colors[color][0]; /* R or precalculated Y, H */ - g_u = tpg->colors[color][1]; /* G or precalculated U, V */ + r_y_h = tpg->colors[color][0]; /* R or precalculated Y, H */ + g_u_s = tpg->colors[color][1]; /* G or precalculated U, V */ b_v = tpg->colors[color][2]; /* B or precalculated V */ switch (tpg->fourcc) { case V4L2_PIX_FMT_GREY: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; break; case V4L2_PIX_FMT_Y16: /* - * Ideally both bytes should be set to r_y, but then you won't + * Ideally both bytes should be set to r_y_h, but then you won't * be able to detect endian problems. So keep it 0 except for - * the corner case where r_y is 0xff so white really will be + * the corner case where r_y_h is 0xff so white really will be * white (0xffff). */ - buf[0][offset] = r_y == 0xff ? r_y : 0; - buf[0][offset+1] = r_y; + buf[0][offset] = r_y_h == 0xff ? r_y_h : 0; + buf[0][offset+1] = r_y_h; break; case V4L2_PIX_FMT_Y16_BE: /* See comment for V4L2_PIX_FMT_Y16 above */ - buf[0][offset] = r_y; - buf[0][offset+1] = r_y == 0xff ? r_y : 0; + buf[0][offset] = r_y_h; + buf[0][offset+1] = r_y_h == 0xff ? r_y_h : 0; break; case V4L2_PIX_FMT_YUV422M: case V4L2_PIX_FMT_YUV422P: case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUV420M: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; if (odd) { - buf[1][0] = (buf[1][0] + g_u) / 2; + buf[1][0] = (buf[1][0] + g_u_s) / 2; buf[2][0] = (buf[2][0] + b_v) / 2; buf[1][1] = buf[1][0]; buf[2][1] = buf[2][0]; break; } - buf[1][0] = g_u; + buf[1][0] = g_u_s; buf[2][0] = b_v; break; case V4L2_PIX_FMT_YVU422M: case V4L2_PIX_FMT_YVU420: case V4L2_PIX_FMT_YVU420M: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; if (odd) { buf[1][0] = (buf[1][0] + b_v) / 2; - buf[2][0] = (buf[2][0] + g_u) / 2; + buf[2][0] = (buf[2][0] + g_u_s) / 2; buf[1][1] = buf[1][0]; buf[2][1] = buf[2][0]; break; } buf[1][0] = b_v; - buf[2][0] = g_u; + buf[2][0] = g_u_s; break; case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: case V4L2_PIX_FMT_NV16: case V4L2_PIX_FMT_NV16M: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; if (odd) { - buf[1][0] = (buf[1][0] + g_u) / 2; + buf[1][0] = (buf[1][0] + g_u_s) / 2; buf[1][1] = (buf[1][1] + b_v) / 2; break; } - buf[1][0] = g_u; + buf[1][0] = g_u_s; buf[1][1] = b_v; break; case V4L2_PIX_FMT_NV21: case V4L2_PIX_FMT_NV21M: case V4L2_PIX_FMT_NV61: case V4L2_PIX_FMT_NV61M: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; if (odd) { buf[1][0] = (buf[1][0] + b_v) / 2; - buf[1][1] = (buf[1][1] + g_u) / 2; + buf[1][1] = (buf[1][1] + g_u_s) / 2; break; } buf[1][0] = b_v; - buf[1][1] = g_u; + buf[1][1] = g_u_s; break; case V4L2_PIX_FMT_YUV444M: - buf[0][offset] = r_y; - buf[1][offset] = g_u; + buf[0][offset] = r_y_h; + buf[1][offset] = g_u_s; buf[2][offset] = b_v; break; case V4L2_PIX_FMT_YVU444M: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; buf[1][offset] = b_v; - buf[2][offset] = g_u; + buf[2][offset] = g_u_s; break; case V4L2_PIX_FMT_NV24: - buf[0][offset] = r_y; - buf[1][2 * offset] = g_u; + buf[0][offset] = r_y_h; + buf[1][2 * offset] = g_u_s; buf[1][2 * offset + 1] = b_v; break; case V4L2_PIX_FMT_NV42: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; buf[1][2 * offset] = b_v; - buf[1][2 * offset + 1] = g_u; + buf[1][2 * offset + 1] = g_u_s; break; case V4L2_PIX_FMT_YUYV: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; if (odd) { - buf[0][1] = (buf[0][1] + g_u) / 2; + buf[0][1] = (buf[0][1] + g_u_s) / 2; buf[0][3] = (buf[0][3] + b_v) / 2; break; } - buf[0][1] = g_u; + buf[0][1] = g_u_s; buf[0][3] = b_v; break; case V4L2_PIX_FMT_UYVY: - buf[0][offset + 1] = r_y; + buf[0][offset + 1] = r_y_h; if (odd) { - buf[0][0] = (buf[0][0] + g_u) / 2; + buf[0][0] = (buf[0][0] + g_u_s) / 2; buf[0][2] = (buf[0][2] + b_v) / 2; break; } - buf[0][0] = g_u; + buf[0][0] = g_u_s; buf[0][2] = b_v; break; case V4L2_PIX_FMT_YVYU: - buf[0][offset] = r_y; + buf[0][offset] = r_y_h; if (odd) { buf[0][1] = (buf[0][1] + b_v) / 2; - buf[0][3] = (buf[0][3] + g_u) / 2; + buf[0][3] = (buf[0][3] + g_u_s) / 2; break; } buf[0][1] = b_v; - buf[0][3] = g_u; + buf[0][3] = g_u_s; break; case V4L2_PIX_FMT_VYUY: - buf[0][offset + 1] = r_y; + buf[0][offset + 1] = r_y_h; if (odd) { buf[0][0] = (buf[0][0] + b_v) / 2; - buf[0][2] = (buf[0][2] + g_u) / 2; + buf[0][2] = (buf[0][2] + g_u_s) / 2; break; } buf[0][0] = b_v; - buf[0][2] = g_u; + buf[0][2] = g_u_s; break; case V4L2_PIX_FMT_RGB332: - buf[0][offset] = (r_y << 5) | (g_u << 2) | b_v; + buf[0][offset] = (r_y_h << 5) | (g_u_s << 2) | b_v; break; case V4L2_PIX_FMT_YUV565: case V4L2_PIX_FMT_RGB565: - buf[0][offset] = (g_u << 5) | b_v; - buf[0][offset + 1] = (r_y << 3) | (g_u >> 3); + buf[0][offset] = (g_u_s << 5) | b_v; + buf[0][offset + 1] = (r_y_h << 3) | (g_u_s >> 3); break; case V4L2_PIX_FMT_RGB565X: - buf[0][offset] = (r_y << 3) | (g_u >> 3); - buf[0][offset + 1] = (g_u << 5) | b_v; + buf[0][offset] = (r_y_h << 3) | (g_u_s >> 3); + buf[0][offset + 1] = (g_u_s << 5) | b_v; break; case V4L2_PIX_FMT_RGB444: case V4L2_PIX_FMT_XRGB444: @@ -1182,8 +1182,8 @@ static void gen_twopix(struct tpg_data *tpg, /* fall through */ case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_ARGB444: - buf[0][offset] = (g_u << 4) | b_v; - buf[0][offset + 1] = (alpha & 0xf0) | r_y; + buf[0][offset] = (g_u_s << 4) | b_v; + buf[0][offset + 1] = (alpha & 0xf0) | r_y_h; break; case V4L2_PIX_FMT_RGB555: case V4L2_PIX_FMT_XRGB555: @@ -1191,32 +1191,33 @@ static void gen_twopix(struct tpg_data *tpg, /* fall through */ case V4L2_PIX_FMT_YUV555: case V4L2_PIX_FMT_ARGB555: - buf[0][offset] = (g_u << 5) | b_v; - buf[0][offset + 1] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); + buf[0][offset] = (g_u_s << 5) | b_v; + buf[0][offset + 1] = (alpha & 0x80) | (r_y_h << 2) + | (g_u_s >> 3); break; case V4L2_PIX_FMT_RGB555X: case V4L2_PIX_FMT_XRGB555X: alpha = 0; /* fall through */ case V4L2_PIX_FMT_ARGB555X: - buf[0][offset] = (alpha & 0x80) | (r_y << 2) | (g_u >> 3); - buf[0][offset + 1] = (g_u << 5) | b_v; + buf[0][offset] = (alpha & 0x80) | (r_y_h << 2) | (g_u_s >> 3); + buf[0][offset + 1] = (g_u_s << 5) | b_v; break; case V4L2_PIX_FMT_RGB24: case V4L2_PIX_FMT_HSV24: - buf[0][offset] = r_y; - buf[0][offset + 1] = g_u; + buf[0][offset] = r_y_h; + buf[0][offset + 1] = g_u_s; buf[0][offset + 2] = b_v; break; case V4L2_PIX_FMT_BGR24: buf[0][offset] = b_v; - buf[0][offset + 1] = g_u; - buf[0][offset + 2] = r_y; + buf[0][offset + 1] = g_u_s; + buf[0][offset + 2] = r_y_h; break; case V4L2_PIX_FMT_BGR666: - buf[0][offset] = (b_v << 2) | (g_u >> 4); - buf[0][offset + 1] = (g_u << 4) | (r_y >> 2); - buf[0][offset + 2] = r_y << 6; + buf[0][offset] = (b_v << 2) | (g_u_s >> 4); + buf[0][offset + 1] = (g_u_s << 4) | (r_y_h >> 2); + buf[0][offset + 2] = r_y_h << 6; buf[0][offset + 3] = 0; break; case V4L2_PIX_FMT_RGB32: @@ -1227,8 +1228,8 @@ static void gen_twopix(struct tpg_data *tpg, case V4L2_PIX_FMT_YUV32: case V4L2_PIX_FMT_ARGB32: buf[0][offset] = alpha; - buf[0][offset + 1] = r_y; - buf[0][offset + 2] = g_u; + buf[0][offset + 1] = r_y_h; + buf[0][offset + 2] = g_u_s; buf[0][offset + 3] = b_v; break; case V4L2_PIX_FMT_BGR32: @@ -1237,87 +1238,87 @@ static void gen_twopix(struct tpg_data *tpg, /* fall through */ case V4L2_PIX_FMT_ABGR32: buf[0][offset] = b_v; - buf[0][offset + 1] = g_u; - buf[0][offset + 2] = r_y; + buf[0][offset + 1] = g_u_s; + buf[0][offset + 2] = r_y_h; buf[0][offset + 3] = alpha; break; case V4L2_PIX_FMT_SBGGR8: - buf[0][offset] = odd ? g_u : b_v; - buf[1][offset] = odd ? r_y : g_u; + buf[0][offset] = odd ? g_u_s : b_v; + buf[1][offset] = odd ? r_y_h : g_u_s; break; case V4L2_PIX_FMT_SGBRG8: - buf[0][offset] = odd ? b_v : g_u; - buf[1][offset] = odd ? g_u : r_y; + buf[0][offset] = odd ? b_v : g_u_s; + buf[1][offset] = odd ? g_u_s : r_y_h; break; case V4L2_PIX_FMT_SGRBG8: - buf[0][offset] = odd ? r_y : g_u; - buf[1][offset] = odd ? g_u : b_v; + buf[0][offset] = odd ? r_y_h : g_u_s; + buf[1][offset] = odd ? g_u_s : b_v; break; case V4L2_PIX_FMT_SRGGB8: - buf[0][offset] = odd ? g_u : r_y; - buf[1][offset] = odd ? b_v : g_u; + buf[0][offset] = odd ? g_u_s : r_y_h; + buf[1][offset] = odd ? b_v : g_u_s; break; case V4L2_PIX_FMT_SBGGR10: - buf[0][offset] = odd ? g_u << 2 : b_v << 2; - buf[0][offset + 1] = odd ? g_u >> 6 : b_v >> 6; - buf[1][offset] = odd ? r_y << 2 : g_u << 2; - buf[1][offset + 1] = odd ? r_y >> 6 : g_u >> 6; + buf[0][offset] = odd ? g_u_s << 2 : b_v << 2; + buf[0][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6; + buf[1][offset] = odd ? r_y_h << 2 : g_u_s << 2; + buf[1][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6; buf[0][offset] |= (buf[0][offset] >> 2) & 3; buf[1][offset] |= (buf[1][offset] >> 2) & 3; break; case V4L2_PIX_FMT_SGBRG10: - buf[0][offset] = odd ? b_v << 2 : g_u << 2; - buf[0][offset + 1] = odd ? b_v >> 6 : g_u >> 6; - buf[1][offset] = odd ? g_u << 2 : r_y << 2; - buf[1][offset + 1] = odd ? g_u >> 6 : r_y >> 6; + buf[0][offset] = odd ? b_v << 2 : g_u_s << 2; + buf[0][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6; + buf[1][offset] = odd ? g_u_s << 2 : r_y_h << 2; + buf[1][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6; buf[0][offset] |= (buf[0][offset] >> 2) & 3; buf[1][offset] |= (buf[1][offset] >> 2) & 3; break; case V4L2_PIX_FMT_SGRBG10: - buf[0][offset] = odd ? r_y << 2 : g_u << 2; - buf[0][offset + 1] = odd ? r_y >> 6 : g_u >> 6; - buf[1][offset] = odd ? g_u << 2 : b_v << 2; - buf[1][offset + 1] = odd ? g_u >> 6 : b_v >> 6; + buf[0][offset] = odd ? r_y_h << 2 : g_u_s << 2; + buf[0][offset + 1] = odd ? r_y_h >> 6 : g_u_s >> 6; + buf[1][offset] = odd ? g_u_s << 2 : b_v << 2; + buf[1][offset + 1] = odd ? g_u_s >> 6 : b_v >> 6; buf[0][offset] |= (buf[0][offset] >> 2) & 3; buf[1][offset] |= (buf[1][offset] >> 2) & 3; break; case V4L2_PIX_FMT_SRGGB10: - buf[0][offset] = odd ? g_u << 2 : r_y << 2; - buf[0][offset + 1] = odd ? g_u >> 6 : r_y >> 6; - buf[1][offset] = odd ? b_v << 2 : g_u << 2; - buf[1][offset + 1] = odd ? b_v >> 6 : g_u >> 6; + buf[0][offset] = odd ? g_u_s << 2 : r_y_h << 2; + buf[0][offset + 1] = odd ? g_u_s >> 6 : r_y_h >> 6; + buf[1][offset] = odd ? b_v << 2 : g_u_s << 2; + buf[1][offset + 1] = odd ? b_v >> 6 : g_u_s >> 6; buf[0][offset] |= (buf[0][offset] >> 2) & 3; buf[1][offset] |= (buf[1][offset] >> 2) & 3; break; case V4L2_PIX_FMT_SBGGR12: - buf[0][offset] = odd ? g_u << 4 : b_v << 4; - buf[0][offset + 1] = odd ? g_u >> 4 : b_v >> 4; - buf[1][offset] = odd ? r_y << 4 : g_u << 4; - buf[1][offset + 1] = odd ? r_y >> 4 : g_u >> 4; + buf[0][offset] = odd ? g_u_s << 4 : b_v << 4; + buf[0][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4; + buf[1][offset] = odd ? r_y_h << 4 : g_u_s << 4; + buf[1][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4; buf[0][offset] |= (buf[0][offset] >> 4) & 0xf; buf[1][offset] |= (buf[1][offset] >> 4) & 0xf; break; case V4L2_PIX_FMT_SGBRG12: - buf[0][offset] = odd ? b_v << 4 : g_u << 4; - buf[0][offset + 1] = odd ? b_v >> 4 : g_u >> 4; - buf[1][offset] = odd ? g_u << 4 : r_y << 4; - buf[1][offset + 1] = odd ? g_u >> 4 : r_y >> 4; + buf[0][offset] = odd ? b_v << 4 : g_u_s << 4; + buf[0][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4; + buf[1][offset] = odd ? g_u_s << 4 : r_y_h << 4; + buf[1][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4; buf[0][offset] |= (buf[0][offset] >> 4) & 0xf; buf[1][offset] |= (buf[1][offset] >> 4) & 0xf; break; case V4L2_PIX_FMT_SGRBG12: - buf[0][offset] = odd ? r_y << 4 : g_u << 4; - buf[0][offset + 1] = odd ? r_y >> 4 : g_u >> 4; - buf[1][offset] = odd ? g_u << 4 : b_v << 4; - buf[1][offset + 1] = odd ? g_u >> 4 : b_v >> 4; + buf[0][offset] = odd ? r_y_h << 4 : g_u_s << 4; + buf[0][offset + 1] = odd ? r_y_h >> 4 : g_u_s >> 4; + buf[1][offset] = odd ? g_u_s << 4 : b_v << 4; + buf[1][offset + 1] = odd ? g_u_s >> 4 : b_v >> 4; buf[0][offset] |= (buf[0][offset] >> 4) & 0xf; buf[1][offset] |= (buf[1][offset] >> 4) & 0xf; break; case V4L2_PIX_FMT_SRGGB12: - buf[0][offset] = odd ? g_u << 4 : r_y << 4; - buf[0][offset + 1] = odd ? g_u >> 4 : r_y >> 4; - buf[1][offset] = odd ? b_v << 4 : g_u << 4; - buf[1][offset + 1] = odd ? b_v >> 4 : g_u >> 4; + buf[0][offset] = odd ? g_u_s << 4 : r_y_h << 4; + buf[0][offset + 1] = odd ? g_u_s >> 4 : r_y_h >> 4; + buf[1][offset] = odd ? b_v << 4 : g_u_s << 4; + buf[1][offset + 1] = odd ? b_v >> 4 : g_u_s >> 4; buf[0][offset] |= (buf[0][offset] >> 4) & 0xf; buf[1][offset] |= (buf[1][offset] >> 4) & 0xf; break; -- cgit v1.2.3 From ca2b32da5988159d4d997aac9e4a87447046aedf Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sat, 16 Jul 2016 05:58:09 -0300 Subject: [media] vivid: Introduce TPG_COLOR_ENC_LUMA Simplifies handling of Gray formats. Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 26 +++++++++++++++++++------ drivers/media/platform/vivid/vivid-vid-common.c | 6 +++--- include/media/v4l2-tpg.h | 1 + 3 files changed, 24 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 0aeabe92ff32..920c8495f3dd 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -234,10 +234,12 @@ bool tpg_s_fourcc(struct tpg_data *tpg, u32 fourcc) case V4L2_PIX_FMT_XBGR32: case V4L2_PIX_FMT_ARGB32: case V4L2_PIX_FMT_ABGR32: + tpg->color_enc = TGP_COLOR_ENC_RGB; + break; case V4L2_PIX_FMT_GREY: case V4L2_PIX_FMT_Y16: case V4L2_PIX_FMT_Y16_BE: - tpg->color_enc = TGP_COLOR_ENC_RGB; + tpg->color_enc = TGP_COLOR_ENC_LUMA; break; case V4L2_PIX_FMT_YUV444: case V4L2_PIX_FMT_YUV555: @@ -823,9 +825,9 @@ static void precalculate_color(struct tpg_data *tpg, int k) g <<= 4; b <<= 4; } - if (tpg->qual == TPG_QUAL_GRAY || tpg->fourcc == V4L2_PIX_FMT_GREY || - tpg->fourcc == V4L2_PIX_FMT_Y16 || - tpg->fourcc == V4L2_PIX_FMT_Y16_BE) { + + if (tpg->qual == TPG_QUAL_GRAY || + tpg->color_enc == TGP_COLOR_ENC_LUMA) { /* Rec. 709 Luma function */ /* (0.2126, 0.7152, 0.0722) * (255 * 256) */ r = g = b = (13879 * r + 46688 * g + 4713 * b) >> 16; @@ -865,8 +867,9 @@ static void precalculate_color(struct tpg_data *tpg, int k) b = (b - (16 << 4)) * 255 / 219; } - if (tpg->brightness != 128 || tpg->contrast != 128 || - tpg->saturation != 128 || tpg->hue) { + if ((tpg->brightness != 128 || tpg->contrast != 128 || + tpg->saturation != 128 || tpg->hue) && + tpg->color_enc != TGP_COLOR_ENC_LUMA) { /* Implement these operations */ int y, cb, cr; int tmp_cb, tmp_cr; @@ -892,6 +895,10 @@ static void precalculate_color(struct tpg_data *tpg, int k) return; } ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b); + } else if ((tpg->brightness != 128 || tpg->contrast != 128) && + tpg->color_enc == TGP_COLOR_ENC_LUMA) { + r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128; + r += (tpg->brightness << 4) - (128 << 4); } switch (tpg->color_enc) { @@ -942,6 +949,11 @@ static void precalculate_color(struct tpg_data *tpg, int k) tpg->colors[k][2] = cr; break; } + case TGP_COLOR_ENC_LUMA: + { + tpg->colors[k][0] = r >> 4; + break; + } case TGP_COLOR_ENC_RGB: { if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { @@ -1983,6 +1995,8 @@ static const char *tpg_color_enc_str(enum tgp_color_enc return "HSV"; case TGP_COLOR_ENC_YCBCR: return "Y'CbCr"; + case TGP_COLOR_ENC_LUMA: + return "Luma"; case TGP_COLOR_ENC_RGB: default: return "R'G'B"; diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 20822b5111b3..e0df44151461 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -184,7 +184,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_GREY, .vdownsampling = { 1 }, .bit_depth = { 8 }, - .color_enc = TGP_COLOR_ENC_YCBCR, + .color_enc = TGP_COLOR_ENC_LUMA, .planes = 1, .buffers = 1, }, @@ -192,7 +192,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_Y16, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, + .color_enc = TGP_COLOR_ENC_LUMA, .planes = 1, .buffers = 1, }, @@ -200,7 +200,7 @@ struct vivid_fmt vivid_formats[] = { .fourcc = V4L2_PIX_FMT_Y16_BE, .vdownsampling = { 1 }, .bit_depth = { 16 }, - .color_enc = TGP_COLOR_ENC_YCBCR, + .color_enc = TGP_COLOR_ENC_LUMA, .planes = 1, .buffers = 1, }, diff --git a/include/media/v4l2-tpg.h b/include/media/v4l2-tpg.h index 4a40f9b79053..8abed92317e8 100644 --- a/include/media/v4l2-tpg.h +++ b/include/media/v4l2-tpg.h @@ -91,6 +91,7 @@ enum tgp_color_enc { TGP_COLOR_ENC_RGB, TGP_COLOR_ENC_YCBCR, TGP_COLOR_ENC_HSV, + TGP_COLOR_ENC_LUMA, }; extern const char * const tpg_aspect_strings[]; -- cgit v1.2.3 From 7a20f3985fb6eb74c93e5f36cf1d375a3b013d77 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sat, 16 Jul 2016 06:26:23 -0300 Subject: [media] vivid: Fix YUV555 and YUV565 handling precalculate_color() had a optimization that avoided duplicated conversion for YUV formats. This optimization did not take into consideration YUV444, YUV555, YUV565 or limited range quantization. This patch keeps the optimization, but fixes the wrong handling. Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 920c8495f3dd..7364ced09abc 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -795,6 +795,8 @@ static void precalculate_color(struct tpg_data *tpg, int k) int r = tpg_colors[col].r; int g = tpg_colors[col].g; int b = tpg_colors[col].b; + int y, cb, cr; + bool ycbcr_valid = false; if (k == TPG_COLOR_TEXTBG) { col = tpg_get_textbg_color(tpg); @@ -871,7 +873,6 @@ static void precalculate_color(struct tpg_data *tpg, int k) tpg->saturation != 128 || tpg->hue) && tpg->color_enc != TGP_COLOR_ENC_LUMA) { /* Implement these operations */ - int y, cb, cr; int tmp_cb, tmp_cr; /* First convert to YCbCr */ @@ -888,13 +889,10 @@ static void precalculate_color(struct tpg_data *tpg, int k) cb = (128 << 4) + (tmp_cb * tpg->contrast * tpg->saturation) / (128 * 128); cr = (128 << 4) + (tmp_cr * tpg->contrast * tpg->saturation) / (128 * 128); - if (tpg->color_enc == TGP_COLOR_ENC_YCBCR) { - tpg->colors[k][0] = clamp(y >> 4, 1, 254); - tpg->colors[k][1] = clamp(cb >> 4, 1, 254); - tpg->colors[k][2] = clamp(cr >> 4, 1, 254); - return; - } - ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b); + if (tpg->color_enc == TGP_COLOR_ENC_YCBCR) + ycbcr_valid = true; + else + ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b); } else if ((tpg->brightness != 128 || tpg->contrast != 128) && tpg->color_enc == TGP_COLOR_ENC_LUMA) { r = (16 << 4) + ((r - (16 << 4)) * tpg->contrast) / 128; @@ -915,9 +913,8 @@ static void precalculate_color(struct tpg_data *tpg, int k) case TGP_COLOR_ENC_YCBCR: { /* Convert to YCbCr */ - int y, cb, cr; - - color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr); + if (!ycbcr_valid) + color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr); if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { y = clamp(y, 16 << 4, 235 << 4); -- cgit v1.2.3 From f1eb926d1d79a210c8a2bac2f0438163f436a077 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Sat, 16 Jul 2016 06:34:19 -0300 Subject: [media] vivid: Local optimization Avoid duplicated clamps when possible. Suggested-by: Philipp Zabel Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 7364ced09abc..ed37ae307cac 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -916,14 +916,18 @@ static void precalculate_color(struct tpg_data *tpg, int k) if (!ycbcr_valid) color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr); + y >>= 4; + cb >>= 4; + cr >>= 4; if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) { - y = clamp(y, 16 << 4, 235 << 4); - cb = clamp(cb, 16 << 4, 240 << 4); - cr = clamp(cr, 16 << 4, 240 << 4); + y = clamp(y, 16, 235); + cb = clamp(cb, 16, 240); + cr = clamp(cr, 16, 240); + } else { + y = clamp(y, 1, 254); + cb = clamp(cb, 1, 254); + cr = clamp(cr, 1, 254); } - y = clamp(y >> 4, 1, 254); - cb = clamp(cb >> 4, 1, 254); - cr = clamp(cr >> 4, 1, 254); switch (tpg->fourcc) { case V4L2_PIX_FMT_YUV444: y >>= 4; -- cgit v1.2.3 From 429175e41f01419ad81f144acabb09be904682cd Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Delgado Date: Mon, 18 Jul 2016 09:16:15 -0300 Subject: [media] vivid: Add support for HSV encoding Support HSV encoding. Most of the logic is replicated from ycbcr_enc. Signed-off-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 25 +++++++++++++++++-------- drivers/media/platform/vivid/vivid-core.h | 1 + drivers/media/platform/vivid/vivid-ctrls.c | 25 +++++++++++++++++++++++++ drivers/media/platform/vivid/vivid-vid-cap.c | 17 +++++++++++++++-- drivers/media/platform/vivid/vivid-vid-common.c | 2 ++ drivers/media/platform/vivid/vivid-vid-out.c | 1 + include/media/v4l2-tpg.h | 15 +++++++++++++++ 7 files changed, 76 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index ed37ae307cac..28d7b072d867 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -504,6 +504,7 @@ static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b, int max_rgb, min_rgb, diff_rgb; int aux; int third; + int third_size; r >>= 4; g >>= 4; @@ -530,30 +531,36 @@ static void color_to_hsv(struct tpg_data *tpg, int r, int g, int b, return; } + third_size = (tpg->real_hsv_enc == V4L2_HSV_ENC_180) ? 60 : 85; + /* Hue */ if (max_rgb == r) { aux = g - b; third = 0; } else if (max_rgb == g) { aux = b - r; - third = 60; + third = third_size; } else { aux = r - g; - third = 120; + third = third_size * 2; } - aux *= 30; + aux *= third_size / 2; aux += diff_rgb / 2; aux /= diff_rgb; aux += third; /* Clamp Hue */ - if (aux < 0) - aux += 180; - else if (aux > 180) - aux -= 180; - *h = aux; + if (tpg->real_hsv_enc == V4L2_HSV_ENC_180) { + if (aux < 0) + aux += 180; + else if (aux > 180) + aux -= 180; + } else { + aux = aux & 0xff; + } + *h = aux; } static void rgb2ycbcr(const int m[3][3], int r, int g, int b, @@ -1928,6 +1935,7 @@ static void tpg_recalc(struct tpg_data *tpg) tpg->recalc_lines = true; tpg->real_xfer_func = tpg->xfer_func; tpg->real_ycbcr_enc = tpg->ycbcr_enc; + tpg->real_hsv_enc = tpg->hsv_enc; tpg->real_quantization = tpg->quantization; if (tpg->xfer_func == V4L2_XFER_FUNC_DEFAULT) @@ -2018,6 +2026,7 @@ void tpg_log_status(struct tpg_data *tpg) pr_info("tpg colorspace: %d\n", tpg->colorspace); pr_info("tpg transfer function: %d/%d\n", tpg->xfer_func, tpg->real_xfer_func); pr_info("tpg Y'CbCr encoding: %d/%d\n", tpg->ycbcr_enc, tpg->real_ycbcr_enc); + pr_info("tpg HSV encoding: %d/%d\n", tpg->hsv_enc, tpg->real_hsv_enc); pr_info("tpg quantization: %d/%d\n", tpg->quantization, tpg->real_quantization); pr_info("tpg RGB range: %d/%d\n", tpg->rgb_range, tpg->real_rgb_range); } diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h index b59b49456d45..5cdf95bdc4d1 100644 --- a/drivers/media/platform/vivid/vivid-core.h +++ b/drivers/media/platform/vivid/vivid-core.h @@ -346,6 +346,7 @@ struct vivid_dev { struct v4l2_dv_timings dv_timings_out; u32 colorspace_out; u32 ycbcr_enc_out; + u32 hsv_enc_out; u32 quantization_out; u32 xfer_func_out; u32 service_set_out; diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c index aceb38d9f7e7..34731f71cc00 100644 --- a/drivers/media/platform/vivid/vivid-ctrls.c +++ b/drivers/media/platform/vivid/vivid-ctrls.c @@ -79,6 +79,7 @@ #define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40) #define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41) #define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42) +#define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43) #define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60) #define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61) @@ -378,6 +379,14 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl) vivid_send_source_change(dev, HDMI); vivid_send_source_change(dev, WEBCAM); break; + case VIVID_CID_HSV_ENC: + tpg_s_hsv_enc(&dev->tpg, ctrl->val ? V4L2_HSV_ENC_256 : + V4L2_HSV_ENC_180); + vivid_send_source_change(dev, TV); + vivid_send_source_change(dev, SVID); + vivid_send_source_change(dev, HDMI); + vivid_send_source_change(dev, WEBCAM); + break; case VIVID_CID_QUANTIZATION: tpg_s_quantization(&dev->tpg, ctrl->val); vivid_send_source_change(dev, TV); @@ -778,6 +787,21 @@ static const struct v4l2_ctrl_config vivid_ctrl_ycbcr_enc = { .qmenu = vivid_ctrl_ycbcr_enc_strings, }; +static const char * const vivid_ctrl_hsv_enc_strings[] = { + "Hue 0-179", + "Hue 0-256", + NULL, +}; + +static const struct v4l2_ctrl_config vivid_ctrl_hsv_enc = { + .ops = &vivid_vid_cap_ctrl_ops, + .id = VIVID_CID_HSV_ENC, + .name = "HSV Encoding", + .type = V4L2_CTRL_TYPE_MENU, + .max = ARRAY_SIZE(vivid_ctrl_hsv_enc_strings) - 2, + .qmenu = vivid_ctrl_hsv_enc_strings, +}; + static const char * const vivid_ctrl_quantization_strings[] = { "Default", "Full Range", @@ -1454,6 +1478,7 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap, &vivid_ctrl_colorspace, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_xfer_func, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL); + v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_hsv_enc, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL); v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL); } diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c index d5c84ecf2027..c52dd8787794 100644 --- a/drivers/media/platform/vivid/vivid-vid-cap.c +++ b/drivers/media/platform/vivid/vivid-vid-cap.c @@ -510,6 +510,13 @@ static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev) return dev->ycbcr_enc_out; } +static unsigned int vivid_hsv_enc_cap(struct vivid_dev *dev) +{ + if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) + return tpg_g_hsv_enc(&dev->tpg); + return dev->hsv_enc_out; +} + static unsigned vivid_quantization_cap(struct vivid_dev *dev) { if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev)) @@ -530,7 +537,10 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv, mp->pixelformat = dev->fmt_cap->fourcc; mp->colorspace = vivid_colorspace_cap(dev); mp->xfer_func = vivid_xfer_func_cap(dev); - mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); + if (dev->fmt_cap->color_enc == TGP_COLOR_ENC_HSV) + mp->hsv_enc = vivid_hsv_enc_cap(dev); + else + mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); mp->quantization = vivid_quantization_cap(dev); mp->num_planes = dev->fmt_cap->buffers; for (p = 0; p < mp->num_planes; p++) { @@ -618,7 +628,10 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv, memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved)); } mp->colorspace = vivid_colorspace_cap(dev); - mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); + if (fmt->color_enc == TGP_COLOR_ENC_HSV) + mp->hsv_enc = vivid_hsv_enc_cap(dev); + else + mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev); mp->xfer_func = vivid_xfer_func_cap(dev); mp->quantization = vivid_quantization_cap(dev); memset(mp->reserved, 0, sizeof(mp->reserved)); diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index e0df44151461..3d003fb913ed 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -630,6 +630,7 @@ void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt) mp->field = pix->field; mp->colorspace = pix->colorspace; mp->xfer_func = pix->xfer_func; + /* Also copies hsv_enc */ mp->ycbcr_enc = pix->ycbcr_enc; mp->quantization = pix->quantization; mp->num_planes = 1; @@ -659,6 +660,7 @@ int fmt_sp2mp_func(struct file *file, void *priv, pix->field = mp->field; pix->colorspace = mp->colorspace; pix->xfer_func = mp->xfer_func; + /* Also copies hsv_enc */ pix->ycbcr_enc = mp->ycbcr_enc; pix->quantization = mp->quantization; pix->sizeimage = ppix->sizeimage; diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c index dd609eea4753..7ba52ee98371 100644 --- a/drivers/media/platform/vivid/vivid-vid-out.c +++ b/drivers/media/platform/vivid/vivid-vid-out.c @@ -256,6 +256,7 @@ void vivid_update_format_out(struct vivid_dev *dev) } dev->xfer_func_out = V4L2_XFER_FUNC_DEFAULT; dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT; + dev->hsv_enc_out = V4L2_HSV_ENC_180; dev->quantization_out = V4L2_QUANTIZATION_DEFAULT; dev->compose_out = dev->sink_rect; dev->compose_bounds_out = dev->sink_rect; diff --git a/include/media/v4l2-tpg.h b/include/media/v4l2-tpg.h index 8abed92317e8..13e49d85cae3 100644 --- a/include/media/v4l2-tpg.h +++ b/include/media/v4l2-tpg.h @@ -130,6 +130,7 @@ struct tpg_data { u32 colorspace; u32 xfer_func; u32 ycbcr_enc; + u32 hsv_enc; /* * Stores the actual transfer function, i.e. will never be * V4L2_XFER_FUNC_DEFAULT. @@ -139,6 +140,7 @@ struct tpg_data { * Stores the actual Y'CbCr encoding, i.e. will never be * V4L2_YCBCR_ENC_DEFAULT. */ + u32 real_hsv_enc; u32 real_ycbcr_enc; u32 quantization; /* @@ -341,6 +343,19 @@ static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg) return tpg->ycbcr_enc; } +static inline void tpg_s_hsv_enc(struct tpg_data *tpg, u32 hsv_enc) +{ + if (tpg->hsv_enc == hsv_enc) + return; + tpg->hsv_enc = hsv_enc; + tpg->recalc_colors = true; +} + +static inline u32 tpg_g_hsv_enc(const struct tpg_data *tpg) +{ + return tpg->hsv_enc; +} + static inline void tpg_s_xfer_func(struct tpg_data *tpg, u32 xfer_func) { if (tpg->xfer_func == xfer_func) -- cgit v1.2.3 From bc9b91e6be38b54a7b245969d0a9247791705e6a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 6 Sep 2016 21:04:53 -0300 Subject: [media] v4l: vsp1: Add support for capture and output in HSV formats Support both the HSV24 and HSV32 formats. From a hardware point of view pretend the formats are RGB, the RPF and WPF will just pass the data through without performing any processing. Signed-off-by: Laurent Pinchart Acked-by: Ricardo Ribalda Delgado Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_pipe.c | 8 ++++++++ drivers/media/platform/vsp1/vsp1_rwpf.c | 2 ++ drivers/media/platform/vsp1/vsp1_video.c | 5 +++++ 3 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_pipe.c b/drivers/media/platform/vsp1/vsp1_pipe.c index 756ca4ea7668..280ba0804699 100644 --- a/drivers/media/platform/vsp1/vsp1_pipe.c +++ b/drivers/media/platform/vsp1/vsp1_pipe.c @@ -78,6 +78,14 @@ static const struct vsp1_format_info vsp1_video_formats[] = { VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, 1, { 32, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_HSV24, MEDIA_BUS_FMT_AHSV8888_1X32, + VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, + 1, { 24, 0, 0 }, false, false, 1, 1, false }, + { V4L2_PIX_FMT_HSV32, MEDIA_BUS_FMT_AHSV8888_1X32, + VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | + VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, + 1, { 32, 0, 0 }, false, false, 1, 1, false }, { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32, VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS | VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS, diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c index 66e4d7ea31d6..04104ef28fb5 100644 --- a/drivers/media/platform/vsp1/vsp1_rwpf.c +++ b/drivers/media/platform/vsp1/vsp1_rwpf.c @@ -37,6 +37,7 @@ static int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev, { static const unsigned int codes[] = { MEDIA_BUS_FMT_ARGB8888_1X32, + MEDIA_BUS_FMT_AHSV8888_1X32, MEDIA_BUS_FMT_AYUV8_1X32, }; @@ -78,6 +79,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, /* Default to YUV if the requested format is not supported. */ if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 && + fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 && fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32) fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32; diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c index d351b9c768d2..41e8b096dab8 100644 --- a/drivers/media/platform/vsp1/vsp1_video.c +++ b/drivers/media/platform/vsp1/vsp1_video.c @@ -124,6 +124,11 @@ static int __vsp1_video_try_format(struct vsp1_video *video, pix->pixelformat = info->fourcc; pix->colorspace = V4L2_COLORSPACE_SRGB; pix->field = V4L2_FIELD_NONE; + + if (info->fourcc == V4L2_PIX_FMT_HSV24 || + info->fourcc == V4L2_PIX_FMT_HSV32) + pix->hsv_enc = V4L2_HSV_ENC_256; + memset(pix->reserved, 0, sizeof(pix->reserved)); /* Align the width and height for YUV 4:2:2 and 4:2:0 formats. */ -- cgit v1.2.3 From e2aad66638f995f825e637ef621f45d902c130d1 Mon Sep 17 00:00:00 2001 From: Sangwon Jee Date: Fri, 21 Oct 2016 15:28:59 -0700 Subject: Input: melfas_mip4 - add product_id sysfs attribute Add product_id sysfs attribute and update protocol version to support it. Signed-off-by: Sangwon Jee Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 40 +++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 552a3773f79d..8739cb718b4c 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -33,7 +33,7 @@ /***************************************************************** * Protocol - * Version : MIP 4.0 Rev 4.6 + * Version : MIP 4.0 Rev 5.4 *****************************************************************/ /* Address */ @@ -81,6 +81,9 @@ #define MIP4_R1_INFO_IC_HW_CATEGORY 0x77 #define MIP4_R1_INFO_CONTACT_THD_SCR 0x78 #define MIP4_R1_INFO_CONTACT_THD_KEY 0x7A +#define MIP4_R1_INFO_PID 0x7C +#define MIP4_R1_INFO_VID 0x7E +#define MIP4_R1_INFO_SLAVE_ADDR 0x80 #define MIP4_R0_EVENT 0x02 #define MIP4_R1_EVENT_SUPPORTED_FUNC 0x00 @@ -157,6 +160,7 @@ struct mip4_ts { char phys[32]; char product_name[16]; + u16 product_id; char ic_name[4]; unsigned int max_x; @@ -264,6 +268,18 @@ static int mip4_query_device(struct mip4_ts *ts) dev_dbg(&ts->client->dev, "product name: %.*s\n", (int)sizeof(ts->product_name), ts->product_name); + /* Product ID */ + cmd[0] = MIP4_R0_INFO; + cmd[1] = MIP4_R1_INFO_PID; + error = mip4_i2c_xfer(ts, cmd, sizeof(cmd), buf, 2); + if (error) { + dev_warn(&ts->client->dev, + "Failed to retrieve product id: %d\n", error); + } else { + ts->product_id = get_unaligned_le16(&buf[0]); + dev_dbg(&ts->client->dev, "product id: %04X\n", ts->product_id); + } + /* IC name */ cmd[0] = MIP4_R0_INFO; cmd[1] = MIP4_R1_INFO_IC_NAME; @@ -1348,6 +1364,25 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev, static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL); +static ssize_t mip4_sysfs_read_product_id(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct mip4_ts *ts = i2c_get_clientdata(client); + size_t count; + + mutex_lock(&ts->input->mutex); + + count = snprintf(buf, PAGE_SIZE, "%04X\n", ts->product_id); + + mutex_unlock(&ts->input->mutex); + + return count; +} + +static DEVICE_ATTR(product_id, S_IRUGO, mip4_sysfs_read_product_id, NULL); + static ssize_t mip4_sysfs_read_ic_name(struct device *dev, struct device_attribute *attr, char *buf) @@ -1371,6 +1406,7 @@ static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL); static struct attribute *mip4_attrs[] = { &dev_attr_fw_version.attr, &dev_attr_hw_version.attr, + &dev_attr_product_id.attr, &dev_attr_ic_name.attr, &dev_attr_update_fw.attr, NULL, @@ -1572,6 +1608,6 @@ static struct i2c_driver mip4_driver = { module_i2c_driver(mip4_driver); MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen"); -MODULE_VERSION("2016.09.28"); +MODULE_VERSION("2016.10.20"); MODULE_AUTHOR("Sangwon Jee "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 77b425399f6d5f1b04c58738bc10ca6decb10c9a Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Fri, 21 Oct 2016 15:35:33 -0700 Subject: Input: i8042 - use chassis info to skip selftest on Asus laptops Instead of relying on this model zoo let's skip selftest on all newer Asus laptops (newer as in when they changed "Computer" -> "COMPUTER" in their DMI data). Signed-off-by: Marcos Paulo de Souza Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 74 +---------------------------------- 1 file changed, 1 insertion(+), 73 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index f4bfb4b2d50a..b42787e21d0a 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -517,79 +517,7 @@ static const struct dmi_system_id i8042_dmi_noselftest_table[] = { { .matches = { DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "R409L"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"), - }, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), - DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"), + DMI_MATCH(DMI_CHASSIS_TYPE, "10"), /* Notebook */ }, }, { } -- cgit v1.2.3 From 668592492409498afc277da41e84799e1d2255c2 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Thu, 20 Oct 2016 10:49:01 +0200 Subject: mtd: nand: Add OX820 NAND Support Add NAND driver to support the Oxford Semiconductor OX820 NAND Controller. This is a simple memory mapped NAND controller with single chip select and software ECC. Acked-by: Rob Herring Signed-off-by: Neil Armstrong Signed-off-by: Boris Brezillon --- .../devicetree/bindings/mtd/oxnas-nand.txt | 41 +++++ drivers/mtd/nand/Kconfig | 5 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/oxnas_nand.c | 195 +++++++++++++++++++++ 4 files changed, 242 insertions(+) create mode 100644 Documentation/devicetree/bindings/mtd/oxnas-nand.txt create mode 100644 drivers/mtd/nand/oxnas_nand.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mtd/oxnas-nand.txt b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt new file mode 100644 index 000000000000..56d5c19da41d --- /dev/null +++ b/Documentation/devicetree/bindings/mtd/oxnas-nand.txt @@ -0,0 +1,41 @@ +* Oxford Semiconductor OXNAS NAND Controller + +Please refer to nand.txt for generic information regarding MTD NAND bindings. + +Required properties: + - compatible: "oxsemi,ox820-nand" + - reg: Base address and length for NAND mapped memory. + +Optional Properties: + - clocks: phandle to the NAND gate clock if needed. + - resets: phandle to the NAND reset control if needed. + +Example: + +nandc: nand-controller@41000000 { + compatible = "oxsemi,ox820-nand"; + reg = <0x41000000 0x100000>; + clocks = <&stdclk CLK_820_NAND>; + resets = <&reset RESET_NAND>; + #address-cells = <1>; + #size-cells = <0>; + + nand@0 { + reg = <0>; + #address-cells = <1>; + #size-cells = <1>; + nand-ecc-mode = "soft"; + nand-ecc-algo = "hamming"; + + partition@0 { + label = "boot"; + reg = <0x00000000 0x00e00000>; + read-only; + }; + + partition@e00000 { + label = "ubi"; + reg = <0x00e00000 0x07200000>; + }; + }; +}; diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 7b7a887b4709..c023125989cf 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -426,6 +426,11 @@ config MTD_NAND_ORION No board specific support is done by this driver, each board must advertise a platform_device for the driver to attach. +config MTD_NAND_OXNAS + tristate "NAND Flash support for Oxford Semiconductor SoC" + help + This enables the NAND flash controller on Oxford Semiconductor SoCs. + config MTD_NAND_FSL_ELBC tristate "NAND support for Freescale eLBC controllers" depends on FSL_SOC diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index cafde6f3d957..05fc054a9472 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -35,6 +35,7 @@ obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o +obj-$(CONFIG_MTD_NAND_OXNAS) += oxnas_nand.o obj-$(CONFIG_MTD_NAND_FSL_ELBC) += fsl_elbc_nand.o obj-$(CONFIG_MTD_NAND_FSL_IFC) += fsl_ifc_nand.o obj-$(CONFIG_MTD_NAND_FSL_UPM) += fsl_upm.o diff --git a/drivers/mtd/nand/oxnas_nand.c b/drivers/mtd/nand/oxnas_nand.c new file mode 100644 index 000000000000..3e3bf3b364d2 --- /dev/null +++ b/drivers/mtd/nand/oxnas_nand.c @@ -0,0 +1,195 @@ +/* + * Oxford Semiconductor OXNAS NAND driver + + * Copyright (C) 2016 Neil Armstrong + * Heavily based on plat_nand.c : + * Author: Vitaly Wool + * Copyright (C) 2013 Ma Haijun + * Copyright (C) 2012 John Crispin + * + * 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 + +/* Nand commands */ +#define OXNAS_NAND_CMD_ALE BIT(18) +#define OXNAS_NAND_CMD_CLE BIT(19) + +#define OXNAS_NAND_MAX_CHIPS 1 + +struct oxnas_nand_ctrl { + struct nand_hw_control base; + void __iomem *io_base; + struct clk *clk; + struct nand_chip *chips[OXNAS_NAND_MAX_CHIPS]; +}; + +static uint8_t oxnas_nand_read_byte(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); + + return readb(oxnas->io_base); +} + +static void oxnas_nand_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); + + ioread8_rep(oxnas->io_base, buf, len); +} + +static void oxnas_nand_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); + + iowrite8_rep(oxnas->io_base, buf, len); +} + +/* Single CS command control */ +static void oxnas_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, + unsigned int ctrl) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct oxnas_nand_ctrl *oxnas = nand_get_controller_data(chip); + + if (ctrl & NAND_CLE) + writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_CLE); + else if (ctrl & NAND_ALE) + writeb(cmd, oxnas->io_base + OXNAS_NAND_CMD_ALE); +} + +/* + * Probe for the NAND device. + */ +static int oxnas_nand_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct device_node *nand_np; + struct oxnas_nand_ctrl *oxnas; + struct nand_chip *chip; + struct mtd_info *mtd; + struct resource *res; + int nchips = 0; + int count = 0; + int err = 0; + + /* Allocate memory for the device structure (and zero it) */ + oxnas = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip), + GFP_KERNEL); + if (!oxnas) + return -ENOMEM; + + nand_hw_control_init(&oxnas->base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + oxnas->io_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(oxnas->io_base)) + return PTR_ERR(oxnas->io_base); + + oxnas->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(oxnas->clk)) + oxnas->clk = NULL; + + /* Only a single chip node is supported */ + count = of_get_child_count(np); + if (count > 1) + return -EINVAL; + + clk_prepare_enable(oxnas->clk); + device_reset_optional(&pdev->dev); + + for_each_child_of_node(np, nand_np) { + chip = devm_kzalloc(&pdev->dev, sizeof(struct nand_chip), + GFP_KERNEL); + if (!chip) + return -ENOMEM; + + chip->controller = &oxnas->base; + + nand_set_flash_node(chip, nand_np); + nand_set_controller_data(chip, oxnas); + + mtd = nand_to_mtd(chip); + mtd->dev.parent = &pdev->dev; + mtd->priv = chip; + + chip->cmd_ctrl = oxnas_nand_cmd_ctrl; + chip->read_buf = oxnas_nand_read_buf; + chip->read_byte = oxnas_nand_read_byte; + chip->write_buf = oxnas_nand_write_buf; + chip->chip_delay = 30; + + /* Scan to find existence of the device */ + err = nand_scan(mtd, 1); + if (err) + return err; + + err = mtd_device_register(mtd, NULL, 0); + if (err) { + nand_release(mtd); + return err; + } + + oxnas->chips[nchips] = chip; + ++nchips; + } + + /* Exit if no chips found */ + if (!nchips) + return -ENODEV; + + platform_set_drvdata(pdev, oxnas); + + return 0; +} + +static int oxnas_nand_remove(struct platform_device *pdev) +{ + struct oxnas_nand_ctrl *oxnas = platform_get_drvdata(pdev); + + if (oxnas->chips[0]) + nand_release(nand_to_mtd(oxnas->chips[0])); + + clk_disable_unprepare(oxnas->clk); + + return 0; +} + +static const struct of_device_id oxnas_nand_match[] = { + { .compatible = "oxsemi,ox820-nand" }, + {}, +}; +MODULE_DEVICE_TABLE(of, oxnas_nand_match); + +static struct platform_driver oxnas_nand_driver = { + .probe = oxnas_nand_probe, + .remove = oxnas_nand_remove, + .driver = { + .name = "oxnas_nand", + .of_match_table = oxnas_nand_match, + }, +}; + +module_platform_driver(oxnas_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Neil Armstrong "); +MODULE_DESCRIPTION("Oxnas NAND driver"); +MODULE_ALIAS("platform:oxnas_nand"); -- cgit v1.2.3 From 304887041d953b6692c0d4a9f8fafb252d32e9a0 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 20 Oct 2016 16:28:01 +0000 Subject: platform/x86: Introduce support for Mellanox hotplug driver Enable system support for the Mellanox Technologies hotplug platform driver, which provides support for the next Mellanox basic systems: "msx6710", "msx6720", "msb7700", "msn2700", "msx1410", "msn2410", "msb7800", "msn2740", "msn2100" and also various number of derivative systems from the above basic types. This driver handles hot-plug events for the power suppliers, power cables and fans for the above systems. The Kconfig currently controlling compilation of this code is: driver/platform/x86:config MLX_CPLD_PLATFORM tristate "Mellanox platform hotplug driver support" Signed-off-by: Vadim Pasternak Signed-off-by: Darren Hart --- MAINTAINERS | 7 + drivers/platform/x86/Kconfig | 11 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/mlxcpld-hotplug.c | 515 ++++++++++++++++++++++++++ include/linux/platform_data/mlxcpld-hotplug.h | 99 +++++ 5 files changed, 633 insertions(+) create mode 100644 drivers/platform/x86/mlxcpld-hotplug.c create mode 100644 include/linux/platform_data/mlxcpld-hotplug.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 1cd38a7e0064..3e30399e715f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7881,6 +7881,13 @@ L: platform-driver-x86@vger.kernel.org S: Supported F: arch/x86/platform/mellanox/mlx-platform.c +MELLANOX MLX CPLD HOTPLUG DRIVER +M: Vadim Pasternak +L: platform-driver-x86@vger.kernel.org +S: Supported +F: drivers/platform/x86/mlxcpld-hotplug.c +F: include/linux/platform_data/mlxcpld-hotplug.h + SOFT-ROCE DRIVER (rxe) M: Moni Shoua L: linux-rdma@vger.kernel.org diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b8a21d7b25d4..185376901d9c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1027,4 +1027,15 @@ config INTEL_TELEMETRY used to get various SoC events and parameters directly via debugfs files. Various tools may use this interface for SoC state monitoring. + +config MLX_CPLD_PLATFORM + tristate "Mellanox platform hotplug driver support" + default n + depends on MLX_PLATFORM + select HWMON + select I2C + ---help--- + This driver handles hot-plug events for the power suppliers, power + cables and fans on the wide range Mellanox IB and Ethernet systems. + endif # X86_PLATFORM_DEVICES diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2efa86d2a1a7..1f06b6339cf7 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -71,3 +71,4 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ intel_telemetry_debugfs.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o +obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o diff --git a/drivers/platform/x86/mlxcpld-hotplug.c b/drivers/platform/x86/mlxcpld-hotplug.c new file mode 100644 index 000000000000..aff3686b3b37 --- /dev/null +++ b/drivers/platform/x86/mlxcpld-hotplug.c @@ -0,0 +1,515 @@ +/* + * drivers/platform/x86/mlxcpld-hotplug.c + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016 Vadim Pasternak + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Offset of event and mask registers from status register */ +#define MLXCPLD_HOTPLUG_EVENT_OFF 1 +#define MLXCPLD_HOTPLUG_MASK_OFF 2 +#define MLXCPLD_HOTPLUG_AGGR_MASK_OFF 1 + +#define MLXCPLD_HOTPLUG_ATTRS_NUM 8 + +/** + * enum mlxcpld_hotplug_attr_type - sysfs attributes for hotplug events: + * @MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: power supply unit attribute; + * @MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: power cable attribute; + * @MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: FAN drawer attribute; + */ +enum mlxcpld_hotplug_attr_type { + MLXCPLD_HOTPLUG_ATTR_TYPE_PSU, + MLXCPLD_HOTPLUG_ATTR_TYPE_PWR, + MLXCPLD_HOTPLUG_ATTR_TYPE_FAN, +}; + +/** + * struct mlxcpld_hotplug_priv_data - platform private data: + * @irq: platform interrupt number; + * @pdev: platform device; + * @plat: platform data; + * @hwmon: hwmon device; + * @mlxcpld_hotplug_attr: sysfs attributes array; + * @mlxcpld_hotplug_dev_attr: sysfs sensor device attribute array; + * @group: sysfs attribute group; + * @groups: list of sysfs attribute group for hwmon registration; + * @dwork: delayed work template; + * @lock: spin lock; + * @aggr_cache: last value of aggregation register status; + * @psu_cache: last value of PSU register status; + * @pwr_cache: last value of power register status; + * @fan_cache: last value of FAN register status; + */ +struct mlxcpld_hotplug_priv_data { + int irq; + struct platform_device *pdev; + struct mlxcpld_hotplug_platform_data *plat; + struct device *hwmon; + struct attribute *mlxcpld_hotplug_attr[MLXCPLD_HOTPLUG_ATTRS_NUM + 1]; + struct sensor_device_attribute_2 + mlxcpld_hotplug_dev_attr[MLXCPLD_HOTPLUG_ATTRS_NUM]; + struct attribute_group group; + const struct attribute_group *groups[2]; + struct delayed_work dwork; + spinlock_t lock; + u8 aggr_cache; + u8 psu_cache; + u8 pwr_cache; + u8 fan_cache; +}; + +static ssize_t mlxcpld_hotplug_attr_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct platform_device *pdev = to_platform_device(dev); + struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev); + int index = to_sensor_dev_attr_2(attr)->index; + int nr = to_sensor_dev_attr_2(attr)->nr; + u8 reg_val = 0; + + switch (nr) { + case MLXCPLD_HOTPLUG_ATTR_TYPE_PSU: + /* Bit = 0 : PSU is present. */ + reg_val = !!!(inb(priv->plat->psu_reg_offset) & BIT(index)); + break; + + case MLXCPLD_HOTPLUG_ATTR_TYPE_PWR: + /* Bit = 1 : power cable is attached. */ + reg_val = !!(inb(priv->plat->pwr_reg_offset) & BIT(index % + priv->plat->pwr_count)); + break; + + case MLXCPLD_HOTPLUG_ATTR_TYPE_FAN: + /* Bit = 0 : FAN is present. */ + reg_val = !!!(inb(priv->plat->fan_reg_offset) & BIT(index % + priv->plat->fan_count)); + break; + } + + return sprintf(buf, "%u\n", reg_val); +} + +#define PRIV_ATTR(i) priv->mlxcpld_hotplug_attr[i] +#define PRIV_DEV_ATTR(i) priv->mlxcpld_hotplug_dev_attr[i] +static int mlxcpld_hotplug_attr_init(struct mlxcpld_hotplug_priv_data *priv) +{ + int num_attrs = priv->plat->psu_count + priv->plat->pwr_count + + priv->plat->fan_count; + int i; + + priv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs * + sizeof(struct attribute *), + GFP_KERNEL); + if (!priv->group.attrs) + return -ENOMEM; + + for (i = 0; i < num_attrs; i++) { + PRIV_ATTR(i) = &PRIV_DEV_ATTR(i).dev_attr.attr; + + if (i < priv->plat->psu_count) { + PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, "psu%u", i + 1); + PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PSU; + } else if (i < priv->plat->psu_count + priv->plat->pwr_count) { + PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, "pwr%u", i % + priv->plat->pwr_count + 1); + PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_PWR; + } else { + PRIV_ATTR(i)->name = devm_kasprintf(&priv->pdev->dev, + GFP_KERNEL, "fan%u", i % + priv->plat->fan_count + 1); + PRIV_DEV_ATTR(i).nr = MLXCPLD_HOTPLUG_ATTR_TYPE_FAN; + } + + if (!PRIV_ATTR(i)->name) { + dev_err(&priv->pdev->dev, "Memory allocation failed for sysfs attribute %d.\n", + i + 1); + return -ENOMEM; + } + + PRIV_DEV_ATTR(i).dev_attr.attr.name = PRIV_ATTR(i)->name; + PRIV_DEV_ATTR(i).dev_attr.attr.mode = S_IRUGO; + PRIV_DEV_ATTR(i).dev_attr.show = mlxcpld_hotplug_attr_show; + PRIV_DEV_ATTR(i).index = i; + sysfs_attr_init(&PRIV_DEV_ATTR(i).dev_attr.attr); + } + + priv->group.attrs = priv->mlxcpld_hotplug_attr; + priv->groups[0] = &priv->group; + priv->groups[1] = NULL; + + return 0; +} + +static int mlxcpld_hotplug_device_create(struct device *dev, + struct mlxcpld_hotplug_device *item) +{ + item->adapter = i2c_get_adapter(item->bus); + if (!item->adapter) { + dev_err(dev, "Failed to get adapter for bus %d\n", + item->bus); + return -EFAULT; + } + + item->client = i2c_new_device(item->adapter, &item->brdinfo); + if (!item->client) { + dev_err(dev, "Failed to create client %s at bus %d at addr 0x%02x\n", + item->brdinfo.type, item->bus, item->brdinfo.addr); + i2c_put_adapter(item->adapter); + item->adapter = NULL; + return -EFAULT; + } + + return 0; +} + +static void mlxcpld_hotplug_device_destroy(struct mlxcpld_hotplug_device *item) +{ + if (item->client) { + i2c_unregister_device(item->client); + item->client = NULL; + } + + if (item->adapter) { + i2c_put_adapter(item->adapter); + item->adapter = NULL; + } +} + +static inline void +mlxcpld_hotplug_work_helper(struct device *dev, + struct mlxcpld_hotplug_device *item, u8 is_inverse, + u16 offset, u8 mask, u8 *cache) +{ + u8 val, asserted; + int bit; + + /* Mask event. */ + outb(0, offset + MLXCPLD_HOTPLUG_MASK_OFF); + /* Read status. */ + val = inb(offset) & mask; + asserted = *cache ^ val; + *cache = val; + + /* + * Validate if item related to received signal type is valid. + * It should never happen, excepted the situation when some + * piece of hardware is broken. In such situation just produce + * error message and return. Caller must continue to handle the + * signals from other devices if any. + */ + if (unlikely(!item)) { + dev_err(dev, "False signal is received: register at offset 0x%02x, mask 0x%02x.\n", + offset, mask); + return; + } + + for_each_set_bit(bit, (unsigned long *)&asserted, 8) { + if (val & BIT(bit)) { + if (is_inverse) + mlxcpld_hotplug_device_destroy(item + bit); + else + mlxcpld_hotplug_device_create(dev, item + bit); + } else { + if (is_inverse) + mlxcpld_hotplug_device_create(dev, item + bit); + else + mlxcpld_hotplug_device_destroy(item + bit); + } + } + + /* Acknowledge event. */ + outb(0, offset + MLXCPLD_HOTPLUG_EVENT_OFF); + /* Unmask event. */ + outb(mask, offset + MLXCPLD_HOTPLUG_MASK_OFF); +} + +/* + * mlxcpld_hotplug_work_handler - performs traversing of CPLD interrupt + * registers according to the below hierarchy schema: + * + * Aggregation registers (status/mask) + * PSU registers: *---* + * *-----------------* | | + * |status/event/mask|----->| * | + * *-----------------* | | + * Power registers: | | + * *-----------------* | | + * |status/event/mask|----->| * |---> CPU + * *-----------------* | | + * FAN registers: + * *-----------------* | | + * |status/event/mask|----->| * | + * *-----------------* | | + * *---* + * In case some system changed are detected: FAN in/out, PSU in/out, power + * cable attached/detached, relevant device is created or destroyed. + */ +static void mlxcpld_hotplug_work_handler(struct work_struct *work) +{ + struct mlxcpld_hotplug_priv_data *priv = container_of(work, + struct mlxcpld_hotplug_priv_data, dwork.work); + u8 val, aggr_asserted; + unsigned long flags; + + /* Mask aggregation event. */ + outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); + /* Read aggregation status. */ + val = inb(priv->plat->top_aggr_offset) & priv->plat->top_aggr_mask; + aggr_asserted = priv->aggr_cache ^ val; + priv->aggr_cache = val; + + /* Handle PSU configuration changes. */ + if (aggr_asserted & priv->plat->top_aggr_psu_mask) + mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->psu, + 1, priv->plat->psu_reg_offset, + priv->plat->psu_mask, + &priv->psu_cache); + + /* Handle power cable configuration changes. */ + if (aggr_asserted & priv->plat->top_aggr_pwr_mask) + mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->pwr, + 0, priv->plat->pwr_reg_offset, + priv->plat->pwr_mask, + &priv->pwr_cache); + + /* Handle FAN configuration changes. */ + if (aggr_asserted & priv->plat->top_aggr_fan_mask) + mlxcpld_hotplug_work_helper(&priv->pdev->dev, priv->plat->fan, + 1, priv->plat->fan_reg_offset, + priv->plat->fan_mask, + &priv->fan_cache); + + if (aggr_asserted) { + spin_lock_irqsave(&priv->lock, flags); + + /* + * It is possible, that some signals have been inserted, while + * interrupt has been masked by mlxcpld_hotplug_work_handler. + * In this case such signals will be missed. In order to handle + * these signals delayed work is canceled and work task + * re-scheduled for immediate execution. It allows to handle + * missed signals, if any. In other case work handler just + * validates that no new signals have been received during + * masking. + */ + cancel_delayed_work(&priv->dwork); + schedule_delayed_work(&priv->dwork, 0); + + spin_unlock_irqrestore(&priv->lock, flags); + + return; + } + + /* Unmask aggregation event (no need acknowledge). */ + outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); +} + +static void mlxcpld_hotplug_set_irq(struct mlxcpld_hotplug_priv_data *priv) +{ + /* Clear psu presense event. */ + outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); + /* Set psu initial status as mask and unmask psu event. */ + priv->psu_cache = priv->plat->psu_mask; + outb(priv->plat->psu_mask, priv->plat->psu_reg_offset + + MLXCPLD_HOTPLUG_MASK_OFF); + + /* Clear power cable event. */ + outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); + /* Keep power initial status as zero and unmask power event. */ + outb(priv->plat->pwr_mask, priv->plat->pwr_reg_offset + + MLXCPLD_HOTPLUG_MASK_OFF); + + /* Clear fan presense event. */ + outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); + /* Set fan initial status as mask and unmask fan event. */ + priv->fan_cache = priv->plat->fan_mask; + outb(priv->plat->fan_mask, priv->plat->fan_reg_offset + + MLXCPLD_HOTPLUG_MASK_OFF); + + /* Keep aggregation initial status as zero and unmask events. */ + outb(priv->plat->top_aggr_mask, priv->plat->top_aggr_offset + + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); + + /* Invoke work handler for initializing hot plug devices setting. */ + mlxcpld_hotplug_work_handler(&priv->dwork.work); + + enable_irq(priv->irq); +} + +static void mlxcpld_hotplug_unset_irq(struct mlxcpld_hotplug_priv_data *priv) +{ + int i; + + disable_irq(priv->irq); + cancel_delayed_work_sync(&priv->dwork); + + /* Mask aggregation event. */ + outb(0, priv->plat->top_aggr_offset + MLXCPLD_HOTPLUG_AGGR_MASK_OFF); + + /* Mask psu presense event. */ + outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); + /* Clear psu presense event. */ + outb(0, priv->plat->psu_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); + + /* Mask power cable event. */ + outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); + /* Clear power cable event. */ + outb(0, priv->plat->pwr_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); + + /* Mask fan presense event. */ + outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_MASK_OFF); + /* Clear fan presense event. */ + outb(0, priv->plat->fan_reg_offset + MLXCPLD_HOTPLUG_EVENT_OFF); + + /* Remove all the attached devices. */ + for (i = 0; i < priv->plat->psu_count; i++) + mlxcpld_hotplug_device_destroy(priv->plat->psu + i); + + for (i = 0; i < priv->plat->pwr_count; i++) + mlxcpld_hotplug_device_destroy(priv->plat->pwr + i); + + for (i = 0; i < priv->plat->fan_count; i++) + mlxcpld_hotplug_device_destroy(priv->plat->fan + i); +} + +static irqreturn_t mlxcpld_hotplug_irq_handler(int irq, void *dev) +{ + struct mlxcpld_hotplug_priv_data *priv = + (struct mlxcpld_hotplug_priv_data *)dev; + + /* Schedule work task for immediate execution.*/ + schedule_delayed_work(&priv->dwork, 0); + + return IRQ_HANDLED; +} + +static int mlxcpld_hotplug_probe(struct platform_device *pdev) +{ + struct mlxcpld_hotplug_platform_data *pdata; + struct mlxcpld_hotplug_priv_data *priv; + int err; + + pdata = dev_get_platdata(&pdev->dev); + if (!pdata) { + dev_err(&pdev->dev, "Failed to get platform data.\n"); + return -EINVAL; + } + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->pdev = pdev; + priv->plat = pdata; + + priv->irq = platform_get_irq(pdev, 0); + if (priv->irq < 0) { + dev_err(&pdev->dev, "Failed to get platform irq: %d\n", + priv->irq); + return priv->irq; + } + + err = devm_request_irq(&pdev->dev, priv->irq, + mlxcpld_hotplug_irq_handler, 0, pdev->name, + priv); + if (err) { + dev_err(&pdev->dev, "Failed to request irq: %d\n", err); + return err; + } + disable_irq(priv->irq); + + INIT_DELAYED_WORK(&priv->dwork, mlxcpld_hotplug_work_handler); + spin_lock_init(&priv->lock); + + err = mlxcpld_hotplug_attr_init(priv); + if (err) { + dev_err(&pdev->dev, "Failed to allocate attributes: %d\n", err); + return err; + } + + priv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev, + "mlxcpld_hotplug", priv, priv->groups); + if (IS_ERR(priv->hwmon)) { + dev_err(&pdev->dev, "Failed to register hwmon device %ld\n", + PTR_ERR(priv->hwmon)); + return PTR_ERR(priv->hwmon); + } + + platform_set_drvdata(pdev, priv); + + /* Perform initial interrupts setup. */ + mlxcpld_hotplug_set_irq(priv); + + return 0; +} + +static int mlxcpld_hotplug_remove(struct platform_device *pdev) +{ + struct mlxcpld_hotplug_priv_data *priv = platform_get_drvdata(pdev); + + /* Clean interrupts setup. */ + mlxcpld_hotplug_unset_irq(priv); + + return 0; +} + +static struct platform_driver mlxcpld_hotplug_driver = { + .driver = { + .name = "mlxcpld-hotplug", + }, + .probe = mlxcpld_hotplug_probe, + .remove = mlxcpld_hotplug_remove, +}; + +module_platform_driver(mlxcpld_hotplug_driver); + +MODULE_AUTHOR("Vadim Pasternak "); +MODULE_DESCRIPTION("Mellanox CPLD hotplug platform driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:mlxcpld-hotplug"); diff --git a/include/linux/platform_data/mlxcpld-hotplug.h b/include/linux/platform_data/mlxcpld-hotplug.h new file mode 100644 index 000000000000..e4cfcffaa6f4 --- /dev/null +++ b/include/linux/platform_data/mlxcpld-hotplug.h @@ -0,0 +1,99 @@ +/* + * include/linux/platform_data/mlxcpld-hotplug.h + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016 Vadim Pasternak + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H +#define __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H + +/** + * struct mlxcpld_hotplug_device - I2C device data: + * @adapter: I2C device adapter; + * @client: I2C device client; + * @brdinfo: device board information; + * @bus: I2C bus, where device is attached; + * + * Structure represents I2C hotplug device static data (board topology) and + * dynamic data (related kernel objects handles). + */ +struct mlxcpld_hotplug_device { + struct i2c_adapter *adapter; + struct i2c_client *client; + struct i2c_board_info brdinfo; + u16 bus; +}; + +/** + * struct mlxcpld_hotplug_platform_data - device platform data: + * @top_aggr_offset: offset of top aggregation interrupt register; + * @top_aggr_mask: top aggregation interrupt common mask; + * @top_aggr_psu_mask: top aggregation interrupt PSU mask; + * @psu_reg_offset: offset of PSU interrupt register; + * @psu_mask: PSU interrupt mask; + * @psu_count: number of equipped replaceable PSUs; + * @psu: pointer to PSU devices data array; + * @top_aggr_pwr_mask: top aggregation interrupt power mask; + * @pwr_reg_offset: offset of power interrupt register + * @pwr_mask: power interrupt mask; + * @pwr_count: number of power sources; + * @pwr: pointer to power devices data array; + * @top_aggr_fan_mask: top aggregation interrupt FAN mask; + * @fan_reg_offset: offset of FAN interrupt register; + * @fan_mask: FAN interrupt mask; + * @fan_count: number of equipped replaceable FANs; + * @fan: pointer to FAN devices data array; + * + * Structure represents board platform data, related to system hotplug events, + * like FAN, PSU, power cable insertion and removing. This data provides the + * number of hot-pluggable devices and hardware description for event handling. + */ +struct mlxcpld_hotplug_platform_data { + u16 top_aggr_offset; + u8 top_aggr_mask; + u8 top_aggr_psu_mask; + u16 psu_reg_offset; + u8 psu_mask; + u8 psu_count; + struct mlxcpld_hotplug_device *psu; + u8 top_aggr_pwr_mask; + u16 pwr_reg_offset; + u8 pwr_mask; + u8 pwr_count; + struct mlxcpld_hotplug_device *pwr; + u8 top_aggr_fan_mask; + u16 fan_reg_offset; + u8 fan_mask; + u8 fan_count; + struct mlxcpld_hotplug_device *fan; +}; + +#endif /* __LINUX_PLATFORM_DATA_MLXCPLD_HOTPLUG_H */ -- cgit v1.2.3 From ed4dba99cae80d14afb8ddcc677a2f547dd70162 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 13 Jun 2016 14:03:34 -0400 Subject: reset: berlin: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/reset/Kconfig:config RESET_BERLIN drivers/reset/Kconfig: bool "Berlin Reset Driver" if COMPILE_TEST drivers/reset/Kconfig: default ARCH_BERLIN or arch/arm/mach-berlin/Kconfig:menuconfig ARCH_BERLIN arch/arm/mach-berlin/Kconfig: bool "Marvell Berlin SoCs" if ARCH_MULTI_V7 or arch/arm64/Kconfig.platforms:config ARCH_BERLIN arch/arm64/Kconfig.platforms: bool "Marvell Berlin SoC Family" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Cc: Antoine Tenart Cc: Sebastian Hesselbarth Signed-off-by: Paul Gortmaker Signed-off-by: Philipp Zabel --- drivers/reset/reset-berlin.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/reset-berlin.c b/drivers/reset/reset-berlin.c index 369f3917fd8e..371197bbd055 100644 --- a/drivers/reset/reset-berlin.c +++ b/drivers/reset/reset-berlin.c @@ -1,6 +1,8 @@ /* * Copyright (C) 2014 Marvell Technology Group Ltd. * + * Marvell Berlin reset driver + * * Antoine Tenart * Sebastian Hesselbarth * @@ -12,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -91,7 +93,6 @@ static const struct of_device_id berlin_reset_dt_match[] = { { .compatible = "marvell,berlin2-reset" }, { }, }; -MODULE_DEVICE_TABLE(of, berlin_reset_dt_match); static struct platform_driver berlin_reset_driver = { .probe = berlin2_reset_probe, @@ -100,9 +101,4 @@ static struct platform_driver berlin_reset_driver = { .of_match_table = berlin_reset_dt_match, }, }; -module_platform_driver(berlin_reset_driver); - -MODULE_AUTHOR("Antoine Tenart "); -MODULE_AUTHOR("Sebastian Hesselbarth "); -MODULE_DESCRIPTION("Marvell Berlin reset driver"); -MODULE_LICENSE("GPL"); +builtin_platform_driver(berlin_reset_driver); -- cgit v1.2.3 From 02163199bed1aae49f9ebd2a2172523148c0aaa2 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 13 Jun 2016 14:03:35 -0400 Subject: reset: socfpga: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/reset/Kconfig:config RESET_SOCFPGA drivers/reset/Kconfig: bool "SoCFPGA Reset Driver" if COMPILE_TEST drivers/reset/Kconfig: default ARCH_SOCFPGA or arch/arm/mach-socfpga/Kconfig:menuconfig ARCH_SOCFPGA arch/arm/mach-socfpga/Kconfig: bool "Altera SOCFPGA family" if ARCH_MULTI_V7 ...meaning that it currently is not being built as a module by anyone. Lets remove the small amount of modular evidence that remains, so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Cc: Steffen Trumtrar Cc: Masahiro Yamada Signed-off-by: Paul Gortmaker Signed-off-by: Philipp Zabel --- drivers/reset/reset-socfpga.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c index 78ebf8424375..43e4a9f39b9b 100644 --- a/drivers/reset/reset-socfpga.c +++ b/drivers/reset/reset-socfpga.c @@ -1,4 +1,6 @@ /* + * Socfpga Reset Controller Driver + * * Copyright 2014 Steffen Trumtrar * * based on @@ -16,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -148,8 +150,4 @@ static struct platform_driver socfpga_reset_driver = { .of_match_table = socfpga_reset_dt_ids, }, }; -module_platform_driver(socfpga_reset_driver); - -MODULE_AUTHOR("Steffen Trumtrar Date: Mon, 13 Jun 2016 14:03:36 -0400 Subject: reset: sunxi: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/reset/Kconfig:config RESET_SUNXI drivers/reset/Kconfig: bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI drivers/reset/Kconfig: default ARCH_SUNXI or arch/arm/mach-sunxi/Kconfig:menuconfig ARCH_SUNXI arch/arm/mach-sunxi/Kconfig: bool "Allwinner SoCs" if ARCH_MULTI_V7 ...meaning that it currently is not being built as a module by anyone. Lets remove the few remaining traces of modular macro usage, so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Cc: Maxime Ripard Signed-off-by: Paul Gortmaker Signed-off-by: Philipp Zabel --- drivers/reset/reset-sunxi.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/reset-sunxi.c b/drivers/reset/reset-sunxi.c index 3080190b3f90..b44f6b5f87b6 100644 --- a/drivers/reset/reset-sunxi.c +++ b/drivers/reset/reset-sunxi.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #include #include @@ -142,7 +142,6 @@ static const struct of_device_id sunxi_reset_dt_ids[] = { { .compatible = "allwinner,sun6i-a31-clock-reset", }, { /* sentinel */ }, }; -MODULE_DEVICE_TABLE(of, sunxi_reset_dt_ids); static int sunxi_reset_probe(struct platform_device *pdev) { @@ -175,8 +174,4 @@ static struct platform_driver sunxi_reset_driver = { .of_match_table = sunxi_reset_dt_ids, }, }; -module_platform_driver(sunxi_reset_driver); - -MODULE_AUTHOR("Maxime Ripard Date: Mon, 13 Jun 2016 14:03:37 -0400 Subject: reset: zynq: make it explicitly non-modular MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Makefile/Kconfig currently controlling compilation of this code is: drivers/reset/Kconfig:config RESET_ZYNQ drivers/reset/Kconfig: bool "ZYNQ Reset Driver" if COMPILE_TEST drivers/reset/Kconfig: default ARCH_ZYNQ or drivers/reset/Makefile:obj-$(CONFIG_ARCH_ZYNQ) += reset-zynq.o arch/arm/mach-zynq/Kconfig:config ARCH_ZYNQ arch/arm/mach-zynq/Kconfig: bool "Xilinx Zynq ARM Cortex A9 Platform" if ARCH_MULTI_V7 ...meaning that it currently is not being built as a module by anyone. Lets remove the few remaining traces of modular macro usage, so that when reading the driver there is no doubt it is builtin-only. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Cc: "Sören Brinkmann" Signed-off-by: Paul Gortmaker Acked-by: Michal Simek Acked-by: Moritz Fischer Signed-off-by: Philipp Zabel --- drivers/reset/reset-zynq.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/reset-zynq.c b/drivers/reset/reset-zynq.c index 138f2f205662..87a4e355578f 100644 --- a/drivers/reset/reset-zynq.c +++ b/drivers/reset/reset-zynq.c @@ -3,6 +3,8 @@ * * Xilinx Zynq Reset controller driver * + * Author: Moritz Fischer + * * 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. @@ -15,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -137,8 +139,4 @@ static struct platform_driver zynq_reset_driver = { .of_match_table = zynq_reset_dt_ids, }, }; -module_platform_driver(zynq_reset_driver); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Moritz Fischer "); -MODULE_DESCRIPTION("Zynq Reset Controller Driver"); +builtin_platform_driver(zynq_reset_driver); -- cgit v1.2.3 From cdd24f76fe84fd6ee3b46f54b2a475d04d79889d Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 13 Jun 2016 14:03:38 -0400 Subject: reset: lpc18xx: make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/reset/Kconfig:config RESET_LPC18XX drivers/reset/Kconfig: bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST drivers/reset/Kconfig: default ARCH_LPC18XX or arch/arm/Kconfig:config ARCH_LPC18XX arch/arm/Kconfig: bool "NXP LPC18xx/LPC43xx" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_platform_driver() uses the same init level priority as builtin_platform_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Cc: Joachim Eastwood Signed-off-by: Paul Gortmaker Signed-off-by: Philipp Zabel --- drivers/reset/reset-lpc18xx.c | 32 +++++--------------------------- 1 file changed, 5 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/reset-lpc18xx.c b/drivers/reset/reset-lpc18xx.c index 54cca0055171..a62ad52e262b 100644 --- a/drivers/reset/reset-lpc18xx.c +++ b/drivers/reset/reset-lpc18xx.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include @@ -218,39 +218,17 @@ dis_clk_reg: return ret; } -static int lpc18xx_rgu_remove(struct platform_device *pdev) -{ - struct lpc18xx_rgu_data *rc = platform_get_drvdata(pdev); - int ret; - - ret = unregister_restart_handler(&rc->restart_nb); - if (ret) - dev_warn(&pdev->dev, "failed to unregister restart handler\n"); - - reset_controller_unregister(&rc->rcdev); - - clk_disable_unprepare(rc->clk_delay); - clk_disable_unprepare(rc->clk_reg); - - return 0; -} - static const struct of_device_id lpc18xx_rgu_match[] = { { .compatible = "nxp,lpc1850-rgu" }, { } }; -MODULE_DEVICE_TABLE(of, lpc18xx_rgu_match); static struct platform_driver lpc18xx_rgu_driver = { .probe = lpc18xx_rgu_probe, - .remove = lpc18xx_rgu_remove, .driver = { - .name = "lpc18xx-reset", - .of_match_table = lpc18xx_rgu_match, + .name = "lpc18xx-reset", + .of_match_table = lpc18xx_rgu_match, + .suppress_bind_attrs = true, }, }; -module_platform_driver(lpc18xx_rgu_driver); - -MODULE_AUTHOR("Joachim Eastwood "); -MODULE_DESCRIPTION("Reset driver for LPC18xx/43xx RGU"); -MODULE_LICENSE("GPL v2"); +builtin_platform_driver(lpc18xx_rgu_driver); -- cgit v1.2.3 From 0889e4a1bd569a2f1bf431170cec453b3ca4a658 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 22 Oct 2016 20:45:23 -0200 Subject: [media] spca506: rewrite a commented line to avoid wrong parsing Keeping Documentation/media/v4l-drivers/gspca-cardlist.rst in sync with the gspca script requires a parser. Simplify the commented line, to make the parser work better. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/spca506.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/spca506.c b/drivers/media/usb/gspca/spca506.c index bcd2c04c770e..ee84863d27d4 100644 --- a/drivers/media/usb/gspca/spca506.c +++ b/drivers/media/usb/gspca/spca506.c @@ -581,8 +581,7 @@ static const struct sd_desc sd_desc = { /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { {USB_DEVICE(0x06e1, 0xa190)}, -/*fixme: may be IntelPCCameraPro BRIDGE_SPCA505 - {USB_DEVICE(0x0733, 0x0430)}, */ +/* {USB_DEVICE(0x0733, 0x0430)}, FIXME: may be IntelPCCameraPro BRIDGE_SPCA505 */ {USB_DEVICE(0x0734, 0x043b)}, {USB_DEVICE(0x99fa, 0x8988)}, {} -- cgit v1.2.3 From b2fdd0ee948f39fb01c53fa15207a8cae71e0a55 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 22 Oct 2016 19:59:57 -0200 Subject: [media] stv06xx: store device name after the USB_DEVICE line That makes easier to parse the names, in order to sync it with gspca-cardlist.rst. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/gspca/stv06xx/stv06xx.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c index 562ddb050cfd..fef7a784b879 100644 --- a/drivers/media/usb/gspca/stv06xx/stv06xx.c +++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c @@ -579,18 +579,12 @@ static int stv06xx_config(struct gspca_dev *gspca_dev, /* -- module initialisation -- */ static const struct usb_device_id device_table[] = { - /* QuickCam Express */ - {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, - /* LEGO cam / QuickCam Web */ - {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 }, - /* Dexxa WebCam USB */ - {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 }, - /* QuickCam Messenger */ - {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 }, - /* QuickCam Communicate */ - {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 }, - /* QuickCam Messenger (new) */ - {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 }, + {USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 }, /* QuickCam Express */ + {USB_DEVICE(0x046d, 0x0850), .driver_info = BRIDGE_STV610 }, /* LEGO cam / QuickCam Web */ + {USB_DEVICE(0x046d, 0x0870), .driver_info = BRIDGE_STV602 }, /* Dexxa WebCam USB */ + {USB_DEVICE(0x046D, 0x08F0), .driver_info = BRIDGE_ST6422 }, /* QuickCam Messenger */ + {USB_DEVICE(0x046D, 0x08F5), .driver_info = BRIDGE_ST6422 }, /* QuickCam Communicate */ + {USB_DEVICE(0x046D, 0x08F6), .driver_info = BRIDGE_ST6422 }, /* QuickCam Messenger (new) */ {} }; MODULE_DEVICE_TABLE(usb, device_table); -- cgit v1.2.3 From e950267ab802c8558f1100eafd4087fd039ad634 Mon Sep 17 00:00:00 2001 From: Henrik Ingo Date: Sun, 29 May 2016 17:58:00 -0300 Subject: [media] uvcvideo: uvc_scan_fallback() for webcams with broken chain Some devices have invalid baSourceID references, causing uvc_scan_chain() to fail, but if we just take the entities we can find and put them together in the most sensible chain we can think of, turns out they do work anyway. Note: This heuristic assumes there is a single chain. At the time of writing, devices known to have such a broken chain are - Acer Integrated Camera (5986:055a) - Realtek rtl157a7 (0bda:57a7) Signed-off-by: Henrik Ingo Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 118 +++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 9c4b56b4a9c6..87b2fc3b0ac2 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1595,6 +1595,114 @@ static const char *uvc_print_chain(struct uvc_video_chain *chain) return buffer; } +static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev) +{ + struct uvc_video_chain *chain; + + chain = kzalloc(sizeof(*chain), GFP_KERNEL); + if (chain == NULL) + return NULL; + + INIT_LIST_HEAD(&chain->entities); + mutex_init(&chain->ctrl_mutex); + chain->dev = dev; + v4l2_prio_init(&chain->prio); + + return chain; +} + +/* + * Fallback heuristic for devices that don't connect units and terminals in a + * valid chain. + * + * Some devices have invalid baSourceID references, causing uvc_scan_chain() + * to fail, but if we just take the entities we can find and put them together + * in the most sensible chain we can think of, turns out they do work anyway. + * Note: This heuristic assumes there is a single chain. + * + * At the time of writing, devices known to have such a broken chain are + * - Acer Integrated Camera (5986:055a) + * - Realtek rtl157a7 (0bda:57a7) + */ +static int uvc_scan_fallback(struct uvc_device *dev) +{ + struct uvc_video_chain *chain; + struct uvc_entity *iterm = NULL; + struct uvc_entity *oterm = NULL; + struct uvc_entity *entity; + struct uvc_entity *prev; + + /* + * Start by locating the input and output terminals. We only support + * devices with exactly one of each for now. + */ + list_for_each_entry(entity, &dev->entities, list) { + if (UVC_ENTITY_IS_ITERM(entity)) { + if (iterm) + return -EINVAL; + iterm = entity; + } + + if (UVC_ENTITY_IS_OTERM(entity)) { + if (oterm) + return -EINVAL; + oterm = entity; + } + } + + if (iterm == NULL || oterm == NULL) + return -EINVAL; + + /* Allocate the chain and fill it. */ + chain = uvc_alloc_chain(dev); + if (chain == NULL) + return -ENOMEM; + + if (uvc_scan_chain_entity(chain, oterm) < 0) + goto error; + + prev = oterm; + + /* + * Add all Processing and Extension Units with two pads. The order + * doesn't matter much, use reverse list traversal to connect units in + * UVC descriptor order as we build the chain from output to input. This + * leads to units appearing in the order meant by the manufacturer for + * the cameras known to require this heuristic. + */ + list_for_each_entry_reverse(entity, &dev->entities, list) { + if (entity->type != UVC_VC_PROCESSING_UNIT && + entity->type != UVC_VC_EXTENSION_UNIT) + continue; + + if (entity->num_pads != 2) + continue; + + if (uvc_scan_chain_entity(chain, entity) < 0) + goto error; + + prev->baSourceID[0] = entity->id; + prev = entity; + } + + if (uvc_scan_chain_entity(chain, iterm) < 0) + goto error; + + prev->baSourceID[0] = iterm->id; + + list_add_tail(&chain->list, &dev->chains); + + uvc_trace(UVC_TRACE_PROBE, + "Found a video chain by fallback heuristic (%s).\n", + uvc_print_chain(chain)); + + return 0; + +error: + kfree(chain); + return -EINVAL; +} + /* * Scan the device for video chains and register video devices. * @@ -1617,15 +1725,10 @@ static int uvc_scan_device(struct uvc_device *dev) if (term->chain.next || term->chain.prev) continue; - chain = kzalloc(sizeof(*chain), GFP_KERNEL); + chain = uvc_alloc_chain(dev); if (chain == NULL) return -ENOMEM; - INIT_LIST_HEAD(&chain->entities); - mutex_init(&chain->ctrl_mutex); - chain->dev = dev; - v4l2_prio_init(&chain->prio); - term->flags |= UVC_ENTITY_FLAG_DEFAULT; if (uvc_scan_chain(chain, term) < 0) { @@ -1639,6 +1742,9 @@ static int uvc_scan_device(struct uvc_device *dev) list_add_tail(&chain->list, &dev->chains); } + if (list_empty(&dev->chains)) + uvc_scan_fallback(dev); + if (list_empty(&dev->chains)) { uvc_printk(KERN_INFO, "No valid video chain found.\n"); return -1; -- cgit v1.2.3 From 37e785682746b53017c7b6e533c3ac2c85bb4ac8 Mon Sep 17 00:00:00 2001 From: CIJOML CIJOMLovic Date: Mon, 1 Aug 2016 18:55:52 -0300 Subject: [media] Add support for EVOLVEO XtraTV stick Add a new USB ID for EVOLVEO XtraTV stick. [mchehab@s-opensource.org: fix patch and make checkpatch happy] Cc: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb-usb-ids.h | 1 + drivers/media/usb/dvb-usb-v2/af9035.c | 2 ++ 2 files changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index a7a4674ccc40..5938ea4abc69 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -411,4 +411,5 @@ #define USB_PID_SVEON_STV27 0xd3af #define USB_PID_TURBOX_DTT_2000 0xd3a4 #define USB_PID_WINTV_SOLOHD 0x0264 +#define USB_PID_EVOLVEO_XTRATV_STICK 0xa115 #endif diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c index 8961dd732522..c673726d9b70 100644 --- a/drivers/media/usb/dvb-usb-v2/af9035.c +++ b/drivers/media/usb/dvb-usb-v2/af9035.c @@ -2095,6 +2095,8 @@ static const struct usb_device_id af9035_id_table[] = { &af9035_props, "TerraTec Cinergy T Stick (rev. 2)", NULL) }, { DVB_USB_DEVICE(USB_VID_AVERMEDIA, 0x0337, &af9035_props, "AVerMedia HD Volar (A867)", NULL) }, + { DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_EVOLVEO_XTRATV_STICK, + &af9035_props, "EVOLVEO XtraTV stick", NULL) }, /* IT9135 devices */ { DVB_USB_DEVICE(USB_VID_ITETECH, USB_PID_ITETECH_IT9135, -- cgit v1.2.3 From bf8e27621effb49da525fb92a1f192db685d39bd Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Fri, 21 Oct 2016 10:30:16 +0800 Subject: regulator: rk808: Use rdev_get_id() to access id of regulator RK808_ID_DCDC1 is 0, no need to do subtract RK808_ID_DCDC1. Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/rk808-regulator.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c index 3314bf299a51..fb44d5215e30 100644 --- a/drivers/regulator/rk808-regulator.c +++ b/drivers/regulator/rk808-regulator.c @@ -120,7 +120,7 @@ static const struct regulator_linear_range rk808_ldo3_voltage_ranges[] = { static int rk808_buck1_2_get_voltage_sel_regmap(struct regulator_dev *rdev) { struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); - int id = rdev->desc->id - RK808_ID_DCDC1; + int id = rdev_get_id(rdev); struct gpio_desc *gpio = pdata->dvs_gpio[id]; unsigned int val; int ret; @@ -193,7 +193,7 @@ static int rk808_buck1_2_set_voltage_sel(struct regulator_dev *rdev, unsigned sel) { struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); - int id = rdev->desc->id - RK808_ID_DCDC1; + int id = rdev_get_id(rdev); struct gpio_desc *gpio = pdata->dvs_gpio[id]; unsigned int reg = rdev->desc->vsel_reg; unsigned old_sel; @@ -232,7 +232,7 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int new_selector) { struct rk808_regulator_data *pdata = rdev_get_drvdata(rdev); - int id = rdev->desc->id - RK808_ID_DCDC1; + int id = rdev_get_id(rdev); struct gpio_desc *gpio = pdata->dvs_gpio[id]; /* if there is no dvs1/2 pin, we don't need wait extra time here. */ @@ -245,8 +245,7 @@ static int rk808_buck1_2_set_voltage_time_sel(struct regulator_dev *rdev, static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay) { unsigned int ramp_value = RK808_RAMP_RATE_10MV_PER_US; - unsigned int reg = rk808_buck_config_regs[rdev->desc->id - - RK808_ID_DCDC1]; + unsigned int reg = rk808_buck_config_regs[rdev_get_id(rdev)]; switch (ramp_delay) { case 1 ... 2000: -- cgit v1.2.3 From c0b34ab141505087d7d66f447d77e6023f34501e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 3 Sep 2016 14:04:17 -0300 Subject: [media] cx24120: do not allow an invalid delivery system types cx24120_set_frontend currently allows invalid delivery system types other than SYS_DVBS2 and SYS_DVBS. Fix this by returning -EINVAL for invalid values. Signed-off-by: Colin Ian King Acked-by: Jemma Denson --- drivers/media/dvb-frontends/cx24120.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/cx24120.c b/drivers/media/dvb-frontends/cx24120.c index 066ee387bf25..3112a3206d46 100644 --- a/drivers/media/dvb-frontends/cx24120.c +++ b/drivers/media/dvb-frontends/cx24120.c @@ -1154,8 +1154,7 @@ static int cx24120_set_frontend(struct dvb_frontend *fe) dev_dbg(&state->i2c->dev, "delivery system(%d) not supported\n", c->delivery_system); - ret = -EINVAL; - break; + return -EINVAL; } state->dnxt.delsys = c->delivery_system; -- cgit v1.2.3 From 06c24f6779ea863a9410c872c577d8ae986a4b60 Mon Sep 17 00:00:00 2001 From: Baoyou Xie Date: Tue, 6 Sep 2016 04:50:56 -0300 Subject: [media] coda: add missing header dependencies We get 1 warning when building kernel with W=1: drivers/media/platform/coda/coda-h264.c:22:5: warning: no previous prototype for 'coda_h264_padding' [-Wmissing-prototypes] In fact, this function is declared in coda.h, so this patch add missing header dependencies. Signed-off-by: Baoyou Xie Acked-by: Arnd Bergmann Acked-by: Philipp Zabel --- drivers/media/platform/coda/coda-h264.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-h264.c b/drivers/media/platform/coda/coda-h264.c index 456773af1f1d..09dfcca7cc50 100644 --- a/drivers/media/platform/coda/coda-h264.c +++ b/drivers/media/platform/coda/coda-h264.c @@ -13,6 +13,7 @@ #include #include +#include static const u8 coda_filler_nal[14] = { 0x00, 0x00, 0x00, 0x01, 0x0c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80 }; -- cgit v1.2.3 From 69117994aa7d9dba8ea3bcdde7676b123d975877 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 6 Sep 2016 09:44:09 -0300 Subject: [media] variable name is never null, so remove null check The variable name is always assigned to a literal string in the proceeding switch statement, so it is never null and hence the null check is redundant. Remove null the check. Signed-off-by: Colin Ian King --- drivers/media/usb/pvrusb2/pvrusb2-sysfs.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c index 06fe63ced58c..d977976b8d91 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c @@ -116,7 +116,6 @@ static ssize_t show_type(struct device *class_dev, } pvr2_sysfs_trace("pvr2_sysfs(%p) show_type(cid=%d) is %s", cip->chptr, cip->ctl_id, name); - if (!name) return -EINVAL; return scnprintf(buf, PAGE_SIZE, "%s\n", name); } -- cgit v1.2.3 From 82b65714a6f5f5124d7cc5a2162272a8576df80f Mon Sep 17 00:00:00 2001 From: Olli Salonen Date: Fri, 9 Sep 2016 16:24:54 -0300 Subject: [media] dvb-usb-dvbsky: Add support for TechnoTrend S2-4650 CI TechnoTrend TT-connect S2-4650 CI seems to be a variation of the DVBSky S960CI device. Signed-off-by: Olli Salonen Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb-usb-ids.h | 1 + drivers/media/usb/dvb-usb-v2/dvbsky.c | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h index 5938ea4abc69..779f4224b63e 100644 --- a/drivers/media/dvb-core/dvb-usb-ids.h +++ b/drivers/media/dvb-core/dvb-usb-ids.h @@ -262,6 +262,7 @@ #define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI 0x3012 #define USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2 0x3015 #define USB_PID_TECHNOTREND_TVSTICK_CT2_4400 0x3014 +#define USB_PID_TECHNOTREND_CONNECT_S2_4650_CI 0x3017 #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a #define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081 #define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058 diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c index 02dbc6c45423..0636eac37bbb 100644 --- a/drivers/media/usb/dvb-usb-v2/dvbsky.c +++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c @@ -851,6 +851,10 @@ static const struct usb_device_id dvbsky_id_table[] = { USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI_2, &dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI v1.1", RC_MAP_TT_1500) }, + { DVB_USB_DEVICE(USB_VID_TECHNOTREND, + USB_PID_TECHNOTREND_CONNECT_S2_4650_CI, + &dvbsky_s960c_props, "TechnoTrend TT-connect S2-4650 CI", + RC_MAP_TT_1500) }, { DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_3, &dvbsky_t680c_props, "Terratec H7 Rev.4", -- cgit v1.2.3 From 19157003abe4d9ca4706fca8ff8306946f7942c6 Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sat, 10 Sep 2016 13:49:01 -0300 Subject: [media] mb86a20s: always initialize a return value In mb86a20s_read_status_and_stats(), when mb86a20s_read_status() fails, the function returns the value in variable rc without initializing it first. Fix this by propagating the error code from variable status_nr. This bug has been found using clang and -Wsometimes-uninitialized warning flag. Signed-off-by: Nicolas Iooss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mb86a20s.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index fe79358b035e..27f425137ce6 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -1967,6 +1967,7 @@ static int mb86a20s_read_status_and_stats(struct dvb_frontend *fe, if (status_nr < 0) { dev_err(&state->i2c->dev, "%s: Can't read frontend lock status\n", __func__); + rc = status_nr; goto error; } -- cgit v1.2.3 From 7ec03e60ef81c19b5d3a46dd070ee966774b860f Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sat, 10 Sep 2016 13:59:49 -0300 Subject: [media] ite-cir: initialize use_demodulator before using it Function ite_set_carrier_params() uses variable use_demodulator after having initialized it to false in some if branches, but this variable is never set to true otherwise. This bug has been found using clang -Wsometimes-uninitialized warning flag. Fixes: 620a32bba4a2 ("[media] rc: New rc-based ite-cir driver for several ITE CIRs") Signed-off-by: Nicolas Iooss Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ite-cir.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c index c5e8e3885766..367b28bed627 100644 --- a/drivers/media/rc/ite-cir.c +++ b/drivers/media/rc/ite-cir.c @@ -261,6 +261,8 @@ static void ite_set_carrier_params(struct ite_dev *dev) if (allowance > ITE_RXDCR_MAX) allowance = ITE_RXDCR_MAX; + + use_demodulator = true; } } -- cgit v1.2.3 From 1a33ac00c5ebc4b2e2efb5bc0252c6ba7dc8ff0f Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Wed, 14 Sep 2016 17:03:13 -0300 Subject: [media] media: i2c: tvp514x: Reported mbus format should be MEDIA_BUS_FMT_UYVY8_2X8 The advertised V4L2 pixel format and Media Bus code don't match. The current media bud code advertised is MEDIA_BUS_FMT_YUYV8_2X8 which does not reflect what the encoder actually outputs. This encoder generate MEDIA_BUS_FMT_UYVY8_2X8 so advertise as such. Signed-off-by: Benoit Parrot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp514x.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c index d5c9347f4c6d..0c62899c3667 100644 --- a/drivers/media/i2c/tvp514x.c +++ b/drivers/media/i2c/tvp514x.c @@ -894,7 +894,7 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd, if (index != 0) return -EINVAL; - code->code = MEDIA_BUS_FMT_YUYV8_2X8; + code->code = MEDIA_BUS_FMT_UYVY8_2X8; return 0; } @@ -922,7 +922,7 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd, return 0; } - format->format.code = MEDIA_BUS_FMT_YUYV8_2X8; + format->format.code = MEDIA_BUS_FMT_UYVY8_2X8; format->format.width = tvp514x_std_list[decoder->current_std].width; format->format.height = tvp514x_std_list[decoder->current_std].height; format->format.colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -946,7 +946,7 @@ static int tvp514x_set_pad_format(struct v4l2_subdev *sd, struct tvp514x_decoder *decoder = to_decoder(sd); if (fmt->format.field != V4L2_FIELD_INTERLACED || - fmt->format.code != MEDIA_BUS_FMT_YUYV8_2X8 || + fmt->format.code != MEDIA_BUS_FMT_UYVY8_2X8 || fmt->format.colorspace != V4L2_COLORSPACE_SMPTE170M || fmt->format.width != tvp514x_std_list[decoder->current_std].width || fmt->format.height != tvp514x_std_list[decoder->current_std].height) -- cgit v1.2.3 From c57a68a152dc7e2d0631acb9d3c00d1c33ddecfb Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 22 Sep 2016 10:19:00 -0300 Subject: [media] media: adv7604: automatic "default-input" selection Documentation states that the "default-input" property should reside directly in the node of the device. This adjusts the parsing to make the implementation consistent with the documentation. Based on patch by William Towle . Signed-off-by: Ulrich Hecht Signed-off-by: Hans Verkuil Acked-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 4003831de712..fa7046ef09b2 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -3074,13 +3074,13 @@ static int adv76xx_parse_dt(struct adv76xx_state *state) return ret; } - if (!of_property_read_u32(endpoint, "default-input", &v)) + of_node_put(endpoint); + + if (!of_property_read_u32(np, "default-input", &v)) state->pdata.default_input = v; else state->pdata.default_input = -1; - of_node_put(endpoint); - flags = bus_cfg.bus.parallel.flags; if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) -- cgit v1.2.3 From 1ff52fa0f19c407e0e091bf0c8e169ee017ef725 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Fri, 16 Sep 2016 07:16:30 -0300 Subject: [media] ad5820: Fix sparse warning Use a type with explicit endianness in machine to big endian conversion. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/ad5820.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c index beab2f381b81..a9026a91855e 100644 --- a/drivers/media/i2c/ad5820.c +++ b/drivers/media/i2c/ad5820.c @@ -65,16 +65,17 @@ static int ad5820_write(struct ad5820_device *coil, u16 data) { struct i2c_client *client = v4l2_get_subdevdata(&coil->subdev); struct i2c_msg msg; + __be16 be_data; int r; if (!client->adapter) return -ENODEV; - data = cpu_to_be16(data); + be_data = cpu_to_be16(data); msg.addr = client->addr; msg.flags = 0; msg.len = 2; - msg.buf = (u8 *)&data; + msg.buf = (u8 *)&be_data; r = i2c_transfer(client->adapter, &msg, 1); if (r < 0) { -- cgit v1.2.3 From 7c073fffb763dceb38737c32408750b3809773f9 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Fri, 16 Sep 2016 08:18:21 -0300 Subject: [media] imon: use complete() instead of complete_all() There is only one waiter for the completion, therefore there is no need to use complete_all(). Let's make that clear by using complete() instead of complete_all(). While we are at it, we do a small optimization with the reinitialization of the completion before we use it. The usage pattern of the completion is: waiter context waker context send_packet() init_completion() usb_submit_urb() wait_for_completion_interruptible() usb_tx_callback() complete() imon_disonnect() complete() Signed-off-by: Daniel Wagner Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/imon.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c index bd807fa4cb9f..0785a24af8fc 100644 --- a/drivers/media/rc/imon.c +++ b/drivers/media/rc/imon.c @@ -607,7 +607,7 @@ static int send_packet(struct imon_context *ictx) ictx->tx_urb->actual_length = 0; } - init_completion(&ictx->tx.finished); + reinit_completion(&ictx->tx.finished); ictx->tx.busy = true; smp_rmb(); /* ensure later readers know we're busy */ @@ -2216,6 +2216,8 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf, ictx->tx_urb = tx_urb; ictx->rf_device = false; + init_completion(&ictx->tx.finished); + ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor); ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct); @@ -2491,7 +2493,7 @@ static void imon_disconnect(struct usb_interface *interface) /* Abort ongoing write */ if (ictx->tx.busy) { usb_kill_urb(ictx->tx_urb); - complete_all(&ictx->tx.finished); + complete(&ictx->tx.finished); } if (ifnum == 0) { -- cgit v1.2.3 From 9b26336356603d457a53255adc7a4fdad31c5ede Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Fri, 16 Sep 2016 08:18:22 -0300 Subject: [media] lirc_imon: use complete() instead complete_all() There is only one waiter for the completion, therefore there is no need to use complete_all(). Let's make that clear by using complete() instead of complete_all(). While we are at it, we do a small optimization with the reinitialization of the completion before we use it. The usage pattern of the completion is: waiter context waker context send_packet() reinit_completion() usb_sumbit_urb() wait_for_completion_interruptible() usb_tx_callback() complete() imon_disconnect() complete() Signed-off-by: Daniel Wagner Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_imon.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c index 198a8057f2f1..00e00b0be275 100644 --- a/drivers/staging/media/lirc/lirc_imon.c +++ b/drivers/staging/media/lirc/lirc_imon.c @@ -334,7 +334,7 @@ static int send_packet(struct imon_context *context) context->tx_urb->actual_length = 0; - init_completion(&context->tx.finished); + reinit_completion(&context->tx.finished); atomic_set(&context->tx.busy, 1); retval = usb_submit_urb(context->tx_urb, GFP_KERNEL); @@ -497,6 +497,8 @@ static int ir_open(void *data) context->rx.initial_space = 1; context->rx.prev_bit = 0; + init_completion(&context->tx.finished); + context->ir_isopen = 1; dev_info(context->driver->dev, "IR port opened\n"); @@ -930,7 +932,7 @@ static void imon_disconnect(struct usb_interface *interface) /* Abort ongoing write */ if (atomic_read(&context->tx.busy)) { usb_kill_urb(context->tx_urb); - complete_all(&context->tx.finished); + complete(&context->tx.finished); } context->dev_present = 0; -- cgit v1.2.3 From ff681022c6639c194fbb6893c50ace9e52a44788 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 19 Sep 2016 09:46:30 -0300 Subject: [media] platform: pxa_camera: add VIDEO_V4L2 dependency Moving the pxa_camera driver from soc_camera lots the implied VIDEO_V4L2 Kconfig dependency, and building the driver without V4L2 results in a kernel that cannot link: drivers/media/platform/pxa_camera.o: In function `pxa_camera_remove': pxa_camera.c:(.text.pxa_camera_remove+0x10): undefined reference to `v4l2_clk_unregister' pxa_camera.c:(.text.pxa_camera_remove+0x18): undefined reference to `v4l2_device_unregister' drivers/media/platform/pxa_camera.o: In function `pxa_camera_probe': pxa_camera.c:(.text.pxa_camera_probe+0x458): undefined reference to `v4l2_of_parse_endpoint' drivers/media/v4l2-core/videobuf2-core.o: In function `__enqueue_in_driver': drivers/media/v4l2-core/videobuf2-core.o: In function `vb2_core_streamon': videobuf2-core.c:(.text.vb2_core_streamon+0x1b4): undefined reference to `v4l_vb2q_enable_media_source' drivers/media/v4l2-core/videobuf2-v4l2.o: In function `vb2_ioctl_reqbufs': videobuf2-v4l2.c:(.text.vb2_ioctl_reqbufs+0xc): undefined reference to `video_devdata' This adds back an explicit dependency. Fixes: 3050b9985024 ("[media] media: platform: pxa_camera: move pxa_camera out of soc_camera") Signed-off-by: Arnd Bergmann Acked-by: Robert Jarzmik Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 8d00a3fdcf96..754edbf1a326 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -93,7 +93,7 @@ config VIDEO_OMAP3_DEBUG config VIDEO_PXA27x tristate "PXA27x Quick Capture Interface driver" - depends on VIDEO_DEV && HAS_DMA + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA depends on PXA27x || COMPILE_TEST select VIDEOBUF2_DMA_SG select SG_SPLIT -- cgit v1.2.3 From b7491e7e902a488503982c9be098cac578a94bdc Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 21 Sep 2016 10:09:23 -0300 Subject: [media] gs1662: remove .owner field for driver Remove .owner field if calls are used which set it automatically. Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/spi/gs1662.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/spi/gs1662.c b/drivers/media/spi/gs1662.c index d76f36233f43..057530bf8528 100644 --- a/drivers/media/spi/gs1662.c +++ b/drivers/media/spi/gs1662.c @@ -463,7 +463,6 @@ static int gs_remove(struct spi_device *spi) static struct spi_driver gs_driver = { .driver = { .name = "gs1662", - .owner = THIS_MODULE, }, .probe = gs_probe, -- cgit v1.2.3 From df94121f02ecce435d6b5277071eb94b764caa89 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 21 Sep 2016 10:09:39 -0300 Subject: [media] gs1662: drop kfree for memory allocated with devm_kzalloc It's not necessary to free memory allocated with devm_kzalloc and using kfree leads to a double free. Fixes: 7aae6e2df127 ("[media] Add GS1662 driver, a video serializer") Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/spi/gs1662.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/spi/gs1662.c b/drivers/media/spi/gs1662.c index 057530bf8528..330dcb2b2e44 100644 --- a/drivers/media/spi/gs1662.c +++ b/drivers/media/spi/gs1662.c @@ -453,10 +453,9 @@ static int gs_probe(struct spi_device *spi) static int gs_remove(struct spi_device *spi) { struct v4l2_subdev *sd = spi_get_drvdata(spi); - struct gs *gs = to_gs(sd); v4l2_device_unregister_subdev(sd); - kfree(gs); + return 0; } -- cgit v1.2.3 From 017f4fb7f2eaa191072e7c0bd1153a879b3e207e Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 21 Sep 2016 12:09:38 -0300 Subject: [media] bdisp: fix error return code in bdisp_probe() Fix to return error code -EINVAL from the platform_get_resource() error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Reviewed-by: Fabien Dessenne Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/bdisp/bdisp-v4l2.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c index 45f82b5ddd77..823608112d89 100644 --- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c +++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c @@ -1337,6 +1337,7 @@ static int bdisp_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!res) { dev_err(dev, "failed to get IRQ resource\n"); + ret = -EINVAL; goto err_clk; } -- cgit v1.2.3 From e546b1ef22850d53a9e21c4d0bcf9a6057cd9293 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 21 Sep 2016 12:12:58 -0300 Subject: [media] cx88: fix error return code in cx8802_dvb_probe() Fix to return error code -ENODEV from the error handling case instead of 0(err maybe overwrited to 0 in the for loop), as done elsewhere in this function. [mchehab@s-opensource.com: remove a now uneeded set for err = -ENODEV] Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-dvb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index fe5fd2a4650b..157bc14874eb 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -1769,7 +1769,6 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) if (err) goto fail_core; - err = -ENODEV; for (i = 1; i <= core->board.num_frontends; i++) { struct vb2_queue *q; @@ -1777,6 +1776,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) if (fe == NULL) { printk(KERN_ERR "%s() failed to get frontend(%d)\n", __func__, i); + err = -ENODEV; goto fail_probe; } q = &fe->dvb.dvbq; -- cgit v1.2.3 From 6dfcd296576a14bc52d0453e4ba7ed09323a26dc Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Wed, 21 Sep 2016 21:04:20 -0300 Subject: [media] tw5864: crop picture width to 704 Previously, width of 720 was used, but it gives 16-pixel wide black bar at right side of encoded picture. Signed-off-by: Andrey Utkin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/tw5864/tw5864-reg.h | 8 ++++++++ drivers/media/pci/tw5864/tw5864-video.c | 13 +++++++++++-- 2 files changed, 19 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/tw5864/tw5864-reg.h b/drivers/media/pci/tw5864/tw5864-reg.h index 92a1b077ef8a..30ac14210e91 100644 --- a/drivers/media/pci/tw5864/tw5864-reg.h +++ b/drivers/media/pci/tw5864/tw5864-reg.h @@ -1879,6 +1879,14 @@ #define TW5864_INDIR_IN_PIC_HEIGHT(channel) (0x201 + 4 * channel) #define TW5864_INDIR_OUT_PIC_WIDTH(channel) (0x202 + 4 * channel) #define TW5864_INDIR_OUT_PIC_HEIGHT(channel) (0x203 + 4 * channel) + +/* Some registers skipped */ + +#define TW5864_INDIR_CROP_ETC 0x260 +/* Define controls in register TW5864_INDIR_CROP_ETC */ +/* Enable cropping from 720 to 704 */ +#define TW5864_INDIR_CROP_ETC_CROP_EN 0x4 + /* * Interrupt status register from the front-end. Write "1" to each bit to clear * the interrupt diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c index 652a059b2e0a..9421216bb942 100644 --- a/drivers/media/pci/tw5864/tw5864-video.c +++ b/drivers/media/pci/tw5864/tw5864-video.c @@ -330,6 +330,15 @@ static int tw5864_enable_input(struct tw5864_input *input) tw_indir_writeb(TW5864_INDIR_OUT_PIC_WIDTH(nr), input->width / 4); tw_indir_writeb(TW5864_INDIR_OUT_PIC_HEIGHT(nr), input->height / 4); + /* + * Crop width from 720 to 704. + * Above register settings need value 720 involved. + */ + input->width = 704; + tw_indir_writeb(TW5864_INDIR_CROP_ETC, + tw_indir_readb(TW5864_INDIR_CROP_ETC) | + TW5864_INDIR_CROP_ETC_CROP_EN); + tw_writel(TW5864_DSP_PIC_MAX_MB, ((input->width / 16) << 8) | (input->height / 16)); @@ -532,7 +541,7 @@ static int tw5864_fmt_vid_cap(struct file *file, void *priv, { struct tw5864_input *input = video_drvdata(file); - f->fmt.pix.width = 720; + f->fmt.pix.width = 704; switch (input->std) { default: WARN_ON_ONCE(1); @@ -738,7 +747,7 @@ static int tw5864_enum_framesizes(struct file *file, void *priv, return -EINVAL; fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; - fsize->discrete.width = 720; + fsize->discrete.width = 704; fsize->discrete.height = input->std == STD_NTSC ? 480 : 576; return 0; -- cgit v1.2.3 From c771f42fed7f21f510793302687884b424cd9f54 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 23 Sep 2016 15:41:39 -0300 Subject: [media] media: platform: pxa_camera: add missing sensor power on During sensors binding, there is a window where the sensor is switched off, while there is a call it to set a new format, which can end up in an access to the sensor, especially an I2C based sensor. Remove this window by activating the sensor. Signed-off-by: Robert Jarzmik Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/pxa_camera.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index bcdac4932fb1..929006f65cc7 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -2125,17 +2125,22 @@ static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, pix->bytesperline, pix->height); pix->pixelformat = pcdev->current_fmt->host_fmt->fourcc; v4l2_fill_mbus_format(mf, pix, pcdev->current_fmt->code); - err = sensor_call(pcdev, pad, set_fmt, NULL, &format); + + err = sensor_call(pcdev, core, s_power, 1); if (err) goto out; + err = sensor_call(pcdev, pad, set_fmt, NULL, &format); + if (err) + goto out_sensor_poweroff; + v4l2_fill_pix_format(pix, mf); pr_info("%s(): colorspace=0x%x pixfmt=0x%x\n", __func__, pix->colorspace, pix->pixelformat); err = pxa_camera_init_videobuf2(pcdev); if (err) - goto out; + goto out_sensor_poweroff; err = video_register_device(&pcdev->vdev, VFL_TYPE_GRABBER, -1); if (err) { @@ -2146,6 +2151,9 @@ static int pxa_camera_sensor_bound(struct v4l2_async_notifier *notifier, "PXA Camera driver attached to camera %s\n", subdev->name); } + +out_sensor_poweroff: + err = sensor_call(pcdev, core, s_power, 0); out: mutex_unlock(&pcdev->mlock); return err; -- cgit v1.2.3 From 8a5d2acee6fa9ec5997335cc3ebdd47c7524d6d2 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Fri, 23 Sep 2016 18:19:01 -0300 Subject: [media] VPU: mediatek: Fix return value in case of error If 'dma_alloc_coherent()' returns NULL, 'vpu_alloc_ext_mem()' will return 0 which means success. Return -ENOMEM instead. Signed-off-by: Christophe JAILLET Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vpu/mtk_vpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c index c3643d929167..463b69c934be 100644 --- a/drivers/media/platform/mtk-vpu/mtk_vpu.c +++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c @@ -689,7 +689,7 @@ static int vpu_alloc_ext_mem(struct mtk_vpu *vpu, u32 fw_type) GFP_KERNEL); if (!vpu->extmem[fw_type].va) { dev_err(dev, "Failed to allocate the extended program memory\n"); - return PTR_ERR(vpu->extmem[fw_type].va); + return -ENOMEM; } /* Disable extend0. Enable extend1 */ -- cgit v1.2.3 From 37e90a220abc4c5dee1fc42382cbca595a0e95bd Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 27 Sep 2016 16:48:47 -0300 Subject: [media] rc: ir-raw: change type of available_protocols to atomic64_t Changing available_protocols to atomic64_t allows to get rid of the mutex protecting access to the variable. This helps to simplify the code. Signed-off-by: Heiner Kallweit Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-ir-raw.c | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c index 205ecc602e34..1c42a9f2f290 100644 --- a/drivers/media/rc/rc-ir-raw.c +++ b/drivers/media/rc/rc-ir-raw.c @@ -26,8 +26,7 @@ static LIST_HEAD(ir_raw_client_list); /* Used to handle IR raw handler extensions */ static DEFINE_MUTEX(ir_raw_handler_lock); static LIST_HEAD(ir_raw_handler_list); -static DEFINE_MUTEX(available_protocols_lock); -static u64 available_protocols; +static atomic64_t available_protocols = ATOMIC64_INIT(0); static int ir_raw_event_thread(void *data) { @@ -234,11 +233,7 @@ EXPORT_SYMBOL_GPL(ir_raw_event_handle); u64 ir_raw_get_allowed_protocols(void) { - u64 protocols; - mutex_lock(&available_protocols_lock); - protocols = available_protocols; - mutex_unlock(&available_protocols_lock); - return protocols; + return atomic64_read(&available_protocols); } static int change_protocol(struct rc_dev *dev, u64 *rc_type) @@ -331,9 +326,7 @@ int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler) if (ir_raw_handler->raw_register) list_for_each_entry(raw, &ir_raw_client_list, list) ir_raw_handler->raw_register(raw->dev); - mutex_lock(&available_protocols_lock); - available_protocols |= ir_raw_handler->protocols; - mutex_unlock(&available_protocols_lock); + atomic64_or(ir_raw_handler->protocols, &available_protocols); mutex_unlock(&ir_raw_handler_lock); return 0; @@ -352,9 +345,7 @@ void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler) if (ir_raw_handler->raw_unregister) ir_raw_handler->raw_unregister(raw->dev); } - mutex_lock(&available_protocols_lock); - available_protocols &= ~protocols; - mutex_unlock(&available_protocols_lock); + atomic64_andnot(protocols, &available_protocols); mutex_unlock(&ir_raw_handler_lock); } EXPORT_SYMBOL(ir_raw_handler_unregister); -- cgit v1.2.3 From fa8bbe0a8567bf4eb87e82739465360a6797c91b Mon Sep 17 00:00:00 2001 From: Songjun Wu Date: Wed, 28 Sep 2016 02:28:57 -0300 Subject: [media] atmel-isc: start dma in some scenario If a new vb buf is added to vb queue, the queue is empty and steaming, dma should be started. Signed-off-by: Songjun Wu Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index ccfe13b7d3f8..8e25d3f56438 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -617,7 +617,13 @@ static void isc_buffer_queue(struct vb2_buffer *vb) unsigned long flags; spin_lock_irqsave(&isc->dma_queue_lock, flags); - list_add_tail(&buf->list, &isc->dma_queue); + if (!isc->cur_frm && list_empty(&isc->dma_queue) && + vb2_is_streaming(vb->vb2_queue)) { + isc->cur_frm = buf; + isc_start_dma(isc->regmap, isc->cur_frm, + isc->current_fmt->reg_dctrl_dview); + } else + list_add_tail(&buf->list, &isc->dma_queue); spin_unlock_irqrestore(&isc->dma_queue_lock, flags); } -- cgit v1.2.3 From 8f3408d5a14f3a50253d9e8fd4c443af4af8fa3f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 28 Sep 2016 12:13:13 -0300 Subject: [media] stih-cec: remove unused including Remove including that don't need it. Signed-off-by: Wei Yongjun Acked-by: Benjamin Gaignard Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/st-cec/stih-cec.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/media/st-cec/stih-cec.c b/drivers/staging/media/st-cec/stih-cec.c index 214344866a6b..b0aee1d4d5d0 100644 --- a/drivers/staging/media/st-cec/stih-cec.c +++ b/drivers/staging/media/st-cec/stih-cec.c @@ -16,7 +16,6 @@ #include #include #include -#include #include -- cgit v1.2.3 From ddbf7d5a698c4d8553ad2f77cb281d7b37898d34 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 30 Sep 2016 17:42:07 -0300 Subject: [media] rc: core: add managed versions of rc_allocate_device and rc_register_device Introduce managed versions of both functions. They allows to simplify the error path in the probe function of rc drivers, and usually also to simplify the remove function. New element managed_alloc in struct rc_dev is needed to correctly handle mixed use, e.g. managed version of rc_register_device and normal version of rc_allocate_device. In addition devm_rc_allocate_device sets rc->dev.parent as having a reference to the parent device might be useful for future extensions. Signed-off-by: Heiner Kallweit Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 58 +++++++++++++++++++++++++++++++++++++++++++++- include/media/rc-core.h | 18 ++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index b241e5f569ef..5087e76dfb03 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -1402,6 +1402,34 @@ void rc_free_device(struct rc_dev *dev) } EXPORT_SYMBOL_GPL(rc_free_device); +static void devm_rc_alloc_release(struct device *dev, void *res) +{ + rc_free_device(*(struct rc_dev **)res); +} + +struct rc_dev *devm_rc_allocate_device(struct device *dev) +{ + struct rc_dev **dr, *rc; + + dr = devres_alloc(devm_rc_alloc_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return NULL; + + rc = rc_allocate_device(); + if (!rc) { + devres_free(dr); + return NULL; + } + + rc->dev.parent = dev; + rc->managed_alloc = true; + *dr = rc; + devres_add(dev, dr); + + return rc; +} +EXPORT_SYMBOL_GPL(devm_rc_allocate_device); + int rc_register_device(struct rc_dev *dev) { static bool raw_init = false; /* raw decoders loaded? */ @@ -1530,6 +1558,33 @@ out_unlock: } EXPORT_SYMBOL_GPL(rc_register_device); +static void devm_rc_release(struct device *dev, void *res) +{ + rc_unregister_device(*(struct rc_dev **)res); +} + +int devm_rc_register_device(struct device *parent, struct rc_dev *dev) +{ + struct rc_dev **dr; + int ret; + + dr = devres_alloc(devm_rc_release, sizeof(*dr), GFP_KERNEL); + if (!dr) + return -ENOMEM; + + ret = rc_register_device(dev); + if (ret) { + devres_free(dr); + return ret; + } + + *dr = dev; + devres_add(parent, dr); + + return 0; +} +EXPORT_SYMBOL_GPL(devm_rc_register_device); + void rc_unregister_device(struct rc_dev *dev) { if (!dev) @@ -1551,7 +1606,8 @@ void rc_unregister_device(struct rc_dev *dev) ida_simple_remove(&rc_ida, dev->minor); - rc_free_device(dev); + if (!dev->managed_alloc) + rc_free_device(dev); } EXPORT_SYMBOL_GPL(rc_unregister_device); diff --git a/include/media/rc-core.h b/include/media/rc-core.h index 40188d362486..55281b92105a 100644 --- a/include/media/rc-core.h +++ b/include/media/rc-core.h @@ -68,6 +68,7 @@ enum rc_filter_type { * struct rc_dev - represents a remote control device * @dev: driver model's view of this device * @initialized: 1 if the device init has completed, 0 otherwise + * @managed_alloc: devm_rc_allocate_device was used to create rc_dev * @sysfs_groups: sysfs attribute groups * @input_name: name of the input child device * @input_phys: physical path to the input child device @@ -131,6 +132,7 @@ enum rc_filter_type { struct rc_dev { struct device dev; atomic_t initialized; + bool managed_alloc; const struct attribute_group *sysfs_groups[5]; const char *input_name; const char *input_phys; @@ -202,6 +204,14 @@ struct rc_dev { */ struct rc_dev *rc_allocate_device(void); +/** + * devm_rc_allocate_device - Managed RC device allocation + * + * @dev: pointer to struct device + * returns a pointer to struct rc_dev. + */ +struct rc_dev *devm_rc_allocate_device(struct device *dev); + /** * rc_free_device - Frees a RC device * @@ -216,6 +226,14 @@ void rc_free_device(struct rc_dev *dev); */ int rc_register_device(struct rc_dev *dev); +/** + * devm_rc_register_device - Manageded registering of a RC device + * + * @parent: pointer to struct device. + * @dev: pointer to struct rc_dev. + */ +int devm_rc_register_device(struct device *parent, struct rc_dev *dev); + /** * rc_unregister_device - Unregisters a RC device * -- cgit v1.2.3 From b6f3ece3873323a3d4dd56d71231d5f758265463 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Fri, 30 Sep 2016 17:42:17 -0300 Subject: [media] rc: nuvoton: use managed versions of rc_allocate_device and rc_register_device Simplify the remove function and the error path in the probe function by using the managed versions of rc_allocate_device and rc_register_device. Signed-off-by: Heiner Kallweit Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 50 +++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 04fedaa75612..3df3bd9aab7e 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -1002,40 +1002,40 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) { struct nvt_dev *nvt; struct rc_dev *rdev; - int ret = -ENOMEM; + int ret; nvt = devm_kzalloc(&pdev->dev, sizeof(struct nvt_dev), GFP_KERNEL); if (!nvt) - return ret; + return -ENOMEM; /* input device for IR remote (and tx) */ - rdev = rc_allocate_device(); + rdev = devm_rc_allocate_device(&pdev->dev); if (!rdev) - goto exit_free_dev_rdev; + return -ENOMEM; - ret = -ENODEV; /* activate pnp device */ - if (pnp_activate_dev(pdev) < 0) { + ret = pnp_activate_dev(pdev); + if (ret) { dev_err(&pdev->dev, "Could not activate PNP device!\n"); - goto exit_free_dev_rdev; + return ret; } /* validate pnp resources */ if (!pnp_port_valid(pdev, 0) || pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) { dev_err(&pdev->dev, "IR PNP Port not valid!\n"); - goto exit_free_dev_rdev; + return -EINVAL; } if (!pnp_irq_valid(pdev, 0)) { dev_err(&pdev->dev, "PNP IRQ not valid!\n"); - goto exit_free_dev_rdev; + return -EINVAL; } if (!pnp_port_valid(pdev, 1) || pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) { dev_err(&pdev->dev, "Wake PNP Port not valid!\n"); - goto exit_free_dev_rdev; + return -EINVAL; } nvt->cir_addr = pnp_port_start(pdev, 0); @@ -1056,7 +1056,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) ret = nvt_hw_detect(nvt); if (ret) - goto exit_free_dev_rdev; + return ret; /* Initialize CIR & CIR Wake Logical Devices */ nvt_efm_enable(nvt); @@ -1099,27 +1099,27 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) #endif nvt->rdev = rdev; - ret = rc_register_device(rdev); + ret = devm_rc_register_device(&pdev->dev, rdev); if (ret) - goto exit_free_dev_rdev; + return ret; - ret = -EBUSY; /* now claim resources */ if (!devm_request_region(&pdev->dev, nvt->cir_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME)) - goto exit_unregister_device; + return -EBUSY; - if (devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr, - IRQF_SHARED, NVT_DRIVER_NAME, (void *)nvt)) - goto exit_unregister_device; + ret = devm_request_irq(&pdev->dev, nvt->cir_irq, nvt_cir_isr, + IRQF_SHARED, NVT_DRIVER_NAME, nvt); + if (ret) + return ret; if (!devm_request_region(&pdev->dev, nvt->cir_wake_addr, CIR_IOREG_LENGTH, NVT_DRIVER_NAME "-wake")) - goto exit_unregister_device; + return -EBUSY; ret = device_create_file(&rdev->dev, &dev_attr_wakeup_data); if (ret) - goto exit_unregister_device; + return ret; device_init_wakeup(&pdev->dev, true); @@ -1130,14 +1130,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) } return 0; - -exit_unregister_device: - rc_unregister_device(rdev); - rdev = NULL; -exit_free_dev_rdev: - rc_free_device(rdev); - - return ret; } static void nvt_remove(struct pnp_dev *pdev) @@ -1150,8 +1142,6 @@ static void nvt_remove(struct pnp_dev *pdev) /* enable CIR Wake (for IR power-on) */ nvt_enable_wake(nvt); - - rc_unregister_device(nvt->rdev); } static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) -- cgit v1.2.3 From e128c9acdd4bffb3e962d8b8c78614971b12abe1 Mon Sep 17 00:00:00 2001 From: Wayne Porter Date: Sat, 1 Oct 2016 21:06:27 -0300 Subject: [media] bcm2048: Remove FSF mailing address FSF address changes, checkpatch recommends removing it Signed-off-by: Wayne Porter Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.h | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.h b/drivers/staging/media/bcm2048/radio-bcm2048.h index 4c90a32db795..4d950c1e2e8b 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.h +++ b/drivers/staging/media/bcm2048/radio-bcm2048.h @@ -14,11 +14,6 @@ * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ #ifndef BCM2048_H -- cgit v1.2.3 From 69fd825c17a9f0e2ad939ee701c64242d181cdb9 Mon Sep 17 00:00:00 2001 From: Enrico Mioso Date: Tue, 4 Oct 2016 08:13:27 -0300 Subject: [media] Add Cinergy S2 rev.4 support This patch derives from previous one(s) by CrazyCat. I used the commit adding rev.3 to mainline Linux kernel as an example, so credits go to its author(s). The hardware seems to scan and tune OK. Signed-off-by: Enrico Mioso Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dw2102.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb/dw2102.c b/drivers/media/usb/dvb-usb/dw2102.c index 38794ab8874e..6ca502d834b4 100644 --- a/drivers/media/usb/dvb-usb/dw2102.c +++ b/drivers/media/usb/dvb-usb/dw2102.c @@ -1641,6 +1641,7 @@ enum dw2102_table_entry { TEVII_S632, TERRATEC_CINERGY_S2_R2, TERRATEC_CINERGY_S2_R3, + TERRATEC_CINERGY_S2_R4, GOTVIEW_SAT_HD, GENIATECH_T220, TECHNOTREND_S2_4600, @@ -1670,6 +1671,7 @@ static struct usb_device_id dw2102_table[] = { [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)}, [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R2)}, [TERRATEC_CINERGY_S2_R3] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R3)}, + [TERRATEC_CINERGY_S2_R4] = {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_S2_R4)}, [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)}, [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)}, [TECHNOTREND_S2_4600] = {USB_DEVICE(USB_VID_TECHNOTREND, -- cgit v1.2.3 From c762ff1f7e3b09293c22ce62135ef550c1b3327c Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Tue, 4 Oct 2016 12:41:37 -0300 Subject: [media] coda: fix the error path in coda_probe() In the case of coda_firmware_request() failure, we should release the prevously acquired resources. Signed-off-by: Fabio Estevam Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/coda/coda-common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c index c39718a63e5e..9e6bdafa16f5 100644 --- a/drivers/media/platform/coda/coda-common.c +++ b/drivers/media/platform/coda/coda-common.c @@ -2295,8 +2295,13 @@ static int coda_probe(struct platform_device *pdev) pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); - return coda_firmware_request(dev); + ret = coda_firmware_request(dev); + if (ret) + goto err_alloc_workqueue; + return 0; +err_alloc_workqueue: + destroy_workqueue(dev->workqueue); err_v4l2_register: v4l2_device_unregister(&dev->v4l2_dev); return ret; -- cgit v1.2.3 From 079933dbcb02132cc48ba052882fe0a9e3b0b762 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Wed, 5 Oct 2016 04:13:10 -0300 Subject: [media] v4l: flash led class: Fix of_node release in probe() error path The sub-device's OF node was used (of_node_get()) if it was set, but device's OF node was always put. Fix this. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-flash-led-class.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index ae7544d5469a..6b31c0aad84a 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -638,7 +638,7 @@ struct v4l2_flash *v4l2_flash_init( v4l2_flash->iled_cdev = iled_cdev; v4l2_flash->ops = ops; sd->dev = dev; - sd->of_node = of_node; + sd->of_node = of_node ? of_node : led_cdev->dev->of_node; v4l2_subdev_init(sd, &v4l2_flash_subdev_ops); sd->internal_ops = &v4l2_flash_subdev_internal_ops; sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -654,10 +654,7 @@ struct v4l2_flash *v4l2_flash_init( if (ret < 0) goto err_init_controls; - if (sd->of_node) - of_node_get(sd->of_node); - else - of_node_get(led_cdev->dev->of_node); + of_node_get(sd->of_node); ret = v4l2_async_register_subdev(sd); if (ret < 0) @@ -666,7 +663,7 @@ struct v4l2_flash *v4l2_flash_init( return v4l2_flash; err_async_register_sd: - of_node_put(led_cdev->dev->of_node); + of_node_put(sd->of_node); v4l2_ctrl_handler_free(sd->ctrl_handler); err_init_controls: media_entity_cleanup(&sd->entity); @@ -688,10 +685,7 @@ void v4l2_flash_release(struct v4l2_flash *v4l2_flash) v4l2_async_unregister_subdev(sd); - if (sd->of_node) - of_node_put(sd->of_node); - else - of_node_put(led_cdev->dev->of_node); + of_node_put(sd->of_node); v4l2_ctrl_handler_free(sd->ctrl_handler); media_entity_cleanup(&sd->entity); -- cgit v1.2.3 From bd676c0c04ec94bd830b9192e2c33f2c4532278d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 24 Oct 2016 18:42:30 -0200 Subject: [media] v4l2-flash-led-class: remove a now unused var commit 079933dbcb02 ("[media] v4l: flash led class: Fix of_node release in probe() error path") removed the need of an ancillary var at the release function, as reported by smatch: drivers/media/v4l2-core/v4l2-flash-led-class.c: In function 'v4l2_flash_release': drivers/media/v4l2-core/v4l2-flash-led-class.c:678:23: warning: variable 'led_cdev' set but not used [-Wunused-but-set-variable] struct led_classdev *led_cdev; ^~~~~~~~ Get rid of it. Fixes: commit 079933dbcb02 ("[media] v4l: flash led class: Fix of_node release in probe() error path") Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-flash-led-class.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-flash-led-class.c b/drivers/media/v4l2-core/v4l2-flash-led-class.c index 6b31c0aad84a..794e563f24f8 100644 --- a/drivers/media/v4l2-core/v4l2-flash-led-class.c +++ b/drivers/media/v4l2-core/v4l2-flash-led-class.c @@ -675,13 +675,11 @@ EXPORT_SYMBOL_GPL(v4l2_flash_init); void v4l2_flash_release(struct v4l2_flash *v4l2_flash) { struct v4l2_subdev *sd; - struct led_classdev *led_cdev; if (IS_ERR_OR_NULL(v4l2_flash)) return; sd = &v4l2_flash->sd; - led_cdev = &v4l2_flash->fled_cdev->led_cdev; v4l2_async_unregister_subdev(sd); -- cgit v1.2.3 From 4e518816a938187b3bfe1b62fa291d4e38dca06e Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Mon, 17 Oct 2016 13:28:00 +0200 Subject: crypto: caam - add support for iMX6UL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i.MX6UL does only require three clocks to enable CAAM module. Signed-off-by: Marcus Folkesson Acked-by: Rob Herring Reviewed-by: Horia Geantă Signed-off-by: Herbert Xu --- .../devicetree/bindings/crypto/fsl-sec4.txt | 20 +++++++++++++ drivers/crypto/caam/ctrl.c | 35 ++++++++++++---------- 2 files changed, 40 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt index adeca34c5a33..10a425f451fc 100644 --- a/Documentation/devicetree/bindings/crypto/fsl-sec4.txt +++ b/Documentation/devicetree/bindings/crypto/fsl-sec4.txt @@ -123,6 +123,9 @@ PROPERTIES EXAMPLE + +iMX6QDL/SX requires four clocks + crypto@300000 { compatible = "fsl,sec-v4.0"; fsl,sec-era = <2>; @@ -139,6 +142,23 @@ EXAMPLE clock-names = "mem", "aclk", "ipg", "emi_slow"; }; + +iMX6UL does only require three clocks + + crypto: caam@2140000 { + compatible = "fsl,sec-v4.0"; + #address-cells = <1>; + #size-cells = <1>; + reg = <0x2140000 0x3c000>; + ranges = <0 0x2140000 0x3c000>; + interrupts = ; + + clocks = <&clks IMX6UL_CLK_CAAM_MEM>, + <&clks IMX6UL_CLK_CAAM_ACLK>, + <&clks IMX6UL_CLK_CAAM_IPG>; + clock-names = "mem", "aclk", "ipg"; + }; + ===================================================================== Job Ring (JR) Node diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index 72ff19658985..a79937d68c26 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -330,8 +330,8 @@ static int caam_remove(struct platform_device *pdev) clk_disable_unprepare(ctrlpriv->caam_ipg); clk_disable_unprepare(ctrlpriv->caam_mem); clk_disable_unprepare(ctrlpriv->caam_aclk); - clk_disable_unprepare(ctrlpriv->caam_emi_slow); - + if (!of_machine_is_compatible("fsl,imx6ul")) + clk_disable_unprepare(ctrlpriv->caam_emi_slow); return 0; } @@ -482,14 +482,16 @@ static int caam_probe(struct platform_device *pdev) } ctrlpriv->caam_aclk = clk; - clk = caam_drv_identify_clk(&pdev->dev, "emi_slow"); - if (IS_ERR(clk)) { - ret = PTR_ERR(clk); - dev_err(&pdev->dev, - "can't identify CAAM emi_slow clk: %d\n", ret); - return ret; + if (!of_machine_is_compatible("fsl,imx6ul")) { + clk = caam_drv_identify_clk(&pdev->dev, "emi_slow"); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + dev_err(&pdev->dev, + "can't identify CAAM emi_slow clk: %d\n", ret); + return ret; + } + ctrlpriv->caam_emi_slow = clk; } - ctrlpriv->caam_emi_slow = clk; ret = clk_prepare_enable(ctrlpriv->caam_ipg); if (ret < 0) { @@ -510,11 +512,13 @@ static int caam_probe(struct platform_device *pdev) goto disable_caam_mem; } - ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); - if (ret < 0) { - dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n", - ret); - goto disable_caam_aclk; + if (!of_machine_is_compatible("fsl,imx6ul")) { + ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); + if (ret < 0) { + dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n", + ret); + goto disable_caam_aclk; + } } /* Get configuration properties from device tree */ @@ -832,7 +836,8 @@ caam_remove: iounmap_ctrl: iounmap(ctrl); disable_caam_emi_slow: - clk_disable_unprepare(ctrlpriv->caam_emi_slow); + if (!of_machine_is_compatible("fsl,imx6ul")) + clk_disable_unprepare(ctrlpriv->caam_emi_slow); disable_caam_aclk: clk_disable_unprepare(ctrlpriv->caam_aclk); disable_caam_mem: -- cgit v1.2.3 From ff4f44de44dbd98feecf8fa76e14353a3993b335 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:08:50 +0000 Subject: crypto: ccp - Fix non static symbol warning Fixes the following sparse warning: drivers/crypto/ccp/ccp-dev.c:44:6: warning: symbol 'ccp_error_codes' was not declared. Should it be static? Signed-off-by: Wei Yongjun Acked-by: Gary R Hook Acked-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index cafa633aae10..c25515a80d33 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -41,7 +41,7 @@ struct ccp_tasklet_data { }; /* Human-readable error strings */ -char *ccp_error_codes[] = { +static char *ccp_error_codes[] = { "", "ERR 01: ILLEGAL_ENGINE", "ERR 02: ILLEGAL_KEY_ID", -- cgit v1.2.3 From 877f69a81eeee94a195cfbcfcf1dbb1b25f12fc8 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 16:51:17 -0300 Subject: hwrng: meson - Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/char/hw_random/meson-rng.ko | grep alias alias: platform:meson-rng After this patch: $ modinfo drivers/char/hw_random/meson-rng.ko | grep alias alias: platform:meson-rng alias: of:N*T*Camlogic,meson-rngC* alias: of:N*T*Camlogic,meson-rng Signed-off-by: Javier Martinez Canillas Acked-by: Neil Armstrong Signed-off-by: Herbert Xu --- drivers/char/hw_random/meson-rng.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/char/hw_random/meson-rng.c b/drivers/char/hw_random/meson-rng.c index 58bef39f7286..51864a509be7 100644 --- a/drivers/char/hw_random/meson-rng.c +++ b/drivers/char/hw_random/meson-rng.c @@ -110,6 +110,7 @@ static const struct of_device_id meson_rng_of_match[] = { { .compatible = "amlogic,meson-rng", }, {}, }; +MODULE_DEVICE_TABLE(of, meson_rng_of_match); static struct platform_driver meson_rng_driver = { .probe = meson_rng_probe, -- cgit v1.2.3 From fdd2cf9db1e25a46a74c5802d18435171c92e7df Mon Sep 17 00:00:00 2001 From: Gary R Hook Date: Tue, 18 Oct 2016 17:28:35 -0500 Subject: crypto: ccp - change bitfield type to unsigned ints Bit fields are not sensitive to endianness, so use a transparent standard data type Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 5afaa53672b3..58e8d382e9ad 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -541,23 +541,23 @@ static inline u32 ccp_addr_hi(struct ccp_dma_info *info) * word 7: upper 16 bits of key pointer; key memory type */ struct dword0 { - __le32 soc:1; - __le32 ioc:1; - __le32 rsvd1:1; - __le32 init:1; - __le32 eom:1; /* AES/SHA only */ - __le32 function:15; - __le32 engine:4; - __le32 prot:1; - __le32 rsvd2:7; + unsigned int soc:1; + unsigned int ioc:1; + unsigned int rsvd1:1; + unsigned int init:1; + unsigned int eom:1; /* AES/SHA only */ + unsigned int function:15; + unsigned int engine:4; + unsigned int prot:1; + unsigned int rsvd2:7; }; struct dword3 { - __le32 src_hi:16; - __le32 src_mem:2; - __le32 lsb_cxt_id:8; - __le32 rsvd1:5; - __le32 fixed:1; + unsigned int src_hi:16; + unsigned int src_mem:2; + unsigned int lsb_cxt_id:8; + unsigned int rsvd1:5; + unsigned int fixed:1; }; union dword4 { @@ -567,18 +567,18 @@ union dword4 { union dword5 { struct { - __le32 dst_hi:16; - __le32 dst_mem:2; - __le32 rsvd1:13; - __le32 fixed:1; + unsigned int dst_hi:16; + unsigned int dst_mem:2; + unsigned int rsvd1:13; + unsigned int fixed:1; } fields; __le32 sha_len_hi; }; struct dword7 { - __le32 key_hi:16; - __le32 key_mem:2; - __le32 rsvd1:14; + unsigned int key_hi:16; + unsigned int key_mem:2; + unsigned int rsvd1:14; }; struct ccp5_desc { -- cgit v1.2.3 From ec9b70df75b3600ca20338198a43173f23e6bb9b Mon Sep 17 00:00:00 2001 From: Gary R Hook Date: Tue, 18 Oct 2016 17:28:49 -0500 Subject: crypto: ccp - remove unneeded code Clean up patch for an unneeded structure member. Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev.h b/drivers/crypto/ccp/ccp-dev.h index 58e8d382e9ad..830f35e6005f 100644 --- a/drivers/crypto/ccp/ccp-dev.h +++ b/drivers/crypto/ccp/ccp-dev.h @@ -515,7 +515,6 @@ struct ccp_op { struct ccp_passthru_op passthru; struct ccp_ecc_op ecc; } u; - struct ccp_mem key; }; static inline u32 ccp_addr_lo(struct ccp_dma_info *info) -- cgit v1.2.3 From 103600ab966a2f02d8986bbfdf87b762b1c6a06d Mon Sep 17 00:00:00 2001 From: Gary R Hook Date: Tue, 18 Oct 2016 17:33:37 -0500 Subject: crypto: ccp - Clean up the LSB slot allocation code Fix a few problems revealed by testing: verify consistent units, especially in public slot allocation. Percolate some common initialization code up to a common routine. Add some comments. Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev-v3.c | 4 ---- drivers/crypto/ccp/ccp-dev-v5.c | 20 ++++++++++++-------- drivers/crypto/ccp/ccp-dev.c | 4 ++++ 3 files changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev-v3.c b/drivers/crypto/ccp/ccp-dev-v3.c index 8d2dbacc6161..7bc09989e18a 100644 --- a/drivers/crypto/ccp/ccp-dev-v3.c +++ b/drivers/crypto/ccp/ccp-dev-v3.c @@ -404,10 +404,6 @@ static int ccp_init(struct ccp_device *ccp) goto e_pool; } - /* Initialize the queues used to wait for KSB space and suspend */ - init_waitqueue_head(&ccp->sb_queue); - init_waitqueue_head(&ccp->suspend_queue); - dev_dbg(dev, "Starting threads...\n"); /* Create a kthread for each queue */ for (i = 0; i < ccp->cmd_q_count; i++) { diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c index faf3cb3ddce2..ff7816a2b8af 100644 --- a/drivers/crypto/ccp/ccp-dev-v5.c +++ b/drivers/crypto/ccp/ccp-dev-v5.c @@ -21,6 +21,12 @@ #include "ccp-dev.h" +/* Allocate the requested number of contiguous LSB slots + * from the LSB bitmap. Look in the private range for this + * queue first; failing that, check the public area. + * If no space is available, wait around. + * Return: first slot number + */ static u32 ccp_lsb_alloc(struct ccp_cmd_queue *cmd_q, unsigned int count) { struct ccp_device *ccp; @@ -50,7 +56,7 @@ static u32 ccp_lsb_alloc(struct ccp_cmd_queue *cmd_q, unsigned int count) bitmap_set(ccp->lsbmap, start, count); mutex_unlock(&ccp->sb_mutex); - return start * LSB_ITEM_SIZE; + return start; } ccp->sb_avail = 0; @@ -63,17 +69,18 @@ static u32 ccp_lsb_alloc(struct ccp_cmd_queue *cmd_q, unsigned int count) } } +/* Free a number of LSB slots from the bitmap, starting at + * the indicated starting slot number. + */ static void ccp_lsb_free(struct ccp_cmd_queue *cmd_q, unsigned int start, unsigned int count) { - int lsbno = start / LSB_SIZE; - if (!start) return; - if (cmd_q->lsb == lsbno) { + if (cmd_q->lsb == start) { /* An entry from the private LSB */ - bitmap_clear(cmd_q->lsbmap, start % LSB_SIZE, count); + bitmap_clear(cmd_q->lsbmap, start, count); } else { /* From the shared LSBs */ struct ccp_device *ccp = cmd_q->ccp; @@ -751,9 +758,6 @@ static int ccp5_init(struct ccp_device *ccp) goto e_pool; } - /* Initialize the queue used to suspend */ - init_waitqueue_head(&ccp->suspend_queue); - dev_dbg(dev, "Loading LSB map...\n"); /* Copy the private LSB mask to the public registers */ status_lo = ioread32(ccp->io_regs + LSB_PRIVATE_MASK_LO_OFFSET); diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c index c25515a80d33..511ab042b5e7 100644 --- a/drivers/crypto/ccp/ccp-dev.c +++ b/drivers/crypto/ccp/ccp-dev.c @@ -478,6 +478,10 @@ struct ccp_device *ccp_alloc_struct(struct device *dev) ccp->sb_count = KSB_COUNT; ccp->sb_start = 0; + /* Initialize the wait queues */ + init_waitqueue_head(&ccp->sb_queue); + init_waitqueue_head(&ccp->suspend_queue); + ccp->ord = ccp_increment_unit_ordinal(); snprintf(ccp->name, MAX_CCP_NAME_LEN, "ccp-%u", ccp->ord); snprintf(ccp->rngname, MAX_CCP_NAME_LEN, "ccp-%u-rng", ccp->ord); -- cgit v1.2.3 From 4e88768a959ad61b77f2f99315e0f352dca4fc31 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 19 Oct 2016 16:50:18 -0300 Subject: hwrng: meson - Remove unneeded platform MODULE_ALIAS The Amlogic Meson is a DT-only platform, which means the devices are registered via OF and not using the legacy platform devices support. So there's no need to have a MODULE_ALIAS("platform:meson-rng") since the reported uevent MODALIAS to user-space will always be the OF one. Signed-off-by: Javier Martinez Canillas Acked-by: Kevin Hilman Acked-by: Neil Armstrong Signed-off-by: Herbert Xu --- drivers/char/hw_random/meson-rng.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/meson-rng.c b/drivers/char/hw_random/meson-rng.c index 51864a509be7..119d698439ae 100644 --- a/drivers/char/hw_random/meson-rng.c +++ b/drivers/char/hw_random/meson-rng.c @@ -122,7 +122,6 @@ static struct platform_driver meson_rng_driver = { module_platform_driver(meson_rng_driver); -MODULE_ALIAS("platform:meson-rng"); MODULE_DESCRIPTION("Meson H/W Random Number Generator driver"); MODULE_AUTHOR("Lawrence Mok "); MODULE_AUTHOR("Neil Armstrong "); -- cgit v1.2.3 From 0aced355757ddc150f78a6bf4f8d885bd4eaf0e2 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Mon, 19 Sep 2016 13:09:02 +0530 Subject: mfd: tps65218: Remove redundant read wrapper Currently read directly calls the repmap read function. Hence remove the redundant wrapper and use regmap read wherever needed. Signed-off-by: Keerthy Signed-off-by: Lee Jones --- drivers/gpio/gpio-tps65218.c | 3 ++- drivers/mfd/tps65218.c | 18 ++---------------- drivers/regulator/tps65218-regulator.c | 5 +++-- include/linux/mfd/tps65218.h | 2 -- 4 files changed, 7 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpio/gpio-tps65218.c b/drivers/gpio/gpio-tps65218.c index d779307a9685..46e6dcc089cb 100644 --- a/drivers/gpio/gpio-tps65218.c +++ b/drivers/gpio/gpio-tps65218.c @@ -16,6 +16,7 @@ #include #include #include +#include #include struct tps65218_gpio { @@ -30,7 +31,7 @@ static int tps65218_gpio_get(struct gpio_chip *gc, unsigned offset) unsigned int val; int ret; - ret = tps65218_reg_read(tps65218, TPS65218_REG_ENABLE2, &val); + ret = regmap_read(tps65218->regmap, TPS65218_REG_ENABLE2, &val); if (ret) return ret; diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index ba610adbdbff..9bca1b1b60ce 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -33,20 +33,6 @@ #define TPS65218_PASSWORD_REGS_UNLOCK 0x7D -/** - * tps65218_reg_read: Read a single tps65218 register. - * - * @tps: Device to read from. - * @reg: Register to read. - * @val: Contians the value - */ -int tps65218_reg_read(struct tps65218 *tps, unsigned int reg, - unsigned int *val) -{ - return regmap_read(tps->regmap, reg, val); -} -EXPORT_SYMBOL_GPL(tps65218_reg_read); - /** * tps65218_reg_write: Write a single tps65218 register. * @@ -93,7 +79,7 @@ static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg, int ret; unsigned int data; - ret = tps65218_reg_read(tps, reg, &data); + ret = regmap_read(tps->regmap, reg, &data); if (ret) { dev_err(tps->dev, "Read from reg 0x%x failed\n", reg); return ret; @@ -251,7 +237,7 @@ static int tps65218_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = tps65218_reg_read(tps, TPS65218_REG_CHIPID, &chipid); + ret = regmap_read(tps->regmap, TPS65218_REG_CHIPID, &chipid); if (ret) { dev_err(tps->dev, "Failed to read chipid: %d\n", ret); return ret; diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index eb0f5b13841a..ae16caf4151c 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -272,7 +273,7 @@ static int tps65218_pmic_get_current_limit(struct regulator_dev *dev) unsigned int index; struct tps65218 *tps = rdev_get_drvdata(dev); - retval = tps65218_reg_read(tps, dev->desc->csel_reg, &index); + retval = regmap_read(tps->regmap, dev->desc->csel_reg, &index); if (retval < 0) return retval; @@ -383,7 +384,7 @@ static int tps65218_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } - ret = tps65218_reg_read(tps, regulators[id].bypass_reg, &val); + ret = regmap_read(tps->regmap, regulators[id].bypass_reg, &val); if (ret) return ret; diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h index d1db9527fab5..51bef539091c 100644 --- a/include/linux/mfd/tps65218.h +++ b/include/linux/mfd/tps65218.h @@ -284,8 +284,6 @@ struct tps65218 { struct regmap *regmap; }; -int tps65218_reg_read(struct tps65218 *tps, unsigned int reg, - unsigned int *val); int tps65218_reg_write(struct tps65218 *tps, unsigned int reg, unsigned int val, unsigned int level); int tps65218_set_bits(struct tps65218 *tps, unsigned int reg, -- cgit v1.2.3 From 77aa99265a8dda5b497ff4ebbcafafa7fa07e87f Mon Sep 17 00:00:00 2001 From: Keerthy Date: Mon, 19 Sep 2016 13:09:04 +0530 Subject: input: tps65218-pwrbutton: Add platform_device_id table platform_device_id table is needed for adding the tps65218-pwrbutton module to the mfd_cell array. Signed-off-by: Keerthy Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/misc/tps65218-pwrbutton.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c index 3273217ce80c..cc74a41bdb0d 100644 --- a/drivers/input/misc/tps65218-pwrbutton.c +++ b/drivers/input/misc/tps65218-pwrbutton.c @@ -150,12 +150,20 @@ static int tps6521x_pb_probe(struct platform_device *pdev) return 0; } +static const struct platform_device_id tps6521x_pwrbtn_id_table[] = { + { "tps65218-pwrbutton", }, + { "tps65217-pwrbutton", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, tps6521x_pwrbtn_id_table); + static struct platform_driver tps6521x_pb_driver = { .probe = tps6521x_pb_probe, .driver = { .name = "tps6521x_pwrbutton", .of_match_table = of_tps6521x_pb_match, }, + .id_table = tps6521x_pwrbtn_id_table, }; module_platform_driver(tps6521x_pb_driver); -- cgit v1.2.3 From 4531156db726d27e593d35800d43c74be4e393b9 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Mon, 19 Sep 2016 13:09:05 +0530 Subject: mfd: tps65218: Use mfd_add_devices instead of of_platform_populate mfd_add_devices enables parsing device tree nodes without compatibles for regulators and gpio modules. Replace of_platform_populate with mfd_add_devices. mfd_cell currently is populated with regulators, gpio and powerbutton. Signed-off-by: Keerthy Signed-off-by: Lee Jones --- drivers/mfd/tps65218.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c index 9bca1b1b60ce..13834a0d2817 100644 --- a/drivers/mfd/tps65218.c +++ b/drivers/mfd/tps65218.c @@ -33,6 +33,18 @@ #define TPS65218_PASSWORD_REGS_UNLOCK 0x7D +static const struct mfd_cell tps65218_cells[] = { + { + .name = "tps65218-pwrbutton", + .of_compatible = "ti,tps65218-pwrbutton", + }, + { + .name = "tps65218-gpio", + .of_compatible = "ti,tps65218-gpio", + }, + { .name = "tps65218-regulator", }, +}; + /** * tps65218_reg_write: Write a single tps65218 register. * @@ -245,8 +257,10 @@ static int tps65218_probe(struct i2c_client *client, tps->rev = chipid & TPS65218_CHIPID_REV_MASK; - ret = of_platform_populate(client->dev.of_node, NULL, NULL, - &client->dev); + ret = mfd_add_devices(tps->dev, PLATFORM_DEVID_AUTO, tps65218_cells, + ARRAY_SIZE(tps65218_cells), NULL, 0, + regmap_irq_get_domain(tps->irq_data)); + if (ret < 0) goto err_irq; -- cgit v1.2.3 From 2dc4940360d4c0c38aa9275532c7c0d7542f6258 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Mon, 19 Sep 2016 13:09:06 +0530 Subject: regulator: tps65218: Remove all the compatibles Remove all the individual compatibles for all the regulators and introduce id_table and update the driver accordingly to parse device tree nodes using the regulator framework. Signed-off-by: Keerthy Acked-by: Mark Brown Signed-off-by: Lee Jones --- drivers/regulator/tps65218-regulator.c | 150 ++++++++++++--------------------- include/linux/mfd/tps65218.h | 1 + 2 files changed, 57 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c index ae16caf4151c..9aafbb03482d 100644 --- a/drivers/regulator/tps65218-regulator.c +++ b/drivers/regulator/tps65218-regulator.c @@ -31,10 +31,11 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, DCDC5, DCDC6, LDO1, LS3 }; -#define TPS65218_REGULATOR(_name, _id, _type, _ops, _n, _vr, _vm, _er, _em, \ - _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \ +#define TPS65218_REGULATOR(_name, _of, _id, _type, _ops, _n, _vr, _vm, _er, \ + _em, _cr, _cm, _lr, _nlr, _delay, _fuv, _sr, _sm) \ { \ .name = _name, \ + .of_match = _of, \ .id = _id, \ .ops = &_ops, \ .n_voltages = _n, \ @@ -55,14 +56,6 @@ enum tps65218_regulators { DCDC1, DCDC2, DCDC3, DCDC4, .bypass_mask = _sm, \ } \ -#define TPS65218_INFO(_id, _nm, _min, _max) \ - [_id] = { \ - .id = _id, \ - .name = _nm, \ - .min_uV = _min, \ - .max_uV = _max, \ - } - static const struct regulator_linear_range dcdc1_dcdc2_ranges[] = { REGULATOR_LINEAR_RANGE(850000, 0x0, 0x32, 10000), REGULATOR_LINEAR_RANGE(1375000, 0x33, 0x3f, 25000), @@ -78,36 +71,6 @@ static const struct regulator_linear_range dcdc4_ranges[] = { REGULATOR_LINEAR_RANGE(1600000, 0x10, 0x34, 50000), }; -static struct tps_info tps65218_pmic_regs[] = { - TPS65218_INFO(DCDC1, "DCDC1", 850000, 1675000), - TPS65218_INFO(DCDC2, "DCDC2", 850000, 1675000), - TPS65218_INFO(DCDC3, "DCDC3", 900000, 3400000), - TPS65218_INFO(DCDC4, "DCDC4", 1175000, 3400000), - TPS65218_INFO(DCDC5, "DCDC5", 1000000, 1000000), - TPS65218_INFO(DCDC6, "DCDC6", 1800000, 1800000), - TPS65218_INFO(LDO1, "LDO1", 900000, 3400000), - TPS65218_INFO(LS3, "LS3", -1, -1), -}; - -#define TPS65218_OF_MATCH(comp, label) \ - { \ - .compatible = comp, \ - .data = &label, \ - } - -static const struct of_device_id tps65218_of_match[] = { - TPS65218_OF_MATCH("ti,tps65218-dcdc1", tps65218_pmic_regs[DCDC1]), - TPS65218_OF_MATCH("ti,tps65218-dcdc2", tps65218_pmic_regs[DCDC2]), - TPS65218_OF_MATCH("ti,tps65218-dcdc3", tps65218_pmic_regs[DCDC3]), - TPS65218_OF_MATCH("ti,tps65218-dcdc4", tps65218_pmic_regs[DCDC4]), - TPS65218_OF_MATCH("ti,tps65218-dcdc5", tps65218_pmic_regs[DCDC5]), - TPS65218_OF_MATCH("ti,tps65218-dcdc6", tps65218_pmic_regs[DCDC6]), - TPS65218_OF_MATCH("ti,tps65218-ldo1", tps65218_pmic_regs[LDO1]), - TPS65218_OF_MATCH("ti,tps65218-ls3", tps65218_pmic_regs[LS3]), - { } -}; -MODULE_DEVICE_TABLE(of, tps65218_of_match); - static int tps65218_pmic_set_voltage_sel(struct regulator_dev *dev, unsigned selector) { @@ -189,7 +152,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev) if (rid == TPS65218_DCDC_3 && tps->rev == TPS65218_REV_2_1) return 0; - if (!tps->info[rid]->strobe) { + if (!tps->strobes[rid]) { if (rid == TPS65218_DCDC_3) tps->info[rid]->strobe = 3; else @@ -198,8 +161,7 @@ static int tps65218_pmic_set_suspend_disable(struct regulator_dev *dev) return tps65218_set_bits(tps, dev->desc->bypass_reg, dev->desc->bypass_mask, - tps->info[rid]->strobe, - TPS65218_PROTECT_L1); + tps->strobes[rid], TPS65218_PROTECT_L1); } /* Operations permitted on DCDC1, DCDC2 */ @@ -301,104 +263,104 @@ static struct regulator_ops tps65218_dcdc56_pmic_ops = { }; static const struct regulator_desc regulators[] = { - TPS65218_REGULATOR("DCDC1", TPS65218_DCDC_1, REGULATOR_VOLTAGE, - tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC1, + TPS65218_REGULATOR("DCDC1", "regulator-dcdc1", TPS65218_DCDC_1, + REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64, + TPS65218_REG_CONTROL_DCDC1, TPS65218_CONTROL_DCDC1_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC1_EN, 0, 0, dcdc1_dcdc2_ranges, 2, 4000, 0, TPS65218_REG_SEQ3, TPS65218_SEQ3_DC1_SEQ_MASK), - TPS65218_REGULATOR("DCDC2", TPS65218_DCDC_2, REGULATOR_VOLTAGE, - tps65218_dcdc12_ops, 64, TPS65218_REG_CONTROL_DCDC2, + TPS65218_REGULATOR("DCDC2", "regulator-dcdc2", TPS65218_DCDC_2, + REGULATOR_VOLTAGE, tps65218_dcdc12_ops, 64, + TPS65218_REG_CONTROL_DCDC2, TPS65218_CONTROL_DCDC2_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC2_EN, 0, 0, dcdc1_dcdc2_ranges, 2, 4000, 0, TPS65218_REG_SEQ3, TPS65218_SEQ3_DC2_SEQ_MASK), - TPS65218_REGULATOR("DCDC3", TPS65218_DCDC_3, REGULATOR_VOLTAGE, - tps65218_ldo1_dcdc34_ops, 64, + TPS65218_REGULATOR("DCDC3", "regulator-dcdc3", TPS65218_DCDC_3, + REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_DCDC3, TPS65218_CONTROL_DCDC3_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC3_EN, 0, 0, ldo1_dcdc3_ranges, 2, 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC3_SEQ_MASK), - TPS65218_REGULATOR("DCDC4", TPS65218_DCDC_4, REGULATOR_VOLTAGE, - tps65218_ldo1_dcdc34_ops, 53, + TPS65218_REGULATOR("DCDC4", "regulator-dcdc4", TPS65218_DCDC_4, + REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 53, TPS65218_REG_CONTROL_DCDC4, TPS65218_CONTROL_DCDC4_MASK, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC4_EN, 0, 0, dcdc4_ranges, 2, 0, 0, TPS65218_REG_SEQ4, TPS65218_SEQ4_DC4_SEQ_MASK), - TPS65218_REGULATOR("DCDC5", TPS65218_DCDC_5, REGULATOR_VOLTAGE, - tps65218_dcdc56_pmic_ops, 1, -1, -1, - TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, 0, - NULL, 0, 0, 1000000, TPS65218_REG_SEQ5, + TPS65218_REGULATOR("DCDC5", "regulator-dcdc5", TPS65218_DCDC_5, + REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, + -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC5_EN, 0, + 0, NULL, 0, 0, 1000000, TPS65218_REG_SEQ5, TPS65218_SEQ5_DC5_SEQ_MASK), - TPS65218_REGULATOR("DCDC6", TPS65218_DCDC_6, REGULATOR_VOLTAGE, - tps65218_dcdc56_pmic_ops, 1, -1, -1, - TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, 0, - NULL, 0, 0, 1800000, TPS65218_REG_SEQ5, + TPS65218_REGULATOR("DCDC6", "regulator-dcdc6", TPS65218_DCDC_6, + REGULATOR_VOLTAGE, tps65218_dcdc56_pmic_ops, 1, -1, + -1, TPS65218_REG_ENABLE1, TPS65218_ENABLE1_DC6_EN, 0, + 0, NULL, 0, 0, 1800000, TPS65218_REG_SEQ5, TPS65218_SEQ5_DC6_SEQ_MASK), - TPS65218_REGULATOR("LDO1", TPS65218_LDO_1, REGULATOR_VOLTAGE, - tps65218_ldo1_dcdc34_ops, 64, + TPS65218_REGULATOR("LDO1", "regulator-ldo1", TPS65218_LDO_1, + REGULATOR_VOLTAGE, tps65218_ldo1_dcdc34_ops, 64, TPS65218_REG_CONTROL_LDO1, TPS65218_CONTROL_LDO1_MASK, TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LDO1_EN, 0, 0, ldo1_dcdc3_ranges, 2, 0, 0, TPS65218_REG_SEQ6, TPS65218_SEQ6_LDO1_SEQ_MASK), - TPS65218_REGULATOR("LS3", TPS65218_LS_3, REGULATOR_CURRENT, - tps65218_ls3_ops, 0, 0, 0, TPS65218_REG_ENABLE2, - TPS65218_ENABLE2_LS3_EN, TPS65218_REG_CONFIG2, - TPS65218_CONFIG2_LS3ILIM_MASK, NULL, 0, 0, 0, 0, 0), + TPS65218_REGULATOR("LS3", "regulator-ls3", TPS65218_LS_3, + REGULATOR_CURRENT, tps65218_ls3_ops, 0, 0, 0, + TPS65218_REG_ENABLE2, TPS65218_ENABLE2_LS3_EN, + TPS65218_REG_CONFIG2, TPS65218_CONFIG2_LS3ILIM_MASK, + NULL, 0, 0, 0, 0, 0), }; static int tps65218_regulator_probe(struct platform_device *pdev) { struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent); - struct regulator_init_data *init_data; - const struct tps_info *template; struct regulator_dev *rdev; - const struct of_device_id *match; struct regulator_config config = { }; - int id, ret; + int i, ret; unsigned int val; - match = of_match_device(tps65218_of_match, &pdev->dev); - if (!match) - return -ENODEV; - - template = match->data; - id = template->id; - init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node, - ®ulators[id]); - - platform_set_drvdata(pdev, tps); - - tps->info[id] = &tps65218_pmic_regs[id]; config.dev = &pdev->dev; - config.init_data = init_data; + config.dev->of_node = tps->dev->of_node; config.driver_data = tps; config.regmap = tps->regmap; - config.of_node = pdev->dev.of_node; - rdev = devm_regulator_register(&pdev->dev, ®ulators[id], &config); - if (IS_ERR(rdev)) { - dev_err(tps->dev, "failed to register %s regulator\n", - pdev->name); - return PTR_ERR(rdev); - } + /* Allocate memory for strobes */ + tps->strobes = devm_kzalloc(&pdev->dev, sizeof(u8) * + TPS65218_NUM_REGULATOR, GFP_KERNEL); - ret = regmap_read(tps->regmap, regulators[id].bypass_reg, &val); - if (ret) - return ret; + for (i = 0; i < ARRAY_SIZE(regulators); i++) { + rdev = devm_regulator_register(&pdev->dev, ®ulators[i], + &config); + if (IS_ERR(rdev)) { + dev_err(tps->dev, "failed to register %s regulator\n", + pdev->name); + return PTR_ERR(rdev); + } - tps->info[id]->strobe = val & regulators[id].bypass_mask; + ret = regmap_read(tps->regmap, regulators[i].bypass_reg, &val); + if (ret) + return ret; + + tps->strobes[i] = val & regulators[i].bypass_mask; + } return 0; } +static const struct platform_device_id tps65218_regulator_id_table[] = { + { "tps65218-regulator", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, tps65218_regulator_id_table); + static struct platform_driver tps65218_regulator_driver = { .driver = { .name = "tps65218-pmic", - .of_match_table = tps65218_of_match, }, .probe = tps65218_regulator_probe, + .id_table = tps65218_regulator_id_table, }; module_platform_driver(tps65218_regulator_driver); diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h index 51bef539091c..bccd2d68b1e3 100644 --- a/include/linux/mfd/tps65218.h +++ b/include/linux/mfd/tps65218.h @@ -282,6 +282,7 @@ struct tps65218 { struct regulator_desc desc[TPS65218_NUM_REGULATOR]; struct tps_info *info[TPS65218_NUM_REGULATOR]; struct regmap *regmap; + u8 *strobes; }; int tps65218_reg_write(struct tps65218 *tps, unsigned int reg, -- cgit v1.2.3 From e9a2ea5a1ba09c35258f3663842fb8d8cf2e00c2 Mon Sep 17 00:00:00 2001 From: Fenghua Yu Date: Sat, 22 Oct 2016 06:19:49 -0700 Subject: cacheinfo: Introduce cache id Cache management software needs an id for each instance of a cache of a particular type. The current cacheinfo structure does not provide any information about the underlying hardware so there is no way to expose it. Hardware with cache management features provides means (cpuid, enumeration etc.) to retrieve the hardware id of a particular cache instance. Cache instances which share hardware have the same hardware id. Add an 'id' field to struct cacheinfo to store this information. Expose this information under the /sys/devices/system/cpu/cpu*/cache/index*/ directory as well. Signed-off-by: Fenghua Yu Cc: "Ravi V Shankar" Cc: "Tony Luck" Cc: "David Carrillo-Cisneros" Cc: "Sai Prakhya" Cc: "Peter Zijlstra" Cc: "Stephane Eranian" Cc: "Dave Hansen" Cc: "Shaohua Li" Cc: "Nilay Vaish" Cc: "Vikas Shivappa" Cc: "Ingo Molnar" Cc: "Borislav Petkov" Cc: "H. Peter Anvin" Link: http://lkml.kernel.org/r/1477142405-32078-3-git-send-email-fenghua.yu@intel.com Signed-off-by: Thomas Gleixner --- drivers/base/cacheinfo.c | 5 +++++ include/linux/cacheinfo.h | 3 +++ 2 files changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/base/cacheinfo.c b/drivers/base/cacheinfo.c index e9fd32e91668..00a9688043f4 100644 --- a/drivers/base/cacheinfo.c +++ b/drivers/base/cacheinfo.c @@ -233,6 +233,7 @@ static ssize_t file_name##_show(struct device *dev, \ return sprintf(buf, "%u\n", this_leaf->object); \ } +show_one(id, id); show_one(level, level); show_one(coherency_line_size, coherency_line_size); show_one(number_of_sets, number_of_sets); @@ -314,6 +315,7 @@ static ssize_t write_policy_show(struct device *dev, return n; } +static DEVICE_ATTR_RO(id); static DEVICE_ATTR_RO(level); static DEVICE_ATTR_RO(type); static DEVICE_ATTR_RO(coherency_line_size); @@ -327,6 +329,7 @@ static DEVICE_ATTR_RO(shared_cpu_list); static DEVICE_ATTR_RO(physical_line_partition); static struct attribute *cache_default_attrs[] = { + &dev_attr_id.attr, &dev_attr_type.attr, &dev_attr_level.attr, &dev_attr_shared_cpu_map.attr, @@ -350,6 +353,8 @@ cache_default_attrs_is_visible(struct kobject *kobj, const struct cpumask *mask = &this_leaf->shared_cpu_map; umode_t mode = attr->mode; + if ((attr == &dev_attr_id.attr) && (this_leaf->attributes & CACHE_ID)) + return mode; if ((attr == &dev_attr_type.attr) && this_leaf->type) return mode; if ((attr == &dev_attr_level.attr) && this_leaf->level) diff --git a/include/linux/cacheinfo.h b/include/linux/cacheinfo.h index 2189935075b4..0bcbb674da9d 100644 --- a/include/linux/cacheinfo.h +++ b/include/linux/cacheinfo.h @@ -18,6 +18,7 @@ enum cache_type { /** * struct cacheinfo - represent a cache leaf node + * @id: This cache's id. It is unique among caches with the same (type, level). * @type: type of the cache - data, inst or unified * @level: represents the hierarchy in the multi-level cache * @coherency_line_size: size of each cache line usually representing @@ -44,6 +45,7 @@ enum cache_type { * keeping, the remaining members form the core properties of the cache */ struct cacheinfo { + unsigned int id; enum cache_type type; unsigned int level; unsigned int coherency_line_size; @@ -61,6 +63,7 @@ struct cacheinfo { #define CACHE_WRITE_ALLOCATE BIT(3) #define CACHE_ALLOCATE_POLICY_MASK \ (CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE) +#define CACHE_ID BIT(4) struct device_node *of_node; bool disable_sysfs; -- cgit v1.2.3 From 6d86c4714da526243d7b0578eaf5e1b54f8c2ed2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 25 Oct 2016 09:35:40 -0700 Subject: Input: pxa27x_keypad - fix typo "debpunce" -> "debounce" Trivial fix to typo in dev_err message Signed-off-by: Colin Ian King Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/pxa27x_keypad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c index fcef5d1365e2..e24443376e75 100644 --- a/drivers/input/keyboard/pxa27x_keypad.c +++ b/drivers/input/keyboard/pxa27x_keypad.c @@ -316,7 +316,7 @@ static int pxa27x_keypad_build_keycode_from_dt(struct pxa27x_keypad *keypad) error = of_property_read_u32(np, "marvell,debounce-interval", &pdata->debounce_interval); if (error) { - dev_err(dev, "failed to parse debpunce-interval\n"); + dev_err(dev, "failed to parse debounce-interval\n"); return error; } -- cgit v1.2.3 From 04d7ad83c6a61395582cd236aa6dc61c8430e227 Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Wed, 26 Oct 2016 15:49:13 -0700 Subject: Input: da9061 - onkey driver Copyright header is updated to add DA9061 in its description and the module description macro is extended to include DA9061. Minor change to the code, alters dev_dbg() statements to report a generic "PMIC" instead of DA9063. This device driver is compatible with DA9061, DA9062 and DA9063. Kconfig is updated to reflect support for DA9061/62/63. Signed-off-by: Steve Twiss Signed-off-by: Dmitry Torokhov --- drivers/input/misc/Kconfig | 7 ++++--- drivers/input/misc/da9063_onkey.c | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 7ffb614ce566..1ae4d9617ff8 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -625,11 +625,12 @@ config INPUT_DA9055_ONKEY will be called da9055_onkey. config INPUT_DA9063_ONKEY - tristate "Dialog DA9062/63 OnKey" + tristate "Dialog DA9063/62/61 OnKey" depends on MFD_DA9063 || MFD_DA9062 help - Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs - as an input device capable of reporting the power button status. + Support the ONKEY of Dialog DA9063, DA9062 and DA9061 Power + Management ICs as an input device capable of reporting the + power button status. To compile this driver as a module, choose M here: the module will be called da9063_onkey. diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index bb863e062b03..dff6fe5724fe 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -1,5 +1,5 @@ /* - * OnKey device driver for DA9063 and DA9062 PMICs + * OnKey device driver for DA9063, DA9062 and DA9061 PMICs * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or @@ -149,13 +149,13 @@ static void da9063_poll_on(struct work_struct *work) * and then send shutdown command */ dev_dbg(&onkey->input->dev, - "Sending SHUTDOWN to DA9063 ...\n"); + "Sending SHUTDOWN to PMIC ...\n"); error = regmap_write(onkey->regmap, config->onkey_shutdown, config->onkey_shutdown_mask); if (error) dev_err(&onkey->input->dev, - "Cannot SHUTDOWN DA9063: %d\n", + "Cannot SHUTDOWN PMIC: %d\n", error); } } @@ -300,6 +300,6 @@ static struct platform_driver da9063_onkey_driver = { module_platform_driver(da9063_onkey_driver); MODULE_AUTHOR("S Twiss "); -MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063 and DA9062"); +MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY); -- cgit v1.2.3 From c2c4ba82022cbe14ab15f394078aaf592664bd69 Mon Sep 17 00:00:00 2001 From: Sangwon Jee Date: Wed, 26 Oct 2016 15:53:13 -0700 Subject: Input: melfas_mip4 - use product id for firmware name Use product id for firmware name to request compatible firmware. Signed-off-by: Sangwon Jee Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 8739cb718b4c..0f2230a9b1a1 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -162,6 +162,7 @@ struct mip4_ts { char product_name[16]; u16 product_id; char ic_name[4]; + char fw_name[32]; unsigned int max_x; unsigned int max_y; @@ -280,6 +281,11 @@ static int mip4_query_device(struct mip4_ts *ts) dev_dbg(&ts->client->dev, "product id: %04X\n", ts->product_id); } + /* Firmware name */ + snprintf(ts->fw_name, sizeof(ts->fw_name), + "melfas_mip4_%04X.fw", ts->product_id); + dev_dbg(&ts->client->dev, "firmware name: %s\n", ts->fw_name); + /* IC name */ cmd[0] = MIP4_R0_INFO; cmd[1] = MIP4_R1_INFO_IC_NAME; @@ -1285,11 +1291,11 @@ static ssize_t mip4_sysfs_fw_update(struct device *dev, const struct firmware *fw; int error; - error = request_firmware(&fw, MIP4_FW_NAME, dev); + error = request_firmware(&fw, ts->fw_name, dev); if (error) { dev_err(&ts->client->dev, "Failed to retrieve firmware %s: %d\n", - MIP4_FW_NAME, error); + ts->fw_name, error); return error; } @@ -1608,6 +1614,6 @@ static struct i2c_driver mip4_driver = { module_i2c_driver(mip4_driver); MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen"); -MODULE_VERSION("2016.10.20"); +MODULE_VERSION("2016.10.24"); MODULE_AUTHOR("Sangwon Jee "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From ea4348c8462a20e8b1b6455a7145d2b86f8a49b6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Oct 2016 15:55:02 -0700 Subject: Input: tca8418_keypad - hide gcc-4.9 -Wmaybe-uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Older versions of gcc warn about the tca8418_irq_handler function as they can't keep track of the variable assignment inside of the loop when using the -Wmaybe-unintialized flag: drivers/input/keyboard/tca8418_keypad.c: In function ‘tca8418_irq_handler’: drivers/input/keyboard/tca8418_keypad.c:172:9: error: ‘reg’ may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/input/keyboard/tca8418_keypad.c:165:5: note: ‘reg’ was declared here This is fixed in gcc-6, but it's possible to rearrange the code in a way that avoids the warning on older compilers as well. Signed-off-by: Arnd Bergmann Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/tca8418_keypad.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/tca8418_keypad.c b/drivers/input/keyboard/tca8418_keypad.c index 9002298698fc..3048ef3e3e16 100644 --- a/drivers/input/keyboard/tca8418_keypad.c +++ b/drivers/input/keyboard/tca8418_keypad.c @@ -164,11 +164,18 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) int error, col, row; u8 reg, state, code; - /* Initial read of the key event FIFO */ - error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); + do { + error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); + if (error < 0) { + dev_err(&keypad_data->client->dev, + "unable to read REG_KEY_EVENT_A\n"); + break; + } + + /* Assume that key code 0 signifies empty FIFO */ + if (reg <= 0) + break; - /* Assume that key code 0 signifies empty FIFO */ - while (error >= 0 && reg > 0) { state = reg & KEY_EVENT_VALUE; code = reg & KEY_EVENT_CODE; @@ -184,11 +191,7 @@ static void tca8418_read_keypad(struct tca8418_keypad *keypad_data) /* Read for next loop */ error = tca8418_read_byte(keypad_data, REG_KEY_EVENT_A, ®); - } - - if (error < 0) - dev_err(&keypad_data->client->dev, - "unable to read REG_KEY_EVENT_A\n"); + } while (1); input_sync(input); } -- cgit v1.2.3 From 39a0d75ae32c061fa403824e56438501d7fb09f7 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 26 Oct 2016 16:26:19 -0700 Subject: Input: elan_i2c - always output the device information it's always easier to retrieve these information in bug reports when it is always printed in the dmesg. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/elan_i2c_core.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c index d15b33813021..fa598f7f4372 100644 --- a/drivers/input/mouse/elan_i2c_core.c +++ b/drivers/input/mouse/elan_i2c_core.c @@ -1093,19 +1093,18 @@ static int elan_probe(struct i2c_client *client, if (error) return error; + dev_info(&client->dev, + "Elan Touchpad: Module ID: 0x%04x, Firmware: 0x%04x, Sample: 0x%04x, IAP: 0x%04x\n", + data->product_id, + data->fw_version, + data->sm_version, + data->iap_version); + dev_dbg(&client->dev, - "Elan Touchpad Information:\n" - " Module product ID: 0x%04x\n" - " Firmware Version: 0x%04x\n" - " Sample Version: 0x%04x\n" - " IAP Version: 0x%04x\n" + "Elan Touchpad Extra Information:\n" " Max ABS X,Y: %d,%d\n" " Width X,Y: %d,%d\n" " Resolution X,Y: %d,%d (dots/mm)\n", - data->product_id, - data->fw_version, - data->sm_version, - data->iap_version, data->max_x, data->max_y, data->width_x, data->width_y, data->x_res, data->y_res); -- cgit v1.2.3 From e1cb73f6f53676fa6ca7eec6b3c371cf68a6797e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 26 Oct 2016 16:46:20 -0700 Subject: Input: fsl-imx25-tcq - fix module autoload when registered via OF If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/input/touchscreen/fsl-imx25-tcq.ko | grep alias After this patch: $ modinfo drivers/input/touchscreen/fsl-imx25-tcq.ko | grep alias alias: of:N*T*Cfsl,imx25-tcqC* alias: of:N*T*Cfsl,imx25-tcq Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/fsl-imx25-tcq.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/touchscreen/fsl-imx25-tcq.c b/drivers/input/touchscreen/fsl-imx25-tcq.c index fe9877a6af9e..d50ee490c9cc 100644 --- a/drivers/input/touchscreen/fsl-imx25-tcq.c +++ b/drivers/input/touchscreen/fsl-imx25-tcq.c @@ -55,6 +55,7 @@ static const struct of_device_id mx25_tcq_ids[] = { { .compatible = "fsl,imx25-tcq", }, { /* Sentinel */ } }; +MODULE_DEVICE_TABLE(of, mx25_tcq_ids); #define TSC_4WIRE_PRE_INDEX 0 #define TSC_4WIRE_X_INDEX 1 -- cgit v1.2.3 From 8dd5e0b364e5b83864cd918475e5a5ef3b352446 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 26 Oct 2016 16:46:41 -0700 Subject: Input: da9063 - fix module autoload when registered via OF If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/input/misc/da9063_onkey.ko | grep alias alias: platform:da9063-onkey After this patch: $ modinfo drivers/input/misc/da9063_onkey.ko | grep alias alias: platform:da9063-onkey alias: of:N*T*Cdlg,da9062-onkeyC* alias: of:N*T*Cdlg,da9062-onkey alias: of:N*T*Cdlg,da9063-onkeyC* alias: of:N*T*Cdlg,da9063-onkey Signed-off-by: Javier Martinez Canillas Signed-off-by: Dmitry Torokhov --- drivers/input/misc/da9063_onkey.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/misc/da9063_onkey.c b/drivers/input/misc/da9063_onkey.c index dff6fe5724fe..b4ff1e86d3d3 100644 --- a/drivers/input/misc/da9063_onkey.c +++ b/drivers/input/misc/da9063_onkey.c @@ -87,6 +87,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = { { .compatible = "dlg,da9062-onkey", .data = &da9062_regs }, { }, }; +MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table); static void da9063_poll_on(struct work_struct *work) { -- cgit v1.2.3 From aa276781a64a5f15ecc21e920960c5b1f84e5fee Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 18 Oct 2016 18:08:34 -0500 Subject: firmware: Add basic support for TI System Control Interface (TI-SCI) protocol Texas Instrument's System Control Interface (TI-SCI) Message Protocol is used in Texas Instrument's System on Chip (SoC) such as those in keystone family K2G SoC to communicate between various compute processors with a central system controller entity. TI-SCI message protocol provides support for management of various hardware entities within the SoC. Add support driver to allow communication with system controller entity within the SoC using the mailbox client. We introduce the basic registration and query capability for the driver protocol as part of this change. Subsequent patches add in functionality specific to the TI-SCI features. Signed-off-by: Nishanth Menon Signed-off-by: Tero Kristo --- MAINTAINERS | 2 + drivers/firmware/Kconfig | 15 + drivers/firmware/Makefile | 1 + drivers/firmware/ti_sci.c | 790 +++++++++++++++++++++++++++++++++ drivers/firmware/ti_sci.h | 93 ++++ include/linux/soc/ti/ti_sci_protocol.h | 69 +++ 6 files changed, 970 insertions(+) create mode 100644 drivers/firmware/ti_sci.c create mode 100644 drivers/firmware/ti_sci.h create mode 100644 include/linux/soc/ti/ti_sci_protocol.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 2bafadf5747a..467b29fafaca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11890,6 +11890,8 @@ M: Santosh Shilimkar L: linux-arm-kernel@lists.infradead.org S: Maintained F: Documentation/devicetree/bindings/arm/keystone/ti,sci.txt +F: drivers/firmware/ti_sci* +F: include/linux/soc/ti/ti_sci_protocol.h THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB DRIVER M: Hans Verkuil diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index bca172d42c74..9418d7d1b0a5 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -203,6 +203,21 @@ config QCOM_SCM_64 def_bool y depends on QCOM_SCM && ARM64 +config TI_SCI_PROTOCOL + tristate "TI System Control Interface (TISCI) Message Protocol" + depends on TI_MESSAGE_MANAGER + help + TI System Control Interface (TISCI) Message Protocol is used to manage + compute systems such as ARM, DSP etc with the system controller in + complex System on Chip(SoC) such as those found on certain keystone + generation SoC from TI. + + System controller provides various facilities including power + management function support. + + This protocol library is used by client drivers to use the features + provided by the system controller. + config HAVE_ARM_SMCCC bool diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 898ac41fa8b3..dcb52c423151 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -20,6 +20,7 @@ obj-$(CONFIG_QCOM_SCM) += qcom_scm.o obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a +obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o obj-y += broadcom/ obj-y += meson/ diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c new file mode 100644 index 000000000000..5e99d7c18276 --- /dev/null +++ b/drivers/firmware/ti_sci.c @@ -0,0 +1,790 @@ +/* + * Texas Instruments System Control Interface Protocol Driver + * + * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ + * Nishanth Menon + * + * 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 "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. + */ + +#define pr_fmt(fmt) "%s: " fmt, __func__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ti_sci.h" + +/* List of all TI SCI devices active in system */ +static LIST_HEAD(ti_sci_list); +/* Protection for the entire list */ +static DEFINE_MUTEX(ti_sci_list_mutex); + +/** + * struct ti_sci_xfer - Structure representing a message flow + * @tx_message: Transmit message + * @rx_len: Receive message length + * @xfer_buf: Preallocated buffer to store receive message + * Since we work with request-ACK protocol, we can + * reuse the same buffer for the rx path as we + * use for the tx path. + * @done: completion event + */ +struct ti_sci_xfer { + struct ti_msgmgr_message tx_message; + u8 rx_len; + u8 *xfer_buf; + struct completion done; +}; + +/** + * struct ti_sci_xfers_info - Structure to manage transfer information + * @sem_xfer_count: Counting Semaphore for managing max simultaneous + * Messages. + * @xfer_block: Preallocated Message array + * @xfer_alloc_table: Bitmap table for allocated messages. + * Index of this bitmap table is also used for message + * sequence identifier. + * @xfer_lock: Protection for message allocation + */ +struct ti_sci_xfers_info { + struct semaphore sem_xfer_count; + struct ti_sci_xfer *xfer_block; + unsigned long *xfer_alloc_table; + /* protect transfer allocation */ + spinlock_t xfer_lock; +}; + +/** + * struct ti_sci_desc - Description of SoC integration + * @host_id: Host identifier representing the compute entity + * @max_rx_timeout_ms: Timeout for communication with SoC (in Milliseconds) + * @max_msgs: Maximum number of messages that can be pending + * simultaneously in the system + * @max_msg_size: Maximum size of data per message that can be handled. + */ +struct ti_sci_desc { + u8 host_id; + int max_rx_timeout_ms; + int max_msgs; + int max_msg_size; +}; + +/** + * struct ti_sci_info - Structure representing a TI SCI instance + * @dev: Device pointer + * @desc: SoC description for this instance + * @d: Debugfs file entry + * @debug_region: Memory region where the debug message are available + * @debug_region_size: Debug region size + * @debug_buffer: Buffer allocated to copy debug messages. + * @handle: Instance of TI SCI handle to send to clients. + * @cl: Mailbox Client + * @chan_tx: Transmit mailbox channel + * @chan_rx: Receive mailbox channel + * @minfo: Message info + * @node: list head + * @users: Number of users of this instance + */ +struct ti_sci_info { + struct device *dev; + const struct ti_sci_desc *desc; + struct dentry *d; + void __iomem *debug_region; + char *debug_buffer; + size_t debug_region_size; + struct ti_sci_handle handle; + struct mbox_client cl; + struct mbox_chan *chan_tx; + struct mbox_chan *chan_rx; + struct ti_sci_xfers_info minfo; + struct list_head node; + /* protected by ti_sci_list_mutex */ + int users; +}; + +#define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl) +#define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle) + +#ifdef CONFIG_DEBUG_FS + +/** + * ti_sci_debug_show() - Helper to dump the debug log + * @s: sequence file pointer + * @unused: unused. + * + * Return: 0 + */ +static int ti_sci_debug_show(struct seq_file *s, void *unused) +{ + struct ti_sci_info *info = s->private; + + memcpy_fromio(info->debug_buffer, info->debug_region, + info->debug_region_size); + /* + * We don't trust firmware to leave NULL terminated last byte (hence + * we have allocated 1 extra 0 byte). Since we cannot guarantee any + * specific data format for debug messages, We just present the data + * in the buffer as is - we expect the messages to be self explanatory. + */ + seq_puts(s, info->debug_buffer); + return 0; +} + +/** + * ti_sci_debug_open() - debug file open + * @inode: inode pointer + * @file: file pointer + * + * Return: result of single_open + */ +static int ti_sci_debug_open(struct inode *inode, struct file *file) +{ + return single_open(file, ti_sci_debug_show, inode->i_private); +} + +/* log file operations */ +static const struct file_operations ti_sci_debug_fops = { + .open = ti_sci_debug_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +/** + * ti_sci_debugfs_create() - Create log debug file + * @pdev: platform device pointer + * @info: Pointer to SCI entity information + * + * Return: 0 if all went fine, else corresponding error. + */ +static int ti_sci_debugfs_create(struct platform_device *pdev, + struct ti_sci_info *info) +{ + struct device *dev = &pdev->dev; + struct resource *res; + char debug_name[50] = "ti_sci_debug@"; + + /* Debug region is optional */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "debug_messages"); + info->debug_region = devm_ioremap_resource(dev, res); + if (IS_ERR(info->debug_region)) + return 0; + info->debug_region_size = resource_size(res); + + info->debug_buffer = devm_kcalloc(dev, info->debug_region_size + 1, + sizeof(char), GFP_KERNEL); + if (!info->debug_buffer) + return -ENOMEM; + /* Setup NULL termination */ + info->debug_buffer[info->debug_region_size] = 0; + + info->d = debugfs_create_file(strncat(debug_name, dev_name(dev), + sizeof(debug_name)), + 0444, NULL, info, &ti_sci_debug_fops); + if (IS_ERR(info->d)) + return PTR_ERR(info->d); + + dev_dbg(dev, "Debug region => %p, size = %zu bytes, resource: %pr\n", + info->debug_region, info->debug_region_size, res); + return 0; +} + +/** + * ti_sci_debugfs_destroy() - clean up log debug file + * @pdev: platform device pointer + * @info: Pointer to SCI entity information + */ +static void ti_sci_debugfs_destroy(struct platform_device *pdev, + struct ti_sci_info *info) +{ + if (IS_ERR(info->debug_region)) + return; + + debugfs_remove(info->d); +} +#else /* CONFIG_DEBUG_FS */ +static inline int ti_sci_debugfs_create(struct platform_device *dev, + struct ti_sci_info *info) +{ + return 0; +} + +static inline void ti_sci_debugfs_destroy(struct platform_device *dev, + struct ti_sci_info *info) +{ +} +#endif /* CONFIG_DEBUG_FS */ + +/** + * ti_sci_dump_header_dbg() - Helper to dump a message header. + * @dev: Device pointer corresponding to the SCI entity + * @hdr: pointer to header. + */ +static inline void ti_sci_dump_header_dbg(struct device *dev, + struct ti_sci_msg_hdr *hdr) +{ + dev_dbg(dev, "MSGHDR:type=0x%04x host=0x%02x seq=0x%02x flags=0x%08x\n", + hdr->type, hdr->host, hdr->seq, hdr->flags); +} + +/** + * ti_sci_rx_callback() - mailbox client callback for receive messages + * @cl: client pointer + * @m: mailbox message + * + * Processes one received message to appropriate transfer information and + * signals completion of the transfer. + * + * NOTE: This function will be invoked in IRQ context, hence should be + * as optimal as possible. + */ +static void ti_sci_rx_callback(struct mbox_client *cl, void *m) +{ + struct ti_sci_info *info = cl_to_ti_sci_info(cl); + struct device *dev = info->dev; + struct ti_sci_xfers_info *minfo = &info->minfo; + struct ti_msgmgr_message *mbox_msg = m; + struct ti_sci_msg_hdr *hdr = (struct ti_sci_msg_hdr *)mbox_msg->buf; + struct ti_sci_xfer *xfer; + u8 xfer_id; + + xfer_id = hdr->seq; + + /* + * Are we even expecting this? + * NOTE: barriers were implicit in locks used for modifying the bitmap + */ + if (!test_bit(xfer_id, minfo->xfer_alloc_table)) { + dev_err(dev, "Message for %d is not expected!\n", xfer_id); + return; + } + + xfer = &minfo->xfer_block[xfer_id]; + + /* Is the message of valid length? */ + if (mbox_msg->len > info->desc->max_msg_size) { + dev_err(dev, "Unable to handle %d xfer(max %d)\n", + mbox_msg->len, info->desc->max_msg_size); + ti_sci_dump_header_dbg(dev, hdr); + return; + } + if (mbox_msg->len < xfer->rx_len) { + dev_err(dev, "Recv xfer %d < expected %d length\n", + mbox_msg->len, xfer->rx_len); + ti_sci_dump_header_dbg(dev, hdr); + return; + } + + ti_sci_dump_header_dbg(dev, hdr); + /* Take a copy to the rx buffer.. */ + memcpy(xfer->xfer_buf, mbox_msg->buf, xfer->rx_len); + complete(&xfer->done); +} + +/** + * ti_sci_get_one_xfer() - Allocate one message + * @info: Pointer to SCI entity information + * @msg_type: Message type + * @msg_flags: Flag to set for the message + * @tx_message_size: transmit message size + * @rx_message_size: receive message size + * + * Helper function which is used by various command functions that are + * exposed to clients of this driver for allocating a message traffic event. + * + * This function can sleep depending on pending requests already in the system + * for the SCI entity. Further, this also holds a spinlock to maintain integrity + * of internal data structures. + * + * Return: 0 if all went fine, else corresponding error. + */ +static struct ti_sci_xfer *ti_sci_get_one_xfer(struct ti_sci_info *info, + u16 msg_type, u32 msg_flags, + size_t tx_message_size, + size_t rx_message_size) +{ + struct ti_sci_xfers_info *minfo = &info->minfo; + struct ti_sci_xfer *xfer; + struct ti_sci_msg_hdr *hdr; + unsigned long flags; + unsigned long bit_pos; + u8 xfer_id; + int ret; + int timeout; + + /* Ensure we have sane transfer sizes */ + if (rx_message_size > info->desc->max_msg_size || + tx_message_size > info->desc->max_msg_size || + rx_message_size < sizeof(*hdr) || tx_message_size < sizeof(*hdr)) + return ERR_PTR(-ERANGE); + + /* + * Ensure we have only controlled number of pending messages. + * Ideally, we might just have to wait a single message, be + * conservative and wait 5 times that.. + */ + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms) * 5; + ret = down_timeout(&minfo->sem_xfer_count, timeout); + if (ret < 0) + return ERR_PTR(ret); + + /* Keep the locked section as small as possible */ + spin_lock_irqsave(&minfo->xfer_lock, flags); + bit_pos = find_first_zero_bit(minfo->xfer_alloc_table, + info->desc->max_msgs); + set_bit(bit_pos, minfo->xfer_alloc_table); + spin_unlock_irqrestore(&minfo->xfer_lock, flags); + + /* + * We already ensured in probe that we can have max messages that can + * fit in hdr.seq - NOTE: this improves access latencies + * to predictable O(1) access, BUT, it opens us to risk if + * remote misbehaves with corrupted message sequence responses. + * If that happens, we are going to be messed up anyways.. + */ + xfer_id = (u8)bit_pos; + + xfer = &minfo->xfer_block[xfer_id]; + + hdr = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; + xfer->tx_message.len = tx_message_size; + xfer->rx_len = (u8)rx_message_size; + + reinit_completion(&xfer->done); + + hdr->seq = xfer_id; + hdr->type = msg_type; + hdr->host = info->desc->host_id; + hdr->flags = msg_flags; + + return xfer; +} + +/** + * ti_sci_put_one_xfer() - Release a message + * @minfo: transfer info pointer + * @xfer: message that was reserved by ti_sci_get_one_xfer + * + * This holds a spinlock to maintain integrity of internal data structures. + */ +static void ti_sci_put_one_xfer(struct ti_sci_xfers_info *minfo, + struct ti_sci_xfer *xfer) +{ + unsigned long flags; + struct ti_sci_msg_hdr *hdr; + u8 xfer_id; + + hdr = (struct ti_sci_msg_hdr *)xfer->tx_message.buf; + xfer_id = hdr->seq; + + /* + * Keep the locked section as small as possible + * NOTE: we might escape with smp_mb and no lock here.. + * but just be conservative and symmetric. + */ + spin_lock_irqsave(&minfo->xfer_lock, flags); + clear_bit(xfer_id, minfo->xfer_alloc_table); + spin_unlock_irqrestore(&minfo->xfer_lock, flags); + + /* Increment the count for the next user to get through */ + up(&minfo->sem_xfer_count); +} + +/** + * ti_sci_do_xfer() - Do one transfer + * @info: Pointer to SCI entity information + * @xfer: Transfer to initiate and wait for response + * + * Return: -ETIMEDOUT in case of no response, if transmit error, + * return corresponding error, else if all goes well, + * return 0. + */ +static inline int ti_sci_do_xfer(struct ti_sci_info *info, + struct ti_sci_xfer *xfer) +{ + int ret; + int timeout; + struct device *dev = info->dev; + + ret = mbox_send_message(info->chan_tx, &xfer->tx_message); + if (ret < 0) + return ret; + + ret = 0; + + /* And we wait for the response. */ + timeout = msecs_to_jiffies(info->desc->max_rx_timeout_ms); + if (!wait_for_completion_timeout(&xfer->done, timeout)) { + dev_err(dev, "Mbox timedout in resp(caller: %pF)\n", + (void *)_RET_IP_); + ret = -ETIMEDOUT; + } + /* + * NOTE: we might prefer not to need the mailbox ticker to manage the + * transfer queueing since the protocol layer queues things by itself. + * Unfortunately, we have to kick the mailbox framework after we have + * received our message. + */ + mbox_client_txdone(info->chan_tx, ret); + + return ret; +} + +/** + * ti_sci_cmd_get_revision() - command to get the revision of the SCI entity + * @info: Pointer to SCI entity information + * + * Updates the SCI information in the internal data structure. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_get_revision(struct ti_sci_info *info) +{ + struct device *dev = info->dev; + struct ti_sci_handle *handle = &info->handle; + struct ti_sci_version_info *ver = &handle->version; + struct ti_sci_msg_resp_version *rev_info; + struct ti_sci_xfer *xfer; + int ret; + + /* No need to setup flags since it is expected to respond */ + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_VERSION, + 0x0, sizeof(struct ti_sci_msg_hdr), + sizeof(*rev_info)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + + rev_info = (struct ti_sci_msg_resp_version *)xfer->xfer_buf; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + ver->abi_major = rev_info->abi_major; + ver->abi_minor = rev_info->abi_minor; + ver->firmware_revision = rev_info->firmware_revision; + strncpy(ver->firmware_description, rev_info->firmware_description, + sizeof(ver->firmware_description)); + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + return ret; +} + +/** + * ti_sci_get_handle() - Get the TI SCI handle for a device + * @dev: Pointer to device for which we want SCI handle + * + * NOTE: The function does not track individual clients of the framework + * and is expected to be maintained by caller of TI SCI protocol library. + * ti_sci_put_handle must be balanced with successful ti_sci_get_handle + * Return: pointer to handle if successful, else: + * -EPROBE_DEFER if the instance is not ready + * -ENODEV if the required node handler is missing + * -EINVAL if invalid conditions are encountered. + */ +const struct ti_sci_handle *ti_sci_get_handle(struct device *dev) +{ + struct device_node *ti_sci_np; + struct list_head *p; + struct ti_sci_handle *handle = NULL; + struct ti_sci_info *info; + + if (!dev) { + pr_err("I need a device pointer\n"); + return ERR_PTR(-EINVAL); + } + ti_sci_np = of_get_parent(dev->of_node); + if (!ti_sci_np) { + dev_err(dev, "No OF information\n"); + return ERR_PTR(-EINVAL); + } + + mutex_lock(&ti_sci_list_mutex); + list_for_each(p, &ti_sci_list) { + info = list_entry(p, struct ti_sci_info, node); + if (ti_sci_np == info->dev->of_node) { + handle = &info->handle; + info->users++; + break; + } + } + mutex_unlock(&ti_sci_list_mutex); + of_node_put(ti_sci_np); + + if (!handle) + return ERR_PTR(-EPROBE_DEFER); + + return handle; +} +EXPORT_SYMBOL_GPL(ti_sci_get_handle); + +/** + * ti_sci_put_handle() - Release the handle acquired by ti_sci_get_handle + * @handle: Handle acquired by ti_sci_get_handle + * + * NOTE: The function does not track individual clients of the framework + * and is expected to be maintained by caller of TI SCI protocol library. + * ti_sci_put_handle must be balanced with successful ti_sci_get_handle + * + * Return: 0 is successfully released + * if an error pointer was passed, it returns the error value back, + * if null was passed, it returns -EINVAL; + */ +int ti_sci_put_handle(const struct ti_sci_handle *handle) +{ + struct ti_sci_info *info; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + mutex_lock(&ti_sci_list_mutex); + if (!WARN_ON(!info->users)) + info->users--; + mutex_unlock(&ti_sci_list_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(ti_sci_put_handle); + +static void devm_ti_sci_release(struct device *dev, void *res) +{ + const struct ti_sci_handle **ptr = res; + const struct ti_sci_handle *handle = *ptr; + int ret; + + ret = ti_sci_put_handle(handle); + if (ret) + dev_err(dev, "failed to put handle %d\n", ret); +} + +/** + * devm_ti_sci_get_handle() - Managed get handle + * @dev: device for which we want SCI handle for. + * + * NOTE: This releases the handle once the device resources are + * no longer needed. MUST NOT BE released with ti_sci_put_handle. + * The function does not track individual clients of the framework + * and is expected to be maintained by caller of TI SCI protocol library. + * + * Return: 0 if all went fine, else corresponding error. + */ +const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev) +{ + const struct ti_sci_handle **ptr; + const struct ti_sci_handle *handle; + + ptr = devres_alloc(devm_ti_sci_release, sizeof(*ptr), GFP_KERNEL); + if (!ptr) + return ERR_PTR(-ENOMEM); + handle = ti_sci_get_handle(dev); + + if (!IS_ERR(handle)) { + *ptr = handle; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return handle; +} +EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle); + +/* Description for K2G */ +static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { + .host_id = 2, + /* Conservative duration */ + .max_rx_timeout_ms = 1000, + /* Limited by MBOX_TX_QUEUE_LEN. K2G can handle upto 128 messages! */ + .max_msgs = 20, + .max_msg_size = 64, +}; + +static const struct of_device_id ti_sci_of_match[] = { + {.compatible = "ti,k2g-sci", .data = &ti_sci_pmmc_k2g_desc}, + { /* Sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, ti_sci_of_match); + +static int ti_sci_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + const struct of_device_id *of_id; + const struct ti_sci_desc *desc; + struct ti_sci_xfer *xfer; + struct ti_sci_info *info = NULL; + struct ti_sci_xfers_info *minfo; + struct mbox_client *cl; + int ret = -EINVAL; + int i; + + of_id = of_match_device(ti_sci_of_match, dev); + if (!of_id) { + dev_err(dev, "OF data missing\n"); + return -EINVAL; + } + desc = of_id->data; + + info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->dev = dev; + info->desc = desc; + INIT_LIST_HEAD(&info->node); + minfo = &info->minfo; + + /* + * Pre-allocate messages + * NEVER allocate more than what we can indicate in hdr.seq + * if we have data description bug, force a fix.. + */ + if (WARN_ON(desc->max_msgs >= + 1 << 8 * sizeof(((struct ti_sci_msg_hdr *)0)->seq))) + return -EINVAL; + + minfo->xfer_block = devm_kcalloc(dev, + desc->max_msgs, + sizeof(*minfo->xfer_block), + GFP_KERNEL); + if (!minfo->xfer_block) + return -ENOMEM; + + minfo->xfer_alloc_table = devm_kzalloc(dev, + BITS_TO_LONGS(desc->max_msgs) + * sizeof(unsigned long), + GFP_KERNEL); + if (!minfo->xfer_alloc_table) + return -ENOMEM; + bitmap_zero(minfo->xfer_alloc_table, desc->max_msgs); + + /* Pre-initialize the buffer pointer to pre-allocated buffers */ + for (i = 0, xfer = minfo->xfer_block; i < desc->max_msgs; i++, xfer++) { + xfer->xfer_buf = devm_kcalloc(dev, 1, desc->max_msg_size, + GFP_KERNEL); + if (!xfer->xfer_buf) + return -ENOMEM; + + xfer->tx_message.buf = xfer->xfer_buf; + init_completion(&xfer->done); + } + + ret = ti_sci_debugfs_create(pdev, info); + if (ret) + dev_warn(dev, "Failed to create debug file\n"); + + platform_set_drvdata(pdev, info); + + cl = &info->cl; + cl->dev = dev; + cl->tx_block = false; + cl->rx_callback = ti_sci_rx_callback; + cl->knows_txdone = true; + + spin_lock_init(&minfo->xfer_lock); + sema_init(&minfo->sem_xfer_count, desc->max_msgs); + + info->chan_rx = mbox_request_channel_byname(cl, "rx"); + if (IS_ERR(info->chan_rx)) { + ret = PTR_ERR(info->chan_rx); + goto out; + } + + info->chan_tx = mbox_request_channel_byname(cl, "tx"); + if (IS_ERR(info->chan_tx)) { + ret = PTR_ERR(info->chan_tx); + goto out; + } + ret = ti_sci_cmd_get_revision(info); + if (ret) { + dev_err(dev, "Unable to communicate with TISCI(%d)\n", ret); + goto out; + } + + dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n", + info->handle.version.abi_major, info->handle.version.abi_minor, + info->handle.version.firmware_revision, + info->handle.version.firmware_description); + + mutex_lock(&ti_sci_list_mutex); + list_add_tail(&info->node, &ti_sci_list); + mutex_unlock(&ti_sci_list_mutex); + + return of_platform_populate(dev->of_node, NULL, NULL, dev); +out: + if (!IS_ERR(info->chan_tx)) + mbox_free_channel(info->chan_tx); + if (!IS_ERR(info->chan_rx)) + mbox_free_channel(info->chan_rx); + debugfs_remove(info->d); + return ret; +} + +static int ti_sci_remove(struct platform_device *pdev) +{ + struct ti_sci_info *info; + struct device *dev = &pdev->dev; + int ret = 0; + + of_platform_depopulate(dev); + + info = platform_get_drvdata(pdev); + + mutex_lock(&ti_sci_list_mutex); + if (info->users) + ret = -EBUSY; + else + list_del(&info->node); + mutex_unlock(&ti_sci_list_mutex); + + if (!ret) { + ti_sci_debugfs_destroy(pdev, info); + + /* Safe to free channels since no more users */ + mbox_free_channel(info->chan_tx); + mbox_free_channel(info->chan_rx); + } + + return ret; +} + +static struct platform_driver ti_sci_driver = { + .probe = ti_sci_probe, + .remove = ti_sci_remove, + .driver = { + .name = "ti-sci", + .of_match_table = of_match_ptr(ti_sci_of_match), + }, +}; +module_platform_driver(ti_sci_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("TI System Control Interface(SCI) driver"); +MODULE_AUTHOR("Nishanth Menon"); +MODULE_ALIAS("platform:ti-sci"); diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h new file mode 100644 index 000000000000..e9dc53f26e0e --- /dev/null +++ b/drivers/firmware/ti_sci.h @@ -0,0 +1,93 @@ +/* + * Texas Instruments System Control Interface (TISCI) Protocol + * + * Communication protocol with TI SCI hardware + * The system works in a message response protocol + * See: http://processors.wiki.ti.com/index.php/TISCI for details + * + * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the + * distribution. + * + * Neither the name of Texas Instruments Incorporated nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef __TI_SCI_H +#define __TI_SCI_H + +/* Generic Messages */ +#define TI_SCI_MSG_ENABLE_WDT 0x0000 +#define TI_SCI_MSG_WAKE_RESET 0x0001 +#define TI_SCI_MSG_VERSION 0x0002 +#define TI_SCI_MSG_WAKE_REASON 0x0003 +#define TI_SCI_MSG_GOODBYE 0x0004 + +/** + * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses + * @type: Type of messages: One of TI_SCI_MSG* values + * @host: Host of the message + * @seq: Message identifier indicating a transfer sequence + * @flags: Flag for the message + */ +struct ti_sci_msg_hdr { + u16 type; + u8 host; + u8 seq; +#define TI_SCI_MSG_FLAG(val) (1 << (val)) +#define TI_SCI_FLAG_REQ_GENERIC_NORESPONSE 0x0 +#define TI_SCI_FLAG_REQ_ACK_ON_RECEIVED TI_SCI_MSG_FLAG(0) +#define TI_SCI_FLAG_REQ_ACK_ON_PROCESSED TI_SCI_MSG_FLAG(1) +#define TI_SCI_FLAG_RESP_GENERIC_NACK 0x0 +#define TI_SCI_FLAG_RESP_GENERIC_ACK TI_SCI_MSG_FLAG(1) + /* Additional Flags */ + u32 flags; +} __packed; + +/** + * struct ti_sci_msg_resp_version - Response for a message + * @hdr: Generic header + * @firmware_description: String describing the firmware + * @firmware_revision: Firmware revision + * @abi_major: Major version of the ABI that firmware supports + * @abi_minor: Minor version of the ABI that firmware supports + * + * In general, ABI version changes follow the rule that minor version increments + * are backward compatible. Major revision changes in ABI may not be + * backward compatible. + * + * Response to a generic message with message type TI_SCI_MSG_VERSION + */ +struct ti_sci_msg_resp_version { + struct ti_sci_msg_hdr hdr; + char firmware_description[32]; + u16 firmware_revision; + u8 abi_major; + u8 abi_minor; +} __packed; + +#endif /* __TI_SCI_H */ diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h new file mode 100644 index 000000000000..e73483fd5327 --- /dev/null +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -0,0 +1,69 @@ +/* + * Texas Instruments System Control Interface Protocol + * + * Copyright (C) 2015-2016 Texas Instruments Incorporated - http://www.ti.com/ + * Nishanth Menon + * + * 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 "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. + */ + +#ifndef __TISCI_PROTOCOL_H +#define __TISCI_PROTOCOL_H + +/** + * struct ti_sci_version_info - version information structure + * @abi_major: Major ABI version. Change here implies risk of backward + * compatibility break. + * @abi_minor: Minor ABI version. Change here implies new feature addition, + * or compatible change in ABI. + * @firmware_revision: Firmware revision (not usually used). + * @firmware_description: Firmware description (not usually used). + */ +struct ti_sci_version_info { + u8 abi_major; + u8 abi_minor; + u16 firmware_revision; + char firmware_description[32]; +}; + +/** + * struct ti_sci_handle - Handle returned to TI SCI clients for usage. + * @version: structure containing version information + */ +struct ti_sci_handle { + struct ti_sci_version_info version; +}; + +#if IS_ENABLED(CONFIG_TI_SCI_PROTOCOL) +const struct ti_sci_handle *ti_sci_get_handle(struct device *dev); +int ti_sci_put_handle(const struct ti_sci_handle *handle); +const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev); + +#else /* CONFIG_TI_SCI_PROTOCOL */ + +static inline const struct ti_sci_handle *ti_sci_get_handle(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} + +static inline int ti_sci_put_handle(const struct ti_sci_handle *handle) +{ + return -EINVAL; +} + +static inline +const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev) +{ + return ERR_PTR(-EINVAL); +} + +#endif /* CONFIG_TI_SCI_PROTOCOL */ + +#endif /* __TISCI_PROTOCOL_H */ -- cgit v1.2.3 From 9e7d756da7a5b0cc756d1f512f3eaf261834180a Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 18 Oct 2016 18:08:35 -0500 Subject: firmware: ti_sci: Add support for Device control Texas Instrument's System Control Interface (TI-SCI) Message Protocol is used in Texas Instrument's System on Chip (SoC) such as those in keystone family K2G SoC to communicate between various compute processors with a central system controller entity. TI-SCI message protocol provides support for management of various hardware entitites within the SoC. Add support driver to allow communication with system controller entity within the SoC using the mailbox client. We introduce the fundamental device management capability support to the driver protocol as part of this change. [d-gerlach@ti.com: Contributed device reset handling] Signed-off-by: Dave Gerlach Signed-off-by: Nishanth Menon Signed-off-by: Tero Kristo --- drivers/firmware/ti_sci.c | 433 +++++++++++++++++++++++++++++++++ drivers/firmware/ti_sci.h | 98 ++++++++ include/linux/soc/ti/ti_sci_protocol.h | 91 +++++++ 3 files changed, 622 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 5e99d7c18276..c7b25ccf6f07 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -494,6 +494,437 @@ fail: return ret; } +/** + * ti_sci_is_response_ack() - Generic ACK/NACK message checkup + * @r: pointer to response buffer + * + * Return: true if the response was an ACK, else returns false. + */ +static inline bool ti_sci_is_response_ack(void *r) +{ + struct ti_sci_msg_hdr *hdr = r; + + return hdr->flags & TI_SCI_FLAG_RESP_GENERIC_ACK ? true : false; +} + +/** + * ti_sci_set_device_state() - Set device state helper + * @handle: pointer to TI SCI handle + * @id: Device identifier + * @flags: flags to setup for the device + * @state: State to move the device to + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_set_device_state(const struct ti_sci_handle *handle, + u32 id, u32 flags, u8 state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_device_state *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_DEVICE_STATE, + flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_set_device_state *)xfer->xfer_buf; + req->id = id; + req->state = state; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_get_device_state() - Get device state helper + * @handle: Handle to the device + * @id: Device Identifier + * @clcnt: Pointer to Context Loss Count + * @resets: pointer to resets + * @p_state: pointer to p_state + * @c_state: pointer to c_state + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_get_device_state(const struct ti_sci_handle *handle, + u32 id, u32 *clcnt, u32 *resets, + u8 *p_state, u8 *c_state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_get_device_state *req; + struct ti_sci_msg_resp_get_device_state *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + if (!clcnt && !resets && !p_state && !c_state) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + /* Response is expected, so need of any flags */ + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_DEVICE_STATE, + 0, sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_get_device_state *)xfer->xfer_buf; + req->id = id; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_get_device_state *)xfer->xfer_buf; + if (!ti_sci_is_response_ack(resp)) { + ret = -ENODEV; + goto fail; + } + + if (clcnt) + *clcnt = resp->context_loss_count; + if (resets) + *resets = resp->resets; + if (p_state) + *p_state = resp->programmed_state; + if (c_state) + *c_state = resp->current_state; +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_get_device() - command to request for device managed by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * + * Request for the device - NOTE: the client MUST maintain integrity of + * usage count by balancing get_device with put_device. No refcounting is + * managed by driver for that purpose. + * + * NOTE: The request is for exclusive access for the processor. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_get_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, + MSG_FLAG_DEVICE_EXCLUSIVE, + MSG_DEVICE_SW_STATE_ON); +} + +/** + * ti_sci_cmd_idle_device() - Command to idle a device managed by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * + * Request for the device - NOTE: the client MUST maintain integrity of + * usage count by balancing get_device with put_device. No refcounting is + * managed by driver for that purpose. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_idle_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, + MSG_FLAG_DEVICE_EXCLUSIVE, + MSG_DEVICE_SW_STATE_RETENTION); +} + +/** + * ti_sci_cmd_put_device() - command to release a device managed by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * + * Request for the device - NOTE: the client MUST maintain integrity of + * usage count by balancing get_device with put_device. No refcounting is + * managed by driver for that purpose. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_put_device(const struct ti_sci_handle *handle, u32 id) +{ + return ti_sci_set_device_state(handle, id, + 0, MSG_DEVICE_SW_STATE_AUTO_OFF); +} + +/** + * ti_sci_cmd_dev_is_valid() - Is the device valid + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * + * Return: 0 if all went fine and the device ID is valid, else return + * appropriate error. + */ +static int ti_sci_cmd_dev_is_valid(const struct ti_sci_handle *handle, u32 id) +{ + u8 unused; + + /* check the device state which will also tell us if the ID is valid */ + return ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &unused); +} + +/** + * ti_sci_cmd_dev_get_clcnt() - Get context loss counter + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @count: Pointer to Context Loss counter to populate + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_get_clcnt(const struct ti_sci_handle *handle, u32 id, + u32 *count) +{ + return ti_sci_get_device_state(handle, id, count, NULL, NULL, NULL); +} + +/** + * ti_sci_cmd_dev_is_idle() - Check if the device is requested to be idle + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @r_state: true if requested to be idle + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_idle(const struct ti_sci_handle *handle, u32 id, + bool *r_state) +{ + int ret; + u8 state; + + if (!r_state) + return -EINVAL; + + ret = ti_sci_get_device_state(handle, id, NULL, NULL, &state, NULL); + if (ret) + return ret; + + *r_state = (state == MSG_DEVICE_SW_STATE_RETENTION); + + return 0; +} + +/** + * ti_sci_cmd_dev_is_stop() - Check if the device is requested to be stopped + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @r_state: true if requested to be stopped + * @curr_state: true if currently stopped. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_stop(const struct ti_sci_handle *handle, u32 id, + bool *r_state, bool *curr_state) +{ + int ret; + u8 p_state, c_state; + + if (!r_state && !curr_state) + return -EINVAL; + + ret = + ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state); + if (ret) + return ret; + + if (r_state) + *r_state = (p_state == MSG_DEVICE_SW_STATE_AUTO_OFF); + if (curr_state) + *curr_state = (c_state == MSG_DEVICE_HW_STATE_OFF); + + return 0; +} + +/** + * ti_sci_cmd_dev_is_on() - Check if the device is requested to be ON + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @r_state: true if requested to be ON + * @curr_state: true if currently ON and active + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_on(const struct ti_sci_handle *handle, u32 id, + bool *r_state, bool *curr_state) +{ + int ret; + u8 p_state, c_state; + + if (!r_state && !curr_state) + return -EINVAL; + + ret = + ti_sci_get_device_state(handle, id, NULL, NULL, &p_state, &c_state); + if (ret) + return ret; + + if (r_state) + *r_state = (p_state == MSG_DEVICE_SW_STATE_ON); + if (curr_state) + *curr_state = (c_state == MSG_DEVICE_HW_STATE_ON); + + return 0; +} + +/** + * ti_sci_cmd_dev_is_trans() - Check if the device is currently transitioning + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @curr_state: true if currently transitioning. + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_dev_is_trans(const struct ti_sci_handle *handle, u32 id, + bool *curr_state) +{ + int ret; + u8 state; + + if (!curr_state) + return -EINVAL; + + ret = ti_sci_get_device_state(handle, id, NULL, NULL, NULL, &state); + if (ret) + return ret; + + *curr_state = (state == MSG_DEVICE_HW_STATE_TRANS); + + return 0; +} + +/** + * ti_sci_cmd_set_device_resets() - command to set resets for device managed + * by TISCI + * @handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * @id: Device Identifier + * @reset_state: Device specific reset bit field + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_set_device_resets(const struct ti_sci_handle *handle, + u32 id, u32 reset_state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_device_resets *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_DEVICE_RESETS, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_set_device_resets *)xfer->xfer_buf; + req->id = id; + req->resets = reset_state; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_get_device_resets() - Get reset state for device managed + * by TISCI + * @handle: Pointer to TISCI handle + * @id: Device Identifier + * @reset_state: Pointer to reset state to populate + * + * Return: 0 if all went fine, else return appropriate error. + */ +static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle, + u32 id, u32 *reset_state) +{ + return ti_sci_get_device_state(handle, id, NULL, reset_state, NULL, + NULL); +} + +/* + * ti_sci_setup_ops() - Setup the operations structures + * @info: pointer to TISCI pointer + */ +static void ti_sci_setup_ops(struct ti_sci_info *info) +{ + struct ti_sci_ops *ops = &info->handle.ops; + struct ti_sci_dev_ops *dops = &ops->dev_ops; + + dops->get_device = ti_sci_cmd_get_device; + dops->idle_device = ti_sci_cmd_idle_device; + dops->put_device = ti_sci_cmd_put_device; + + dops->is_valid = ti_sci_cmd_dev_is_valid; + dops->get_context_loss_count = ti_sci_cmd_dev_get_clcnt; + dops->is_idle = ti_sci_cmd_dev_is_idle; + dops->is_stop = ti_sci_cmd_dev_is_stop; + dops->is_on = ti_sci_cmd_dev_is_on; + dops->is_transitioning = ti_sci_cmd_dev_is_trans; + dops->set_device_resets = ti_sci_cmd_set_device_resets; + dops->get_device_resets = ti_sci_cmd_get_device_resets; +} + /** * ti_sci_get_handle() - Get the TI SCI handle for a device * @dev: Pointer to device for which we want SCI handle @@ -727,6 +1158,8 @@ static int ti_sci_probe(struct platform_device *pdev) goto out; } + ti_sci_setup_ops(info); + dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n", info->handle.version.abi_major, info->handle.version.abi_minor, info->handle.version.firmware_revision, diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index e9dc53f26e0e..29ce0532a7ca 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -47,6 +47,11 @@ #define TI_SCI_MSG_WAKE_REASON 0x0003 #define TI_SCI_MSG_GOODBYE 0x0004 +/* Device requests */ +#define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 +#define TI_SCI_MSG_GET_DEVICE_STATE 0x0201 +#define TI_SCI_MSG_SET_DEVICE_RESETS 0x0202 + /** * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses * @type: Type of messages: One of TI_SCI_MSG* values @@ -90,4 +95,97 @@ struct ti_sci_msg_resp_version { u8 abi_minor; } __packed; +/** + * struct ti_sci_msg_req_set_device_state - Set the desired state of the device + * @hdr: Generic header + * @id: Indicates which device to modify + * @reserved: Reserved space in message, must be 0 for backward compatibility + * @state: The desired state of the device. + * + * Certain flags can also be set to alter the device state: + * + MSG_FLAG_DEVICE_WAKE_ENABLED - Configure the device to be a wake source. + * The meaning of this flag will vary slightly from device to device and from + * SoC to SoC but it generally allows the device to wake the SoC out of deep + * suspend states. + * + MSG_FLAG_DEVICE_RESET_ISO - Enable reset isolation for this device. + * + MSG_FLAG_DEVICE_EXCLUSIVE - Claim this device exclusively. When passed + * with STATE_RETENTION or STATE_ON, it will claim the device exclusively. + * If another host already has this device set to STATE_RETENTION or STATE_ON, + * the message will fail. Once successful, other hosts attempting to set + * STATE_RETENTION or STATE_ON will fail. + * + * Request type is TI_SCI_MSG_SET_DEVICE_STATE, responded with a generic + * ACK/NACK message. + */ +struct ti_sci_msg_req_set_device_state { + /* Additional hdr->flags options */ +#define MSG_FLAG_DEVICE_WAKE_ENABLED TI_SCI_MSG_FLAG(8) +#define MSG_FLAG_DEVICE_RESET_ISO TI_SCI_MSG_FLAG(9) +#define MSG_FLAG_DEVICE_EXCLUSIVE TI_SCI_MSG_FLAG(10) + struct ti_sci_msg_hdr hdr; + u32 id; + u32 reserved; + +#define MSG_DEVICE_SW_STATE_AUTO_OFF 0 +#define MSG_DEVICE_SW_STATE_RETENTION 1 +#define MSG_DEVICE_SW_STATE_ON 2 + u8 state; +} __packed; + +/** + * struct ti_sci_msg_req_get_device_state - Request to get device. + * @hdr: Generic header + * @id: Device Identifier + * + * Request type is TI_SCI_MSG_GET_DEVICE_STATE, responded device state + * information + */ +struct ti_sci_msg_req_get_device_state { + struct ti_sci_msg_hdr hdr; + u32 id; +} __packed; + +/** + * struct ti_sci_msg_resp_get_device_state - Response to get device request. + * @hdr: Generic header + * @context_loss_count: Indicates how many times the device has lost context. A + * driver can use this monotonic counter to determine if the device has + * lost context since the last time this message was exchanged. + * @resets: Programmed state of the reset lines. + * @programmed_state: The state as programmed by set_device. + * - Uses the MSG_DEVICE_SW_* macros + * @current_state: The actual state of the hardware. + * + * Response to request TI_SCI_MSG_GET_DEVICE_STATE. + */ +struct ti_sci_msg_resp_get_device_state { + struct ti_sci_msg_hdr hdr; + u32 context_loss_count; + u32 resets; + u8 programmed_state; +#define MSG_DEVICE_HW_STATE_OFF 0 +#define MSG_DEVICE_HW_STATE_ON 1 +#define MSG_DEVICE_HW_STATE_TRANS 2 + u8 current_state; +} __packed; + +/** + * struct ti_sci_msg_req_set_device_resets - Set the desired resets + * configuration of the device + * @hdr: Generic header + * @id: Indicates which device to modify + * @resets: A bit field of resets for the device. The meaning, behavior, + * and usage of the reset flags are device specific. 0 for a bit + * indicates releasing the reset represented by that bit while 1 + * indicates keeping it held. + * + * Request type is TI_SCI_MSG_SET_DEVICE_RESETS, responded with a generic + * ACK/NACK message. + */ +struct ti_sci_msg_req_set_device_resets { + struct ti_sci_msg_hdr hdr; + u32 id; + u32 resets; +} __packed; + #endif /* __TI_SCI_H */ diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h index e73483fd5327..87fa73851471 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -33,12 +33,103 @@ struct ti_sci_version_info { char firmware_description[32]; }; +struct ti_sci_handle; + +/** + * struct ti_sci_dev_ops - Device control operations + * @get_device: Command to request for device managed by TISCI + * Returns 0 for successful exclusive request, else returns + * corresponding error message. + * @idle_device: Command to idle a device managed by TISCI + * Returns 0 for successful exclusive request, else returns + * corresponding error message. + * @put_device: Command to release a device managed by TISCI + * Returns 0 for successful release, else returns corresponding + * error message. + * @is_valid: Check if the device ID is a valid ID. + * Returns 0 if the ID is valid, else returns corresponding error. + * @get_context_loss_count: Command to retrieve context loss counter - this + * increments every time the device looses context. Overflow + * is possible. + * - count: pointer to u32 which will retrieve counter + * Returns 0 for successful information request and count has + * proper data, else returns corresponding error message. + * @is_idle: Reports back about device idle state + * - req_state: Returns requested idle state + * Returns 0 for successful information request and req_state and + * current_state has proper data, else returns corresponding error + * message. + * @is_stop: Reports back about device stop state + * - req_state: Returns requested stop state + * - current_state: Returns current stop state + * Returns 0 for successful information request and req_state and + * current_state has proper data, else returns corresponding error + * message. + * @is_on: Reports back about device ON(or active) state + * - req_state: Returns requested ON state + * - current_state: Returns current ON state + * Returns 0 for successful information request and req_state and + * current_state has proper data, else returns corresponding error + * message. + * @is_transitioning: Reports back if the device is in the middle of transition + * of state. + * -current_state: Returns 'true' if currently transitioning. + * @set_device_resets: Command to configure resets for device managed by TISCI. + * -reset_state: Device specific reset bit field + * Returns 0 for successful request, else returns + * corresponding error message. + * @get_device_resets: Command to read state of resets for device managed + * by TISCI. + * -reset_state: pointer to u32 which will retrieve resets + * Returns 0 for successful request, else returns + * corresponding error message. + * + * NOTE: for all these functions, the following parameters are generic in + * nature: + * -handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * -id: Device Identifier + * + * Request for the device - NOTE: the client MUST maintain integrity of + * usage count by balancing get_device with put_device. No refcounting is + * managed by driver for that purpose. + */ +struct ti_sci_dev_ops { + int (*get_device)(const struct ti_sci_handle *handle, u32 id); + int (*idle_device)(const struct ti_sci_handle *handle, u32 id); + int (*put_device)(const struct ti_sci_handle *handle, u32 id); + int (*is_valid)(const struct ti_sci_handle *handle, u32 id); + int (*get_context_loss_count)(const struct ti_sci_handle *handle, + u32 id, u32 *count); + int (*is_idle)(const struct ti_sci_handle *handle, u32 id, + bool *requested_state); + int (*is_stop)(const struct ti_sci_handle *handle, u32 id, + bool *req_state, bool *current_state); + int (*is_on)(const struct ti_sci_handle *handle, u32 id, + bool *req_state, bool *current_state); + int (*is_transitioning)(const struct ti_sci_handle *handle, u32 id, + bool *current_state); + int (*set_device_resets)(const struct ti_sci_handle *handle, u32 id, + u32 reset_state); + int (*get_device_resets)(const struct ti_sci_handle *handle, u32 id, + u32 *reset_state); +}; + +/** + * struct ti_sci_ops - Function support for TI SCI + * @dev_ops: Device specific operations + */ +struct ti_sci_ops { + struct ti_sci_dev_ops dev_ops; +}; + /** * struct ti_sci_handle - Handle returned to TI SCI clients for usage. * @version: structure containing version information + * @ops: operations that are made available to TI SCI clients */ struct ti_sci_handle { struct ti_sci_version_info version; + struct ti_sci_ops ops; }; #if IS_ENABLED(CONFIG_TI_SCI_PROTOCOL) -- cgit v1.2.3 From 9f72322050e4762adde66619f048b7317ad12d77 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 18 Oct 2016 18:08:36 -0500 Subject: firmware: ti_sci: Add support for Clock control Texas Instrument's System Control Interface (TI-SCI) Message Protocol is used in Texas Instrument's System on Chip (SoC) such as those in keystone family K2G SoC to communicate between various compute processors with a central system controller entity. TI-SCI message protocol provides support for management of various hardware entities within the SoC. Add support driver to allow communication with system controller entity within the SoC using the mailbox client. In general, we expect to function at a device level of abstraction, however, for proper operation of hardware blocks, many clocks directly supplying the hardware block needs to be queried or configured. Introduce support for the set of SCI message protocol support that provide us with this capability. Signed-off-by: Nishanth Menon Signed-off-by: Tero Kristo --- drivers/firmware/ti_sci.c | 685 +++++++++++++++++++++++++++++++++ drivers/firmware/ti_sci.h | 289 ++++++++++++++ include/linux/soc/ti/ti_sci_protocol.h | 78 ++++ 3 files changed, 1052 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index c7b25ccf6f07..496a007e5c69 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -902,6 +902,675 @@ static int ti_sci_cmd_get_device_resets(const struct ti_sci_handle *handle, NULL); } +/** + * ti_sci_set_clock_state() - Set clock state helper + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @flags: Header flags as needed + * @state: State to request for the clock. + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_set_clock_state(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, + u32 flags, u8 state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_clock_state *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_STATE, + flags | TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_set_clock_state *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + req->request_state = state; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_get_clock_state() - Get clock state helper + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @programmed_state: State requested for clock to move to + * @current_state: State that the clock is currently in + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_get_clock_state(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, + u8 *programmed_state, u8 *current_state) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_get_clock_state *req; + struct ti_sci_msg_resp_get_clock_state *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + if (!programmed_state && !current_state) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_STATE, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_get_clock_state *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_get_clock_state *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) { + ret = -ENODEV; + goto fail; + } + + if (programmed_state) + *programmed_state = resp->programmed_state; + if (current_state) + *current_state = resp->current_state; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_get_clock() - Get control of a clock from TI SCI + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @needs_ssc: 'true' if Spread Spectrum clock is desired, else 'false' + * @can_change_freq: 'true' if frequency change is desired, else 'false' + * @enable_input_term: 'true' if input termination is desired, else 'false' + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id, + u8 clk_id, bool needs_ssc, bool can_change_freq, + bool enable_input_term) +{ + u32 flags = 0; + + flags |= needs_ssc ? MSG_FLAG_CLOCK_ALLOW_SSC : 0; + flags |= can_change_freq ? MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE : 0; + flags |= enable_input_term ? MSG_FLAG_CLOCK_INPUT_TERM : 0; + + return ti_sci_set_clock_state(handle, dev_id, clk_id, flags, + MSG_CLOCK_SW_STATE_REQ); +} + +/** + * ti_sci_cmd_idle_clock() - Idle a clock which is in our control + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * + * NOTE: This clock must have been requested by get_clock previously. + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id) +{ + return ti_sci_set_clock_state(handle, dev_id, clk_id, 0, + MSG_CLOCK_SW_STATE_UNREQ); +} + +/** + * ti_sci_cmd_put_clock() - Release a clock from our control back to TISCI + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * + * NOTE: This clock must have been requested by get_clock previously. + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id) +{ + return ti_sci_set_clock_state(handle, dev_id, clk_id, 0, + MSG_CLOCK_SW_STATE_AUTO); +} + +/** + * ti_sci_cmd_clk_is_auto() - Is the clock being auto managed + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @req_state: state indicating if the clock is auto managed + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_is_auto(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, bool *req_state) +{ + u8 state = 0; + int ret; + + if (!req_state) + return -EINVAL; + + ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id, &state, NULL); + if (ret) + return ret; + + *req_state = (state == MSG_CLOCK_SW_STATE_AUTO); + return 0; +} + +/** + * ti_sci_cmd_clk_is_on() - Is the clock ON + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @req_state: state indicating if the clock is managed by us and enabled + * @curr_state: state indicating if the clock is ready for operation + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_is_on(const struct ti_sci_handle *handle, u32 dev_id, + u8 clk_id, bool *req_state, bool *curr_state) +{ + u8 c_state = 0, r_state = 0; + int ret; + + if (!req_state && !curr_state) + return -EINVAL; + + ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id, + &r_state, &c_state); + if (ret) + return ret; + + if (req_state) + *req_state = (r_state == MSG_CLOCK_SW_STATE_REQ); + if (curr_state) + *curr_state = (c_state == MSG_CLOCK_HW_STATE_READY); + return 0; +} + +/** + * ti_sci_cmd_clk_is_off() - Is the clock OFF + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @req_state: state indicating if the clock is managed by us and disabled + * @curr_state: state indicating if the clock is NOT ready for operation + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_is_off(const struct ti_sci_handle *handle, u32 dev_id, + u8 clk_id, bool *req_state, bool *curr_state) +{ + u8 c_state = 0, r_state = 0; + int ret; + + if (!req_state && !curr_state) + return -EINVAL; + + ret = ti_sci_cmd_get_clock_state(handle, dev_id, clk_id, + &r_state, &c_state); + if (ret) + return ret; + + if (req_state) + *req_state = (r_state == MSG_CLOCK_SW_STATE_UNREQ); + if (curr_state) + *curr_state = (c_state == MSG_CLOCK_HW_STATE_NOT_READY); + return 0; +} + +/** + * ti_sci_cmd_clk_set_parent() - Set the clock source of a specific device clock + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @parent_id: Parent clock identifier to set + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_set_parent(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, u8 parent_id) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_clock_parent *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_PARENT, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_set_clock_parent *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + req->parent_id = parent_id; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_clk_get_parent() - Get current parent clock source + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @parent_id: Current clock parent + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, u8 *parent_id) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_get_clock_parent *req; + struct ti_sci_msg_resp_get_clock_parent *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle || !parent_id) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_PARENT, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_get_clock_parent *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) + ret = -ENODEV; + else + *parent_id = resp->parent_id; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_clk_get_num_parents() - Get num parents of the current clk source + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @num_parents: Returns he number of parents to the current clock. + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_get_num_parents(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, + u8 *num_parents) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_get_clock_num_parents *req; + struct ti_sci_msg_resp_get_clock_num_parents *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle || !num_parents) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_get_clock_num_parents *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_get_clock_num_parents *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) + ret = -ENODEV; + else + *num_parents = resp->num_parents; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_clk_get_match_freq() - Find a good match for frequency + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @min_freq: The minimum allowable frequency in Hz. This is the minimum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * @target_freq: The target clock frequency in Hz. A frequency will be + * processed as close to this target frequency as possible. + * @max_freq: The maximum allowable frequency in Hz. This is the maximum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * @match_freq: Frequency match in Hz response. + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_get_match_freq(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, u64 min_freq, + u64 target_freq, u64 max_freq, + u64 *match_freq) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_query_clock_freq *req; + struct ti_sci_msg_resp_query_clock_freq *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle || !match_freq) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_QUERY_CLOCK_FREQ, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_query_clock_freq *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + req->min_freq_hz = min_freq; + req->target_freq_hz = target_freq; + req->max_freq_hz = max_freq; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_query_clock_freq *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) + ret = -ENODEV; + else + *match_freq = resp->freq_hz; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_clk_set_freq() - Set a frequency for clock + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @min_freq: The minimum allowable frequency in Hz. This is the minimum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * @target_freq: The target clock frequency in Hz. A frequency will be + * processed as close to this target frequency as possible. + * @max_freq: The maximum allowable frequency in Hz. This is the maximum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_set_freq(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, u64 min_freq, + u64 target_freq, u64 max_freq) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_set_clock_freq *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SET_CLOCK_FREQ, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_set_clock_freq *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + req->min_freq_hz = min_freq; + req->target_freq_hz = target_freq; + req->max_freq_hz = max_freq; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + ret = ti_sci_is_response_ack(resp) ? 0 : -ENODEV; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + +/** + * ti_sci_cmd_clk_get_freq() - Get current frequency + * @handle: pointer to TI SCI handle + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @freq: Currently frequency in Hz + * + * Return: 0 if all went well, else returns appropriate error value. + */ +static int ti_sci_cmd_clk_get_freq(const struct ti_sci_handle *handle, + u32 dev_id, u8 clk_id, u64 *freq) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_get_clock_freq *req; + struct ti_sci_msg_resp_get_clock_freq *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle || !freq) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_GET_CLOCK_FREQ, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_get_clock_freq *)xfer->xfer_buf; + req->dev_id = dev_id; + req->clk_id = clk_id; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_resp_get_clock_freq *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) + ret = -ENODEV; + else + *freq = resp->freq_hz; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + /* * ti_sci_setup_ops() - Setup the operations structures * @info: pointer to TISCI pointer @@ -910,6 +1579,7 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) { struct ti_sci_ops *ops = &info->handle.ops; struct ti_sci_dev_ops *dops = &ops->dev_ops; + struct ti_sci_clk_ops *cops = &ops->clk_ops; dops->get_device = ti_sci_cmd_get_device; dops->idle_device = ti_sci_cmd_idle_device; @@ -923,6 +1593,21 @@ static void ti_sci_setup_ops(struct ti_sci_info *info) dops->is_transitioning = ti_sci_cmd_dev_is_trans; dops->set_device_resets = ti_sci_cmd_set_device_resets; dops->get_device_resets = ti_sci_cmd_get_device_resets; + + cops->get_clock = ti_sci_cmd_get_clock; + cops->idle_clock = ti_sci_cmd_idle_clock; + cops->put_clock = ti_sci_cmd_put_clock; + cops->is_auto = ti_sci_cmd_clk_is_auto; + cops->is_on = ti_sci_cmd_clk_is_on; + cops->is_off = ti_sci_cmd_clk_is_off; + + cops->set_parent = ti_sci_cmd_clk_set_parent; + cops->get_parent = ti_sci_cmd_clk_get_parent; + cops->get_num_parents = ti_sci_cmd_clk_get_num_parents; + + cops->get_best_match_freq = ti_sci_cmd_clk_get_match_freq; + cops->set_freq = ti_sci_cmd_clk_set_freq; + cops->get_freq = ti_sci_cmd_clk_get_freq; } /** diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index 29ce0532a7ca..f69907cfc128 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -52,6 +52,16 @@ #define TI_SCI_MSG_GET_DEVICE_STATE 0x0201 #define TI_SCI_MSG_SET_DEVICE_RESETS 0x0202 +/* Clock requests */ +#define TI_SCI_MSG_SET_CLOCK_STATE 0x0100 +#define TI_SCI_MSG_GET_CLOCK_STATE 0x0101 +#define TI_SCI_MSG_SET_CLOCK_PARENT 0x0102 +#define TI_SCI_MSG_GET_CLOCK_PARENT 0x0103 +#define TI_SCI_MSG_GET_NUM_CLOCK_PARENTS 0x0104 +#define TI_SCI_MSG_SET_CLOCK_FREQ 0x010c +#define TI_SCI_MSG_QUERY_CLOCK_FREQ 0x010d +#define TI_SCI_MSG_GET_CLOCK_FREQ 0x010e + /** * struct ti_sci_msg_hdr - Generic Message Header for All messages and responses * @type: Type of messages: One of TI_SCI_MSG* values @@ -188,4 +198,283 @@ struct ti_sci_msg_req_set_device_resets { u32 resets; } __packed; +/** + * struct ti_sci_msg_req_set_clock_state - Request to setup a Clock state + * @hdr: Generic Header, Certain flags can be set specific to the clocks: + * MSG_FLAG_CLOCK_ALLOW_SSC: Allow this clock to be modified + * via spread spectrum clocking. + * MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE: Allow this clock's + * frequency to be changed while it is running so long as it + * is within the min/max limits. + * MSG_FLAG_CLOCK_INPUT_TERM: Enable input termination, this + * is only applicable to clock inputs on the SoC pseudo-device. + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @request_state: Request the state for the clock to be set to. + * MSG_CLOCK_SW_STATE_UNREQ: The IP does not require this clock, + * it can be disabled, regardless of the state of the device + * MSG_CLOCK_SW_STATE_AUTO: Allow the System Controller to + * automatically manage the state of this clock. If the device + * is enabled, then the clock is enabled. If the device is set + * to off or retention, then the clock is internally set as not + * being required by the device.(default) + * MSG_CLOCK_SW_STATE_REQ: Configure the clock to be enabled, + * regardless of the state of the device. + * + * Normally, all required clocks are managed by TISCI entity, this is used + * only for specific control *IF* required. Auto managed state is + * MSG_CLOCK_SW_STATE_AUTO, in other states, TISCI entity assume remote + * will explicitly control. + * + * Request type is TI_SCI_MSG_SET_CLOCK_STATE, response is a generic + * ACK or NACK message. + */ +struct ti_sci_msg_req_set_clock_state { + /* Additional hdr->flags options */ +#define MSG_FLAG_CLOCK_ALLOW_SSC TI_SCI_MSG_FLAG(8) +#define MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE TI_SCI_MSG_FLAG(9) +#define MSG_FLAG_CLOCK_INPUT_TERM TI_SCI_MSG_FLAG(10) + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u8 clk_id; +#define MSG_CLOCK_SW_STATE_UNREQ 0 +#define MSG_CLOCK_SW_STATE_AUTO 1 +#define MSG_CLOCK_SW_STATE_REQ 2 + u8 request_state; +} __packed; + +/** + * struct ti_sci_msg_req_get_clock_state - Request for clock state + * @hdr: Generic Header + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to get state of. + * + * Request type is TI_SCI_MSG_GET_CLOCK_STATE, response is state + * of the clock + */ +struct ti_sci_msg_req_get_clock_state { + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u8 clk_id; +} __packed; + +/** + * struct ti_sci_msg_resp_get_clock_state - Response to get clock state + * @hdr: Generic Header + * @programmed_state: Any programmed state of the clock. This is one of + * MSG_CLOCK_SW_STATE* values. + * @current_state: Current state of the clock. This is one of: + * MSG_CLOCK_HW_STATE_NOT_READY: Clock is not ready + * MSG_CLOCK_HW_STATE_READY: Clock is ready + * + * Response to TI_SCI_MSG_GET_CLOCK_STATE. + */ +struct ti_sci_msg_resp_get_clock_state { + struct ti_sci_msg_hdr hdr; + u8 programmed_state; +#define MSG_CLOCK_HW_STATE_NOT_READY 0 +#define MSG_CLOCK_HW_STATE_READY 1 + u8 current_state; +} __packed; + +/** + * struct ti_sci_msg_req_set_clock_parent - Set the clock parent + * @hdr: Generic Header + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * @parent_id: The new clock parent is selectable by an index via this + * parameter. + * + * Request type is TI_SCI_MSG_SET_CLOCK_PARENT, response is generic + * ACK / NACK message. + */ +struct ti_sci_msg_req_set_clock_parent { + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u8 clk_id; + u8 parent_id; +} __packed; + +/** + * struct ti_sci_msg_req_get_clock_parent - Get the clock parent + * @hdr: Generic Header + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to get the parent for. + * + * Request type is TI_SCI_MSG_GET_CLOCK_PARENT, response is parent information + */ +struct ti_sci_msg_req_get_clock_parent { + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u8 clk_id; +} __packed; + +/** + * struct ti_sci_msg_resp_get_clock_parent - Response with clock parent + * @hdr: Generic Header + * @parent_id: The current clock parent + * + * Response to TI_SCI_MSG_GET_CLOCK_PARENT. + */ +struct ti_sci_msg_resp_get_clock_parent { + struct ti_sci_msg_hdr hdr; + u8 parent_id; +} __packed; + +/** + * struct ti_sci_msg_req_get_clock_num_parents - Request to get clock parents + * @hdr: Generic header + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * + * This request provides information about how many clock parent options + * are available for a given clock to a device. This is typically used + * for input clocks. + * + * Request type is TI_SCI_MSG_GET_NUM_CLOCK_PARENTS, response is appropriate + * message, or NACK in case of inability to satisfy request. + */ +struct ti_sci_msg_req_get_clock_num_parents { + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u8 clk_id; +} __packed; + +/** + * struct ti_sci_msg_resp_get_clock_num_parents - Response for get clk parents + * @hdr: Generic header + * @num_parents: Number of clock parents + * + * Response to TI_SCI_MSG_GET_NUM_CLOCK_PARENTS + */ +struct ti_sci_msg_resp_get_clock_num_parents { + struct ti_sci_msg_hdr hdr; + u8 num_parents; +} __packed; + +/** + * struct ti_sci_msg_req_query_clock_freq - Request to query a frequency + * @hdr: Generic Header + * @dev_id: Device identifier this request is for + * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * @target_freq_hz: The target clock frequency. A frequency will be found + * as close to this target frequency as possible. + * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * @clk_id: Clock identifier for the device for this request. + * + * NOTE: Normally clock frequency management is automatically done by TISCI + * entity. In case of specific requests, TISCI evaluates capability to achieve + * requested frequency within provided range and responds with + * result message. + * + * Request type is TI_SCI_MSG_QUERY_CLOCK_FREQ, response is appropriate message, + * or NACK in case of inability to satisfy request. + */ +struct ti_sci_msg_req_query_clock_freq { + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u64 min_freq_hz; + u64 target_freq_hz; + u64 max_freq_hz; + u8 clk_id; +} __packed; + +/** + * struct ti_sci_msg_resp_query_clock_freq - Response to a clock frequency query + * @hdr: Generic Header + * @freq_hz: Frequency that is the best match in Hz. + * + * Response to request type TI_SCI_MSG_QUERY_CLOCK_FREQ. NOTE: if the request + * cannot be satisfied, the message will be of type NACK. + */ +struct ti_sci_msg_resp_query_clock_freq { + struct ti_sci_msg_hdr hdr; + u64 freq_hz; +} __packed; + +/** + * struct ti_sci_msg_req_set_clock_freq - Request to setup a clock frequency + * @hdr: Generic Header + * @dev_id: Device identifier this request is for + * @min_freq_hz: The minimum allowable frequency in Hz. This is the minimum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * @target_freq_hz: The target clock frequency. The clock will be programmed + * at a rate as close to this target frequency as possible. + * @max_freq_hz: The maximum allowable frequency in Hz. This is the maximum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * @clk_id: Clock identifier for the device for this request. + * + * NOTE: Normally clock frequency management is automatically done by TISCI + * entity. In case of specific requests, TISCI evaluates capability to achieve + * requested range and responds with success/failure message. + * + * This sets the desired frequency for a clock within an allowable + * range. This message will fail on an enabled clock unless + * MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE is set for the clock. Additionally, + * if other clocks have their frequency modified due to this message, + * they also must have the MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE or be disabled. + * + * Calling set frequency on a clock input to the SoC pseudo-device will + * inform the PMMC of that clock's frequency. Setting a frequency of + * zero will indicate the clock is disabled. + * + * Calling set frequency on clock outputs from the SoC pseudo-device will + * function similarly to setting the clock frequency on a device. + * + * Request type is TI_SCI_MSG_SET_CLOCK_FREQ, response is a generic ACK/NACK + * message. + */ +struct ti_sci_msg_req_set_clock_freq { + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u64 min_freq_hz; + u64 target_freq_hz; + u64 max_freq_hz; + u8 clk_id; +} __packed; + +/** + * struct ti_sci_msg_req_get_clock_freq - Request to get the clock frequency + * @hdr: Generic Header + * @dev_id: Device identifier this request is for + * @clk_id: Clock identifier for the device for this request. + * + * NOTE: Normally clock frequency management is automatically done by TISCI + * entity. In some cases, clock frequencies are configured by host. + * + * Request type is TI_SCI_MSG_GET_CLOCK_FREQ, responded with clock frequency + * that the clock is currently at. + */ +struct ti_sci_msg_req_get_clock_freq { + struct ti_sci_msg_hdr hdr; + u32 dev_id; + u8 clk_id; +} __packed; + +/** + * struct ti_sci_msg_resp_get_clock_freq - Response of clock frequency request + * @hdr: Generic Header + * @freq_hz: Frequency that the clock is currently on, in Hz. + * + * Response to request type TI_SCI_MSG_GET_CLOCK_FREQ. + */ +struct ti_sci_msg_resp_get_clock_freq { + struct ti_sci_msg_hdr hdr; + u64 freq_hz; +} __packed; + #endif /* __TI_SCI_H */ diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h index 87fa73851471..76378fddf609 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -114,12 +114,90 @@ struct ti_sci_dev_ops { u32 *reset_state); }; +/** + * struct ti_sci_clk_ops - Clock control operations + * @get_clock: Request for activation of clock and manage by processor + * - needs_ssc: 'true' if Spread Spectrum clock is desired. + * - can_change_freq: 'true' if frequency change is desired. + * - enable_input_term: 'true' if input termination is desired. + * @idle_clock: Request for Idling a clock managed by processor + * @put_clock: Release the clock to be auto managed by TISCI + * @is_auto: Is the clock being auto managed + * - req_state: state indicating if the clock is auto managed + * @is_on: Is the clock ON + * - req_state: if the clock is requested to be forced ON + * - current_state: if the clock is currently ON + * @is_off: Is the clock OFF + * - req_state: if the clock is requested to be forced OFF + * - current_state: if the clock is currently Gated + * @set_parent: Set the clock source of a specific device clock + * - parent_id: Parent clock identifier to set. + * @get_parent: Get the current clock source of a specific device clock + * - parent_id: Parent clock identifier which is the parent. + * @get_num_parents: Get the number of parents of the current clock source + * - num_parents: returns the number of parent clocks. + * @get_best_match_freq: Find a best matching frequency for a frequency + * range. + * - match_freq: Best matching frequency in Hz. + * @set_freq: Set the Clock frequency + * @get_freq: Get the Clock frequency + * - current_freq: Frequency in Hz that the clock is at. + * + * NOTE: for all these functions, the following parameters are generic in + * nature: + * -handle: Pointer to TISCI handle as retrieved by *ti_sci_get_handle + * -did: Device identifier this request is for + * -cid: Clock identifier for the device for this request. + * Each device has it's own set of clock inputs. This indexes + * which clock input to modify. + * -min_freq: The minimum allowable frequency in Hz. This is the minimum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * -target_freq: The target clock frequency in Hz. A frequency will be + * processed as close to this target frequency as possible. + * -max_freq: The maximum allowable frequency in Hz. This is the maximum + * allowable programmed frequency and does not account for clock + * tolerances and jitter. + * + * Request for the clock - NOTE: the client MUST maintain integrity of + * usage count by balancing get_clock with put_clock. No refcounting is + * managed by driver for that purpose. + */ +struct ti_sci_clk_ops { + int (*get_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid, + bool needs_ssc, bool can_change_freq, + bool enable_input_term); + int (*idle_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid); + int (*put_clock)(const struct ti_sci_handle *handle, u32 did, u8 cid); + int (*is_auto)(const struct ti_sci_handle *handle, u32 did, u8 cid, + bool *req_state); + int (*is_on)(const struct ti_sci_handle *handle, u32 did, u8 cid, + bool *req_state, bool *current_state); + int (*is_off)(const struct ti_sci_handle *handle, u32 did, u8 cid, + bool *req_state, bool *current_state); + int (*set_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid, + u8 parent_id); + int (*get_parent)(const struct ti_sci_handle *handle, u32 did, u8 cid, + u8 *parent_id); + int (*get_num_parents)(const struct ti_sci_handle *handle, u32 did, + u8 cid, u8 *num_parents); + int (*get_best_match_freq)(const struct ti_sci_handle *handle, u32 did, + u8 cid, u64 min_freq, u64 target_freq, + u64 max_freq, u64 *match_freq); + int (*set_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid, + u64 min_freq, u64 target_freq, u64 max_freq); + int (*get_freq)(const struct ti_sci_handle *handle, u32 did, u8 cid, + u64 *current_freq); +}; + /** * struct ti_sci_ops - Function support for TI SCI * @dev_ops: Device specific operations + * @clk_ops: Clock specific operations */ struct ti_sci_ops { struct ti_sci_dev_ops dev_ops; + struct ti_sci_clk_ops clk_ops; }; /** -- cgit v1.2.3 From 912cffb4ed8612dc99ee0251cc0c9785855162cd Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 18 Oct 2016 18:08:37 -0500 Subject: firmware: ti_sci: Add support for reboot core service Since system controller now has control over SoC power management, it needs to be explicitly requested to reboot the SoC. Add support for it. In some systems however, SoC needs to toggle a GPIO or send event to an external entity (like a PMIC) for a system reboot to take place. To facilitate that, we allow for a DT property to determine if the reboot handler will be registered and further, the service is also made available to other drivers (such as PMIC driver) to sequence the additional operation and trigger the SoC reboot as the last step. Tested-by: Lokesh Vutla Signed-off-by: Nishanth Menon Signed-off-by: Tero Kristo --- drivers/firmware/ti_sci.c | 83 ++++++++++++++++++++++++++++++++++ drivers/firmware/ti_sci.h | 12 +++++ include/linux/soc/ti/ti_sci_protocol.h | 11 +++++ 3 files changed, 106 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c index 496a007e5c69..874ff32db366 100644 --- a/drivers/firmware/ti_sci.c +++ b/drivers/firmware/ti_sci.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "ti_sci.h" @@ -90,6 +91,7 @@ struct ti_sci_desc { * struct ti_sci_info - Structure representing a TI SCI instance * @dev: Device pointer * @desc: SoC description for this instance + * @nb: Reboot Notifier block * @d: Debugfs file entry * @debug_region: Memory region where the debug message are available * @debug_region_size: Debug region size @@ -104,6 +106,7 @@ struct ti_sci_desc { */ struct ti_sci_info { struct device *dev; + struct notifier_block nb; const struct ti_sci_desc *desc; struct dentry *d; void __iomem *debug_region; @@ -117,10 +120,12 @@ struct ti_sci_info { struct list_head node; /* protected by ti_sci_list_mutex */ int users; + }; #define cl_to_ti_sci_info(c) container_of(c, struct ti_sci_info, cl) #define handle_to_ti_sci_info(h) container_of(h, struct ti_sci_info, handle) +#define reboot_to_ti_sci_info(n) container_of(n, struct ti_sci_info, nb) #ifdef CONFIG_DEBUG_FS @@ -1571,6 +1576,52 @@ fail: return ret; } +static int ti_sci_cmd_core_reboot(const struct ti_sci_handle *handle) +{ + struct ti_sci_info *info; + struct ti_sci_msg_req_reboot *req; + struct ti_sci_msg_hdr *resp; + struct ti_sci_xfer *xfer; + struct device *dev; + int ret = 0; + + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (!handle) + return -EINVAL; + + info = handle_to_ti_sci_info(handle); + dev = info->dev; + + xfer = ti_sci_get_one_xfer(info, TI_SCI_MSG_SYS_RESET, + TI_SCI_FLAG_REQ_ACK_ON_PROCESSED, + sizeof(*req), sizeof(*resp)); + if (IS_ERR(xfer)) { + ret = PTR_ERR(xfer); + dev_err(dev, "Message alloc failed(%d)\n", ret); + return ret; + } + req = (struct ti_sci_msg_req_reboot *)xfer->xfer_buf; + + ret = ti_sci_do_xfer(info, xfer); + if (ret) { + dev_err(dev, "Mbox send fail %d\n", ret); + goto fail; + } + + resp = (struct ti_sci_msg_hdr *)xfer->xfer_buf; + + if (!ti_sci_is_response_ack(resp)) + ret = -ENODEV; + else + ret = 0; + +fail: + ti_sci_put_one_xfer(&info->minfo, xfer); + + return ret; +} + /* * ti_sci_setup_ops() - Setup the operations structures * @info: pointer to TISCI pointer @@ -1578,9 +1629,12 @@ fail: static void ti_sci_setup_ops(struct ti_sci_info *info) { struct ti_sci_ops *ops = &info->handle.ops; + struct ti_sci_core_ops *core_ops = &ops->core_ops; struct ti_sci_dev_ops *dops = &ops->dev_ops; struct ti_sci_clk_ops *cops = &ops->clk_ops; + core_ops->reboot_device = ti_sci_cmd_core_reboot; + dops->get_device = ti_sci_cmd_get_device; dops->idle_device = ti_sci_cmd_idle_device; dops->put_device = ti_sci_cmd_put_device; @@ -1732,6 +1786,18 @@ const struct ti_sci_handle *devm_ti_sci_get_handle(struct device *dev) } EXPORT_SYMBOL_GPL(devm_ti_sci_get_handle); +static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode, + void *cmd) +{ + struct ti_sci_info *info = reboot_to_ti_sci_info(nb); + const struct ti_sci_handle *handle = &info->handle; + + ti_sci_cmd_core_reboot(handle); + + /* call fail OR pass, we should not be here in the first place */ + return NOTIFY_BAD; +} + /* Description for K2G */ static const struct ti_sci_desc ti_sci_pmmc_k2g_desc = { .host_id = 2, @@ -1759,6 +1825,7 @@ static int ti_sci_probe(struct platform_device *pdev) struct mbox_client *cl; int ret = -EINVAL; int i; + int reboot = 0; of_id = of_match_device(ti_sci_of_match, dev); if (!of_id) { @@ -1773,6 +1840,8 @@ static int ti_sci_probe(struct platform_device *pdev) info->dev = dev; info->desc = desc; + reboot = of_property_read_bool(dev->of_node, + "ti,system-reboot-controller"); INIT_LIST_HEAD(&info->node); minfo = &info->minfo; @@ -1845,6 +1914,17 @@ static int ti_sci_probe(struct platform_device *pdev) ti_sci_setup_ops(info); + if (reboot) { + info->nb.notifier_call = tisci_reboot_handler; + info->nb.priority = 128; + + ret = register_restart_handler(&info->nb); + if (ret) { + dev_err(dev, "reboot registration fail(%d)\n", ret); + return ret; + } + } + dev_info(dev, "ABI: %d.%d (firmware rev 0x%04x '%s')\n", info->handle.version.abi_major, info->handle.version.abi_minor, info->handle.version.firmware_revision, @@ -1874,6 +1954,9 @@ static int ti_sci_remove(struct platform_device *pdev) info = platform_get_drvdata(pdev); + if (info->nb.notifier_call) + unregister_restart_handler(&info->nb); + mutex_lock(&ti_sci_list_mutex); if (info->users) ret = -EBUSY; diff --git a/drivers/firmware/ti_sci.h b/drivers/firmware/ti_sci.h index f69907cfc128..9b611e9e6f6d 100644 --- a/drivers/firmware/ti_sci.h +++ b/drivers/firmware/ti_sci.h @@ -46,6 +46,7 @@ #define TI_SCI_MSG_VERSION 0x0002 #define TI_SCI_MSG_WAKE_REASON 0x0003 #define TI_SCI_MSG_GOODBYE 0x0004 +#define TI_SCI_MSG_SYS_RESET 0x0005 /* Device requests */ #define TI_SCI_MSG_SET_DEVICE_STATE 0x0200 @@ -105,6 +106,17 @@ struct ti_sci_msg_resp_version { u8 abi_minor; } __packed; +/** + * struct ti_sci_msg_req_reboot - Reboot the SoC + * @hdr: Generic Header + * + * Request type is TI_SCI_MSG_SYS_RESET, responded with a generic + * ACK/NACK message. + */ +struct ti_sci_msg_req_reboot { + struct ti_sci_msg_hdr hdr; +} __packed; + /** * struct ti_sci_msg_req_set_device_state - Set the desired state of the device * @hdr: Generic header diff --git a/include/linux/soc/ti/ti_sci_protocol.h b/include/linux/soc/ti/ti_sci_protocol.h index 76378fddf609..0ccbc138c26a 100644 --- a/include/linux/soc/ti/ti_sci_protocol.h +++ b/include/linux/soc/ti/ti_sci_protocol.h @@ -35,6 +35,16 @@ struct ti_sci_version_info { struct ti_sci_handle; +/** + * struct ti_sci_core_ops - SoC Core Operations + * @reboot_device: Reboot the SoC + * Returns 0 for successful request(ideally should never return), + * else returns corresponding error value. + */ +struct ti_sci_core_ops { + int (*reboot_device)(const struct ti_sci_handle *handle); +}; + /** * struct ti_sci_dev_ops - Device control operations * @get_device: Command to request for device managed by TISCI @@ -196,6 +206,7 @@ struct ti_sci_clk_ops { * @clk_ops: Clock specific operations */ struct ti_sci_ops { + struct ti_sci_core_ops core_ops; struct ti_sci_dev_ops dev_ops; struct ti_sci_clk_ops clk_ops; }; -- cgit v1.2.3 From 6078c651947a148c1de543b54fe55af43a63043a Mon Sep 17 00:00:00 2001 From: James Liao Date: Thu, 20 Oct 2016 16:56:35 +0800 Subject: soc: mediatek: Refine scpsys to support multiple platform Refine scpsys driver common code to support multiple SoC / platform. Signed-off-by: James Liao Reviewed-by: Kevin Hilman Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/mtk-scpsys.c | 348 +++++++++++++++++++++++--------------- 1 file changed, 210 insertions(+), 138 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 837effe19907..722aac80e611 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -11,17 +11,15 @@ * GNU General Public License for more details. */ #include -#include +#include #include -#include #include -#include #include #include #include -#include -#include #include +#include + #include #define SPM_VDE_PWR_CON 0x0210 @@ -34,6 +32,7 @@ #define SPM_MFG_2D_PWR_CON 0x02c0 #define SPM_MFG_ASYNC_PWR_CON 0x02c4 #define SPM_USB_PWR_CON 0x02cc + #define SPM_PWR_STATUS 0x060c #define SPM_PWR_STATUS_2ND 0x0610 @@ -55,12 +54,21 @@ #define PWR_STATUS_USB BIT(25) enum clk_id { - MT8173_CLK_NONE, - MT8173_CLK_MM, - MT8173_CLK_MFG, - MT8173_CLK_VENC, - MT8173_CLK_VENC_LT, - MT8173_CLK_MAX, + CLK_NONE, + CLK_MM, + CLK_MFG, + CLK_VENC, + CLK_VENC_LT, + CLK_MAX, +}; + +static const char * const clk_names[] = { + NULL, + "mm", + "mfg", + "venc", + "venc_lt", + NULL, }; #define MAX_CLKS 2 @@ -76,98 +84,6 @@ struct scp_domain_data { bool active_wakeup; }; -static const struct scp_domain_data scp_domain_data[] = { - [MT8173_POWER_DOMAIN_VDEC] = { - .name = "vdec", - .sta_mask = PWR_STATUS_VDEC, - .ctl_offs = SPM_VDE_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(12, 12), - .clk_id = {MT8173_CLK_MM}, - }, - [MT8173_POWER_DOMAIN_VENC] = { - .name = "venc", - .sta_mask = PWR_STATUS_VENC, - .ctl_offs = SPM_VEN_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC}, - }, - [MT8173_POWER_DOMAIN_ISP] = { - .name = "isp", - .sta_mask = PWR_STATUS_ISP, - .ctl_offs = SPM_ISP_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(13, 12), - .clk_id = {MT8173_CLK_MM}, - }, - [MT8173_POWER_DOMAIN_MM] = { - .name = "mm", - .sta_mask = PWR_STATUS_DISP, - .ctl_offs = SPM_DIS_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(12, 12), - .clk_id = {MT8173_CLK_MM}, - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | - MT8173_TOP_AXI_PROT_EN_MM_M1, - }, - [MT8173_POWER_DOMAIN_VENC_LT] = { - .name = "venc_lt", - .sta_mask = PWR_STATUS_VENC_LT, - .ctl_offs = SPM_VEN2_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_MM, MT8173_CLK_VENC_LT}, - }, - [MT8173_POWER_DOMAIN_AUDIO] = { - .name = "audio", - .sta_mask = PWR_STATUS_AUDIO, - .ctl_offs = SPM_AUDIO_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_NONE}, - }, - [MT8173_POWER_DOMAIN_USB] = { - .name = "usb", - .sta_mask = PWR_STATUS_USB, - .ctl_offs = SPM_USB_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(15, 12), - .clk_id = {MT8173_CLK_NONE}, - .active_wakeup = true, - }, - [MT8173_POWER_DOMAIN_MFG_ASYNC] = { - .name = "mfg_async", - .sta_mask = PWR_STATUS_MFG_ASYNC, - .ctl_offs = SPM_MFG_ASYNC_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = 0, - .clk_id = {MT8173_CLK_MFG}, - }, - [MT8173_POWER_DOMAIN_MFG_2D] = { - .name = "mfg_2d", - .sta_mask = PWR_STATUS_MFG_2D, - .ctl_offs = SPM_MFG_2D_PWR_CON, - .sram_pdn_bits = GENMASK(11, 8), - .sram_pdn_ack_bits = GENMASK(13, 12), - .clk_id = {MT8173_CLK_NONE}, - }, - [MT8173_POWER_DOMAIN_MFG] = { - .name = "mfg", - .sta_mask = PWR_STATUS_MFG, - .ctl_offs = SPM_MFG_PWR_CON, - .sram_pdn_bits = GENMASK(13, 8), - .sram_pdn_ack_bits = GENMASK(21, 16), - .clk_id = {MT8173_CLK_NONE}, - .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | - MT8173_TOP_AXI_PROT_EN_MFG_M0 | - MT8173_TOP_AXI_PROT_EN_MFG_M1 | - MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, - }, -}; - -#define NUM_DOMAINS ARRAY_SIZE(scp_domain_data) - struct scp; struct scp_domain { @@ -179,7 +95,7 @@ struct scp_domain { }; struct scp { - struct scp_domain domains[NUM_DOMAINS]; + struct scp_domain *domains; struct genpd_onecell_data pd_data; struct device *dev; void __iomem *base; @@ -408,57 +324,55 @@ static bool scpsys_active_wakeup(struct device *dev) return scpd->data->active_wakeup; } -static int scpsys_probe(struct platform_device *pdev) +static void init_clks(struct platform_device *pdev, struct clk **clk) +{ + int i; + + for (i = CLK_NONE + 1; i < CLK_MAX; i++) + clk[i] = devm_clk_get(&pdev->dev, clk_names[i]); +} + +static struct scp *init_scp(struct platform_device *pdev, + const struct scp_domain_data *scp_domain_data, int num) { struct genpd_onecell_data *pd_data; struct resource *res; - int i, j, ret; + int i, j; struct scp *scp; - struct clk *clk[MT8173_CLK_MAX]; + struct clk *clk[CLK_MAX]; scp = devm_kzalloc(&pdev->dev, sizeof(*scp), GFP_KERNEL); if (!scp) - return -ENOMEM; + return ERR_PTR(-ENOMEM); scp->dev = &pdev->dev; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); scp->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(scp->base)) - return PTR_ERR(scp->base); + return ERR_CAST(scp->base); + + scp->domains = devm_kzalloc(&pdev->dev, + sizeof(*scp->domains) * num, GFP_KERNEL); + if (!scp->domains) + return ERR_PTR(-ENOMEM); pd_data = &scp->pd_data; pd_data->domains = devm_kzalloc(&pdev->dev, - sizeof(*pd_data->domains) * NUM_DOMAINS, GFP_KERNEL); + sizeof(*pd_data->domains) * num, GFP_KERNEL); if (!pd_data->domains) - return -ENOMEM; - - clk[MT8173_CLK_MM] = devm_clk_get(&pdev->dev, "mm"); - if (IS_ERR(clk[MT8173_CLK_MM])) - return PTR_ERR(clk[MT8173_CLK_MM]); - - clk[MT8173_CLK_MFG] = devm_clk_get(&pdev->dev, "mfg"); - if (IS_ERR(clk[MT8173_CLK_MFG])) - return PTR_ERR(clk[MT8173_CLK_MFG]); - - clk[MT8173_CLK_VENC] = devm_clk_get(&pdev->dev, "venc"); - if (IS_ERR(clk[MT8173_CLK_VENC])) - return PTR_ERR(clk[MT8173_CLK_VENC]); - - clk[MT8173_CLK_VENC_LT] = devm_clk_get(&pdev->dev, "venc_lt"); - if (IS_ERR(clk[MT8173_CLK_VENC_LT])) - return PTR_ERR(clk[MT8173_CLK_VENC_LT]); + return ERR_PTR(-ENOMEM); scp->infracfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "infracfg"); if (IS_ERR(scp->infracfg)) { dev_err(&pdev->dev, "Cannot find infracfg controller: %ld\n", PTR_ERR(scp->infracfg)); - return PTR_ERR(scp->infracfg); + return ERR_CAST(scp->infracfg); } - for (i = 0; i < NUM_DOMAINS; i++) { + for (i = 0; i < num; i++) { struct scp_domain *scpd = &scp->domains[i]; const struct scp_domain_data *data = &scp_domain_data[i]; @@ -467,13 +381,15 @@ static int scpsys_probe(struct platform_device *pdev) if (PTR_ERR(scpd->supply) == -ENODEV) scpd->supply = NULL; else - return PTR_ERR(scpd->supply); + return ERR_CAST(scpd->supply); } } - pd_data->num_domains = NUM_DOMAINS; + pd_data->num_domains = num; - for (i = 0; i < NUM_DOMAINS; i++) { + init_clks(pdev, clk); + + for (i = 0; i < num; i++) { struct scp_domain *scpd = &scp->domains[i]; struct generic_pm_domain *genpd = &scpd->genpd; const struct scp_domain_data *data = &scp_domain_data[i]; @@ -482,13 +398,37 @@ static int scpsys_probe(struct platform_device *pdev) scpd->scp = scp; scpd->data = data; - for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) - scpd->clk[j] = clk[data->clk_id[j]]; + + for (j = 0; j < MAX_CLKS && data->clk_id[j]; j++) { + struct clk *c = clk[data->clk_id[j]]; + + if (IS_ERR(c)) { + dev_err(&pdev->dev, "%s: clk unavailable\n", + data->name); + return ERR_CAST(c); + } + + scpd->clk[j] = c; + } genpd->name = data->name; genpd->power_off = scpsys_power_off; genpd->power_on = scpsys_power_on; genpd->dev_ops.active_wakeup = scpsys_active_wakeup; + } + + return scp; +} + +static void mtk_register_power_domains(struct platform_device *pdev, + struct scp *scp, int num) +{ + struct genpd_onecell_data *pd_data; + int i, ret; + + for (i = 0; i < num; i++) { + struct scp_domain *scpd = &scp->domains[i]; + struct generic_pm_domain *genpd = &scpd->genpd; /* * Initially turn on all domains to make the domains usable @@ -507,6 +447,123 @@ static int scpsys_probe(struct platform_device *pdev) * valid. */ + pd_data = &scp->pd_data; + + ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); + if (ret) + dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); +} + +/* + * MT8173 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt8173[] = { + [MT8173_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + }, + [MT8173_POWER_DOMAIN_VENC] = { + .name = "venc", + .sta_mask = PWR_STATUS_VENC, + .ctl_offs = SPM_VEN_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC}, + }, + [MT8173_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + }, + [MT8173_POWER_DOMAIN_MM] = { + .name = "mm", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MM_M0 | + MT8173_TOP_AXI_PROT_EN_MM_M1, + }, + [MT8173_POWER_DOMAIN_VENC_LT] = { + .name = "venc_lt", + .sta_mask = PWR_STATUS_VENC_LT, + .ctl_offs = SPM_VEN2_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_MM, CLK_VENC_LT}, + }, + [MT8173_POWER_DOMAIN_AUDIO] = { + .name = "audio", + .sta_mask = PWR_STATUS_AUDIO, + .ctl_offs = SPM_AUDIO_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + }, + [MT8173_POWER_DOMAIN_USB] = { + .name = "usb", + .sta_mask = PWR_STATUS_USB, + .ctl_offs = SPM_USB_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT8173_POWER_DOMAIN_MFG_ASYNC] = { + .name = "mfg_async", + .sta_mask = PWR_STATUS_MFG_ASYNC, + .ctl_offs = SPM_MFG_ASYNC_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = 0, + .clk_id = {CLK_MFG}, + }, + [MT8173_POWER_DOMAIN_MFG_2D] = { + .name = "mfg_2d", + .sta_mask = PWR_STATUS_MFG_2D, + .ctl_offs = SPM_MFG_2D_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_NONE}, + }, + [MT8173_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(13, 8), + .sram_pdn_ack_bits = GENMASK(21, 16), + .clk_id = {CLK_NONE}, + .bus_prot_mask = MT8173_TOP_AXI_PROT_EN_MFG_S | + MT8173_TOP_AXI_PROT_EN_MFG_M0 | + MT8173_TOP_AXI_PROT_EN_MFG_M1 | + MT8173_TOP_AXI_PROT_EN_MFG_SNOOP_OUT, + }, +}; + +#define NUM_DOMAINS_MT8173 ARRAY_SIZE(scp_domain_data_mt8173) + +static int __init scpsys_probe_mt8173(struct platform_device *pdev) +{ + struct scp *scp; + struct genpd_onecell_data *pd_data; + int ret; + + scp = init_scp(pdev, scp_domain_data_mt8173, NUM_DOMAINS_MT8173); + if (IS_ERR(scp)) + return PTR_ERR(scp); + + mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT8173); + + pd_data = &scp->pd_data; + ret = pm_genpd_add_subdomain(pd_data->domains[MT8173_POWER_DOMAIN_MFG_ASYNC], pd_data->domains[MT8173_POWER_DOMAIN_MFG_2D]); if (ret && IS_ENABLED(CONFIG_PM)) @@ -517,21 +574,36 @@ static int scpsys_probe(struct platform_device *pdev) if (ret && IS_ENABLED(CONFIG_PM)) dev_err(&pdev->dev, "Failed to add subdomain: %d\n", ret); - ret = of_genpd_add_provider_onecell(pdev->dev.of_node, pd_data); - if (ret) - dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); - return 0; } +/* + * scpsys driver init + */ + static const struct of_device_id of_scpsys_match_tbl[] = { { .compatible = "mediatek,mt8173-scpsys", + .data = scpsys_probe_mt8173, }, { /* sentinel */ } }; +static int scpsys_probe(struct platform_device *pdev) +{ + int (*probe)(struct platform_device *); + const struct of_device_id *of_id; + + of_id = of_match_node(of_scpsys_match_tbl, pdev->dev.of_node); + if (!of_id || !of_id->data) + return -EINVAL; + + probe = of_id->data; + + return probe(pdev); +} + static struct platform_driver scpsys_drv = { .probe = scpsys_probe, .driver = { -- cgit v1.2.3 From 112ef1882e12094c823937f9d72f2f598db02df7 Mon Sep 17 00:00:00 2001 From: Shunli Wang Date: Thu, 20 Oct 2016 16:56:38 +0800 Subject: soc: mediatek: Add MT2701 scpsys driver Add scpsys driver for MT2701. mtk-scpsys now supports MT8173 (arm64) and MT2701 (arm). So it should be enabled on both arm64 and arm platforms. Signed-off-by: Shunli Wang Signed-off-by: James Liao Reviewed-by: Kevin Hilman Signed-off-by: Matthias Brugger --- drivers/soc/mediatek/Kconfig | 2 +- drivers/soc/mediatek/mtk-scpsys.c | 117 +++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index 0a4ea809a61b..609bb3424c14 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -23,7 +23,7 @@ config MTK_PMIC_WRAP config MTK_SCPSYS bool "MediaTek SCPSYS Support" depends on ARCH_MEDIATEK || COMPILE_TEST - default ARM64 && ARCH_MEDIATEK + default ARCH_MEDIATEK select REGMAP select MTK_INFRACFG select PM_GENERIC_DOMAINS if PM diff --git a/drivers/soc/mediatek/mtk-scpsys.c b/drivers/soc/mediatek/mtk-scpsys.c index 722aac80e611..beb79162369a 100644 --- a/drivers/soc/mediatek/mtk-scpsys.c +++ b/drivers/soc/mediatek/mtk-scpsys.c @@ -20,6 +20,7 @@ #include #include +#include #include #define SPM_VDE_PWR_CON 0x0210 @@ -27,8 +28,13 @@ #define SPM_VEN_PWR_CON 0x0230 #define SPM_ISP_PWR_CON 0x0238 #define SPM_DIS_PWR_CON 0x023c +#define SPM_CONN_PWR_CON 0x0280 #define SPM_VEN2_PWR_CON 0x0298 -#define SPM_AUDIO_PWR_CON 0x029c +#define SPM_AUDIO_PWR_CON 0x029c /* MT8173 */ +#define SPM_BDP_PWR_CON 0x029c /* MT2701 */ +#define SPM_ETH_PWR_CON 0x02a0 +#define SPM_HIF_PWR_CON 0x02a4 +#define SPM_IFR_MSC_PWR_CON 0x02a8 #define SPM_MFG_2D_PWR_CON 0x02c0 #define SPM_MFG_ASYNC_PWR_CON 0x02c4 #define SPM_USB_PWR_CON 0x02cc @@ -42,10 +48,15 @@ #define PWR_ON_2ND_BIT BIT(3) #define PWR_CLK_DIS_BIT BIT(4) +#define PWR_STATUS_CONN BIT(1) #define PWR_STATUS_DISP BIT(3) #define PWR_STATUS_MFG BIT(4) #define PWR_STATUS_ISP BIT(5) #define PWR_STATUS_VDEC BIT(7) +#define PWR_STATUS_BDP BIT(14) +#define PWR_STATUS_ETH BIT(15) +#define PWR_STATUS_HIF BIT(16) +#define PWR_STATUS_IFR_MSC BIT(17) #define PWR_STATUS_VENC_LT BIT(20) #define PWR_STATUS_VENC BIT(21) #define PWR_STATUS_MFG_2D BIT(22) @@ -59,6 +70,7 @@ enum clk_id { CLK_MFG, CLK_VENC, CLK_VENC_LT, + CLK_ETHIF, CLK_MAX, }; @@ -68,6 +80,7 @@ static const char * const clk_names[] = { "mfg", "venc", "venc_lt", + "ethif", NULL, }; @@ -454,6 +467,105 @@ static void mtk_register_power_domains(struct platform_device *pdev, dev_err(&pdev->dev, "Failed to add OF provider: %d\n", ret); } +/* + * MT2701 power domain support + */ + +static const struct scp_domain_data scp_domain_data_mt2701[] = { + [MT2701_POWER_DOMAIN_CONN] = { + .name = "conn", + .sta_mask = PWR_STATUS_CONN, + .ctl_offs = SPM_CONN_PWR_CON, + .bus_prot_mask = 0x0104, + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_DISP] = { + .name = "disp", + .sta_mask = PWR_STATUS_DISP, + .ctl_offs = SPM_DIS_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .clk_id = {CLK_MM}, + .bus_prot_mask = 0x0002, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_MFG] = { + .name = "mfg", + .sta_mask = PWR_STATUS_MFG, + .ctl_offs = SPM_MFG_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MFG}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_VDEC] = { + .name = "vdec", + .sta_mask = PWR_STATUS_VDEC, + .ctl_offs = SPM_VDE_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(12, 12), + .clk_id = {CLK_MM}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_ISP] = { + .name = "isp", + .sta_mask = PWR_STATUS_ISP, + .ctl_offs = SPM_ISP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(13, 12), + .clk_id = {CLK_MM}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_BDP] = { + .name = "bdp", + .sta_mask = PWR_STATUS_BDP, + .ctl_offs = SPM_BDP_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_ETH] = { + .name = "eth", + .sta_mask = PWR_STATUS_ETH, + .ctl_offs = SPM_ETH_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_HIF] = { + .name = "hif", + .sta_mask = PWR_STATUS_HIF, + .ctl_offs = SPM_HIF_PWR_CON, + .sram_pdn_bits = GENMASK(11, 8), + .sram_pdn_ack_bits = GENMASK(15, 12), + .clk_id = {CLK_ETHIF}, + .active_wakeup = true, + }, + [MT2701_POWER_DOMAIN_IFR_MSC] = { + .name = "ifr_msc", + .sta_mask = PWR_STATUS_IFR_MSC, + .ctl_offs = SPM_IFR_MSC_PWR_CON, + .clk_id = {CLK_NONE}, + .active_wakeup = true, + }, +}; + +#define NUM_DOMAINS_MT2701 ARRAY_SIZE(scp_domain_data_mt2701) + +static int __init scpsys_probe_mt2701(struct platform_device *pdev) +{ + struct scp *scp; + + scp = init_scp(pdev, scp_domain_data_mt2701, NUM_DOMAINS_MT2701); + if (IS_ERR(scp)) + return PTR_ERR(scp); + + mtk_register_power_domains(pdev, scp, NUM_DOMAINS_MT2701); + + return 0; +} + /* * MT8173 power domain support */ @@ -583,6 +695,9 @@ static int __init scpsys_probe_mt8173(struct platform_device *pdev) static const struct of_device_id of_scpsys_match_tbl[] = { { + .compatible = "mediatek,mt2701-scpsys", + .data = scpsys_probe_mt2701, + }, { .compatible = "mediatek,mt8173-scpsys", .data = scpsys_probe_mt8173, }, { -- cgit v1.2.3 From 542ccf4551fa019a8ae9dfb7c8cd7e73a3d7e614 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Mon, 31 Oct 2016 12:04:09 +0100 Subject: PCI: hv: Make unnecessarily global IRQ masking functions static Make hv_irq_mask() and hv_irq_unmask() static as they are only used in pci-hyperv.c This fixes a sparse warning. Signed-off-by: Tobias Klauser Signed-off-by: Bjorn Helgaas Acked-by: K. Y. Srinivasan --- drivers/pci/host/pci-hyperv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 763ff8745828..06c98695c06c 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -755,7 +755,7 @@ static int hv_set_affinity(struct irq_data *data, const struct cpumask *dest, return parent->chip->irq_set_affinity(parent, dest, force); } -void hv_irq_mask(struct irq_data *data) +static void hv_irq_mask(struct irq_data *data) { pci_msi_mask_irq(data); } @@ -770,7 +770,7 @@ void hv_irq_mask(struct irq_data *data) * is built out of this PCI bus's instance GUID and the function * number of the device. */ -void hv_irq_unmask(struct irq_data *data) +static void hv_irq_unmask(struct irq_data *data) { struct msi_desc *msi_desc = irq_data_get_msi_desc(data); struct irq_cfg *cfg = irqd_cfg(data); -- cgit v1.2.3 From 2cc751545854d7bd7eedf4d7e377bb52e176cd07 Mon Sep 17 00:00:00 2001 From: Stephan Mueller Date: Sat, 22 Oct 2016 15:57:05 +0200 Subject: hwrng: core - zeroize buffers with random data The HWRNG core allocates two buffers during initialization which are used to obtain random data. After that data is processed, it is now zeroized as it is possible that the HWRNG core will not be asked to produce more random data for a long time. This prevents leaving such sensitive data in memory. Signed-off-by: Stephan Mueller Signed-off-by: Herbert Xu --- drivers/char/hw_random/core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index d2d2c89de5b4..f9766415ff10 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -92,6 +92,7 @@ static void add_early_randomness(struct hwrng *rng) mutex_unlock(&reading_mutex); if (bytes_read > 0) add_device_randomness(rng_buffer, bytes_read); + memset(rng_buffer, 0, size); } static inline void cleanup_rng(struct kref *kref) @@ -287,6 +288,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf, } } out: + memset(rng_buffer, 0, rng_buffer_size()); return ret ? : err; out_unlock_reading: @@ -425,6 +427,7 @@ static int hwrng_fillfn(void *unused) /* Outside lock, sure, but y'know: randomness. */ add_hwgenerator_randomness((void *)rng_fillbuf, rc, rc * current_quality * 8 >> 10); + memset(rng_fillbuf, 0, rng_buffer_size()); } hwrng_fill = NULL; return 0; -- cgit v1.2.3 From fc783341f0e65a28d95cba8d6998bf90304017c5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 24 Oct 2016 14:51:22 +0000 Subject: crypto: atmel - drop pointless static qualifier in atmel_aes_probe() There is no need to have the 'struct atmel_aes_dev *aes_dd' variable static since new value always be assigned before use it. Signed-off-by: Wei Yongjun Signed-off-by: Herbert Xu --- drivers/crypto/atmel-aes.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c index 6b656f4a9378..0e3d0d655b96 100644 --- a/drivers/crypto/atmel-aes.c +++ b/drivers/crypto/atmel-aes.c @@ -2311,7 +2311,7 @@ aes_dd_err: static int atmel_aes_remove(struct platform_device *pdev) { - static struct atmel_aes_dev *aes_dd; + struct atmel_aes_dev *aes_dd; aes_dd = platform_get_drvdata(pdev); if (!aes_dd) -- cgit v1.2.3 From 9ae811f28070d6f63a675d7482bd1fc140a3a7c6 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 25 Oct 2016 12:07:27 +0100 Subject: crypto: sahara - fix typo "Decidated" -> "Dedicated" Trivial fix to typo in dev_dbg message Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu --- drivers/crypto/sahara.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c index 0c49956ee0ce..1d9ecd368b5b 100644 --- a/drivers/crypto/sahara.c +++ b/drivers/crypto/sahara.c @@ -390,7 +390,7 @@ static void sahara_decode_status(struct sahara_dev *dev, unsigned int status) if (status & SAHARA_STATUS_MODE_BATCH) dev_dbg(dev->device, " - Batch Mode.\n"); else if (status & SAHARA_STATUS_MODE_DEDICATED) - dev_dbg(dev->device, " - Decidated Mode.\n"); + dev_dbg(dev->device, " - Dedicated Mode.\n"); else if (status & SAHARA_STATUS_MODE_DEBUG) dev_dbg(dev->device, " - Debug Mode.\n"); -- cgit v1.2.3 From d69985a07692cbe67c50fa0e0ed8ffbd25cedd71 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 25 Oct 2016 23:29:10 +0200 Subject: crypto: caam - fix type mismatch warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building the caam driver on arm64 produces a harmless warning: drivers/crypto/caam/caamalg.c:140:139: warning: comparison of distinct pointer types lacks a cast We can use min_t to tell the compiler which type we want it to use here. Fixes: 5ecf8ef9103c ("crypto: caam - fix sg dump") Signed-off-by: Arnd Bergmann Reviewed-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 156aad167cd6..8de85dfb1b04 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -137,7 +137,7 @@ static void dbg_dump_sg(const char *level, const char *prefix_str, } buf = it_page + it->offset; - len = min(tlen, it->length); + len = min_t(size_t, tlen, it->length); print_hex_dump(level, prefix_str, prefix_type, rowsize, groupsize, buf, len, ascii); tlen -= len; -- cgit v1.2.3 From a1fa98d8116fb4f8a5df91fb2267ce8d192f6875 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Fri, 28 Oct 2016 16:00:46 +0800 Subject: hwrng: atmel - disable TRNG during suspend To fix the over consumption on the VDDCore due to the TRNG enabled, disable the TRNG during suspend, not only disable the user interface clock (which is controlled by PMC). Because the user interface clock is independent from any clock that may be used in the entropy source logic circuitry. Signed-off-by: Wenyou Yang Acked-by: Nicolas Ferre Signed-off-by: Herbert Xu --- drivers/char/hw_random/atmel-rng.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index 0fcc9e69a346..ae7cae579eac 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -48,6 +48,16 @@ static int atmel_trng_read(struct hwrng *rng, void *buf, size_t max, return 0; } +static void atmel_trng_enable(struct atmel_trng *trng) +{ + writel(TRNG_KEY | 1, trng->base + TRNG_CR); +} + +static void atmel_trng_disable(struct atmel_trng *trng) +{ + writel(TRNG_KEY, trng->base + TRNG_CR); +} + static int atmel_trng_probe(struct platform_device *pdev) { struct atmel_trng *trng; @@ -71,7 +81,7 @@ static int atmel_trng_probe(struct platform_device *pdev) if (ret) return ret; - writel(TRNG_KEY | 1, trng->base + TRNG_CR); + atmel_trng_enable(trng); trng->rng.name = pdev->name; trng->rng.read = atmel_trng_read; @@ -94,7 +104,7 @@ static int atmel_trng_remove(struct platform_device *pdev) hwrng_unregister(&trng->rng); - writel(TRNG_KEY, trng->base + TRNG_CR); + atmel_trng_disable(trng); clk_disable_unprepare(trng->clk); return 0; @@ -105,6 +115,7 @@ static int atmel_trng_suspend(struct device *dev) { struct atmel_trng *trng = dev_get_drvdata(dev); + atmel_trng_disable(trng); clk_disable_unprepare(trng->clk); return 0; @@ -113,8 +124,15 @@ static int atmel_trng_suspend(struct device *dev) static int atmel_trng_resume(struct device *dev) { struct atmel_trng *trng = dev_get_drvdata(dev); + int ret; + + ret = clk_prepare_enable(trng->clk); + if (ret) + return ret; - return clk_prepare_enable(trng->clk); + atmel_trng_enable(trng); + + return 0; } static const struct dev_pm_ops atmel_trng_pm_ops = { -- cgit v1.2.3 From bae203d58b7dce89664071b3fafe20cedaa3e4f6 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 26 Sep 2016 03:03:42 +0300 Subject: clk: imx31: fix rewritten input argument of mx31_clocks_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function mx31_clocks_init() is called during clock intialization on legacy boards with reference clock frequency passed as its input argument, this can be verified by examination of the function declaration found in arch/arm/mach-imx/common.h and actual function users which include that header file. Inside CCF driver the function ignores its input argument, by chance the used value in the function body is the same as input arguments on side of all callers. Fixes: d9388c843237 ("clk: imx31: Do not call mxc_timer_init twice when booting with DT") Signed-off-by: Vladimir Zapolskiy Reviewed-by: Uwe Kleine-König Acked-by: Stephen Boyd Signed-off-by: Shawn Guo --- drivers/clk/imx/clk-imx31.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c index 6a964144a5b5..6a49ba2b9671 100644 --- a/drivers/clk/imx/clk-imx31.c +++ b/drivers/clk/imx/clk-imx31.c @@ -157,10 +157,8 @@ static void __init _mx31_clocks_init(unsigned long fref) } } -int __init mx31_clocks_init(void) +int __init mx31_clocks_init(unsigned long fref) { - u32 fref = 26000000; /* default */ - _mx31_clocks_init(fref); clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); -- cgit v1.2.3 From 6fe5aeb5e7e9318bb720b1f582fc86b7ac3118c0 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 26 Sep 2016 03:03:43 +0300 Subject: ARM: clk: imx31: properly init clocks for machines with DT Clock initialization for i.MX31 powered machines with DT support should be done by a call of an init function registered with CLK_OF_DECLARE() in common clock framework. The change converts exported mx31_clocks_init_dt() into a static initialization function registered by CLK_OF_DECLARE(). Signed-off-by: Vladimir Zapolskiy Acked-by: Stephen Boyd Signed-off-by: Shawn Guo --- arch/arm/mach-imx/common.h | 1 - arch/arm/mach-imx/imx31-dt.c | 6 ------ drivers/clk/imx/clk-imx31.c | 50 +++++++++++++++++++++++--------------------- 3 files changed, 26 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h index c4436d9c52ff..b09a2ec19267 100644 --- a/arch/arm/mach-imx/common.h +++ b/arch/arm/mach-imx/common.h @@ -43,7 +43,6 @@ int mx21_clocks_init(unsigned long lref, unsigned long fref); int mx27_clocks_init(unsigned long fref); int mx31_clocks_init(unsigned long fref); int mx35_clocks_init(void); -int mx31_clocks_init_dt(void); struct platform_device *mxc_register_gpio(char *name, int id, resource_size_t iobase, resource_size_t iosize, int irq, int irq_high); void mxc_set_cpu_type(unsigned int type); diff --git a/arch/arm/mach-imx/imx31-dt.c b/arch/arm/mach-imx/imx31-dt.c index 62e6b4fb5370..668d74b72511 100644 --- a/arch/arm/mach-imx/imx31-dt.c +++ b/arch/arm/mach-imx/imx31-dt.c @@ -23,11 +23,6 @@ static const char * const imx31_dt_board_compat[] __initconst = { NULL }; -static void __init imx31_dt_timer_init(void) -{ - mx31_clocks_init_dt(); -} - /* FIXME: replace with DT binding */ static const struct resource imx31_rnga_res[] __initconst = { DEFINE_RES_MEM(MX31_RNGA_BASE_ADDR, SZ_16K), @@ -43,7 +38,6 @@ DT_MACHINE_START(IMX31_DT, "Freescale i.MX31 (Device Tree Support)") .map_io = mx31_map_io, .init_early = imx31_init_early, .init_irq = mx31_init_irq, - .init_time = imx31_dt_timer_init, .init_machine = imx31_dt_mach_init, .dt_compat = imx31_dt_board_compat, MACHINE_END diff --git a/drivers/clk/imx/clk-imx31.c b/drivers/clk/imx/clk-imx31.c index 6a49ba2b9671..cbce308aad04 100644 --- a/drivers/clk/imx/clk-imx31.c +++ b/drivers/clk/imx/clk-imx31.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -72,14 +73,8 @@ static struct clk ** const uart_clks[] __initconst = { NULL }; -static void __init _mx31_clocks_init(unsigned long fref) +static void __init _mx31_clocks_init(void __iomem *base, unsigned long fref) { - void __iomem *base; - struct device_node *np; - - base = ioremap(MX31_CCM_BASE_ADDR, SZ_4K); - BUG_ON(!base); - clk[dummy] = imx_clk_fixed("dummy", 0); clk[ckih] = imx_clk_fixed("ckih", fref); clk[ckil] = imx_clk_fixed("ckil", 32768); @@ -147,19 +142,17 @@ static void __init _mx31_clocks_init(unsigned long fref) clk_prepare_enable(clk[iim_gate]); mx31_revision(); clk_disable_unprepare(clk[iim_gate]); - - np = of_find_compatible_node(NULL, NULL, "fsl,imx31-ccm"); - - if (np) { - clk_data.clks = clk; - clk_data.clk_num = ARRAY_SIZE(clk); - of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); - } } int __init mx31_clocks_init(unsigned long fref) { - _mx31_clocks_init(fref); + void __iomem *base; + + base = ioremap(MX31_CCM_BASE_ADDR, SZ_4K); + if (!base) + panic("%s: failed to map registers\n", __func__); + + _mx31_clocks_init(base, fref); clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0"); clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0"); @@ -222,22 +215,31 @@ int __init mx31_clocks_init(unsigned long fref) return 0; } -int __init mx31_clocks_init_dt(void) +static void __init mx31_clocks_init_dt(struct device_node *np) { - struct device_node *np; + struct device_node *osc_np; u32 fref = 26000000; /* default */ + void __iomem *ccm; - for_each_compatible_node(np, NULL, "fixed-clock") { - if (!of_device_is_compatible(np, "fsl,imx-osc26m")) + for_each_compatible_node(osc_np, NULL, "fixed-clock") { + if (!of_device_is_compatible(osc_np, "fsl,imx-osc26m")) continue; - if (!of_property_read_u32(np, "clock-frequency", &fref)) { - of_node_put(np); + if (!of_property_read_u32(osc_np, "clock-frequency", &fref)) { + of_node_put(osc_np); break; } } - _mx31_clocks_init(fref); + ccm = of_iomap(np, 0); + if (!ccm) + panic("%s: failed to map registers\n", __func__); - return 0; + _mx31_clocks_init(ccm, fref); + + clk_data.clks = clk; + clk_data.clk_num = ARRAY_SIZE(clk); + of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data); } + +CLK_OF_DECLARE(imx31_ccm, "fsl,imx31-ccm", mx31_clocks_init_dt); -- cgit v1.2.3 From bb789cd12cfc314458f8bd24548dbda3e683bc26 Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 5 Oct 2016 09:33:31 +0200 Subject: firmware: arm_scpi: increase MAX_DVFS_OPPS to 16 entries Since Amlogic SoCs supports more than 8 OPPs per domains, we need increase the OPP structure size. This patch increases the MAX_DVFS_OPPS to 16. Signed-off-by: Neil Armstrong Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 9e9b022450eb..21542a32ad9f 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -63,7 +63,7 @@ #define SCPI_SLOT 0 #define MAX_DVFS_DOMAINS 8 -#define MAX_DVFS_OPPS 8 +#define MAX_DVFS_OPPS 16 #define DVFS_LATENCY(hdr) (le32_to_cpu(hdr) >> 16) #define DVFS_OPP_COUNT(hdr) ((le32_to_cpu(hdr) >> 8) & 0xff) -- cgit v1.2.3 From 4dfe32d5cd0586fef6c716d95542e2857afb7add Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 19 Oct 2016 14:51:08 +0200 Subject: firmware: arm_scpi: add alternative legacy structures, functions and macros This patch adds support for the Legacy SCPI protocol that is available in very early JUNO versions and shipped Amlogic ARMv8 based SoCs. Some Rockchip SoC are also known to use this version of protocol with extended vendor commands. In order to support the legacy SCPI protocol variant, we need to add the structures and macros definitions that varies against the final SCPI v1.0 specification. We add the indirection table for legacy commands set so that it can co-exist with the standard v1.0 command set. It also adds bitmap field for channel selection since the legacy protocol mandates to send only selected subset of the commands on the high priority channel. Signed-off-by: Neil Armstrong [sudeep.holla@arm.com: Updated the changelog] Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scpi.c | 192 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 174 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 21542a32ad9f..2982bc7b8c33 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -50,13 +50,20 @@ #define CMD_TOKEN_ID_MASK 0xff #define CMD_DATA_SIZE_SHIFT 16 #define CMD_DATA_SIZE_MASK 0x1ff +#define CMD_LEGACY_DATA_SIZE_SHIFT 20 +#define CMD_LEGACY_DATA_SIZE_MASK 0x1ff #define PACK_SCPI_CMD(cmd_id, tx_sz) \ ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \ (((tx_sz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT)) #define ADD_SCPI_TOKEN(cmd, token) \ ((cmd) |= (((token) & CMD_TOKEN_ID_MASK) << CMD_TOKEN_ID_SHIFT)) +#define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \ + ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \ + (((tx_sz) & CMD_LEGACY_DATA_SIZE_MASK) << CMD_LEGACY_DATA_SIZE_SHIFT)) #define CMD_SIZE(cmd) (((cmd) >> CMD_DATA_SIZE_SHIFT) & CMD_DATA_SIZE_MASK) +#define CMD_LEGACY_SIZE(cmd) (((cmd) >> CMD_LEGACY_DATA_SIZE_SHIFT) & \ + CMD_LEGACY_DATA_SIZE_MASK) #define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK << CMD_TOKEN_ID_SHIFT | CMD_ID_MASK) #define CMD_XTRACT_UNIQ(cmd) ((cmd) & CMD_UNIQ_MASK) @@ -133,7 +140,62 @@ enum scpi_std_cmd { SCPI_CMD_COUNT }; -/* List of all commands used by this driver, used as indices */ +/* SCPI Legacy Commands */ +enum legacy_scpi_std_cmd { + LEGACY_SCPI_CMD_INVALID = 0x00, + LEGACY_SCPI_CMD_SCPI_READY = 0x01, + LEGACY_SCPI_CMD_SCPI_CAPABILITIES = 0x02, + LEGACY_SCPI_CMD_EVENT = 0x03, + LEGACY_SCPI_CMD_SET_CSS_PWR_STATE = 0x04, + LEGACY_SCPI_CMD_GET_CSS_PWR_STATE = 0x05, + LEGACY_SCPI_CMD_CFG_PWR_STATE_STAT = 0x06, + LEGACY_SCPI_CMD_GET_PWR_STATE_STAT = 0x07, + LEGACY_SCPI_CMD_SYS_PWR_STATE = 0x08, + LEGACY_SCPI_CMD_L2_READY = 0x09, + LEGACY_SCPI_CMD_SET_AP_TIMER = 0x0a, + LEGACY_SCPI_CMD_CANCEL_AP_TIME = 0x0b, + LEGACY_SCPI_CMD_DVFS_CAPABILITIES = 0x0c, + LEGACY_SCPI_CMD_GET_DVFS_INFO = 0x0d, + LEGACY_SCPI_CMD_SET_DVFS = 0x0e, + LEGACY_SCPI_CMD_GET_DVFS = 0x0f, + LEGACY_SCPI_CMD_GET_DVFS_STAT = 0x10, + LEGACY_SCPI_CMD_SET_RTC = 0x11, + LEGACY_SCPI_CMD_GET_RTC = 0x12, + LEGACY_SCPI_CMD_CLOCK_CAPABILITIES = 0x13, + LEGACY_SCPI_CMD_SET_CLOCK_INDEX = 0x14, + LEGACY_SCPI_CMD_SET_CLOCK_VALUE = 0x15, + LEGACY_SCPI_CMD_GET_CLOCK_VALUE = 0x16, + LEGACY_SCPI_CMD_PSU_CAPABILITIES = 0x17, + LEGACY_SCPI_CMD_SET_PSU = 0x18, + LEGACY_SCPI_CMD_GET_PSU = 0x19, + LEGACY_SCPI_CMD_SENSOR_CAPABILITIES = 0x1a, + LEGACY_SCPI_CMD_SENSOR_INFO = 0x1b, + LEGACY_SCPI_CMD_SENSOR_VALUE = 0x1c, + LEGACY_SCPI_CMD_SENSOR_CFG_PERIODIC = 0x1d, + LEGACY_SCPI_CMD_SENSOR_CFG_BOUNDS = 0x1e, + LEGACY_SCPI_CMD_SENSOR_ASYNC_VALUE = 0x1f, + LEGACY_SCPI_CMD_COUNT +}; + +/* List all commands that are required to go through the high priority link */ +static int legacy_hpriority_cmds[] = { + LEGACY_SCPI_CMD_GET_CSS_PWR_STATE, + LEGACY_SCPI_CMD_CFG_PWR_STATE_STAT, + LEGACY_SCPI_CMD_GET_PWR_STATE_STAT, + LEGACY_SCPI_CMD_SET_DVFS, + LEGACY_SCPI_CMD_GET_DVFS, + LEGACY_SCPI_CMD_SET_RTC, + LEGACY_SCPI_CMD_GET_RTC, + LEGACY_SCPI_CMD_SET_CLOCK_INDEX, + LEGACY_SCPI_CMD_SET_CLOCK_VALUE, + LEGACY_SCPI_CMD_GET_CLOCK_VALUE, + LEGACY_SCPI_CMD_SET_PSU, + LEGACY_SCPI_CMD_GET_PSU, + LEGACY_SCPI_CMD_SENSOR_CFG_PERIODIC, + LEGACY_SCPI_CMD_SENSOR_CFG_BOUNDS, +}; + +/* List all commands used by this driver, used as indexes */ enum scpi_drv_cmds { CMD_SCPI_CAPABILITIES = 0, CMD_GET_CLOCK_INFO, @@ -165,6 +227,21 @@ static int scpi_std_commands[CMD_MAX_COUNT] = { SCPI_CMD_GET_DEVICE_PWR_STATE, }; +static int scpi_legacy_commands[CMD_MAX_COUNT] = { + LEGACY_SCPI_CMD_SCPI_CAPABILITIES, + -1, /* GET_CLOCK_INFO */ + LEGACY_SCPI_CMD_GET_CLOCK_VALUE, + LEGACY_SCPI_CMD_SET_CLOCK_VALUE, + LEGACY_SCPI_CMD_GET_DVFS, + LEGACY_SCPI_CMD_SET_DVFS, + LEGACY_SCPI_CMD_GET_DVFS_INFO, + LEGACY_SCPI_CMD_SENSOR_CAPABILITIES, + LEGACY_SCPI_CMD_SENSOR_INFO, + LEGACY_SCPI_CMD_SENSOR_VALUE, + -1, /* SET_DEVICE_PWR_STATE */ + -1, /* GET_DEVICE_PWR_STATE */ +}; + struct scpi_xfer { u32 slot; /* has to be first element */ u32 cmd; @@ -193,8 +270,10 @@ struct scpi_chan { struct scpi_drvinfo { u32 protocol_version; u32 firmware_version; + bool is_legacy; int num_chans; int *commands; + DECLARE_BITMAP(cmd_priority, LEGACY_SCPI_CMD_COUNT); atomic_t next_chan; struct scpi_ops *scpi_ops; struct scpi_chan *channels; @@ -211,6 +290,11 @@ struct scpi_shared_mem { u8 payload[0]; } __packed; +struct legacy_scpi_shared_mem { + __le32 status; + u8 payload[0]; +} __packed; + struct scp_capabilities { __le32 protocol_version; __le32 event_version; @@ -236,6 +320,12 @@ struct clk_set_value { __le32 rate; } __packed; +struct legacy_clk_set_value { + __le32 rate; + __le16 id; + __le16 reserved; +} __packed; + struct dvfs_info { __le32 header; struct { @@ -307,19 +397,43 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd) return; } - list_for_each_entry(t, &ch->rx_pending, node) - if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) { - list_del(&t->node); - match = t; - break; - } + /* Command type is not replied by the SCP Firmware in legacy Mode + * We should consider that command is the head of pending RX commands + * if the list is not empty. In TX only mode, the list would be empty. + */ + if (scpi_info->is_legacy) { + match = list_first_entry(&ch->rx_pending, struct scpi_xfer, + node); + list_del(&match->node); + } else { + list_for_each_entry(t, &ch->rx_pending, node) + if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) { + list_del(&t->node); + match = t; + break; + } + } /* check if wait_for_completion is in progress or timed-out */ if (match && !completion_done(&match->done)) { - struct scpi_shared_mem *mem = ch->rx_payload; - unsigned int len = min(match->rx_len, CMD_SIZE(cmd)); + unsigned int len; + + if (scpi_info->is_legacy) { + struct legacy_scpi_shared_mem *mem = ch->rx_payload; + + /* RX Length is not replied by the legacy Firmware */ + len = match->rx_len; + + match->status = le32_to_cpu(mem->status); + memcpy_fromio(match->rx_buf, mem->payload, len); + } else { + struct scpi_shared_mem *mem = ch->rx_payload; + + len = min(match->rx_len, CMD_SIZE(cmd)); + + match->status = le32_to_cpu(mem->status); + memcpy_fromio(match->rx_buf, mem->payload, len); + } - match->status = le32_to_cpu(mem->status); - memcpy_fromio(match->rx_buf, mem->payload, len); if (match->rx_len > len) memset(match->rx_buf + len, 0, match->rx_len - len); complete(&match->done); @@ -331,7 +445,10 @@ static void scpi_handle_remote_msg(struct mbox_client *c, void *msg) { struct scpi_chan *ch = container_of(c, struct scpi_chan, cl); struct scpi_shared_mem *mem = ch->rx_payload; - u32 cmd = le32_to_cpu(mem->command); + u32 cmd = 0; + + if (!scpi_info->is_legacy) + cmd = le32_to_cpu(mem->command); scpi_process_cmd(ch, cmd); } @@ -343,8 +460,13 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg) struct scpi_chan *ch = container_of(c, struct scpi_chan, cl); struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload; - if (t->tx_buf) - memcpy_toio(mem->payload, t->tx_buf, t->tx_len); + if (t->tx_buf) { + if (scpi_info->is_legacy) + memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len); + else + memcpy_toio(mem->payload, t->tx_buf, t->tx_len); + } + if (t->rx_buf) { if (!(++ch->token)) ++ch->token; @@ -353,7 +475,9 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg) list_add_tail(&t->node, &ch->rx_pending); spin_unlock_irqrestore(&ch->rx_lock, flags); } - mem->command = cpu_to_le32(t->cmd); + + if (!scpi_info->is_legacy) + mem->command = cpu_to_le32(t->cmd); } static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch) @@ -392,15 +516,24 @@ static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len, cmd = scpi_info->commands[idx]; - chan = atomic_inc_return(&scpi_info->next_chan) % scpi_info->num_chans; + if (scpi_info->is_legacy) + chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0; + else + chan = atomic_inc_return(&scpi_info->next_chan) % + scpi_info->num_chans; scpi_chan = scpi_info->channels + chan; msg = get_scpi_xfer(scpi_chan); if (!msg) return -ENOMEM; - msg->slot = BIT(SCPI_SLOT); - msg->cmd = PACK_SCPI_CMD(cmd, tx_len); + if (scpi_info->is_legacy) { + msg->cmd = PACK_LEGACY_SCPI_CMD(cmd, tx_len); + msg->slot = msg->cmd; + } else { + msg->slot = BIT(SCPI_SLOT); + msg->cmd = PACK_SCPI_CMD(cmd, tx_len); + } msg->tx_buf = tx_buf; msg->tx_len = tx_len; msg->rx_buf = rx_buf; @@ -470,6 +603,18 @@ static int scpi_clk_set_val(u16 clk_id, unsigned long rate) &stat, sizeof(stat)); } +static int legacy_scpi_clk_set_val(u16 clk_id, unsigned long rate) +{ + int stat; + struct legacy_clk_set_value clk = { + .id = cpu_to_le16(clk_id), + .rate = cpu_to_le32(rate) + }; + + return scpi_send_message(CMD_SET_CLOCK_VALUE, &clk, sizeof(clk), + &stat, sizeof(stat)); +} + static int scpi_dvfs_get_idx(u8 domain) { int ret; @@ -800,6 +945,17 @@ err: platform_set_drvdata(pdev, scpi_info); + if (scpi_info->is_legacy) { + /* Replace with legacy variants */ + scpi_ops.clk_set_val = legacy_scpi_clk_set_val; + scpi_info->commands = scpi_legacy_commands; + + /* Fill priority bitmap */ + for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++) + set_bit(legacy_hpriority_cmds[idx], + scpi_info->cmd_priority); + } + ret = scpi_init_versions(scpi_info); if (ret) { dev_err(dev, "incorrect or no SCP firmware found\n"); -- cgit v1.2.3 From abd3e80545c184f2b472f7527ae8eda34bd59f2d Mon Sep 17 00:00:00 2001 From: Neil Armstrong Date: Wed, 19 Oct 2016 14:51:09 +0200 Subject: firmware: arm_scpi: allow firmware with get_capabilities not implemented On Amlogic SCPI legacy implementation, the GET_CAPABILITIES command is not supported, failover by using 0.0.0 version. Signed-off-by: Neil Armstrong [sudeep.holla@arm.com: changed the subject] Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scpi.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 2982bc7b8c33..902233642bd3 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -783,6 +783,10 @@ static int scpi_init_versions(struct scpi_drvinfo *info) info->protocol_version = le32_to_cpu(caps.protocol_version); info->firmware_version = le32_to_cpu(caps.platform_version); } + /* Ignore error if not implemented */ + if (scpi_info->is_legacy && ret == -EOPNOTSUPP) + return 0; + return ret; } -- cgit v1.2.3 From e4c8cd82d5e1146590611c393001d846535bac5b Mon Sep 17 00:00:00 2001 From: Caesar Wang Date: Thu, 13 Oct 2016 02:16:08 +0800 Subject: soc: rockchip: power-domain: avoid infinite loop In some cases, we have met the infinite loop in rockchip_pmu_set_idle_request() or rockchip_do_pmu_set_power_domain(). As the crosbug.com/p/57351 reported, the boot hangs right after this [1.629163] bootconsole [uart8250] disabled [1.639286] [drm:drm_core_init] Initialized drm 1.1.0 20060810 [1.645926] [drm:drm_get_platform_dev] Initialized vgem 1.0.0 20120112.. [1.654558] iommu: Adding device ff8f0000.vop to group 0 [1.660569] iommu: Adding device ff900000.vop to group 1 This patch adds the error message and timeout to avoid infinite loop if it fails to get the ack. Signed-off-by: Caesar Wang Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 48 +++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 5f106b16e622..988bfd708706 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -105,12 +106,24 @@ static bool rockchip_pmu_domain_is_idle(struct rockchip_pm_domain *pd) return (val & pd_info->idle_mask) == pd_info->idle_mask; } +static unsigned int rockchip_pmu_read_ack(struct rockchip_pmu *pmu) +{ + unsigned int val; + + regmap_read(pmu->regmap, pmu->info->ack_offset, &val); + return val; +} + static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, bool idle) { const struct rockchip_domain_info *pd_info = pd->info; + struct generic_pm_domain *genpd = &pd->genpd; struct rockchip_pmu *pmu = pd->pmu; + unsigned int target_ack; unsigned int val; + bool is_idle; + int ret; if (pd_info->req_mask == 0) return 0; @@ -120,12 +133,26 @@ static int rockchip_pmu_set_idle_request(struct rockchip_pm_domain *pd, dsb(sy); - do { - regmap_read(pmu->regmap, pmu->info->ack_offset, &val); - } while ((val & pd_info->ack_mask) != (idle ? pd_info->ack_mask : 0)); + /* Wait util idle_ack = 1 */ + target_ack = idle ? pd_info->ack_mask : 0; + ret = readx_poll_timeout_atomic(rockchip_pmu_read_ack, pmu, val, + (val & pd_info->ack_mask) == target_ack, + 0, 10000); + if (ret) { + dev_err(pmu->dev, + "failed to get ack on domain '%s', val=0x%x\n", + genpd->name, val); + return ret; + } - while (rockchip_pmu_domain_is_idle(pd) != idle) - cpu_relax(); + ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_idle, pd, + is_idle, is_idle == idle, 0, 10000); + if (ret) { + dev_err(pmu->dev, + "failed to set idle on domain '%s', val=%d\n", + genpd->name, is_idle); + return ret; + } return 0; } @@ -198,6 +225,8 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, bool on) { struct rockchip_pmu *pmu = pd->pmu; + struct generic_pm_domain *genpd = &pd->genpd; + bool is_on; if (pd->info->pwr_mask == 0) return; @@ -207,8 +236,13 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, dsb(sy); - while (rockchip_pmu_domain_is_on(pd) != on) - cpu_relax(); + if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, + is_on == on, 0, 10000)) { + dev_err(pmu->dev, + "failed to set domain '%s', val=%d\n", + genpd->name, is_on); + return; + } } static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) -- cgit v1.2.3 From bdcfddfd7481d7756edfeb30fc28b550f6c64812 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 21 Oct 2016 12:37:56 -0400 Subject: dmaengine: qcom_hidma: make pending_tre_count atomic Getting ready for the MSI interrupts. The pending_tre_count is used in the interrupt handler to make sure all outstanding requests are serviced. The driver will allocate 11 MSI interrupts. Each MSI interrupt can be assigned to a different CPU. Then, we have a race condition for common variables as they share the same interrupt handler with a different cause bit and they can potentially be executed in parallel. Making this variable atomic so that it can be updated from multiple processor contexts. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.h | 2 +- drivers/dma/qcom/hidma_dbg.c | 3 ++- drivers/dma/qcom/hidma_ll.c | 13 ++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h index de6176497524..181f7e0d08f6 100644 --- a/drivers/dma/qcom/hidma.h +++ b/drivers/dma/qcom/hidma.h @@ -59,7 +59,7 @@ struct hidma_lldev { void __iomem *evca; /* Event Channel address */ struct hidma_tre **pending_tre_list; /* Pointers to pending TREs */ - s32 pending_tre_count; /* Number of TREs pending */ + atomic_t pending_tre_count; /* Number of TREs pending */ void *tre_ring; /* TRE ring */ dma_addr_t tre_dma; /* TRE ring to be shared with HW */ diff --git a/drivers/dma/qcom/hidma_dbg.c b/drivers/dma/qcom/hidma_dbg.c index 3d83b9962220..3bdcb8056a36 100644 --- a/drivers/dma/qcom/hidma_dbg.c +++ b/drivers/dma/qcom/hidma_dbg.c @@ -74,7 +74,8 @@ static void hidma_ll_devstats(struct seq_file *s, void *llhndl) seq_printf(s, "tre_ring_handle=%pap\n", &lldev->tre_dma); seq_printf(s, "tre_ring_size = 0x%x\n", lldev->tre_ring_size); seq_printf(s, "tre_processed_off = 0x%x\n", lldev->tre_processed_off); - seq_printf(s, "pending_tre_count=%d\n", lldev->pending_tre_count); + seq_printf(s, "pending_tre_count=%d\n", + atomic_read(&lldev->pending_tre_count)); seq_printf(s, "evca=%p\n", lldev->evca); seq_printf(s, "evre_ring=%p\n", lldev->evre_ring); seq_printf(s, "evre_ring_handle=%pap\n", &lldev->evre_dma); diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index e605c9096545..114409e7eec1 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -218,10 +218,9 @@ static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator, * Keep track of pending TREs that SW is expecting to receive * from HW. We got one now. Decrement our counter. */ - lldev->pending_tre_count--; - if (lldev->pending_tre_count < 0) { + if (atomic_dec_return(&lldev->pending_tre_count) < 0) { dev_warn(lldev->dev, "tre count mismatch on completion"); - lldev->pending_tre_count = 0; + atomic_set(&lldev->pending_tre_count, 0); } spin_unlock_irqrestore(&lldev->lock, flags); @@ -328,7 +327,7 @@ void hidma_cleanup_pending_tre(struct hidma_lldev *lldev, u8 err_info, u32 tre_read_off; tre_iterator = lldev->tre_processed_off; - while (lldev->pending_tre_count) { + while (atomic_read(&lldev->pending_tre_count)) { if (hidma_post_completed(lldev, tre_iterator, err_info, err_code)) break; @@ -555,7 +554,7 @@ void hidma_ll_queue_request(struct hidma_lldev *lldev, u32 tre_ch) tre->err_code = 0; tre->err_info = 0; tre->queued = 1; - lldev->pending_tre_count++; + atomic_inc(&lldev->pending_tre_count); lldev->tre_write_offset = (lldev->tre_write_offset + HIDMA_TRE_SIZE) % lldev->tre_ring_size; spin_unlock_irqrestore(&lldev->lock, flags); @@ -650,7 +649,7 @@ int hidma_ll_setup(struct hidma_lldev *lldev) u32 val; u32 nr_tres = lldev->nr_tres; - lldev->pending_tre_count = 0; + atomic_set(&lldev->pending_tre_count, 0); lldev->tre_processed_off = 0; lldev->evre_processed_off = 0; lldev->tre_write_offset = 0; @@ -831,7 +830,7 @@ int hidma_ll_uninit(struct hidma_lldev *lldev) tasklet_kill(&lldev->task); memset(lldev->trepool, 0, required_bytes); lldev->trepool = NULL; - lldev->pending_tre_count = 0; + atomic_set(&lldev->pending_tre_count, 0); lldev->tre_write_offset = 0; rc = hidma_ll_reset(lldev); -- cgit v1.2.3 From 9483d9ae09452ad4cdf7f0bb0c0fae2775278c85 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 21 Oct 2016 12:37:57 -0400 Subject: dmaengine: qcom_hidma: bring out interrupt cause Bring out the interrupt cause to the top level so that MSI interrupts can be hooked at a later stage. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_ll.c | 62 ++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 114409e7eec1..9193f466c9e7 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -418,12 +418,24 @@ static int hidma_ll_reset(struct hidma_lldev *lldev) * requests traditionally to the destination, this concept does not apply * here for this HW. */ -irqreturn_t hidma_ll_inthandler(int chirq, void *arg) +static void hidma_ll_int_handler_internal(struct hidma_lldev *lldev, int cause) { - struct hidma_lldev *lldev = arg; - u32 status; - u32 enable; - u32 cause; + if (cause & HIDMA_ERR_INT_MASK) { + dev_err(lldev->dev, "error 0x%x, disabling...\n", + cause); + + /* Clear out pending interrupts */ + writel(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); + + /* No further submissions. */ + hidma_ll_disable(lldev); + + /* Driver completes the txn and intimates the client.*/ + hidma_cleanup_pending_tre(lldev, 0xFF, + HIDMA_EVRE_STATUS_ERROR); + + return; + } /* * Fine tuned for this HW... @@ -432,35 +444,28 @@ irqreturn_t hidma_ll_inthandler(int chirq, void *arg) * read and write accessors are used for performance reasons due to * interrupt delivery guarantees. Do not copy this code blindly and * expect that to work. + * + * Try to consume as many EVREs as possible. */ + hidma_handle_tre_completion(lldev); + + /* We consumed TREs or there are pending TREs or EVREs. */ + writel_relaxed(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); +} + +irqreturn_t hidma_ll_inthandler(int chirq, void *arg) +{ + struct hidma_lldev *lldev = arg; + u32 status; + u32 enable; + u32 cause; + status = readl_relaxed(lldev->evca + HIDMA_EVCA_IRQ_STAT_REG); enable = readl_relaxed(lldev->evca + HIDMA_EVCA_IRQ_EN_REG); cause = status & enable; while (cause) { - if (cause & HIDMA_ERR_INT_MASK) { - dev_err(lldev->dev, "error 0x%x, disabling...\n", - cause); - - /* Clear out pending interrupts */ - writel(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); - - /* No further submissions. */ - hidma_ll_disable(lldev); - - /* Driver completes the txn and intimates the client.*/ - hidma_cleanup_pending_tre(lldev, 0xFF, - HIDMA_EVRE_STATUS_ERROR); - goto out; - } - - /* - * Try to consume as many EVREs as possible. - */ - hidma_handle_tre_completion(lldev); - - /* We consumed TREs or there are pending TREs or EVREs. */ - writel_relaxed(cause, lldev->evca + HIDMA_EVCA_IRQ_CLR_REG); + hidma_ll_int_handler_internal(lldev, cause); /* * Another interrupt might have arrived while we are @@ -471,7 +476,6 @@ irqreturn_t hidma_ll_inthandler(int chirq, void *arg) cause = status & enable; } -out: return IRQ_HANDLED; } -- cgit v1.2.3 From 0e858f8d6f66df25545861759e174023bd7d5c1f Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 21 Oct 2016 12:37:58 -0400 Subject: dmaengine: qcom_hidma: protect common data structures When MSI interrupts are supported, error and the transfer interrupt can come from multiple processor contexts. Each error interrupt is an MSI interrupt. If the channel is disabled by the first error interrupt, the remaining error interrupts will gracefully return in the interrupt handler. If an error is observed while servicing the completions in success case, the posting of the completions will be aborted as soon as channel disabled state is observed. The error interrupt handler will take it from there and finish the remaining completions. We don't want to create multiple success and error messages to be delivered to the client in mixed order. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_ll.c | 44 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 9193f466c9e7..7fe43afcbe32 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -198,13 +198,16 @@ static void hidma_ll_tre_complete(unsigned long arg) } } -static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator, - u8 err_info, u8 err_code) +static int hidma_post_completed(struct hidma_lldev *lldev, u8 err_info, + u8 err_code) { struct hidma_tre *tre; unsigned long flags; + u32 tre_iterator; spin_lock_irqsave(&lldev->lock, flags); + + tre_iterator = lldev->tre_processed_off; tre = lldev->pending_tre_list[tre_iterator / HIDMA_TRE_SIZE]; if (!tre) { spin_unlock_irqrestore(&lldev->lock, flags); @@ -223,6 +226,9 @@ static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator, atomic_set(&lldev->pending_tre_count, 0); } + HIDMA_INCREMENT_ITERATOR(tre_iterator, HIDMA_TRE_SIZE, + lldev->tre_ring_size); + lldev->tre_processed_off = tre_iterator; spin_unlock_irqrestore(&lldev->lock, flags); tre->err_info = err_info; @@ -244,13 +250,11 @@ static int hidma_post_completed(struct hidma_lldev *lldev, int tre_iterator, static int hidma_handle_tre_completion(struct hidma_lldev *lldev) { u32 evre_ring_size = lldev->evre_ring_size; - u32 tre_ring_size = lldev->tre_ring_size; u32 err_info, err_code, evre_write_off; - u32 tre_iterator, evre_iterator; + u32 evre_iterator; u32 num_completed = 0; evre_write_off = readl_relaxed(lldev->evca + HIDMA_EVCA_WRITE_PTR_REG); - tre_iterator = lldev->tre_processed_off; evre_iterator = lldev->evre_processed_off; if ((evre_write_off > evre_ring_size) || @@ -273,12 +277,9 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev) err_code = (cfg >> HIDMA_EVRE_CODE_BIT_POS) & HIDMA_EVRE_CODE_MASK; - if (hidma_post_completed(lldev, tre_iterator, err_info, - err_code)) + if (hidma_post_completed(lldev, err_info, err_code)) break; - HIDMA_INCREMENT_ITERATOR(tre_iterator, HIDMA_TRE_SIZE, - tre_ring_size); HIDMA_INCREMENT_ITERATOR(evre_iterator, HIDMA_EVRE_SIZE, evre_ring_size); @@ -302,16 +303,10 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev) if (num_completed) { u32 evre_read_off = (lldev->evre_processed_off + HIDMA_EVRE_SIZE * num_completed); - u32 tre_read_off = (lldev->tre_processed_off + - HIDMA_TRE_SIZE * num_completed); - evre_read_off = evre_read_off % evre_ring_size; - tre_read_off = tre_read_off % tre_ring_size; - writel(evre_read_off, lldev->evca + HIDMA_EVCA_DOORBELL_REG); /* record the last processed tre offset */ - lldev->tre_processed_off = tre_read_off; lldev->evre_processed_off = evre_read_off; } @@ -321,27 +316,10 @@ static int hidma_handle_tre_completion(struct hidma_lldev *lldev) void hidma_cleanup_pending_tre(struct hidma_lldev *lldev, u8 err_info, u8 err_code) { - u32 tre_iterator; - u32 tre_ring_size = lldev->tre_ring_size; - int num_completed = 0; - u32 tre_read_off; - - tre_iterator = lldev->tre_processed_off; while (atomic_read(&lldev->pending_tre_count)) { - if (hidma_post_completed(lldev, tre_iterator, err_info, - err_code)) + if (hidma_post_completed(lldev, err_info, err_code)) break; - HIDMA_INCREMENT_ITERATOR(tre_iterator, HIDMA_TRE_SIZE, - tre_ring_size); - num_completed++; } - tre_read_off = (lldev->tre_processed_off + - HIDMA_TRE_SIZE * num_completed); - - tre_read_off = tre_read_off % tre_ring_size; - - /* record the last processed tre offset */ - lldev->tre_processed_off = tre_read_off; } static int hidma_ll_reset(struct hidma_lldev *lldev) -- cgit v1.2.3 From 1c0e3e82a7fb01c7398ea9533f57c0a77099428f Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Fri, 21 Oct 2016 12:37:59 -0400 Subject: dmaengine: qcom_hidma: add MSI support for interrupts The interrupts can now be delivered as platform MSI interrupts on newer platforms. The code looks for a new OF and ACPI strings in order to enable the functionality. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 143 ++++++++++++++++++++++++++++++++++++++++++-- drivers/dma/qcom/hidma.h | 2 + drivers/dma/qcom/hidma_ll.c | 8 +++ 3 files changed, 147 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index e244e10a94b5..d5e7991ad737 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -56,6 +56,7 @@ #include #include #include +#include #include "../dmaengine.h" #include "hidma.h" @@ -70,6 +71,7 @@ #define HIDMA_ERR_INFO_SW 0xFF #define HIDMA_ERR_CODE_UNEXPECTED_TERMINATE 0x0 #define HIDMA_NR_DEFAULT_DESC 10 +#define HIDMA_MSI_INTS 11 static inline struct hidma_dev *to_hidma_dev(struct dma_device *dmadev) { @@ -553,6 +555,15 @@ static irqreturn_t hidma_chirq_handler(int chirq, void *arg) return hidma_ll_inthandler(chirq, lldev); } +static irqreturn_t hidma_chirq_handler_msi(int chirq, void *arg) +{ + struct hidma_lldev **lldevp = arg; + struct hidma_dev *dmadev = to_hidma_dev_from_lldev(lldevp); + + return hidma_ll_inthandler_msi(chirq, *lldevp, + 1 << (chirq - dmadev->msi_virqbase)); +} + static ssize_t hidma_show_values(struct device *dev, struct device_attribute *attr, char *buf) { @@ -590,6 +601,104 @@ static int hidma_create_sysfs_entry(struct hidma_dev *dev, char *name, return device_create_file(dev->ddev.dev, attrs); } +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN +static void hidma_write_msi_msg(struct msi_desc *desc, struct msi_msg *msg) +{ + struct device *dev = msi_desc_to_dev(desc); + struct hidma_dev *dmadev = dev_get_drvdata(dev); + + if (!desc->platform.msi_index) { + writel(msg->address_lo, dmadev->dev_evca + 0x118); + writel(msg->address_hi, dmadev->dev_evca + 0x11C); + writel(msg->data, dmadev->dev_evca + 0x120); + } +} +#endif + +static void hidma_free_msis(struct hidma_dev *dmadev) +{ +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN + struct device *dev = dmadev->ddev.dev; + struct msi_desc *desc; + + /* free allocated MSI interrupts above */ + for_each_msi_entry(desc, dev) + devm_free_irq(dev, desc->irq, &dmadev->lldev); + + platform_msi_domain_free_irqs(dev); +#endif +} + +static int hidma_request_msi(struct hidma_dev *dmadev, + struct platform_device *pdev) +{ +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN + int rc; + struct msi_desc *desc; + struct msi_desc *failed_desc = NULL; + + rc = platform_msi_domain_alloc_irqs(&pdev->dev, HIDMA_MSI_INTS, + hidma_write_msi_msg); + if (rc) + return rc; + + for_each_msi_entry(desc, &pdev->dev) { + if (!desc->platform.msi_index) + dmadev->msi_virqbase = desc->irq; + + rc = devm_request_irq(&pdev->dev, desc->irq, + hidma_chirq_handler_msi, + 0, "qcom-hidma-msi", + &dmadev->lldev); + if (rc) { + failed_desc = desc; + break; + } + } + + if (rc) { + /* free allocated MSI interrupts above */ + for_each_msi_entry(desc, &pdev->dev) { + if (desc == failed_desc) + break; + devm_free_irq(&pdev->dev, desc->irq, + &dmadev->lldev); + } + } else { + /* Add callback to free MSIs on teardown */ + hidma_ll_setup_irq(dmadev->lldev, true); + + } + if (rc) + dev_warn(&pdev->dev, + "failed to request MSI irq, falling back to wired IRQ\n"); + return rc; +#else + return -EINVAL; +#endif +} + +static bool hidma_msi_capable(struct device *dev) +{ + struct acpi_device *adev = ACPI_COMPANION(dev); + const char *of_compat; + int ret = -EINVAL; + + if (!adev || acpi_disabled) { + ret = device_property_read_string(dev, "compatible", + &of_compat); + if (ret) + return false; + + ret = strcmp(of_compat, "qcom,hidma-1.1"); + } else { +#ifdef CONFIG_ACPI + ret = strcmp(acpi_device_hid(adev), "QCOM8062"); +#endif + } + return ret == 0; +} + static int hidma_probe(struct platform_device *pdev) { struct hidma_dev *dmadev; @@ -599,6 +708,7 @@ static int hidma_probe(struct platform_device *pdev) void __iomem *evca; void __iomem *trca; int rc; + bool msi; pm_runtime_set_autosuspend_delay(&pdev->dev, HIDMA_AUTOSUSPEND_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); @@ -660,6 +770,12 @@ static int hidma_probe(struct platform_device *pdev) dmadev->ddev.device_terminate_all = hidma_terminate_all; dmadev->ddev.copy_align = 8; + /* + * Determine the MSI capability of the platform. Old HW doesn't + * support MSI. + */ + msi = hidma_msi_capable(&pdev->dev); + device_property_read_u32(&pdev->dev, "desc-count", &dmadev->nr_descriptors); @@ -688,10 +804,17 @@ static int hidma_probe(struct platform_device *pdev) goto dmafree; } - rc = devm_request_irq(&pdev->dev, chirq, hidma_chirq_handler, 0, - "qcom-hidma", dmadev->lldev); - if (rc) - goto uninit; + platform_set_drvdata(pdev, dmadev); + if (msi) + rc = hidma_request_msi(dmadev, pdev); + + if (!msi || rc) { + hidma_ll_setup_irq(dmadev->lldev, false); + rc = devm_request_irq(&pdev->dev, chirq, hidma_chirq_handler, + 0, "qcom-hidma", dmadev->lldev); + if (rc) + goto uninit; + } INIT_LIST_HEAD(&dmadev->ddev.channels); rc = hidma_chan_init(dmadev, 0); @@ -707,12 +830,14 @@ static int hidma_probe(struct platform_device *pdev) hidma_debug_init(dmadev); hidma_create_sysfs_entry(dmadev, "chid", S_IRUGO); dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n"); - platform_set_drvdata(pdev, dmadev); pm_runtime_mark_last_busy(dmadev->ddev.dev); pm_runtime_put_autosuspend(dmadev->ddev.dev); return 0; uninit: + if (msi) + hidma_free_msis(dmadev); + hidma_debug_uninit(dmadev); hidma_ll_uninit(dmadev->lldev); dmafree: @@ -730,7 +855,11 @@ static int hidma_remove(struct platform_device *pdev) pm_runtime_get_sync(dmadev->ddev.dev); dma_async_device_unregister(&dmadev->ddev); - devm_free_irq(dmadev->ddev.dev, dmadev->irq, dmadev->lldev); + if (!dmadev->lldev->msi_support) + devm_free_irq(dmadev->ddev.dev, dmadev->irq, dmadev->lldev); + else + hidma_free_msis(dmadev); + tasklet_kill(&dmadev->task); hidma_debug_uninit(dmadev); hidma_ll_uninit(dmadev->lldev); @@ -746,12 +875,14 @@ static int hidma_remove(struct platform_device *pdev) #if IS_ENABLED(CONFIG_ACPI) static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8061"}, + {"QCOM8062"}, {}, }; #endif static const struct of_device_id hidma_match[] = { {.compatible = "qcom,hidma-1.0",}, + {.compatible = "qcom,hidma-1.1",}, {}, }; MODULE_DEVICE_TABLE(of, hidma_match); diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h index 181f7e0d08f6..05f8ba49e6c6 100644 --- a/drivers/dma/qcom/hidma.h +++ b/drivers/dma/qcom/hidma.h @@ -115,6 +115,7 @@ struct hidma_dev { int irq; int chidx; u32 nr_descriptors; + int msi_virqbase; struct hidma_lldev *lldev; void __iomem *dev_trca; @@ -153,6 +154,7 @@ struct hidma_lldev *hidma_ll_init(struct device *dev, u32 max_channels, u8 chidx); int hidma_ll_uninit(struct hidma_lldev *llhndl); irqreturn_t hidma_ll_inthandler(int irq, void *arg); +irqreturn_t hidma_ll_inthandler_msi(int irq, void *arg, int cause); void hidma_cleanup_pending_tre(struct hidma_lldev *llhndl, u8 err_info, u8 err_code); int hidma_debug_init(struct hidma_dev *dmadev); diff --git a/drivers/dma/qcom/hidma_ll.c b/drivers/dma/qcom/hidma_ll.c index 7fe43afcbe32..6645bdf0d151 100644 --- a/drivers/dma/qcom/hidma_ll.c +++ b/drivers/dma/qcom/hidma_ll.c @@ -457,6 +457,14 @@ irqreturn_t hidma_ll_inthandler(int chirq, void *arg) return IRQ_HANDLED; } +irqreturn_t hidma_ll_inthandler_msi(int chirq, void *arg, int cause) +{ + struct hidma_lldev *lldev = arg; + + hidma_ll_int_handler_internal(lldev, cause); + return IRQ_HANDLED; +} + int hidma_ll_enable(struct hidma_lldev *lldev) { u32 val; -- cgit v1.2.3 From c18b4c52c755175dc62aed7b409dca24f028ce76 Mon Sep 17 00:00:00 2001 From: Mirza Krak Date: Mon, 17 Oct 2016 15:53:31 +0200 Subject: rtc: pcf85063: do not register a RTC device if chip is not present Add a sanity check to see if chip is present. If we can not communicate with the chip there is no point in registering a RTC device. Signed-off-by: Mirza Krak Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index efb0a08ac117..a06dff994c83 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -191,12 +191,19 @@ static int pcf85063_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct rtc_device *rtc; + int err; dev_dbg(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; + err = i2c_smbus_read_byte_data(client, PCF85063_REG_CTRL1); + if (err < 0) { + dev_err(&client->dev, "RTC chip is not present\n"); + return err; + } + rtc = devm_rtc_device_register(&client->dev, pcf85063_driver.driver.name, &pcf85063_rtc_ops, THIS_MODULE); -- cgit v1.2.3 From 87ebfd6439c12df09c3b4e319e1fa9e1ebba3d55 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 31 Oct 2016 14:55:25 -0400 Subject: rtc: make rtc-lib explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/rtc/Kconfig:config RTC_LIB drivers/rtc/Kconfig: bool ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. We delete the MODULE_LICENSE tag since all that information is already contained at the top of the file in the comments. We don't replace module.h with init.h since the file doesn't need that. However we do add export.h since the file uses EXPORT_SYMBOL. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Paul Gortmaker Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-lib.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index e6bfb9c42a10..1ae7da5cfc60 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -11,7 +11,7 @@ * published by the Free Software Foundation. */ -#include +#include #include static const unsigned char rtc_days_in_month[] = { @@ -148,5 +148,3 @@ struct rtc_time rtc_ktime_to_tm(ktime_t kt) return ret; } EXPORT_SYMBOL_GPL(rtc_ktime_to_tm); - -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 683cec8a06a0f1e67ff8f00791471e3ff04ce0f0 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 31 Oct 2016 14:55:26 -0400 Subject: rtc: sparc: make starfire explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/rtc/Kconfig:config RTC_DRV_STARFIRE drivers/rtc/Kconfig: bool "Starfire RTC" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. We delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Cc: rtc-linux@googlegroups.com Signed-off-by: Paul Gortmaker Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-starfire.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c index 83a057a03060..7fc36973fa33 100644 --- a/drivers/rtc/rtc-starfire.c +++ b/drivers/rtc/rtc-starfire.c @@ -1,20 +1,18 @@ /* rtc-starfire.c: Starfire platform RTC driver. + * + * Author: David S. Miller + * License: GPL * * Copyright (C) 2008 David S. Miller */ #include -#include #include #include #include #include -MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("Starfire RTC driver"); -MODULE_LICENSE("GPL"); - static u32 starfire_get_time(void) { static char obp_gettod[32]; @@ -57,4 +55,4 @@ static struct platform_driver starfire_rtc_driver = { }, }; -module_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe); +builtin_platform_driver_probe(starfire_rtc_driver, starfire_rtc_probe); -- cgit v1.2.3 From 8b6102534cef64624caca7eb0a15e83f5ab9864c Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 31 Oct 2016 14:55:27 -0400 Subject: rtc: sparc: make sun4v explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/rtc/Kconfig:config RTC_DRV_SUN4V drivers/rtc/Kconfig: bool "SUN4V Hypervisor RTC" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. We delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: "David S. Miller" Cc: sparclinux@vger.kernel.org Cc: rtc-linux@googlegroups.com Signed-off-by: Paul Gortmaker Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun4v.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c index 7c696c12f28f..11bc562eba5d 100644 --- a/drivers/rtc/rtc-sun4v.c +++ b/drivers/rtc/rtc-sun4v.c @@ -1,4 +1,7 @@ /* rtc-sun4v.c: Hypervisor based RTC for SUN4V systems. + * + * Author: David S. Miller + * License: GPL * * Copyright (C) 2008 David S. Miller */ @@ -6,7 +9,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include -#include #include #include #include @@ -98,8 +100,4 @@ static struct platform_driver sun4v_rtc_driver = { }, }; -module_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe); - -MODULE_AUTHOR("David S. Miller "); -MODULE_DESCRIPTION("SUN4V RTC driver"); -MODULE_LICENSE("GPL"); +builtin_platform_driver_probe(sun4v_rtc_driver, sun4v_rtc_probe); -- cgit v1.2.3 From cd563200c090de628eb71c7478f272eaedc6fa4d Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 31 Oct 2016 21:39:45 +0100 Subject: rtc: jz4740: Add support for the RTC in the jz4780 SoC The RTC unit present in the JZ4780 works mostly the same as the one in the JZ4740. The major difference is that register writes need to be explicitly enabled, by writing a magic code (0xA55A) to a "write enable" register before each access. Signed-off-by: Paul Cercueil Acked-by: Maarten ter Huurne Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 6 +++--- drivers/rtc/rtc-jz4740.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4cbea34e6003..1d0ae30e9927 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1550,10 +1550,10 @@ config RTC_DRV_MPC5121 config RTC_DRV_JZ4740 tristate "Ingenic JZ4740 SoC" - depends on MACH_JZ4740 || COMPILE_TEST + depends on MACH_INGENIC || COMPILE_TEST help - If you say yes here you get support for the Ingenic JZ4740 SoC RTC - controller. + If you say yes here you get support for the Ingenic JZ47xx SoCs RTC + controllers. This driver can also be buillt as a module. If so, the module will be called rtc-jz4740. diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 5e14651b71a8..7ad2d7965b4e 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -29,6 +29,10 @@ #define JZ_REG_RTC_HIBERNATE 0x20 #define JZ_REG_RTC_SCRATCHPAD 0x34 +/* The following are present on the jz4780 */ +#define JZ_REG_RTC_WENR 0x3C +#define JZ_RTC_WENR_WEN BIT(31) + #define JZ_RTC_CTRL_WRDY BIT(7) #define JZ_RTC_CTRL_1HZ BIT(6) #define JZ_RTC_CTRL_1HZ_IRQ BIT(5) @@ -37,8 +41,17 @@ #define JZ_RTC_CTRL_AE BIT(2) #define JZ_RTC_CTRL_ENABLE BIT(0) +/* Magic value to enable writes on jz4780 */ +#define JZ_RTC_WENR_MAGIC 0xA55A + +enum jz4740_rtc_type { + ID_JZ4740, + ID_JZ4780, +}; + struct jz4740_rtc { void __iomem *base; + enum jz4740_rtc_type type; struct rtc_device *rtc; @@ -64,11 +77,33 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc) return timeout ? 0 : -EIO; } +static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc) +{ + uint32_t ctrl; + int ret, timeout = 1000; + + ret = jz4740_rtc_wait_write_ready(rtc); + if (ret != 0) + return ret; + + writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR); + + do { + ctrl = readl(rtc->base + JZ_REG_RTC_WENR); + } while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout); + + return timeout ? 0 : -EIO; +} + static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg, uint32_t val) { - int ret; - ret = jz4740_rtc_wait_write_ready(rtc); + int ret = 0; + + if (rtc->type >= ID_JZ4780) + ret = jz4780_rtc_enable_write(rtc); + if (ret == 0) + ret = jz4740_rtc_wait_write_ready(rtc); if (ret == 0) writel(val, rtc->base + reg); @@ -216,11 +251,14 @@ static int jz4740_rtc_probe(struct platform_device *pdev) struct jz4740_rtc *rtc; uint32_t scratchpad; struct resource *mem; + const struct platform_device_id *id = platform_get_device_id(pdev); rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; + rtc->type = id->driver_data; + rtc->irq = platform_get_irq(pdev, 0); if (rtc->irq < 0) { dev_err(&pdev->dev, "Failed to get platform irq\n"); @@ -295,12 +333,20 @@ static const struct dev_pm_ops jz4740_pm_ops = { #define JZ4740_RTC_PM_OPS NULL #endif /* CONFIG_PM */ +static const struct platform_device_id jz4740_rtc_ids[] = { + { "jz4740-rtc", ID_JZ4740 }, + { "jz4780-rtc", ID_JZ4780 }, + {} +}; +MODULE_DEVICE_TABLE(platform, jz4740_rtc_ids); + static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, .driver = { .name = "jz4740-rtc", .pm = JZ4740_RTC_PM_OPS, }, + .id_table = jz4740_rtc_ids, }; module_platform_driver(jz4740_rtc_driver); -- cgit v1.2.3 From c05229a893e79dc992abe0e561d7da0e3e84e1d8 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 31 Oct 2016 21:39:47 +0100 Subject: rtc: jz4740: Add support for devicetree See Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt for a description of the bindings. Signed-off-by: Paul Cercueil Acked-by: Maarten ter Huurne Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 7ad2d7965b4e..c2895cec56b4 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -245,6 +246,13 @@ void jz4740_rtc_poweroff(struct device *dev) } EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff); +static const struct of_device_id jz4740_rtc_of_match[] = { + { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 }, + { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, + {}, +}; +MODULE_DEVICE_TABLE(of, jz4740_rtc_of_match); + static int jz4740_rtc_probe(struct platform_device *pdev) { int ret; @@ -252,12 +260,17 @@ static int jz4740_rtc_probe(struct platform_device *pdev) uint32_t scratchpad; struct resource *mem; const struct platform_device_id *id = platform_get_device_id(pdev); + const struct of_device_id *of_id = of_match_device( + jz4740_rtc_of_match, &pdev->dev); rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; - rtc->type = id->driver_data; + if (of_id) + rtc->type = (enum jz4740_rtc_type)of_id->data; + else + rtc->type = id->driver_data; rtc->irq = platform_get_irq(pdev, 0); if (rtc->irq < 0) { @@ -345,6 +358,7 @@ static struct platform_driver jz4740_rtc_driver = { .driver = { .name = "jz4740-rtc", .pm = JZ4740_RTC_PM_OPS, + .of_match_table = of_match_ptr(jz4740_rtc_of_match), }, .id_table = jz4740_rtc_ids, }; -- cgit v1.2.3 From f9eb69d1ae2f82b0e556852bf719f550c2a34193 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Mon, 31 Oct 2016 21:39:48 +0100 Subject: rtc: jz4740: Add support for acting as the system power controller The 'system-power-controller' singleton entry can be used in the devicetree node of the jz4740-rtc driver to specify that the driver is granted the right to power off the system through the registers of the RTC unit. See the documentation for more details: Documentation/devicetree/bindings/rtc/ingenic,jz4740-rtc.txt Signed-off-by: Paul Cercueil Acked-by: Maarten ter Huurne Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) (limited to 'drivers') diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index c2895cec56b4..33ccd73ee947 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -14,11 +14,13 @@ * */ +#include #include #include #include #include #include +#include #include #include #include @@ -28,6 +30,8 @@ #define JZ_REG_RTC_SEC_ALARM 0x08 #define JZ_REG_RTC_REGULATOR 0x0C #define JZ_REG_RTC_HIBERNATE 0x20 +#define JZ_REG_RTC_WAKEUP_FILTER 0x24 +#define JZ_REG_RTC_RESET_COUNTER 0x28 #define JZ_REG_RTC_SCRATCHPAD 0x34 /* The following are present on the jz4780 */ @@ -45,6 +49,9 @@ /* Magic value to enable writes on jz4780 */ #define JZ_RTC_WENR_MAGIC 0xA55A +#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 +#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 + enum jz4740_rtc_type { ID_JZ4740, ID_JZ4780, @@ -55,12 +62,18 @@ struct jz4740_rtc { enum jz4740_rtc_type type; struct rtc_device *rtc; + struct clk *clk; int irq; spinlock_t lock; + + unsigned int min_wakeup_pin_assert_time; + unsigned int reset_pin_assert_time; }; +static struct device *dev_for_power_off; + static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg) { return readl(rtc->base + reg); @@ -246,6 +259,46 @@ void jz4740_rtc_poweroff(struct device *dev) } EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff); +static void jz4740_rtc_power_off(void) +{ + struct jz4740_rtc *rtc = dev_get_drvdata(dev_for_power_off); + unsigned long rtc_rate; + unsigned long wakeup_filter_ticks; + unsigned long reset_counter_ticks; + + clk_prepare_enable(rtc->clk); + + rtc_rate = clk_get_rate(rtc->clk); + + /* + * Set minimum wakeup pin assertion time: 100 ms. + * Range is 0 to 2 sec if RTC is clocked at 32 kHz. + */ + wakeup_filter_ticks = + (rtc->min_wakeup_pin_assert_time * rtc_rate) / 1000; + if (wakeup_filter_ticks < JZ_RTC_WAKEUP_FILTER_MASK) + wakeup_filter_ticks &= JZ_RTC_WAKEUP_FILTER_MASK; + else + wakeup_filter_ticks = JZ_RTC_WAKEUP_FILTER_MASK; + jz4740_rtc_reg_write(rtc, + JZ_REG_RTC_WAKEUP_FILTER, wakeup_filter_ticks); + + /* + * Set reset pin low-level assertion time after wakeup: 60 ms. + * Range is 0 to 125 ms if RTC is clocked at 32 kHz. + */ + reset_counter_ticks = (rtc->reset_pin_assert_time * rtc_rate) / 1000; + if (reset_counter_ticks < JZ_RTC_RESET_COUNTER_MASK) + reset_counter_ticks &= JZ_RTC_RESET_COUNTER_MASK; + else + reset_counter_ticks = JZ_RTC_RESET_COUNTER_MASK; + jz4740_rtc_reg_write(rtc, + JZ_REG_RTC_RESET_COUNTER, reset_counter_ticks); + + jz4740_rtc_poweroff(dev_for_power_off); + machine_halt(); +} + static const struct of_device_id jz4740_rtc_of_match[] = { { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 }, { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, @@ -262,6 +315,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev) const struct platform_device_id *id = platform_get_device_id(pdev); const struct of_device_id *of_id = of_match_device( jz4740_rtc_of_match, &pdev->dev); + struct device_node *np = pdev->dev.of_node; rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) @@ -283,6 +337,12 @@ static int jz4740_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc->base)) return PTR_ERR(rtc->base); + rtc->clk = devm_clk_get(&pdev->dev, "rtc"); + if (IS_ERR(rtc->clk)) { + dev_err(&pdev->dev, "Failed to get RTC clock\n"); + return PTR_ERR(rtc->clk); + } + spin_lock_init(&rtc->lock); platform_set_drvdata(pdev, rtc); @@ -314,6 +374,27 @@ static int jz4740_rtc_probe(struct platform_device *pdev) } } + if (np && of_device_is_system_power_controller(np)) { + if (!pm_power_off) { + /* Default: 60ms */ + rtc->reset_pin_assert_time = 60; + of_property_read_u32(np, "reset-pin-assert-time-ms", + &rtc->reset_pin_assert_time); + + /* Default: 100ms */ + rtc->min_wakeup_pin_assert_time = 100; + of_property_read_u32(np, + "min-wakeup-pin-assert-time-ms", + &rtc->min_wakeup_pin_assert_time); + + dev_for_power_off = &pdev->dev; + pm_power_off = jz4740_rtc_power_off; + } else { + dev_warn(&pdev->dev, + "Poweroff handler already present!\n"); + } + } + return 0; } -- cgit v1.2.3 From 959df7778bbd3003fe2ade67e3b41ecb5e0ca25d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 2 Oct 2016 22:58:16 +0200 Subject: rtc: Enable compile testing for Maxim and Samsung drivers max8907, max77686 and s5m RTC drivers can be compile tested to increase build coverage. The s5m-rtc uses REGMAP_IRQ so add this as explicit dependency. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 1d0ae30e9927..4259ce61c31b 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -303,7 +303,7 @@ config RTC_DRV_MAX6900 config RTC_DRV_MAX8907 tristate "Maxim MAX8907" - depends on MFD_MAX8907 + depends on MFD_MAX8907 || COMPILE_TEST help If you say yes here you will get support for the RTC of Maxim MAX8907 PMIC. @@ -343,7 +343,7 @@ config RTC_DRV_MAX8997 config RTC_DRV_MAX77686 tristate "Maxim MAX77686" - depends on MFD_MAX77686 || MFD_MAX77620 + depends on MFD_MAX77686 || MFD_MAX77620 || COMPILE_TEST help If you say yes here you will get support for the RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC. @@ -602,7 +602,8 @@ config RTC_DRV_RV8803 config RTC_DRV_S5M tristate "Samsung S2M/S5M series" - depends on MFD_SEC_CORE + depends on MFD_SEC_CORE || COMPILE_TEST + select REGMAP_IRQ help If you say yes here you will get support for the RTC of Samsung S2MPS14 and S5M PMIC series. -- cgit v1.2.3 From e2474541032db65d02bf88b6a8c2f954654b443f Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Mon, 3 Oct 2016 22:06:08 +0200 Subject: i2c: bcm2835: Fix hang for writing messages larger than 16 bytes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Writing messages larger than the FIFO size results in a hang, rendering the machine unusable. This is because the RXD status flag is set on the first interrupt which results in bcm2835_drain_rxfifo() stealing bytes from the buffer. The controller continues to trigger interrupts waiting for the missing bytes, but bcm2835_fill_txfifo() has none to give. In this situation wait_for_completion_timeout() apparently is unable to stop the madness. The BCM2835 ARM Peripherals datasheet has this to say about the flags: TXD: is set when the FIFO has space for at least one byte of data. RXD: is set when the FIFO contains at least one byte of data. TXW: is set during a write transfer and the FIFO is less than full. RXR: is set during a read transfer and the FIFO is or more full. Implementing the logic from the downstream i2c-bcm2708 driver solved the hang problem. Signed-off-by: Noralf Trønnes Reviewed-by: Eric Anholt Reviewed-by: Martin Sperl Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index d4f3239b5686..f283b714aa79 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -64,6 +64,7 @@ struct bcm2835_i2c_dev { int irq; struct i2c_adapter adapter; struct completion completion; + struct i2c_msg *curr_msg; u32 msg_err; u8 *msg_buf; size_t msg_buf_remaining; @@ -126,14 +127,13 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) return IRQ_HANDLED; } - if (val & BCM2835_I2C_S_RXD) { - bcm2835_drain_rxfifo(i2c_dev); - if (!(val & BCM2835_I2C_S_DONE)) - return IRQ_HANDLED; - } - if (val & BCM2835_I2C_S_DONE) { - if (i2c_dev->msg_buf_remaining) + if (i2c_dev->curr_msg->flags & I2C_M_RD) { + bcm2835_drain_rxfifo(i2c_dev); + val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); + } + + if ((val & BCM2835_I2C_S_RXD) || i2c_dev->msg_buf_remaining) i2c_dev->msg_err = BCM2835_I2C_S_LEN; else i2c_dev->msg_err = 0; @@ -141,11 +141,16 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) return IRQ_HANDLED; } - if (val & BCM2835_I2C_S_TXD) { + if (val & BCM2835_I2C_S_TXW) { bcm2835_fill_txfifo(i2c_dev); return IRQ_HANDLED; } + if (val & BCM2835_I2C_S_RXR) { + bcm2835_drain_rxfifo(i2c_dev); + return IRQ_HANDLED; + } + return IRQ_NONE; } @@ -155,6 +160,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, u32 c; unsigned long time_left; + i2c_dev->curr_msg = msg; i2c_dev->msg_buf = msg->buf; i2c_dev->msg_buf_remaining = msg->len; reinit_completion(&i2c_dev->completion); -- cgit v1.2.3 From d4030d75c7cbb434b2a3e5f6af5065879d2615a5 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Mon, 3 Oct 2016 22:06:09 +0200 Subject: i2c: bcm2835: Protect against unexpected TXW/RXR interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If an unexpected TXW or RXR interrupt occurs (msg_buf_remaining == 0), the driver has no way to fill/drain the FIFO to stop the interrupts. In this case the controller has to be disabled and the transfer completed to avoid hang. (CLKT | ERR) and DONE interrupts are completed in their own paths, and the controller is disabled in the transfer function after completion. Unite the code paths and do disabling inside the interrupt routine. Clear interrupt status bits in the united completion path instead of trying to do it on every interrupt which isn't necessary. Only CLKT, ERR and DONE can be cleared that way. Add the status value to the error value in case of TXW/RXR errors to distinguish them from the other S_LEN error. Signed-off-by: Noralf Trønnes Reviewed-by: Eric Anholt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index f283b714aa79..d2ba1a4de36a 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -50,8 +50,6 @@ #define BCM2835_I2C_S_CLKT BIT(9) #define BCM2835_I2C_S_LEN BIT(10) /* Fake bit for SW error reporting */ -#define BCM2835_I2C_BITMSK_S 0x03FF - #define BCM2835_I2C_CDIV_MIN 0x0002 #define BCM2835_I2C_CDIV_MAX 0xFFFE @@ -111,20 +109,26 @@ static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev) } } +/* + * Note about I2C_C_CLEAR on error: + * The I2C_C_CLEAR on errors will take some time to resolve -- if you were in + * non-idle state and I2C_C_READ, it sets an abort_rx flag and runs through + * the state machine to send a NACK and a STOP. Since we're setting CLEAR + * without I2CEN, that NACK will be hanging around queued up for next time + * we start the engine. + */ + static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) { struct bcm2835_i2c_dev *i2c_dev = data; u32 val, err; val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); - val &= BCM2835_I2C_BITMSK_S; - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, val); err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); if (err) { i2c_dev->msg_err = err; - complete(&i2c_dev->completion); - return IRQ_HANDLED; + goto complete; } if (val & BCM2835_I2C_S_DONE) { @@ -137,21 +141,38 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) i2c_dev->msg_err = BCM2835_I2C_S_LEN; else i2c_dev->msg_err = 0; - complete(&i2c_dev->completion); - return IRQ_HANDLED; + goto complete; } if (val & BCM2835_I2C_S_TXW) { + if (!i2c_dev->msg_buf_remaining) { + i2c_dev->msg_err = val | BCM2835_I2C_S_LEN; + goto complete; + } + bcm2835_fill_txfifo(i2c_dev); return IRQ_HANDLED; } if (val & BCM2835_I2C_S_RXR) { + if (!i2c_dev->msg_buf_remaining) { + i2c_dev->msg_err = val | BCM2835_I2C_S_LEN; + goto complete; + } + bcm2835_drain_rxfifo(i2c_dev); return IRQ_HANDLED; } return IRQ_NONE; + +complete: + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_S, BCM2835_I2C_S_CLKT | + BCM2835_I2C_S_ERR | BCM2835_I2C_S_DONE); + complete(&i2c_dev->completion); + + return IRQ_HANDLED; } static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, @@ -181,8 +202,9 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, time_left = wait_for_completion_timeout(&i2c_dev->completion, BCM2835_I2C_TIMEOUT); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); if (!time_left) { + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, + BCM2835_I2C_C_CLEAR); dev_err(i2c_dev->dev, "i2c transfer timed out\n"); return -ETIMEDOUT; } -- cgit v1.2.3 From 23c9540b3ad1d7473fe40df80074d0fb0bf04869 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Mon, 3 Oct 2016 22:06:10 +0200 Subject: i2c: bcm2835: Use dev_dbg logging on transfer errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Writing to an AT24C32 generates on average 2x i2c transfer errors per 32-byte page write. Which amounts to a lot for a 4k write. This is due to the fact that the chip doesn't respond during it's internal write cycle when the at24 driver tries and retries the next write. Only a handful drivers use dev_err() on transfer error, so switch to dev_dbg() instead. Signed-off-by: Noralf Trønnes Reviewed-by: Eric Anholt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index d2ba1a4de36a..54d510abd46a 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -216,7 +216,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, (msg->flags & I2C_M_IGNORE_NAK)) return 0; - dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); + dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; -- cgit v1.2.3 From 8d2cc5cc6ee5c0fc48a96bb29af55fc700f66fdf Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Mon, 3 Oct 2016 22:06:11 +0200 Subject: i2c: bcm2835: Can't support I2C_M_IGNORE_NAK MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The controller can't support this flag, so remove it. Documentation/i2c/i2c-protocol states that all of the message is sent: I2C_M_IGNORE_NAK: Normally message is interrupted immediately if there is [NA] from the client. Setting this flag treats any [NA] as [A], and all of message is sent. >From the BCM2835 ARM Peripherals datasheet: The ERR field is set when the slave fails to acknowledge either its address or a data byte written to it. So when the controller doesn't receive an ack, it sets ERR and raises an interrupt. In other words, the whole message is not sent. Signed-off-by: Noralf Trønnes Reviewed-by: Eric Anholt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 54d510abd46a..565ef69ce614 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -212,10 +212,6 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, if (likely(!i2c_dev->msg_err)) return 0; - if ((i2c_dev->msg_err & BCM2835_I2C_S_ERR) && - (msg->flags & I2C_M_IGNORE_NAK)) - return 0; - dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) -- cgit v1.2.3 From ee05fea21b017b81a9477569b6a0c2d8e2946ac9 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Mon, 3 Oct 2016 22:06:12 +0200 Subject: i2c: bcm2835: Add support for Repeated Start Condition MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documentation/i2c/i2c-protocol states that Combined transactions should separate messages with a Start bit and end the whole transaction with a Stop bit. This patch adds support for issuing only a Start between messages instead of a Stop followed by a Start. This implementation differs from downstream i2c-bcm2708 in 2 respects: - it uses an interrupt to detect that the transfer is active instead of using polling. There is no interrupt for Transfer Active, but by not prefilling the FIFO it's possible to use the TXW interrupt. - when resetting/disabling the controller between transfers it writes CLEAR to the control register instead of just zero. Using just zero gave many errors. This might be the reason why downstream had to disable this feature and make it available with a module parameter. I have run thousands of transfers to a DS1307 (rtc), MMA8451 (accel) and AT24C32 (eeprom) in parallel without problems. Signed-off-by: Noralf Trønnes Acked-by: Eric Anholt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 101 ++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 565ef69ce614..241e08ae7c27 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -63,6 +63,7 @@ struct bcm2835_i2c_dev { struct i2c_adapter adapter; struct completion completion; struct i2c_msg *curr_msg; + int num_msgs; u32 msg_err; u8 *msg_buf; size_t msg_buf_remaining; @@ -109,6 +110,45 @@ static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev) } } +/* + * Repeated Start Condition (Sr) + * The BCM2835 ARM Peripherals datasheet mentions a way to trigger a Sr when it + * talks about reading from a slave with 10 bit address. This is achieved by + * issuing a write, poll the I2CS.TA flag and wait for it to be set, and then + * issue a read. + * A comment in https://github.com/raspberrypi/linux/issues/254 shows how the + * firmware actually does it using polling and says that it's a workaround for + * a problem in the state machine. + * It turns out that it is possible to use the TXW interrupt to know when the + * transfer is active, provided the FIFO has not been prefilled. + */ + +static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev) +{ + u32 c = BCM2835_I2C_C_ST | BCM2835_I2C_C_I2CEN; + struct i2c_msg *msg = i2c_dev->curr_msg; + bool last_msg = (i2c_dev->num_msgs == 1); + + if (!i2c_dev->num_msgs) + return; + + i2c_dev->num_msgs--; + i2c_dev->msg_buf = msg->buf; + i2c_dev->msg_buf_remaining = msg->len; + + if (msg->flags & I2C_M_RD) + c |= BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR; + else + c |= BCM2835_I2C_C_INTT; + + if (last_msg) + c |= BCM2835_I2C_C_INTD; + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len); + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c); +} + /* * Note about I2C_C_CLEAR on error: * The I2C_C_CLEAR on errors will take some time to resolve -- if you were in @@ -151,6 +191,12 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) } bcm2835_fill_txfifo(i2c_dev); + + if (i2c_dev->num_msgs && !i2c_dev->msg_buf_remaining) { + i2c_dev->curr_msg++; + bcm2835_i2c_start_transfer(i2c_dev); + } + return IRQ_HANDLED; } @@ -175,30 +221,25 @@ complete: return IRQ_HANDLED; } -static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, - struct i2c_msg *msg) +static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], + int num) { - u32 c; + struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); unsigned long time_left; + int i; - i2c_dev->curr_msg = msg; - i2c_dev->msg_buf = msg->buf; - i2c_dev->msg_buf_remaining = msg->len; - reinit_completion(&i2c_dev->completion); - - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); + for (i = 0; i < (num - 1); i++) + if (msgs[i].flags & I2C_M_RD) { + dev_warn_once(i2c_dev->dev, + "only one read message supported, has to be last\n"); + return -EOPNOTSUPP; + } - if (msg->flags & I2C_M_RD) { - c = BCM2835_I2C_C_READ | BCM2835_I2C_C_INTR; - } else { - c = BCM2835_I2C_C_INTT; - bcm2835_fill_txfifo(i2c_dev); - } - c |= BCM2835_I2C_C_ST | BCM2835_I2C_C_INTD | BCM2835_I2C_C_I2CEN; + i2c_dev->curr_msg = msgs; + i2c_dev->num_msgs = num; + reinit_completion(&i2c_dev->completion); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c); + bcm2835_i2c_start_transfer(i2c_dev); time_left = wait_for_completion_timeout(&i2c_dev->completion, BCM2835_I2C_TIMEOUT); @@ -209,31 +250,15 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev, return -ETIMEDOUT; } - if (likely(!i2c_dev->msg_err)) - return 0; + if (!i2c_dev->msg_err) + return num; dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) return -EREMOTEIO; - else - return -EIO; -} - -static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - int num) -{ - struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - int i; - int ret = 0; - - for (i = 0; i < num; i++) { - ret = bcm2835_i2c_xfer_msg(i2c_dev, &msgs[i]); - if (ret) - break; - } - return ret ?: i; + return -EIO; } static u32 bcm2835_i2c_func(struct i2c_adapter *adap) -- cgit v1.2.3 From e13e19e12f66401ce1e21ab491715835852babe7 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Mon, 3 Oct 2016 22:06:13 +0200 Subject: i2c: bcm2835: Support i2c-dev ioctl I2C_TIMEOUT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use i2c_adapter->timeout for the completion timeout value. The core default is 1 second. Signed-off-by: Noralf Trønnes Reviewed-by: Eric Anholt Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index 241e08ae7c27..d2085dd3742e 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -53,8 +53,6 @@ #define BCM2835_I2C_CDIV_MIN 0x0002 #define BCM2835_I2C_CDIV_MAX 0xFFFE -#define BCM2835_I2C_TIMEOUT (msecs_to_jiffies(1000)) - struct bcm2835_i2c_dev { struct device *dev; void __iomem *regs; @@ -242,7 +240,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], bcm2835_i2c_start_transfer(i2c_dev); time_left = wait_for_completion_timeout(&i2c_dev->completion, - BCM2835_I2C_TIMEOUT); + adap->timeout); if (!time_left) { bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); -- cgit v1.2.3 From 9446f62e8e18057fceb179d947508df2f7253b26 Mon Sep 17 00:00:00 2001 From: Noralf Trønnes Date: Mon, 3 Oct 2016 22:06:14 +0200 Subject: i2c: bcm2835: Add support for dynamic clock MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Support a dynamic clock by reading the frequency and setting the divisor in the transfer function instead of during probe. Signed-off-by: Noralf Trønnes Reviewed-by: Martin Sperl Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 51 +++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index d2085dd3742e..c3436f627028 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -58,6 +58,7 @@ struct bcm2835_i2c_dev { void __iomem *regs; struct clk *clk; int irq; + u32 bus_clk_rate; struct i2c_adapter adapter; struct completion completion; struct i2c_msg *curr_msg; @@ -78,6 +79,30 @@ static inline u32 bcm2835_i2c_readl(struct bcm2835_i2c_dev *i2c_dev, u32 reg) return readl(i2c_dev->regs + reg); } +static int bcm2835_i2c_set_divider(struct bcm2835_i2c_dev *i2c_dev) +{ + u32 divider; + + divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), + i2c_dev->bus_clk_rate); + /* + * Per the datasheet, the register is always interpreted as an even + * number, by rounding down. In other words, the LSB is ignored. So, + * if the LSB is set, increment the divider to avoid any issue. + */ + if (divider & 1) + divider++; + if ((divider < BCM2835_I2C_CDIV_MIN) || + (divider > BCM2835_I2C_CDIV_MAX)) { + dev_err_ratelimited(i2c_dev->dev, "Invalid clock-frequency\n"); + return -EINVAL; + } + + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); + + return 0; +} + static void bcm2835_fill_txfifo(struct bcm2835_i2c_dev *i2c_dev) { u32 val; @@ -224,7 +249,7 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], { struct bcm2835_i2c_dev *i2c_dev = i2c_get_adapdata(adap); unsigned long time_left; - int i; + int i, ret; for (i = 0; i < (num - 1); i++) if (msgs[i].flags & I2C_M_RD) { @@ -233,6 +258,10 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], return -EOPNOTSUPP; } + ret = bcm2835_i2c_set_divider(i2c_dev); + if (ret) + return ret; + i2c_dev->curr_msg = msgs; i2c_dev->num_msgs = num; reinit_completion(&i2c_dev->completion); @@ -282,7 +311,6 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev; struct resource *mem, *irq; - u32 bus_clk_rate, divider; int ret; struct i2c_adapter *adap; @@ -306,27 +334,12 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) } ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &bus_clk_rate); + &i2c_dev->bus_clk_rate); if (ret < 0) { dev_warn(&pdev->dev, "Could not read clock-frequency property\n"); - bus_clk_rate = 100000; - } - - divider = DIV_ROUND_UP(clk_get_rate(i2c_dev->clk), bus_clk_rate); - /* - * Per the datasheet, the register is always interpreted as an even - * number, by rounding down. In other words, the LSB is ignored. So, - * if the LSB is set, increment the divider to avoid any issue. - */ - if (divider & 1) - divider++; - if ((divider < BCM2835_I2C_CDIV_MIN) || - (divider > BCM2835_I2C_CDIV_MAX)) { - dev_err(&pdev->dev, "Invalid clock-frequency\n"); - return -ENODEV; + i2c_dev->bus_clk_rate = 100000; } - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DIV, divider); irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { -- cgit v1.2.3 From e9f66ae23c209eec617130126a23bf547bf7a6d8 Mon Sep 17 00:00:00 2001 From: Sergio Prado Date: Thu, 20 Oct 2016 19:42:44 -0200 Subject: mtd: s3c2410: make ecc mode configurable via platform data Removing CONFIG_MTD_NAND_S3C2410_HWECC option and adding a ecc_mode field in the drivers's platform data structure so it can be selectable via platform data. Also setting this field to NAND_ECC_SOFT in all boards using this driver since none of them had CONFIG_MTD_NAND_S3C2410_HWECC enabled. Signed-off-by: Sergio Prado Acked-by: Krzysztof Kozlowski Signed-off-by: Boris Brezillon --- arch/arm/mach-s3c24xx/common-smdk.c | 1 + arch/arm/mach-s3c24xx/mach-anubis.c | 1 + arch/arm/mach-s3c24xx/mach-at2440evb.c | 1 + arch/arm/mach-s3c24xx/mach-bast.c | 1 + arch/arm/mach-s3c24xx/mach-gta02.c | 1 + arch/arm/mach-s3c24xx/mach-jive.c | 1 + arch/arm/mach-s3c24xx/mach-mini2440.c | 1 + arch/arm/mach-s3c24xx/mach-osiris.c | 1 + arch/arm/mach-s3c24xx/mach-qt2410.c | 1 + arch/arm/mach-s3c24xx/mach-rx1950.c | 1 + arch/arm/mach-s3c24xx/mach-rx3715.c | 1 + arch/arm/mach-s3c24xx/mach-vstms.c | 1 + arch/arm/mach-s3c64xx/mach-hmt.c | 1 + arch/arm/mach-s3c64xx/mach-mini6410.c | 1 + arch/arm/mach-s3c64xx/mach-real6410.c | 1 + drivers/mtd/nand/Kconfig | 9 -- drivers/mtd/nand/s3c2410.c | 123 +++++++++++++------------ include/linux/platform_data/mtd-nand-s3c2410.h | 6 +- 18 files changed, 82 insertions(+), 71 deletions(-) (limited to 'drivers') diff --git a/arch/arm/mach-s3c24xx/common-smdk.c b/arch/arm/mach-s3c24xx/common-smdk.c index e9fbcc91c5c0..9e0bc46e90ec 100644 --- a/arch/arm/mach-s3c24xx/common-smdk.c +++ b/arch/arm/mach-s3c24xx/common-smdk.c @@ -171,6 +171,7 @@ static struct s3c2410_platform_nand smdk_nand_info = { .twrph1 = 20, .nr_sets = ARRAY_SIZE(smdk_nand_sets), .sets = smdk_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; /* devices we initialise */ diff --git a/arch/arm/mach-s3c24xx/mach-anubis.c b/arch/arm/mach-s3c24xx/mach-anubis.c index d03df0df01fa..029ef1b58925 100644 --- a/arch/arm/mach-s3c24xx/mach-anubis.c +++ b/arch/arm/mach-s3c24xx/mach-anubis.c @@ -223,6 +223,7 @@ static struct s3c2410_platform_nand __initdata anubis_nand_info = { .nr_sets = ARRAY_SIZE(anubis_nand_sets), .sets = anubis_nand_sets, .select_chip = anubis_nand_select, + .ecc_mode = NAND_ECC_SOFT, }; /* IDE channels */ diff --git a/arch/arm/mach-s3c24xx/mach-at2440evb.c b/arch/arm/mach-s3c24xx/mach-at2440evb.c index 9ae170fef2a7..7b28eb623fc1 100644 --- a/arch/arm/mach-s3c24xx/mach-at2440evb.c +++ b/arch/arm/mach-s3c24xx/mach-at2440evb.c @@ -114,6 +114,7 @@ static struct s3c2410_platform_nand __initdata at2440evb_nand_info = { .twrph1 = 40, .nr_sets = ARRAY_SIZE(at2440evb_nand_sets), .sets = at2440evb_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; /* DM9000AEP 10/100 ethernet controller */ diff --git a/arch/arm/mach-s3c24xx/mach-bast.c b/arch/arm/mach-s3c24xx/mach-bast.c index ed07cf392d4b..5185036765db 100644 --- a/arch/arm/mach-s3c24xx/mach-bast.c +++ b/arch/arm/mach-s3c24xx/mach-bast.c @@ -299,6 +299,7 @@ static struct s3c2410_platform_nand __initdata bast_nand_info = { .nr_sets = ARRAY_SIZE(bast_nand_sets), .sets = bast_nand_sets, .select_chip = bast_nand_select, + .ecc_mode = NAND_ECC_SOFT, }; /* DM9000 */ diff --git a/arch/arm/mach-s3c24xx/mach-gta02.c b/arch/arm/mach-s3c24xx/mach-gta02.c index 27ae6877550f..b0ed401da3a3 100644 --- a/arch/arm/mach-s3c24xx/mach-gta02.c +++ b/arch/arm/mach-s3c24xx/mach-gta02.c @@ -443,6 +443,7 @@ static struct s3c2410_platform_nand __initdata gta02_nand_info = { .twrph1 = 15, .nr_sets = ARRAY_SIZE(gta02_nand_sets), .sets = gta02_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; diff --git a/arch/arm/mach-s3c24xx/mach-jive.c b/arch/arm/mach-s3c24xx/mach-jive.c index 7d99fe8f6157..895aca225952 100644 --- a/arch/arm/mach-s3c24xx/mach-jive.c +++ b/arch/arm/mach-s3c24xx/mach-jive.c @@ -232,6 +232,7 @@ static struct s3c2410_platform_nand __initdata jive_nand_info = { .twrph1 = 40, .sets = jive_nand_sets, .nr_sets = ARRAY_SIZE(jive_nand_sets), + .ecc_mode = NAND_ECC_SOFT, }; static int __init jive_mtdset(char *options) diff --git a/arch/arm/mach-s3c24xx/mach-mini2440.c b/arch/arm/mach-s3c24xx/mach-mini2440.c index ec60bd4a1646..71af8d2fd320 100644 --- a/arch/arm/mach-s3c24xx/mach-mini2440.c +++ b/arch/arm/mach-s3c24xx/mach-mini2440.c @@ -287,6 +287,7 @@ static struct s3c2410_platform_nand mini2440_nand_info __initdata = { .nr_sets = ARRAY_SIZE(mini2440_nand_sets), .sets = mini2440_nand_sets, .ignore_unset_ecc = 1, + .ecc_mode = NAND_ECC_SOFT, }; /* DM9000AEP 10/100 ethernet controller */ diff --git a/arch/arm/mach-s3c24xx/mach-osiris.c b/arch/arm/mach-s3c24xx/mach-osiris.c index 2f6fdc326835..70b0eb7d3134 100644 --- a/arch/arm/mach-s3c24xx/mach-osiris.c +++ b/arch/arm/mach-s3c24xx/mach-osiris.c @@ -238,6 +238,7 @@ static struct s3c2410_platform_nand __initdata osiris_nand_info = { .nr_sets = ARRAY_SIZE(osiris_nand_sets), .sets = osiris_nand_sets, .select_chip = osiris_nand_select, + .ecc_mode = NAND_ECC_SOFT, }; /* PCMCIA control and configuration */ diff --git a/arch/arm/mach-s3c24xx/mach-qt2410.c b/arch/arm/mach-s3c24xx/mach-qt2410.c index 984516e8307a..868c82087403 100644 --- a/arch/arm/mach-s3c24xx/mach-qt2410.c +++ b/arch/arm/mach-s3c24xx/mach-qt2410.c @@ -284,6 +284,7 @@ static struct s3c2410_platform_nand __initdata qt2410_nand_info = { .twrph1 = 20, .nr_sets = ARRAY_SIZE(qt2410_nand_sets), .sets = qt2410_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; /* UDC */ diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c index 25a139bb9826..e86ad6a68a0b 100644 --- a/arch/arm/mach-s3c24xx/mach-rx1950.c +++ b/arch/arm/mach-s3c24xx/mach-rx1950.c @@ -611,6 +611,7 @@ static struct s3c2410_platform_nand rx1950_nand_info = { .twrph1 = 15, .nr_sets = ARRAY_SIZE(rx1950_nand_sets), .sets = rx1950_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; static struct s3c2410_udc_mach_info rx1950_udc_cfg __initdata = { diff --git a/arch/arm/mach-s3c24xx/mach-rx3715.c b/arch/arm/mach-s3c24xx/mach-rx3715.c index cf55196f89ca..a39fb9780dd3 100644 --- a/arch/arm/mach-s3c24xx/mach-rx3715.c +++ b/arch/arm/mach-s3c24xx/mach-rx3715.c @@ -164,6 +164,7 @@ static struct s3c2410_platform_nand __initdata rx3715_nand_info = { .twrph1 = 15, .nr_sets = ARRAY_SIZE(rx3715_nand_sets), .sets = rx3715_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; static struct platform_device *rx3715_devices[] __initdata = { diff --git a/arch/arm/mach-s3c24xx/mach-vstms.c b/arch/arm/mach-s3c24xx/mach-vstms.c index b4460d5f7011..f5e6322145fa 100644 --- a/arch/arm/mach-s3c24xx/mach-vstms.c +++ b/arch/arm/mach-s3c24xx/mach-vstms.c @@ -117,6 +117,7 @@ static struct s3c2410_platform_nand __initdata vstms_nand_info = { .twrph1 = 20, .nr_sets = ARRAY_SIZE(vstms_nand_sets), .sets = vstms_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; static struct platform_device *vstms_devices[] __initdata = { diff --git a/arch/arm/mach-s3c64xx/mach-hmt.c b/arch/arm/mach-s3c64xx/mach-hmt.c index bc7dc1fcbf7d..59b5531f1987 100644 --- a/arch/arm/mach-s3c64xx/mach-hmt.c +++ b/arch/arm/mach-s3c64xx/mach-hmt.c @@ -204,6 +204,7 @@ static struct s3c2410_platform_nand hmt_nand_info = { .twrph1 = 40, .nr_sets = ARRAY_SIZE(hmt_nand_sets), .sets = hmt_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; static struct gpio_led hmt_leds[] = { diff --git a/arch/arm/mach-s3c64xx/mach-mini6410.c b/arch/arm/mach-s3c64xx/mach-mini6410.c index ae999fb3fe6d..a3e3e25728b4 100644 --- a/arch/arm/mach-s3c64xx/mach-mini6410.c +++ b/arch/arm/mach-s3c64xx/mach-mini6410.c @@ -142,6 +142,7 @@ static struct s3c2410_platform_nand mini6410_nand_info = { .twrph1 = 40, .nr_sets = ARRAY_SIZE(mini6410_nand_sets), .sets = mini6410_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; static struct s3c_fb_pd_win mini6410_lcd_type0_fb_win = { diff --git a/arch/arm/mach-s3c64xx/mach-real6410.c b/arch/arm/mach-s3c64xx/mach-real6410.c index 4e240ffa7ac7..d6b3ffd7704b 100644 --- a/arch/arm/mach-s3c64xx/mach-real6410.c +++ b/arch/arm/mach-s3c64xx/mach-real6410.c @@ -194,6 +194,7 @@ static struct s3c2410_platform_nand real6410_nand_info = { .twrph1 = 40, .nr_sets = ARRAY_SIZE(real6410_nand_sets), .sets = real6410_nand_sets, + .ecc_mode = NAND_ECC_SOFT, }; static struct platform_device *real6410_devices[] __initdata = { diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index c023125989cf..60757af314d3 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -179,15 +179,6 @@ config MTD_NAND_S3C2410_DEBUG help Enable debugging of the S3C NAND driver -config MTD_NAND_S3C2410_HWECC - bool "Samsung S3C NAND Hardware ECC" - depends on MTD_NAND_S3C2410 - help - Enable the use of the controller's internal ECC generator when - using NAND. Early versions of the chips have had problems with - incorrect ECC generation, and if using these, the default of - software ECC is preferable. - config MTD_NAND_NDFC tristate "NDFC NanD Flash Controller" depends on 4xx diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index d459c19d78de..bb4ac3179d17 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -497,7 +497,6 @@ static int s3c2412_nand_devready(struct mtd_info *mtd) /* ECC handling functions */ -#ifdef CONFIG_MTD_NAND_S3C2410_HWECC static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc) { @@ -649,7 +648,6 @@ static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat, return 0; } -#endif /* over-ride the standard functions for a little more speed. We can * use read/write block to move the data buffers to/from the controller @@ -858,50 +856,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, nmtd->info = info; nmtd->set = set; -#ifdef CONFIG_MTD_NAND_S3C2410_HWECC - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - chip->ecc.correct = s3c2410_nand_correct_data; - chip->ecc.mode = NAND_ECC_HW; - chip->ecc.strength = 1; - - switch (info->cpu_type) { - case TYPE_S3C2410: - chip->ecc.hwctl = s3c2410_nand_enable_hwecc; - chip->ecc.calculate = s3c2410_nand_calculate_ecc; - break; - - case TYPE_S3C2412: - chip->ecc.hwctl = s3c2412_nand_enable_hwecc; - chip->ecc.calculate = s3c2412_nand_calculate_ecc; - break; - - case TYPE_S3C2440: - chip->ecc.hwctl = s3c2440_nand_enable_hwecc; - chip->ecc.calculate = s3c2440_nand_calculate_ecc; - break; - } -#else - chip->ecc.mode = NAND_ECC_SOFT; - chip->ecc.algo = NAND_ECC_HAMMING; -#endif - - if (set->disable_ecc) - chip->ecc.mode = NAND_ECC_NONE; - - switch (chip->ecc.mode) { - case NAND_ECC_NONE: - dev_info(info->device, "NAND ECC disabled\n"); - break; - case NAND_ECC_SOFT: - dev_info(info->device, "NAND soft ECC\n"); - break; - case NAND_ECC_HW: - dev_info(info->device, "NAND hardware ECC\n"); - break; - default: - dev_info(info->device, "NAND ECC UNKNOWN\n"); - break; - } + chip->ecc.mode = info->platform->ecc_mode; /* If you use u-boot BBT creation code, specifying this flag will * let the kernel fish out the BBT from the NAND, and also skip the @@ -923,28 +878,74 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, * * The internal state is currently limited to the ECC state information. */ -static void s3c2410_nand_update_chip(struct s3c2410_nand_info *info, - struct s3c2410_nand_mtd *nmtd) +static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info, + struct s3c2410_nand_mtd *nmtd) { struct nand_chip *chip = &nmtd->chip; - dev_dbg(info->device, "chip %p => page shift %d\n", - chip, chip->page_shift); + switch (chip->ecc.mode) { - if (chip->ecc.mode != NAND_ECC_HW) - return; + case NAND_ECC_NONE: + dev_info(info->device, "ECC disabled\n"); + break; + + case NAND_ECC_SOFT: + /* + * This driver expects Hamming based ECC when ecc_mode is set + * to NAND_ECC_SOFT. Force ecc.algo to NAND_ECC_HAMMING to + * avoid adding an extra ecc_algo field to + * s3c2410_platform_nand. + */ + chip->ecc.algo = NAND_ECC_HAMMING; + dev_info(info->device, "soft ECC\n"); + break; + + case NAND_ECC_HW: + chip->ecc.calculate = s3c2410_nand_calculate_ecc; + chip->ecc.correct = s3c2410_nand_correct_data; + chip->ecc.strength = 1; + + switch (info->cpu_type) { + case TYPE_S3C2410: + chip->ecc.hwctl = s3c2410_nand_enable_hwecc; + chip->ecc.calculate = s3c2410_nand_calculate_ecc; + break; + + case TYPE_S3C2412: + chip->ecc.hwctl = s3c2412_nand_enable_hwecc; + chip->ecc.calculate = s3c2412_nand_calculate_ecc; + break; + + case TYPE_S3C2440: + chip->ecc.hwctl = s3c2440_nand_enable_hwecc; + chip->ecc.calculate = s3c2440_nand_calculate_ecc; + break; + } + + dev_dbg(info->device, "chip %p => page shift %d\n", + chip, chip->page_shift); /* change the behaviour depending on whether we are using * the large or small page nand device */ + if (chip->page_shift > 10) { + chip->ecc.size = 256; + chip->ecc.bytes = 3; + } else { + chip->ecc.size = 512; + chip->ecc.bytes = 3; + mtd_set_ooblayout(nand_to_mtd(chip), + &s3c2410_ooblayout_ops); + } - if (chip->page_shift > 10) { - chip->ecc.size = 256; - chip->ecc.bytes = 3; - } else { - chip->ecc.size = 512; - chip->ecc.bytes = 3; - mtd_set_ooblayout(nand_to_mtd(chip), &s3c2410_ooblayout_ops); + dev_info(info->device, "hardware ECC\n"); + break; + + default: + dev_err(info->device, "invalid ECC mode!\n"); + return -EINVAL; } + + return 0; } /* s3c24xx_nand_probe @@ -1046,7 +1047,9 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) NULL); if (nmtd->scan_res == 0) { - s3c2410_nand_update_chip(info, nmtd); + err = s3c2410_nand_update_chip(info, nmtd); + if (err < 0) + goto exit_error; nand_scan_tail(mtd); s3c2410_nand_add_partition(info, nmtd, sets); } diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h index c55e42ee57fa..729af13d1773 100644 --- a/include/linux/platform_data/mtd-nand-s3c2410.h +++ b/include/linux/platform_data/mtd-nand-s3c2410.h @@ -12,9 +12,10 @@ #ifndef __MTD_NAND_S3C2410_H #define __MTD_NAND_S3C2410_H +#include + /** * struct s3c2410_nand_set - define a set of one or more nand chips - * @disable_ecc: Entirely disable ECC - Dangerous * @flash_bbt: Openmoko u-boot can create a Bad Block Table * Setting this flag will allow the kernel to * look for it at boot time and also skip the NAND @@ -31,7 +32,6 @@ * a warning at boot time. */ struct s3c2410_nand_set { - unsigned int disable_ecc:1; unsigned int flash_bbt:1; unsigned int options; @@ -51,6 +51,8 @@ struct s3c2410_platform_nand { unsigned int ignore_unset_ecc:1; + nand_ecc_modes_t ecc_mode; + int nr_sets; struct s3c2410_nand_set *sets; -- cgit v1.2.3 From 1c825ad1b8cfe12ccc145dcdba360c52c0272c04 Mon Sep 17 00:00:00 2001 From: Sergio Prado Date: Wed, 26 Oct 2016 21:59:55 -0200 Subject: mtd: s3c2410: parse the device configuration from OF node Allows configuring Samsung's s3c2410 memory controller using a devicetree. Signed-off-by: Sergio Prado Acked-by: Krzysztof Kozlowski Signed-off-by: Boris Brezillon --- drivers/mtd/nand/s3c2410.c | 163 ++++++++++++++++++++++--- include/linux/platform_data/mtd-nand-s3c2410.h | 1 + 2 files changed, 147 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index bb4ac3179d17..f0b030d44f71 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -185,6 +187,22 @@ struct s3c2410_nand_info { #endif }; +struct s3c24XX_nand_devtype_data { + enum s3c_cpu_type type; +}; + +static const struct s3c24XX_nand_devtype_data s3c2410_nand_devtype_data = { + .type = TYPE_S3C2410, +}; + +static const struct s3c24XX_nand_devtype_data s3c2412_nand_devtype_data = { + .type = TYPE_S3C2412, +}; + +static const struct s3c24XX_nand_devtype_data s3c2440_nand_devtype_data = { + .type = TYPE_S3C2440, +}; + /* conversion functions */ static struct s3c2410_nand_mtd *s3c2410_nand_mtd_toours(struct mtd_info *mtd) @@ -794,6 +812,30 @@ static int s3c2410_nand_add_partition(struct s3c2410_nand_info *info, return -ENODEV; } +static int s3c2410_nand_setup_data_interface(struct mtd_info *mtd, + const struct nand_data_interface *conf, + bool check_only) +{ + struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd); + struct s3c2410_platform_nand *pdata = info->platform; + const struct nand_sdr_timings *timings; + int tacls; + + timings = nand_get_sdr_timings(conf); + if (IS_ERR(timings)) + return -ENOTSUPP; + + tacls = timings->tCLS_min - timings->tWP_min; + if (tacls < 0) + tacls = 0; + + pdata->tacls = DIV_ROUND_UP(tacls, 1000); + pdata->twrph0 = DIV_ROUND_UP(timings->tWP_min, 1000); + pdata->twrph1 = DIV_ROUND_UP(timings->tCLH_min, 1000); + + return s3c2410_nand_setrate(info); +} + /** * s3c2410_nand_init_chip - initialise a single instance of an chip * @info: The base NAND controller the chip is on. @@ -808,9 +850,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, struct s3c2410_nand_mtd *nmtd, struct s3c2410_nand_set *set) { + struct device_node *np = info->device->of_node; struct nand_chip *chip = &nmtd->chip; void __iomem *regs = info->regs; + nand_set_flash_node(chip, set->of_node); + chip->write_buf = s3c2410_nand_write_buf; chip->read_buf = s3c2410_nand_read_buf; chip->select_chip = s3c2410_nand_select_chip; @@ -819,6 +864,13 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->options = set->options; chip->controller = &info->controller; + /* + * let's keep behavior unchanged for legacy boards booting via pdata and + * auto-detect timings only when booting with a device tree. + */ + if (np) + chip->setup_data_interface = s3c2410_nand_setup_data_interface; + switch (info->cpu_type) { case TYPE_S3C2410: chip->IO_ADDR_W = regs + S3C2410_NFDATA; @@ -858,13 +910,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info, chip->ecc.mode = info->platform->ecc_mode; - /* If you use u-boot BBT creation code, specifying this flag will - * let the kernel fish out the BBT from the NAND, and also skip the - * full NAND scan that can take 1/2s or so. Little things... */ - if (set->flash_bbt) { + /* + * If you use u-boot BBT creation code, specifying this flag will + * let the kernel fish out the BBT from the NAND. + */ + if (set->flash_bbt) chip->bbt_options |= NAND_BBT_USE_FLASH; - chip->options |= NAND_SKIP_BBTSCAN; - } } /** @@ -945,6 +996,78 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info, return -EINVAL; } + if (chip->bbt_options & NAND_BBT_USE_FLASH) + chip->options |= NAND_SKIP_BBTSCAN; + + return 0; +} + +static const struct of_device_id s3c24xx_nand_dt_ids[] = { + { + .compatible = "samsung,s3c2410-nand", + .data = &s3c2410_nand_devtype_data, + }, { + /* also compatible with s3c6400 */ + .compatible = "samsung,s3c2412-nand", + .data = &s3c2412_nand_devtype_data, + }, { + .compatible = "samsung,s3c2440-nand", + .data = &s3c2440_nand_devtype_data, + }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, s3c24xx_nand_dt_ids); + +static int s3c24xx_nand_probe_dt(struct platform_device *pdev) +{ + const struct s3c24XX_nand_devtype_data *devtype_data; + struct s3c2410_platform_nand *pdata; + struct s3c2410_nand_info *info = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node, *child; + struct s3c2410_nand_set *sets; + + devtype_data = of_device_get_match_data(&pdev->dev); + if (!devtype_data) + return -ENODEV; + + info->cpu_type = devtype_data->type; + + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdev->dev.platform_data = pdata; + + pdata->nr_sets = of_get_child_count(np); + if (!pdata->nr_sets) + return 0; + + sets = devm_kzalloc(&pdev->dev, sizeof(*sets) * pdata->nr_sets, + GFP_KERNEL); + if (!sets) + return -ENOMEM; + + pdata->sets = sets; + + for_each_available_child_of_node(np, child) { + sets->name = (char *)child->name; + sets->of_node = child; + sets->nr_chips = 1; + + of_node_get(child); + + sets++; + } + + return 0; +} + +static int s3c24xx_nand_probe_pdata(struct platform_device *pdev) +{ + struct s3c2410_nand_info *info = platform_get_drvdata(pdev); + + info->cpu_type = platform_get_device_id(pdev)->driver_data; + return 0; } @@ -957,8 +1080,7 @@ static int s3c2410_nand_update_chip(struct s3c2410_nand_info *info, */ static int s3c24xx_nand_probe(struct platform_device *pdev) { - struct s3c2410_platform_nand *plat = to_nand_plat(pdev); - enum s3c_cpu_type cpu_type; + struct s3c2410_platform_nand *plat; struct s3c2410_nand_info *info; struct s3c2410_nand_mtd *nmtd; struct s3c2410_nand_set *sets; @@ -968,8 +1090,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) int nr_sets; int setno; - cpu_type = platform_get_device_id(pdev)->driver_data; - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { err = -ENOMEM; @@ -991,6 +1111,16 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) s3c2410_nand_clk_set_state(info, CLOCK_ENABLE); + if (pdev->dev.of_node) + err = s3c24xx_nand_probe_dt(pdev); + else + err = s3c24xx_nand_probe_pdata(pdev); + + if (err) + goto exit_error; + + plat = to_nand_plat(pdev); + /* allocate and map the resource */ /* currently we assume we have the one resource */ @@ -999,7 +1129,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) info->device = &pdev->dev; info->platform = plat; - info->cpu_type = cpu_type; info->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(info->regs)) { @@ -1009,12 +1138,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "mapped registers at %p\n", info->regs); - /* initialise the hardware */ - - err = s3c2410_nand_inithw(info); - if (err != 0) - goto exit_error; - sets = (plat != NULL) ? plat->sets : NULL; nr_sets = (plat != NULL) ? plat->nr_sets : 1; @@ -1058,6 +1181,11 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) sets++; } + /* initialise the hardware */ + err = s3c2410_nand_inithw(info); + if (err != 0) + goto exit_error; + err = s3c2410_nand_cpufreq_register(info); if (err < 0) { dev_err(&pdev->dev, "failed to init cpufreq support\n"); @@ -1158,6 +1286,7 @@ static struct platform_driver s3c24xx_nand_driver = { .id_table = s3c24xx_driver_ids, .driver = { .name = "s3c24xx-nand", + .of_match_table = s3c24xx_nand_dt_ids, }, }; diff --git a/include/linux/platform_data/mtd-nand-s3c2410.h b/include/linux/platform_data/mtd-nand-s3c2410.h index 729af13d1773..f01659026b26 100644 --- a/include/linux/platform_data/mtd-nand-s3c2410.h +++ b/include/linux/platform_data/mtd-nand-s3c2410.h @@ -40,6 +40,7 @@ struct s3c2410_nand_set { char *name; int *nr_map; struct mtd_partition *partitions; + struct device_node *of_node; }; struct s3c2410_platform_nand { -- cgit v1.2.3 From 204e7ecd47e26cc12d9e8e8a7e7a2eeb9573f0ba Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sat, 1 Oct 2016 10:24:02 +0200 Subject: mtd: nand: Add a few more timings to nand_sdr_timings Add the tR_max, tBERS_max, tPROG_max and tCCS_min timings to the nand_sdr_timings struct. Assign default/safe values for the statically defined timings, and extract them from the ONFI parameter table if the NAND is ONFI compliant. Signed-off-by: Boris Brezillon Tested-by: Marc Gonzalez --- drivers/mtd/nand/nand_timings.c | 26 +++++++++++++++++++++++++- include/linux/mtd/nand.h | 8 ++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_timings.c b/drivers/mtd/nand/nand_timings.c index 13a587407be3..f06312df3669 100644 --- a/drivers/mtd/nand/nand_timings.c +++ b/drivers/mtd/nand/nand_timings.c @@ -18,6 +18,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 20000, .tALS_min = 50000, @@ -58,6 +60,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 10000, .tALS_min = 25000, @@ -98,6 +102,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 10000, .tALS_min = 15000, @@ -138,6 +144,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -178,6 +186,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -218,6 +228,8 @@ static const struct nand_data_interface onfi_sdr_timings[] = { { .type = NAND_SDR_IFACE, .timings.sdr = { + .tCCS_min = 500000, + .tR_max = 200000000, .tADL_min = 400000, .tALH_min = 5000, .tALS_min = 10000, @@ -290,10 +302,22 @@ int onfi_init_data_interface(struct nand_chip *chip, *iface = onfi_sdr_timings[timing_mode]; /* - * TODO: initialize timings that cannot be deduced from timing mode: + * Initialize timings that cannot be deduced from timing mode: * tR, tPROG, tCCS, ... * These information are part of the ONFI parameter page. */ + if (chip->onfi_version) { + struct nand_onfi_params *params = &chip->onfi_params; + struct nand_sdr_timings *timings = &iface->timings.sdr; + + /* microseconds -> picoseconds */ + timings->tPROG_max = 1000000UL * le16_to_cpu(params->t_prog); + timings->tBERS_max = 1000000UL * le16_to_cpu(params->t_bers); + timings->tR_max = 1000000UL * le16_to_cpu(params->t_r); + + /* nanoseconds -> picoseconds */ + timings->tCCS_min = 1000UL * le16_to_cpu(params->t_ccs); + } return 0; } diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index c5d3d5024fc8..6fe83bce83a6 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -584,6 +584,10 @@ struct nand_buffers { * * All these timings are expressed in picoseconds. * + * @tBERS_max: Block erase time + * @tCCS_min: Change column setup time + * @tPROG_max: Page program time + * @tR_max: Page read time * @tALH_min: ALE hold time * @tADL_min: ALE to data loading time * @tALS_min: ALE setup time @@ -621,6 +625,10 @@ struct nand_buffers { * @tWW_min: WP# transition to WE# low */ struct nand_sdr_timings { + u32 tBERS_max; + u32 tCCS_min; + u32 tPROG_max; + u32 tR_max; u32 tALH_min; u32 tADL_min; u32 tALS_min; -- cgit v1.2.3 From 6ea40a3ba93e1b14ffb349e276f9dfefc4334b99 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Sat, 1 Oct 2016 10:24:03 +0200 Subject: mtd: nand: Wait tCCS after a column change Drivers implementing ->cmd_ctrl() and relying on the default ->cmdfunc() implementation usually don't wait tCCS when a column change (RNDIN or RNDOUT) is requested. Add an option flag to ask the core to do so (note that we keep this as an opt-in to avoid breaking existing implementations), and make use of the ->data_interface information is available (otherwise, wait 500ns). Signed-off-by: Boris Brezillon Tested-by: Marc Gonzalez --- drivers/mtd/nand/nand_base.c | 26 +++++++++++++++++++++++++- include/linux/mtd/nand.h | 10 ++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index e5718e5ecf92..0acb0070280a 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -709,6 +709,25 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, nand_wait_ready(mtd); } +static void nand_ccs_delay(struct nand_chip *chip) +{ + /* + * The controller already takes care of waiting for tCCS when the RNDIN + * or RNDOUT command is sent, return directly. + */ + if (!(chip->options & NAND_WAIT_TCCS)) + return; + + /* + * Wait tCCS_min if it is correctly defined, otherwise wait 500ns + * (which should be safe for all NANDs). + */ + if (chip->data_interface && chip->data_interface->timings.sdr.tCCS_min) + ndelay(chip->data_interface->timings.sdr.tCCS_min / 1000); + else + ndelay(500); +} + /** * nand_command_lp - [DEFAULT] Send command to NAND large page device * @mtd: MTD device structure @@ -773,10 +792,13 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: case NAND_CMD_SEQIN: - case NAND_CMD_RNDIN: case NAND_CMD_STATUS: return; + case NAND_CMD_RNDIN: + nand_ccs_delay(chip); + return; + case NAND_CMD_RESET: if (chip->dev_ready) break; @@ -795,6 +817,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); + + nand_ccs_delay(chip); return; case NAND_CMD_READ0: diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 6fe83bce83a6..970ceb948835 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -210,6 +210,16 @@ enum nand_ecc_algo { */ #define NAND_USE_BOUNCE_BUFFER 0x00100000 +/* + * In case your controller is implementing ->cmd_ctrl() and is relying on the + * default ->cmdfunc() implementation, you may want to let the core handle the + * tCCS delay which is required when a column change (RNDIN or RNDOUT) is + * requested. + * If your controller already takes care of this delay, you don't need to set + * this flag. + */ +#define NAND_WAIT_TCCS 0x00200000 + /* Options set by nand scan */ /* Nand scan has allocated controller struct */ #define NAND_CONTROLLER_ALLOC 0x80000000 -- cgit v1.2.3 From 8bd8fbd8bccf6e32198000792ee8d1e9189f441f Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 19 Sep 2016 11:21:18 +0200 Subject: mtd: nand: pxa3xx_nand: write exactly one message on probe failure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For some error paths alloc_nand_resource() emitted an error message, for others it didn't. Make it consistently print a message including the error code where it's not constant and drop the hardly helpful additional message printed by the caller of alloc_nand_resource. Signed-off-by: Uwe Kleine-König Reviewed-by: Robert Jarzmik Signed-off-by: Boris Brezillon --- drivers/mtd/nand/pxa3xx_nand.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b121bf4ed73a..4c749b030301 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1774,8 +1774,11 @@ static int alloc_nand_resource(struct platform_device *pdev) int ret, irq, cs; pdata = dev_get_platdata(&pdev->dev); - if (pdata->num_cs <= 0) + if (pdata->num_cs <= 0) { + dev_err(&pdev->dev, "invalid number of chip selects\n"); return -ENODEV; + } + info = devm_kzalloc(&pdev->dev, sizeof(*info) + sizeof(*host) * pdata->num_cs, GFP_KERNEL); @@ -1813,8 +1816,9 @@ static int alloc_nand_resource(struct platform_device *pdev) nand_hw_control_init(chip->controller); info->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) { - dev_err(&pdev->dev, "failed to get nand clock\n"); - return PTR_ERR(info->clk); + ret = PTR_ERR(info->clk); + dev_err(&pdev->dev, "failed to get nand clock: %d\n", ret); + return ret; } ret = clk_prepare_enable(info->clk); if (ret < 0) @@ -1842,6 +1846,7 @@ static int alloc_nand_resource(struct platform_device *pdev) info->mmio_base = devm_ioremap_resource(&pdev->dev, r); if (IS_ERR(info->mmio_base)) { ret = PTR_ERR(info->mmio_base); + dev_err(&pdev->dev, "failed to map register space: %d\n", ret); goto fail_disable_clk; } info->mmio_phys = r->start; @@ -1861,7 +1866,7 @@ static int alloc_nand_resource(struct platform_device *pdev) pxa3xx_nand_irq_thread, IRQF_ONESHOT, pdev->name, info); if (ret < 0) { - dev_err(&pdev->dev, "failed to request IRQ\n"); + dev_err(&pdev->dev, "failed to request IRQ: %d\n", ret); goto fail_free_buf; } @@ -1960,10 +1965,8 @@ static int pxa3xx_nand_probe(struct platform_device *pdev) } ret = alloc_nand_resource(pdev); - if (ret) { - dev_err(&pdev->dev, "alloc nand resource failed\n"); + if (ret) return ret; - } info = platform_get_drvdata(pdev); probe_success = 0; -- cgit v1.2.3 From 6956e2385a16175ca350e199f9c760eb1644d5bf Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Tue, 25 Oct 2016 18:10:47 +0200 Subject: mtd: nand: add tango NAND flash controller support This driver supports the NAND Flash controller embedded in recent Tango chips, such as SMP8758 and SMP8759. Signed-off-by: Marc Gonzalez Signed-off-by: Boris Brezillon --- drivers/mtd/nand/Kconfig | 7 + drivers/mtd/nand/Makefile | 1 + drivers/mtd/nand/tango_nand.c | 658 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 666 insertions(+) create mode 100644 drivers/mtd/nand/tango_nand.c (limited to 'drivers') diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index 60757af314d3..353a9ddf6b97 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -196,6 +196,13 @@ config MTD_NAND_S3C2410_CLKSTOP when the is NAND chip selected or released, but will save approximately 5mA of power when there is nothing happening. +config MTD_NAND_TANGO + tristate "NAND Flash support for Tango chips" + depends on ARCH_TANGO || COMPILE_TEST + depends on HAS_DMA + help + Enables the NAND Flash controller on Tango chips. + config MTD_NAND_DISKONCHIP tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)" depends on HAS_IOMEM diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 05fc054a9472..19a66e404d5b 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_DENALI_DT) += denali_dt.o obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o obj-$(CONFIG_MTD_NAND_BF5XX) += bf5xx_nand.o obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o +obj-$(CONFIG_MTD_NAND_TANGO) += tango_nand.o obj-$(CONFIG_MTD_NAND_DAVINCI) += davinci_nand.o obj-$(CONFIG_MTD_NAND_DISKONCHIP) += diskonchip.o obj-$(CONFIG_MTD_NAND_DOCG4) += docg4.o diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c new file mode 100644 index 000000000000..fd8cf414cb2b --- /dev/null +++ b/drivers/mtd/nand/tango_nand.c @@ -0,0 +1,658 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Offsets relative to chip->base */ +#define PBUS_CMD 0 +#define PBUS_ADDR 4 +#define PBUS_DATA 8 + +/* Offsets relative to reg_base */ +#define NFC_STATUS 0x00 +#define NFC_FLASH_CMD 0x04 +#define NFC_DEVICE_CFG 0x08 +#define NFC_TIMING1 0x0c +#define NFC_TIMING2 0x10 +#define NFC_XFER_CFG 0x14 +#define NFC_PKT_0_CFG 0x18 +#define NFC_PKT_N_CFG 0x1c +#define NFC_BB_CFG 0x20 +#define NFC_ADDR_PAGE 0x24 +#define NFC_ADDR_OFFSET 0x28 +#define NFC_XFER_STATUS 0x2c + +/* NFC_STATUS values */ +#define CMD_READY BIT(31) + +/* NFC_FLASH_CMD values */ +#define NFC_READ 1 +#define NFC_WRITE 2 + +/* NFC_XFER_STATUS values */ +#define PAGE_IS_EMPTY BIT(16) + +/* Offsets relative to mem_base */ +#define METADATA 0x000 +#define ERROR_REPORT 0x1c0 + +/* + * Error reports are split in two bytes: + * byte 0 for the first packet in the page (PKT_0) + * byte 1 for other packets in the page (PKT_N, for N > 0) + * ERR_COUNT_PKT_N is the max error count over all but the first packet. + */ +#define DECODE_OK_PKT_0(v) ((v) & BIT(7)) +#define DECODE_OK_PKT_N(v) ((v) & BIT(15)) +#define ERR_COUNT_PKT_0(v) (((v) >> 0) & 0x3f) +#define ERR_COUNT_PKT_N(v) (((v) >> 8) & 0x3f) + +/* Offsets relative to pbus_base */ +#define PBUS_CS_CTRL 0x83c +#define PBUS_PAD_MODE 0x8f0 + +/* PBUS_CS_CTRL values */ +#define PBUS_IORDY BIT(31) + +/* + * PBUS_PAD_MODE values + * In raw mode, the driver communicates directly with the NAND chips. + * In NFC mode, the NAND Flash controller manages the communication. + * We use NFC mode for read and write; raw mode for everything else. + */ +#define MODE_RAW 0 +#define MODE_NFC BIT(31) + +#define METADATA_SIZE 4 +#define BBM_SIZE 6 +#define FIELD_ORDER 15 + +#define MAX_CS 4 + +struct tango_nfc { + struct nand_hw_control hw; + void __iomem *reg_base; + void __iomem *mem_base; + void __iomem *pbus_base; + struct tango_chip *chips[MAX_CS]; + struct dma_chan *chan; + int freq_kHz; +}; + +#define to_tango_nfc(ptr) container_of(ptr, struct tango_nfc, hw) + +struct tango_chip { + struct nand_chip nand_chip; + void __iomem *base; + u32 timing1; + u32 timing2; + u32 xfer_cfg; + u32 pkt_0_cfg; + u32 pkt_n_cfg; + u32 bb_cfg; +}; + +#define to_tango_chip(ptr) container_of(ptr, struct tango_chip, nand_chip) + +#define XFER_CFG(cs, page_count, steps, metadata_size) \ + ((cs) << 24 | (page_count) << 16 | (steps) << 8 | (metadata_size)) + +#define PKT_CFG(size, strength) ((size) << 16 | (strength)) + +#define BB_CFG(bb_offset, bb_size) ((bb_offset) << 16 | (bb_size)) + +#define TIMING(t0, t1, t2, t3) ((t0) << 24 | (t1) << 16 | (t2) << 8 | (t3)) + +static void tango_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl) +{ + struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + + if (ctrl & NAND_CLE) + writeb_relaxed(dat, tchip->base + PBUS_CMD); + + if (ctrl & NAND_ALE) + writeb_relaxed(dat, tchip->base + PBUS_ADDR); +} + +static int tango_dev_ready(struct mtd_info *mtd) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct tango_nfc *nfc = to_tango_nfc(chip->controller); + + return readl_relaxed(nfc->pbus_base + PBUS_CS_CTRL) & PBUS_IORDY; +} + +static u8 tango_read_byte(struct mtd_info *mtd) +{ + struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + + return readb_relaxed(tchip->base + PBUS_DATA); +} + +static void tango_read_buf(struct mtd_info *mtd, u8 *buf, int len) +{ + struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + + ioread8_rep(tchip->base + PBUS_DATA, buf, len); +} + +static void tango_write_buf(struct mtd_info *mtd, const u8 *buf, int len) +{ + struct tango_chip *tchip = to_tango_chip(mtd_to_nand(mtd)); + + iowrite8_rep(tchip->base + PBUS_DATA, buf, len); +} + +static void tango_select_chip(struct mtd_info *mtd, int idx) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct tango_nfc *nfc = to_tango_nfc(chip->controller); + struct tango_chip *tchip = to_tango_chip(chip); + + if (idx < 0) + return; /* No "chip unselect" function */ + + writel_relaxed(tchip->timing1, nfc->reg_base + NFC_TIMING1); + writel_relaxed(tchip->timing2, nfc->reg_base + NFC_TIMING2); + writel_relaxed(tchip->xfer_cfg, nfc->reg_base + NFC_XFER_CFG); + writel_relaxed(tchip->pkt_0_cfg, nfc->reg_base + NFC_PKT_0_CFG); + writel_relaxed(tchip->pkt_n_cfg, nfc->reg_base + NFC_PKT_N_CFG); + writel_relaxed(tchip->bb_cfg, nfc->reg_base + NFC_BB_CFG); +} + +/* + * The controller does not check for bitflips in erased pages, + * therefore software must check instead. + */ +static int check_erased_page(struct nand_chip *chip, u8 *buf) +{ + u8 *meta = chip->oob_poi + BBM_SIZE; + u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE; + const int ecc_size = chip->ecc.bytes; + const int pkt_size = chip->ecc.size; + int i, res, meta_len, bitflips = 0; + + for (i = 0; i < chip->ecc.steps; ++i) { + meta_len = i ? 0 : METADATA_SIZE; + res = nand_check_erased_ecc_chunk(buf, pkt_size, ecc, ecc_size, + meta, meta_len, + chip->ecc.strength); + if (res < 0) + chip->mtd.ecc_stats.failed++; + + bitflips = max(res, bitflips); + buf += pkt_size; + ecc += ecc_size; + } + + return bitflips; +} + +static int decode_error_report(struct tango_nfc *nfc) +{ + u32 status, res; + + status = readl_relaxed(nfc->reg_base + NFC_XFER_STATUS); + if (status & PAGE_IS_EMPTY) + return 0; + + res = readl_relaxed(nfc->mem_base + ERROR_REPORT); + + if (DECODE_OK_PKT_0(res) && DECODE_OK_PKT_N(res)) + return max(ERR_COUNT_PKT_0(res), ERR_COUNT_PKT_N(res)); + + return -EBADMSG; +} + +static void tango_dma_callback(void *arg) +{ + complete(arg); +} + +static int do_dma(struct tango_nfc *nfc, int dir, int cmd, const void *buf, + int len, int page) +{ + void __iomem *addr = nfc->reg_base + NFC_STATUS; + struct dma_chan *chan = nfc->chan; + struct dma_async_tx_descriptor *desc; + struct scatterlist sg; + struct completion tx_done; + int err = -EIO; + u32 res, val; + + sg_init_one(&sg, buf, len); + if (dma_map_sg(chan->device->dev, &sg, 1, dir) != 1) + return -EIO; + + desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir, DMA_PREP_INTERRUPT); + if (!desc) + goto dma_unmap; + + desc->callback = tango_dma_callback; + desc->callback_param = &tx_done; + init_completion(&tx_done); + + writel_relaxed(MODE_NFC, nfc->pbus_base + PBUS_PAD_MODE); + + writel_relaxed(page, nfc->reg_base + NFC_ADDR_PAGE); + writel_relaxed(0, nfc->reg_base + NFC_ADDR_OFFSET); + writel_relaxed(cmd, nfc->reg_base + NFC_FLASH_CMD); + + dmaengine_submit(desc); + dma_async_issue_pending(chan); + + res = wait_for_completion_timeout(&tx_done, HZ); + if (res > 0) + err = readl_poll_timeout(addr, val, val & CMD_READY, 0, 1000); + + writel_relaxed(MODE_RAW, nfc->pbus_base + PBUS_PAD_MODE); + +dma_unmap: + dma_unmap_sg(chan->device->dev, &sg, 1, dir); + + return err; +} + +static int tango_read_page(struct mtd_info *mtd, struct nand_chip *chip, + u8 *buf, int oob_required, int page) +{ + struct tango_nfc *nfc = to_tango_nfc(chip->controller); + int err, res, len = mtd->writesize; + + if (oob_required) + chip->ecc.read_oob(mtd, chip, page); + + err = do_dma(nfc, DMA_FROM_DEVICE, NFC_READ, buf, len, page); + if (err) + return err; + + res = decode_error_report(nfc); + if (res < 0) { + chip->ecc.read_oob_raw(mtd, chip, page); + res = check_erased_page(chip, buf); + } + + return res; +} + +static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip, + const u8 *buf, int oob_required, int page) +{ + struct tango_nfc *nfc = to_tango_nfc(chip->controller); + int err, len = mtd->writesize; + + /* Calling tango_write_oob() would send PAGEPROG twice */ + if (oob_required) + return -ENOTSUPP; + + writel_relaxed(0xffffffff, nfc->mem_base + METADATA); + err = do_dma(nfc, DMA_TO_DEVICE, NFC_WRITE, buf, len, page); + if (err) + return err; + + return 0; +} + +static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) +{ + *pos += len; + + if (!*buf) { + /* skip over "len" bytes */ + chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1); + } else { + tango_read_buf(&chip->mtd, *buf, len); + *buf += len; + } +} + +static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) +{ + *pos += len; + + if (!*buf) { + /* skip over "len" bytes */ + chip->cmdfunc(&chip->mtd, NAND_CMD_SEQIN, *pos, -1); + } else { + tango_write_buf(&chip->mtd, *buf, len); + *buf += len; + } +} + +/* + * Physical page layout (not drawn to scale) + * + * NB: Bad Block Marker area splits PKT_N in two (N1, N2). + * + * +---+-----------------+-------+-----+-----------+-----+----+-------+ + * | M | PKT_0 | ECC_0 | ... | N1 | BBM | N2 | ECC_N | + * +---+-----------------+-------+-----+-----------+-----+----+-------+ + * + * Logical page layout: + * + * +-----+---+-------+-----+-------+ + * oob = | BBM | M | ECC_0 | ... | ECC_N | + * +-----+---+-------+-----+-------+ + * + * +-----------------+-----+-----------------+ + * buf = | PKT_0 | ... | PKT_N | + * +-----------------+-----+-----------------+ + */ +static int raw_read(struct nand_chip *chip, u8 *buf, u8 *oob) +{ + u8 *oob_orig = oob; + const int page_size = chip->mtd.writesize; + const int ecc_size = chip->ecc.bytes; + const int pkt_size = chip->ecc.size; + int pos = 0; /* position within physical page */ + int rem = page_size; /* bytes remaining until BBM area */ + + if (oob) + oob += BBM_SIZE; + + aux_read(chip, &oob, METADATA_SIZE, &pos); + + while (rem > pkt_size) { + aux_read(chip, &buf, pkt_size, &pos); + aux_read(chip, &oob, ecc_size, &pos); + rem = page_size - pos; + } + + aux_read(chip, &buf, rem, &pos); + aux_read(chip, &oob_orig, BBM_SIZE, &pos); + aux_read(chip, &buf, pkt_size - rem, &pos); + aux_read(chip, &oob, ecc_size, &pos); + + return 0; +} + +static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) +{ + const u8 *oob_orig = oob; + const int page_size = chip->mtd.writesize; + const int ecc_size = chip->ecc.bytes; + const int pkt_size = chip->ecc.size; + int pos = 0; /* position within physical page */ + int rem = page_size; /* bytes remaining until BBM area */ + + if (oob) + oob += BBM_SIZE; + + aux_write(chip, &oob, METADATA_SIZE, &pos); + + while (rem > pkt_size) { + aux_write(chip, &buf, pkt_size, &pos); + aux_write(chip, &oob, ecc_size, &pos); + rem = page_size - pos; + } + + aux_write(chip, &buf, rem, &pos); + aux_write(chip, &oob_orig, BBM_SIZE, &pos); + aux_write(chip, &buf, pkt_size - rem, &pos); + aux_write(chip, &oob, ecc_size, &pos); + + return 0; +} + +static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + u8 *buf, int oob_required, int page) +{ + return raw_read(chip, buf, chip->oob_poi); +} + +static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, + const u8 *buf, int oob_required, int page) +{ + return raw_write(chip, buf, chip->oob_poi); +} + +static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); + return raw_read(chip, NULL, chip->oob_poi); +} + +static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, + int page) +{ + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); + raw_write(chip, NULL, chip->oob_poi); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + chip->waitfunc(mtd, chip); + return 0; +} + +static int oob_ecc(struct mtd_info *mtd, int idx, struct mtd_oob_region *res) +{ + struct nand_chip *chip = mtd_to_nand(mtd); + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (idx >= ecc->steps) + return -ERANGE; + + res->offset = BBM_SIZE + METADATA_SIZE + ecc->bytes * idx; + res->length = ecc->bytes; + + return 0; +} + +static int oob_free(struct mtd_info *mtd, int idx, struct mtd_oob_region *res) +{ + return -ERANGE; /* no free space in spare area */ +} + +static const struct mtd_ooblayout_ops tango_nand_ooblayout_ops = { + .ecc = oob_ecc, + .free = oob_free, +}; + +static u32 to_ticks(int kHz, int ps) +{ + return DIV_ROUND_UP_ULL((u64)kHz * ps, NSEC_PER_SEC); +} + +static int tango_set_timings(struct mtd_info *mtd, + const struct nand_data_interface *conf, + bool check_only) +{ + const struct nand_sdr_timings *sdr = nand_get_sdr_timings(conf); + struct nand_chip *chip = mtd_to_nand(mtd); + struct tango_nfc *nfc = to_tango_nfc(chip->controller); + struct tango_chip *tchip = to_tango_chip(chip); + u32 Trdy, Textw, Twc, Twpw, Tacc, Thold, Trpw, Textr; + int kHz = nfc->freq_kHz; + + if (IS_ERR(sdr)) + return PTR_ERR(sdr); + + if (check_only) + return 0; + + Trdy = to_ticks(kHz, sdr->tCEA_max - sdr->tREA_max); + Textw = to_ticks(kHz, sdr->tWB_max); + Twc = to_ticks(kHz, sdr->tWC_min); + Twpw = to_ticks(kHz, sdr->tWC_min - sdr->tWP_min); + + Tacc = to_ticks(kHz, sdr->tREA_max); + Thold = to_ticks(kHz, sdr->tREH_min); + Trpw = to_ticks(kHz, sdr->tRC_min - sdr->tREH_min); + Textr = to_ticks(kHz, sdr->tRHZ_max); + + tchip->timing1 = TIMING(Trdy, Textw, Twc, Twpw); + tchip->timing2 = TIMING(Tacc, Thold, Trpw, Textr); + + return 0; +} + +static int chip_init(struct device *dev, struct device_node *np) +{ + u32 cs; + int err, res; + struct mtd_info *mtd; + struct nand_chip *chip; + struct tango_chip *tchip; + struct nand_ecc_ctrl *ecc; + struct tango_nfc *nfc = dev_get_drvdata(dev); + + tchip = devm_kzalloc(dev, sizeof(*tchip), GFP_KERNEL); + if (!tchip) + return -ENOMEM; + + res = of_property_count_u32_elems(np, "reg"); + if (res < 0) + return res; + + if (res != 1) + return -ENOTSUPP; /* Multi-CS chips are not supported */ + + err = of_property_read_u32_index(np, "reg", 0, &cs); + if (err) + return err; + + if (cs >= MAX_CS) + return -EINVAL; + + chip = &tchip->nand_chip; + ecc = &chip->ecc; + mtd = &chip->mtd; + + chip->read_byte = tango_read_byte; + chip->write_buf = tango_write_buf; + chip->read_buf = tango_read_buf; + chip->select_chip = tango_select_chip; + chip->cmd_ctrl = tango_cmd_ctrl; + chip->dev_ready = tango_dev_ready; + chip->setup_data_interface = tango_set_timings; + chip->options = NAND_USE_BOUNCE_BUFFER | + NAND_NO_SUBPAGE_WRITE | + NAND_WAIT_TCCS; + chip->controller = &nfc->hw; + tchip->base = nfc->pbus_base + (cs * 256); + + nand_set_flash_node(chip, np); + mtd_set_ooblayout(mtd, &tango_nand_ooblayout_ops); + mtd->dev.parent = dev; + + err = nand_scan_ident(mtd, 1, NULL); + if (err) + return err; + + ecc->mode = NAND_ECC_HW; + ecc->algo = NAND_ECC_BCH; + ecc->bytes = DIV_ROUND_UP(ecc->strength * FIELD_ORDER, BITS_PER_BYTE); + + ecc->read_page_raw = tango_read_page_raw; + ecc->write_page_raw = tango_write_page_raw; + ecc->read_page = tango_read_page; + ecc->write_page = tango_write_page; + ecc->read_oob = tango_read_oob; + ecc->write_oob = tango_write_oob; + + err = nand_scan_tail(mtd); + if (err) + return err; + + tchip->xfer_cfg = XFER_CFG(cs, 1, ecc->steps, METADATA_SIZE); + tchip->pkt_0_cfg = PKT_CFG(ecc->size + METADATA_SIZE, ecc->strength); + tchip->pkt_n_cfg = PKT_CFG(ecc->size, ecc->strength); + tchip->bb_cfg = BB_CFG(mtd->writesize, BBM_SIZE); + + err = mtd_device_register(mtd, NULL, 0); + if (err) + return err; + + nfc->chips[cs] = tchip; + + return 0; +} + +static int tango_nand_remove(struct platform_device *pdev) +{ + int cs; + struct tango_nfc *nfc = platform_get_drvdata(pdev); + + dma_release_channel(nfc->chan); + + for (cs = 0; cs < MAX_CS; ++cs) { + if (nfc->chips[cs]) + nand_release(&nfc->chips[cs]->nand_chip.mtd); + } + + return 0; +} + +static int tango_nand_probe(struct platform_device *pdev) +{ + int err; + struct clk *clk; + struct resource *res; + struct tango_nfc *nfc; + struct device_node *np; + + nfc = devm_kzalloc(&pdev->dev, sizeof(*nfc), GFP_KERNEL); + if (!nfc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + nfc->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(nfc->reg_base)) + return PTR_ERR(nfc->reg_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + nfc->mem_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(nfc->mem_base)) + return PTR_ERR(nfc->mem_base); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 2); + nfc->pbus_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(nfc->pbus_base)) + return PTR_ERR(nfc->pbus_base); + + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + nfc->chan = dma_request_chan(&pdev->dev, "nfc_sbox"); + if (IS_ERR(nfc->chan)) + return PTR_ERR(nfc->chan); + + platform_set_drvdata(pdev, nfc); + nand_hw_control_init(&nfc->hw); + nfc->freq_kHz = clk_get_rate(clk) / 1000; + + for_each_child_of_node(pdev->dev.of_node, np) { + err = chip_init(&pdev->dev, np); + if (err) { + tango_nand_remove(pdev); + return err; + } + } + + return 0; +} + +static const struct of_device_id tango_nand_ids[] = { + { .compatible = "sigma,smp8758-nand" }, + { /* sentinel */ } +}; + +static struct platform_driver tango_nand_driver = { + .probe = tango_nand_probe, + .remove = tango_nand_remove, + .driver = { + .name = "tango-nand", + .of_match_table = tango_nand_ids, + }, +}; + +module_platform_driver(tango_nand_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sigma Designs"); +MODULE_DESCRIPTION("Tango4 NAND Flash controller driver"); -- cgit v1.2.3 From a1a261707b51d728d0c2b4c32630bc43a8eb33b2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Thu, 3 Nov 2016 02:21:04 +0900 Subject: mtd: nand: denali_dt: replace clk_disable() with clk_disable_unprepare() The denali_dt_probe() calls clk_disable_unprepare() in the bailout path, whereas denali_dt_remove calls clk_disable(), inconsistently. Replace the latter with clk_disable_unprepare() to make sure to unprepare the clock. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali_dt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index 0cb1e8d9fbfc..f821dc1c5739 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -110,7 +110,7 @@ static int denali_dt_remove(struct platform_device *ofdev) struct denali_dt *dt = platform_get_drvdata(ofdev); denali_remove(&dt->denali); - clk_disable(dt->clk); + clk_disable_unprepare(dt->clk); return 0; } -- cgit v1.2.3 From 4722c0e958e636226100f37cd6d17ac09b695827 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 17:49:08 +0900 Subject: mtd: nand: change return type of nand_get_flash_type() to int Since commit d1e1f4e42b5d ("mtd: nand: add support for reading ONFI parameters from NAND device"), the returned "type" is never used in nand_scan_ident(). Make nand_get_flash_type() simply return an integer value in order to avoid unnecessary ERR_PTR/PTR_ERR dance. Signed-off-by: Masahiro Yamada Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 0acb0070280a..4d099d4f442c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -3999,10 +3999,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip, /* * Get the flash and manufacturer id and lookup if the type is supported. */ -static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, - struct nand_chip *chip, - int *maf_id, int *dev_id, - struct nand_flash_dev *type) +static int nand_get_flash_type(struct mtd_info *mtd, struct nand_chip *chip, + int *maf_id, int *dev_id, + struct nand_flash_dev *type) { int busw; int i, maf_idx; @@ -4040,7 +4039,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, if (id_data[0] != *maf_id || id_data[1] != *dev_id) { pr_info("second ID read did not match %02x,%02x against %02x,%02x\n", *maf_id, *dev_id, id_data[0], id_data[1]); - return ERR_PTR(-ENODEV); + return -ENODEV; } if (!type) @@ -4067,7 +4066,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd, } if (!type->name) - return ERR_PTR(-ENODEV); + return -ENODEV; if (!mtd->name) mtd->name = type->name; @@ -4112,7 +4111,7 @@ ident_done: pr_warn("bus width %d instead %d bit\n", (chip->options & NAND_BUSWIDTH_16) ? 16 : 8, busw ? 16 : 8); - return ERR_PTR(-EINVAL); + return -EINVAL; } nand_decode_bbm_options(mtd, chip, id_data); @@ -4154,7 +4153,7 @@ ident_done: pr_info("%d MiB, %s, erase size: %d KiB, page size: %d, OOB size: %d\n", (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); - return type; + return 0; } static const char * const nand_ecc_modes[] = { @@ -4320,7 +4319,6 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, { int i, nand_maf_id, nand_dev_id; struct nand_chip *chip = mtd_to_nand(mtd); - struct nand_flash_dev *type; int ret; ret = nand_dt_init(chip); @@ -4343,14 +4341,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16); /* Read the flash type */ - type = nand_get_flash_type(mtd, chip, &nand_maf_id, - &nand_dev_id, table); - - if (IS_ERR(type)) { + ret = nand_get_flash_type(mtd, chip, &nand_maf_id, &nand_dev_id, table); + if (ret) { if (!(chip->options & NAND_SCAN_SILENT_NODEV)) pr_warn("No NAND device found\n"); chip->select_chip(mtd, -1); - return PTR_ERR(type); + return ret; } ret = nand_init_data_interface(chip); -- cgit v1.2.3 From 0d0aa866ffa45471b12c9b9c5c48cbc02dcca59b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:49 +0900 Subject: mtd: nand: ams-delta: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/ams-delta.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c index 78e12cc8bac2..5d6c26f3cf7f 100644 --- a/drivers/mtd/nand/ams-delta.c +++ b/drivers/mtd/nand/ams-delta.c @@ -234,10 +234,9 @@ static int ams_delta_init(struct platform_device *pdev) goto out_gpio; /* Scan to find existence of the device */ - if (nand_scan(ams_delta_mtd, 1)) { - err = -ENXIO; + err = nand_scan(ams_delta_mtd, 1); + if (err) goto out_mtd; - } /* Register the partitions */ mtd_device_register(ams_delta_mtd, partition_info, -- cgit v1.2.3 From 546fe03fe349fd79df28ed8fed5efb1357110e28 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:50 +0900 Subject: mtd: nand: cmx270: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/cmx270_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 49133783ca53..226ac0bcafc6 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c @@ -195,9 +195,9 @@ static int __init cmx270_init(void) this->write_buf = cmx270_write_buf; /* Scan to find existence of the device */ - if (nand_scan (cmx270_nand_mtd, 1)) { + ret = nand_scan(cmx270_nand_mtd, 1); + if (ret) { pr_notice("No NAND device\n"); - ret = -ENXIO; goto err_scan; } -- cgit v1.2.3 From 29453ba40bb5e91dcaa9b571208da1c1e75e63f1 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:51 +0900 Subject: mtd: nand: cs553x: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/cs553x_nand.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/cs553x_nand.c b/drivers/mtd/nand/cs553x_nand.c index a65e4e0f57a1..594b28684138 100644 --- a/drivers/mtd/nand/cs553x_nand.c +++ b/drivers/mtd/nand/cs553x_nand.c @@ -242,10 +242,9 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr) } /* Scan to find existence of the device */ - if (nand_scan(new_mtd, 1)) { - err = -ENXIO; + err = nand_scan(new_mtd, 1); + if (err) goto out_free; - } cs553x_mtd[cs] = new_mtd; goto out; -- cgit v1.2.3 From 408bf51e92752d084d82d21e2c1f838d0ecc5eea Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:52 +0900 Subject: mtd: nand: gpio: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/gpio.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/gpio.c b/drivers/mtd/nand/gpio.c index 6317f6836022..0d24857469ab 100644 --- a/drivers/mtd/nand/gpio.c +++ b/drivers/mtd/nand/gpio.c @@ -286,10 +286,9 @@ static int gpio_nand_probe(struct platform_device *pdev) if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) gpio_direction_output(gpiomtd->plat.gpio_nwp, 1); - if (nand_scan(mtd, 1)) { - ret = -ENXIO; + ret = nand_scan(mtd, 1); + if (ret) goto err_wp; - } if (gpiomtd->plat.adjust_parts) gpiomtd->plat.adjust_parts(&gpiomtd->plat, mtd->size); -- cgit v1.2.3 From bbd4d03c56083069cf0808681bd301cf31701fbd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:53 +0900 Subject: mtd: nand: mpc5121: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mpc5121_nfc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c index 7eacb2f545f5..6d6eaed2d20c 100644 --- a/drivers/mtd/nand/mpc5121_nfc.c +++ b/drivers/mtd/nand/mpc5121_nfc.c @@ -777,9 +777,9 @@ static int mpc5121_nfc_probe(struct platform_device *op) } /* Detect NAND chips */ - if (nand_scan(mtd, be32_to_cpup(chips_no))) { + retval = nand_scan(mtd, be32_to_cpup(chips_no)); + if (retval) { dev_err(dev, "NAND Flash not found !\n"); - retval = -ENXIO; goto error; } -- cgit v1.2.3 From 43358c173d02446b9f8da25fb0de8cfc22eb1ae6 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:54 +0900 Subject: mtd: nand: tmio: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENODEV. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/tmio_nand.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c index 08b30549ec0a..fc5e773f8b60 100644 --- a/drivers/mtd/nand/tmio_nand.c +++ b/drivers/mtd/nand/tmio_nand.c @@ -435,10 +435,10 @@ static int tmio_probe(struct platform_device *dev) nand_chip->waitfunc = tmio_nand_wait; /* Scan to find existence of the device */ - if (nand_scan(mtd, 1)) { - retval = -ENODEV; + retval = nand_scan(mtd, 1); + if (retval) goto err_irq; - } + /* Register the partitions */ retval = mtd_device_parse_register(mtd, NULL, NULL, data ? data->partition : NULL, -- cgit v1.2.3 From 6c34ad7d17849bbfaf362d7c5bed11d80c1cdab4 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:55 +0900 Subject: mtd: nand: orion: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/orion_nand.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/orion_nand.c b/drivers/mtd/nand/orion_nand.c index 40a7c4a2cf0d..4a91c5d000be 100644 --- a/drivers/mtd/nand/orion_nand.c +++ b/drivers/mtd/nand/orion_nand.c @@ -155,10 +155,9 @@ static int __init orion_nand_probe(struct platform_device *pdev) clk_put(clk); } - if (nand_scan(mtd, 1)) { - ret = -ENXIO; + ret = nand_scan(mtd, 1); + if (ret) goto no_dev; - } mtd->name = "orion_nand"; ret = mtd_device_register(mtd, board->parts, board->nr_parts); -- cgit v1.2.3 From 4e5af27e2a3a393558936b82fece1942ec49f534 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:56 +0900 Subject: mtd: nand: pasemi: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/pasemi_nand.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pasemi_nand.c b/drivers/mtd/nand/pasemi_nand.c index 5de7591b0510..074b8b01289e 100644 --- a/drivers/mtd/nand/pasemi_nand.c +++ b/drivers/mtd/nand/pasemi_nand.c @@ -156,10 +156,9 @@ static int pasemi_nand_probe(struct platform_device *ofdev) chip->bbt_options = NAND_BBT_USE_FLASH; /* Scan to find existence of the device */ - if (nand_scan(pasemi_nand_mtd, 1)) { - err = -ENXIO; + err = nand_scan(pasemi_nand_mtd, 1); + if (err) goto out_lpc; - } if (mtd_device_register(pasemi_nand_mtd, NULL, 0)) { dev_err(dev, "Unable to register MTD device\n"); -- cgit v1.2.3 From ce2eaca7ebf13006cb992ed2f8ce46aaf8724c71 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:57 +0900 Subject: mtd: nand: plat_nand: return error code of nand_scan() on error The nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/plat_nand.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c index 415a53a0deeb..791de3e4bbb6 100644 --- a/drivers/mtd/nand/plat_nand.c +++ b/drivers/mtd/nand/plat_nand.c @@ -86,10 +86,9 @@ static int plat_nand_probe(struct platform_device *pdev) } /* Scan to find existence of the device */ - if (nand_scan(mtd, pdata->chip.nr_chips)) { - err = -ENXIO; + err = nand_scan(mtd, pdata->chip.nr_chips); + if (err) goto out; - } part_types = pdata->chip.part_probe_types; -- cgit v1.2.3 From b5169d35ed585c0d5fb49cad38f3ae1d6963a641 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:58 +0900 Subject: mtd: nand: atmel: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/atmel_nand.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 68b9160108c9..9ebd5ecefea6 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -2267,10 +2267,9 @@ static int atmel_nand_probe(struct platform_device *pdev) dev_info(host->dev, "No DMA support for NAND access.\n"); /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1, NULL)) { - res = -ENXIO; + res = nand_scan_ident(mtd, 1, NULL); + if (res) goto err_scan_ident; - } if (host->board.on_flash_bbt || on_flash_bbt) nand_chip->bbt_options |= NAND_BBT_USE_FLASH; @@ -2304,10 +2303,9 @@ static int atmel_nand_probe(struct platform_device *pdev) } /* second phase scan */ - if (nand_scan_tail(mtd)) { - res = -ENXIO; + res = nand_scan_tail(mtd); + if (res) goto err_scan_tail; - } mtd->name = "atmel_nand"; res = mtd_device_register(mtd, host->board.parts, -- cgit v1.2.3 From c25cca0336a2f748779fd4a0f08177bde984e7be Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:42:59 +0900 Subject: mtd: nand: brcmnand: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/brcmnand/brcmnand.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/brcmnand/brcmnand.c b/drivers/mtd/nand/brcmnand/brcmnand.c index 9d2424bfdbf5..42ebd73f821d 100644 --- a/drivers/mtd/nand/brcmnand/brcmnand.c +++ b/drivers/mtd/nand/brcmnand/brcmnand.c @@ -2209,8 +2209,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn) nand_writereg(ctrl, cfg_offs, nand_readreg(ctrl, cfg_offs) & ~CFG_BUS_WIDTH); - if (nand_scan_ident(mtd, 1, NULL)) - return -ENXIO; + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + return ret; chip->options |= NAND_NO_SUBPAGE_WRITE; /* @@ -2234,8 +2235,9 @@ static int brcmnand_init_cs(struct brcmnand_host *host, struct device_node *dn) if (ret) return ret; - if (nand_scan_tail(mtd)) - return -ENXIO; + ret = nand_scan_tail(mtd); + if (ret) + return ret; return mtd_device_register(mtd, NULL, 0); } -- cgit v1.2.3 From ad5678ec40764ccd38dd688f5ec5c1c835241abd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:00 +0900 Subject: mtd: nand: fsmc: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/fsmc_nand.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index d4f454a4b35e..4924b43977ef 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -926,8 +926,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) /* * Scan to find existence of the device */ - if (nand_scan_ident(mtd, 1, NULL)) { - ret = -ENXIO; + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) { dev_err(&pdev->dev, "No NAND Device found!\n"); goto err_scan_ident; } @@ -992,10 +992,9 @@ static int __init fsmc_nand_probe(struct platform_device *pdev) } /* Second stage of scan to fill MTD data-structures */ - if (nand_scan_tail(mtd)) { - ret = -ENXIO; + ret = nand_scan_tail(mtd); + if (ret) goto err_probe; - } /* * The partition information can is accessed by (in the same precedence) -- cgit v1.2.3 From b04bafca67dac3c390041bbcd694973e3d3f3b7d Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:01 +0900 Subject: mtd: nand: lpc32xx: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Acked-by: Vladimir Zapolskiy Signed-off-by: Boris Brezillon --- drivers/mtd/nand/lpc32xx_mlc.c | 10 ++++------ drivers/mtd/nand/lpc32xx_slc.c | 10 ++++------ 2 files changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/lpc32xx_mlc.c b/drivers/mtd/nand/lpc32xx_mlc.c index 852388171f20..5553a5d9efd1 100644 --- a/drivers/mtd/nand/lpc32xx_mlc.c +++ b/drivers/mtd/nand/lpc32xx_mlc.c @@ -747,10 +747,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) * Scan to find existance of the device and * Get the type of NAND device SMALL block or LARGE block */ - if (nand_scan_ident(mtd, 1, NULL)) { - res = -ENXIO; + res = nand_scan_ident(mtd, 1, NULL); + if (res) goto err_exit3; - } host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL); if (!host->dma_buf) { @@ -793,10 +792,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) * Fills out all the uninitialized function pointers with the defaults * And scans for a bad block table if appropriate. */ - if (nand_scan_tail(mtd)) { - res = -ENXIO; + res = nand_scan_tail(mtd); + if (res) goto err_exit4; - } mtd->name = DRV_NAME; diff --git a/drivers/mtd/nand/lpc32xx_slc.c b/drivers/mtd/nand/lpc32xx_slc.c index 8d3edc34958e..53bafe23ab39 100644 --- a/drivers/mtd/nand/lpc32xx_slc.c +++ b/drivers/mtd/nand/lpc32xx_slc.c @@ -894,10 +894,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) } /* Find NAND device */ - if (nand_scan_ident(mtd, 1, NULL)) { - res = -ENXIO; + res = nand_scan_ident(mtd, 1, NULL); + if (res) goto err_exit3; - } /* OOB and ECC CPU and DMA work areas */ host->ecc_buf = (uint32_t *)(host->data_buf + LPC32XX_DMA_DATA_SIZE); @@ -929,10 +928,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev) /* * Fills out all the uninitialized function pointers with the defaults */ - if (nand_scan_tail(mtd)) { - res = -ENXIO; + res = nand_scan_tail(mtd); + if (res) goto err_exit3; - } mtd->name = "nxp_lpc3220_slc"; res = mtd_device_register(mtd, host->ncfg->parts, -- cgit v1.2.3 From f0dbe4aa35e73e4282d9446abb8900ab0636d483 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:02 +0900 Subject: mtd: nand: mediatek: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENODEV. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mtk_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mtk_nand.c b/drivers/mtd/nand/mtk_nand.c index 5223a2182ee4..6c3eed3c2094 100644 --- a/drivers/mtd/nand/mtk_nand.c +++ b/drivers/mtd/nand/mtk_nand.c @@ -1297,7 +1297,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, ret = nand_scan_ident(mtd, nsels, NULL); if (ret) - return -ENODEV; + return ret; /* store bbt magic in page, cause OOB is not protected */ if (nand->bbt_options & NAND_BBT_USE_FLASH) @@ -1323,7 +1323,7 @@ static int mtk_nfc_nand_chip_init(struct device *dev, struct mtk_nfc *nfc, ret = nand_scan_tail(mtd); if (ret) - return -ENODEV; + return ret; ret = mtd_device_parse_register(mtd, NULL, NULL, NULL, 0); if (ret) { -- cgit v1.2.3 From bc83c78871037b67d41d6fe70c7937ea89868d3b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:03 +0900 Subject: mtd: nand: mxc: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/mxc_nand.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index d7f724b24fd7..61ca020c5272 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1747,10 +1747,9 @@ static int mxcnd_probe(struct platform_device *pdev) } /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL)) { - err = -ENXIO; + err = nand_scan_ident(mtd, is_imx25_nfc(host) ? 4 : 1, NULL); + if (err) goto escan; - } switch (this->ecc.mode) { case NAND_ECC_HW: @@ -1808,10 +1807,9 @@ static int mxcnd_probe(struct platform_device *pdev) } /* second phase scan */ - if (nand_scan_tail(mtd)) { - err = -ENXIO; + err = nand_scan_tail(mtd); + if (err) goto escan; - } /* Register the partitions */ mtd_device_parse_register(mtd, part_probes, -- cgit v1.2.3 From bd93a3af82d5175a86badf7bc0e30d17cc6469ce Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:04 +0900 Subject: mtd: nand: omap2: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/omap2.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c index 0934c3b3f70e..2a52101120d4 100644 --- a/drivers/mtd/nand/omap2.c +++ b/drivers/mtd/nand/omap2.c @@ -1895,10 +1895,10 @@ static int omap_nand_probe(struct platform_device *pdev) /* scan NAND device connected to chip controller */ nand_chip->options |= info->devsize & NAND_BUSWIDTH_16; - if (nand_scan_ident(mtd, 1, NULL)) { + err = nand_scan_ident(mtd, 1, NULL); + if (err) { dev_err(&info->pdev->dev, "scan failed, may be bus-width mismatch\n"); - err = -ENXIO; goto return_error; } @@ -2154,10 +2154,9 @@ static int omap_nand_probe(struct platform_device *pdev) scan_tail: /* second phase scan */ - if (nand_scan_tail(mtd)) { - err = -ENXIO; + err = nand_scan_tail(mtd); + if (err) goto return_error; - } if (dev->of_node) mtd_device_register(mtd, NULL, 0); -- cgit v1.2.3 From e9d354b4b26aa8fe18b3a6858f2161a43a040e1f Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:05 +0900 Subject: mtd: nand: vf610: return error code of nand_scan_ident/tail() on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/vf610_nfc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/vf610_nfc.c b/drivers/mtd/nand/vf610_nfc.c index 3ad514c44dcb..3ea4bb19e12d 100644 --- a/drivers/mtd/nand/vf610_nfc.c +++ b/drivers/mtd/nand/vf610_nfc.c @@ -717,10 +717,9 @@ static int vf610_nfc_probe(struct platform_device *pdev) vf610_nfc_preinit_controller(nfc); /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1, NULL)) { - err = -ENXIO; + err = nand_scan_ident(mtd, 1, NULL); + if (err) goto error; - } vf610_nfc_init_controller(nfc); @@ -775,10 +774,9 @@ static int vf610_nfc_probe(struct platform_device *pdev) } /* second phase scan */ - if (nand_scan_tail(mtd)) { - err = -ENXIO; + err = nand_scan_tail(mtd); + if (err) goto error; - } platform_set_drvdata(pdev, mtd); -- cgit v1.2.3 From 72480e4e9537fe7c8b9ccc980873665676002808 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:06 +0900 Subject: mtd: nand: cafe: return error code of nand_scan_ident() on error The nand_scan_ident() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. (This driver is already doing so for nand_scan_tail().) Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/cafe_nand.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/cafe_nand.c b/drivers/mtd/nand/cafe_nand.c index 0b0c93702abb..d40c32d311d8 100644 --- a/drivers/mtd/nand/cafe_nand.c +++ b/drivers/mtd/nand/cafe_nand.c @@ -725,10 +725,9 @@ static int cafe_nand_probe(struct pci_dev *pdev, usedma = 0; /* Scan to find existence of the device */ - if (nand_scan_ident(mtd, 2, NULL)) { - err = -ENXIO; + err = nand_scan_ident(mtd, 2, NULL); + if (err) goto out_irq; - } cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers) + -- cgit v1.2.3 From c8cae35572b6132e7c3fbb708ebee4b84e29bbed Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:07 +0900 Subject: mtd: nand: hisi504: return error code of nand_scan_ident() on error The nand_scan_ident() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENODEV. (This driver is already doing so for nand_scan_tail().) Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/hisi504_nand.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c index 9432546f4cd4..e40364eeb556 100644 --- a/drivers/mtd/nand/hisi504_nand.c +++ b/drivers/mtd/nand/hisi504_nand.c @@ -774,10 +774,8 @@ static int hisi_nfc_probe(struct platform_device *pdev) } ret = nand_scan_ident(mtd, max_chips, NULL); - if (ret) { - ret = -ENODEV; + if (ret) goto err_res; - } host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize, &host->dma_buffer, GFP_KERNEL); -- cgit v1.2.3 From 133fe8fa614175eb7e59599dbfe357c7bc7da851 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:08 +0900 Subject: mtd: nand: pxa3xx: return error code of nand_scan_ident() on error The nand_scan_ident() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENODEV. (This driver is already doing so for nand_scan_tail().) Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/pxa3xx_nand.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 4c749b030301..649ba8200832 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1680,8 +1680,9 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) chip->ecc.strength = pdata->ecc_strength; chip->ecc.size = pdata->ecc_step_size; - if (nand_scan_ident(mtd, 1, NULL)) - return -ENODEV; + ret = nand_scan_ident(mtd, 1, NULL); + if (ret) + return ret; if (!pdata->keep_config) { ret = pxa3xx_nand_init(host); -- cgit v1.2.3 From c75183020fca0229fce1fd6ba21ae840b41d79e9 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:09 +0900 Subject: mtd: nand: nandsim: remove unneeded checks for nand_scan_ident/tail() The nand_scan_ident/tail() never returns a positive value when it fails. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nandsim.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index 1eb934414eb5..c76287a69663 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -2313,8 +2313,6 @@ static int __init ns_init_module(void) retval = nand_scan_ident(nsmtd, 1, NULL); if (retval) { NS_ERR("cannot scan NAND Simulator device\n"); - if (retval > 0) - retval = -ENXIO; goto error; } @@ -2350,8 +2348,6 @@ static int __init ns_init_module(void) retval = nand_scan_tail(nsmtd); if (retval) { NS_ERR("can't register NAND Simulator\n"); - if (retval > 0) - retval = -ENXIO; goto error; } -- cgit v1.2.3 From 83f48f80de8a03c053ff0cac1521c1eaeaa107f2 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:43:10 +0900 Subject: mtd: nand: socrates: use nand_scan() for nand_scan_ident/tail() combo For this driver, there is nothing between nand_scan_ident() and nand_scan_tail(). They can be merged into nand_scan(). Also, nand_scan() returns an appropriate error value when it fails. Use it instead of the fixed error code -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/socrates_nand.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/socrates_nand.c b/drivers/mtd/nand/socrates_nand.c index 888fd314c62a..72369bd079af 100644 --- a/drivers/mtd/nand/socrates_nand.c +++ b/drivers/mtd/nand/socrates_nand.c @@ -187,17 +187,9 @@ static int socrates_nand_probe(struct platform_device *ofdev) dev_set_drvdata(&ofdev->dev, host); - /* first scan to find the device and get the page size */ - if (nand_scan_ident(mtd, 1, NULL)) { - res = -ENXIO; + res = nand_scan(mtd, 1); + if (res) goto out; - } - - /* second phase scan */ - if (nand_scan_tail(mtd)) { - res = -ENXIO; - goto out; - } res = mtd_device_register(mtd, NULL, 0); if (!res) -- cgit v1.2.3 From 5ac7b2fccd0cc2e1451d5d5388dad69e858fa0d4 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Thu, 27 Oct 2016 10:12:18 -0500 Subject: ipmi: Periodically check for events, not messages Commit d9b7e4f717a1 ("ipmi: Periodically check to see if irqs and messages are set right") to verify the contents of global events. However, the wrong function was being called in some cases, checking for messages, not events. Signed-off-by: Corey Minyard Tested-by: Jason DiPietro --- drivers/char/ipmi/ipmi_si_intf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index a112c0146012..cb451088a4af 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -789,7 +789,7 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->si_state = SI_NORMAL; break; } - start_getting_msg_queue(smi_info); + start_getting_events(smi_info); } else { smi_info->si_state = SI_NORMAL; } @@ -812,7 +812,7 @@ static void handle_transaction_done(struct smi_info *smi_info) smi_info->si_state = SI_NORMAL; break; } - start_getting_msg_queue(smi_info); + start_getting_events(smi_info); } else { smi_info->si_state = SI_NORMAL; } -- cgit v1.2.3 From 56189b5f2f0f386838f278e93654d2e2cbb51c9a Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Tue, 25 Oct 2016 20:31:23 -0500 Subject: ipmi_ssif: Remove an unused module parameter Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_ssif.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 5673ffff00be..04232431eaf7 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -1154,10 +1154,6 @@ static bool ssif_dbg_probe; module_param_named(dbg_probe, ssif_dbg_probe, bool, 0); MODULE_PARM_DESC(dbg_probe, "Enable debugging of probing of adapters."); -static int use_thread; -module_param(use_thread, int, 0); -MODULE_PARM_DESC(use_thread, "Use the thread interface."); - static bool ssif_tryacpi = true; module_param_named(tryacpi, ssif_tryacpi, bool, 0); MODULE_PARM_DESC(tryacpi, "Setting this to zero will disable the default scan of the interfaces identified via ACPI"); -- cgit v1.2.3 From 2ae2e28852f21ec9efc527c1f3ecc5f7c7e27e42 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 22 Sep 2016 00:09:38 +0200 Subject: misc: sram: add Atmel securam support The Atmel secure SRAM is connected to a security module and may be erased automatically under certain conditions. For that reason, it is necessary to wait for the security module to flag that SRAM accesses are allowed before accessing it. Signed-off-by: Alexandre Belloni Acked-by: Greg Kroah-Hartman --- drivers/misc/sram.c | 42 +++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index f84b53d6ce50..b0d4dd9b0586 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -19,12 +19,17 @@ */ #include +#include #include #include #include #include +#include #include +#include #include +#include +#include #define SRAM_GRANULARITY 32 @@ -334,12 +339,35 @@ static int sram_reserve_regions(struct sram_dev *sram, struct resource *res) return ret; } +static int atmel_securam_wait(void) +{ + struct regmap *regmap; + u32 val; + + regmap = syscon_regmap_lookup_by_compatible("atmel,sama5d2-secumod"); + if (IS_ERR(regmap)) + return -ENODEV; + + return regmap_read_poll_timeout(regmap, AT91_SECUMOD_RAMRDY, val, + val & AT91_SECUMOD_RAMRDY_READY, + 10000, 500000); +} + +#ifdef CONFIG_OF +static const struct of_device_id sram_dt_ids[] = { + { .compatible = "mmio-sram" }, + { .compatible = "atmel,sama5d2-securam", .data = atmel_securam_wait }, + {} +}; +#endif + static int sram_probe(struct platform_device *pdev) { struct sram_dev *sram; struct resource *res; size_t size; int ret; + int (*init_func)(void); sram = devm_kzalloc(&pdev->dev, sizeof(*sram), GFP_KERNEL); if (!sram) @@ -384,6 +412,13 @@ static int sram_probe(struct platform_device *pdev) platform_set_drvdata(pdev, sram); + init_func = of_device_get_match_data(&pdev->dev); + if (init_func) { + ret = init_func(); + if (ret) + return ret; + } + dev_dbg(sram->dev, "SRAM pool: %zu KiB @ 0x%p\n", gen_pool_size(sram->pool) / 1024, sram->virt_base); @@ -405,13 +440,6 @@ static int sram_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_OF -static const struct of_device_id sram_dt_ids[] = { - { .compatible = "mmio-sram" }, - {} -}; -#endif - static struct platform_driver sram_driver = { .driver = { .name = "sram", -- cgit v1.2.3 From 0f78ba96bbcf30a78224fe56f8fd72f87915afdd Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 23 Feb 2016 15:32:14 -0800 Subject: Input: gpio_keys_polled - keep button data constant Commit 633a21d80b4a ("input: gpio_keys_polled: Add support for GPIO descriptors") placed gpio descriptor into gpio_keys_button structure, which is supposed to be part of platform data and not modifiable by the driver. To keep the data constant, let's move the descriptor to gpio_keys_button_data structure instead. Tested-by: Mika Westerberg Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 10 +-- drivers/input/keyboard/gpio_keys_polled.c | 105 +++++++++++++++++------------- include/linux/gpio_keys.h | 5 +- 3 files changed, 64 insertions(+), 56 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 29093657f2ef..890eb397d987 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -624,7 +624,6 @@ gpio_keys_get_devtree_pdata(struct device *dev) struct gpio_keys_button *button; int error; int nbuttons; - int i; node = dev->of_node; if (!node) @@ -640,19 +639,18 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (!pdata) return ERR_PTR(-ENOMEM); - pdata->buttons = (struct gpio_keys_button *)(pdata + 1); + button = (struct gpio_keys_button *)(pdata + 1); + + pdata->buttons = button; pdata->nbuttons = nbuttons; pdata->rep = !!of_get_property(node, "autorepeat", NULL); of_property_read_string(node, "label", &pdata->name); - i = 0; for_each_available_child_of_node(node, pp) { enum of_gpio_flags flags; - button = &pdata->buttons[i++]; - button->gpio = of_get_gpio_flags(pp, 0, &flags); if (button->gpio < 0) { error = button->gpio; @@ -694,6 +692,8 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (of_property_read_u32(pp, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; + + button++; } if (pdata->nbuttons == 0) diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 62bdb1d48c49..2cf407831f06 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -30,6 +30,7 @@ #define DRV_NAME "gpio-keys-polled" struct gpio_keys_button_data { + struct gpio_desc *gpiod; int last_state; int count; int threshold; @@ -46,7 +47,7 @@ struct gpio_keys_polled_dev { }; static void gpio_keys_button_event(struct input_polled_dev *dev, - struct gpio_keys_button *button, + const struct gpio_keys_button *button, int state) { struct gpio_keys_polled_dev *bdev = dev->private; @@ -70,15 +71,15 @@ static void gpio_keys_button_event(struct input_polled_dev *dev, } static void gpio_keys_polled_check_state(struct input_polled_dev *dev, - struct gpio_keys_button *button, + const struct gpio_keys_button *button, struct gpio_keys_button_data *bdata) { int state; if (bdata->can_sleep) - state = !!gpiod_get_value_cansleep(button->gpiod); + state = !!gpiod_get_value_cansleep(bdata->gpiod); else - state = !!gpiod_get_value(button->gpiod); + state = !!gpiod_get_value(bdata->gpiod); gpio_keys_button_event(dev, button, state); @@ -142,48 +143,35 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev) pdata->disable(bdev->dev); } -static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev) +static struct gpio_keys_platform_data * +gpio_keys_polled_get_devtree_pdata(struct device *dev) { struct gpio_keys_platform_data *pdata; struct gpio_keys_button *button; struct fwnode_handle *child; - int error; int nbuttons; nbuttons = device_get_child_node_count(dev); if (nbuttons == 0) - return NULL; + return ERR_PTR(-EINVAL); pdata = devm_kzalloc(dev, sizeof(*pdata) + nbuttons * sizeof(*button), GFP_KERNEL); if (!pdata) return ERR_PTR(-ENOMEM); - pdata->buttons = (struct gpio_keys_button *)(pdata + 1); + button = (struct gpio_keys_button *)(pdata + 1); + + pdata->buttons = button; + pdata->nbuttons = nbuttons; pdata->rep = device_property_present(dev, "autorepeat"); device_property_read_u32(dev, "poll-interval", &pdata->poll_interval); device_for_each_child_node(dev, child) { - struct gpio_desc *desc; - - desc = devm_get_gpiod_from_child(dev, NULL, child); - if (IS_ERR(desc)) { - error = PTR_ERR(desc); - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get gpio flags, error: %d\n", - error); - fwnode_handle_put(child); - return ERR_PTR(error); - } - - button = &pdata->buttons[pdata->nbuttons++]; - button->gpiod = desc; - - if (fwnode_property_read_u32(child, "linux,code", &button->code)) { - dev_err(dev, "Button without keycode: %d\n", - pdata->nbuttons - 1); + if (fwnode_property_read_u32(child, "linux,code", + &button->code)) { + dev_err(dev, "button without keycode\n"); fwnode_handle_put(child); return ERR_PTR(-EINVAL); } @@ -206,10 +194,9 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct if (fwnode_property_read_u32(child, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; - } - if (pdata->nbuttons == 0) - return ERR_PTR(-EINVAL); + button++; + } return pdata; } @@ -220,7 +207,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input, int i, min = 0, max = 0; for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; + const struct gpio_keys_button *button = &pdata->buttons[i]; if (button->type != EV_ABS || button->code != code) continue; @@ -230,6 +217,7 @@ static void gpio_keys_polled_set_abs_params(struct input_dev *input, if (button->value > max) max = button->value; } + input_set_abs_params(input, code, min, max, 0, 0); } @@ -242,6 +230,7 @@ MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match); static int gpio_keys_polled_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct fwnode_handle *child = NULL; const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); struct gpio_keys_polled_dev *bdev; struct input_polled_dev *poll_dev; @@ -254,10 +243,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) pdata = gpio_keys_polled_get_devtree_pdata(dev); if (IS_ERR(pdata)) return PTR_ERR(pdata); - if (!pdata) { - dev_err(dev, "missing platform data\n"); - return -EINVAL; - } } if (!pdata->poll_interval) { @@ -300,20 +285,40 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) __set_bit(EV_REP, input->evbit); for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = &pdata->buttons[i]; + const struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_keys_button_data *bdata = &bdev->data[i]; unsigned int type = button->type ?: EV_KEY; if (button->wakeup) { dev_err(dev, DRV_NAME " does not support wakeup\n"); + fwnode_handle_put(child); return -EINVAL; } - /* - * Legacy GPIO number so request the GPIO here and - * convert it to descriptor. - */ - if (!button->gpiod && gpio_is_valid(button->gpio)) { + if (!dev_get_platdata(dev)) { + /* No legacy static platform data */ + child = device_get_next_child_node(dev, child); + if (!child) { + dev_err(dev, "missing child device node\n"); + return -EINVAL; + } + + bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, + child); + if (IS_ERR(bdata->gpiod)) { + error = PTR_ERR(bdata->gpiod); + if (error != -EPROBE_DEFER) + dev_err(dev, + "failed to get gpio: %d\n", + error); + fwnode_handle_put(child); + return error; + } + } else if (gpio_is_valid(button->gpio)) { + /* + * Legacy GPIO number so request the GPIO here and + * convert it to descriptor. + */ unsigned flags = GPIOF_IN; if (button->active_low) @@ -322,18 +327,22 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) error = devm_gpio_request_one(&pdev->dev, button->gpio, flags, button->desc ? : DRV_NAME); if (error) { - dev_err(dev, "unable to claim gpio %u, err=%d\n", + dev_err(dev, + "unable to claim gpio %u, err=%d\n", button->gpio, error); return error; } - button->gpiod = gpio_to_desc(button->gpio); + bdata->gpiod = gpio_to_desc(button->gpio); + if (!bdata->gpiod) { + dev_err(dev, + "unable to convert gpio %u to descriptor\n", + button->gpio); + return -EINVAL; + } } - if (IS_ERR(button->gpiod)) - return PTR_ERR(button->gpiod); - - bdata->can_sleep = gpiod_cansleep(button->gpiod); + bdata->can_sleep = gpiod_cansleep(bdata->gpiod); bdata->last_state = -1; bdata->threshold = DIV_ROUND_UP(button->debounce_interval, pdata->poll_interval); @@ -344,6 +353,8 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) button->code); } + fwnode_handle_put(child); + bdev->poll_dev = poll_dev; bdev->dev = dev; bdev->pdata = pdata; diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index ee2d8c6f9130..0b71024c082c 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -2,7 +2,6 @@ #define _GPIO_KEYS_H struct device; -struct gpio_desc; /** * struct gpio_keys_button - configuration parameters @@ -18,7 +17,6 @@ struct gpio_desc; * disable button via sysfs * @value: axis value for %EV_ABS * @irq: Irq number in case of interrupt keys - * @gpiod: GPIO descriptor */ struct gpio_keys_button { unsigned int code; @@ -31,7 +29,6 @@ struct gpio_keys_button { bool can_disable; int value; unsigned int irq; - struct gpio_desc *gpiod; }; /** @@ -46,7 +43,7 @@ struct gpio_keys_button { * @name: input device name */ struct gpio_keys_platform_data { - struct gpio_keys_button *buttons; + const struct gpio_keys_button *buttons; int nbuttons; unsigned int poll_interval; unsigned int rep:1; -- cgit v1.2.3 From ea6aabf877d82fe10627f40069e0f3d412706a8a Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 19 Oct 2016 16:36:19 -0700 Subject: Input: gpio_keys_polled - always use gpiod_get_value_cansleep It does not matter if given GPIO may sleep or not when reading state, polling is always done in a non-atomic context, so we should always be able to simply use gpiod_get_value_cansleep(). Also let's note in the logs when we fail to read gpio state. Reviewed-by: Hans de Goede Reviewed-by: Mika Westerberg Tested-by: Mika Westerberg Acked-by: Linus Walleij Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys_polled.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 2cf407831f06..72b350315d43 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -34,7 +34,6 @@ struct gpio_keys_button_data { int last_state; int count; int threshold; - int can_sleep; }; struct gpio_keys_polled_dev { @@ -76,16 +75,17 @@ static void gpio_keys_polled_check_state(struct input_polled_dev *dev, { int state; - if (bdata->can_sleep) - state = !!gpiod_get_value_cansleep(bdata->gpiod); - else - state = !!gpiod_get_value(bdata->gpiod); - - gpio_keys_button_event(dev, button, state); + state = gpiod_get_value_cansleep(bdata->gpiod); + if (state < 0) { + dev_err(dev->input->dev.parent, + "failed to get gpio state: %d\n", state); + } else { + gpio_keys_button_event(dev, button, state); - if (state != bdata->last_state) { - bdata->count = 0; - bdata->last_state = state; + if (state != bdata->last_state) { + bdata->count = 0; + bdata->last_state = state; + } } } @@ -342,7 +342,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) } } - bdata->can_sleep = gpiod_cansleep(bdata->gpiod); bdata->last_state = -1; bdata->threshold = DIV_ROUND_UP(button->debounce_interval, pdata->poll_interval); -- cgit v1.2.3 From f9645f22584250336a99a23bc9e444396b5bc323 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 19 Oct 2016 15:38:26 -0700 Subject: Input: gpio_keys - annotate PM methods as __maybe_unused Instead of using #ifdef, let's mark suspend and resume methods as __maybe_unused to provide better compile coverage. Tested-by: Mika Westerberg Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 890eb397d987..8f7c20b9cc5c 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -814,8 +814,7 @@ static int gpio_keys_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int gpio_keys_suspend(struct device *dev) +static int __maybe_unused gpio_keys_suspend(struct device *dev) { struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); struct input_dev *input = ddata->input; @@ -837,7 +836,7 @@ static int gpio_keys_suspend(struct device *dev) return 0; } -static int gpio_keys_resume(struct device *dev) +static int __maybe_unused gpio_keys_resume(struct device *dev) { struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); struct input_dev *input = ddata->input; @@ -863,7 +862,6 @@ static int gpio_keys_resume(struct device *dev) gpio_keys_report_state(ddata); return 0; } -#endif static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); -- cgit v1.2.3 From 0860913b02c28f0a1d8b515b99ae6419ef10569f Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 20 Oct 2016 15:11:45 -0700 Subject: Input: gpio_keys - fix leaking DT node references for_each_available_child_of_node(node, pp) takes reference to 'pp' and drops it when attempting next iteration. However if we exit the loop early we need to drop the reference ourselves. Tested-by: Mika Westerberg Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 8f7c20b9cc5c..d75a25c187ae 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -659,6 +659,7 @@ gpio_keys_get_devtree_pdata(struct device *dev) dev_err(dev, "Failed to get gpio flags, error: %d\n", error); + of_node_put(pp); return ERR_PTR(error); } } else { @@ -669,12 +670,14 @@ gpio_keys_get_devtree_pdata(struct device *dev) if (!gpio_is_valid(button->gpio) && !button->irq) { dev_err(dev, "Found button without gpios or irqs\n"); + of_node_put(pp); return ERR_PTR(-EINVAL); } if (of_property_read_u32(pp, "linux,code", &button->code)) { dev_err(dev, "Button without keycode: 0x%x\n", button->gpio); + of_node_put(pp); return ERR_PTR(-EINVAL); } -- cgit v1.2.3 From 5feeca3c1e39c01f9ef5abc94dea94021ccf94fc Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Wed, 19 Oct 2016 15:47:21 -0700 Subject: Input: gpio_keys - add support for GPIO descriptors GPIO descriptors are the preferred way over legacy GPIO numbers nowadays. Convert the driver to use GPIO descriptors internally but still allow passing legacy GPIO numbers from platform data to support existing platforms. Based on commits 633a21d80b4a2cd6 ("input: gpio_keys_polled: Add support for GPIO descriptors") and 1ae5ddb6f8837558 ("Input: gpio_keys_polled - request GPIO pin as input."). Signed-off-by: Geert Uytterhoeven Reviewed-by: Linus Walleij Tested-by: Mika Westerberg Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 37 ++++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index d75a25c187ae..0f04cb1569a0 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,7 @@ struct gpio_button_data { const struct gpio_keys_button *button; struct input_dev *input; + struct gpio_desc *gpiod; struct timer_list release_timer; unsigned int release_delay; /* in msecs, for IRQ-only buttons */ @@ -140,7 +142,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) */ disable_irq(bdata->irq); - if (gpio_is_valid(bdata->button->gpio)) + if (bdata->gpiod) cancel_delayed_work_sync(&bdata->work); else del_timer_sync(&bdata->release_timer); @@ -358,19 +360,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) const struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; - int state = gpio_get_value_cansleep(button->gpio); + int state; + state = gpiod_get_value_cansleep(bdata->gpiod); if (state < 0) { - dev_err(input->dev.parent, "failed to get gpio state\n"); + dev_err(input->dev.parent, + "failed to get gpio state: %d\n", state); return; } - state = (state ? 1 : 0) ^ button->active_low; if (type == EV_ABS) { if (state) input_event(input, type, button->code, button->value); } else { - input_event(input, type, button->code, !!state); + input_event(input, type, button->code, state); } input_sync(input); } @@ -456,7 +459,7 @@ static void gpio_keys_quiesce_key(void *data) { struct gpio_button_data *bdata = data; - if (gpio_is_valid(bdata->button->gpio)) + if (bdata->gpiod) cancel_delayed_work_sync(&bdata->work); else del_timer_sync(&bdata->release_timer); @@ -478,18 +481,30 @@ static int gpio_keys_setup_key(struct platform_device *pdev, bdata->button = button; spin_lock_init(&bdata->lock); + /* + * Legacy GPIO number, so request the GPIO here and + * convert it to descriptor. + */ if (gpio_is_valid(button->gpio)) { + unsigned flags = GPIOF_IN; + + if (button->active_low) + flags |= GPIOF_ACTIVE_LOW; - error = devm_gpio_request_one(&pdev->dev, button->gpio, - GPIOF_IN, desc); + error = devm_gpio_request_one(&pdev->dev, button->gpio, flags, + desc); if (error < 0) { dev_err(dev, "Failed to request GPIO %d, error %d\n", button->gpio, error); return error; } + bdata->gpiod = gpio_to_desc(button->gpio); + if (!bdata->gpiod) + return -EINVAL; + if (button->debounce_interval) { - error = gpio_set_debounce(button->gpio, + error = gpiod_set_debounce(bdata->gpiod, button->debounce_interval * 1000); /* use timer if gpiolib doesn't provide debounce */ if (error < 0) @@ -500,7 +515,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, if (button->irq) { bdata->irq = button->irq; } else { - irq = gpio_to_irq(button->gpio); + irq = gpiod_to_irq(bdata->gpiod); if (irq < 0) { error = irq; dev_err(dev, @@ -575,7 +590,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) for (i = 0; i < ddata->pdata->nbuttons; i++) { struct gpio_button_data *bdata = &ddata->data[i]; - if (gpio_is_valid(bdata->button->gpio)) + if (bdata->gpiod) gpio_keys_gpio_report_event(bdata); } input_sync(input); -- cgit v1.2.3 From 700a38b27eefc582099fdf69effacfad0ad738a4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 19 Oct 2016 19:34:48 -0700 Subject: Input: gpio_keys - switch to using generic device properties Make use of the device property API in this driver so that both OF based systems and ACPI based systems can use this driver. Suggested-by: Geert Uytterhoeven Suggested-by: Mika Westerberg Tested-by: Mika Westerberg Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 141 ++++++++++++++++++------------------- 1 file changed, 69 insertions(+), 72 deletions(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 0f04cb1569a0..5576f2ae0b71 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include @@ -468,7 +466,8 @@ static void gpio_keys_quiesce_key(void *data) static int gpio_keys_setup_key(struct platform_device *pdev, struct input_dev *input, struct gpio_button_data *bdata, - const struct gpio_keys_button *button) + const struct gpio_keys_button *button, + struct fwnode_handle *child) { const char *desc = button->desc ? button->desc : "gpio_keys"; struct device *dev = &pdev->dev; @@ -481,11 +480,28 @@ static int gpio_keys_setup_key(struct platform_device *pdev, bdata->button = button; spin_lock_init(&bdata->lock); - /* - * Legacy GPIO number, so request the GPIO here and - * convert it to descriptor. - */ - if (gpio_is_valid(button->gpio)) { + if (child) { + bdata->gpiod = devm_get_gpiod_from_child(dev, NULL, child); + if (IS_ERR(bdata->gpiod)) { + error = PTR_ERR(bdata->gpiod); + if (error == -ENOENT) { + /* + * GPIO is optional, we may be dealing with + * purely interrupt-driven setup. + */ + bdata->gpiod = NULL; + } else { + if (error != -EPROBE_DEFER) + dev_err(dev, "failed to get gpio: %d\n", + error); + return error; + } + } + } else if (gpio_is_valid(button->gpio)) { + /* + * Legacy GPIO number, so request the GPIO here and + * convert it to descriptor. + */ unsigned flags = GPIOF_IN; if (button->active_low) @@ -502,7 +518,9 @@ static int gpio_keys_setup_key(struct platform_device *pdev, bdata->gpiod = gpio_to_desc(button->gpio); if (!bdata->gpiod) return -EINVAL; + } + if (bdata->gpiod) { if (button->debounce_interval) { error = gpiod_set_debounce(bdata->gpiod, button->debounce_interval * 1000); @@ -533,9 +551,10 @@ static int gpio_keys_setup_key(struct platform_device *pdev, } else { if (!button->irq) { - dev_err(dev, "No IRQ specified\n"); + dev_err(dev, "Found button without gpio or irq\n"); return -EINVAL; } + bdata->irq = button->irq; if (button->type && button->type != EV_KEY) { @@ -627,24 +646,18 @@ static void gpio_keys_close(struct input_dev *input) * Handlers for alternative sources of platform_data */ -#ifdef CONFIG_OF /* - * Translate OpenFirmware node properties into platform_data + * Translate properties into platform_data */ static struct gpio_keys_platform_data * gpio_keys_get_devtree_pdata(struct device *dev) { - struct device_node *node, *pp; struct gpio_keys_platform_data *pdata; struct gpio_keys_button *button; - int error; + struct fwnode_handle *child; int nbuttons; - node = dev->of_node; - if (!node) - return ERR_PTR(-ENODEV); - - nbuttons = of_get_available_child_count(node); + nbuttons = device_get_child_node_count(dev); if (nbuttons == 0) return ERR_PTR(-ENODEV); @@ -659,64 +672,43 @@ gpio_keys_get_devtree_pdata(struct device *dev) pdata->buttons = button; pdata->nbuttons = nbuttons; - pdata->rep = !!of_get_property(node, "autorepeat", NULL); + pdata->rep = device_property_read_bool(dev, "autorepeat"); - of_property_read_string(node, "label", &pdata->name); + device_property_read_string(dev, "label", &pdata->name); - for_each_available_child_of_node(node, pp) { - enum of_gpio_flags flags; + device_for_each_child_node(dev, child) { + if (is_of_node(child)) + button->irq = + irq_of_parse_and_map(to_of_node(child), 0); - button->gpio = of_get_gpio_flags(pp, 0, &flags); - if (button->gpio < 0) { - error = button->gpio; - if (error != -ENOENT) { - if (error != -EPROBE_DEFER) - dev_err(dev, - "Failed to get gpio flags, error: %d\n", - error); - of_node_put(pp); - return ERR_PTR(error); - } - } else { - button->active_low = flags & OF_GPIO_ACTIVE_LOW; - } - - button->irq = irq_of_parse_and_map(pp, 0); - - if (!gpio_is_valid(button->gpio) && !button->irq) { - dev_err(dev, "Found button without gpios or irqs\n"); - of_node_put(pp); - return ERR_PTR(-EINVAL); - } - - if (of_property_read_u32(pp, "linux,code", &button->code)) { - dev_err(dev, "Button without keycode: 0x%x\n", - button->gpio); - of_node_put(pp); + if (fwnode_property_read_u32(child, "linux,code", + &button->code)) { + dev_err(dev, "Button without keycode\n"); + fwnode_handle_put(child); return ERR_PTR(-EINVAL); } - button->desc = of_get_property(pp, "label", NULL); + fwnode_property_read_string(child, "label", &button->desc); - if (of_property_read_u32(pp, "linux,input-type", &button->type)) + if (fwnode_property_read_u32(child, "linux,input-type", + &button->type)) button->type = EV_KEY; - button->wakeup = of_property_read_bool(pp, "wakeup-source") || - /* legacy name */ - of_property_read_bool(pp, "gpio-key,wakeup"); + button->wakeup = + fwnode_property_read_bool(child, "wakeup-source") || + /* legacy name */ + fwnode_property_read_bool(child, "gpio-key,wakeup"); - button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL); + button->can_disable = + fwnode_property_read_bool(child, "linux,can-disable"); - if (of_property_read_u32(pp, "debounce-interval", + if (fwnode_property_read_u32(child, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; button++; } - if (pdata->nbuttons == 0) - return ERR_PTR(-EINVAL); - return pdata; } @@ -726,20 +718,11 @@ static const struct of_device_id gpio_keys_of_match[] = { }; MODULE_DEVICE_TABLE(of, gpio_keys_of_match); -#else - -static inline struct gpio_keys_platform_data * -gpio_keys_get_devtree_pdata(struct device *dev) -{ - return ERR_PTR(-ENODEV); -} - -#endif - static int gpio_keys_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; const struct gpio_keys_platform_data *pdata = dev_get_platdata(dev); + struct fwnode_handle *child = NULL; struct gpio_keys_drvdata *ddata; struct input_dev *input; size_t size; @@ -792,14 +775,28 @@ static int gpio_keys_probe(struct platform_device *pdev) const struct gpio_keys_button *button = &pdata->buttons[i]; struct gpio_button_data *bdata = &ddata->data[i]; - error = gpio_keys_setup_key(pdev, input, bdata, button); - if (error) + if (!dev_get_platdata(dev)) { + child = device_get_next_child_node(&pdev->dev, child); + if (!child) { + dev_err(&pdev->dev, + "missing child device node for entry %d\n", + i); + return -EINVAL; + } + } + + error = gpio_keys_setup_key(pdev, input, bdata, button, child); + if (error) { + fwnode_handle_put(child); return error; + } if (button->wakeup) wakeup = 1; } + fwnode_handle_put(child); + error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group); if (error) { dev_err(dev, "Unable to export keys/switches, error: %d\n", @@ -889,7 +886,7 @@ static struct platform_driver gpio_keys_device_driver = { .driver = { .name = "gpio-keys", .pm = &gpio_keys_pm_ops, - .of_match_table = of_match_ptr(gpio_keys_of_match), + .of_match_table = gpio_keys_of_match, } }; -- cgit v1.2.3 From 64ad46379fcf14f437553f654d1adcd3d0e0d7f9 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Mon, 15 Aug 2016 14:21:28 +0200 Subject: mtd: bcm47xxsflash: use uncached MMIO access for BCM53573 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BCM53573 is a new series of Broadcom's SoCs. It's based on ARM and uses this old ChipCommon-based flash access. Early tests resulted in flash corruptions that were tracked down to using cached MMIO for flash read access. Switch to ioremap_nocache conditionally to support BCM53573 and don't break performance on old MIPS devices. Signed-off-by: Rafał Miłecki Reviewed-by: Boris Brezillon Signed-off-by: Brian Norris --- drivers/mtd/devices/bcm47xxsflash.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/bcm47xxsflash.c b/drivers/mtd/devices/bcm47xxsflash.c index 1c65c15b31a1..514be04c0b6c 100644 --- a/drivers/mtd/devices/bcm47xxsflash.c +++ b/drivers/mtd/devices/bcm47xxsflash.c @@ -296,16 +296,30 @@ static int bcm47xxsflash_bcma_probe(struct platform_device *pdev) dev_err(dev, "can't request region for resource %pR\n", res); return -EBUSY; } - b47s->window = ioremap_cache(res->start, resource_size(res)); - if (!b47s->window) { - dev_err(dev, "ioremap failed for resource %pR\n", res); - return -ENOMEM; - } b47s->bcma_cc = container_of(sflash, struct bcma_drv_cc, sflash); b47s->cc_read = bcm47xxsflash_bcma_cc_read; b47s->cc_write = bcm47xxsflash_bcma_cc_write; + /* + * On old MIPS devices cache was magically invalidated when needed, + * allowing us to use cached access and gain some performance. Trying + * the same on ARM based BCM53573 results in flash corruptions, we need + * to use uncached access for it. + * + * It may be arch specific, but right now there is only 1 ARM SoC using + * this driver, so let's follow Broadcom's reference code and check + * ChipCommon revision. + */ + if (b47s->bcma_cc->core->id.rev == 54) + b47s->window = ioremap_nocache(res->start, resource_size(res)); + else + b47s->window = ioremap_cache(res->start, resource_size(res)); + if (!b47s->window) { + dev_err(dev, "ioremap failed for resource %pR\n", res); + return -ENOMEM; + } + switch (b47s->bcma_cc->capabilities & BCMA_CC_CAP_FLASHT) { case BCMA_CC_FLASHT_STSER: b47s->type = BCM47XXSFLASH_TYPE_ST; -- cgit v1.2.3 From 819c21785b498d38fbbe361458dc2f05d943cc46 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 8 Nov 2016 22:20:37 +0100 Subject: rtc: jz4740: remove unused EXPORT_SYMBOL jz4740_rtc_poweroff() is only called from the driver, stop exporting it. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 33ccd73ee947..18feae6c4e95 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -252,12 +252,11 @@ static irqreturn_t jz4740_rtc_irq(int irq, void *data) return IRQ_HANDLED; } -void jz4740_rtc_poweroff(struct device *dev) +static void jz4740_rtc_poweroff(struct device *dev) { struct jz4740_rtc *rtc = dev_get_drvdata(dev); jz4740_rtc_reg_write(rtc, JZ_REG_RTC_HIBERNATE, 1); } -EXPORT_SYMBOL_GPL(jz4740_rtc_poweroff); static void jz4740_rtc_power_off(void) { -- cgit v1.2.3 From d1d111e073840b8dbc1ae90ba3fc274736451bdc Mon Sep 17 00:00:00 2001 From: Jan Beulich Date: Tue, 8 Nov 2016 00:43:54 -0700 Subject: PCI/MSI: Check for NULL affinity mask in pci_irq_get_affinity() If msi_setup_entry() fails to allocate an affinity mask, it logs a message but continues on and allocates an MSI entry with entry->affinity == NULL. Check for this case in pci_irq_get_affinity() so we don't try to dereference a NULL pointer. [bhelgaas: changelog] Fixes: ee8d41e53efe "pci/msi: Retrieve affinity for a vector" Signed-off-by: Jan Beulich Signed-off-by: Bjorn Helgaas Reviewed-by: Christoph Hellwig CC: Thomas Gleixner --- drivers/pci/msi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c index bfdd0744b686..da4e3c1248db 100644 --- a/drivers/pci/msi.c +++ b/drivers/pci/msi.c @@ -1292,7 +1292,8 @@ const struct cpumask *pci_irq_get_affinity(struct pci_dev *dev, int nr) } else if (dev->msi_enabled) { struct msi_desc *entry = first_pci_msi_entry(dev); - if (WARN_ON_ONCE(!entry || nr >= entry->nvec_used)) + if (WARN_ON_ONCE(!entry || !entry->affinity || + nr >= entry->nvec_used)) return NULL; return &entry->affinity[nr]; -- cgit v1.2.3 From ad338e8b5c8cdb5142380cd6b058dfe24956ee93 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Mon, 7 Nov 2016 17:33:07 -0800 Subject: Input: synaptics-rmi4 - stop scanning PDT after two empty pages We have encountered some RMI4 firmwares where there are blank pages in between PDT pages which contain functions. This change makes them correctly enumerate all functions on the device. Tested on S7817 (has empty page 2). Signed-off-by: Nick Dyer [Tested successfully on S7817 and S7300 Synaptics touch controllers] Tested-by: Chris Healy Reviewed-by: Andrew Duggan Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index c83bce89028b..81e20f1f7ec3 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -423,6 +423,7 @@ static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt, static int rmi_scan_pdt_page(struct rmi_device *rmi_dev, int page, + int *empty_pages, void *ctx, int (*callback)(struct rmi_device *rmi_dev, void *ctx, @@ -450,7 +451,16 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev, return retval; } - return (data->f01_bootloader_mode || addr == pdt_start) ? + /* + * Count number of empty PDT pages. If a gap of two pages + * or more is found, stop scanning. + */ + if (addr == pdt_start) + ++*empty_pages; + else + *empty_pages = 0; + + return (data->f01_bootloader_mode || *empty_pages >= 2) ? RMI_SCAN_DONE : RMI_SCAN_CONTINUE; } @@ -460,10 +470,12 @@ static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, const struct pdt_entry *entry)) { int page; + int empty_pages = 0; int retval = RMI_SCAN_DONE; for (page = 0; page <= RMI4_MAX_PAGE; page++) { - retval = rmi_scan_pdt_page(rmi_dev, page, ctx, callback); + retval = rmi_scan_pdt_page(rmi_dev, page, &empty_pages, + ctx, callback); if (retval != RMI_SCAN_CONTINUE) break; } -- cgit v1.2.3 From 6bd0dcfacf2875f234483d57acc16b015cd313f3 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Mon, 7 Nov 2016 17:35:15 -0800 Subject: Input: synaptics-rmi4 - factor out functions from probe Signed-off-by: Nick Dyer Signed-off-by: Benjamin Tissoires Tested-by: Chris Healy Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 139 +++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 81e20f1f7ec3..282522e58286 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -39,6 +39,8 @@ static void rmi_free_function_list(struct rmi_device *rmi_dev) struct rmi_function *fn, *tmp; struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); + rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n"); + data->f01_container = NULL; /* Doing it in the reverse order so F01 will be removed last */ @@ -855,15 +857,90 @@ static inline int rmi_driver_of_probe(struct device *dev, } #endif +static int rmi_probe_interrupts(struct rmi_driver_data *data) +{ + struct rmi_device *rmi_dev = data->rmi_dev; + struct device *dev = &rmi_dev->dev; + int irq_count; + size_t size; + void *irq_memory; + int retval; + + /* + * We need to count the IRQs and allocate their storage before scanning + * the PDT and creating the function entries, because adding a new + * function can trigger events that result in the IRQ related storage + * being accessed. + */ + rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__); + irq_count = 0; + retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs); + if (retval < 0) { + dev_err(dev, "IRQ counting failed with code %d.\n", retval); + return retval; + } + data->irq_count = irq_count; + data->num_of_irq_regs = (data->irq_count + 7) / 8; + + size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long); + irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL); + if (!irq_memory) { + dev_err(dev, "Failed to allocate memory for irq masks.\n"); + return retval; + } + + data->irq_status = irq_memory + size * 0; + data->fn_irq_bits = irq_memory + size * 1; + data->current_irq_mask = irq_memory + size * 2; + data->new_irq_mask = irq_memory + size * 3; + + return retval; +} + +static int rmi_init_functions(struct rmi_driver_data *data) +{ + struct rmi_device *rmi_dev = data->rmi_dev; + struct device *dev = &rmi_dev->dev; + int irq_count; + int retval; + + irq_count = 0; + rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__); + retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function); + if (retval < 0) { + dev_err(dev, "Function creation failed with code %d.\n", + retval); + goto err_destroy_functions; + } + + if (!data->f01_container) { + dev_err(dev, "Missing F01 container!\n"); + retval = -EINVAL; + goto err_destroy_functions; + } + + retval = rmi_read_block(rmi_dev, + data->f01_container->fd.control_base_addr + 1, + data->current_irq_mask, data->num_of_irq_regs); + if (retval < 0) { + dev_err(dev, "%s: Failed to read current IRQ mask.\n", + __func__); + goto err_destroy_functions; + } + + return 0; + +err_destroy_functions: + rmi_free_function_list(rmi_dev); + return retval; +} + static int rmi_driver_probe(struct device *dev) { struct rmi_driver *rmi_driver; struct rmi_driver_data *data; struct rmi_device_platform_data *pdata; struct rmi_device *rmi_dev; - size_t size; - void *irq_memory; - int irq_count; int retval; rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Starting probe.\n", @@ -929,35 +1006,11 @@ static int rmi_driver_probe(struct device *dev) PDT_PROPERTIES_LOCATION, retval); } - /* - * We need to count the IRQs and allocate their storage before scanning - * the PDT and creating the function entries, because adding a new - * function can trigger events that result in the IRQ related storage - * being accessed. - */ - rmi_dbg(RMI_DEBUG_CORE, dev, "Counting IRQs.\n"); - irq_count = 0; - retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs); - if (retval < 0) { - dev_err(dev, "IRQ counting failed with code %d.\n", retval); - goto err; - } - data->irq_count = irq_count; - data->num_of_irq_regs = (data->irq_count + 7) / 8; - mutex_init(&data->irq_mutex); - size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long); - irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL); - if (!irq_memory) { - dev_err(dev, "Failed to allocate memory for irq masks.\n"); + retval = rmi_probe_interrupts(data); + if (retval) goto err; - } - - data->irq_status = irq_memory + size * 0; - data->fn_irq_bits = irq_memory + size * 1; - data->current_irq_mask = irq_memory + size * 2; - data->new_irq_mask = irq_memory + size * 3; if (rmi_dev->xport->input) { /* @@ -974,36 +1027,16 @@ static int rmi_driver_probe(struct device *dev) dev_err(dev, "%s: Failed to allocate input device.\n", __func__); retval = -ENOMEM; - goto err_destroy_functions; + goto err; } rmi_driver_set_input_params(rmi_dev, data->input); data->input->phys = devm_kasprintf(dev, GFP_KERNEL, "%s/input0", dev_name(dev)); } - irq_count = 0; - rmi_dbg(RMI_DEBUG_CORE, dev, "Creating functions."); - retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function); - if (retval < 0) { - dev_err(dev, "Function creation failed with code %d.\n", - retval); - goto err_destroy_functions; - } - - if (!data->f01_container) { - dev_err(dev, "Missing F01 container!\n"); - retval = -EINVAL; - goto err_destroy_functions; - } - - retval = rmi_read_block(rmi_dev, - data->f01_container->fd.control_base_addr + 1, - data->current_irq_mask, data->num_of_irq_regs); - if (retval < 0) { - dev_err(dev, "%s: Failed to read current IRQ mask.\n", - __func__); - goto err_destroy_functions; - } + retval = rmi_init_functions(data); + if (retval) + goto err; if (data->input) { rmi_driver_set_input_name(rmi_dev, data->input); -- cgit v1.2.3 From 8029a283c4ac100dc4492993633d4c87a7da55d6 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Mon, 7 Nov 2016 17:36:57 -0800 Subject: Input: synaptics-rmi4 - add a couple of debug lines Signed-off-by: Nick Dyer Tested-by: Chris Healy Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_bus.c | 3 +++ drivers/input/rmi4/rmi_driver.c | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 09c769c6e91f..84b321262d74 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -231,6 +231,9 @@ err_put_device: void rmi_unregister_function(struct rmi_function *fn) { + rmi_dbg(RMI_DEBUG_CORE, &fn->dev, "Unregistering F%02X.\n", + fn->fd.function_number); + device_del(&fn->dev); of_node_put(fn->dev.of_node); put_device(&fn->dev); diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 282522e58286..06feede3ce17 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -735,6 +735,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev, return RMI_SCAN_DONE; } + rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Sending reset\n"); error = rmi_write_block(rmi_dev, cmd_addr, &cmd_buf, 1); if (error) { dev_err(&rmi_dev->dev, -- cgit v1.2.3 From c3fc60893d2d3ef55844c26770d080eceff68fd5 Mon Sep 17 00:00:00 2001 From: Sangwon Jee Date: Tue, 8 Nov 2016 16:07:05 -0800 Subject: Input: melfas_mip4 - add product ID reporting Add reporting product ID through input_id. Signed-off-by: Sangwon Jee Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/melfas_mip4.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/melfas_mip4.c b/drivers/input/touchscreen/melfas_mip4.c index 0f2230a9b1a1..703d7f983d0a 100644 --- a/drivers/input/touchscreen/melfas_mip4.c +++ b/drivers/input/touchscreen/melfas_mip4.c @@ -1477,6 +1477,7 @@ static int mip4_probe(struct i2c_client *client, const struct i2c_device_id *id) input->id.bustype = BUS_I2C; input->id.vendor = 0x13c5; + input->id.product = ts->product_id; input->open = mip4_input_open; input->close = mip4_input_close; @@ -1614,6 +1615,6 @@ static struct i2c_driver mip4_driver = { module_i2c_driver(mip4_driver); MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen"); -MODULE_VERSION("2016.10.24"); +MODULE_VERSION("2016.10.31"); MODULE_AUTHOR("Sangwon Jee "); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From b9168c539c0b2de756aaffd380384dbde8adbe07 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 8 Nov 2016 22:49:55 +0100 Subject: rtc: jz4740: make the driver builtin only Since the driver is now calling machine_halt() that is not exported, it has to be built in the kernel. Building it as a module will fail at linking time. Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 5 +---- drivers/rtc/rtc-jz4740.c | 10 +--------- 2 files changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4259ce61c31b..24b0778f6e28 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1550,15 +1550,12 @@ config RTC_DRV_MPC5121 will be called rtc-mpc5121. config RTC_DRV_JZ4740 - tristate "Ingenic JZ4740 SoC" + bool "Ingenic JZ4740 SoC" depends on MACH_INGENIC || COMPILE_TEST help If you say yes here you get support for the Ingenic JZ47xx SoCs RTC controllers. - This driver can also be buillt as a module. If so, the module - will be called rtc-jz4740. - config RTC_DRV_LPC24XX tristate "NXP RTC for LPC178x/18xx/408x/43xx" depends on ARCH_LPC18XX || COMPILE_TEST diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 18feae6c4e95..72918c1ba092 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -303,7 +302,6 @@ static const struct of_device_id jz4740_rtc_of_match[] = { { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, {}, }; -MODULE_DEVICE_TABLE(of, jz4740_rtc_of_match); static int jz4740_rtc_probe(struct platform_device *pdev) { @@ -431,7 +429,6 @@ static const struct platform_device_id jz4740_rtc_ids[] = { { "jz4780-rtc", ID_JZ4780 }, {} }; -MODULE_DEVICE_TABLE(platform, jz4740_rtc_ids); static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, @@ -443,9 +440,4 @@ static struct platform_driver jz4740_rtc_driver = { .id_table = jz4740_rtc_ids, }; -module_platform_driver(jz4740_rtc_driver); - -MODULE_AUTHOR("Lars-Peter Clausen "); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("RTC driver for the JZ4740 SoC\n"); -MODULE_ALIAS("platform:jz4740-rtc"); +builtin_platform_driver(jz4740_rtc_driver); -- cgit v1.2.3 From 72d3d79f8da9b17e1f47db567b8def0f9674555c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 8 Nov 2016 22:51:45 +0100 Subject: rtc: fix typos in Kconfig s/buillt/built/g Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 24b0778f6e28..ab55f35019fc 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1565,7 +1565,7 @@ config RTC_DRV_LPC24XX NXP LPC178x/18xx/408x/43xx devices. If you have one of the devices above enable this driver to use - the hardware RTC. This driver can also be buillt as a module. If + the hardware RTC. This driver can also be built as a module. If so, the module will be called rtc-lpc24xx. config RTC_DRV_LPC32XX @@ -1574,7 +1574,7 @@ config RTC_DRV_LPC32XX help This enables support for the NXP RTC in the LPC32XX - This driver can also be buillt as a module. If so, the module + This driver can also be built as a module. If so, the module will be called rtc-lpc32xx. config RTC_DRV_PM8XXX -- cgit v1.2.3 From 3aeed5b573f97b4525841cc07c1e948227af389f Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 8 Nov 2016 16:34:57 -0800 Subject: Input: synaptics-rmi4 - move IRQ handling to rmi_driver The attn IRQ is related to the chip, rather than the transport, so move all handling of interrupts to the core driver. This also makes sure that there are no races between interrupts and availability of the resources used by the core driver. Signed-off-by: Bjorn Andersson Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 73 +++++++++++++++++++++++++++++++++++++--- drivers/input/rmi4/rmi_i2c.c | 74 +++-------------------------------------- drivers/input/rmi4/rmi_spi.c | 72 +++------------------------------------ include/linux/rmi.h | 7 ++-- 4 files changed, 83 insertions(+), 143 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 06feede3ce17..4f8d19794b01 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -136,7 +137,7 @@ static void process_one_interrupt(struct rmi_driver_data *data, } } -int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) +static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) { struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); struct device *dev = &rmi_dev->dev; @@ -181,7 +182,42 @@ int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) return 0; } -EXPORT_SYMBOL_GPL(rmi_process_interrupt_requests); + +static irqreturn_t rmi_irq_fn(int irq, void *dev_id) +{ + struct rmi_device *rmi_dev = dev_id; + int ret; + + ret = rmi_process_interrupt_requests(rmi_dev); + if (ret) + rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, + "Failed to process interrupt request: %d\n", ret); + + return IRQ_HANDLED; +} + +static int rmi_irq_init(struct rmi_device *rmi_dev) +{ + struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); + int irq_flags = irq_get_trigger_type(pdata->irq); + int ret; + + if (!irq_flags) + irq_flags = IRQF_TRIGGER_LOW; + + ret = devm_request_threaded_irq(&rmi_dev->dev, pdata->irq, NULL, + rmi_irq_fn, irq_flags | IRQF_ONESHOT, + dev_name(rmi_dev->xport->dev), + rmi_dev); + if (ret < 0) { + dev_err(&rmi_dev->dev, "Failed to register interrupt %d\n", + pdata->irq); + + return ret; + } + + return 0; +} static int suspend_one_function(struct rmi_function *fn) { @@ -802,8 +838,10 @@ err_put_fn: return error; } -int rmi_driver_suspend(struct rmi_device *rmi_dev) +int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake) { + struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); + int irq = pdata->irq; int retval = 0; retval = rmi_suspend_functions(rmi_dev); @@ -811,14 +849,33 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev) dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", retval); + disable_irq(irq); + if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) { + retval = enable_irq_wake(irq); + if (!retval) + dev_warn(&rmi_dev->dev, + "Failed to enable irq for wake: %d\n", + retval); + } return retval; } EXPORT_SYMBOL_GPL(rmi_driver_suspend); -int rmi_driver_resume(struct rmi_device *rmi_dev) +int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake) { + struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); + int irq = pdata->irq; int retval; + enable_irq(irq); + if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) { + retval = disable_irq_wake(irq); + if (!retval) + dev_warn(&rmi_dev->dev, + "Failed to disable irq for wake: %d\n", + retval); + } + retval = rmi_resume_functions(rmi_dev); if (retval) dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", @@ -831,6 +888,10 @@ EXPORT_SYMBOL_GPL(rmi_driver_resume); static int rmi_driver_remove(struct device *dev) { struct rmi_device *rmi_dev = to_rmi_device(dev); + struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); + int irq = pdata->irq; + + disable_irq(irq); rmi_free_function_list(rmi_dev); @@ -1050,6 +1111,10 @@ static int rmi_driver_probe(struct device *dev) } } + retval = rmi_irq_init(rmi_dev); + if (retval < 0) + goto err_destroy_functions; + if (data->f01_container->dev.driver) /* Driver already bound, so enable ATTN now. */ return enable_sensor(rmi_dev); diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c index 6f2e0e4f0296..64a548822da4 100644 --- a/drivers/input/rmi4/rmi_i2c.c +++ b/drivers/input/rmi4/rmi_i2c.c @@ -9,7 +9,6 @@ #include #include -#include #include #include #include @@ -35,8 +34,6 @@ struct rmi_i2c_xport { struct mutex page_mutex; int page; - int irq; - u8 *tx_buf; size_t tx_buf_size; @@ -177,42 +174,6 @@ static const struct rmi_transport_ops rmi_i2c_ops = { .read_block = rmi_i2c_read_block, }; -static irqreturn_t rmi_i2c_irq(int irq, void *dev_id) -{ - struct rmi_i2c_xport *rmi_i2c = dev_id; - struct rmi_device *rmi_dev = rmi_i2c->xport.rmi_dev; - int ret; - - ret = rmi_process_interrupt_requests(rmi_dev); - if (ret) - rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev, - "Failed to process interrupt request: %d\n", ret); - - return IRQ_HANDLED; -} - -static int rmi_i2c_init_irq(struct i2c_client *client) -{ - struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); - int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_i2c->irq)); - int ret; - - if (!irq_flags) - irq_flags = IRQF_TRIGGER_LOW; - - ret = devm_request_threaded_irq(&client->dev, rmi_i2c->irq, NULL, - rmi_i2c_irq, irq_flags | IRQF_ONESHOT, client->name, - rmi_i2c); - if (ret < 0) { - dev_warn(&client->dev, "Failed to register interrupt %d\n", - rmi_i2c->irq); - - return ret; - } - - return 0; -} - #ifdef CONFIG_OF static const struct of_device_id rmi_i2c_of_match[] = { { .compatible = "syna,rmi4-i2c" }, @@ -240,8 +201,7 @@ static int rmi_i2c_probe(struct i2c_client *client, if (!client->dev.of_node && client_pdata) *pdata = *client_pdata; - if (client->irq > 0) - rmi_i2c->irq = client->irq; + pdata->irq = client->irq; rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n", dev_name(&client->dev)); @@ -295,10 +255,6 @@ static int rmi_i2c_probe(struct i2c_client *client, return retval; } - retval = rmi_i2c_init_irq(client); - if (retval < 0) - return retval; - dev_info(&client->dev, "registered rmi i2c driver at %#04x.\n", client->addr); return 0; @@ -322,18 +278,10 @@ static int rmi_i2c_suspend(struct device *dev) struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); int ret; - ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev); + ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, true); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); - disable_irq(rmi_i2c->irq); - if (device_may_wakeup(&client->dev)) { - ret = enable_irq_wake(rmi_i2c->irq); - if (!ret) - dev_warn(dev, "Failed to enable irq for wake: %d\n", - ret); - } - regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), rmi_i2c->supplies); @@ -353,15 +301,7 @@ static int rmi_i2c_resume(struct device *dev) msleep(rmi_i2c->startup_delay); - enable_irq(rmi_i2c->irq); - if (device_may_wakeup(&client->dev)) { - ret = disable_irq_wake(rmi_i2c->irq); - if (!ret) - dev_warn(dev, "Failed to disable irq for wake: %d\n", - ret); - } - - ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev); + ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, true); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); @@ -376,12 +316,10 @@ static int rmi_i2c_runtime_suspend(struct device *dev) struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client); int ret; - ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev); + ret = rmi_driver_suspend(rmi_i2c->xport.rmi_dev, false); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); - disable_irq(rmi_i2c->irq); - regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies), rmi_i2c->supplies); @@ -401,9 +339,7 @@ static int rmi_i2c_runtime_resume(struct device *dev) msleep(rmi_i2c->startup_delay); - enable_irq(rmi_i2c->irq); - - ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev); + ret = rmi_driver_resume(rmi_i2c->xport.rmi_dev, false); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); diff --git a/drivers/input/rmi4/rmi_spi.c b/drivers/input/rmi4/rmi_spi.c index 55bd1b34970c..f3e9e488635c 100644 --- a/drivers/input/rmi4/rmi_spi.c +++ b/drivers/input/rmi4/rmi_spi.c @@ -12,7 +12,6 @@ #include #include #include -#include #include #include "rmi_driver.h" @@ -44,8 +43,6 @@ struct rmi_spi_xport { struct mutex page_mutex; int page; - int irq; - u8 *rx_buf; u8 *tx_buf; int xfer_buf_size; @@ -326,41 +323,6 @@ static const struct rmi_transport_ops rmi_spi_ops = { .read_block = rmi_spi_read_block, }; -static irqreturn_t rmi_spi_irq(int irq, void *dev_id) -{ - struct rmi_spi_xport *rmi_spi = dev_id; - struct rmi_device *rmi_dev = rmi_spi->xport.rmi_dev; - int ret; - - ret = rmi_process_interrupt_requests(rmi_dev); - if (ret) - rmi_dbg(RMI_DEBUG_XPORT, &rmi_dev->dev, - "Failed to process interrupt request: %d\n", ret); - - return IRQ_HANDLED; -} - -static int rmi_spi_init_irq(struct spi_device *spi) -{ - struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); - int irq_flags = irqd_get_trigger_type(irq_get_irq_data(rmi_spi->irq)); - int ret; - - if (!irq_flags) - irq_flags = IRQF_TRIGGER_LOW; - - ret = devm_request_threaded_irq(&spi->dev, rmi_spi->irq, NULL, - rmi_spi_irq, irq_flags | IRQF_ONESHOT, - dev_name(&spi->dev), rmi_spi); - if (ret < 0) { - dev_warn(&spi->dev, "Failed to register interrupt %d\n", - rmi_spi->irq); - return ret; - } - - return 0; -} - #ifdef CONFIG_OF static int rmi_spi_of_probe(struct spi_device *spi, struct rmi_device_platform_data *pdata) @@ -433,8 +395,7 @@ static int rmi_spi_probe(struct spi_device *spi) return retval; } - if (spi->irq > 0) - rmi_spi->irq = spi->irq; + pdata->irq = spi->irq; rmi_spi->spi = spi; mutex_init(&rmi_spi->page_mutex); @@ -465,10 +426,6 @@ static int rmi_spi_probe(struct spi_device *spi) return retval; } - retval = rmi_spi_init_irq(spi); - if (retval < 0) - return retval; - dev_info(&spi->dev, "registered RMI SPI driver\n"); return 0; } @@ -489,17 +446,10 @@ static int rmi_spi_suspend(struct device *dev) struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); int ret; - ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev); + ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, true); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); - disable_irq(rmi_spi->irq); - if (device_may_wakeup(&spi->dev)) { - ret = enable_irq_wake(rmi_spi->irq); - if (!ret) - dev_warn(dev, "Failed to enable irq for wake: %d\n", - ret); - } return ret; } @@ -509,15 +459,7 @@ static int rmi_spi_resume(struct device *dev) struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); int ret; - enable_irq(rmi_spi->irq); - if (device_may_wakeup(&spi->dev)) { - ret = disable_irq_wake(rmi_spi->irq); - if (!ret) - dev_warn(dev, "Failed to disable irq for wake: %d\n", - ret); - } - - ret = rmi_driver_resume(rmi_spi->xport.rmi_dev); + ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, true); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); @@ -532,12 +474,10 @@ static int rmi_spi_runtime_suspend(struct device *dev) struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); int ret; - ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev); + ret = rmi_driver_suspend(rmi_spi->xport.rmi_dev, false); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); - disable_irq(rmi_spi->irq); - return 0; } @@ -547,9 +487,7 @@ static int rmi_spi_runtime_resume(struct device *dev) struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi); int ret; - enable_irq(rmi_spi->irq); - - ret = rmi_driver_resume(rmi_spi->xport.rmi_dev); + ret = rmi_driver_resume(rmi_spi->xport.rmi_dev, false); if (ret) dev_warn(dev, "Failed to resume device: %d\n", ret); diff --git a/include/linux/rmi.h b/include/linux/rmi.h index e0aca1476001..5944e6c2470d 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -204,9 +204,11 @@ struct rmi_device_platform_data_spi { * @reset_delay_ms - after issuing a reset command to the touch sensor, the * driver waits a few milliseconds to give the firmware a chance to * to re-initialize. You can override the default wait period here. + * @irq: irq associated with the attn gpio line, or negative */ struct rmi_device_platform_data { int reset_delay_ms; + int irq; struct rmi_device_platform_data_spi spi_data; @@ -352,8 +354,7 @@ struct rmi_driver_data { int rmi_register_transport_device(struct rmi_transport_dev *xport); void rmi_unregister_transport_device(struct rmi_transport_dev *xport); -int rmi_process_interrupt_requests(struct rmi_device *rmi_dev); -int rmi_driver_suspend(struct rmi_device *rmi_dev); -int rmi_driver_resume(struct rmi_device *rmi_dev); +int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake); +int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake); #endif -- cgit v1.2.3 From 6d0dbeae71f074c67b081eae45cd58fa39dfda2e Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 8 Nov 2016 16:46:20 -0800 Subject: Input: synaptics-rmi4 - handle incomplete input data Commit 5b65c2a02966 ("HID: rmi: check sanity of the incoming report") added support for handling incomplete HID reports do to the input data being corrupted in transit. This patch reimplements this functionality in the function drivers so they can handle getting less valid data then they expect. Signed-off-by: Andrew Duggan Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f11.c | 54 ++++++++++++++++++++++++++++++++------------ drivers/input/rmi4/rmi_f12.c | 23 ++++++++++++++----- drivers/input/rmi4/rmi_f30.c | 4 ++++ 3 files changed, 61 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index 20c7134b3d3b..3218742d2d8c 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -572,31 +572,48 @@ static inline u8 rmi_f11_parse_finger_state(const u8 *f_state, u8 n_finger) static void rmi_f11_finger_handler(struct f11_data *f11, struct rmi_2d_sensor *sensor, - unsigned long *irq_bits, int num_irq_regs) + unsigned long *irq_bits, int num_irq_regs, + int size) { const u8 *f_state = f11->data.f_state; u8 finger_state; u8 i; + int abs_fingers; + int rel_fingers; + int abs_size = sensor->nbr_fingers * RMI_F11_ABS_BYTES; int abs_bits = bitmap_and(f11->result_bits, irq_bits, f11->abs_mask, num_irq_regs * 8); int rel_bits = bitmap_and(f11->result_bits, irq_bits, f11->rel_mask, num_irq_regs * 8); - for (i = 0; i < sensor->nbr_fingers; i++) { - /* Possible of having 4 fingers per f_statet register */ - finger_state = rmi_f11_parse_finger_state(f_state, i); - if (finger_state == F11_RESERVED) { - pr_err("Invalid finger state[%d]: 0x%02x", i, - finger_state); - continue; - } + if (abs_bits) { + if (abs_size > size) + abs_fingers = size / RMI_F11_ABS_BYTES; + else + abs_fingers = sensor->nbr_fingers; + + for (i = 0; i < abs_fingers; i++) { + /* Possible of having 4 fingers per f_state register */ + finger_state = rmi_f11_parse_finger_state(f_state, i); + if (finger_state == F11_RESERVED) { + pr_err("Invalid finger state[%d]: 0x%02x", i, + finger_state); + continue; + } - if (abs_bits) rmi_f11_abs_pos_process(f11, sensor, &sensor->objs[i], finger_state, i); + } + } + + if (rel_bits) { + if ((abs_size + sensor->nbr_fingers * RMI_F11_REL_BYTES) > size) + rel_fingers = (size - abs_size) / RMI_F11_REL_BYTES; + else + rel_fingers = sensor->nbr_fingers; - if (rel_bits) + for (i = 0; i < rel_fingers; i++) rmi_f11_rel_pos_report(f11, i); } @@ -612,7 +629,7 @@ static void rmi_f11_finger_handler(struct f11_data *f11, sensor->nbr_fingers, sensor->dmax); - for (i = 0; i < sensor->nbr_fingers; i++) { + for (i = 0; i < abs_fingers; i++) { finger_state = rmi_f11_parse_finger_state(f_state, i); if (finger_state == F11_RESERVED) /* no need to send twice the error */ @@ -1242,10 +1259,19 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) struct f11_data *f11 = dev_get_drvdata(&fn->dev); u16 data_base_addr = fn->fd.data_base_addr; int error; + int valid_bytes = f11->sensor.pkt_size; if (rmi_dev->xport->attn_data) { + /* + * The valid data in the attention report is less then + * expected. Only process the complete fingers. + */ + if (f11->sensor.attn_size > rmi_dev->xport->attn_size) + valid_bytes = rmi_dev->xport->attn_size; + else + valid_bytes = f11->sensor.attn_size; memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data, - f11->sensor.attn_size); + valid_bytes); rmi_dev->xport->attn_data += f11->sensor.attn_size; rmi_dev->xport->attn_size -= f11->sensor.attn_size; } else { @@ -1257,7 +1283,7 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) } rmi_f11_finger_handler(f11, &f11->sensor, irq_bits, - drvdata->num_of_irq_regs); + drvdata->num_of_irq_regs, valid_bytes); return 0; } diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 332c02f0b107..767ac7920c75 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -26,6 +26,8 @@ enum rmi_f12_object_type { RMI_F12_OBJECT_SMALL_OBJECT = 0x0D, }; +#define F12_DATA1_BYTES_PER_OBJ 8 + struct f12_data { struct rmi_2d_sensor sensor; struct rmi_2d_sensor_platform_data sensor_pdata; @@ -146,12 +148,16 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) return 0; } -static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1) +static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1, int size) { int i; struct rmi_2d_sensor *sensor = &f12->sensor; + int objects = f12->data1->num_subpackets; + + if ((f12->data1->num_subpackets * F12_DATA1_BYTES_PER_OBJ) > size) + objects = size / F12_DATA1_BYTES_PER_OBJ; - for (i = 0; i < f12->data1->num_subpackets; i++) { + for (i = 0; i < objects; i++) { struct rmi_2d_sensor_abs_object *obj = &sensor->objs[i]; obj->type = RMI_2D_OBJECT_NONE; @@ -182,7 +188,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1) rmi_2d_sensor_abs_process(sensor, obj, i); - data1 += 8; + data1 += F12_DATA1_BYTES_PER_OBJ; } if (sensor->kernel_tracking) @@ -192,7 +198,7 @@ static void rmi_f12_process_objects(struct f12_data *f12, u8 *data1) sensor->nbr_fingers, sensor->dmax); - for (i = 0; i < sensor->nbr_fingers; i++) + for (i = 0; i < objects; i++) rmi_2d_sensor_abs_report(sensor, &sensor->objs[i], i); } @@ -203,10 +209,15 @@ static int rmi_f12_attention(struct rmi_function *fn, struct rmi_device *rmi_dev = fn->rmi_dev; struct f12_data *f12 = dev_get_drvdata(&fn->dev); struct rmi_2d_sensor *sensor = &f12->sensor; + int valid_bytes = sensor->pkt_size; if (rmi_dev->xport->attn_data) { + if (sensor->attn_size > rmi_dev->xport->attn_size) + valid_bytes = rmi_dev->xport->attn_size; + else + valid_bytes = sensor->attn_size; memcpy(sensor->data_pkt, rmi_dev->xport->attn_data, - sensor->attn_size); + valid_bytes); rmi_dev->xport->attn_data += sensor->attn_size; rmi_dev->xport->attn_size -= sensor->attn_size; } else { @@ -221,7 +232,7 @@ static int rmi_f12_attention(struct rmi_function *fn, if (f12->data1) rmi_f12_process_objects(f12, - &sensor->data_pkt[f12->data1_offset]); + &sensor->data_pkt[f12->data1_offset], valid_bytes); input_mt_sync_frame(sensor->input); diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c index 760aff1bc420..485907ff10f4 100644 --- a/drivers/input/rmi4/rmi_f30.c +++ b/drivers/input/rmi4/rmi_f30.c @@ -110,6 +110,10 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits) /* Read the gpi led data. */ if (rmi_dev->xport->attn_data) { + if (rmi_dev->xport->attn_size < f30->register_count) { + dev_warn(&fn->dev, "F30 interrupted, but data is missing\n"); + return 0; + } memcpy(f30->data_regs, rmi_dev->xport->attn_data, f30->register_count); rmi_dev->xport->attn_data += f30->register_count; -- cgit v1.2.3 From 2775e523246e11c5ce90b69226c5e67aa43e64a5 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 8 Nov 2016 16:48:48 -0800 Subject: Input: synaptics-rmi4 - add parameters for dribble packets and palm detect gesture The rmi_f11 driver currently disables dribble packets and the palm detect gesture for all devices. This patch creates a parameter in the 2d sensor platform data for controlling this functionality on a per device basis. For more information on dribble packets: Commit 05ba999fcabb ("HID: rmi: disable dribble packets on Synaptics touchpads") For more information on the palm detect gesture: Commit f097deef59a6 ("HID: rmi: disable palm detect gesture when present") Signed-off-by: Andrew Duggan Reviewed-by: Benjamin Tissoires Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_2d_sensor.h | 2 ++ drivers/input/rmi4/rmi_f01.c | 6 +++--- drivers/input/rmi4/rmi_f11.c | 32 ++++++++++++++++++++++++++++---- include/linux/rmi.h | 21 +++++++++++++-------- 4 files changed, 46 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_2d_sensor.h b/drivers/input/rmi4/rmi_2d_sensor.h index 77fcdfef003c..c871bef4dac0 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.h +++ b/drivers/input/rmi4/rmi_2d_sensor.h @@ -67,6 +67,8 @@ struct rmi_2d_sensor { u8 report_rel; u8 x_mm; u8 y_mm; + enum rmi_reg_state dribble; + enum rmi_reg_state palm_detect; }; int rmi_2d_sensor_of_probe(struct device *dev, diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c index fac81fc9bcf6..2cfa9f64acfb 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c @@ -327,12 +327,12 @@ static int rmi_f01_probe(struct rmi_function *fn) } switch (pdata->power_management.nosleep) { - case RMI_F01_NOSLEEP_DEFAULT: + case RMI_REG_STATE_DEFAULT: break; - case RMI_F01_NOSLEEP_OFF: + case RMI_REG_STATE_OFF: f01->device_control.ctrl0 &= ~RMI_F01_CTRL0_NOSLEEP_BIT; break; - case RMI_F01_NOSLEEP_ON: + case RMI_REG_STATE_ON: f01->device_control.ctrl0 |= RMI_F01_CTRL0_NOSLEEP_BIT; break; } diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index 3218742d2d8c..c252d405df4c 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -1142,6 +1142,8 @@ static int rmi_f11_initialize(struct rmi_function *fn) sensor->topbuttonpad = f11->sensor_pdata.topbuttonpad; sensor->kernel_tracking = f11->sensor_pdata.kernel_tracking; sensor->dmax = f11->sensor_pdata.dmax; + sensor->dribble = f11->sensor_pdata.dribble; + sensor->palm_detect = f11->sensor_pdata.palm_detect; if (f11->sens_query.has_physical_props) { sensor->x_mm = f11->sens_query.x_sensor_size_mm; @@ -1209,11 +1211,33 @@ static int rmi_f11_initialize(struct rmi_function *fn) ctrl->ctrl0_11[RMI_F11_DELTA_Y_THRESHOLD] = sensor->axis_align.delta_y_threshold; - if (f11->sens_query.has_dribble) - ctrl->ctrl0_11[0] = ctrl->ctrl0_11[0] & ~BIT(6); + if (f11->sens_query.has_dribble) { + switch (sensor->dribble) { + case RMI_REG_STATE_OFF: + ctrl->ctrl0_11[0] &= ~BIT(6); + break; + case RMI_REG_STATE_ON: + ctrl->ctrl0_11[0] |= BIT(6); + break; + case RMI_REG_STATE_DEFAULT: + default: + break; + } + } - if (f11->sens_query.has_palm_det) - ctrl->ctrl0_11[11] = ctrl->ctrl0_11[11] & ~BIT(0); + if (f11->sens_query.has_palm_det) { + switch (sensor->palm_detect) { + case RMI_REG_STATE_OFF: + ctrl->ctrl0_11[11] &= ~BIT(0); + break; + case RMI_REG_STATE_ON: + ctrl->ctrl0_11[11] |= BIT(0); + break; + case RMI_REG_STATE_DEFAULT: + default: + break; + } + } rc = f11_write_control_regs(fn, &f11->sens_query, &f11->dev_controls, fn->fd.query_base_addr); diff --git a/include/linux/rmi.h b/include/linux/rmi.h index 5944e6c2470d..ac904bb439a5 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -99,6 +99,8 @@ struct rmi_2d_sensor_platform_data { bool topbuttonpad; bool kernel_tracking; int dmax; + int dribble; + int palm_detect; }; /** @@ -116,14 +118,17 @@ struct rmi_f30_data { bool disable; }; -/** - * struct rmi_f01_power - override default power management settings. - * + +/* + * Set the state of a register + * DEFAULT - use the default value set by the firmware config + * OFF - explicitly disable the register + * ON - explicitly enable the register */ -enum rmi_f01_nosleep { - RMI_F01_NOSLEEP_DEFAULT = 0, - RMI_F01_NOSLEEP_OFF = 1, - RMI_F01_NOSLEEP_ON = 2 +enum rmi_reg_state { + RMI_REG_STATE_DEFAULT = 0, + RMI_REG_STATE_OFF = 1, + RMI_REG_STATE_ON = 2 }; /** @@ -143,7 +148,7 @@ enum rmi_f01_nosleep { * when the touch sensor is in doze mode, in units of 10ms. */ struct rmi_f01_power_management { - enum rmi_f01_nosleep nosleep; + enum rmi_reg_state nosleep; u8 wakeup_threshold; u8 doze_holdoff; u8 doze_interval; -- cgit v1.2.3 From 24f63b1cb05034de74289a684e0938388757085d Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 8 Nov 2016 16:47:58 -0800 Subject: Input: synaptics-rmi4 - add support for controlling dribble packets in F12 Implements reading and setting the dribble bit in F12's control registers. Signed-off-by: Andrew Duggan Acked-by: Benjamin Tissoires Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f12.c | 70 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 767ac7920c75..d7255f18306d 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -31,6 +31,7 @@ enum rmi_f12_object_type { struct f12_data { struct rmi_2d_sensor sensor; struct rmi_2d_sensor_platform_data sensor_pdata; + bool has_dribble; u16 data_addr; @@ -239,12 +240,76 @@ static int rmi_f12_attention(struct rmi_function *fn, return 0; } +static int rmi_f12_write_control_regs(struct rmi_function *fn) +{ + int ret; + const struct rmi_register_desc_item *item; + struct rmi_device *rmi_dev = fn->rmi_dev; + struct f12_data *f12 = dev_get_drvdata(&fn->dev); + int control_size; + char buf[3]; + u16 control_offset = 0; + u8 subpacket_offset = 0; + + if (f12->has_dribble + && (f12->sensor.dribble != RMI_REG_STATE_DEFAULT)) { + item = rmi_get_register_desc_item(&f12->control_reg_desc, 20); + if (item) { + control_offset = rmi_register_desc_calc_reg_offset( + &f12->control_reg_desc, 20); + + /* + * The byte containing the EnableDribble bit will be + * in either byte 0 or byte 2 of control 20. Depending + * on the existence of subpacket 0. If control 20 is + * larger then 3 bytes, just read the first 3. + */ + control_size = min(item->reg_size, 3UL); + + ret = rmi_read_block(rmi_dev, fn->fd.control_base_addr + + control_offset, buf, control_size); + if (ret) + return ret; + + if (rmi_register_desc_has_subpacket(item, 0)) + subpacket_offset += 1; + + switch (f12->sensor.dribble) { + case RMI_REG_STATE_OFF: + buf[subpacket_offset] &= ~BIT(2); + break; + case RMI_REG_STATE_ON: + buf[subpacket_offset] |= BIT(2); + break; + case RMI_REG_STATE_DEFAULT: + default: + break; + } + + ret = rmi_write_block(rmi_dev, + fn->fd.control_base_addr + control_offset, + buf, control_size); + if (ret) + return ret; + } + } + + return 0; + +} + static int rmi_f12_config(struct rmi_function *fn) { struct rmi_driver *drv = fn->rmi_dev->driver; + int ret; drv->set_irq_bits(fn->rmi_dev, fn->irq_mask); + ret = rmi_f12_write_control_regs(fn); + if (ret) + dev_warn(&fn->dev, + "Failed to write F12 control registers: %d\n", ret); + return 0; } @@ -271,7 +336,7 @@ static int rmi_f12_probe(struct rmi_function *fn) } ++query_addr; - if (!(buf & 0x1)) { + if (!(buf & BIT(0))) { dev_err(&fn->dev, "Behavior of F12 without register descriptors is undefined.\n"); return -ENODEV; @@ -281,6 +346,8 @@ static int rmi_f12_probe(struct rmi_function *fn) if (!f12) return -ENOMEM; + f12->has_dribble = !!(buf & BIT(3)); + if (fn->dev.of_node) { ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata); if (ret) @@ -329,6 +396,7 @@ static int rmi_f12_probe(struct rmi_function *fn) sensor->x_mm = f12->sensor_pdata.x_mm; sensor->y_mm = f12->sensor_pdata.y_mm; + sensor->dribble = f12->sensor_pdata.dribble; if (sensor->sensor_type == rmi_sensor_default) sensor->sensor_type = -- cgit v1.2.3 From 332c3988fe9cbecf9d50f19596b66a34b5eda6de Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 8 Nov 2016 17:03:16 -0800 Subject: Input: synaptics-rmi4 - set the ABS_MT_TOOL_TYPE bit to report tool type The rmi4 2D sensor functions report the tool type via input_mt_report_slot_state(), but the abs parameter bit has not been set so the tool type is not reported to userspace. This patch set the ABS_MT_TOOL_TYPE bit. Signed-off-by: Andrew Duggan Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_2d_sensor.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_2d_sensor.c b/drivers/input/rmi4/rmi_2d_sensor.c index e97bd7fabccc..07007ff8e29f 100644 --- a/drivers/input/rmi4/rmi_2d_sensor.c +++ b/drivers/input/rmi4/rmi_2d_sensor.c @@ -177,10 +177,12 @@ static void rmi_2d_sensor_set_input_params(struct rmi_2d_sensor *sensor) sensor->dmax = DMAX * res_x; } - input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); - input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); - input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); + input_set_abs_params(input, ABS_MT_PRESSURE, 0, 0xff, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 0x0f, 0, 0); + input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 0x0f, 0, 0); + input_set_abs_params(input, ABS_MT_ORIENTATION, 0, 1, 0, 0); + input_set_abs_params(input, ABS_MT_TOOL_TYPE, + 0, MT_TOOL_MAX, 0, 0); if (sensor->sensor_type == rmi_sensor_touchpad) input_flags = INPUT_MT_POINTER; -- cgit v1.2.3 From 82264d0cf7aef2247563c031ff2ab96579d5d0cc Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 8 Nov 2016 17:05:58 -0800 Subject: Input: synaptics-rmi4 - add SMBus support Code obtained from https://raw.githubusercontent.com/mightybigcar/synaptics-rmi4/jf/drivers/input/rmi4/rmi_smbus.c and updated to match upstream. And fixed to make it work. Signed-off-by: Benjamin Tissoires Signed-off-by: Andrew Duggan Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/Kconfig | 12 ++ drivers/input/rmi4/Makefile | 1 + drivers/input/rmi4/rmi_bus.h | 12 ++ drivers/input/rmi4/rmi_smbus.c | 447 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 472 insertions(+) create mode 100644 drivers/input/rmi4/rmi_smbus.c (limited to 'drivers') diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index 4c8a55857e00..8cbd362ae8a7 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -27,6 +27,18 @@ config RMI4_SPI If unsure, say N. +config RMI4_SMB + tristate "RMI4 SMB Support" + depends on RMI4_CORE && I2C + help + Say Y here if you want to support RMI4 devices connected to an SMB + bus. + + If unsure, say N. + + To compile this driver as a module, choose M here: the module will be + called rmi_smbus. + config RMI4_2D_SENSOR bool depends on RMI4_CORE diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index 0bafc8502c4b..a6e27527d514 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -12,3 +12,4 @@ rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o # Transports obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o obj-$(CONFIG_RMI4_SPI) += rmi_spi.o +obj-$(CONFIG_RMI4_SMB) += rmi_smbus.o diff --git a/drivers/input/rmi4/rmi_bus.h b/drivers/input/rmi4/rmi_bus.h index 899579830536..b7625a9ac66a 100644 --- a/drivers/input/rmi4/rmi_bus.h +++ b/drivers/input/rmi4/rmi_bus.h @@ -104,6 +104,18 @@ rmi_get_platform_data(struct rmi_device *d) bool rmi_is_physical_device(struct device *dev); +/** + * rmi_reset - reset a RMI4 device + * @d: Pointer to an RMI device + * + * Calls for a reset of each function implemented by a specific device. + * Returns 0 on success or a negative error code. + */ +static inline int rmi_reset(struct rmi_device *d) +{ + return d->driver->reset_handler(d); +} + /** * rmi_read - read a single byte * @d: Pointer to an RMI device diff --git a/drivers/input/rmi4/rmi_smbus.c b/drivers/input/rmi4/rmi_smbus.c new file mode 100644 index 000000000000..76752555d809 --- /dev/null +++ b/drivers/input/rmi4/rmi_smbus.c @@ -0,0 +1,447 @@ +/* + * Copyright (c) 2015 - 2016 Red Hat, Inc + * Copyright (c) 2011, 2012 Synaptics Incorporated + * Copyright (c) 2011 Unixphere + * + * 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 "rmi_driver.h" + +#define SMB_PROTOCOL_VERSION_ADDRESS 0xfd +#define SMB_MAX_COUNT 32 +#define RMI_SMB2_MAP_SIZE 8 /* 8 entry of 4 bytes each */ +#define RMI_SMB2_MAP_FLAGS_WE 0x01 + +struct mapping_table_entry { + __le16 rmiaddr; + u8 readcount; + u8 flags; +}; + +struct rmi_smb_xport { + struct rmi_transport_dev xport; + struct i2c_client *client; + + struct mutex page_mutex; + int page; + u8 table_index; + struct mutex mappingtable_mutex; + struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE]; +}; + +static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb) +{ + struct i2c_client *client = rmi_smb->client; + int retval; + + /* Check if for SMBus new version device by reading version byte. */ + retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS); + if (retval < 0) { + dev_err(&client->dev, "failed to get SMBus version number!\n"); + return retval; + } + return retval + 1; +} + +/* SMB block write - wrapper over ic2_smb_write_block */ +static int smb_block_write(struct rmi_transport_dev *xport, + u8 commandcode, const void *buf, size_t len) +{ + struct rmi_smb_xport *rmi_smb = + container_of(xport, struct rmi_smb_xport, xport); + struct i2c_client *client = rmi_smb->client; + int retval; + + retval = i2c_smbus_write_block_data(client, commandcode, len, buf); + + rmi_dbg(RMI_DEBUG_XPORT, &client->dev, + "wrote %zd bytes at %#04x: %d (%*ph)\n", + len, commandcode, retval, (int)len, buf); + + return retval; +} + +/* + * The function to get command code for smbus operations and keeps + * records to the driver mapping table + */ +static int rmi_smb_get_command_code(struct rmi_transport_dev *xport, + u16 rmiaddr, int bytecount, bool isread, u8 *commandcode) +{ + struct rmi_smb_xport *rmi_smb = + container_of(xport, struct rmi_smb_xport, xport); + int i; + int retval; + struct mapping_table_entry mapping_data[1]; + + mutex_lock(&rmi_smb->mappingtable_mutex); + for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) { + if (rmi_smb->mapping_table[i].rmiaddr == rmiaddr) { + if (isread) { + if (rmi_smb->mapping_table[i].readcount + == bytecount) { + *commandcode = i; + retval = 0; + goto exit; + } + } else { + if (rmi_smb->mapping_table[i].flags & + RMI_SMB2_MAP_FLAGS_WE) { + *commandcode = i; + retval = 0; + goto exit; + } + } + } + } + i = rmi_smb->table_index; + rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE; + + /* constructs mapping table data entry. 4 bytes each entry */ + memset(mapping_data, 0, sizeof(mapping_data)); + + mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr); + mapping_data[0].readcount = bytecount; + mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; + + retval = smb_block_write(xport, i + 0x80, mapping_data, + sizeof(mapping_data)); + + if (retval < 0) { + /* + * if not written to device mapping table + * clear the driver mapping table records + */ + rmi_smb->mapping_table[i].rmiaddr = 0x0000; + rmi_smb->mapping_table[i].readcount = 0; + rmi_smb->mapping_table[i].flags = 0; + goto exit; + } + /* save to the driver level mapping table */ + rmi_smb->mapping_table[i].rmiaddr = rmiaddr; + rmi_smb->mapping_table[i].readcount = bytecount; + rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0; + *commandcode = i; + +exit: + mutex_unlock(&rmi_smb->mappingtable_mutex); + + return retval; +} + +static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr, + const void *databuff, size_t len) +{ + int retval = 0; + u8 commandcode; + struct rmi_smb_xport *rmi_smb = + container_of(xport, struct rmi_smb_xport, xport); + int cur_len = (int)len; + + mutex_lock(&rmi_smb->page_mutex); + + while (cur_len > 0) { + /* + * break into 32 bytes chunks to write get command code + */ + int block_len = min_t(int, len, SMB_MAX_COUNT); + + retval = rmi_smb_get_command_code(xport, rmiaddr, block_len, + false, &commandcode); + if (retval < 0) + goto exit; + + retval = smb_block_write(xport, commandcode, + databuff, block_len); + if (retval < 0) + goto exit; + + /* prepare to write next block of bytes */ + cur_len -= SMB_MAX_COUNT; + databuff += SMB_MAX_COUNT; + rmiaddr += SMB_MAX_COUNT; + } +exit: + mutex_unlock(&rmi_smb->page_mutex); + return retval; +} + +/* SMB block read - wrapper over ic2_smb_read_block */ +static int smb_block_read(struct rmi_transport_dev *xport, + u8 commandcode, void *buf, size_t len) +{ + struct rmi_smb_xport *rmi_smb = + container_of(xport, struct rmi_smb_xport, xport); + struct i2c_client *client = rmi_smb->client; + int retval; + + retval = i2c_smbus_read_block_data(client, commandcode, buf); + if (retval < 0) + return retval; + + return retval; +} + +static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr, + void *databuff, size_t len) +{ + struct rmi_smb_xport *rmi_smb = + container_of(xport, struct rmi_smb_xport, xport); + int retval; + u8 commandcode; + int cur_len = (int)len; + + mutex_lock(&rmi_smb->page_mutex); + memset(databuff, 0, len); + + while (cur_len > 0) { + /* break into 32 bytes chunks to write get command code */ + int block_len = min_t(int, cur_len, SMB_MAX_COUNT); + + retval = rmi_smb_get_command_code(xport, rmiaddr, block_len, + true, &commandcode); + if (retval < 0) + goto exit; + + retval = smb_block_read(xport, commandcode, + databuff, block_len); + if (retval < 0) + goto exit; + + /* prepare to read next block of bytes */ + cur_len -= SMB_MAX_COUNT; + databuff += SMB_MAX_COUNT; + rmiaddr += SMB_MAX_COUNT; + } + + retval = 0; + +exit: + mutex_unlock(&rmi_smb->page_mutex); + return retval; +} + +static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb) +{ + /* the mapping table has been flushed, discard the current one */ + mutex_lock(&rmi_smb->mappingtable_mutex); + memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table)); + mutex_unlock(&rmi_smb->mappingtable_mutex); +} + +static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb) +{ + int retval; + + /* we need to get the smbus version to activate the touchpad */ + retval = rmi_smb_get_version(rmi_smb); + if (retval < 0) + return retval; + + return 0; +} + +static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr) +{ + struct rmi_smb_xport *rmi_smb = + container_of(xport, struct rmi_smb_xport, xport); + + rmi_smb_clear_state(rmi_smb); + + /* + * we do not call the actual reset command, it has to be handled in + * PS/2 or there will be races between PS/2 and SMBus. + * PS/2 should ensure that a psmouse_reset is called before + * intializing the device and after it has been removed to be in a known + * state. + */ + return rmi_smb_enable_smbus_mode(rmi_smb); +} + +static const struct rmi_transport_ops rmi_smb_ops = { + .write_block = rmi_smb_write_block, + .read_block = rmi_smb_read_block, + .reset = rmi_smb_reset, +}; + +static int rmi_smb_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev); + struct rmi_smb_xport *rmi_smb; + int retval; + int smbus_version; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BLOCK_DATA | + I2C_FUNC_SMBUS_HOST_NOTIFY)) { + dev_err(&client->dev, + "adapter does not support required functionality.\n"); + return -ENODEV; + } + + if (client->irq <= 0) { + dev_err(&client->dev, "no IRQ provided, giving up.\n"); + return client->irq ? client->irq : -ENODEV; + } + + rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport), + GFP_KERNEL); + if (!rmi_smb) + return -ENOMEM; + + if (!pdata) { + dev_err(&client->dev, "no platform data, aborting\n"); + return -ENOMEM; + } + + rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n", + dev_name(&client->dev)); + + rmi_smb->client = client; + mutex_init(&rmi_smb->page_mutex); + mutex_init(&rmi_smb->mappingtable_mutex); + + rmi_smb->xport.dev = &client->dev; + rmi_smb->xport.pdata = *pdata; + rmi_smb->xport.pdata.irq = client->irq; + rmi_smb->xport.proto_name = "smb2"; + rmi_smb->xport.ops = &rmi_smb_ops; + + retval = rmi_smb_get_version(rmi_smb); + if (retval < 0) + return retval; + + smbus_version = retval; + rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d", + smbus_version); + + if (smbus_version != 2) { + dev_err(&client->dev, "Unrecognized SMB version %d.\n", + smbus_version); + return -ENODEV; + } + + i2c_set_clientdata(client, rmi_smb); + + retval = rmi_register_transport_device(&rmi_smb->xport); + if (retval) { + dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n", + client->addr); + i2c_set_clientdata(client, NULL); + return retval; + } + + dev_info(&client->dev, "registered rmi smb driver at %#04x.\n", + client->addr); + return 0; + +} + +static int rmi_smb_remove(struct i2c_client *client) +{ + struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client); + + rmi_unregister_transport_device(&rmi_smb->xport); + + return 0; +} + +static int __maybe_unused rmi_smb_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client); + int ret; + + ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true); + if (ret) + dev_warn(dev, "Failed to suspend device: %d\n", ret); + + return ret; +} + +static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client); + int ret; + + ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false); + if (ret) + dev_warn(dev, "Failed to suspend device: %d\n", ret); + + return ret; +} + +static int __maybe_unused rmi_smb_resume(struct device *dev) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client); + struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev; + int ret; + + rmi_smb_reset(&rmi_smb->xport, 0); + + rmi_reset(rmi_dev); + + ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true); + if (ret) + dev_warn(dev, "Failed to resume device: %d\n", ret); + + return 0; +} + +static int __maybe_unused rmi_smb_runtime_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client); + int ret; + + ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false); + if (ret) + dev_warn(dev, "Failed to resume device: %d\n", ret); + + return 0; +} + +static const struct dev_pm_ops rmi_smb_pm = { + SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume) + SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume, + NULL) +}; + +static const struct i2c_device_id rmi_id[] = { + { "rmi4_smbus", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rmi_id); + +static struct i2c_driver rmi_smb_driver = { + .driver = { + .name = "rmi4_smbus", + .pm = &rmi_smb_pm, + }, + .id_table = rmi_id, + .probe = rmi_smb_probe, + .remove = rmi_smb_remove, +}; + +module_i2c_driver(rmi_smb_driver); + +MODULE_AUTHOR("Andrew Duggan "); +MODULE_AUTHOR("Benjamin Tissoires "); +MODULE_DESCRIPTION("RMI4 SMBus driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 58f0d1d536bc71718286073aceb819eb0064e4ce Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 17 Oct 2016 12:49:20 +0100 Subject: iommu/mediatek: Convert M4Uv2 to iommu_fwspec Our per-device data consists of the M4U instance and firmware-provided list of LARB IDs, which is a perfect fit for the generic iommu_fwspec machinery. Use that directly as a simpler alternative to the custom archdata code. CC: Yong Wu Signed-off-by: Robin Murphy Tested-by: Yong Wu Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 75 ++++++++++++----------------------------------- 1 file changed, 18 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index b12c12d74c33..13bb57995cd3 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -195,14 +195,14 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id) static void mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev, bool enable) { - struct mtk_iommu_client_priv *head, *cur, *next; struct mtk_smi_larb_iommu *larb_mmu; unsigned int larbid, portid; + struct iommu_fwspec *fwspec = dev->iommu_fwspec; + int i; - head = dev->archdata.iommu; - list_for_each_entry_safe(cur, next, &head->client, client) { - larbid = MTK_M4U_TO_LARB(cur->mtk_m4u_id); - portid = MTK_M4U_TO_PORT(cur->mtk_m4u_id); + for (i = 0; i < fwspec->num_ids; ++i) { + larbid = MTK_M4U_TO_LARB(fwspec->ids[i]); + portid = MTK_M4U_TO_PORT(fwspec->ids[i]); larb_mmu = &data->smi_imu.larb_imu[larbid]; dev_dbg(dev, "%s iommu port: %d\n", @@ -282,14 +282,12 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); - struct mtk_iommu_client_priv *priv = dev->archdata.iommu; - struct mtk_iommu_data *data; + struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; int ret; - if (!priv) + if (!data) return -ENODEV; - data = dev_get_drvdata(priv->m4udev); if (!data->m4u_dom) { data->m4u_dom = dom; ret = mtk_iommu_domain_finalise(data); @@ -310,13 +308,11 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, static void mtk_iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - struct mtk_iommu_client_priv *priv = dev->archdata.iommu; - struct mtk_iommu_data *data; + struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; - if (!priv) + if (!data) return; - data = dev_get_drvdata(priv->m4udev); mtk_iommu_config(data, dev, false); } @@ -366,8 +362,8 @@ static int mtk_iommu_add_device(struct device *dev) { struct iommu_group *group; - if (!dev->archdata.iommu) /* Not a iommu client device */ - return -ENODEV; + if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) + return -ENODEV; /* Not a iommu client device */ group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) @@ -379,33 +375,21 @@ static int mtk_iommu_add_device(struct device *dev) static void mtk_iommu_remove_device(struct device *dev) { - struct mtk_iommu_client_priv *head, *cur, *next; - - head = dev->archdata.iommu; - if (!head) + if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) return; - list_for_each_entry_safe(cur, next, &head->client, client) { - list_del(&cur->client); - kfree(cur); - } - kfree(head); - dev->archdata.iommu = NULL; - iommu_group_remove_device(dev); + iommu_fwspec_free(dev); } static struct iommu_group *mtk_iommu_device_group(struct device *dev) { - struct mtk_iommu_data *data; - struct mtk_iommu_client_priv *priv; + struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; - priv = dev->archdata.iommu; - if (!priv) + if (!data) return ERR_PTR(-ENODEV); /* All the client devices are in the same m4u iommu-group */ - data = dev_get_drvdata(priv->m4udev); if (!data->m4u_group) { data->m4u_group = iommu_group_alloc(); if (IS_ERR(data->m4u_group)) @@ -416,7 +400,6 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev) static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) { - struct mtk_iommu_client_priv *head, *priv, *next; struct platform_device *m4updev; if (args->args_count != 1) { @@ -425,38 +408,16 @@ static int mtk_iommu_of_xlate(struct device *dev, struct of_phandle_args *args) return -EINVAL; } - if (!dev->archdata.iommu) { + if (!dev->iommu_fwspec->iommu_priv) { /* Get the m4u device */ m4updev = of_find_device_by_node(args->np); if (WARN_ON(!m4updev)) return -EINVAL; - head = kzalloc(sizeof(*head), GFP_KERNEL); - if (!head) - return -ENOMEM; - - dev->archdata.iommu = head; - INIT_LIST_HEAD(&head->client); - head->m4udev = &m4updev->dev; - } else { - head = dev->archdata.iommu; + dev->iommu_fwspec->iommu_priv = platform_get_drvdata(m4updev); } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - goto err_free_mem; - - priv->mtk_m4u_id = args->args[0]; - list_add_tail(&priv->client, &head->client); - - return 0; - -err_free_mem: - list_for_each_entry_safe(priv, next, &head->client, client) - kfree(priv); - kfree(head); - dev->archdata.iommu = NULL; - return -ENOMEM; + return iommu_fwspec_add_ids(dev, args->args, 1); } static struct iommu_ops mtk_iommu_ops = { -- cgit v1.2.3 From 84672f192671e64e473eb535259c910860cab7a9 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 17 Oct 2016 12:49:21 +0100 Subject: iommu/mediatek: Convert M4Uv1 to iommu_fwspec Our per-device data consists of the M4U instance and firmware-provided list of LARB IDs, which is a perfect fit for the generic iommu_fwspec machinery. Use that directly instead of the custom archdata code - while we can't rely on the of_xlate() mechanism to initialise things until the 32-bit ARM DMA code learns about groups and default domains, it still results in a reasonable simplification overall. CC: Honghui Zhang Signed-off-by: Robin Murphy Tested-by: Honghui Zhang Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.h | 6 --- drivers/iommu/mtk_iommu_v1.c | 95 +++++++++++++++++--------------------------- 2 files changed, 36 insertions(+), 65 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h index 3dab13b4a211..f59609f20270 100644 --- a/drivers/iommu/mtk_iommu.h +++ b/drivers/iommu/mtk_iommu.h @@ -34,12 +34,6 @@ struct mtk_iommu_suspend_reg { u32 int_main_control; }; -struct mtk_iommu_client_priv { - struct list_head client; - unsigned int mtk_m4u_id; - struct device *m4udev; -}; - struct mtk_iommu_domain; struct mtk_iommu_data { diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index b8aeb0768483..884c80cb795e 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -204,14 +204,14 @@ static irqreturn_t mtk_iommu_isr(int irq, void *dev_id) static void mtk_iommu_config(struct mtk_iommu_data *data, struct device *dev, bool enable) { - struct mtk_iommu_client_priv *head, *cur, *next; struct mtk_smi_larb_iommu *larb_mmu; unsigned int larbid, portid; + struct iommu_fwspec *fwspec = dev->iommu_fwspec; + int i; - head = dev->archdata.iommu; - list_for_each_entry_safe(cur, next, &head->client, client) { - larbid = mt2701_m4u_to_larb(cur->mtk_m4u_id); - portid = mt2701_m4u_to_port(cur->mtk_m4u_id); + for (i = 0; i < fwspec->num_ids; ++i) { + larbid = mt2701_m4u_to_larb(fwspec->ids[i]); + portid = mt2701_m4u_to_port(fwspec->ids[i]); larb_mmu = &data->smi_imu.larb_imu[larbid]; dev_dbg(dev, "%s iommu port: %d\n", @@ -271,14 +271,12 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, struct device *dev) { struct mtk_iommu_domain *dom = to_mtk_domain(domain); - struct mtk_iommu_client_priv *priv = dev->archdata.iommu; - struct mtk_iommu_data *data; + struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; int ret; - if (!priv) + if (!data) return -ENODEV; - data = dev_get_drvdata(priv->m4udev); if (!data->m4u_dom) { data->m4u_dom = dom; ret = mtk_iommu_domain_finalise(data); @@ -295,13 +293,11 @@ static int mtk_iommu_attach_device(struct iommu_domain *domain, static void mtk_iommu_detach_device(struct iommu_domain *domain, struct device *dev) { - struct mtk_iommu_client_priv *priv = dev->archdata.iommu; - struct mtk_iommu_data *data; + struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; - if (!priv) + if (!data) return; - data = dev_get_drvdata(priv->m4udev); mtk_iommu_config(data, dev, false); } @@ -366,6 +362,8 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, return pa; } +static struct iommu_ops mtk_iommu_ops; + /* * MTK generation one iommu HW only support one iommu domain, and all the client * sharing the same iova address space. @@ -373,7 +371,7 @@ static phys_addr_t mtk_iommu_iova_to_phys(struct iommu_domain *domain, static int mtk_iommu_create_mapping(struct device *dev, struct of_phandle_args *args) { - struct mtk_iommu_client_priv *head, *priv, *next; + struct mtk_iommu_data *data; struct platform_device *m4updev; struct dma_iommu_mapping *mtk_mapping; struct device *m4udev; @@ -385,41 +383,37 @@ static int mtk_iommu_create_mapping(struct device *dev, return -EINVAL; } - if (!dev->archdata.iommu) { + if (!dev->iommu_fwspec) { + ret = iommu_fwspec_init(dev, &args->np->fwnode, &mtk_iommu_ops); + if (ret) + return ret; + } else if (dev->iommu_fwspec->ops != &mtk_iommu_ops) { + return -EINVAL; + } + + if (!dev->iommu_fwspec->iommu_priv) { /* Get the m4u device */ m4updev = of_find_device_by_node(args->np); if (WARN_ON(!m4updev)) return -EINVAL; - head = kzalloc(sizeof(*head), GFP_KERNEL); - if (!head) - return -ENOMEM; - - dev->archdata.iommu = head; - INIT_LIST_HEAD(&head->client); - head->m4udev = &m4updev->dev; - } else { - head = dev->archdata.iommu; + dev->iommu_fwspec->iommu_priv = platform_get_drvdata(m4updev); } - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - ret = -ENOMEM; - goto err_free_mem; - } - priv->mtk_m4u_id = args->args[0]; - list_add_tail(&priv->client, &head->client); + ret = iommu_fwspec_add_ids(dev, args->args, 1); + if (ret) + return ret; - m4udev = head->m4udev; + data = dev->iommu_fwspec->iommu_priv; + m4udev = data->dev; mtk_mapping = m4udev->archdata.iommu; if (!mtk_mapping) { /* MTK iommu support 4GB iova address space. */ mtk_mapping = arm_iommu_create_mapping(&platform_bus_type, 0, 1ULL << 32); - if (IS_ERR(mtk_mapping)) { - ret = PTR_ERR(mtk_mapping); - goto err_free_mem; - } + if (IS_ERR(mtk_mapping)) + return PTR_ERR(mtk_mapping); + m4udev->archdata.iommu = mtk_mapping; } @@ -432,11 +426,6 @@ static int mtk_iommu_create_mapping(struct device *dev, err_release_mapping: arm_iommu_release_mapping(mtk_mapping); m4udev->archdata.iommu = NULL; -err_free_mem: - list_for_each_entry_safe(priv, next, &head->client, client) - kfree(priv); - kfree(head); - dev->archdata.iommu = NULL; return ret; } @@ -458,8 +447,8 @@ static int mtk_iommu_add_device(struct device *dev) of_node_put(iommu_spec.np); } - if (!dev->archdata.iommu) /* Not a iommu client device */ - return -ENODEV; + if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) + return -ENODEV; /* Not a iommu client device */ group = iommu_group_get_for_dev(dev); if (IS_ERR(group)) @@ -471,33 +460,21 @@ static int mtk_iommu_add_device(struct device *dev) static void mtk_iommu_remove_device(struct device *dev) { - struct mtk_iommu_client_priv *head, *cur, *next; - - head = dev->archdata.iommu; - if (!head) + if (!dev->iommu_fwspec || dev->iommu_fwspec->ops != &mtk_iommu_ops) return; - list_for_each_entry_safe(cur, next, &head->client, client) { - list_del(&cur->client); - kfree(cur); - } - kfree(head); - dev->archdata.iommu = NULL; - iommu_group_remove_device(dev); + iommu_fwspec_free(dev); } static struct iommu_group *mtk_iommu_device_group(struct device *dev) { - struct mtk_iommu_data *data; - struct mtk_iommu_client_priv *priv; + struct mtk_iommu_data *data = dev->iommu_fwspec->iommu_priv; - priv = dev->archdata.iommu; - if (!priv) + if (!data) return ERR_PTR(-ENODEV); /* All the client devices are in the same m4u iommu-group */ - data = dev_get_drvdata(priv->m4udev); if (!data->m4u_group) { data->m4u_group = iommu_group_alloc(); if (IS_ERR(data->m4u_group)) -- cgit v1.2.3 From 00c7c81f7b49d9b739690c45d9986474d52c6240 Mon Sep 17 00:00:00 2001 From: Russell King Date: Wed, 19 Oct 2016 11:30:34 +0100 Subject: iommu/mediatek: Convert DT component matching to component_match_add_release() Convert DT component matching to use component_match_add_release(). Signed-off-by: Russell King Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 8 +++++--- drivers/iommu/mtk_iommu.h | 5 +++++ drivers/iommu/mtk_iommu_v1.c | 8 +++++--- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 13bb57995cd3..55b29620fd4f 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -544,17 +544,19 @@ static int mtk_iommu_probe(struct platform_device *pdev) continue; plarbdev = of_find_device_by_node(larbnode); - of_node_put(larbnode); if (!plarbdev) { plarbdev = of_platform_device_create( larbnode, NULL, platform_bus_type.dev_root); - if (!plarbdev) + if (!plarbdev) { + of_node_put(larbnode); return -EPROBE_DEFER; + } } data->smi_imu.larb_imu[i].dev = &plarbdev->dev; - component_match_add(dev, &match, compare_of, larbnode); + component_match_add_release(dev, &match, release_of, + compare_of, larbnode); } platform_set_drvdata(pdev, data); diff --git a/drivers/iommu/mtk_iommu.h b/drivers/iommu/mtk_iommu.h index f59609f20270..50177f738e4e 100644 --- a/drivers/iommu/mtk_iommu.h +++ b/drivers/iommu/mtk_iommu.h @@ -54,6 +54,11 @@ static inline int compare_of(struct device *dev, void *data) return dev->of_node == data; } +static inline void release_of(struct device *dev, void *data) +{ + of_node_put(data); +} + static inline int mtk_iommu_bind(struct device *dev) { struct mtk_iommu_data *data = dev_get_drvdata(dev); diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index 884c80cb795e..af70040038e9 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -601,17 +601,19 @@ static int mtk_iommu_probe(struct platform_device *pdev) continue; plarbdev = of_find_device_by_node(larb_spec.np); - of_node_put(larb_spec.np); if (!plarbdev) { plarbdev = of_platform_device_create( larb_spec.np, NULL, platform_bus_type.dev_root); - if (!plarbdev) + if (!plarbdev) { + of_node_put(larb_spec.np); return -EPROBE_DEFER; + } } data->smi_imu.larb_imu[larb_nr].dev = &plarbdev->dev; - component_match_add(dev, &match, compare_of, larb_spec.np); + component_match_add_release(dev, &match, release_of, + compare_of, larb_spec.np); larb_nr++; } -- cgit v1.2.3 From ebcfa284395474187cca3d26d2a995b1d0fcce21 Mon Sep 17 00:00:00 2001 From: Lucas Stach Date: Wed, 26 Oct 2016 13:09:53 +0200 Subject: iommu/amd: Tell kmemleak about the irq_remap_table This will get rid of a lot false positives caused by kmemleak being unaware of the irq_remap_table. Based on a suggestion from Catalin Marinas. Signed-off-by: Lucas Stach Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_init.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 157e93421fb8..971154cbbb03 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -2090,6 +2091,7 @@ static struct syscore_ops amd_iommu_syscore_ops = { static void __init free_on_init_error(void) { + kmemleak_free(irq_lookup_table); free_pages((unsigned long)irq_lookup_table, get_order(rlookup_table_size)); @@ -2321,6 +2323,8 @@ static int __init early_amd_iommu_init(void) irq_lookup_table = (void *)__get_free_pages( GFP_KERNEL | __GFP_ZERO, get_order(rlookup_table_size)); + kmemleak_alloc(irq_lookup_table, rlookup_table_size, + 1, GFP_KERNEL); if (!irq_lookup_table) goto out; } -- cgit v1.2.3 From 79d12b7a7f227ed51dd86b16a7536b391e46f7b0 Mon Sep 17 00:00:00 2001 From: Heiko Stuebner Date: Fri, 16 Sep 2016 00:14:38 +0200 Subject: soc: rockchip: power-domain: use pm_genpd_remove in error cleanup The newly introduced pm_genpd_remove reverts the initialization done by pm_genpd_init and is necessary in the error path of the rockchip power-domain driver. Without it the driver will in the error case cleanup the devm-allocated structures including the elements referenced in the gpd_list thus making deactivation of unused domains (and probably later genpd accesses as well) fail by accessing invalid pointers. Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index 988bfd708706..d36a7351af9d 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -479,7 +479,16 @@ err_out: static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd) { - int i; + int i, ret; + + /* + * We're in the error cleanup already, so we only complain, + * but won't emit another error on top of the original one. + */ + ret = pm_genpd_remove(&pd->genpd); + if (ret < 0) + dev_err(pd->pmu->dev, "failed to remove domain '%s' : %d - state may be inconsistent\n", + pd->genpd.name, ret); for (i = 0; i < pd->num_clks; i++) { clk_unprepare(pd->clks[i]); -- cgit v1.2.3 From dabc0259db63338f0e64107cc92b2241f98a3284 Mon Sep 17 00:00:00 2001 From: Tomeu Vizoso Date: Fri, 16 Sep 2016 00:14:39 +0200 Subject: soc: rockchip: power-domain: Handle errors from of_genpd_add_provider_onecell It was a bit surprising that the device was reported to have probed just fine, but the provider hadn't been registered. So handle any errors when registering the provider and fail the probe accordingly. Signed-off-by: Tomeu Vizoso Cc: Caesar Wang Signed-off-by: Heiko Stuebner --- drivers/soc/rockchip/pm_domains.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/rockchip/pm_domains.c b/drivers/soc/rockchip/pm_domains.c index d36a7351af9d..1c78c42416c6 100644 --- a/drivers/soc/rockchip/pm_domains.c +++ b/drivers/soc/rockchip/pm_domains.c @@ -672,7 +672,11 @@ static int rockchip_pm_domain_probe(struct platform_device *pdev) goto err_out; } - of_genpd_add_provider_onecell(np, &pmu->genpd_data); + error = of_genpd_add_provider_onecell(np, &pmu->genpd_data); + if (error) { + dev_err(dev, "failed to add provider: %d\n", error); + goto err_out; + } return 0; -- cgit v1.2.3 From c5d933b1229c6bb79de3a144d2b33e756f4afd6d Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 10 Sep 2016 12:31:01 +0000 Subject: PCI: altera: Use builtin_platform_driver() to simplify the code Use the builtin_platform_driver() macro to make the code simpler. Signed-off-by: Wei Yongjun Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-altera.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index b0ac4dfafa0b..eefcb38004fe 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -641,8 +641,4 @@ static struct platform_driver altera_pcie_driver = { }, }; -static int altera_pcie_init(void) -{ - return platform_driver_register(&altera_pcie_driver); -} -device_initcall(altera_pcie_init); +builtin_platform_driver(altera_pcie_driver); -- cgit v1.2.3 From c19699a8c6574efe2fb7949ee5b467612193e2fc Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 14:56:13 +0000 Subject: PCI: altera: Remove redundant error message in altera_pcie_parse_dt() There is an error message from devm_ioremap_resource() already, so remove the dev_err() call to avoid redundant error messages. Signed-off-by: Wei Yongjun Signed-off-by: Bjorn Helgaas Acked-by: Ley Foon Tan --- drivers/pci/host/pcie-altera.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-altera.c b/drivers/pci/host/pcie-altera.c index eefcb38004fe..0c1540225ca3 100644 --- a/drivers/pci/host/pcie-altera.c +++ b/drivers/pci/host/pcie-altera.c @@ -550,10 +550,8 @@ static int altera_pcie_parse_dt(struct altera_pcie *pcie) cra = platform_get_resource_byname(pdev, IORESOURCE_MEM, "Cra"); pcie->cra_base = devm_ioremap_resource(dev, cra); - if (IS_ERR(pcie->cra_base)) { - dev_err(dev, "failed to map cra memory\n"); + if (IS_ERR(pcie->cra_base)) return PTR_ERR(pcie->cra_base); - } /* setup IRQ */ pcie->irq = platform_get_irq(pdev, 0); -- cgit v1.2.3 From e594233803aa9bff9ee6912b7b07db2c7898a06c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 14:55:40 +0000 Subject: PCI: layerscape: Remove redundant error message from ls_pcie_probe() There is an error message from devm_ioremap_resource() already, so remove the dev_err() call to avoid redundant error messages. Signed-off-by: Wei Yongjun Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-layerscape.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c index 2cb7315e26d0..bbd3d232b934 100644 --- a/drivers/pci/host/pci-layerscape.c +++ b/drivers/pci/host/pci-layerscape.c @@ -251,10 +251,8 @@ static int __init ls_pcie_probe(struct platform_device *pdev) dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs"); pcie->pp.dbi_base = devm_ioremap_resource(dev, dbi_base); - if (IS_ERR(pcie->pp.dbi_base)) { - dev_err(dev, "missing *regs* space\n"); + if (IS_ERR(pcie->pp.dbi_base)) return PTR_ERR(pcie->pp.dbi_base); - } pcie->drvdata = match->data; pcie->lut = pcie->pp.dbi_base + pcie->drvdata->lut_offset; -- cgit v1.2.3 From ad719956a8487753e6514d7be3b4a6edc99e35bd Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 14:56:50 +0000 Subject: PCI: hisi: Remove redundant error message from hisi_pcie_probe() There is an error message from devm_ioremap_resource() already, so remove the dev_err() call to avoid redundant error messages. Signed-off-by: Wei Yongjun Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-hisi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c index 56154c25980c..a77b9bda1974 100644 --- a/drivers/pci/host/pcie-hisi.c +++ b/drivers/pci/host/pcie-hisi.c @@ -185,10 +185,8 @@ static int hisi_pcie_probe(struct platform_device *pdev) reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rc_dbi"); pp->dbi_base = devm_ioremap_resource(dev, reg); - if (IS_ERR(pp->dbi_base)) { - dev_err(dev, "cannot get rc_dbi base\n"); + if (IS_ERR(pp->dbi_base)) return PTR_ERR(pp->dbi_base); - } ret = hisi_add_pcie_port(hisi_pcie, pdev); if (ret) -- cgit v1.2.3 From 5b23e8fa46ca037e0f61df919e8a08659c0e7640 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:04:44 +0000 Subject: PCI: vmd: Remove unnecessary pci_set_drvdata() The driver core clears the driver data to NULL after device_release or on probe failure. Thus, it is not needed to manually clear the device driver data to NULL. Signed-off-by: Wei Yongjun Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/host/vmd.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c index 37e29b580be3..6614b3552b9c 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/host/vmd.c @@ -719,7 +719,6 @@ static void vmd_remove(struct pci_dev *dev) struct vmd_dev *vmd = pci_get_drvdata(dev); vmd_detach_resources(vmd); - pci_set_drvdata(dev, NULL); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_stop_root_bus(vmd->bus); pci_remove_root_bus(vmd->bus); -- cgit v1.2.3 From 6496ebd7edf446fccf8266a1a70ffcb64252593e Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Oct 2016 16:45:38 -0400 Subject: PCI: Check for PME in targeted sleep state One some systems, the firmware does not allow certain PCI devices to be put in deep D-states. This can cause problems for wakeup signalling, if the device does not support PME# in the deepest allowed suspend state. For example, Pierre reports that on his system, ACPI does not permit his xHCI host controller to go into D3 during runtime suspend -- but D3 is the only state in which the controller can generate PME# signals. As a result, the controller goes into runtime suspend but never wakes up, so it doesn't work properly. USB devices plugged into the controller are never detected. If the device relies on PME# for wakeup signals but is not capable of generating PME# in the target state, the PCI core should accurately report that it cannot do wakeup from runtime suspend. This patch modifies the pci_dev_run_wake() routine to add this check. Reported-by: Pierre de Villemereuil Tested-by: Pierre de Villemereuil Signed-off-by: Alan Stern Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki CC: stable@vger.kernel.org CC: Lukas Wunner --- drivers/pci/pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ba34907538f6..eda6a7cf0e54 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2106,6 +2106,10 @@ bool pci_dev_run_wake(struct pci_dev *dev) if (!dev->pme_support) return false; + /* PME-capable in principle, but not from the intended sleep state */ + if (!pci_pme_capable(dev, pci_target_state(dev))) + return false; + while (bus->parent) { struct pci_dev *bridge = bus->self; -- cgit v1.2.3 From ccdb6be9ec6580ef69f68949ebe26e0fb58a6fb0 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Fri, 21 Oct 2016 16:49:07 -0400 Subject: USB: UHCI: report non-PME wakeup signalling for Intel hardware The UHCI controllers in Intel chipsets rely on a platform-specific non-PME mechanism for wakeup signalling. They can generate wakeup signals even though they don't support PME. We need to let the USB core know this so that it will enable runtime suspend for UHCI controllers. Signed-off-by: Alan Stern Signed-off-by: Bjorn Helgaas Acked-by: Greg Kroah-Hartman CC: stable@vger.kernel.org --- drivers/usb/host/uhci-pci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/usb/host/uhci-pci.c b/drivers/usb/host/uhci-pci.c index 940304c33224..02260cfdedb1 100644 --- a/drivers/usb/host/uhci-pci.c +++ b/drivers/usb/host/uhci-pci.c @@ -129,6 +129,10 @@ static int uhci_pci_init(struct usb_hcd *hcd) if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP) uhci->wait_for_hp = 1; + /* Intel controllers use non-PME wakeup signalling */ + if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_INTEL) + device_set_run_wake(uhci_dev(uhci), 1); + /* Set up pointers to PCI-specific functions */ uhci->reset_hc = uhci_pci_reset_hc; uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc; -- cgit v1.2.3 From 1d77040bde2d21dc7db575d4b43c1da24c94cca1 Mon Sep 17 00:00:00 2001 From: Mingkai Hu Date: Tue, 25 Oct 2016 20:36:56 +0800 Subject: PCI: layerscape: Add LS1046a support Add support for the LS1046a PCIe controller. This device has a different LUT_DBG offset, so add "lut_dbg" to ls_pcie_drvdata to describe this difference. [bhelgaas: changelog, remove now-unused PCIE_LUT_DBG] Signed-off-by: Mingkai Hu Signed-off-by: Minghuan Lian Signed-off-by: Bjorn Helgaas --- Documentation/devicetree/bindings/pci/layerscape-pci.txt | 1 + drivers/pci/host/pci-layerscape.c | 16 ++++++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt index 41e9f55a1467..ee1c72d5162e 100644 --- a/Documentation/devicetree/bindings/pci/layerscape-pci.txt +++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt @@ -15,6 +15,7 @@ Required properties: - compatible: should contain the platform identifier such as: "fsl,ls1021a-pcie", "snps,dw-pcie" "fsl,ls2080a-pcie", "fsl,ls2085a-pcie", "snps,dw-pcie" + "fsl,ls1046a-pcie" - reg: base addresses and lengths of the PCIe controller - interrupts: A list of interrupt outputs of the controller. Must contain an entry for each entry in the interrupt-names property. diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c index bbd3d232b934..ca48ceb6ebaf 100644 --- a/drivers/pci/host/pci-layerscape.c +++ b/drivers/pci/host/pci-layerscape.c @@ -35,12 +35,10 @@ #define PCIE_STRFMR1 0x71c /* Symbol Timer & Filter Mask Register1 */ #define PCIE_DBI_RO_WR_EN 0x8bc /* DBI Read-Only Write Enable Register */ -/* PEX LUT registers */ -#define PCIE_LUT_DBG 0x7FC /* PEX LUT Debug Register */ - struct ls_pcie_drvdata { u32 lut_offset; u32 ltssm_shift; + u32 lut_dbg; struct pcie_host_ops *ops; }; @@ -134,7 +132,7 @@ static int ls_pcie_link_up(struct pcie_port *pp) struct ls_pcie *pcie = to_ls_pcie(pp); u32 state; - state = (ioread32(pcie->lut + PCIE_LUT_DBG) >> + state = (ioread32(pcie->lut + pcie->drvdata->lut_dbg) >> pcie->drvdata->ltssm_shift) & LTSSM_STATE_MASK; @@ -196,18 +194,28 @@ static struct ls_pcie_drvdata ls1021_drvdata = { static struct ls_pcie_drvdata ls1043_drvdata = { .lut_offset = 0x10000, .ltssm_shift = 24, + .lut_dbg = 0x7fc, + .ops = &ls_pcie_host_ops, +}; + +static struct ls_pcie_drvdata ls1046_drvdata = { + .lut_offset = 0x80000, + .ltssm_shift = 24, + .lut_dbg = 0x407fc, .ops = &ls_pcie_host_ops, }; static struct ls_pcie_drvdata ls2080_drvdata = { .lut_offset = 0x80000, .ltssm_shift = 0, + .lut_dbg = 0x7fc, .ops = &ls_pcie_host_ops, }; static const struct of_device_id ls_pcie_of_match[] = { { .compatible = "fsl,ls1021a-pcie", .data = &ls1021_drvdata }, { .compatible = "fsl,ls1043a-pcie", .data = &ls1043_drvdata }, + { .compatible = "fsl,ls1046a-pcie", .data = &ls1046_drvdata }, { .compatible = "fsl,ls2080a-pcie", .data = &ls2080_drvdata }, { .compatible = "fsl,ls2085a-pcie", .data = &ls2080_drvdata }, { }, -- cgit v1.2.3 From 82bf1037f2cab2d6960a08ae08513f2c3c0b335a Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Fri, 11 Nov 2016 12:37:36 -0700 Subject: libnvdimm: check and clear poison before writing to pmem We need to clear any poison when we are writing to pmem. The granularity will be sector size. If it's less then we can't do anything about it barring corruption. Signed-off-by: Dave Jiang Reviewed-by: Vishal Verma [djbw: fixup 0-length write request to succeed] Signed-off-by: Dan Williams --- drivers/nvdimm/claim.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index d5dc80c48b4c..8d66fbb779ed 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -226,6 +226,12 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, resource_size_t offset, void *buf, size_t size, int rw) { struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev); + unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512); + sector_t sector = offset >> 9; + int rc = 0; + + if (unlikely(!size)) + return 0; if (unlikely(offset + size > nsio->size)) { dev_WARN_ONCE(&ndns->dev, 1, "request out of range\n"); @@ -233,17 +239,33 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, } if (rw == READ) { - unsigned int sz_align = ALIGN(size + (offset & (512 - 1)), 512); - - if (unlikely(is_bad_pmem(&nsio->bb, offset / 512, sz_align))) + if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) return -EIO; return memcpy_from_pmem(buf, nsio->addr + offset, size); } else { + + if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { + if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) { + long cleared; + + cleared = nvdimm_clear_poison(&ndns->dev, + offset, size); + if (cleared != size) { + size = cleared; + rc = -EIO; + } + + badblocks_clear(&nsio->bb, sector, + cleared >> 9); + } else + rc = -EIO; + } + memcpy_to_pmem(nsio->addr + offset, buf, size); nvdimm_flush(to_nd_region(ndns->dev.parent)); } - return 0; + return rc; } int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio) -- cgit v1.2.3 From 2d9a02744f5a2e8325fc0c3e5533593261cead0a Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sat, 29 Oct 2016 13:28:52 +0200 Subject: nvdimm: use the right length of "pmem" In order to test that the name of a resource begins with "pmem", call strncmp() with 4 as length instead of 3 to match the whole prefix. Signed-off-by: Nicolas Iooss Signed-off-by: Dan Williams --- drivers/nvdimm/label.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvdimm/label.c b/drivers/nvdimm/label.c index fac7cabe8f56..dd615345699f 100644 --- a/drivers/nvdimm/label.c +++ b/drivers/nvdimm/label.c @@ -938,7 +938,7 @@ int nd_pmem_namespace_label_update(struct nd_region *nd_region, } for_each_dpa_resource(ndd, res) - if (strncmp(res->name, "pmem", 3) == 0) + if (strncmp(res->name, "pmem", 4) == 0) count++; WARN_ON_ONCE(!count); -- cgit v1.2.3 From bd4760ca03156731674a570e44490986189d8228 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sun, 28 Aug 2016 16:29:10 +0000 Subject: firmware: qcom: scm: Use devm_reset_controller_register() Use devm_reset_controller_register() for the reset controller registration and fixes the memory leak when unload the module. Signed-off-by: Wei Yongjun Signed-off-by: Andy Gross --- drivers/firmware/qcom_scm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index d95c70227c05..9bf66aefdbd0 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -356,7 +356,9 @@ static int qcom_scm_probe(struct platform_device *pdev) scm->reset.ops = &qcom_scm_pas_reset_ops; scm->reset.nr_resets = 1; scm->reset.of_node = pdev->dev.of_node; - reset_controller_register(&scm->reset); + ret = devm_reset_controller_register(&pdev->dev, &scm->reset); + if (ret) + return ret; /* vote for max clk rate for highest performance */ ret = clk_set_rate(scm->core_clk, INT_MAX); -- cgit v1.2.3 From e6414b13ea39e3011901a84eb1bdefa65610b0f8 Mon Sep 17 00:00:00 2001 From: Gary R Hook Date: Tue, 1 Nov 2016 14:05:05 -0500 Subject: crypto: ccp - Fix handling of RSA exponent on a v5 device The exponent size in the ccp_op structure is in bits. A v5 CCP requires the exponent size to be in bytes, so convert the size from bits to bytes when populating the descriptor. The current code references the exponent in memory, but these fields have not been set since the exponent is actually store in the LSB. Populate the descriptor with the LSB location (address). Signed-off-by: Gary R Hook Signed-off-by: Herbert Xu --- drivers/crypto/ccp/ccp-dev-v5.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/ccp/ccp-dev-v5.c b/drivers/crypto/ccp/ccp-dev-v5.c index ff7816a2b8af..e2ce8190ecc9 100644 --- a/drivers/crypto/ccp/ccp-dev-v5.c +++ b/drivers/crypto/ccp/ccp-dev-v5.c @@ -403,7 +403,7 @@ static int ccp5_perform_rsa(struct ccp_op *op) CCP5_CMD_PROT(&desc) = 0; function.raw = 0; - CCP_RSA_SIZE(&function) = op->u.rsa.mod_size; + CCP_RSA_SIZE(&function) = op->u.rsa.mod_size >> 3; CCP5_CMD_FUNCTION(&desc) = function.raw; CCP5_CMD_LEN(&desc) = op->u.rsa.input_len; @@ -418,10 +418,10 @@ static int ccp5_perform_rsa(struct ccp_op *op) CCP5_CMD_DST_HI(&desc) = ccp_addr_hi(&op->dst.u.dma); CCP5_CMD_DST_MEM(&desc) = CCP_MEMTYPE_SYSTEM; - /* Key (Exponent) is in external memory */ - CCP5_CMD_KEY_LO(&desc) = ccp_addr_lo(&op->exp.u.dma); - CCP5_CMD_KEY_HI(&desc) = ccp_addr_hi(&op->exp.u.dma); - CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SYSTEM; + /* Exponent is in LSB memory */ + CCP5_CMD_KEY_LO(&desc) = op->sb_key * LSB_ITEM_SIZE; + CCP5_CMD_KEY_HI(&desc) = 0; + CCP5_CMD_KEY_MEM(&desc) = CCP_MEMTYPE_SB; return ccp5_do_cmd(&desc, op->cmd_q); } -- cgit v1.2.3 From 4d9b3a5b93800d5eb6939a7e363dc82d4439da0b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 1 Nov 2016 20:14:04 -0600 Subject: crypto: talitos - fix spelling mistake Trivial fix to spelling mistake "pointeur" to "pointer" in dev_err message Signed-off-by: Colin Ian King Signed-off-by: Herbert Xu --- drivers/crypto/talitos.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c index 0418a2f41dc0..0bba6a19d36a 100644 --- a/drivers/crypto/talitos.c +++ b/drivers/crypto/talitos.c @@ -590,7 +590,7 @@ static void talitos_error(struct device *dev, u32 isr, u32 isr_lo) if (v_lo & TALITOS_CCPSR_LO_MDTE) dev_err(dev, "master data transfer error\n"); if (v_lo & TALITOS_CCPSR_LO_SGDLZ) - dev_err(dev, is_sec1 ? "pointeur not complete error\n" + dev_err(dev, is_sec1 ? "pointer not complete error\n" : "s/g data length zero error\n"); if (v_lo & TALITOS_CCPSR_LO_FPZ) dev_err(dev, is_sec1 ? "parity error\n" -- cgit v1.2.3 From 650d4a978271850278466ba7222bcfc893ce9542 Mon Sep 17 00:00:00 2001 From: Nadim almas Date: Wed, 2 Nov 2016 17:28:45 +0530 Subject: Crypto: mv_cesa - Switch to using managed resources Switch to resource-managed function devm_kzalloc instead of kzalloc and remove unneeded kfree Also, remove kfree in probe function and remove function, mv_remove as it is now has nothing to do. The Coccinelle semantic patch used to make this change is as follows: // @platform@ identifier p, probefn, removefn; @@ struct platform_driver p = { .probe = probefn, .remove = removefn, }; @prb@ identifier platform.probefn, pdev; expression e, e1, e2; @@ probefn(struct platform_device *pdev, ...) { <+... - e = kzalloc(e1, e2) + e = devm_kzalloc(&pdev->dev, e1, e2) ... ?-kfree(e); ...+> } @rem depends on prb@ identifier platform.removefn; expression prb.e; @@ removefn(...) { <... - kfree(e); ...> } // Signed-off-by: Nadim Almas Signed-off-by: Herbert Xu --- drivers/crypto/mv_cesa.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/mv_cesa.c b/drivers/crypto/mv_cesa.c index 104e9ce9400a..451fa18c1c7b 100644 --- a/drivers/crypto/mv_cesa.c +++ b/drivers/crypto/mv_cesa.c @@ -1073,7 +1073,7 @@ static int mv_probe(struct platform_device *pdev) if (!res) return -ENXIO; - cp = kzalloc(sizeof(*cp), GFP_KERNEL); + cp = devm_kzalloc(&pdev->dev, sizeof(*cp), GFP_KERNEL); if (!cp) return -ENOMEM; @@ -1163,7 +1163,6 @@ err_irq: err_thread: kthread_stop(cp->queue_th); err: - kfree(cp); cpg = NULL; return ret; } @@ -1187,7 +1186,6 @@ static int mv_remove(struct platform_device *pdev) clk_put(cp->clk); } - kfree(cp); cpg = NULL; return 0; } -- cgit v1.2.3 From d128af17876d79b87edf048303f98b35f6a53dbc Mon Sep 17 00:00:00 2001 From: Alex Porosanu Date: Wed, 9 Nov 2016 10:46:11 +0200 Subject: crypto: caam - fix AEAD givenc descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AEAD givenc descriptor relies on moving the IV through the output FIFO and then back to the CTX2 for authentication. The SEQ FIFO STORE could be scheduled before the data can be read from OFIFO, especially since the SEQ FIFO LOAD needs to wait for the SEQ FIFO LOAD SKIP to finish first. The SKIP takes more time when the input is SG than when it's a contiguous buffer. If the SEQ FIFO LOAD is not scheduled before the STORE, the DECO will hang waiting for data to be available in the OFIFO so it can be transferred to C2. In order to overcome this, first force transfer of IV to C2 by starting the "cryptlen" transfer first and then starting to store data from OFIFO to the output buffer. Fixes: 1acebad3d8db8 ("crypto: caam - faster aead implementation") Cc: # 3.2+ Signed-off-by: Alex Porosanu Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 8de85dfb1b04..5317d8cad44d 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -736,7 +736,9 @@ copy_iv: /* Will read cryptlen */ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | + FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH); + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); /* Write ICV */ append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | -- cgit v1.2.3 From 39957c8eb362438e6de1decc13117a737c98c46c Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:12 +0200 Subject: crypto: caam - completely remove error propagation handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 4464a7d4f53d756101291da26563f37f7fce40f3 ("crypto: caam - remove error propagation handling") removed error propagation handling only from caamalg. Do this in all other places: caamhash, caamrng. Update descriptors' lengths appropriately. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 5 +---- drivers/crypto/caam/caamrng.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 660dc206969f..51990dd56024 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -72,7 +72,7 @@ #define CAAM_MAX_HASH_DIGEST_SIZE SHA512_DIGEST_SIZE /* length of descriptors text */ -#define DESC_AHASH_BASE (4 * CAAM_CMD_SZ) +#define DESC_AHASH_BASE (3 * CAAM_CMD_SZ) #define DESC_AHASH_UPDATE_LEN (6 * CAAM_CMD_SZ) #define DESC_AHASH_UPDATE_FIRST_LEN (DESC_AHASH_BASE + 4 * CAAM_CMD_SZ) #define DESC_AHASH_FINAL_LEN (DESC_AHASH_BASE + 5 * CAAM_CMD_SZ) @@ -246,9 +246,6 @@ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) set_jump_tgt_here(desc, key_jump_cmd); } - - /* Propagate errors from shared to job descriptor */ - append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); } /* diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 9b92af2c7241..bb1c118b2d1b 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -52,7 +52,7 @@ /* length of descriptors */ #define DESC_JOB_O_LEN (CAAM_CMD_SZ * 2 + CAAM_PTR_SZ * 2) -#define DESC_RNG_LEN (4 * CAAM_CMD_SZ) +#define DESC_RNG_LEN (3 * CAAM_CMD_SZ) /* Buffer, its dma address and lock */ struct buf_data { @@ -196,9 +196,6 @@ static inline int rng_create_sh_desc(struct caam_rng_ctx *ctx) init_sh_desc(desc, HDR_SHARE_SERIAL); - /* Propagate errors from shared to job descriptor */ - append_cmd(desc, SET_OK_NO_PROP_ERRORS | CMD_LOAD); - /* Generate random bytes */ append_operation(desc, OP_ALG_ALGSEL_RNG | OP_TYPE_CLASS1_ALG); -- cgit v1.2.3 From 2090456a01289e0c91685c649645614953026b15 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:13 +0200 Subject: crypto: caam - desc.h fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. fix HDR_START_IDX_MASK, HDR_SD_SHARE_MASK, HDR_JD_SHARE_MASK Define HDR_START_IDX_MASK consistently with the other masks: mask = bitmask << offset 2. OP_ALG_TYPE_CLASS1 and OP_ALG_TYPE_CLASS2 must be shifted. 3. fix FIFO_STORE output data type value for AFHA S-Box 4. fix OPERATION pkha modular arithmetic source mask 5. rename LDST_SRCDST_WORD_CLASS1_ICV_SZ to LDST_SRCDST_WORD_CLASS1_IV_SZ (it refers to IV, not ICV). Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/desc.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index 513b6646bb36..61059abef737 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -90,8 +90,8 @@ struct sec4_sg_entry { #define HDR_ZRO 0x00008000 /* Start Index or SharedDesc Length */ -#define HDR_START_IDX_MASK 0x3f #define HDR_START_IDX_SHIFT 16 +#define HDR_START_IDX_MASK (0x3f << HDR_START_IDX_SHIFT) /* If shared descriptor header, 6-bit length */ #define HDR_DESCLEN_SHR_MASK 0x3f @@ -121,10 +121,10 @@ struct sec4_sg_entry { #define HDR_PROP_DNR 0x00000800 /* JobDesc/SharedDesc share property */ -#define HDR_SD_SHARE_MASK 0x03 #define HDR_SD_SHARE_SHIFT 8 -#define HDR_JD_SHARE_MASK 0x07 +#define HDR_SD_SHARE_MASK (0x03 << HDR_SD_SHARE_SHIFT) #define HDR_JD_SHARE_SHIFT 8 +#define HDR_JD_SHARE_MASK (0x07 << HDR_JD_SHARE_SHIFT) #define HDR_SHARE_NEVER (0x00 << HDR_SD_SHARE_SHIFT) #define HDR_SHARE_WAIT (0x01 << HDR_SD_SHARE_SHIFT) @@ -235,7 +235,7 @@ struct sec4_sg_entry { #define LDST_SRCDST_WORD_DECO_MATH2 (0x0a << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_DECO_AAD_SZ (0x0b << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_DECO_MATH3 (0x0b << LDST_SRCDST_SHIFT) -#define LDST_SRCDST_WORD_CLASS1_ICV_SZ (0x0c << LDST_SRCDST_SHIFT) +#define LDST_SRCDST_WORD_CLASS1_IV_SZ (0x0c << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_ALTDS_CLASS1 (0x0f << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_PKHA_A_SZ (0x10 << LDST_SRCDST_SHIFT) #define LDST_SRCDST_WORD_PKHA_B_SZ (0x11 << LDST_SRCDST_SHIFT) @@ -400,7 +400,7 @@ struct sec4_sg_entry { #define FIFOST_TYPE_PKHA_N (0x08 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_PKHA_A (0x0c << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_PKHA_B (0x0d << FIFOST_TYPE_SHIFT) -#define FIFOST_TYPE_AF_SBOX_JKEK (0x10 << FIFOST_TYPE_SHIFT) +#define FIFOST_TYPE_AF_SBOX_JKEK (0x20 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_AF_SBOX_TKEK (0x21 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_PKHA_E_JKEK (0x22 << FIFOST_TYPE_SHIFT) #define FIFOST_TYPE_PKHA_E_TKEK (0x23 << FIFOST_TYPE_SHIFT) @@ -1107,8 +1107,8 @@ struct sec4_sg_entry { /* For non-protocol/alg-only op commands */ #define OP_ALG_TYPE_SHIFT 24 #define OP_ALG_TYPE_MASK (0x7 << OP_ALG_TYPE_SHIFT) -#define OP_ALG_TYPE_CLASS1 2 -#define OP_ALG_TYPE_CLASS2 4 +#define OP_ALG_TYPE_CLASS1 (2 << OP_ALG_TYPE_SHIFT) +#define OP_ALG_TYPE_CLASS2 (4 << OP_ALG_TYPE_SHIFT) #define OP_ALG_ALGSEL_SHIFT 16 #define OP_ALG_ALGSEL_MASK (0xff << OP_ALG_ALGSEL_SHIFT) @@ -1249,7 +1249,7 @@ struct sec4_sg_entry { #define OP_ALG_PKMODE_MOD_PRIMALITY 0x00f /* PKHA mode copy-memory functions */ -#define OP_ALG_PKMODE_SRC_REG_SHIFT 13 +#define OP_ALG_PKMODE_SRC_REG_SHIFT 17 #define OP_ALG_PKMODE_SRC_REG_MASK (7 << OP_ALG_PKMODE_SRC_REG_SHIFT) #define OP_ALG_PKMODE_DST_REG_SHIFT 10 #define OP_ALG_PKMODE_DST_REG_MASK (7 << OP_ALG_PKMODE_DST_REG_SHIFT) -- cgit v1.2.3 From 8439e94fceb3812989bae41922567123cffd1cf7 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:14 +0200 Subject: crypto: caam - fix sparse warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following sparse warning (note that endianness issues are not not addressed in current patch): drivers/crypto/caam/ctrl.c:388:24: warning: incorrect type in argument 1 (different address spaces) drivers/crypto/caam/ctrl.c:388:24: expected void [noderef] *reg drivers/crypto/caam/ctrl.c:388:24: got unsigned int * drivers/crypto/caam/ctrl.c:390:24: warning: incorrect type in argument 1 (different address spaces) drivers/crypto/caam/ctrl.c:390:24: expected void [noderef] *reg drivers/crypto/caam/ctrl.c:390:24: got unsigned int * drivers/crypto/caam/ctrl.c:548:24: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:548:24: expected struct caam_ctrl [noderef] *ctrl drivers/crypto/caam/ctrl.c:548:24: got struct caam_ctrl * drivers/crypto/caam/ctrl.c:550:30: warning: cast removes address space of expression drivers/crypto/caam/ctrl.c:549:26: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:549:26: expected struct caam_assurance [noderef] *assure drivers/crypto/caam/ctrl.c:549:26: got struct caam_assurance * drivers/crypto/caam/ctrl.c:554:28: warning: cast removes address space of expression drivers/crypto/caam/ctrl.c:553:24: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:553:24: expected struct caam_deco [noderef] *deco drivers/crypto/caam/ctrl.c:553:24: got struct caam_deco * drivers/crypto/caam/ctrl.c:634:48: warning: cast removes address space of expression drivers/crypto/caam/ctrl.c:633:44: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:633:44: expected struct caam_job_ring [noderef] * drivers/crypto/caam/ctrl.c:633:44: got struct caam_job_ring * drivers/crypto/caam/ctrl.c:648:34: warning: cast removes address space of expression drivers/crypto/caam/ctrl.c:647:30: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:647:30: expected struct caam_queue_if [noderef] *qi drivers/crypto/caam/ctrl.c:647:30: got struct caam_queue_if * drivers/crypto/caam/ctrl.c:806:37: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:806:37: expected void *data drivers/crypto/caam/ctrl.c:806:37: got unsigned int [noderef] * drivers/crypto/caam/ctrl.c:814:38: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:814:38: expected void *data drivers/crypto/caam/ctrl.c:814:38: got unsigned int [noderef] * drivers/crypto/caam/ctrl.c:822:38: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/ctrl.c:822:38: expected void *data drivers/crypto/caam/ctrl.c:822:38: got unsigned int [noderef] * drivers/crypto/caam/jr.c:492:23: warning: incorrect type in assignment (different address spaces) drivers/crypto/caam/jr.c:492:23: expected struct caam_job_ring [noderef] *rregs drivers/crypto/caam/jr.c:492:23: got struct caam_job_ring * drivers/crypto/caam/caampkc.c:398:35: warning: Using plain integer as NULL pointer drivers/crypto/caam/caampkc.c:444:35: warning: Using plain integer as NULL pointer Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caampkc.c | 4 ++-- drivers/crypto/caam/ctrl.c | 40 +++++++++++++++++----------------------- drivers/crypto/caam/jr.c | 2 +- 3 files changed, 20 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caampkc.c b/drivers/crypto/caam/caampkc.c index 851015e652b8..32100c4851dd 100644 --- a/drivers/crypto/caam/caampkc.c +++ b/drivers/crypto/caam/caampkc.c @@ -395,7 +395,7 @@ static int caam_rsa_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); - struct rsa_key raw_key = {0}; + struct rsa_key raw_key = {NULL}; struct caam_rsa_key *rsa_key = &ctx->key; int ret; @@ -441,7 +441,7 @@ static int caam_rsa_set_priv_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) { struct caam_rsa_ctx *ctx = akcipher_tfm_ctx(tfm); - struct rsa_key raw_key = {0}; + struct rsa_key raw_key = {NULL}; struct caam_rsa_key *rsa_key = &ctx->key; int ret; diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index a79937d68c26..be62a7f482ac 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -365,11 +365,8 @@ static void kick_trng(struct platform_device *pdev, int ent_delay) */ val = (rd_reg32(&r4tst->rtsdctl) & RTSDCTL_ENT_DLY_MASK) >> RTSDCTL_ENT_DLY_SHIFT; - if (ent_delay <= val) { - /* put RNG4 into run mode */ - clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, 0); - return; - } + if (ent_delay <= val) + goto start_rng; val = rd_reg32(&r4tst->rtsdctl); val = (val & ~RTSDCTL_ENT_DLY_MASK) | @@ -381,15 +378,12 @@ static void kick_trng(struct platform_device *pdev, int ent_delay) wr_reg32(&r4tst->rtfrqmax, RTFRQMAX_DISABLE); /* read the control register */ val = rd_reg32(&r4tst->rtmctl); +start_rng: /* * select raw sampling in both entropy shifter - * and statistical checker + * and statistical checker; ; put RNG4 into run mode */ - clrsetbits_32(&val, 0, RTMCTL_SAMP_MODE_RAW_ES_SC); - /* put RNG4 into run mode */ - clrsetbits_32(&val, RTMCTL_PRGM, 0); - /* write back the control register */ - wr_reg32(&r4tst->rtmctl, val); + clrsetbits_32(&r4tst->rtmctl, RTMCTL_PRGM, RTMCTL_SAMP_MODE_RAW_ES_SC); } /** @@ -545,13 +539,13 @@ static int caam_probe(struct platform_device *pdev) else BLOCK_OFFSET = PG_SIZE_64K; - ctrlpriv->ctrl = (struct caam_ctrl __force *)ctrl; - ctrlpriv->assure = (struct caam_assurance __force *) - ((uint8_t *)ctrl + + ctrlpriv->ctrl = (struct caam_ctrl __iomem __force *)ctrl; + ctrlpriv->assure = (struct caam_assurance __iomem __force *) + ((__force uint8_t *)ctrl + BLOCK_OFFSET * ASSURE_BLOCK_NUMBER ); - ctrlpriv->deco = (struct caam_deco __force *) - ((uint8_t *)ctrl + + ctrlpriv->deco = (struct caam_deco __iomem __force *) + ((__force uint8_t *)ctrl + BLOCK_OFFSET * DECO_BLOCK_NUMBER ); @@ -630,8 +624,8 @@ static int caam_probe(struct platform_device *pdev) ring); continue; } - ctrlpriv->jr[ring] = (struct caam_job_ring __force *) - ((uint8_t *)ctrl + + ctrlpriv->jr[ring] = (struct caam_job_ring __iomem __force *) + ((__force uint8_t *)ctrl + (ring + JR_BLOCK_NUMBER) * BLOCK_OFFSET ); @@ -644,8 +638,8 @@ static int caam_probe(struct platform_device *pdev) !!(rd_reg32(&ctrl->perfmon.comp_parms_ms) & CTPR_MS_QI_MASK); if (ctrlpriv->qi_present) { - ctrlpriv->qi = (struct caam_queue_if __force *) - ((uint8_t *)ctrl + + ctrlpriv->qi = (struct caam_queue_if __iomem __force *) + ((__force uint8_t *)ctrl + BLOCK_OFFSET * QI_BLOCK_NUMBER ); /* This is all that's required to physically enable QI */ @@ -803,7 +797,7 @@ static int caam_probe(struct platform_device *pdev) &caam_fops_u32_ro); /* Internal covering keys (useful in non-secure mode only) */ - ctrlpriv->ctl_kek_wrap.data = &ctrlpriv->ctrl->kek[0]; + ctrlpriv->ctl_kek_wrap.data = (__force void *)&ctrlpriv->ctrl->kek[0]; ctrlpriv->ctl_kek_wrap.size = KEK_KEY_SIZE * sizeof(u32); ctrlpriv->ctl_kek = debugfs_create_blob("kek", S_IRUSR | @@ -811,7 +805,7 @@ static int caam_probe(struct platform_device *pdev) ctrlpriv->ctl, &ctrlpriv->ctl_kek_wrap); - ctrlpriv->ctl_tkek_wrap.data = &ctrlpriv->ctrl->tkek[0]; + ctrlpriv->ctl_tkek_wrap.data = (__force void *)&ctrlpriv->ctrl->tkek[0]; ctrlpriv->ctl_tkek_wrap.size = KEK_KEY_SIZE * sizeof(u32); ctrlpriv->ctl_tkek = debugfs_create_blob("tkek", S_IRUSR | @@ -819,7 +813,7 @@ static int caam_probe(struct platform_device *pdev) ctrlpriv->ctl, &ctrlpriv->ctl_tkek_wrap); - ctrlpriv->ctl_tdsk_wrap.data = &ctrlpriv->ctrl->tdsk[0]; + ctrlpriv->ctl_tdsk_wrap.data = (__force void *)&ctrlpriv->ctrl->tdsk[0]; ctrlpriv->ctl_tdsk_wrap.size = KEK_KEY_SIZE * sizeof(u32); ctrlpriv->ctl_tdsk = debugfs_create_blob("tdsk", S_IRUSR | diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 757c27f9953d..7331ea734f37 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -489,7 +489,7 @@ static int caam_jr_probe(struct platform_device *pdev) return -ENOMEM; } - jrpriv->rregs = (struct caam_job_ring __force *)ctrl; + jrpriv->rregs = (struct caam_job_ring __iomem __force *)ctrl; if (sizeof(dma_addr_t) == sizeof(u64)) if (of_device_is_compatible(nprop, "fsl,sec-v5.0-job-ring")) -- cgit v1.2.3 From c530e34140612855ab00f9190a19c41953aa0749 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:15 +0200 Subject: crypto: caam - fix smatch warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following smatch warnings: drivers/crypto/caam/caamalg.c:2350 aead_edesc_alloc() warn: we tested 'src_nents' before and it was 'true' drivers/crypto/caam/caamrng.c:351 caam_rng_init() error: no modifiers for allocation. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 4 +--- drivers/crypto/caam/caamrng.c | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 5317d8cad44d..bc433edd34c4 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -2346,10 +2346,8 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req, /* Check if data are contiguous. */ all_contig = !src_nents; - if (!all_contig) { - src_nents = src_nents ? : 1; + if (!all_contig) sec4_sg_len = src_nents; - } sec4_sg_len += dst_nents; diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index bb1c118b2d1b..38bb2411afcf 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -348,7 +348,7 @@ static int __init caam_rng_init(void) pr_err("Job Ring Device allocation for transform failed\n"); return PTR_ERR(dev); } - rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA); + rng_ctx = kmalloc(sizeof(*rng_ctx), GFP_DMA | GFP_KERNEL); if (!rng_ctx) { err = -ENOMEM; goto free_caam_alloc; -- cgit v1.2.3 From 00fef2b26a354ab9c1316f15677cb36966c91240 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:16 +0200 Subject: crypto: caam - remove unused may_sleep in dbg_dump_sg() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 5ecf8ef9103cb "crypto: caam - fix sg dump" Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index bc433edd34c4..cb26a57c5aaf 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -117,8 +117,7 @@ static void dbg_dump_sg(const char *level, const char *prefix_str, int prefix_type, int rowsize, int groupsize, - struct scatterlist *sg, size_t tlen, bool ascii, - bool may_sleep) + struct scatterlist *sg, size_t tlen, bool ascii) { struct scatterlist *it; void *it_page; @@ -2033,7 +2032,7 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, edesc->src_nents > 1 ? 100 : ivsize, 1); dbg_dump_sg(KERN_ERR, "dst @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, - edesc->dst_nents > 1 ? 100 : req->nbytes, 1, true); + edesc->dst_nents > 1 ? 100 : req->nbytes, 1); #endif ablkcipher_unmap(jrdev, edesc, req); @@ -2065,7 +2064,7 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, ivsize, 1); dbg_dump_sg(KERN_ERR, "dst @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->dst, - edesc->dst_nents > 1 ? 100 : req->nbytes, 1, true); + edesc->dst_nents > 1 ? 100 : req->nbytes, 1); #endif ablkcipher_unmap(jrdev, edesc, req); @@ -2220,15 +2219,13 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr, int len, sec4_sg_index = 0; #ifdef DEBUG - bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) != 0); print_hex_dump(KERN_ERR, "presciv@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->info, ivsize, 1); printk(KERN_ERR "asked=%d, nbytes%d\n", (int)edesc->src_nents ? 100 : req->nbytes, req->nbytes); dbg_dump_sg(KERN_ERR, "src @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->src, - edesc->src_nents ? 100 : req->nbytes, 1, may_sleep); + edesc->src_nents ? 100 : req->nbytes, 1); #endif len = desc_len(sh_desc); @@ -2280,14 +2277,12 @@ static void init_ablkcipher_giv_job(u32 *sh_desc, dma_addr_t ptr, int len, sec4_sg_index = 0; #ifdef DEBUG - bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) != 0); print_hex_dump(KERN_ERR, "presciv@" __stringify(__LINE__) ": ", DUMP_PREFIX_ADDRESS, 16, 4, req->info, ivsize, 1); dbg_dump_sg(KERN_ERR, "src @" __stringify(__LINE__) ": ", DUMP_PREFIX_ADDRESS, 16, 4, req->src, - edesc->src_nents ? 100 : req->nbytes, 1, may_sleep); + edesc->src_nents ? 100 : req->nbytes, 1); #endif len = desc_len(sh_desc); @@ -2556,11 +2551,9 @@ static int aead_decrypt(struct aead_request *req) int ret = 0; #ifdef DEBUG - bool may_sleep = ((req->base.flags & (CRYPTO_TFM_REQ_MAY_BACKLOG | - CRYPTO_TFM_REQ_MAY_SLEEP)) != 0); dbg_dump_sg(KERN_ERR, "dec src@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, req->src, - req->assoclen + req->cryptlen, 1, may_sleep); + req->assoclen + req->cryptlen, 1); #endif /* allocate extended descriptor */ -- cgit v1.2.3 From 1b008eedb0afcc7afa26f17ce16069789f8ce5ba Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:17 +0200 Subject: crypto: caam - remove unused command from aead givencrypt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit REG3 no longer needs to be updated, since it's not used after that. This shared descriptor command is a leftover of the conversion to AEAD interface. Fixes: 479bcc7c5b9e1 "crypto: caam - Convert authenc to new AEAD interface" Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index cb26a57c5aaf..1982dacce80e 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -75,7 +75,7 @@ #define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) #define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) #define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) -#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 9 * CAAM_CMD_SZ) +#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) /* Note: Nonce is counted in enckeylen */ #define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ) @@ -697,9 +697,6 @@ copy_iv: append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - /* ivsize + cryptlen = seqoutlen - authsize */ - append_math_sub_imm_u32(desc, REG3, SEQOUTLEN, IMM, ctx->authsize); - /* Skip assoc data */ append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); -- cgit v1.2.3 From 4ca7c7d8fea1ffdc36df33578c1e68d0d6367b0c Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:18 +0200 Subject: crypto: caam - trivial code clean-up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit -replace offsetof with container_of -remove unused "assoc_nents", "iv_dma" from aead_edesc and fix comments -remove unused CAAM_MAX_IV_LENGTH #define Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 16 ++++------------ drivers/crypto/caam/caamhash.c | 12 ++++-------- drivers/crypto/caam/caamrng.c | 3 +-- 3 files changed, 9 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 1982dacce80e..34dfcdb7ff84 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -62,8 +62,6 @@ #define CAAM_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + \ CTR_RFC3686_NONCE_SIZE + \ SHA512_DIGEST_SIZE * 2) -/* max IV is max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */ -#define CAAM_MAX_IV_LENGTH 16 #define AEAD_DESC_JOB_IO_LEN (DESC_JOB_IO_LEN + CAAM_CMD_SZ * 2) #define GCM_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + \ @@ -1873,20 +1871,16 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* * aead_edesc - s/w-extended aead descriptor - * @assoc_nents: number of segments in associated data (SPI+Seq) scatterlist * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist - * @iv_dma: dma address of iv for checking continuity and link table - * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) * @sec4_sg_bytes: length of dma mapped sec4_sg space * @sec4_sg_dma: bus physical mapped address of h/w link table + * @sec4_sg: pointer to h/w link table * @hw_desc: the h/w job descriptor followed by any referenced link tables */ struct aead_edesc { - int assoc_nents; int src_nents; int dst_nents; - dma_addr_t iv_dma; int sec4_sg_bytes; dma_addr_t sec4_sg_dma; struct sec4_sg_entry *sec4_sg; @@ -1898,9 +1892,9 @@ struct aead_edesc { * @src_nents: number of segments in input scatterlist * @dst_nents: number of segments in output scatterlist * @iv_dma: dma address of iv for checking continuity and link table - * @desc: h/w descriptor (variable length; must not exceed MAX_CAAM_DESCSIZE) * @sec4_sg_bytes: length of dma mapped sec4_sg space * @sec4_sg_dma: bus physical mapped address of h/w link table + * @sec4_sg: pointer to h/w link table * @hw_desc: the h/w job descriptor followed by any referenced link tables */ struct ablkcipher_edesc { @@ -2017,8 +2011,7 @@ static void ablkcipher_encrypt_done(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = (struct ablkcipher_edesc *)((char *)desc - - offsetof(struct ablkcipher_edesc, hw_desc)); + edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); @@ -2050,8 +2043,7 @@ static void ablkcipher_decrypt_done(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = (struct ablkcipher_edesc *)((char *)desc - - offsetof(struct ablkcipher_edesc, hw_desc)); + edesc = container_of(desc, struct ablkcipher_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 51990dd56024..d5a06c6923c0 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -636,8 +636,7 @@ static void ahash_done(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = (struct ahash_edesc *)((char *)desc - - offsetof(struct ahash_edesc, hw_desc)); + edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); @@ -671,8 +670,7 @@ static void ahash_done_bi(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = (struct ahash_edesc *)((char *)desc - - offsetof(struct ahash_edesc, hw_desc)); + edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); @@ -706,8 +704,7 @@ static void ahash_done_ctx_src(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = (struct ahash_edesc *)((char *)desc - - offsetof(struct ahash_edesc, hw_desc)); + edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); @@ -741,8 +738,7 @@ static void ahash_done_ctx_dst(struct device *jrdev, u32 *desc, u32 err, dev_err(jrdev, "%s %d: err 0x%x\n", __func__, __LINE__, err); #endif - edesc = (struct ahash_edesc *)((char *)desc - - offsetof(struct ahash_edesc, hw_desc)); + edesc = container_of(desc, struct ahash_edesc, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); diff --git a/drivers/crypto/caam/caamrng.c b/drivers/crypto/caam/caamrng.c index 38bb2411afcf..41398da3edf4 100644 --- a/drivers/crypto/caam/caamrng.c +++ b/drivers/crypto/caam/caamrng.c @@ -100,8 +100,7 @@ static void rng_done(struct device *jrdev, u32 *desc, u32 err, void *context) { struct buf_data *bd; - bd = (struct buf_data *)((char *)desc - - offsetof(struct buf_data, hw_desc)); + bd = container_of(desc, struct buf_data, hw_desc[0]); if (err) caam_jr_strstatus(jrdev, err); -- cgit v1.2.3 From 9305dff7ab8b5e1aef2c4c5c733ce7e1dc345433 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:19 +0200 Subject: crypto: caam - remove unreachable code in report_ccb_status() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ERRID is a 4-bit field. Since err_id values are in [0..15] and err_id_list array size is 16, the condition "err_id < ARRAY_SIZE(err_id_list)" is always true. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/error.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c index 33e41ea83fcc..79a0cc70717f 100644 --- a/drivers/crypto/caam/error.c +++ b/drivers/crypto/caam/error.c @@ -146,10 +146,9 @@ static void report_ccb_status(struct device *jrdev, const u32 status, strlen(rng_err_id_list[err_id])) { /* RNG-only error */ err_str = rng_err_id_list[err_id]; - } else if (err_id < ARRAY_SIZE(err_id_list)) + } else { err_str = err_id_list[err_id]; - else - snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id); + } /* * CCB ICV check failures are part of normal operation life; -- cgit v1.2.3 From c73e36e82b2394b1e199cb975485444cf05ed662 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:20 +0200 Subject: crypto: caam - fix DMA API mapping leak in ablkcipher code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit alkcipher_edesc_alloc() and ablkcipher_giv_edesc_alloc() don't free / unmap resources on error path: - dmap_map_sg() could fail, thus make sure the return value is checked - unmap DMA mappings in case of error Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 44 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 34dfcdb7ff84..8db54b090d39 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -2600,16 +2600,33 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request if (likely(req->src == req->dst)) { sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, DMA_BIDIRECTIONAL); + if (unlikely(!sgc)) { + dev_err(jrdev, "unable to map source\n"); + return ERR_PTR(-ENOMEM); + } } else { sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, DMA_TO_DEVICE); + if (unlikely(!sgc)) { + dev_err(jrdev, "unable to map source\n"); + return ERR_PTR(-ENOMEM); + } + sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, DMA_FROM_DEVICE); + if (unlikely(!sgc)) { + dev_err(jrdev, "unable to map destination\n"); + dma_unmap_sg(jrdev, req->src, src_nents ? : 1, + DMA_TO_DEVICE); + return ERR_PTR(-ENOMEM); + } } iv_dma = dma_map_single(jrdev, req->info, ivsize, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, iv_dma)) { dev_err(jrdev, "unable to map IV\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0); return ERR_PTR(-ENOMEM); } @@ -2629,6 +2646,8 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, + iv_dma, ivsize, 0, 0); return ERR_PTR(-ENOMEM); } @@ -2655,6 +2674,9 @@ static struct ablkcipher_edesc *ablkcipher_edesc_alloc(struct ablkcipher_request sec4_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { dev_err(jrdev, "unable to map S/G table\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, + iv_dma, ivsize, 0, 0); + kfree(edesc); return ERR_PTR(-ENOMEM); } @@ -2776,11 +2798,26 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( if (likely(req->src == req->dst)) { sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, DMA_BIDIRECTIONAL); + if (unlikely(!sgc)) { + dev_err(jrdev, "unable to map source\n"); + return ERR_PTR(-ENOMEM); + } } else { sgc = dma_map_sg(jrdev, req->src, src_nents ? : 1, DMA_TO_DEVICE); + if (unlikely(!sgc)) { + dev_err(jrdev, "unable to map source\n"); + return ERR_PTR(-ENOMEM); + } + sgc = dma_map_sg(jrdev, req->dst, dst_nents ? : 1, DMA_FROM_DEVICE); + if (unlikely(!sgc)) { + dev_err(jrdev, "unable to map destination\n"); + dma_unmap_sg(jrdev, req->src, src_nents ? : 1, + DMA_TO_DEVICE); + return ERR_PTR(-ENOMEM); + } } /* @@ -2790,6 +2827,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( iv_dma = dma_map_single(jrdev, greq->giv, ivsize, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, iv_dma)) { dev_err(jrdev, "unable to map IV\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, 0, + 0, 0, 0); return ERR_PTR(-ENOMEM); } @@ -2805,6 +2844,8 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( GFP_DMA | flags); if (!edesc) { dev_err(jrdev, "could not allocate extended descriptor\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, + iv_dma, ivsize, 0, 0); return ERR_PTR(-ENOMEM); } @@ -2832,6 +2873,9 @@ static struct ablkcipher_edesc *ablkcipher_giv_edesc_alloc( sec4_sg_bytes, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, edesc->sec4_sg_dma)) { dev_err(jrdev, "unable to map S/G table\n"); + caam_unmap(jrdev, req->src, req->dst, src_nents, dst_nents, + iv_dma, ivsize, 0, 0); + kfree(edesc); return ERR_PTR(-ENOMEM); } edesc->iv_dma = iv_dma; -- cgit v1.2.3 From 2b163b5bce04546da72617bfb6c8bf07a45c4b17 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:21 +0200 Subject: Revert "crypto: caam - get rid of tasklet" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 66d2e2028091a074aa1290d2eeda5ddb1a6c329c. Quoting from Russell's findings: https://www.mail-archive.com/linux-crypto@vger.kernel.org/msg21136.html [quote] Okay, I've re-tested, using a different way of measuring, because using openssl speed is impractical for off-loaded engines. I've decided to use this way to measure the performance: dd if=/dev/zero bs=1048576 count=128 | /usr/bin/time openssl dgst -md5 For the threaded IRQs case gives: 0.05user 2.74system 0:05.30elapsed 52%CPU (0avgtext+0avgdata 2400maxresident)k 0.06user 2.52system 0:05.18elapsed 49%CPU (0avgtext+0avgdata 2404maxresident)k 0.12user 2.60system 0:05.61elapsed 48%CPU (0avgtext+0avgdata 2460maxresident)k => 5.36s => 25.0MB/s and the tasklet case: 0.08user 2.53system 0:04.83elapsed 54%CPU (0avgtext+0avgdata 2468maxresident)k 0.09user 2.47system 0:05.16elapsed 49%CPU (0avgtext+0avgdata 2368maxresident)k 0.10user 2.51system 0:04.87elapsed 53%CPU (0avgtext+0avgdata 2460maxresident)k => 4.95 => 27.1MB/s which corresponds to an 8% slowdown for the threaded IRQ case. So, tasklets are indeed faster than threaded IRQs. [...] I think I've proven from the above that this patch needs to be reverted due to the performance regression, and that there _is_ most definitely a deterimental effect of switching from tasklets to threaded IRQs. [/quote] Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/intern.h | 1 + drivers/crypto/caam/jr.c | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/intern.h b/drivers/crypto/caam/intern.h index 5d4c05074a5c..e2bcacc1a921 100644 --- a/drivers/crypto/caam/intern.h +++ b/drivers/crypto/caam/intern.h @@ -41,6 +41,7 @@ struct caam_drv_private_jr { struct device *dev; int ridx; struct caam_job_ring __iomem *rregs; /* JobR's register space */ + struct tasklet_struct irqtask; int irq; /* One per queue */ /* Number of scatterlist crypt transforms active on the JobR */ diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c index 7331ea734f37..c8604dfadbf5 100644 --- a/drivers/crypto/caam/jr.c +++ b/drivers/crypto/caam/jr.c @@ -73,6 +73,8 @@ static int caam_jr_shutdown(struct device *dev) ret = caam_reset_hw_jr(dev); + tasklet_kill(&jrp->irqtask); + /* Release interrupt */ free_irq(jrp->irq, dev); @@ -128,7 +130,7 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) /* * Check the output ring for ready responses, kick - * the threaded irq if jobs done. + * tasklet if jobs done. */ irqstate = rd_reg32(&jrp->rregs->jrintstatus); if (!irqstate) @@ -150,13 +152,18 @@ static irqreturn_t caam_jr_interrupt(int irq, void *st_dev) /* Have valid interrupt at this point, just ACK and trigger */ wr_reg32(&jrp->rregs->jrintstatus, irqstate); - return IRQ_WAKE_THREAD; + preempt_disable(); + tasklet_schedule(&jrp->irqtask); + preempt_enable(); + + return IRQ_HANDLED; } -static irqreturn_t caam_jr_threadirq(int irq, void *st_dev) +/* Deferred service handler, run as interrupt-fired tasklet */ +static void caam_jr_dequeue(unsigned long devarg) { int hw_idx, sw_idx, i, head, tail; - struct device *dev = st_dev; + struct device *dev = (struct device *)devarg; struct caam_drv_private_jr *jrp = dev_get_drvdata(dev); void (*usercall)(struct device *dev, u32 *desc, u32 status, void *arg); u32 *userdesc, userstatus; @@ -230,8 +237,6 @@ static irqreturn_t caam_jr_threadirq(int irq, void *st_dev) /* reenable / unmask IRQs */ clrsetbits_32(&jrp->rregs->rconfig_lo, JRCFG_IMSK, 0); - - return IRQ_HANDLED; } /** @@ -389,10 +394,11 @@ static int caam_jr_init(struct device *dev) jrp = dev_get_drvdata(dev); + tasklet_init(&jrp->irqtask, caam_jr_dequeue, (unsigned long)dev); + /* Connect job ring interrupt handler. */ - error = request_threaded_irq(jrp->irq, caam_jr_interrupt, - caam_jr_threadirq, IRQF_SHARED, - dev_name(dev), dev); + error = request_irq(jrp->irq, caam_jr_interrupt, IRQF_SHARED, + dev_name(dev), dev); if (error) { dev_err(dev, "can't connect JobR %d interrupt (%d)\n", jrp->ridx, jrp->irq); @@ -454,6 +460,7 @@ out_free_inpring: out_free_irq: free_irq(jrp->irq, dev); out_kill_deq: + tasklet_kill(&jrp->irqtask); return error; } -- cgit v1.2.3 From e25ff92e8feb5ab3fb511aabeccc67304807366f Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:22 +0200 Subject: crypto: caam - move sec4_sg_entry to sg_sw_sec4.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit sec4_sg_entry structure is used only by helper functions in sg_sw_sec4.h. Since SEC HW S/G entries are to be manipulated only indirectly, via these functions, move sec4_sg_entry to the corresponding header. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/desc.h | 6 ------ drivers/crypto/caam/sg_sw_sec4.h | 6 +++++- 2 files changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/desc.h b/drivers/crypto/caam/desc.h index 61059abef737..2e6766a1573f 100644 --- a/drivers/crypto/caam/desc.h +++ b/drivers/crypto/caam/desc.h @@ -22,12 +22,6 @@ #define SEC4_SG_LEN_MASK 0x3fffffff /* Excludes EXT and FINAL */ #define SEC4_SG_OFFSET_MASK 0x00001fff -struct sec4_sg_entry { - u64 ptr; - u32 len; - u32 bpid_offset; -}; - /* Max size of any CAAM descriptor in 32-bit words, inclusive of header */ #define MAX_CAAM_DESCSIZE 64 diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h index 41cd5a356d05..6afa20c4a013 100644 --- a/drivers/crypto/caam/sg_sw_sec4.h +++ b/drivers/crypto/caam/sg_sw_sec4.h @@ -7,7 +7,11 @@ #include "regs.h" -struct sec4_sg_entry; +struct sec4_sg_entry { + u64 ptr; + u32 len; + u32 bpid_offset; +}; /* * convert single dma address to h/w link table format -- cgit v1.2.3 From 24a4f14f0a93f6fff7e6ade5d99b402c831bbd96 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:23 +0200 Subject: crypto: caam - constify pointer to descriptor buffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pointer to the descriptor buffer is not touched, it always points to start of the descriptor buffer. Thus, make it const. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/desc_constr.h | 72 +++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index a8cd8a78ec1f..354da735af62 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -33,38 +33,39 @@ extern bool caam_little_end; -static inline int desc_len(u32 *desc) +static inline int desc_len(u32 * const desc) { return caam32_to_cpu(*desc) & HDR_DESCLEN_MASK; } -static inline int desc_bytes(void *desc) +static inline int desc_bytes(void * const desc) { return desc_len(desc) * CAAM_CMD_SZ; } -static inline u32 *desc_end(u32 *desc) +static inline u32 *desc_end(u32 * const desc) { return desc + desc_len(desc); } -static inline void *sh_desc_pdb(u32 *desc) +static inline void *sh_desc_pdb(u32 * const desc) { return desc + 1; } -static inline void init_desc(u32 *desc, u32 options) +static inline void init_desc(u32 * const desc, u32 options) { *desc = cpu_to_caam32((options | HDR_ONE) + 1); } -static inline void init_sh_desc(u32 *desc, u32 options) +static inline void init_sh_desc(u32 * const desc, u32 options) { PRINT_POS; init_desc(desc, CMD_SHARED_DESC_HDR | options); } -static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) +static inline void init_sh_desc_pdb(u32 * const desc, u32 options, + size_t pdb_bytes) { u32 pdb_len = (pdb_bytes + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ; @@ -72,19 +73,20 @@ static inline void init_sh_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) options); } -static inline void init_job_desc(u32 *desc, u32 options) +static inline void init_job_desc(u32 * const desc, u32 options) { init_desc(desc, CMD_DESC_HDR | options); } -static inline void init_job_desc_pdb(u32 *desc, u32 options, size_t pdb_bytes) +static inline void init_job_desc_pdb(u32 * const desc, u32 options, + size_t pdb_bytes) { u32 pdb_len = (pdb_bytes + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ; init_job_desc(desc, (((pdb_len + 1) << HDR_START_IDX_SHIFT)) | options); } -static inline void append_ptr(u32 *desc, dma_addr_t ptr) +static inline void append_ptr(u32 * const desc, dma_addr_t ptr) { dma_addr_t *offset = (dma_addr_t *)desc_end(desc); @@ -94,8 +96,8 @@ static inline void append_ptr(u32 *desc, dma_addr_t ptr) CAAM_PTR_SZ / CAAM_CMD_SZ); } -static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len, - u32 options) +static inline void init_job_desc_shared(u32 * const desc, dma_addr_t ptr, + int len, u32 options) { PRINT_POS; init_job_desc(desc, HDR_SHARED | options | @@ -103,7 +105,7 @@ static inline void init_job_desc_shared(u32 *desc, dma_addr_t ptr, int len, append_ptr(desc, ptr); } -static inline void append_data(u32 *desc, void *data, int len) +static inline void append_data(u32 * const desc, void *data, int len) { u32 *offset = desc_end(desc); @@ -114,7 +116,7 @@ static inline void append_data(u32 *desc, void *data, int len) (len + CAAM_CMD_SZ - 1) / CAAM_CMD_SZ); } -static inline void append_cmd(u32 *desc, u32 command) +static inline void append_cmd(u32 * const desc, u32 command) { u32 *cmd = desc_end(desc); @@ -125,7 +127,7 @@ static inline void append_cmd(u32 *desc, u32 command) #define append_u32 append_cmd -static inline void append_u64(u32 *desc, u64 data) +static inline void append_u64(u32 * const desc, u64 data) { u32 *offset = desc_end(desc); @@ -142,14 +144,14 @@ static inline void append_u64(u32 *desc, u64 data) } /* Write command without affecting header, and return pointer to next word */ -static inline u32 *write_cmd(u32 *desc, u32 command) +static inline u32 *write_cmd(u32 * const desc, u32 command) { *desc = cpu_to_caam32(command); return desc + 1; } -static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len, +static inline void append_cmd_ptr(u32 * const desc, dma_addr_t ptr, int len, u32 command) { append_cmd(desc, command | len); @@ -157,7 +159,7 @@ static inline void append_cmd_ptr(u32 *desc, dma_addr_t ptr, int len, } /* Write length after pointer, rather than inside command */ -static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr, +static inline void append_cmd_ptr_extlen(u32 * const desc, dma_addr_t ptr, unsigned int len, u32 command) { append_cmd(desc, command); @@ -166,7 +168,7 @@ static inline void append_cmd_ptr_extlen(u32 *desc, dma_addr_t ptr, append_cmd(desc, len); } -static inline void append_cmd_data(u32 *desc, void *data, int len, +static inline void append_cmd_data(u32 * const desc, void *data, int len, u32 command) { append_cmd(desc, command | IMMEDIATE | len); @@ -174,7 +176,7 @@ static inline void append_cmd_data(u32 *desc, void *data, int len, } #define APPEND_CMD_RET(cmd, op) \ -static inline u32 *append_##cmd(u32 *desc, u32 options) \ +static inline u32 *append_##cmd(u32 * const desc, u32 options) \ { \ u32 *cmd = desc_end(desc); \ PRINT_POS; \ @@ -184,13 +186,13 @@ static inline u32 *append_##cmd(u32 *desc, u32 options) \ APPEND_CMD_RET(jump, JUMP) APPEND_CMD_RET(move, MOVE) -static inline void set_jump_tgt_here(u32 *desc, u32 *jump_cmd) +static inline void set_jump_tgt_here(u32 * const desc, u32 *jump_cmd) { *jump_cmd = cpu_to_caam32(caam32_to_cpu(*jump_cmd) | (desc_len(desc) - (jump_cmd - desc))); } -static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd) +static inline void set_move_tgt_here(u32 * const desc, u32 *move_cmd) { u32 val = caam32_to_cpu(*move_cmd); @@ -200,7 +202,7 @@ static inline void set_move_tgt_here(u32 *desc, u32 *move_cmd) } #define APPEND_CMD(cmd, op) \ -static inline void append_##cmd(u32 *desc, u32 options) \ +static inline void append_##cmd(u32 * const desc, u32 options) \ { \ PRINT_POS; \ append_cmd(desc, CMD_##op | options); \ @@ -208,7 +210,8 @@ static inline void append_##cmd(u32 *desc, u32 options) \ APPEND_CMD(operation, OPERATION) #define APPEND_CMD_LEN(cmd, op) \ -static inline void append_##cmd(u32 *desc, unsigned int len, u32 options) \ +static inline void append_##cmd(u32 * const desc, unsigned int len, \ + u32 options) \ { \ PRINT_POS; \ append_cmd(desc, CMD_##op | len | options); \ @@ -220,8 +223,8 @@ APPEND_CMD_LEN(seq_fifo_load, SEQ_FIFO_LOAD) APPEND_CMD_LEN(seq_fifo_store, SEQ_FIFO_STORE) #define APPEND_CMD_PTR(cmd, op) \ -static inline void append_##cmd(u32 *desc, dma_addr_t ptr, unsigned int len, \ - u32 options) \ +static inline void append_##cmd(u32 * const desc, dma_addr_t ptr, \ + unsigned int len, u32 options) \ { \ PRINT_POS; \ append_cmd_ptr(desc, ptr, len, CMD_##op | options); \ @@ -231,8 +234,8 @@ APPEND_CMD_PTR(load, LOAD) APPEND_CMD_PTR(fifo_load, FIFO_LOAD) APPEND_CMD_PTR(fifo_store, FIFO_STORE) -static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len, - u32 options) +static inline void append_store(u32 * const desc, dma_addr_t ptr, + unsigned int len, u32 options) { u32 cmd_src; @@ -249,7 +252,8 @@ static inline void append_store(u32 *desc, dma_addr_t ptr, unsigned int len, } #define APPEND_SEQ_PTR_INTLEN(cmd, op) \ -static inline void append_seq_##cmd##_ptr_intlen(u32 *desc, dma_addr_t ptr, \ +static inline void append_seq_##cmd##_ptr_intlen(u32 * const desc, \ + dma_addr_t ptr, \ unsigned int len, \ u32 options) \ { \ @@ -263,7 +267,7 @@ APPEND_SEQ_PTR_INTLEN(in, IN) APPEND_SEQ_PTR_INTLEN(out, OUT) #define APPEND_CMD_PTR_TO_IMM(cmd, op) \ -static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ +static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \ unsigned int len, u32 options) \ { \ PRINT_POS; \ @@ -273,7 +277,7 @@ APPEND_CMD_PTR_TO_IMM(load, LOAD); APPEND_CMD_PTR_TO_IMM(fifo_load, FIFO_LOAD); #define APPEND_CMD_PTR_EXTLEN(cmd, op) \ -static inline void append_##cmd##_extlen(u32 *desc, dma_addr_t ptr, \ +static inline void append_##cmd##_extlen(u32 * const desc, dma_addr_t ptr, \ unsigned int len, u32 options) \ { \ PRINT_POS; \ @@ -287,7 +291,7 @@ APPEND_CMD_PTR_EXTLEN(seq_out_ptr, SEQ_OUT_PTR) * the size of its type */ #define APPEND_CMD_PTR_LEN(cmd, op, type) \ -static inline void append_##cmd(u32 *desc, dma_addr_t ptr, \ +static inline void append_##cmd(u32 * const desc, dma_addr_t ptr, \ type len, u32 options) \ { \ PRINT_POS; \ @@ -304,7 +308,7 @@ APPEND_CMD_PTR_LEN(seq_out_ptr, SEQ_OUT_PTR, u32) * from length of immediate data provided, e.g., split keys */ #define APPEND_CMD_PTR_TO_IMM2(cmd, op) \ -static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ +static inline void append_##cmd##_as_imm(u32 * const desc, void *data, \ unsigned int data_len, \ unsigned int len, u32 options) \ { \ @@ -315,7 +319,7 @@ static inline void append_##cmd##_as_imm(u32 *desc, void *data, \ APPEND_CMD_PTR_TO_IMM2(key, KEY); #define APPEND_CMD_RAW_IMM(cmd, op, type) \ -static inline void append_##cmd##_imm_##type(u32 *desc, type immediate, \ +static inline void append_##cmd##_imm_##type(u32 * const desc, type immediate, \ u32 options) \ { \ PRINT_POS; \ -- cgit v1.2.3 From 9a1a1c08dc285df9460a2b1b3de2bca129ebc6e2 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Wed, 9 Nov 2016 10:46:24 +0200 Subject: crypto: caam - merge identical ahash_final/finup shared desc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shared descriptors used by ahash_final() and ahash_finup() are identical, thus get rid of one of them (sh_desc_finup). Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index d5a06c6923c0..86f360853502 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -103,12 +103,10 @@ struct caam_hash_ctx { u32 sh_desc_update_first[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; u32 sh_desc_fin[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; u32 sh_desc_digest[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; - u32 sh_desc_finup[DESC_HASH_MAX_USED_LEN] ____cacheline_aligned; dma_addr_t sh_desc_update_dma ____cacheline_aligned; dma_addr_t sh_desc_update_first_dma; dma_addr_t sh_desc_fin_dma; dma_addr_t sh_desc_digest_dma; - dma_addr_t sh_desc_finup_dma; struct device *jrdev; u32 alg_type; u32 alg_op; @@ -380,24 +378,6 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) desc_bytes(desc), 1); #endif - /* ahash_finup shared descriptor */ - desc = ctx->sh_desc_finup; - - ahash_ctx_data_to_out(desc, have_key | ctx->alg_type, - OP_ALG_AS_FINALIZE, digestsize, ctx); - - ctx->sh_desc_finup_dma = dma_map_single(jrdev, desc, desc_bytes(desc), - DMA_TO_DEVICE); - if (dma_mapping_error(jrdev, ctx->sh_desc_finup_dma)) { - dev_err(jrdev, "unable to map shared descriptor\n"); - return -ENOMEM; - } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "ahash finup shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - /* ahash_digest shared descriptor */ desc = ctx->sh_desc_digest; @@ -1071,7 +1051,7 @@ static int ahash_finup_ctx(struct ahash_request *req) /* allocate space for base edesc and hw desc commands, link tables */ edesc = ahash_edesc_alloc(ctx, sec4_sg_src_index + mapped_nents, - ctx->sh_desc_finup, ctx->sh_desc_finup_dma, + ctx->sh_desc_fin, ctx->sh_desc_fin_dma, flags); if (!edesc) { dma_unmap_sg(jrdev, req->src, src_nents, DMA_TO_DEVICE); @@ -1886,10 +1866,6 @@ static void caam_hash_cra_exit(struct crypto_tfm *tfm) dma_unmap_single(ctx->jrdev, ctx->sh_desc_digest_dma, desc_bytes(ctx->sh_desc_digest), DMA_TO_DEVICE); - if (ctx->sh_desc_finup_dma && - !dma_mapping_error(ctx->jrdev, ctx->sh_desc_finup_dma)) - dma_unmap_single(ctx->jrdev, ctx->sh_desc_finup_dma, - desc_bytes(ctx->sh_desc_finup), DMA_TO_DEVICE); caam_jr_free(ctx->jrdev); } -- cgit v1.2.3 From 811073b11b83c4da78413ecdb24c5adf3e5631ae Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Nov 2016 12:47:36 +0000 Subject: i2c: Add pointer dereference protection to i2c_match_id() Here we're providing dereference protection for i2c_match_id(), which saves us having to do it each time it's called. We're also stripping out the (now) needless checks in i2c_device_match(). This patch paves the way for other, similar code trimming. Acked-by: Grant Likely Signed-off-by: Lee Jones Tested-by: Kieran Bingham Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Kieran Bingham Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b432b64e307a..86083e5e5520 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -679,6 +679,9 @@ static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, const struct i2c_client *client) { + if (!(id && client)) + return NULL; + while (id->name[0]) { if (strcmp(client->name, id->name) == 0) return id; @@ -692,8 +695,6 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; - if (!client) - return 0; /* Attempt an OF style match */ if (of_driver_match_device(dev, drv)) @@ -704,9 +705,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) return 1; driver = to_i2c_driver(drv); - /* match on an id table if there is one */ - if (driver->id_table) - return i2c_match_id(driver->id_table, client) != NULL; + + /* Finally an I2C match */ + if (i2c_match_id(driver->id_table, client)) + return 1; return 0; } -- cgit v1.2.3 From 0e865a80c1358db9311c411c4763b9e2e324d0df Mon Sep 17 00:00:00 2001 From: Elimar Riesebieter Date: Sun, 18 Sep 2016 13:08:45 +0200 Subject: macintosh: Remove dependency on IDE_GD_ATA if ADB_PMU_LED_DISK is selected We can use the front led of powerbooks/ibooks to visualize disk activity without the deprecated IDE_GD_ATA. Signed-off-by: Elimar Riesebieter Signed-off-by: Michael Ellerman --- drivers/macintosh/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig index d28690f6e262..5d80810934df 100644 --- a/drivers/macintosh/Kconfig +++ b/drivers/macintosh/Kconfig @@ -102,7 +102,6 @@ config ADB_PMU_LED_DISK bool "Use front LED as DISK LED by default" depends on ADB_PMU_LED depends on LEDS_CLASS - depends on IDE_GD_ATA select LEDS_TRIGGERS select LEDS_TRIGGER_DISK help -- cgit v1.2.3 From d0b2a5b80317cae1249d84136c1ab9bc036c0917 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 19 Oct 2016 17:32:33 -0300 Subject: dmaengine: fsl_raid: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/dma/fsl_raid.ko | grep alias $ After this patch: $ modinfo drivers/dma/fsl_raid.ko | grep alias alias: of:N*T*Cfsl,raideng-v1.0C* alias: of:N*T*Cfsl,raideng-v1.0 Signed-off-by: Javier Martinez Canillas Signed-off-by: Vinod Koul --- drivers/dma/fsl_raid.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/dma/fsl_raid.c b/drivers/dma/fsl_raid.c index db2f9e1653a2..90d29f90acfb 100644 --- a/drivers/dma/fsl_raid.c +++ b/drivers/dma/fsl_raid.c @@ -881,6 +881,7 @@ static struct of_device_id fsl_re_ids[] = { { .compatible = "fsl,raideng-v1.0", }, {} }; +MODULE_DEVICE_TABLE(of, fsl_re_ids); static struct platform_driver fsl_re_driver = { .driver = { -- cgit v1.2.3 From 87ffcea5530393e771ea34ba2e98986258e534f2 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 22 Oct 2016 14:38:54 +0000 Subject: dmaengine: qcom_hidma: remove unneeded of_node_put() Device node iterators put the previous value of the index variable, so an explicit put causes a double put. Generated by: scripts/coccinelle/iterators/device_node_continue.cocci Signed-off-by: Wei Yongjun Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma_mgmt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 185d29c77c22..985f5ac2695d 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -402,7 +402,6 @@ static int __init hidma_mgmt_init(void) for_each_matching_node(child, hidma_mgmt_match) { /* device tree based firmware here */ hidma_mgmt_of_populate_channels(child); - of_node_put(child); } #endif platform_driver_register(&hidma_mgmt_driver); -- cgit v1.2.3 From 3ed16793e0e77ee9934611ac574468d1c984c3d8 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sat, 22 Oct 2016 18:25:10 -0400 Subject: dmaengine: tegra210-adma: convert TEGRA210_ADMA from bool to tristate This driver currently uses modular infrastructure but is controlled by a bool Kconfig. There is a general consensus from the DMA reviewers and maintainers that "if it can be modular, it should be modular" in order to keep the bzImage size under control for multi platform kernels. Build tested only. Also needed some new pm_clk symbols exported before this commit is applied to tree in order to avoid modpost errors like: ERROR: "pm_clk_add_clk" [drivers/dma/tegra210-adma.ko] undefined! ERROR: "pm_clk_create" [drivers/dma/tegra210-adma.ko] undefined! ERROR: "pm_clk_destroy" [drivers/dma/tegra210-adma.ko] undefined! ERROR: "pm_clk_suspend" [drivers/dma/tegra210-adma.ko] undefined! ERROR: "pm_clk_resume" [drivers/dma/tegra210-adma.ko] undefined! These were added as exports in the v4.8-rc1 merge window. Cc: Laxman Dewangan Cc: Jon Hunter Acked-by: Jon Hunter Cc: Dan Williams Cc: Vinod Koul Cc: Stephen Warren Cc: Thierry Reding Cc: Alexandre Courbot Cc: dmaengine@vger.kernel.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Paul Gortmaker Signed-off-by: Vinod Koul --- drivers/dma/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index af63a6bcf564..4595f5009244 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -479,7 +479,7 @@ config TEGRA20_APB_DMA or vice versa. It does not support memory to memory data transfer. config TEGRA210_ADMA - bool "NVIDIA Tegra210 ADMA support" + tristate "NVIDIA Tegra210 ADMA support" depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST) && PM_CLK select DMA_ENGINE select DMA_VIRTUAL_CHANNELS -- cgit v1.2.3 From 9a1a34f3c8612864f18a71febc134957a03eca64 Mon Sep 17 00:00:00 2001 From: Niklas Cassel Date: Mon, 24 Oct 2016 15:29:15 +0200 Subject: dmaengine: nbpfaxi: add optional max-burst property for memory reads/writes Due to a hardware bug, reading memory (from the Accelerator Coherency Port) with a burst size equal to the maximum burst size allowed by the DMA hardware's buffer size will cause a hardware hang on the ARTPEC-6 SoC, where the only solution is a manual power cycle. On ARTPEC-6, this hardware bug does not trigger when writing memory (to the Accelerator Coherency Port) with a burst size equal to the maximum burst size allowed by the DMA hardware's buffer size. To avoid this hardware hang, introduce a new optional max-burst property for memory reads. For completeness, also introduce a max-burst property for memory writes. Signed-off-by: Niklas Cassel Acked-by: Rob Herring Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/nbpfaxi.txt | 8 +++++ drivers/dma/nbpfaxi.c | 38 ++++++++++++++++++++--- 2 files changed, 42 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/dma/nbpfaxi.txt b/Documentation/devicetree/bindings/dma/nbpfaxi.txt index d5e2522b9ec1..d2e1e62e346a 100644 --- a/Documentation/devicetree/bindings/dma/nbpfaxi.txt +++ b/Documentation/devicetree/bindings/dma/nbpfaxi.txt @@ -23,6 +23,14 @@ Required properties #define NBPF_SLAVE_RQ_LEVEL 4 Optional properties: +- max-burst-mem-read: limit burst size for memory reads + (DMA_MEM_TO_MEM/DMA_MEM_TO_DEV) to this value, specified in bytes, rather + than using the maximum burst size allowed by the hardware's buffer size. +- max-burst-mem-write: limit burst size for memory writes + (DMA_DEV_TO_MEM/DMA_MEM_TO_MEM) to this value, specified in bytes, rather + than using the maximum burst size allowed by the hardware's buffer size. + If both max-burst-mem-read and max-burst-mem-write are set, DMA_MEM_TO_MEM + will use the lower value. You can use dma-channels and dma-requests as described in dma.txt, although they won't be used, this information is derived from the compatibility string. diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c index 09de71519d37..3f45b9bdf201 100644 --- a/drivers/dma/nbpfaxi.c +++ b/drivers/dma/nbpfaxi.c @@ -225,6 +225,8 @@ struct nbpf_channel { struct nbpf_device { struct dma_device dma_dev; void __iomem *base; + u32 max_burst_mem_read; + u32 max_burst_mem_write; struct clk *clk; const struct nbpf_config *config; unsigned int eirq; @@ -425,10 +427,33 @@ static void nbpf_chan_configure(struct nbpf_channel *chan) nbpf_chan_write(chan, NBPF_CHAN_CFG, NBPF_CHAN_CFG_DMS | chan->dmarq_cfg); } -static u32 nbpf_xfer_ds(struct nbpf_device *nbpf, size_t size) +static u32 nbpf_xfer_ds(struct nbpf_device *nbpf, size_t size, + enum dma_transfer_direction direction) { + int max_burst = nbpf->config->buffer_size * 8; + + if (nbpf->max_burst_mem_read || nbpf->max_burst_mem_write) { + switch (direction) { + case DMA_MEM_TO_MEM: + max_burst = min_not_zero(nbpf->max_burst_mem_read, + nbpf->max_burst_mem_write); + break; + case DMA_MEM_TO_DEV: + if (nbpf->max_burst_mem_read) + max_burst = nbpf->max_burst_mem_read; + break; + case DMA_DEV_TO_MEM: + if (nbpf->max_burst_mem_write) + max_burst = nbpf->max_burst_mem_write; + break; + case DMA_DEV_TO_DEV: + default: + break; + } + } + /* Maximum supported bursts depend on the buffer size */ - return min_t(int, __ffs(size), ilog2(nbpf->config->buffer_size * 8)); + return min_t(int, __ffs(size), ilog2(max_burst)); } static size_t nbpf_xfer_size(struct nbpf_device *nbpf, @@ -458,7 +483,7 @@ static size_t nbpf_xfer_size(struct nbpf_device *nbpf, size = burst; } - return nbpf_xfer_ds(nbpf, size); + return nbpf_xfer_ds(nbpf, size, DMA_TRANS_NONE); } /* @@ -507,7 +532,7 @@ static int nbpf_prep_one(struct nbpf_link_desc *ldesc, * transfers we enable the SBE bit and terminate the transfer in our * .device_pause handler. */ - mem_xfer = nbpf_xfer_ds(chan->nbpf, size); + mem_xfer = nbpf_xfer_ds(chan->nbpf, size, direction); switch (direction) { case DMA_DEV_TO_MEM: @@ -1313,6 +1338,11 @@ static int nbpf_probe(struct platform_device *pdev) if (IS_ERR(nbpf->clk)) return PTR_ERR(nbpf->clk); + of_property_read_u32(np, "max-burst-mem-read", + &nbpf->max_burst_mem_read); + of_property_read_u32(np, "max-burst-mem-write", + &nbpf->max_burst_mem_write); + nbpf->config = cfg; for (i = 0; irqs < ARRAY_SIZE(irqbuf); i++) { -- cgit v1.2.3 From c44da03dd517c11c2b3525937b0a241fc1c69399 Mon Sep 17 00:00:00 2001 From: Stephen Barber Date: Tue, 1 Nov 2016 16:44:27 -0700 Subject: dmaengine: pl330: Handle xferred count if DMAMOV hasn't finished After executing DMAGO it's possible that a request can come in for the current xferred count, but if that happens too soon then DMAMOV SAR/DAR may not have yet completed. If that happens, we should explicitly return 0 since nothing has been transferred yet. Signed-off-by: Stephen Barber Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 030fe05ed43b..458a712a9da1 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -2263,6 +2263,11 @@ static int pl330_get_current_xferred_count(struct dma_pl330_chan *pch, } pm_runtime_mark_last_busy(pch->dmac->ddma.dev); pm_runtime_put_autosuspend(pl330->ddma.dev); + + /* If DMAMOV hasn't finished yet, SAR/DAR can be zero */ + if (!val) + return 0; + return val - addr; } -- cgit v1.2.3 From 8cc12b26b403611175c4f1aec13abc4e383897fb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 8 Nov 2016 14:48:59 +0100 Subject: dmaengine: qcom_hidma: hide MSI handler when unused The newly added MSI support causes a harmless warning when MSI is disabled: drivers/dma/qcom/hidma.c:558:20: error: 'hidma_chirq_handler_msi' defined but not used [-Werror=unused-function] This adds another #ifdef to match that around the users of the function. Fixes: 1c0e3e82a7fb ("dmaengine: qcom_hidma: add MSI support for interrupts") Signed-off-by: Arnd Bergmann Acked-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index d5e7991ad737..10425e134e06 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -555,6 +555,7 @@ static irqreturn_t hidma_chirq_handler(int chirq, void *arg) return hidma_ll_inthandler(chirq, lldev); } +#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN static irqreturn_t hidma_chirq_handler_msi(int chirq, void *arg) { struct hidma_lldev **lldevp = arg; @@ -563,6 +564,7 @@ static irqreturn_t hidma_chirq_handler_msi(int chirq, void *arg) return hidma_ll_inthandler_msi(chirq, *lldevp, 1 << (chirq - dmadev->msi_virqbase)); } +#endif static ssize_t hidma_show_values(struct device *dev, struct device_attribute *attr, char *buf) -- cgit v1.2.3 From d46dc99507de14ad224d3ac412852b489c1934f7 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 9 Nov 2016 10:48:26 -0700 Subject: dmaengine: ioatdma: error string table missing an entry The error for DMA Transfer Source Address Error was missing. Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/dma.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 42ff3073d89d..87fd4f4b4f36 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -39,6 +39,7 @@ #include "../dmaengine.h" static char *chanerr_str[] = { + "DMA Transfer Source Address Error", "DMA Transfer Destination Address Error", "Next Descriptor Address Error", "Descriptor Error", -- cgit v1.2.3 From 7da33a37b48f11ffcb4a718f29a3d4552423fea1 Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 12 Nov 2016 14:13:03 +0100 Subject: reset: allow using reset_control_reset with shared reset Some SoCs (for example Amlogic GXBB) implement a reset controller which only supports a reset pulse (triggered via reset_control_reset). At the same time multiple devices (in case of the Amlogic GXBB SoC both USB PHYs) are sharing the same reset line. This patch allows using reset_control_reset also for shared resets. There are limitations though: reset_control_reset can only be used if reset_control_assert was not used yet. reset_control_assert can only be used if reset_control_reset was not used yet. For shared resets the reset is only triggered once for the lifetime of the reset_control instance (the reset can be triggered again if all consumers of that specific reset_control are gone, as the reset framework will free the reset_control instance in that case). Signed-off-by: Martin Blumenstingl Signed-off-by: Philipp Zabel --- drivers/reset/core.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/reset/core.c b/drivers/reset/core.c index b8ae1dbd4c17..10368ed8fd13 100644 --- a/drivers/reset/core.c +++ b/drivers/reset/core.c @@ -32,6 +32,9 @@ static LIST_HEAD(reset_controller_list); * @refcnt: Number of gets of this reset_control * @shared: Is this a shared (1), or an exclusive (0) reset_control? * @deassert_cnt: Number of times this reset line has been deasserted + * @triggered_count: Number of times this reset line has been reset. Currently + * only used for shared resets, which means that the value + * will be either 0 or 1. */ struct reset_control { struct reset_controller_dev *rcdev; @@ -40,6 +43,7 @@ struct reset_control { unsigned int refcnt; int shared; atomic_t deassert_count; + atomic_t triggered_count; }; /** @@ -134,18 +138,35 @@ EXPORT_SYMBOL_GPL(devm_reset_controller_register); * reset_control_reset - reset the controlled device * @rstc: reset controller * - * Calling this on a shared reset controller is an error. + * On a shared reset line the actual reset pulse is only triggered once for the + * lifetime of the reset_control instance: for all but the first caller this is + * a no-op. + * Consumers must not use reset_control_(de)assert on shared reset lines when + * reset_control_reset has been used. */ int reset_control_reset(struct reset_control *rstc) { - if (WARN_ON(IS_ERR_OR_NULL(rstc)) || - WARN_ON(rstc->shared)) + int ret; + + if (WARN_ON(IS_ERR_OR_NULL(rstc))) return -EINVAL; - if (rstc->rcdev->ops->reset) - return rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); + if (!rstc->rcdev->ops->reset) + return -ENOTSUPP; - return -ENOTSUPP; + if (rstc->shared) { + if (WARN_ON(atomic_read(&rstc->deassert_count) != 0)) + return -EINVAL; + + if (atomic_inc_return(&rstc->triggered_count) != 1) + return 0; + } + + ret = rstc->rcdev->ops->reset(rstc->rcdev, rstc->id); + if (rstc->shared && !ret) + atomic_dec(&rstc->triggered_count); + + return ret; } EXPORT_SYMBOL_GPL(reset_control_reset); @@ -159,6 +180,8 @@ EXPORT_SYMBOL_GPL(reset_control_reset); * * For shared reset controls a driver cannot expect the hw's registers and * internal state to be reset, but must be prepared for this to happen. + * Consumers must not use reset_control_reset on shared reset lines when + * reset_control_(de)assert has been used. */ int reset_control_assert(struct reset_control *rstc) { @@ -169,6 +192,9 @@ int reset_control_assert(struct reset_control *rstc) return -ENOTSUPP; if (rstc->shared) { + if (WARN_ON(atomic_read(&rstc->triggered_count) != 0)) + return -EINVAL; + if (WARN_ON(atomic_read(&rstc->deassert_count) == 0)) return -EINVAL; @@ -185,6 +211,8 @@ EXPORT_SYMBOL_GPL(reset_control_assert); * @rstc: reset controller * * After calling this function, the reset is guaranteed to be deasserted. + * Consumers must not use reset_control_reset on shared reset lines when + * reset_control_(de)assert has been used. */ int reset_control_deassert(struct reset_control *rstc) { @@ -195,6 +223,9 @@ int reset_control_deassert(struct reset_control *rstc) return -ENOTSUPP; if (rstc->shared) { + if (WARN_ON(atomic_read(&rstc->triggered_count) != 0)) + return -EINVAL; + if (atomic_inc_return(&rstc->deassert_count) != 1) return 0; } -- cgit v1.2.3 From 99e5cde5eae78bef95bfe7c16ccda87fb070149b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Nov 2016 16:26:03 +0100 Subject: powerpc/pci/rpadlpar: Fix device reference leaks Make sure to drop any device reference taken by vio_find_node() when adding and removing virtual I/O slots. Fixes: 5eeb8c63a38f ("[PATCH] PCI Hotplug: rpaphp: Move VIO registration") Signed-off-by: Johan Hovold Signed-off-by: Michael Ellerman --- drivers/pci/hotplug/rpadlpar_core.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index dc67f39779ec..c614ff7c3bc3 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -257,8 +257,13 @@ static int dlpar_add_phb(char *drc_name, struct device_node *dn) static int dlpar_add_vio_slot(char *drc_name, struct device_node *dn) { - if (vio_find_node(dn)) + struct vio_dev *vio_dev; + + vio_dev = vio_find_node(dn); + if (vio_dev) { + put_device(&vio_dev->dev); return -EINVAL; + } if (!vio_register_device_node(dn)) { printk(KERN_ERR @@ -334,6 +339,9 @@ static int dlpar_remove_vio_slot(char *drc_name, struct device_node *dn) return -EINVAL; vio_unregister_device(vio_dev); + + put_device(&vio_dev->dev); + return 0; } -- cgit v1.2.3 From 62a8a73923edf97cdc4997a99065045743caddf1 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 31 Oct 2016 15:45:34 +0100 Subject: memory: davinci: add support for da8xx DDR2/mDDR controller Create a new driver for the da8xx DDR2/mDDR controller and implement support for writing to the Peripheral Bus Burst Priority Register. Reviewed-by: Kevin Hilman Acked-by: Rob Herring Signed-off-by: Bartosz Golaszewski [nsekhar@ti.com: subject line adjustment] Signed-off-by: Sekhar Nori --- .../memory-controllers/ti-da8xx-ddrctl.txt | 20 +++ drivers/memory/Kconfig | 8 + drivers/memory/Makefile | 1 + drivers/memory/da8xx-ddrctl.c | 175 +++++++++++++++++++++ 4 files changed, 204 insertions(+) create mode 100644 Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt create mode 100644 drivers/memory/da8xx-ddrctl.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt new file mode 100644 index 000000000000..ec1dd408d573 --- /dev/null +++ b/Documentation/devicetree/bindings/memory-controllers/ti-da8xx-ddrctl.txt @@ -0,0 +1,20 @@ +* Device tree bindings for Texas Instruments da8xx DDR2/mDDR memory controller + +The DDR2/mDDR memory controller present on Texas Instruments da8xx SoCs features +a set of registers which allow to tweak the controller's behavior. + +Documentation: +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf + +Required properties: + +- compatible: "ti,da850-ddr-controller" - for da850 SoC based boards +- reg: a tuple containing the base address of the memory + controller and the size of the memory area to map + +Example for da850 shown below. + +ddrctl { + compatible = "ti,da850-ddr-controller"; + reg = <0xb0000000 0xe8>; +}; diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig index 4b4c0c3c3d2f..ec80e35c8dfe 100644 --- a/drivers/memory/Kconfig +++ b/drivers/memory/Kconfig @@ -134,6 +134,14 @@ config MTK_SMI mainly help enable/disable iommu and control the power domain and clocks for each local arbiter. +config DA8XX_DDRCTL + bool "Texas Instruments da8xx DDR2/mDDR driver" + depends on ARCH_DAVINCI_DA8XX + help + This driver is for the DDR2/mDDR Memory Controller present on + Texas Instruments da8xx SoCs. It's used to tweak various memory + controller configuration options. + source "drivers/memory/samsung/Kconfig" source "drivers/memory/tegra/Kconfig" diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile index b20ae38b5bfb..e88097fbc085 100644 --- a/drivers/memory/Makefile +++ b/drivers/memory/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o obj-$(CONFIG_JZ4780_NEMC) += jz4780-nemc.o obj-$(CONFIG_MTK_SMI) += mtk-smi.o +obj-$(CONFIG_DA8XX_DDRCTL) += da8xx-ddrctl.o obj-$(CONFIG_SAMSUNG_MC) += samsung/ obj-$(CONFIG_TEGRA_MC) += tegra/ diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c new file mode 100644 index 000000000000..a20e7bbbcbe0 --- /dev/null +++ b/drivers/memory/da8xx-ddrctl.c @@ -0,0 +1,175 @@ +/* + * TI da8xx DDR2/mDDR controller driver + * + * Copyright (C) 2016 BayLibre SAS + * + * Author: + * Bartosz Golaszewski + * + * 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 + +/* + * REVISIT: Linux doesn't have a good framework for the kind of performance + * knobs this driver controls. We can't use device tree properties as it deals + * with hardware configuration rather than description. We also don't want to + * commit to maintaining some random sysfs attributes. + * + * For now we just hardcode the register values for the boards that need + * some changes (as is the case for the LCD controller on da850-lcdk - the + * first board we support here). When linux gets an appropriate framework, + * we'll easily convert the driver to it. + */ + +struct da8xx_ddrctl_config_knob { + const char *name; + u32 reg; + u32 mask; + u32 shift; +}; + +static const struct da8xx_ddrctl_config_knob da8xx_ddrctl_knobs[] = { + { + .name = "da850-pbbpr", + .reg = 0x20, + .mask = 0xffffff00, + .shift = 0, + }, +}; + +struct da8xx_ddrctl_setting { + const char *name; + u32 val; +}; + +struct da8xx_ddrctl_board_settings { + const char *board; + const struct da8xx_ddrctl_setting *settings; +}; + +static const struct da8xx_ddrctl_setting da850_lcdk_ddrctl_settings[] = { + { + .name = "da850-pbbpr", + .val = 0x20, + }, + { } +}; + +static const struct da8xx_ddrctl_board_settings da8xx_ddrctl_board_confs[] = { + { + .board = "ti,da850-lcdk", + .settings = da850_lcdk_ddrctl_settings, + }, +}; + +static const struct da8xx_ddrctl_config_knob * +da8xx_ddrctl_match_knob(const struct da8xx_ddrctl_setting *setting) +{ + const struct da8xx_ddrctl_config_knob *knob; + int i; + + for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_knobs); i++) { + knob = &da8xx_ddrctl_knobs[i]; + + if (strcmp(knob->name, setting->name) == 0) + return knob; + } + + return NULL; +} + +static const struct da8xx_ddrctl_setting *da8xx_ddrctl_get_board_settings(void) +{ + const struct da8xx_ddrctl_board_settings *board_settings; + int i; + + for (i = 0; i < ARRAY_SIZE(da8xx_ddrctl_board_confs); i++) { + board_settings = &da8xx_ddrctl_board_confs[i]; + + if (of_machine_is_compatible(board_settings->board)) + return board_settings->settings; + } + + return NULL; +} + +static int da8xx_ddrctl_probe(struct platform_device *pdev) +{ + const struct da8xx_ddrctl_config_knob *knob; + const struct da8xx_ddrctl_setting *setting; + struct device_node *node; + struct resource *res; + void __iomem *ddrctl; + struct device *dev; + u32 reg; + + dev = &pdev->dev; + node = dev->of_node; + + setting = da8xx_ddrctl_get_board_settings(); + if (!setting) { + dev_err(dev, "no settings for board '%s'\n", + of_flat_dt_get_machine_name()); + return -EINVAL; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + ddrctl = devm_ioremap_resource(dev, res); + if (IS_ERR(ddrctl)) { + dev_err(dev, "unable to map memory controller registers\n"); + return PTR_ERR(ddrctl); + } + + for (; setting->name; setting++) { + knob = da8xx_ddrctl_match_knob(setting); + if (!knob) { + dev_warn(dev, + "no such config option: %s\n", setting->name); + continue; + } + + if (knob->reg + sizeof(u32) > resource_size(res)) { + dev_warn(dev, + "register offset of '%s' exceeds mapped memory size\n", + knob->name); + continue; + } + + reg = readl(ddrctl + knob->reg); + reg &= knob->mask; + reg |= setting->val << knob->shift; + + dev_dbg(dev, "writing 0x%08x to %s\n", reg, setting->name); + + writel(reg, ddrctl + knob->reg); + } + + return 0; +} + +static const struct of_device_id da8xx_ddrctl_of_match[] = { + { .compatible = "ti,da850-ddr-controller", }, + { }, +}; + +static struct platform_driver da8xx_ddrctl_driver = { + .probe = da8xx_ddrctl_probe, + .driver = { + .name = "da850-ddr-controller", + .of_match_table = da8xx_ddrctl_of_match, + }, +}; +module_platform_driver(da8xx_ddrctl_driver); + +MODULE_AUTHOR("Bartosz Golaszewski "); +MODULE_DESCRIPTION("TI da8xx DDR2/mDDR controller driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 8e7223fc8626db7c302136747bb68213100d290c Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 31 Oct 2016 15:45:35 +0100 Subject: bus: davinci: add support for da8xx bus master priority control Create the driver for the da8xx master peripheral priority configuration and implement support for writing to the three Master Priority registers on da850 SoCs. Reviewed-by: Kevin Hilman Acked-by: Rob Herring Signed-off-by: Bartosz Golaszewski [nsekhar@ti.com: subject line adjustment] Signed-off-by: Sekhar Nori --- .../devicetree/bindings/bus/ti,da850-mstpri.txt | 20 ++ drivers/bus/Kconfig | 9 + drivers/bus/Makefile | 2 + drivers/bus/da8xx-mstpri.c | 269 +++++++++++++++++++++ 4 files changed, 300 insertions(+) create mode 100644 Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt create mode 100644 drivers/bus/da8xx-mstpri.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt b/Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt new file mode 100644 index 000000000000..72daefc6b4a1 --- /dev/null +++ b/Documentation/devicetree/bindings/bus/ti,da850-mstpri.txt @@ -0,0 +1,20 @@ +* Device tree bindings for Texas Instruments da8xx master peripheral + priority driver + +DA8XX SoCs feature a set of registers allowing to change the priority of all +peripherals classified as masters. + +Documentation: +OMAP-L138 (DA850) - http://www.ti.com/lit/ug/spruh82c/spruh82c.pdf + +Required properties: + +- compatible: "ti,da850-mstpri" - for da850 based boards +- reg: offset and length of the mstpri registers + +Example for da850-lcdk is shown below. + +mstpri { + compatible = "ti,da850-mstpri"; + reg = <0x14110 0x0c>; +}; diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 7010dcac9328..ed6a89c06481 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -166,4 +166,13 @@ config VEXPRESS_CONFIG help Platform configuration infrastructure for the ARM Ltd. Versatile Express. + +config DA8XX_MSTPRI + bool "TI da8xx master peripheral priority driver" + depends on ARCH_DAVINCI_DA8XX + help + Driver for Texas Instruments da8xx master peripheral priority + configuration. Allows to adjust the priorities of all master + peripherals. + endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c6cfa6b2606e..2adb5401ff0a 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -21,3 +21,5 @@ obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o + +obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o diff --git a/drivers/bus/da8xx-mstpri.c b/drivers/bus/da8xx-mstpri.c new file mode 100644 index 000000000000..85f0b533f8e4 --- /dev/null +++ b/drivers/bus/da8xx-mstpri.c @@ -0,0 +1,269 @@ +/* + * TI da8xx master peripheral priority driver + * + * Copyright (C) 2016 BayLibre SAS + * + * Author: + * Bartosz Golaszewski + * + * 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 + +/* + * REVISIT: Linux doesn't have a good framework for the kind of performance + * knobs this driver controls. We can't use device tree properties as it deals + * with hardware configuration rather than description. We also don't want to + * commit to maintaining some random sysfs attributes. + * + * For now we just hardcode the register values for the boards that need + * some changes (as is the case for the LCD controller on da850-lcdk - the + * first board we support here). When linux gets an appropriate framework, + * we'll easily convert the driver to it. + */ + +#define DA8XX_MSTPRI0_OFFSET 0 +#define DA8XX_MSTPRI1_OFFSET 4 +#define DA8XX_MSTPRI2_OFFSET 8 + +enum { + DA8XX_MSTPRI_ARM_I = 0, + DA8XX_MSTPRI_ARM_D, + DA8XX_MSTPRI_UPP, + DA8XX_MSTPRI_SATA, + DA8XX_MSTPRI_PRU0, + DA8XX_MSTPRI_PRU1, + DA8XX_MSTPRI_EDMA30TC0, + DA8XX_MSTPRI_EDMA30TC1, + DA8XX_MSTPRI_EDMA31TC0, + DA8XX_MSTPRI_VPIF_DMA_0, + DA8XX_MSTPRI_VPIF_DMA_1, + DA8XX_MSTPRI_EMAC, + DA8XX_MSTPRI_USB0CFG, + DA8XX_MSTPRI_USB0CDMA, + DA8XX_MSTPRI_UHPI, + DA8XX_MSTPRI_USB1, + DA8XX_MSTPRI_LCDC, +}; + +struct da8xx_mstpri_descr { + int reg; + int shift; + int mask; +}; + +static const struct da8xx_mstpri_descr da8xx_mstpri_priority_list[] = { + [DA8XX_MSTPRI_ARM_I] = { + .reg = DA8XX_MSTPRI0_OFFSET, + .shift = 0, + .mask = 0x0000000f, + }, + [DA8XX_MSTPRI_ARM_D] = { + .reg = DA8XX_MSTPRI0_OFFSET, + .shift = 4, + .mask = 0x000000f0, + }, + [DA8XX_MSTPRI_UPP] = { + .reg = DA8XX_MSTPRI0_OFFSET, + .shift = 16, + .mask = 0x000f0000, + }, + [DA8XX_MSTPRI_SATA] = { + .reg = DA8XX_MSTPRI0_OFFSET, + .shift = 20, + .mask = 0x00f00000, + }, + [DA8XX_MSTPRI_PRU0] = { + .reg = DA8XX_MSTPRI1_OFFSET, + .shift = 0, + .mask = 0x0000000f, + }, + [DA8XX_MSTPRI_PRU1] = { + .reg = DA8XX_MSTPRI1_OFFSET, + .shift = 4, + .mask = 0x000000f0, + }, + [DA8XX_MSTPRI_EDMA30TC0] = { + .reg = DA8XX_MSTPRI1_OFFSET, + .shift = 8, + .mask = 0x00000f00, + }, + [DA8XX_MSTPRI_EDMA30TC1] = { + .reg = DA8XX_MSTPRI1_OFFSET, + .shift = 12, + .mask = 0x0000f000, + }, + [DA8XX_MSTPRI_EDMA31TC0] = { + .reg = DA8XX_MSTPRI1_OFFSET, + .shift = 16, + .mask = 0x000f0000, + }, + [DA8XX_MSTPRI_VPIF_DMA_0] = { + .reg = DA8XX_MSTPRI1_OFFSET, + .shift = 24, + .mask = 0x0f000000, + }, + [DA8XX_MSTPRI_VPIF_DMA_1] = { + .reg = DA8XX_MSTPRI1_OFFSET, + .shift = 28, + .mask = 0xf0000000, + }, + [DA8XX_MSTPRI_EMAC] = { + .reg = DA8XX_MSTPRI2_OFFSET, + .shift = 0, + .mask = 0x0000000f, + }, + [DA8XX_MSTPRI_USB0CFG] = { + .reg = DA8XX_MSTPRI2_OFFSET, + .shift = 8, + .mask = 0x00000f00, + }, + [DA8XX_MSTPRI_USB0CDMA] = { + .reg = DA8XX_MSTPRI2_OFFSET, + .shift = 12, + .mask = 0x0000f000, + }, + [DA8XX_MSTPRI_UHPI] = { + .reg = DA8XX_MSTPRI2_OFFSET, + .shift = 20, + .mask = 0x00f00000, + }, + [DA8XX_MSTPRI_USB1] = { + .reg = DA8XX_MSTPRI2_OFFSET, + .shift = 24, + .mask = 0x0f000000, + }, + [DA8XX_MSTPRI_LCDC] = { + .reg = DA8XX_MSTPRI2_OFFSET, + .shift = 28, + .mask = 0xf0000000, + }, +}; + +struct da8xx_mstpri_priority { + int which; + u32 val; +}; + +struct da8xx_mstpri_board_priorities { + const char *board; + const struct da8xx_mstpri_priority *priorities; + size_t numprio; +}; + +/* + * Default memory settings of da850 do not meet the throughput/latency + * requirements of tilcdc. This results in the image displayed being + * incorrect and the following warning being displayed by the LCDC + * drm driver: + * + * tilcdc da8xx_lcdc.0: tilcdc_crtc_irq(0x00000020): FIFO underfow + */ +static const struct da8xx_mstpri_priority da850_lcdk_priorities[] = { + { + .which = DA8XX_MSTPRI_LCDC, + .val = 0, + }, + { + .which = DA8XX_MSTPRI_EDMA30TC1, + .val = 0, + }, + { + .which = DA8XX_MSTPRI_EDMA30TC0, + .val = 1, + }, +}; + +static const struct da8xx_mstpri_board_priorities da8xx_mstpri_board_confs[] = { + { + .board = "ti,da850-lcdk", + .priorities = da850_lcdk_priorities, + .numprio = ARRAY_SIZE(da850_lcdk_priorities), + }, +}; + +static const struct da8xx_mstpri_board_priorities * +da8xx_mstpri_get_board_prio(void) +{ + const struct da8xx_mstpri_board_priorities *board_prio; + int i; + + for (i = 0; i < ARRAY_SIZE(da8xx_mstpri_board_confs); i++) { + board_prio = &da8xx_mstpri_board_confs[i]; + + if (of_machine_is_compatible(board_prio->board)) + return board_prio; + } + + return NULL; +} + +static int da8xx_mstpri_probe(struct platform_device *pdev) +{ + const struct da8xx_mstpri_board_priorities *prio_list; + const struct da8xx_mstpri_descr *prio_descr; + const struct da8xx_mstpri_priority *prio; + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *mstpri; + u32 reg; + int i; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + mstpri = devm_ioremap_resource(dev, res); + if (IS_ERR(mstpri)) { + dev_err(dev, "unable to map MSTPRI registers\n"); + return PTR_ERR(mstpri); + } + + prio_list = da8xx_mstpri_get_board_prio(); + if (!prio_list) { + dev_err(dev, "no master priotities defined for board '%s'\n", + of_flat_dt_get_machine_name()); + return -EINVAL; + } + + for (i = 0; i < prio_list->numprio; i++) { + prio = &prio_list->priorities[i]; + prio_descr = &da8xx_mstpri_priority_list[prio->which]; + + if (prio_descr->reg + sizeof(u32) > resource_size(res)) { + dev_warn(dev, "register offset out of range\n"); + continue; + } + + reg = readl(mstpri + prio_descr->reg); + reg &= ~prio_descr->mask; + reg |= prio->val << prio_descr->shift; + + writel(reg, mstpri + prio_descr->reg); + } + + return 0; +} + +static const struct of_device_id da8xx_mstpri_of_match[] = { + { .compatible = "ti,da850-mstpri", }, + { }, +}; + +static struct platform_driver da8xx_mstpri_driver = { + .probe = da8xx_mstpri_probe, + .driver = { + .name = "da8xx-mstpri", + .of_match_table = da8xx_mstpri_of_match, + }, +}; +module_platform_driver(da8xx_mstpri_driver); + +MODULE_AUTHOR("Bartosz Golaszewski "); +MODULE_DESCRIPTION("TI da8xx master peripheral priority driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 1a0d8dac5155de0be01dad805413ee7515177436 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 3 Nov 2016 09:04:45 +0100 Subject: iommu/exynos: Add support for page access protection bits This patch add support for page access protection bits. Till now this feature was disabled and Exynos SYSMMU always mapped pages as read/write. Now page access bits are set according to the protection bits provided in iommu_map(), so Exynos SYSMMU is able to detect incorrect access to mapped pages. Exynos SYSMMU earlier than v5 doesn't support write-only mappings, so pages with such protection bits are mapped as read/write. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 63 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 30808e91b775..e249e2f6dd3b 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -70,6 +70,36 @@ static short PG_ENT_SHIFT = -1; #define SYSMMU_PG_ENT_SHIFT 0 #define SYSMMU_V5_PG_ENT_SHIFT 4 +static const sysmmu_pte_t *LV1_PROT; +static const sysmmu_pte_t SYSMMU_LV1_PROT[] = { + ((0 << 15) | (0 << 10)), /* no access */ + ((1 << 15) | (1 << 10)), /* IOMMU_READ only */ + ((0 << 15) | (1 << 10)), /* IOMMU_WRITE not supported, use read/write */ + ((0 << 15) | (1 << 10)), /* IOMMU_READ | IOMMU_WRITE */ +}; +static const sysmmu_pte_t SYSMMU_V5_LV1_PROT[] = { + (0 << 4), /* no access */ + (1 << 4), /* IOMMU_READ only */ + (2 << 4), /* IOMMU_WRITE only */ + (3 << 4), /* IOMMU_READ | IOMMU_WRITE */ +}; + +static const sysmmu_pte_t *LV2_PROT; +static const sysmmu_pte_t SYSMMU_LV2_PROT[] = { + ((0 << 9) | (0 << 4)), /* no access */ + ((1 << 9) | (1 << 4)), /* IOMMU_READ only */ + ((0 << 9) | (1 << 4)), /* IOMMU_WRITE not supported, use read/write */ + ((0 << 9) | (1 << 4)), /* IOMMU_READ | IOMMU_WRITE */ +}; +static const sysmmu_pte_t SYSMMU_V5_LV2_PROT[] = { + (0 << 2), /* no access */ + (1 << 2), /* IOMMU_READ only */ + (2 << 2), /* IOMMU_WRITE only */ + (3 << 2), /* IOMMU_READ | IOMMU_WRITE */ +}; + +#define SYSMMU_SUPPORTED_PROT_BITS (IOMMU_READ | IOMMU_WRITE) + #define sect_to_phys(ent) (((phys_addr_t) ent) << PG_ENT_SHIFT) #define section_phys(sent) (sect_to_phys(*(sent)) & SECT_MASK) #define section_offs(iova) (iova & (SECT_SIZE - 1)) @@ -97,16 +127,17 @@ static u32 lv2ent_offset(sysmmu_iova_t iova) #define SPAGES_PER_LPAGE (LPAGE_SIZE / SPAGE_SIZE) #define lv2table_base(sent) (sect_to_phys(*(sent) & 0xFFFFFFC0)) -#define mk_lv1ent_sect(pa) ((pa >> PG_ENT_SHIFT) | 2) +#define mk_lv1ent_sect(pa, prot) ((pa >> PG_ENT_SHIFT) | LV1_PROT[prot] | 2) #define mk_lv1ent_page(pa) ((pa >> PG_ENT_SHIFT) | 1) -#define mk_lv2ent_lpage(pa) ((pa >> PG_ENT_SHIFT) | 1) -#define mk_lv2ent_spage(pa) ((pa >> PG_ENT_SHIFT) | 2) +#define mk_lv2ent_lpage(pa, prot) ((pa >> PG_ENT_SHIFT) | LV2_PROT[prot] | 1) +#define mk_lv2ent_spage(pa, prot) ((pa >> PG_ENT_SHIFT) | LV2_PROT[prot] | 2) #define CTRL_ENABLE 0x5 #define CTRL_BLOCK 0x7 #define CTRL_DISABLE 0x0 #define CFG_LRU 0x1 +#define CFG_EAP (1 << 2) #define CFG_QOS(n) ((n & 0xF) << 7) #define CFG_ACGEN (1 << 24) /* System MMU 3.3 only */ #define CFG_SYSSEL (1 << 22) /* System MMU 3.2 only */ @@ -481,6 +512,8 @@ static void __sysmmu_init_config(struct sysmmu_drvdata *data) else cfg = CFG_QOS(15) | CFG_FLPDCACHE | CFG_ACGEN; + cfg |= CFG_EAP; /* enable access protection bits check */ + writel(cfg, data->sfrbase + REG_MMU_CFG); } @@ -652,10 +685,15 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) __sysmmu_get_version(data); if (PG_ENT_SHIFT < 0) { - if (MMU_MAJ_VER(data->version) < 5) + if (MMU_MAJ_VER(data->version) < 5) { PG_ENT_SHIFT = SYSMMU_PG_ENT_SHIFT; - else + LV1_PROT = SYSMMU_LV1_PROT; + LV2_PROT = SYSMMU_LV2_PROT; + } else { PG_ENT_SHIFT = SYSMMU_V5_PG_ENT_SHIFT; + LV1_PROT = SYSMMU_V5_LV1_PROT; + LV2_PROT = SYSMMU_V5_LV2_PROT; + } } pm_runtime_enable(dev); @@ -954,7 +992,7 @@ static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain, static int lv1set_section(struct exynos_iommu_domain *domain, sysmmu_pte_t *sent, sysmmu_iova_t iova, - phys_addr_t paddr, short *pgcnt) + phys_addr_t paddr, int prot, short *pgcnt) { if (lv1ent_section(sent)) { WARN(1, "Trying mapping on 1MiB@%#08x that is mapped", @@ -973,7 +1011,7 @@ static int lv1set_section(struct exynos_iommu_domain *domain, *pgcnt = 0; } - update_pte(sent, mk_lv1ent_sect(paddr)); + update_pte(sent, mk_lv1ent_sect(paddr, prot)); spin_lock(&domain->lock); if (lv1ent_page_zero(sent)) { @@ -991,13 +1029,13 @@ static int lv1set_section(struct exynos_iommu_domain *domain, } static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size, - short *pgcnt) + int prot, short *pgcnt) { if (size == SPAGE_SIZE) { if (WARN_ON(!lv2ent_fault(pent))) return -EADDRINUSE; - update_pte(pent, mk_lv2ent_spage(paddr)); + update_pte(pent, mk_lv2ent_spage(paddr, prot)); *pgcnt -= 1; } else { /* size == LPAGE_SIZE */ int i; @@ -1013,7 +1051,7 @@ static int lv2set_page(sysmmu_pte_t *pent, phys_addr_t paddr, size_t size, return -EADDRINUSE; } - *pent = mk_lv2ent_lpage(paddr); + *pent = mk_lv2ent_lpage(paddr, prot); } dma_sync_single_for_device(dma_dev, pent_base, sizeof(*pent) * SPAGES_PER_LPAGE, @@ -1061,13 +1099,14 @@ static int exynos_iommu_map(struct iommu_domain *iommu_domain, int ret = -ENOMEM; BUG_ON(domain->pgtable == NULL); + prot &= SYSMMU_SUPPORTED_PROT_BITS; spin_lock_irqsave(&domain->pgtablelock, flags); entry = section_entry(domain->pgtable, iova); if (size == SECT_SIZE) { - ret = lv1set_section(domain, entry, iova, paddr, + ret = lv1set_section(domain, entry, iova, paddr, prot, &domain->lv2entcnt[lv1ent_offset(iova)]); } else { sysmmu_pte_t *pent; @@ -1078,7 +1117,7 @@ static int exynos_iommu_map(struct iommu_domain *iommu_domain, if (IS_ERR(pent)) ret = PTR_ERR(pent); else - ret = lv2set_page(pent, paddr, size, + ret = lv2set_page(pent, paddr, size, prot, &domain->lv2entcnt[lv1ent_offset(iova)]); } -- cgit v1.2.3 From 51f8cc9e818a9e6df376db7aeb5822d43e58cfb3 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Mon, 14 Nov 2016 12:16:26 +0000 Subject: iommu/dma: Implement dma_{map,unmap}_resource() With the new dma_{map,unmap}_resource() functions added to the DMA API for the benefit of cases like slave DMA, add suitable implementations to the arsenal of our generic layer. Since cache maintenance should not be a concern, these can both be standalone callback implementations without the need for arch code wrappers. CC: Joerg Roedel Signed-off-by: Robin Murphy Reviewed-by: Catalin Marinas Signed-off-by: Joerg Roedel --- drivers/iommu/dma-iommu.c | 24 +++++++++++++++++++++--- include/linux/dma-iommu.h | 4 ++++ 2 files changed, 25 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c index c5ab8667e6f2..2db0d641cf45 100644 --- a/drivers/iommu/dma-iommu.c +++ b/drivers/iommu/dma-iommu.c @@ -432,13 +432,12 @@ int iommu_dma_mmap(struct page **pages, size_t size, struct vm_area_struct *vma) return ret; } -dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, int prot) +static dma_addr_t __iommu_dma_map(struct device *dev, phys_addr_t phys, + size_t size, int prot) { dma_addr_t dma_addr; struct iommu_domain *domain = iommu_get_domain_for_dev(dev); struct iova_domain *iovad = cookie_iovad(domain); - phys_addr_t phys = page_to_phys(page) + offset; size_t iova_off = iova_offset(iovad, phys); size_t len = iova_align(iovad, size + iova_off); struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev)); @@ -454,6 +453,12 @@ dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, return dma_addr + iova_off; } +dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, int prot) +{ + return __iommu_dma_map(dev, page_to_phys(page) + offset, size, prot); +} + void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs) { @@ -624,6 +629,19 @@ void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, __iommu_dma_unmap(iommu_get_domain_for_dev(dev), sg_dma_address(sg)); } +dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, + size_t size, enum dma_data_direction dir, unsigned long attrs) +{ + return __iommu_dma_map(dev, phys, size, + dma_direction_to_prot(dir, false) | IOMMU_MMIO); +} + +void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir, unsigned long attrs) +{ + __iommu_dma_unmap(iommu_get_domain_for_dev(dev), handle); +} + int iommu_dma_supported(struct device *dev, u64 mask) { /* diff --git a/include/linux/dma-iommu.h b/include/linux/dma-iommu.h index 32c589062bd9..7f7e9a7e3839 100644 --- a/include/linux/dma-iommu.h +++ b/include/linux/dma-iommu.h @@ -61,6 +61,10 @@ void iommu_dma_unmap_page(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir, unsigned long attrs); void iommu_dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir, unsigned long attrs); +dma_addr_t iommu_dma_map_resource(struct device *dev, phys_addr_t phys, + size_t size, enum dma_data_direction dir, unsigned long attrs); +void iommu_dma_unmap_resource(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir, unsigned long attrs); int iommu_dma_supported(struct device *dev, u64 mask); int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); -- cgit v1.2.3 From e7689f0dc4000441cafff386c8e374a900ccb203 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 11:08:06 +0100 Subject: iommu/exynos: Remove excessive, useless debug Remove excessive, useless debug about skipping TLB invalidation, which is a normal situation when more aggressive power management is enabled. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index e249e2f6dd3b..65bf9372c890 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -611,9 +611,6 @@ static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, sysmmu_unblock(data); } clk_disable(data->clk_master); - } else { - dev_dbg(data->master, - "disabled. Skipping TLB invalidation @ %#x\n", iova); } spin_unlock_irqrestore(&data->lock, flags); } -- cgit v1.2.3 From b0d4c861a99d002d08b74ab7daf95a8674255ba5 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 11:08:07 +0100 Subject: iommu/exynos: Remove dead code __sysmmu_enable/disable functions were designed to do ref-count based operations, but current code always calls them only once, so the code for checking the conditions and invalid conditions can be simply removed without any influence to the driver operation. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 65 ++++++++++++-------------------------------- 1 file changed, 17 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 65bf9372c890..33229853c70c 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -491,9 +491,6 @@ static bool __sysmmu_disable(struct sysmmu_drvdata *data) __sysmmu_disable_nocount(data); dev_dbg(data->sysmmu, "Disabled\n"); - } else { - dev_dbg(data->sysmmu, "%d times left to disable\n", - data->activations); } spin_unlock_irqrestore(&data->lock, flags); @@ -541,29 +538,18 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) static int __sysmmu_enable(struct sysmmu_drvdata *data, phys_addr_t pgtable, struct exynos_iommu_domain *domain) { - int ret = 0; unsigned long flags; spin_lock_irqsave(&data->lock, flags); if (set_sysmmu_active(data)) { data->pgtable = pgtable; data->domain = domain; - __sysmmu_enable_nocount(data); - dev_dbg(data->sysmmu, "Enabled\n"); - } else { - ret = (pgtable == data->pgtable) ? 1 : -EBUSY; - - dev_dbg(data->sysmmu, "already enabled\n"); } - - if (WARN_ON(ret < 0)) - set_sysmmu_inactive(data); /* decrement count */ - spin_unlock_irqrestore(&data->lock, flags); - return ret; + return 0; } static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, @@ -831,8 +817,8 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) spin_lock_irqsave(&domain->lock, flags); list_for_each_entry_safe(data, next, &domain->clients, domain_node) { - if (__sysmmu_disable(data)) - data->master = NULL; + __sysmmu_disable(data); + data->master = NULL; list_del_init(&data->domain_node); } @@ -867,31 +853,23 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, phys_addr_t pagetable = virt_to_phys(domain->pgtable); struct sysmmu_drvdata *data, *next; unsigned long flags; - bool found = false; if (!has_sysmmu(dev) || owner->domain != iommu_domain) return; spin_lock_irqsave(&domain->lock, flags); list_for_each_entry_safe(data, next, &domain->clients, domain_node) { - if (data->master == dev) { - if (__sysmmu_disable(data)) { - data->master = NULL; - list_del_init(&data->domain_node); - } - pm_runtime_put(data->sysmmu); - found = true; - } + __sysmmu_disable(data); + data->master = NULL; + list_del_init(&data->domain_node); + pm_runtime_put(data->sysmmu); } spin_unlock_irqrestore(&domain->lock, flags); owner->domain = NULL; - if (found) - dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", - __func__, &pagetable); - else - dev_err(dev, "%s: No IOMMU is attached\n", __func__); + dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, + &pagetable); } static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, @@ -902,7 +880,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, struct sysmmu_drvdata *data; phys_addr_t pagetable = virt_to_phys(domain->pgtable); unsigned long flags; - int ret = -ENODEV; if (!has_sysmmu(dev)) return -ENODEV; @@ -912,27 +889,19 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, list_for_each_entry(data, &owner->controllers, owner_node) { pm_runtime_get_sync(data->sysmmu); - ret = __sysmmu_enable(data, pagetable, domain); - if (ret >= 0) { - data->master = dev; + __sysmmu_enable(data, pagetable, domain); + data->master = dev; - spin_lock_irqsave(&domain->lock, flags); - list_add_tail(&data->domain_node, &domain->clients); - spin_unlock_irqrestore(&domain->lock, flags); - } - } - - if (ret < 0) { - dev_err(dev, "%s: Failed to attach IOMMU with pgtable %pa\n", - __func__, &pagetable); - return ret; + spin_lock_irqsave(&domain->lock, flags); + list_add_tail(&data->domain_node, &domain->clients); + spin_unlock_irqrestore(&domain->lock, flags); } owner->domain = iommu_domain; - dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa %s\n", - __func__, &pagetable, (ret == 0) ? "" : ", again"); + dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__, + &pagetable); - return ret; + return 0; } static sysmmu_pte_t *alloc_lv2entry(struct exynos_iommu_domain *domain, -- cgit v1.2.3 From 47a574fffca10244b7085196e7c0d2dc34eaa6df Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 11:08:08 +0100 Subject: iommu/exynos: Simplify internal enable/disable functions Remove remaining leftovers of the ref-count related code in the __sysmmu_enable/disable functions inline __sysmmu_enable/disable_nocount to them. Suspend/resume callbacks now checks if master device is set for given SYSMMU controller instead of relying on the activation count. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 104 ++++++++++++------------------------------- 1 file changed, 29 insertions(+), 75 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 33229853c70c..45a7c6bab9b3 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -268,8 +268,8 @@ struct sysmmu_drvdata { struct clk *aclk; /* SYSMMU's aclk clock */ struct clk *pclk; /* SYSMMU's pclk clock */ struct clk *clk_master; /* master's device clock */ - int activations; /* number of calls to sysmmu_enable */ spinlock_t lock; /* lock for modyfying state */ + bool active; /* current status */ struct exynos_iommu_domain *domain; /* domain we belong to */ struct list_head domain_node; /* node for domain clients list */ struct list_head owner_node; /* node for owner controllers list */ @@ -282,25 +282,6 @@ static struct exynos_iommu_domain *to_exynos_domain(struct iommu_domain *dom) return container_of(dom, struct exynos_iommu_domain, domain); } -static bool set_sysmmu_active(struct sysmmu_drvdata *data) -{ - /* return true if the System MMU was not active previously - and it needs to be initialized */ - return ++data->activations == 1; -} - -static bool set_sysmmu_inactive(struct sysmmu_drvdata *data) -{ - /* return true if the System MMU is needed to be disabled */ - BUG_ON(data->activations < 1); - return --data->activations == 0; -} - -static bool is_sysmmu_active(struct sysmmu_drvdata *data) -{ - return data->activations > 0; -} - static void sysmmu_unblock(struct sysmmu_drvdata *data) { writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); @@ -419,7 +400,7 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) unsigned short reg_status, reg_clear; int ret = -ENOSYS; - WARN_ON(!is_sysmmu_active(data)); + WARN_ON(!data->active); if (MMU_MAJ_VER(data->version) < 5) { reg_status = REG_INT_STATUS; @@ -465,37 +446,19 @@ static irqreturn_t exynos_sysmmu_irq(int irq, void *dev_id) return IRQ_HANDLED; } -static void __sysmmu_disable_nocount(struct sysmmu_drvdata *data) +static void __sysmmu_disable(struct sysmmu_drvdata *data) { + unsigned long flags; + clk_enable(data->clk_master); + spin_lock_irqsave(&data->lock, flags); writel(CTRL_DISABLE, data->sfrbase + REG_MMU_CTRL); writel(0, data->sfrbase + REG_MMU_CFG); - - __sysmmu_disable_clocks(data); -} - -static bool __sysmmu_disable(struct sysmmu_drvdata *data) -{ - bool disabled; - unsigned long flags; - - spin_lock_irqsave(&data->lock, flags); - - disabled = set_sysmmu_inactive(data); - - if (disabled) { - data->pgtable = 0; - data->domain = NULL; - - __sysmmu_disable_nocount(data); - - dev_dbg(data->sysmmu, "Disabled\n"); - } - + data->active = false; spin_unlock_irqrestore(&data->lock, flags); - return disabled; + __sysmmu_disable_clocks(data); } static void __sysmmu_init_config(struct sysmmu_drvdata *data) @@ -514,17 +477,19 @@ static void __sysmmu_init_config(struct sysmmu_drvdata *data) writel(cfg, data->sfrbase + REG_MMU_CFG); } -static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) +static void __sysmmu_enable(struct sysmmu_drvdata *data) { + unsigned long flags; + __sysmmu_enable_clocks(data); + spin_lock_irqsave(&data->lock, flags); writel(CTRL_BLOCK, data->sfrbase + REG_MMU_CTRL); - __sysmmu_init_config(data); - __sysmmu_set_ptbase(data, data->pgtable); - writel(CTRL_ENABLE, data->sfrbase + REG_MMU_CTRL); + data->active = true; + spin_unlock_irqrestore(&data->lock, flags); /* * SYSMMU driver keeps master's clock enabled only for the short @@ -535,37 +500,18 @@ static void __sysmmu_enable_nocount(struct sysmmu_drvdata *data) clk_disable(data->clk_master); } -static int __sysmmu_enable(struct sysmmu_drvdata *data, phys_addr_t pgtable, - struct exynos_iommu_domain *domain) -{ - unsigned long flags; - - spin_lock_irqsave(&data->lock, flags); - if (set_sysmmu_active(data)) { - data->pgtable = pgtable; - data->domain = domain; - __sysmmu_enable_nocount(data); - dev_dbg(data->sysmmu, "Enabled\n"); - } - spin_unlock_irqrestore(&data->lock, flags); - - return 0; -} - static void sysmmu_tlb_invalidate_flpdcache(struct sysmmu_drvdata *data, sysmmu_iova_t iova) { unsigned long flags; - spin_lock_irqsave(&data->lock, flags); - if (is_sysmmu_active(data) && data->version >= MAKE_MMU_VER(3, 3)) { + if (data->active && data->version >= MAKE_MMU_VER(3, 3)) { clk_enable(data->clk_master); __sysmmu_tlb_invalidate_entry(data, iova, 1); clk_disable(data->clk_master); } spin_unlock_irqrestore(&data->lock, flags); - } static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, @@ -574,7 +520,7 @@ static void sysmmu_tlb_invalidate_entry(struct sysmmu_drvdata *data, unsigned long flags; spin_lock_irqsave(&data->lock, flags); - if (is_sysmmu_active(data)) { + if (data->active) { unsigned int num_inv = 1; clk_enable(data->clk_master); @@ -690,10 +636,11 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) static int exynos_sysmmu_suspend(struct device *dev) { struct sysmmu_drvdata *data = dev_get_drvdata(dev); + struct device *master = data->master; dev_dbg(dev, "suspend\n"); - if (is_sysmmu_active(data)) { - __sysmmu_disable_nocount(data); + if (master) { + __sysmmu_disable(data); pm_runtime_put(dev); } return 0; @@ -702,11 +649,12 @@ static int exynos_sysmmu_suspend(struct device *dev) static int exynos_sysmmu_resume(struct device *dev) { struct sysmmu_drvdata *data = dev_get_drvdata(dev); + struct device *master = data->master; dev_dbg(dev, "resume\n"); - if (is_sysmmu_active(data)) { + if (master) { pm_runtime_get_sync(dev); - __sysmmu_enable_nocount(data); + __sysmmu_enable(data); } return 0; } @@ -818,6 +766,8 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) list_for_each_entry_safe(data, next, &domain->clients, domain_node) { __sysmmu_disable(data); + data->pgtable = 0; + data->domain = NULL; data->master = NULL; list_del_init(&data->domain_node); } @@ -861,6 +811,8 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, list_for_each_entry_safe(data, next, &domain->clients, domain_node) { __sysmmu_disable(data); data->master = NULL; + data->pgtable = 0; + data->domain = NULL; list_del_init(&data->domain_node); pm_runtime_put(data->sysmmu); } @@ -888,8 +840,10 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, exynos_iommu_detach_device(owner->domain, dev); list_for_each_entry(data, &owner->controllers, owner_node) { + data->pgtable = pagetable; + data->domain = domain; pm_runtime_get_sync(data->sysmmu); - __sysmmu_enable(data, pagetable, domain); + __sysmmu_enable(data); data->master = dev; spin_lock_irqsave(&domain->lock, flags); -- cgit v1.2.3 From 92798b4566b1adcf2e259b3116c38553fe655852 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 11:08:09 +0100 Subject: iommu/exynos: Set master device once on boot To avoid possible races, set master device pointer in each SYSMMU controller once on boot. Suspend/resume callbacks now properly relies on the configured iommu domain to enable or disable SYSMMU controller. While changing the code, also update the sleep debug messages and make them conditional. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 45a7c6bab9b3..52ded8461a74 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -638,10 +638,12 @@ static int exynos_sysmmu_suspend(struct device *dev) struct sysmmu_drvdata *data = dev_get_drvdata(dev); struct device *master = data->master; - dev_dbg(dev, "suspend\n"); if (master) { - __sysmmu_disable(data); pm_runtime_put(dev); + if (data->domain) { + dev_dbg(data->sysmmu, "saving state\n"); + __sysmmu_disable(data); + } } return 0; } @@ -651,10 +653,12 @@ static int exynos_sysmmu_resume(struct device *dev) struct sysmmu_drvdata *data = dev_get_drvdata(dev); struct device *master = data->master; - dev_dbg(dev, "resume\n"); if (master) { pm_runtime_get_sync(dev); - __sysmmu_enable(data); + if (data->domain) { + dev_dbg(data->sysmmu, "restoring state\n"); + __sysmmu_enable(data); + } } return 0; } @@ -768,7 +772,6 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) __sysmmu_disable(data); data->pgtable = 0; data->domain = NULL; - data->master = NULL; list_del_init(&data->domain_node); } @@ -810,7 +813,6 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, spin_lock_irqsave(&domain->lock, flags); list_for_each_entry_safe(data, next, &domain->clients, domain_node) { __sysmmu_disable(data); - data->master = NULL; data->pgtable = 0; data->domain = NULL; list_del_init(&data->domain_node); @@ -844,7 +846,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, data->domain = domain; pm_runtime_get_sync(data->sysmmu); __sysmmu_enable(data); - data->master = dev; spin_lock_irqsave(&domain->lock, flags); list_add_tail(&data->domain_node, &domain->clients); @@ -1231,6 +1232,7 @@ static int exynos_iommu_of_xlate(struct device *dev, } list_add_tail(&data->owner_node, &owner->controllers); + data->master = dev; return 0; } -- cgit v1.2.3 From e11723000f16419f9b0f69f15d99cf7ab37edc24 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 11:08:10 +0100 Subject: iommu/exynos: Rework and fix internal locking This patch reworks locking in the exynos_iommu_attach/detach_device functions to ensure that all entries of the sysmmu_drvdata and exynos_iommu_owner structure are updated under the respective spinlocks, while runtime pm functions are called without any spinlocks held. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 52ded8461a74..0423dff206d4 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -769,10 +769,12 @@ static void exynos_iommu_domain_free(struct iommu_domain *iommu_domain) spin_lock_irqsave(&domain->lock, flags); list_for_each_entry_safe(data, next, &domain->clients, domain_node) { + spin_lock(&data->lock); __sysmmu_disable(data); data->pgtable = 0; data->domain = NULL; list_del_init(&data->domain_node); + spin_unlock(&data->lock); } spin_unlock_irqrestore(&domain->lock, flags); @@ -810,17 +812,22 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, if (!has_sysmmu(dev) || owner->domain != iommu_domain) return; + list_for_each_entry(data, &owner->controllers, owner_node) { + __sysmmu_disable(data); + pm_runtime_put(data->sysmmu); + } + spin_lock_irqsave(&domain->lock, flags); list_for_each_entry_safe(data, next, &domain->clients, domain_node) { - __sysmmu_disable(data); + spin_lock(&data->lock); data->pgtable = 0; data->domain = NULL; list_del_init(&data->domain_node); - pm_runtime_put(data->sysmmu); + spin_unlock(&data->lock); } + owner->domain = NULL; spin_unlock_irqrestore(&domain->lock, flags); - owner->domain = NULL; dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, &pagetable); @@ -841,18 +848,22 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, if (owner->domain) exynos_iommu_detach_device(owner->domain, dev); + spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(data, &owner->controllers, owner_node) { + spin_lock(&data->lock); data->pgtable = pagetable; data->domain = domain; + list_add_tail(&data->domain_node, &domain->clients); + spin_unlock(&data->lock); + } + owner->domain = iommu_domain; + spin_unlock_irqrestore(&domain->lock, flags); + + list_for_each_entry(data, &owner->controllers, owner_node) { pm_runtime_get_sync(data->sysmmu); __sysmmu_enable(data); - - spin_lock_irqsave(&domain->lock, flags); - list_add_tail(&data->domain_node, &domain->clients); - spin_unlock_irqrestore(&domain->lock, flags); } - owner->domain = iommu_domain; dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__, &pagetable); -- cgit v1.2.3 From 9b265536c271163ec4acc140ca0a40a732971cbf Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 11:08:11 +0100 Subject: iommu/exynos: Add runtime pm support This patch adds runtime pm implementation, which is based on previous suspend/resume code. SYSMMU controller is now being enabled/disabled mainly from the runtime pm callbacks. System sleep callbacks relies on generic pm_runtime_force_suspend/pm_runtime_force_resume helpers. To ensure internal state consistency, additional lock for runtime pm transitions was introduced. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 45 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 0423dff206d4..22bc7e5c4dcc 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -237,6 +237,7 @@ static const struct sysmmu_fault_info sysmmu_v5_faults[] = { struct exynos_iommu_owner { struct list_head controllers; /* list of sysmmu_drvdata.owner_node */ struct iommu_domain *domain; /* domain this device is attached */ + struct mutex rpm_lock; /* for runtime pm of all sysmmus */ }; /* @@ -632,40 +633,46 @@ static int __init exynos_sysmmu_probe(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP -static int exynos_sysmmu_suspend(struct device *dev) +static int __maybe_unused exynos_sysmmu_suspend(struct device *dev) { struct sysmmu_drvdata *data = dev_get_drvdata(dev); struct device *master = data->master; if (master) { - pm_runtime_put(dev); + struct exynos_iommu_owner *owner = master->archdata.iommu; + + mutex_lock(&owner->rpm_lock); if (data->domain) { dev_dbg(data->sysmmu, "saving state\n"); __sysmmu_disable(data); } + mutex_unlock(&owner->rpm_lock); } return 0; } -static int exynos_sysmmu_resume(struct device *dev) +static int __maybe_unused exynos_sysmmu_resume(struct device *dev) { struct sysmmu_drvdata *data = dev_get_drvdata(dev); struct device *master = data->master; if (master) { - pm_runtime_get_sync(dev); + struct exynos_iommu_owner *owner = master->archdata.iommu; + + mutex_lock(&owner->rpm_lock); if (data->domain) { dev_dbg(data->sysmmu, "restoring state\n"); __sysmmu_enable(data); } + mutex_unlock(&owner->rpm_lock); } return 0; } -#endif static const struct dev_pm_ops sysmmu_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(exynos_sysmmu_suspend, exynos_sysmmu_resume) + SET_RUNTIME_PM_OPS(exynos_sysmmu_suspend, exynos_sysmmu_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static const struct of_device_id sysmmu_of_match[] __initconst = { @@ -813,7 +820,15 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, return; list_for_each_entry(data, &owner->controllers, owner_node) { - __sysmmu_disable(data); + pm_runtime_put_sync(data->sysmmu); + } + + mutex_lock(&owner->rpm_lock); + + list_for_each_entry(data, &owner->controllers, owner_node) { + pm_runtime_get_noresume(data->sysmmu); + if (pm_runtime_active(data->sysmmu)) + __sysmmu_disable(data); pm_runtime_put(data->sysmmu); } @@ -828,6 +843,7 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, owner->domain = NULL; spin_unlock_irqrestore(&domain->lock, flags); + mutex_unlock(&owner->rpm_lock); dev_dbg(dev, "%s: Detached IOMMU with pgtable %pa\n", __func__, &pagetable); @@ -848,6 +864,8 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, if (owner->domain) exynos_iommu_detach_device(owner->domain, dev); + mutex_lock(&owner->rpm_lock); + spin_lock_irqsave(&domain->lock, flags); list_for_each_entry(data, &owner->controllers, owner_node) { spin_lock(&data->lock); @@ -859,9 +877,17 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, owner->domain = iommu_domain; spin_unlock_irqrestore(&domain->lock, flags); + list_for_each_entry(data, &owner->controllers, owner_node) { + pm_runtime_get_noresume(data->sysmmu); + if (pm_runtime_active(data->sysmmu)) + __sysmmu_enable(data); + pm_runtime_put(data->sysmmu); + } + + mutex_unlock(&owner->rpm_lock); + list_for_each_entry(data, &owner->controllers, owner_node) { pm_runtime_get_sync(data->sysmmu); - __sysmmu_enable(data); } dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__, @@ -1239,6 +1265,7 @@ static int exynos_iommu_of_xlate(struct device *dev, return -ENOMEM; INIT_LIST_HEAD(&owner->controllers); + mutex_init(&owner->rpm_lock); dev->archdata.iommu = owner; } -- cgit v1.2.3 From 2f5f44f205cc958bcd881ee21e4844fae83b0364 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 11:08:12 +0100 Subject: iommu/exynos: Use device dependency links to control runtime pm This patch uses recently introduced device dependency links to track the runtime pm state of the master's device. The goal is to let SYSMMU controller device's runtime PM to follow the runtime PM state of the respective master's device. This way each SYSMMU controller is active only when its master's device is active and can properly restore or save its state instead on runtime PM transition of master's device. This approach replaces old behavior, when SYSMMU controller was set to runtime active once after attaching to the master device. In the new approach SYSMMU controllers no longer prevents respective power domains to be turned off when master's device is not being used. This patch reduces total power consumption of idle system, because most power domains can be finally turned off. For example, on Exynos 4412 based Odroid U3 this patch reduces power consuption from 136mA to 130mA at 5V (by 4.4%). The dependency links also enforce proper order of suspending/restoring devices during system sleep transition, so there is no more need to use LATE_SYSTEM_SLEEP_PM_OPS-based workaround for ensuring that SYSMMUs are suspended after their master devices. Signed-off-by: Marek Szyprowski Signed-off-by: Joerg Roedel --- drivers/iommu/exynos-iommu.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c index 22bc7e5c4dcc..57ba0d3091ea 100644 --- a/drivers/iommu/exynos-iommu.c +++ b/drivers/iommu/exynos-iommu.c @@ -671,8 +671,8 @@ static int __maybe_unused exynos_sysmmu_resume(struct device *dev) static const struct dev_pm_ops sysmmu_pm_ops = { SET_RUNTIME_PM_OPS(exynos_sysmmu_suspend, exynos_sysmmu_resume, NULL) - SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static const struct of_device_id sysmmu_of_match[] __initconst = { @@ -819,10 +819,6 @@ static void exynos_iommu_detach_device(struct iommu_domain *iommu_domain, if (!has_sysmmu(dev) || owner->domain != iommu_domain) return; - list_for_each_entry(data, &owner->controllers, owner_node) { - pm_runtime_put_sync(data->sysmmu); - } - mutex_lock(&owner->rpm_lock); list_for_each_entry(data, &owner->controllers, owner_node) { @@ -886,10 +882,6 @@ static int exynos_iommu_attach_device(struct iommu_domain *iommu_domain, mutex_unlock(&owner->rpm_lock); - list_for_each_entry(data, &owner->controllers, owner_node) { - pm_runtime_get_sync(data->sysmmu); - } - dev_dbg(dev, "%s: Attached IOMMU with pgtable %pa\n", __func__, &pagetable); @@ -1271,6 +1263,14 @@ static int exynos_iommu_of_xlate(struct device *dev, list_add_tail(&data->owner_node, &owner->controllers); data->master = dev; + + /* + * SYSMMU will be runtime activated via device link (dependency) to its + * master device, so there are no direct calls to pm_runtime_get/put + * in this driver. + */ + device_link_add(dev, data->sysmmu, DL_FLAG_PM_RUNTIME); + return 0; } -- cgit v1.2.3 From 9a1dc3891255afd836f355b117fd6b975d0b1eb2 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Mon, 14 Nov 2016 15:21:14 -0600 Subject: of/pci: Add of_pci_get_max_link_speed() to parse max-link-speed from DT This new helper function could be used by host drivers to get the limitaion of max link speed provided by DT. If the property isn't assigned or is invalid, it will return -EINVAL to the caller. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas Acked-by: Rob Herring --- drivers/of/of_pci.c | 21 +++++++++++++++++++++ include/linux/of_pci.h | 7 +++++++ 2 files changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c index b58be12ab277..0ee42c3e66a1 100644 --- a/drivers/of/of_pci.c +++ b/drivers/of/of_pci.c @@ -119,6 +119,27 @@ int of_get_pci_domain_nr(struct device_node *node) } EXPORT_SYMBOL_GPL(of_get_pci_domain_nr); +/** + * This function will try to find the limitation of link speed by finding + * a property called "max-link-speed" of the given device node. + * + * @node: device tree node with the max link speed information + * + * Returns the associated max link speed from DT, or a negative value if the + * required property is not found or is invalid. + */ +int of_pci_get_max_link_speed(struct device_node *node) +{ + u32 max_link_speed; + + if (of_property_read_u32(node, "max-link-speed", &max_link_speed) || + max_link_speed > 4) + return -EINVAL; + + return max_link_speed; +} +EXPORT_SYMBOL_GPL(of_pci_get_max_link_speed); + /** * of_pci_check_probe_only - Setup probe only mode if linux,pci-probe-only * is present and valid diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h index 7fd5cfce9140..0e0974eceb80 100644 --- a/include/linux/of_pci.h +++ b/include/linux/of_pci.h @@ -16,6 +16,7 @@ int of_pci_get_devfn(struct device_node *np); int of_irq_parse_and_map_pci(const struct pci_dev *dev, u8 slot, u8 pin); int of_pci_parse_bus_range(struct device_node *node, struct resource *res); int of_get_pci_domain_nr(struct device_node *node); +int of_pci_get_max_link_speed(struct device_node *node); void of_pci_check_probe_only(void); int of_pci_map_rid(struct device_node *np, u32 rid, const char *map_name, const char *map_mask_name, @@ -62,6 +63,12 @@ static inline int of_pci_map_rid(struct device_node *np, u32 rid, return -EINVAL; } +static inline int +of_pci_get_max_link_speed(struct device_node *node) +{ + return -EINVAL; +} + static inline void of_pci_check_probe_only(void) { } #endif -- cgit v1.2.3 From fc4f57fadea906648a4ccae4c3ff4bfd7f277649 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 29 Oct 2016 21:37:07 +0200 Subject: PCI/ASPM: Use permission-specific DEVICE_ATTR variants Use DEVICE_ATTR_RW for read-write attributes. This simplifies the source code, improves readability, and reduces the chance of inconsistencies. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @rw@ declarer name DEVICE_ATTR; identifier x,x_show,x_store; @@ DEVICE_ATTR(x, \(0644\|S_IRUGO|S_IWUSR\), x_show, x_store); @script:ocaml@ x << rw.x; x_show << rw.x_show; x_store << rw.x_store; @@ if not (x^"_show" = x_show && x^"_store" = x_store) then Coccilib.include_match false @@ declarer name DEVICE_ATTR_RW; identifier rw.x,rw.x_show,rw.x_store; @@ - DEVICE_ATTR(x, \(0644\|S_IRUGO|S_IWUSR\), x_show, x_store); + DEVICE_ATTR_RW(x); // Signed-off-by: Julia Lawall Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 0ec649d961d7..3b14d9e85dee 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -886,8 +886,8 @@ static ssize_t clk_ctl_store(struct device *dev, return n; } -static DEVICE_ATTR(link_state, 0644, link_state_show, link_state_store); -static DEVICE_ATTR(clk_ctl, 0644, clk_ctl_show, clk_ctl_store); +static DEVICE_ATTR_RW(link_state); +static DEVICE_ATTR_RW(clk_ctl); static char power_group[] = "power"; void pcie_aspm_create_sysfs_dev_files(struct pci_dev *pdev) -- cgit v1.2.3 From 06324ede76cdf895b3b0bf590775d746a61c7668 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:30 -0700 Subject: PCI: iproc: Improve core register population As the number of iProc PCIe core registers starts to grow and differ between different revisions of the iProc PCIe controllers, the current way of populating each individual unsupported register with value 'IPROC_PCIE_REG_INVALID' with a table entry has become a bit messy and is difficult to scale up in the future. Improve the current driver by populating the invalid entries with code instead of through individual table entries. This helps to avoid a significant number of invalid table entries when support for the next revision of the iProc controller is added. Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc.c | 83 +++++++++++++++++++++++++++++++------------ drivers/pci/host/pcie-iproc.h | 4 ++- 2 files changed, 64 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 0b999a9fb843..a9b9cd8631f4 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -69,18 +69,35 @@ #define IPROC_PCIE_REG_INVALID 0xffff +/* + * iProc PCIe host registers + */ enum iproc_pcie_reg { + /* clock/reset signal control */ IPROC_PCIE_CLK_CTRL = 0, + + /* allow access to root complex configuration space */ IPROC_PCIE_CFG_IND_ADDR, IPROC_PCIE_CFG_IND_DATA, + + /* allow access to device configuration space */ IPROC_PCIE_CFG_ADDR, IPROC_PCIE_CFG_DATA, + + /* enable INTx */ IPROC_PCIE_INTX_EN, + + /* outbound address mapping */ IPROC_PCIE_OARR_LO, IPROC_PCIE_OARR_HI, IPROC_PCIE_OMAP_LO, IPROC_PCIE_OMAP_HI, + + /* link status */ IPROC_PCIE_LINK_STATUS, + + /* total number of core registers */ + IPROC_PCIE_MAX_NUM_REG, }; /* iProc PCIe PAXB registers */ @@ -105,12 +122,6 @@ static const u16 iproc_pcie_reg_paxc[] = { [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, [IPROC_PCIE_CFG_ADDR] = 0x1f8, [IPROC_PCIE_CFG_DATA] = 0x1fc, - [IPROC_PCIE_INTX_EN] = IPROC_PCIE_REG_INVALID, - [IPROC_PCIE_OARR_LO] = IPROC_PCIE_REG_INVALID, - [IPROC_PCIE_OARR_HI] = IPROC_PCIE_REG_INVALID, - [IPROC_PCIE_OMAP_LO] = IPROC_PCIE_REG_INVALID, - [IPROC_PCIE_OMAP_HI] = IPROC_PCIE_REG_INVALID, - [IPROC_PCIE_LINK_STATUS] = IPROC_PCIE_REG_INVALID, }; static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) @@ -204,7 +215,7 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus, * PAXC is connected to an internally emulated EP within the SoC. It * allows only one device. */ - if (pcie->type == IPROC_PCIE_PAXC) + if (pcie->ep_is_internal) if (slot > 0) return NULL; @@ -232,7 +243,7 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie) { u32 val; - if (pcie->type == IPROC_PCIE_PAXC) { + if (pcie->ep_is_internal) { val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); val &= ~PAXC_RESET_MASK; iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); @@ -270,7 +281,7 @@ static int iproc_pcie_check_link(struct iproc_pcie *pcie, struct pci_bus *bus) * PAXC connects to emulated endpoint devices directly and does not * have a Serdes. Therefore skip the link detection logic here. */ - if (pcie->type == IPROC_PCIE_PAXC) + if (pcie->ep_is_internal) return 0; val = iproc_pcie_read_reg(pcie, IPROC_PCIE_LINK_STATUS); @@ -454,6 +465,40 @@ static void iproc_pcie_msi_disable(struct iproc_pcie *pcie) iproc_msi_exit(pcie); } +static int iproc_pcie_rev_init(struct iproc_pcie *pcie) +{ + struct device *dev = pcie->dev; + unsigned int reg_idx; + const u16 *regs; + + switch (pcie->type) { + case IPROC_PCIE_PAXB: + regs = iproc_pcie_reg_paxb; + break; + case IPROC_PCIE_PAXC: + regs = iproc_pcie_reg_paxc; + pcie->ep_is_internal = true; + break; + default: + dev_err(dev, "incompatible iProc PCIe interface\n"); + return -EINVAL; + } + + pcie->reg_offsets = devm_kcalloc(dev, IPROC_PCIE_MAX_NUM_REG, + sizeof(*pcie->reg_offsets), + GFP_KERNEL); + if (!pcie->reg_offsets) + return -ENOMEM; + + /* go through the register table and populate all valid registers */ + pcie->reg_offsets[0] = regs[0]; + for (reg_idx = 1; reg_idx < IPROC_PCIE_MAX_NUM_REG; reg_idx++) + pcie->reg_offsets[reg_idx] = regs[reg_idx] ? + regs[reg_idx] : IPROC_PCIE_REG_INVALID; + + return 0; +} + int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) { struct device *dev; @@ -462,6 +507,13 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) struct pci_bus *bus; dev = pcie->dev; + + ret = iproc_pcie_rev_init(pcie); + if (ret) { + dev_err(dev, "unable to initialize controller parameters\n"); + return ret; + } + ret = devm_request_pci_bus_resources(dev, res); if (ret) return ret; @@ -478,19 +530,6 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) goto err_exit_phy; } - switch (pcie->type) { - case IPROC_PCIE_PAXB: - pcie->reg_offsets = iproc_pcie_reg_paxb; - break; - case IPROC_PCIE_PAXC: - pcie->reg_offsets = iproc_pcie_reg_paxc; - break; - default: - dev_err(dev, "incompatible iProc PCIe interface\n"); - ret = -EINVAL; - goto err_power_off_phy; - } - iproc_pcie_reset(pcie); if (pcie->need_ob_cfg) { diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index e84d93c53c7b..83643d55383d 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -55,6 +55,7 @@ struct iproc_msi; * @root_bus: pointer to root bus * @phy: optional PHY device that controls the Serdes * @map_irq: function callback to map interrupts + * @ep_is_internal: indicates an internal emulated endpoint device is connected * @need_ob_cfg: indicates SW needs to configure the outbound mapping window * @ob: outbound mapping parameters * @msi: MSI data @@ -62,7 +63,7 @@ struct iproc_msi; struct iproc_pcie { struct device *dev; enum iproc_pcie_type type; - const u16 *reg_offsets; + u16 *reg_offsets; void __iomem *base; phys_addr_t base_addr; #ifdef CONFIG_ARM @@ -71,6 +72,7 @@ struct iproc_pcie { struct pci_bus *root_bus; struct phy *phy; int (*map_irq)(const struct pci_dev *, u8, u8); + bool ep_is_internal; bool need_ob_cfg; struct iproc_pcie_ob ob; struct iproc_msi *msi; -- cgit v1.2.3 From 7cbd50d275fe4f6a31f536e140b6124f68998c61 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:31 -0700 Subject: PCI: iproc: Do not reset PAXC when initializing the driver During initialization, the current iProc PCIe host driver resets PAXC and the downstream internal endpoint device that PAXC connects to. If the endpoint device is already loaded with firmware and has started running from the bootloader stage, this downstream reset causes the endpoint device to stop working. Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index a9b9cd8631f4..93b4d619c0ed 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -243,16 +243,13 @@ static void iproc_pcie_reset(struct iproc_pcie *pcie) { u32 val; - if (pcie->ep_is_internal) { - val = iproc_pcie_read_reg(pcie, IPROC_PCIE_CLK_CTRL); - val &= ~PAXC_RESET_MASK; - iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); - udelay(100); - val |= PAXC_RESET_MASK; - iproc_pcie_write_reg(pcie, IPROC_PCIE_CLK_CTRL, val); - udelay(100); + /* + * PAXC and the internal emulated endpoint device downstream should not + * be reset. If firmware has been loaded on the endpoint device at an + * earlier boot stage, reset here causes issues. + */ + if (pcie->ep_is_internal) return; - } /* * Select perst_b signal as reset source. Put the device into reset, -- cgit v1.2.3 From 404349c5c806d56de2b41f48a99402c3c7573af5 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:32 -0700 Subject: PCI: iproc: Add BCMA type The iProc PCIe driver is currently using type IPROC_PCIE_PAXB for the following SoCs: NS, NSP, Cygnus, NS2, and Pegasus. In fact, the BCMA-based NS uses a legacy PAXB controller that is slightly different from the PAXB controller used in the rest of SoCs, e.g., some registers are missing and it does not require software configuration of outbound/inbound address mapping. Add a new type, IPROC_PCIE_PAXB_BCMA, to allow us to properly support the BCMA-based NS along with other iProc-based SoCs going forward. Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc-bcma.c | 1 + drivers/pci/host/pcie-iproc-msi.c | 1 + drivers/pci/host/pcie-iproc.c | 14 ++++++++++++++ drivers/pci/host/pcie-iproc.h | 3 ++- 4 files changed, 18 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc-bcma.c b/drivers/pci/host/pcie-iproc-bcma.c index 8ce089043a27..bd4c9ec25edc 100644 --- a/drivers/pci/host/pcie-iproc-bcma.c +++ b/drivers/pci/host/pcie-iproc-bcma.c @@ -54,6 +54,7 @@ static int iproc_pcie_bcma_probe(struct bcma_device *bdev) pcie->dev = dev; + pcie->type = IPROC_PCIE_PAXB_BCMA; pcie->base = bdev->io_addr; if (!pcie->base) { dev_err(dev, "no controller registers\n"); diff --git a/drivers/pci/host/pcie-iproc-msi.c b/drivers/pci/host/pcie-iproc-msi.c index 9a2973bdc78a..9fad7915f82a 100644 --- a/drivers/pci/host/pcie-iproc-msi.c +++ b/drivers/pci/host/pcie-iproc-msi.c @@ -563,6 +563,7 @@ int iproc_msi_init(struct iproc_pcie *pcie, struct device_node *node) } switch (pcie->type) { + case IPROC_PCIE_PAXB_BCMA: case IPROC_PCIE_PAXB: msi->reg_offsets = iproc_msi_reg_paxb; msi->nr_eq_region = 1; diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 93b4d619c0ed..912a1cbe561e 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -100,6 +100,17 @@ enum iproc_pcie_reg { IPROC_PCIE_MAX_NUM_REG, }; +/* iProc PCIe PAXB BCMA registers */ +static const u16 iproc_pcie_reg_paxb_bcma[] = { + [IPROC_PCIE_CLK_CTRL] = 0x000, + [IPROC_PCIE_CFG_IND_ADDR] = 0x120, + [IPROC_PCIE_CFG_IND_DATA] = 0x124, + [IPROC_PCIE_CFG_ADDR] = 0x1f8, + [IPROC_PCIE_CFG_DATA] = 0x1fc, + [IPROC_PCIE_INTX_EN] = 0x330, + [IPROC_PCIE_LINK_STATUS] = 0xf0c, +}; + /* iProc PCIe PAXB registers */ static const u16 iproc_pcie_reg_paxb[] = { [IPROC_PCIE_CLK_CTRL] = 0x000, @@ -469,6 +480,9 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) const u16 *regs; switch (pcie->type) { + case IPROC_PCIE_PAXB_BCMA: + regs = iproc_pcie_reg_paxb_bcma; + break; case IPROC_PCIE_PAXB: regs = iproc_pcie_reg_paxb; break; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 83643d55383d..768be05cf496 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -24,7 +24,8 @@ * endpoint devices. */ enum iproc_pcie_type { - IPROC_PCIE_PAXB = 0, + IPROC_PCIE_PAXB_BCMA = 0, + IPROC_PCIE_PAXB, IPROC_PCIE_PAXC, }; -- cgit v1.2.3 From 538928fd6ce8e0342d98a203a1d16caf2ce33f2b Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:33 -0700 Subject: PCI: iproc: Fix exception with multi-function devices During enumeration with multi-function EP devices, access to the configuration space of a non-existent function results in an unsupported request being returned as expected. By default the PAXB-based iProc PCIe controller forwards this as an APB error to the host system and that causes an exception, which is undesired. Disable this undesired behaviour and let the kernel PCI stack deal with an access to the non-existent function, in which case a vendor ID of 0xffff is returned and handled gracefully. Reported-by: JD Zheng Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: JD Zheng Reviewed-by: Oza Oza Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc.c | 58 +++++++++++++++++++++++++++++++++++++++++-- drivers/pci/host/pcie-iproc.h | 3 +++ 2 files changed, 59 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 912a1cbe561e..15aafbfec7f1 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -58,6 +58,9 @@ #define PCIE_DL_ACTIVE_SHIFT 2 #define PCIE_DL_ACTIVE BIT(PCIE_DL_ACTIVE_SHIFT) +#define APB_ERR_EN_SHIFT 0 +#define APB_ERR_EN BIT(APB_ERR_EN_SHIFT) + #define OARR_VALID_SHIFT 0 #define OARR_VALID BIT(OARR_VALID_SHIFT) #define OARR_SIZE_CFG_SHIFT 1 @@ -96,6 +99,9 @@ enum iproc_pcie_reg { /* link status */ IPROC_PCIE_LINK_STATUS, + /* enable APB error for unsupported requests */ + IPROC_PCIE_APB_ERR_EN, + /* total number of core registers */ IPROC_PCIE_MAX_NUM_REG, }; @@ -124,6 +130,7 @@ static const u16 iproc_pcie_reg_paxb[] = { [IPROC_PCIE_OMAP_LO] = 0xd40, [IPROC_PCIE_OMAP_HI] = 0xd44, [IPROC_PCIE_LINK_STATUS] = 0xf0c, + [IPROC_PCIE_APB_ERR_EN] = 0xf40, }; /* iProc PCIe PAXC v1 registers */ @@ -181,6 +188,28 @@ static inline void iproc_pcie_write_reg(struct iproc_pcie *pcie, writel(val, pcie->base + offset); } +/** + * APB error forwarding can be disabled during access of configuration + * registers of the endpoint device, to prevent unsupported requests + * (typically seen during enumeration with multi-function devices) from + * triggering a system exception. + */ +static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus, + bool disable) +{ + struct iproc_pcie *pcie = iproc_data(bus); + u32 val; + + if (bus->number && pcie->has_apb_err_disable) { + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_APB_ERR_EN); + if (disable) + val &= ~APB_ERR_EN; + else + val |= APB_ERR_EN; + iproc_pcie_write_reg(pcie, IPROC_PCIE_APB_ERR_EN, val); + } +} + static inline void iproc_pcie_ob_write(struct iproc_pcie *pcie, enum iproc_pcie_reg reg, unsigned window, u32 val) @@ -244,10 +273,34 @@ static void __iomem *iproc_pcie_map_cfg_bus(struct pci_bus *bus, return (pcie->base + offset); } +static int iproc_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 *val) +{ + int ret; + + iproc_pcie_apb_err_disable(bus, true); + ret = pci_generic_config_read32(bus, devfn, where, size, val); + iproc_pcie_apb_err_disable(bus, false); + + return ret; +} + +static int iproc_pcie_config_write32(struct pci_bus *bus, unsigned int devfn, + int where, int size, u32 val) +{ + int ret; + + iproc_pcie_apb_err_disable(bus, true); + ret = pci_generic_config_write32(bus, devfn, where, size, val); + iproc_pcie_apb_err_disable(bus, false); + + return ret; +} + static struct pci_ops iproc_pcie_ops = { .map_bus = iproc_pcie_map_cfg_bus, - .read = pci_generic_config_read32, - .write = pci_generic_config_write32, + .read = iproc_pcie_config_read32, + .write = iproc_pcie_config_write32, }; static void iproc_pcie_reset(struct iproc_pcie *pcie) @@ -485,6 +538,7 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) break; case IPROC_PCIE_PAXB: regs = iproc_pcie_reg_paxb; + pcie->has_apb_err_disable = true; break; case IPROC_PCIE_PAXC: regs = iproc_pcie_reg_paxc; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 768be05cf496..711dd3a5f55b 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -57,6 +57,8 @@ struct iproc_msi; * @phy: optional PHY device that controls the Serdes * @map_irq: function callback to map interrupts * @ep_is_internal: indicates an internal emulated endpoint device is connected + * @has_apb_err_disable: indicates the controller can be configured to prevent + * unsupported request from being forwarded as an APB bus error * @need_ob_cfg: indicates SW needs to configure the outbound mapping window * @ob: outbound mapping parameters * @msi: MSI data @@ -74,6 +76,7 @@ struct iproc_pcie { struct phy *phy; int (*map_irq)(const struct pci_dev *, u8, u8); bool ep_is_internal; + bool has_apb_err_disable; bool need_ob_cfg; struct iproc_pcie_ob ob; struct iproc_msi *msi; -- cgit v1.2.3 From c6e4584dab244752ffc1d7f95cdcf5290e7f1369 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Mon, 14 Nov 2016 14:34:53 -0500 Subject: dmaengine: qcom_hidma: cleanup sysfs entries during remove The 4.8-rc8 kernel is printing duplicate file entry warnings while removing the HIDMA object. This is caused by stale sysfs entries remaining from the previous execution. _sysfs_warn_dup+0x5c/0x78 sysfs_add_file_mode_ns+0x13c/0x1c0 sysfs_create_file_ns+0x2c/0x40 device_create_file+0x54/0xa0 hidma_probe+0x7c8/0x808 Create hidma_sysfs_init and hidma_sysfs_uninit functions and call them from the probe and remove path. To do proper clean up, adding the attrs object to the device data structure to keep it around until remove call is made. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 27 +++++++++++++++++++++------ drivers/dma/qcom/hidma.h | 3 +++ 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 10425e134e06..248e74bfd95a 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -580,8 +580,13 @@ static ssize_t hidma_show_values(struct device *dev, return strlen(buf); } -static int hidma_create_sysfs_entry(struct hidma_dev *dev, char *name, - int mode) +static inline void hidma_sysfs_uninit(struct hidma_dev *dev) +{ + device_remove_file(dev->ddev.dev, dev->chid_attrs); +} + +static struct device_attribute* +hidma_create_sysfs_entry(struct hidma_dev *dev, char *name, int mode) { struct device_attribute *attrs; char *name_copy; @@ -589,18 +594,27 @@ static int hidma_create_sysfs_entry(struct hidma_dev *dev, char *name, attrs = devm_kmalloc(dev->ddev.dev, sizeof(struct device_attribute), GFP_KERNEL); if (!attrs) - return -ENOMEM; + return NULL; name_copy = devm_kstrdup(dev->ddev.dev, name, GFP_KERNEL); if (!name_copy) - return -ENOMEM; + return NULL; attrs->attr.name = name_copy; attrs->attr.mode = mode; attrs->show = hidma_show_values; sysfs_attr_init(&attrs->attr); - return device_create_file(dev->ddev.dev, attrs); + return attrs; +} + +static int hidma_sysfs_init(struct hidma_dev *dev) +{ + dev->chid_attrs = hidma_create_sysfs_entry(dev, "chid", S_IRUGO); + if (!dev->chid_attrs) + return -ENOMEM; + + return device_create_file(dev->ddev.dev, dev->chid_attrs); } #ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN @@ -830,7 +844,7 @@ static int hidma_probe(struct platform_device *pdev) dmadev->irq = chirq; tasklet_init(&dmadev->task, hidma_issue_task, (unsigned long)dmadev); hidma_debug_init(dmadev); - hidma_create_sysfs_entry(dmadev, "chid", S_IRUGO); + hidma_sysfs_init(dmadev); dev_info(&pdev->dev, "HI-DMA engine driver registration complete\n"); pm_runtime_mark_last_busy(dmadev->ddev.dev); pm_runtime_put_autosuspend(dmadev->ddev.dev); @@ -863,6 +877,7 @@ static int hidma_remove(struct platform_device *pdev) hidma_free_msis(dmadev); tasklet_kill(&dmadev->task); + hidma_sysfs_uninit(dmadev); hidma_debug_uninit(dmadev); hidma_ll_uninit(dmadev->lldev); hidma_free(dmadev); diff --git a/drivers/dma/qcom/hidma.h b/drivers/dma/qcom/hidma.h index 05f8ba49e6c6..c7d014235c32 100644 --- a/drivers/dma/qcom/hidma.h +++ b/drivers/dma/qcom/hidma.h @@ -130,6 +130,9 @@ struct hidma_dev { struct dentry *debugfs; struct dentry *stats; + /* sysfs entry for the channel id */ + struct device_attribute *chid_attrs; + /* Task delivering issue_pending */ struct tasklet_struct task; }; -- cgit v1.2.3 From 13f59a78c6d69a9bf4c8989dd5f3396f54a2fe41 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 11 Nov 2016 17:59:21 +0000 Subject: iommu: Allow taking a reference on a group directly iommu_group_get_for_dev() expects that the IOMMU driver's device_group callback return a group with a reference held for the given device. Whilst allocating a new group is fine, and pci_device_group() correctly handles reusing an existing group, there is no general means for IOMMU drivers doing their own group lookup to take additional references on an existing group pointer without having to also store device pointers or resort to elaborate trickery. Add an IOMMU-driver-specific function to fill the hole. Acked-by: Sricharan R Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/iommu.c | 13 +++++++++++++ include/linux/iommu.h | 1 + 2 files changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9a2f1960873b..9408c3145483 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -551,6 +551,19 @@ struct iommu_group *iommu_group_get(struct device *dev) } EXPORT_SYMBOL_GPL(iommu_group_get); +/** + * iommu_group_ref_get - Increment reference on a group + * @group: the group to use, must not be NULL + * + * This function is called by iommu drivers to take additional references on an + * existing group. Returns the given group for convenience. + */ +struct iommu_group *iommu_group_ref_get(struct iommu_group *group) +{ + kobject_get(group->devices_kobj); + return group; +} + /** * iommu_group_put - Decrement group reference * @group: the group to use diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 436dc21318af..431638110c6a 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -253,6 +253,7 @@ extern void iommu_group_remove_device(struct device *dev); extern int iommu_group_for_each_dev(struct iommu_group *group, void *data, int (*fn)(struct device *, void *)); extern struct iommu_group *iommu_group_get(struct device *dev); +extern struct iommu_group *iommu_group_ref_get(struct iommu_group *group); extern void iommu_group_put(struct iommu_group *group); extern int iommu_group_register_notifier(struct iommu_group *group, struct notifier_block *nb); -- cgit v1.2.3 From e1b44cbe7b5d4d97e43a1476b68e0adc1aa5e383 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 11 Nov 2016 17:59:22 +0000 Subject: iommu/arm-smmu: Fix group refcounting When arm_smmu_device_group() finds an existing group due to Stream ID aliasing, it should be taking an additional reference on that group. Otherwise, the caller of iommu_group_get_for_dev() will inadvertently remove the reference taken by iommu_group_add_device(), and the group will be freed prematurely if any device is removed. Reported-by: Sricharan R Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index c841eb7a1a74..b85fa2471738 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1466,7 +1466,7 @@ static struct iommu_group *arm_smmu_device_group(struct device *dev) } if (group) - return group; + return iommu_group_ref_get(group); if (dev_is_pci(dev)) group = pci_device_group(dev); -- cgit v1.2.3 From f2f101f6bcb3c47a432543dd309056e58192550f Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 11 Nov 2016 17:59:23 +0000 Subject: iommu/amd: Fix group refcounting If acpihid_device_group() finds an existing group for the relevant devid, it should be taking an additional reference on that group. Otherwise, the caller of iommu_group_get_for_dev() will inadvertently remove the reference taken by iommu_group_add_device(), and the group will be freed prematurely if any device is removed. Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 754595ee11b6..019e02707cd5 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -373,6 +373,8 @@ static struct iommu_group *acpihid_device_group(struct device *dev) if (!entry->group) entry->group = generic_device_group(dev); + else + iommu_group_ref_get(entry->group); return entry->group; } -- cgit v1.2.3 From 3a8d40b6ce8c3f682d3b00a568d406b2f8726701 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 11 Nov 2016 17:59:24 +0000 Subject: iommu/mediatek: Fix M4Uv2 group refcounting For each subsequent device assigned to the m4u_group after its initial allocation, we need to take an additional reference. Otherwise, the caller of iommu_group_get_for_dev() will inadvertently remove the reference taken by iommu_group_add_device(), and the group will be freed prematurely if any device is removed. Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index b12c12d74c33..9799daeaacde 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -410,6 +410,8 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev) data->m4u_group = iommu_group_alloc(); if (IS_ERR(data->m4u_group)) dev_err(dev, "Failed to allocate M4U IOMMU group\n"); + } else { + iommu_group_ref_get(data->m4u_group); } return data->m4u_group; } -- cgit v1.2.3 From 5d1d43b0f6231cfffde61f8774283f170c040776 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 11 Nov 2016 17:59:25 +0000 Subject: iommu/mediatek: Fix M4Uv1 group refcounting For each subsequent device assigned to the m4u_group after its initial allocation, we need to take an additional reference. Otherwise, the caller of iommu_group_get_for_dev() will inadvertently remove the reference taken by iommu_group_add_device(), and the group will be freed prematurely if any device is removed. Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/mtk_iommu_v1.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/iommu/mtk_iommu_v1.c b/drivers/iommu/mtk_iommu_v1.c index b8aeb0768483..c7063e9d67d8 100644 --- a/drivers/iommu/mtk_iommu_v1.c +++ b/drivers/iommu/mtk_iommu_v1.c @@ -502,6 +502,8 @@ static struct iommu_group *mtk_iommu_device_group(struct device *dev) data->m4u_group = iommu_group_alloc(); if (IS_ERR(data->m4u_group)) dev_err(dev, "Failed to allocate M4U IOMMU group\n"); + } else { + iommu_group_ref_get(data->m4u_group); } return data->m4u_group; } -- cgit v1.2.3 From 62280cf2e8bb46d14b47b198720ab2d69b43faf7 Mon Sep 17 00:00:00 2001 From: Robin Murphy Date: Fri, 11 Nov 2016 18:35:46 +0000 Subject: iommu/iova: Extend cached node lookup condition When searching for a free IOVA range, we optimise the tree traversal by starting from the cached32_node, instead of the last node, when limit_pfn is equal to dma_32bit_pfn. However, if limit_pfn happens to be smaller, then we'll go ahead and start from the top even though dma_32bit_pfn is still a more suitable upper bound. Since this is clearly a silly thing to do, adjust the lookup condition appropriately. Signed-off-by: Robin Murphy Signed-off-by: Joerg Roedel --- drivers/iommu/iova.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c index e23001bfcfee..080beca0197d 100644 --- a/drivers/iommu/iova.c +++ b/drivers/iommu/iova.c @@ -56,7 +56,7 @@ EXPORT_SYMBOL_GPL(init_iova_domain); static struct rb_node * __get_cached_rbnode(struct iova_domain *iovad, unsigned long *limit_pfn) { - if ((*limit_pfn != iovad->dma_32bit_pfn) || + if ((*limit_pfn > iovad->dma_32bit_pfn) || (iovad->cached32_node == NULL)) return rb_last(&iovad->rbroot); else { -- cgit v1.2.3 From 25a06442656001daac6edca98d868414355ee5b8 Mon Sep 17 00:00:00 2001 From: Joseph Lo Date: Tue, 5 Jul 2016 17:04:27 +0800 Subject: soc/tegra: Add Tegra186 support The Tegra186 features a combination of Denver and Cortex-A57 CPU cores and a GPU based on the Pascal architecture. It contains an ADSP with a Cortex-A9 CPU used for audio processing, hardware video encoders and decoders with multi-format support, ISP for image capture processing and BPMP for power management. Signed-off-by: Joseph Lo Signed-off-by: Thierry Reding --- drivers/soc/tegra/Kconfig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/Kconfig b/drivers/soc/tegra/Kconfig index 03089ad2fc65..e5e124c07066 100644 --- a/drivers/soc/tegra/Kconfig +++ b/drivers/soc/tegra/Kconfig @@ -77,5 +77,19 @@ config ARCH_TEGRA_210_SOC controllers, such as GPIO, I2C, SPI, SDHCI, PCIe, SATA and XHCI, to name only a few. +config ARCH_TEGRA_186_SOC + bool "NVIDIA Tegra186 SoC" + select MAILBOX + select TEGRA_BPMP + select TEGRA_HSP_MBOX + select TEGRA_IVC + help + Enable support for the NVIDIA Tegar186 SoC. The Tegra186 features a + combination of Denver and Cortex-A57 CPU cores and a GPU based on + the Pascal architecture. It contains an ADSP with a Cortex-A9 CPU + used for audio processing, hardware video encoders/decoders with + multi-format support, ISP for image capture processing and BPMP for + power management. + endif endif -- cgit v1.2.3 From 6c0bd217c361fa820d953e33fc7b6b95571c28ac Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Jun 2016 18:36:12 +0530 Subject: soc/tegra: pmc: Use BIT macro for register field definition Use BIT macro for register field definition and make constant as U when using in shift operator like (3 << 30) to (3U << 30) Signed-off-by: Laxman Dewangan Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 7792ed88d80b..3013c6d28521 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -45,29 +45,29 @@ #include #define PMC_CNTRL 0x0 -#define PMC_CNTRL_SYSCLK_POLARITY (1 << 10) /* sys clk polarity */ -#define PMC_CNTRL_SYSCLK_OE (1 << 11) /* system clock enable */ -#define PMC_CNTRL_SIDE_EFFECT_LP0 (1 << 14) /* LP0 when CPU pwr gated */ -#define PMC_CNTRL_CPU_PWRREQ_POLARITY (1 << 15) /* CPU pwr req polarity */ -#define PMC_CNTRL_CPU_PWRREQ_OE (1 << 16) /* CPU pwr req enable */ -#define PMC_CNTRL_INTR_POLARITY (1 << 17) /* inverts INTR polarity */ -#define PMC_CNTRL_MAIN_RST (1 << 4) +#define PMC_CNTRL_MAIN_RST BIT(4) +#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ +#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ +#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ +#define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ +#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ +#define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ #define DPD_SAMPLE 0x020 -#define DPD_SAMPLE_ENABLE (1 << 0) +#define DPD_SAMPLE_ENABLE BIT(0) #define DPD_SAMPLE_DISABLE (0 << 0) #define PWRGATE_TOGGLE 0x30 -#define PWRGATE_TOGGLE_START (1 << 8) +#define PWRGATE_TOGGLE_START BIT(8) #define REMOVE_CLAMPING 0x34 #define PWRGATE_STATUS 0x38 #define PMC_SCRATCH0 0x50 -#define PMC_SCRATCH0_MODE_RECOVERY (1 << 31) -#define PMC_SCRATCH0_MODE_BOOTLOADER (1 << 30) -#define PMC_SCRATCH0_MODE_RCM (1 << 1) +#define PMC_SCRATCH0_MODE_RECOVERY BIT(31) +#define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) +#define PMC_SCRATCH0_MODE_RCM BIT(1) #define PMC_SCRATCH0_MODE_MASK (PMC_SCRATCH0_MODE_RECOVERY | \ PMC_SCRATCH0_MODE_BOOTLOADER | \ PMC_SCRATCH0_MODE_RCM) @@ -78,8 +78,8 @@ #define PMC_SCRATCH41 0x140 #define PMC_SENSOR_CTRL 0x1b0 -#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2) -#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1) +#define PMC_SENSOR_CTRL_SCRATCH_WRITE BIT(2) +#define PMC_SENSOR_CTRL_ENABLE_RST BIT(1) #define PMC_RST_STATUS 0x1b4 #define PMC_RST_STATUS_POR 0 @@ -90,10 +90,10 @@ #define PMC_RST_STATUS_AOTAG 5 #define IO_DPD_REQ 0x1b8 -#define IO_DPD_REQ_CODE_IDLE (0 << 30) -#define IO_DPD_REQ_CODE_OFF (1 << 30) -#define IO_DPD_REQ_CODE_ON (2 << 30) -#define IO_DPD_REQ_CODE_MASK (3 << 30) +#define IO_DPD_REQ_CODE_IDLE (0U << 30) +#define IO_DPD_REQ_CODE_OFF (1U << 30) +#define IO_DPD_REQ_CODE_ON (2U << 30) +#define IO_DPD_REQ_CODE_MASK (3U << 30) #define IO_DPD_STATUS 0x1bc #define IO_DPD2_REQ 0x1c0 @@ -101,16 +101,16 @@ #define SEL_DPD_TIM 0x1c8 #define PMC_SCRATCH54 0x258 -#define PMC_SCRATCH54_DATA_SHIFT 8 -#define PMC_SCRATCH54_ADDR_SHIFT 0 +#define PMC_SCRATCH54_DATA_SHIFT 8 +#define PMC_SCRATCH54_ADDR_SHIFT 0 #define PMC_SCRATCH55 0x25c -#define PMC_SCRATCH55_RESET_TEGRA (1 << 31) -#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 -#define PMC_SCRATCH55_PINMUX_SHIFT 24 -#define PMC_SCRATCH55_16BITOP (1 << 15) -#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 -#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 +#define PMC_SCRATCH55_RESET_TEGRA BIT(31) +#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27 +#define PMC_SCRATCH55_PINMUX_SHIFT 24 +#define PMC_SCRATCH55_16BITOP BIT(15) +#define PMC_SCRATCH55_CHECKSUM_SHIFT 16 +#define PMC_SCRATCH55_I2CSLV1_SHIFT 0 #define GPU_RG_CNTRL 0x2d4 -- cgit v1.2.3 From 84cf85ea6ea29fc0c933a85fb3e900315759a581 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Fri, 17 Jun 2016 18:36:13 +0530 Subject: soc/tegra: pmc: Correct type of variable for tegra_pmc_readl() The function tegra_pmc_readl() returns the u32 type data and hence change the data type of variable where this data is stored to u32 type. Signed-off-by: Laxman Dewangan Reviewed-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 3013c6d28521..01da62484e20 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -942,10 +942,10 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, return 0; } -static int tegra_io_rail_poll(unsigned long offset, unsigned long mask, - unsigned long val, unsigned long timeout) +static int tegra_io_rail_poll(unsigned long offset, u32 mask, + u32 val, unsigned long timeout) { - unsigned long value; + u32 value; timeout = jiffies + msecs_to_jiffies(timeout); -- cgit v1.2.3 From 95b780b3d7e3f1900e09dfe90e959f220a8df343 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Mon, 10 Oct 2016 13:13:36 +0200 Subject: soc/tegra: pmc: Use consistent ordering of bit definitions Bit definitions are sorted in decreasing order by offset. Apply the same ordering to all definitions. Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 01da62484e20..d57f3e0f5f27 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -45,13 +45,13 @@ #include #define PMC_CNTRL 0x0 -#define PMC_CNTRL_MAIN_RST BIT(4) -#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ -#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ -#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ -#define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ -#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ #define PMC_CNTRL_INTR_POLARITY BIT(17) /* inverts INTR polarity */ +#define PMC_CNTRL_CPU_PWRREQ_OE BIT(16) /* CPU pwr req enable */ +#define PMC_CNTRL_CPU_PWRREQ_POLARITY BIT(15) /* CPU pwr req polarity */ +#define PMC_CNTRL_SIDE_EFFECT_LP0 BIT(14) /* LP0 when CPU pwr gated */ +#define PMC_CNTRL_SYSCLK_OE BIT(11) /* system clock enable */ +#define PMC_CNTRL_SYSCLK_POLARITY BIT(10) /* sys clk polarity */ +#define PMC_CNTRL_MAIN_RST BIT(4) #define DPD_SAMPLE 0x020 #define DPD_SAMPLE_ENABLE BIT(0) -- cgit v1.2.3 From 21b4991051780b49b217c363f79366ed94c3b4b7 Mon Sep 17 00:00:00 2001 From: Laxman Dewangan Date: Mon, 10 Oct 2016 15:14:34 +0200 Subject: soc/tegra: pmc: Add I/O pad voltage support I/O pins on Tegra SoCs are grouped into so-called I/O pads. Each such pad can be used to control the common voltage signal level and power state of the pins in the given pad. I/O pads can be powered down even if the system is active, which can save power from that I/O interface. For SoC generations prior to Tegra124 the I/O pad voltage is automatically detected and hence the system software doesn't need to configure it. However, starting with Tegra210 the detection logic has been removed, so explicit control of the I/O pad voltage by system software is required. Signed-off-by: Laxman Dewangan Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 273 +++++++++++++++++++++++++++++++++++++++++------- include/soc/tegra/pmc.h | 126 ++++++++++++++++------ 2 files changed, 332 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index d57f3e0f5f27..81968ef19618 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -64,6 +64,8 @@ #define PWRGATE_STATUS 0x38 +#define PMC_PWR_DET 0x48 + #define PMC_SCRATCH0 0x50 #define PMC_SCRATCH0_MODE_RECOVERY BIT(31) #define PMC_SCRATCH0_MODE_BOOTLOADER BIT(30) @@ -75,6 +77,8 @@ #define PMC_CPUPWRGOOD_TIMER 0xc8 #define PMC_CPUPWROFF_TIMER 0xcc +#define PMC_PWR_DET_VALUE 0xe4 + #define PMC_SCRATCH41 0x140 #define PMC_SENSOR_CTRL 0x1b0 @@ -124,6 +128,12 @@ struct tegra_powergate { unsigned int num_resets; }; +struct tegra_io_pad_soc { + enum tegra_io_pad id; + unsigned int dpd; + unsigned int voltage; +}; + struct tegra_pmc_soc { unsigned int num_powergates; const char *const *powergates; @@ -132,6 +142,9 @@ struct tegra_pmc_soc { bool has_tsense_reset; bool has_gpu_clamps; + + const struct tegra_io_pad_soc *io_pads; + unsigned int num_io_pads; }; /** @@ -908,21 +921,34 @@ static void tegra_powergate_init(struct tegra_pmc *pmc, of_node_put(np); } -static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, - unsigned long *status, unsigned int *bit) +static const struct tegra_io_pad_soc * +tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id) +{ + unsigned int i; + + for (i = 0; i < pmc->soc->num_io_pads; i++) + if (pmc->soc->io_pads[i].id == id) + return &pmc->soc->io_pads[i]; + + return NULL; +} + +static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, + unsigned long *status, unsigned int *bit) { + const struct tegra_io_pad_soc *pad; unsigned long rate, value; - *bit = id % 32; + pad = tegra_io_pad_find(pmc, id); + if (!pad) + return -ENOENT; - /* - * There are two sets of 30 bits to select IO rails, but bits 30 and - * 31 are control bits rather than IO rail selection bits. - */ - if (id > 63 || *bit == 30 || *bit == 31) - return -EINVAL; + if (pad->dpd == UINT_MAX) + return -ENOTSUPP; - if (id < 32) { + *bit = pad->dpd % 32; + + if (pad->dpd < 32) { *status = IO_DPD_STATUS; *request = IO_DPD_REQ; } else { @@ -942,8 +968,8 @@ static int tegra_io_rail_prepare(unsigned int id, unsigned long *request, return 0; } -static int tegra_io_rail_poll(unsigned long offset, u32 mask, - u32 val, unsigned long timeout) +static int tegra_io_pad_poll(unsigned long offset, u32 mask, + u32 val, unsigned long timeout) { u32 value; @@ -960,12 +986,18 @@ static int tegra_io_rail_poll(unsigned long offset, u32 mask, return -ETIMEDOUT; } -static void tegra_io_rail_unprepare(void) +static void tegra_io_pad_unprepare(void) { tegra_pmc_writel(DPD_SAMPLE_DISABLE, DPD_SAMPLE); } -int tegra_io_rail_power_on(unsigned int id) +/** + * tegra_io_pad_power_enable() - enable power to I/O pad + * @id: Tegra I/O pad ID for which to enable power + * + * Returns: 0 on success or a negative error code on failure. + */ +int tegra_io_pad_power_enable(enum tegra_io_pad id) { unsigned long request, status; unsigned int bit; @@ -973,28 +1005,35 @@ int tegra_io_rail_power_on(unsigned int id) mutex_lock(&pmc->powergates_lock); - err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err) - goto error; + err = tegra_io_pad_prepare(id, &request, &status, &bit); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + goto unlock; + } tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(bit), request); - err = tegra_io_rail_poll(status, BIT(bit), 0, 250); - if (err) { - pr_info("tegra_io_rail_poll() failed: %d\n", err); - goto error; + err = tegra_io_pad_poll(status, BIT(bit), 0, 250); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + goto unlock; } - tegra_io_rail_unprepare(); + tegra_io_pad_unprepare(); -error: +unlock: mutex_unlock(&pmc->powergates_lock); - return err; } -EXPORT_SYMBOL(tegra_io_rail_power_on); +EXPORT_SYMBOL(tegra_io_pad_power_enable); -int tegra_io_rail_power_off(unsigned int id) +/** + * tegra_io_pad_power_disable() - disable power to I/O pad + * @id: Tegra I/O pad ID for which to disable power + * + * Returns: 0 on success or a negative error code on failure. + */ +int tegra_io_pad_power_disable(enum tegra_io_pad id) { unsigned long request, status; unsigned int bit; @@ -1002,25 +1041,109 @@ int tegra_io_rail_power_off(unsigned int id) mutex_lock(&pmc->powergates_lock); - err = tegra_io_rail_prepare(id, &request, &status, &bit); - if (err) { - pr_info("tegra_io_rail_prepare() failed: %d\n", err); - goto error; + err = tegra_io_pad_prepare(id, &request, &status, &bit); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + goto unlock; } tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(bit), request); - err = tegra_io_rail_poll(status, BIT(bit), BIT(bit), 250); - if (err) - goto error; + err = tegra_io_pad_poll(status, BIT(bit), BIT(bit), 250); + if (err < 0) { + dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + goto unlock; + } - tegra_io_rail_unprepare(); + tegra_io_pad_unprepare(); -error: +unlock: mutex_unlock(&pmc->powergates_lock); - return err; } +EXPORT_SYMBOL(tegra_io_pad_power_disable); + +int tegra_io_pad_set_voltage(enum tegra_io_pad id, + enum tegra_io_pad_voltage voltage) +{ + const struct tegra_io_pad_soc *pad; + u32 value; + + pad = tegra_io_pad_find(pmc, id); + if (!pad) + return -ENOENT; + + if (pad->voltage == UINT_MAX) + return -ENOTSUPP; + + mutex_lock(&pmc->powergates_lock); + + /* write-enable PMC_PWR_DET_VALUE[pad->voltage] */ + value = tegra_pmc_readl(PMC_PWR_DET); + value |= BIT(pad->voltage); + tegra_pmc_writel(value, PMC_PWR_DET); + + /* update I/O voltage */ + value = tegra_pmc_readl(PMC_PWR_DET_VALUE); + + if (voltage == TEGRA_IO_PAD_1800000UV) + value &= ~BIT(pad->voltage); + else + value |= BIT(pad->voltage); + + tegra_pmc_writel(value, PMC_PWR_DET_VALUE); + + mutex_unlock(&pmc->powergates_lock); + + usleep_range(100, 250); + + return 0; +} +EXPORT_SYMBOL(tegra_io_pad_set_voltage); + +int tegra_io_pad_get_voltage(enum tegra_io_pad id) +{ + const struct tegra_io_pad_soc *pad; + u32 value; + + pad = tegra_io_pad_find(pmc, id); + if (!pad) + return -ENOENT; + + if (pad->voltage == UINT_MAX) + return -ENOTSUPP; + + value = tegra_pmc_readl(PMC_PWR_DET_VALUE); + + if ((value & BIT(pad->voltage)) == 0) + return TEGRA_IO_PAD_1800000UV; + + return TEGRA_IO_PAD_3300000UV; +} +EXPORT_SYMBOL(tegra_io_pad_get_voltage); + +/** + * tegra_io_rail_power_on() - enable power to I/O rail + * @id: Tegra I/O pad ID for which to enable power + * + * See also: tegra_io_pad_power_enable() + */ +int tegra_io_rail_power_on(unsigned int id) +{ + return tegra_io_pad_power_enable(id); +} +EXPORT_SYMBOL(tegra_io_rail_power_on); + +/** + * tegra_io_rail_power_off() - disable power to I/O rail + * @id: Tegra I/O pad ID for which to disable power + * + * See also: tegra_io_pad_power_disable() + */ +int tegra_io_rail_power_off(unsigned int id) +{ + return tegra_io_pad_power_disable(id); +} EXPORT_SYMBOL(tegra_io_rail_power_off); #ifdef CONFIG_PM_SLEEP @@ -1454,6 +1577,39 @@ static const u8 tegra124_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const struct tegra_io_pad_soc tegra124_io_pads[] = { + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_BB, .dpd = 15, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_COMP, .dpd = 22, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HV, .dpd = 38, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_NAND, .dpd = 13, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = 32, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SDMMC4, .dpd = 35, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_SYS_DDC, .dpd = 58, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX }, +}; + static const struct tegra_pmc_soc tegra124_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra124_powergates), .powergates = tegra124_powergates, @@ -1461,6 +1617,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = { .cpu_powergates = tegra124_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = true, + .num_io_pads = ARRAY_SIZE(tegra124_io_pads), + .io_pads = tegra124_io_pads, }; static const char * const tegra210_powergates[] = { @@ -1497,6 +1655,47 @@ static const u8 tegra210_cpu_powergates[] = { TEGRA_POWERGATE_CPU3, }; +static const struct tegra_io_pad_soc tegra210_io_pads[] = { + { .id = TEGRA_IO_PAD_AUDIO, .dpd = 17, .voltage = 5 }, + { .id = TEGRA_IO_PAD_AUDIO_HV, .dpd = 61, .voltage = 18 }, + { .id = TEGRA_IO_PAD_CAM, .dpd = 36, .voltage = 10 }, + { .id = TEGRA_IO_PAD_CSIA, .dpd = 0, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIB, .dpd = 1, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIC, .dpd = 42, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSID, .dpd = 43, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIE, .dpd = 44, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_CSIF, .dpd = 45, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DBG, .dpd = 25, .voltage = 19 }, + { .id = TEGRA_IO_PAD_DEBUG_NONAO, .dpd = 26, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DMIC, .dpd = 50, .voltage = 20 }, + { .id = TEGRA_IO_PAD_DP, .dpd = 51, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSI, .dpd = 2, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIB, .dpd = 39, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSIC, .dpd = 40, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_DSID, .dpd = 41, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EMMC, .dpd = 35, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_EMMC2, .dpd = 37, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_GPIO, .dpd = 27, .voltage = 21 }, + { .id = TEGRA_IO_PAD_HDMI, .dpd = 28, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_HSIC, .dpd = 19, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_LVDS, .dpd = 57, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_MIPI_BIAS, .dpd = 3, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_BIAS, .dpd = 4, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK1, .dpd = 5, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CLK2, .dpd = 6, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_PEX_CNTRL, .dpd = UINT_MAX, .voltage = 11 }, + { .id = TEGRA_IO_PAD_SDMMC1, .dpd = 33, .voltage = 12 }, + { .id = TEGRA_IO_PAD_SDMMC3, .dpd = 34, .voltage = 13 }, + { .id = TEGRA_IO_PAD_SPI, .dpd = 46, .voltage = 22 }, + { .id = TEGRA_IO_PAD_SPI_HV, .dpd = 47, .voltage = 23 }, + { .id = TEGRA_IO_PAD_UART, .dpd = 14, .voltage = 2 }, + { .id = TEGRA_IO_PAD_USB0, .dpd = 9, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB1, .dpd = 10, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB2, .dpd = 11, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB3, .dpd = 18, .voltage = UINT_MAX }, + { .id = TEGRA_IO_PAD_USB_BIAS, .dpd = 12, .voltage = UINT_MAX }, +}; + static const struct tegra_pmc_soc tegra210_pmc_soc = { .num_powergates = ARRAY_SIZE(tegra210_powergates), .powergates = tegra210_powergates, @@ -1504,6 +1703,8 @@ static const struct tegra_pmc_soc tegra210_pmc_soc = { .cpu_powergates = tegra210_cpu_powergates, .has_tsense_reset = true, .has_gpu_clamps = true, + .num_io_pads = ARRAY_SIZE(tegra210_io_pads), + .io_pads = tegra210_io_pads, }; static const struct of_device_id tegra_pmc_match[] = { diff --git a/include/soc/tegra/pmc.h b/include/soc/tegra/pmc.h index e9e53473a63e..2f271d1b9cea 100644 --- a/include/soc/tegra/pmc.h +++ b/include/soc/tegra/pmc.h @@ -76,37 +76,73 @@ int tegra_pmc_cpu_remove_clamping(unsigned int cpuid); #define TEGRA_POWERGATE_3D0 TEGRA_POWERGATE_3D -#define TEGRA_IO_RAIL_CSIA 0 -#define TEGRA_IO_RAIL_CSIB 1 -#define TEGRA_IO_RAIL_DSI 2 -#define TEGRA_IO_RAIL_MIPI_BIAS 3 -#define TEGRA_IO_RAIL_PEX_BIAS 4 -#define TEGRA_IO_RAIL_PEX_CLK1 5 -#define TEGRA_IO_RAIL_PEX_CLK2 6 -#define TEGRA_IO_RAIL_USB0 9 -#define TEGRA_IO_RAIL_USB1 10 -#define TEGRA_IO_RAIL_USB2 11 -#define TEGRA_IO_RAIL_USB_BIAS 12 -#define TEGRA_IO_RAIL_NAND 13 -#define TEGRA_IO_RAIL_UART 14 -#define TEGRA_IO_RAIL_BB 15 -#define TEGRA_IO_RAIL_AUDIO 17 -#define TEGRA_IO_RAIL_HSIC 19 -#define TEGRA_IO_RAIL_COMP 22 -#define TEGRA_IO_RAIL_HDMI 28 -#define TEGRA_IO_RAIL_PEX_CNTRL 32 -#define TEGRA_IO_RAIL_SDMMC1 33 -#define TEGRA_IO_RAIL_SDMMC3 34 -#define TEGRA_IO_RAIL_SDMMC4 35 -#define TEGRA_IO_RAIL_CAM 36 -#define TEGRA_IO_RAIL_RES 37 -#define TEGRA_IO_RAIL_HV 38 -#define TEGRA_IO_RAIL_DSIB 39 -#define TEGRA_IO_RAIL_DSIC 40 -#define TEGRA_IO_RAIL_DSID 41 -#define TEGRA_IO_RAIL_CSIE 44 -#define TEGRA_IO_RAIL_LVDS 57 -#define TEGRA_IO_RAIL_SYS_DDC 58 +/** + * enum tegra_io_pad - I/O pad group identifier + * + * I/O pins on Tegra SoCs are grouped into so-called I/O pads. Each such pad + * can be used to control the common voltage signal level and power state of + * the pins of the given pad. + */ +enum tegra_io_pad { + TEGRA_IO_PAD_AUDIO, + TEGRA_IO_PAD_AUDIO_HV, + TEGRA_IO_PAD_BB, + TEGRA_IO_PAD_CAM, + TEGRA_IO_PAD_COMP, + TEGRA_IO_PAD_CSIA, + TEGRA_IO_PAD_CSIB, + TEGRA_IO_PAD_CSIC, + TEGRA_IO_PAD_CSID, + TEGRA_IO_PAD_CSIE, + TEGRA_IO_PAD_CSIF, + TEGRA_IO_PAD_DBG, + TEGRA_IO_PAD_DEBUG_NONAO, + TEGRA_IO_PAD_DMIC, + TEGRA_IO_PAD_DP, + TEGRA_IO_PAD_DSI, + TEGRA_IO_PAD_DSIB, + TEGRA_IO_PAD_DSIC, + TEGRA_IO_PAD_DSID, + TEGRA_IO_PAD_EMMC, + TEGRA_IO_PAD_EMMC2, + TEGRA_IO_PAD_GPIO, + TEGRA_IO_PAD_HDMI, + TEGRA_IO_PAD_HSIC, + TEGRA_IO_PAD_HV, + TEGRA_IO_PAD_LVDS, + TEGRA_IO_PAD_MIPI_BIAS, + TEGRA_IO_PAD_NAND, + TEGRA_IO_PAD_PEX_BIAS, + TEGRA_IO_PAD_PEX_CLK1, + TEGRA_IO_PAD_PEX_CLK2, + TEGRA_IO_PAD_PEX_CNTRL, + TEGRA_IO_PAD_SDMMC1, + TEGRA_IO_PAD_SDMMC3, + TEGRA_IO_PAD_SDMMC4, + TEGRA_IO_PAD_SPI, + TEGRA_IO_PAD_SPI_HV, + TEGRA_IO_PAD_SYS_DDC, + TEGRA_IO_PAD_UART, + TEGRA_IO_PAD_USB0, + TEGRA_IO_PAD_USB1, + TEGRA_IO_PAD_USB2, + TEGRA_IO_PAD_USB3, + TEGRA_IO_PAD_USB_BIAS, +}; + +/* deprecated, use TEGRA_IO_PAD_{HDMI,LVDS} instead */ +#define TEGRA_IO_RAIL_HDMI TEGRA_IO_PAD_HDMI +#define TEGRA_IO_RAIL_LVDS TEGRA_IO_PAD_LVDS + +/** + * enum tegra_io_pad_voltage - voltage level of the I/O pad's source rail + * @TEGRA_IO_PAD_1800000UV: 1.8 V + * @TEGRA_IO_PAD_3300000UV: 3.3 V + */ +enum tegra_io_pad_voltage { + TEGRA_IO_PAD_1800000UV, + TEGRA_IO_PAD_3300000UV, +}; #ifdef CONFIG_ARCH_TEGRA int tegra_powergate_is_powered(unsigned int id); @@ -118,6 +154,13 @@ int tegra_powergate_remove_clamping(unsigned int id); int tegra_powergate_sequence_power_up(unsigned int id, struct clk *clk, struct reset_control *rst); +int tegra_io_pad_power_enable(enum tegra_io_pad id); +int tegra_io_pad_power_disable(enum tegra_io_pad id); +int tegra_io_pad_set_voltage(enum tegra_io_pad id, + enum tegra_io_pad_voltage voltage); +int tegra_io_pad_get_voltage(enum tegra_io_pad id); + +/* deprecated, use tegra_io_pad_power_{enable,disable}() instead */ int tegra_io_rail_power_on(unsigned int id); int tegra_io_rail_power_off(unsigned int id); #else @@ -148,6 +191,27 @@ static inline int tegra_powergate_sequence_power_up(unsigned int id, return -ENOSYS; } +static inline int tegra_io_pad_power_enable(enum tegra_io_pad id) +{ + return -ENOSYS; +} + +static inline int tegra_io_pad_power_disable(enum tegra_io_pad id) +{ + return -ENOSYS; +} + +static inline int tegra_io_pad_set_voltage(enum tegra_io_pad id, + enum tegra_io_pad_voltage voltage) +{ + return -ENOSYS; +} + +static inline int tegra_io_pad_get_voltage(enum tegra_io_pad id) +{ + return -ENOSYS; +} + static inline int tegra_io_rail_power_on(unsigned int id) { return -ENOSYS; -- cgit v1.2.3 From f4392d6da5f52727a53298321f4dfeac6df1a093 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:52 +0100 Subject: soc/tegra: pmc: Guard against uninitialised PMC clock It is possible for the public functions, tegra_io_rail_power_on/off() to be called before the PMC device has been probed. If this happens then the pmc->clk member will not be initialised and the call to clk_get_rate() in tegra_io_rail_prepare() will return zero and lead to a divide-by-zero exception. The function clk_get_rate() will return zero if a NULl clk pointer is passed. Therefore, rather that checking if pmc->clk is initialised, fix this by checking the return value for clk_get_rate() to make sure it is not zero. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 81968ef19618..c8b54b9dc093 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -957,6 +957,8 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, } rate = clk_get_rate(pmc->clk); + if (!rate) + return -ENODEV; tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); -- cgit v1.2.3 From 27b12b4e58525f7e8a612af5a3999126d0ea76fb Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:53 +0100 Subject: soc/tegra: pmc: Simplify IO rail bit handling The function tegra_io_rail_prepare() converts the IO rail ID into a bit position that is used to check the status and control the IO rail in the PMC registers. However, rather than converting to a bit position it is more useful to convert to a bit-mask because this is what is actually used. By doing so the BIT() marco only needs to be used once and we can use the IO_DPD_REQ_CODE_MASK when checking for erroneous rail IDs. Signed-off-by: Jon Hunter [treding@nvidia.com: rebase and rename bit -> mask] Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index c8b54b9dc093..c21d48db058e 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -934,7 +934,7 @@ tegra_io_pad_find(struct tegra_pmc *pmc, enum tegra_io_pad id) } static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, - unsigned long *status, unsigned int *bit) + unsigned long *status, u32 *mask) { const struct tegra_io_pad_soc *pad; unsigned long rate, value; @@ -946,7 +946,7 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, if (pad->dpd == UINT_MAX) return -ENOTSUPP; - *bit = pad->dpd % 32; + *mask = BIT(pad->dpd % 32); if (pad->dpd < 32) { *status = IO_DPD_STATUS; @@ -1002,20 +1002,20 @@ static void tegra_io_pad_unprepare(void) int tegra_io_pad_power_enable(enum tegra_io_pad id) { unsigned long request, status; - unsigned int bit; + u32 mask; int err; mutex_lock(&pmc->powergates_lock); - err = tegra_io_pad_prepare(id, &request, &status, &bit); + err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); goto unlock; } - tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | BIT(bit), request); + tegra_pmc_writel(IO_DPD_REQ_CODE_OFF | mask, request); - err = tegra_io_pad_poll(status, BIT(bit), 0, 250); + err = tegra_io_pad_poll(status, mask, 0, 250); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); goto unlock; @@ -1038,20 +1038,20 @@ EXPORT_SYMBOL(tegra_io_pad_power_enable); int tegra_io_pad_power_disable(enum tegra_io_pad id) { unsigned long request, status; - unsigned int bit; + u32 mask; int err; mutex_lock(&pmc->powergates_lock); - err = tegra_io_pad_prepare(id, &request, &status, &bit); + err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); goto unlock; } - tegra_pmc_writel(IO_DPD_REQ_CODE_ON | BIT(bit), request); + tegra_pmc_writel(IO_DPD_REQ_CODE_ON | mask, request); - err = tegra_io_pad_poll(status, BIT(bit), BIT(bit), 250); + err = tegra_io_pad_poll(status, mask, mask, 250); if (err < 0) { dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); goto unlock; -- cgit v1.2.3 From 54e247211f6ba24f8fc0cbbd801d4d58e9b161ea Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 8 Nov 2016 10:58:32 +0100 Subject: soc/tegra: pmc: Clean-up I/O rail error messages Use pr_err() instead of dev_err() when the pmc->dev field has not been initialized yet and add a few missing error messages as well as remove duplicate ones. Based on work by Jon Hunter . Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index c21d48db058e..78fffa22966f 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -251,8 +251,6 @@ static int tegra_powergate_lookup(struct tegra_pmc *pmc, const char *name) return i; } - dev_err(pmc->dev, "powergate %s not found\n", name); - return -ENODEV; } @@ -469,13 +467,12 @@ disable_clks: static int tegra_genpd_power_on(struct generic_pm_domain *domain) { struct tegra_powergate *pg = to_powergate(domain); - struct tegra_pmc *pmc = pg->pmc; int err; err = tegra_powergate_power_up(pg, true); if (err) - dev_err(pmc->dev, "failed to turn on PM domain %s: %d\n", - pg->genpd.name, err); + pr_err("failed to turn on PM domain %s: %d\n", pg->genpd.name, + err); return err; } @@ -483,13 +480,12 @@ static int tegra_genpd_power_on(struct generic_pm_domain *domain) static int tegra_genpd_power_off(struct generic_pm_domain *domain) { struct tegra_powergate *pg = to_powergate(domain); - struct tegra_pmc *pmc = pg->pmc; int err; err = tegra_powergate_power_down(pg); if (err) - dev_err(pmc->dev, "failed to turn off PM domain %s: %d\n", - pg->genpd.name, err); + pr_err("failed to turn off PM domain %s: %d\n", + pg->genpd.name, err); return err; } @@ -814,8 +810,7 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) id = tegra_powergate_lookup(pmc, np->name); if (id < 0) { - dev_err(pmc->dev, "powergate lookup failed for %s: %d\n", - np->name, id); + pr_err("powergate lookup failed for %s: %d\n", np->name, id); goto free_mem; } @@ -835,15 +830,13 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = tegra_powergate_of_get_clks(pg, np); if (err < 0) { - dev_err(pmc->dev, "failed to get clocks for %s: %d\n", - np->name, err); + pr_err("failed to get clocks for %s: %d\n", np->name, err); goto set_available; } err = tegra_powergate_of_get_resets(pg, np, off); if (err < 0) { - dev_err(pmc->dev, "failed to get resets for %s: %d\n", - np->name, err); + pr_err("failed to get resets for %s: %d\n", np->name, err); goto remove_clks; } @@ -866,12 +859,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { - dev_err(pmc->dev, "failed to add genpd provider for %s: %d\n", - np->name, err); + pr_err("failed to add genpd provider for %s: %d\n", np->name, + err); goto remove_resets; } - dev_dbg(pmc->dev, "added power domain %s\n", pg->genpd.name); + pr_debug("added power domain %s\n", pg->genpd.name); return; @@ -940,8 +933,10 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, unsigned long rate, value; pad = tegra_io_pad_find(pmc, id); - if (!pad) + if (!pad) { + pr_err("invalid I/O pad ID %u\n", id); return -ENOENT; + } if (pad->dpd == UINT_MAX) return -ENOTSUPP; @@ -957,8 +952,10 @@ static int tegra_io_pad_prepare(enum tegra_io_pad id, unsigned long *request, } rate = clk_get_rate(pmc->clk); - if (!rate) + if (!rate) { + pr_err("failed to get clock rate\n"); return -ENODEV; + } tegra_pmc_writel(DPD_SAMPLE_ENABLE, DPD_SAMPLE); @@ -1009,7 +1006,7 @@ int tegra_io_pad_power_enable(enum tegra_io_pad id) err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + pr_err("failed to prepare I/O pad: %d\n", err); goto unlock; } @@ -1017,7 +1014,7 @@ int tegra_io_pad_power_enable(enum tegra_io_pad id) err = tegra_io_pad_poll(status, mask, 0, 250); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + pr_err("failed to enable I/O pad: %d\n", err); goto unlock; } @@ -1045,7 +1042,7 @@ int tegra_io_pad_power_disable(enum tegra_io_pad id) err = tegra_io_pad_prepare(id, &request, &status, &mask); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_prepare() failed: %d\n", err); + pr_err("failed to prepare I/O pad: %d\n", err); goto unlock; } @@ -1053,7 +1050,7 @@ int tegra_io_pad_power_disable(enum tegra_io_pad id) err = tegra_io_pad_poll(status, mask, mask, 250); if (err < 0) { - dev_err(pmc->dev, "tegra_io_pad_poll() failed: %d\n", err); + pr_err("failed to disable I/O pad: %d\n", err); goto unlock; } -- cgit v1.2.3 From cd5ceda27d4b45b797ede85c844fc08da5aa70e3 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:55 +0100 Subject: soc/tegra: pmc: Check return code for pm_genpd_init() Commit 7eb231c337e0 ("PM / Domains: Convert pm_genpd_init() to return an error code") updated pm_genpd_init() to return an error code. Update the Tegra PMC driver to check the return value from pm_genpd_init() and handle any errors returned. Signed-off-by: Jon Hunter [treding@nvidia.com: use pr_err() instead of dev_err()] Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 78fffa22966f..bc4267c7fe15 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -855,7 +855,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) goto power_on_cleanup; - pm_genpd_init(&pg->genpd, NULL, off); + err = pm_genpd_init(&pg->genpd, NULL, off); + if (err < 0) { + pr_err("failed to initialise power domain %s: %d\n", np->name, + err); + goto remove_resets; + } err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { -- cgit v1.2.3 From 0b137340d04b9dfa911cc882bc26ed611671f5f5 Mon Sep 17 00:00:00 2001 From: Jon Hunter Date: Sat, 22 Oct 2016 20:23:56 +0100 Subject: soc/tegra: pmc: Remove genpd when adding provider fails Commit 3fe577107ccf ("PM / Domains: Add support for removing PM domains") add support for removing PM domains. Update the Tegra PMC driver to remove PM domains if we fail to add a provider for the PM domain. Please note that the code under 'power_on_cleanup' label does not really belong in the clean-up error path for tegra_powergate_add(). To keep the error path simple, remove this label and move the associated code to where it needs to be invoked. Signed-off-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index bc4267c7fe15..3400ec355adb 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -840,8 +840,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) goto remove_clks; } - if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) - goto power_on_cleanup; + if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS)) { + if (off) + WARN_ON(tegra_powergate_power_up(pg, true)); + + goto remove_resets; + } /* * FIXME: If XHCI is enabled for Tegra, then power-up the XUSB @@ -852,8 +856,12 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) * to be unused. */ if (IS_ENABLED(CONFIG_USB_XHCI_TEGRA) && - (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) - goto power_on_cleanup; + (id == TEGRA_POWERGATE_XUSBA || id == TEGRA_POWERGATE_XUSBC)) { + if (off) + WARN_ON(tegra_powergate_power_up(pg, true)); + + goto remove_resets; + } err = pm_genpd_init(&pg->genpd, NULL, off); if (err < 0) { @@ -866,16 +874,15 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) if (err < 0) { pr_err("failed to add genpd provider for %s: %d\n", np->name, err); - goto remove_resets; + goto remove_genpd; } pr_debug("added power domain %s\n", pg->genpd.name); return; -power_on_cleanup: - if (off) - WARN_ON(tegra_powergate_power_up(pg, true)); +remove_genpd: + pm_genpd_remove(&pg->genpd); remove_resets: while (pg->num_resets--) -- cgit v1.2.3 From 4522112069a976908e32e5dd3231c9272d19794a Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 8 Nov 2016 11:05:03 +0100 Subject: soc/tegra: pmc: Use consistent naming for PM domains The various error messages refer to the PM domains as "power domain", "genpd" and "PM domain". That's confusing, so convert all error messages to use the most prominent: "PM domain". Acked-by: Jon Hunter Signed-off-by: Thierry Reding --- drivers/soc/tegra/pmc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c index 3400ec355adb..e233dd5dcab3 100644 --- a/drivers/soc/tegra/pmc.c +++ b/drivers/soc/tegra/pmc.c @@ -865,19 +865,19 @@ static void tegra_powergate_add(struct tegra_pmc *pmc, struct device_node *np) err = pm_genpd_init(&pg->genpd, NULL, off); if (err < 0) { - pr_err("failed to initialise power domain %s: %d\n", np->name, + pr_err("failed to initialise PM domain %s: %d\n", np->name, err); goto remove_resets; } err = of_genpd_add_provider_simple(np, &pg->genpd); if (err < 0) { - pr_err("failed to add genpd provider for %s: %d\n", np->name, - err); + pr_err("failed to add PM domain provider for %s: %d\n", + np->name, err); goto remove_genpd; } - pr_debug("added power domain %s\n", pg->genpd.name); + pr_debug("added PM domain %s\n", pg->genpd.name); return; -- cgit v1.2.3 From b6cc9474e2dd9f0c19b694b40961d81117f1e918 Mon Sep 17 00:00:00 2001 From: David Daney Date: Fri, 28 Oct 2016 14:15:02 -0700 Subject: of, numa: Return NUMA_NO_NODE from disable of_node_to_nid() if nid not possible. On arm64 NUMA kernels we can pass "numa=off" on the command line to disable NUMA. A side effect of this is that kmalloc_node() calls to non-zero nodes will crash the system with an OOPS: [ 0.000000] ITS@0x0000901000020000: allocated 2097152 Devices @10002000000 (flat, esz 8, psz 64K, shr 1) [ 0.000000] Unable to handle kernel NULL pointer dereference at virtual address 00001680 [ 0.000000] pgd = fffffc0009470000 [ 0.000000] [00001680] *pgd=0000010ffff90003, *pud=0000010ffff90003, *pmd=0000010ffff90003, *pte=0000000000000000 [ 0.000000] Internal error: Oops: 96000006 [#1] SMP . . . [ 0.000000] [] __alloc_pages_nodemask+0xa4/0xe68 [ 0.000000] [] new_slab+0xd0/0x564 [ 0.000000] [] ___slab_alloc+0x2e4/0x514 [ 0.000000] [] __slab_alloc+0x48/0x58 [ 0.000000] [] __kmalloc_node+0xd0/0x2dc [ 0.000000] [] __irq_domain_add+0x7c/0x164 [ 0.000000] [] its_probe+0x784/0x81c [ 0.000000] [] its_init+0x48/0x1b0 [ 0.000000] [] gic_init_bases+0x228/0x360 [ 0.000000] [] gic_of_init+0x148/0x1cc [ 0.000000] [] of_irq_init+0x184/0x298 [ 0.000000] [] irqchip_init+0x14/0x38 [ 0.000000] [] init_IRQ+0xc/0x30 [ 0.000000] [] start_kernel+0x240/0x3b8 [ 0.000000] [] __primary_switched+0x30/0x6c [ 0.000000] Code: 912ec2a0 b9403809 0a0902fb 37b007db (f9400300) . . . This is caused by code like this in kernel/irq/irqdomain.c domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size), GFP_KERNEL, of_node_to_nid(of_node)); When NUMA is disabled, the concept of a node is really undefined, so of_node_to_nid() should unconditionally return NUMA_NO_NODE. Fix by returning NUMA_NO_NODE when the nid is not in the set of possible nodes. Reported-by: Gilbert Netzer Signed-off-by: David Daney Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Rob Herring --- drivers/of/of_numa.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/of/of_numa.c b/drivers/of/of_numa.c index f63d4b0deff0..a53982a330ea 100644 --- a/drivers/of/of_numa.c +++ b/drivers/of/of_numa.c @@ -176,7 +176,12 @@ int of_node_to_nid(struct device_node *device) np->name); of_node_put(np); - if (!r) + /* + * If numa=off passed on command line, or with a defective + * device tree, the nid may not be in the set of possible + * nodes. Check for this case and return NUMA_NO_NODE. + */ + if (!r && nid < MAX_NUMNODES && node_possible(nid)) return nid; return NUMA_NO_NODE; -- cgit v1.2.3 From a67976ecc81bfcaef74151ee7fb3117ca2189eff Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:21 -0700 Subject: of: Remove comments that state the obvious, to reduce clutter Remove comments that report what is obvious from the code. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 31 ++----------------------------- 1 file changed, 2 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 46325d6394cf..4ff0220d7aa2 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -36,7 +36,6 @@ static struct device_node *__of_find_node_by_full_name(struct device_node *node, if (node == NULL) return NULL; - /* check */ if (of_node_cmp(node->full_name, full_name) == 0) return of_node_get(node); @@ -60,7 +59,6 @@ static phandle of_get_tree_max_phandle(void) phandle phandle; unsigned long flags; - /* now search recursively */ raw_spin_lock_irqsave(&devtree_lock, flags); phandle = 0; for_each_of_allnodes(node) { @@ -75,8 +73,6 @@ static phandle of_get_tree_max_phandle(void) /* * Adjust a subtree's phandle values by a given delta. - * Makes sure not to just adjust the device node's phandle value, - * but modify the phandle properties values as well. */ static void __of_adjust_tree_phandles(struct device_node *node, int phandle_delta) @@ -85,32 +81,25 @@ static void __of_adjust_tree_phandles(struct device_node *node, struct property *prop; phandle phandle; - /* first adjust the node's phandle direct value */ if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL) node->phandle += phandle_delta; - /* now adjust phandle & linux,phandle values */ for_each_property_of_node(node, prop) { - /* only look for these two */ if (of_prop_cmp(prop->name, "phandle") != 0 && of_prop_cmp(prop->name, "linux,phandle") != 0) continue; - /* must be big enough */ if (prop->length < 4) continue; - /* read phandle value */ phandle = be32_to_cpup(prop->value); - if (phandle == OF_PHANDLE_ILLEGAL) /* unresolved */ + if (phandle == OF_PHANDLE_ILLEGAL) continue; - /* adjust */ *(uint32_t *)prop->value = cpu_to_be32(node->phandle); } - /* now do the children recursively */ for_each_child_of_node(node, child) __of_adjust_tree_phandles(child, phandle_delta); } @@ -125,7 +114,6 @@ static int __of_adjust_phandle_ref(struct device_node *node, int offset, propcurlen; int err = 0; - /* make a copy */ propval = kmalloc(rprop->length, GFP_KERNEL); if (!propval) { pr_err("%s: Could not copy value of '%s'\n", @@ -165,7 +153,6 @@ static int __of_adjust_phandle_ref(struct device_node *node, goto err_fail; } - /* look into the resolve node for the full path */ refnode = __of_find_node_by_full_name(node, nodestr); if (!refnode) { pr_warn("%s: Could not find refnode '%s'\n", @@ -173,7 +160,6 @@ static int __of_adjust_phandle_ref(struct device_node *node, continue; } - /* now find the property */ for_each_property_of_node(refnode, sprop) { if (of_prop_cmp(sprop->name, propstr) == 0) break; @@ -240,7 +226,6 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, } count = rprop->length / sizeof(__be32); - /* now find the target property */ for_each_property_of_node(target, sprop) { if (of_prop_cmp(sprop->name, rprop->name) == 0) break; @@ -254,7 +239,6 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, for (i = 0; i < count; i++) { off = be32_to_cpu(((__be32 *)rprop->value)[i]); - /* make sure the offset doesn't overstep (even wrap) */ if (off >= sprop->length || (off + 4) > sprop->length) { pr_err("%s: Illegal property '%s' @%s\n", @@ -264,7 +248,6 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, } if (phandle_delta) { - /* adjust */ phandle = be32_to_cpu(*(__be32 *)(sprop->value + off)); phandle += phandle_delta; *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle); @@ -320,22 +303,18 @@ int of_resolve_phandles(struct device_node *resolve) if (resolve && !of_node_check_flag(resolve, OF_DETACHED)) pr_err("%s: node %s not detached\n", __func__, resolve->full_name); - /* the resolve node must exist, and be detached */ if (!resolve || !of_node_check_flag(resolve, OF_DETACHED)) return -EINVAL; - /* first we need to adjust the phandles */ phandle_delta = of_get_tree_max_phandle() + 1; __of_adjust_tree_phandles(resolve, phandle_delta); - /* locate the local fixups */ childroot = NULL; for_each_child_of_node(resolve, childroot) if (of_node_cmp(childroot->name, "__local_fixups__") == 0) break; if (childroot != NULL) { - /* resolve root is guaranteed to be the '/' */ err = __of_adjust_tree_phandle_references(childroot, resolve, 0); if (err != 0) @@ -349,10 +328,8 @@ int of_resolve_phandles(struct device_node *resolve) resolve_sym = NULL; resolve_fix = NULL; - /* this may fail (if no fixups are required) */ root_sym = of_find_node_by_path("/__symbols__"); - /* locate the symbols & fixups nodes on resolve */ for_each_child_of_node(resolve, child) { if (!resolve_sym && @@ -363,18 +340,15 @@ int of_resolve_phandles(struct device_node *resolve) of_node_cmp(child->name, "__fixups__") == 0) resolve_fix = child; - /* both found, don't bother anymore */ if (resolve_sym && resolve_fix) break; } - /* we do allow for the case where no fixups are needed */ if (!resolve_fix) { - err = 0; /* no error */ + err = 0; goto out; } - /* we need to fixup, but no root symbols... */ if (!root_sym) { pr_err("%s: no symbols in root of device tree.\n", __func__); err = -EINVAL; @@ -415,7 +389,6 @@ int of_resolve_phandles(struct device_node *resolve) } out: - /* NULL is handled by of_node_put as NOP */ of_node_put(root_sym); return err; -- cgit v1.2.3 From 96d1c8e8e38f264fa65c74545fbb913df3af10d3 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:22 -0700 Subject: of: Remove excessive printks to reduce clutter. Remove extra debug and error printks. A single pr_err() will be added at the end of this series to replace many of these error messages. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 53 ++++++++------------------------------------------- 1 file changed, 8 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 4ff0220d7aa2..c61ba99a1792 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -115,11 +115,8 @@ static int __of_adjust_phandle_ref(struct device_node *node, int err = 0; propval = kmalloc(rprop->length, GFP_KERNEL); - if (!propval) { - pr_err("%s: Could not copy value of '%s'\n", - __func__, rprop->name); + if (!propval) return -ENOMEM; - } memcpy(propval, rprop->value, rprop->length); propend = propval + rprop->length; @@ -129,8 +126,6 @@ static int __of_adjust_phandle_ref(struct device_node *node, nodestr = propcur; s = strchr(propcur, ':'); if (!s) { - pr_err("%s: Illegal symbol entry '%s' (1)\n", - __func__, propcur); err = -EINVAL; goto err_fail; } @@ -139,26 +134,18 @@ static int __of_adjust_phandle_ref(struct device_node *node, propstr = s; s = strchr(s, ':'); if (!s) { - pr_err("%s: Illegal symbol entry '%s' (2)\n", - __func__, (char *)rprop->value); err = -EINVAL; goto err_fail; } *s++ = '\0'; err = kstrtoint(s, 10, &offset); - if (err != 0) { - pr_err("%s: Could get offset '%s'\n", - __func__, (char *)rprop->value); + if (err != 0) goto err_fail; - } refnode = __of_find_node_by_full_name(node, nodestr); - if (!refnode) { - pr_warn("%s: Could not find refnode '%s'\n", - __func__, (char *)rprop->value); + if (!refnode) continue; - } for_each_property_of_node(refnode, sprop) { if (of_prop_cmp(sprop->name, propstr) == 0) @@ -167,8 +154,6 @@ static int __of_adjust_phandle_ref(struct device_node *node, of_node_put(refnode); if (!sprop) { - pr_err("%s: Could not find property '%s'\n", - __func__, (char *)rprop->value); err = -ENOENT; goto err_fail; } @@ -219,11 +204,8 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, of_prop_cmp(rprop->name, "linux,phandle") == 0) continue; - if ((rprop->length % 4) != 0 || rprop->length == 0) { - pr_err("%s: Illegal property (size) '%s' @%s\n", - __func__, rprop->name, node->full_name); + if ((rprop->length % 4) != 0 || rprop->length == 0) return -EINVAL; - } count = rprop->length / sizeof(__be32); for_each_property_of_node(target, sprop) { @@ -231,21 +213,13 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, break; } - if (sprop == NULL) { - pr_err("%s: Could not find target property '%s' @%s\n", - __func__, rprop->name, node->full_name); + if (sprop == NULL) return -EINVAL; - } for (i = 0; i < count; i++) { off = be32_to_cpu(((__be32 *)rprop->value)[i]); - if (off >= sprop->length || - (off + 4) > sprop->length) { - pr_err("%s: Illegal property '%s' @%s\n", - __func__, rprop->name, - node->full_name); + if (off >= sprop->length || (off + 4) > sprop->length) return -EINVAL; - } if (phandle_delta) { phandle = be32_to_cpu(*(__be32 *)(sprop->value + off)); @@ -261,11 +235,8 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, if (__of_node_name_cmp(child, childtarget) == 0) break; - if (!childtarget) { - pr_err("%s: Could not find target child '%s' @%s\n", - __func__, child->name, node->full_name); + if (!childtarget) return -EINVAL; - } err = __of_adjust_tree_phandle_references(child, childtarget, phandle_delta); @@ -363,16 +334,11 @@ int of_resolve_phandles(struct device_node *resolve) err = of_property_read_string(root_sym, rprop->name, &refpath); - if (err != 0) { - pr_err("%s: Could not find symbol '%s'\n", - __func__, rprop->name); + if (err != 0) goto out; - } refnode = of_find_node_by_path(refpath); if (!refnode) { - pr_err("%s: Could not find node by path '%s'\n", - __func__, refpath); err = -ENOENT; goto out; } @@ -380,9 +346,6 @@ int of_resolve_phandles(struct device_node *resolve) phandle = refnode->phandle; of_node_put(refnode); - pr_debug("%s: %s phandle is 0x%08x\n", - __func__, rprop->name, phandle); - err = __of_adjust_phandle_ref(resolve, rprop, phandle); if (err) break; -- cgit v1.2.3 From 9f27ede49dc481a35244c03193236ac2fddd10a1 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:23 -0700 Subject: of: Convert comparisons to zero or NULL to logical expressions Convert comparisons to zero or NULL to logical expressions. A small number of such comparisons remain where they provide more clarity of the numeric nature of a variable. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 42 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index c61ba99a1792..31fd3800787a 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -33,10 +33,10 @@ static struct device_node *__of_find_node_by_full_name(struct device_node *node, { struct device_node *child, *found; - if (node == NULL) + if (!node) return NULL; - if (of_node_cmp(node->full_name, full_name) == 0) + if (!of_node_cmp(node->full_name, full_name)) return of_node_get(node); for_each_child_of_node(node, child) { @@ -86,8 +86,8 @@ static void __of_adjust_tree_phandles(struct device_node *node, for_each_property_of_node(node, prop) { - if (of_prop_cmp(prop->name, "phandle") != 0 && - of_prop_cmp(prop->name, "linux,phandle") != 0) + if (of_prop_cmp(prop->name, "phandle") && + of_prop_cmp(prop->name, "linux,phandle")) continue; if (prop->length < 4) @@ -140,7 +140,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, *s++ = '\0'; err = kstrtoint(s, 10, &offset); - if (err != 0) + if (err) goto err_fail; refnode = __of_find_node_by_full_name(node, nodestr); @@ -148,7 +148,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, continue; for_each_property_of_node(refnode, sprop) { - if (of_prop_cmp(sprop->name, propstr) == 0) + if (!of_prop_cmp(sprop->name, propstr)) break; } of_node_put(refnode); @@ -193,15 +193,15 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, unsigned int off; phandle phandle; - if (node == NULL) + if (!node) return 0; for_each_property_of_node(node, rprop) { /* skip properties added automatically */ - if (of_prop_cmp(rprop->name, "name") == 0 || - of_prop_cmp(rprop->name, "phandle") == 0 || - of_prop_cmp(rprop->name, "linux,phandle") == 0) + if (!of_prop_cmp(rprop->name, "name") || + !of_prop_cmp(rprop->name, "phandle") || + !of_prop_cmp(rprop->name, "linux,phandle")) continue; if ((rprop->length % 4) != 0 || rprop->length == 0) @@ -209,11 +209,11 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, count = rprop->length / sizeof(__be32); for_each_property_of_node(target, sprop) { - if (of_prop_cmp(sprop->name, rprop->name) == 0) + if (!of_prop_cmp(sprop->name, rprop->name)) break; } - if (sprop == NULL) + if (!sprop) return -EINVAL; for (i = 0; i < count; i++) { @@ -232,7 +232,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, for_each_child_of_node(node, child) { for_each_child_of_node(target, childtarget) - if (__of_node_name_cmp(child, childtarget) == 0) + if (!__of_node_name_cmp(child, childtarget)) break; if (!childtarget) @@ -240,7 +240,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, err = __of_adjust_tree_phandle_references(child, childtarget, phandle_delta); - if (err != 0) + if (err) return err; } @@ -282,13 +282,13 @@ int of_resolve_phandles(struct device_node *resolve) childroot = NULL; for_each_child_of_node(resolve, childroot) - if (of_node_cmp(childroot->name, "__local_fixups__") == 0) + if (!of_node_cmp(childroot->name, "__local_fixups__")) break; if (childroot != NULL) { err = __of_adjust_tree_phandle_references(childroot, resolve, 0); - if (err != 0) + if (err) return err; BUG_ON(__of_adjust_tree_phandle_references(childroot, @@ -303,12 +303,10 @@ int of_resolve_phandles(struct device_node *resolve) for_each_child_of_node(resolve, child) { - if (!resolve_sym && - of_node_cmp(child->name, "__symbols__") == 0) + if (!resolve_sym && !of_node_cmp(child->name, "__symbols__")) resolve_sym = child; - if (!resolve_fix && - of_node_cmp(child->name, "__fixups__") == 0) + if (!resolve_fix && !of_node_cmp(child->name, "__fixups__")) resolve_fix = child; if (resolve_sym && resolve_fix) @@ -329,12 +327,12 @@ int of_resolve_phandles(struct device_node *resolve) for_each_property_of_node(resolve_fix, rprop) { /* skip properties added automatically */ - if (of_prop_cmp(rprop->name, "name") == 0) + if (!of_prop_cmp(rprop->name, "name")) continue; err = of_property_read_string(root_sym, rprop->name, &refpath); - if (err != 0) + if (err) goto out; refnode = of_find_node_by_path(refpath); -- cgit v1.2.3 From f94823f2ebd5436d4377d20b762fd2c1bc3263f6 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:24 -0700 Subject: of: Rename functions to more accurately reflect what they do Some function names are misleading or do not provide a good sense of what they do. Rename the functions to ne more informative. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 31fd3800787a..3d123b612789 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -53,7 +53,7 @@ static struct device_node *__of_find_node_by_full_name(struct device_node *node, /* * Find live tree's maximum phandle value. */ -static phandle of_get_tree_max_phandle(void) +static phandle live_tree_max_phandle(void) { struct device_node *node; phandle phandle; @@ -74,7 +74,7 @@ static phandle of_get_tree_max_phandle(void) /* * Adjust a subtree's phandle values by a given delta. */ -static void __of_adjust_tree_phandles(struct device_node *node, +static void adjust_overlay_phandles(struct device_node *node, int phandle_delta) { struct device_node *child; @@ -101,10 +101,10 @@ static void __of_adjust_tree_phandles(struct device_node *node, } for_each_child_of_node(node, child) - __of_adjust_tree_phandles(child, phandle_delta); + adjust_overlay_phandles(child, phandle_delta); } -static int __of_adjust_phandle_ref(struct device_node *node, +static int update_usages_of_a_phandle_reference(struct device_node *node, struct property *rprop, int value) { phandle phandle; @@ -184,7 +184,7 @@ static int __of_node_name_cmp(const struct device_node *dn1, * Does not take any devtree locks so make sure you call this on a tree * which is at the detached state. */ -static int __of_adjust_tree_phandle_references(struct device_node *node, +static int adjust_local_phandle_references(struct device_node *node, struct device_node *target, int phandle_delta) { struct device_node *child, *childtarget; @@ -238,7 +238,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node, if (!childtarget) return -EINVAL; - err = __of_adjust_tree_phandle_references(child, childtarget, + err = adjust_local_phandle_references(child, childtarget, phandle_delta); if (err) return err; @@ -277,8 +277,8 @@ int of_resolve_phandles(struct device_node *resolve) if (!resolve || !of_node_check_flag(resolve, OF_DETACHED)) return -EINVAL; - phandle_delta = of_get_tree_max_phandle() + 1; - __of_adjust_tree_phandles(resolve, phandle_delta); + phandle_delta = live_tree_max_phandle() + 1; + adjust_overlay_phandles(resolve, phandle_delta); childroot = NULL; for_each_child_of_node(resolve, childroot) @@ -286,12 +286,12 @@ int of_resolve_phandles(struct device_node *resolve) break; if (childroot != NULL) { - err = __of_adjust_tree_phandle_references(childroot, + err = adjust_local_phandle_references(childroot, resolve, 0); if (err) return err; - BUG_ON(__of_adjust_tree_phandle_references(childroot, + BUG_ON(adjust_local_phandle_references(childroot, resolve, phandle_delta)); } @@ -344,7 +344,7 @@ int of_resolve_phandles(struct device_node *resolve) phandle = refnode->phandle; of_node_put(refnode); - err = __of_adjust_phandle_ref(resolve, rprop, phandle); + err = update_usages_of_a_phandle_reference(resolve, rprop, phandle); if (err) break; } -- cgit v1.2.3 From fad556bf3f5a9182aa8ec9d1a988735dabfd6631 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:25 -0700 Subject: of: Remove prefix "__of_" from local function names Remove "__of_" prefix from local function names. The pattern of a leading "__" is used in drivers/of/ to signify a function that must be called with a lock held. These functions do not fit that pattern. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 3d123b612789..0ce38aa0ed3c 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -28,7 +28,7 @@ * Find a node with the give full name by recursively following any of * the child node links. */ -static struct device_node *__of_find_node_by_full_name(struct device_node *node, +static struct device_node *find_node_by_full_name(struct device_node *node, const char *full_name) { struct device_node *child, *found; @@ -40,7 +40,7 @@ static struct device_node *__of_find_node_by_full_name(struct device_node *node, return of_node_get(node); for_each_child_of_node(node, child) { - found = __of_find_node_by_full_name(child, full_name); + found = find_node_by_full_name(child, full_name); if (found != NULL) { of_node_put(child); return found; @@ -143,7 +143,7 @@ static int update_usages_of_a_phandle_reference(struct device_node *node, if (err) goto err_fail; - refnode = __of_find_node_by_full_name(node, nodestr); + refnode = find_node_by_full_name(node, nodestr); if (!refnode) continue; @@ -168,7 +168,7 @@ err_fail: } /* compare nodes taking into account that 'name' strips out the @ part */ -static int __of_node_name_cmp(const struct device_node *dn1, +static int node_name_cmp(const struct device_node *dn1, const struct device_node *dn2) { const char *n1 = strrchr(dn1->full_name, '/') ? : "/"; @@ -232,7 +232,7 @@ static int adjust_local_phandle_references(struct device_node *node, for_each_child_of_node(node, child) { for_each_child_of_node(target, childtarget) - if (!__of_node_name_cmp(child, childtarget)) + if (!node_name_cmp(child, childtarget)) break; if (!childtarget) -- cgit v1.2.3 From 25e1687767612e593c054d5855f6717cf8104c1f Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:26 -0700 Subject: of: Rename variables to better reflect purpose or follow convention Rename variables to better reflect what their purpose is. As a side effect, this reduces the need for some of the comments previously removed in this series. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 172 +++++++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 87 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 0ce38aa0ed3c..0778747cdd58 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -74,17 +74,17 @@ static phandle live_tree_max_phandle(void) /* * Adjust a subtree's phandle values by a given delta. */ -static void adjust_overlay_phandles(struct device_node *node, +static void adjust_overlay_phandles(struct device_node *overlay, int phandle_delta) { struct device_node *child; struct property *prop; phandle phandle; - if (node->phandle != 0 && node->phandle != OF_PHANDLE_ILLEGAL) - node->phandle += phandle_delta; + if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL) + overlay->phandle += phandle_delta; - for_each_property_of_node(node, prop) { + for_each_property_of_node(overlay, prop) { if (of_prop_cmp(prop->name, "phandle") && of_prop_cmp(prop->name, "linux,phandle")) @@ -97,41 +97,40 @@ static void adjust_overlay_phandles(struct device_node *node, if (phandle == OF_PHANDLE_ILLEGAL) continue; - *(uint32_t *)prop->value = cpu_to_be32(node->phandle); + *(uint32_t *)prop->value = cpu_to_be32(overlay->phandle); } - for_each_child_of_node(node, child) + for_each_child_of_node(overlay, child) adjust_overlay_phandles(child, phandle_delta); } -static int update_usages_of_a_phandle_reference(struct device_node *node, - struct property *rprop, int value) +static int update_usages_of_a_phandle_reference(struct device_node *overlay, + struct property *prop_fixup, phandle phandle) { - phandle phandle; struct device_node *refnode; - struct property *sprop; - char *propval, *propcur, *propend, *nodestr, *propstr, *s; - int offset, propcurlen; + struct property *prop; + char *value, *cur, *end, *node_path, *prop_name, *s; + int offset, len; int err = 0; - propval = kmalloc(rprop->length, GFP_KERNEL); - if (!propval) + value = kmalloc(prop_fixup->length, GFP_KERNEL); + if (!value) return -ENOMEM; - memcpy(propval, rprop->value, rprop->length); + memcpy(value, prop_fixup->value, prop_fixup->length); - propend = propval + rprop->length; - for (propcur = propval; propcur < propend; propcur += propcurlen + 1) { - propcurlen = strlen(propcur); + end = value + prop_fixup->length; + for (cur = value; cur < end; cur += len + 1) { + len = strlen(cur); - nodestr = propcur; - s = strchr(propcur, ':'); + node_path = cur; + s = strchr(cur, ':'); if (!s) { err = -EINVAL; goto err_fail; } *s++ = '\0'; - propstr = s; + prop_name = s; s = strchr(s, ':'); if (!s) { err = -EINVAL; @@ -143,27 +142,26 @@ static int update_usages_of_a_phandle_reference(struct device_node *node, if (err) goto err_fail; - refnode = find_node_by_full_name(node, nodestr); + refnode = find_node_by_full_name(overlay, node_path); if (!refnode) continue; - for_each_property_of_node(refnode, sprop) { - if (!of_prop_cmp(sprop->name, propstr)) + for_each_property_of_node(refnode, prop) { + if (!of_prop_cmp(prop->name, prop_name)) break; } of_node_put(refnode); - if (!sprop) { + if (!prop) { err = -ENOENT; goto err_fail; } - phandle = value; - *(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle); + *(__be32 *)(prop->value + offset) = cpu_to_be32(phandle); } err_fail: - kfree(propval); + kfree(value); return err; } @@ -184,61 +182,61 @@ static int node_name_cmp(const struct device_node *dn1, * Does not take any devtree locks so make sure you call this on a tree * which is at the detached state. */ -static int adjust_local_phandle_references(struct device_node *node, - struct device_node *target, int phandle_delta) +static int adjust_local_phandle_references(struct device_node *local_fixups, + struct device_node *overlay, int phandle_delta) { - struct device_node *child, *childtarget; - struct property *rprop, *sprop; + struct device_node *child, *overlay_child; + struct property *prop_fix, *prop; int err, i, count; unsigned int off; phandle phandle; - if (!node) + if (!local_fixups) return 0; - for_each_property_of_node(node, rprop) { + for_each_property_of_node(local_fixups, prop_fix) { /* skip properties added automatically */ - if (!of_prop_cmp(rprop->name, "name") || - !of_prop_cmp(rprop->name, "phandle") || - !of_prop_cmp(rprop->name, "linux,phandle")) + if (!of_prop_cmp(prop_fix->name, "name") || + !of_prop_cmp(prop_fix->name, "phandle") || + !of_prop_cmp(prop_fix->name, "linux,phandle")) continue; - if ((rprop->length % 4) != 0 || rprop->length == 0) + if ((prop_fix->length % 4) != 0 || prop_fix->length == 0) return -EINVAL; - count = rprop->length / sizeof(__be32); + count = prop_fix->length / sizeof(__be32); - for_each_property_of_node(target, sprop) { - if (!of_prop_cmp(sprop->name, rprop->name)) + for_each_property_of_node(overlay, prop) { + if (!of_prop_cmp(prop->name, prop_fix->name)) break; } - if (!sprop) + if (!prop) return -EINVAL; for (i = 0; i < count; i++) { - off = be32_to_cpu(((__be32 *)rprop->value)[i]); - if (off >= sprop->length || (off + 4) > sprop->length) + off = be32_to_cpu(((__be32 *)prop_fix->value)[i]); + if (off >= prop->length || (off + 4) > prop->length) return -EINVAL; if (phandle_delta) { - phandle = be32_to_cpu(*(__be32 *)(sprop->value + off)); + phandle = be32_to_cpu(*(__be32 *)(prop->value + off)); phandle += phandle_delta; - *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle); + *(__be32 *)(prop->value + off) = cpu_to_be32(phandle); } } } - for_each_child_of_node(node, child) { + for_each_child_of_node(local_fixups, child) { - for_each_child_of_node(target, childtarget) - if (!node_name_cmp(child, childtarget)) + for_each_child_of_node(overlay, overlay_child) + if (!node_name_cmp(child, overlay_child)) break; - if (!childtarget) + if (!overlay_child) return -EINVAL; - err = adjust_local_phandle_references(child, childtarget, + err = adjust_local_phandle_references(child, overlay_child, phandle_delta); if (err) return err; @@ -260,78 +258,78 @@ static int adjust_local_phandle_references(struct device_node *node, * are fit to be inserted or operate upon the live tree. * Returns 0 on success or a negative error value on error. */ -int of_resolve_phandles(struct device_node *resolve) +int of_resolve_phandles(struct device_node *overlay) { - struct device_node *child, *childroot, *refnode; - struct device_node *root_sym, *resolve_sym, *resolve_fix; - struct property *rprop; + struct device_node *child, *local_fixups, *refnode; + struct device_node *tree_symbols, *overlay_symbols, *overlay_fixups; + struct property *prop; const char *refpath; phandle phandle, phandle_delta; int err; - if (!resolve) - pr_err("%s: null node\n", __func__); - if (resolve && !of_node_check_flag(resolve, OF_DETACHED)) + if (!overlay) + pr_err("%s: null overlay\n", __func__); + if (overlay && !of_node_check_flag(overlay, OF_DETACHED)) pr_err("%s: node %s not detached\n", __func__, - resolve->full_name); - if (!resolve || !of_node_check_flag(resolve, OF_DETACHED)) + overlay->full_name); + if (!overlay || !of_node_check_flag(overlay, OF_DETACHED)) return -EINVAL; phandle_delta = live_tree_max_phandle() + 1; - adjust_overlay_phandles(resolve, phandle_delta); + adjust_overlay_phandles(overlay, phandle_delta); - childroot = NULL; - for_each_child_of_node(resolve, childroot) - if (!of_node_cmp(childroot->name, "__local_fixups__")) + local_fixups = NULL; + for_each_child_of_node(overlay, local_fixups) + if (!of_node_cmp(local_fixups->name, "__local_fixups__")) break; - if (childroot != NULL) { - err = adjust_local_phandle_references(childroot, - resolve, 0); + if (local_fixups != NULL) { + err = adjust_local_phandle_references(local_fixups, + overlay, 0); if (err) return err; - BUG_ON(adjust_local_phandle_references(childroot, - resolve, phandle_delta)); + BUG_ON(adjust_local_phandle_references(local_fixups, + overlay, phandle_delta)); } - root_sym = NULL; - resolve_sym = NULL; - resolve_fix = NULL; + tree_symbols = NULL; + overlay_symbols = NULL; + overlay_fixups = NULL; - root_sym = of_find_node_by_path("/__symbols__"); + tree_symbols = of_find_node_by_path("/__symbols__"); - for_each_child_of_node(resolve, child) { + for_each_child_of_node(overlay, child) { - if (!resolve_sym && !of_node_cmp(child->name, "__symbols__")) - resolve_sym = child; + if (!overlay_symbols && !of_node_cmp(child->name, "__symbols__")) + overlay_symbols = child; - if (!resolve_fix && !of_node_cmp(child->name, "__fixups__")) - resolve_fix = child; + if (!overlay_fixups && !of_node_cmp(child->name, "__fixups__")) + overlay_fixups = child; - if (resolve_sym && resolve_fix) + if (overlay_symbols && overlay_fixups) break; } - if (!resolve_fix) { + if (!overlay_fixups) { err = 0; goto out; } - if (!root_sym) { + if (!tree_symbols) { pr_err("%s: no symbols in root of device tree.\n", __func__); err = -EINVAL; goto out; } - for_each_property_of_node(resolve_fix, rprop) { + for_each_property_of_node(overlay_fixups, prop) { /* skip properties added automatically */ - if (!of_prop_cmp(rprop->name, "name")) + if (!of_prop_cmp(prop->name, "name")) continue; - err = of_property_read_string(root_sym, - rprop->name, &refpath); + err = of_property_read_string(tree_symbols, + prop->name, &refpath); if (err) goto out; @@ -344,13 +342,13 @@ int of_resolve_phandles(struct device_node *resolve) phandle = refnode->phandle; of_node_put(refnode); - err = update_usages_of_a_phandle_reference(resolve, rprop, phandle); + err = update_usages_of_a_phandle_reference(overlay, prop, phandle); if (err) break; } out: - of_node_put(root_sym); + of_node_put(tree_symbols); return err; } -- cgit v1.2.3 From 624ab2a49ca30fd61f6c268567d74aaaf949a489 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:27 -0700 Subject: of: Update structure of code to be clearer, also remove BUG_ON() Remove BUG_ON(), which is frowned upon and not needed here. Restructure to remove some excessive complexity. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 48 +++++++++++++++++------------------------------- 1 file changed, 17 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 0778747cdd58..708daca1d522 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -136,8 +136,8 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay, err = -EINVAL; goto err_fail; } - *s++ = '\0'; + err = kstrtoint(s, 10, &offset); if (err) goto err_fail; @@ -219,11 +219,9 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, if (off >= prop->length || (off + 4) > prop->length) return -EINVAL; - if (phandle_delta) { - phandle = be32_to_cpu(*(__be32 *)(prop->value + off)); - phandle += phandle_delta; - *(__be32 *)(prop->value + off) = cpu_to_be32(phandle); - } + phandle = be32_to_cpu(*(__be32 *)(prop->value + off)); + phandle += phandle_delta; + *(__be32 *)(prop->value + off) = cpu_to_be32(phandle); } } @@ -267,48 +265,36 @@ int of_resolve_phandles(struct device_node *overlay) phandle phandle, phandle_delta; int err; - if (!overlay) - pr_err("%s: null overlay\n", __func__); - if (overlay && !of_node_check_flag(overlay, OF_DETACHED)) - pr_err("%s: node %s not detached\n", __func__, - overlay->full_name); - if (!overlay || !of_node_check_flag(overlay, OF_DETACHED)) + if (!overlay) { + pr_err("null overlay\n"); + return -EINVAL; + } + if (!of_node_check_flag(overlay, OF_DETACHED)) { + pr_err("overlay not detached\n"); return -EINVAL; + } phandle_delta = live_tree_max_phandle() + 1; adjust_overlay_phandles(overlay, phandle_delta); - local_fixups = NULL; for_each_child_of_node(overlay, local_fixups) if (!of_node_cmp(local_fixups->name, "__local_fixups__")) break; - if (local_fixups != NULL) { - err = adjust_local_phandle_references(local_fixups, - overlay, 0); - if (err) - return err; + err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); + if (err) + return err; - BUG_ON(adjust_local_phandle_references(local_fixups, - overlay, phandle_delta)); - } - - tree_symbols = NULL; overlay_symbols = NULL; overlay_fixups = NULL; tree_symbols = of_find_node_by_path("/__symbols__"); for_each_child_of_node(overlay, child) { - - if (!overlay_symbols && !of_node_cmp(child->name, "__symbols__")) + if (!of_node_cmp(child->name, "__symbols__")) overlay_symbols = child; - - if (!overlay_fixups && !of_node_cmp(child->name, "__fixups__")) + if (!of_node_cmp(child->name, "__fixups__")) overlay_fixups = child; - - if (overlay_symbols && overlay_fixups) - break; } if (!overlay_fixups) { @@ -317,7 +303,7 @@ int of_resolve_phandles(struct device_node *overlay) } if (!tree_symbols) { - pr_err("%s: no symbols in root of device tree.\n", __func__); + pr_err("no symbols in root of device tree.\n"); err = -EINVAL; goto out; } -- cgit v1.2.3 From ea8229b78899bd1edee3051686a4370e5dd56762 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:28 -0700 Subject: of: Remove redundant size check Remove a redundant check of buffer size. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 708daca1d522..76c09cb57eae 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -216,7 +216,7 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, for (i = 0; i < count; i++) { off = be32_to_cpu(((__be32 *)prop_fix->value)[i]); - if (off >= prop->length || (off + 4) > prop->length) + if ((off + 4) > prop->length) return -EINVAL; phandle = be32_to_cpu(*(__be32 *)(prop->value + off)); -- cgit v1.2.3 From 269f1a67d0978b2fbf26a00fc8e5970272f862fe Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:29 -0700 Subject: of: Update comments to reflect changes and increase clarity Update comments to better explain what functions are doing. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 66 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 47 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 76c09cb57eae..f842dbd1585c 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -50,9 +50,6 @@ static struct device_node *find_node_by_full_name(struct device_node *node, return NULL; } -/* - * Find live tree's maximum phandle value. - */ static phandle live_tree_max_phandle(void) { struct device_node *node; @@ -71,9 +68,6 @@ static phandle live_tree_max_phandle(void) return phandle; } -/* - * Adjust a subtree's phandle values by a given delta. - */ static void adjust_overlay_phandles(struct device_node *overlay, int phandle_delta) { @@ -81,9 +75,11 @@ static void adjust_overlay_phandles(struct device_node *overlay, struct property *prop; phandle phandle; + /* adjust node's phandle in node */ if (overlay->phandle != 0 && overlay->phandle != OF_PHANDLE_ILLEGAL) overlay->phandle += phandle_delta; + /* copy adjusted phandle into *phandle properties */ for_each_property_of_node(overlay, prop) { if (of_prop_cmp(prop->name, "phandle") && @@ -118,6 +114,7 @@ static int update_usages_of_a_phandle_reference(struct device_node *overlay, return -ENOMEM; memcpy(value, prop_fixup->value, prop_fixup->length); + /* prop_fixup contains a list of tuples of path:property_name:offset */ end = value + prop_fixup->length; for (cur = value; cur < end; cur += len + 1) { len = strlen(cur); @@ -177,10 +174,14 @@ static int node_name_cmp(const struct device_node *dn1, /* * Adjust the local phandle references by the given phandle delta. - * Assumes the existances of a __local_fixups__ node at the root. - * Assumes that __of_verify_tree_phandle_references has been called. - * Does not take any devtree locks so make sure you call this on a tree - * which is at the detached state. + * + * Subtree @local_fixups, which is overlay node __local_fixups__, + * mirrors the fragment node structure at the root of the overlay. + * + * For each property in the fragments that contains a phandle reference, + * @local_fixups has a property of the same name that contains a list + * of offsets of the phandle reference(s) within the respective property + * value(s). The values at these offsets will be fixed up. */ static int adjust_local_phandle_references(struct device_node *local_fixups, struct device_node *overlay, int phandle_delta) @@ -225,6 +226,13 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, } } + /* + * These nested loops recurse down two subtrees in parallel, where the + * node names in the two subtrees match. + * + * The roots of the subtrees are the overlay's __local_fixups__ node + * and the overlay's root node. + */ for_each_child_of_node(local_fixups, child) { for_each_child_of_node(overlay, overlay_child) @@ -244,17 +252,37 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, } /** - * of_resolve - Resolve the given node against the live tree. + * of_resolve_phandles - Relocate and resolve overlay against live tree + * + * @overlay: Pointer to devicetree overlay to relocate and resolve + * + * Modify (relocate) values of local phandles in @overlay to a range that + * does not conflict with the live expanded devicetree. Update references + * to the local phandles in @overlay. Update (resolve) phandle references + * in @overlay that refer to the live expanded devicetree. + * + * Phandle values in the live tree are in the range of + * 1 .. live_tree_max_phandle(). The range of phandle values in the overlay + * also begin with at 1. Adjust the phandle values in the overlay to begin + * at live_tree_max_phandle() + 1. Update references to the phandles to + * the adjusted phandle values. + * + * The name of each property in the "__fixups__" node in the overlay matches + * the name of a symbol (a label) in the live tree. The values of each + * property in the "__fixups__" node is a list of the property values in the + * overlay that need to be updated to contain the phandle reference + * corresponding to that symbol in the live tree. Update the references in + * the overlay with the phandle values in the live tree. + * + * @overlay must be detached. * - * @resolve: Node to resolve + * Resolving and applying @overlay to the live expanded devicetree must be + * protected by a mechanism to ensure that multiple overlays are processed + * in a single threaded manner so that multiple overlays will not relocate + * phandles to overlapping ranges. The mechanism to enforce this is not + * yet implemented. * - * Perform dynamic Device Tree resolution against the live tree - * to the given node to resolve. This depends on the live tree - * having a __symbols__ node, and the resolve node the __fixups__ & - * __local_fixups__ nodes (if needed). - * The result of the operation is a resolve node that it's contents - * are fit to be inserted or operate upon the live tree. - * Returns 0 on success or a negative error value on error. + * Return: %0 on success or a negative error value on error. */ int of_resolve_phandles(struct device_node *overlay) { -- cgit v1.2.3 From d9181b20a83bd8de207e0cb54be499d9880b00e3 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:30 -0700 Subject: of: Add back an error message, restructured Add a single pr_err() to cover a range of errors that were reported by several pr_err() that were removed earlier in this series. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index f842dbd1585c..eb78010c21a3 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -293,13 +293,17 @@ int of_resolve_phandles(struct device_node *overlay) phandle phandle, phandle_delta; int err; + tree_symbols = NULL; + if (!overlay) { pr_err("null overlay\n"); - return -EINVAL; + err = -EINVAL; + goto err_out; } if (!of_node_check_flag(overlay, OF_DETACHED)) { pr_err("overlay not detached\n"); - return -EINVAL; + err = -EINVAL; + goto err_out; } phandle_delta = live_tree_max_phandle() + 1; @@ -311,7 +315,7 @@ int of_resolve_phandles(struct device_node *overlay) err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); if (err) - return err; + goto err_out; overlay_symbols = NULL; overlay_fixups = NULL; @@ -333,7 +337,7 @@ int of_resolve_phandles(struct device_node *overlay) if (!tree_symbols) { pr_err("no symbols in root of device tree.\n"); err = -EINVAL; - goto out; + goto err_out; } for_each_property_of_node(overlay_fixups, prop) { @@ -345,12 +349,12 @@ int of_resolve_phandles(struct device_node *overlay) err = of_property_read_string(tree_symbols, prop->name, &refpath); if (err) - goto out; + goto err_out; refnode = of_find_node_by_path(refpath); if (!refnode) { err = -ENOENT; - goto out; + goto err_out; } phandle = refnode->phandle; @@ -361,6 +365,8 @@ int of_resolve_phandles(struct device_node *overlay) break; } +err_out: + pr_err("overlay phandle fixup failed: %d\n", err); out: of_node_put(tree_symbols); -- cgit v1.2.3 From 4458db4c9b7363a60d9ad07275fb2eea4ecf3b52 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:31 -0700 Subject: of: Move setting of pointer to beside test for non-null Value of pointer was calculated in an earlier block than where it was used. Move it down into the block where it is used, immediately before where is is checked to be valid. Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index eb78010c21a3..53353cc8f2bb 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -320,8 +320,6 @@ int of_resolve_phandles(struct device_node *overlay) overlay_symbols = NULL; overlay_fixups = NULL; - tree_symbols = of_find_node_by_path("/__symbols__"); - for_each_child_of_node(overlay, child) { if (!of_node_cmp(child->name, "__symbols__")) overlay_symbols = child; @@ -334,6 +332,7 @@ int of_resolve_phandles(struct device_node *overlay) goto out; } + tree_symbols = of_find_node_by_path("/__symbols__"); if (!tree_symbols) { pr_err("no symbols in root of device tree.\n"); err = -EINVAL; -- cgit v1.2.3 From 5581a95f2dacb3674827f450ac406e1f8ae3b3e5 Mon Sep 17 00:00:00 2001 From: Frank Rowand Date: Fri, 28 Oct 2016 23:26:32 -0700 Subject: of: Remove unused variable overlay_symbols Remove unused pointer to node "__symbols__". Signed-off-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 53353cc8f2bb..783bd09463b5 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -287,7 +287,7 @@ static int adjust_local_phandle_references(struct device_node *local_fixups, int of_resolve_phandles(struct device_node *overlay) { struct device_node *child, *local_fixups, *refnode; - struct device_node *tree_symbols, *overlay_symbols, *overlay_fixups; + struct device_node *tree_symbols, *overlay_fixups; struct property *prop; const char *refpath; phandle phandle, phandle_delta; @@ -317,12 +317,9 @@ int of_resolve_phandles(struct device_node *overlay) if (err) goto err_out; - overlay_symbols = NULL; overlay_fixups = NULL; for_each_child_of_node(overlay, child) { - if (!of_node_cmp(child->name, "__symbols__")) - overlay_symbols = child; if (!of_node_cmp(child->name, "__fixups__")) overlay_fixups = child; } -- cgit v1.2.3 From 71ec6f4f7314d4d3ac44bae038bd748bd7961dc6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Nov 2016 11:53:21 +0100 Subject: of/platform: fix of_platform_device_destroy comment Update the comment to of_platform_device_destroy() to reflect that it no longer returns a status value. Fixes: 75f353b61342 ("of/platform: Fix of_platform_device_destroy...") Signed-off-by: Johan Hovold Signed-off-by: Rob Herring --- drivers/of/platform.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/of/platform.c b/drivers/of/platform.c index e4bf07d20f9b..cb4c7800f37d 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -558,9 +558,6 @@ static int of_platform_device_destroy(struct device *dev, void *data) * of the given device (and, recurrently, their children) that have been * created from their respective device tree nodes (and only those, * leaving others - eg. manually created - unharmed). - * - * Returns 0 when all children devices have been removed or - * -EBUSY when some children remained. */ void of_platform_depopulate(struct device *parent) { -- cgit v1.2.3 From 4fb373dfabee1367b7553003b4d6491ee8bf4c2a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Nov 2016 11:53:22 +0100 Subject: of/platform: clarify of_find_device_by_node refcounting Add comment clarifying that of_find_device_by_node() takes a reference to the embedded struct device which needs to be dropped after use. Note that most current users fail to do so. Signed-off-by: Johan Hovold Signed-off-by: Rob Herring --- drivers/of/platform.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/of/platform.c b/drivers/of/platform.c index cb4c7800f37d..b8064bc2b6eb 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c @@ -45,6 +45,9 @@ static int of_dev_node_match(struct device *dev, void *data) * of_find_device_by_node - Find the platform_device associated with a node * @np: Pointer to device tree node * + * Takes a reference to the embedded struct device which needs to be dropped + * after use. + * * Returns platform_device pointer, or NULL if not found */ struct platform_device *of_find_device_by_node(struct device_node *np) -- cgit v1.2.3 From 40eb47767852a9122ef99a48f8d208ec6327e07f Mon Sep 17 00:00:00 2001 From: Mirza Krak Date: Mon, 7 Nov 2016 09:30:05 +0100 Subject: bus: Add support for Tegra Generic Memory Interface The Generic Memory Interface bus can be used to connect high-speed devices such as NOR flash, FPGAs, DSPs... Signed-off-by: Mirza Krak Tested-by: Marcel Ziswiler Tested-on: Colibri T20/T30 on EvalBoard V3.x and GMI-Memory Board Acked-by: Jon Hunter [treding@nvidia.com: symmetry and coding style OCD] Signed-off-by: Thierry Reding --- drivers/bus/Kconfig | 7 ++ drivers/bus/Makefile | 1 + drivers/bus/tegra-gmi.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 292 insertions(+) create mode 100644 drivers/bus/tegra-gmi.c (limited to 'drivers') diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index 7010dcac9328..0c6da1efa216 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -149,6 +149,13 @@ config TEGRA_ACONNECT Driver for the Tegra ACONNECT bus which is used to interface with the devices inside the Audio Processing Engine (APE) for Tegra210. +config TEGRA_GMI + tristate "Tegra Generic Memory Interface bus driver" + depends on ARCH_TEGRA + help + Driver for the Tegra Generic Memory Interface bus which can be used + to attach devices such as NOR, UART, FPGA and more. + config UNIPHIER_SYSTEM_BUS tristate "UniPhier System Bus driver" depends on ARCH_UNIPHIER && OF diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index c6cfa6b2606e..a679d00fc4eb 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -19,5 +19,6 @@ obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o +obj-$(CONFIG_TEGRA_GMI) += tegra-gmi.o obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o diff --git a/drivers/bus/tegra-gmi.c b/drivers/bus/tegra-gmi.c new file mode 100644 index 000000000000..a6570789f7af --- /dev/null +++ b/drivers/bus/tegra-gmi.c @@ -0,0 +1,284 @@ +/* + * Driver for NVIDIA Generic Memory Interface + * + * Copyright (C) 2016 Host Mobility AB. All rights reserved. + * + * 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 + +#define TEGRA_GMI_CONFIG 0x00 +#define TEGRA_GMI_CONFIG_GO BIT(31) +#define TEGRA_GMI_BUS_WIDTH_32BIT BIT(30) +#define TEGRA_GMI_MUX_MODE BIT(28) +#define TEGRA_GMI_RDY_BEFORE_DATA BIT(24) +#define TEGRA_GMI_RDY_ACTIVE_HIGH BIT(23) +#define TEGRA_GMI_ADV_ACTIVE_HIGH BIT(22) +#define TEGRA_GMI_OE_ACTIVE_HIGH BIT(21) +#define TEGRA_GMI_CS_ACTIVE_HIGH BIT(20) +#define TEGRA_GMI_CS_SELECT(x) ((x & 0x7) << 4) + +#define TEGRA_GMI_TIMING0 0x10 +#define TEGRA_GMI_MUXED_WIDTH(x) ((x & 0xf) << 12) +#define TEGRA_GMI_HOLD_WIDTH(x) ((x & 0xf) << 8) +#define TEGRA_GMI_ADV_WIDTH(x) ((x & 0xf) << 4) +#define TEGRA_GMI_CE_WIDTH(x) (x & 0xf) + +#define TEGRA_GMI_TIMING1 0x14 +#define TEGRA_GMI_WE_WIDTH(x) ((x & 0xff) << 16) +#define TEGRA_GMI_OE_WIDTH(x) ((x & 0xff) << 8) +#define TEGRA_GMI_WAIT_WIDTH(x) (x & 0xff) + +#define TEGRA_GMI_MAX_CHIP_SELECT 8 + +struct tegra_gmi { + struct device *dev; + void __iomem *base; + struct clk *clk; + struct reset_control *rst; + + u32 snor_config; + u32 snor_timing0; + u32 snor_timing1; +}; + +static int tegra_gmi_enable(struct tegra_gmi *gmi) +{ + int err; + + err = clk_prepare_enable(gmi->clk); + if (err < 0) { + dev_err(gmi->dev, "failed to enable clock: %d\n", err); + return err; + } + + reset_control_assert(gmi->rst); + usleep_range(2000, 4000); + reset_control_deassert(gmi->rst); + + writel(gmi->snor_timing0, gmi->base + TEGRA_GMI_TIMING0); + writel(gmi->snor_timing1, gmi->base + TEGRA_GMI_TIMING1); + + gmi->snor_config |= TEGRA_GMI_CONFIG_GO; + writel(gmi->snor_config, gmi->base + TEGRA_GMI_CONFIG); + + return 0; +} + +static void tegra_gmi_disable(struct tegra_gmi *gmi) +{ + u32 config; + + /* stop GMI operation */ + config = readl(gmi->base + TEGRA_GMI_CONFIG); + config &= ~TEGRA_GMI_CONFIG_GO; + writel(config, gmi->base + TEGRA_GMI_CONFIG); + + reset_control_assert(gmi->rst); + clk_disable_unprepare(gmi->clk); +} + +static int tegra_gmi_parse_dt(struct tegra_gmi *gmi) +{ + struct device_node *child; + u32 property, ranges[4]; + int err; + + child = of_get_next_available_child(gmi->dev->of_node, NULL); + if (!child) { + dev_err(gmi->dev, "no child nodes found\n"); + return -ENODEV; + } + + /* + * We currently only support one child device due to lack of + * chip-select address decoding. Which means that we only have one + * chip-select line from the GMI controller. + */ + if (of_get_child_count(gmi->dev->of_node) > 1) + dev_warn(gmi->dev, "only one child device is supported."); + + if (of_property_read_bool(child, "nvidia,snor-data-width-32bit")) + gmi->snor_config |= TEGRA_GMI_BUS_WIDTH_32BIT; + + if (of_property_read_bool(child, "nvidia,snor-mux-mode")) + gmi->snor_config |= TEGRA_GMI_MUX_MODE; + + if (of_property_read_bool(child, "nvidia,snor-rdy-active-before-data")) + gmi->snor_config |= TEGRA_GMI_RDY_BEFORE_DATA; + + if (of_property_read_bool(child, "nvidia,snor-rdy-active-high")) + gmi->snor_config |= TEGRA_GMI_RDY_ACTIVE_HIGH; + + if (of_property_read_bool(child, "nvidia,snor-adv-active-high")) + gmi->snor_config |= TEGRA_GMI_ADV_ACTIVE_HIGH; + + if (of_property_read_bool(child, "nvidia,snor-oe-active-high")) + gmi->snor_config |= TEGRA_GMI_OE_ACTIVE_HIGH; + + if (of_property_read_bool(child, "nvidia,snor-cs-active-high")) + gmi->snor_config |= TEGRA_GMI_CS_ACTIVE_HIGH; + + /* Decode the CS# */ + err = of_property_read_u32_array(child, "ranges", ranges, 4); + if (err < 0) { + /* Invalid binding */ + if (err == -EOVERFLOW) { + dev_err(gmi->dev, + "failed to decode CS: invalid ranges length\n"); + goto error_cs; + } + + /* + * If we reach here it means that the child node has an empty + * ranges or it does not exist at all. Attempt to decode the + * CS# from the reg property instead. + */ + err = of_property_read_u32(child, "reg", &property); + if (err < 0) { + dev_err(gmi->dev, + "failed to decode CS: no reg property found\n"); + goto error_cs; + } + } else { + property = ranges[1]; + } + + /* Valid chip selects are CS0-CS7 */ + if (property >= TEGRA_GMI_MAX_CHIP_SELECT) { + dev_err(gmi->dev, "invalid chip select: %d", property); + err = -EINVAL; + goto error_cs; + } + + gmi->snor_config |= TEGRA_GMI_CS_SELECT(property); + + /* The default values that are provided below are reset values */ + if (!of_property_read_u32(child, "nvidia,snor-muxed-width", &property)) + gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(property); + else + gmi->snor_timing0 |= TEGRA_GMI_MUXED_WIDTH(1); + + if (!of_property_read_u32(child, "nvidia,snor-hold-width", &property)) + gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(property); + else + gmi->snor_timing0 |= TEGRA_GMI_HOLD_WIDTH(1); + + if (!of_property_read_u32(child, "nvidia,snor-adv-width", &property)) + gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(property); + else + gmi->snor_timing0 |= TEGRA_GMI_ADV_WIDTH(1); + + if (!of_property_read_u32(child, "nvidia,snor-ce-width", &property)) + gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(property); + else + gmi->snor_timing0 |= TEGRA_GMI_CE_WIDTH(4); + + if (!of_property_read_u32(child, "nvidia,snor-we-width", &property)) + gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(property); + else + gmi->snor_timing1 |= TEGRA_GMI_WE_WIDTH(1); + + if (!of_property_read_u32(child, "nvidia,snor-oe-width", &property)) + gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(property); + else + gmi->snor_timing1 |= TEGRA_GMI_OE_WIDTH(1); + + if (!of_property_read_u32(child, "nvidia,snor-wait-width", &property)) + gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(property); + else + gmi->snor_timing1 |= TEGRA_GMI_WAIT_WIDTH(3); + +error_cs: + of_node_put(child); + return err; +} + +static int tegra_gmi_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct tegra_gmi *gmi; + struct resource *res; + int err; + + gmi = devm_kzalloc(dev, sizeof(*gmi), GFP_KERNEL); + if (!gmi) + return -ENOMEM; + + gmi->dev = dev; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gmi->base = devm_ioremap_resource(dev, res); + if (IS_ERR(gmi->base)) + return PTR_ERR(gmi->base); + + gmi->clk = devm_clk_get(dev, "gmi"); + if (IS_ERR(gmi->clk)) { + dev_err(dev, "can not get clock\n"); + return PTR_ERR(gmi->clk); + } + + gmi->rst = devm_reset_control_get(dev, "gmi"); + if (IS_ERR(gmi->rst)) { + dev_err(dev, "can not get reset\n"); + return PTR_ERR(gmi->rst); + } + + err = tegra_gmi_parse_dt(gmi); + if (err) + return err; + + err = tegra_gmi_enable(gmi); + if (err < 0) + return err; + + err = of_platform_default_populate(dev->of_node, NULL, dev); + if (err < 0) { + dev_err(dev, "fail to create devices.\n"); + tegra_gmi_disable(gmi); + return err; + } + + platform_set_drvdata(pdev, gmi); + + return 0; +} + +static int tegra_gmi_remove(struct platform_device *pdev) +{ + struct tegra_gmi *gmi = platform_get_drvdata(pdev); + + of_platform_depopulate(gmi->dev); + tegra_gmi_disable(gmi); + + return 0; +} + +static const struct of_device_id tegra_gmi_id_table[] = { + { .compatible = "nvidia,tegra20-gmi", }, + { .compatible = "nvidia,tegra30-gmi", }, + { } +}; +MODULE_DEVICE_TABLE(of, tegra_gmi_id_table); + +static struct platform_driver tegra_gmi_driver = { + .probe = tegra_gmi_probe, + .remove = tegra_gmi_remove, + .driver = { + .name = "tegra-gmi", + .of_match_table = tegra_gmi_id_table, + }, +}; +module_platform_driver(tegra_gmi_driver); + +MODULE_AUTHOR("Mirza Krak Date: Mon, 10 Oct 2016 06:14:28 -0700 Subject: IB/hfi1: Add unique txwait_lock for txreq events Profiling suggests that the read_seqbegin() in the txreq put logic is colliding with other uses of the iowait lock. The packet at a time use of this lock dictates a unique lock to avoid reader/writer collisions when the number of vTxWait events is low. In order to support a unique lock the iowait struct embedded in the QP is extended to remember the lock that protects the queue head. The QP destroy removes that QP from any wait list. It doesn't need to know the head because of the linked list API, but it does need to know the lock required to protect the head. This also opens up the wait logic to have unique per resources locks which needs to be in future refinement. Reviewed-by: Sebastian Sanchez Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/iowait.h | 8 ++++++++ drivers/infiniband/hw/hfi1/pio.c | 1 + drivers/infiniband/hw/hfi1/qp.c | 11 ++++++++--- drivers/infiniband/hw/hfi1/verbs.c | 4 ++++ drivers/infiniband/hw/hfi1/verbs.h | 13 +++++++------ drivers/infiniband/hw/hfi1/verbs_txreq.c | 13 +++++++------ 6 files changed, 35 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/iowait.h b/drivers/infiniband/hw/hfi1/iowait.h index 2ec6ef38d389..d9740ddea6f1 100644 --- a/drivers/infiniband/hw/hfi1/iowait.h +++ b/drivers/infiniband/hw/hfi1/iowait.h @@ -64,6 +64,7 @@ struct sdma_engine; /** * struct iowait - linkage for delayed progress/waiting * @list: used to add/insert into QP/PQ wait lists + * @lock: uses to record the list head lock * @tx_head: overflow list of sdma_txreq's * @sleep: no space callback * @wakeup: space callback wakeup @@ -91,6 +92,11 @@ struct sdma_engine; * so sleeping is not allowed. * * The wait_dma member along with the iow + * + * The lock field is used by waiters to record + * the seqlock_t that guards the list head. + * Waiters explicity know that, but the destroy + * code that unwaits QPs does not. */ struct iowait { @@ -103,6 +109,7 @@ struct iowait { unsigned seq); void (*wakeup)(struct iowait *wait, int reason); void (*sdma_drained)(struct iowait *wait); + seqlock_t *lock; struct work_struct iowork; wait_queue_head_t wait_dma; wait_queue_head_t wait_pio; @@ -141,6 +148,7 @@ static inline void iowait_init( void (*sdma_drained)(struct iowait *wait)) { wait->count = 0; + wait->lock = NULL; INIT_LIST_HEAD(&wait->list); INIT_LIST_HEAD(&wait->tx_head); INIT_WORK(&wait->iowork, func); diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 50a3a36d9363..385e4dcf2cd3 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -1580,6 +1580,7 @@ static void sc_piobufavail(struct send_context *sc) qp = iowait_to_qp(wait); priv = qp->priv; list_del_init(&priv->s_iowait.list); + priv->s_iowait.lock = NULL; /* refcount held until actual wake up */ qps[n++] = qp; } diff --git a/drivers/infiniband/hw/hfi1/qp.c b/drivers/infiniband/hw/hfi1/qp.c index 9fc75e7e8781..d752d6768a49 100644 --- a/drivers/infiniband/hw/hfi1/qp.c +++ b/drivers/infiniband/hw/hfi1/qp.c @@ -196,15 +196,18 @@ static void flush_tx_list(struct rvt_qp *qp) static void flush_iowait(struct rvt_qp *qp) { struct hfi1_qp_priv *priv = qp->priv; - struct hfi1_ibdev *dev = to_idev(qp->ibqp.device); unsigned long flags; + seqlock_t *lock = priv->s_iowait.lock; - write_seqlock_irqsave(&dev->iowait_lock, flags); + if (!lock) + return; + write_seqlock_irqsave(lock, flags); if (!list_empty(&priv->s_iowait.list)) { list_del_init(&priv->s_iowait.list); + priv->s_iowait.lock = NULL; rvt_put_qp(qp); } - write_sequnlock_irqrestore(&dev->iowait_lock, flags); + write_sequnlock_irqrestore(lock, flags); } static inline int opa_mtu_enum_to_int(int mtu) @@ -543,6 +546,7 @@ static int iowait_sleep( ibp->rvp.n_dmawait++; qp->s_flags |= RVT_S_WAIT_DMA_DESC; list_add_tail(&priv->s_iowait.list, &sde->dmawait); + priv->s_iowait.lock = &dev->iowait_lock; trace_hfi1_qpsleep(qp, RVT_S_WAIT_DMA_DESC); rvt_get_qp(qp); } @@ -964,6 +968,7 @@ void notify_error_qp(struct rvt_qp *qp) if (!list_empty(&priv->s_iowait.list) && !(qp->s_flags & RVT_S_BUSY)) { qp->s_flags &= ~RVT_S_ANY_WAIT_IO; list_del_init(&priv->s_iowait.list); + priv->s_iowait.lock = NULL; rvt_put_qp(qp); } write_sequnlock(&dev->iowait_lock); diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 4b7a16ceb362..feecacb62162 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -694,6 +694,7 @@ static void mem_timer(unsigned long data) qp = iowait_to_qp(wait); priv = qp->priv; list_del_init(&priv->s_iowait.list); + priv->s_iowait.lock = NULL; /* refcount held until actual wake up */ if (!list_empty(list)) mod_timer(&dev->mem_timer, jiffies + 1); @@ -769,6 +770,7 @@ static int wait_kmem(struct hfi1_ibdev *dev, mod_timer(&dev->mem_timer, jiffies + 1); qp->s_flags |= RVT_S_WAIT_KMEM; list_add_tail(&priv->s_iowait.list, &dev->memwait); + priv->s_iowait.lock = &dev->iowait_lock; trace_hfi1_qpsleep(qp, RVT_S_WAIT_KMEM); rvt_get_qp(qp); } @@ -980,6 +982,7 @@ static int pio_wait(struct rvt_qp *qp, qp->s_flags |= flag; was_empty = list_empty(&sc->piowait); list_add_tail(&priv->s_iowait.list, &sc->piowait); + priv->s_iowait.lock = &dev->iowait_lock; trace_hfi1_qpsleep(qp, RVT_S_WAIT_PIO); rvt_get_qp(qp); /* counting: only call wantpiobuf_intr if first user */ @@ -1632,6 +1635,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) setup_timer(&dev->mem_timer, mem_timer, (unsigned long)dev); seqlock_init(&dev->iowait_lock); + seqlock_init(&dev->txwait_lock); INIT_LIST_HEAD(&dev->txwait); INIT_LIST_HEAD(&dev->memwait); diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index 1c3815d89eb7..7a8af39e99d4 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -180,18 +180,19 @@ struct hfi1_ibdev { struct rvt_dev_info rdi; /* Must be first */ /* QP numbers are shared by all IB ports */ - /* protect wait lists */ - seqlock_t iowait_lock; + /* protect txwait list */ + seqlock_t txwait_lock ____cacheline_aligned_in_smp; struct list_head txwait; /* list for wait verbs_txreq */ struct list_head memwait; /* list for wait kernel memory */ - struct list_head txreq_free; struct kmem_cache *verbs_txreq_cache; - struct timer_list mem_timer; + u64 n_txwait; + u64 n_kmem_wait; + /* protect iowait lists */ + seqlock_t iowait_lock ____cacheline_aligned_in_smp; u64 n_piowait; u64 n_piodrain; - u64 n_txwait; - u64 n_kmem_wait; + struct timer_list mem_timer; #ifdef CONFIG_DEBUG_FS /* per HFI debugfs */ diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.c b/drivers/infiniband/hw/hfi1/verbs_txreq.c index 094ab829ec42..5d23172c470f 100644 --- a/drivers/infiniband/hw/hfi1/verbs_txreq.c +++ b/drivers/infiniband/hw/hfi1/verbs_txreq.c @@ -72,22 +72,22 @@ void hfi1_put_txreq(struct verbs_txreq *tx) kmem_cache_free(dev->verbs_txreq_cache, tx); do { - seq = read_seqbegin(&dev->iowait_lock); + seq = read_seqbegin(&dev->txwait_lock); if (!list_empty(&dev->txwait)) { struct iowait *wait; - write_seqlock_irqsave(&dev->iowait_lock, flags); + write_seqlock_irqsave(&dev->txwait_lock, flags); wait = list_first_entry(&dev->txwait, struct iowait, list); qp = iowait_to_qp(wait); priv = qp->priv; list_del_init(&priv->s_iowait.list); /* refcount held until actual wake up */ - write_sequnlock_irqrestore(&dev->iowait_lock, flags); + write_sequnlock_irqrestore(&dev->txwait_lock, flags); hfi1_qp_wakeup(qp, RVT_S_WAIT_TX); break; } - } while (read_seqretry(&dev->iowait_lock, seq)); + } while (read_seqretry(&dev->txwait_lock, seq)); } struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev, @@ -96,7 +96,7 @@ struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev, { struct verbs_txreq *tx = ERR_PTR(-EBUSY); - write_seqlock(&dev->iowait_lock); + write_seqlock(&dev->txwait_lock); if (ib_rvt_state_ops[qp->state] & RVT_PROCESS_RECV_OK) { struct hfi1_qp_priv *priv; @@ -108,13 +108,14 @@ struct verbs_txreq *__get_txreq(struct hfi1_ibdev *dev, dev->n_txwait++; qp->s_flags |= RVT_S_WAIT_TX; list_add_tail(&priv->s_iowait.list, &dev->txwait); + priv->s_iowait.lock = &dev->txwait_lock; trace_hfi1_qpsleep(qp, RVT_S_WAIT_TX); rvt_get_qp(qp); } qp->s_flags &= ~RVT_S_BUSY; } out: - write_sequnlock(&dev->iowait_lock); + write_sequnlock(&dev->txwait_lock); return tx; } -- cgit v1.2.3 From 63df8e09e185796ba532cff7c31f88811dd6cae6 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Oct 2016 06:14:34 -0700 Subject: IB/hfi1: Inline sdma_txclean() for verbs pio Short circuit sdma_txclean() by adding an __sdma_txclean() that is only called when the tx has sdma mappings. Convert internal calls to __sdma_txclean(). This removes a call from the critical path. Reviewed-by: Sebastian Sanchez Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/sdma.c | 18 +++++++++--------- drivers/infiniband/hw/hfi1/sdma.h | 12 +++++++++--- 2 files changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/sdma.c b/drivers/infiniband/hw/hfi1/sdma.c index fd39bcaa062d..7102a076146d 100644 --- a/drivers/infiniband/hw/hfi1/sdma.c +++ b/drivers/infiniband/hw/hfi1/sdma.c @@ -375,7 +375,7 @@ static inline void complete_tx(struct sdma_engine *sde, sde->head_sn, tx->sn); sde->head_sn++; #endif - sdma_txclean(sde->dd, tx); + __sdma_txclean(sde->dd, tx); if (complete) (*complete)(tx, res); if (wait && iowait_sdma_dec(wait)) @@ -1643,7 +1643,7 @@ static inline u8 ahg_mode(struct sdma_txreq *tx) } /** - * sdma_txclean() - clean tx of mappings, descp *kmalloc's + * __sdma_txclean() - clean tx of mappings, descp *kmalloc's * @dd: hfi1_devdata for unmapping * @tx: tx request to clean * @@ -1653,7 +1653,7 @@ static inline u8 ahg_mode(struct sdma_txreq *tx) * The code can be called multiple times without issue. * */ -void sdma_txclean( +void __sdma_txclean( struct hfi1_devdata *dd, struct sdma_txreq *tx) { @@ -3080,7 +3080,7 @@ static int _extend_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx) tx->descp[i] = tx->descs[i]; return 0; enomem: - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return -ENOMEM; } @@ -3109,14 +3109,14 @@ int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx, rval = _extend_sdma_tx_descs(dd, tx); if (rval) { - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return rval; } /* If coalesce buffer is allocated, copy data into it */ if (tx->coalesce_buf) { if (type == SDMA_MAP_NONE) { - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return -EINVAL; } @@ -3124,7 +3124,7 @@ int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx, kvaddr = kmap(page); kvaddr += offset; } else if (WARN_ON(!kvaddr)) { - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return -EINVAL; } @@ -3154,7 +3154,7 @@ int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(&dd->pcidev->dev, addr))) { - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return -ENOSPC; } @@ -3196,7 +3196,7 @@ int _pad_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx) if ((unlikely(tx->num_desc == tx->desc_limit))) { rval = _extend_sdma_tx_descs(dd, tx); if (rval) { - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return rval; } } diff --git a/drivers/infiniband/hw/hfi1/sdma.h b/drivers/infiniband/hw/hfi1/sdma.h index 56257ea3598f..21f1e2834f37 100644 --- a/drivers/infiniband/hw/hfi1/sdma.h +++ b/drivers/infiniband/hw/hfi1/sdma.h @@ -667,7 +667,13 @@ int ext_coal_sdma_tx_descs(struct hfi1_devdata *dd, struct sdma_txreq *tx, int type, void *kvaddr, struct page *page, unsigned long offset, u16 len); int _pad_sdma_tx_descs(struct hfi1_devdata *, struct sdma_txreq *); -void sdma_txclean(struct hfi1_devdata *, struct sdma_txreq *); +void __sdma_txclean(struct hfi1_devdata *, struct sdma_txreq *); + +static inline void sdma_txclean(struct hfi1_devdata *dd, struct sdma_txreq *tx) +{ + if (tx->num_desc) + __sdma_txclean(dd, tx); +} /* helpers used by public routines */ static inline void _sdma_close_tx(struct hfi1_devdata *dd, @@ -753,7 +759,7 @@ static inline int sdma_txadd_page( DMA_TO_DEVICE); if (unlikely(dma_mapping_error(&dd->pcidev->dev, addr))) { - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return -ENOSPC; } @@ -834,7 +840,7 @@ static inline int sdma_txadd_kvaddr( DMA_TO_DEVICE); if (unlikely(dma_mapping_error(&dd->pcidev->dev, addr))) { - sdma_txclean(dd, tx); + __sdma_txclean(dd, tx); return -ENOSPC; } -- cgit v1.2.3 From 99f80d2f5fb6d4165186390ecba83952803b667b Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 10 Oct 2016 06:14:39 -0700 Subject: IB/hfi1: Optimize lkey validation structures Profiling shows that the key validation is susceptible to cache line trading when accessing the lkey table. Fix by separating out the read mostly fields from the write fields. In addition the shift amount, which is function of the lkey table size, is precomputed and stored with the table pointer. Since both the shift and table pointer are in the same read mostly cacheline, this saves a cache line in this hot path. Reviewed-by: Sebastian Sanchez Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/mr.c | 10 +++++----- include/rdma/rdmavt_mr.h | 10 +++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c index 46b64970058e..4acf179adf3b 100644 --- a/drivers/infiniband/sw/rdmavt/mr.c +++ b/drivers/infiniband/sw/rdmavt/mr.c @@ -84,6 +84,7 @@ int rvt_driver_mr_init(struct rvt_dev_info *rdi) lkey_table_size = rdi->dparms.lkey_table_size; } rdi->lkey_table.max = 1 << lkey_table_size; + rdi->lkey_table.shift = 32 - lkey_table_size; lk_tab_size = rdi->lkey_table.max * sizeof(*rdi->lkey_table.table); rdi->lkey_table.table = (struct rvt_mregion __rcu **) vmalloc_node(lk_tab_size, rdi->dparms.node); @@ -774,7 +775,6 @@ int rvt_lkey_ok(struct rvt_lkey_table *rkt, struct rvt_pd *pd, struct rvt_mregion *mr; unsigned n, m; size_t off; - struct rvt_dev_info *dev = ib_to_rvt(pd->ibpd.device); /* * We use LKEY == zero for kernel virtual addresses @@ -782,6 +782,8 @@ int rvt_lkey_ok(struct rvt_lkey_table *rkt, struct rvt_pd *pd, */ rcu_read_lock(); if (sge->lkey == 0) { + struct rvt_dev_info *dev = ib_to_rvt(pd->ibpd.device); + if (pd->user) goto bail; mr = rcu_dereference(dev->dma_mr); @@ -798,8 +800,7 @@ int rvt_lkey_ok(struct rvt_lkey_table *rkt, struct rvt_pd *pd, isge->n = 0; goto ok; } - mr = rcu_dereference( - rkt->table[(sge->lkey >> (32 - dev->dparms.lkey_table_size))]); + mr = rcu_dereference(rkt->table[sge->lkey >> rkt->shift]); if (unlikely(!mr || atomic_read(&mr->lkey_invalid) || mr->lkey != sge->lkey || mr->pd != &pd->ibpd)) goto bail; @@ -899,8 +900,7 @@ int rvt_rkey_ok(struct rvt_qp *qp, struct rvt_sge *sge, goto ok; } - mr = rcu_dereference( - rkt->table[(rkey >> (32 - dev->dparms.lkey_table_size))]); + mr = rcu_dereference(rkt->table[rkey >> rkt->shift]); if (unlikely(!mr || atomic_read(&mr->lkey_invalid) || mr->lkey != rkey || qp->ibqp.pd != mr->pd)) goto bail; diff --git a/include/rdma/rdmavt_mr.h b/include/rdma/rdmavt_mr.h index 6b3c6c8b6b77..de59de28b6a2 100644 --- a/include/rdma/rdmavt_mr.h +++ b/include/rdma/rdmavt_mr.h @@ -90,11 +90,15 @@ struct rvt_mregion { #define RVT_MAX_LKEY_TABLE_BITS 23 struct rvt_lkey_table { - spinlock_t lock; /* protect changes in this struct */ - u32 next; /* next unused index (speeds search) */ - u32 gen; /* generation count */ + /* read mostly fields */ u32 max; /* size of the table */ + u32 shift; /* lkey/rkey shift */ struct rvt_mregion __rcu **table; + /* writeable fields */ + /* protect changes in this struct */ + spinlock_t lock ____cacheline_aligned_in_smp; + u32 next; /* next unused index (speeds search) */ + u32 gen; /* generation count */ }; /* -- cgit v1.2.3 From 99c7abfb626d0ce4e6e190dc7aeeb55eb21e335f Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Mon, 17 Oct 2016 04:19:13 -0700 Subject: IB/hfi1: Optimize pio cachelines Move buffers_allocated pcpu pointer to allocator line. Move hw_free pointer to releaser line. Fill other holes revealed by pahole. Reviewed-by: Sebastian Sanchez Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/pio.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/pio.h b/drivers/infiniband/hw/hfi1/pio.h index e709eaf743b5..bd19507b6bb0 100644 --- a/drivers/infiniband/hw/hfi1/pio.h +++ b/drivers/infiniband/hw/hfi1/pio.h @@ -104,7 +104,6 @@ struct send_context { void __iomem *base_addr; /* start of PIO memory */ union pio_shadow_ring *sr; /* shadow ring */ - volatile __le64 *hw_free; /* HW free counter */ struct work_struct halt_work; /* halted context work queue entry */ unsigned long flags; /* flags */ int node; /* context home node */ @@ -116,19 +115,20 @@ struct send_context { u32 group; /* credit return group */ /* allocator fields */ spinlock_t alloc_lock ____cacheline_aligned_in_smp; + u32 sr_head; /* shadow ring head */ unsigned long fill; /* official alloc count */ unsigned long alloc_free; /* copy of free (less cache thrash) */ - u32 sr_head; /* shadow ring head */ + u32 __percpu *buffers_allocated;/* count of buffers allocated */ /* releaser fields */ spinlock_t release_lock ____cacheline_aligned_in_smp; - unsigned long free; /* official free count */ u32 sr_tail; /* shadow ring tail */ + unsigned long free; /* official free count */ + volatile __le64 *hw_free; /* HW free counter */ /* list for PIO waiters */ struct list_head piowait ____cacheline_aligned_in_smp; spinlock_t credit_ctrl_lock ____cacheline_aligned_in_smp; - u64 credit_ctrl; /* cache for credit control */ u32 credit_intr_count; /* count of credit intr users */ - u32 __percpu *buffers_allocated;/* count of buffers allocated */ + u64 credit_ctrl; /* cache for credit control */ wait_queue_head_t halt_wait; /* wait until kernel sees interrupt */ }; -- cgit v1.2.3 From a6cd5f08e085176fe8dbd4c57217058e53dfc4d9 Mon Sep 17 00:00:00 2001 From: Jakub Pawlak Date: Mon, 17 Oct 2016 04:19:30 -0700 Subject: IB/hfi1: Unify access to GUID entries This patch consolidates the node GUIDs and the port GUID handling and unifies access to these items. The knowledge of hfi1 GUIDs' design and their location are kept in accessors to centralize access. Reviewed-by: Mike Marciniszyn Reviewed-by: Dennis Dalessandro Reviewed-by: Brian Welty Signed-off-by: Jakub Pawlak Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 4 ++-- drivers/infiniband/hw/hfi1/hfi.h | 19 +++++++++++++++++-- drivers/infiniband/hw/hfi1/mad.c | 19 ++++++++++--------- drivers/infiniband/hw/hfi1/ruc.c | 16 +++------------- drivers/infiniband/hw/hfi1/verbs.c | 15 +++++++-------- drivers/infiniband/hw/hfi1/verbs.h | 3 --- 6 files changed, 39 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index 9bf5f23544d4..f87d80567572 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -9567,11 +9567,11 @@ int bringup_serdes(struct hfi1_pportdata *ppd) if (HFI1_CAP_IS_KSET(EXTENDED_PSN)) add_rcvctrl(dd, RCV_CTRL_RCV_EXTENDED_PSN_ENABLE_SMASK); - guid = ppd->guid; + guid = ppd->guids[HFI1_PORT_GUID_INDEX]; if (!guid) { if (dd->base_guid) guid = dd->base_guid + ppd->port - 1; - ppd->guid = guid; + ppd->guids[HFI1_PORT_GUID_INDEX] = guid; } /* Set linkinit_reason on power up per OPA spec */ diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 7eef11b316ff..a2ea643a79fc 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -512,6 +512,9 @@ struct rvt_sge_state; #define HFI1_MIN_VLS_SUPPORTED 1 #define HFI1_MAX_VLS_SUPPORTED 8 +#define HFI1_GUIDS_PER_PORT 5 +#define HFI1_PORT_GUID_INDEX 0 + static inline void incr_cntr64(u64 *cntr) { if (*cntr < (u64)-1LL) @@ -582,8 +585,9 @@ struct hfi1_pportdata { u32 port_type; struct qsfp_data qsfp_info; - /* GUID for this interface, in host order */ - u64 guid; + /* GUIDs for this interface, in host order, guids[0] is a port guid */ + u64 guids[HFI1_GUIDS_PER_PORT]; + /* GUID for peer interface, in host order */ u64 neighbor_guid; @@ -1632,6 +1636,17 @@ static inline u16 hfi1_get_pkey(struct hfi1_ibport *ibp, unsigned index) return ret; } +/* + * Return the indexed GUID from the port GUIDs table. + */ +static inline __be64 get_sguid(struct hfi1_ibport *ibp, unsigned int index) +{ + struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); + + WARN_ON(index >= HFI1_GUIDS_PER_PORT); + return cpu_to_be64(ppd->guids[index]); +} + /* * Called by readers of cc_state only, must call under rcu_read_lock(). */ diff --git a/drivers/infiniband/hw/hfi1/mad.c b/drivers/infiniband/hw/hfi1/mad.c index 9487c9bb8920..0ef62e67f283 100644 --- a/drivers/infiniband/hw/hfi1/mad.c +++ b/drivers/infiniband/hw/hfi1/mad.c @@ -336,20 +336,20 @@ static int __subn_get_opa_nodeinfo(struct opa_smp *smp, u32 am, u8 *data, ni = (struct opa_node_info *)data; /* GUID 0 is illegal */ - if (am || pidx >= dd->num_pports || dd->pport[pidx].guid == 0) { + if (am || pidx >= dd->num_pports || ibdev->node_guid == 0 || + get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX) == 0) { smp->status |= IB_SMP_INVALID_FIELD; return reply((struct ib_mad_hdr *)smp); } - ni->port_guid = cpu_to_be64(dd->pport[pidx].guid); + ni->port_guid = get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX); ni->base_version = OPA_MGMT_BASE_VERSION; ni->class_version = OPA_SMI_CLASS_VERSION; ni->node_type = 1; /* channel adapter */ ni->num_ports = ibdev->phys_port_cnt; /* This is already in network order */ ni->system_image_guid = ib_hfi1_sys_image_guid; - /* Use first-port GUID as node */ - ni->node_guid = cpu_to_be64(dd->pport->guid); + ni->node_guid = ibdev->node_guid; ni->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); ni->device_id = cpu_to_be16(dd->pcidev->device); ni->revision = cpu_to_be32(dd->minrev); @@ -373,19 +373,20 @@ static int subn_get_nodeinfo(struct ib_smp *smp, struct ib_device *ibdev, /* GUID 0 is illegal */ if (smp->attr_mod || pidx >= dd->num_pports || - dd->pport[pidx].guid == 0) + ibdev->node_guid == 0 || + get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX) == 0) { smp->status |= IB_SMP_INVALID_FIELD; - else - nip->port_guid = cpu_to_be64(dd->pport[pidx].guid); + return reply((struct ib_mad_hdr *)smp); + } + nip->port_guid = get_sguid(to_iport(ibdev, port), HFI1_PORT_GUID_INDEX); nip->base_version = OPA_MGMT_BASE_VERSION; nip->class_version = OPA_SMI_CLASS_VERSION; nip->node_type = 1; /* channel adapter */ nip->num_ports = ibdev->phys_port_cnt; /* This is already in network order */ nip->sys_guid = ib_hfi1_sys_image_guid; - /* Use first-port GUID as node */ - nip->node_guid = cpu_to_be64(dd->pport->guid); + nip->node_guid = ibdev->node_guid; nip->partition_cap = cpu_to_be16(hfi1_get_npkeys(dd)); nip->device_id = cpu_to_be16(dd->pcidev->device); nip->revision = cpu_to_be32(dd->minrev); diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index a1576aea4756..5a70e91b5191 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -239,16 +239,6 @@ bail: return ret; } -static __be64 get_sguid(struct hfi1_ibport *ibp, unsigned index) -{ - if (!index) { - struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); - - return cpu_to_be64(ppd->guid); - } - return ibp->guids[index - 1]; -} - static int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id) { return (gid->global.interface_id == id && @@ -699,9 +689,9 @@ u32 hfi1_make_grh(struct hfi1_ibport *ibp, struct ib_grh *hdr, /* The SGID is 32-bit aligned. */ hdr->sgid.global.subnet_prefix = ibp->rvp.gid_prefix; hdr->sgid.global.interface_id = - grh->sgid_index && grh->sgid_index < ARRAY_SIZE(ibp->guids) ? - ibp->guids[grh->sgid_index - 1] : - cpu_to_be64(ppd_from_ibp(ibp)->guid); + grh->sgid_index < HFI1_GUIDS_PER_PORT ? + get_sguid(ibp, grh->sgid_index) : + get_sguid(ibp, HFI1_PORT_GUID_INDEX); hdr->dgid = grh->dgid; /* GRH header size in 32-bit words. */ diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index feecacb62162..f1dead369258 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1486,15 +1486,11 @@ static int hfi1_get_guid_be(struct rvt_dev_info *rdi, struct rvt_ibport *rvp, int guid_index, __be64 *guid) { struct hfi1_ibport *ibp = container_of(rvp, struct hfi1_ibport, rvp); - struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); - if (guid_index == 0) - *guid = cpu_to_be64(ppd->guid); - else if (guid_index < HFI1_GUIDS_PER_PORT) - *guid = ibp->guids[guid_index - 1]; - else + if (guid_index >= HFI1_GUIDS_PER_PORT) return -EINVAL; + *guid = get_sguid(ibp, guid_index); return 0; } @@ -1623,6 +1619,7 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) struct hfi1_ibdev *dev = &dd->verbs_dev; struct ib_device *ibdev = &dev->rdi.ibdev; struct hfi1_pportdata *ppd = dd->pport; + struct hfi1_ibport *ibp = &ppd->ibport_data; unsigned i; int ret; size_t lcpysz = IB_DEVICE_NAME_MAX; @@ -1643,17 +1640,19 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) if (ret) goto err_verbs_txreq; + /* Use first-port GUID as node guid */ + ibdev->node_guid = get_sguid(ibp, HFI1_PORT_GUID_INDEX); + /* * The system image GUID is supposed to be the same for all * HFIs in a single system but since there can be other * device types in the system, we can't be sure this is unique. */ if (!ib_hfi1_sys_image_guid) - ib_hfi1_sys_image_guid = cpu_to_be64(ppd->guid); + ib_hfi1_sys_image_guid = ibdev->node_guid; lcpysz = strlcpy(ibdev->name, class_name(), lcpysz); strlcpy(ibdev->name + lcpysz, "_%d", IB_DEVICE_NAME_MAX - lcpysz); ibdev->owner = THIS_MODULE; - ibdev->node_guid = cpu_to_be64(ppd->guid); ibdev->phys_port_cnt = dd->num_pports; ibdev->dma_device = &dd->pcidev->dev; ibdev->modify_device = modify_device; diff --git a/drivers/infiniband/hw/hfi1/verbs.h b/drivers/infiniband/hw/hfi1/verbs.h index 7a8af39e99d4..e6b893010e6d 100644 --- a/drivers/infiniband/hw/hfi1/verbs.h +++ b/drivers/infiniband/hw/hfi1/verbs.h @@ -73,7 +73,6 @@ struct hfi1_packet; #include "iowait.h" #define HFI1_MAX_RDMA_ATOMIC 16 -#define HFI1_GUIDS_PER_PORT 5 /* * Increment this value if any changes that break userspace ABI @@ -169,8 +168,6 @@ struct hfi1_ibport { struct rvt_qp __rcu *qp[2]; struct rvt_ibport rvp; - __be64 guids[HFI1_GUIDS_PER_PORT - 1]; /* writable GUIDs */ - /* the first 16 entries are sl_to_vl for !OPA */ u8 sl_to_sc[32]; u8 sc_to_sl[32]; -- cgit v1.2.3 From 6e768f0682e26e7683c4af5b0de04a2e08bc67db Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Mon, 17 Oct 2016 04:19:35 -0700 Subject: IB/hfi1: Optimize devdata cachelines Profiling shows hot path struct members that need to be in a minimum set of cachelines. Group these struct member in the same cacheline: sc2vl_lock sc2vl rhf_rcv_function_map rcv_limit rhf_offset Group these struct member in the same cacheline: process_pio_send process_dma_send pport rcd int_counter flags num_pports first_user_ctxt Fill holes in struct hfi1_devdata revealed by pahole. Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/hfi.h | 108 ++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index a2ea643a79fc..25e44c4af995 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -852,32 +852,29 @@ struct hfi1_devdata { u8 __iomem *kregend; /* physical address of chip for io_remap, etc. */ resource_size_t physaddr; - /* receive context data */ - struct hfi1_ctxtdata **rcd; + /* Per VL data. Enough for all VLs but not all elements are set/used. */ + struct per_vl_data vld[PER_VL_SEND_CONTEXTS]; /* send context data */ struct send_context_info *send_contexts; /* map hardware send contexts to software index */ u8 *hw_to_sw; /* spinlock for allocating and releasing send context resources */ spinlock_t sc_lock; - /* Per VL data. Enough for all VLs but not all elements are set/used. */ - struct per_vl_data vld[PER_VL_SEND_CONTEXTS]; /* lock for pio_map */ spinlock_t pio_map_lock; + /* Send Context initialization lock. */ + spinlock_t sc_init_lock; + /* lock for sdma_map */ + spinlock_t sde_map_lock; /* array of kernel send contexts */ struct send_context **kernel_send_context; /* array of vl maps */ struct pio_vl_map __rcu *pio_map; - /* seqlock for sc2vl */ - seqlock_t sc2vl_lock; - u64 sc2vl[4]; - /* Send Context initialization lock. */ - spinlock_t sc_init_lock; + /* default flags to last descriptor */ + u64 default_desc1; /* fields common to all SDMA engines */ - /* default flags to last descriptor */ - u64 default_desc1; volatile __le64 *sdma_heads_dma; /* DMA'ed by chip */ dma_addr_t sdma_heads_phys; void *sdma_pad_dma; /* DMA'ed by chip */ @@ -888,8 +885,6 @@ struct hfi1_devdata { u32 chip_sdma_engines; /* num used */ u32 num_sdma; - /* lock for sdma_map */ - spinlock_t sde_map_lock; /* array of engines sized by num_sdma */ struct sdma_engine *per_sdma; /* array of vl maps */ @@ -898,14 +893,11 @@ struct hfi1_devdata { wait_queue_head_t sdma_unfreeze_wq; atomic_t sdma_unfreeze_count; + u32 lcb_access_count; /* count of LCB users */ + /* common data between shared ASIC HFIs in this OS */ struct hfi1_asic_data *asic_data; - /* hfi1_pportdata, points to array of (physical) port-specific - * data structs, indexed by pidx (0..n-1) - */ - struct hfi1_pportdata *pport; - /* mem-mapped pointer to base of PIO buffers */ void __iomem *piobase; /* @@ -922,20 +914,13 @@ struct hfi1_devdata { /* send context numbers and sizes for each type */ struct sc_config_sizes sc_sizes[SC_MAX]; - u32 lcb_access_count; /* count of LCB users */ - char *boardname; /* human readable board info */ - /* device (not port) flags, basically device capabilities */ - u32 flags; - /* reset value */ u64 z_int_counter; u64 z_rcv_limit; u64 z_send_schedule; - /* percpu int_counter */ - u64 __percpu *int_counter; - u64 __percpu *rcv_limit; + u64 __percpu *send_schedule; /* number of receive contexts in use by the driver */ u32 num_rcv_contexts; @@ -950,6 +935,7 @@ struct hfi1_devdata { /* base receive interrupt timeout, in CSR units */ u32 rcv_intr_timeout_csr; + u32 freezelen; /* max length of freezemsg */ u64 __iomem *egrtidbase; spinlock_t sendctrl_lock; /* protect changes to SendCtrl */ spinlock_t rcvctrl_lock; /* protect changes to RcvCtrl */ @@ -971,7 +957,6 @@ struct hfi1_devdata { * IB link status cheaply */ struct hfi1_status *status; - u32 freezelen; /* max length of freezemsg */ /* revision register shadow */ u64 revision; @@ -999,6 +984,8 @@ struct hfi1_devdata { u16 rcvegrbufsize_shift; /* both sides of the PCIe link are gen3 capable */ u8 link_gen3_capable; + /* default link down value (poll/sleep) */ + u8 link_default; /* localbus width (1, 2,4,8,16,32) from config space */ u32 lbus_width; /* localbus speed in MHz */ @@ -1034,8 +1021,6 @@ struct hfi1_devdata { u8 hfi1_id; /* implementation code */ u8 icode; - /* default link down value (poll/sleep) */ - u8 link_default; /* vAU of this device */ u8 vau; /* vCU of this device */ @@ -1046,27 +1031,17 @@ struct hfi1_devdata { u16 vl15_init; /* Misc small ints */ - /* Number of physical ports available */ - u8 num_pports; - /* Lowest context number which can be used by user processes */ - u8 first_user_ctxt; u8 n_krcv_queues; u8 qos_shift; - u8 qpn_mask; - u16 rhf_offset; /* offset of RHF within receive header entry */ u16 irev; /* implementation revision */ u16 dc8051_ver; /* 8051 firmware version */ + spinlock_t hfi1_diag_trans_lock; /* protect diag observer ops */ struct platform_config platform_config; struct platform_config_cache pcfg_cache; struct diag_client *diag_client; - spinlock_t hfi1_diag_trans_lock; /* protect diag observer ops */ - - u8 psxmitwait_supported; - /* cycle length of PS* counters in HW (in picoseconds) */ - u16 psxmitwait_check_rate; /* MSI-X information */ struct hfi1_msix_entry *msix_entries; @@ -1081,6 +1056,9 @@ struct hfi1_devdata { struct rcv_array_data rcv_entries; + /* cycle length of PS* counters in HW (in picoseconds) */ + u16 psxmitwait_check_rate; + /* * 64 bit synthetic counters */ @@ -1113,11 +1091,11 @@ struct hfi1_devdata { struct err_info_rcvport err_info_rcvport; struct err_info_constraint err_info_rcv_constraint; struct err_info_constraint err_info_xmit_constraint; - u8 err_info_uncorrectable; - u8 err_info_fmconfig; atomic_t drop_packet; u8 do_drop; + u8 err_info_uncorrectable; + u8 err_info_fmconfig; /* * Software counters for the status bits defined by the @@ -1140,47 +1118,71 @@ struct hfi1_devdata { u64 sw_cce_err_status_aggregate; /* Software counter that aggregates all bypass packet rcv errors */ u64 sw_rcv_bypass_packet_errors; - /* receive interrupt functions */ - rhf_rcv_function_ptr *rhf_rcv_function_map; + /* receive interrupt function */ rhf_rcv_function_ptr normal_rhf_rcv_functions[8]; + /* Save the enabled LCB error bits */ + u64 lcb_err_en; + /* * Handlers for outgoing data so that snoop/capture does not * have to have its hooks in the send path */ - send_routine process_pio_send; + send_routine process_pio_send ____cacheline_aligned_in_smp; send_routine process_dma_send; void (*pio_inline_send)(struct hfi1_devdata *dd, struct pio_buf *pbuf, u64 pbc, const void *from, size_t count); + /* hfi1_pportdata, points to array of (physical) port-specific + * data structs, indexed by pidx (0..n-1) + */ + struct hfi1_pportdata *pport; + /* receive context data */ + struct hfi1_ctxtdata **rcd; + u64 __percpu *int_counter; + /* device (not port) flags, basically device capabilities */ + u16 flags; + /* Number of physical ports available */ + u8 num_pports; + /* Lowest context number which can be used by user processes */ + u8 first_user_ctxt; + /* adding a new field here would make it part of this cacheline */ + + /* seqlock for sc2vl */ + seqlock_t sc2vl_lock ____cacheline_aligned_in_smp; + u64 sc2vl[4]; + /* receive interrupt functions */ + rhf_rcv_function_ptr *rhf_rcv_function_map; + u64 __percpu *rcv_limit; + u16 rhf_offset; /* offset of RHF within receive header entry */ + /* adding a new field here would make it part of this cacheline */ /* OUI comes from the HW. Used everywhere as 3 separate bytes. */ u8 oui1; u8 oui2; u8 oui3; + u8 dc_shutdown; + /* Timer and counter used to detect RcvBufOvflCnt changes */ struct timer_list rcverr_timer; - u32 rcv_ovfl_cnt; wait_queue_head_t event_queue; - /* Save the enabled LCB error bits */ - u64 lcb_err_en; - u8 dc_shutdown; - /* receive context tail dummy address */ __le64 *rcvhdrtail_dummy_kvaddr; dma_addr_t rcvhdrtail_dummy_dma; - bool eprom_available; /* true if EPROM is available for this device */ - bool aspm_supported; /* Does HW support ASPM */ - bool aspm_enabled; /* ASPM state: enabled/disabled */ + u32 rcv_ovfl_cnt; /* Serialize ASPM enable/disable between multiple verbs contexts */ spinlock_t aspm_lock; /* Number of verbs contexts which have disabled ASPM */ atomic_t aspm_disabled_cnt; struct hfi1_affinity *affinity; + bool eprom_available; /* true if EPROM is available for this device */ + bool aspm_supported; /* Does HW support ASPM */ + bool aspm_enabled; /* ASPM state: enabled/disabled */ struct rhashtable sdma_rht; + struct kobject kobj; }; -- cgit v1.2.3 From fe4d924396a861937256293ff4a84b76b84854d8 Mon Sep 17 00:00:00 2001 From: Easwar Hariharan Date: Mon, 17 Oct 2016 04:19:47 -0700 Subject: IB/hfi1: Add active channel and backplane support for integrated devices Use scratch registers within the HFI1 device to recover signal integrity information that is then used to tune the channel. While there, update error messages to better convey the result of falling back to a backup file. Reviewed-by: Ira Weiny Reviewed-by: Dennis Dalessandro Reviewed-by: Dean Luick Signed-off-by: Easwar Hariharan Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip_registers.h | 3 + drivers/infiniband/hw/hfi1/firmware.c | 136 +++++++++++++++++++++---- drivers/infiniband/hw/hfi1/hfi.h | 16 ++- drivers/infiniband/hw/hfi1/platform.c | 149 +++++++++++++++++++++++----- drivers/infiniband/hw/hfi1/platform.h | 117 ++++++++++++++++++++++ 5 files changed, 376 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/chip_registers.h b/drivers/infiniband/hw/hfi1/chip_registers.h index 5b9993899789..5bfa839d1c48 100644 --- a/drivers/infiniband/hw/hfi1/chip_registers.h +++ b/drivers/infiniband/hw/hfi1/chip_registers.h @@ -415,6 +415,9 @@ #define ASIC_CFG_SBUS_REQUEST_DATA_IN_SHIFT 32 #define ASIC_CFG_SBUS_REQUEST_RECEIVER_ADDR_SHIFT 0 #define ASIC_CFG_SCRATCH (ASIC + 0x000000000020) +#define ASIC_CFG_SCRATCH_1 (ASIC_CFG_SCRATCH + 0x08) +#define ASIC_CFG_SCRATCH_2 (ASIC_CFG_SCRATCH + 0x10) +#define ASIC_CFG_SCRATCH_3 (ASIC_CFG_SCRATCH + 0x18) #define ASIC_CFG_THERM_POLL_EN (ASIC + 0x000000000050) #define ASIC_EEP_ADDR_CMD (ASIC + 0x000000000308) #define ASIC_EEP_ADDR_CMD_EP_ADDR_MASK 0xFFFFFFull diff --git a/drivers/infiniband/hw/hfi1/firmware.c b/drivers/infiniband/hw/hfi1/firmware.c index 13db8eb4f4ec..9a36c8c2f8a1 100644 --- a/drivers/infiniband/hw/hfi1/firmware.c +++ b/drivers/infiniband/hw/hfi1/firmware.c @@ -707,6 +707,9 @@ static int obtain_firmware(struct hfi1_devdata *dd) &dd->pcidev->dev); if (err) { platform_config = NULL; + dd_dev_err(dd, + "%s: No default platform config file found\n", + __func__); goto done; } dd->platform_config.data = platform_config->data; @@ -1761,8 +1764,17 @@ int parse_platform_config(struct hfi1_devdata *dd) u32 record_idx = 0, table_type = 0, table_length_dwords = 0; int ret = -EINVAL; /* assume failure */ + /* + * For integrated devices that did not fall back to the default file, + * the SI tuning information for active channels is acquired from the + * scratch register bitmap, thus there is no platform config to parse. + * Skip parsing in these situations. + */ + if (is_integrated(dd) && !platform_config_load) + return 0; + if (!dd->platform_config.data) { - dd_dev_info(dd, "%s: Missing config file\n", __func__); + dd_dev_err(dd, "%s: Missing config file\n", __func__); goto bail; } ptr = (u32 *)dd->platform_config.data; @@ -1770,7 +1782,7 @@ int parse_platform_config(struct hfi1_devdata *dd) magic_num = *ptr; ptr++; if (magic_num != PLATFORM_CONFIG_MAGIC_NUM) { - dd_dev_info(dd, "%s: Bad config file\n", __func__); + dd_dev_err(dd, "%s: Bad config file\n", __func__); goto bail; } @@ -1797,9 +1809,9 @@ int parse_platform_config(struct hfi1_devdata *dd) header1 = *ptr; header2 = *(ptr + 1); if (header1 != ~header2) { - dd_dev_info(dd, "%s: Failed validation at offset %ld\n", - __func__, (ptr - (u32 *) - dd->platform_config.data)); + dd_dev_err(dd, "%s: Failed validation at offset %ld\n", + __func__, (ptr - (u32 *) + dd->platform_config.data)); goto bail; } @@ -1841,11 +1853,11 @@ int parse_platform_config(struct hfi1_devdata *dd) table_length_dwords; break; default: - dd_dev_info(dd, - "%s: Unknown data table %d, offset %ld\n", - __func__, table_type, - (ptr - (u32 *) - dd->platform_config.data)); + dd_dev_err(dd, + "%s: Unknown data table %d, offset %ld\n", + __func__, table_type, + (ptr - (u32 *) + dd->platform_config.data)); goto bail; /* We don't trust this file now */ } pcfgcache->config_tables[table_type].table = ptr; @@ -1865,11 +1877,11 @@ int parse_platform_config(struct hfi1_devdata *dd) case PLATFORM_CONFIG_VARIABLE_SETTINGS_TABLE: break; default: - dd_dev_info(dd, - "%s: Unknown meta table %d, offset %ld\n", - __func__, table_type, - (ptr - - (u32 *)dd->platform_config.data)); + dd_dev_err(dd, + "%s: Unknown meta table %d, offset %ld\n", + __func__, table_type, + (ptr - + (u32 *)dd->platform_config.data)); goto bail; /* We don't trust this file now */ } pcfgcache->config_tables[table_type].table_metadata = @@ -1884,10 +1896,9 @@ int parse_platform_config(struct hfi1_devdata *dd) /* Jump the table */ ptr += table_length_dwords; if (crc != *ptr) { - dd_dev_info(dd, "%s: Failed CRC check at offset %ld\n", - __func__, (ptr - - (u32 *) - dd->platform_config.data)); + dd_dev_err(dd, "%s: Failed CRC check at offset %ld\n", + __func__, (ptr - + (u32 *)dd->platform_config.data)); goto bail; } /* Jump the CRC DWORD */ @@ -1901,6 +1912,84 @@ bail: return ret; } +static void get_integrated_platform_config_field( + struct hfi1_devdata *dd, + enum platform_config_table_type_encoding table_type, + int field_index, u32 *data) +{ + struct hfi1_pportdata *ppd = dd->pport; + u8 *cache = ppd->qsfp_info.cache; + u32 tx_preset = 0; + + switch (table_type) { + case PLATFORM_CONFIG_SYSTEM_TABLE: + if (field_index == SYSTEM_TABLE_QSFP_POWER_CLASS_MAX) + *data = ppd->max_power_class; + else if (field_index == SYSTEM_TABLE_QSFP_ATTENUATION_DEFAULT_25G) + *data = ppd->default_atten; + break; + case PLATFORM_CONFIG_PORT_TABLE: + if (field_index == PORT_TABLE_PORT_TYPE) + *data = ppd->port_type; + else if (field_index == PORT_TABLE_LOCAL_ATTEN_25G) + *data = ppd->local_atten; + else if (field_index == PORT_TABLE_REMOTE_ATTEN_25G) + *data = ppd->remote_atten; + break; + case PLATFORM_CONFIG_RX_PRESET_TABLE: + if (field_index == RX_PRESET_TABLE_QSFP_RX_CDR_APPLY) + *data = (ppd->rx_preset & QSFP_RX_CDR_APPLY_SMASK) >> + QSFP_RX_CDR_APPLY_SHIFT; + else if (field_index == RX_PRESET_TABLE_QSFP_RX_EMP_APPLY) + *data = (ppd->rx_preset & QSFP_RX_EMP_APPLY_SMASK) >> + QSFP_RX_EMP_APPLY_SHIFT; + else if (field_index == RX_PRESET_TABLE_QSFP_RX_AMP_APPLY) + *data = (ppd->rx_preset & QSFP_RX_AMP_APPLY_SMASK) >> + QSFP_RX_AMP_APPLY_SHIFT; + else if (field_index == RX_PRESET_TABLE_QSFP_RX_CDR) + *data = (ppd->rx_preset & QSFP_RX_CDR_SMASK) >> + QSFP_RX_CDR_SHIFT; + else if (field_index == RX_PRESET_TABLE_QSFP_RX_EMP) + *data = (ppd->rx_preset & QSFP_RX_EMP_SMASK) >> + QSFP_RX_EMP_SHIFT; + else if (field_index == RX_PRESET_TABLE_QSFP_RX_AMP) + *data = (ppd->rx_preset & QSFP_RX_AMP_SMASK) >> + QSFP_RX_AMP_SHIFT; + break; + case PLATFORM_CONFIG_TX_PRESET_TABLE: + if (cache[QSFP_EQ_INFO_OFFS] & 0x4) + tx_preset = ppd->tx_preset_eq; + else + tx_preset = ppd->tx_preset_noeq; + if (field_index == TX_PRESET_TABLE_PRECUR) + *data = (tx_preset & TX_PRECUR_SMASK) >> + TX_PRECUR_SHIFT; + else if (field_index == TX_PRESET_TABLE_ATTN) + *data = (tx_preset & TX_ATTN_SMASK) >> + TX_ATTN_SHIFT; + else if (field_index == TX_PRESET_TABLE_POSTCUR) + *data = (tx_preset & TX_POSTCUR_SMASK) >> + TX_POSTCUR_SHIFT; + else if (field_index == TX_PRESET_TABLE_QSFP_TX_CDR_APPLY) + *data = (tx_preset & QSFP_TX_CDR_APPLY_SMASK) >> + QSFP_TX_CDR_APPLY_SHIFT; + else if (field_index == TX_PRESET_TABLE_QSFP_TX_EQ_APPLY) + *data = (tx_preset & QSFP_TX_EQ_APPLY_SMASK) >> + QSFP_TX_EQ_APPLY_SHIFT; + else if (field_index == TX_PRESET_TABLE_QSFP_TX_CDR) + *data = (tx_preset & QSFP_TX_CDR_SMASK) >> + QSFP_TX_CDR_SHIFT; + else if (field_index == TX_PRESET_TABLE_QSFP_TX_EQ) + *data = (tx_preset & QSFP_TX_EQ_SMASK) >> + QSFP_TX_EQ_SHIFT; + break; + case PLATFORM_CONFIG_QSFP_ATTEN_TABLE: + case PLATFORM_CONFIG_VARIABLE_SETTINGS_TABLE: + default: + break; + } +} + static int get_platform_fw_field_metadata(struct hfi1_devdata *dd, int table, int field, u32 *field_len_bits, u32 *field_start_bits) @@ -1976,6 +2065,15 @@ int get_platform_config_field(struct hfi1_devdata *dd, else return -EINVAL; + if (is_integrated(dd) && !platform_config_load) { + /* + * Use saved configuration from ppd for integrated platforms + */ + get_integrated_platform_config_field(dd, table_type, + field_index, data); + return 0; + } + ret = get_platform_fw_field_metadata(dd, table_type, field_index, &field_len_bits, &field_start_bits); diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index 25e44c4af995..a66d198199ff 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -582,8 +582,16 @@ struct hfi1_pportdata { struct kobject vl2mtu_kobj; /* PHY support */ - u32 port_type; struct qsfp_data qsfp_info; + /* Values for SI tuning of SerDes */ + u32 port_type; + u32 tx_preset_eq; + u32 tx_preset_noeq; + u32 rx_preset; + u8 local_atten; + u8 remote_atten; + u8 default_atten; + u8 max_power_class; /* GUIDs for this interface, in host order, guids[0] is a port guid */ u64 guids[HFI1_GUIDS_PER_PORT]; @@ -2020,6 +2028,12 @@ static inline u32 qsfp_resource(struct hfi1_devdata *dd) return i2c_target(dd->hfi1_id); } +/* Is this device integrated or discrete? */ +static inline bool is_integrated(struct hfi1_devdata *dd) +{ + return dd->pcidev->device == PCI_DEVICE_ID_INTEL1; +} + int hfi1_tempsense_rd(struct hfi1_devdata *dd, struct hfi1_temp *temp); #define DD_DEV_ENTRY(dd) __string(dev, dev_name(&(dd)->pcidev->dev)) diff --git a/drivers/infiniband/hw/hfi1/platform.c b/drivers/infiniband/hw/hfi1/platform.c index 202433178864..0e7043801bb1 100644 --- a/drivers/infiniband/hw/hfi1/platform.c +++ b/drivers/infiniband/hw/hfi1/platform.c @@ -49,6 +49,90 @@ #include "efivar.h" #include "eprom.h" +static int validate_scratch_checksum(struct hfi1_devdata *dd) +{ + u64 checksum = 0, temp_scratch = 0; + int i, j, version; + + temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH); + version = (temp_scratch & BITMAP_VERSION_SMASK) >> BITMAP_VERSION_SHIFT; + + /* Prevent power on default of all zeroes from passing checksum */ + if (!version) + return 0; + + /* + * ASIC scratch 0 only contains the checksum and bitmap version as + * fields of interest, both of which are handled separately from the + * loop below, so skip it + */ + checksum += version; + for (i = 1; i < ASIC_NUM_SCRATCH; i++) { + temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH + (8 * i)); + for (j = sizeof(u64); j != 0; j -= 2) { + checksum += (temp_scratch & 0xFFFF); + temp_scratch >>= 16; + } + } + + while (checksum >> 16) + checksum = (checksum & CHECKSUM_MASK) + (checksum >> 16); + + temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH); + temp_scratch &= CHECKSUM_SMASK; + temp_scratch >>= CHECKSUM_SHIFT; + + if (checksum + temp_scratch == 0xFFFF) + return 1; + return 0; +} + +static void save_platform_config_fields(struct hfi1_devdata *dd) +{ + struct hfi1_pportdata *ppd = dd->pport; + u64 temp_scratch = 0, temp_dest = 0; + + temp_scratch = read_csr(dd, ASIC_CFG_SCRATCH_1); + + temp_dest = temp_scratch & + (dd->hfi1_id ? PORT1_PORT_TYPE_SMASK : + PORT0_PORT_TYPE_SMASK); + ppd->port_type = temp_dest >> + (dd->hfi1_id ? PORT1_PORT_TYPE_SHIFT : + PORT0_PORT_TYPE_SHIFT); + + temp_dest = temp_scratch & + (dd->hfi1_id ? PORT1_LOCAL_ATTEN_SMASK : + PORT0_LOCAL_ATTEN_SMASK); + ppd->local_atten = temp_dest >> + (dd->hfi1_id ? PORT1_LOCAL_ATTEN_SHIFT : + PORT0_LOCAL_ATTEN_SHIFT); + + temp_dest = temp_scratch & + (dd->hfi1_id ? PORT1_REMOTE_ATTEN_SMASK : + PORT0_REMOTE_ATTEN_SMASK); + ppd->remote_atten = temp_dest >> + (dd->hfi1_id ? PORT1_REMOTE_ATTEN_SHIFT : + PORT0_REMOTE_ATTEN_SHIFT); + + temp_dest = temp_scratch & + (dd->hfi1_id ? PORT1_DEFAULT_ATTEN_SMASK : + PORT0_DEFAULT_ATTEN_SMASK); + ppd->default_atten = temp_dest >> + (dd->hfi1_id ? PORT1_DEFAULT_ATTEN_SHIFT : + PORT0_DEFAULT_ATTEN_SHIFT); + + temp_scratch = read_csr(dd, dd->hfi1_id ? ASIC_CFG_SCRATCH_3 : + ASIC_CFG_SCRATCH_2); + + ppd->tx_preset_eq = (temp_scratch & TX_EQ_SMASK) >> TX_EQ_SHIFT; + ppd->tx_preset_noeq = (temp_scratch & TX_NO_EQ_SMASK) >> TX_NO_EQ_SHIFT; + ppd->rx_preset = (temp_scratch & RX_SMASK) >> RX_SHIFT; + + ppd->max_power_class = (temp_scratch & QSFP_MAX_POWER_SMASK) >> + QSFP_MAX_POWER_SHIFT; +} + void get_platform_config(struct hfi1_devdata *dd) { int ret = 0; @@ -56,38 +140,49 @@ void get_platform_config(struct hfi1_devdata *dd) u8 *temp_platform_config = NULL; u32 esize; - ret = eprom_read_platform_config(dd, (void **)&temp_platform_config, - &esize); - if (!ret) { - /* success */ - size = esize; - goto success; + if (is_integrated(dd)) { + if (validate_scratch_checksum(dd)) { + save_platform_config_fields(dd); + return; + } + dd_dev_err(dd, "%s: Config bitmap corrupted/uninitialized\n", + __func__); + dd_dev_err(dd, + "%s: Please update your BIOS to support active channels\n", + __func__); + } else { + ret = eprom_read_platform_config(dd, + (void **)&temp_platform_config, + &esize); + if (!ret) { + /* success */ + dd->platform_config.data = temp_platform_config; + dd->platform_config.size = esize; + return; + } + /* fail, try EFI variable */ + + ret = read_hfi1_efi_var(dd, "configuration", &size, + (void **)&temp_platform_config); + if (!ret) { + dd->platform_config.data = temp_platform_config; + dd->platform_config.size = size; + return; + } } - /* fail, try EFI variable */ - - ret = read_hfi1_efi_var(dd, "configuration", &size, - (void **)&temp_platform_config); - if (!ret) - goto success; - - dd_dev_info(dd, - "%s: Failed to get platform config from UEFI, falling back to request firmware\n", - __func__); + dd_dev_err(dd, + "%s: Failed to get platform config, falling back to sub-optimal default file\n", + __func__); /* fall back to request firmware */ platform_config_load = 1; - return; - -success: - dd->platform_config.data = temp_platform_config; - dd->platform_config.size = size; } void free_platform_config(struct hfi1_devdata *dd) { if (!platform_config_load) { /* - * was loaded from EFI, release memory - * allocated by read_efi_var + * was loaded from EFI or the EPROM, release memory + * allocated by read_efi_var/eprom_read_platform_config */ kfree(dd->platform_config.data); } @@ -100,12 +195,16 @@ void free_platform_config(struct hfi1_devdata *dd) void get_port_type(struct hfi1_pportdata *ppd) { int ret; + u32 temp; ret = get_platform_config_field(ppd->dd, PLATFORM_CONFIG_PORT_TABLE, 0, - PORT_TABLE_PORT_TYPE, &ppd->port_type, + PORT_TABLE_PORT_TYPE, &temp, 4); - if (ret) + if (ret) { ppd->port_type = PORT_TYPE_UNKNOWN; + return; + } + ppd->port_type = temp; } int set_qsfp_tx(struct hfi1_pportdata *ppd, int on) diff --git a/drivers/infiniband/hw/hfi1/platform.h b/drivers/infiniband/hw/hfi1/platform.h index e2c21613c326..31155401a95b 100644 --- a/drivers/infiniband/hw/hfi1/platform.h +++ b/drivers/infiniband/hw/hfi1/platform.h @@ -295,6 +295,123 @@ enum link_tuning_encoding { OPA_UNKNOWN_TUNING }; +/* + * Shifts and masks for the link SI tuning values stuffed into the ASIC scratch + * registers for integrated platforms + */ +#define PORT0_PORT_TYPE_SHIFT 0 +#define PORT0_LOCAL_ATTEN_SHIFT 4 +#define PORT0_REMOTE_ATTEN_SHIFT 10 +#define PORT0_DEFAULT_ATTEN_SHIFT 32 + +#define PORT1_PORT_TYPE_SHIFT 16 +#define PORT1_LOCAL_ATTEN_SHIFT 20 +#define PORT1_REMOTE_ATTEN_SHIFT 26 +#define PORT1_DEFAULT_ATTEN_SHIFT 40 + +#define PORT0_PORT_TYPE_MASK 0xFUL +#define PORT0_LOCAL_ATTEN_MASK 0x3FUL +#define PORT0_REMOTE_ATTEN_MASK 0x3FUL +#define PORT0_DEFAULT_ATTEN_MASK 0xFFUL + +#define PORT1_PORT_TYPE_MASK 0xFUL +#define PORT1_LOCAL_ATTEN_MASK 0x3FUL +#define PORT1_REMOTE_ATTEN_MASK 0x3FUL +#define PORT1_DEFAULT_ATTEN_MASK 0xFFUL + +#define PORT0_PORT_TYPE_SMASK (PORT0_PORT_TYPE_MASK << \ + PORT0_PORT_TYPE_SHIFT) +#define PORT0_LOCAL_ATTEN_SMASK (PORT0_LOCAL_ATTEN_MASK << \ + PORT0_LOCAL_ATTEN_SHIFT) +#define PORT0_REMOTE_ATTEN_SMASK (PORT0_REMOTE_ATTEN_MASK << \ + PORT0_REMOTE_ATTEN_SHIFT) +#define PORT0_DEFAULT_ATTEN_SMASK (PORT0_DEFAULT_ATTEN_MASK << \ + PORT0_DEFAULT_ATTEN_SHIFT) + +#define PORT1_PORT_TYPE_SMASK (PORT1_PORT_TYPE_MASK << \ + PORT1_PORT_TYPE_SHIFT) +#define PORT1_LOCAL_ATTEN_SMASK (PORT1_LOCAL_ATTEN_MASK << \ + PORT1_LOCAL_ATTEN_SHIFT) +#define PORT1_REMOTE_ATTEN_SMASK (PORT1_REMOTE_ATTEN_MASK << \ + PORT1_REMOTE_ATTEN_SHIFT) +#define PORT1_DEFAULT_ATTEN_SMASK (PORT1_DEFAULT_ATTEN_MASK << \ + PORT1_DEFAULT_ATTEN_SHIFT) + +#define QSFP_MAX_POWER_SHIFT 0 +#define TX_NO_EQ_SHIFT 4 +#define TX_EQ_SHIFT 25 +#define RX_SHIFT 46 + +#define QSFP_MAX_POWER_MASK 0xFUL +#define TX_NO_EQ_MASK 0x1FFFFFUL +#define TX_EQ_MASK 0x1FFFFFUL +#define RX_MASK 0xFFFFUL + +#define QSFP_MAX_POWER_SMASK (QSFP_MAX_POWER_MASK << \ + QSFP_MAX_POWER_SHIFT) +#define TX_NO_EQ_SMASK (TX_NO_EQ_MASK << TX_NO_EQ_SHIFT) +#define TX_EQ_SMASK (TX_EQ_MASK << TX_EQ_SHIFT) +#define RX_SMASK (RX_MASK << RX_SHIFT) + +#define TX_PRECUR_SHIFT 0 +#define TX_ATTN_SHIFT 4 +#define QSFP_TX_CDR_APPLY_SHIFT 9 +#define QSFP_TX_EQ_APPLY_SHIFT 10 +#define QSFP_TX_CDR_SHIFT 11 +#define QSFP_TX_EQ_SHIFT 12 +#define TX_POSTCUR_SHIFT 16 + +#define TX_PRECUR_MASK 0xFUL +#define TX_ATTN_MASK 0x1FUL +#define QSFP_TX_CDR_APPLY_MASK 0x1UL +#define QSFP_TX_EQ_APPLY_MASK 0x1UL +#define QSFP_TX_CDR_MASK 0x1UL +#define QSFP_TX_EQ_MASK 0xFUL +#define TX_POSTCUR_MASK 0x1FUL + +#define TX_PRECUR_SMASK (TX_PRECUR_MASK << TX_PRECUR_SHIFT) +#define TX_ATTN_SMASK (TX_ATTN_MASK << TX_ATTN_SHIFT) +#define QSFP_TX_CDR_APPLY_SMASK (QSFP_TX_CDR_APPLY_MASK << \ + QSFP_TX_CDR_APPLY_SHIFT) +#define QSFP_TX_EQ_APPLY_SMASK (QSFP_TX_EQ_APPLY_MASK << \ + QSFP_TX_EQ_APPLY_SHIFT) +#define QSFP_TX_CDR_SMASK (QSFP_TX_CDR_MASK << QSFP_TX_CDR_SHIFT) +#define QSFP_TX_EQ_SMASK (QSFP_TX_EQ_MASK << QSFP_TX_EQ_SHIFT) +#define TX_POSTCUR_SMASK (TX_POSTCUR_MASK << TX_POSTCUR_SHIFT) + +#define QSFP_RX_CDR_APPLY_SHIFT 0 +#define QSFP_RX_EMP_APPLY_SHIFT 1 +#define QSFP_RX_AMP_APPLY_SHIFT 2 +#define QSFP_RX_CDR_SHIFT 3 +#define QSFP_RX_EMP_SHIFT 4 +#define QSFP_RX_AMP_SHIFT 8 + +#define QSFP_RX_CDR_APPLY_MASK 0x1UL +#define QSFP_RX_EMP_APPLY_MASK 0x1UL +#define QSFP_RX_AMP_APPLY_MASK 0x1UL +#define QSFP_RX_CDR_MASK 0x1UL +#define QSFP_RX_EMP_MASK 0xFUL +#define QSFP_RX_AMP_MASK 0x3UL + +#define QSFP_RX_CDR_APPLY_SMASK (QSFP_RX_CDR_APPLY_MASK << \ + QSFP_RX_CDR_APPLY_SHIFT) +#define QSFP_RX_EMP_APPLY_SMASK (QSFP_RX_EMP_APPLY_MASK << \ + QSFP_RX_EMP_APPLY_SHIFT) +#define QSFP_RX_AMP_APPLY_SMASK (QSFP_RX_AMP_APPLY_MASK << \ + QSFP_RX_AMP_APPLY_SHIFT) +#define QSFP_RX_CDR_SMASK (QSFP_RX_CDR_MASK << QSFP_RX_CDR_SHIFT) +#define QSFP_RX_EMP_SMASK (QSFP_RX_EMP_MASK << QSFP_RX_EMP_SHIFT) +#define QSFP_RX_AMP_SMASK (QSFP_RX_AMP_MASK << QSFP_RX_AMP_SHIFT) + +#define BITMAP_VERSION 1 +#define BITMAP_VERSION_SHIFT 44 +#define BITMAP_VERSION_MASK 0xFUL +#define BITMAP_VERSION_SMASK (BITMAP_VERSION_MASK << \ + BITMAP_VERSION_SHIFT) +#define CHECKSUM_SHIFT 48 +#define CHECKSUM_MASK 0xFFFFUL +#define CHECKSUM_SMASK (CHECKSUM_MASK << CHECKSUM_SHIFT) + /* platform.c */ void get_platform_config(struct hfi1_devdata *dd); void free_platform_config(struct hfi1_devdata *dd); -- cgit v1.2.3 From 2474d775d9e2f935ff6840c8b21b4262afacc821 Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Tue, 25 Oct 2016 13:12:28 -0700 Subject: IB/hfi1: Get rid of divide in pio buffer allocator The div instruction shows costly in profiles. Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/pio.c | 11 +++++++---- drivers/infiniband/hw/hfi1/pio.h | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 385e4dcf2cd3..516fac38d31e 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -1249,6 +1249,7 @@ int sc_enable(struct send_context *sc) sc->free = 0; sc->alloc_free = 0; sc->fill = 0; + sc->fill_wrap = 0; sc->sr_head = 0; sc->sr_tail = 0; sc->flags = 0; @@ -1392,7 +1393,7 @@ struct pio_buf *sc_buffer_alloc(struct send_context *sc, u32 dw_len, unsigned long flags; unsigned long avail; unsigned long blocks = dwords_to_blocks(dw_len); - unsigned long start_fill; + u32 fill_wrap; int trycount = 0; u32 head, next; @@ -1435,8 +1436,11 @@ retry: head = sc->sr_head; /* "allocate" the buffer */ - start_fill = sc->fill; sc->fill += blocks; + fill_wrap = sc->fill_wrap; + sc->fill_wrap += blocks; + if (sc->fill_wrap >= sc->credits) + sc->fill_wrap = sc->fill_wrap - sc->credits; /* * Fill the parts that the releaser looks at before moving the head. @@ -1465,8 +1469,7 @@ retry: spin_unlock_irqrestore(&sc->alloc_lock, flags); /* finish filling in the buffer outside the lock */ - pbuf->start = sc->base_addr + ((start_fill % sc->credits) - * PIO_BLOCK_SIZE); + pbuf->start = sc->base_addr + fill_wrap * PIO_BLOCK_SIZE; pbuf->size = sc->credits * PIO_BLOCK_SIZE; pbuf->end = sc->base_addr + pbuf->size; pbuf->block_count = blocks; diff --git a/drivers/infiniband/hw/hfi1/pio.h b/drivers/infiniband/hw/hfi1/pio.h index bd19507b6bb0..498b548055e0 100644 --- a/drivers/infiniband/hw/hfi1/pio.h +++ b/drivers/infiniband/hw/hfi1/pio.h @@ -119,6 +119,7 @@ struct send_context { unsigned long fill; /* official alloc count */ unsigned long alloc_free; /* copy of free (less cache thrash) */ u32 __percpu *buffers_allocated;/* count of buffers allocated */ + u32 fill_wrap; /* tracks fill within ring */ /* releaser fields */ spinlock_t release_lock ____cacheline_aligned_in_smp; u32 sr_tail; /* shadow ring tail */ -- cgit v1.2.3 From 8af8d2970ed98493a2db88dfcad88b0065e55e79 Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Tue, 25 Oct 2016 13:12:34 -0700 Subject: IB/hfi1: Optimize pio_buf and send_context structs Both pio_buf and send_context structs have oversized fields and have cachelines that can be optimized. Reduce oversized fields for both structs. Make sure pio_buf struct fits within a cacheline. Move read-only fields to their own cacheline in send_context struct. All of this will avoid cacheline trading as the ring progresses and pio buffers/send contexts are used. Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/pio.c | 5 ++--- drivers/infiniband/hw/hfi1/pio.h | 29 +++++++++++++++-------------- drivers/infiniband/hw/hfi1/pio_copy.c | 22 +++++++++++----------- 3 files changed, 28 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 516fac38d31e..86a7f365b624 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -765,6 +765,7 @@ struct send_context *sc_alloc(struct hfi1_devdata *dd, int type, sc->hw_context = hw_context; cr_group_addresses(sc, &dma); sc->credits = sci->credits; + sc->size = sc->credits * PIO_BLOCK_SIZE; /* PIO Send Memory Address details */ #define PIO_ADDR_CONTEXT_MASK 0xfful @@ -1470,9 +1471,7 @@ retry: /* finish filling in the buffer outside the lock */ pbuf->start = sc->base_addr + fill_wrap * PIO_BLOCK_SIZE; - pbuf->size = sc->credits * PIO_BLOCK_SIZE; - pbuf->end = sc->base_addr + pbuf->size; - pbuf->block_count = blocks; + pbuf->end = sc->base_addr + sc->size; pbuf->qw_written = 0; pbuf->carry_bytes = 0; pbuf->carry.val64 = 0; diff --git a/drivers/infiniband/hw/hfi1/pio.h b/drivers/infiniband/hw/hfi1/pio.h index 498b548055e0..867e5ffc3595 100644 --- a/drivers/infiniband/hw/hfi1/pio.h +++ b/drivers/infiniband/hw/hfi1/pio.h @@ -83,43 +83,43 @@ struct pio_buf { void *arg; /* argument for cb */ void __iomem *start; /* buffer start address */ void __iomem *end; /* context end address */ - unsigned long size; /* context size, in bytes */ unsigned long sent_at; /* buffer is sent when <= free */ - u32 block_count; /* size of buffer, in blocks */ - u32 qw_written; /* QW written so far */ - u32 carry_bytes; /* number of valid bytes in carry */ union mix carry; /* pending unwritten bytes */ + u16 qw_written; /* QW written so far */ + u8 carry_bytes; /* number of valid bytes in carry */ }; /* cache line aligned pio buffer array */ union pio_shadow_ring { struct pio_buf pbuf; - u64 unused[16]; /* cache line spacer */ } ____cacheline_aligned; /* per-NUMA send context */ struct send_context { /* read-only after init */ struct hfi1_devdata *dd; /* device */ - void __iomem *base_addr; /* start of PIO memory */ union pio_shadow_ring *sr; /* shadow ring */ + void __iomem *base_addr; /* start of PIO memory */ + u32 __percpu *buffers_allocated;/* count of buffers allocated */ + u32 size; /* context size, in bytes */ - struct work_struct halt_work; /* halted context work queue entry */ - unsigned long flags; /* flags */ int node; /* context home node */ - int type; /* context type */ - u32 sw_index; /* software index number */ - u32 hw_context; /* hardware context number */ - u32 credits; /* number of blocks in context */ u32 sr_size; /* size of the shadow ring */ - u32 group; /* credit return group */ + u16 flags; /* flags */ + u8 type; /* context type */ + u8 sw_index; /* software index number */ + u8 hw_context; /* hardware context number */ + u8 group; /* credit return group */ + /* allocator fields */ spinlock_t alloc_lock ____cacheline_aligned_in_smp; u32 sr_head; /* shadow ring head */ unsigned long fill; /* official alloc count */ unsigned long alloc_free; /* copy of free (less cache thrash) */ - u32 __percpu *buffers_allocated;/* count of buffers allocated */ u32 fill_wrap; /* tracks fill within ring */ + u32 credits; /* number of blocks in context */ + /* adding a new field here would make it part of this cacheline */ + /* releaser fields */ spinlock_t release_lock ____cacheline_aligned_in_smp; u32 sr_tail; /* shadow ring tail */ @@ -131,6 +131,7 @@ struct send_context { u32 credit_intr_count; /* count of credit intr users */ u64 credit_ctrl; /* cache for credit control */ wait_queue_head_t halt_wait; /* wait until kernel sees interrupt */ + struct work_struct halt_work; /* halted context work queue entry */ }; /* send context flags */ diff --git a/drivers/infiniband/hw/hfi1/pio_copy.c b/drivers/infiniband/hw/hfi1/pio_copy.c index aa7773643107..03024cec78dd 100644 --- a/drivers/infiniband/hw/hfi1/pio_copy.c +++ b/drivers/infiniband/hw/hfi1/pio_copy.c @@ -129,8 +129,8 @@ void pio_copy(struct hfi1_devdata *dd, struct pio_buf *pbuf, u64 pbc, dest += sizeof(u64); } - dest -= pbuf->size; - dend -= pbuf->size; + dest -= pbuf->sc->size; + dend -= pbuf->sc->size; } /* write 8-byte non-SOP, non-wrap chunk data */ @@ -361,8 +361,8 @@ void seg_pio_copy_start(struct pio_buf *pbuf, u64 pbc, dest += sizeof(u64); } - dest -= pbuf->size; - dend -= pbuf->size; + dest -= pbuf->sc->size; + dend -= pbuf->sc->size; } /* write 8-byte non-SOP, non-wrap chunk data */ @@ -458,8 +458,8 @@ static void mid_copy_mix(struct pio_buf *pbuf, const void *from, size_t nbytes) dest += sizeof(u64); } - dest -= pbuf->size; - dend -= pbuf->size; + dest -= pbuf->sc->size; + dend -= pbuf->sc->size; } /* write 8-byte non-SOP, non-wrap chunk data */ @@ -492,7 +492,7 @@ static void mid_copy_mix(struct pio_buf *pbuf, const void *from, size_t nbytes) */ /* adjust if we have wrapped */ if (dest >= pbuf->end) - dest -= pbuf->size; + dest -= pbuf->sc->size; /* jump to the SOP range if within the first block */ else if (pbuf->qw_written < PIO_BLOCK_QWS) dest += SOP_DISTANCE; @@ -584,8 +584,8 @@ static void mid_copy_straight(struct pio_buf *pbuf, dest += sizeof(u64); } - dest -= pbuf->size; - dend -= pbuf->size; + dest -= pbuf->sc->size; + dend -= pbuf->sc->size; } /* write 8-byte non-SOP, non-wrap chunk data */ @@ -666,7 +666,7 @@ void seg_pio_copy_mid(struct pio_buf *pbuf, const void *from, size_t nbytes) */ /* adjust if we've wrapped */ if (dest >= pbuf->end) - dest -= pbuf->size; + dest -= pbuf->sc->size; /* jump to SOP range if within the first block */ else if (pbuf->qw_written < PIO_BLOCK_QWS) dest += SOP_DISTANCE; @@ -719,7 +719,7 @@ void seg_pio_copy_end(struct pio_buf *pbuf) */ /* adjust if we have wrapped */ if (dest >= pbuf->end) - dest -= pbuf->size; + dest -= pbuf->sc->size; /* jump to the SOP range if within the first block */ else if (pbuf->qw_written < PIO_BLOCK_QWS) dest += SOP_DISTANCE; -- cgit v1.2.3 From d2dc12d6c8325d1093ffb142315f6b4fc53f95e7 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 7 Oct 2016 16:07:43 -0300 Subject: [media] dvb-tc90522: Use kmalloc_array() in tc90522_master_xfer() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/tc90522.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index 31cd32532387..c2d45f071331 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -656,7 +656,7 @@ tc90522_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) for (i = 0; i < num; i++) if (msgs[i].flags & I2C_M_RD) rd_num++; - new_msgs = kmalloc(sizeof(*new_msgs) * (num + rd_num), GFP_KERNEL); + new_msgs = kmalloc_array(num + rd_num, sizeof(*new_msgs), GFP_KERNEL); if (!new_msgs) return -ENOMEM; -- cgit v1.2.3 From 68226b4dfa9b2e064e2f9e792bf7469f465054c7 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 7 Oct 2016 16:13:57 -0300 Subject: [media] dvb-tc90522: Rename a jump label in tc90522_probe() Adjust a jump label according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/tc90522.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c index c2d45f071331..4687e1546af2 100644 --- a/drivers/media/dvb-frontends/tc90522.c +++ b/drivers/media/dvb-frontends/tc90522.c @@ -794,14 +794,13 @@ static int tc90522_probe(struct i2c_client *client, i2c_set_adapdata(adap, state); ret = i2c_add_adapter(adap); if (ret < 0) - goto err; + goto free_state; cfg->tuner_i2c = state->cfg.tuner_i2c = adap; i2c_set_clientdata(client, &state->cfg); dev_info(&client->dev, "Toshiba TC90522 attached.\n"); return 0; - -err: +free_state: kfree(state); return ret; } -- cgit v1.2.3 From 045d69ce2116f72d9e658ff59427a11c93754a98 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 7 Oct 2016 17:07:27 -0300 Subject: [media] cx88-dsp: Use kmalloc_array() in read_rds_samples() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-dsp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index 7fafd132ccaf..341e24432fab 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -245,8 +245,7 @@ static s16 *read_rds_samples(struct cx88_core *core, u32 *N) current_address, current_address - srch->fifo_start, sample_count, cx_read(MO_AUD_INTSTAT)); - - samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL); + samples = kmalloc_array(sample_count, sizeof(*samples), GFP_KERNEL); if (!samples) return NULL; -- cgit v1.2.3 From 26f61c0ddf0e191fdab5c15f00c4bf8f3544be6b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 7 Oct 2016 17:30:40 -0300 Subject: [media] cx88-dsp: Add some spaces for better code readability Use space characters at some source code places according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-dsp.c | 40 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index 341e24432fab..33f3c58f8197 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -31,7 +31,7 @@ #define INT_PI ((s32)(3.141592653589 * 32768.0)) #define compat_remainder(a, b) \ - ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0) + ((float)(((s32)((a) * 100)) % ((s32)((b) * 100))) / 100.0) #define baseband_freq(carrier, srate, tone) ((s32)( \ (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI)) @@ -82,15 +82,15 @@ static s32 int_cos(u32 x) if (period % 2) return -int_cos(x - INT_PI); x = x % INT_PI; - if (x > INT_PI/2) - return -int_cos(INT_PI/2 - (x % (INT_PI/2))); + if (x > INT_PI / 2) + return -int_cos(INT_PI / 2 - (x % (INT_PI / 2))); /* Now x is between 0 and INT_PI/2. * To calculate cos(x) we use it's Taylor polinom. */ - t2 = x*x/32768/2; - t4 = t2*x/32768*x/32768/3/4; - t6 = t4*x/32768*x/32768/5/6; - t8 = t6*x/32768*x/32768/7/8; - ret = 32768-t2+t4-t6+t8; + t2 = x * x / 32768 / 2; + t4 = t2 * x / 32768 * x / 32768 / 3 / 4; + t6 = t4 * x / 32768 * x / 32768 / 5 / 6; + t8 = t6 * x / 32768 * x / 32768 / 7 / 8; + ret = 32768 - t2 + t4 - t6 + t8; return ret; } @@ -100,14 +100,14 @@ static u32 int_goertzel(s16 x[], u32 N, u32 freq) * given frequency in the signal */ s32 s_prev = 0; s32 s_prev2 = 0; - s32 coeff = 2*int_cos(freq); + s32 coeff = 2 * int_cos(freq); u32 i; u64 tmp; u32 divisor; for (i = 0; i < N; i++) { - s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2; + s32 s = x[i] + ((s64)coeff * s_prev / 32768) - s_prev2; s_prev2 = s_prev; s_prev = s; } @@ -138,7 +138,7 @@ static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end) if (N > 192) { /* The last 192 samples are enough for noise detection */ - x += (N-192); + x += (N - 192); N = 192; } @@ -196,8 +196,8 @@ static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) if (core->tvaudio == WW_EIAJ) { /* EIAJ checks may need adjustments */ - if ((carrier > max(stereo, dual)*2) && - (carrier < max(stereo, dual)*6) && + if ((carrier > max(stereo, dual) * 2) && + (carrier < max(stereo, dual) * 6) && (carrier > 20 && carrier < 200) && (max(stereo, dual) > min(stereo, dual))) { /* For EIAJ the carrier is always present, @@ -205,11 +205,11 @@ static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) return ret; } } else { - if ((carrier > max(stereo, dual)*2) && - (carrier < max(stereo, dual)*8) && + if ((carrier > max(stereo, dual) * 2) && + (carrier < max(stereo, dual) * 8) && (carrier > 20 && carrier < 200) && (noise < 10) && - (max(stereo, dual) > min(stereo, dual)*2)) { + (max(stereo, dual) > min(stereo, dual) * 2)) { return ret; } } @@ -234,9 +234,9 @@ static s16 *read_rds_samples(struct cx88_core *core, u32 *N) s16 *samples; unsigned int i; - unsigned int bpl = srch->fifo_size/AUD_RDS_LINES; - unsigned int spl = bpl/4; - unsigned int sample_count = spl*(AUD_RDS_LINES-1); + unsigned int bpl = srch->fifo_size / AUD_RDS_LINES; + unsigned int spl = bpl / 4; + unsigned int sample_count = spl * (AUD_RDS_LINES - 1); u32 current_address = cx_read(srch->ptr1_reg); u32 offset = (current_address - srch->fifo_start + bpl); @@ -252,7 +252,7 @@ static s16 *read_rds_samples(struct cx88_core *core, u32 *N) *N = sample_count; for (i = 0; i < sample_count; i++) { - offset = offset % (AUD_RDS_LINES*bpl); + offset = offset % (AUD_RDS_LINES * bpl); samples[i] = cx_read(srch->fifo_start + offset); offset += 4; } -- cgit v1.2.3 From 73446966b9ab9da118bb905bdbb5e8d3a1826b25 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 9 Oct 2016 16:12:13 -0300 Subject: [media] blackfin-capture: Use kcalloc() in bcap_init_sensor_formats() A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus reuse the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/blackfin/bfin_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index 8eb03397d736..c5e10439e8b9 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -169,7 +169,7 @@ static int bcap_init_sensor_formats(struct bcap_device *bcap_dev) if (!num_formats) return -ENXIO; - sf = kzalloc(num_formats * sizeof(*sf), GFP_KERNEL); + sf = kcalloc(num_formats, sizeof(*sf), GFP_KERNEL); if (!sf) return -ENOMEM; -- cgit v1.2.3 From e44e9489a7bda01bb26986fdf5b17559d26c26af Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 9 Oct 2016 16:30:18 -0300 Subject: [media] blackfin-capture: Delete an error message for a failed memory allocation The script "checkpatch.pl" pointed information out like the following. WARNING: Possible unnecessary 'out of memory' message Thus remove such a statement here. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/blackfin/bfin_capture.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c index c5e10439e8b9..2e6edc09b58f 100644 --- a/drivers/media/platform/blackfin/bfin_capture.c +++ b/drivers/media/platform/blackfin/bfin_capture.c @@ -802,10 +802,8 @@ static int bcap_probe(struct platform_device *pdev) } bcap_dev = kzalloc(sizeof(*bcap_dev), GFP_KERNEL); - if (!bcap_dev) { - v4l2_err(pdev->dev.driver, "Unable to alloc bcap_dev\n"); + if (!bcap_dev) return -ENOMEM; - } bcap_dev->cfg = config; -- cgit v1.2.3 From f42afd29e60585904fc5127862263437ed7cbbd5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 11 Oct 2016 04:40:41 -0300 Subject: [media] DaVinci-VPBE: Use kmalloc_array() in vpbe_initialize() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 7d2670732805..785d6cf93152 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -676,9 +676,9 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) * store venc sd index. */ num_encoders = vpbe_dev->cfg->num_ext_encoders + 1; - vpbe_dev->encoders = kmalloc( - sizeof(struct v4l2_subdev *)*num_encoders, - GFP_KERNEL); + vpbe_dev->encoders = kmalloc_array(num_encoders, + sizeof(*vpbe_dev->encoders), + GFP_KERNEL); if (NULL == vpbe_dev->encoders) { v4l2_err(&vpbe_dev->v4l2_dev, "unable to allocate memory for encoders sub devices"); -- cgit v1.2.3 From 2ac0989242fbf2f2da7109eab08f68382884a81a Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 11 Oct 2016 04:56:13 -0300 Subject: [media] DaVinci-VPBE: Delete two error messages for a failed memory allocation The script "checkpatch.pl" pointed information out like the following. WARNING: Possible unnecessary 'out of memory' message Thus remove such a logging statement in two functions. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 785d6cf93152..79c2ebe3862a 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -680,8 +680,6 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) sizeof(*vpbe_dev->encoders), GFP_KERNEL); if (NULL == vpbe_dev->encoders) { - v4l2_err(&vpbe_dev->v4l2_dev, - "unable to allocate memory for encoders sub devices"); ret = -ENOMEM; goto fail_dev_unregister; } @@ -837,10 +835,9 @@ static int vpbe_probe(struct platform_device *pdev) } vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); - if (vpbe_dev == NULL) { - v4l2_err(pdev->dev.driver, "Unable to allocate memory for vpbe_device\n"); + if (!vpbe_dev) return -ENOMEM; - } + vpbe_dev->cfg = cfg; vpbe_dev->ops = vpbe_dev_ops; vpbe_dev->pdev = &pdev->dev; -- cgit v1.2.3 From 135387513d1b0d35baa0433dfa9acc1fb9d97e40 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 11 Oct 2016 08:37:10 -0300 Subject: [media] DaVinci-VPBE: Adjust 16 checks for null pointers The script "checkpatch.pl" pointed information out like the following. Comparison to NULL could be written ... Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 79c2ebe3862a..c8c69442c793 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -107,7 +107,7 @@ static int vpbe_find_encoder_sd_index(struct vpbe_config *cfg, static int vpbe_g_cropcap(struct vpbe_device *vpbe_dev, struct v4l2_cropcap *cropcap) { - if (NULL == cropcap) + if (!cropcap) return -EINVAL; cropcap->bounds.left = 0; cropcap->bounds.top = 0; @@ -149,7 +149,7 @@ static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode, int curr_output = output_index; int i; - if (NULL == mode) + if (!mode) return -EINVAL; for (i = 0; i < cfg->outputs[curr_output].num_modes; i++) { @@ -166,7 +166,7 @@ static int vpbe_get_mode_info(struct vpbe_device *vpbe_dev, char *mode, static int vpbe_get_current_mode_info(struct vpbe_device *vpbe_dev, struct vpbe_enc_mode_info *mode_info) { - if (NULL == mode_info) + if (!mode_info) return -EINVAL; *mode_info = vpbe_dev->current_timings; @@ -356,7 +356,7 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev, ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, s_dv_timings, dv_timings); - if (!ret && (vpbe_dev->amp != NULL)) { + if (!ret && vpbe_dev->amp) { /* Call amplifier subdevice */ ret = v4l2_subdev_call(vpbe_dev->amp, video, s_dv_timings, dv_timings); @@ -512,7 +512,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, int ret = 0; int i; - if ((NULL == mode_info) || (NULL == mode_info->name)) + if (!mode_info || !mode_info->name) return -EINVAL; for (i = 0; i < cfg->outputs[out_index].num_modes; i++) { @@ -536,7 +536,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, } /* Only custom timing should reach here */ - if (preset_mode == NULL) + if (!preset_mode) return -EINVAL; mutex_lock(&vpbe_dev->lock); @@ -570,9 +570,9 @@ static int platform_device_get(struct device *dev, void *data) struct platform_device *pdev = to_platform_device(dev); struct vpbe_device *vpbe_dev = data; - if (strstr(pdev->name, "vpbe-osd") != NULL) + if (strstr(pdev->name, "vpbe-osd")) vpbe_dev->osd_device = platform_get_drvdata(pdev); - if (strstr(pdev->name, "vpbe-venc") != NULL) + if (strstr(pdev->name, "vpbe-venc")) vpbe_dev->venc_device = dev_get_platdata(&pdev->dev); return 0; @@ -606,7 +606,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) * from the platform device by iteration of platform drivers and * matching with device name */ - if (NULL == vpbe_dev || NULL == dev) { + if (!vpbe_dev || !dev) { printk(KERN_ERR "Null device pointers.\n"); return -ENODEV; } @@ -652,7 +652,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) vpbe_dev->venc = venc_sub_dev_init(&vpbe_dev->v4l2_dev, vpbe_dev->cfg->venc.module_name); /* register venc sub device */ - if (vpbe_dev->venc == NULL) { + if (!vpbe_dev->venc) { v4l2_err(&vpbe_dev->v4l2_dev, "vpbe unable to init venc sub device\n"); ret = -ENODEV; @@ -660,8 +660,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) } /* initialize osd device */ osd_device = vpbe_dev->osd_device; - - if (NULL != osd_device->ops.initialize) { + if (osd_device->ops.initialize) { err = osd_device->ops.initialize(osd_device); if (err) { v4l2_err(&vpbe_dev->v4l2_dev, @@ -679,7 +678,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) vpbe_dev->encoders = kmalloc_array(num_encoders, sizeof(*vpbe_dev->encoders), GFP_KERNEL); - if (NULL == vpbe_dev->encoders) { + if (!vpbe_dev->encoders) { ret = -ENOMEM; goto fail_dev_unregister; } @@ -713,7 +712,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev) } /* Add amplifier subdevice for dm365 */ if ((strcmp(vpbe_dev->cfg->module_name, "dm365-vpbe-display") == 0) && - vpbe_dev->cfg->amp != NULL) { + vpbe_dev->cfg->amp) { amp_info = vpbe_dev->cfg->amp; if (amp_info->is_i2c) { vpbe_dev->amp = v4l2_i2c_new_subdev_board( @@ -821,7 +820,7 @@ static int vpbe_probe(struct platform_device *pdev) struct vpbe_config *cfg; int ret = -EINVAL; - if (pdev->dev.platform_data == NULL) { + if (!pdev->dev.platform_data) { v4l2_err(pdev->dev.driver, "No platform data\n"); return -ENODEV; } -- cgit v1.2.3 From 9d2fe9ae298d6144546e168d4b0067b2340ec246 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Tue, 11 Oct 2016 08:43:25 -0300 Subject: [media] DaVinci-VPBE: Return an error code only as a constant in vpbe_probe() * Return an error code without storing it in an intermediate variable. * Delete the local variable "ret" which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index c8c69442c793..3ac4ba35832a 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -818,7 +818,6 @@ static int vpbe_probe(struct platform_device *pdev) { struct vpbe_device *vpbe_dev; struct vpbe_config *cfg; - int ret = -EINVAL; if (!pdev->dev.platform_data) { v4l2_err(pdev->dev.driver, "No platform data\n"); @@ -830,7 +829,7 @@ static int vpbe_probe(struct platform_device *pdev) !cfg->osd.module_name[0] || !cfg->venc.module_name[0]) { v4l2_err(pdev->dev.driver, "vpbe display module names not defined\n"); - return ret; + return -EINVAL; } vpbe_dev = kzalloc(sizeof(*vpbe_dev), GFP_KERNEL); -- cgit v1.2.3 From ca7948aa85290f55b8929a8c028352913167bca3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 04:51:29 -0300 Subject: [media] DaVinci-VPBE: Return the success indication only as a constant in vpbe_set_mode() * Return a success code without storing it in an intermediate variable. * Delete the local variable "ret" which became unnecessary with this refactoring. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 3ac4ba35832a..50b9e3df68b5 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -509,7 +509,6 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, struct v4l2_dv_timings dv_timings; struct osd_state *osd_device; int out_index = vpbe_dev->current_out_index; - int ret = 0; int i; if (!mode_info || !mode_info->name) @@ -549,8 +548,7 @@ static int vpbe_set_mode(struct vpbe_device *vpbe_dev, vpbe_dev->current_timings.upper_margin); mutex_unlock(&vpbe_dev->lock); - - return ret; + return 0; } static int vpbe_set_default_mode(struct vpbe_device *vpbe_dev) -- cgit v1.2.3 From 837fdcf05af645c3961cae69fd188a0fee1add52 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 04:54:26 -0300 Subject: [media] DaVinci-VPBE: Reduce the scope for a variable in vpbe_set_default_output() * Move the definition for the variable "ret" into an if branch so that an extra initialisation can be avoided at the beginning by this refactoring. * Return a success code as a constant at the end. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 50b9e3df68b5..77b3365b71ef 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -297,19 +297,19 @@ out: static int vpbe_set_default_output(struct vpbe_device *vpbe_dev) { struct vpbe_config *cfg = vpbe_dev->cfg; - int ret = 0; int i; for (i = 0; i < cfg->num_outputs; i++) { if (!strcmp(def_output, cfg->outputs[i].output.name)) { - ret = vpbe_set_output(vpbe_dev, i); + int ret = vpbe_set_output(vpbe_dev, i); + if (!ret) vpbe_dev->current_out_index = i; return ret; } } - return ret; + return 0; } /** -- cgit v1.2.3 From 15a78313b7fd43763aeba584c385f1fb17a1bdb5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:10:19 -0300 Subject: [media] DaVinci-VPBE: Rename a jump label in vpbe_set_output() Adjust jump labels according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 77b3365b71ef..968c2a67468f 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -254,20 +254,20 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) sd_index = vpbe_find_encoder_sd_index(cfg, index); if (sd_index < 0) { ret = -EINVAL; - goto out; + goto unlock; } if_params = cfg->outputs[index].if_params; venc_device->setup_if_config(if_params); if (ret) - goto out; + goto unlock; } /* Set output at the encoder */ ret = v4l2_subdev_call(vpbe_dev->encoders[sd_index], video, s_routing, 0, enc_out_index, 0); if (ret) - goto out; + goto unlock; /* * It is assumed that venc or extenal encoder will set a default @@ -289,7 +289,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) vpbe_dev->current_sd_index = sd_index; vpbe_dev->current_out_index = index; } -out: +unlock: mutex_unlock(&vpbe_dev->lock); return ret; } -- cgit v1.2.3 From 630bf79a455bbb5fd13e7721280cd149860bcd56 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:16:23 -0300 Subject: [media] DaVinci-VPBE: Delete an unnecessary variable initialisation in vpbe_set_output() The local variable "ret" will be set to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 968c2a67468f..7dcdb7f4b323 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -230,7 +230,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) u32 if_params; int enc_out_index; int sd_index; - int ret = 0; + int ret; if (index >= cfg->num_outputs) return -EINVAL; -- cgit v1.2.3 From ed011a23c90796c386ae7004ef0823ade6583d21 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:20:02 -0300 Subject: [media] DaVinci-VPFE-Capture: Use kmalloc_array() in vpfe_probe() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ca22c3493f55..a9bc35e785a3 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1938,8 +1938,9 @@ static int vpfe_probe(struct platform_device *pdev) video_set_drvdata(&vpfe_dev->video_dev, vpfe_dev); i2c_adap = i2c_get_adapter(vpfe_cfg->i2c_adapter_id); num_subdevs = vpfe_cfg->num_subdevs; - vpfe_dev->sd = kmalloc(sizeof(struct v4l2_subdev *) * num_subdevs, - GFP_KERNEL); + vpfe_dev->sd = kmalloc_array(num_subdevs, + sizeof(*vpfe_dev->sd), + GFP_KERNEL); if (NULL == vpfe_dev->sd) { v4l2_err(&vpfe_dev->v4l2_dev, "unable to allocate memory for subdevice pointers\n"); -- cgit v1.2.3 From 11691f0e8aaef776320938c9018f5785d09f59c5 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:22:47 -0300 Subject: [media] DaVinci-VPFE-Capture: Delete three error messages for a failed memory allocation The script "checkpatch.pl" pointed information out like the following. WARNING: Possible unnecessary 'out of memory' message Thus remove such a logging statement in two functions. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index a9bc35e785a3..22f48342584b 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -512,11 +512,9 @@ static int vpfe_open(struct file *file) /* Allocate memory for the file handle object */ fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); - if (NULL == fh) { - v4l2_err(&vpfe_dev->v4l2_dev, - "unable to allocate memory for file handle object\n"); + if (!fh) return -ENOMEM; - } + /* store pointer to fh in private_data member of file */ file->private_data = fh; fh->vpfe_dev = vpfe_dev; @@ -1851,11 +1849,8 @@ static int vpfe_probe(struct platform_device *pdev) /* Allocate memory for ccdc configuration */ ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); - if (NULL == ccdc_cfg) { - v4l2_err(pdev->dev.driver, - "Memory allocation failed for ccdc_cfg\n"); + if (!ccdc_cfg) goto probe_free_dev_mem; - } mutex_lock(&ccdc_lock); @@ -1942,8 +1937,6 @@ static int vpfe_probe(struct platform_device *pdev) sizeof(*vpfe_dev->sd), GFP_KERNEL); if (NULL == vpfe_dev->sd) { - v4l2_err(&vpfe_dev->v4l2_dev, - "unable to allocate memory for subdevice pointers\n"); ret = -ENOMEM; goto probe_out_video_unregister; } -- cgit v1.2.3 From e4c0cd0ae34b5e8ea3e8f4eced531dccabe3124c Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:24:57 -0300 Subject: [media] DaVinci-VPFE-Capture: Improve another size determination in vpfe_probe() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 22f48342584b..9109a286a869 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1848,7 +1848,7 @@ static int vpfe_probe(struct platform_device *pdev) } /* Allocate memory for ccdc configuration */ - ccdc_cfg = kmalloc(sizeof(struct ccdc_config), GFP_KERNEL); + ccdc_cfg = kmalloc(sizeof(*ccdc_cfg), GFP_KERNEL); if (!ccdc_cfg) goto probe_free_dev_mem; -- cgit v1.2.3 From efb74461f5a66c0004d0c13ef59c86bcf5961477 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:30:28 -0300 Subject: [media] DaVinci-VPFE-Capture: Delete an unnecessary variable initialisation in vpfe_probe() * Return an error code as a constant after a failed call of the function "vpfe_initialize". * The local variable "ret" will be set then to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 9109a286a869..cee14aa95061 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1817,7 +1817,7 @@ static int vpfe_probe(struct platform_device *pdev) struct vpfe_device *vpfe_dev; struct i2c_adapter *i2c_adap; struct video_device *vfd; - int ret = -ENOMEM, i, j; + int ret, i, j; int num_subdevs = 0; /* Get the pointer to the device object */ @@ -1826,7 +1826,7 @@ static int vpfe_probe(struct platform_device *pdev) if (!vpfe_dev) { v4l2_err(pdev->dev.driver, "Failed to allocate memory for vpfe_dev\n"); - return ret; + return -ENOMEM; } vpfe_dev->pdev = &pdev->dev; -- cgit v1.2.3 From 1d3811d35c0fc8d8c6cb3d8e666261ca84687b03 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:44:05 -0300 Subject: [media] DaVinci-VPFE-Capture: Improve another size determination in vpfe_open() Replace the specification of a data structure by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index cee14aa95061..ab073f273b95 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -511,7 +511,7 @@ static int vpfe_open(struct file *file) } /* Allocate memory for the file handle object */ - fh = kmalloc(sizeof(struct vpfe_fh), GFP_KERNEL); + fh = kmalloc(sizeof(*fh), GFP_KERNEL); if (!fh) return -ENOMEM; -- cgit v1.2.3 From c580f295663ea22b49edeefbdcdf2e67ce9ef91f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:46:28 -0300 Subject: [media] DaVinci-VPFE-Capture: Adjust 13 checks for null pointers Convert comparisons with the preprocessor symbol "NULL" to condition checks without it. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ab073f273b95..71f1ac1adec0 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -229,7 +229,7 @@ int vpfe_register_ccdc_device(struct ccdc_hw_device *dev) BUG_ON(!dev->hw_ops.getfid); mutex_lock(&ccdc_lock); - if (NULL == ccdc_cfg) { + if (!ccdc_cfg) { /* * TODO. Will this ever happen? if so, we need to fix it. * Proabably we need to add the request to a linked list and @@ -265,7 +265,7 @@ EXPORT_SYMBOL(vpfe_register_ccdc_device); */ void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) { - if (NULL == dev) { + if (!dev) { printk(KERN_ERR "invalid ccdc device ptr\n"); return; } @@ -469,7 +469,7 @@ static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) /* now open the ccdc device to initialize it */ mutex_lock(&ccdc_lock); - if (NULL == ccdc_dev) { + if (!ccdc_dev) { v4l2_err(&vpfe_dev->v4l2_dev, "ccdc device not registered\n"); ret = -ENODEV; goto unlock; @@ -582,7 +582,7 @@ static irqreturn_t vpfe_isr(int irq, void *dev_id) goto clear_intr; /* only for 6446 this will be applicable */ - if (NULL != ccdc_dev->hw_ops.reset) + if (ccdc_dev->hw_ops.reset) ccdc_dev->hw_ops.reset(); if (field == V4L2_FIELD_NONE) { @@ -822,7 +822,7 @@ static const struct vpfe_pixel_format * int temp, found; vpfe_pix_fmt = vpfe_lookup_pix_format(pixfmt->pixelformat); - if (NULL == vpfe_pix_fmt) { + if (!vpfe_pix_fmt) { /* * use current pixel format in the vpfe device. We * will find this pix format in the table @@ -964,7 +964,7 @@ static int vpfe_enum_fmt_vid_cap(struct file *file, void *priv, /* Fill in the information about format */ pix_fmt = vpfe_lookup_pix_format(pix); - if (NULL != pix_fmt) { + if (pix_fmt) { temp_index = fmt->index; *fmt = pix_fmt->fmtdesc; fmt->index = temp_index; @@ -990,8 +990,7 @@ static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, /* Check for valid frame format */ pix_fmts = vpfe_check_format(vpfe_dev, &fmt->fmt.pix); - - if (NULL == pix_fmts) + if (!pix_fmts) return -EINVAL; /* store the pixel format in the device object */ @@ -1017,7 +1016,7 @@ static int vpfe_try_fmt_vid_cap(struct file *file, void *priv, v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_try_fmt_vid_cap\n"); pix_fmts = vpfe_check_format(vpfe_dev, &f->fmt.pix); - if (NULL == pix_fmts) + if (!pix_fmts) return -EINVAL; return 0; } @@ -1831,7 +1830,7 @@ static int vpfe_probe(struct platform_device *pdev) vpfe_dev->pdev = &pdev->dev; - if (NULL == pdev->dev.platform_data) { + if (!pdev->dev.platform_data) { v4l2_err(pdev->dev.driver, "Unable to get vpfe config\n"); ret = -ENODEV; goto probe_free_dev_mem; @@ -1839,9 +1838,7 @@ static int vpfe_probe(struct platform_device *pdev) vpfe_cfg = pdev->dev.platform_data; vpfe_dev->cfg = vpfe_cfg; - if (NULL == vpfe_cfg->ccdc || - NULL == vpfe_cfg->card_name || - NULL == vpfe_cfg->sub_devs) { + if (!vpfe_cfg->ccdc || !vpfe_cfg->card_name || !vpfe_cfg->sub_devs) { v4l2_err(pdev->dev.driver, "null ptr in vpfe_cfg\n"); ret = -ENOENT; goto probe_free_dev_mem; @@ -1936,7 +1933,7 @@ static int vpfe_probe(struct platform_device *pdev) vpfe_dev->sd = kmalloc_array(num_subdevs, sizeof(*vpfe_dev->sd), GFP_KERNEL); - if (NULL == vpfe_dev->sd) { + if (!vpfe_dev->sd) { ret = -ENOMEM; goto probe_out_video_unregister; } -- cgit v1.2.3 From 2a0de2c84288fdf9381f6e2a85c0c6825221851e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 05:50:54 -0300 Subject: [media] DaVinci-VPFE-Capture: Delete an unnecessary variable initialisation in 11 functions The local variable "ret" will be set to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 71f1ac1adec0..ca044bf1c05c 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -384,7 +384,7 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, }; struct v4l2_mbus_framefmt *mbus_fmt = &fmt.format; struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix; - int i, ret = 0; + int i, ret; for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) { if (vpfe_standards[i].std_id & std_id) { @@ -453,7 +453,7 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev, static int vpfe_initialize_device(struct vpfe_device *vpfe_dev) { - int ret = 0; + int ret; /* set first input of current subdevice as the current input */ vpfe_dev->current_input = 0; @@ -978,7 +978,7 @@ static int vpfe_s_fmt_vid_cap(struct file *file, void *priv, { struct vpfe_device *vpfe_dev = video_drvdata(file); const struct vpfe_pixel_format *pix_fmts; - int ret = 0; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_fmt_vid_cap\n"); @@ -1110,7 +1110,7 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) int subdev_index, inp_index; struct vpfe_route *route; u32 input = 0, output = 0; - int ret = -EINVAL; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); @@ -1176,7 +1176,7 @@ static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id) { struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_subdev_info *sdinfo; - int ret = 0; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querystd\n"); @@ -1195,7 +1195,7 @@ static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id) { struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_subdev_info *sdinfo; - int ret = 0; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_std\n"); @@ -1344,7 +1344,7 @@ static int vpfe_reqbufs(struct file *file, void *priv, { struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_fh *fh = file->private_data; - int ret = 0; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_reqbufs\n"); @@ -1476,7 +1476,7 @@ static int vpfe_streamon(struct file *file, void *priv, struct vpfe_fh *fh = file->private_data; struct vpfe_subdev_info *sdinfo; unsigned long addr; - int ret = 0; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamon\n"); @@ -1559,7 +1559,7 @@ static int vpfe_streamoff(struct file *file, void *priv, struct vpfe_device *vpfe_dev = video_drvdata(file); struct vpfe_fh *fh = file->private_data; struct vpfe_subdev_info *sdinfo; - int ret = 0; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_streamoff\n"); @@ -1645,7 +1645,7 @@ static int vpfe_s_selection(struct file *file, void *priv, { struct vpfe_device *vpfe_dev = video_drvdata(file); struct v4l2_rect rect = sel->r; - int ret = 0; + int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_selection\n"); @@ -1703,7 +1703,7 @@ static long vpfe_param_handler(struct file *file, void *priv, bool valid_prio, unsigned int cmd, void *param) { struct vpfe_device *vpfe_dev = video_drvdata(file); - int ret = 0; + int ret; v4l2_dbg(2, debug, &vpfe_dev->v4l2_dev, "vpfe_param_handler\n"); -- cgit v1.2.3 From 19d4695a4fbde30881ad9005e7f46e569b1fc911 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 06:22:23 -0300 Subject: [media] DaVinci-VPFE-Capture: Move two assignments in vpfe_s_input() Move assignments for two local variables into an else branch so that their setting will only be performed after corresponding data processing succeeded by this function. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index ca044bf1c05c..86509d2f274a 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1109,7 +1109,7 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) struct vpfe_subdev_info *sdinfo; int subdev_index, inp_index; struct vpfe_route *route; - u32 input = 0, output = 0; + u32 input, output; int ret; v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_s_input\n"); @@ -1142,6 +1142,9 @@ static int vpfe_s_input(struct file *file, void *priv, unsigned int index) if (route && sdinfo->can_route) { input = route->input; output = route->output; + } else { + input = 0; + output = 0; } if (sd) -- cgit v1.2.3 From b899065640fc0c8b02d762bd5869c0afd3120c64 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 09:54:21 -0300 Subject: [media] DaVinci-VPFE-Capture: Delete unnecessary braces in vpfe_isr() Do not use curly brackets at one source code place where a single statement should be sufficient. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 86509d2f274a..1acca83426ea 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -615,9 +615,8 @@ static irqreturn_t vpfe_isr(int irq, void *dev_id) * interleavely or separately in memory, reconfigure * the CCDC memory address */ - if (field == V4L2_FIELD_SEQ_TB) { + if (field == V4L2_FIELD_SEQ_TB) vpfe_schedule_bottom_field(vpfe_dev); - } goto clear_intr; } /* -- cgit v1.2.3 From 96ca88423605116c041b5e5a6ef3af685402afb1 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:10:54 -0300 Subject: [media] DaVinci-VPFE-Capture: Delete an unnecessary return statement in vpfe_unregister_ccdc_device() The script "checkpatch.pl" pointed information out like the following. WARNING: void function return statements are not generally useful Thus remove such a statement here. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 1acca83426ea..71caebf125f1 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -281,7 +281,6 @@ void vpfe_unregister_ccdc_device(struct ccdc_hw_device *dev) mutex_lock(&ccdc_lock); ccdc_dev = NULL; mutex_unlock(&ccdc_lock); - return; } EXPORT_SYMBOL(vpfe_unregister_ccdc_device); -- cgit v1.2.3 From b442c46f1b10f5e91025e36824362839ea3f3331 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:15:34 -0300 Subject: [media] DaVinci-VPIF-Capture: Use kcalloc() in vpif_probe() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index c6a3a904afc8..8a7d46210a44 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1459,8 +1459,7 @@ static __init int vpif_probe(struct platform_device *pdev) vpif_obj.config = pdev->dev.platform_data; subdev_count = vpif_obj.config->subdev_count; - vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); + vpif_obj.sd = kcalloc(subdev_count, sizeof(*vpif_obj.sd), GFP_KERNEL); if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; -- cgit v1.2.3 From bc285799f7e8c61eaacdd73aa8644b1eaf504bb4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:18:45 -0300 Subject: [media] DaVinci-VPIF-Capture: Delete an error message for a failed memory allocation Omit an extra message for a memory allocation failure in this function. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 8a7d46210a44..515384b25ea1 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -1461,7 +1461,6 @@ static __init int vpif_probe(struct platform_device *pdev) subdev_count = vpif_obj.config->subdev_count; vpif_obj.sd = kcalloc(subdev_count, sizeof(*vpif_obj.sd), GFP_KERNEL); if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; goto vpif_unregister; } -- cgit v1.2.3 From 03161cdb69ef98434a2c8e85234aae7975ca4501 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:20:34 -0300 Subject: [media] DaVinci-VPIF-Capture: Adjust ten checks for null pointers The script "checkpatch.pl" pointed information out like the following. Comparison to NULL could be written ... Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 515384b25ea1..0c44e2b84434 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -291,10 +291,10 @@ static void vpif_stop_streaming(struct vb2_queue *vq) vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } else { - if (common->cur_frm != NULL) + if (common->cur_frm) vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); - if (common->next_frm != NULL) + if (common->next_frm) vb2_buffer_done(&common->next_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } @@ -648,7 +648,7 @@ static int vpif_input_to_subdev( vpif_dbg(2, debug, "vpif_input_to_subdev\n"); subdev_name = chan_cfg->inputs[input_index].subdev_name; - if (subdev_name == NULL) + if (!subdev_name) return -1; /* loop through the sub device list to get the sub device info */ @@ -764,7 +764,7 @@ static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) vpif_dbg(2, debug, "vpif_g_std\n"); - if (config->chan_config[ch->channel_id].inputs == NULL) + if (!config->chan_config[ch->channel_id].inputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -794,7 +794,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id) vpif_dbg(2, debug, "vpif_s_std\n"); - if (config->chan_config[ch->channel_id].inputs == NULL) + if (!config->chan_config[ch->channel_id].inputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1050,7 +1050,7 @@ vpif_enum_dv_timings(struct file *file, void *priv, struct v4l2_input input; int ret; - if (config->chan_config[ch->channel_id].inputs == NULL) + if (!config->chan_config[ch->channel_id].inputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1084,7 +1084,7 @@ vpif_query_dv_timings(struct file *file, void *priv, struct v4l2_input input; int ret; - if (config->chan_config[ch->channel_id].inputs == NULL) + if (!config->chan_config[ch->channel_id].inputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1120,7 +1120,7 @@ static int vpif_s_dv_timings(struct file *file, void *priv, struct v4l2_input input; int ret; - if (config->chan_config[ch->channel_id].inputs == NULL) + if (!config->chan_config[ch->channel_id].inputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1213,7 +1213,7 @@ static int vpif_g_dv_timings(struct file *file, void *priv, struct vpif_capture_chan_config *chan_cfg; struct v4l2_input input; - if (config->chan_config[ch->channel_id].inputs == NULL) + if (!config->chan_config[ch->channel_id].inputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1460,7 +1460,7 @@ static __init int vpif_probe(struct platform_device *pdev) subdev_count = vpif_obj.config->subdev_count; vpif_obj.sd = kcalloc(subdev_count, sizeof(*vpif_obj.sd), GFP_KERNEL); - if (vpif_obj.sd == NULL) { + if (!vpif_obj.sd) { err = -ENOMEM; goto vpif_unregister; } -- cgit v1.2.3 From 6a842cc29dbfd311a289bb7f34865828e951791d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:22:45 -0300 Subject: [media] DaVinci-VPIF-Capture: Delete an unnecessary variable initialisation in vpif_querystd() The local variable "ret" will be set to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 0c44e2b84434..77f67a05d047 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -731,7 +731,7 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id) { struct video_device *vdev = video_devdata(file); struct channel_obj *ch = video_get_drvdata(vdev); - int ret = 0; + int ret; vpif_dbg(2, debug, "vpif_querystd\n"); -- cgit v1.2.3 From c64d61df9a5d67e50ed347287d80a4b75e9d660d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:25:08 -0300 Subject: [media] DaVinci-VPIF-Capture: Delete an unnecessary variable initialisation in vpif_channel_isr() The local variable "channel_id" will be set to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c index 77f67a05d047..f791f5c402bf 100644 --- a/drivers/media/platform/davinci/vpif_capture.c +++ b/drivers/media/platform/davinci/vpif_capture.c @@ -375,7 +375,7 @@ 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; - int channel_id = 0; + int channel_id; int fid = -1, i; channel_id = *(int *)(dev_id); -- cgit v1.2.3 From d5cf467ecec5a3924a602018c6e405ad6d0dbecc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:30:44 -0300 Subject: [media] DaVinci-VPIF-Display: Use kcalloc() in vpif_probe() * A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. * Replace the specification of a data type by a pointer dereference to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 6b3ea1e8e97f..0faab86db9a1 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1274,8 +1274,7 @@ static __init int vpif_probe(struct platform_device *pdev) vpif_obj.config = pdev->dev.platform_data; subdev_count = vpif_obj.config->subdev_count; subdevdata = vpif_obj.config->subdevinfo; - vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count, - GFP_KERNEL); + vpif_obj.sd = kcalloc(subdev_count, sizeof(*vpif_obj.sd), GFP_KERNEL); if (vpif_obj.sd == NULL) { vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; -- cgit v1.2.3 From ded1c8fa7563614bac9c3e69b0dec8238032725c Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:38:41 -0300 Subject: [media] DaVinci-VPIF-Display: Delete an error message for a failed memory allocation Omit an extra message for a memory allocation failure in this function. Link: http://events.linuxfoundation.org/sites/events/files/slides/LCJ16-Refactor_Strings-WSang_0.pdf Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 0faab86db9a1..987c17d3825d 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -1276,7 +1276,6 @@ static __init int vpif_probe(struct platform_device *pdev) subdevdata = vpif_obj.config->subdevinfo; vpif_obj.sd = kcalloc(subdev_count, sizeof(*vpif_obj.sd), GFP_KERNEL); if (vpif_obj.sd == NULL) { - vpif_err("unable to allocate memory for subdevice pointers\n"); err = -ENOMEM; goto vpif_unregister; } -- cgit v1.2.3 From 396c88e6c80cc30d4ef8dc927aae1b15f251a217 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:40:32 -0300 Subject: [media] DaVinci-VPIF-Display: Adjust 11 checks for null pointers The script "checkpatch.pl" pointed information out like the following. Comparison to NULL could be written... Thus fix the affected source code places. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 987c17d3825d..867bf5c63cb6 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -271,10 +271,10 @@ static void vpif_stop_streaming(struct vb2_queue *vq) vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } else { - if (common->cur_frm != NULL) + if (common->cur_frm) vb2_buffer_done(&common->cur_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); - if (common->next_frm != NULL) + if (common->next_frm) vb2_buffer_done(&common->next_frm->vb.vb2_buf, VB2_BUF_STATE_ERROR); } @@ -686,7 +686,7 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id std_id) struct v4l2_output output; int ret; - if (config->chan_config[ch->channel_id].outputs == NULL) + if (!config->chan_config[ch->channel_id].outputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -732,7 +732,7 @@ static int vpif_g_std(struct file *file, void *priv, v4l2_std_id *std) struct vpif_display_chan_config *chan_cfg; struct v4l2_output output; - if (config->chan_config[ch->channel_id].outputs == NULL) + if (!config->chan_config[ch->channel_id].outputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -783,11 +783,11 @@ vpif_output_to_subdev(struct vpif_display_config *vpif_cfg, vpif_dbg(2, debug, "vpif_output_to_subdev\n"); - if (chan_cfg->outputs == NULL) + if (!chan_cfg->outputs) return -1; subdev_name = chan_cfg->outputs[index].subdev_name; - if (subdev_name == NULL) + if (!subdev_name) return -1; /* loop through the sub device list to get the sub device info */ @@ -833,7 +833,7 @@ static int vpif_set_output(struct vpif_display_config *vpif_cfg, } ch->output_idx = index; ch->sd = sd; - if (chan_cfg->outputs != NULL) + if (chan_cfg->outputs) /* update tvnorms from the sub device output info */ ch->video_dev.tvnorms = chan_cfg->outputs[index].output.std; return 0; @@ -885,7 +885,7 @@ vpif_enum_dv_timings(struct file *file, void *priv, struct v4l2_output output; int ret; - if (config->chan_config[ch->channel_id].outputs == NULL) + if (!config->chan_config[ch->channel_id].outputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -922,7 +922,7 @@ static int vpif_s_dv_timings(struct file *file, void *priv, struct v4l2_output output; int ret; - if (config->chan_config[ch->channel_id].outputs == NULL) + if (!config->chan_config[ch->channel_id].outputs) return -ENODATA; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1016,7 +1016,7 @@ static int vpif_g_dv_timings(struct file *file, void *priv, struct video_obj *vid_ch = &ch->video; struct v4l2_output output; - if (config->chan_config[ch->channel_id].outputs == NULL) + if (!config->chan_config[ch->channel_id].outputs) goto error; chan_cfg = &config->chan_config[ch->channel_id]; @@ -1275,7 +1275,7 @@ static __init int vpif_probe(struct platform_device *pdev) subdev_count = vpif_obj.config->subdev_count; subdevdata = vpif_obj.config->subdevinfo; vpif_obj.sd = kcalloc(subdev_count, sizeof(*vpif_obj.sd), GFP_KERNEL); - if (vpif_obj.sd == NULL) { + if (!vpif_obj.sd) { err = -ENOMEM; goto vpif_unregister; } -- cgit v1.2.3 From 3ce5f660147039f880949d339c578e5af553876f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:43:12 -0300 Subject: [media] DaVinci-VPIF-Display: Delete an unnecessary variable initialisation in vpif_channel_isr() The local variable "channel_id" will be reassigned with the following statement at the beginning. Thus omit the explicit initialisation. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 867bf5c63cb6..3bf68aace5af 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -363,7 +363,7 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id) struct channel_obj *ch; struct common_obj *common; int fid = -1, i; - int channel_id = 0; + int channel_id; channel_id = *(int *)(dev_id); if (!vpif_intr_status(channel_id + 2)) -- cgit v1.2.3 From ea0e437cf9443ae58e38bff1242ff0c80d0c4efb Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Wed, 12 Oct 2016 10:45:03 -0300 Subject: [media] DaVinci-VPIF-Display: Delete an unnecessary variable initialisation in process_progressive_mode() The local variable "addr" will be set to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpif_display.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c index 3bf68aace5af..e5f18448dbf7 100644 --- a/drivers/media/platform/davinci/vpif_display.c +++ b/drivers/media/platform/davinci/vpif_display.c @@ -301,7 +301,7 @@ static struct vb2_ops video_qops = { static void process_progressive_mode(struct common_obj *common) { - unsigned long addr = 0; + unsigned long addr; spin_lock(&common->irqlock); /* Get the next buffer from buffer queue */ -- cgit v1.2.3 From eadf081146ec327d6fbbb6aff28e3d9aac329dc6 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 13 Oct 2016 11:39:04 -0300 Subject: [media] s5p-cec: mark PM functions as __maybe_unused again MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A bugfix removed the two callers of s5p_cec_runtime_suspend and s5p_cec_runtime_resume, leading to the return of a harmless warning that I had previously fixed in commit aee8937089b1 ("[media] s5p_cec: mark suspend/resume as __maybe_unused"): staging/media/s5p-cec/s5p_cec.c:234:12: error: ‘s5p_cec_runtime_suspend’ defined but not used [-Werror=unused-function] staging/media/s5p-cec/s5p_cec.c:242:12: error: ‘s5p_cec_runtime_resume’ defined but not used [-Werror=unused-function] This adds the __maybe_unused annotations to the function that were not removed and that are now unused when CONFIG_PM is disabled. Fixes: 57b978ada073 ("[media] s5p-cec: fix system and runtime PM integration") Signed-off-by: Arnd Bergmann Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/s5p-cec/s5p_cec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/s5p-cec/s5p_cec.c b/drivers/staging/media/s5p-cec/s5p_cec.c index 1780a08b73c9..58d756231136 100644 --- a/drivers/staging/media/s5p-cec/s5p_cec.c +++ b/drivers/staging/media/s5p-cec/s5p_cec.c @@ -231,7 +231,7 @@ static int s5p_cec_remove(struct platform_device *pdev) return 0; } -static int s5p_cec_runtime_suspend(struct device *dev) +static int __maybe_unused s5p_cec_runtime_suspend(struct device *dev) { struct s5p_cec_dev *cec = dev_get_drvdata(dev); @@ -239,7 +239,7 @@ static int s5p_cec_runtime_suspend(struct device *dev) return 0; } -static int s5p_cec_runtime_resume(struct device *dev) +static int __maybe_unused s5p_cec_runtime_resume(struct device *dev) { struct s5p_cec_dev *cec = dev_get_drvdata(dev); int ret; -- cgit v1.2.3 From 6b2bed891253c08e7f4c17dbd46b71fc87f22eef Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 14 Oct 2016 04:32:24 -0300 Subject: [media] st-hva: fix some error handling in hva_hw_probe() The devm_ioremap_resource() returns error pointers, never NULL. The platform_get_resource() returns NULL on error, never error pointers. The error code needs to be set, as well. The current code returns PTR_ERR(NULL) which is success. Fixes: 57b2c0628b60 ("[media] st-hva: multi-format video encoder V4L2 driver") Signed-off-by: Dan Carpenter Acked-by: Jean-Christophe Trotin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/hva/hva-hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c index d341d4994528..cf2a8d884536 100644 --- a/drivers/media/platform/sti/hva/hva-hw.c +++ b/drivers/media/platform/sti/hva/hva-hw.c @@ -305,16 +305,16 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva) /* get memory for registers */ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); hva->regs = devm_ioremap_resource(dev, regs); - if (IS_ERR_OR_NULL(hva->regs)) { + if (IS_ERR(hva->regs)) { dev_err(dev, "%s failed to get regs\n", HVA_PREFIX); return PTR_ERR(hva->regs); } /* get memory for esram */ esram = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (IS_ERR_OR_NULL(esram)) { + if (!esram) { dev_err(dev, "%s failed to get esram\n", HVA_PREFIX); - return PTR_ERR(esram); + return -ENODEV; } hva->esram_addr = esram->start; hva->esram_size = resource_size(esram); -- cgit v1.2.3 From c53a846c48f21c909102677c127ece94b1247668 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Sun, 16 Oct 2016 07:38:22 -0200 Subject: [media] usbtv: add video controls Brightness, Contrast, Hue and Color Saturation are supported. Signed-off-by: Lubomir Rintel Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-video.c | 97 ++++++++++++++++++++++++++++++++++- drivers/media/usb/usbtv/usbtv.h | 3 ++ 2 files changed, 99 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 6cbe4a245c9f..86ffbf8780f2 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Lubomir Rintel + * Copyright (c) 2013,2016 Lubomir Rintel * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -259,6 +259,10 @@ static int usbtv_setup_capture(struct usbtv *usbtv) if (ret) return ret; + ret = v4l2_ctrl_handler_setup(&usbtv->ctrl); + if (ret) + return ret; + return 0; } @@ -696,11 +700,83 @@ static const struct vb2_ops usbtv_vb2_ops = { .stop_streaming = usbtv_stop_streaming, }; +static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct usbtv *usbtv = container_of(ctrl->handler, struct usbtv, + ctrl); + u8 data[3]; + u16 index, size; + int ret; + + /* + * Read in the current brightness/contrast registers. We need them + * both, because the values are for some reason interleaved. + */ + if (ctrl->id == V4L2_CID_BRIGHTNESS || ctrl->id == V4L2_CID_CONTRAST) { + ret = usb_control_msg(usbtv->udev, + usb_sndctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, USBTV_BASE + 0x0244, (void *)data, 3, 0); + } + + switch (ctrl->id) { + case V4L2_CID_BRIGHTNESS: + index = USBTV_BASE + 0x0244; + size = 3; + data[0] &= 0xf0; + data[0] |= (ctrl->val >> 8) & 0xf; + data[2] = ctrl->val & 0xff; + break; + case V4L2_CID_CONTRAST: + index = USBTV_BASE + 0x0244; + size = 3; + data[0] &= 0x0f; + data[0] |= (ctrl->val >> 4) & 0xf0; + data[1] = ctrl->val & 0xff; + break; + case V4L2_CID_SATURATION: + index = USBTV_BASE + 0x0242; + data[0] = ctrl->val >> 8; + data[1] = ctrl->val & 0xff; + size = 2; + break; + case V4L2_CID_HUE: + index = USBTV_BASE + 0x0240; + size = 2; + if (ctrl->val > 0) { + data[0] = 0x92 + (ctrl->val >> 8); + data[1] = ctrl->val & 0xff; + } else { + data[0] = 0x82 + (-ctrl->val >> 8); + data[1] = -ctrl->val & 0xff; + } + break; + default: + return -EINVAL; + } + + ret = usb_control_msg(usbtv->udev, usb_sndctrlpipe(usbtv->udev, 0), + USBTV_CONTROL_REG, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + 0, index, (void *)data, size, 0); + if (ret < 0) { + dev_warn(usbtv->dev, "Failed to submit a control request.\n"); + return ret; + } + + return 0; +} + +static const struct v4l2_ctrl_ops usbtv_ctrl_ops = { + .s_ctrl = usbtv_s_ctrl, +}; + static void usbtv_release(struct v4l2_device *v4l2_dev) { struct usbtv *usbtv = container_of(v4l2_dev, struct usbtv, v4l2_dev); v4l2_device_unregister(&usbtv->v4l2_dev); + v4l2_ctrl_handler_free(&usbtv->ctrl); vb2_queue_release(&usbtv->vb2q); kfree(usbtv); } @@ -731,7 +807,24 @@ int usbtv_video_init(struct usbtv *usbtv) return ret; } + /* controls */ + v4l2_ctrl_handler_init(&usbtv->ctrl, 4); + v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops, + V4L2_CID_CONTRAST, 0, 0x3ff, 1, 0x1d0); + v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops, + V4L2_CID_BRIGHTNESS, 0, 0x3ff, 1, 0x1c0); + v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops, + V4L2_CID_SATURATION, 0, 0x3ff, 1, 0x200); + v4l2_ctrl_new_std(&usbtv->ctrl, &usbtv_ctrl_ops, + V4L2_CID_HUE, -0xdff, 0xdff, 1, 0x000); + ret = usbtv->ctrl.error; + if (ret < 0) { + dev_warn(usbtv->dev, "Could not initialize controls\n"); + goto ctrl_fail; + } + /* v4l2 structure */ + usbtv->v4l2_dev.ctrl_handler = &usbtv->ctrl; usbtv->v4l2_dev.release = usbtv_release; ret = v4l2_device_register(usbtv->dev, &usbtv->v4l2_dev); if (ret < 0) { @@ -760,6 +853,8 @@ int usbtv_video_init(struct usbtv *usbtv) vdev_fail: v4l2_device_unregister(&usbtv->v4l2_dev); v4l2_fail: +ctrl_fail: + v4l2_ctrl_handler_free(&usbtv->ctrl); vb2_queue_release(&usbtv->vb2q); return ret; diff --git a/drivers/media/usb/usbtv/usbtv.h b/drivers/media/usb/usbtv/usbtv.h index 011f9fdc77a9..0231e449877e 100644 --- a/drivers/media/usb/usbtv/usbtv.h +++ b/drivers/media/usb/usbtv/usbtv.h @@ -38,6 +38,7 @@ #include #include +#include #include #include @@ -45,6 +46,7 @@ #define USBTV_VIDEO_ENDP 0x81 #define USBTV_AUDIO_ENDP 0x83 #define USBTV_BASE 0xc000 +#define USBTV_CONTROL_REG 11 #define USBTV_REQUEST_REG 12 /* Number of concurrent isochronous urbs submitted. @@ -87,6 +89,7 @@ struct usbtv { /* video */ struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler ctrl; struct video_device vdev; struct vb2_queue vb2q; struct mutex v4l2_lock; -- cgit v1.2.3 From 62de7d99dcfe5ceff0c40d27a819a2256c8dfc73 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Nov 2016 13:13:02 -0200 Subject: [media] usbtv: don't do DMA on stack As reported by smatch: drivers/media/usb/usbtv/usbtv-video.c:716 usbtv_s_ctrl() error: doing dma on the stack (data) drivers/media/usb/usbtv/usbtv-video.c:758 usbtv_s_ctrl() error: doing dma on the stack (data) We should not do it, as it won't work on Kernels 4.9 and upper. So, alloc a buffer for it. Fixes: c53a846c48f2 ("[media] usbtv: add video controls") Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/usbtv/usbtv-video.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 86ffbf8780f2..d3b6d3dfaa09 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -704,10 +704,14 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) { struct usbtv *usbtv = container_of(ctrl->handler, struct usbtv, ctrl); - u8 data[3]; + u8 *data; u16 index, size; int ret; + data = kmalloc(3, GFP_KERNEL); + if (!data) + return -ENOMEM; + /* * Read in the current brightness/contrast registers. We need them * both, because the values are for some reason interleaved. @@ -717,6 +721,8 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) usb_sndctrlpipe(usbtv->udev, 0), USBTV_CONTROL_REG, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, USBTV_BASE + 0x0244, (void *)data, 3, 0); + if (ret < 0) + goto error; } switch (ctrl->id) { @@ -752,6 +758,7 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) } break; default: + kfree(data); return -EINVAL; } @@ -759,12 +766,13 @@ static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl) USBTV_CONTROL_REG, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0, index, (void *)data, size, 0); - if (ret < 0) { + +error: + if (ret < 0) dev_warn(usbtv->dev, "Failed to submit a control request.\n"); - return ret; - } - return 0; + kfree(data); + return ret; } static const struct v4l2_ctrl_ops usbtv_ctrl_ops = { -- cgit v1.2.3 From 3184c3bf67d1360a303dd02edccab41e37a637bd Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 13:44:08 -0200 Subject: [media] v4l: vsp1: Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/media/platform/vsp1/vsp1.ko | grep alias alias: vsp1 After this patch: $ modinfo drivers/media/platform/vsp1/vsp1.ko | grep alias alias: vsp1 alias: of:N*T*Crenesas,vsp2C* alias: of:N*T*Crenesas,vsp2 alias: of:N*T*Crenesas,vsp1C* alias: of:N*T*Crenesas,vsp1 Signed-off-by: Javier Martinez Canillas Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vsp1/vsp1_drv.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c index 57c713a4e1df..aa237b48ad55 100644 --- a/drivers/media/platform/vsp1/vsp1_drv.c +++ b/drivers/media/platform/vsp1/vsp1_drv.c @@ -770,6 +770,7 @@ static const struct of_device_id vsp1_of_match[] = { { .compatible = "renesas,vsp2" }, { }, }; +MODULE_DEVICE_TABLE(of, vsp1_of_match); static struct platform_driver vsp1_platform_driver = { .probe = vsp1_probe, -- cgit v1.2.3 From d6023d33a4ac9bc53975c9029a59135d71a76268 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 13:44:09 -0200 Subject: [media] v4l: rcar-fcp: Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/media/platform/rcar-fcp.ko | grep alias alias: rcar-fcp After this patch: $ modinfo drivers/media/platform/rcar-fcp.ko | grep alias alias: rcar-fcp alias: of:N*T*Crenesas,fcpvC* alias: of:N*T*Crenesas,fcpv alias: of:N*T*Crenesas,fcpfC* alias: of:N*T*Crenesas,fcpf Signed-off-by: Javier Martinez Canillas Reviewed-by: Laurent Pinchart Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar-fcp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c index f3a3f31cdfa9..7146fc5ef168 100644 --- a/drivers/media/platform/rcar-fcp.c +++ b/drivers/media/platform/rcar-fcp.c @@ -169,6 +169,7 @@ static const struct of_device_id rcar_fcp_of_match[] = { { .compatible = "renesas,fcpv" }, { }, }; +MODULE_DEVICE_TABLE(of, rcar_fcp_of_match); static struct platform_driver rcar_fcp_platform_driver = { .probe = rcar_fcp_probe, -- cgit v1.2.3 From 5bb50fe731fbb681bc5459e0d39b5bdbd950c33b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 13:44:10 -0200 Subject: [media] rc: meson-ir: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/media/rc/meson-ir.ko | grep alias $ After this patch: $ modinfo drivers/media/rc/meson-ir.ko | grep alias alias: of:N*T*Camlogic,meson-gxbb-irC* alias: of:N*T*Camlogic,meson-gxbb-ir alias: of:N*T*Camlogic,meson8b-irC* alias: of:N*T*Camlogic,meson8b-ir alias: of:N*T*Camlogic,meson6-irC* alias: of:N*T*Camlogic,meson6-ir Signed-off-by: Javier Martinez Canillas Acked-by: Kevin Hilman Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/meson-ir.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c index 003fff07ade2..7eb3f4f1ddcd 100644 --- a/drivers/media/rc/meson-ir.c +++ b/drivers/media/rc/meson-ir.c @@ -218,6 +218,7 @@ static const struct of_device_id meson_ir_match[] = { { .compatible = "amlogic,meson-gxbb-ir" }, { }, }; +MODULE_DEVICE_TABLE(of, meson_ir_match); static struct platform_driver meson_ir_driver = { .probe = meson_ir_probe, -- cgit v1.2.3 From 0dc5fb0a0b378c2b1ad98021d385441ec24a015d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 13:44:11 -0200 Subject: [media] s5p-cec: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/staging/media/s5p-cec/s5p-cec.ko | grep alias $ After this patch: $ modinfo drivers/staging/media/s5p-cec/s5p-cec.ko | grep alias alias: of:N*T*Csamsung,s5p-cecC* alias: of:N*T*Csamsung,s5p-cec Signed-off-by: Javier Martinez Canillas Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/s5p-cec/s5p_cec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/media/s5p-cec/s5p_cec.c b/drivers/staging/media/s5p-cec/s5p_cec.c index 58d756231136..097e20298886 100644 --- a/drivers/staging/media/s5p-cec/s5p_cec.c +++ b/drivers/staging/media/s5p-cec/s5p_cec.c @@ -263,6 +263,7 @@ static const struct of_device_id s5p_cec_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, s5p_cec_match); static struct platform_driver s5p_cec_pdrv = { .probe = s5p_cec_probe, -- cgit v1.2.3 From 2411434a2b78b38f70b3447d46b9c7db4f20fe54 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 17 Oct 2016 13:44:12 -0200 Subject: [media] st-cec: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/staging/media//st-cec/stih-cec.ko | grep alias $ After this patch: $ modinfo drivers/staging/media//st-cec/stih-cec.ko | grep alias alias: of:N*T*Cst,stih-cecC* alias: of:N*T*Cst,stih-cec Signed-off-by: Javier Martinez Canillas Acked-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/st-cec/stih-cec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/staging/media/st-cec/stih-cec.c b/drivers/staging/media/st-cec/stih-cec.c index b0aee1d4d5d0..1f1542e8154f 100644 --- a/drivers/staging/media/st-cec/stih-cec.c +++ b/drivers/staging/media/st-cec/stih-cec.c @@ -362,6 +362,7 @@ static const struct of_device_id stih_cec_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, stih_cec_match); static struct platform_driver stih_cec_pdrv = { .probe = stih_cec_probe, -- cgit v1.2.3 From 5fc4b067ec082c3127e0156f800769b7e0dce078 Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Sat, 22 Oct 2016 13:34:36 -0200 Subject: [media] media: solo6x10: fix lockup by avoiding delayed register write This fixes a lockup at device probing which happens on some solo6010 hardware samples. This is a regression introduced by commit e1ceb25a1569 ("[media] SOLO6x10: remove unneeded register locking and barriers") The observed lockup happens in solo_set_motion_threshold() called from solo_motion_config(). This extra "flushing" is not fundamentally needed for every write, but apparently the code in driver assumes such behaviour at last in some places. Actual fix was proposed by Hans Verkuil. Fixes: e1ceb25a1569 ("[media] SOLO6x10: remove unneeded register locking and barriers") Cc: stable@vger.kernel.org # 4.3 and up Signed-off-by: Andrey Utkin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/solo6x10/solo6x10.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h index 5bd498735a66..3f8da5e8c430 100644 --- a/drivers/media/pci/solo6x10/solo6x10.h +++ b/drivers/media/pci/solo6x10/solo6x10.h @@ -284,7 +284,10 @@ static inline u32 solo_reg_read(struct solo_dev *solo_dev, int reg) static inline void solo_reg_write(struct solo_dev *solo_dev, int reg, u32 data) { + u16 val; + writel(data, solo_dev->reg_base + reg); + pci_read_config_word(solo_dev->pdev, PCI_STATUS, &val); } static inline void solo_irq_on(struct solo_dev *dev, u32 mask) -- cgit v1.2.3 From 55d80506c5f7c3a44bad4a2bedeb3cc8235a69a1 Mon Sep 17 00:00:00 2001 From: Vincent Stehlé Date: Thu, 27 Oct 2016 18:23:25 -0200 Subject: [media] media: mtk-mdp: NULL-terminate mtk_mdp_comp_dt_ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mtk_mdp_comp_dt_ids[] array should be NULL-terminated; add therefore an empty entry in the end. Fixes: c8eb2d7e8202fd9c ("[media] media: Add Mediatek MDP Driver") Signed-off-by: Vincent Stehlé Cc: Minghsiu Tsai Cc: Mauro Carvalho Chehab Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index 40a229d8a1f5..53296e22a024 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -50,7 +50,8 @@ static const struct of_device_id mtk_mdp_comp_dt_ids[] = { }, { .compatible = "mediatek,mt8173-mdp-wrot", .data = (void *)MTK_MDP_WROT - } + }, + { }, }; static const struct of_device_id mtk_mdp_of_ids[] = { -- cgit v1.2.3 From f76fb34a25965f0a5d9cee9f6c5ecc4f96928dc4 Mon Sep 17 00:00:00 2001 From: Fengguang Wu Date: Thu, 27 Oct 2016 20:34:37 -0200 Subject: [media] media: fix platform_no_drv_owner.cocci warnings drivers/media/platform/mtk-mdp/mtk_mdp_core.c:284:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci CC: Minghsiu Tsai Signed-off-by: Fengguang Wu Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index 53296e22a024..51f2b50e406f 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -282,7 +282,6 @@ static struct platform_driver mtk_mdp_driver = { .remove = mtk_mdp_remove, .driver = { .name = MTK_MDP_MODULE_NAME, - .owner = THIS_MODULE, .pm = &mtk_mdp_pm_ops, .of_match_table = mtk_mdp_of_ids, } -- cgit v1.2.3 From 4a3229834d5f41e5ad9fc60b444c5924853ee6bc Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 14:17:55 -0200 Subject: [media] s5p-cec: remove unused including Remove including that don't need it. Signed-off-by: Wei Yongjun Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/s5p-cec/s5p_cec.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/media/s5p-cec/s5p_cec.c b/drivers/staging/media/s5p-cec/s5p_cec.c index 097e20298886..33e435855d66 100644 --- a/drivers/staging/media/s5p-cec/s5p_cec.c +++ b/drivers/staging/media/s5p-cec/s5p_cec.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 29a8d9792514557e26a9b05deaf671f2d83fa8ec Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 6 Sep 2016 19:52:24 -0300 Subject: [media] squash lines for simple wrapper functions Remove unneeded variables and assignments. Signed-off-by: Masahiro Yamada Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 8 ++------ drivers/media/pci/meye/meye.c | 5 +---- drivers/media/pci/ttpci/av7110.c | 4 +--- drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c | 17 +++-------------- drivers/media/platform/ti-vpe/cal.c | 6 +----- drivers/media/rc/fintek-cir.c | 6 +----- drivers/media/usb/dvb-usb-v2/lmedm04.c | 14 ++++++-------- drivers/media/usb/dvb-usb/m920x.c | 10 +++------- drivers/media/usb/gspca/jl2005bcd.c | 5 +---- drivers/media/usb/gspca/sq905c.c | 5 +---- 10 files changed, 20 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 98edf46b22d0..cdb7048874c5 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -1520,12 +1520,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe); static bool is_dvbv3_delsys(u32 delsys) { - bool status; - - status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) || - (delsys == SYS_DVBS) || (delsys == SYS_ATSC); - - return status; + return (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) || + (delsys == SYS_DVBS) || (delsys == SYS_ATSC); } /** diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index 11d81389ab1e..e825bc93ea7a 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -586,10 +586,7 @@ static void mchip_hic_stop(void) /* get the next ready frame from the dma engine */ static u32 mchip_get_frame(void) { - u32 v; - - v = mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); - return v; + return mchip_read(MCHIP_MM_FIR(meye.mchip_fnum)); } /* frees the current frame from the dma engine */ diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index fbcc2e5c9414..37e7e6684e3c 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -2925,9 +2925,7 @@ static struct saa7146_extension av7110_extension_driver = { static int __init av7110_init(void) { - int retval; - retval = saa7146_register_extension(&av7110_extension_driver); - return retval; + return saa7146_register_extension(&av7110_extension_driver); } diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c index 0912d0a892e2..a1d823ab0c63 100644 --- a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c +++ b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c @@ -178,20 +178,12 @@ void exynos4_jpeg_set_interrupt(void __iomem *base, unsigned int version) unsigned int exynos4_jpeg_get_int_status(void __iomem *base) { - unsigned int int_status; - - int_status = readl(base + EXYNOS4_INT_STATUS_REG); - - return int_status; + return readl(base + EXYNOS4_INT_STATUS_REG); } unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base) { - unsigned int fifo_status; - - fifo_status = readl(base + EXYNOS4_FIFO_STATUS_REG); - - return fifo_status; + return readl(base + EXYNOS4_FIFO_STATUS_REG); } void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value) @@ -296,10 +288,7 @@ void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt) unsigned int exynos4_jpeg_get_stream_size(void __iomem *base) { - unsigned int size; - - size = readl(base + EXYNOS4_BITSTREAM_SIZE_REG); - return size; + return readl(base + EXYNOS4_BITSTREAM_SIZE_REG); } void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size) diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index 44323cb5d287..b2d166b2221a 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -483,11 +483,7 @@ static void cal_get_hwinfo(struct cal_dev *dev) static inline int cal_runtime_get(struct cal_dev *dev) { - int r; - - r = pm_runtime_get_sync(&dev->pdev->dev); - - return r; + return pm_runtime_get_sync(&dev->pdev->dev); } static inline void cal_runtime_put(struct cal_dev *dev) diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c index bd7b3bdb1a88..ecab69ea3d51 100644 --- a/drivers/media/rc/fintek-cir.c +++ b/drivers/media/rc/fintek-cir.c @@ -104,11 +104,7 @@ static inline void fintek_cir_reg_write(struct fintek_dev *fintek, u8 val, u8 of /* read val from cir config register */ static u8 fintek_cir_reg_read(struct fintek_dev *fintek, u8 offset) { - u8 val; - - val = inb(fintek->cir_addr + offset); - - return val; + return inb(fintek->cir_addr + offset); } /* dump current cir register contents */ diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index 0e8fb89896c4..5fea02672685 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -156,21 +156,19 @@ struct lme2510_state { static int lme2510_bulk_write(struct usb_device *dev, u8 *snd, int len, u8 pipe) { - int ret, actual_l; + int actual_l; - ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), - snd, len , &actual_l, 100); - return ret; + return usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe), + snd, len, &actual_l, 100); } static int lme2510_bulk_read(struct usb_device *dev, u8 *rev, int len, u8 pipe) { - int ret, actual_l; + int actual_l; - ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), - rev, len , &actual_l, 200); - return ret; + return usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe), + rev, len, &actual_l, 200); } static int lme2510_usb_talk(struct dvb_usb_device *d, diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c index eafc5c82467f..70672e1e5ec7 100644 --- a/drivers/media/usb/dvb-usb/m920x.c +++ b/drivers/media/usb/dvb-usb/m920x.c @@ -55,13 +55,9 @@ static inline int m920x_read(struct usb_device *udev, u8 request, u16 value, static inline int m920x_write(struct usb_device *udev, u8 request, u16 value, u16 index) { - int ret; - - ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), - request, USB_TYPE_VENDOR | USB_DIR_OUT, - value, index, NULL, 0, 2000); - - return ret; + return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), request, + USB_TYPE_VENDOR | USB_DIR_OUT, value, index, + NULL, 0, 2000); } static inline int m920x_write_seq(struct usb_device *udev, u8 request, diff --git a/drivers/media/usb/gspca/jl2005bcd.c b/drivers/media/usb/gspca/jl2005bcd.c index ac295f04bd18..b12ecb72df4c 100644 --- a/drivers/media/usb/gspca/jl2005bcd.c +++ b/drivers/media/usb/gspca/jl2005bcd.c @@ -299,10 +299,7 @@ static int jl2005c_stream_start_cif_small(struct gspca_dev *gspca_dev) static int jl2005c_stop(struct gspca_dev *gspca_dev) { - int retval; - - retval = jl2005c_write_reg(gspca_dev, 0x07, 0x00); - return retval; + return jl2005c_write_reg(gspca_dev, 0x07, 0x00); } /* diff --git a/drivers/media/usb/gspca/sq905c.c b/drivers/media/usb/gspca/sq905c.c index e02b8c1d06a2..6c45dcc44eb0 100644 --- a/drivers/media/usb/gspca/sq905c.c +++ b/drivers/media/usb/gspca/sq905c.c @@ -257,11 +257,8 @@ static void sd_stop0(struct gspca_dev *gspca_dev) /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { - int ret; - /* connect to the camera and reset it. */ - ret = sq905c_command(gspca_dev, SQ905C_CLEAR, 0); - return ret; + return sq905c_command(gspca_dev, SQ905C_CLEAR, 0); } /* Set up for getting frames. */ -- cgit v1.2.3 From 20d93338bf250f3f6adeb71cc234fca966ef51d7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 19 Sep 2016 03:19:28 -0300 Subject: [media] st-hva: fix a copy-and-paste variable name error The second check for an error on hva->lmi_err_reg appears to be a copy-and-paste error, it should be hva->emi_err_reg instead. Signed-off-by: Colin Ian King Acked-by: Jean-Christophe Trotin Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/hva/hva-hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c index cf2a8d884536..68d625b412b6 100644 --- a/drivers/media/platform/sti/hva/hva-hw.c +++ b/drivers/media/platform/sti/hva/hva-hw.c @@ -245,7 +245,7 @@ static irqreturn_t hva_hw_err_irq_thread(int irq, void *arg) ctx->hw_err = true; } - if (hva->lmi_err_reg) { + if (hva->emi_err_reg) { dev_err(dev, "%s external memory interface error: 0x%08x\n", ctx->name, hva->emi_err_reg); ctx->hw_err = true; -- cgit v1.2.3 From a503ff812430e104f591287b512aa4e3a83f20b1 Mon Sep 17 00:00:00 2001 From: Jonathan Sims Date: Sun, 23 Oct 2016 16:19:07 -0200 Subject: [media] hdpvr: fix interrupted recording This is a reworking of a patch originally submitted by Ryley Angus, modified by Hans Verkuil and then seemingly forgotten before changes suggested by Keith Pyle here: http://www.mail-archive.com/linux-media@vger.kernel.org/msg75163.html were made and tested. I have implemented the suggested changes and have been testing for the last 2 months. I am no longer experiencing lockups while recording (with blue light on, requiring power cycling) which had been a long standing problem with the HD-PVR. I have not noticed any other problems since applying the patch. Signed-off-by: Jonathan Sims Reported-by: Ryley Angus Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/hdpvr/hdpvr-video.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index e3e7682d0f0e..7fb036d6a86e 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -449,6 +449,7 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, if (buf->status != BUFSTAT_READY && dev->status != STATUS_DISCONNECTED) { + int err; /* return nonblocking */ if (file->f_flags & O_NONBLOCK) { if (!ret) @@ -456,9 +457,24 @@ static ssize_t hdpvr_read(struct file *file, char __user *buffer, size_t count, goto err; } - if (wait_event_interruptible(dev->wait_data, - buf->status == BUFSTAT_READY)) - return -ERESTARTSYS; + err = wait_event_interruptible_timeout(dev->wait_data, + buf->status == BUFSTAT_READY, + msecs_to_jiffies(1000)); + if (err < 0) { + ret = err; + goto err; + } + if (!err) { + v4l2_dbg(MSG_INFO, hdpvr_debug, &dev->v4l2_dev, + "timeout: restart streaming\n"); + hdpvr_stop_streaming(dev); + msecs_to_jiffies(4000); + err = hdpvr_start_streaming(dev); + if (err) { + ret = err; + goto err; + } + } } if (buf->status != BUFSTAT_READY) -- cgit v1.2.3 From 652430763f9f48af0fea83ef9a6fecf7680d9210 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 14 Jul 2016 07:59:12 -0300 Subject: [media] v4l2-dv-timings: add helpers for vic and pixelaspect ratio Add a helper to find timings based on the CEA-861 VIC code. Also, add a helper that returns the pixel aspect ratio based on the v4l2_dv_timings struct. [mchehab@s-opensource.com: fix coding style] Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/Kconfig | 1 + drivers/media/v4l2-core/v4l2-dv-timings.c | 59 +++++++++++++++++++++++++++++-- include/media/v4l2-dv-timings.h | 20 ++++++++++- 3 files changed, 77 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig index 367523a3c774..6b1b78ff1417 100644 --- a/drivers/media/v4l2-core/Kconfig +++ b/drivers/media/v4l2-core/Kconfig @@ -6,6 +6,7 @@ config VIDEO_V4L2 tristate depends on (I2C || I2C=n) && VIDEO_DEV + select RATIONAL default (I2C || I2C=n) && VIDEO_DEV config VIDEO_ADV_DEBUG diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c index 730a7c392c1d..5c8c49d240d1 100644 --- a/drivers/media/v4l2-core/v4l2-dv-timings.c +++ b/drivers/media/v4l2-core/v4l2-dv-timings.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,24 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, } EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cap); +bool v4l2_find_dv_timings_cea861_vic(struct v4l2_dv_timings *t, u8 vic) +{ + unsigned int i; + + for (i = 0; i < v4l2_dv_timings_presets[i].bt.width; i++) { + const struct v4l2_bt_timings *bt = + &v4l2_dv_timings_presets[i].bt; + + if ((bt->flags & V4L2_DV_FL_HAS_CEA861_VIC) && + bt->cea861_vic == vic) { + *t = v4l2_dv_timings_presets[i]; + return true; + } + } + return false; +} +EXPORT_SYMBOL_GPL(v4l2_find_dv_timings_cea861_vic); + /** * v4l2_match_dv_timings - check if two timings match * @t1 - compare this v4l2_dv_timings struct... @@ -306,7 +325,8 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, (bt->polarities & V4L2_DV_VSYNC_POS_POL) ? "+" : "-", bt->il_vsync, bt->il_vbackporch); pr_info("%s: pixelclock: %llu\n", dev_prefix, bt->pixelclock); - pr_info("%s: flags (0x%x):%s%s%s%s%s%s%s\n", dev_prefix, bt->flags, + pr_info("%s: flags (0x%x):%s%s%s%s%s%s%s%s%s%s\n", + dev_prefix, bt->flags, (bt->flags & V4L2_DV_FL_REDUCED_BLANKING) ? " REDUCED_BLANKING" : "", ((bt->flags & V4L2_DV_FL_REDUCED_BLANKING) && @@ -320,16 +340,51 @@ void v4l2_print_dv_timings(const char *dev_prefix, const char *prefix, (bt->flags & V4L2_DV_FL_IS_CE_VIDEO) ? " CE_VIDEO" : "", (bt->flags & V4L2_DV_FL_FIRST_FIELD_EXTRA_LINE) ? - " FIRST_FIELD_EXTRA_LINE" : ""); + " FIRST_FIELD_EXTRA_LINE" : "", + (bt->flags & V4L2_DV_FL_HAS_PICTURE_ASPECT) ? + " HAS_PICTURE_ASPECT" : "", + (bt->flags & V4L2_DV_FL_HAS_CEA861_VIC) ? + " HAS_CEA861_VIC" : "", + (bt->flags & V4L2_DV_FL_HAS_HDMI_VIC) ? + " HAS_HDMI_VIC" : ""); pr_info("%s: standards (0x%x):%s%s%s%s%s\n", dev_prefix, bt->standards, (bt->standards & V4L2_DV_BT_STD_CEA861) ? " CEA" : "", (bt->standards & V4L2_DV_BT_STD_DMT) ? " DMT" : "", (bt->standards & V4L2_DV_BT_STD_CVT) ? " CVT" : "", (bt->standards & V4L2_DV_BT_STD_GTF) ? " GTF" : "", (bt->standards & V4L2_DV_BT_STD_SDI) ? " SDI" : ""); + if (bt->flags & V4L2_DV_FL_HAS_PICTURE_ASPECT) + pr_info("%s: picture aspect (hor:vert): %u:%u\n", dev_prefix, + bt->picture_aspect.numerator, + bt->picture_aspect.denominator); + if (bt->flags & V4L2_DV_FL_HAS_CEA861_VIC) + pr_info("%s: CEA-861 VIC: %u\n", dev_prefix, bt->cea861_vic); + if (bt->flags & V4L2_DV_FL_HAS_HDMI_VIC) + pr_info("%s: HDMI VIC: %u\n", dev_prefix, bt->hdmi_vic); } EXPORT_SYMBOL_GPL(v4l2_print_dv_timings); +struct v4l2_fract v4l2_dv_timings_aspect_ratio(const struct v4l2_dv_timings *t) +{ + struct v4l2_fract ratio = { 1, 1 }; + unsigned long n, d; + + if (t->type != V4L2_DV_BT_656_1120) + return ratio; + if (!(t->bt.flags & V4L2_DV_FL_HAS_PICTURE_ASPECT)) + return ratio; + + ratio.numerator = t->bt.width * t->bt.picture_aspect.denominator; + ratio.denominator = t->bt.height * t->bt.picture_aspect.numerator; + + rational_best_approximation(ratio.numerator, ratio.denominator, + ratio.numerator, ratio.denominator, &n, &d); + ratio.numerator = n; + ratio.denominator = d; + return ratio; +} +EXPORT_SYMBOL_GPL(v4l2_dv_timings_aspect_ratio); + /* * CVT defines * Based on Coordinated Video Timings Standard diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h index 0a7d9e1fc8c8..61a18893e004 100644 --- a/include/media/v4l2-dv-timings.h +++ b/include/media/v4l2-dv-timings.h @@ -100,13 +100,23 @@ bool v4l2_find_dv_timings_cap(struct v4l2_dv_timings *t, v4l2_check_dv_timings_fnc fnc, void *fnc_handle); +/** + * v4l2_find_dv_timings_cea861_vic() - find timings based on CEA-861 VIC + * @t: the timings data. + * @vic: CEA-861 VIC code + * + * On success it will fill in @t with the found timings and it returns true. + * On failure it will return false. + */ +bool v4l2_find_dv_timings_cea861_vic(struct v4l2_dv_timings *t, u8 vic); + /** * v4l2_match_dv_timings() - do two timings match? * * @measured: the measured timings data. * @standard: the timings according to the standard. * @pclock_delta: maximum delta in Hz between standard->pixelclock and - * the measured timings. + * the measured timings. * @match_reduced_fps: if true, then fail if V4L2_DV_FL_REDUCED_FPS does not * match. * @@ -185,6 +195,14 @@ bool v4l2_detect_gtf(unsigned frame_height, unsigned hfreq, unsigned vsync, */ struct v4l2_fract v4l2_calc_aspect_ratio(u8 hor_landscape, u8 vert_portrait); +/** + * v4l2_dv_timings_aspect_ratio - calculate the aspect ratio based on the + * v4l2_dv_timings information. + * + * @t: the timings data. + */ +struct v4l2_fract v4l2_dv_timings_aspect_ratio(const struct v4l2_dv_timings *t); + /* * reduce_fps - check if conditions for reduced fps are true. * bt - v4l2 timing structure -- cgit v1.2.3 From d736e348a0bcf25972c23d743821b91d3694e328 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Sun, 17 Jul 2016 05:42:07 -0300 Subject: [media] cobalt: add cropcap support Now that the timings contain picture aspect ratio information, we can support cropcap to return the pixel aspect ratio. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-v4l2.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers') diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index 5c76637900d0..3fea24613059 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -1084,12 +1084,33 @@ static int cobalt_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a) return 0; } +static int cobalt_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cc) +{ + struct cobalt_stream *s = video_drvdata(file); + struct v4l2_dv_timings timings; + int err = 0; + + if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + return -EINVAL; + if (s->input == 1) + timings = cea1080p60; + else + err = v4l2_subdev_call(s->sd, video, g_dv_timings, &timings); + if (!err) { + cc->bounds.width = cc->defrect.width = timings.bt.width; + cc->bounds.height = cc->defrect.height = timings.bt.height; + cc->pixelaspect = v4l2_dv_timings_aspect_ratio(&timings); + } + return err; +} + static const struct v4l2_ioctl_ops cobalt_ioctl_ops = { .vidioc_querycap = cobalt_querycap, .vidioc_g_parm = cobalt_g_parm, .vidioc_log_status = cobalt_log_status, .vidioc_streamon = vb2_ioctl_streamon, .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_cropcap = cobalt_cropcap, .vidioc_enum_input = cobalt_enum_input, .vidioc_g_input = cobalt_g_input, .vidioc_s_input = cobalt_s_input, -- cgit v1.2.3 From 827c1f525a07e07997bee034a84d32216af10e58 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Thu, 14 Jul 2016 11:53:47 -0300 Subject: [media] adv7604: add vic detect Obtain the correct timings based on the VIC code from the AVI InfoFrame. It does a sanity check to see if at least the measured width and height are in line with what the VIC code reports. If not, then use the timings instead of the VIC code (as per the CEA-861 spec). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/adv7604.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index fa7046ef09b2..5630eb22daaa 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -1566,10 +1566,24 @@ static int adv76xx_query_dv_timings(struct v4l2_subdev *sd, V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE; if (is_digital_input(sd)) { + bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80; + u8 vic = 0; + u32 w, h; + + w = hdmi_read16(sd, 0x07, info->linewidth_mask); + h = hdmi_read16(sd, 0x09, info->field0_height_mask); + + if (hdmi_signal && (io_read(sd, 0x60) & 1)) + vic = infoframe_read(sd, 0x04); + + if (vic && v4l2_find_dv_timings_cea861_vic(timings, vic) && + bt->width == w && bt->height == h) + goto found; + timings->type = V4L2_DV_BT_656_1120; - bt->width = hdmi_read16(sd, 0x07, info->linewidth_mask); - bt->height = hdmi_read16(sd, 0x09, info->field0_height_mask); + bt->width = w; + bt->height = h; bt->pixelclock = info->read_hdmi_pixelclock(sd); bt->hfrontporch = hdmi_read16(sd, 0x20, info->hfrontporch_mask); bt->hsync = hdmi_read16(sd, 0x22, info->hsync_mask); -- cgit v1.2.3 From 64bab1a20c21875dd021e426ec9d8a21dfb4b3ac Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Fri, 4 Nov 2016 05:58:31 -0200 Subject: [media] staging: st-cec: add parentheses around complex macros This patch fixes the following checkpatch.pl error: ERROR: Macros with complex values should be enclosed in parentheses Signed-off-by: Maninder Singh Acked-by: Benjamin Gaignard Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/st-cec/stih-cec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/st-cec/stih-cec.c b/drivers/staging/media/st-cec/stih-cec.c index 1f1542e8154f..eed1fd6bbefa 100644 --- a/drivers/staging/media/st-cec/stih-cec.c +++ b/drivers/staging/media/st-cec/stih-cec.c @@ -107,11 +107,11 @@ /* Constants for CEC_BIT_TOUT_THRESH register */ #define CEC_SBIT_TOUT_47MS BIT(1) -#define CEC_SBIT_TOUT_48MS BIT(0) | BIT(1) +#define CEC_SBIT_TOUT_48MS (BIT(0) | BIT(1)) #define CEC_SBIT_TOUT_50MS BIT(2) #define CEC_DBIT_TOUT_27MS BIT(0) #define CEC_DBIT_TOUT_28MS BIT(1) -#define CEC_DBIT_TOUT_29MS BIT(0) | BIT(1) +#define CEC_DBIT_TOUT_29MS (BIT(0) | BIT(1)) /* Constants for CEC_BIT_PULSE_THRESH register */ #define CEC_BIT_LPULSE_03MS BIT(1) -- cgit v1.2.3 From 2eaa68f33b86bf9a6c6cbfaf773d74f1f8bddd4e Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 6 Nov 2016 17:40:20 -0200 Subject: [media] DaVinci-VPBE: Check return value of a setup_if_config() call in vpbe_set_output() * A function was called over the pointer "setup_if_config" in the data structure "venc_platform_data". But the return value was not used so far. Thus assign it to the local variable "ret" which will be checked with the next statement. Fixes: 9a7f95ad1c946efdd7a7a72df27db738260a0fd8 ("[media] davinci vpbe: add dm365 VPBE display driver changes") * Pass a value to this function call without storing it in an intermediate variable before. * Delete the local variable "if_params" which became unnecessary with this refactoring. Acked-by: Lad, Prabhakar Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpbe.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c index 7dcdb7f4b323..8c8cbeb7d90f 100644 --- a/drivers/media/platform/davinci/vpbe.c +++ b/drivers/media/platform/davinci/vpbe.c @@ -227,7 +227,6 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) vpbe_current_encoder_info(vpbe_dev); struct vpbe_config *cfg = vpbe_dev->cfg; struct venc_platform_data *venc_device = vpbe_dev->venc_device; - u32 if_params; int enc_out_index; int sd_index; int ret; @@ -257,8 +256,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index) goto unlock; } - if_params = cfg->outputs[index].if_params; - venc_device->setup_if_config(if_params); + ret = venc_device->setup_if_config(cfg->outputs[index].if_params); if (ret) goto unlock; } -- cgit v1.2.3 From e91b6006bfa65600a14e79b7d8371ec711a7c84f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sun, 6 Nov 2016 18:54:38 -0200 Subject: [media] DaVinci-VPFE-Capture: Replace a memcpy() call by an assignment in vpfe_enum_input() Use a direct assignment for an array element which can be set over the pointer variable "inp" instead of calling the function "memcpy" here. Suggested-by: Hans Verkuil Signed-off-by: Markus Elfring Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 71caebf125f1..6c41782b3ba0 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1086,7 +1086,7 @@ static int vpfe_enum_input(struct file *file, void *priv, return -EINVAL; } sdinfo = &vpfe_dev->cfg->sub_devs[subdev]; - memcpy(inp, &sdinfo->inputs[index], sizeof(struct v4l2_input)); + *inp = sdinfo->inputs[index]; return 0; } -- cgit v1.2.3 From b7ccb9fb7994d0340314a5d467a8c4d3e37d6531 Mon Sep 17 00:00:00 2001 From: Wu-Cheng Li Date: Thu, 10 Nov 2016 03:24:05 -0200 Subject: [media] mtk-vcodec: add index check in decoder vidioc_qbuf vb2_qbuf will check the buffer index. If a driver overrides vidioc_qbuf and use the buffer index, the driver needs to check the index. Signed-off-by: Wu-Cheng Li Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c index 05209193ff7e..074659227864 100644 --- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c +++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c @@ -533,6 +533,10 @@ static int vidioc_vdec_qbuf(struct file *file, void *priv, } vq = v4l2_m2m_get_vq(ctx->m2m_ctx, buf->type); + if (buf->index >= vq->num_buffers) { + mtk_v4l2_debug(1, "buffer index %d out of range", buf->index); + return -EINVAL; + } vb = vq->bufs[buf->index]; vb2_v4l2 = container_of(vb, struct vb2_v4l2_buffer, vb2_buf); mtkbuf = container_of(vb2_v4l2, struct mtk_video_dec_buf, vb); -- cgit v1.2.3 From 9f750b2b15125e842a2bd0a8c16f06ee65da26a2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Nov 2016 08:33:05 -0200 Subject: [media] cobalt: fix copy-and-paste error The vmr_stat variable was filled with the contents of the control register, not the status register. Classic copy-and-paste error. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cobalt/cobalt-v4l2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c index 3fea24613059..def4a3b37084 100644 --- a/drivers/media/pci/cobalt/cobalt-v4l2.c +++ b/drivers/media/pci/cobalt/cobalt-v4l2.c @@ -527,7 +527,7 @@ static void cobalt_video_input_status_show(struct cobalt_stream *s) cvi_ctrl = ioread32(&cvi->control); cvi_stat = ioread32(&cvi->status); vmr_ctrl = ioread32(&vmr->control); - vmr_stat = ioread32(&vmr->control); + vmr_stat = ioread32(&vmr->status); cobalt_info("rx%d: cvi resolution: %dx%d\n", rx, ioread32(&cvi->frame_width), ioread32(&cvi->frame_height)); cobalt_info("rx%d: cvi control: %s%s%s\n", rx, -- cgit v1.2.3 From acd4973563f5f80a833f2cc97c5f45048be93250 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 1 Nov 2016 06:47:10 -0200 Subject: [media] pulse8-cec: set all_device_types when restoring config When the persistent state is restored, the all_device_types field was never filled in. Fix this. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/pulse8-cec/pulse8-cec.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/staging/media/pulse8-cec/pulse8-cec.c b/drivers/staging/media/pulse8-cec/pulse8-cec.c index 1732c3857b8e..9092494bb43c 100644 --- a/drivers/staging/media/pulse8-cec/pulse8-cec.c +++ b/drivers/staging/media/pulse8-cec/pulse8-cec.c @@ -375,27 +375,35 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio, switch (log_addrs->primary_device_type[0]) { case CEC_OP_PRIM_DEVTYPE_TV: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TV; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TV; break; case CEC_OP_PRIM_DEVTYPE_RECORD: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_RECORD; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_RECORD; break; case CEC_OP_PRIM_DEVTYPE_TUNER: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TUNER; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TUNER; break; case CEC_OP_PRIM_DEVTYPE_PLAYBACK: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_PLAYBACK; break; case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM; break; case CEC_OP_PRIM_DEVTYPE_SWITCH: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; break; case CEC_OP_PRIM_DEVTYPE_PROCESSOR: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_SPECIFIC; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; break; default: log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; dev_info(pulse8->dev, "Unknown Primary Device Type: %d\n", log_addrs->primary_device_type[0]); break; -- cgit v1.2.3 From f4062625ede8f0280d8246437f4070c8eb7fe9f3 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 1 Nov 2016 07:59:34 -0200 Subject: [media] cec: add flag to cec_log_addrs to enable RC passthrough By default the CEC_MSG_USER_CONTROL_PRESSED/RELEASED messages are passed on to the follower(s) only. If the new CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU flag is set in the flags field of struct cec_log_addrs then these messages are also passed on to the remote control input subsystem and they will appear as keystrokes. This used to be the default behavior, but now you have to explicitly enable it. This is done to force the caller to think about possible security issues (e.g. if these messages are used to enter passwords). Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst | 10 ++++++++++ drivers/staging/media/cec/TODO | 2 -- drivers/staging/media/cec/cec-adap.c | 6 ++++-- drivers/staging/media/cec/cec-api.c | 3 ++- include/linux/cec.h | 2 ++ 5 files changed, 18 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst b/Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst index af35f7185439..571ae57b75ae 100644 --- a/Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst +++ b/Documentation/media/uapi/cec/cec-ioc-adap-g-log-addrs.rst @@ -166,6 +166,16 @@ logical address types are already defined will return with error ``EBUSY``. it will go back to the unconfigured state. If this flag is set, then it will fallback to the Unregistered logical address. Note that if the Unregistered logical address was explicitly requested, then this flag has no effect. + * .. _`CEC-LOG-ADDRS-FL-ALLOW-RC-PASSTHRU`: + + - ``CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU`` + - 2 + - By default the ``CEC_MSG_USER_CONTROL_PRESSED`` and ``CEC_MSG_USER_CONTROL_RELEASED`` + messages are only passed on to the follower(s), if any. If this flag is set, + then these messages are also passed on to the remote control input subsystem + and will appear as keystrokes. This features needs to be enabled explicitly. + If CEC is used to enter e.g. passwords, then you may not want to enable this + to avoid trivial snooping of the keystrokes. .. tabularcolumns:: |p{6.6cm}|p{2.2cm}|p{8.7cm}| diff --git a/drivers/staging/media/cec/TODO b/drivers/staging/media/cec/TODO index 13224694a8ae..084120687d06 100644 --- a/drivers/staging/media/cec/TODO +++ b/drivers/staging/media/cec/TODO @@ -13,8 +13,6 @@ Hopefully this will happen later in 2016. Other TODOs: - There are two possible replies to CEC_MSG_INITIATE_ARC. How to handle that? -- Add a flag to inhibit passing CEC RC messages to the rc subsystem. - Applications should be able to choose this when calling S_LOG_ADDRS. - If the reply field of cec_msg is set then when the reply arrives it is only sent to the filehandle that transmitted the original message and not to any followers. Should this behavior change or perhaps diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c index 611e07b78bfe..589e4576fbe9 100644 --- a/drivers/staging/media/cec/cec-adap.c +++ b/drivers/staging/media/cec/cec-adap.c @@ -1478,7 +1478,8 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, } case CEC_MSG_USER_CONTROL_PRESSED: - if (!(adap->capabilities & CEC_CAP_RC)) + if (!(adap->capabilities & CEC_CAP_RC) || + !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) break; #if IS_REACHABLE(CONFIG_RC_CORE) @@ -1515,7 +1516,8 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, break; case CEC_MSG_USER_CONTROL_RELEASED: - if (!(adap->capabilities & CEC_CAP_RC)) + if (!(adap->capabilities & CEC_CAP_RC) || + !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) break; #if IS_REACHABLE(CONFIG_RC_CORE) rc_keyup(adap->rc); diff --git a/drivers/staging/media/cec/cec-api.c b/drivers/staging/media/cec/cec-api.c index e274e2f22398..040ca7ddf2b0 100644 --- a/drivers/staging/media/cec/cec-api.c +++ b/drivers/staging/media/cec/cec-api.c @@ -162,7 +162,8 @@ static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, return -ENOTTY; if (copy_from_user(&log_addrs, parg, sizeof(log_addrs))) return -EFAULT; - log_addrs.flags &= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK; + log_addrs.flags &= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK | + CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU; mutex_lock(&adap->lock); if (!adap->is_configuring && (!log_addrs.num_log_addrs || !adap->is_configured) && diff --git a/include/linux/cec.h b/include/linux/cec.h index 851968e803fa..825455fae3cc 100644 --- a/include/linux/cec.h +++ b/include/linux/cec.h @@ -391,6 +391,8 @@ struct cec_log_addrs { /* Allow a fallback to unregistered */ #define CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK (1 << 0) +/* Passthrough RC messages to the input subsystem */ +#define CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU (1 << 1) /* Events */ -- cgit v1.2.3 From adc0c622783978ab0c740af77f98fc8f65c87d66 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 1 Nov 2016 08:55:05 -0200 Subject: [media] cec: add CEC_MSG_FL_REPLY_TO_FOLLOWERS Give the caller more control over how replies to a transmit are handled. By default the reply will only go to the filehandle that called CEC_TRANSMIT. If this new flag is set, then the reply will also go to all followers. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/cec/cec-ioc-receive.rst | 22 +++++++++++++++++++++- drivers/staging/media/cec/TODO | 4 ---- drivers/staging/media/cec/cec-adap.c | 6 +++--- drivers/staging/media/cec/cec-api.c | 1 + include/linux/cec.h | 5 ++++- 5 files changed, 29 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/Documentation/media/uapi/cec/cec-ioc-receive.rst b/Documentation/media/uapi/cec/cec-ioc-receive.rst index 21a88df3d9d9..b4dffd2f7dfa 100644 --- a/Documentation/media/uapi/cec/cec-ioc-receive.rst +++ b/Documentation/media/uapi/cec/cec-ioc-receive.rst @@ -119,7 +119,7 @@ result. transmit. * - __u32 - ``flags`` - - Flags. No flags are defined yet, so set this to 0. + - Flags. See :ref:`cec-msg-flags` for a list of available flags. * - __u8 - ``tx_status`` - The status bits of the transmitted message. See @@ -180,6 +180,26 @@ result. valid if the :ref:`CEC_TX_STATUS_ERROR ` status bit is set. +.. _cec-msg-flags: + +.. flat-table:: Flags for struct cec_msg + :header-rows: 0 + :stub-columns: 0 + :widths: 3 1 4 + + * .. _`CEC-MSG-FL-REPLY-TO-FOLLOWERS`: + + - ``CEC_MSG_FL_REPLY_TO_FOLLOWERS`` + - 1 + - If a CEC transmit expects a reply, then by default that reply is only sent to + the filehandle that called :ref:`ioctl CEC_TRANSMIT `. If this + flag is set, then the reply is also sent to all followers, if any. If the + filehandle that called :ref:`ioctl CEC_TRANSMIT ` is also a + follower, then that filehandle will receive the reply twice: once as the + result of the :ref:`ioctl CEC_TRANSMIT `, and once via + :ref:`ioctl CEC_RECEIVE `. + + .. tabularcolumns:: |p{5.6cm}|p{0.9cm}|p{11.0cm}| .. _cec-tx-status: diff --git a/drivers/staging/media/cec/TODO b/drivers/staging/media/cec/TODO index 084120687d06..ce69001b0428 100644 --- a/drivers/staging/media/cec/TODO +++ b/drivers/staging/media/cec/TODO @@ -13,10 +13,6 @@ Hopefully this will happen later in 2016. Other TODOs: - There are two possible replies to CEC_MSG_INITIATE_ARC. How to handle that? -- If the reply field of cec_msg is set then when the reply arrives it - is only sent to the filehandle that transmitted the original message - and not to any followers. Should this behavior change or perhaps - controlled through a cec_msg flag? - Should CEC_LOG_ADDR_TYPE_SPECIFIC be replaced by TYPE_2ND_TV and TYPE_PROCESSOR? And also TYPE_SWITCH and TYPE_CDC_ONLY in addition to the TYPE_UNREGISTERED? This should give the framework more information about the device type diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c index 589e4576fbe9..6aceb1d4a7a0 100644 --- a/drivers/staging/media/cec/cec-adap.c +++ b/drivers/staging/media/cec/cec-adap.c @@ -587,7 +587,6 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, msg->tx_nack_cnt = 0; msg->tx_low_drive_cnt = 0; msg->tx_error_cnt = 0; - msg->flags = 0; msg->sequence = ++adap->sequence; if (!msg->sequence) msg->sequence = ++adap->sequence; @@ -823,6 +822,7 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) dst->rx_status = msg->rx_status; if (abort) dst->rx_status |= CEC_RX_STATUS_FEATURE_ABORT; + msg->flags = dst->flags; /* Remove it from the wait_queue */ list_del_init(&data->list); @@ -1575,8 +1575,8 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, } skip_processing: - /* If this was a reply, then we're done */ - if (is_reply) + /* If this was a reply, then we're done, unless otherwise specified */ + if (is_reply && !(msg->flags & CEC_MSG_FL_REPLY_TO_FOLLOWERS)) return 0; /* diff --git a/drivers/staging/media/cec/cec-api.c b/drivers/staging/media/cec/cec-api.c index 040ca7ddf2b0..54148a6b3326 100644 --- a/drivers/staging/media/cec/cec-api.c +++ b/drivers/staging/media/cec/cec-api.c @@ -190,6 +190,7 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, return -ENOTTY; if (copy_from_user(&msg, parg, sizeof(msg))) return -EFAULT; + msg.flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; mutex_lock(&adap->lock); if (!adap->is_configured) err = -ENONET; diff --git a/include/linux/cec.h b/include/linux/cec.h index 825455fae3cc..3f2f076027b1 100644 --- a/include/linux/cec.h +++ b/include/linux/cec.h @@ -175,7 +175,10 @@ static inline void cec_msg_set_reply_to(struct cec_msg *msg, msg->reply = msg->timeout = 0; } -/* cec status field */ +/* cec_msg flags field */ +#define CEC_MSG_FL_REPLY_TO_FOLLOWERS (1 << 0) + +/* cec_msg tx/rx_status field */ #define CEC_TX_STATUS_OK (1 << 0) #define CEC_TX_STATUS_ARB_LOST (1 << 1) #define CEC_TX_STATUS_NACK (1 << 2) -- cgit v1.2.3 From 3074fe4a7da5775bcf31675d6d9e2687c434fef2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 1 Nov 2016 10:48:22 -0200 Subject: [media] cec: filter invalid messages As per the CEC specification: - CEC messages with a too-small payload should be ignored. - Broadcast messages that are only allowed as directed messages should be ignored. - Directed messages that are only allowed as broadcast messages should be ignored. Implement this in the core CEC framework. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/cec/cec-adap.c | 157 ++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c index 6aceb1d4a7a0..93b53e602e48 100644 --- a/drivers/staging/media/cec/cec-adap.c +++ b/drivers/staging/media/cec/cec-adap.c @@ -762,14 +762,105 @@ EXPORT_SYMBOL_GPL(cec_transmit_msg); static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, bool is_reply); +#define DIRECTED 0x80 +#define BCAST1_4 0x40 +#define BCAST2_0 0x20 /* broadcast only allowed for >= 2.0 */ +#define BCAST (BCAST1_4 | BCAST2_0) +#define BOTH (BCAST | DIRECTED) + +/* + * Specify minimum length and whether the message is directed, broadcast + * or both. Messages that do not match the criteria are ignored as per + * the CEC specification. + */ +static const u8 cec_msg_size[256] = { + [CEC_MSG_ACTIVE_SOURCE] = 4 | BCAST, + [CEC_MSG_IMAGE_VIEW_ON] = 2 | DIRECTED, + [CEC_MSG_TEXT_VIEW_ON] = 2 | DIRECTED, + [CEC_MSG_INACTIVE_SOURCE] = 4 | DIRECTED, + [CEC_MSG_REQUEST_ACTIVE_SOURCE] = 2 | BCAST, + [CEC_MSG_ROUTING_CHANGE] = 6 | BCAST, + [CEC_MSG_ROUTING_INFORMATION] = 4 | BCAST, + [CEC_MSG_SET_STREAM_PATH] = 4 | BCAST, + [CEC_MSG_STANDBY] = 2 | BOTH, + [CEC_MSG_RECORD_OFF] = 2 | DIRECTED, + [CEC_MSG_RECORD_ON] = 3 | DIRECTED, + [CEC_MSG_RECORD_STATUS] = 3 | DIRECTED, + [CEC_MSG_RECORD_TV_SCREEN] = 2 | DIRECTED, + [CEC_MSG_CLEAR_ANALOGUE_TIMER] = 13 | DIRECTED, + [CEC_MSG_CLEAR_DIGITAL_TIMER] = 16 | DIRECTED, + [CEC_MSG_CLEAR_EXT_TIMER] = 13 | DIRECTED, + [CEC_MSG_SET_ANALOGUE_TIMER] = 13 | DIRECTED, + [CEC_MSG_SET_DIGITAL_TIMER] = 16 | DIRECTED, + [CEC_MSG_SET_EXT_TIMER] = 13 | DIRECTED, + [CEC_MSG_SET_TIMER_PROGRAM_TITLE] = 2 | DIRECTED, + [CEC_MSG_TIMER_CLEARED_STATUS] = 3 | DIRECTED, + [CEC_MSG_TIMER_STATUS] = 3 | DIRECTED, + [CEC_MSG_CEC_VERSION] = 3 | DIRECTED, + [CEC_MSG_GET_CEC_VERSION] = 2 | DIRECTED, + [CEC_MSG_GIVE_PHYSICAL_ADDR] = 2 | DIRECTED, + [CEC_MSG_GET_MENU_LANGUAGE] = 2 | DIRECTED, + [CEC_MSG_REPORT_PHYSICAL_ADDR] = 5 | BCAST, + [CEC_MSG_SET_MENU_LANGUAGE] = 5 | BCAST, + [CEC_MSG_REPORT_FEATURES] = 6 | BCAST, + [CEC_MSG_GIVE_FEATURES] = 2 | DIRECTED, + [CEC_MSG_DECK_CONTROL] = 3 | DIRECTED, + [CEC_MSG_DECK_STATUS] = 3 | DIRECTED, + [CEC_MSG_GIVE_DECK_STATUS] = 3 | DIRECTED, + [CEC_MSG_PLAY] = 3 | DIRECTED, + [CEC_MSG_GIVE_TUNER_DEVICE_STATUS] = 3 | DIRECTED, + [CEC_MSG_SELECT_ANALOGUE_SERVICE] = 6 | DIRECTED, + [CEC_MSG_SELECT_DIGITAL_SERVICE] = 9 | DIRECTED, + [CEC_MSG_TUNER_DEVICE_STATUS] = 7 | DIRECTED, + [CEC_MSG_TUNER_STEP_DECREMENT] = 2 | DIRECTED, + [CEC_MSG_TUNER_STEP_INCREMENT] = 2 | DIRECTED, + [CEC_MSG_DEVICE_VENDOR_ID] = 5 | BCAST, + [CEC_MSG_GIVE_DEVICE_VENDOR_ID] = 2 | DIRECTED, + [CEC_MSG_VENDOR_COMMAND] = 2 | DIRECTED, + [CEC_MSG_VENDOR_COMMAND_WITH_ID] = 5 | BOTH, + [CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN] = 2 | BOTH, + [CEC_MSG_VENDOR_REMOTE_BUTTON_UP] = 2 | BOTH, + [CEC_MSG_SET_OSD_STRING] = 3 | DIRECTED, + [CEC_MSG_GIVE_OSD_NAME] = 2 | DIRECTED, + [CEC_MSG_SET_OSD_NAME] = 2 | DIRECTED, + [CEC_MSG_MENU_REQUEST] = 3 | DIRECTED, + [CEC_MSG_MENU_STATUS] = 3 | DIRECTED, + [CEC_MSG_USER_CONTROL_PRESSED] = 3 | DIRECTED, + [CEC_MSG_USER_CONTROL_RELEASED] = 2 | DIRECTED, + [CEC_MSG_GIVE_DEVICE_POWER_STATUS] = 2 | DIRECTED, + [CEC_MSG_REPORT_POWER_STATUS] = 3 | DIRECTED | BCAST2_0, + [CEC_MSG_FEATURE_ABORT] = 4 | DIRECTED, + [CEC_MSG_ABORT] = 2 | DIRECTED, + [CEC_MSG_GIVE_AUDIO_STATUS] = 2 | DIRECTED, + [CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS] = 2 | DIRECTED, + [CEC_MSG_REPORT_AUDIO_STATUS] = 3 | DIRECTED, + [CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, + [CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, + [CEC_MSG_SET_SYSTEM_AUDIO_MODE] = 3 | BOTH, + [CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST] = 2 | DIRECTED, + [CEC_MSG_SYSTEM_AUDIO_MODE_STATUS] = 3 | DIRECTED, + [CEC_MSG_SET_AUDIO_RATE] = 3 | DIRECTED, + [CEC_MSG_INITIATE_ARC] = 2 | DIRECTED, + [CEC_MSG_REPORT_ARC_INITIATED] = 2 | DIRECTED, + [CEC_MSG_REPORT_ARC_TERMINATED] = 2 | DIRECTED, + [CEC_MSG_REQUEST_ARC_INITIATION] = 2 | DIRECTED, + [CEC_MSG_REQUEST_ARC_TERMINATION] = 2 | DIRECTED, + [CEC_MSG_TERMINATE_ARC] = 2 | DIRECTED, + [CEC_MSG_REQUEST_CURRENT_LATENCY] = 4 | BCAST, + [CEC_MSG_REPORT_CURRENT_LATENCY] = 7 | BCAST, + [CEC_MSG_CDC_MESSAGE] = 2 | BCAST, +}; + /* Called by the CEC adapter if a message is received */ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) { struct cec_data *data; u8 msg_init = cec_msg_initiator(msg); u8 msg_dest = cec_msg_destination(msg); + u8 cmd = msg->msg[1]; bool is_reply = false; bool valid_la = true; + u8 min_len = 0; if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE)) return; @@ -789,9 +880,71 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) if (!cec_msg_is_broadcast(msg)) valid_la = cec_has_log_addr(adap, msg_dest); + /* + * Check if the length is not too short or if the message is a + * broadcast message where a directed message was expected or + * vice versa. If so, then the message has to be ignored (according + * to section CEC 7.3 and CEC 12.2). + */ + if (valid_la && msg->len > 1 && cec_msg_size[cmd]) { + u8 dir_fl = cec_msg_size[cmd] & BOTH; + + min_len = cec_msg_size[cmd] & 0x1f; + if (msg->len < min_len) + valid_la = false; + else if (!cec_msg_is_broadcast(msg) && !(dir_fl & DIRECTED)) + valid_la = false; + else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST1_4)) + valid_la = false; + else if (cec_msg_is_broadcast(msg) && + adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0 && + !(dir_fl & BCAST2_0)) + valid_la = false; + } + if (valid_la && min_len) { + /* These messages have special length requirements */ + switch (cmd) { + case CEC_MSG_TIMER_STATUS: + if (msg->msg[2] & 0x10) { + switch (msg->msg[2] & 0xf) { + case CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE: + case CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE: + if (msg->len < 5) + valid_la = false; + break; + } + } else if ((msg->msg[2] & 0xf) == CEC_OP_PROG_ERROR_DUPLICATE) { + if (msg->len < 5) + valid_la = false; + } + break; + case CEC_MSG_RECORD_ON: + switch (msg->msg[2]) { + case CEC_OP_RECORD_SRC_OWN: + break; + case CEC_OP_RECORD_SRC_DIGITAL: + if (msg->len < 10) + valid_la = false; + break; + case CEC_OP_RECORD_SRC_ANALOG: + if (msg->len < 7) + valid_la = false; + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + if (msg->len < 4) + valid_la = false; + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + if (msg->len < 5) + valid_la = false; + break; + } + break; + } + } + /* It's a valid message and not a poll or CDC message */ - if (valid_la && msg->len > 1 && msg->msg[1] != CEC_MSG_CDC_MESSAGE) { - u8 cmd = msg->msg[1]; + if (valid_la && msg->len > 1 && cmd != CEC_MSG_CDC_MESSAGE) { bool abort = cmd == CEC_MSG_FEATURE_ABORT; /* The aborted command is in msg[2] */ -- cgit v1.2.3 From f5580d8d6fd07a569e468fca51f435aa5b122fc4 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Tue, 1 Nov 2016 11:07:17 -0200 Subject: [media] cec: accept two replies for CEC_MSG_INITIATE_ARC The CEC_MSG_INITIATE_ARC message is special since it is the ONLY CEC message that accepts two possible valid replies: CEC_MSG_REPORT_ARC_INITIATED and CEC_MSG_REPORT_ARC_TERMINATED. So if the transmitted message is CEC_MSG_INITIATE_ARC and the remote side replied with CEC_MSG_REPORT_ARC_INITIATED or CEC_MSG_REPORT_ARC_TERMINATED, then a msg->reply value of CEC_MSG_REPORT_ARC_INITIATED or CEC_MSG_REPORT_ARC_TERMINATED will match either reply. I thought about either adding a second reply2 field, but that's ugly for all other messages that have only one reply, and what if in the future a new message is added that can have three replies? Another option would be to add a cec_msg flag, but really, the combination of CEC_MSG_REPORT_ARC_INITIATED and a reply value of one of the two possible replies already functions as a flag. Another advantage of this approach is that it is safe to re-use a cec_msg struct. No need to zero a flags field or a reply2 field. So since this really is an exception in the CEC specification, I decided to implement it as an exception as well. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/cec/cec-ioc-receive.rst | 8 ++++++++ drivers/staging/media/cec/TODO | 15 +-------------- drivers/staging/media/cec/cec-adap.c | 12 ++++++++++++ 3 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/Documentation/media/uapi/cec/cec-ioc-receive.rst b/Documentation/media/uapi/cec/cec-ioc-receive.rst index b4dffd2f7dfa..bdf015b1d1dc 100644 --- a/Documentation/media/uapi/cec/cec-ioc-receive.rst +++ b/Documentation/media/uapi/cec/cec-ioc-receive.rst @@ -142,6 +142,14 @@ result. Feature Abort reply. In this case ``rx_status`` will either be set to :ref:`CEC_RX_STATUS_TIMEOUT ` or :ref:`CEC_RX_STATUS_FEATURE_ABORT `. + + If the transmitter message is ``CEC_MSG_INITIATE_ARC`` then the ``reply`` + values ``CEC_MSG_REPORT_ARC_INITIATED`` and ``CEC_MSG_REPORT_ARC_TERMINATED`` + are processed differently: either value will match both possible replies. + The reason is that the ``CEC_MSG_INITIATE_ARC`` message is the only CEC + message that has two possible replies other than Feature Abort. The + ``reply`` field will be updated with the actual reply so that it is + synchronized with the contents of the received message. * - __u8 - ``rx_status`` - The status bits of the received message. See diff --git a/drivers/staging/media/cec/TODO b/drivers/staging/media/cec/TODO index ce69001b0428..5a4cfdf8d15e 100644 --- a/drivers/staging/media/cec/TODO +++ b/drivers/staging/media/cec/TODO @@ -1,18 +1,5 @@ -The reason why cec.c is still in staging is that I would like -to have a bit more confidence in the uABI. The kABI is fine, -no problem there, but I would like to let the public API mature -a bit. +TODOs: -Once I'm confident that I didn't miss anything then the cec.c source -can move to drivers/media and the linux/cec.h and linux/cec-funcs.h -headers can move to uapi/linux and added to uapi/linux/Kbuild to make -them public. - -Hopefully this will happen later in 2016. - -Other TODOs: - -- There are two possible replies to CEC_MSG_INITIATE_ARC. How to handle that? - Should CEC_LOG_ADDR_TYPE_SPECIFIC be replaced by TYPE_2ND_TV and TYPE_PROCESSOR? And also TYPE_SWITCH and TYPE_CDC_ONLY in addition to the TYPE_UNREGISTERED? This should give the framework more information about the device type diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c index 93b53e602e48..a65d8667b78e 100644 --- a/drivers/staging/media/cec/cec-adap.c +++ b/drivers/staging/media/cec/cec-adap.c @@ -958,6 +958,18 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) list_for_each_entry(data, &adap->wait_queue, list) { struct cec_msg *dst = &data->msg; + /* + * The *only* CEC message that has two possible replies + * is CEC_MSG_INITIATE_ARC. + * In this case allow either of the two replies. + */ + if (!abort && dst->msg[1] == CEC_MSG_INITIATE_ARC && + (cmd == CEC_MSG_REPORT_ARC_INITIATED || + cmd == CEC_MSG_REPORT_ARC_TERMINATED) && + (dst->reply == CEC_MSG_REPORT_ARC_INITIATED || + dst->reply == CEC_MSG_REPORT_ARC_TERMINATED)) + dst->reply = cmd; + /* Does the command match? */ if ((abort && cmd != dst->msg[1]) || (!abort && cmd != dst->reply)) -- cgit v1.2.3 From a69a168a1bd470cb8a8c5f2ff4b54463de615226 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 2 Nov 2016 07:41:41 -0200 Subject: [media] cec: add proper support for CDC-Only CEC devices CDC-Only CEC devices are CEC devices that can only handle CDC messages, all other messages are ignored. Add a flag to signal that this is a CDC-Only device and act accordingly. Also add helper functions to identify if a CEC device is configured as a CDC-Only device, a second TV, a switch or a processor, since these variations cannot be determined by the logical address alone. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/cec/TODO | 4 --- drivers/staging/media/cec/cec-adap.c | 31 ++++++++++++++++++++- drivers/staging/media/cec/cec-api.c | 9 ++++++- include/linux/cec.h | 52 ++++++++++++++++++++++++++++++++++++ 4 files changed, 90 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/cec/TODO b/drivers/staging/media/cec/TODO index 5a4cfdf8d15e..504d35c7ae95 100644 --- a/drivers/staging/media/cec/TODO +++ b/drivers/staging/media/cec/TODO @@ -1,9 +1,5 @@ TODOs: -- Should CEC_LOG_ADDR_TYPE_SPECIFIC be replaced by TYPE_2ND_TV and TYPE_PROCESSOR? - And also TYPE_SWITCH and TYPE_CDC_ONLY in addition to the TYPE_UNREGISTERED? - This should give the framework more information about the device type - since SPECIFIC and UNREGISTERED give no useful information. - Once this is out of staging this should no longer be a separate config option, instead it should be selected by drivers that want it. - Revisit the IS_REACHABLE(RC_CORE): perhaps the RC_CORE support should diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c index a65d8667b78e..054cd06e2247 100644 --- a/drivers/staging/media/cec/cec-adap.c +++ b/drivers/staging/media/cec/cec-adap.c @@ -1233,7 +1233,8 @@ configured: mutex_unlock(&adap->lock); for (i = 0; i < las->num_log_addrs; i++) { - if (las->log_addr[i] == CEC_LOG_ADDR_INVALID) + if (las->log_addr[i] == CEC_LOG_ADDR_INVALID || + (las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY)) continue; /* @@ -1355,6 +1356,29 @@ int __cec_s_log_addrs(struct cec_adapter *adap, return 0; } + if (log_addrs->flags & CEC_LOG_ADDRS_FL_CDC_ONLY) { + /* + * Sanitize log_addrs fields if a CDC-Only device is + * requested. + */ + log_addrs->num_log_addrs = 1; + log_addrs->osd_name[0] = '\0'; + log_addrs->vendor_id = CEC_VENDOR_ID_NONE; + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; + /* + * This is just an internal convention since a CDC-Only device + * doesn't have to be a switch. But switches already use + * unregistered, so it makes some kind of sense to pick this + * as the primary device. Since a CDC-Only device never sends + * any 'normal' CEC messages this primary device type is never + * sent over the CEC bus. + */ + log_addrs->primary_device_type[0] = CEC_OP_PRIM_DEVTYPE_SWITCH; + log_addrs->all_device_types[0] = 0; + log_addrs->features[0][0] = 0; + log_addrs->features[0][1] = 0; + } + /* Ensure the osd name is 0-terminated */ log_addrs->osd_name[sizeof(log_addrs->osd_name) - 1] = '\0'; @@ -1575,6 +1599,11 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, dprintk(1, "cec_receive_notify: %*ph\n", msg->len, msg->msg); + /* If this is a CDC-Only device, then ignore any non-CDC messages */ + if (cec_is_cdc_only(&adap->log_addrs) && + msg->msg[1] != CEC_MSG_CDC_MESSAGE) + return 0; + if (adap->ops->received) { /* Allow drivers to process the message first */ if (adap->ops->received(adap, msg) != -ENOMSG) diff --git a/drivers/staging/media/cec/cec-api.c b/drivers/staging/media/cec/cec-api.c index 54148a6b3326..d4bc4ee2c6e5 100644 --- a/drivers/staging/media/cec/cec-api.c +++ b/drivers/staging/media/cec/cec-api.c @@ -163,7 +163,8 @@ static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, if (copy_from_user(&log_addrs, parg, sizeof(log_addrs))) return -EFAULT; log_addrs.flags &= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK | - CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU; + CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU | + CEC_LOG_ADDRS_FL_CDC_ONLY; mutex_lock(&adap->lock); if (!adap->is_configuring && (!log_addrs.num_log_addrs || !adap->is_configured) && @@ -190,6 +191,12 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, return -ENOTTY; if (copy_from_user(&msg, parg, sizeof(msg))) return -EFAULT; + + /* A CDC-Only device can only send CDC messages */ + if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && + (msg.len == 1 || msg.msg[1] != CEC_MSG_CDC_MESSAGE)) + return -EINVAL; + msg.flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; mutex_lock(&adap->lock); if (!adap->is_configured) diff --git a/include/linux/cec.h b/include/linux/cec.h index 3f2f076027b1..9c87711c0e1c 100644 --- a/include/linux/cec.h +++ b/include/linux/cec.h @@ -396,6 +396,8 @@ struct cec_log_addrs { #define CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK (1 << 0) /* Passthrough RC messages to the input subsystem */ #define CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU (1 << 1) +/* CDC-Only device: supports only CDC messages */ +#define CEC_LOG_ADDRS_FL_CDC_ONLY (1 << 2) /* Events */ @@ -1016,4 +1018,54 @@ struct cec_event { #define CEC_OP_HPD_ERROR_OTHER 3 #define CEC_OP_HPD_ERROR_NONE_NO_VIDEO 4 +/* End of Messages */ + +/* Helper functions to identify the 'special' CEC devices */ + +static inline bool cec_is_2nd_tv(const struct cec_log_addrs *las) +{ + /* + * It is a second TV if the logical address is 14 or 15 and the + * primary device type is a TV. + */ + return las->num_log_addrs && + las->log_addr[0] >= CEC_LOG_ADDR_SPECIFIC && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_TV; +} + +static inline bool cec_is_processor(const struct cec_log_addrs *las) +{ + /* + * It is a processor if the logical address is 12-15 and the + * primary device type is a Processor. + */ + return las->num_log_addrs && + las->log_addr[0] >= CEC_LOG_ADDR_BACKUP_1 && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_PROCESSOR; +} + +static inline bool cec_is_switch(const struct cec_log_addrs *las) +{ + /* + * It is a switch if the logical address is 15 and the + * primary device type is a Switch and the CDC-Only flag is not set. + */ + return las->num_log_addrs == 1 && + las->log_addr[0] == CEC_LOG_ADDR_UNREGISTERED && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH && + !(las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY); +} + +static inline bool cec_is_cdc_only(const struct cec_log_addrs *las) +{ + /* + * It is a CDC-only device if the logical address is 15 and the + * primary device type is a Switch and the CDC-Only flag is set. + */ + return las->num_log_addrs == 1 && + las->log_addr[0] == CEC_LOG_ADDR_UNREGISTERED && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH && + (las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY); +} + #endif -- cgit v1.2.3 From 0dbacebede1e4e44bf500f94d692fad05eb2c293 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 2 Nov 2016 08:25:28 -0200 Subject: [media] cec: move the CEC framework out of staging and to media The last open issues have been addressed, so it is time to move this out of staging and into the mainline and to move the public cec headers to include/uapi/linux. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/Makefile | 2 +- drivers/media/Kconfig | 16 + drivers/media/Makefile | 4 + drivers/media/cec/Makefile | 5 + drivers/media/cec/cec-adap.c | 1856 ++++++++++++++++++++++++++++ drivers/media/cec/cec-api.c | 588 +++++++++ drivers/media/cec/cec-core.c | 411 +++++++ drivers/media/cec/cec-priv.h | 56 + drivers/media/i2c/Kconfig | 6 +- drivers/media/platform/vivid/Kconfig | 2 +- drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/cec/Kconfig | 12 - drivers/staging/media/cec/Makefile | 5 - drivers/staging/media/cec/TODO | 9 - drivers/staging/media/cec/cec-adap.c | 1856 ---------------------------- drivers/staging/media/cec/cec-api.c | 588 --------- drivers/staging/media/cec/cec-core.c | 411 ------- drivers/staging/media/cec/cec-priv.h | 56 - drivers/staging/media/pulse8-cec/Kconfig | 2 +- drivers/staging/media/s5p-cec/Kconfig | 2 +- drivers/staging/media/st-cec/Kconfig | 2 +- include/linux/cec-funcs.h | 1971 ------------------------------ include/linux/cec.h | 1071 ---------------- include/media/cec.h | 2 +- include/uapi/linux/Kbuild | 2 + include/uapi/linux/cec-funcs.h | 1965 +++++++++++++++++++++++++++++ include/uapi/linux/cec.h | 1065 ++++++++++++++++ 28 files changed, 5977 insertions(+), 5991 deletions(-) create mode 100644 drivers/media/cec/Makefile create mode 100644 drivers/media/cec/cec-adap.c create mode 100644 drivers/media/cec/cec-api.c create mode 100644 drivers/media/cec/cec-core.c create mode 100644 drivers/media/cec/cec-priv.h delete mode 100644 drivers/staging/media/cec/Kconfig delete mode 100644 drivers/staging/media/cec/Makefile delete mode 100644 drivers/staging/media/cec/TODO delete mode 100644 drivers/staging/media/cec/cec-adap.c delete mode 100644 drivers/staging/media/cec/cec-api.c delete mode 100644 drivers/staging/media/cec/cec-core.c delete mode 100644 drivers/staging/media/cec/cec-priv.h delete mode 100644 include/linux/cec-funcs.h delete mode 100644 include/linux/cec.h create mode 100644 include/uapi/linux/cec-funcs.h create mode 100644 include/uapi/linux/cec.h (limited to 'drivers') diff --git a/Documentation/media/Makefile b/Documentation/media/Makefile index a7fb35291f6c..61afa052c501 100644 --- a/Documentation/media/Makefile +++ b/Documentation/media/Makefile @@ -51,7 +51,7 @@ $(BUILDDIR)/videodev2.h.rst: ${UAPI}/videodev2.h ${PARSER} $(SRC_DIR)/videodev2. $(BUILDDIR)/media.h.rst: ${UAPI}/media.h ${PARSER} $(SRC_DIR)/media.h.rst.exceptions @$($(quiet)gen_rst) -$(BUILDDIR)/cec.h.rst: ${KAPI}/cec.h ${PARSER} $(SRC_DIR)/cec.h.rst.exceptions +$(BUILDDIR)/cec.h.rst: ${UAPI}/cec.h ${PARSER} $(SRC_DIR)/cec.h.rst.exceptions @$($(quiet)gen_rst) $(BUILDDIR)/lirc.h.rst: ${UAPI}/lirc.h ${PARSER} $(SRC_DIR)/lirc.h.rst.exceptions diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index 7b8540291217..bc643cbf813e 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -80,6 +80,22 @@ config MEDIA_RC_SUPPORT Say Y when you have a TV or an IR device. +config MEDIA_CEC_SUPPORT + bool "HDMI CEC support" + select MEDIA_CEC_EDID + ---help--- + Enable support for HDMI CEC (Consumer Electronics Control), + which is an optional HDMI feature. + + Say Y when you have an HDMI receiver, transmitter or a USB CEC + adapter that supports HDMI CEC. + +config MEDIA_CEC_DEBUG + bool "HDMI CEC debugfs interface" + depends on MEDIA_CEC_SUPPORT && DEBUG_FS + ---help--- + Turns on the DebugFS interface for CEC devices. + config MEDIA_CEC_EDID bool diff --git a/drivers/media/Makefile b/drivers/media/Makefile index 0deaa93efdee..d87ccb8eeabe 100644 --- a/drivers/media/Makefile +++ b/drivers/media/Makefile @@ -6,6 +6,10 @@ ifeq ($(CONFIG_MEDIA_CEC_EDID),y) obj-$(CONFIG_MEDIA_SUPPORT) += cec-edid.o endif +ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y) + obj-$(CONFIG_MEDIA_SUPPORT) += cec/ +endif + media-objs := media-device.o media-devnode.o media-entity.o # diff --git a/drivers/media/cec/Makefile b/drivers/media/cec/Makefile new file mode 100644 index 000000000000..d6686337275f --- /dev/null +++ b/drivers/media/cec/Makefile @@ -0,0 +1,5 @@ +cec-objs := cec-core.o cec-adap.o cec-api.o + +ifeq ($(CONFIG_MEDIA_CEC_SUPPORT),y) + obj-$(CONFIG_MEDIA_SUPPORT) += cec.o +endif diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c new file mode 100644 index 000000000000..054cd06e2247 --- /dev/null +++ b/drivers/media/cec/cec-adap.c @@ -0,0 +1,1856 @@ +/* + * cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cec-priv.h" + +static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx); +static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx); + +/* + * 400 ms is the time it takes for one 16 byte message to be + * transferred and 5 is the maximum number of retries. Add + * another 100 ms as a margin. So if the transmit doesn't + * finish before that time something is really wrong and we + * have to time out. + * + * This is a sign that something it really wrong and a warning + * will be issued. + */ +#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) + +#define call_op(adap, op, arg...) \ + (adap->ops->op ? adap->ops->op(adap, ## arg) : 0) + +#define call_void_op(adap, op, arg...) \ + do { \ + if (adap->ops->op) \ + adap->ops->op(adap, ## arg); \ + } while (0) + +static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr) +{ + int i; + + for (i = 0; i < adap->log_addrs.num_log_addrs; i++) + if (adap->log_addrs.log_addr[i] == log_addr) + return i; + return -1; +} + +static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr) +{ + int i = cec_log_addr2idx(adap, log_addr); + + return adap->log_addrs.primary_device_type[i < 0 ? 0 : i]; +} + +/* + * Queue a new event for this filehandle. If ts == 0, then set it + * to the current time. + * + * The two events that are currently defined do not need to keep track + * of intermediate events, so no actual queue of events is needed, + * instead just store the latest state and the total number of lost + * messages. + * + * Should new events be added in the future that require intermediate + * results to be queued as well, then a proper queue data structure is + * required. But until then, just keep it simple. + */ +void cec_queue_event_fh(struct cec_fh *fh, + const struct cec_event *new_ev, u64 ts) +{ + struct cec_event *ev = &fh->events[new_ev->event - 1]; + + if (ts == 0) + ts = ktime_get_ns(); + + mutex_lock(&fh->lock); + if (new_ev->event == CEC_EVENT_LOST_MSGS && + fh->pending_events & (1 << new_ev->event)) { + /* + * If there is already a lost_msgs event, then just + * update the lost_msgs count. This effectively + * merges the old and new events into one. + */ + ev->lost_msgs.lost_msgs += new_ev->lost_msgs.lost_msgs; + goto unlock; + } + + /* + * Intermediate states are not interesting, so just + * overwrite any older event. + */ + *ev = *new_ev; + ev->ts = ts; + fh->pending_events |= 1 << new_ev->event; + +unlock: + mutex_unlock(&fh->lock); + wake_up_interruptible(&fh->wait); +} + +/* Queue a new event for all open filehandles. */ +static void cec_queue_event(struct cec_adapter *adap, + const struct cec_event *ev) +{ + u64 ts = ktime_get_ns(); + struct cec_fh *fh; + + mutex_lock(&adap->devnode.lock); + list_for_each_entry(fh, &adap->devnode.fhs, list) + cec_queue_event_fh(fh, ev, ts); + mutex_unlock(&adap->devnode.lock); +} + +/* + * Queue a new message for this filehandle. If there is no more room + * in the queue, then send the LOST_MSGS event instead. + */ +static void cec_queue_msg_fh(struct cec_fh *fh, const struct cec_msg *msg) +{ + static const struct cec_event ev_lost_msg = { + .ts = 0, + .event = CEC_EVENT_LOST_MSGS, + .flags = 0, + { + .lost_msgs.lost_msgs = 1, + }, + }; + struct cec_msg_entry *entry; + + mutex_lock(&fh->lock); + entry = kmalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + goto lost_msgs; + + entry->msg = *msg; + /* Add new msg at the end of the queue */ + list_add_tail(&entry->list, &fh->msgs); + + /* + * if the queue now has more than CEC_MAX_MSG_RX_QUEUE_SZ + * messages, drop the oldest one and send a lost message event. + */ + if (fh->queued_msgs == CEC_MAX_MSG_RX_QUEUE_SZ) { + list_del(&entry->list); + goto lost_msgs; + } + fh->queued_msgs++; + mutex_unlock(&fh->lock); + wake_up_interruptible(&fh->wait); + return; + +lost_msgs: + mutex_unlock(&fh->lock); + cec_queue_event_fh(fh, &ev_lost_msg, 0); +} + +/* + * Queue the message for those filehandles that are in monitor mode. + * If valid_la is true (this message is for us or was sent by us), + * then pass it on to any monitoring filehandle. If this message + * isn't for us or from us, then only give it to filehandles that + * are in MONITOR_ALL mode. + * + * This can only happen if the CEC_CAP_MONITOR_ALL capability is + * set and the CEC adapter was placed in 'monitor all' mode. + */ +static void cec_queue_msg_monitor(struct cec_adapter *adap, + const struct cec_msg *msg, + bool valid_la) +{ + struct cec_fh *fh; + u32 monitor_mode = valid_la ? CEC_MODE_MONITOR : + CEC_MODE_MONITOR_ALL; + + mutex_lock(&adap->devnode.lock); + list_for_each_entry(fh, &adap->devnode.fhs, list) { + if (fh->mode_follower >= monitor_mode) + cec_queue_msg_fh(fh, msg); + } + mutex_unlock(&adap->devnode.lock); +} + +/* + * Queue the message for follower filehandles. + */ +static void cec_queue_msg_followers(struct cec_adapter *adap, + const struct cec_msg *msg) +{ + struct cec_fh *fh; + + mutex_lock(&adap->devnode.lock); + list_for_each_entry(fh, &adap->devnode.fhs, list) { + if (fh->mode_follower == CEC_MODE_FOLLOWER) + cec_queue_msg_fh(fh, msg); + } + mutex_unlock(&adap->devnode.lock); +} + +/* Notify userspace of an adapter state change. */ +static void cec_post_state_event(struct cec_adapter *adap) +{ + struct cec_event ev = { + .event = CEC_EVENT_STATE_CHANGE, + }; + + ev.state_change.phys_addr = adap->phys_addr; + ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; + cec_queue_event(adap, &ev); +} + +/* + * A CEC transmit (and a possible wait for reply) completed. + * If this was in blocking mode, then complete it, otherwise + * queue the message for userspace to dequeue later. + * + * This function is called with adap->lock held. + */ +static void cec_data_completed(struct cec_data *data) +{ + /* + * Delete this transmit from the filehandle's xfer_list since + * we're done with it. + * + * Note that if the filehandle is closed before this transmit + * finished, then the release() function will set data->fh to NULL. + * Without that we would be referring to a closed filehandle. + */ + if (data->fh) + list_del(&data->xfer_list); + + if (data->blocking) { + /* + * Someone is blocking so mark the message as completed + * and call complete. + */ + data->completed = true; + complete(&data->c); + } else { + /* + * No blocking, so just queue the message if needed and + * free the memory. + */ + if (data->fh) + cec_queue_msg_fh(data->fh, &data->msg); + kfree(data); + } +} + +/* + * A pending CEC transmit needs to be cancelled, either because the CEC + * adapter is disabled or the transmit takes an impossibly long time to + * finish. + * + * This function is called with adap->lock held. + */ +static void cec_data_cancel(struct cec_data *data) +{ + /* + * It's either the current transmit, or it is a pending + * transmit. Take the appropriate action to clear it. + */ + if (data->adap->transmitting == data) { + data->adap->transmitting = NULL; + } else { + list_del_init(&data->list); + if (!(data->msg.tx_status & CEC_TX_STATUS_OK)) + data->adap->transmit_queue_sz--; + } + + /* Mark it as an error */ + data->msg.tx_ts = ktime_get_ns(); + data->msg.tx_status = CEC_TX_STATUS_ERROR | + CEC_TX_STATUS_MAX_RETRIES; + data->attempts = 0; + data->msg.tx_error_cnt = 1; + /* Queue transmitted message for monitoring purposes */ + cec_queue_msg_monitor(data->adap, &data->msg, 1); + + cec_data_completed(data); +} + +/* + * Main CEC state machine + * + * Wait until the thread should be stopped, or we are not transmitting and + * a new transmit message is queued up, in which case we start transmitting + * that message. When the adapter finished transmitting the message it will + * call cec_transmit_done(). + * + * If the adapter is disabled, then remove all queued messages instead. + * + * If the current transmit times out, then cancel that transmit. + */ +int cec_thread_func(void *_adap) +{ + struct cec_adapter *adap = _adap; + + for (;;) { + unsigned int signal_free_time; + struct cec_data *data; + bool timeout = false; + u8 attempts; + + if (adap->transmitting) { + int err; + + /* + * We are transmitting a message, so add a timeout + * to prevent the state machine to get stuck waiting + * for this message to finalize and add a check to + * see if the adapter is disabled in which case the + * transmit should be canceled. + */ + err = wait_event_interruptible_timeout(adap->kthread_waitq, + kthread_should_stop() || + (!adap->is_configured && !adap->is_configuring) || + (!adap->transmitting && + !list_empty(&adap->transmit_queue)), + msecs_to_jiffies(CEC_XFER_TIMEOUT_MS)); + timeout = err == 0; + } else { + /* Otherwise we just wait for something to happen. */ + wait_event_interruptible(adap->kthread_waitq, + kthread_should_stop() || + (!adap->transmitting && + !list_empty(&adap->transmit_queue))); + } + + mutex_lock(&adap->lock); + + if ((!adap->is_configured && !adap->is_configuring) || + kthread_should_stop()) { + /* + * If the adapter is disabled, or we're asked to stop, + * then cancel any pending transmits. + */ + while (!list_empty(&adap->transmit_queue)) { + data = list_first_entry(&adap->transmit_queue, + struct cec_data, list); + cec_data_cancel(data); + } + if (adap->transmitting) + cec_data_cancel(adap->transmitting); + + /* + * Cancel the pending timeout work. We have to unlock + * the mutex when flushing the work since + * cec_wait_timeout() will take it. This is OK since + * no new entries can be added to wait_queue as long + * as adap->transmitting is NULL, which it is due to + * the cec_data_cancel() above. + */ + while (!list_empty(&adap->wait_queue)) { + data = list_first_entry(&adap->wait_queue, + struct cec_data, list); + + if (!cancel_delayed_work(&data->work)) { + mutex_unlock(&adap->lock); + flush_scheduled_work(); + mutex_lock(&adap->lock); + } + cec_data_cancel(data); + } + goto unlock; + } + + if (adap->transmitting && timeout) { + /* + * If we timeout, then log that. This really shouldn't + * happen and is an indication of a faulty CEC adapter + * driver, or the CEC bus is in some weird state. + */ + dprintk(0, "message %*ph timed out!\n", + adap->transmitting->msg.len, + adap->transmitting->msg.msg); + /* Just give up on this. */ + cec_data_cancel(adap->transmitting); + goto unlock; + } + + /* + * If we are still transmitting, or there is nothing new to + * transmit, then just continue waiting. + */ + if (adap->transmitting || list_empty(&adap->transmit_queue)) + goto unlock; + + /* Get a new message to transmit */ + data = list_first_entry(&adap->transmit_queue, + struct cec_data, list); + list_del_init(&data->list); + adap->transmit_queue_sz--; + /* Make this the current transmitting message */ + adap->transmitting = data; + + /* + * Suggested number of attempts as per the CEC 2.0 spec: + * 4 attempts is the default, except for 'secondary poll + * messages', i.e. poll messages not sent during the adapter + * configuration phase when it allocates logical addresses. + */ + if (data->msg.len == 1 && adap->is_configured) + attempts = 2; + else + attempts = 4; + + /* Set the suggested signal free time */ + if (data->attempts) { + /* should be >= 3 data bit periods for a retry */ + signal_free_time = CEC_SIGNAL_FREE_TIME_RETRY; + } else if (data->new_initiator) { + /* should be >= 5 data bit periods for new initiator */ + signal_free_time = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR; + } else { + /* + * should be >= 7 data bit periods for sending another + * frame immediately after another. + */ + signal_free_time = CEC_SIGNAL_FREE_TIME_NEXT_XFER; + } + if (data->attempts == 0) + data->attempts = attempts; + + /* Tell the adapter to transmit, cancel on error */ + if (adap->ops->adap_transmit(adap, data->attempts, + signal_free_time, &data->msg)) + cec_data_cancel(data); + +unlock: + mutex_unlock(&adap->lock); + + if (kthread_should_stop()) + break; + } + return 0; +} + +/* + * Called by the CEC adapter if a transmit finished. + */ +void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, + u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt) +{ + struct cec_data *data; + struct cec_msg *msg; + u64 ts = ktime_get_ns(); + + dprintk(2, "cec_transmit_done %02x\n", status); + mutex_lock(&adap->lock); + data = adap->transmitting; + if (!data) { + /* + * This can happen if a transmit was issued and the cable is + * unplugged while the transmit is ongoing. Ignore this + * transmit in that case. + */ + dprintk(1, "cec_transmit_done without an ongoing transmit!\n"); + goto unlock; + } + + msg = &data->msg; + + /* Drivers must fill in the status! */ + WARN_ON(status == 0); + msg->tx_ts = ts; + msg->tx_status |= status; + msg->tx_arb_lost_cnt += arb_lost_cnt; + msg->tx_nack_cnt += nack_cnt; + msg->tx_low_drive_cnt += low_drive_cnt; + msg->tx_error_cnt += error_cnt; + + /* Mark that we're done with this transmit */ + adap->transmitting = NULL; + + /* + * If there are still retry attempts left and there was an error and + * the hardware didn't signal that it retried itself (by setting + * CEC_TX_STATUS_MAX_RETRIES), then we will retry ourselves. + */ + if (data->attempts > 1 && + !(status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK))) { + /* Retry this message */ + data->attempts--; + /* Add the message in front of the transmit queue */ + list_add(&data->list, &adap->transmit_queue); + adap->transmit_queue_sz++; + goto wake_thread; + } + + data->attempts = 0; + + /* Always set CEC_TX_STATUS_MAX_RETRIES on error */ + if (!(status & CEC_TX_STATUS_OK)) + msg->tx_status |= CEC_TX_STATUS_MAX_RETRIES; + + /* Queue transmitted message for monitoring purposes */ + cec_queue_msg_monitor(adap, msg, 1); + + if ((status & CEC_TX_STATUS_OK) && adap->is_configured && + msg->timeout) { + /* + * Queue the message into the wait queue if we want to wait + * for a reply. + */ + list_add_tail(&data->list, &adap->wait_queue); + schedule_delayed_work(&data->work, + msecs_to_jiffies(msg->timeout)); + } else { + /* Otherwise we're done */ + cec_data_completed(data); + } + +wake_thread: + /* + * Wake up the main thread to see if another message is ready + * for transmitting or to retry the current message. + */ + wake_up_interruptible(&adap->kthread_waitq); +unlock: + mutex_unlock(&adap->lock); +} +EXPORT_SYMBOL_GPL(cec_transmit_done); + +/* + * Called when waiting for a reply times out. + */ +static void cec_wait_timeout(struct work_struct *work) +{ + struct cec_data *data = container_of(work, struct cec_data, work.work); + struct cec_adapter *adap = data->adap; + + mutex_lock(&adap->lock); + /* + * Sanity check in case the timeout and the arrival of the message + * happened at the same time. + */ + if (list_empty(&data->list)) + goto unlock; + + /* Mark the message as timed out */ + list_del_init(&data->list); + data->msg.rx_ts = ktime_get_ns(); + data->msg.rx_status = CEC_RX_STATUS_TIMEOUT; + cec_data_completed(data); +unlock: + mutex_unlock(&adap->lock); +} + +/* + * Transmit a message. The fh argument may be NULL if the transmit is not + * associated with a specific filehandle. + * + * This function is called with adap->lock held. + */ +int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, + struct cec_fh *fh, bool block) +{ + struct cec_data *data; + u8 last_initiator = 0xff; + unsigned int timeout; + int res = 0; + + msg->rx_ts = 0; + msg->tx_ts = 0; + msg->rx_status = 0; + msg->tx_status = 0; + msg->tx_arb_lost_cnt = 0; + msg->tx_nack_cnt = 0; + msg->tx_low_drive_cnt = 0; + msg->tx_error_cnt = 0; + msg->sequence = ++adap->sequence; + if (!msg->sequence) + msg->sequence = ++adap->sequence; + + if (msg->reply && msg->timeout == 0) { + /* Make sure the timeout isn't 0. */ + msg->timeout = 1000; + } + + /* Sanity checks */ + if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { + dprintk(1, "cec_transmit_msg: invalid length %d\n", msg->len); + return -EINVAL; + } + if (msg->timeout && msg->len == 1) { + dprintk(1, "cec_transmit_msg: can't reply for poll msg\n"); + return -EINVAL; + } + memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); + if (msg->len == 1) { + if (cec_msg_initiator(msg) != 0xf || + cec_msg_destination(msg) == 0xf) { + dprintk(1, "cec_transmit_msg: invalid poll message\n"); + return -EINVAL; + } + if (cec_has_log_addr(adap, cec_msg_destination(msg))) { + /* + * If the destination is a logical address our adapter + * has already claimed, then just NACK this. + * It depends on the hardware what it will do with a + * POLL to itself (some OK this), so it is just as + * easy to handle it here so the behavior will be + * consistent. + */ + msg->tx_ts = ktime_get_ns(); + msg->tx_status = CEC_TX_STATUS_NACK | + CEC_TX_STATUS_MAX_RETRIES; + msg->tx_nack_cnt = 1; + return 0; + } + } + if (msg->len > 1 && !cec_msg_is_broadcast(msg) && + cec_has_log_addr(adap, cec_msg_destination(msg))) { + dprintk(1, "cec_transmit_msg: destination is the adapter itself\n"); + return -EINVAL; + } + if (cec_msg_initiator(msg) != 0xf && + !cec_has_log_addr(adap, cec_msg_initiator(msg))) { + dprintk(1, "cec_transmit_msg: initiator has unknown logical address %d\n", + cec_msg_initiator(msg)); + return -EINVAL; + } + if (!adap->is_configured && !adap->is_configuring) + return -ENONET; + + if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) + return -EBUSY; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { + msg->msg[2] = adap->phys_addr >> 8; + msg->msg[3] = adap->phys_addr & 0xff; + } + + if (msg->timeout) + dprintk(2, "cec_transmit_msg: %*ph (wait for 0x%02x%s)\n", + msg->len, msg->msg, msg->reply, !block ? ", nb" : ""); + else + dprintk(2, "cec_transmit_msg: %*ph%s\n", + msg->len, msg->msg, !block ? " (nb)" : ""); + + data->msg = *msg; + data->fh = fh; + data->adap = adap; + data->blocking = block; + + /* + * Determine if this message follows a message from the same + * initiator. Needed to determine the free signal time later on. + */ + if (msg->len > 1) { + if (!(list_empty(&adap->transmit_queue))) { + const struct cec_data *last; + + last = list_last_entry(&adap->transmit_queue, + const struct cec_data, list); + last_initiator = cec_msg_initiator(&last->msg); + } else if (adap->transmitting) { + last_initiator = + cec_msg_initiator(&adap->transmitting->msg); + } + } + data->new_initiator = last_initiator != cec_msg_initiator(msg); + init_completion(&data->c); + INIT_DELAYED_WORK(&data->work, cec_wait_timeout); + + if (fh) + list_add_tail(&data->xfer_list, &fh->xfer_list); + list_add_tail(&data->list, &adap->transmit_queue); + adap->transmit_queue_sz++; + if (!adap->transmitting) + wake_up_interruptible(&adap->kthread_waitq); + + /* All done if we don't need to block waiting for completion */ + if (!block) + return 0; + + /* + * If we don't get a completion before this time something is really + * wrong and we time out. + */ + timeout = CEC_XFER_TIMEOUT_MS; + /* Add the requested timeout if we have to wait for a reply as well */ + if (msg->timeout) + timeout += msg->timeout; + + /* + * Release the lock and wait, retake the lock afterwards. + */ + mutex_unlock(&adap->lock); + res = wait_for_completion_killable_timeout(&data->c, + msecs_to_jiffies(timeout)); + mutex_lock(&adap->lock); + + if (data->completed) { + /* The transmit completed (possibly with an error) */ + *msg = data->msg; + kfree(data); + return 0; + } + /* + * The wait for completion timed out or was interrupted, so mark this + * as non-blocking and disconnect from the filehandle since it is + * still 'in flight'. When it finally completes it will just drop the + * result silently. + */ + data->blocking = false; + if (data->fh) + list_del(&data->xfer_list); + data->fh = NULL; + + if (res == 0) { /* timed out */ + /* Check if the reply or the transmit failed */ + if (msg->timeout && (msg->tx_status & CEC_TX_STATUS_OK)) + msg->rx_status = CEC_RX_STATUS_TIMEOUT; + else + msg->tx_status = CEC_TX_STATUS_MAX_RETRIES; + } + return res > 0 ? 0 : res; +} + +/* Helper function to be used by drivers and this framework. */ +int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg, + bool block) +{ + int ret; + + mutex_lock(&adap->lock); + ret = cec_transmit_msg_fh(adap, msg, NULL, block); + mutex_unlock(&adap->lock); + return ret; +} +EXPORT_SYMBOL_GPL(cec_transmit_msg); + +/* + * I don't like forward references but without this the low-level + * cec_received_msg() function would come after a bunch of high-level + * CEC protocol handling functions. That was very confusing. + */ +static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, + bool is_reply); + +#define DIRECTED 0x80 +#define BCAST1_4 0x40 +#define BCAST2_0 0x20 /* broadcast only allowed for >= 2.0 */ +#define BCAST (BCAST1_4 | BCAST2_0) +#define BOTH (BCAST | DIRECTED) + +/* + * Specify minimum length and whether the message is directed, broadcast + * or both. Messages that do not match the criteria are ignored as per + * the CEC specification. + */ +static const u8 cec_msg_size[256] = { + [CEC_MSG_ACTIVE_SOURCE] = 4 | BCAST, + [CEC_MSG_IMAGE_VIEW_ON] = 2 | DIRECTED, + [CEC_MSG_TEXT_VIEW_ON] = 2 | DIRECTED, + [CEC_MSG_INACTIVE_SOURCE] = 4 | DIRECTED, + [CEC_MSG_REQUEST_ACTIVE_SOURCE] = 2 | BCAST, + [CEC_MSG_ROUTING_CHANGE] = 6 | BCAST, + [CEC_MSG_ROUTING_INFORMATION] = 4 | BCAST, + [CEC_MSG_SET_STREAM_PATH] = 4 | BCAST, + [CEC_MSG_STANDBY] = 2 | BOTH, + [CEC_MSG_RECORD_OFF] = 2 | DIRECTED, + [CEC_MSG_RECORD_ON] = 3 | DIRECTED, + [CEC_MSG_RECORD_STATUS] = 3 | DIRECTED, + [CEC_MSG_RECORD_TV_SCREEN] = 2 | DIRECTED, + [CEC_MSG_CLEAR_ANALOGUE_TIMER] = 13 | DIRECTED, + [CEC_MSG_CLEAR_DIGITAL_TIMER] = 16 | DIRECTED, + [CEC_MSG_CLEAR_EXT_TIMER] = 13 | DIRECTED, + [CEC_MSG_SET_ANALOGUE_TIMER] = 13 | DIRECTED, + [CEC_MSG_SET_DIGITAL_TIMER] = 16 | DIRECTED, + [CEC_MSG_SET_EXT_TIMER] = 13 | DIRECTED, + [CEC_MSG_SET_TIMER_PROGRAM_TITLE] = 2 | DIRECTED, + [CEC_MSG_TIMER_CLEARED_STATUS] = 3 | DIRECTED, + [CEC_MSG_TIMER_STATUS] = 3 | DIRECTED, + [CEC_MSG_CEC_VERSION] = 3 | DIRECTED, + [CEC_MSG_GET_CEC_VERSION] = 2 | DIRECTED, + [CEC_MSG_GIVE_PHYSICAL_ADDR] = 2 | DIRECTED, + [CEC_MSG_GET_MENU_LANGUAGE] = 2 | DIRECTED, + [CEC_MSG_REPORT_PHYSICAL_ADDR] = 5 | BCAST, + [CEC_MSG_SET_MENU_LANGUAGE] = 5 | BCAST, + [CEC_MSG_REPORT_FEATURES] = 6 | BCAST, + [CEC_MSG_GIVE_FEATURES] = 2 | DIRECTED, + [CEC_MSG_DECK_CONTROL] = 3 | DIRECTED, + [CEC_MSG_DECK_STATUS] = 3 | DIRECTED, + [CEC_MSG_GIVE_DECK_STATUS] = 3 | DIRECTED, + [CEC_MSG_PLAY] = 3 | DIRECTED, + [CEC_MSG_GIVE_TUNER_DEVICE_STATUS] = 3 | DIRECTED, + [CEC_MSG_SELECT_ANALOGUE_SERVICE] = 6 | DIRECTED, + [CEC_MSG_SELECT_DIGITAL_SERVICE] = 9 | DIRECTED, + [CEC_MSG_TUNER_DEVICE_STATUS] = 7 | DIRECTED, + [CEC_MSG_TUNER_STEP_DECREMENT] = 2 | DIRECTED, + [CEC_MSG_TUNER_STEP_INCREMENT] = 2 | DIRECTED, + [CEC_MSG_DEVICE_VENDOR_ID] = 5 | BCAST, + [CEC_MSG_GIVE_DEVICE_VENDOR_ID] = 2 | DIRECTED, + [CEC_MSG_VENDOR_COMMAND] = 2 | DIRECTED, + [CEC_MSG_VENDOR_COMMAND_WITH_ID] = 5 | BOTH, + [CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN] = 2 | BOTH, + [CEC_MSG_VENDOR_REMOTE_BUTTON_UP] = 2 | BOTH, + [CEC_MSG_SET_OSD_STRING] = 3 | DIRECTED, + [CEC_MSG_GIVE_OSD_NAME] = 2 | DIRECTED, + [CEC_MSG_SET_OSD_NAME] = 2 | DIRECTED, + [CEC_MSG_MENU_REQUEST] = 3 | DIRECTED, + [CEC_MSG_MENU_STATUS] = 3 | DIRECTED, + [CEC_MSG_USER_CONTROL_PRESSED] = 3 | DIRECTED, + [CEC_MSG_USER_CONTROL_RELEASED] = 2 | DIRECTED, + [CEC_MSG_GIVE_DEVICE_POWER_STATUS] = 2 | DIRECTED, + [CEC_MSG_REPORT_POWER_STATUS] = 3 | DIRECTED | BCAST2_0, + [CEC_MSG_FEATURE_ABORT] = 4 | DIRECTED, + [CEC_MSG_ABORT] = 2 | DIRECTED, + [CEC_MSG_GIVE_AUDIO_STATUS] = 2 | DIRECTED, + [CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS] = 2 | DIRECTED, + [CEC_MSG_REPORT_AUDIO_STATUS] = 3 | DIRECTED, + [CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, + [CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, + [CEC_MSG_SET_SYSTEM_AUDIO_MODE] = 3 | BOTH, + [CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST] = 2 | DIRECTED, + [CEC_MSG_SYSTEM_AUDIO_MODE_STATUS] = 3 | DIRECTED, + [CEC_MSG_SET_AUDIO_RATE] = 3 | DIRECTED, + [CEC_MSG_INITIATE_ARC] = 2 | DIRECTED, + [CEC_MSG_REPORT_ARC_INITIATED] = 2 | DIRECTED, + [CEC_MSG_REPORT_ARC_TERMINATED] = 2 | DIRECTED, + [CEC_MSG_REQUEST_ARC_INITIATION] = 2 | DIRECTED, + [CEC_MSG_REQUEST_ARC_TERMINATION] = 2 | DIRECTED, + [CEC_MSG_TERMINATE_ARC] = 2 | DIRECTED, + [CEC_MSG_REQUEST_CURRENT_LATENCY] = 4 | BCAST, + [CEC_MSG_REPORT_CURRENT_LATENCY] = 7 | BCAST, + [CEC_MSG_CDC_MESSAGE] = 2 | BCAST, +}; + +/* Called by the CEC adapter if a message is received */ +void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) +{ + struct cec_data *data; + u8 msg_init = cec_msg_initiator(msg); + u8 msg_dest = cec_msg_destination(msg); + u8 cmd = msg->msg[1]; + bool is_reply = false; + bool valid_la = true; + u8 min_len = 0; + + if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE)) + return; + + msg->rx_ts = ktime_get_ns(); + msg->rx_status = CEC_RX_STATUS_OK; + msg->sequence = msg->reply = msg->timeout = 0; + msg->tx_status = 0; + msg->tx_ts = 0; + msg->flags = 0; + memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); + + mutex_lock(&adap->lock); + dprintk(2, "cec_received_msg: %*ph\n", msg->len, msg->msg); + + /* Check if this message was for us (directed or broadcast). */ + if (!cec_msg_is_broadcast(msg)) + valid_la = cec_has_log_addr(adap, msg_dest); + + /* + * Check if the length is not too short or if the message is a + * broadcast message where a directed message was expected or + * vice versa. If so, then the message has to be ignored (according + * to section CEC 7.3 and CEC 12.2). + */ + if (valid_la && msg->len > 1 && cec_msg_size[cmd]) { + u8 dir_fl = cec_msg_size[cmd] & BOTH; + + min_len = cec_msg_size[cmd] & 0x1f; + if (msg->len < min_len) + valid_la = false; + else if (!cec_msg_is_broadcast(msg) && !(dir_fl & DIRECTED)) + valid_la = false; + else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST1_4)) + valid_la = false; + else if (cec_msg_is_broadcast(msg) && + adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0 && + !(dir_fl & BCAST2_0)) + valid_la = false; + } + if (valid_la && min_len) { + /* These messages have special length requirements */ + switch (cmd) { + case CEC_MSG_TIMER_STATUS: + if (msg->msg[2] & 0x10) { + switch (msg->msg[2] & 0xf) { + case CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE: + case CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE: + if (msg->len < 5) + valid_la = false; + break; + } + } else if ((msg->msg[2] & 0xf) == CEC_OP_PROG_ERROR_DUPLICATE) { + if (msg->len < 5) + valid_la = false; + } + break; + case CEC_MSG_RECORD_ON: + switch (msg->msg[2]) { + case CEC_OP_RECORD_SRC_OWN: + break; + case CEC_OP_RECORD_SRC_DIGITAL: + if (msg->len < 10) + valid_la = false; + break; + case CEC_OP_RECORD_SRC_ANALOG: + if (msg->len < 7) + valid_la = false; + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + if (msg->len < 4) + valid_la = false; + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + if (msg->len < 5) + valid_la = false; + break; + } + break; + } + } + + /* It's a valid message and not a poll or CDC message */ + if (valid_la && msg->len > 1 && cmd != CEC_MSG_CDC_MESSAGE) { + bool abort = cmd == CEC_MSG_FEATURE_ABORT; + + /* The aborted command is in msg[2] */ + if (abort) + cmd = msg->msg[2]; + + /* + * Walk over all transmitted messages that are waiting for a + * reply. + */ + list_for_each_entry(data, &adap->wait_queue, list) { + struct cec_msg *dst = &data->msg; + + /* + * The *only* CEC message that has two possible replies + * is CEC_MSG_INITIATE_ARC. + * In this case allow either of the two replies. + */ + if (!abort && dst->msg[1] == CEC_MSG_INITIATE_ARC && + (cmd == CEC_MSG_REPORT_ARC_INITIATED || + cmd == CEC_MSG_REPORT_ARC_TERMINATED) && + (dst->reply == CEC_MSG_REPORT_ARC_INITIATED || + dst->reply == CEC_MSG_REPORT_ARC_TERMINATED)) + dst->reply = cmd; + + /* Does the command match? */ + if ((abort && cmd != dst->msg[1]) || + (!abort && cmd != dst->reply)) + continue; + + /* Does the addressing match? */ + if (msg_init != cec_msg_destination(dst) && + !cec_msg_is_broadcast(dst)) + continue; + + /* We got a reply */ + memcpy(dst->msg, msg->msg, msg->len); + dst->len = msg->len; + dst->rx_ts = msg->rx_ts; + dst->rx_status = msg->rx_status; + if (abort) + dst->rx_status |= CEC_RX_STATUS_FEATURE_ABORT; + msg->flags = dst->flags; + /* Remove it from the wait_queue */ + list_del_init(&data->list); + + /* Cancel the pending timeout work */ + if (!cancel_delayed_work(&data->work)) { + mutex_unlock(&adap->lock); + flush_scheduled_work(); + mutex_lock(&adap->lock); + } + /* + * Mark this as a reply, provided someone is still + * waiting for the answer. + */ + if (data->fh) + is_reply = true; + cec_data_completed(data); + break; + } + } + mutex_unlock(&adap->lock); + + /* Pass the message on to any monitoring filehandles */ + cec_queue_msg_monitor(adap, msg, valid_la); + + /* We're done if it is not for us or a poll message */ + if (!valid_la || msg->len <= 1) + return; + + if (adap->log_addrs.log_addr_mask == 0) + return; + + /* + * Process the message on the protocol level. If is_reply is true, + * then cec_receive_notify() won't pass on the reply to the listener(s) + * since that was already done by cec_data_completed() above. + */ + cec_receive_notify(adap, msg, is_reply); +} +EXPORT_SYMBOL_GPL(cec_received_msg); + +/* Logical Address Handling */ + +/* + * Attempt to claim a specific logical address. + * + * This function is called with adap->lock held. + */ +static int cec_config_log_addr(struct cec_adapter *adap, + unsigned int idx, + unsigned int log_addr) +{ + struct cec_log_addrs *las = &adap->log_addrs; + struct cec_msg msg = { }; + int err; + + if (cec_has_log_addr(adap, log_addr)) + return 0; + + /* Send poll message */ + msg.len = 1; + msg.msg[0] = 0xf0 | log_addr; + err = cec_transmit_msg_fh(adap, &msg, NULL, true); + + /* + * While trying to poll the physical address was reset + * and the adapter was unconfigured, so bail out. + */ + if (!adap->is_configuring) + return -EINTR; + + if (err) + return err; + + if (msg.tx_status & CEC_TX_STATUS_OK) + return 0; + + /* + * Message not acknowledged, so this logical + * address is free to use. + */ + err = adap->ops->adap_log_addr(adap, log_addr); + if (err) + return err; + + las->log_addr[idx] = log_addr; + las->log_addr_mask |= 1 << log_addr; + adap->phys_addrs[log_addr] = adap->phys_addr; + + dprintk(2, "claimed addr %d (%d)\n", log_addr, + las->primary_device_type[idx]); + return 1; +} + +/* + * Unconfigure the adapter: clear all logical addresses and send + * the state changed event. + * + * This function is called with adap->lock held. + */ +static void cec_adap_unconfigure(struct cec_adapter *adap) +{ + WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID)); + adap->log_addrs.log_addr_mask = 0; + adap->is_configuring = false; + adap->is_configured = false; + memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); + wake_up_interruptible(&adap->kthread_waitq); + cec_post_state_event(adap); +} + +/* + * Attempt to claim the required logical addresses. + */ +static int cec_config_thread_func(void *arg) +{ + /* The various LAs for each type of device */ + static const u8 tv_log_addrs[] = { + CEC_LOG_ADDR_TV, CEC_LOG_ADDR_SPECIFIC, + CEC_LOG_ADDR_INVALID + }; + static const u8 record_log_addrs[] = { + CEC_LOG_ADDR_RECORD_1, CEC_LOG_ADDR_RECORD_2, + CEC_LOG_ADDR_RECORD_3, + CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, + CEC_LOG_ADDR_INVALID + }; + static const u8 tuner_log_addrs[] = { + CEC_LOG_ADDR_TUNER_1, CEC_LOG_ADDR_TUNER_2, + CEC_LOG_ADDR_TUNER_3, CEC_LOG_ADDR_TUNER_4, + CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, + CEC_LOG_ADDR_INVALID + }; + static const u8 playback_log_addrs[] = { + CEC_LOG_ADDR_PLAYBACK_1, CEC_LOG_ADDR_PLAYBACK_2, + CEC_LOG_ADDR_PLAYBACK_3, + CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, + CEC_LOG_ADDR_INVALID + }; + static const u8 audiosystem_log_addrs[] = { + CEC_LOG_ADDR_AUDIOSYSTEM, + CEC_LOG_ADDR_INVALID + }; + static const u8 specific_use_log_addrs[] = { + CEC_LOG_ADDR_SPECIFIC, + CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, + CEC_LOG_ADDR_INVALID + }; + static const u8 *type2addrs[6] = { + [CEC_LOG_ADDR_TYPE_TV] = tv_log_addrs, + [CEC_LOG_ADDR_TYPE_RECORD] = record_log_addrs, + [CEC_LOG_ADDR_TYPE_TUNER] = tuner_log_addrs, + [CEC_LOG_ADDR_TYPE_PLAYBACK] = playback_log_addrs, + [CEC_LOG_ADDR_TYPE_AUDIOSYSTEM] = audiosystem_log_addrs, + [CEC_LOG_ADDR_TYPE_SPECIFIC] = specific_use_log_addrs, + }; + static const u16 type2mask[] = { + [CEC_LOG_ADDR_TYPE_TV] = CEC_LOG_ADDR_MASK_TV, + [CEC_LOG_ADDR_TYPE_RECORD] = CEC_LOG_ADDR_MASK_RECORD, + [CEC_LOG_ADDR_TYPE_TUNER] = CEC_LOG_ADDR_MASK_TUNER, + [CEC_LOG_ADDR_TYPE_PLAYBACK] = CEC_LOG_ADDR_MASK_PLAYBACK, + [CEC_LOG_ADDR_TYPE_AUDIOSYSTEM] = CEC_LOG_ADDR_MASK_AUDIOSYSTEM, + [CEC_LOG_ADDR_TYPE_SPECIFIC] = CEC_LOG_ADDR_MASK_SPECIFIC, + }; + struct cec_adapter *adap = arg; + struct cec_log_addrs *las = &adap->log_addrs; + int err; + int i, j; + + mutex_lock(&adap->lock); + dprintk(1, "physical address: %x.%x.%x.%x, claim %d logical addresses\n", + cec_phys_addr_exp(adap->phys_addr), las->num_log_addrs); + las->log_addr_mask = 0; + + if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED) + goto configured; + + for (i = 0; i < las->num_log_addrs; i++) { + unsigned int type = las->log_addr_type[i]; + const u8 *la_list; + u8 last_la; + + /* + * The TV functionality can only map to physical address 0. + * For any other address, try the Specific functionality + * instead as per the spec. + */ + if (adap->phys_addr && type == CEC_LOG_ADDR_TYPE_TV) + type = CEC_LOG_ADDR_TYPE_SPECIFIC; + + la_list = type2addrs[type]; + last_la = las->log_addr[i]; + las->log_addr[i] = CEC_LOG_ADDR_INVALID; + if (last_la == CEC_LOG_ADDR_INVALID || + last_la == CEC_LOG_ADDR_UNREGISTERED || + !(last_la & type2mask[type])) + last_la = la_list[0]; + + err = cec_config_log_addr(adap, i, last_la); + if (err > 0) /* Reused last LA */ + continue; + + if (err < 0) + goto unconfigure; + + for (j = 0; la_list[j] != CEC_LOG_ADDR_INVALID; j++) { + /* Tried this one already, skip it */ + if (la_list[j] == last_la) + continue; + /* The backup addresses are CEC 2.0 specific */ + if ((la_list[j] == CEC_LOG_ADDR_BACKUP_1 || + la_list[j] == CEC_LOG_ADDR_BACKUP_2) && + las->cec_version < CEC_OP_CEC_VERSION_2_0) + continue; + + err = cec_config_log_addr(adap, i, la_list[j]); + if (err == 0) /* LA is in use */ + continue; + if (err < 0) + goto unconfigure; + /* Done, claimed an LA */ + break; + } + + if (la_list[j] == CEC_LOG_ADDR_INVALID) + dprintk(1, "could not claim LA %d\n", i); + } + + if (adap->log_addrs.log_addr_mask == 0 && + !(las->flags & CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK)) + goto unconfigure; + +configured: + if (adap->log_addrs.log_addr_mask == 0) { + /* Fall back to unregistered */ + las->log_addr[0] = CEC_LOG_ADDR_UNREGISTERED; + las->log_addr_mask = 1 << las->log_addr[0]; + for (i = 1; i < las->num_log_addrs; i++) + las->log_addr[i] = CEC_LOG_ADDR_INVALID; + } + adap->is_configured = true; + adap->is_configuring = false; + cec_post_state_event(adap); + mutex_unlock(&adap->lock); + + for (i = 0; i < las->num_log_addrs; i++) { + if (las->log_addr[i] == CEC_LOG_ADDR_INVALID || + (las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY)) + continue; + + /* + * Report Features must come first according + * to CEC 2.0 + */ + if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED) + cec_report_features(adap, i); + cec_report_phys_addr(adap, i); + } + for (i = las->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++) + las->log_addr[i] = CEC_LOG_ADDR_INVALID; + mutex_lock(&adap->lock); + adap->kthread_config = NULL; + mutex_unlock(&adap->lock); + complete(&adap->config_completion); + return 0; + +unconfigure: + for (i = 0; i < las->num_log_addrs; i++) + las->log_addr[i] = CEC_LOG_ADDR_INVALID; + cec_adap_unconfigure(adap); + adap->kthread_config = NULL; + mutex_unlock(&adap->lock); + complete(&adap->config_completion); + return 0; +} + +/* + * Called from either __cec_s_phys_addr or __cec_s_log_addrs to claim the + * logical addresses. + * + * This function is called with adap->lock held. + */ +static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) +{ + if (WARN_ON(adap->is_configuring || adap->is_configured)) + return; + + init_completion(&adap->config_completion); + + /* Ready to kick off the thread */ + adap->is_configuring = true; + adap->kthread_config = kthread_run(cec_config_thread_func, adap, + "ceccfg-%s", adap->name); + if (IS_ERR(adap->kthread_config)) { + adap->kthread_config = NULL; + } else if (block) { + mutex_unlock(&adap->lock); + wait_for_completion(&adap->config_completion); + mutex_lock(&adap->lock); + } +} + +/* Set a new physical address and send an event notifying userspace of this. + * + * This function is called with adap->lock held. + */ +void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) +{ + if (phys_addr == adap->phys_addr || adap->devnode.unregistered) + return; + + if (phys_addr == CEC_PHYS_ADDR_INVALID || + adap->phys_addr != CEC_PHYS_ADDR_INVALID) { + adap->phys_addr = CEC_PHYS_ADDR_INVALID; + cec_post_state_event(adap); + cec_adap_unconfigure(adap); + /* Disabling monitor all mode should always succeed */ + if (adap->monitor_all_cnt) + WARN_ON(call_op(adap, adap_monitor_all_enable, false)); + WARN_ON(adap->ops->adap_enable(adap, false)); + if (phys_addr == CEC_PHYS_ADDR_INVALID) + return; + } + + if (adap->ops->adap_enable(adap, true)) + return; + + if (adap->monitor_all_cnt && + call_op(adap, adap_monitor_all_enable, true)) { + WARN_ON(adap->ops->adap_enable(adap, false)); + return; + } + adap->phys_addr = phys_addr; + cec_post_state_event(adap); + if (adap->log_addrs.num_log_addrs) + cec_claim_log_addrs(adap, block); +} + +void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) +{ + if (IS_ERR_OR_NULL(adap)) + return; + + mutex_lock(&adap->lock); + __cec_s_phys_addr(adap, phys_addr, block); + mutex_unlock(&adap->lock); +} +EXPORT_SYMBOL_GPL(cec_s_phys_addr); + +/* + * Called from either the ioctl or a driver to set the logical addresses. + * + * This function is called with adap->lock held. + */ +int __cec_s_log_addrs(struct cec_adapter *adap, + struct cec_log_addrs *log_addrs, bool block) +{ + u16 type_mask = 0; + int i; + + if (adap->devnode.unregistered) + return -ENODEV; + + if (!log_addrs || log_addrs->num_log_addrs == 0) { + adap->log_addrs.num_log_addrs = 0; + cec_adap_unconfigure(adap); + return 0; + } + + if (log_addrs->flags & CEC_LOG_ADDRS_FL_CDC_ONLY) { + /* + * Sanitize log_addrs fields if a CDC-Only device is + * requested. + */ + log_addrs->num_log_addrs = 1; + log_addrs->osd_name[0] = '\0'; + log_addrs->vendor_id = CEC_VENDOR_ID_NONE; + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; + /* + * This is just an internal convention since a CDC-Only device + * doesn't have to be a switch. But switches already use + * unregistered, so it makes some kind of sense to pick this + * as the primary device. Since a CDC-Only device never sends + * any 'normal' CEC messages this primary device type is never + * sent over the CEC bus. + */ + log_addrs->primary_device_type[0] = CEC_OP_PRIM_DEVTYPE_SWITCH; + log_addrs->all_device_types[0] = 0; + log_addrs->features[0][0] = 0; + log_addrs->features[0][1] = 0; + } + + /* Ensure the osd name is 0-terminated */ + log_addrs->osd_name[sizeof(log_addrs->osd_name) - 1] = '\0'; + + /* Sanity checks */ + if (log_addrs->num_log_addrs > adap->available_log_addrs) { + dprintk(1, "num_log_addrs > %d\n", adap->available_log_addrs); + return -EINVAL; + } + + /* + * Vendor ID is a 24 bit number, so check if the value is + * within the correct range. + */ + if (log_addrs->vendor_id != CEC_VENDOR_ID_NONE && + (log_addrs->vendor_id & 0xff000000) != 0) + return -EINVAL; + + if (log_addrs->cec_version != CEC_OP_CEC_VERSION_1_4 && + log_addrs->cec_version != CEC_OP_CEC_VERSION_2_0) + return -EINVAL; + + if (log_addrs->num_log_addrs > 1) + for (i = 0; i < log_addrs->num_log_addrs; i++) + if (log_addrs->log_addr_type[i] == + CEC_LOG_ADDR_TYPE_UNREGISTERED) { + dprintk(1, "num_log_addrs > 1 can't be combined with unregistered LA\n"); + return -EINVAL; + } + + for (i = 0; i < log_addrs->num_log_addrs; i++) { + const u8 feature_sz = ARRAY_SIZE(log_addrs->features[0]); + u8 *features = log_addrs->features[i]; + bool op_is_dev_features = false; + + log_addrs->log_addr[i] = CEC_LOG_ADDR_INVALID; + if (type_mask & (1 << log_addrs->log_addr_type[i])) { + dprintk(1, "duplicate logical address type\n"); + return -EINVAL; + } + type_mask |= 1 << log_addrs->log_addr_type[i]; + if ((type_mask & (1 << CEC_LOG_ADDR_TYPE_RECORD)) && + (type_mask & (1 << CEC_LOG_ADDR_TYPE_PLAYBACK))) { + /* Record already contains the playback functionality */ + dprintk(1, "invalid record + playback combination\n"); + return -EINVAL; + } + if (log_addrs->primary_device_type[i] > + CEC_OP_PRIM_DEVTYPE_PROCESSOR) { + dprintk(1, "unknown primary device type\n"); + return -EINVAL; + } + if (log_addrs->primary_device_type[i] == 2) { + dprintk(1, "invalid primary device type\n"); + return -EINVAL; + } + if (log_addrs->log_addr_type[i] > CEC_LOG_ADDR_TYPE_UNREGISTERED) { + dprintk(1, "unknown logical address type\n"); + return -EINVAL; + } + for (i = 0; i < feature_sz; i++) { + if ((features[i] & 0x80) == 0) { + if (op_is_dev_features) + break; + op_is_dev_features = true; + } + } + if (!op_is_dev_features || i == feature_sz) { + dprintk(1, "malformed features\n"); + return -EINVAL; + } + /* Zero unused part of the feature array */ + memset(features + i + 1, 0, feature_sz - i - 1); + } + + if (log_addrs->cec_version >= CEC_OP_CEC_VERSION_2_0) { + if (log_addrs->num_log_addrs > 2) { + dprintk(1, "CEC 2.0 allows no more than 2 logical addresses\n"); + return -EINVAL; + } + if (log_addrs->num_log_addrs == 2) { + if (!(type_mask & ((1 << CEC_LOG_ADDR_TYPE_AUDIOSYSTEM) | + (1 << CEC_LOG_ADDR_TYPE_TV)))) { + dprintk(1, "Two LAs is only allowed for audiosystem and TV\n"); + return -EINVAL; + } + if (!(type_mask & ((1 << CEC_LOG_ADDR_TYPE_PLAYBACK) | + (1 << CEC_LOG_ADDR_TYPE_RECORD)))) { + dprintk(1, "An audiosystem/TV can only be combined with record or playback\n"); + return -EINVAL; + } + } + } + + /* Zero unused LAs */ + for (i = log_addrs->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++) { + log_addrs->primary_device_type[i] = 0; + log_addrs->log_addr_type[i] = 0; + log_addrs->all_device_types[i] = 0; + memset(log_addrs->features[i], 0, + sizeof(log_addrs->features[i])); + } + + log_addrs->log_addr_mask = adap->log_addrs.log_addr_mask; + adap->log_addrs = *log_addrs; + if (adap->phys_addr != CEC_PHYS_ADDR_INVALID) + cec_claim_log_addrs(adap, block); + return 0; +} + +int cec_s_log_addrs(struct cec_adapter *adap, + struct cec_log_addrs *log_addrs, bool block) +{ + int err; + + mutex_lock(&adap->lock); + err = __cec_s_log_addrs(adap, log_addrs, block); + mutex_unlock(&adap->lock); + return err; +} +EXPORT_SYMBOL_GPL(cec_s_log_addrs); + +/* High-level core CEC message handling */ + +/* Transmit the Report Features message */ +static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx) +{ + struct cec_msg msg = { }; + const struct cec_log_addrs *las = &adap->log_addrs; + const u8 *features = las->features[la_idx]; + bool op_is_dev_features = false; + unsigned int idx; + + /* This is 2.0 and up only */ + if (adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0) + return 0; + + /* Report Features */ + msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f; + msg.len = 4; + msg.msg[1] = CEC_MSG_REPORT_FEATURES; + msg.msg[2] = adap->log_addrs.cec_version; + msg.msg[3] = las->all_device_types[la_idx]; + + /* Write RC Profiles first, then Device Features */ + for (idx = 0; idx < ARRAY_SIZE(las->features[0]); idx++) { + msg.msg[msg.len++] = features[idx]; + if ((features[idx] & CEC_OP_FEAT_EXT) == 0) { + if (op_is_dev_features) + break; + op_is_dev_features = true; + } + } + return cec_transmit_msg(adap, &msg, false); +} + +/* Transmit the Report Physical Address message */ +static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx) +{ + const struct cec_log_addrs *las = &adap->log_addrs; + struct cec_msg msg = { }; + + /* Report Physical Address */ + msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f; + cec_msg_report_physical_addr(&msg, adap->phys_addr, + las->primary_device_type[la_idx]); + dprintk(2, "config: la %d pa %x.%x.%x.%x\n", + las->log_addr[la_idx], + cec_phys_addr_exp(adap->phys_addr)); + return cec_transmit_msg(adap, &msg, false); +} + +/* Transmit the Feature Abort message */ +static int cec_feature_abort_reason(struct cec_adapter *adap, + struct cec_msg *msg, u8 reason) +{ + struct cec_msg tx_msg = { }; + + /* + * Don't reply with CEC_MSG_FEATURE_ABORT to a CEC_MSG_FEATURE_ABORT + * message! + */ + if (msg->msg[1] == CEC_MSG_FEATURE_ABORT) + return 0; + cec_msg_set_reply_to(&tx_msg, msg); + cec_msg_feature_abort(&tx_msg, msg->msg[1], reason); + return cec_transmit_msg(adap, &tx_msg, false); +} + +static int cec_feature_abort(struct cec_adapter *adap, struct cec_msg *msg) +{ + return cec_feature_abort_reason(adap, msg, + CEC_OP_ABORT_UNRECOGNIZED_OP); +} + +static int cec_feature_refused(struct cec_adapter *adap, struct cec_msg *msg) +{ + return cec_feature_abort_reason(adap, msg, + CEC_OP_ABORT_REFUSED); +} + +/* + * Called when a CEC message is received. This function will do any + * necessary core processing. The is_reply bool is true if this message + * is a reply to an earlier transmit. + * + * The message is either a broadcast message or a valid directed message. + */ +static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, + bool is_reply) +{ + bool is_broadcast = cec_msg_is_broadcast(msg); + u8 dest_laddr = cec_msg_destination(msg); + u8 init_laddr = cec_msg_initiator(msg); + u8 devtype = cec_log_addr2dev(adap, dest_laddr); + int la_idx = cec_log_addr2idx(adap, dest_laddr); + bool from_unregistered = init_laddr == 0xf; + struct cec_msg tx_cec_msg = { }; + + dprintk(1, "cec_receive_notify: %*ph\n", msg->len, msg->msg); + + /* If this is a CDC-Only device, then ignore any non-CDC messages */ + if (cec_is_cdc_only(&adap->log_addrs) && + msg->msg[1] != CEC_MSG_CDC_MESSAGE) + return 0; + + if (adap->ops->received) { + /* Allow drivers to process the message first */ + if (adap->ops->received(adap, msg) != -ENOMSG) + return 0; + } + + /* + * REPORT_PHYSICAL_ADDR, CEC_MSG_USER_CONTROL_PRESSED and + * CEC_MSG_USER_CONTROL_RELEASED messages always have to be + * handled by the CEC core, even if the passthrough mode is on. + * The others are just ignored if passthrough mode is on. + */ + switch (msg->msg[1]) { + case CEC_MSG_GET_CEC_VERSION: + case CEC_MSG_GIVE_DEVICE_VENDOR_ID: + case CEC_MSG_ABORT: + case CEC_MSG_GIVE_DEVICE_POWER_STATUS: + case CEC_MSG_GIVE_PHYSICAL_ADDR: + case CEC_MSG_GIVE_OSD_NAME: + case CEC_MSG_GIVE_FEATURES: + /* + * Skip processing these messages if the passthrough mode + * is on. + */ + if (adap->passthrough) + goto skip_processing; + /* Ignore if addressing is wrong */ + if (is_broadcast || from_unregistered) + return 0; + break; + + case CEC_MSG_USER_CONTROL_PRESSED: + case CEC_MSG_USER_CONTROL_RELEASED: + /* Wrong addressing mode: don't process */ + if (is_broadcast || from_unregistered) + goto skip_processing; + break; + + case CEC_MSG_REPORT_PHYSICAL_ADDR: + /* + * This message is always processed, regardless of the + * passthrough setting. + * + * Exception: don't process if wrong addressing mode. + */ + if (!is_broadcast) + goto skip_processing; + break; + + default: + break; + } + + cec_msg_set_reply_to(&tx_cec_msg, msg); + + switch (msg->msg[1]) { + /* The following messages are processed but still passed through */ + case CEC_MSG_REPORT_PHYSICAL_ADDR: { + u16 pa = (msg->msg[2] << 8) | msg->msg[3]; + + if (!from_unregistered) + adap->phys_addrs[init_laddr] = pa; + dprintk(1, "Reported physical address %x.%x.%x.%x for logical address %d\n", + cec_phys_addr_exp(pa), init_laddr); + break; + } + + case CEC_MSG_USER_CONTROL_PRESSED: + if (!(adap->capabilities & CEC_CAP_RC) || + !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) + break; + +#if IS_REACHABLE(CONFIG_RC_CORE) + switch (msg->msg[2]) { + /* + * Play function, this message can have variable length + * depending on the specific play function that is used. + */ + case 0x60: + if (msg->len == 2) + rc_keydown(adap->rc, RC_TYPE_CEC, + msg->msg[2], 0); + else + rc_keydown(adap->rc, RC_TYPE_CEC, + msg->msg[2] << 8 | msg->msg[3], 0); + break; + /* + * Other function messages that are not handled. + * Currently the RC framework does not allow to supply an + * additional parameter to a keypress. These "keys" contain + * other information such as channel number, an input number + * etc. + * For the time being these messages are not processed by the + * framework and are simply forwarded to the user space. + */ + case 0x56: case 0x57: + case 0x67: case 0x68: case 0x69: case 0x6a: + break; + default: + rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2], 0); + break; + } +#endif + break; + + case CEC_MSG_USER_CONTROL_RELEASED: + if (!(adap->capabilities & CEC_CAP_RC) || + !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) + break; +#if IS_REACHABLE(CONFIG_RC_CORE) + rc_keyup(adap->rc); +#endif + break; + + /* + * The remaining messages are only processed if the passthrough mode + * is off. + */ + case CEC_MSG_GET_CEC_VERSION: + cec_msg_cec_version(&tx_cec_msg, adap->log_addrs.cec_version); + return cec_transmit_msg(adap, &tx_cec_msg, false); + + case CEC_MSG_GIVE_PHYSICAL_ADDR: + /* Do nothing for CEC switches using addr 15 */ + if (devtype == CEC_OP_PRIM_DEVTYPE_SWITCH && dest_laddr == 15) + return 0; + cec_msg_report_physical_addr(&tx_cec_msg, adap->phys_addr, devtype); + return cec_transmit_msg(adap, &tx_cec_msg, false); + + case CEC_MSG_GIVE_DEVICE_VENDOR_ID: + if (adap->log_addrs.vendor_id == CEC_VENDOR_ID_NONE) + return cec_feature_abort(adap, msg); + cec_msg_device_vendor_id(&tx_cec_msg, adap->log_addrs.vendor_id); + return cec_transmit_msg(adap, &tx_cec_msg, false); + + case CEC_MSG_ABORT: + /* Do nothing for CEC switches */ + if (devtype == CEC_OP_PRIM_DEVTYPE_SWITCH) + return 0; + return cec_feature_refused(adap, msg); + + case CEC_MSG_GIVE_OSD_NAME: { + if (adap->log_addrs.osd_name[0] == 0) + return cec_feature_abort(adap, msg); + cec_msg_set_osd_name(&tx_cec_msg, adap->log_addrs.osd_name); + return cec_transmit_msg(adap, &tx_cec_msg, false); + } + + case CEC_MSG_GIVE_FEATURES: + if (adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0) + return cec_report_features(adap, la_idx); + return 0; + + default: + /* + * Unprocessed messages are aborted if userspace isn't doing + * any processing either. + */ + if (!is_broadcast && !is_reply && !adap->follower_cnt && + !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) + return cec_feature_abort(adap, msg); + break; + } + +skip_processing: + /* If this was a reply, then we're done, unless otherwise specified */ + if (is_reply && !(msg->flags & CEC_MSG_FL_REPLY_TO_FOLLOWERS)) + return 0; + + /* + * Send to the exclusive follower if there is one, otherwise send + * to all followers. + */ + if (adap->cec_follower) + cec_queue_msg_fh(adap->cec_follower, msg); + else + cec_queue_msg_followers(adap, msg); + return 0; +} + +/* + * Helper functions to keep track of the 'monitor all' use count. + * + * These functions are called with adap->lock held. + */ +int cec_monitor_all_cnt_inc(struct cec_adapter *adap) +{ + int ret = 0; + + if (adap->monitor_all_cnt == 0) + ret = call_op(adap, adap_monitor_all_enable, 1); + if (ret == 0) + adap->monitor_all_cnt++; + return ret; +} + +void cec_monitor_all_cnt_dec(struct cec_adapter *adap) +{ + adap->monitor_all_cnt--; + if (adap->monitor_all_cnt == 0) + WARN_ON(call_op(adap, adap_monitor_all_enable, 0)); +} + +#ifdef CONFIG_MEDIA_CEC_DEBUG +/* + * Log the current state of the CEC adapter. + * Very useful for debugging. + */ +int cec_adap_status(struct seq_file *file, void *priv) +{ + struct cec_adapter *adap = dev_get_drvdata(file->private); + struct cec_data *data; + + mutex_lock(&adap->lock); + seq_printf(file, "configured: %d\n", adap->is_configured); + seq_printf(file, "configuring: %d\n", adap->is_configuring); + seq_printf(file, "phys_addr: %x.%x.%x.%x\n", + cec_phys_addr_exp(adap->phys_addr)); + seq_printf(file, "number of LAs: %d\n", adap->log_addrs.num_log_addrs); + seq_printf(file, "LA mask: 0x%04x\n", adap->log_addrs.log_addr_mask); + if (adap->cec_follower) + seq_printf(file, "has CEC follower%s\n", + adap->passthrough ? " (in passthrough mode)" : ""); + if (adap->cec_initiator) + seq_puts(file, "has CEC initiator\n"); + if (adap->monitor_all_cnt) + seq_printf(file, "file handles in Monitor All mode: %u\n", + adap->monitor_all_cnt); + data = adap->transmitting; + if (data) + seq_printf(file, "transmitting message: %*ph (reply: %02x, timeout: %ums)\n", + data->msg.len, data->msg.msg, data->msg.reply, + data->msg.timeout); + seq_printf(file, "pending transmits: %u\n", adap->transmit_queue_sz); + list_for_each_entry(data, &adap->transmit_queue, list) { + seq_printf(file, "queued tx message: %*ph (reply: %02x, timeout: %ums)\n", + data->msg.len, data->msg.msg, data->msg.reply, + data->msg.timeout); + } + list_for_each_entry(data, &adap->wait_queue, list) { + seq_printf(file, "message waiting for reply: %*ph (reply: %02x, timeout: %ums)\n", + data->msg.len, data->msg.msg, data->msg.reply, + data->msg.timeout); + } + + call_void_op(adap, adap_status, file); + mutex_unlock(&adap->lock); + return 0; +} +#endif diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c new file mode 100644 index 000000000000..d4bc4ee2c6e5 --- /dev/null +++ b/drivers/media/cec/cec-api.c @@ -0,0 +1,588 @@ +/* + * cec-api.c - HDMI Consumer Electronics Control framework - API + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cec-priv.h" + +static inline struct cec_devnode *cec_devnode_data(struct file *filp) +{ + struct cec_fh *fh = filp->private_data; + + return &fh->adap->devnode; +} + +/* CEC file operations */ + +static unsigned int cec_poll(struct file *filp, + struct poll_table_struct *poll) +{ + struct cec_devnode *devnode = cec_devnode_data(filp); + struct cec_fh *fh = filp->private_data; + struct cec_adapter *adap = fh->adap; + unsigned int res = 0; + + if (!devnode->registered) + return POLLERR | POLLHUP; + mutex_lock(&adap->lock); + if (adap->is_configured && + adap->transmit_queue_sz < CEC_MAX_MSG_TX_QUEUE_SZ) + res |= POLLOUT | POLLWRNORM; + if (fh->queued_msgs) + res |= POLLIN | POLLRDNORM; + if (fh->pending_events) + res |= POLLPRI; + poll_wait(filp, &fh->wait, poll); + mutex_unlock(&adap->lock); + return res; +} + +static bool cec_is_busy(const struct cec_adapter *adap, + const struct cec_fh *fh) +{ + bool valid_initiator = adap->cec_initiator && adap->cec_initiator == fh; + bool valid_follower = adap->cec_follower && adap->cec_follower == fh; + + /* + * Exclusive initiators and followers can always access the CEC adapter + */ + if (valid_initiator || valid_follower) + return false; + /* + * All others can only access the CEC adapter if there is no + * exclusive initiator and they are in INITIATOR mode. + */ + return adap->cec_initiator || + fh->mode_initiator == CEC_MODE_NO_INITIATOR; +} + +static long cec_adap_g_caps(struct cec_adapter *adap, + struct cec_caps __user *parg) +{ + struct cec_caps caps = {}; + + strlcpy(caps.driver, adap->devnode.parent->driver->name, + sizeof(caps.driver)); + strlcpy(caps.name, adap->name, sizeof(caps.name)); + caps.available_log_addrs = adap->available_log_addrs; + caps.capabilities = adap->capabilities; + caps.version = LINUX_VERSION_CODE; + if (copy_to_user(parg, &caps, sizeof(caps))) + return -EFAULT; + return 0; +} + +static long cec_adap_g_phys_addr(struct cec_adapter *adap, + __u16 __user *parg) +{ + u16 phys_addr; + + mutex_lock(&adap->lock); + phys_addr = adap->phys_addr; + mutex_unlock(&adap->lock); + if (copy_to_user(parg, &phys_addr, sizeof(phys_addr))) + return -EFAULT; + return 0; +} + +static long cec_adap_s_phys_addr(struct cec_adapter *adap, struct cec_fh *fh, + bool block, __u16 __user *parg) +{ + u16 phys_addr; + long err; + + if (!(adap->capabilities & CEC_CAP_PHYS_ADDR)) + return -ENOTTY; + if (copy_from_user(&phys_addr, parg, sizeof(phys_addr))) + return -EFAULT; + + err = cec_phys_addr_validate(phys_addr, NULL, NULL); + if (err) + return err; + mutex_lock(&adap->lock); + if (cec_is_busy(adap, fh)) + err = -EBUSY; + else + __cec_s_phys_addr(adap, phys_addr, block); + mutex_unlock(&adap->lock); + return err; +} + +static long cec_adap_g_log_addrs(struct cec_adapter *adap, + struct cec_log_addrs __user *parg) +{ + struct cec_log_addrs log_addrs; + + mutex_lock(&adap->lock); + log_addrs = adap->log_addrs; + if (!adap->is_configured) + memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID, + sizeof(log_addrs.log_addr)); + mutex_unlock(&adap->lock); + + if (copy_to_user(parg, &log_addrs, sizeof(log_addrs))) + return -EFAULT; + return 0; +} + +static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, + bool block, struct cec_log_addrs __user *parg) +{ + struct cec_log_addrs log_addrs; + long err = -EBUSY; + + if (!(adap->capabilities & CEC_CAP_LOG_ADDRS)) + return -ENOTTY; + if (copy_from_user(&log_addrs, parg, sizeof(log_addrs))) + return -EFAULT; + log_addrs.flags &= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK | + CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU | + CEC_LOG_ADDRS_FL_CDC_ONLY; + mutex_lock(&adap->lock); + if (!adap->is_configuring && + (!log_addrs.num_log_addrs || !adap->is_configured) && + !cec_is_busy(adap, fh)) { + err = __cec_s_log_addrs(adap, &log_addrs, block); + if (!err) + log_addrs = adap->log_addrs; + } + mutex_unlock(&adap->lock); + if (err) + return err; + if (copy_to_user(parg, &log_addrs, sizeof(log_addrs))) + return -EFAULT; + return 0; +} + +static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, + bool block, struct cec_msg __user *parg) +{ + struct cec_msg msg = {}; + long err = 0; + + if (!(adap->capabilities & CEC_CAP_TRANSMIT)) + return -ENOTTY; + if (copy_from_user(&msg, parg, sizeof(msg))) + return -EFAULT; + + /* A CDC-Only device can only send CDC messages */ + if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && + (msg.len == 1 || msg.msg[1] != CEC_MSG_CDC_MESSAGE)) + return -EINVAL; + + msg.flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; + mutex_lock(&adap->lock); + if (!adap->is_configured) + err = -ENONET; + else if (cec_is_busy(adap, fh)) + err = -EBUSY; + else + err = cec_transmit_msg_fh(adap, &msg, fh, block); + mutex_unlock(&adap->lock); + if (err) + return err; + if (copy_to_user(parg, &msg, sizeof(msg))) + return -EFAULT; + return 0; +} + +/* Called by CEC_RECEIVE: wait for a message to arrive */ +static int cec_receive_msg(struct cec_fh *fh, struct cec_msg *msg, bool block) +{ + u32 timeout = msg->timeout; + int res; + + do { + mutex_lock(&fh->lock); + /* Are there received messages queued up? */ + if (fh->queued_msgs) { + /* Yes, return the first one */ + struct cec_msg_entry *entry = + list_first_entry(&fh->msgs, + struct cec_msg_entry, list); + + list_del(&entry->list); + *msg = entry->msg; + kfree(entry); + fh->queued_msgs--; + mutex_unlock(&fh->lock); + /* restore original timeout value */ + msg->timeout = timeout; + return 0; + } + + /* No, return EAGAIN in non-blocking mode or wait */ + mutex_unlock(&fh->lock); + + /* Return when in non-blocking mode */ + if (!block) + return -EAGAIN; + + if (msg->timeout) { + /* The user specified a timeout */ + res = wait_event_interruptible_timeout(fh->wait, + fh->queued_msgs, + msecs_to_jiffies(msg->timeout)); + if (res == 0) + res = -ETIMEDOUT; + else if (res > 0) + res = 0; + } else { + /* Wait indefinitely */ + res = wait_event_interruptible(fh->wait, + fh->queued_msgs); + } + /* Exit on error, otherwise loop to get the new message */ + } while (!res); + return res; +} + +static long cec_receive(struct cec_adapter *adap, struct cec_fh *fh, + bool block, struct cec_msg __user *parg) +{ + struct cec_msg msg = {}; + long err = 0; + + if (copy_from_user(&msg, parg, sizeof(msg))) + return -EFAULT; + mutex_lock(&adap->lock); + if (!adap->is_configured && fh->mode_follower < CEC_MODE_MONITOR) + err = -ENONET; + mutex_unlock(&adap->lock); + if (err) + return err; + + err = cec_receive_msg(fh, &msg, block); + if (err) + return err; + if (copy_to_user(parg, &msg, sizeof(msg))) + return -EFAULT; + return 0; +} + +static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh, + bool block, struct cec_event __user *parg) +{ + struct cec_event *ev = NULL; + u64 ts = ~0ULL; + unsigned int i; + long err = 0; + + mutex_lock(&fh->lock); + while (!fh->pending_events && block) { + mutex_unlock(&fh->lock); + err = wait_event_interruptible(fh->wait, fh->pending_events); + if (err) + return err; + mutex_lock(&fh->lock); + } + + /* Find the oldest event */ + for (i = 0; i < CEC_NUM_EVENTS; i++) { + if (fh->pending_events & (1 << (i + 1)) && + fh->events[i].ts <= ts) { + ev = &fh->events[i]; + ts = ev->ts; + } + } + if (!ev) { + err = -EAGAIN; + goto unlock; + } + + if (copy_to_user(parg, ev, sizeof(*ev))) { + err = -EFAULT; + goto unlock; + } + + fh->pending_events &= ~(1 << ev->event); + +unlock: + mutex_unlock(&fh->lock); + return err; +} + +static long cec_g_mode(struct cec_adapter *adap, struct cec_fh *fh, + u32 __user *parg) +{ + u32 mode = fh->mode_initiator | fh->mode_follower; + + if (copy_to_user(parg, &mode, sizeof(mode))) + return -EFAULT; + return 0; +} + +static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, + u32 __user *parg) +{ + u32 mode; + u8 mode_initiator; + u8 mode_follower; + long err = 0; + + if (copy_from_user(&mode, parg, sizeof(mode))) + return -EFAULT; + if (mode & ~(CEC_MODE_INITIATOR_MSK | CEC_MODE_FOLLOWER_MSK)) + return -EINVAL; + + mode_initiator = mode & CEC_MODE_INITIATOR_MSK; + mode_follower = mode & CEC_MODE_FOLLOWER_MSK; + + if (mode_initiator > CEC_MODE_EXCL_INITIATOR || + mode_follower > CEC_MODE_MONITOR_ALL) + return -EINVAL; + + if (mode_follower == CEC_MODE_MONITOR_ALL && + !(adap->capabilities & CEC_CAP_MONITOR_ALL)) + return -EINVAL; + + /* Follower modes should always be able to send CEC messages */ + if ((mode_initiator == CEC_MODE_NO_INITIATOR || + !(adap->capabilities & CEC_CAP_TRANSMIT)) && + mode_follower >= CEC_MODE_FOLLOWER && + mode_follower <= CEC_MODE_EXCL_FOLLOWER_PASSTHRU) + return -EINVAL; + + /* Monitor modes require CEC_MODE_NO_INITIATOR */ + if (mode_initiator && mode_follower >= CEC_MODE_MONITOR) + return -EINVAL; + + /* Monitor modes require CAP_NET_ADMIN */ + if (mode_follower >= CEC_MODE_MONITOR && !capable(CAP_NET_ADMIN)) + return -EPERM; + + mutex_lock(&adap->lock); + /* + * You can't become exclusive follower if someone else already + * has that job. + */ + if ((mode_follower == CEC_MODE_EXCL_FOLLOWER || + mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) && + adap->cec_follower && adap->cec_follower != fh) + err = -EBUSY; + /* + * You can't become exclusive initiator if someone else already + * has that job. + */ + if (mode_initiator == CEC_MODE_EXCL_INITIATOR && + adap->cec_initiator && adap->cec_initiator != fh) + err = -EBUSY; + + if (!err) { + bool old_mon_all = fh->mode_follower == CEC_MODE_MONITOR_ALL; + bool new_mon_all = mode_follower == CEC_MODE_MONITOR_ALL; + + if (old_mon_all != new_mon_all) { + if (new_mon_all) + err = cec_monitor_all_cnt_inc(adap); + else + cec_monitor_all_cnt_dec(adap); + } + } + + if (err) { + mutex_unlock(&adap->lock); + return err; + } + + if (fh->mode_follower == CEC_MODE_FOLLOWER) + adap->follower_cnt--; + if (mode_follower == CEC_MODE_FOLLOWER) + adap->follower_cnt++; + if (mode_follower == CEC_MODE_EXCL_FOLLOWER || + mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) { + adap->passthrough = + mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU; + adap->cec_follower = fh; + } else if (adap->cec_follower == fh) { + adap->passthrough = false; + adap->cec_follower = NULL; + } + if (mode_initiator == CEC_MODE_EXCL_INITIATOR) + adap->cec_initiator = fh; + else if (adap->cec_initiator == fh) + adap->cec_initiator = NULL; + fh->mode_initiator = mode_initiator; + fh->mode_follower = mode_follower; + mutex_unlock(&adap->lock); + return 0; +} + +static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct cec_devnode *devnode = cec_devnode_data(filp); + struct cec_fh *fh = filp->private_data; + struct cec_adapter *adap = fh->adap; + bool block = !(filp->f_flags & O_NONBLOCK); + void __user *parg = (void __user *)arg; + + if (!devnode->registered) + return -ENODEV; + + switch (cmd) { + case CEC_ADAP_G_CAPS: + return cec_adap_g_caps(adap, parg); + + case CEC_ADAP_G_PHYS_ADDR: + return cec_adap_g_phys_addr(adap, parg); + + case CEC_ADAP_S_PHYS_ADDR: + return cec_adap_s_phys_addr(adap, fh, block, parg); + + case CEC_ADAP_G_LOG_ADDRS: + return cec_adap_g_log_addrs(adap, parg); + + case CEC_ADAP_S_LOG_ADDRS: + return cec_adap_s_log_addrs(adap, fh, block, parg); + + case CEC_TRANSMIT: + return cec_transmit(adap, fh, block, parg); + + case CEC_RECEIVE: + return cec_receive(adap, fh, block, parg); + + case CEC_DQEVENT: + return cec_dqevent(adap, fh, block, parg); + + case CEC_G_MODE: + return cec_g_mode(adap, fh, parg); + + case CEC_S_MODE: + return cec_s_mode(adap, fh, parg); + + default: + return -ENOTTY; + } +} + +static int cec_open(struct inode *inode, struct file *filp) +{ + struct cec_devnode *devnode = + container_of(inode->i_cdev, struct cec_devnode, cdev); + struct cec_adapter *adap = to_cec_adapter(devnode); + struct cec_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); + /* + * Initial events that are automatically sent when the cec device is + * opened. + */ + struct cec_event ev_state = { + .event = CEC_EVENT_STATE_CHANGE, + .flags = CEC_EVENT_FL_INITIAL_STATE, + }; + int err; + + if (!fh) + return -ENOMEM; + + INIT_LIST_HEAD(&fh->msgs); + INIT_LIST_HEAD(&fh->xfer_list); + mutex_init(&fh->lock); + init_waitqueue_head(&fh->wait); + + fh->mode_initiator = CEC_MODE_INITIATOR; + fh->adap = adap; + + err = cec_get_device(devnode); + if (err) { + kfree(fh); + return err; + } + + filp->private_data = fh; + + mutex_lock(&devnode->lock); + /* Queue up initial state events */ + ev_state.state_change.phys_addr = adap->phys_addr; + ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; + cec_queue_event_fh(fh, &ev_state, 0); + + list_add(&fh->list, &devnode->fhs); + mutex_unlock(&devnode->lock); + + return 0; +} + +/* Override for the release function */ +static int cec_release(struct inode *inode, struct file *filp) +{ + struct cec_devnode *devnode = cec_devnode_data(filp); + struct cec_adapter *adap = to_cec_adapter(devnode); + struct cec_fh *fh = filp->private_data; + + mutex_lock(&adap->lock); + if (adap->cec_initiator == fh) + adap->cec_initiator = NULL; + if (adap->cec_follower == fh) { + adap->cec_follower = NULL; + adap->passthrough = false; + } + if (fh->mode_follower == CEC_MODE_FOLLOWER) + adap->follower_cnt--; + if (fh->mode_follower == CEC_MODE_MONITOR_ALL) + cec_monitor_all_cnt_dec(adap); + mutex_unlock(&adap->lock); + + mutex_lock(&devnode->lock); + list_del(&fh->list); + mutex_unlock(&devnode->lock); + + /* Unhook pending transmits from this filehandle. */ + mutex_lock(&adap->lock); + while (!list_empty(&fh->xfer_list)) { + struct cec_data *data = + list_first_entry(&fh->xfer_list, struct cec_data, xfer_list); + + data->blocking = false; + data->fh = NULL; + list_del(&data->xfer_list); + } + mutex_unlock(&adap->lock); + while (!list_empty(&fh->msgs)) { + struct cec_msg_entry *entry = + list_first_entry(&fh->msgs, struct cec_msg_entry, list); + + list_del(&entry->list); + kfree(entry); + } + kfree(fh); + + cec_put_device(devnode); + filp->private_data = NULL; + return 0; +} + +const struct file_operations cec_devnode_fops = { + .owner = THIS_MODULE, + .open = cec_open, + .unlocked_ioctl = cec_ioctl, + .release = cec_release, + .poll = cec_poll, + .llseek = no_llseek, +}; diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c new file mode 100644 index 000000000000..b0137e247dc9 --- /dev/null +++ b/drivers/media/cec/cec-core.c @@ -0,0 +1,411 @@ +/* + * cec-core.c - HDMI Consumer Electronics Control framework - Core + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cec-priv.h" + +#define CEC_NUM_DEVICES 256 +#define CEC_NAME "cec" + +int cec_debug; +module_param_named(debug, cec_debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); + +static dev_t cec_dev_t; + +/* Active devices */ +static DEFINE_MUTEX(cec_devnode_lock); +static DECLARE_BITMAP(cec_devnode_nums, CEC_NUM_DEVICES); + +static struct dentry *top_cec_dir; + +/* dev to cec_devnode */ +#define to_cec_devnode(cd) container_of(cd, struct cec_devnode, dev) + +int cec_get_device(struct cec_devnode *devnode) +{ + /* + * Check if the cec device is available. This needs to be done with + * the devnode->lock held to prevent an open/unregister race: + * without the lock, the device could be unregistered and freed between + * the devnode->registered check and get_device() calls, leading to + * a crash. + */ + mutex_lock(&devnode->lock); + /* + * return ENXIO if the cec device has been removed + * already or if it is not registered anymore. + */ + if (!devnode->registered) { + mutex_unlock(&devnode->lock); + return -ENXIO; + } + /* and increase the device refcount */ + get_device(&devnode->dev); + mutex_unlock(&devnode->lock); + return 0; +} + +void cec_put_device(struct cec_devnode *devnode) +{ + put_device(&devnode->dev); +} + +/* Called when the last user of the cec device exits. */ +static void cec_devnode_release(struct device *cd) +{ + struct cec_devnode *devnode = to_cec_devnode(cd); + + mutex_lock(&cec_devnode_lock); + /* Mark device node number as free */ + clear_bit(devnode->minor, cec_devnode_nums); + mutex_unlock(&cec_devnode_lock); + + cec_delete_adapter(to_cec_adapter(devnode)); +} + +static struct bus_type cec_bus_type = { + .name = CEC_NAME, +}; + +/* + * Register a cec device node + * + * The registration code assigns minor numbers and registers the new device node + * with the kernel. An error is returned if no free minor number can be found, + * or if the registration of the device node fails. + * + * Zero is returned on success. + * + * Note that if the cec_devnode_register call fails, the release() callback of + * the cec_devnode structure is *not* called, so the caller is responsible for + * freeing any data. + */ +static int __must_check cec_devnode_register(struct cec_devnode *devnode, + struct module *owner) +{ + int minor; + int ret; + + /* Initialization */ + INIT_LIST_HEAD(&devnode->fhs); + mutex_init(&devnode->lock); + + /* Part 1: Find a free minor number */ + mutex_lock(&cec_devnode_lock); + minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0); + if (minor == CEC_NUM_DEVICES) { + mutex_unlock(&cec_devnode_lock); + pr_err("could not get a free minor\n"); + return -ENFILE; + } + + set_bit(minor, cec_devnode_nums); + mutex_unlock(&cec_devnode_lock); + + devnode->minor = minor; + devnode->dev.bus = &cec_bus_type; + devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor); + devnode->dev.release = cec_devnode_release; + devnode->dev.parent = devnode->parent; + dev_set_name(&devnode->dev, "cec%d", devnode->minor); + device_initialize(&devnode->dev); + + /* Part 2: Initialize and register the character device */ + cdev_init(&devnode->cdev, &cec_devnode_fops); + devnode->cdev.kobj.parent = &devnode->dev.kobj; + devnode->cdev.owner = owner; + + ret = cdev_add(&devnode->cdev, devnode->dev.devt, 1); + if (ret < 0) { + pr_err("%s: cdev_add failed\n", __func__); + goto clr_bit; + } + + ret = device_add(&devnode->dev); + if (ret) + goto cdev_del; + + devnode->registered = true; + return 0; + +cdev_del: + cdev_del(&devnode->cdev); +clr_bit: + mutex_lock(&cec_devnode_lock); + clear_bit(devnode->minor, cec_devnode_nums); + mutex_unlock(&cec_devnode_lock); + return ret; +} + +/* + * Unregister a cec device node + * + * This unregisters the passed device. Future open calls will be met with + * errors. + * + * This function can safely be called if the device node has never been + * registered or has already been unregistered. + */ +static void cec_devnode_unregister(struct cec_devnode *devnode) +{ + struct cec_fh *fh; + + mutex_lock(&devnode->lock); + + /* Check if devnode was never registered or already unregistered */ + if (!devnode->registered || devnode->unregistered) { + mutex_unlock(&devnode->lock); + return; + } + + list_for_each_entry(fh, &devnode->fhs, list) + wake_up_interruptible(&fh->wait); + + devnode->registered = false; + devnode->unregistered = true; + mutex_unlock(&devnode->lock); + + device_del(&devnode->dev); + cdev_del(&devnode->cdev); + put_device(&devnode->dev); +} + +struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, + void *priv, const char *name, u32 caps, + u8 available_las, struct device *parent) +{ + struct cec_adapter *adap; + int res; + + if (WARN_ON(!parent)) + return ERR_PTR(-EINVAL); + if (WARN_ON(!caps)) + return ERR_PTR(-EINVAL); + if (WARN_ON(!ops)) + return ERR_PTR(-EINVAL); + if (WARN_ON(!available_las || available_las > CEC_MAX_LOG_ADDRS)) + return ERR_PTR(-EINVAL); + adap = kzalloc(sizeof(*adap), GFP_KERNEL); + if (!adap) + return ERR_PTR(-ENOMEM); + adap->owner = parent->driver->owner; + adap->devnode.parent = parent; + strlcpy(adap->name, name, sizeof(adap->name)); + adap->phys_addr = CEC_PHYS_ADDR_INVALID; + adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; + adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; + adap->capabilities = caps; + adap->available_log_addrs = available_las; + adap->sequence = 0; + adap->ops = ops; + adap->priv = priv; + memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); + mutex_init(&adap->lock); + INIT_LIST_HEAD(&adap->transmit_queue); + INIT_LIST_HEAD(&adap->wait_queue); + init_waitqueue_head(&adap->kthread_waitq); + + adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); + if (IS_ERR(adap->kthread)) { + pr_err("cec-%s: kernel_thread() failed\n", name); + res = PTR_ERR(adap->kthread); + kfree(adap); + return ERR_PTR(res); + } + + if (!(caps & CEC_CAP_RC)) + return adap; + +#if IS_REACHABLE(CONFIG_RC_CORE) + /* Prepare the RC input device */ + adap->rc = rc_allocate_device(); + if (!adap->rc) { + pr_err("cec-%s: failed to allocate memory for rc_dev\n", + name); + kthread_stop(adap->kthread); + kfree(adap); + return ERR_PTR(-ENOMEM); + } + + snprintf(adap->input_name, sizeof(adap->input_name), + "RC for %s", name); + snprintf(adap->input_phys, sizeof(adap->input_phys), + "%s/input0", name); + + adap->rc->input_name = adap->input_name; + adap->rc->input_phys = adap->input_phys; + adap->rc->input_id.bustype = BUS_CEC; + adap->rc->input_id.vendor = 0; + adap->rc->input_id.product = 0; + adap->rc->input_id.version = 1; + adap->rc->dev.parent = parent; + adap->rc->driver_type = RC_DRIVER_SCANCODE; + adap->rc->driver_name = CEC_NAME; + adap->rc->allowed_protocols = RC_BIT_CEC; + adap->rc->priv = adap; + adap->rc->map_name = RC_MAP_CEC; + adap->rc->timeout = MS_TO_NS(100); +#else + adap->capabilities &= ~CEC_CAP_RC; +#endif + return adap; +} +EXPORT_SYMBOL_GPL(cec_allocate_adapter); + +int cec_register_adapter(struct cec_adapter *adap) +{ + int res; + + if (IS_ERR_OR_NULL(adap)) + return 0; + +#if IS_REACHABLE(CONFIG_RC_CORE) + if (adap->capabilities & CEC_CAP_RC) { + res = rc_register_device(adap->rc); + + if (res) { + pr_err("cec-%s: failed to prepare input device\n", + adap->name); + rc_free_device(adap->rc); + adap->rc = NULL; + return res; + } + } +#endif + + res = cec_devnode_register(&adap->devnode, adap->owner); + if (res) { +#if IS_REACHABLE(CONFIG_RC_CORE) + /* Note: rc_unregister also calls rc_free */ + rc_unregister_device(adap->rc); + adap->rc = NULL; +#endif + return res; + } + + dev_set_drvdata(&adap->devnode.dev, adap); +#ifdef CONFIG_MEDIA_CEC_DEBUG + if (!top_cec_dir) + return 0; + + adap->cec_dir = debugfs_create_dir(dev_name(&adap->devnode.dev), top_cec_dir); + if (IS_ERR_OR_NULL(adap->cec_dir)) { + pr_warn("cec-%s: Failed to create debugfs dir\n", adap->name); + return 0; + } + adap->status_file = debugfs_create_devm_seqfile(&adap->devnode.dev, + "status", adap->cec_dir, cec_adap_status); + if (IS_ERR_OR_NULL(adap->status_file)) { + pr_warn("cec-%s: Failed to create status file\n", adap->name); + debugfs_remove_recursive(adap->cec_dir); + adap->cec_dir = NULL; + } +#endif + return 0; +} +EXPORT_SYMBOL_GPL(cec_register_adapter); + +void cec_unregister_adapter(struct cec_adapter *adap) +{ + if (IS_ERR_OR_NULL(adap)) + return; + +#if IS_REACHABLE(CONFIG_RC_CORE) + /* Note: rc_unregister also calls rc_free */ + rc_unregister_device(adap->rc); + adap->rc = NULL; +#endif + debugfs_remove_recursive(adap->cec_dir); + cec_devnode_unregister(&adap->devnode); +} +EXPORT_SYMBOL_GPL(cec_unregister_adapter); + +void cec_delete_adapter(struct cec_adapter *adap) +{ + if (IS_ERR_OR_NULL(adap)) + return; + mutex_lock(&adap->lock); + __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); + mutex_unlock(&adap->lock); + kthread_stop(adap->kthread); + if (adap->kthread_config) + kthread_stop(adap->kthread_config); +#if IS_REACHABLE(CONFIG_RC_CORE) + rc_free_device(adap->rc); +#endif + kfree(adap); +} +EXPORT_SYMBOL_GPL(cec_delete_adapter); + +/* + * Initialise cec for linux + */ +static int __init cec_devnode_init(void) +{ + int ret; + + pr_info("Linux cec interface: v0.10\n"); + ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, + CEC_NAME); + if (ret < 0) { + pr_warn("cec: unable to allocate major\n"); + return ret; + } + +#ifdef CONFIG_MEDIA_CEC_DEBUG + top_cec_dir = debugfs_create_dir("cec", NULL); + if (IS_ERR_OR_NULL(top_cec_dir)) { + pr_warn("cec: Failed to create debugfs cec dir\n"); + top_cec_dir = NULL; + } +#endif + + ret = bus_register(&cec_bus_type); + if (ret < 0) { + unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); + pr_warn("cec: bus_register failed\n"); + return -EIO; + } + + return 0; +} + +static void __exit cec_devnode_exit(void) +{ + debugfs_remove_recursive(top_cec_dir); + bus_unregister(&cec_bus_type); + unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); +} + +subsys_initcall(cec_devnode_init); +module_exit(cec_devnode_exit) + +MODULE_AUTHOR("Hans Verkuil "); +MODULE_DESCRIPTION("Device node registration for cec drivers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/cec/cec-priv.h b/drivers/media/cec/cec-priv.h new file mode 100644 index 000000000000..70767a7900f2 --- /dev/null +++ b/drivers/media/cec/cec-priv.h @@ -0,0 +1,56 @@ +/* + * cec-priv.h - HDMI Consumer Electronics Control internal header + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _CEC_PRIV_H +#define _CEC_PRIV_H + +#include +#include + +#define dprintk(lvl, fmt, arg...) \ + do { \ + if (lvl <= cec_debug) \ + pr_info("cec-%s: " fmt, adap->name, ## arg); \ + } while (0) + +/* devnode to cec_adapter */ +#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode) + +/* cec-core.c */ +extern int cec_debug; +int cec_get_device(struct cec_devnode *devnode); +void cec_put_device(struct cec_devnode *devnode); + +/* cec-adap.c */ +int cec_monitor_all_cnt_inc(struct cec_adapter *adap); +void cec_monitor_all_cnt_dec(struct cec_adapter *adap); +int cec_adap_status(struct seq_file *file, void *priv); +int cec_thread_func(void *_adap); +void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); +int __cec_s_log_addrs(struct cec_adapter *adap, + struct cec_log_addrs *log_addrs, bool block); +int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, + struct cec_fh *fh, bool block); +void cec_queue_event_fh(struct cec_fh *fh, + const struct cec_event *new_ev, u64 ts); + +/* cec-api.c */ +extern const struct file_operations cec_devnode_fops; + +#endif diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig index 2669b4bad910..b31fa6fae009 100644 --- a/drivers/media/i2c/Kconfig +++ b/drivers/media/i2c/Kconfig @@ -221,7 +221,7 @@ config VIDEO_ADV7604 config VIDEO_ADV7604_CEC bool "Enable Analog Devices ADV7604 CEC support" - depends on VIDEO_ADV7604 && MEDIA_CEC + depends on VIDEO_ADV7604 && MEDIA_CEC_SUPPORT ---help--- When selected the adv7604 will support the optional HDMI CEC feature. @@ -242,7 +242,7 @@ config VIDEO_ADV7842 config VIDEO_ADV7842_CEC bool "Enable Analog Devices ADV7842 CEC support" - depends on VIDEO_ADV7842 && MEDIA_CEC + depends on VIDEO_ADV7842 && MEDIA_CEC_SUPPORT ---help--- When selected the adv7842 will support the optional HDMI CEC feature. @@ -481,7 +481,7 @@ config VIDEO_ADV7511 config VIDEO_ADV7511_CEC bool "Enable Analog Devices ADV7511 CEC support" - depends on VIDEO_ADV7511 && MEDIA_CEC + depends on VIDEO_ADV7511 && MEDIA_CEC_SUPPORT ---help--- When selected the adv7511 will support the optional HDMI CEC feature. diff --git a/drivers/media/platform/vivid/Kconfig b/drivers/media/platform/vivid/Kconfig index 8e6918c5c87c..db0dd19d227a 100644 --- a/drivers/media/platform/vivid/Kconfig +++ b/drivers/media/platform/vivid/Kconfig @@ -25,7 +25,7 @@ config VIDEO_VIVID config VIDEO_VIVID_CEC bool "Enable CEC emulation support" - depends on VIDEO_VIVID && MEDIA_CEC + depends on VIDEO_VIVID && MEDIA_CEC_SUPPORT ---help--- When selected the vivid module will emulate the optional HDMI CEC feature. diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 6620d96ee44d..0abe5ffb4934 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -21,8 +21,6 @@ if STAGING_MEDIA && MEDIA_SUPPORT # Please keep them in alphabetic order source "drivers/staging/media/bcm2048/Kconfig" -source "drivers/staging/media/cec/Kconfig" - source "drivers/staging/media/cxd2099/Kconfig" source "drivers/staging/media/davinci_vpfe/Kconfig" diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 906257e94dda..246299eff80d 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -1,5 +1,4 @@ obj-$(CONFIG_I2C_BCM2048) += bcm2048/ -obj-$(CONFIG_MEDIA_CEC) += cec/ obj-$(CONFIG_VIDEO_SAMSUNG_S5P_CEC) += s5p-cec/ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_LIRC_STAGING) += lirc/ diff --git a/drivers/staging/media/cec/Kconfig b/drivers/staging/media/cec/Kconfig deleted file mode 100644 index 6e12d41b1f86..000000000000 --- a/drivers/staging/media/cec/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config MEDIA_CEC - bool "CEC API (EXPERIMENTAL)" - depends on MEDIA_SUPPORT - select MEDIA_CEC_EDID - ---help--- - Enable the CEC API. - -config MEDIA_CEC_DEBUG - bool "CEC debugfs interface (EXPERIMENTAL)" - depends on MEDIA_CEC && DEBUG_FS - ---help--- - Turns on the DebugFS interface for CEC devices. diff --git a/drivers/staging/media/cec/Makefile b/drivers/staging/media/cec/Makefile deleted file mode 100644 index bd7f3c593468..000000000000 --- a/drivers/staging/media/cec/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -cec-objs := cec-core.o cec-adap.o cec-api.o - -ifeq ($(CONFIG_MEDIA_CEC),y) - obj-$(CONFIG_MEDIA_SUPPORT) += cec.o -endif diff --git a/drivers/staging/media/cec/TODO b/drivers/staging/media/cec/TODO deleted file mode 100644 index 504d35c7ae95..000000000000 --- a/drivers/staging/media/cec/TODO +++ /dev/null @@ -1,9 +0,0 @@ -TODOs: - -- Once this is out of staging this should no longer be a separate - config option, instead it should be selected by drivers that want it. -- Revisit the IS_REACHABLE(RC_CORE): perhaps the RC_CORE support should - be enabled through a separate config option in drivers/media/Kconfig - or rc/Kconfig? - -Hans Verkuil diff --git a/drivers/staging/media/cec/cec-adap.c b/drivers/staging/media/cec/cec-adap.c deleted file mode 100644 index 054cd06e2247..000000000000 --- a/drivers/staging/media/cec/cec-adap.c +++ /dev/null @@ -1,1856 +0,0 @@ -/* - * cec-adap.c - HDMI Consumer Electronics Control framework - CEC adapter - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cec-priv.h" - -static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx); -static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx); - -/* - * 400 ms is the time it takes for one 16 byte message to be - * transferred and 5 is the maximum number of retries. Add - * another 100 ms as a margin. So if the transmit doesn't - * finish before that time something is really wrong and we - * have to time out. - * - * This is a sign that something it really wrong and a warning - * will be issued. - */ -#define CEC_XFER_TIMEOUT_MS (5 * 400 + 100) - -#define call_op(adap, op, arg...) \ - (adap->ops->op ? adap->ops->op(adap, ## arg) : 0) - -#define call_void_op(adap, op, arg...) \ - do { \ - if (adap->ops->op) \ - adap->ops->op(adap, ## arg); \ - } while (0) - -static int cec_log_addr2idx(const struct cec_adapter *adap, u8 log_addr) -{ - int i; - - for (i = 0; i < adap->log_addrs.num_log_addrs; i++) - if (adap->log_addrs.log_addr[i] == log_addr) - return i; - return -1; -} - -static unsigned int cec_log_addr2dev(const struct cec_adapter *adap, u8 log_addr) -{ - int i = cec_log_addr2idx(adap, log_addr); - - return adap->log_addrs.primary_device_type[i < 0 ? 0 : i]; -} - -/* - * Queue a new event for this filehandle. If ts == 0, then set it - * to the current time. - * - * The two events that are currently defined do not need to keep track - * of intermediate events, so no actual queue of events is needed, - * instead just store the latest state and the total number of lost - * messages. - * - * Should new events be added in the future that require intermediate - * results to be queued as well, then a proper queue data structure is - * required. But until then, just keep it simple. - */ -void cec_queue_event_fh(struct cec_fh *fh, - const struct cec_event *new_ev, u64 ts) -{ - struct cec_event *ev = &fh->events[new_ev->event - 1]; - - if (ts == 0) - ts = ktime_get_ns(); - - mutex_lock(&fh->lock); - if (new_ev->event == CEC_EVENT_LOST_MSGS && - fh->pending_events & (1 << new_ev->event)) { - /* - * If there is already a lost_msgs event, then just - * update the lost_msgs count. This effectively - * merges the old and new events into one. - */ - ev->lost_msgs.lost_msgs += new_ev->lost_msgs.lost_msgs; - goto unlock; - } - - /* - * Intermediate states are not interesting, so just - * overwrite any older event. - */ - *ev = *new_ev; - ev->ts = ts; - fh->pending_events |= 1 << new_ev->event; - -unlock: - mutex_unlock(&fh->lock); - wake_up_interruptible(&fh->wait); -} - -/* Queue a new event for all open filehandles. */ -static void cec_queue_event(struct cec_adapter *adap, - const struct cec_event *ev) -{ - u64 ts = ktime_get_ns(); - struct cec_fh *fh; - - mutex_lock(&adap->devnode.lock); - list_for_each_entry(fh, &adap->devnode.fhs, list) - cec_queue_event_fh(fh, ev, ts); - mutex_unlock(&adap->devnode.lock); -} - -/* - * Queue a new message for this filehandle. If there is no more room - * in the queue, then send the LOST_MSGS event instead. - */ -static void cec_queue_msg_fh(struct cec_fh *fh, const struct cec_msg *msg) -{ - static const struct cec_event ev_lost_msg = { - .ts = 0, - .event = CEC_EVENT_LOST_MSGS, - .flags = 0, - { - .lost_msgs.lost_msgs = 1, - }, - }; - struct cec_msg_entry *entry; - - mutex_lock(&fh->lock); - entry = kmalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - goto lost_msgs; - - entry->msg = *msg; - /* Add new msg at the end of the queue */ - list_add_tail(&entry->list, &fh->msgs); - - /* - * if the queue now has more than CEC_MAX_MSG_RX_QUEUE_SZ - * messages, drop the oldest one and send a lost message event. - */ - if (fh->queued_msgs == CEC_MAX_MSG_RX_QUEUE_SZ) { - list_del(&entry->list); - goto lost_msgs; - } - fh->queued_msgs++; - mutex_unlock(&fh->lock); - wake_up_interruptible(&fh->wait); - return; - -lost_msgs: - mutex_unlock(&fh->lock); - cec_queue_event_fh(fh, &ev_lost_msg, 0); -} - -/* - * Queue the message for those filehandles that are in monitor mode. - * If valid_la is true (this message is for us or was sent by us), - * then pass it on to any monitoring filehandle. If this message - * isn't for us or from us, then only give it to filehandles that - * are in MONITOR_ALL mode. - * - * This can only happen if the CEC_CAP_MONITOR_ALL capability is - * set and the CEC adapter was placed in 'monitor all' mode. - */ -static void cec_queue_msg_monitor(struct cec_adapter *adap, - const struct cec_msg *msg, - bool valid_la) -{ - struct cec_fh *fh; - u32 monitor_mode = valid_la ? CEC_MODE_MONITOR : - CEC_MODE_MONITOR_ALL; - - mutex_lock(&adap->devnode.lock); - list_for_each_entry(fh, &adap->devnode.fhs, list) { - if (fh->mode_follower >= monitor_mode) - cec_queue_msg_fh(fh, msg); - } - mutex_unlock(&adap->devnode.lock); -} - -/* - * Queue the message for follower filehandles. - */ -static void cec_queue_msg_followers(struct cec_adapter *adap, - const struct cec_msg *msg) -{ - struct cec_fh *fh; - - mutex_lock(&adap->devnode.lock); - list_for_each_entry(fh, &adap->devnode.fhs, list) { - if (fh->mode_follower == CEC_MODE_FOLLOWER) - cec_queue_msg_fh(fh, msg); - } - mutex_unlock(&adap->devnode.lock); -} - -/* Notify userspace of an adapter state change. */ -static void cec_post_state_event(struct cec_adapter *adap) -{ - struct cec_event ev = { - .event = CEC_EVENT_STATE_CHANGE, - }; - - ev.state_change.phys_addr = adap->phys_addr; - ev.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; - cec_queue_event(adap, &ev); -} - -/* - * A CEC transmit (and a possible wait for reply) completed. - * If this was in blocking mode, then complete it, otherwise - * queue the message for userspace to dequeue later. - * - * This function is called with adap->lock held. - */ -static void cec_data_completed(struct cec_data *data) -{ - /* - * Delete this transmit from the filehandle's xfer_list since - * we're done with it. - * - * Note that if the filehandle is closed before this transmit - * finished, then the release() function will set data->fh to NULL. - * Without that we would be referring to a closed filehandle. - */ - if (data->fh) - list_del(&data->xfer_list); - - if (data->blocking) { - /* - * Someone is blocking so mark the message as completed - * and call complete. - */ - data->completed = true; - complete(&data->c); - } else { - /* - * No blocking, so just queue the message if needed and - * free the memory. - */ - if (data->fh) - cec_queue_msg_fh(data->fh, &data->msg); - kfree(data); - } -} - -/* - * A pending CEC transmit needs to be cancelled, either because the CEC - * adapter is disabled or the transmit takes an impossibly long time to - * finish. - * - * This function is called with adap->lock held. - */ -static void cec_data_cancel(struct cec_data *data) -{ - /* - * It's either the current transmit, or it is a pending - * transmit. Take the appropriate action to clear it. - */ - if (data->adap->transmitting == data) { - data->adap->transmitting = NULL; - } else { - list_del_init(&data->list); - if (!(data->msg.tx_status & CEC_TX_STATUS_OK)) - data->adap->transmit_queue_sz--; - } - - /* Mark it as an error */ - data->msg.tx_ts = ktime_get_ns(); - data->msg.tx_status = CEC_TX_STATUS_ERROR | - CEC_TX_STATUS_MAX_RETRIES; - data->attempts = 0; - data->msg.tx_error_cnt = 1; - /* Queue transmitted message for monitoring purposes */ - cec_queue_msg_monitor(data->adap, &data->msg, 1); - - cec_data_completed(data); -} - -/* - * Main CEC state machine - * - * Wait until the thread should be stopped, or we are not transmitting and - * a new transmit message is queued up, in which case we start transmitting - * that message. When the adapter finished transmitting the message it will - * call cec_transmit_done(). - * - * If the adapter is disabled, then remove all queued messages instead. - * - * If the current transmit times out, then cancel that transmit. - */ -int cec_thread_func(void *_adap) -{ - struct cec_adapter *adap = _adap; - - for (;;) { - unsigned int signal_free_time; - struct cec_data *data; - bool timeout = false; - u8 attempts; - - if (adap->transmitting) { - int err; - - /* - * We are transmitting a message, so add a timeout - * to prevent the state machine to get stuck waiting - * for this message to finalize and add a check to - * see if the adapter is disabled in which case the - * transmit should be canceled. - */ - err = wait_event_interruptible_timeout(adap->kthread_waitq, - kthread_should_stop() || - (!adap->is_configured && !adap->is_configuring) || - (!adap->transmitting && - !list_empty(&adap->transmit_queue)), - msecs_to_jiffies(CEC_XFER_TIMEOUT_MS)); - timeout = err == 0; - } else { - /* Otherwise we just wait for something to happen. */ - wait_event_interruptible(adap->kthread_waitq, - kthread_should_stop() || - (!adap->transmitting && - !list_empty(&adap->transmit_queue))); - } - - mutex_lock(&adap->lock); - - if ((!adap->is_configured && !adap->is_configuring) || - kthread_should_stop()) { - /* - * If the adapter is disabled, or we're asked to stop, - * then cancel any pending transmits. - */ - while (!list_empty(&adap->transmit_queue)) { - data = list_first_entry(&adap->transmit_queue, - struct cec_data, list); - cec_data_cancel(data); - } - if (adap->transmitting) - cec_data_cancel(adap->transmitting); - - /* - * Cancel the pending timeout work. We have to unlock - * the mutex when flushing the work since - * cec_wait_timeout() will take it. This is OK since - * no new entries can be added to wait_queue as long - * as adap->transmitting is NULL, which it is due to - * the cec_data_cancel() above. - */ - while (!list_empty(&adap->wait_queue)) { - data = list_first_entry(&adap->wait_queue, - struct cec_data, list); - - if (!cancel_delayed_work(&data->work)) { - mutex_unlock(&adap->lock); - flush_scheduled_work(); - mutex_lock(&adap->lock); - } - cec_data_cancel(data); - } - goto unlock; - } - - if (adap->transmitting && timeout) { - /* - * If we timeout, then log that. This really shouldn't - * happen and is an indication of a faulty CEC adapter - * driver, or the CEC bus is in some weird state. - */ - dprintk(0, "message %*ph timed out!\n", - adap->transmitting->msg.len, - adap->transmitting->msg.msg); - /* Just give up on this. */ - cec_data_cancel(adap->transmitting); - goto unlock; - } - - /* - * If we are still transmitting, or there is nothing new to - * transmit, then just continue waiting. - */ - if (adap->transmitting || list_empty(&adap->transmit_queue)) - goto unlock; - - /* Get a new message to transmit */ - data = list_first_entry(&adap->transmit_queue, - struct cec_data, list); - list_del_init(&data->list); - adap->transmit_queue_sz--; - /* Make this the current transmitting message */ - adap->transmitting = data; - - /* - * Suggested number of attempts as per the CEC 2.0 spec: - * 4 attempts is the default, except for 'secondary poll - * messages', i.e. poll messages not sent during the adapter - * configuration phase when it allocates logical addresses. - */ - if (data->msg.len == 1 && adap->is_configured) - attempts = 2; - else - attempts = 4; - - /* Set the suggested signal free time */ - if (data->attempts) { - /* should be >= 3 data bit periods for a retry */ - signal_free_time = CEC_SIGNAL_FREE_TIME_RETRY; - } else if (data->new_initiator) { - /* should be >= 5 data bit periods for new initiator */ - signal_free_time = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR; - } else { - /* - * should be >= 7 data bit periods for sending another - * frame immediately after another. - */ - signal_free_time = CEC_SIGNAL_FREE_TIME_NEXT_XFER; - } - if (data->attempts == 0) - data->attempts = attempts; - - /* Tell the adapter to transmit, cancel on error */ - if (adap->ops->adap_transmit(adap, data->attempts, - signal_free_time, &data->msg)) - cec_data_cancel(data); - -unlock: - mutex_unlock(&adap->lock); - - if (kthread_should_stop()) - break; - } - return 0; -} - -/* - * Called by the CEC adapter if a transmit finished. - */ -void cec_transmit_done(struct cec_adapter *adap, u8 status, u8 arb_lost_cnt, - u8 nack_cnt, u8 low_drive_cnt, u8 error_cnt) -{ - struct cec_data *data; - struct cec_msg *msg; - u64 ts = ktime_get_ns(); - - dprintk(2, "cec_transmit_done %02x\n", status); - mutex_lock(&adap->lock); - data = adap->transmitting; - if (!data) { - /* - * This can happen if a transmit was issued and the cable is - * unplugged while the transmit is ongoing. Ignore this - * transmit in that case. - */ - dprintk(1, "cec_transmit_done without an ongoing transmit!\n"); - goto unlock; - } - - msg = &data->msg; - - /* Drivers must fill in the status! */ - WARN_ON(status == 0); - msg->tx_ts = ts; - msg->tx_status |= status; - msg->tx_arb_lost_cnt += arb_lost_cnt; - msg->tx_nack_cnt += nack_cnt; - msg->tx_low_drive_cnt += low_drive_cnt; - msg->tx_error_cnt += error_cnt; - - /* Mark that we're done with this transmit */ - adap->transmitting = NULL; - - /* - * If there are still retry attempts left and there was an error and - * the hardware didn't signal that it retried itself (by setting - * CEC_TX_STATUS_MAX_RETRIES), then we will retry ourselves. - */ - if (data->attempts > 1 && - !(status & (CEC_TX_STATUS_MAX_RETRIES | CEC_TX_STATUS_OK))) { - /* Retry this message */ - data->attempts--; - /* Add the message in front of the transmit queue */ - list_add(&data->list, &adap->transmit_queue); - adap->transmit_queue_sz++; - goto wake_thread; - } - - data->attempts = 0; - - /* Always set CEC_TX_STATUS_MAX_RETRIES on error */ - if (!(status & CEC_TX_STATUS_OK)) - msg->tx_status |= CEC_TX_STATUS_MAX_RETRIES; - - /* Queue transmitted message for monitoring purposes */ - cec_queue_msg_monitor(adap, msg, 1); - - if ((status & CEC_TX_STATUS_OK) && adap->is_configured && - msg->timeout) { - /* - * Queue the message into the wait queue if we want to wait - * for a reply. - */ - list_add_tail(&data->list, &adap->wait_queue); - schedule_delayed_work(&data->work, - msecs_to_jiffies(msg->timeout)); - } else { - /* Otherwise we're done */ - cec_data_completed(data); - } - -wake_thread: - /* - * Wake up the main thread to see if another message is ready - * for transmitting or to retry the current message. - */ - wake_up_interruptible(&adap->kthread_waitq); -unlock: - mutex_unlock(&adap->lock); -} -EXPORT_SYMBOL_GPL(cec_transmit_done); - -/* - * Called when waiting for a reply times out. - */ -static void cec_wait_timeout(struct work_struct *work) -{ - struct cec_data *data = container_of(work, struct cec_data, work.work); - struct cec_adapter *adap = data->adap; - - mutex_lock(&adap->lock); - /* - * Sanity check in case the timeout and the arrival of the message - * happened at the same time. - */ - if (list_empty(&data->list)) - goto unlock; - - /* Mark the message as timed out */ - list_del_init(&data->list); - data->msg.rx_ts = ktime_get_ns(); - data->msg.rx_status = CEC_RX_STATUS_TIMEOUT; - cec_data_completed(data); -unlock: - mutex_unlock(&adap->lock); -} - -/* - * Transmit a message. The fh argument may be NULL if the transmit is not - * associated with a specific filehandle. - * - * This function is called with adap->lock held. - */ -int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, - struct cec_fh *fh, bool block) -{ - struct cec_data *data; - u8 last_initiator = 0xff; - unsigned int timeout; - int res = 0; - - msg->rx_ts = 0; - msg->tx_ts = 0; - msg->rx_status = 0; - msg->tx_status = 0; - msg->tx_arb_lost_cnt = 0; - msg->tx_nack_cnt = 0; - msg->tx_low_drive_cnt = 0; - msg->tx_error_cnt = 0; - msg->sequence = ++adap->sequence; - if (!msg->sequence) - msg->sequence = ++adap->sequence; - - if (msg->reply && msg->timeout == 0) { - /* Make sure the timeout isn't 0. */ - msg->timeout = 1000; - } - - /* Sanity checks */ - if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { - dprintk(1, "cec_transmit_msg: invalid length %d\n", msg->len); - return -EINVAL; - } - if (msg->timeout && msg->len == 1) { - dprintk(1, "cec_transmit_msg: can't reply for poll msg\n"); - return -EINVAL; - } - memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); - if (msg->len == 1) { - if (cec_msg_initiator(msg) != 0xf || - cec_msg_destination(msg) == 0xf) { - dprintk(1, "cec_transmit_msg: invalid poll message\n"); - return -EINVAL; - } - if (cec_has_log_addr(adap, cec_msg_destination(msg))) { - /* - * If the destination is a logical address our adapter - * has already claimed, then just NACK this. - * It depends on the hardware what it will do with a - * POLL to itself (some OK this), so it is just as - * easy to handle it here so the behavior will be - * consistent. - */ - msg->tx_ts = ktime_get_ns(); - msg->tx_status = CEC_TX_STATUS_NACK | - CEC_TX_STATUS_MAX_RETRIES; - msg->tx_nack_cnt = 1; - return 0; - } - } - if (msg->len > 1 && !cec_msg_is_broadcast(msg) && - cec_has_log_addr(adap, cec_msg_destination(msg))) { - dprintk(1, "cec_transmit_msg: destination is the adapter itself\n"); - return -EINVAL; - } - if (cec_msg_initiator(msg) != 0xf && - !cec_has_log_addr(adap, cec_msg_initiator(msg))) { - dprintk(1, "cec_transmit_msg: initiator has unknown logical address %d\n", - cec_msg_initiator(msg)); - return -EINVAL; - } - if (!adap->is_configured && !adap->is_configuring) - return -ENONET; - - if (adap->transmit_queue_sz >= CEC_MAX_MSG_TX_QUEUE_SZ) - return -EBUSY; - - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; - - if (msg->len > 1 && msg->msg[1] == CEC_MSG_CDC_MESSAGE) { - msg->msg[2] = adap->phys_addr >> 8; - msg->msg[3] = adap->phys_addr & 0xff; - } - - if (msg->timeout) - dprintk(2, "cec_transmit_msg: %*ph (wait for 0x%02x%s)\n", - msg->len, msg->msg, msg->reply, !block ? ", nb" : ""); - else - dprintk(2, "cec_transmit_msg: %*ph%s\n", - msg->len, msg->msg, !block ? " (nb)" : ""); - - data->msg = *msg; - data->fh = fh; - data->adap = adap; - data->blocking = block; - - /* - * Determine if this message follows a message from the same - * initiator. Needed to determine the free signal time later on. - */ - if (msg->len > 1) { - if (!(list_empty(&adap->transmit_queue))) { - const struct cec_data *last; - - last = list_last_entry(&adap->transmit_queue, - const struct cec_data, list); - last_initiator = cec_msg_initiator(&last->msg); - } else if (adap->transmitting) { - last_initiator = - cec_msg_initiator(&adap->transmitting->msg); - } - } - data->new_initiator = last_initiator != cec_msg_initiator(msg); - init_completion(&data->c); - INIT_DELAYED_WORK(&data->work, cec_wait_timeout); - - if (fh) - list_add_tail(&data->xfer_list, &fh->xfer_list); - list_add_tail(&data->list, &adap->transmit_queue); - adap->transmit_queue_sz++; - if (!adap->transmitting) - wake_up_interruptible(&adap->kthread_waitq); - - /* All done if we don't need to block waiting for completion */ - if (!block) - return 0; - - /* - * If we don't get a completion before this time something is really - * wrong and we time out. - */ - timeout = CEC_XFER_TIMEOUT_MS; - /* Add the requested timeout if we have to wait for a reply as well */ - if (msg->timeout) - timeout += msg->timeout; - - /* - * Release the lock and wait, retake the lock afterwards. - */ - mutex_unlock(&adap->lock); - res = wait_for_completion_killable_timeout(&data->c, - msecs_to_jiffies(timeout)); - mutex_lock(&adap->lock); - - if (data->completed) { - /* The transmit completed (possibly with an error) */ - *msg = data->msg; - kfree(data); - return 0; - } - /* - * The wait for completion timed out or was interrupted, so mark this - * as non-blocking and disconnect from the filehandle since it is - * still 'in flight'. When it finally completes it will just drop the - * result silently. - */ - data->blocking = false; - if (data->fh) - list_del(&data->xfer_list); - data->fh = NULL; - - if (res == 0) { /* timed out */ - /* Check if the reply or the transmit failed */ - if (msg->timeout && (msg->tx_status & CEC_TX_STATUS_OK)) - msg->rx_status = CEC_RX_STATUS_TIMEOUT; - else - msg->tx_status = CEC_TX_STATUS_MAX_RETRIES; - } - return res > 0 ? 0 : res; -} - -/* Helper function to be used by drivers and this framework. */ -int cec_transmit_msg(struct cec_adapter *adap, struct cec_msg *msg, - bool block) -{ - int ret; - - mutex_lock(&adap->lock); - ret = cec_transmit_msg_fh(adap, msg, NULL, block); - mutex_unlock(&adap->lock); - return ret; -} -EXPORT_SYMBOL_GPL(cec_transmit_msg); - -/* - * I don't like forward references but without this the low-level - * cec_received_msg() function would come after a bunch of high-level - * CEC protocol handling functions. That was very confusing. - */ -static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, - bool is_reply); - -#define DIRECTED 0x80 -#define BCAST1_4 0x40 -#define BCAST2_0 0x20 /* broadcast only allowed for >= 2.0 */ -#define BCAST (BCAST1_4 | BCAST2_0) -#define BOTH (BCAST | DIRECTED) - -/* - * Specify minimum length and whether the message is directed, broadcast - * or both. Messages that do not match the criteria are ignored as per - * the CEC specification. - */ -static const u8 cec_msg_size[256] = { - [CEC_MSG_ACTIVE_SOURCE] = 4 | BCAST, - [CEC_MSG_IMAGE_VIEW_ON] = 2 | DIRECTED, - [CEC_MSG_TEXT_VIEW_ON] = 2 | DIRECTED, - [CEC_MSG_INACTIVE_SOURCE] = 4 | DIRECTED, - [CEC_MSG_REQUEST_ACTIVE_SOURCE] = 2 | BCAST, - [CEC_MSG_ROUTING_CHANGE] = 6 | BCAST, - [CEC_MSG_ROUTING_INFORMATION] = 4 | BCAST, - [CEC_MSG_SET_STREAM_PATH] = 4 | BCAST, - [CEC_MSG_STANDBY] = 2 | BOTH, - [CEC_MSG_RECORD_OFF] = 2 | DIRECTED, - [CEC_MSG_RECORD_ON] = 3 | DIRECTED, - [CEC_MSG_RECORD_STATUS] = 3 | DIRECTED, - [CEC_MSG_RECORD_TV_SCREEN] = 2 | DIRECTED, - [CEC_MSG_CLEAR_ANALOGUE_TIMER] = 13 | DIRECTED, - [CEC_MSG_CLEAR_DIGITAL_TIMER] = 16 | DIRECTED, - [CEC_MSG_CLEAR_EXT_TIMER] = 13 | DIRECTED, - [CEC_MSG_SET_ANALOGUE_TIMER] = 13 | DIRECTED, - [CEC_MSG_SET_DIGITAL_TIMER] = 16 | DIRECTED, - [CEC_MSG_SET_EXT_TIMER] = 13 | DIRECTED, - [CEC_MSG_SET_TIMER_PROGRAM_TITLE] = 2 | DIRECTED, - [CEC_MSG_TIMER_CLEARED_STATUS] = 3 | DIRECTED, - [CEC_MSG_TIMER_STATUS] = 3 | DIRECTED, - [CEC_MSG_CEC_VERSION] = 3 | DIRECTED, - [CEC_MSG_GET_CEC_VERSION] = 2 | DIRECTED, - [CEC_MSG_GIVE_PHYSICAL_ADDR] = 2 | DIRECTED, - [CEC_MSG_GET_MENU_LANGUAGE] = 2 | DIRECTED, - [CEC_MSG_REPORT_PHYSICAL_ADDR] = 5 | BCAST, - [CEC_MSG_SET_MENU_LANGUAGE] = 5 | BCAST, - [CEC_MSG_REPORT_FEATURES] = 6 | BCAST, - [CEC_MSG_GIVE_FEATURES] = 2 | DIRECTED, - [CEC_MSG_DECK_CONTROL] = 3 | DIRECTED, - [CEC_MSG_DECK_STATUS] = 3 | DIRECTED, - [CEC_MSG_GIVE_DECK_STATUS] = 3 | DIRECTED, - [CEC_MSG_PLAY] = 3 | DIRECTED, - [CEC_MSG_GIVE_TUNER_DEVICE_STATUS] = 3 | DIRECTED, - [CEC_MSG_SELECT_ANALOGUE_SERVICE] = 6 | DIRECTED, - [CEC_MSG_SELECT_DIGITAL_SERVICE] = 9 | DIRECTED, - [CEC_MSG_TUNER_DEVICE_STATUS] = 7 | DIRECTED, - [CEC_MSG_TUNER_STEP_DECREMENT] = 2 | DIRECTED, - [CEC_MSG_TUNER_STEP_INCREMENT] = 2 | DIRECTED, - [CEC_MSG_DEVICE_VENDOR_ID] = 5 | BCAST, - [CEC_MSG_GIVE_DEVICE_VENDOR_ID] = 2 | DIRECTED, - [CEC_MSG_VENDOR_COMMAND] = 2 | DIRECTED, - [CEC_MSG_VENDOR_COMMAND_WITH_ID] = 5 | BOTH, - [CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN] = 2 | BOTH, - [CEC_MSG_VENDOR_REMOTE_BUTTON_UP] = 2 | BOTH, - [CEC_MSG_SET_OSD_STRING] = 3 | DIRECTED, - [CEC_MSG_GIVE_OSD_NAME] = 2 | DIRECTED, - [CEC_MSG_SET_OSD_NAME] = 2 | DIRECTED, - [CEC_MSG_MENU_REQUEST] = 3 | DIRECTED, - [CEC_MSG_MENU_STATUS] = 3 | DIRECTED, - [CEC_MSG_USER_CONTROL_PRESSED] = 3 | DIRECTED, - [CEC_MSG_USER_CONTROL_RELEASED] = 2 | DIRECTED, - [CEC_MSG_GIVE_DEVICE_POWER_STATUS] = 2 | DIRECTED, - [CEC_MSG_REPORT_POWER_STATUS] = 3 | DIRECTED | BCAST2_0, - [CEC_MSG_FEATURE_ABORT] = 4 | DIRECTED, - [CEC_MSG_ABORT] = 2 | DIRECTED, - [CEC_MSG_GIVE_AUDIO_STATUS] = 2 | DIRECTED, - [CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS] = 2 | DIRECTED, - [CEC_MSG_REPORT_AUDIO_STATUS] = 3 | DIRECTED, - [CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, - [CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR] = 2 | DIRECTED, - [CEC_MSG_SET_SYSTEM_AUDIO_MODE] = 3 | BOTH, - [CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST] = 2 | DIRECTED, - [CEC_MSG_SYSTEM_AUDIO_MODE_STATUS] = 3 | DIRECTED, - [CEC_MSG_SET_AUDIO_RATE] = 3 | DIRECTED, - [CEC_MSG_INITIATE_ARC] = 2 | DIRECTED, - [CEC_MSG_REPORT_ARC_INITIATED] = 2 | DIRECTED, - [CEC_MSG_REPORT_ARC_TERMINATED] = 2 | DIRECTED, - [CEC_MSG_REQUEST_ARC_INITIATION] = 2 | DIRECTED, - [CEC_MSG_REQUEST_ARC_TERMINATION] = 2 | DIRECTED, - [CEC_MSG_TERMINATE_ARC] = 2 | DIRECTED, - [CEC_MSG_REQUEST_CURRENT_LATENCY] = 4 | BCAST, - [CEC_MSG_REPORT_CURRENT_LATENCY] = 7 | BCAST, - [CEC_MSG_CDC_MESSAGE] = 2 | BCAST, -}; - -/* Called by the CEC adapter if a message is received */ -void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) -{ - struct cec_data *data; - u8 msg_init = cec_msg_initiator(msg); - u8 msg_dest = cec_msg_destination(msg); - u8 cmd = msg->msg[1]; - bool is_reply = false; - bool valid_la = true; - u8 min_len = 0; - - if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE)) - return; - - msg->rx_ts = ktime_get_ns(); - msg->rx_status = CEC_RX_STATUS_OK; - msg->sequence = msg->reply = msg->timeout = 0; - msg->tx_status = 0; - msg->tx_ts = 0; - msg->flags = 0; - memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); - - mutex_lock(&adap->lock); - dprintk(2, "cec_received_msg: %*ph\n", msg->len, msg->msg); - - /* Check if this message was for us (directed or broadcast). */ - if (!cec_msg_is_broadcast(msg)) - valid_la = cec_has_log_addr(adap, msg_dest); - - /* - * Check if the length is not too short or if the message is a - * broadcast message where a directed message was expected or - * vice versa. If so, then the message has to be ignored (according - * to section CEC 7.3 and CEC 12.2). - */ - if (valid_la && msg->len > 1 && cec_msg_size[cmd]) { - u8 dir_fl = cec_msg_size[cmd] & BOTH; - - min_len = cec_msg_size[cmd] & 0x1f; - if (msg->len < min_len) - valid_la = false; - else if (!cec_msg_is_broadcast(msg) && !(dir_fl & DIRECTED)) - valid_la = false; - else if (cec_msg_is_broadcast(msg) && !(dir_fl & BCAST1_4)) - valid_la = false; - else if (cec_msg_is_broadcast(msg) && - adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0 && - !(dir_fl & BCAST2_0)) - valid_la = false; - } - if (valid_la && min_len) { - /* These messages have special length requirements */ - switch (cmd) { - case CEC_MSG_TIMER_STATUS: - if (msg->msg[2] & 0x10) { - switch (msg->msg[2] & 0xf) { - case CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE: - case CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE: - if (msg->len < 5) - valid_la = false; - break; - } - } else if ((msg->msg[2] & 0xf) == CEC_OP_PROG_ERROR_DUPLICATE) { - if (msg->len < 5) - valid_la = false; - } - break; - case CEC_MSG_RECORD_ON: - switch (msg->msg[2]) { - case CEC_OP_RECORD_SRC_OWN: - break; - case CEC_OP_RECORD_SRC_DIGITAL: - if (msg->len < 10) - valid_la = false; - break; - case CEC_OP_RECORD_SRC_ANALOG: - if (msg->len < 7) - valid_la = false; - break; - case CEC_OP_RECORD_SRC_EXT_PLUG: - if (msg->len < 4) - valid_la = false; - break; - case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: - if (msg->len < 5) - valid_la = false; - break; - } - break; - } - } - - /* It's a valid message and not a poll or CDC message */ - if (valid_la && msg->len > 1 && cmd != CEC_MSG_CDC_MESSAGE) { - bool abort = cmd == CEC_MSG_FEATURE_ABORT; - - /* The aborted command is in msg[2] */ - if (abort) - cmd = msg->msg[2]; - - /* - * Walk over all transmitted messages that are waiting for a - * reply. - */ - list_for_each_entry(data, &adap->wait_queue, list) { - struct cec_msg *dst = &data->msg; - - /* - * The *only* CEC message that has two possible replies - * is CEC_MSG_INITIATE_ARC. - * In this case allow either of the two replies. - */ - if (!abort && dst->msg[1] == CEC_MSG_INITIATE_ARC && - (cmd == CEC_MSG_REPORT_ARC_INITIATED || - cmd == CEC_MSG_REPORT_ARC_TERMINATED) && - (dst->reply == CEC_MSG_REPORT_ARC_INITIATED || - dst->reply == CEC_MSG_REPORT_ARC_TERMINATED)) - dst->reply = cmd; - - /* Does the command match? */ - if ((abort && cmd != dst->msg[1]) || - (!abort && cmd != dst->reply)) - continue; - - /* Does the addressing match? */ - if (msg_init != cec_msg_destination(dst) && - !cec_msg_is_broadcast(dst)) - continue; - - /* We got a reply */ - memcpy(dst->msg, msg->msg, msg->len); - dst->len = msg->len; - dst->rx_ts = msg->rx_ts; - dst->rx_status = msg->rx_status; - if (abort) - dst->rx_status |= CEC_RX_STATUS_FEATURE_ABORT; - msg->flags = dst->flags; - /* Remove it from the wait_queue */ - list_del_init(&data->list); - - /* Cancel the pending timeout work */ - if (!cancel_delayed_work(&data->work)) { - mutex_unlock(&adap->lock); - flush_scheduled_work(); - mutex_lock(&adap->lock); - } - /* - * Mark this as a reply, provided someone is still - * waiting for the answer. - */ - if (data->fh) - is_reply = true; - cec_data_completed(data); - break; - } - } - mutex_unlock(&adap->lock); - - /* Pass the message on to any monitoring filehandles */ - cec_queue_msg_monitor(adap, msg, valid_la); - - /* We're done if it is not for us or a poll message */ - if (!valid_la || msg->len <= 1) - return; - - if (adap->log_addrs.log_addr_mask == 0) - return; - - /* - * Process the message on the protocol level. If is_reply is true, - * then cec_receive_notify() won't pass on the reply to the listener(s) - * since that was already done by cec_data_completed() above. - */ - cec_receive_notify(adap, msg, is_reply); -} -EXPORT_SYMBOL_GPL(cec_received_msg); - -/* Logical Address Handling */ - -/* - * Attempt to claim a specific logical address. - * - * This function is called with adap->lock held. - */ -static int cec_config_log_addr(struct cec_adapter *adap, - unsigned int idx, - unsigned int log_addr) -{ - struct cec_log_addrs *las = &adap->log_addrs; - struct cec_msg msg = { }; - int err; - - if (cec_has_log_addr(adap, log_addr)) - return 0; - - /* Send poll message */ - msg.len = 1; - msg.msg[0] = 0xf0 | log_addr; - err = cec_transmit_msg_fh(adap, &msg, NULL, true); - - /* - * While trying to poll the physical address was reset - * and the adapter was unconfigured, so bail out. - */ - if (!adap->is_configuring) - return -EINTR; - - if (err) - return err; - - if (msg.tx_status & CEC_TX_STATUS_OK) - return 0; - - /* - * Message not acknowledged, so this logical - * address is free to use. - */ - err = adap->ops->adap_log_addr(adap, log_addr); - if (err) - return err; - - las->log_addr[idx] = log_addr; - las->log_addr_mask |= 1 << log_addr; - adap->phys_addrs[log_addr] = adap->phys_addr; - - dprintk(2, "claimed addr %d (%d)\n", log_addr, - las->primary_device_type[idx]); - return 1; -} - -/* - * Unconfigure the adapter: clear all logical addresses and send - * the state changed event. - * - * This function is called with adap->lock held. - */ -static void cec_adap_unconfigure(struct cec_adapter *adap) -{ - WARN_ON(adap->ops->adap_log_addr(adap, CEC_LOG_ADDR_INVALID)); - adap->log_addrs.log_addr_mask = 0; - adap->is_configuring = false; - adap->is_configured = false; - memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); - wake_up_interruptible(&adap->kthread_waitq); - cec_post_state_event(adap); -} - -/* - * Attempt to claim the required logical addresses. - */ -static int cec_config_thread_func(void *arg) -{ - /* The various LAs for each type of device */ - static const u8 tv_log_addrs[] = { - CEC_LOG_ADDR_TV, CEC_LOG_ADDR_SPECIFIC, - CEC_LOG_ADDR_INVALID - }; - static const u8 record_log_addrs[] = { - CEC_LOG_ADDR_RECORD_1, CEC_LOG_ADDR_RECORD_2, - CEC_LOG_ADDR_RECORD_3, - CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, - CEC_LOG_ADDR_INVALID - }; - static const u8 tuner_log_addrs[] = { - CEC_LOG_ADDR_TUNER_1, CEC_LOG_ADDR_TUNER_2, - CEC_LOG_ADDR_TUNER_3, CEC_LOG_ADDR_TUNER_4, - CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, - CEC_LOG_ADDR_INVALID - }; - static const u8 playback_log_addrs[] = { - CEC_LOG_ADDR_PLAYBACK_1, CEC_LOG_ADDR_PLAYBACK_2, - CEC_LOG_ADDR_PLAYBACK_3, - CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, - CEC_LOG_ADDR_INVALID - }; - static const u8 audiosystem_log_addrs[] = { - CEC_LOG_ADDR_AUDIOSYSTEM, - CEC_LOG_ADDR_INVALID - }; - static const u8 specific_use_log_addrs[] = { - CEC_LOG_ADDR_SPECIFIC, - CEC_LOG_ADDR_BACKUP_1, CEC_LOG_ADDR_BACKUP_2, - CEC_LOG_ADDR_INVALID - }; - static const u8 *type2addrs[6] = { - [CEC_LOG_ADDR_TYPE_TV] = tv_log_addrs, - [CEC_LOG_ADDR_TYPE_RECORD] = record_log_addrs, - [CEC_LOG_ADDR_TYPE_TUNER] = tuner_log_addrs, - [CEC_LOG_ADDR_TYPE_PLAYBACK] = playback_log_addrs, - [CEC_LOG_ADDR_TYPE_AUDIOSYSTEM] = audiosystem_log_addrs, - [CEC_LOG_ADDR_TYPE_SPECIFIC] = specific_use_log_addrs, - }; - static const u16 type2mask[] = { - [CEC_LOG_ADDR_TYPE_TV] = CEC_LOG_ADDR_MASK_TV, - [CEC_LOG_ADDR_TYPE_RECORD] = CEC_LOG_ADDR_MASK_RECORD, - [CEC_LOG_ADDR_TYPE_TUNER] = CEC_LOG_ADDR_MASK_TUNER, - [CEC_LOG_ADDR_TYPE_PLAYBACK] = CEC_LOG_ADDR_MASK_PLAYBACK, - [CEC_LOG_ADDR_TYPE_AUDIOSYSTEM] = CEC_LOG_ADDR_MASK_AUDIOSYSTEM, - [CEC_LOG_ADDR_TYPE_SPECIFIC] = CEC_LOG_ADDR_MASK_SPECIFIC, - }; - struct cec_adapter *adap = arg; - struct cec_log_addrs *las = &adap->log_addrs; - int err; - int i, j; - - mutex_lock(&adap->lock); - dprintk(1, "physical address: %x.%x.%x.%x, claim %d logical addresses\n", - cec_phys_addr_exp(adap->phys_addr), las->num_log_addrs); - las->log_addr_mask = 0; - - if (las->log_addr_type[0] == CEC_LOG_ADDR_TYPE_UNREGISTERED) - goto configured; - - for (i = 0; i < las->num_log_addrs; i++) { - unsigned int type = las->log_addr_type[i]; - const u8 *la_list; - u8 last_la; - - /* - * The TV functionality can only map to physical address 0. - * For any other address, try the Specific functionality - * instead as per the spec. - */ - if (adap->phys_addr && type == CEC_LOG_ADDR_TYPE_TV) - type = CEC_LOG_ADDR_TYPE_SPECIFIC; - - la_list = type2addrs[type]; - last_la = las->log_addr[i]; - las->log_addr[i] = CEC_LOG_ADDR_INVALID; - if (last_la == CEC_LOG_ADDR_INVALID || - last_la == CEC_LOG_ADDR_UNREGISTERED || - !(last_la & type2mask[type])) - last_la = la_list[0]; - - err = cec_config_log_addr(adap, i, last_la); - if (err > 0) /* Reused last LA */ - continue; - - if (err < 0) - goto unconfigure; - - for (j = 0; la_list[j] != CEC_LOG_ADDR_INVALID; j++) { - /* Tried this one already, skip it */ - if (la_list[j] == last_la) - continue; - /* The backup addresses are CEC 2.0 specific */ - if ((la_list[j] == CEC_LOG_ADDR_BACKUP_1 || - la_list[j] == CEC_LOG_ADDR_BACKUP_2) && - las->cec_version < CEC_OP_CEC_VERSION_2_0) - continue; - - err = cec_config_log_addr(adap, i, la_list[j]); - if (err == 0) /* LA is in use */ - continue; - if (err < 0) - goto unconfigure; - /* Done, claimed an LA */ - break; - } - - if (la_list[j] == CEC_LOG_ADDR_INVALID) - dprintk(1, "could not claim LA %d\n", i); - } - - if (adap->log_addrs.log_addr_mask == 0 && - !(las->flags & CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK)) - goto unconfigure; - -configured: - if (adap->log_addrs.log_addr_mask == 0) { - /* Fall back to unregistered */ - las->log_addr[0] = CEC_LOG_ADDR_UNREGISTERED; - las->log_addr_mask = 1 << las->log_addr[0]; - for (i = 1; i < las->num_log_addrs; i++) - las->log_addr[i] = CEC_LOG_ADDR_INVALID; - } - adap->is_configured = true; - adap->is_configuring = false; - cec_post_state_event(adap); - mutex_unlock(&adap->lock); - - for (i = 0; i < las->num_log_addrs; i++) { - if (las->log_addr[i] == CEC_LOG_ADDR_INVALID || - (las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY)) - continue; - - /* - * Report Features must come first according - * to CEC 2.0 - */ - if (las->log_addr[i] != CEC_LOG_ADDR_UNREGISTERED) - cec_report_features(adap, i); - cec_report_phys_addr(adap, i); - } - for (i = las->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++) - las->log_addr[i] = CEC_LOG_ADDR_INVALID; - mutex_lock(&adap->lock); - adap->kthread_config = NULL; - mutex_unlock(&adap->lock); - complete(&adap->config_completion); - return 0; - -unconfigure: - for (i = 0; i < las->num_log_addrs; i++) - las->log_addr[i] = CEC_LOG_ADDR_INVALID; - cec_adap_unconfigure(adap); - adap->kthread_config = NULL; - mutex_unlock(&adap->lock); - complete(&adap->config_completion); - return 0; -} - -/* - * Called from either __cec_s_phys_addr or __cec_s_log_addrs to claim the - * logical addresses. - * - * This function is called with adap->lock held. - */ -static void cec_claim_log_addrs(struct cec_adapter *adap, bool block) -{ - if (WARN_ON(adap->is_configuring || adap->is_configured)) - return; - - init_completion(&adap->config_completion); - - /* Ready to kick off the thread */ - adap->is_configuring = true; - adap->kthread_config = kthread_run(cec_config_thread_func, adap, - "ceccfg-%s", adap->name); - if (IS_ERR(adap->kthread_config)) { - adap->kthread_config = NULL; - } else if (block) { - mutex_unlock(&adap->lock); - wait_for_completion(&adap->config_completion); - mutex_lock(&adap->lock); - } -} - -/* Set a new physical address and send an event notifying userspace of this. - * - * This function is called with adap->lock held. - */ -void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) -{ - if (phys_addr == adap->phys_addr || adap->devnode.unregistered) - return; - - if (phys_addr == CEC_PHYS_ADDR_INVALID || - adap->phys_addr != CEC_PHYS_ADDR_INVALID) { - adap->phys_addr = CEC_PHYS_ADDR_INVALID; - cec_post_state_event(adap); - cec_adap_unconfigure(adap); - /* Disabling monitor all mode should always succeed */ - if (adap->monitor_all_cnt) - WARN_ON(call_op(adap, adap_monitor_all_enable, false)); - WARN_ON(adap->ops->adap_enable(adap, false)); - if (phys_addr == CEC_PHYS_ADDR_INVALID) - return; - } - - if (adap->ops->adap_enable(adap, true)) - return; - - if (adap->monitor_all_cnt && - call_op(adap, adap_monitor_all_enable, true)) { - WARN_ON(adap->ops->adap_enable(adap, false)); - return; - } - adap->phys_addr = phys_addr; - cec_post_state_event(adap); - if (adap->log_addrs.num_log_addrs) - cec_claim_log_addrs(adap, block); -} - -void cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block) -{ - if (IS_ERR_OR_NULL(adap)) - return; - - mutex_lock(&adap->lock); - __cec_s_phys_addr(adap, phys_addr, block); - mutex_unlock(&adap->lock); -} -EXPORT_SYMBOL_GPL(cec_s_phys_addr); - -/* - * Called from either the ioctl or a driver to set the logical addresses. - * - * This function is called with adap->lock held. - */ -int __cec_s_log_addrs(struct cec_adapter *adap, - struct cec_log_addrs *log_addrs, bool block) -{ - u16 type_mask = 0; - int i; - - if (adap->devnode.unregistered) - return -ENODEV; - - if (!log_addrs || log_addrs->num_log_addrs == 0) { - adap->log_addrs.num_log_addrs = 0; - cec_adap_unconfigure(adap); - return 0; - } - - if (log_addrs->flags & CEC_LOG_ADDRS_FL_CDC_ONLY) { - /* - * Sanitize log_addrs fields if a CDC-Only device is - * requested. - */ - log_addrs->num_log_addrs = 1; - log_addrs->osd_name[0] = '\0'; - log_addrs->vendor_id = CEC_VENDOR_ID_NONE; - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; - /* - * This is just an internal convention since a CDC-Only device - * doesn't have to be a switch. But switches already use - * unregistered, so it makes some kind of sense to pick this - * as the primary device. Since a CDC-Only device never sends - * any 'normal' CEC messages this primary device type is never - * sent over the CEC bus. - */ - log_addrs->primary_device_type[0] = CEC_OP_PRIM_DEVTYPE_SWITCH; - log_addrs->all_device_types[0] = 0; - log_addrs->features[0][0] = 0; - log_addrs->features[0][1] = 0; - } - - /* Ensure the osd name is 0-terminated */ - log_addrs->osd_name[sizeof(log_addrs->osd_name) - 1] = '\0'; - - /* Sanity checks */ - if (log_addrs->num_log_addrs > adap->available_log_addrs) { - dprintk(1, "num_log_addrs > %d\n", adap->available_log_addrs); - return -EINVAL; - } - - /* - * Vendor ID is a 24 bit number, so check if the value is - * within the correct range. - */ - if (log_addrs->vendor_id != CEC_VENDOR_ID_NONE && - (log_addrs->vendor_id & 0xff000000) != 0) - return -EINVAL; - - if (log_addrs->cec_version != CEC_OP_CEC_VERSION_1_4 && - log_addrs->cec_version != CEC_OP_CEC_VERSION_2_0) - return -EINVAL; - - if (log_addrs->num_log_addrs > 1) - for (i = 0; i < log_addrs->num_log_addrs; i++) - if (log_addrs->log_addr_type[i] == - CEC_LOG_ADDR_TYPE_UNREGISTERED) { - dprintk(1, "num_log_addrs > 1 can't be combined with unregistered LA\n"); - return -EINVAL; - } - - for (i = 0; i < log_addrs->num_log_addrs; i++) { - const u8 feature_sz = ARRAY_SIZE(log_addrs->features[0]); - u8 *features = log_addrs->features[i]; - bool op_is_dev_features = false; - - log_addrs->log_addr[i] = CEC_LOG_ADDR_INVALID; - if (type_mask & (1 << log_addrs->log_addr_type[i])) { - dprintk(1, "duplicate logical address type\n"); - return -EINVAL; - } - type_mask |= 1 << log_addrs->log_addr_type[i]; - if ((type_mask & (1 << CEC_LOG_ADDR_TYPE_RECORD)) && - (type_mask & (1 << CEC_LOG_ADDR_TYPE_PLAYBACK))) { - /* Record already contains the playback functionality */ - dprintk(1, "invalid record + playback combination\n"); - return -EINVAL; - } - if (log_addrs->primary_device_type[i] > - CEC_OP_PRIM_DEVTYPE_PROCESSOR) { - dprintk(1, "unknown primary device type\n"); - return -EINVAL; - } - if (log_addrs->primary_device_type[i] == 2) { - dprintk(1, "invalid primary device type\n"); - return -EINVAL; - } - if (log_addrs->log_addr_type[i] > CEC_LOG_ADDR_TYPE_UNREGISTERED) { - dprintk(1, "unknown logical address type\n"); - return -EINVAL; - } - for (i = 0; i < feature_sz; i++) { - if ((features[i] & 0x80) == 0) { - if (op_is_dev_features) - break; - op_is_dev_features = true; - } - } - if (!op_is_dev_features || i == feature_sz) { - dprintk(1, "malformed features\n"); - return -EINVAL; - } - /* Zero unused part of the feature array */ - memset(features + i + 1, 0, feature_sz - i - 1); - } - - if (log_addrs->cec_version >= CEC_OP_CEC_VERSION_2_0) { - if (log_addrs->num_log_addrs > 2) { - dprintk(1, "CEC 2.0 allows no more than 2 logical addresses\n"); - return -EINVAL; - } - if (log_addrs->num_log_addrs == 2) { - if (!(type_mask & ((1 << CEC_LOG_ADDR_TYPE_AUDIOSYSTEM) | - (1 << CEC_LOG_ADDR_TYPE_TV)))) { - dprintk(1, "Two LAs is only allowed for audiosystem and TV\n"); - return -EINVAL; - } - if (!(type_mask & ((1 << CEC_LOG_ADDR_TYPE_PLAYBACK) | - (1 << CEC_LOG_ADDR_TYPE_RECORD)))) { - dprintk(1, "An audiosystem/TV can only be combined with record or playback\n"); - return -EINVAL; - } - } - } - - /* Zero unused LAs */ - for (i = log_addrs->num_log_addrs; i < CEC_MAX_LOG_ADDRS; i++) { - log_addrs->primary_device_type[i] = 0; - log_addrs->log_addr_type[i] = 0; - log_addrs->all_device_types[i] = 0; - memset(log_addrs->features[i], 0, - sizeof(log_addrs->features[i])); - } - - log_addrs->log_addr_mask = adap->log_addrs.log_addr_mask; - adap->log_addrs = *log_addrs; - if (adap->phys_addr != CEC_PHYS_ADDR_INVALID) - cec_claim_log_addrs(adap, block); - return 0; -} - -int cec_s_log_addrs(struct cec_adapter *adap, - struct cec_log_addrs *log_addrs, bool block) -{ - int err; - - mutex_lock(&adap->lock); - err = __cec_s_log_addrs(adap, log_addrs, block); - mutex_unlock(&adap->lock); - return err; -} -EXPORT_SYMBOL_GPL(cec_s_log_addrs); - -/* High-level core CEC message handling */ - -/* Transmit the Report Features message */ -static int cec_report_features(struct cec_adapter *adap, unsigned int la_idx) -{ - struct cec_msg msg = { }; - const struct cec_log_addrs *las = &adap->log_addrs; - const u8 *features = las->features[la_idx]; - bool op_is_dev_features = false; - unsigned int idx; - - /* This is 2.0 and up only */ - if (adap->log_addrs.cec_version < CEC_OP_CEC_VERSION_2_0) - return 0; - - /* Report Features */ - msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f; - msg.len = 4; - msg.msg[1] = CEC_MSG_REPORT_FEATURES; - msg.msg[2] = adap->log_addrs.cec_version; - msg.msg[3] = las->all_device_types[la_idx]; - - /* Write RC Profiles first, then Device Features */ - for (idx = 0; idx < ARRAY_SIZE(las->features[0]); idx++) { - msg.msg[msg.len++] = features[idx]; - if ((features[idx] & CEC_OP_FEAT_EXT) == 0) { - if (op_is_dev_features) - break; - op_is_dev_features = true; - } - } - return cec_transmit_msg(adap, &msg, false); -} - -/* Transmit the Report Physical Address message */ -static int cec_report_phys_addr(struct cec_adapter *adap, unsigned int la_idx) -{ - const struct cec_log_addrs *las = &adap->log_addrs; - struct cec_msg msg = { }; - - /* Report Physical Address */ - msg.msg[0] = (las->log_addr[la_idx] << 4) | 0x0f; - cec_msg_report_physical_addr(&msg, adap->phys_addr, - las->primary_device_type[la_idx]); - dprintk(2, "config: la %d pa %x.%x.%x.%x\n", - las->log_addr[la_idx], - cec_phys_addr_exp(adap->phys_addr)); - return cec_transmit_msg(adap, &msg, false); -} - -/* Transmit the Feature Abort message */ -static int cec_feature_abort_reason(struct cec_adapter *adap, - struct cec_msg *msg, u8 reason) -{ - struct cec_msg tx_msg = { }; - - /* - * Don't reply with CEC_MSG_FEATURE_ABORT to a CEC_MSG_FEATURE_ABORT - * message! - */ - if (msg->msg[1] == CEC_MSG_FEATURE_ABORT) - return 0; - cec_msg_set_reply_to(&tx_msg, msg); - cec_msg_feature_abort(&tx_msg, msg->msg[1], reason); - return cec_transmit_msg(adap, &tx_msg, false); -} - -static int cec_feature_abort(struct cec_adapter *adap, struct cec_msg *msg) -{ - return cec_feature_abort_reason(adap, msg, - CEC_OP_ABORT_UNRECOGNIZED_OP); -} - -static int cec_feature_refused(struct cec_adapter *adap, struct cec_msg *msg) -{ - return cec_feature_abort_reason(adap, msg, - CEC_OP_ABORT_REFUSED); -} - -/* - * Called when a CEC message is received. This function will do any - * necessary core processing. The is_reply bool is true if this message - * is a reply to an earlier transmit. - * - * The message is either a broadcast message or a valid directed message. - */ -static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg, - bool is_reply) -{ - bool is_broadcast = cec_msg_is_broadcast(msg); - u8 dest_laddr = cec_msg_destination(msg); - u8 init_laddr = cec_msg_initiator(msg); - u8 devtype = cec_log_addr2dev(adap, dest_laddr); - int la_idx = cec_log_addr2idx(adap, dest_laddr); - bool from_unregistered = init_laddr == 0xf; - struct cec_msg tx_cec_msg = { }; - - dprintk(1, "cec_receive_notify: %*ph\n", msg->len, msg->msg); - - /* If this is a CDC-Only device, then ignore any non-CDC messages */ - if (cec_is_cdc_only(&adap->log_addrs) && - msg->msg[1] != CEC_MSG_CDC_MESSAGE) - return 0; - - if (adap->ops->received) { - /* Allow drivers to process the message first */ - if (adap->ops->received(adap, msg) != -ENOMSG) - return 0; - } - - /* - * REPORT_PHYSICAL_ADDR, CEC_MSG_USER_CONTROL_PRESSED and - * CEC_MSG_USER_CONTROL_RELEASED messages always have to be - * handled by the CEC core, even if the passthrough mode is on. - * The others are just ignored if passthrough mode is on. - */ - switch (msg->msg[1]) { - case CEC_MSG_GET_CEC_VERSION: - case CEC_MSG_GIVE_DEVICE_VENDOR_ID: - case CEC_MSG_ABORT: - case CEC_MSG_GIVE_DEVICE_POWER_STATUS: - case CEC_MSG_GIVE_PHYSICAL_ADDR: - case CEC_MSG_GIVE_OSD_NAME: - case CEC_MSG_GIVE_FEATURES: - /* - * Skip processing these messages if the passthrough mode - * is on. - */ - if (adap->passthrough) - goto skip_processing; - /* Ignore if addressing is wrong */ - if (is_broadcast || from_unregistered) - return 0; - break; - - case CEC_MSG_USER_CONTROL_PRESSED: - case CEC_MSG_USER_CONTROL_RELEASED: - /* Wrong addressing mode: don't process */ - if (is_broadcast || from_unregistered) - goto skip_processing; - break; - - case CEC_MSG_REPORT_PHYSICAL_ADDR: - /* - * This message is always processed, regardless of the - * passthrough setting. - * - * Exception: don't process if wrong addressing mode. - */ - if (!is_broadcast) - goto skip_processing; - break; - - default: - break; - } - - cec_msg_set_reply_to(&tx_cec_msg, msg); - - switch (msg->msg[1]) { - /* The following messages are processed but still passed through */ - case CEC_MSG_REPORT_PHYSICAL_ADDR: { - u16 pa = (msg->msg[2] << 8) | msg->msg[3]; - - if (!from_unregistered) - adap->phys_addrs[init_laddr] = pa; - dprintk(1, "Reported physical address %x.%x.%x.%x for logical address %d\n", - cec_phys_addr_exp(pa), init_laddr); - break; - } - - case CEC_MSG_USER_CONTROL_PRESSED: - if (!(adap->capabilities & CEC_CAP_RC) || - !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) - break; - -#if IS_REACHABLE(CONFIG_RC_CORE) - switch (msg->msg[2]) { - /* - * Play function, this message can have variable length - * depending on the specific play function that is used. - */ - case 0x60: - if (msg->len == 2) - rc_keydown(adap->rc, RC_TYPE_CEC, - msg->msg[2], 0); - else - rc_keydown(adap->rc, RC_TYPE_CEC, - msg->msg[2] << 8 | msg->msg[3], 0); - break; - /* - * Other function messages that are not handled. - * Currently the RC framework does not allow to supply an - * additional parameter to a keypress. These "keys" contain - * other information such as channel number, an input number - * etc. - * For the time being these messages are not processed by the - * framework and are simply forwarded to the user space. - */ - case 0x56: case 0x57: - case 0x67: case 0x68: case 0x69: case 0x6a: - break; - default: - rc_keydown(adap->rc, RC_TYPE_CEC, msg->msg[2], 0); - break; - } -#endif - break; - - case CEC_MSG_USER_CONTROL_RELEASED: - if (!(adap->capabilities & CEC_CAP_RC) || - !(adap->log_addrs.flags & CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU)) - break; -#if IS_REACHABLE(CONFIG_RC_CORE) - rc_keyup(adap->rc); -#endif - break; - - /* - * The remaining messages are only processed if the passthrough mode - * is off. - */ - case CEC_MSG_GET_CEC_VERSION: - cec_msg_cec_version(&tx_cec_msg, adap->log_addrs.cec_version); - return cec_transmit_msg(adap, &tx_cec_msg, false); - - case CEC_MSG_GIVE_PHYSICAL_ADDR: - /* Do nothing for CEC switches using addr 15 */ - if (devtype == CEC_OP_PRIM_DEVTYPE_SWITCH && dest_laddr == 15) - return 0; - cec_msg_report_physical_addr(&tx_cec_msg, adap->phys_addr, devtype); - return cec_transmit_msg(adap, &tx_cec_msg, false); - - case CEC_MSG_GIVE_DEVICE_VENDOR_ID: - if (adap->log_addrs.vendor_id == CEC_VENDOR_ID_NONE) - return cec_feature_abort(adap, msg); - cec_msg_device_vendor_id(&tx_cec_msg, adap->log_addrs.vendor_id); - return cec_transmit_msg(adap, &tx_cec_msg, false); - - case CEC_MSG_ABORT: - /* Do nothing for CEC switches */ - if (devtype == CEC_OP_PRIM_DEVTYPE_SWITCH) - return 0; - return cec_feature_refused(adap, msg); - - case CEC_MSG_GIVE_OSD_NAME: { - if (adap->log_addrs.osd_name[0] == 0) - return cec_feature_abort(adap, msg); - cec_msg_set_osd_name(&tx_cec_msg, adap->log_addrs.osd_name); - return cec_transmit_msg(adap, &tx_cec_msg, false); - } - - case CEC_MSG_GIVE_FEATURES: - if (adap->log_addrs.cec_version >= CEC_OP_CEC_VERSION_2_0) - return cec_report_features(adap, la_idx); - return 0; - - default: - /* - * Unprocessed messages are aborted if userspace isn't doing - * any processing either. - */ - if (!is_broadcast && !is_reply && !adap->follower_cnt && - !adap->cec_follower && msg->msg[1] != CEC_MSG_FEATURE_ABORT) - return cec_feature_abort(adap, msg); - break; - } - -skip_processing: - /* If this was a reply, then we're done, unless otherwise specified */ - if (is_reply && !(msg->flags & CEC_MSG_FL_REPLY_TO_FOLLOWERS)) - return 0; - - /* - * Send to the exclusive follower if there is one, otherwise send - * to all followers. - */ - if (adap->cec_follower) - cec_queue_msg_fh(adap->cec_follower, msg); - else - cec_queue_msg_followers(adap, msg); - return 0; -} - -/* - * Helper functions to keep track of the 'monitor all' use count. - * - * These functions are called with adap->lock held. - */ -int cec_monitor_all_cnt_inc(struct cec_adapter *adap) -{ - int ret = 0; - - if (adap->monitor_all_cnt == 0) - ret = call_op(adap, adap_monitor_all_enable, 1); - if (ret == 0) - adap->monitor_all_cnt++; - return ret; -} - -void cec_monitor_all_cnt_dec(struct cec_adapter *adap) -{ - adap->monitor_all_cnt--; - if (adap->monitor_all_cnt == 0) - WARN_ON(call_op(adap, adap_monitor_all_enable, 0)); -} - -#ifdef CONFIG_MEDIA_CEC_DEBUG -/* - * Log the current state of the CEC adapter. - * Very useful for debugging. - */ -int cec_adap_status(struct seq_file *file, void *priv) -{ - struct cec_adapter *adap = dev_get_drvdata(file->private); - struct cec_data *data; - - mutex_lock(&adap->lock); - seq_printf(file, "configured: %d\n", adap->is_configured); - seq_printf(file, "configuring: %d\n", adap->is_configuring); - seq_printf(file, "phys_addr: %x.%x.%x.%x\n", - cec_phys_addr_exp(adap->phys_addr)); - seq_printf(file, "number of LAs: %d\n", adap->log_addrs.num_log_addrs); - seq_printf(file, "LA mask: 0x%04x\n", adap->log_addrs.log_addr_mask); - if (adap->cec_follower) - seq_printf(file, "has CEC follower%s\n", - adap->passthrough ? " (in passthrough mode)" : ""); - if (adap->cec_initiator) - seq_puts(file, "has CEC initiator\n"); - if (adap->monitor_all_cnt) - seq_printf(file, "file handles in Monitor All mode: %u\n", - adap->monitor_all_cnt); - data = adap->transmitting; - if (data) - seq_printf(file, "transmitting message: %*ph (reply: %02x, timeout: %ums)\n", - data->msg.len, data->msg.msg, data->msg.reply, - data->msg.timeout); - seq_printf(file, "pending transmits: %u\n", adap->transmit_queue_sz); - list_for_each_entry(data, &adap->transmit_queue, list) { - seq_printf(file, "queued tx message: %*ph (reply: %02x, timeout: %ums)\n", - data->msg.len, data->msg.msg, data->msg.reply, - data->msg.timeout); - } - list_for_each_entry(data, &adap->wait_queue, list) { - seq_printf(file, "message waiting for reply: %*ph (reply: %02x, timeout: %ums)\n", - data->msg.len, data->msg.msg, data->msg.reply, - data->msg.timeout); - } - - call_void_op(adap, adap_status, file); - mutex_unlock(&adap->lock); - return 0; -} -#endif diff --git a/drivers/staging/media/cec/cec-api.c b/drivers/staging/media/cec/cec-api.c deleted file mode 100644 index d4bc4ee2c6e5..000000000000 --- a/drivers/staging/media/cec/cec-api.c +++ /dev/null @@ -1,588 +0,0 @@ -/* - * cec-api.c - HDMI Consumer Electronics Control framework - API - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cec-priv.h" - -static inline struct cec_devnode *cec_devnode_data(struct file *filp) -{ - struct cec_fh *fh = filp->private_data; - - return &fh->adap->devnode; -} - -/* CEC file operations */ - -static unsigned int cec_poll(struct file *filp, - struct poll_table_struct *poll) -{ - struct cec_devnode *devnode = cec_devnode_data(filp); - struct cec_fh *fh = filp->private_data; - struct cec_adapter *adap = fh->adap; - unsigned int res = 0; - - if (!devnode->registered) - return POLLERR | POLLHUP; - mutex_lock(&adap->lock); - if (adap->is_configured && - adap->transmit_queue_sz < CEC_MAX_MSG_TX_QUEUE_SZ) - res |= POLLOUT | POLLWRNORM; - if (fh->queued_msgs) - res |= POLLIN | POLLRDNORM; - if (fh->pending_events) - res |= POLLPRI; - poll_wait(filp, &fh->wait, poll); - mutex_unlock(&adap->lock); - return res; -} - -static bool cec_is_busy(const struct cec_adapter *adap, - const struct cec_fh *fh) -{ - bool valid_initiator = adap->cec_initiator && adap->cec_initiator == fh; - bool valid_follower = adap->cec_follower && adap->cec_follower == fh; - - /* - * Exclusive initiators and followers can always access the CEC adapter - */ - if (valid_initiator || valid_follower) - return false; - /* - * All others can only access the CEC adapter if there is no - * exclusive initiator and they are in INITIATOR mode. - */ - return adap->cec_initiator || - fh->mode_initiator == CEC_MODE_NO_INITIATOR; -} - -static long cec_adap_g_caps(struct cec_adapter *adap, - struct cec_caps __user *parg) -{ - struct cec_caps caps = {}; - - strlcpy(caps.driver, adap->devnode.parent->driver->name, - sizeof(caps.driver)); - strlcpy(caps.name, adap->name, sizeof(caps.name)); - caps.available_log_addrs = adap->available_log_addrs; - caps.capabilities = adap->capabilities; - caps.version = LINUX_VERSION_CODE; - if (copy_to_user(parg, &caps, sizeof(caps))) - return -EFAULT; - return 0; -} - -static long cec_adap_g_phys_addr(struct cec_adapter *adap, - __u16 __user *parg) -{ - u16 phys_addr; - - mutex_lock(&adap->lock); - phys_addr = adap->phys_addr; - mutex_unlock(&adap->lock); - if (copy_to_user(parg, &phys_addr, sizeof(phys_addr))) - return -EFAULT; - return 0; -} - -static long cec_adap_s_phys_addr(struct cec_adapter *adap, struct cec_fh *fh, - bool block, __u16 __user *parg) -{ - u16 phys_addr; - long err; - - if (!(adap->capabilities & CEC_CAP_PHYS_ADDR)) - return -ENOTTY; - if (copy_from_user(&phys_addr, parg, sizeof(phys_addr))) - return -EFAULT; - - err = cec_phys_addr_validate(phys_addr, NULL, NULL); - if (err) - return err; - mutex_lock(&adap->lock); - if (cec_is_busy(adap, fh)) - err = -EBUSY; - else - __cec_s_phys_addr(adap, phys_addr, block); - mutex_unlock(&adap->lock); - return err; -} - -static long cec_adap_g_log_addrs(struct cec_adapter *adap, - struct cec_log_addrs __user *parg) -{ - struct cec_log_addrs log_addrs; - - mutex_lock(&adap->lock); - log_addrs = adap->log_addrs; - if (!adap->is_configured) - memset(log_addrs.log_addr, CEC_LOG_ADDR_INVALID, - sizeof(log_addrs.log_addr)); - mutex_unlock(&adap->lock); - - if (copy_to_user(parg, &log_addrs, sizeof(log_addrs))) - return -EFAULT; - return 0; -} - -static long cec_adap_s_log_addrs(struct cec_adapter *adap, struct cec_fh *fh, - bool block, struct cec_log_addrs __user *parg) -{ - struct cec_log_addrs log_addrs; - long err = -EBUSY; - - if (!(adap->capabilities & CEC_CAP_LOG_ADDRS)) - return -ENOTTY; - if (copy_from_user(&log_addrs, parg, sizeof(log_addrs))) - return -EFAULT; - log_addrs.flags &= CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK | - CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU | - CEC_LOG_ADDRS_FL_CDC_ONLY; - mutex_lock(&adap->lock); - if (!adap->is_configuring && - (!log_addrs.num_log_addrs || !adap->is_configured) && - !cec_is_busy(adap, fh)) { - err = __cec_s_log_addrs(adap, &log_addrs, block); - if (!err) - log_addrs = adap->log_addrs; - } - mutex_unlock(&adap->lock); - if (err) - return err; - if (copy_to_user(parg, &log_addrs, sizeof(log_addrs))) - return -EFAULT; - return 0; -} - -static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, - bool block, struct cec_msg __user *parg) -{ - struct cec_msg msg = {}; - long err = 0; - - if (!(adap->capabilities & CEC_CAP_TRANSMIT)) - return -ENOTTY; - if (copy_from_user(&msg, parg, sizeof(msg))) - return -EFAULT; - - /* A CDC-Only device can only send CDC messages */ - if ((adap->log_addrs.flags & CEC_LOG_ADDRS_FL_CDC_ONLY) && - (msg.len == 1 || msg.msg[1] != CEC_MSG_CDC_MESSAGE)) - return -EINVAL; - - msg.flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; - mutex_lock(&adap->lock); - if (!adap->is_configured) - err = -ENONET; - else if (cec_is_busy(adap, fh)) - err = -EBUSY; - else - err = cec_transmit_msg_fh(adap, &msg, fh, block); - mutex_unlock(&adap->lock); - if (err) - return err; - if (copy_to_user(parg, &msg, sizeof(msg))) - return -EFAULT; - return 0; -} - -/* Called by CEC_RECEIVE: wait for a message to arrive */ -static int cec_receive_msg(struct cec_fh *fh, struct cec_msg *msg, bool block) -{ - u32 timeout = msg->timeout; - int res; - - do { - mutex_lock(&fh->lock); - /* Are there received messages queued up? */ - if (fh->queued_msgs) { - /* Yes, return the first one */ - struct cec_msg_entry *entry = - list_first_entry(&fh->msgs, - struct cec_msg_entry, list); - - list_del(&entry->list); - *msg = entry->msg; - kfree(entry); - fh->queued_msgs--; - mutex_unlock(&fh->lock); - /* restore original timeout value */ - msg->timeout = timeout; - return 0; - } - - /* No, return EAGAIN in non-blocking mode or wait */ - mutex_unlock(&fh->lock); - - /* Return when in non-blocking mode */ - if (!block) - return -EAGAIN; - - if (msg->timeout) { - /* The user specified a timeout */ - res = wait_event_interruptible_timeout(fh->wait, - fh->queued_msgs, - msecs_to_jiffies(msg->timeout)); - if (res == 0) - res = -ETIMEDOUT; - else if (res > 0) - res = 0; - } else { - /* Wait indefinitely */ - res = wait_event_interruptible(fh->wait, - fh->queued_msgs); - } - /* Exit on error, otherwise loop to get the new message */ - } while (!res); - return res; -} - -static long cec_receive(struct cec_adapter *adap, struct cec_fh *fh, - bool block, struct cec_msg __user *parg) -{ - struct cec_msg msg = {}; - long err = 0; - - if (copy_from_user(&msg, parg, sizeof(msg))) - return -EFAULT; - mutex_lock(&adap->lock); - if (!adap->is_configured && fh->mode_follower < CEC_MODE_MONITOR) - err = -ENONET; - mutex_unlock(&adap->lock); - if (err) - return err; - - err = cec_receive_msg(fh, &msg, block); - if (err) - return err; - if (copy_to_user(parg, &msg, sizeof(msg))) - return -EFAULT; - return 0; -} - -static long cec_dqevent(struct cec_adapter *adap, struct cec_fh *fh, - bool block, struct cec_event __user *parg) -{ - struct cec_event *ev = NULL; - u64 ts = ~0ULL; - unsigned int i; - long err = 0; - - mutex_lock(&fh->lock); - while (!fh->pending_events && block) { - mutex_unlock(&fh->lock); - err = wait_event_interruptible(fh->wait, fh->pending_events); - if (err) - return err; - mutex_lock(&fh->lock); - } - - /* Find the oldest event */ - for (i = 0; i < CEC_NUM_EVENTS; i++) { - if (fh->pending_events & (1 << (i + 1)) && - fh->events[i].ts <= ts) { - ev = &fh->events[i]; - ts = ev->ts; - } - } - if (!ev) { - err = -EAGAIN; - goto unlock; - } - - if (copy_to_user(parg, ev, sizeof(*ev))) { - err = -EFAULT; - goto unlock; - } - - fh->pending_events &= ~(1 << ev->event); - -unlock: - mutex_unlock(&fh->lock); - return err; -} - -static long cec_g_mode(struct cec_adapter *adap, struct cec_fh *fh, - u32 __user *parg) -{ - u32 mode = fh->mode_initiator | fh->mode_follower; - - if (copy_to_user(parg, &mode, sizeof(mode))) - return -EFAULT; - return 0; -} - -static long cec_s_mode(struct cec_adapter *adap, struct cec_fh *fh, - u32 __user *parg) -{ - u32 mode; - u8 mode_initiator; - u8 mode_follower; - long err = 0; - - if (copy_from_user(&mode, parg, sizeof(mode))) - return -EFAULT; - if (mode & ~(CEC_MODE_INITIATOR_MSK | CEC_MODE_FOLLOWER_MSK)) - return -EINVAL; - - mode_initiator = mode & CEC_MODE_INITIATOR_MSK; - mode_follower = mode & CEC_MODE_FOLLOWER_MSK; - - if (mode_initiator > CEC_MODE_EXCL_INITIATOR || - mode_follower > CEC_MODE_MONITOR_ALL) - return -EINVAL; - - if (mode_follower == CEC_MODE_MONITOR_ALL && - !(adap->capabilities & CEC_CAP_MONITOR_ALL)) - return -EINVAL; - - /* Follower modes should always be able to send CEC messages */ - if ((mode_initiator == CEC_MODE_NO_INITIATOR || - !(adap->capabilities & CEC_CAP_TRANSMIT)) && - mode_follower >= CEC_MODE_FOLLOWER && - mode_follower <= CEC_MODE_EXCL_FOLLOWER_PASSTHRU) - return -EINVAL; - - /* Monitor modes require CEC_MODE_NO_INITIATOR */ - if (mode_initiator && mode_follower >= CEC_MODE_MONITOR) - return -EINVAL; - - /* Monitor modes require CAP_NET_ADMIN */ - if (mode_follower >= CEC_MODE_MONITOR && !capable(CAP_NET_ADMIN)) - return -EPERM; - - mutex_lock(&adap->lock); - /* - * You can't become exclusive follower if someone else already - * has that job. - */ - if ((mode_follower == CEC_MODE_EXCL_FOLLOWER || - mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) && - adap->cec_follower && adap->cec_follower != fh) - err = -EBUSY; - /* - * You can't become exclusive initiator if someone else already - * has that job. - */ - if (mode_initiator == CEC_MODE_EXCL_INITIATOR && - adap->cec_initiator && adap->cec_initiator != fh) - err = -EBUSY; - - if (!err) { - bool old_mon_all = fh->mode_follower == CEC_MODE_MONITOR_ALL; - bool new_mon_all = mode_follower == CEC_MODE_MONITOR_ALL; - - if (old_mon_all != new_mon_all) { - if (new_mon_all) - err = cec_monitor_all_cnt_inc(adap); - else - cec_monitor_all_cnt_dec(adap); - } - } - - if (err) { - mutex_unlock(&adap->lock); - return err; - } - - if (fh->mode_follower == CEC_MODE_FOLLOWER) - adap->follower_cnt--; - if (mode_follower == CEC_MODE_FOLLOWER) - adap->follower_cnt++; - if (mode_follower == CEC_MODE_EXCL_FOLLOWER || - mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU) { - adap->passthrough = - mode_follower == CEC_MODE_EXCL_FOLLOWER_PASSTHRU; - adap->cec_follower = fh; - } else if (adap->cec_follower == fh) { - adap->passthrough = false; - adap->cec_follower = NULL; - } - if (mode_initiator == CEC_MODE_EXCL_INITIATOR) - adap->cec_initiator = fh; - else if (adap->cec_initiator == fh) - adap->cec_initiator = NULL; - fh->mode_initiator = mode_initiator; - fh->mode_follower = mode_follower; - mutex_unlock(&adap->lock); - return 0; -} - -static long cec_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct cec_devnode *devnode = cec_devnode_data(filp); - struct cec_fh *fh = filp->private_data; - struct cec_adapter *adap = fh->adap; - bool block = !(filp->f_flags & O_NONBLOCK); - void __user *parg = (void __user *)arg; - - if (!devnode->registered) - return -ENODEV; - - switch (cmd) { - case CEC_ADAP_G_CAPS: - return cec_adap_g_caps(adap, parg); - - case CEC_ADAP_G_PHYS_ADDR: - return cec_adap_g_phys_addr(adap, parg); - - case CEC_ADAP_S_PHYS_ADDR: - return cec_adap_s_phys_addr(adap, fh, block, parg); - - case CEC_ADAP_G_LOG_ADDRS: - return cec_adap_g_log_addrs(adap, parg); - - case CEC_ADAP_S_LOG_ADDRS: - return cec_adap_s_log_addrs(adap, fh, block, parg); - - case CEC_TRANSMIT: - return cec_transmit(adap, fh, block, parg); - - case CEC_RECEIVE: - return cec_receive(adap, fh, block, parg); - - case CEC_DQEVENT: - return cec_dqevent(adap, fh, block, parg); - - case CEC_G_MODE: - return cec_g_mode(adap, fh, parg); - - case CEC_S_MODE: - return cec_s_mode(adap, fh, parg); - - default: - return -ENOTTY; - } -} - -static int cec_open(struct inode *inode, struct file *filp) -{ - struct cec_devnode *devnode = - container_of(inode->i_cdev, struct cec_devnode, cdev); - struct cec_adapter *adap = to_cec_adapter(devnode); - struct cec_fh *fh = kzalloc(sizeof(*fh), GFP_KERNEL); - /* - * Initial events that are automatically sent when the cec device is - * opened. - */ - struct cec_event ev_state = { - .event = CEC_EVENT_STATE_CHANGE, - .flags = CEC_EVENT_FL_INITIAL_STATE, - }; - int err; - - if (!fh) - return -ENOMEM; - - INIT_LIST_HEAD(&fh->msgs); - INIT_LIST_HEAD(&fh->xfer_list); - mutex_init(&fh->lock); - init_waitqueue_head(&fh->wait); - - fh->mode_initiator = CEC_MODE_INITIATOR; - fh->adap = adap; - - err = cec_get_device(devnode); - if (err) { - kfree(fh); - return err; - } - - filp->private_data = fh; - - mutex_lock(&devnode->lock); - /* Queue up initial state events */ - ev_state.state_change.phys_addr = adap->phys_addr; - ev_state.state_change.log_addr_mask = adap->log_addrs.log_addr_mask; - cec_queue_event_fh(fh, &ev_state, 0); - - list_add(&fh->list, &devnode->fhs); - mutex_unlock(&devnode->lock); - - return 0; -} - -/* Override for the release function */ -static int cec_release(struct inode *inode, struct file *filp) -{ - struct cec_devnode *devnode = cec_devnode_data(filp); - struct cec_adapter *adap = to_cec_adapter(devnode); - struct cec_fh *fh = filp->private_data; - - mutex_lock(&adap->lock); - if (adap->cec_initiator == fh) - adap->cec_initiator = NULL; - if (adap->cec_follower == fh) { - adap->cec_follower = NULL; - adap->passthrough = false; - } - if (fh->mode_follower == CEC_MODE_FOLLOWER) - adap->follower_cnt--; - if (fh->mode_follower == CEC_MODE_MONITOR_ALL) - cec_monitor_all_cnt_dec(adap); - mutex_unlock(&adap->lock); - - mutex_lock(&devnode->lock); - list_del(&fh->list); - mutex_unlock(&devnode->lock); - - /* Unhook pending transmits from this filehandle. */ - mutex_lock(&adap->lock); - while (!list_empty(&fh->xfer_list)) { - struct cec_data *data = - list_first_entry(&fh->xfer_list, struct cec_data, xfer_list); - - data->blocking = false; - data->fh = NULL; - list_del(&data->xfer_list); - } - mutex_unlock(&adap->lock); - while (!list_empty(&fh->msgs)) { - struct cec_msg_entry *entry = - list_first_entry(&fh->msgs, struct cec_msg_entry, list); - - list_del(&entry->list); - kfree(entry); - } - kfree(fh); - - cec_put_device(devnode); - filp->private_data = NULL; - return 0; -} - -const struct file_operations cec_devnode_fops = { - .owner = THIS_MODULE, - .open = cec_open, - .unlocked_ioctl = cec_ioctl, - .release = cec_release, - .poll = cec_poll, - .llseek = no_llseek, -}; diff --git a/drivers/staging/media/cec/cec-core.c b/drivers/staging/media/cec/cec-core.c deleted file mode 100644 index b0137e247dc9..000000000000 --- a/drivers/staging/media/cec/cec-core.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * cec-core.c - HDMI Consumer Electronics Control framework - Core - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cec-priv.h" - -#define CEC_NUM_DEVICES 256 -#define CEC_NAME "cec" - -int cec_debug; -module_param_named(debug, cec_debug, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-2)"); - -static dev_t cec_dev_t; - -/* Active devices */ -static DEFINE_MUTEX(cec_devnode_lock); -static DECLARE_BITMAP(cec_devnode_nums, CEC_NUM_DEVICES); - -static struct dentry *top_cec_dir; - -/* dev to cec_devnode */ -#define to_cec_devnode(cd) container_of(cd, struct cec_devnode, dev) - -int cec_get_device(struct cec_devnode *devnode) -{ - /* - * Check if the cec device is available. This needs to be done with - * the devnode->lock held to prevent an open/unregister race: - * without the lock, the device could be unregistered and freed between - * the devnode->registered check and get_device() calls, leading to - * a crash. - */ - mutex_lock(&devnode->lock); - /* - * return ENXIO if the cec device has been removed - * already or if it is not registered anymore. - */ - if (!devnode->registered) { - mutex_unlock(&devnode->lock); - return -ENXIO; - } - /* and increase the device refcount */ - get_device(&devnode->dev); - mutex_unlock(&devnode->lock); - return 0; -} - -void cec_put_device(struct cec_devnode *devnode) -{ - put_device(&devnode->dev); -} - -/* Called when the last user of the cec device exits. */ -static void cec_devnode_release(struct device *cd) -{ - struct cec_devnode *devnode = to_cec_devnode(cd); - - mutex_lock(&cec_devnode_lock); - /* Mark device node number as free */ - clear_bit(devnode->minor, cec_devnode_nums); - mutex_unlock(&cec_devnode_lock); - - cec_delete_adapter(to_cec_adapter(devnode)); -} - -static struct bus_type cec_bus_type = { - .name = CEC_NAME, -}; - -/* - * Register a cec device node - * - * The registration code assigns minor numbers and registers the new device node - * with the kernel. An error is returned if no free minor number can be found, - * or if the registration of the device node fails. - * - * Zero is returned on success. - * - * Note that if the cec_devnode_register call fails, the release() callback of - * the cec_devnode structure is *not* called, so the caller is responsible for - * freeing any data. - */ -static int __must_check cec_devnode_register(struct cec_devnode *devnode, - struct module *owner) -{ - int minor; - int ret; - - /* Initialization */ - INIT_LIST_HEAD(&devnode->fhs); - mutex_init(&devnode->lock); - - /* Part 1: Find a free minor number */ - mutex_lock(&cec_devnode_lock); - minor = find_next_zero_bit(cec_devnode_nums, CEC_NUM_DEVICES, 0); - if (minor == CEC_NUM_DEVICES) { - mutex_unlock(&cec_devnode_lock); - pr_err("could not get a free minor\n"); - return -ENFILE; - } - - set_bit(minor, cec_devnode_nums); - mutex_unlock(&cec_devnode_lock); - - devnode->minor = minor; - devnode->dev.bus = &cec_bus_type; - devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor); - devnode->dev.release = cec_devnode_release; - devnode->dev.parent = devnode->parent; - dev_set_name(&devnode->dev, "cec%d", devnode->minor); - device_initialize(&devnode->dev); - - /* Part 2: Initialize and register the character device */ - cdev_init(&devnode->cdev, &cec_devnode_fops); - devnode->cdev.kobj.parent = &devnode->dev.kobj; - devnode->cdev.owner = owner; - - ret = cdev_add(&devnode->cdev, devnode->dev.devt, 1); - if (ret < 0) { - pr_err("%s: cdev_add failed\n", __func__); - goto clr_bit; - } - - ret = device_add(&devnode->dev); - if (ret) - goto cdev_del; - - devnode->registered = true; - return 0; - -cdev_del: - cdev_del(&devnode->cdev); -clr_bit: - mutex_lock(&cec_devnode_lock); - clear_bit(devnode->minor, cec_devnode_nums); - mutex_unlock(&cec_devnode_lock); - return ret; -} - -/* - * Unregister a cec device node - * - * This unregisters the passed device. Future open calls will be met with - * errors. - * - * This function can safely be called if the device node has never been - * registered or has already been unregistered. - */ -static void cec_devnode_unregister(struct cec_devnode *devnode) -{ - struct cec_fh *fh; - - mutex_lock(&devnode->lock); - - /* Check if devnode was never registered or already unregistered */ - if (!devnode->registered || devnode->unregistered) { - mutex_unlock(&devnode->lock); - return; - } - - list_for_each_entry(fh, &devnode->fhs, list) - wake_up_interruptible(&fh->wait); - - devnode->registered = false; - devnode->unregistered = true; - mutex_unlock(&devnode->lock); - - device_del(&devnode->dev); - cdev_del(&devnode->cdev); - put_device(&devnode->dev); -} - -struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, - void *priv, const char *name, u32 caps, - u8 available_las, struct device *parent) -{ - struct cec_adapter *adap; - int res; - - if (WARN_ON(!parent)) - return ERR_PTR(-EINVAL); - if (WARN_ON(!caps)) - return ERR_PTR(-EINVAL); - if (WARN_ON(!ops)) - return ERR_PTR(-EINVAL); - if (WARN_ON(!available_las || available_las > CEC_MAX_LOG_ADDRS)) - return ERR_PTR(-EINVAL); - adap = kzalloc(sizeof(*adap), GFP_KERNEL); - if (!adap) - return ERR_PTR(-ENOMEM); - adap->owner = parent->driver->owner; - adap->devnode.parent = parent; - strlcpy(adap->name, name, sizeof(adap->name)); - adap->phys_addr = CEC_PHYS_ADDR_INVALID; - adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; - adap->log_addrs.vendor_id = CEC_VENDOR_ID_NONE; - adap->capabilities = caps; - adap->available_log_addrs = available_las; - adap->sequence = 0; - adap->ops = ops; - adap->priv = priv; - memset(adap->phys_addrs, 0xff, sizeof(adap->phys_addrs)); - mutex_init(&adap->lock); - INIT_LIST_HEAD(&adap->transmit_queue); - INIT_LIST_HEAD(&adap->wait_queue); - init_waitqueue_head(&adap->kthread_waitq); - - adap->kthread = kthread_run(cec_thread_func, adap, "cec-%s", name); - if (IS_ERR(adap->kthread)) { - pr_err("cec-%s: kernel_thread() failed\n", name); - res = PTR_ERR(adap->kthread); - kfree(adap); - return ERR_PTR(res); - } - - if (!(caps & CEC_CAP_RC)) - return adap; - -#if IS_REACHABLE(CONFIG_RC_CORE) - /* Prepare the RC input device */ - adap->rc = rc_allocate_device(); - if (!adap->rc) { - pr_err("cec-%s: failed to allocate memory for rc_dev\n", - name); - kthread_stop(adap->kthread); - kfree(adap); - return ERR_PTR(-ENOMEM); - } - - snprintf(adap->input_name, sizeof(adap->input_name), - "RC for %s", name); - snprintf(adap->input_phys, sizeof(adap->input_phys), - "%s/input0", name); - - adap->rc->input_name = adap->input_name; - adap->rc->input_phys = adap->input_phys; - adap->rc->input_id.bustype = BUS_CEC; - adap->rc->input_id.vendor = 0; - adap->rc->input_id.product = 0; - adap->rc->input_id.version = 1; - adap->rc->dev.parent = parent; - adap->rc->driver_type = RC_DRIVER_SCANCODE; - adap->rc->driver_name = CEC_NAME; - adap->rc->allowed_protocols = RC_BIT_CEC; - adap->rc->priv = adap; - adap->rc->map_name = RC_MAP_CEC; - adap->rc->timeout = MS_TO_NS(100); -#else - adap->capabilities &= ~CEC_CAP_RC; -#endif - return adap; -} -EXPORT_SYMBOL_GPL(cec_allocate_adapter); - -int cec_register_adapter(struct cec_adapter *adap) -{ - int res; - - if (IS_ERR_OR_NULL(adap)) - return 0; - -#if IS_REACHABLE(CONFIG_RC_CORE) - if (adap->capabilities & CEC_CAP_RC) { - res = rc_register_device(adap->rc); - - if (res) { - pr_err("cec-%s: failed to prepare input device\n", - adap->name); - rc_free_device(adap->rc); - adap->rc = NULL; - return res; - } - } -#endif - - res = cec_devnode_register(&adap->devnode, adap->owner); - if (res) { -#if IS_REACHABLE(CONFIG_RC_CORE) - /* Note: rc_unregister also calls rc_free */ - rc_unregister_device(adap->rc); - adap->rc = NULL; -#endif - return res; - } - - dev_set_drvdata(&adap->devnode.dev, adap); -#ifdef CONFIG_MEDIA_CEC_DEBUG - if (!top_cec_dir) - return 0; - - adap->cec_dir = debugfs_create_dir(dev_name(&adap->devnode.dev), top_cec_dir); - if (IS_ERR_OR_NULL(adap->cec_dir)) { - pr_warn("cec-%s: Failed to create debugfs dir\n", adap->name); - return 0; - } - adap->status_file = debugfs_create_devm_seqfile(&adap->devnode.dev, - "status", adap->cec_dir, cec_adap_status); - if (IS_ERR_OR_NULL(adap->status_file)) { - pr_warn("cec-%s: Failed to create status file\n", adap->name); - debugfs_remove_recursive(adap->cec_dir); - adap->cec_dir = NULL; - } -#endif - return 0; -} -EXPORT_SYMBOL_GPL(cec_register_adapter); - -void cec_unregister_adapter(struct cec_adapter *adap) -{ - if (IS_ERR_OR_NULL(adap)) - return; - -#if IS_REACHABLE(CONFIG_RC_CORE) - /* Note: rc_unregister also calls rc_free */ - rc_unregister_device(adap->rc); - adap->rc = NULL; -#endif - debugfs_remove_recursive(adap->cec_dir); - cec_devnode_unregister(&adap->devnode); -} -EXPORT_SYMBOL_GPL(cec_unregister_adapter); - -void cec_delete_adapter(struct cec_adapter *adap) -{ - if (IS_ERR_OR_NULL(adap)) - return; - mutex_lock(&adap->lock); - __cec_s_phys_addr(adap, CEC_PHYS_ADDR_INVALID, false); - mutex_unlock(&adap->lock); - kthread_stop(adap->kthread); - if (adap->kthread_config) - kthread_stop(adap->kthread_config); -#if IS_REACHABLE(CONFIG_RC_CORE) - rc_free_device(adap->rc); -#endif - kfree(adap); -} -EXPORT_SYMBOL_GPL(cec_delete_adapter); - -/* - * Initialise cec for linux - */ -static int __init cec_devnode_init(void) -{ - int ret; - - pr_info("Linux cec interface: v0.10\n"); - ret = alloc_chrdev_region(&cec_dev_t, 0, CEC_NUM_DEVICES, - CEC_NAME); - if (ret < 0) { - pr_warn("cec: unable to allocate major\n"); - return ret; - } - -#ifdef CONFIG_MEDIA_CEC_DEBUG - top_cec_dir = debugfs_create_dir("cec", NULL); - if (IS_ERR_OR_NULL(top_cec_dir)) { - pr_warn("cec: Failed to create debugfs cec dir\n"); - top_cec_dir = NULL; - } -#endif - - ret = bus_register(&cec_bus_type); - if (ret < 0) { - unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); - pr_warn("cec: bus_register failed\n"); - return -EIO; - } - - return 0; -} - -static void __exit cec_devnode_exit(void) -{ - debugfs_remove_recursive(top_cec_dir); - bus_unregister(&cec_bus_type); - unregister_chrdev_region(cec_dev_t, CEC_NUM_DEVICES); -} - -subsys_initcall(cec_devnode_init); -module_exit(cec_devnode_exit) - -MODULE_AUTHOR("Hans Verkuil "); -MODULE_DESCRIPTION("Device node registration for cec drivers"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/media/cec/cec-priv.h b/drivers/staging/media/cec/cec-priv.h deleted file mode 100644 index 70767a7900f2..000000000000 --- a/drivers/staging/media/cec/cec-priv.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * cec-priv.h - HDMI Consumer Electronics Control internal header - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _CEC_PRIV_H -#define _CEC_PRIV_H - -#include -#include - -#define dprintk(lvl, fmt, arg...) \ - do { \ - if (lvl <= cec_debug) \ - pr_info("cec-%s: " fmt, adap->name, ## arg); \ - } while (0) - -/* devnode to cec_adapter */ -#define to_cec_adapter(node) container_of(node, struct cec_adapter, devnode) - -/* cec-core.c */ -extern int cec_debug; -int cec_get_device(struct cec_devnode *devnode); -void cec_put_device(struct cec_devnode *devnode); - -/* cec-adap.c */ -int cec_monitor_all_cnt_inc(struct cec_adapter *adap); -void cec_monitor_all_cnt_dec(struct cec_adapter *adap); -int cec_adap_status(struct seq_file *file, void *priv); -int cec_thread_func(void *_adap); -void __cec_s_phys_addr(struct cec_adapter *adap, u16 phys_addr, bool block); -int __cec_s_log_addrs(struct cec_adapter *adap, - struct cec_log_addrs *log_addrs, bool block); -int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, - struct cec_fh *fh, bool block); -void cec_queue_event_fh(struct cec_fh *fh, - const struct cec_event *new_ev, u64 ts); - -/* cec-api.c */ -extern const struct file_operations cec_devnode_fops; - -#endif diff --git a/drivers/staging/media/pulse8-cec/Kconfig b/drivers/staging/media/pulse8-cec/Kconfig index c6aa2d1c9df0..6ffc407de62f 100644 --- a/drivers/staging/media/pulse8-cec/Kconfig +++ b/drivers/staging/media/pulse8-cec/Kconfig @@ -1,6 +1,6 @@ config USB_PULSE8_CEC tristate "Pulse Eight HDMI CEC" - depends on USB_ACM && MEDIA_CEC + depends on USB_ACM && MEDIA_CEC_SUPPORT select SERIO select SERIO_SERPORT ---help--- diff --git a/drivers/staging/media/s5p-cec/Kconfig b/drivers/staging/media/s5p-cec/Kconfig index 0315fd7ad0f1..ddfd955da0d4 100644 --- a/drivers/staging/media/s5p-cec/Kconfig +++ b/drivers/staging/media/s5p-cec/Kconfig @@ -1,6 +1,6 @@ config VIDEO_SAMSUNG_S5P_CEC tristate "Samsung S5P CEC driver" - depends on VIDEO_DEV && MEDIA_CEC && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) + depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) ---help--- This is a driver for Samsung S5P HDMI CEC interface. It uses the generic CEC framework interface. diff --git a/drivers/staging/media/st-cec/Kconfig b/drivers/staging/media/st-cec/Kconfig index 784d2c600aca..c04283db58d6 100644 --- a/drivers/staging/media/st-cec/Kconfig +++ b/drivers/staging/media/st-cec/Kconfig @@ -1,6 +1,6 @@ config VIDEO_STI_HDMI_CEC tristate "STMicroelectronics STiH4xx HDMI CEC driver" - depends on VIDEO_DEV && MEDIA_CEC && (ARCH_STI || COMPILE_TEST) + depends on VIDEO_DEV && MEDIA_CEC_SUPPORT && (ARCH_STI || COMPILE_TEST) ---help--- This is a driver for STIH4xx HDMI CEC interface. It uses the generic CEC framework interface. diff --git a/include/linux/cec-funcs.h b/include/linux/cec-funcs.h deleted file mode 100644 index 138bbf721e70..000000000000 --- a/include/linux/cec-funcs.h +++ /dev/null @@ -1,1971 +0,0 @@ -/* - * cec - HDMI Consumer Electronics Control message functions - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * Alternatively you can redistribute this file under the terms of the - * BSD license as stated below: - * - * 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. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * 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. - */ - -/* - * Note: this framework is still in staging and it is likely the API - * will change before it goes out of staging. - * - * Once it is moved out of staging this header will move to uapi. - */ -#ifndef _CEC_UAPI_FUNCS_H -#define _CEC_UAPI_FUNCS_H - -#include - -/* One Touch Play Feature */ -static inline void cec_msg_active_source(struct cec_msg *msg, __u16 phys_addr) -{ - msg->len = 4; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_ACTIVE_SOURCE; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; -} - -static inline void cec_ops_active_source(const struct cec_msg *msg, - __u16 *phys_addr) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - -static inline void cec_msg_image_view_on(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_IMAGE_VIEW_ON; -} - -static inline void cec_msg_text_view_on(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_TEXT_VIEW_ON; -} - - -/* Routing Control Feature */ -static inline void cec_msg_inactive_source(struct cec_msg *msg, - __u16 phys_addr) -{ - msg->len = 4; - msg->msg[1] = CEC_MSG_INACTIVE_SOURCE; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; -} - -static inline void cec_ops_inactive_source(const struct cec_msg *msg, - __u16 *phys_addr) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - -static inline void cec_msg_request_active_source(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_REQUEST_ACTIVE_SOURCE; - msg->reply = reply ? CEC_MSG_ACTIVE_SOURCE : 0; -} - -static inline void cec_msg_routing_information(struct cec_msg *msg, - __u16 phys_addr) -{ - msg->len = 4; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_ROUTING_INFORMATION; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; -} - -static inline void cec_ops_routing_information(const struct cec_msg *msg, - __u16 *phys_addr) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - -static inline void cec_msg_routing_change(struct cec_msg *msg, - bool reply, - __u16 orig_phys_addr, - __u16 new_phys_addr) -{ - msg->len = 6; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_ROUTING_CHANGE; - msg->msg[2] = orig_phys_addr >> 8; - msg->msg[3] = orig_phys_addr & 0xff; - msg->msg[4] = new_phys_addr >> 8; - msg->msg[5] = new_phys_addr & 0xff; - msg->reply = reply ? CEC_MSG_ROUTING_INFORMATION : 0; -} - -static inline void cec_ops_routing_change(const struct cec_msg *msg, - __u16 *orig_phys_addr, - __u16 *new_phys_addr) -{ - *orig_phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *new_phys_addr = (msg->msg[4] << 8) | msg->msg[5]; -} - -static inline void cec_msg_set_stream_path(struct cec_msg *msg, __u16 phys_addr) -{ - msg->len = 4; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_SET_STREAM_PATH; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; -} - -static inline void cec_ops_set_stream_path(const struct cec_msg *msg, - __u16 *phys_addr) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - - -/* Standby Feature */ -static inline void cec_msg_standby(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_STANDBY; -} - - -/* One Touch Record Feature */ -static inline void cec_msg_record_off(struct cec_msg *msg, bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_RECORD_OFF; - msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0; -} - -struct cec_op_arib_data { - __u16 transport_id; - __u16 service_id; - __u16 orig_network_id; -}; - -struct cec_op_atsc_data { - __u16 transport_id; - __u16 program_number; -}; - -struct cec_op_dvb_data { - __u16 transport_id; - __u16 service_id; - __u16 orig_network_id; -}; - -struct cec_op_channel_data { - __u8 channel_number_fmt; - __u16 major; - __u16 minor; -}; - -struct cec_op_digital_service_id { - __u8 service_id_method; - __u8 dig_bcast_system; - union { - struct cec_op_arib_data arib; - struct cec_op_atsc_data atsc; - struct cec_op_dvb_data dvb; - struct cec_op_channel_data channel; - }; -}; - -struct cec_op_record_src { - __u8 type; - union { - struct cec_op_digital_service_id digital; - struct { - __u8 ana_bcast_type; - __u16 ana_freq; - __u8 bcast_system; - } analog; - struct { - __u8 plug; - } ext_plug; - struct { - __u16 phys_addr; - } ext_phys_addr; - }; -}; - -static inline void cec_set_digital_service_id(__u8 *msg, - const struct cec_op_digital_service_id *digital) -{ - *msg++ = (digital->service_id_method << 7) | digital->dig_bcast_system; - if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { - *msg++ = (digital->channel.channel_number_fmt << 2) | - (digital->channel.major >> 8); - *msg++ = digital->channel.major & 0xff; - *msg++ = digital->channel.minor >> 8; - *msg++ = digital->channel.minor & 0xff; - *msg++ = 0; - *msg++ = 0; - return; - } - switch (digital->dig_bcast_system) { - case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN: - case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE: - case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT: - case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: - *msg++ = digital->atsc.transport_id >> 8; - *msg++ = digital->atsc.transport_id & 0xff; - *msg++ = digital->atsc.program_number >> 8; - *msg++ = digital->atsc.program_number & 0xff; - *msg++ = 0; - *msg++ = 0; - break; - default: - *msg++ = digital->dvb.transport_id >> 8; - *msg++ = digital->dvb.transport_id & 0xff; - *msg++ = digital->dvb.service_id >> 8; - *msg++ = digital->dvb.service_id & 0xff; - *msg++ = digital->dvb.orig_network_id >> 8; - *msg++ = digital->dvb.orig_network_id & 0xff; - break; - } -} - -static inline void cec_get_digital_service_id(const __u8 *msg, - struct cec_op_digital_service_id *digital) -{ - digital->service_id_method = msg[0] >> 7; - digital->dig_bcast_system = msg[0] & 0x7f; - if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { - digital->channel.channel_number_fmt = msg[1] >> 2; - digital->channel.major = ((msg[1] & 3) << 6) | msg[2]; - digital->channel.minor = (msg[3] << 8) | msg[4]; - return; - } - digital->dvb.transport_id = (msg[1] << 8) | msg[2]; - digital->dvb.service_id = (msg[3] << 8) | msg[4]; - digital->dvb.orig_network_id = (msg[5] << 8) | msg[6]; -} - -static inline void cec_msg_record_on_own(struct cec_msg *msg) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_RECORD_ON; - msg->msg[2] = CEC_OP_RECORD_SRC_OWN; -} - -static inline void cec_msg_record_on_digital(struct cec_msg *msg, - const struct cec_op_digital_service_id *digital) -{ - msg->len = 10; - msg->msg[1] = CEC_MSG_RECORD_ON; - msg->msg[2] = CEC_OP_RECORD_SRC_DIGITAL; - cec_set_digital_service_id(msg->msg + 3, digital); -} - -static inline void cec_msg_record_on_analog(struct cec_msg *msg, - __u8 ana_bcast_type, - __u16 ana_freq, - __u8 bcast_system) -{ - msg->len = 7; - msg->msg[1] = CEC_MSG_RECORD_ON; - msg->msg[2] = CEC_OP_RECORD_SRC_ANALOG; - msg->msg[3] = ana_bcast_type; - msg->msg[4] = ana_freq >> 8; - msg->msg[5] = ana_freq & 0xff; - msg->msg[6] = bcast_system; -} - -static inline void cec_msg_record_on_plug(struct cec_msg *msg, - __u8 plug) -{ - msg->len = 4; - msg->msg[1] = CEC_MSG_RECORD_ON; - msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PLUG; - msg->msg[3] = plug; -} - -static inline void cec_msg_record_on_phys_addr(struct cec_msg *msg, - __u16 phys_addr) -{ - msg->len = 5; - msg->msg[1] = CEC_MSG_RECORD_ON; - msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR; - msg->msg[3] = phys_addr >> 8; - msg->msg[4] = phys_addr & 0xff; -} - -static inline void cec_msg_record_on(struct cec_msg *msg, - bool reply, - const struct cec_op_record_src *rec_src) -{ - switch (rec_src->type) { - case CEC_OP_RECORD_SRC_OWN: - cec_msg_record_on_own(msg); - break; - case CEC_OP_RECORD_SRC_DIGITAL: - cec_msg_record_on_digital(msg, &rec_src->digital); - break; - case CEC_OP_RECORD_SRC_ANALOG: - cec_msg_record_on_analog(msg, - rec_src->analog.ana_bcast_type, - rec_src->analog.ana_freq, - rec_src->analog.bcast_system); - break; - case CEC_OP_RECORD_SRC_EXT_PLUG: - cec_msg_record_on_plug(msg, rec_src->ext_plug.plug); - break; - case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: - cec_msg_record_on_phys_addr(msg, - rec_src->ext_phys_addr.phys_addr); - break; - } - msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0; -} - -static inline void cec_ops_record_on(const struct cec_msg *msg, - struct cec_op_record_src *rec_src) -{ - rec_src->type = msg->msg[2]; - switch (rec_src->type) { - case CEC_OP_RECORD_SRC_OWN: - break; - case CEC_OP_RECORD_SRC_DIGITAL: - cec_get_digital_service_id(msg->msg + 3, &rec_src->digital); - break; - case CEC_OP_RECORD_SRC_ANALOG: - rec_src->analog.ana_bcast_type = msg->msg[3]; - rec_src->analog.ana_freq = - (msg->msg[4] << 8) | msg->msg[5]; - rec_src->analog.bcast_system = msg->msg[6]; - break; - case CEC_OP_RECORD_SRC_EXT_PLUG: - rec_src->ext_plug.plug = msg->msg[3]; - break; - case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: - rec_src->ext_phys_addr.phys_addr = - (msg->msg[3] << 8) | msg->msg[4]; - break; - } -} - -static inline void cec_msg_record_status(struct cec_msg *msg, __u8 rec_status) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_RECORD_STATUS; - msg->msg[2] = rec_status; -} - -static inline void cec_ops_record_status(const struct cec_msg *msg, - __u8 *rec_status) -{ - *rec_status = msg->msg[2]; -} - -static inline void cec_msg_record_tv_screen(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_RECORD_TV_SCREEN; - msg->reply = reply ? CEC_MSG_RECORD_ON : 0; -} - - -/* Timer Programming Feature */ -static inline void cec_msg_timer_status(struct cec_msg *msg, - __u8 timer_overlap_warning, - __u8 media_info, - __u8 prog_info, - __u8 prog_error, - __u8 duration_hr, - __u8 duration_min) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_TIMER_STATUS; - msg->msg[2] = (timer_overlap_warning << 7) | - (media_info << 5) | - (prog_info ? 0x10 : 0) | - (prog_info ? prog_info : prog_error); - if (prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || - prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || - prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { - msg->len += 2; - msg->msg[3] = ((duration_hr / 10) << 4) | (duration_hr % 10); - msg->msg[4] = ((duration_min / 10) << 4) | (duration_min % 10); - } -} - -static inline void cec_ops_timer_status(const struct cec_msg *msg, - __u8 *timer_overlap_warning, - __u8 *media_info, - __u8 *prog_info, - __u8 *prog_error, - __u8 *duration_hr, - __u8 *duration_min) -{ - *timer_overlap_warning = msg->msg[2] >> 7; - *media_info = (msg->msg[2] >> 5) & 3; - if (msg->msg[2] & 0x10) { - *prog_info = msg->msg[2] & 0xf; - *prog_error = 0; - } else { - *prog_info = 0; - *prog_error = msg->msg[2] & 0xf; - } - if (*prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || - *prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || - *prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { - *duration_hr = (msg->msg[3] >> 4) * 10 + (msg->msg[3] & 0xf); - *duration_min = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); - } else { - *duration_hr = *duration_min = 0; - } -} - -static inline void cec_msg_timer_cleared_status(struct cec_msg *msg, - __u8 timer_cleared_status) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_TIMER_CLEARED_STATUS; - msg->msg[2] = timer_cleared_status; -} - -static inline void cec_ops_timer_cleared_status(const struct cec_msg *msg, - __u8 *timer_cleared_status) -{ - *timer_cleared_status = msg->msg[2]; -} - -static inline void cec_msg_clear_analogue_timer(struct cec_msg *msg, - bool reply, - __u8 day, - __u8 month, - __u8 start_hr, - __u8 start_min, - __u8 duration_hr, - __u8 duration_min, - __u8 recording_seq, - __u8 ana_bcast_type, - __u16 ana_freq, - __u8 bcast_system) -{ - msg->len = 13; - msg->msg[1] = CEC_MSG_CLEAR_ANALOGUE_TIMER; - msg->msg[2] = day; - msg->msg[3] = month; - /* Hours and minutes are in BCD format */ - msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); - msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); - msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); - msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); - msg->msg[8] = recording_seq; - msg->msg[9] = ana_bcast_type; - msg->msg[10] = ana_freq >> 8; - msg->msg[11] = ana_freq & 0xff; - msg->msg[12] = bcast_system; - msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; -} - -static inline void cec_ops_clear_analogue_timer(const struct cec_msg *msg, - __u8 *day, - __u8 *month, - __u8 *start_hr, - __u8 *start_min, - __u8 *duration_hr, - __u8 *duration_min, - __u8 *recording_seq, - __u8 *ana_bcast_type, - __u16 *ana_freq, - __u8 *bcast_system) -{ - *day = msg->msg[2]; - *month = msg->msg[3]; - /* Hours and minutes are in BCD format */ - *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); - *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); - *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); - *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); - *recording_seq = msg->msg[8]; - *ana_bcast_type = msg->msg[9]; - *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; - *bcast_system = msg->msg[12]; -} - -static inline void cec_msg_clear_digital_timer(struct cec_msg *msg, - bool reply, - __u8 day, - __u8 month, - __u8 start_hr, - __u8 start_min, - __u8 duration_hr, - __u8 duration_min, - __u8 recording_seq, - const struct cec_op_digital_service_id *digital) -{ - msg->len = 16; - msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; - msg->msg[1] = CEC_MSG_CLEAR_DIGITAL_TIMER; - msg->msg[2] = day; - msg->msg[3] = month; - /* Hours and minutes are in BCD format */ - msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); - msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); - msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); - msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); - msg->msg[8] = recording_seq; - cec_set_digital_service_id(msg->msg + 9, digital); -} - -static inline void cec_ops_clear_digital_timer(const struct cec_msg *msg, - __u8 *day, - __u8 *month, - __u8 *start_hr, - __u8 *start_min, - __u8 *duration_hr, - __u8 *duration_min, - __u8 *recording_seq, - struct cec_op_digital_service_id *digital) -{ - *day = msg->msg[2]; - *month = msg->msg[3]; - /* Hours and minutes are in BCD format */ - *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); - *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); - *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); - *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); - *recording_seq = msg->msg[8]; - cec_get_digital_service_id(msg->msg + 9, digital); -} - -static inline void cec_msg_clear_ext_timer(struct cec_msg *msg, - bool reply, - __u8 day, - __u8 month, - __u8 start_hr, - __u8 start_min, - __u8 duration_hr, - __u8 duration_min, - __u8 recording_seq, - __u8 ext_src_spec, - __u8 plug, - __u16 phys_addr) -{ - msg->len = 13; - msg->msg[1] = CEC_MSG_CLEAR_EXT_TIMER; - msg->msg[2] = day; - msg->msg[3] = month; - /* Hours and minutes are in BCD format */ - msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); - msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); - msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); - msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); - msg->msg[8] = recording_seq; - msg->msg[9] = ext_src_spec; - msg->msg[10] = plug; - msg->msg[11] = phys_addr >> 8; - msg->msg[12] = phys_addr & 0xff; - msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; -} - -static inline void cec_ops_clear_ext_timer(const struct cec_msg *msg, - __u8 *day, - __u8 *month, - __u8 *start_hr, - __u8 *start_min, - __u8 *duration_hr, - __u8 *duration_min, - __u8 *recording_seq, - __u8 *ext_src_spec, - __u8 *plug, - __u16 *phys_addr) -{ - *day = msg->msg[2]; - *month = msg->msg[3]; - /* Hours and minutes are in BCD format */ - *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); - *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); - *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); - *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); - *recording_seq = msg->msg[8]; - *ext_src_spec = msg->msg[9]; - *plug = msg->msg[10]; - *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; -} - -static inline void cec_msg_set_analogue_timer(struct cec_msg *msg, - bool reply, - __u8 day, - __u8 month, - __u8 start_hr, - __u8 start_min, - __u8 duration_hr, - __u8 duration_min, - __u8 recording_seq, - __u8 ana_bcast_type, - __u16 ana_freq, - __u8 bcast_system) -{ - msg->len = 13; - msg->msg[1] = CEC_MSG_SET_ANALOGUE_TIMER; - msg->msg[2] = day; - msg->msg[3] = month; - /* Hours and minutes are in BCD format */ - msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); - msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); - msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); - msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); - msg->msg[8] = recording_seq; - msg->msg[9] = ana_bcast_type; - msg->msg[10] = ana_freq >> 8; - msg->msg[11] = ana_freq & 0xff; - msg->msg[12] = bcast_system; - msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; -} - -static inline void cec_ops_set_analogue_timer(const struct cec_msg *msg, - __u8 *day, - __u8 *month, - __u8 *start_hr, - __u8 *start_min, - __u8 *duration_hr, - __u8 *duration_min, - __u8 *recording_seq, - __u8 *ana_bcast_type, - __u16 *ana_freq, - __u8 *bcast_system) -{ - *day = msg->msg[2]; - *month = msg->msg[3]; - /* Hours and minutes are in BCD format */ - *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); - *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); - *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); - *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); - *recording_seq = msg->msg[8]; - *ana_bcast_type = msg->msg[9]; - *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; - *bcast_system = msg->msg[12]; -} - -static inline void cec_msg_set_digital_timer(struct cec_msg *msg, - bool reply, - __u8 day, - __u8 month, - __u8 start_hr, - __u8 start_min, - __u8 duration_hr, - __u8 duration_min, - __u8 recording_seq, - const struct cec_op_digital_service_id *digital) -{ - msg->len = 16; - msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; - msg->msg[1] = CEC_MSG_SET_DIGITAL_TIMER; - msg->msg[2] = day; - msg->msg[3] = month; - /* Hours and minutes are in BCD format */ - msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); - msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); - msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); - msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); - msg->msg[8] = recording_seq; - cec_set_digital_service_id(msg->msg + 9, digital); -} - -static inline void cec_ops_set_digital_timer(const struct cec_msg *msg, - __u8 *day, - __u8 *month, - __u8 *start_hr, - __u8 *start_min, - __u8 *duration_hr, - __u8 *duration_min, - __u8 *recording_seq, - struct cec_op_digital_service_id *digital) -{ - *day = msg->msg[2]; - *month = msg->msg[3]; - /* Hours and minutes are in BCD format */ - *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); - *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); - *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); - *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); - *recording_seq = msg->msg[8]; - cec_get_digital_service_id(msg->msg + 9, digital); -} - -static inline void cec_msg_set_ext_timer(struct cec_msg *msg, - bool reply, - __u8 day, - __u8 month, - __u8 start_hr, - __u8 start_min, - __u8 duration_hr, - __u8 duration_min, - __u8 recording_seq, - __u8 ext_src_spec, - __u8 plug, - __u16 phys_addr) -{ - msg->len = 13; - msg->msg[1] = CEC_MSG_SET_EXT_TIMER; - msg->msg[2] = day; - msg->msg[3] = month; - /* Hours and minutes are in BCD format */ - msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); - msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); - msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); - msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); - msg->msg[8] = recording_seq; - msg->msg[9] = ext_src_spec; - msg->msg[10] = plug; - msg->msg[11] = phys_addr >> 8; - msg->msg[12] = phys_addr & 0xff; - msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; -} - -static inline void cec_ops_set_ext_timer(const struct cec_msg *msg, - __u8 *day, - __u8 *month, - __u8 *start_hr, - __u8 *start_min, - __u8 *duration_hr, - __u8 *duration_min, - __u8 *recording_seq, - __u8 *ext_src_spec, - __u8 *plug, - __u16 *phys_addr) -{ - *day = msg->msg[2]; - *month = msg->msg[3]; - /* Hours and minutes are in BCD format */ - *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); - *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); - *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); - *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); - *recording_seq = msg->msg[8]; - *ext_src_spec = msg->msg[9]; - *plug = msg->msg[10]; - *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; -} - -static inline void cec_msg_set_timer_program_title(struct cec_msg *msg, - const char *prog_title) -{ - unsigned int len = strlen(prog_title); - - if (len > 14) - len = 14; - msg->len = 2 + len; - msg->msg[1] = CEC_MSG_SET_TIMER_PROGRAM_TITLE; - memcpy(msg->msg + 2, prog_title, len); -} - -static inline void cec_ops_set_timer_program_title(const struct cec_msg *msg, - char *prog_title) -{ - unsigned int len = msg->len > 2 ? msg->len - 2 : 0; - - if (len > 14) - len = 14; - memcpy(prog_title, msg->msg + 2, len); - prog_title[len] = '\0'; -} - -/* System Information Feature */ -static inline void cec_msg_cec_version(struct cec_msg *msg, __u8 cec_version) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_CEC_VERSION; - msg->msg[2] = cec_version; -} - -static inline void cec_ops_cec_version(const struct cec_msg *msg, - __u8 *cec_version) -{ - *cec_version = msg->msg[2]; -} - -static inline void cec_msg_get_cec_version(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GET_CEC_VERSION; - msg->reply = reply ? CEC_MSG_CEC_VERSION : 0; -} - -static inline void cec_msg_report_physical_addr(struct cec_msg *msg, - __u16 phys_addr, __u8 prim_devtype) -{ - msg->len = 5; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_REPORT_PHYSICAL_ADDR; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; - msg->msg[4] = prim_devtype; -} - -static inline void cec_ops_report_physical_addr(const struct cec_msg *msg, - __u16 *phys_addr, __u8 *prim_devtype) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *prim_devtype = msg->msg[4]; -} - -static inline void cec_msg_give_physical_addr(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GIVE_PHYSICAL_ADDR; - msg->reply = reply ? CEC_MSG_REPORT_PHYSICAL_ADDR : 0; -} - -static inline void cec_msg_set_menu_language(struct cec_msg *msg, - const char *language) -{ - msg->len = 5; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_SET_MENU_LANGUAGE; - memcpy(msg->msg + 2, language, 3); -} - -static inline void cec_ops_set_menu_language(const struct cec_msg *msg, - char *language) -{ - memcpy(language, msg->msg + 2, 3); - language[3] = '\0'; -} - -static inline void cec_msg_get_menu_language(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GET_MENU_LANGUAGE; - msg->reply = reply ? CEC_MSG_SET_MENU_LANGUAGE : 0; -} - -/* - * Assumes a single RC Profile byte and a single Device Features byte, - * i.e. no extended features are supported by this helper function. - * - * As of CEC 2.0 no extended features are defined, should those be added - * in the future, then this function needs to be adapted or a new function - * should be added. - */ -static inline void cec_msg_report_features(struct cec_msg *msg, - __u8 cec_version, __u8 all_device_types, - __u8 rc_profile, __u8 dev_features) -{ - msg->len = 6; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_REPORT_FEATURES; - msg->msg[2] = cec_version; - msg->msg[3] = all_device_types; - msg->msg[4] = rc_profile; - msg->msg[5] = dev_features; -} - -static inline void cec_ops_report_features(const struct cec_msg *msg, - __u8 *cec_version, __u8 *all_device_types, - const __u8 **rc_profile, const __u8 **dev_features) -{ - const __u8 *p = &msg->msg[4]; - - *cec_version = msg->msg[2]; - *all_device_types = msg->msg[3]; - *rc_profile = p; - while (p < &msg->msg[14] && (*p & CEC_OP_FEAT_EXT)) - p++; - if (!(*p & CEC_OP_FEAT_EXT)) { - *dev_features = p + 1; - while (p < &msg->msg[15] && (*p & CEC_OP_FEAT_EXT)) - p++; - } - if (*p & CEC_OP_FEAT_EXT) - *rc_profile = *dev_features = NULL; -} - -static inline void cec_msg_give_features(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GIVE_FEATURES; - msg->reply = reply ? CEC_MSG_REPORT_FEATURES : 0; -} - -/* Deck Control Feature */ -static inline void cec_msg_deck_control(struct cec_msg *msg, - __u8 deck_control_mode) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_DECK_CONTROL; - msg->msg[2] = deck_control_mode; -} - -static inline void cec_ops_deck_control(const struct cec_msg *msg, - __u8 *deck_control_mode) -{ - *deck_control_mode = msg->msg[2]; -} - -static inline void cec_msg_deck_status(struct cec_msg *msg, - __u8 deck_info) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_DECK_STATUS; - msg->msg[2] = deck_info; -} - -static inline void cec_ops_deck_status(const struct cec_msg *msg, - __u8 *deck_info) -{ - *deck_info = msg->msg[2]; -} - -static inline void cec_msg_give_deck_status(struct cec_msg *msg, - bool reply, - __u8 status_req) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS; - msg->msg[2] = status_req; - msg->reply = reply ? CEC_MSG_DECK_STATUS : 0; -} - -static inline void cec_ops_give_deck_status(const struct cec_msg *msg, - __u8 *status_req) -{ - *status_req = msg->msg[2]; -} - -static inline void cec_msg_play(struct cec_msg *msg, - __u8 play_mode) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_PLAY; - msg->msg[2] = play_mode; -} - -static inline void cec_ops_play(const struct cec_msg *msg, - __u8 *play_mode) -{ - *play_mode = msg->msg[2]; -} - - -/* Tuner Control Feature */ -struct cec_op_tuner_device_info { - __u8 rec_flag; - __u8 tuner_display_info; - bool is_analog; - union { - struct cec_op_digital_service_id digital; - struct { - __u8 ana_bcast_type; - __u16 ana_freq; - __u8 bcast_system; - } analog; - }; -}; - -static inline void cec_msg_tuner_device_status_analog(struct cec_msg *msg, - __u8 rec_flag, - __u8 tuner_display_info, - __u8 ana_bcast_type, - __u16 ana_freq, - __u8 bcast_system) -{ - msg->len = 7; - msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; - msg->msg[2] = (rec_flag << 7) | tuner_display_info; - msg->msg[3] = ana_bcast_type; - msg->msg[4] = ana_freq >> 8; - msg->msg[5] = ana_freq & 0xff; - msg->msg[6] = bcast_system; -} - -static inline void cec_msg_tuner_device_status_digital(struct cec_msg *msg, - __u8 rec_flag, __u8 tuner_display_info, - const struct cec_op_digital_service_id *digital) -{ - msg->len = 10; - msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; - msg->msg[2] = (rec_flag << 7) | tuner_display_info; - cec_set_digital_service_id(msg->msg + 3, digital); -} - -static inline void cec_msg_tuner_device_status(struct cec_msg *msg, - const struct cec_op_tuner_device_info *tuner_dev_info) -{ - if (tuner_dev_info->is_analog) - cec_msg_tuner_device_status_analog(msg, - tuner_dev_info->rec_flag, - tuner_dev_info->tuner_display_info, - tuner_dev_info->analog.ana_bcast_type, - tuner_dev_info->analog.ana_freq, - tuner_dev_info->analog.bcast_system); - else - cec_msg_tuner_device_status_digital(msg, - tuner_dev_info->rec_flag, - tuner_dev_info->tuner_display_info, - &tuner_dev_info->digital); -} - -static inline void cec_ops_tuner_device_status(const struct cec_msg *msg, - struct cec_op_tuner_device_info *tuner_dev_info) -{ - tuner_dev_info->is_analog = msg->len < 10; - tuner_dev_info->rec_flag = msg->msg[2] >> 7; - tuner_dev_info->tuner_display_info = msg->msg[2] & 0x7f; - if (tuner_dev_info->is_analog) { - tuner_dev_info->analog.ana_bcast_type = msg->msg[3]; - tuner_dev_info->analog.ana_freq = (msg->msg[4] << 8) | msg->msg[5]; - tuner_dev_info->analog.bcast_system = msg->msg[6]; - return; - } - cec_get_digital_service_id(msg->msg + 3, &tuner_dev_info->digital); -} - -static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg, - bool reply, - __u8 status_req) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS; - msg->msg[2] = status_req; - msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0; -} - -static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg, - __u8 *status_req) -{ - *status_req = msg->msg[2]; -} - -static inline void cec_msg_select_analogue_service(struct cec_msg *msg, - __u8 ana_bcast_type, - __u16 ana_freq, - __u8 bcast_system) -{ - msg->len = 6; - msg->msg[1] = CEC_MSG_SELECT_ANALOGUE_SERVICE; - msg->msg[2] = ana_bcast_type; - msg->msg[3] = ana_freq >> 8; - msg->msg[4] = ana_freq & 0xff; - msg->msg[5] = bcast_system; -} - -static inline void cec_ops_select_analogue_service(const struct cec_msg *msg, - __u8 *ana_bcast_type, - __u16 *ana_freq, - __u8 *bcast_system) -{ - *ana_bcast_type = msg->msg[2]; - *ana_freq = (msg->msg[3] << 8) | msg->msg[4]; - *bcast_system = msg->msg[5]; -} - -static inline void cec_msg_select_digital_service(struct cec_msg *msg, - const struct cec_op_digital_service_id *digital) -{ - msg->len = 9; - msg->msg[1] = CEC_MSG_SELECT_DIGITAL_SERVICE; - cec_set_digital_service_id(msg->msg + 2, digital); -} - -static inline void cec_ops_select_digital_service(const struct cec_msg *msg, - struct cec_op_digital_service_id *digital) -{ - cec_get_digital_service_id(msg->msg + 2, digital); -} - -static inline void cec_msg_tuner_step_decrement(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_TUNER_STEP_DECREMENT; -} - -static inline void cec_msg_tuner_step_increment(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_TUNER_STEP_INCREMENT; -} - - -/* Vendor Specific Commands Feature */ -static inline void cec_msg_device_vendor_id(struct cec_msg *msg, __u32 vendor_id) -{ - msg->len = 5; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_DEVICE_VENDOR_ID; - msg->msg[2] = vendor_id >> 16; - msg->msg[3] = (vendor_id >> 8) & 0xff; - msg->msg[4] = vendor_id & 0xff; -} - -static inline void cec_ops_device_vendor_id(const struct cec_msg *msg, - __u32 *vendor_id) -{ - *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4]; -} - -static inline void cec_msg_give_device_vendor_id(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GIVE_DEVICE_VENDOR_ID; - msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0; -} - -static inline void cec_msg_vendor_command(struct cec_msg *msg, - __u8 size, const __u8 *vendor_cmd) -{ - if (size > 14) - size = 14; - msg->len = 2 + size; - msg->msg[1] = CEC_MSG_VENDOR_COMMAND; - memcpy(msg->msg + 2, vendor_cmd, size); -} - -static inline void cec_ops_vendor_command(const struct cec_msg *msg, - __u8 *size, - const __u8 **vendor_cmd) -{ - *size = msg->len - 2; - - if (*size > 14) - *size = 14; - *vendor_cmd = msg->msg + 2; -} - -static inline void cec_msg_vendor_command_with_id(struct cec_msg *msg, - __u32 vendor_id, __u8 size, - const __u8 *vendor_cmd) -{ - if (size > 11) - size = 11; - msg->len = 5 + size; - msg->msg[1] = CEC_MSG_VENDOR_COMMAND_WITH_ID; - msg->msg[2] = vendor_id >> 16; - msg->msg[3] = (vendor_id >> 8) & 0xff; - msg->msg[4] = vendor_id & 0xff; - memcpy(msg->msg + 5, vendor_cmd, size); -} - -static inline void cec_ops_vendor_command_with_id(const struct cec_msg *msg, - __u32 *vendor_id, __u8 *size, - const __u8 **vendor_cmd) -{ - *size = msg->len - 5; - - if (*size > 11) - *size = 11; - *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4]; - *vendor_cmd = msg->msg + 5; -} - -static inline void cec_msg_vendor_remote_button_down(struct cec_msg *msg, - __u8 size, - const __u8 *rc_code) -{ - if (size > 14) - size = 14; - msg->len = 2 + size; - msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN; - memcpy(msg->msg + 2, rc_code, size); -} - -static inline void cec_ops_vendor_remote_button_down(const struct cec_msg *msg, - __u8 *size, - const __u8 **rc_code) -{ - *size = msg->len - 2; - - if (*size > 14) - *size = 14; - *rc_code = msg->msg + 2; -} - -static inline void cec_msg_vendor_remote_button_up(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_UP; -} - - -/* OSD Display Feature */ -static inline void cec_msg_set_osd_string(struct cec_msg *msg, - __u8 disp_ctl, - const char *osd) -{ - unsigned int len = strlen(osd); - - if (len > 13) - len = 13; - msg->len = 3 + len; - msg->msg[1] = CEC_MSG_SET_OSD_STRING; - msg->msg[2] = disp_ctl; - memcpy(msg->msg + 3, osd, len); -} - -static inline void cec_ops_set_osd_string(const struct cec_msg *msg, - __u8 *disp_ctl, - char *osd) -{ - unsigned int len = msg->len > 3 ? msg->len - 3 : 0; - - *disp_ctl = msg->msg[2]; - if (len > 13) - len = 13; - memcpy(osd, msg->msg + 3, len); - osd[len] = '\0'; -} - - -/* Device OSD Transfer Feature */ -static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name) -{ - unsigned int len = strlen(name); - - if (len > 14) - len = 14; - msg->len = 2 + len; - msg->msg[1] = CEC_MSG_SET_OSD_NAME; - memcpy(msg->msg + 2, name, len); -} - -static inline void cec_ops_set_osd_name(const struct cec_msg *msg, - char *name) -{ - unsigned int len = msg->len > 2 ? msg->len - 2 : 0; - - if (len > 14) - len = 14; - memcpy(name, msg->msg + 2, len); - name[len] = '\0'; -} - -static inline void cec_msg_give_osd_name(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GIVE_OSD_NAME; - msg->reply = reply ? CEC_MSG_SET_OSD_NAME : 0; -} - - -/* Device Menu Control Feature */ -static inline void cec_msg_menu_status(struct cec_msg *msg, - __u8 menu_state) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_MENU_STATUS; - msg->msg[2] = menu_state; -} - -static inline void cec_ops_menu_status(const struct cec_msg *msg, - __u8 *menu_state) -{ - *menu_state = msg->msg[2]; -} - -static inline void cec_msg_menu_request(struct cec_msg *msg, - bool reply, - __u8 menu_req) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_MENU_REQUEST; - msg->msg[2] = menu_req; - msg->reply = reply ? CEC_MSG_MENU_STATUS : 0; -} - -static inline void cec_ops_menu_request(const struct cec_msg *msg, - __u8 *menu_req) -{ - *menu_req = msg->msg[2]; -} - -struct cec_op_ui_command { - __u8 ui_cmd; - bool has_opt_arg; - union { - struct cec_op_channel_data channel_identifier; - __u8 ui_broadcast_type; - __u8 ui_sound_presentation_control; - __u8 play_mode; - __u8 ui_function_media; - __u8 ui_function_select_av_input; - __u8 ui_function_select_audio_input; - }; -}; - -static inline void cec_msg_user_control_pressed(struct cec_msg *msg, - const struct cec_op_ui_command *ui_cmd) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_USER_CONTROL_PRESSED; - msg->msg[2] = ui_cmd->ui_cmd; - if (!ui_cmd->has_opt_arg) - return; - switch (ui_cmd->ui_cmd) { - case 0x56: - case 0x57: - case 0x60: - case 0x68: - case 0x69: - case 0x6a: - /* The optional operand is one byte for all these ui commands */ - msg->len++; - msg->msg[3] = ui_cmd->play_mode; - break; - case 0x67: - msg->len += 4; - msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) | - (ui_cmd->channel_identifier.major >> 8); - msg->msg[4] = ui_cmd->channel_identifier.major & 0xff; - msg->msg[5] = ui_cmd->channel_identifier.minor >> 8; - msg->msg[6] = ui_cmd->channel_identifier.minor & 0xff; - break; - } -} - -static inline void cec_ops_user_control_pressed(const struct cec_msg *msg, - struct cec_op_ui_command *ui_cmd) -{ - ui_cmd->ui_cmd = msg->msg[2]; - ui_cmd->has_opt_arg = false; - if (msg->len == 3) - return; - switch (ui_cmd->ui_cmd) { - case 0x56: - case 0x57: - case 0x60: - case 0x68: - case 0x69: - case 0x6a: - /* The optional operand is one byte for all these ui commands */ - ui_cmd->play_mode = msg->msg[3]; - ui_cmd->has_opt_arg = true; - break; - case 0x67: - if (msg->len < 7) - break; - ui_cmd->has_opt_arg = true; - ui_cmd->channel_identifier.channel_number_fmt = msg->msg[3] >> 2; - ui_cmd->channel_identifier.major = ((msg->msg[3] & 3) << 6) | msg->msg[4]; - ui_cmd->channel_identifier.minor = (msg->msg[5] << 8) | msg->msg[6]; - break; - } -} - -static inline void cec_msg_user_control_released(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_USER_CONTROL_RELEASED; -} - -/* Remote Control Passthrough Feature */ - -/* Power Status Feature */ -static inline void cec_msg_report_power_status(struct cec_msg *msg, - __u8 pwr_state) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_REPORT_POWER_STATUS; - msg->msg[2] = pwr_state; -} - -static inline void cec_ops_report_power_status(const struct cec_msg *msg, - __u8 *pwr_state) -{ - *pwr_state = msg->msg[2]; -} - -static inline void cec_msg_give_device_power_status(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GIVE_DEVICE_POWER_STATUS; - msg->reply = reply ? CEC_MSG_REPORT_POWER_STATUS : 0; -} - -/* General Protocol Messages */ -static inline void cec_msg_feature_abort(struct cec_msg *msg, - __u8 abort_msg, __u8 reason) -{ - msg->len = 4; - msg->msg[1] = CEC_MSG_FEATURE_ABORT; - msg->msg[2] = abort_msg; - msg->msg[3] = reason; -} - -static inline void cec_ops_feature_abort(const struct cec_msg *msg, - __u8 *abort_msg, __u8 *reason) -{ - *abort_msg = msg->msg[2]; - *reason = msg->msg[3]; -} - -/* This changes the current message into a feature abort message */ -static inline void cec_msg_reply_feature_abort(struct cec_msg *msg, __u8 reason) -{ - cec_msg_set_reply_to(msg, msg); - msg->len = 4; - msg->msg[2] = msg->msg[1]; - msg->msg[3] = reason; - msg->msg[1] = CEC_MSG_FEATURE_ABORT; -} - -static inline void cec_msg_abort(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_ABORT; -} - - -/* System Audio Control Feature */ -static inline void cec_msg_report_audio_status(struct cec_msg *msg, - __u8 aud_mute_status, - __u8 aud_vol_status) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_REPORT_AUDIO_STATUS; - msg->msg[2] = (aud_mute_status << 7) | (aud_vol_status & 0x7f); -} - -static inline void cec_ops_report_audio_status(const struct cec_msg *msg, - __u8 *aud_mute_status, - __u8 *aud_vol_status) -{ - *aud_mute_status = msg->msg[2] >> 7; - *aud_vol_status = msg->msg[2] & 0x7f; -} - -static inline void cec_msg_give_audio_status(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GIVE_AUDIO_STATUS; - msg->reply = reply ? CEC_MSG_REPORT_AUDIO_STATUS : 0; -} - -static inline void cec_msg_set_system_audio_mode(struct cec_msg *msg, - __u8 sys_aud_status) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_SET_SYSTEM_AUDIO_MODE; - msg->msg[2] = sys_aud_status; -} - -static inline void cec_ops_set_system_audio_mode(const struct cec_msg *msg, - __u8 *sys_aud_status) -{ - *sys_aud_status = msg->msg[2]; -} - -static inline void cec_msg_system_audio_mode_request(struct cec_msg *msg, - bool reply, - __u16 phys_addr) -{ - msg->len = phys_addr == 0xffff ? 2 : 4; - msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; - msg->reply = reply ? CEC_MSG_SET_SYSTEM_AUDIO_MODE : 0; - -} - -static inline void cec_ops_system_audio_mode_request(const struct cec_msg *msg, - __u16 *phys_addr) -{ - if (msg->len < 4) - *phys_addr = 0xffff; - else - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - -static inline void cec_msg_system_audio_mode_status(struct cec_msg *msg, - __u8 sys_aud_status) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_STATUS; - msg->msg[2] = sys_aud_status; -} - -static inline void cec_ops_system_audio_mode_status(const struct cec_msg *msg, - __u8 *sys_aud_status) -{ - *sys_aud_status = msg->msg[2]; -} - -static inline void cec_msg_give_system_audio_mode_status(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS; - msg->reply = reply ? CEC_MSG_SYSTEM_AUDIO_MODE_STATUS : 0; -} - -static inline void cec_msg_report_short_audio_descriptor(struct cec_msg *msg, - __u8 num_descriptors, - const __u32 *descriptors) -{ - unsigned int i; - - if (num_descriptors > 4) - num_descriptors = 4; - msg->len = 2 + num_descriptors * 3; - msg->msg[1] = CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR; - for (i = 0; i < num_descriptors; i++) { - msg->msg[2 + i * 3] = (descriptors[i] >> 16) & 0xff; - msg->msg[3 + i * 3] = (descriptors[i] >> 8) & 0xff; - msg->msg[4 + i * 3] = descriptors[i] & 0xff; - } -} - -static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *msg, - __u8 *num_descriptors, - __u32 *descriptors) -{ - unsigned int i; - - *num_descriptors = (msg->len - 2) / 3; - if (*num_descriptors > 4) - *num_descriptors = 4; - for (i = 0; i < *num_descriptors; i++) - descriptors[i] = (msg->msg[2 + i * 3] << 16) | - (msg->msg[3 + i * 3] << 8) | - msg->msg[4 + i * 3]; -} - -static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, - bool reply, - __u8 num_descriptors, - const __u8 *audio_format_id, - const __u8 *audio_format_code) -{ - unsigned int i; - - if (num_descriptors > 4) - num_descriptors = 4; - msg->len = 2 + num_descriptors; - msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR; - msg->reply = reply ? CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR : 0; - for (i = 0; i < num_descriptors; i++) - msg->msg[2 + i] = (audio_format_id[i] << 6) | - (audio_format_code[i] & 0x3f); -} - -static inline void cec_ops_request_short_audio_descriptor(const struct cec_msg *msg, - __u8 *num_descriptors, - __u8 *audio_format_id, - __u8 *audio_format_code) -{ - unsigned int i; - - *num_descriptors = msg->len - 2; - if (*num_descriptors > 4) - *num_descriptors = 4; - for (i = 0; i < *num_descriptors; i++) { - audio_format_id[i] = msg->msg[2 + i] >> 6; - audio_format_code[i] = msg->msg[2 + i] & 0x3f; - } -} - - -/* Audio Rate Control Feature */ -static inline void cec_msg_set_audio_rate(struct cec_msg *msg, - __u8 audio_rate) -{ - msg->len = 3; - msg->msg[1] = CEC_MSG_SET_AUDIO_RATE; - msg->msg[2] = audio_rate; -} - -static inline void cec_ops_set_audio_rate(const struct cec_msg *msg, - __u8 *audio_rate) -{ - *audio_rate = msg->msg[2]; -} - - -/* Audio Return Channel Control Feature */ -static inline void cec_msg_report_arc_initiated(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_REPORT_ARC_INITIATED; -} - -static inline void cec_msg_initiate_arc(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_INITIATE_ARC; - msg->reply = reply ? CEC_MSG_REPORT_ARC_INITIATED : 0; -} - -static inline void cec_msg_request_arc_initiation(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_REQUEST_ARC_INITIATION; - msg->reply = reply ? CEC_MSG_INITIATE_ARC : 0; -} - -static inline void cec_msg_report_arc_terminated(struct cec_msg *msg) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_REPORT_ARC_TERMINATED; -} - -static inline void cec_msg_terminate_arc(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_TERMINATE_ARC; - msg->reply = reply ? CEC_MSG_REPORT_ARC_TERMINATED : 0; -} - -static inline void cec_msg_request_arc_termination(struct cec_msg *msg, - bool reply) -{ - msg->len = 2; - msg->msg[1] = CEC_MSG_REQUEST_ARC_TERMINATION; - msg->reply = reply ? CEC_MSG_TERMINATE_ARC : 0; -} - - -/* Dynamic Audio Lipsync Feature */ -/* Only for CEC 2.0 and up */ -static inline void cec_msg_report_current_latency(struct cec_msg *msg, - __u16 phys_addr, - __u8 video_latency, - __u8 low_latency_mode, - __u8 audio_out_compensated, - __u8 audio_out_delay) -{ - msg->len = 7; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; - msg->msg[4] = video_latency; - msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated; - msg->msg[6] = audio_out_delay; -} - -static inline void cec_ops_report_current_latency(const struct cec_msg *msg, - __u16 *phys_addr, - __u8 *video_latency, - __u8 *low_latency_mode, - __u8 *audio_out_compensated, - __u8 *audio_out_delay) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *video_latency = msg->msg[4]; - *low_latency_mode = (msg->msg[5] >> 2) & 1; - *audio_out_compensated = msg->msg[5] & 3; - *audio_out_delay = msg->msg[6]; -} - -static inline void cec_msg_request_current_latency(struct cec_msg *msg, - bool reply, - __u16 phys_addr) -{ - msg->len = 4; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_REQUEST_CURRENT_LATENCY; - msg->msg[2] = phys_addr >> 8; - msg->msg[3] = phys_addr & 0xff; - msg->reply = reply ? CEC_MSG_REPORT_CURRENT_LATENCY : 0; -} - -static inline void cec_ops_request_current_latency(const struct cec_msg *msg, - __u16 *phys_addr) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - - -/* Capability Discovery and Control Feature */ -static inline void cec_msg_cdc_hec_inquire_state(struct cec_msg *msg, - __u16 phys_addr1, - __u16 phys_addr2) -{ - msg->len = 9; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; - msg->msg[5] = phys_addr1 >> 8; - msg->msg[6] = phys_addr1 & 0xff; - msg->msg[7] = phys_addr2 >> 8; - msg->msg[8] = phys_addr2 & 0xff; -} - -static inline void cec_ops_cdc_hec_inquire_state(const struct cec_msg *msg, - __u16 *phys_addr, - __u16 *phys_addr1, - __u16 *phys_addr2) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; - *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; -} - -static inline void cec_msg_cdc_hec_report_state(struct cec_msg *msg, - __u16 target_phys_addr, - __u8 hec_func_state, - __u8 host_func_state, - __u8 enc_func_state, - __u8 cdc_errcode, - __u8 has_field, - __u16 hec_field) -{ - msg->len = has_field ? 10 : 8; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HEC_REPORT_STATE; - msg->msg[5] = target_phys_addr >> 8; - msg->msg[6] = target_phys_addr & 0xff; - msg->msg[7] = (hec_func_state << 6) | - (host_func_state << 4) | - (enc_func_state << 2) | - cdc_errcode; - if (has_field) { - msg->msg[8] = hec_field >> 8; - msg->msg[9] = hec_field & 0xff; - } -} - -static inline void cec_ops_cdc_hec_report_state(const struct cec_msg *msg, - __u16 *phys_addr, - __u16 *target_phys_addr, - __u8 *hec_func_state, - __u8 *host_func_state, - __u8 *enc_func_state, - __u8 *cdc_errcode, - __u8 *has_field, - __u16 *hec_field) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *target_phys_addr = (msg->msg[5] << 8) | msg->msg[6]; - *hec_func_state = msg->msg[7] >> 6; - *host_func_state = (msg->msg[7] >> 4) & 3; - *enc_func_state = (msg->msg[7] >> 4) & 3; - *cdc_errcode = msg->msg[7] & 3; - *has_field = msg->len >= 10; - *hec_field = *has_field ? ((msg->msg[8] << 8) | msg->msg[9]) : 0; -} - -static inline void cec_msg_cdc_hec_set_state(struct cec_msg *msg, - __u16 phys_addr1, - __u16 phys_addr2, - __u8 hec_set_state, - __u16 phys_addr3, - __u16 phys_addr4, - __u16 phys_addr5) -{ - msg->len = 10; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; - msg->msg[5] = phys_addr1 >> 8; - msg->msg[6] = phys_addr1 & 0xff; - msg->msg[7] = phys_addr2 >> 8; - msg->msg[8] = phys_addr2 & 0xff; - msg->msg[9] = hec_set_state; - if (phys_addr3 != CEC_PHYS_ADDR_INVALID) { - msg->msg[msg->len++] = phys_addr3 >> 8; - msg->msg[msg->len++] = phys_addr3 & 0xff; - if (phys_addr4 != CEC_PHYS_ADDR_INVALID) { - msg->msg[msg->len++] = phys_addr4 >> 8; - msg->msg[msg->len++] = phys_addr4 & 0xff; - if (phys_addr5 != CEC_PHYS_ADDR_INVALID) { - msg->msg[msg->len++] = phys_addr5 >> 8; - msg->msg[msg->len++] = phys_addr5 & 0xff; - } - } - } -} - -static inline void cec_ops_cdc_hec_set_state(const struct cec_msg *msg, - __u16 *phys_addr, - __u16 *phys_addr1, - __u16 *phys_addr2, - __u8 *hec_set_state, - __u16 *phys_addr3, - __u16 *phys_addr4, - __u16 *phys_addr5) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; - *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; - *hec_set_state = msg->msg[9]; - *phys_addr3 = *phys_addr4 = *phys_addr5 = CEC_PHYS_ADDR_INVALID; - if (msg->len >= 12) - *phys_addr3 = (msg->msg[10] << 8) | msg->msg[11]; - if (msg->len >= 14) - *phys_addr4 = (msg->msg[12] << 8) | msg->msg[13]; - if (msg->len >= 16) - *phys_addr5 = (msg->msg[14] << 8) | msg->msg[15]; -} - -static inline void cec_msg_cdc_hec_set_state_adjacent(struct cec_msg *msg, - __u16 phys_addr1, - __u8 hec_set_state) -{ - msg->len = 8; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HEC_SET_STATE_ADJACENT; - msg->msg[5] = phys_addr1 >> 8; - msg->msg[6] = phys_addr1 & 0xff; - msg->msg[7] = hec_set_state; -} - -static inline void cec_ops_cdc_hec_set_state_adjacent(const struct cec_msg *msg, - __u16 *phys_addr, - __u16 *phys_addr1, - __u8 *hec_set_state) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; - *hec_set_state = msg->msg[7]; -} - -static inline void cec_msg_cdc_hec_request_deactivation(struct cec_msg *msg, - __u16 phys_addr1, - __u16 phys_addr2, - __u16 phys_addr3) -{ - msg->len = 11; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION; - msg->msg[5] = phys_addr1 >> 8; - msg->msg[6] = phys_addr1 & 0xff; - msg->msg[7] = phys_addr2 >> 8; - msg->msg[8] = phys_addr2 & 0xff; - msg->msg[9] = phys_addr3 >> 8; - msg->msg[10] = phys_addr3 & 0xff; -} - -static inline void cec_ops_cdc_hec_request_deactivation(const struct cec_msg *msg, - __u16 *phys_addr, - __u16 *phys_addr1, - __u16 *phys_addr2, - __u16 *phys_addr3) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; - *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; - *phys_addr3 = (msg->msg[9] << 8) | msg->msg[10]; -} - -static inline void cec_msg_cdc_hec_notify_alive(struct cec_msg *msg) -{ - msg->len = 5; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HEC_NOTIFY_ALIVE; -} - -static inline void cec_ops_cdc_hec_notify_alive(const struct cec_msg *msg, - __u16 *phys_addr) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - -static inline void cec_msg_cdc_hec_discover(struct cec_msg *msg) -{ - msg->len = 5; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HEC_DISCOVER; -} - -static inline void cec_ops_cdc_hec_discover(const struct cec_msg *msg, - __u16 *phys_addr) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; -} - -static inline void cec_msg_cdc_hpd_set_state(struct cec_msg *msg, - __u8 input_port, - __u8 hpd_state) -{ - msg->len = 6; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HPD_SET_STATE; - msg->msg[5] = (input_port << 4) | hpd_state; -} - -static inline void cec_ops_cdc_hpd_set_state(const struct cec_msg *msg, - __u16 *phys_addr, - __u8 *input_port, - __u8 *hpd_state) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *input_port = msg->msg[5] >> 4; - *hpd_state = msg->msg[5] & 0xf; -} - -static inline void cec_msg_cdc_hpd_report_state(struct cec_msg *msg, - __u8 hpd_state, - __u8 hpd_error) -{ - msg->len = 6; - msg->msg[0] |= 0xf; /* broadcast */ - msg->msg[1] = CEC_MSG_CDC_MESSAGE; - /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ - msg->msg[4] = CEC_MSG_CDC_HPD_REPORT_STATE; - msg->msg[5] = (hpd_state << 4) | hpd_error; -} - -static inline void cec_ops_cdc_hpd_report_state(const struct cec_msg *msg, - __u16 *phys_addr, - __u8 *hpd_state, - __u8 *hpd_error) -{ - *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; - *hpd_state = msg->msg[5] >> 4; - *hpd_error = msg->msg[5] & 0xf; -} - -#endif diff --git a/include/linux/cec.h b/include/linux/cec.h deleted file mode 100644 index 9c87711c0e1c..000000000000 --- a/include/linux/cec.h +++ /dev/null @@ -1,1071 +0,0 @@ -/* - * cec - HDMI Consumer Electronics Control public header - * - * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. - * - * This program is free software; you may redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * Alternatively you can redistribute this file under the terms of the - * BSD license as stated below: - * - * 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. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * 3. The names of its contributors may not be used to endorse or promote - * products derived from this software without specific prior written - * permission. - * - * 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. - */ - -/* - * Note: this framework is still in staging and it is likely the API - * will change before it goes out of staging. - * - * Once it is moved out of staging this header will move to uapi. - */ -#ifndef _CEC_UAPI_H -#define _CEC_UAPI_H - -#include - -#define CEC_MAX_MSG_SIZE 16 - -/** - * struct cec_msg - CEC message structure. - * @tx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the - * driver when the message transmission has finished. - * @rx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the - * driver when the message was received. - * @len: Length in bytes of the message. - * @timeout: The timeout (in ms) that is used to timeout CEC_RECEIVE. - * Set to 0 if you want to wait forever. This timeout can also be - * used with CEC_TRANSMIT as the timeout for waiting for a reply. - * If 0, then it will use a 1 second timeout instead of waiting - * forever as is done with CEC_RECEIVE. - * @sequence: The framework assigns a sequence number to messages that are - * sent. This can be used to track replies to previously sent - * messages. - * @flags: Set to 0. - * @msg: The message payload. - * @reply: This field is ignored with CEC_RECEIVE and is only used by - * CEC_TRANSMIT. If non-zero, then wait for a reply with this - * opcode. Set to CEC_MSG_FEATURE_ABORT if you want to wait for - * a possible ABORT reply. If there was an error when sending the - * msg or FeatureAbort was returned, then reply is set to 0. - * If reply is non-zero upon return, then len/msg are set to - * the received message. - * If reply is zero upon return and status has the - * CEC_TX_STATUS_FEATURE_ABORT bit set, then len/msg are set to - * the received feature abort message. - * If reply is zero upon return and status has the - * CEC_TX_STATUS_MAX_RETRIES bit set, then no reply was seen at - * all. If reply is non-zero for CEC_TRANSMIT and the message is a - * broadcast, then -EINVAL is returned. - * if reply is non-zero, then timeout is set to 1000 (the required - * maximum response time). - * @rx_status: The message receive status bits. Set by the driver. - * @tx_status: The message transmit status bits. Set by the driver. - * @tx_arb_lost_cnt: The number of 'Arbitration Lost' events. Set by the driver. - * @tx_nack_cnt: The number of 'Not Acknowledged' events. Set by the driver. - * @tx_low_drive_cnt: The number of 'Low Drive Detected' events. Set by the - * driver. - * @tx_error_cnt: The number of 'Error' events. Set by the driver. - */ -struct cec_msg { - __u64 tx_ts; - __u64 rx_ts; - __u32 len; - __u32 timeout; - __u32 sequence; - __u32 flags; - __u8 msg[CEC_MAX_MSG_SIZE]; - __u8 reply; - __u8 rx_status; - __u8 tx_status; - __u8 tx_arb_lost_cnt; - __u8 tx_nack_cnt; - __u8 tx_low_drive_cnt; - __u8 tx_error_cnt; -}; - -/** - * cec_msg_initiator - return the initiator's logical address. - * @msg: the message structure - */ -static inline __u8 cec_msg_initiator(const struct cec_msg *msg) -{ - return msg->msg[0] >> 4; -} - -/** - * cec_msg_destination - return the destination's logical address. - * @msg: the message structure - */ -static inline __u8 cec_msg_destination(const struct cec_msg *msg) -{ - return msg->msg[0] & 0xf; -} - -/** - * cec_msg_opcode - return the opcode of the message, -1 for poll - * @msg: the message structure - */ -static inline int cec_msg_opcode(const struct cec_msg *msg) -{ - return msg->len > 1 ? msg->msg[1] : -1; -} - -/** - * cec_msg_is_broadcast - return true if this is a broadcast message. - * @msg: the message structure - */ -static inline bool cec_msg_is_broadcast(const struct cec_msg *msg) -{ - return (msg->msg[0] & 0xf) == 0xf; -} - -/** - * cec_msg_init - initialize the message structure. - * @msg: the message structure - * @initiator: the logical address of the initiator - * @destination:the logical address of the destination (0xf for broadcast) - * - * The whole structure is zeroed, the len field is set to 1 (i.e. a poll - * message) and the initiator and destination are filled in. - */ -static inline void cec_msg_init(struct cec_msg *msg, - __u8 initiator, __u8 destination) -{ - memset(msg, 0, sizeof(*msg)); - msg->msg[0] = (initiator << 4) | destination; - msg->len = 1; -} - -/** - * cec_msg_set_reply_to - fill in destination/initiator in a reply message. - * @msg: the message structure for the reply - * @orig: the original message structure - * - * Set the msg destination to the orig initiator and the msg initiator to the - * orig destination. Note that msg and orig may be the same pointer, in which - * case the change is done in place. - */ -static inline void cec_msg_set_reply_to(struct cec_msg *msg, - struct cec_msg *orig) -{ - /* The destination becomes the initiator and vice versa */ - msg->msg[0] = (cec_msg_destination(orig) << 4) | - cec_msg_initiator(orig); - msg->reply = msg->timeout = 0; -} - -/* cec_msg flags field */ -#define CEC_MSG_FL_REPLY_TO_FOLLOWERS (1 << 0) - -/* cec_msg tx/rx_status field */ -#define CEC_TX_STATUS_OK (1 << 0) -#define CEC_TX_STATUS_ARB_LOST (1 << 1) -#define CEC_TX_STATUS_NACK (1 << 2) -#define CEC_TX_STATUS_LOW_DRIVE (1 << 3) -#define CEC_TX_STATUS_ERROR (1 << 4) -#define CEC_TX_STATUS_MAX_RETRIES (1 << 5) - -#define CEC_RX_STATUS_OK (1 << 0) -#define CEC_RX_STATUS_TIMEOUT (1 << 1) -#define CEC_RX_STATUS_FEATURE_ABORT (1 << 2) - -static inline bool cec_msg_status_is_ok(const struct cec_msg *msg) -{ - if (msg->tx_status && !(msg->tx_status & CEC_TX_STATUS_OK)) - return false; - if (msg->rx_status && !(msg->rx_status & CEC_RX_STATUS_OK)) - return false; - if (!msg->tx_status && !msg->rx_status) - return false; - return !(msg->rx_status & CEC_RX_STATUS_FEATURE_ABORT); -} - -#define CEC_LOG_ADDR_INVALID 0xff -#define CEC_PHYS_ADDR_INVALID 0xffff - -/* - * The maximum number of logical addresses one device can be assigned to. - * The CEC 2.0 spec allows for only 2 logical addresses at the moment. The - * Analog Devices CEC hardware supports 3. So let's go wild and go for 4. - */ -#define CEC_MAX_LOG_ADDRS 4 - -/* The logical addresses defined by CEC 2.0 */ -#define CEC_LOG_ADDR_TV 0 -#define CEC_LOG_ADDR_RECORD_1 1 -#define CEC_LOG_ADDR_RECORD_2 2 -#define CEC_LOG_ADDR_TUNER_1 3 -#define CEC_LOG_ADDR_PLAYBACK_1 4 -#define CEC_LOG_ADDR_AUDIOSYSTEM 5 -#define CEC_LOG_ADDR_TUNER_2 6 -#define CEC_LOG_ADDR_TUNER_3 7 -#define CEC_LOG_ADDR_PLAYBACK_2 8 -#define CEC_LOG_ADDR_RECORD_3 9 -#define CEC_LOG_ADDR_TUNER_4 10 -#define CEC_LOG_ADDR_PLAYBACK_3 11 -#define CEC_LOG_ADDR_BACKUP_1 12 -#define CEC_LOG_ADDR_BACKUP_2 13 -#define CEC_LOG_ADDR_SPECIFIC 14 -#define CEC_LOG_ADDR_UNREGISTERED 15 /* as initiator address */ -#define CEC_LOG_ADDR_BROADCAST 15 /* ad destination address */ - -/* The logical address types that the CEC device wants to claim */ -#define CEC_LOG_ADDR_TYPE_TV 0 -#define CEC_LOG_ADDR_TYPE_RECORD 1 -#define CEC_LOG_ADDR_TYPE_TUNER 2 -#define CEC_LOG_ADDR_TYPE_PLAYBACK 3 -#define CEC_LOG_ADDR_TYPE_AUDIOSYSTEM 4 -#define CEC_LOG_ADDR_TYPE_SPECIFIC 5 -#define CEC_LOG_ADDR_TYPE_UNREGISTERED 6 -/* - * Switches should use UNREGISTERED. - * Processors should use SPECIFIC. - */ - -#define CEC_LOG_ADDR_MASK_TV (1 << CEC_LOG_ADDR_TV) -#define CEC_LOG_ADDR_MASK_RECORD ((1 << CEC_LOG_ADDR_RECORD_1) | \ - (1 << CEC_LOG_ADDR_RECORD_2) | \ - (1 << CEC_LOG_ADDR_RECORD_3)) -#define CEC_LOG_ADDR_MASK_TUNER ((1 << CEC_LOG_ADDR_TUNER_1) | \ - (1 << CEC_LOG_ADDR_TUNER_2) | \ - (1 << CEC_LOG_ADDR_TUNER_3) | \ - (1 << CEC_LOG_ADDR_TUNER_4)) -#define CEC_LOG_ADDR_MASK_PLAYBACK ((1 << CEC_LOG_ADDR_PLAYBACK_1) | \ - (1 << CEC_LOG_ADDR_PLAYBACK_2) | \ - (1 << CEC_LOG_ADDR_PLAYBACK_3)) -#define CEC_LOG_ADDR_MASK_AUDIOSYSTEM (1 << CEC_LOG_ADDR_AUDIOSYSTEM) -#define CEC_LOG_ADDR_MASK_BACKUP ((1 << CEC_LOG_ADDR_BACKUP_1) | \ - (1 << CEC_LOG_ADDR_BACKUP_2)) -#define CEC_LOG_ADDR_MASK_SPECIFIC (1 << CEC_LOG_ADDR_SPECIFIC) -#define CEC_LOG_ADDR_MASK_UNREGISTERED (1 << CEC_LOG_ADDR_UNREGISTERED) - -static inline bool cec_has_tv(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_TV; -} - -static inline bool cec_has_record(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_RECORD; -} - -static inline bool cec_has_tuner(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_TUNER; -} - -static inline bool cec_has_playback(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_PLAYBACK; -} - -static inline bool cec_has_audiosystem(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_AUDIOSYSTEM; -} - -static inline bool cec_has_backup(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_BACKUP; -} - -static inline bool cec_has_specific(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_SPECIFIC; -} - -static inline bool cec_is_unregistered(__u16 log_addr_mask) -{ - return log_addr_mask & CEC_LOG_ADDR_MASK_UNREGISTERED; -} - -static inline bool cec_is_unconfigured(__u16 log_addr_mask) -{ - return log_addr_mask == 0; -} - -/* - * Use this if there is no vendor ID (CEC_G_VENDOR_ID) or if the vendor ID - * should be disabled (CEC_S_VENDOR_ID) - */ -#define CEC_VENDOR_ID_NONE 0xffffffff - -/* The message handling modes */ -/* Modes for initiator */ -#define CEC_MODE_NO_INITIATOR (0x0 << 0) -#define CEC_MODE_INITIATOR (0x1 << 0) -#define CEC_MODE_EXCL_INITIATOR (0x2 << 0) -#define CEC_MODE_INITIATOR_MSK 0x0f - -/* Modes for follower */ -#define CEC_MODE_NO_FOLLOWER (0x0 << 4) -#define CEC_MODE_FOLLOWER (0x1 << 4) -#define CEC_MODE_EXCL_FOLLOWER (0x2 << 4) -#define CEC_MODE_EXCL_FOLLOWER_PASSTHRU (0x3 << 4) -#define CEC_MODE_MONITOR (0xe << 4) -#define CEC_MODE_MONITOR_ALL (0xf << 4) -#define CEC_MODE_FOLLOWER_MSK 0xf0 - -/* Userspace has to configure the physical address */ -#define CEC_CAP_PHYS_ADDR (1 << 0) -/* Userspace has to configure the logical addresses */ -#define CEC_CAP_LOG_ADDRS (1 << 1) -/* Userspace can transmit messages (and thus become follower as well) */ -#define CEC_CAP_TRANSMIT (1 << 2) -/* - * Passthrough all messages instead of processing them. - */ -#define CEC_CAP_PASSTHROUGH (1 << 3) -/* Supports remote control */ -#define CEC_CAP_RC (1 << 4) -/* Hardware can monitor all messages, not just directed and broadcast. */ -#define CEC_CAP_MONITOR_ALL (1 << 5) - -/** - * struct cec_caps - CEC capabilities structure. - * @driver: name of the CEC device driver. - * @name: name of the CEC device. @driver + @name must be unique. - * @available_log_addrs: number of available logical addresses. - * @capabilities: capabilities of the CEC adapter. - * @version: version of the CEC adapter framework. - */ -struct cec_caps { - char driver[32]; - char name[32]; - __u32 available_log_addrs; - __u32 capabilities; - __u32 version; -}; - -/** - * struct cec_log_addrs - CEC logical addresses structure. - * @log_addr: the claimed logical addresses. Set by the driver. - * @log_addr_mask: current logical address mask. Set by the driver. - * @cec_version: the CEC version that the adapter should implement. Set by the - * caller. - * @num_log_addrs: how many logical addresses should be claimed. Set by the - * caller. - * @vendor_id: the vendor ID of the device. Set by the caller. - * @flags: flags. - * @osd_name: the OSD name of the device. Set by the caller. - * @primary_device_type: the primary device type for each logical address. - * Set by the caller. - * @log_addr_type: the logical address types. Set by the caller. - * @all_device_types: CEC 2.0: all device types represented by the logical - * address. Set by the caller. - * @features: CEC 2.0: The logical address features. Set by the caller. - */ -struct cec_log_addrs { - __u8 log_addr[CEC_MAX_LOG_ADDRS]; - __u16 log_addr_mask; - __u8 cec_version; - __u8 num_log_addrs; - __u32 vendor_id; - __u32 flags; - char osd_name[15]; - __u8 primary_device_type[CEC_MAX_LOG_ADDRS]; - __u8 log_addr_type[CEC_MAX_LOG_ADDRS]; - - /* CEC 2.0 */ - __u8 all_device_types[CEC_MAX_LOG_ADDRS]; - __u8 features[CEC_MAX_LOG_ADDRS][12]; -}; - -/* Allow a fallback to unregistered */ -#define CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK (1 << 0) -/* Passthrough RC messages to the input subsystem */ -#define CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU (1 << 1) -/* CDC-Only device: supports only CDC messages */ -#define CEC_LOG_ADDRS_FL_CDC_ONLY (1 << 2) - -/* Events */ - -/* Event that occurs when the adapter state changes */ -#define CEC_EVENT_STATE_CHANGE 1 -/* - * This event is sent when messages are lost because the application - * didn't empty the message queue in time - */ -#define CEC_EVENT_LOST_MSGS 2 - -#define CEC_EVENT_FL_INITIAL_STATE (1 << 0) - -/** - * struct cec_event_state_change - used when the CEC adapter changes state. - * @phys_addr: the current physical address - * @log_addr_mask: the current logical address mask - */ -struct cec_event_state_change { - __u16 phys_addr; - __u16 log_addr_mask; -}; - -/** - * struct cec_event_lost_msgs - tells you how many messages were lost due. - * @lost_msgs: how many messages were lost. - */ -struct cec_event_lost_msgs { - __u32 lost_msgs; -}; - -/** - * struct cec_event - CEC event structure - * @ts: the timestamp of when the event was sent. - * @event: the event. - * array. - * @state_change: the event payload for CEC_EVENT_STATE_CHANGE. - * @lost_msgs: the event payload for CEC_EVENT_LOST_MSGS. - * @raw: array to pad the union. - */ -struct cec_event { - __u64 ts; - __u32 event; - __u32 flags; - union { - struct cec_event_state_change state_change; - struct cec_event_lost_msgs lost_msgs; - __u32 raw[16]; - }; -}; - -/* ioctls */ - -/* Adapter capabilities */ -#define CEC_ADAP_G_CAPS _IOWR('a', 0, struct cec_caps) - -/* - * phys_addr is either 0 (if this is the CEC root device) - * or a valid physical address obtained from the sink's EDID - * as read by this CEC device (if this is a source device) - * or a physical address obtained and modified from a sink - * EDID and used for a sink CEC device. - * If nothing is connected, then phys_addr is 0xffff. - * See HDMI 1.4b, section 8.7 (Physical Address). - * - * The CEC_ADAP_S_PHYS_ADDR ioctl may not be available if that is handled - * internally. - */ -#define CEC_ADAP_G_PHYS_ADDR _IOR('a', 1, __u16) -#define CEC_ADAP_S_PHYS_ADDR _IOW('a', 2, __u16) - -/* - * Configure the CEC adapter. It sets the device type and which - * logical types it will try to claim. It will return which - * logical addresses it could actually claim. - * An error is returned if the adapter is disabled or if there - * is no physical address assigned. - */ - -#define CEC_ADAP_G_LOG_ADDRS _IOR('a', 3, struct cec_log_addrs) -#define CEC_ADAP_S_LOG_ADDRS _IOWR('a', 4, struct cec_log_addrs) - -/* Transmit/receive a CEC command */ -#define CEC_TRANSMIT _IOWR('a', 5, struct cec_msg) -#define CEC_RECEIVE _IOWR('a', 6, struct cec_msg) - -/* Dequeue CEC events */ -#define CEC_DQEVENT _IOWR('a', 7, struct cec_event) - -/* - * Get and set the message handling mode for this filehandle. - */ -#define CEC_G_MODE _IOR('a', 8, __u32) -#define CEC_S_MODE _IOW('a', 9, __u32) - -/* - * The remainder of this header defines all CEC messages and operands. - * The format matters since it the cec-ctl utility parses it to generate - * code for implementing all these messages. - * - * Comments ending with 'Feature' group messages for each feature. - * If messages are part of multiple features, then the "Has also" - * comment is used to list the previously defined messages that are - * supported by the feature. - * - * Before operands are defined a comment is added that gives the - * name of the operand and in brackets the variable name of the - * corresponding argument in the cec-funcs.h function. - */ - -/* Messages */ - -/* One Touch Play Feature */ -#define CEC_MSG_ACTIVE_SOURCE 0x82 -#define CEC_MSG_IMAGE_VIEW_ON 0x04 -#define CEC_MSG_TEXT_VIEW_ON 0x0d - - -/* Routing Control Feature */ - -/* - * Has also: - * CEC_MSG_ACTIVE_SOURCE - */ - -#define CEC_MSG_INACTIVE_SOURCE 0x9d -#define CEC_MSG_REQUEST_ACTIVE_SOURCE 0x85 -#define CEC_MSG_ROUTING_CHANGE 0x80 -#define CEC_MSG_ROUTING_INFORMATION 0x81 -#define CEC_MSG_SET_STREAM_PATH 0x86 - - -/* Standby Feature */ -#define CEC_MSG_STANDBY 0x36 - - -/* One Touch Record Feature */ -#define CEC_MSG_RECORD_OFF 0x0b -#define CEC_MSG_RECORD_ON 0x09 -/* Record Source Type Operand (rec_src_type) */ -#define CEC_OP_RECORD_SRC_OWN 1 -#define CEC_OP_RECORD_SRC_DIGITAL 2 -#define CEC_OP_RECORD_SRC_ANALOG 3 -#define CEC_OP_RECORD_SRC_EXT_PLUG 4 -#define CEC_OP_RECORD_SRC_EXT_PHYS_ADDR 5 -/* Service Identification Method Operand (service_id_method) */ -#define CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID 0 -#define CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL 1 -/* Digital Service Broadcast System Operand (dig_bcast_system) */ -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN 0x00 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN 0x01 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN 0x02 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS 0x08 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS 0x09 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T 0x0a -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE 0x10 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT 0x11 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T 0x12 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C 0x18 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S 0x19 -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 0x1a -#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T 0x1b -/* Analogue Broadcast Type Operand (ana_bcast_type) */ -#define CEC_OP_ANA_BCAST_TYPE_CABLE 0 -#define CEC_OP_ANA_BCAST_TYPE_SATELLITE 1 -#define CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL 2 -/* Broadcast System Operand (bcast_system) */ -#define CEC_OP_BCAST_SYSTEM_PAL_BG 0x00 -#define CEC_OP_BCAST_SYSTEM_SECAM_LQ 0x01 /* SECAM L' */ -#define CEC_OP_BCAST_SYSTEM_PAL_M 0x02 -#define CEC_OP_BCAST_SYSTEM_NTSC_M 0x03 -#define CEC_OP_BCAST_SYSTEM_PAL_I 0x04 -#define CEC_OP_BCAST_SYSTEM_SECAM_DK 0x05 -#define CEC_OP_BCAST_SYSTEM_SECAM_BG 0x06 -#define CEC_OP_BCAST_SYSTEM_SECAM_L 0x07 -#define CEC_OP_BCAST_SYSTEM_PAL_DK 0x08 -#define CEC_OP_BCAST_SYSTEM_OTHER 0x1f -/* Channel Number Format Operand (channel_number_fmt) */ -#define CEC_OP_CHANNEL_NUMBER_FMT_1_PART 0x01 -#define CEC_OP_CHANNEL_NUMBER_FMT_2_PART 0x02 - -#define CEC_MSG_RECORD_STATUS 0x0a -/* Record Status Operand (rec_status) */ -#define CEC_OP_RECORD_STATUS_CUR_SRC 0x01 -#define CEC_OP_RECORD_STATUS_DIG_SERVICE 0x02 -#define CEC_OP_RECORD_STATUS_ANA_SERVICE 0x03 -#define CEC_OP_RECORD_STATUS_EXT_INPUT 0x04 -#define CEC_OP_RECORD_STATUS_NO_DIG_SERVICE 0x05 -#define CEC_OP_RECORD_STATUS_NO_ANA_SERVICE 0x06 -#define CEC_OP_RECORD_STATUS_NO_SERVICE 0x07 -#define CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG 0x09 -#define CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR 0x0a -#define CEC_OP_RECORD_STATUS_UNSUP_CA 0x0b -#define CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS 0x0c -#define CEC_OP_RECORD_STATUS_CANT_COPY_SRC 0x0d -#define CEC_OP_RECORD_STATUS_NO_MORE_COPIES 0x0e -#define CEC_OP_RECORD_STATUS_NO_MEDIA 0x10 -#define CEC_OP_RECORD_STATUS_PLAYING 0x11 -#define CEC_OP_RECORD_STATUS_ALREADY_RECORDING 0x12 -#define CEC_OP_RECORD_STATUS_MEDIA_PROT 0x13 -#define CEC_OP_RECORD_STATUS_NO_SIGNAL 0x14 -#define CEC_OP_RECORD_STATUS_MEDIA_PROBLEM 0x15 -#define CEC_OP_RECORD_STATUS_NO_SPACE 0x16 -#define CEC_OP_RECORD_STATUS_PARENTAL_LOCK 0x17 -#define CEC_OP_RECORD_STATUS_TERMINATED_OK 0x1a -#define CEC_OP_RECORD_STATUS_ALREADY_TERM 0x1b -#define CEC_OP_RECORD_STATUS_OTHER 0x1f - -#define CEC_MSG_RECORD_TV_SCREEN 0x0f - - -/* Timer Programming Feature */ -#define CEC_MSG_CLEAR_ANALOGUE_TIMER 0x33 -/* Recording Sequence Operand (recording_seq) */ -#define CEC_OP_REC_SEQ_SUNDAY 0x01 -#define CEC_OP_REC_SEQ_MONDAY 0x02 -#define CEC_OP_REC_SEQ_TUESDAY 0x04 -#define CEC_OP_REC_SEQ_WEDNESDAY 0x08 -#define CEC_OP_REC_SEQ_THURSDAY 0x10 -#define CEC_OP_REC_SEQ_FRIDAY 0x20 -#define CEC_OP_REC_SEQ_SATERDAY 0x40 -#define CEC_OP_REC_SEQ_ONCE_ONLY 0x00 - -#define CEC_MSG_CLEAR_DIGITAL_TIMER 0x99 - -#define CEC_MSG_CLEAR_EXT_TIMER 0xa1 -/* External Source Specifier Operand (ext_src_spec) */ -#define CEC_OP_EXT_SRC_PLUG 0x04 -#define CEC_OP_EXT_SRC_PHYS_ADDR 0x05 - -#define CEC_MSG_SET_ANALOGUE_TIMER 0x34 -#define CEC_MSG_SET_DIGITAL_TIMER 0x97 -#define CEC_MSG_SET_EXT_TIMER 0xa2 - -#define CEC_MSG_SET_TIMER_PROGRAM_TITLE 0x67 -#define CEC_MSG_TIMER_CLEARED_STATUS 0x43 -/* Timer Cleared Status Data Operand (timer_cleared_status) */ -#define CEC_OP_TIMER_CLR_STAT_RECORDING 0x00 -#define CEC_OP_TIMER_CLR_STAT_NO_MATCHING 0x01 -#define CEC_OP_TIMER_CLR_STAT_NO_INFO 0x02 -#define CEC_OP_TIMER_CLR_STAT_CLEARED 0x80 - -#define CEC_MSG_TIMER_STATUS 0x35 -/* Timer Overlap Warning Operand (timer_overlap_warning) */ -#define CEC_OP_TIMER_OVERLAP_WARNING_NO_OVERLAP 0 -#define CEC_OP_TIMER_OVERLAP_WARNING_OVERLAP 1 -/* Media Info Operand (media_info) */ -#define CEC_OP_MEDIA_INFO_UNPROT_MEDIA 0 -#define CEC_OP_MEDIA_INFO_PROT_MEDIA 1 -#define CEC_OP_MEDIA_INFO_NO_MEDIA 2 -/* Programmed Indicator Operand (prog_indicator) */ -#define CEC_OP_PROG_IND_NOT_PROGRAMMED 0 -#define CEC_OP_PROG_IND_PROGRAMMED 1 -/* Programmed Info Operand (prog_info) */ -#define CEC_OP_PROG_INFO_ENOUGH_SPACE 0x08 -#define CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE 0x09 -#define CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE 0x0b -#define CEC_OP_PROG_INFO_NONE_AVAILABLE 0x0a -/* Not Programmed Error Info Operand (prog_error) */ -#define CEC_OP_PROG_ERROR_NO_FREE_TIMER 0x01 -#define CEC_OP_PROG_ERROR_DATE_OUT_OF_RANGE 0x02 -#define CEC_OP_PROG_ERROR_REC_SEQ_ERROR 0x03 -#define CEC_OP_PROG_ERROR_INV_EXT_PLUG 0x04 -#define CEC_OP_PROG_ERROR_INV_EXT_PHYS_ADDR 0x05 -#define CEC_OP_PROG_ERROR_CA_UNSUPP 0x06 -#define CEC_OP_PROG_ERROR_INSUF_CA_ENTITLEMENTS 0x07 -#define CEC_OP_PROG_ERROR_RESOLUTION_UNSUPP 0x08 -#define CEC_OP_PROG_ERROR_PARENTAL_LOCK 0x09 -#define CEC_OP_PROG_ERROR_CLOCK_FAILURE 0x0a -#define CEC_OP_PROG_ERROR_DUPLICATE 0x0e - - -/* System Information Feature */ -#define CEC_MSG_CEC_VERSION 0x9e -/* CEC Version Operand (cec_version) */ -#define CEC_OP_CEC_VERSION_1_3A 4 -#define CEC_OP_CEC_VERSION_1_4 5 -#define CEC_OP_CEC_VERSION_2_0 6 - -#define CEC_MSG_GET_CEC_VERSION 0x9f -#define CEC_MSG_GIVE_PHYSICAL_ADDR 0x83 -#define CEC_MSG_GET_MENU_LANGUAGE 0x91 -#define CEC_MSG_REPORT_PHYSICAL_ADDR 0x84 -/* Primary Device Type Operand (prim_devtype) */ -#define CEC_OP_PRIM_DEVTYPE_TV 0 -#define CEC_OP_PRIM_DEVTYPE_RECORD 1 -#define CEC_OP_PRIM_DEVTYPE_TUNER 3 -#define CEC_OP_PRIM_DEVTYPE_PLAYBACK 4 -#define CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM 5 -#define CEC_OP_PRIM_DEVTYPE_SWITCH 6 -#define CEC_OP_PRIM_DEVTYPE_PROCESSOR 7 - -#define CEC_MSG_SET_MENU_LANGUAGE 0x32 -#define CEC_MSG_REPORT_FEATURES 0xa6 /* HDMI 2.0 */ -/* All Device Types Operand (all_device_types) */ -#define CEC_OP_ALL_DEVTYPE_TV 0x80 -#define CEC_OP_ALL_DEVTYPE_RECORD 0x40 -#define CEC_OP_ALL_DEVTYPE_TUNER 0x20 -#define CEC_OP_ALL_DEVTYPE_PLAYBACK 0x10 -#define CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM 0x08 -#define CEC_OP_ALL_DEVTYPE_SWITCH 0x04 -/* - * And if you wondering what happened to PROCESSOR devices: those should - * be mapped to a SWITCH. - */ - -/* Valid for RC Profile and Device Feature operands */ -#define CEC_OP_FEAT_EXT 0x80 /* Extension bit */ -/* RC Profile Operand (rc_profile) */ -#define CEC_OP_FEAT_RC_TV_PROFILE_NONE 0x00 -#define CEC_OP_FEAT_RC_TV_PROFILE_1 0x02 -#define CEC_OP_FEAT_RC_TV_PROFILE_2 0x06 -#define CEC_OP_FEAT_RC_TV_PROFILE_3 0x0a -#define CEC_OP_FEAT_RC_TV_PROFILE_4 0x0e -#define CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU 0x50 -#define CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU 0x48 -#define CEC_OP_FEAT_RC_SRC_HAS_CONTENTS_MENU 0x44 -#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU 0x42 -#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU 0x41 -/* Device Feature Operand (dev_features) */ -#define CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN 0x40 -#define CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING 0x20 -#define CEC_OP_FEAT_DEV_HAS_DECK_CONTROL 0x10 -#define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE 0x08 -#define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX 0x04 -#define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX 0x02 - -#define CEC_MSG_GIVE_FEATURES 0xa5 /* HDMI 2.0 */ - - -/* Deck Control Feature */ -#define CEC_MSG_DECK_CONTROL 0x42 -/* Deck Control Mode Operand (deck_control_mode) */ -#define CEC_OP_DECK_CTL_MODE_SKIP_FWD 1 -#define CEC_OP_DECK_CTL_MODE_SKIP_REV 2 -#define CEC_OP_DECK_CTL_MODE_STOP 3 -#define CEC_OP_DECK_CTL_MODE_EJECT 4 - -#define CEC_MSG_DECK_STATUS 0x1b -/* Deck Info Operand (deck_info) */ -#define CEC_OP_DECK_INFO_PLAY 0x11 -#define CEC_OP_DECK_INFO_RECORD 0x12 -#define CEC_OP_DECK_INFO_PLAY_REV 0x13 -#define CEC_OP_DECK_INFO_STILL 0x14 -#define CEC_OP_DECK_INFO_SLOW 0x15 -#define CEC_OP_DECK_INFO_SLOW_REV 0x16 -#define CEC_OP_DECK_INFO_FAST_FWD 0x17 -#define CEC_OP_DECK_INFO_FAST_REV 0x18 -#define CEC_OP_DECK_INFO_NO_MEDIA 0x19 -#define CEC_OP_DECK_INFO_STOP 0x1a -#define CEC_OP_DECK_INFO_SKIP_FWD 0x1b -#define CEC_OP_DECK_INFO_SKIP_REV 0x1c -#define CEC_OP_DECK_INFO_INDEX_SEARCH_FWD 0x1d -#define CEC_OP_DECK_INFO_INDEX_SEARCH_REV 0x1e -#define CEC_OP_DECK_INFO_OTHER 0x1f - -#define CEC_MSG_GIVE_DECK_STATUS 0x1a -/* Status Request Operand (status_req) */ -#define CEC_OP_STATUS_REQ_ON 1 -#define CEC_OP_STATUS_REQ_OFF 2 -#define CEC_OP_STATUS_REQ_ONCE 3 - -#define CEC_MSG_PLAY 0x41 -/* Play Mode Operand (play_mode) */ -#define CEC_OP_PLAY_MODE_PLAY_FWD 0x24 -#define CEC_OP_PLAY_MODE_PLAY_REV 0x20 -#define CEC_OP_PLAY_MODE_PLAY_STILL 0x25 -#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN 0x05 -#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED 0x06 -#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX 0x07 -#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN 0x09 -#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED 0x0a -#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX 0x0b -#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN 0x15 -#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED 0x16 -#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX 0x17 -#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN 0x19 -#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED 0x1a -#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX 0x1b - - -/* Tuner Control Feature */ -#define CEC_MSG_GIVE_TUNER_DEVICE_STATUS 0x08 -#define CEC_MSG_SELECT_ANALOGUE_SERVICE 0x92 -#define CEC_MSG_SELECT_DIGITAL_SERVICE 0x93 -#define CEC_MSG_TUNER_DEVICE_STATUS 0x07 -/* Recording Flag Operand (rec_flag) */ -#define CEC_OP_REC_FLAG_USED 0 -#define CEC_OP_REC_FLAG_NOT_USED 1 -/* Tuner Display Info Operand (tuner_display_info) */ -#define CEC_OP_TUNER_DISPLAY_INFO_DIGITAL 0 -#define CEC_OP_TUNER_DISPLAY_INFO_NONE 1 -#define CEC_OP_TUNER_DISPLAY_INFO_ANALOGUE 2 - -#define CEC_MSG_TUNER_STEP_DECREMENT 0x06 -#define CEC_MSG_TUNER_STEP_INCREMENT 0x05 - - -/* Vendor Specific Commands Feature */ - -/* - * Has also: - * CEC_MSG_CEC_VERSION - * CEC_MSG_GET_CEC_VERSION - */ -#define CEC_MSG_DEVICE_VENDOR_ID 0x87 -#define CEC_MSG_GIVE_DEVICE_VENDOR_ID 0x8c -#define CEC_MSG_VENDOR_COMMAND 0x89 -#define CEC_MSG_VENDOR_COMMAND_WITH_ID 0xa0 -#define CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN 0x8a -#define CEC_MSG_VENDOR_REMOTE_BUTTON_UP 0x8b - - -/* OSD Display Feature */ -#define CEC_MSG_SET_OSD_STRING 0x64 -/* Display Control Operand (disp_ctl) */ -#define CEC_OP_DISP_CTL_DEFAULT 0x00 -#define CEC_OP_DISP_CTL_UNTIL_CLEARED 0x40 -#define CEC_OP_DISP_CTL_CLEAR 0x80 - - -/* Device OSD Transfer Feature */ -#define CEC_MSG_GIVE_OSD_NAME 0x46 -#define CEC_MSG_SET_OSD_NAME 0x47 - - -/* Device Menu Control Feature */ -#define CEC_MSG_MENU_REQUEST 0x8d -/* Menu Request Type Operand (menu_req) */ -#define CEC_OP_MENU_REQUEST_ACTIVATE 0x00 -#define CEC_OP_MENU_REQUEST_DEACTIVATE 0x01 -#define CEC_OP_MENU_REQUEST_QUERY 0x02 - -#define CEC_MSG_MENU_STATUS 0x8e -/* Menu State Operand (menu_state) */ -#define CEC_OP_MENU_STATE_ACTIVATED 0x00 -#define CEC_OP_MENU_STATE_DEACTIVATED 0x01 - -#define CEC_MSG_USER_CONTROL_PRESSED 0x44 -/* UI Broadcast Type Operand (ui_bcast_type) */ -#define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL 0x00 -#define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA 0x01 -#define CEC_OP_UI_BCAST_TYPE_ANALOGUE 0x10 -#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_T 0x20 -#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_CABLE 0x30 -#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_SAT 0x40 -#define CEC_OP_UI_BCAST_TYPE_DIGITAL 0x50 -#define CEC_OP_UI_BCAST_TYPE_DIGITAL_T 0x60 -#define CEC_OP_UI_BCAST_TYPE_DIGITAL_CABLE 0x70 -#define CEC_OP_UI_BCAST_TYPE_DIGITAL_SAT 0x80 -#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT 0x90 -#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT2 0x91 -#define CEC_OP_UI_BCAST_TYPE_IP 0xa0 -/* UI Sound Presentation Control Operand (ui_snd_pres_ctl) */ -#define CEC_OP_UI_SND_PRES_CTL_DUAL_MONO 0x10 -#define CEC_OP_UI_SND_PRES_CTL_KARAOKE 0x20 -#define CEC_OP_UI_SND_PRES_CTL_DOWNMIX 0x80 -#define CEC_OP_UI_SND_PRES_CTL_REVERB 0x90 -#define CEC_OP_UI_SND_PRES_CTL_EQUALIZER 0xa0 -#define CEC_OP_UI_SND_PRES_CTL_BASS_UP 0xb1 -#define CEC_OP_UI_SND_PRES_CTL_BASS_NEUTRAL 0xb2 -#define CEC_OP_UI_SND_PRES_CTL_BASS_DOWN 0xb3 -#define CEC_OP_UI_SND_PRES_CTL_TREBLE_UP 0xc1 -#define CEC_OP_UI_SND_PRES_CTL_TREBLE_NEUTRAL 0xc2 -#define CEC_OP_UI_SND_PRES_CTL_TREBLE_DOWN 0xc3 - -#define CEC_MSG_USER_CONTROL_RELEASED 0x45 - - -/* Remote Control Passthrough Feature */ - -/* - * Has also: - * CEC_MSG_USER_CONTROL_PRESSED - * CEC_MSG_USER_CONTROL_RELEASED - */ - - -/* Power Status Feature */ -#define CEC_MSG_GIVE_DEVICE_POWER_STATUS 0x8f -#define CEC_MSG_REPORT_POWER_STATUS 0x90 -/* Power Status Operand (pwr_state) */ -#define CEC_OP_POWER_STATUS_ON 0 -#define CEC_OP_POWER_STATUS_STANDBY 1 -#define CEC_OP_POWER_STATUS_TO_ON 2 -#define CEC_OP_POWER_STATUS_TO_STANDBY 3 - - -/* General Protocol Messages */ -#define CEC_MSG_FEATURE_ABORT 0x00 -/* Abort Reason Operand (reason) */ -#define CEC_OP_ABORT_UNRECOGNIZED_OP 0 -#define CEC_OP_ABORT_INCORRECT_MODE 1 -#define CEC_OP_ABORT_NO_SOURCE 2 -#define CEC_OP_ABORT_INVALID_OP 3 -#define CEC_OP_ABORT_REFUSED 4 -#define CEC_OP_ABORT_UNDETERMINED 5 - -#define CEC_MSG_ABORT 0xff - - -/* System Audio Control Feature */ - -/* - * Has also: - * CEC_MSG_USER_CONTROL_PRESSED - * CEC_MSG_USER_CONTROL_RELEASED - */ -#define CEC_MSG_GIVE_AUDIO_STATUS 0x71 -#define CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7d -#define CEC_MSG_REPORT_AUDIO_STATUS 0x7a -/* Audio Mute Status Operand (aud_mute_status) */ -#define CEC_OP_AUD_MUTE_STATUS_OFF 0 -#define CEC_OP_AUD_MUTE_STATUS_ON 1 - -#define CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR 0xa3 -#define CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR 0xa4 -#define CEC_MSG_SET_SYSTEM_AUDIO_MODE 0x72 -/* System Audio Status Operand (sys_aud_status) */ -#define CEC_OP_SYS_AUD_STATUS_OFF 0 -#define CEC_OP_SYS_AUD_STATUS_ON 1 - -#define CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST 0x70 -#define CEC_MSG_SYSTEM_AUDIO_MODE_STATUS 0x7e -/* Audio Format ID Operand (audio_format_id) */ -#define CEC_OP_AUD_FMT_ID_CEA861 0 -#define CEC_OP_AUD_FMT_ID_CEA861_CXT 1 - - -/* Audio Rate Control Feature */ -#define CEC_MSG_SET_AUDIO_RATE 0x9a -/* Audio Rate Operand (audio_rate) */ -#define CEC_OP_AUD_RATE_OFF 0 -#define CEC_OP_AUD_RATE_WIDE_STD 1 -#define CEC_OP_AUD_RATE_WIDE_FAST 2 -#define CEC_OP_AUD_RATE_WIDE_SLOW 3 -#define CEC_OP_AUD_RATE_NARROW_STD 4 -#define CEC_OP_AUD_RATE_NARROW_FAST 5 -#define CEC_OP_AUD_RATE_NARROW_SLOW 6 - - -/* Audio Return Channel Control Feature */ -#define CEC_MSG_INITIATE_ARC 0xc0 -#define CEC_MSG_REPORT_ARC_INITIATED 0xc1 -#define CEC_MSG_REPORT_ARC_TERMINATED 0xc2 -#define CEC_MSG_REQUEST_ARC_INITIATION 0xc3 -#define CEC_MSG_REQUEST_ARC_TERMINATION 0xc4 -#define CEC_MSG_TERMINATE_ARC 0xc5 - - -/* Dynamic Audio Lipsync Feature */ -/* Only for CEC 2.0 and up */ -#define CEC_MSG_REQUEST_CURRENT_LATENCY 0xa7 -#define CEC_MSG_REPORT_CURRENT_LATENCY 0xa8 -/* Low Latency Mode Operand (low_latency_mode) */ -#define CEC_OP_LOW_LATENCY_MODE_OFF 0 -#define CEC_OP_LOW_LATENCY_MODE_ON 1 -/* Audio Output Compensated Operand (audio_out_compensated) */ -#define CEC_OP_AUD_OUT_COMPENSATED_NA 0 -#define CEC_OP_AUD_OUT_COMPENSATED_DELAY 1 -#define CEC_OP_AUD_OUT_COMPENSATED_NO_DELAY 2 -#define CEC_OP_AUD_OUT_COMPENSATED_PARTIAL_DELAY 3 - - -/* Capability Discovery and Control Feature */ -#define CEC_MSG_CDC_MESSAGE 0xf8 -/* Ethernet-over-HDMI: nobody ever does this... */ -#define CEC_MSG_CDC_HEC_INQUIRE_STATE 0x00 -#define CEC_MSG_CDC_HEC_REPORT_STATE 0x01 -/* HEC Functionality State Operand (hec_func_state) */ -#define CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED 0 -#define CEC_OP_HEC_FUNC_STATE_INACTIVE 1 -#define CEC_OP_HEC_FUNC_STATE_ACTIVE 2 -#define CEC_OP_HEC_FUNC_STATE_ACTIVATION_FIELD 3 -/* Host Functionality State Operand (host_func_state) */ -#define CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED 0 -#define CEC_OP_HOST_FUNC_STATE_INACTIVE 1 -#define CEC_OP_HOST_FUNC_STATE_ACTIVE 2 -/* ENC Functionality State Operand (enc_func_state) */ -#define CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED 0 -#define CEC_OP_ENC_FUNC_STATE_EXT_CON_INACTIVE 1 -#define CEC_OP_ENC_FUNC_STATE_EXT_CON_ACTIVE 2 -/* CDC Error Code Operand (cdc_errcode) */ -#define CEC_OP_CDC_ERROR_CODE_NONE 0 -#define CEC_OP_CDC_ERROR_CODE_CAP_UNSUPPORTED 1 -#define CEC_OP_CDC_ERROR_CODE_WRONG_STATE 2 -#define CEC_OP_CDC_ERROR_CODE_OTHER 3 -/* HEC Support Operand (hec_support) */ -#define CEC_OP_HEC_SUPPORT_NO 0 -#define CEC_OP_HEC_SUPPORT_YES 1 -/* HEC Activation Operand (hec_activation) */ -#define CEC_OP_HEC_ACTIVATION_ON 0 -#define CEC_OP_HEC_ACTIVATION_OFF 1 - -#define CEC_MSG_CDC_HEC_SET_STATE_ADJACENT 0x02 -#define CEC_MSG_CDC_HEC_SET_STATE 0x03 -/* HEC Set State Operand (hec_set_state) */ -#define CEC_OP_HEC_SET_STATE_DEACTIVATE 0 -#define CEC_OP_HEC_SET_STATE_ACTIVATE 1 - -#define CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION 0x04 -#define CEC_MSG_CDC_HEC_NOTIFY_ALIVE 0x05 -#define CEC_MSG_CDC_HEC_DISCOVER 0x06 -/* Hotplug Detect messages */ -#define CEC_MSG_CDC_HPD_SET_STATE 0x10 -/* HPD State Operand (hpd_state) */ -#define CEC_OP_HPD_STATE_CP_EDID_DISABLE 0 -#define CEC_OP_HPD_STATE_CP_EDID_ENABLE 1 -#define CEC_OP_HPD_STATE_CP_EDID_DISABLE_ENABLE 2 -#define CEC_OP_HPD_STATE_EDID_DISABLE 3 -#define CEC_OP_HPD_STATE_EDID_ENABLE 4 -#define CEC_OP_HPD_STATE_EDID_DISABLE_ENABLE 5 -#define CEC_MSG_CDC_HPD_REPORT_STATE 0x11 -/* HPD Error Code Operand (hpd_error) */ -#define CEC_OP_HPD_ERROR_NONE 0 -#define CEC_OP_HPD_ERROR_INITIATOR_NOT_CAPABLE 1 -#define CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE 2 -#define CEC_OP_HPD_ERROR_OTHER 3 -#define CEC_OP_HPD_ERROR_NONE_NO_VIDEO 4 - -/* End of Messages */ - -/* Helper functions to identify the 'special' CEC devices */ - -static inline bool cec_is_2nd_tv(const struct cec_log_addrs *las) -{ - /* - * It is a second TV if the logical address is 14 or 15 and the - * primary device type is a TV. - */ - return las->num_log_addrs && - las->log_addr[0] >= CEC_LOG_ADDR_SPECIFIC && - las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_TV; -} - -static inline bool cec_is_processor(const struct cec_log_addrs *las) -{ - /* - * It is a processor if the logical address is 12-15 and the - * primary device type is a Processor. - */ - return las->num_log_addrs && - las->log_addr[0] >= CEC_LOG_ADDR_BACKUP_1 && - las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_PROCESSOR; -} - -static inline bool cec_is_switch(const struct cec_log_addrs *las) -{ - /* - * It is a switch if the logical address is 15 and the - * primary device type is a Switch and the CDC-Only flag is not set. - */ - return las->num_log_addrs == 1 && - las->log_addr[0] == CEC_LOG_ADDR_UNREGISTERED && - las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH && - !(las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY); -} - -static inline bool cec_is_cdc_only(const struct cec_log_addrs *las) -{ - /* - * It is a CDC-only device if the logical address is 15 and the - * primary device type is a Switch and the CDC-Only flag is set. - */ - return las->num_log_addrs == 1 && - las->log_addr[0] == CEC_LOG_ADDR_UNREGISTERED && - las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH && - (las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY); -} - -#endif diff --git a/include/media/cec.h b/include/media/cec.h index fdb5d600e4bb..717eaf552f3d 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -196,7 +196,7 @@ static inline bool cec_is_sink(const struct cec_adapter *adap) return adap->phys_addr == 0; } -#if IS_ENABLED(CONFIG_MEDIA_CEC) +#if IS_ENABLED(CONFIG_MEDIA_CEC_SUPPORT) struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, void *priv, const char *name, u32 caps, u8 available_las, struct device *parent); diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index 6965d0909554..c49c448cff92 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -82,6 +82,8 @@ header-y += capi.h header-y += cciss_defs.h header-y += cciss_ioctl.h header-y += cdrom.h +header-y += cec.h +header-y += cec-funcs.h header-y += cgroupstats.h header-y += chio.h header-y += cm4000_cs.h diff --git a/include/uapi/linux/cec-funcs.h b/include/uapi/linux/cec-funcs.h new file mode 100644 index 000000000000..1a1de2169f48 --- /dev/null +++ b/include/uapi/linux/cec-funcs.h @@ -0,0 +1,1965 @@ +/* + * cec - HDMI Consumer Electronics Control message functions + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * Alternatively you can redistribute this file under the terms of the + * BSD license as stated below: + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * 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 _CEC_UAPI_FUNCS_H +#define _CEC_UAPI_FUNCS_H + +#include + +/* One Touch Play Feature */ +static inline void cec_msg_active_source(struct cec_msg *msg, __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ACTIVE_SOURCE; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_active_source(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_image_view_on(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_IMAGE_VIEW_ON; +} + +static inline void cec_msg_text_view_on(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TEXT_VIEW_ON; +} + + +/* Routing Control Feature */ +static inline void cec_msg_inactive_source(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_INACTIVE_SOURCE; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_inactive_source(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_request_active_source(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REQUEST_ACTIVE_SOURCE; + msg->reply = reply ? CEC_MSG_ACTIVE_SOURCE : 0; +} + +static inline void cec_msg_routing_information(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ROUTING_INFORMATION; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_routing_information(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_routing_change(struct cec_msg *msg, + bool reply, + __u16 orig_phys_addr, + __u16 new_phys_addr) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_ROUTING_CHANGE; + msg->msg[2] = orig_phys_addr >> 8; + msg->msg[3] = orig_phys_addr & 0xff; + msg->msg[4] = new_phys_addr >> 8; + msg->msg[5] = new_phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_ROUTING_INFORMATION : 0; +} + +static inline void cec_ops_routing_change(const struct cec_msg *msg, + __u16 *orig_phys_addr, + __u16 *new_phys_addr) +{ + *orig_phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *new_phys_addr = (msg->msg[4] << 8) | msg->msg[5]; +} + +static inline void cec_msg_set_stream_path(struct cec_msg *msg, __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_SET_STREAM_PATH; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; +} + +static inline void cec_ops_set_stream_path(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + + +/* Standby Feature */ +static inline void cec_msg_standby(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_STANDBY; +} + + +/* One Touch Record Feature */ +static inline void cec_msg_record_off(struct cec_msg *msg, bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_RECORD_OFF; + msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0; +} + +struct cec_op_arib_data { + __u16 transport_id; + __u16 service_id; + __u16 orig_network_id; +}; + +struct cec_op_atsc_data { + __u16 transport_id; + __u16 program_number; +}; + +struct cec_op_dvb_data { + __u16 transport_id; + __u16 service_id; + __u16 orig_network_id; +}; + +struct cec_op_channel_data { + __u8 channel_number_fmt; + __u16 major; + __u16 minor; +}; + +struct cec_op_digital_service_id { + __u8 service_id_method; + __u8 dig_bcast_system; + union { + struct cec_op_arib_data arib; + struct cec_op_atsc_data atsc; + struct cec_op_dvb_data dvb; + struct cec_op_channel_data channel; + }; +}; + +struct cec_op_record_src { + __u8 type; + union { + struct cec_op_digital_service_id digital; + struct { + __u8 ana_bcast_type; + __u16 ana_freq; + __u8 bcast_system; + } analog; + struct { + __u8 plug; + } ext_plug; + struct { + __u16 phys_addr; + } ext_phys_addr; + }; +}; + +static inline void cec_set_digital_service_id(__u8 *msg, + const struct cec_op_digital_service_id *digital) +{ + *msg++ = (digital->service_id_method << 7) | digital->dig_bcast_system; + if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { + *msg++ = (digital->channel.channel_number_fmt << 2) | + (digital->channel.major >> 8); + *msg++ = digital->channel.major & 0xff; + *msg++ = digital->channel.minor >> 8; + *msg++ = digital->channel.minor & 0xff; + *msg++ = 0; + *msg++ = 0; + return; + } + switch (digital->dig_bcast_system) { + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT: + case CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T: + *msg++ = digital->atsc.transport_id >> 8; + *msg++ = digital->atsc.transport_id & 0xff; + *msg++ = digital->atsc.program_number >> 8; + *msg++ = digital->atsc.program_number & 0xff; + *msg++ = 0; + *msg++ = 0; + break; + default: + *msg++ = digital->dvb.transport_id >> 8; + *msg++ = digital->dvb.transport_id & 0xff; + *msg++ = digital->dvb.service_id >> 8; + *msg++ = digital->dvb.service_id & 0xff; + *msg++ = digital->dvb.orig_network_id >> 8; + *msg++ = digital->dvb.orig_network_id & 0xff; + break; + } +} + +static inline void cec_get_digital_service_id(const __u8 *msg, + struct cec_op_digital_service_id *digital) +{ + digital->service_id_method = msg[0] >> 7; + digital->dig_bcast_system = msg[0] & 0x7f; + if (digital->service_id_method == CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL) { + digital->channel.channel_number_fmt = msg[1] >> 2; + digital->channel.major = ((msg[1] & 3) << 6) | msg[2]; + digital->channel.minor = (msg[3] << 8) | msg[4]; + return; + } + digital->dvb.transport_id = (msg[1] << 8) | msg[2]; + digital->dvb.service_id = (msg[3] << 8) | msg[4]; + digital->dvb.orig_network_id = (msg[5] << 8) | msg[6]; +} + +static inline void cec_msg_record_on_own(struct cec_msg *msg) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_OWN; +} + +static inline void cec_msg_record_on_digital(struct cec_msg *msg, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 10; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_DIGITAL; + cec_set_digital_service_id(msg->msg + 3, digital); +} + +static inline void cec_msg_record_on_analog(struct cec_msg *msg, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 7; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_ANALOG; + msg->msg[3] = ana_bcast_type; + msg->msg[4] = ana_freq >> 8; + msg->msg[5] = ana_freq & 0xff; + msg->msg[6] = bcast_system; +} + +static inline void cec_msg_record_on_plug(struct cec_msg *msg, + __u8 plug) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PLUG; + msg->msg[3] = plug; +} + +static inline void cec_msg_record_on_phys_addr(struct cec_msg *msg, + __u16 phys_addr) +{ + msg->len = 5; + msg->msg[1] = CEC_MSG_RECORD_ON; + msg->msg[2] = CEC_OP_RECORD_SRC_EXT_PHYS_ADDR; + msg->msg[3] = phys_addr >> 8; + msg->msg[4] = phys_addr & 0xff; +} + +static inline void cec_msg_record_on(struct cec_msg *msg, + bool reply, + const struct cec_op_record_src *rec_src) +{ + switch (rec_src->type) { + case CEC_OP_RECORD_SRC_OWN: + cec_msg_record_on_own(msg); + break; + case CEC_OP_RECORD_SRC_DIGITAL: + cec_msg_record_on_digital(msg, &rec_src->digital); + break; + case CEC_OP_RECORD_SRC_ANALOG: + cec_msg_record_on_analog(msg, + rec_src->analog.ana_bcast_type, + rec_src->analog.ana_freq, + rec_src->analog.bcast_system); + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + cec_msg_record_on_plug(msg, rec_src->ext_plug.plug); + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + cec_msg_record_on_phys_addr(msg, + rec_src->ext_phys_addr.phys_addr); + break; + } + msg->reply = reply ? CEC_MSG_RECORD_STATUS : 0; +} + +static inline void cec_ops_record_on(const struct cec_msg *msg, + struct cec_op_record_src *rec_src) +{ + rec_src->type = msg->msg[2]; + switch (rec_src->type) { + case CEC_OP_RECORD_SRC_OWN: + break; + case CEC_OP_RECORD_SRC_DIGITAL: + cec_get_digital_service_id(msg->msg + 3, &rec_src->digital); + break; + case CEC_OP_RECORD_SRC_ANALOG: + rec_src->analog.ana_bcast_type = msg->msg[3]; + rec_src->analog.ana_freq = + (msg->msg[4] << 8) | msg->msg[5]; + rec_src->analog.bcast_system = msg->msg[6]; + break; + case CEC_OP_RECORD_SRC_EXT_PLUG: + rec_src->ext_plug.plug = msg->msg[3]; + break; + case CEC_OP_RECORD_SRC_EXT_PHYS_ADDR: + rec_src->ext_phys_addr.phys_addr = + (msg->msg[3] << 8) | msg->msg[4]; + break; + } +} + +static inline void cec_msg_record_status(struct cec_msg *msg, __u8 rec_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_RECORD_STATUS; + msg->msg[2] = rec_status; +} + +static inline void cec_ops_record_status(const struct cec_msg *msg, + __u8 *rec_status) +{ + *rec_status = msg->msg[2]; +} + +static inline void cec_msg_record_tv_screen(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_RECORD_TV_SCREEN; + msg->reply = reply ? CEC_MSG_RECORD_ON : 0; +} + + +/* Timer Programming Feature */ +static inline void cec_msg_timer_status(struct cec_msg *msg, + __u8 timer_overlap_warning, + __u8 media_info, + __u8 prog_info, + __u8 prog_error, + __u8 duration_hr, + __u8 duration_min) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_TIMER_STATUS; + msg->msg[2] = (timer_overlap_warning << 7) | + (media_info << 5) | + (prog_info ? 0x10 : 0) | + (prog_info ? prog_info : prog_error); + if (prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || + prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || + prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { + msg->len += 2; + msg->msg[3] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[4] = ((duration_min / 10) << 4) | (duration_min % 10); + } +} + +static inline void cec_ops_timer_status(const struct cec_msg *msg, + __u8 *timer_overlap_warning, + __u8 *media_info, + __u8 *prog_info, + __u8 *prog_error, + __u8 *duration_hr, + __u8 *duration_min) +{ + *timer_overlap_warning = msg->msg[2] >> 7; + *media_info = (msg->msg[2] >> 5) & 3; + if (msg->msg[2] & 0x10) { + *prog_info = msg->msg[2] & 0xf; + *prog_error = 0; + } else { + *prog_info = 0; + *prog_error = msg->msg[2] & 0xf; + } + if (*prog_info == CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE || + *prog_info == CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE || + *prog_error == CEC_OP_PROG_ERROR_DUPLICATE) { + *duration_hr = (msg->msg[3] >> 4) * 10 + (msg->msg[3] & 0xf); + *duration_min = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + } else { + *duration_hr = *duration_min = 0; + } +} + +static inline void cec_msg_timer_cleared_status(struct cec_msg *msg, + __u8 timer_cleared_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_TIMER_CLEARED_STATUS; + msg->msg[2] = timer_cleared_status; +} + +static inline void cec_ops_timer_cleared_status(const struct cec_msg *msg, + __u8 *timer_cleared_status) +{ + *timer_cleared_status = msg->msg[2]; +} + +static inline void cec_msg_clear_analogue_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_CLEAR_ANALOGUE_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ana_bcast_type; + msg->msg[10] = ana_freq >> 8; + msg->msg[11] = ana_freq & 0xff; + msg->msg[12] = bcast_system; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; +} + +static inline void cec_ops_clear_analogue_timer(const struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ana_bcast_type = msg->msg[9]; + *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; + *bcast_system = msg->msg[12]; +} + +static inline void cec_msg_clear_digital_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 16; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; + msg->msg[1] = CEC_MSG_CLEAR_DIGITAL_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + cec_set_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_ops_clear_digital_timer(const struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + struct cec_op_digital_service_id *digital) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + cec_get_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_msg_clear_ext_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ext_src_spec, + __u8 plug, + __u16 phys_addr) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_CLEAR_EXT_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ext_src_spec; + msg->msg[10] = plug; + msg->msg[11] = phys_addr >> 8; + msg->msg[12] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_TIMER_CLEARED_STATUS : 0; +} + +static inline void cec_ops_clear_ext_timer(const struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ext_src_spec, + __u8 *plug, + __u16 *phys_addr) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ext_src_spec = msg->msg[9]; + *plug = msg->msg[10]; + *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; +} + +static inline void cec_msg_set_analogue_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_SET_ANALOGUE_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ana_bcast_type; + msg->msg[10] = ana_freq >> 8; + msg->msg[11] = ana_freq & 0xff; + msg->msg[12] = bcast_system; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; +} + +static inline void cec_ops_set_analogue_timer(const struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ana_bcast_type = msg->msg[9]; + *ana_freq = (msg->msg[10] << 8) | msg->msg[11]; + *bcast_system = msg->msg[12]; +} + +static inline void cec_msg_set_digital_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 16; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; + msg->msg[1] = CEC_MSG_SET_DIGITAL_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + cec_set_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_ops_set_digital_timer(const struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + struct cec_op_digital_service_id *digital) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + cec_get_digital_service_id(msg->msg + 9, digital); +} + +static inline void cec_msg_set_ext_timer(struct cec_msg *msg, + bool reply, + __u8 day, + __u8 month, + __u8 start_hr, + __u8 start_min, + __u8 duration_hr, + __u8 duration_min, + __u8 recording_seq, + __u8 ext_src_spec, + __u8 plug, + __u16 phys_addr) +{ + msg->len = 13; + msg->msg[1] = CEC_MSG_SET_EXT_TIMER; + msg->msg[2] = day; + msg->msg[3] = month; + /* Hours and minutes are in BCD format */ + msg->msg[4] = ((start_hr / 10) << 4) | (start_hr % 10); + msg->msg[5] = ((start_min / 10) << 4) | (start_min % 10); + msg->msg[6] = ((duration_hr / 10) << 4) | (duration_hr % 10); + msg->msg[7] = ((duration_min / 10) << 4) | (duration_min % 10); + msg->msg[8] = recording_seq; + msg->msg[9] = ext_src_spec; + msg->msg[10] = plug; + msg->msg[11] = phys_addr >> 8; + msg->msg[12] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_TIMER_STATUS : 0; +} + +static inline void cec_ops_set_ext_timer(const struct cec_msg *msg, + __u8 *day, + __u8 *month, + __u8 *start_hr, + __u8 *start_min, + __u8 *duration_hr, + __u8 *duration_min, + __u8 *recording_seq, + __u8 *ext_src_spec, + __u8 *plug, + __u16 *phys_addr) +{ + *day = msg->msg[2]; + *month = msg->msg[3]; + /* Hours and minutes are in BCD format */ + *start_hr = (msg->msg[4] >> 4) * 10 + (msg->msg[4] & 0xf); + *start_min = (msg->msg[5] >> 4) * 10 + (msg->msg[5] & 0xf); + *duration_hr = (msg->msg[6] >> 4) * 10 + (msg->msg[6] & 0xf); + *duration_min = (msg->msg[7] >> 4) * 10 + (msg->msg[7] & 0xf); + *recording_seq = msg->msg[8]; + *ext_src_spec = msg->msg[9]; + *plug = msg->msg[10]; + *phys_addr = (msg->msg[11] << 8) | msg->msg[12]; +} + +static inline void cec_msg_set_timer_program_title(struct cec_msg *msg, + const char *prog_title) +{ + unsigned int len = strlen(prog_title); + + if (len > 14) + len = 14; + msg->len = 2 + len; + msg->msg[1] = CEC_MSG_SET_TIMER_PROGRAM_TITLE; + memcpy(msg->msg + 2, prog_title, len); +} + +static inline void cec_ops_set_timer_program_title(const struct cec_msg *msg, + char *prog_title) +{ + unsigned int len = msg->len > 2 ? msg->len - 2 : 0; + + if (len > 14) + len = 14; + memcpy(prog_title, msg->msg + 2, len); + prog_title[len] = '\0'; +} + +/* System Information Feature */ +static inline void cec_msg_cec_version(struct cec_msg *msg, __u8 cec_version) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_CEC_VERSION; + msg->msg[2] = cec_version; +} + +static inline void cec_ops_cec_version(const struct cec_msg *msg, + __u8 *cec_version) +{ + *cec_version = msg->msg[2]; +} + +static inline void cec_msg_get_cec_version(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GET_CEC_VERSION; + msg->reply = reply ? CEC_MSG_CEC_VERSION : 0; +} + +static inline void cec_msg_report_physical_addr(struct cec_msg *msg, + __u16 phys_addr, __u8 prim_devtype) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_PHYSICAL_ADDR; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->msg[4] = prim_devtype; +} + +static inline void cec_ops_report_physical_addr(const struct cec_msg *msg, + __u16 *phys_addr, __u8 *prim_devtype) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *prim_devtype = msg->msg[4]; +} + +static inline void cec_msg_give_physical_addr(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_PHYSICAL_ADDR; + msg->reply = reply ? CEC_MSG_REPORT_PHYSICAL_ADDR : 0; +} + +static inline void cec_msg_set_menu_language(struct cec_msg *msg, + const char *language) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_SET_MENU_LANGUAGE; + memcpy(msg->msg + 2, language, 3); +} + +static inline void cec_ops_set_menu_language(const struct cec_msg *msg, + char *language) +{ + memcpy(language, msg->msg + 2, 3); + language[3] = '\0'; +} + +static inline void cec_msg_get_menu_language(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GET_MENU_LANGUAGE; + msg->reply = reply ? CEC_MSG_SET_MENU_LANGUAGE : 0; +} + +/* + * Assumes a single RC Profile byte and a single Device Features byte, + * i.e. no extended features are supported by this helper function. + * + * As of CEC 2.0 no extended features are defined, should those be added + * in the future, then this function needs to be adapted or a new function + * should be added. + */ +static inline void cec_msg_report_features(struct cec_msg *msg, + __u8 cec_version, __u8 all_device_types, + __u8 rc_profile, __u8 dev_features) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_FEATURES; + msg->msg[2] = cec_version; + msg->msg[3] = all_device_types; + msg->msg[4] = rc_profile; + msg->msg[5] = dev_features; +} + +static inline void cec_ops_report_features(const struct cec_msg *msg, + __u8 *cec_version, __u8 *all_device_types, + const __u8 **rc_profile, const __u8 **dev_features) +{ + const __u8 *p = &msg->msg[4]; + + *cec_version = msg->msg[2]; + *all_device_types = msg->msg[3]; + *rc_profile = p; + while (p < &msg->msg[14] && (*p & CEC_OP_FEAT_EXT)) + p++; + if (!(*p & CEC_OP_FEAT_EXT)) { + *dev_features = p + 1; + while (p < &msg->msg[15] && (*p & CEC_OP_FEAT_EXT)) + p++; + } + if (*p & CEC_OP_FEAT_EXT) + *rc_profile = *dev_features = NULL; +} + +static inline void cec_msg_give_features(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_FEATURES; + msg->reply = reply ? CEC_MSG_REPORT_FEATURES : 0; +} + +/* Deck Control Feature */ +static inline void cec_msg_deck_control(struct cec_msg *msg, + __u8 deck_control_mode) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_DECK_CONTROL; + msg->msg[2] = deck_control_mode; +} + +static inline void cec_ops_deck_control(const struct cec_msg *msg, + __u8 *deck_control_mode) +{ + *deck_control_mode = msg->msg[2]; +} + +static inline void cec_msg_deck_status(struct cec_msg *msg, + __u8 deck_info) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_DECK_STATUS; + msg->msg[2] = deck_info; +} + +static inline void cec_ops_deck_status(const struct cec_msg *msg, + __u8 *deck_info) +{ + *deck_info = msg->msg[2]; +} + +static inline void cec_msg_give_deck_status(struct cec_msg *msg, + bool reply, + __u8 status_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_GIVE_DECK_STATUS; + msg->msg[2] = status_req; + msg->reply = reply ? CEC_MSG_DECK_STATUS : 0; +} + +static inline void cec_ops_give_deck_status(const struct cec_msg *msg, + __u8 *status_req) +{ + *status_req = msg->msg[2]; +} + +static inline void cec_msg_play(struct cec_msg *msg, + __u8 play_mode) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_PLAY; + msg->msg[2] = play_mode; +} + +static inline void cec_ops_play(const struct cec_msg *msg, + __u8 *play_mode) +{ + *play_mode = msg->msg[2]; +} + + +/* Tuner Control Feature */ +struct cec_op_tuner_device_info { + __u8 rec_flag; + __u8 tuner_display_info; + bool is_analog; + union { + struct cec_op_digital_service_id digital; + struct { + __u8 ana_bcast_type; + __u16 ana_freq; + __u8 bcast_system; + } analog; + }; +}; + +static inline void cec_msg_tuner_device_status_analog(struct cec_msg *msg, + __u8 rec_flag, + __u8 tuner_display_info, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 7; + msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; + msg->msg[2] = (rec_flag << 7) | tuner_display_info; + msg->msg[3] = ana_bcast_type; + msg->msg[4] = ana_freq >> 8; + msg->msg[5] = ana_freq & 0xff; + msg->msg[6] = bcast_system; +} + +static inline void cec_msg_tuner_device_status_digital(struct cec_msg *msg, + __u8 rec_flag, __u8 tuner_display_info, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 10; + msg->msg[1] = CEC_MSG_TUNER_DEVICE_STATUS; + msg->msg[2] = (rec_flag << 7) | tuner_display_info; + cec_set_digital_service_id(msg->msg + 3, digital); +} + +static inline void cec_msg_tuner_device_status(struct cec_msg *msg, + const struct cec_op_tuner_device_info *tuner_dev_info) +{ + if (tuner_dev_info->is_analog) + cec_msg_tuner_device_status_analog(msg, + tuner_dev_info->rec_flag, + tuner_dev_info->tuner_display_info, + tuner_dev_info->analog.ana_bcast_type, + tuner_dev_info->analog.ana_freq, + tuner_dev_info->analog.bcast_system); + else + cec_msg_tuner_device_status_digital(msg, + tuner_dev_info->rec_flag, + tuner_dev_info->tuner_display_info, + &tuner_dev_info->digital); +} + +static inline void cec_ops_tuner_device_status(const struct cec_msg *msg, + struct cec_op_tuner_device_info *tuner_dev_info) +{ + tuner_dev_info->is_analog = msg->len < 10; + tuner_dev_info->rec_flag = msg->msg[2] >> 7; + tuner_dev_info->tuner_display_info = msg->msg[2] & 0x7f; + if (tuner_dev_info->is_analog) { + tuner_dev_info->analog.ana_bcast_type = msg->msg[3]; + tuner_dev_info->analog.ana_freq = (msg->msg[4] << 8) | msg->msg[5]; + tuner_dev_info->analog.bcast_system = msg->msg[6]; + return; + } + cec_get_digital_service_id(msg->msg + 3, &tuner_dev_info->digital); +} + +static inline void cec_msg_give_tuner_device_status(struct cec_msg *msg, + bool reply, + __u8 status_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_GIVE_TUNER_DEVICE_STATUS; + msg->msg[2] = status_req; + msg->reply = reply ? CEC_MSG_TUNER_DEVICE_STATUS : 0; +} + +static inline void cec_ops_give_tuner_device_status(const struct cec_msg *msg, + __u8 *status_req) +{ + *status_req = msg->msg[2]; +} + +static inline void cec_msg_select_analogue_service(struct cec_msg *msg, + __u8 ana_bcast_type, + __u16 ana_freq, + __u8 bcast_system) +{ + msg->len = 6; + msg->msg[1] = CEC_MSG_SELECT_ANALOGUE_SERVICE; + msg->msg[2] = ana_bcast_type; + msg->msg[3] = ana_freq >> 8; + msg->msg[4] = ana_freq & 0xff; + msg->msg[5] = bcast_system; +} + +static inline void cec_ops_select_analogue_service(const struct cec_msg *msg, + __u8 *ana_bcast_type, + __u16 *ana_freq, + __u8 *bcast_system) +{ + *ana_bcast_type = msg->msg[2]; + *ana_freq = (msg->msg[3] << 8) | msg->msg[4]; + *bcast_system = msg->msg[5]; +} + +static inline void cec_msg_select_digital_service(struct cec_msg *msg, + const struct cec_op_digital_service_id *digital) +{ + msg->len = 9; + msg->msg[1] = CEC_MSG_SELECT_DIGITAL_SERVICE; + cec_set_digital_service_id(msg->msg + 2, digital); +} + +static inline void cec_ops_select_digital_service(const struct cec_msg *msg, + struct cec_op_digital_service_id *digital) +{ + cec_get_digital_service_id(msg->msg + 2, digital); +} + +static inline void cec_msg_tuner_step_decrement(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TUNER_STEP_DECREMENT; +} + +static inline void cec_msg_tuner_step_increment(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TUNER_STEP_INCREMENT; +} + + +/* Vendor Specific Commands Feature */ +static inline void cec_msg_device_vendor_id(struct cec_msg *msg, __u32 vendor_id) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_DEVICE_VENDOR_ID; + msg->msg[2] = vendor_id >> 16; + msg->msg[3] = (vendor_id >> 8) & 0xff; + msg->msg[4] = vendor_id & 0xff; +} + +static inline void cec_ops_device_vendor_id(const struct cec_msg *msg, + __u32 *vendor_id) +{ + *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4]; +} + +static inline void cec_msg_give_device_vendor_id(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_DEVICE_VENDOR_ID; + msg->reply = reply ? CEC_MSG_DEVICE_VENDOR_ID : 0; +} + +static inline void cec_msg_vendor_command(struct cec_msg *msg, + __u8 size, const __u8 *vendor_cmd) +{ + if (size > 14) + size = 14; + msg->len = 2 + size; + msg->msg[1] = CEC_MSG_VENDOR_COMMAND; + memcpy(msg->msg + 2, vendor_cmd, size); +} + +static inline void cec_ops_vendor_command(const struct cec_msg *msg, + __u8 *size, + const __u8 **vendor_cmd) +{ + *size = msg->len - 2; + + if (*size > 14) + *size = 14; + *vendor_cmd = msg->msg + 2; +} + +static inline void cec_msg_vendor_command_with_id(struct cec_msg *msg, + __u32 vendor_id, __u8 size, + const __u8 *vendor_cmd) +{ + if (size > 11) + size = 11; + msg->len = 5 + size; + msg->msg[1] = CEC_MSG_VENDOR_COMMAND_WITH_ID; + msg->msg[2] = vendor_id >> 16; + msg->msg[3] = (vendor_id >> 8) & 0xff; + msg->msg[4] = vendor_id & 0xff; + memcpy(msg->msg + 5, vendor_cmd, size); +} + +static inline void cec_ops_vendor_command_with_id(const struct cec_msg *msg, + __u32 *vendor_id, __u8 *size, + const __u8 **vendor_cmd) +{ + *size = msg->len - 5; + + if (*size > 11) + *size = 11; + *vendor_id = (msg->msg[2] << 16) | (msg->msg[3] << 8) | msg->msg[4]; + *vendor_cmd = msg->msg + 5; +} + +static inline void cec_msg_vendor_remote_button_down(struct cec_msg *msg, + __u8 size, + const __u8 *rc_code) +{ + if (size > 14) + size = 14; + msg->len = 2 + size; + msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN; + memcpy(msg->msg + 2, rc_code, size); +} + +static inline void cec_ops_vendor_remote_button_down(const struct cec_msg *msg, + __u8 *size, + const __u8 **rc_code) +{ + *size = msg->len - 2; + + if (*size > 14) + *size = 14; + *rc_code = msg->msg + 2; +} + +static inline void cec_msg_vendor_remote_button_up(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_VENDOR_REMOTE_BUTTON_UP; +} + + +/* OSD Display Feature */ +static inline void cec_msg_set_osd_string(struct cec_msg *msg, + __u8 disp_ctl, + const char *osd) +{ + unsigned int len = strlen(osd); + + if (len > 13) + len = 13; + msg->len = 3 + len; + msg->msg[1] = CEC_MSG_SET_OSD_STRING; + msg->msg[2] = disp_ctl; + memcpy(msg->msg + 3, osd, len); +} + +static inline void cec_ops_set_osd_string(const struct cec_msg *msg, + __u8 *disp_ctl, + char *osd) +{ + unsigned int len = msg->len > 3 ? msg->len - 3 : 0; + + *disp_ctl = msg->msg[2]; + if (len > 13) + len = 13; + memcpy(osd, msg->msg + 3, len); + osd[len] = '\0'; +} + + +/* Device OSD Transfer Feature */ +static inline void cec_msg_set_osd_name(struct cec_msg *msg, const char *name) +{ + unsigned int len = strlen(name); + + if (len > 14) + len = 14; + msg->len = 2 + len; + msg->msg[1] = CEC_MSG_SET_OSD_NAME; + memcpy(msg->msg + 2, name, len); +} + +static inline void cec_ops_set_osd_name(const struct cec_msg *msg, + char *name) +{ + unsigned int len = msg->len > 2 ? msg->len - 2 : 0; + + if (len > 14) + len = 14; + memcpy(name, msg->msg + 2, len); + name[len] = '\0'; +} + +static inline void cec_msg_give_osd_name(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_OSD_NAME; + msg->reply = reply ? CEC_MSG_SET_OSD_NAME : 0; +} + + +/* Device Menu Control Feature */ +static inline void cec_msg_menu_status(struct cec_msg *msg, + __u8 menu_state) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_MENU_STATUS; + msg->msg[2] = menu_state; +} + +static inline void cec_ops_menu_status(const struct cec_msg *msg, + __u8 *menu_state) +{ + *menu_state = msg->msg[2]; +} + +static inline void cec_msg_menu_request(struct cec_msg *msg, + bool reply, + __u8 menu_req) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_MENU_REQUEST; + msg->msg[2] = menu_req; + msg->reply = reply ? CEC_MSG_MENU_STATUS : 0; +} + +static inline void cec_ops_menu_request(const struct cec_msg *msg, + __u8 *menu_req) +{ + *menu_req = msg->msg[2]; +} + +struct cec_op_ui_command { + __u8 ui_cmd; + bool has_opt_arg; + union { + struct cec_op_channel_data channel_identifier; + __u8 ui_broadcast_type; + __u8 ui_sound_presentation_control; + __u8 play_mode; + __u8 ui_function_media; + __u8 ui_function_select_av_input; + __u8 ui_function_select_audio_input; + }; +}; + +static inline void cec_msg_user_control_pressed(struct cec_msg *msg, + const struct cec_op_ui_command *ui_cmd) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_USER_CONTROL_PRESSED; + msg->msg[2] = ui_cmd->ui_cmd; + if (!ui_cmd->has_opt_arg) + return; + switch (ui_cmd->ui_cmd) { + case 0x56: + case 0x57: + case 0x60: + case 0x68: + case 0x69: + case 0x6a: + /* The optional operand is one byte for all these ui commands */ + msg->len++; + msg->msg[3] = ui_cmd->play_mode; + break; + case 0x67: + msg->len += 4; + msg->msg[3] = (ui_cmd->channel_identifier.channel_number_fmt << 2) | + (ui_cmd->channel_identifier.major >> 8); + msg->msg[4] = ui_cmd->channel_identifier.major & 0xff; + msg->msg[5] = ui_cmd->channel_identifier.minor >> 8; + msg->msg[6] = ui_cmd->channel_identifier.minor & 0xff; + break; + } +} + +static inline void cec_ops_user_control_pressed(const struct cec_msg *msg, + struct cec_op_ui_command *ui_cmd) +{ + ui_cmd->ui_cmd = msg->msg[2]; + ui_cmd->has_opt_arg = false; + if (msg->len == 3) + return; + switch (ui_cmd->ui_cmd) { + case 0x56: + case 0x57: + case 0x60: + case 0x68: + case 0x69: + case 0x6a: + /* The optional operand is one byte for all these ui commands */ + ui_cmd->play_mode = msg->msg[3]; + ui_cmd->has_opt_arg = true; + break; + case 0x67: + if (msg->len < 7) + break; + ui_cmd->has_opt_arg = true; + ui_cmd->channel_identifier.channel_number_fmt = msg->msg[3] >> 2; + ui_cmd->channel_identifier.major = ((msg->msg[3] & 3) << 6) | msg->msg[4]; + ui_cmd->channel_identifier.minor = (msg->msg[5] << 8) | msg->msg[6]; + break; + } +} + +static inline void cec_msg_user_control_released(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_USER_CONTROL_RELEASED; +} + +/* Remote Control Passthrough Feature */ + +/* Power Status Feature */ +static inline void cec_msg_report_power_status(struct cec_msg *msg, + __u8 pwr_state) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_REPORT_POWER_STATUS; + msg->msg[2] = pwr_state; +} + +static inline void cec_ops_report_power_status(const struct cec_msg *msg, + __u8 *pwr_state) +{ + *pwr_state = msg->msg[2]; +} + +static inline void cec_msg_give_device_power_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_DEVICE_POWER_STATUS; + msg->reply = reply ? CEC_MSG_REPORT_POWER_STATUS : 0; +} + +/* General Protocol Messages */ +static inline void cec_msg_feature_abort(struct cec_msg *msg, + __u8 abort_msg, __u8 reason) +{ + msg->len = 4; + msg->msg[1] = CEC_MSG_FEATURE_ABORT; + msg->msg[2] = abort_msg; + msg->msg[3] = reason; +} + +static inline void cec_ops_feature_abort(const struct cec_msg *msg, + __u8 *abort_msg, __u8 *reason) +{ + *abort_msg = msg->msg[2]; + *reason = msg->msg[3]; +} + +/* This changes the current message into a feature abort message */ +static inline void cec_msg_reply_feature_abort(struct cec_msg *msg, __u8 reason) +{ + cec_msg_set_reply_to(msg, msg); + msg->len = 4; + msg->msg[2] = msg->msg[1]; + msg->msg[3] = reason; + msg->msg[1] = CEC_MSG_FEATURE_ABORT; +} + +static inline void cec_msg_abort(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_ABORT; +} + + +/* System Audio Control Feature */ +static inline void cec_msg_report_audio_status(struct cec_msg *msg, + __u8 aud_mute_status, + __u8 aud_vol_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_REPORT_AUDIO_STATUS; + msg->msg[2] = (aud_mute_status << 7) | (aud_vol_status & 0x7f); +} + +static inline void cec_ops_report_audio_status(const struct cec_msg *msg, + __u8 *aud_mute_status, + __u8 *aud_vol_status) +{ + *aud_mute_status = msg->msg[2] >> 7; + *aud_vol_status = msg->msg[2] & 0x7f; +} + +static inline void cec_msg_give_audio_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_AUDIO_STATUS; + msg->reply = reply ? CEC_MSG_REPORT_AUDIO_STATUS : 0; +} + +static inline void cec_msg_set_system_audio_mode(struct cec_msg *msg, + __u8 sys_aud_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SET_SYSTEM_AUDIO_MODE; + msg->msg[2] = sys_aud_status; +} + +static inline void cec_ops_set_system_audio_mode(const struct cec_msg *msg, + __u8 *sys_aud_status) +{ + *sys_aud_status = msg->msg[2]; +} + +static inline void cec_msg_system_audio_mode_request(struct cec_msg *msg, + bool reply, + __u16 phys_addr) +{ + msg->len = phys_addr == 0xffff ? 2 : 4; + msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_SET_SYSTEM_AUDIO_MODE : 0; + +} + +static inline void cec_ops_system_audio_mode_request(const struct cec_msg *msg, + __u16 *phys_addr) +{ + if (msg->len < 4) + *phys_addr = 0xffff; + else + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_system_audio_mode_status(struct cec_msg *msg, + __u8 sys_aud_status) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SYSTEM_AUDIO_MODE_STATUS; + msg->msg[2] = sys_aud_status; +} + +static inline void cec_ops_system_audio_mode_status(const struct cec_msg *msg, + __u8 *sys_aud_status) +{ + *sys_aud_status = msg->msg[2]; +} + +static inline void cec_msg_give_system_audio_mode_status(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS; + msg->reply = reply ? CEC_MSG_SYSTEM_AUDIO_MODE_STATUS : 0; +} + +static inline void cec_msg_report_short_audio_descriptor(struct cec_msg *msg, + __u8 num_descriptors, + const __u32 *descriptors) +{ + unsigned int i; + + if (num_descriptors > 4) + num_descriptors = 4; + msg->len = 2 + num_descriptors * 3; + msg->msg[1] = CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR; + for (i = 0; i < num_descriptors; i++) { + msg->msg[2 + i * 3] = (descriptors[i] >> 16) & 0xff; + msg->msg[3 + i * 3] = (descriptors[i] >> 8) & 0xff; + msg->msg[4 + i * 3] = descriptors[i] & 0xff; + } +} + +static inline void cec_ops_report_short_audio_descriptor(const struct cec_msg *msg, + __u8 *num_descriptors, + __u32 *descriptors) +{ + unsigned int i; + + *num_descriptors = (msg->len - 2) / 3; + if (*num_descriptors > 4) + *num_descriptors = 4; + for (i = 0; i < *num_descriptors; i++) + descriptors[i] = (msg->msg[2 + i * 3] << 16) | + (msg->msg[3 + i * 3] << 8) | + msg->msg[4 + i * 3]; +} + +static inline void cec_msg_request_short_audio_descriptor(struct cec_msg *msg, + bool reply, + __u8 num_descriptors, + const __u8 *audio_format_id, + const __u8 *audio_format_code) +{ + unsigned int i; + + if (num_descriptors > 4) + num_descriptors = 4; + msg->len = 2 + num_descriptors; + msg->msg[1] = CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR; + msg->reply = reply ? CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR : 0; + for (i = 0; i < num_descriptors; i++) + msg->msg[2 + i] = (audio_format_id[i] << 6) | + (audio_format_code[i] & 0x3f); +} + +static inline void cec_ops_request_short_audio_descriptor(const struct cec_msg *msg, + __u8 *num_descriptors, + __u8 *audio_format_id, + __u8 *audio_format_code) +{ + unsigned int i; + + *num_descriptors = msg->len - 2; + if (*num_descriptors > 4) + *num_descriptors = 4; + for (i = 0; i < *num_descriptors; i++) { + audio_format_id[i] = msg->msg[2 + i] >> 6; + audio_format_code[i] = msg->msg[2 + i] & 0x3f; + } +} + + +/* Audio Rate Control Feature */ +static inline void cec_msg_set_audio_rate(struct cec_msg *msg, + __u8 audio_rate) +{ + msg->len = 3; + msg->msg[1] = CEC_MSG_SET_AUDIO_RATE; + msg->msg[2] = audio_rate; +} + +static inline void cec_ops_set_audio_rate(const struct cec_msg *msg, + __u8 *audio_rate) +{ + *audio_rate = msg->msg[2]; +} + + +/* Audio Return Channel Control Feature */ +static inline void cec_msg_report_arc_initiated(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REPORT_ARC_INITIATED; +} + +static inline void cec_msg_initiate_arc(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_INITIATE_ARC; + msg->reply = reply ? CEC_MSG_REPORT_ARC_INITIATED : 0; +} + +static inline void cec_msg_request_arc_initiation(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REQUEST_ARC_INITIATION; + msg->reply = reply ? CEC_MSG_INITIATE_ARC : 0; +} + +static inline void cec_msg_report_arc_terminated(struct cec_msg *msg) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REPORT_ARC_TERMINATED; +} + +static inline void cec_msg_terminate_arc(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_TERMINATE_ARC; + msg->reply = reply ? CEC_MSG_REPORT_ARC_TERMINATED : 0; +} + +static inline void cec_msg_request_arc_termination(struct cec_msg *msg, + bool reply) +{ + msg->len = 2; + msg->msg[1] = CEC_MSG_REQUEST_ARC_TERMINATION; + msg->reply = reply ? CEC_MSG_TERMINATE_ARC : 0; +} + + +/* Dynamic Audio Lipsync Feature */ +/* Only for CEC 2.0 and up */ +static inline void cec_msg_report_current_latency(struct cec_msg *msg, + __u16 phys_addr, + __u8 video_latency, + __u8 low_latency_mode, + __u8 audio_out_compensated, + __u8 audio_out_delay) +{ + msg->len = 7; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REPORT_CURRENT_LATENCY; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->msg[4] = video_latency; + msg->msg[5] = (low_latency_mode << 2) | audio_out_compensated; + msg->msg[6] = audio_out_delay; +} + +static inline void cec_ops_report_current_latency(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *video_latency, + __u8 *low_latency_mode, + __u8 *audio_out_compensated, + __u8 *audio_out_delay) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *video_latency = msg->msg[4]; + *low_latency_mode = (msg->msg[5] >> 2) & 1; + *audio_out_compensated = msg->msg[5] & 3; + *audio_out_delay = msg->msg[6]; +} + +static inline void cec_msg_request_current_latency(struct cec_msg *msg, + bool reply, + __u16 phys_addr) +{ + msg->len = 4; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_REQUEST_CURRENT_LATENCY; + msg->msg[2] = phys_addr >> 8; + msg->msg[3] = phys_addr & 0xff; + msg->reply = reply ? CEC_MSG_REPORT_CURRENT_LATENCY : 0; +} + +static inline void cec_ops_request_current_latency(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + + +/* Capability Discovery and Control Feature */ +static inline void cec_msg_cdc_hec_inquire_state(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2) +{ + msg->len = 9; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; +} + +static inline void cec_ops_cdc_hec_inquire_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; +} + +static inline void cec_msg_cdc_hec_report_state(struct cec_msg *msg, + __u16 target_phys_addr, + __u8 hec_func_state, + __u8 host_func_state, + __u8 enc_func_state, + __u8 cdc_errcode, + __u8 has_field, + __u16 hec_field) +{ + msg->len = has_field ? 10 : 8; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_REPORT_STATE; + msg->msg[5] = target_phys_addr >> 8; + msg->msg[6] = target_phys_addr & 0xff; + msg->msg[7] = (hec_func_state << 6) | + (host_func_state << 4) | + (enc_func_state << 2) | + cdc_errcode; + if (has_field) { + msg->msg[8] = hec_field >> 8; + msg->msg[9] = hec_field & 0xff; + } +} + +static inline void cec_ops_cdc_hec_report_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *target_phys_addr, + __u8 *hec_func_state, + __u8 *host_func_state, + __u8 *enc_func_state, + __u8 *cdc_errcode, + __u8 *has_field, + __u16 *hec_field) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *target_phys_addr = (msg->msg[5] << 8) | msg->msg[6]; + *hec_func_state = msg->msg[7] >> 6; + *host_func_state = (msg->msg[7] >> 4) & 3; + *enc_func_state = (msg->msg[7] >> 4) & 3; + *cdc_errcode = msg->msg[7] & 3; + *has_field = msg->len >= 10; + *hec_field = *has_field ? ((msg->msg[8] << 8) | msg->msg[9]) : 0; +} + +static inline void cec_msg_cdc_hec_set_state(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2, + __u8 hec_set_state, + __u16 phys_addr3, + __u16 phys_addr4, + __u16 phys_addr5) +{ + msg->len = 10; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_INQUIRE_STATE; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; + msg->msg[9] = hec_set_state; + if (phys_addr3 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr3 >> 8; + msg->msg[msg->len++] = phys_addr3 & 0xff; + if (phys_addr4 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr4 >> 8; + msg->msg[msg->len++] = phys_addr4 & 0xff; + if (phys_addr5 != CEC_PHYS_ADDR_INVALID) { + msg->msg[msg->len++] = phys_addr5 >> 8; + msg->msg[msg->len++] = phys_addr5 & 0xff; + } + } + } +} + +static inline void cec_ops_cdc_hec_set_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2, + __u8 *hec_set_state, + __u16 *phys_addr3, + __u16 *phys_addr4, + __u16 *phys_addr5) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; + *hec_set_state = msg->msg[9]; + *phys_addr3 = *phys_addr4 = *phys_addr5 = CEC_PHYS_ADDR_INVALID; + if (msg->len >= 12) + *phys_addr3 = (msg->msg[10] << 8) | msg->msg[11]; + if (msg->len >= 14) + *phys_addr4 = (msg->msg[12] << 8) | msg->msg[13]; + if (msg->len >= 16) + *phys_addr5 = (msg->msg[14] << 8) | msg->msg[15]; +} + +static inline void cec_msg_cdc_hec_set_state_adjacent(struct cec_msg *msg, + __u16 phys_addr1, + __u8 hec_set_state) +{ + msg->len = 8; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_SET_STATE_ADJACENT; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = hec_set_state; +} + +static inline void cec_ops_cdc_hec_set_state_adjacent(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u8 *hec_set_state) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *hec_set_state = msg->msg[7]; +} + +static inline void cec_msg_cdc_hec_request_deactivation(struct cec_msg *msg, + __u16 phys_addr1, + __u16 phys_addr2, + __u16 phys_addr3) +{ + msg->len = 11; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION; + msg->msg[5] = phys_addr1 >> 8; + msg->msg[6] = phys_addr1 & 0xff; + msg->msg[7] = phys_addr2 >> 8; + msg->msg[8] = phys_addr2 & 0xff; + msg->msg[9] = phys_addr3 >> 8; + msg->msg[10] = phys_addr3 & 0xff; +} + +static inline void cec_ops_cdc_hec_request_deactivation(const struct cec_msg *msg, + __u16 *phys_addr, + __u16 *phys_addr1, + __u16 *phys_addr2, + __u16 *phys_addr3) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *phys_addr1 = (msg->msg[5] << 8) | msg->msg[6]; + *phys_addr2 = (msg->msg[7] << 8) | msg->msg[8]; + *phys_addr3 = (msg->msg[9] << 8) | msg->msg[10]; +} + +static inline void cec_msg_cdc_hec_notify_alive(struct cec_msg *msg) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_NOTIFY_ALIVE; +} + +static inline void cec_ops_cdc_hec_notify_alive(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_cdc_hec_discover(struct cec_msg *msg) +{ + msg->len = 5; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HEC_DISCOVER; +} + +static inline void cec_ops_cdc_hec_discover(const struct cec_msg *msg, + __u16 *phys_addr) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; +} + +static inline void cec_msg_cdc_hpd_set_state(struct cec_msg *msg, + __u8 input_port, + __u8 hpd_state) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HPD_SET_STATE; + msg->msg[5] = (input_port << 4) | hpd_state; +} + +static inline void cec_ops_cdc_hpd_set_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *input_port, + __u8 *hpd_state) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *input_port = msg->msg[5] >> 4; + *hpd_state = msg->msg[5] & 0xf; +} + +static inline void cec_msg_cdc_hpd_report_state(struct cec_msg *msg, + __u8 hpd_state, + __u8 hpd_error) +{ + msg->len = 6; + msg->msg[0] |= 0xf; /* broadcast */ + msg->msg[1] = CEC_MSG_CDC_MESSAGE; + /* msg[2] and msg[3] (phys_addr) are filled in by the CEC framework */ + msg->msg[4] = CEC_MSG_CDC_HPD_REPORT_STATE; + msg->msg[5] = (hpd_state << 4) | hpd_error; +} + +static inline void cec_ops_cdc_hpd_report_state(const struct cec_msg *msg, + __u16 *phys_addr, + __u8 *hpd_state, + __u8 *hpd_error) +{ + *phys_addr = (msg->msg[2] << 8) | msg->msg[3]; + *hpd_state = msg->msg[5] >> 4; + *hpd_error = msg->msg[5] & 0xf; +} + +#endif diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h new file mode 100644 index 000000000000..f4ec0af67707 --- /dev/null +++ b/include/uapi/linux/cec.h @@ -0,0 +1,1065 @@ +/* + * cec - HDMI Consumer Electronics Control public header + * + * Copyright 2016 Cisco Systems, Inc. and/or its affiliates. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * Alternatively you can redistribute this file under the terms of the + * BSD license as stated below: + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. The names of its contributors may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * 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 _CEC_UAPI_H +#define _CEC_UAPI_H + +#include + +#define CEC_MAX_MSG_SIZE 16 + +/** + * struct cec_msg - CEC message structure. + * @tx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the + * driver when the message transmission has finished. + * @rx_ts: Timestamp in nanoseconds using CLOCK_MONOTONIC. Set by the + * driver when the message was received. + * @len: Length in bytes of the message. + * @timeout: The timeout (in ms) that is used to timeout CEC_RECEIVE. + * Set to 0 if you want to wait forever. This timeout can also be + * used with CEC_TRANSMIT as the timeout for waiting for a reply. + * If 0, then it will use a 1 second timeout instead of waiting + * forever as is done with CEC_RECEIVE. + * @sequence: The framework assigns a sequence number to messages that are + * sent. This can be used to track replies to previously sent + * messages. + * @flags: Set to 0. + * @msg: The message payload. + * @reply: This field is ignored with CEC_RECEIVE and is only used by + * CEC_TRANSMIT. If non-zero, then wait for a reply with this + * opcode. Set to CEC_MSG_FEATURE_ABORT if you want to wait for + * a possible ABORT reply. If there was an error when sending the + * msg or FeatureAbort was returned, then reply is set to 0. + * If reply is non-zero upon return, then len/msg are set to + * the received message. + * If reply is zero upon return and status has the + * CEC_TX_STATUS_FEATURE_ABORT bit set, then len/msg are set to + * the received feature abort message. + * If reply is zero upon return and status has the + * CEC_TX_STATUS_MAX_RETRIES bit set, then no reply was seen at + * all. If reply is non-zero for CEC_TRANSMIT and the message is a + * broadcast, then -EINVAL is returned. + * if reply is non-zero, then timeout is set to 1000 (the required + * maximum response time). + * @rx_status: The message receive status bits. Set by the driver. + * @tx_status: The message transmit status bits. Set by the driver. + * @tx_arb_lost_cnt: The number of 'Arbitration Lost' events. Set by the driver. + * @tx_nack_cnt: The number of 'Not Acknowledged' events. Set by the driver. + * @tx_low_drive_cnt: The number of 'Low Drive Detected' events. Set by the + * driver. + * @tx_error_cnt: The number of 'Error' events. Set by the driver. + */ +struct cec_msg { + __u64 tx_ts; + __u64 rx_ts; + __u32 len; + __u32 timeout; + __u32 sequence; + __u32 flags; + __u8 msg[CEC_MAX_MSG_SIZE]; + __u8 reply; + __u8 rx_status; + __u8 tx_status; + __u8 tx_arb_lost_cnt; + __u8 tx_nack_cnt; + __u8 tx_low_drive_cnt; + __u8 tx_error_cnt; +}; + +/** + * cec_msg_initiator - return the initiator's logical address. + * @msg: the message structure + */ +static inline __u8 cec_msg_initiator(const struct cec_msg *msg) +{ + return msg->msg[0] >> 4; +} + +/** + * cec_msg_destination - return the destination's logical address. + * @msg: the message structure + */ +static inline __u8 cec_msg_destination(const struct cec_msg *msg) +{ + return msg->msg[0] & 0xf; +} + +/** + * cec_msg_opcode - return the opcode of the message, -1 for poll + * @msg: the message structure + */ +static inline int cec_msg_opcode(const struct cec_msg *msg) +{ + return msg->len > 1 ? msg->msg[1] : -1; +} + +/** + * cec_msg_is_broadcast - return true if this is a broadcast message. + * @msg: the message structure + */ +static inline bool cec_msg_is_broadcast(const struct cec_msg *msg) +{ + return (msg->msg[0] & 0xf) == 0xf; +} + +/** + * cec_msg_init - initialize the message structure. + * @msg: the message structure + * @initiator: the logical address of the initiator + * @destination:the logical address of the destination (0xf for broadcast) + * + * The whole structure is zeroed, the len field is set to 1 (i.e. a poll + * message) and the initiator and destination are filled in. + */ +static inline void cec_msg_init(struct cec_msg *msg, + __u8 initiator, __u8 destination) +{ + memset(msg, 0, sizeof(*msg)); + msg->msg[0] = (initiator << 4) | destination; + msg->len = 1; +} + +/** + * cec_msg_set_reply_to - fill in destination/initiator in a reply message. + * @msg: the message structure for the reply + * @orig: the original message structure + * + * Set the msg destination to the orig initiator and the msg initiator to the + * orig destination. Note that msg and orig may be the same pointer, in which + * case the change is done in place. + */ +static inline void cec_msg_set_reply_to(struct cec_msg *msg, + struct cec_msg *orig) +{ + /* The destination becomes the initiator and vice versa */ + msg->msg[0] = (cec_msg_destination(orig) << 4) | + cec_msg_initiator(orig); + msg->reply = msg->timeout = 0; +} + +/* cec_msg flags field */ +#define CEC_MSG_FL_REPLY_TO_FOLLOWERS (1 << 0) + +/* cec_msg tx/rx_status field */ +#define CEC_TX_STATUS_OK (1 << 0) +#define CEC_TX_STATUS_ARB_LOST (1 << 1) +#define CEC_TX_STATUS_NACK (1 << 2) +#define CEC_TX_STATUS_LOW_DRIVE (1 << 3) +#define CEC_TX_STATUS_ERROR (1 << 4) +#define CEC_TX_STATUS_MAX_RETRIES (1 << 5) + +#define CEC_RX_STATUS_OK (1 << 0) +#define CEC_RX_STATUS_TIMEOUT (1 << 1) +#define CEC_RX_STATUS_FEATURE_ABORT (1 << 2) + +static inline bool cec_msg_status_is_ok(const struct cec_msg *msg) +{ + if (msg->tx_status && !(msg->tx_status & CEC_TX_STATUS_OK)) + return false; + if (msg->rx_status && !(msg->rx_status & CEC_RX_STATUS_OK)) + return false; + if (!msg->tx_status && !msg->rx_status) + return false; + return !(msg->rx_status & CEC_RX_STATUS_FEATURE_ABORT); +} + +#define CEC_LOG_ADDR_INVALID 0xff +#define CEC_PHYS_ADDR_INVALID 0xffff + +/* + * The maximum number of logical addresses one device can be assigned to. + * The CEC 2.0 spec allows for only 2 logical addresses at the moment. The + * Analog Devices CEC hardware supports 3. So let's go wild and go for 4. + */ +#define CEC_MAX_LOG_ADDRS 4 + +/* The logical addresses defined by CEC 2.0 */ +#define CEC_LOG_ADDR_TV 0 +#define CEC_LOG_ADDR_RECORD_1 1 +#define CEC_LOG_ADDR_RECORD_2 2 +#define CEC_LOG_ADDR_TUNER_1 3 +#define CEC_LOG_ADDR_PLAYBACK_1 4 +#define CEC_LOG_ADDR_AUDIOSYSTEM 5 +#define CEC_LOG_ADDR_TUNER_2 6 +#define CEC_LOG_ADDR_TUNER_3 7 +#define CEC_LOG_ADDR_PLAYBACK_2 8 +#define CEC_LOG_ADDR_RECORD_3 9 +#define CEC_LOG_ADDR_TUNER_4 10 +#define CEC_LOG_ADDR_PLAYBACK_3 11 +#define CEC_LOG_ADDR_BACKUP_1 12 +#define CEC_LOG_ADDR_BACKUP_2 13 +#define CEC_LOG_ADDR_SPECIFIC 14 +#define CEC_LOG_ADDR_UNREGISTERED 15 /* as initiator address */ +#define CEC_LOG_ADDR_BROADCAST 15 /* ad destination address */ + +/* The logical address types that the CEC device wants to claim */ +#define CEC_LOG_ADDR_TYPE_TV 0 +#define CEC_LOG_ADDR_TYPE_RECORD 1 +#define CEC_LOG_ADDR_TYPE_TUNER 2 +#define CEC_LOG_ADDR_TYPE_PLAYBACK 3 +#define CEC_LOG_ADDR_TYPE_AUDIOSYSTEM 4 +#define CEC_LOG_ADDR_TYPE_SPECIFIC 5 +#define CEC_LOG_ADDR_TYPE_UNREGISTERED 6 +/* + * Switches should use UNREGISTERED. + * Processors should use SPECIFIC. + */ + +#define CEC_LOG_ADDR_MASK_TV (1 << CEC_LOG_ADDR_TV) +#define CEC_LOG_ADDR_MASK_RECORD ((1 << CEC_LOG_ADDR_RECORD_1) | \ + (1 << CEC_LOG_ADDR_RECORD_2) | \ + (1 << CEC_LOG_ADDR_RECORD_3)) +#define CEC_LOG_ADDR_MASK_TUNER ((1 << CEC_LOG_ADDR_TUNER_1) | \ + (1 << CEC_LOG_ADDR_TUNER_2) | \ + (1 << CEC_LOG_ADDR_TUNER_3) | \ + (1 << CEC_LOG_ADDR_TUNER_4)) +#define CEC_LOG_ADDR_MASK_PLAYBACK ((1 << CEC_LOG_ADDR_PLAYBACK_1) | \ + (1 << CEC_LOG_ADDR_PLAYBACK_2) | \ + (1 << CEC_LOG_ADDR_PLAYBACK_3)) +#define CEC_LOG_ADDR_MASK_AUDIOSYSTEM (1 << CEC_LOG_ADDR_AUDIOSYSTEM) +#define CEC_LOG_ADDR_MASK_BACKUP ((1 << CEC_LOG_ADDR_BACKUP_1) | \ + (1 << CEC_LOG_ADDR_BACKUP_2)) +#define CEC_LOG_ADDR_MASK_SPECIFIC (1 << CEC_LOG_ADDR_SPECIFIC) +#define CEC_LOG_ADDR_MASK_UNREGISTERED (1 << CEC_LOG_ADDR_UNREGISTERED) + +static inline bool cec_has_tv(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_TV; +} + +static inline bool cec_has_record(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_RECORD; +} + +static inline bool cec_has_tuner(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_TUNER; +} + +static inline bool cec_has_playback(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_PLAYBACK; +} + +static inline bool cec_has_audiosystem(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_AUDIOSYSTEM; +} + +static inline bool cec_has_backup(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_BACKUP; +} + +static inline bool cec_has_specific(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_SPECIFIC; +} + +static inline bool cec_is_unregistered(__u16 log_addr_mask) +{ + return log_addr_mask & CEC_LOG_ADDR_MASK_UNREGISTERED; +} + +static inline bool cec_is_unconfigured(__u16 log_addr_mask) +{ + return log_addr_mask == 0; +} + +/* + * Use this if there is no vendor ID (CEC_G_VENDOR_ID) or if the vendor ID + * should be disabled (CEC_S_VENDOR_ID) + */ +#define CEC_VENDOR_ID_NONE 0xffffffff + +/* The message handling modes */ +/* Modes for initiator */ +#define CEC_MODE_NO_INITIATOR (0x0 << 0) +#define CEC_MODE_INITIATOR (0x1 << 0) +#define CEC_MODE_EXCL_INITIATOR (0x2 << 0) +#define CEC_MODE_INITIATOR_MSK 0x0f + +/* Modes for follower */ +#define CEC_MODE_NO_FOLLOWER (0x0 << 4) +#define CEC_MODE_FOLLOWER (0x1 << 4) +#define CEC_MODE_EXCL_FOLLOWER (0x2 << 4) +#define CEC_MODE_EXCL_FOLLOWER_PASSTHRU (0x3 << 4) +#define CEC_MODE_MONITOR (0xe << 4) +#define CEC_MODE_MONITOR_ALL (0xf << 4) +#define CEC_MODE_FOLLOWER_MSK 0xf0 + +/* Userspace has to configure the physical address */ +#define CEC_CAP_PHYS_ADDR (1 << 0) +/* Userspace has to configure the logical addresses */ +#define CEC_CAP_LOG_ADDRS (1 << 1) +/* Userspace can transmit messages (and thus become follower as well) */ +#define CEC_CAP_TRANSMIT (1 << 2) +/* + * Passthrough all messages instead of processing them. + */ +#define CEC_CAP_PASSTHROUGH (1 << 3) +/* Supports remote control */ +#define CEC_CAP_RC (1 << 4) +/* Hardware can monitor all messages, not just directed and broadcast. */ +#define CEC_CAP_MONITOR_ALL (1 << 5) + +/** + * struct cec_caps - CEC capabilities structure. + * @driver: name of the CEC device driver. + * @name: name of the CEC device. @driver + @name must be unique. + * @available_log_addrs: number of available logical addresses. + * @capabilities: capabilities of the CEC adapter. + * @version: version of the CEC adapter framework. + */ +struct cec_caps { + char driver[32]; + char name[32]; + __u32 available_log_addrs; + __u32 capabilities; + __u32 version; +}; + +/** + * struct cec_log_addrs - CEC logical addresses structure. + * @log_addr: the claimed logical addresses. Set by the driver. + * @log_addr_mask: current logical address mask. Set by the driver. + * @cec_version: the CEC version that the adapter should implement. Set by the + * caller. + * @num_log_addrs: how many logical addresses should be claimed. Set by the + * caller. + * @vendor_id: the vendor ID of the device. Set by the caller. + * @flags: flags. + * @osd_name: the OSD name of the device. Set by the caller. + * @primary_device_type: the primary device type for each logical address. + * Set by the caller. + * @log_addr_type: the logical address types. Set by the caller. + * @all_device_types: CEC 2.0: all device types represented by the logical + * address. Set by the caller. + * @features: CEC 2.0: The logical address features. Set by the caller. + */ +struct cec_log_addrs { + __u8 log_addr[CEC_MAX_LOG_ADDRS]; + __u16 log_addr_mask; + __u8 cec_version; + __u8 num_log_addrs; + __u32 vendor_id; + __u32 flags; + char osd_name[15]; + __u8 primary_device_type[CEC_MAX_LOG_ADDRS]; + __u8 log_addr_type[CEC_MAX_LOG_ADDRS]; + + /* CEC 2.0 */ + __u8 all_device_types[CEC_MAX_LOG_ADDRS]; + __u8 features[CEC_MAX_LOG_ADDRS][12]; +}; + +/* Allow a fallback to unregistered */ +#define CEC_LOG_ADDRS_FL_ALLOW_UNREG_FALLBACK (1 << 0) +/* Passthrough RC messages to the input subsystem */ +#define CEC_LOG_ADDRS_FL_ALLOW_RC_PASSTHRU (1 << 1) +/* CDC-Only device: supports only CDC messages */ +#define CEC_LOG_ADDRS_FL_CDC_ONLY (1 << 2) + +/* Events */ + +/* Event that occurs when the adapter state changes */ +#define CEC_EVENT_STATE_CHANGE 1 +/* + * This event is sent when messages are lost because the application + * didn't empty the message queue in time + */ +#define CEC_EVENT_LOST_MSGS 2 + +#define CEC_EVENT_FL_INITIAL_STATE (1 << 0) + +/** + * struct cec_event_state_change - used when the CEC adapter changes state. + * @phys_addr: the current physical address + * @log_addr_mask: the current logical address mask + */ +struct cec_event_state_change { + __u16 phys_addr; + __u16 log_addr_mask; +}; + +/** + * struct cec_event_lost_msgs - tells you how many messages were lost due. + * @lost_msgs: how many messages were lost. + */ +struct cec_event_lost_msgs { + __u32 lost_msgs; +}; + +/** + * struct cec_event - CEC event structure + * @ts: the timestamp of when the event was sent. + * @event: the event. + * array. + * @state_change: the event payload for CEC_EVENT_STATE_CHANGE. + * @lost_msgs: the event payload for CEC_EVENT_LOST_MSGS. + * @raw: array to pad the union. + */ +struct cec_event { + __u64 ts; + __u32 event; + __u32 flags; + union { + struct cec_event_state_change state_change; + struct cec_event_lost_msgs lost_msgs; + __u32 raw[16]; + }; +}; + +/* ioctls */ + +/* Adapter capabilities */ +#define CEC_ADAP_G_CAPS _IOWR('a', 0, struct cec_caps) + +/* + * phys_addr is either 0 (if this is the CEC root device) + * or a valid physical address obtained from the sink's EDID + * as read by this CEC device (if this is a source device) + * or a physical address obtained and modified from a sink + * EDID and used for a sink CEC device. + * If nothing is connected, then phys_addr is 0xffff. + * See HDMI 1.4b, section 8.7 (Physical Address). + * + * The CEC_ADAP_S_PHYS_ADDR ioctl may not be available if that is handled + * internally. + */ +#define CEC_ADAP_G_PHYS_ADDR _IOR('a', 1, __u16) +#define CEC_ADAP_S_PHYS_ADDR _IOW('a', 2, __u16) + +/* + * Configure the CEC adapter. It sets the device type and which + * logical types it will try to claim. It will return which + * logical addresses it could actually claim. + * An error is returned if the adapter is disabled or if there + * is no physical address assigned. + */ + +#define CEC_ADAP_G_LOG_ADDRS _IOR('a', 3, struct cec_log_addrs) +#define CEC_ADAP_S_LOG_ADDRS _IOWR('a', 4, struct cec_log_addrs) + +/* Transmit/receive a CEC command */ +#define CEC_TRANSMIT _IOWR('a', 5, struct cec_msg) +#define CEC_RECEIVE _IOWR('a', 6, struct cec_msg) + +/* Dequeue CEC events */ +#define CEC_DQEVENT _IOWR('a', 7, struct cec_event) + +/* + * Get and set the message handling mode for this filehandle. + */ +#define CEC_G_MODE _IOR('a', 8, __u32) +#define CEC_S_MODE _IOW('a', 9, __u32) + +/* + * The remainder of this header defines all CEC messages and operands. + * The format matters since it the cec-ctl utility parses it to generate + * code for implementing all these messages. + * + * Comments ending with 'Feature' group messages for each feature. + * If messages are part of multiple features, then the "Has also" + * comment is used to list the previously defined messages that are + * supported by the feature. + * + * Before operands are defined a comment is added that gives the + * name of the operand and in brackets the variable name of the + * corresponding argument in the cec-funcs.h function. + */ + +/* Messages */ + +/* One Touch Play Feature */ +#define CEC_MSG_ACTIVE_SOURCE 0x82 +#define CEC_MSG_IMAGE_VIEW_ON 0x04 +#define CEC_MSG_TEXT_VIEW_ON 0x0d + + +/* Routing Control Feature */ + +/* + * Has also: + * CEC_MSG_ACTIVE_SOURCE + */ + +#define CEC_MSG_INACTIVE_SOURCE 0x9d +#define CEC_MSG_REQUEST_ACTIVE_SOURCE 0x85 +#define CEC_MSG_ROUTING_CHANGE 0x80 +#define CEC_MSG_ROUTING_INFORMATION 0x81 +#define CEC_MSG_SET_STREAM_PATH 0x86 + + +/* Standby Feature */ +#define CEC_MSG_STANDBY 0x36 + + +/* One Touch Record Feature */ +#define CEC_MSG_RECORD_OFF 0x0b +#define CEC_MSG_RECORD_ON 0x09 +/* Record Source Type Operand (rec_src_type) */ +#define CEC_OP_RECORD_SRC_OWN 1 +#define CEC_OP_RECORD_SRC_DIGITAL 2 +#define CEC_OP_RECORD_SRC_ANALOG 3 +#define CEC_OP_RECORD_SRC_EXT_PLUG 4 +#define CEC_OP_RECORD_SRC_EXT_PHYS_ADDR 5 +/* Service Identification Method Operand (service_id_method) */ +#define CEC_OP_SERVICE_ID_METHOD_BY_DIG_ID 0 +#define CEC_OP_SERVICE_ID_METHOD_BY_CHANNEL 1 +/* Digital Service Broadcast System Operand (dig_bcast_system) */ +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_GEN 0x00 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_GEN 0x01 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_GEN 0x02 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_BS 0x08 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_CS 0x09 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ARIB_T 0x0a +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_CABLE 0x10 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_SAT 0x11 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_ATSC_T 0x12 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_C 0x18 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S 0x19 +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_S2 0x1a +#define CEC_OP_DIG_SERVICE_BCAST_SYSTEM_DVB_T 0x1b +/* Analogue Broadcast Type Operand (ana_bcast_type) */ +#define CEC_OP_ANA_BCAST_TYPE_CABLE 0 +#define CEC_OP_ANA_BCAST_TYPE_SATELLITE 1 +#define CEC_OP_ANA_BCAST_TYPE_TERRESTRIAL 2 +/* Broadcast System Operand (bcast_system) */ +#define CEC_OP_BCAST_SYSTEM_PAL_BG 0x00 +#define CEC_OP_BCAST_SYSTEM_SECAM_LQ 0x01 /* SECAM L' */ +#define CEC_OP_BCAST_SYSTEM_PAL_M 0x02 +#define CEC_OP_BCAST_SYSTEM_NTSC_M 0x03 +#define CEC_OP_BCAST_SYSTEM_PAL_I 0x04 +#define CEC_OP_BCAST_SYSTEM_SECAM_DK 0x05 +#define CEC_OP_BCAST_SYSTEM_SECAM_BG 0x06 +#define CEC_OP_BCAST_SYSTEM_SECAM_L 0x07 +#define CEC_OP_BCAST_SYSTEM_PAL_DK 0x08 +#define CEC_OP_BCAST_SYSTEM_OTHER 0x1f +/* Channel Number Format Operand (channel_number_fmt) */ +#define CEC_OP_CHANNEL_NUMBER_FMT_1_PART 0x01 +#define CEC_OP_CHANNEL_NUMBER_FMT_2_PART 0x02 + +#define CEC_MSG_RECORD_STATUS 0x0a +/* Record Status Operand (rec_status) */ +#define CEC_OP_RECORD_STATUS_CUR_SRC 0x01 +#define CEC_OP_RECORD_STATUS_DIG_SERVICE 0x02 +#define CEC_OP_RECORD_STATUS_ANA_SERVICE 0x03 +#define CEC_OP_RECORD_STATUS_EXT_INPUT 0x04 +#define CEC_OP_RECORD_STATUS_NO_DIG_SERVICE 0x05 +#define CEC_OP_RECORD_STATUS_NO_ANA_SERVICE 0x06 +#define CEC_OP_RECORD_STATUS_NO_SERVICE 0x07 +#define CEC_OP_RECORD_STATUS_INVALID_EXT_PLUG 0x09 +#define CEC_OP_RECORD_STATUS_INVALID_EXT_PHYS_ADDR 0x0a +#define CEC_OP_RECORD_STATUS_UNSUP_CA 0x0b +#define CEC_OP_RECORD_STATUS_NO_CA_ENTITLEMENTS 0x0c +#define CEC_OP_RECORD_STATUS_CANT_COPY_SRC 0x0d +#define CEC_OP_RECORD_STATUS_NO_MORE_COPIES 0x0e +#define CEC_OP_RECORD_STATUS_NO_MEDIA 0x10 +#define CEC_OP_RECORD_STATUS_PLAYING 0x11 +#define CEC_OP_RECORD_STATUS_ALREADY_RECORDING 0x12 +#define CEC_OP_RECORD_STATUS_MEDIA_PROT 0x13 +#define CEC_OP_RECORD_STATUS_NO_SIGNAL 0x14 +#define CEC_OP_RECORD_STATUS_MEDIA_PROBLEM 0x15 +#define CEC_OP_RECORD_STATUS_NO_SPACE 0x16 +#define CEC_OP_RECORD_STATUS_PARENTAL_LOCK 0x17 +#define CEC_OP_RECORD_STATUS_TERMINATED_OK 0x1a +#define CEC_OP_RECORD_STATUS_ALREADY_TERM 0x1b +#define CEC_OP_RECORD_STATUS_OTHER 0x1f + +#define CEC_MSG_RECORD_TV_SCREEN 0x0f + + +/* Timer Programming Feature */ +#define CEC_MSG_CLEAR_ANALOGUE_TIMER 0x33 +/* Recording Sequence Operand (recording_seq) */ +#define CEC_OP_REC_SEQ_SUNDAY 0x01 +#define CEC_OP_REC_SEQ_MONDAY 0x02 +#define CEC_OP_REC_SEQ_TUESDAY 0x04 +#define CEC_OP_REC_SEQ_WEDNESDAY 0x08 +#define CEC_OP_REC_SEQ_THURSDAY 0x10 +#define CEC_OP_REC_SEQ_FRIDAY 0x20 +#define CEC_OP_REC_SEQ_SATERDAY 0x40 +#define CEC_OP_REC_SEQ_ONCE_ONLY 0x00 + +#define CEC_MSG_CLEAR_DIGITAL_TIMER 0x99 + +#define CEC_MSG_CLEAR_EXT_TIMER 0xa1 +/* External Source Specifier Operand (ext_src_spec) */ +#define CEC_OP_EXT_SRC_PLUG 0x04 +#define CEC_OP_EXT_SRC_PHYS_ADDR 0x05 + +#define CEC_MSG_SET_ANALOGUE_TIMER 0x34 +#define CEC_MSG_SET_DIGITAL_TIMER 0x97 +#define CEC_MSG_SET_EXT_TIMER 0xa2 + +#define CEC_MSG_SET_TIMER_PROGRAM_TITLE 0x67 +#define CEC_MSG_TIMER_CLEARED_STATUS 0x43 +/* Timer Cleared Status Data Operand (timer_cleared_status) */ +#define CEC_OP_TIMER_CLR_STAT_RECORDING 0x00 +#define CEC_OP_TIMER_CLR_STAT_NO_MATCHING 0x01 +#define CEC_OP_TIMER_CLR_STAT_NO_INFO 0x02 +#define CEC_OP_TIMER_CLR_STAT_CLEARED 0x80 + +#define CEC_MSG_TIMER_STATUS 0x35 +/* Timer Overlap Warning Operand (timer_overlap_warning) */ +#define CEC_OP_TIMER_OVERLAP_WARNING_NO_OVERLAP 0 +#define CEC_OP_TIMER_OVERLAP_WARNING_OVERLAP 1 +/* Media Info Operand (media_info) */ +#define CEC_OP_MEDIA_INFO_UNPROT_MEDIA 0 +#define CEC_OP_MEDIA_INFO_PROT_MEDIA 1 +#define CEC_OP_MEDIA_INFO_NO_MEDIA 2 +/* Programmed Indicator Operand (prog_indicator) */ +#define CEC_OP_PROG_IND_NOT_PROGRAMMED 0 +#define CEC_OP_PROG_IND_PROGRAMMED 1 +/* Programmed Info Operand (prog_info) */ +#define CEC_OP_PROG_INFO_ENOUGH_SPACE 0x08 +#define CEC_OP_PROG_INFO_NOT_ENOUGH_SPACE 0x09 +#define CEC_OP_PROG_INFO_MIGHT_NOT_BE_ENOUGH_SPACE 0x0b +#define CEC_OP_PROG_INFO_NONE_AVAILABLE 0x0a +/* Not Programmed Error Info Operand (prog_error) */ +#define CEC_OP_PROG_ERROR_NO_FREE_TIMER 0x01 +#define CEC_OP_PROG_ERROR_DATE_OUT_OF_RANGE 0x02 +#define CEC_OP_PROG_ERROR_REC_SEQ_ERROR 0x03 +#define CEC_OP_PROG_ERROR_INV_EXT_PLUG 0x04 +#define CEC_OP_PROG_ERROR_INV_EXT_PHYS_ADDR 0x05 +#define CEC_OP_PROG_ERROR_CA_UNSUPP 0x06 +#define CEC_OP_PROG_ERROR_INSUF_CA_ENTITLEMENTS 0x07 +#define CEC_OP_PROG_ERROR_RESOLUTION_UNSUPP 0x08 +#define CEC_OP_PROG_ERROR_PARENTAL_LOCK 0x09 +#define CEC_OP_PROG_ERROR_CLOCK_FAILURE 0x0a +#define CEC_OP_PROG_ERROR_DUPLICATE 0x0e + + +/* System Information Feature */ +#define CEC_MSG_CEC_VERSION 0x9e +/* CEC Version Operand (cec_version) */ +#define CEC_OP_CEC_VERSION_1_3A 4 +#define CEC_OP_CEC_VERSION_1_4 5 +#define CEC_OP_CEC_VERSION_2_0 6 + +#define CEC_MSG_GET_CEC_VERSION 0x9f +#define CEC_MSG_GIVE_PHYSICAL_ADDR 0x83 +#define CEC_MSG_GET_MENU_LANGUAGE 0x91 +#define CEC_MSG_REPORT_PHYSICAL_ADDR 0x84 +/* Primary Device Type Operand (prim_devtype) */ +#define CEC_OP_PRIM_DEVTYPE_TV 0 +#define CEC_OP_PRIM_DEVTYPE_RECORD 1 +#define CEC_OP_PRIM_DEVTYPE_TUNER 3 +#define CEC_OP_PRIM_DEVTYPE_PLAYBACK 4 +#define CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM 5 +#define CEC_OP_PRIM_DEVTYPE_SWITCH 6 +#define CEC_OP_PRIM_DEVTYPE_PROCESSOR 7 + +#define CEC_MSG_SET_MENU_LANGUAGE 0x32 +#define CEC_MSG_REPORT_FEATURES 0xa6 /* HDMI 2.0 */ +/* All Device Types Operand (all_device_types) */ +#define CEC_OP_ALL_DEVTYPE_TV 0x80 +#define CEC_OP_ALL_DEVTYPE_RECORD 0x40 +#define CEC_OP_ALL_DEVTYPE_TUNER 0x20 +#define CEC_OP_ALL_DEVTYPE_PLAYBACK 0x10 +#define CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM 0x08 +#define CEC_OP_ALL_DEVTYPE_SWITCH 0x04 +/* + * And if you wondering what happened to PROCESSOR devices: those should + * be mapped to a SWITCH. + */ + +/* Valid for RC Profile and Device Feature operands */ +#define CEC_OP_FEAT_EXT 0x80 /* Extension bit */ +/* RC Profile Operand (rc_profile) */ +#define CEC_OP_FEAT_RC_TV_PROFILE_NONE 0x00 +#define CEC_OP_FEAT_RC_TV_PROFILE_1 0x02 +#define CEC_OP_FEAT_RC_TV_PROFILE_2 0x06 +#define CEC_OP_FEAT_RC_TV_PROFILE_3 0x0a +#define CEC_OP_FEAT_RC_TV_PROFILE_4 0x0e +#define CEC_OP_FEAT_RC_SRC_HAS_DEV_ROOT_MENU 0x50 +#define CEC_OP_FEAT_RC_SRC_HAS_DEV_SETUP_MENU 0x48 +#define CEC_OP_FEAT_RC_SRC_HAS_CONTENTS_MENU 0x44 +#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_TOP_MENU 0x42 +#define CEC_OP_FEAT_RC_SRC_HAS_MEDIA_CONTEXT_MENU 0x41 +/* Device Feature Operand (dev_features) */ +#define CEC_OP_FEAT_DEV_HAS_RECORD_TV_SCREEN 0x40 +#define CEC_OP_FEAT_DEV_HAS_SET_OSD_STRING 0x20 +#define CEC_OP_FEAT_DEV_HAS_DECK_CONTROL 0x10 +#define CEC_OP_FEAT_DEV_HAS_SET_AUDIO_RATE 0x08 +#define CEC_OP_FEAT_DEV_SINK_HAS_ARC_TX 0x04 +#define CEC_OP_FEAT_DEV_SOURCE_HAS_ARC_RX 0x02 + +#define CEC_MSG_GIVE_FEATURES 0xa5 /* HDMI 2.0 */ + + +/* Deck Control Feature */ +#define CEC_MSG_DECK_CONTROL 0x42 +/* Deck Control Mode Operand (deck_control_mode) */ +#define CEC_OP_DECK_CTL_MODE_SKIP_FWD 1 +#define CEC_OP_DECK_CTL_MODE_SKIP_REV 2 +#define CEC_OP_DECK_CTL_MODE_STOP 3 +#define CEC_OP_DECK_CTL_MODE_EJECT 4 + +#define CEC_MSG_DECK_STATUS 0x1b +/* Deck Info Operand (deck_info) */ +#define CEC_OP_DECK_INFO_PLAY 0x11 +#define CEC_OP_DECK_INFO_RECORD 0x12 +#define CEC_OP_DECK_INFO_PLAY_REV 0x13 +#define CEC_OP_DECK_INFO_STILL 0x14 +#define CEC_OP_DECK_INFO_SLOW 0x15 +#define CEC_OP_DECK_INFO_SLOW_REV 0x16 +#define CEC_OP_DECK_INFO_FAST_FWD 0x17 +#define CEC_OP_DECK_INFO_FAST_REV 0x18 +#define CEC_OP_DECK_INFO_NO_MEDIA 0x19 +#define CEC_OP_DECK_INFO_STOP 0x1a +#define CEC_OP_DECK_INFO_SKIP_FWD 0x1b +#define CEC_OP_DECK_INFO_SKIP_REV 0x1c +#define CEC_OP_DECK_INFO_INDEX_SEARCH_FWD 0x1d +#define CEC_OP_DECK_INFO_INDEX_SEARCH_REV 0x1e +#define CEC_OP_DECK_INFO_OTHER 0x1f + +#define CEC_MSG_GIVE_DECK_STATUS 0x1a +/* Status Request Operand (status_req) */ +#define CEC_OP_STATUS_REQ_ON 1 +#define CEC_OP_STATUS_REQ_OFF 2 +#define CEC_OP_STATUS_REQ_ONCE 3 + +#define CEC_MSG_PLAY 0x41 +/* Play Mode Operand (play_mode) */ +#define CEC_OP_PLAY_MODE_PLAY_FWD 0x24 +#define CEC_OP_PLAY_MODE_PLAY_REV 0x20 +#define CEC_OP_PLAY_MODE_PLAY_STILL 0x25 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MIN 0x05 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MED 0x06 +#define CEC_OP_PLAY_MODE_PLAY_FAST_FWD_MAX 0x07 +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MIN 0x09 +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MED 0x0a +#define CEC_OP_PLAY_MODE_PLAY_FAST_REV_MAX 0x0b +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MIN 0x15 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MED 0x16 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_FWD_MAX 0x17 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MIN 0x19 +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MED 0x1a +#define CEC_OP_PLAY_MODE_PLAY_SLOW_REV_MAX 0x1b + + +/* Tuner Control Feature */ +#define CEC_MSG_GIVE_TUNER_DEVICE_STATUS 0x08 +#define CEC_MSG_SELECT_ANALOGUE_SERVICE 0x92 +#define CEC_MSG_SELECT_DIGITAL_SERVICE 0x93 +#define CEC_MSG_TUNER_DEVICE_STATUS 0x07 +/* Recording Flag Operand (rec_flag) */ +#define CEC_OP_REC_FLAG_USED 0 +#define CEC_OP_REC_FLAG_NOT_USED 1 +/* Tuner Display Info Operand (tuner_display_info) */ +#define CEC_OP_TUNER_DISPLAY_INFO_DIGITAL 0 +#define CEC_OP_TUNER_DISPLAY_INFO_NONE 1 +#define CEC_OP_TUNER_DISPLAY_INFO_ANALOGUE 2 + +#define CEC_MSG_TUNER_STEP_DECREMENT 0x06 +#define CEC_MSG_TUNER_STEP_INCREMENT 0x05 + + +/* Vendor Specific Commands Feature */ + +/* + * Has also: + * CEC_MSG_CEC_VERSION + * CEC_MSG_GET_CEC_VERSION + */ +#define CEC_MSG_DEVICE_VENDOR_ID 0x87 +#define CEC_MSG_GIVE_DEVICE_VENDOR_ID 0x8c +#define CEC_MSG_VENDOR_COMMAND 0x89 +#define CEC_MSG_VENDOR_COMMAND_WITH_ID 0xa0 +#define CEC_MSG_VENDOR_REMOTE_BUTTON_DOWN 0x8a +#define CEC_MSG_VENDOR_REMOTE_BUTTON_UP 0x8b + + +/* OSD Display Feature */ +#define CEC_MSG_SET_OSD_STRING 0x64 +/* Display Control Operand (disp_ctl) */ +#define CEC_OP_DISP_CTL_DEFAULT 0x00 +#define CEC_OP_DISP_CTL_UNTIL_CLEARED 0x40 +#define CEC_OP_DISP_CTL_CLEAR 0x80 + + +/* Device OSD Transfer Feature */ +#define CEC_MSG_GIVE_OSD_NAME 0x46 +#define CEC_MSG_SET_OSD_NAME 0x47 + + +/* Device Menu Control Feature */ +#define CEC_MSG_MENU_REQUEST 0x8d +/* Menu Request Type Operand (menu_req) */ +#define CEC_OP_MENU_REQUEST_ACTIVATE 0x00 +#define CEC_OP_MENU_REQUEST_DEACTIVATE 0x01 +#define CEC_OP_MENU_REQUEST_QUERY 0x02 + +#define CEC_MSG_MENU_STATUS 0x8e +/* Menu State Operand (menu_state) */ +#define CEC_OP_MENU_STATE_ACTIVATED 0x00 +#define CEC_OP_MENU_STATE_DEACTIVATED 0x01 + +#define CEC_MSG_USER_CONTROL_PRESSED 0x44 +/* UI Broadcast Type Operand (ui_bcast_type) */ +#define CEC_OP_UI_BCAST_TYPE_TOGGLE_ALL 0x00 +#define CEC_OP_UI_BCAST_TYPE_TOGGLE_DIG_ANA 0x01 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE 0x10 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_T 0x20 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_CABLE 0x30 +#define CEC_OP_UI_BCAST_TYPE_ANALOGUE_SAT 0x40 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL 0x50 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_T 0x60 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_CABLE 0x70 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_SAT 0x80 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT 0x90 +#define CEC_OP_UI_BCAST_TYPE_DIGITAL_COM_SAT2 0x91 +#define CEC_OP_UI_BCAST_TYPE_IP 0xa0 +/* UI Sound Presentation Control Operand (ui_snd_pres_ctl) */ +#define CEC_OP_UI_SND_PRES_CTL_DUAL_MONO 0x10 +#define CEC_OP_UI_SND_PRES_CTL_KARAOKE 0x20 +#define CEC_OP_UI_SND_PRES_CTL_DOWNMIX 0x80 +#define CEC_OP_UI_SND_PRES_CTL_REVERB 0x90 +#define CEC_OP_UI_SND_PRES_CTL_EQUALIZER 0xa0 +#define CEC_OP_UI_SND_PRES_CTL_BASS_UP 0xb1 +#define CEC_OP_UI_SND_PRES_CTL_BASS_NEUTRAL 0xb2 +#define CEC_OP_UI_SND_PRES_CTL_BASS_DOWN 0xb3 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_UP 0xc1 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_NEUTRAL 0xc2 +#define CEC_OP_UI_SND_PRES_CTL_TREBLE_DOWN 0xc3 + +#define CEC_MSG_USER_CONTROL_RELEASED 0x45 + + +/* Remote Control Passthrough Feature */ + +/* + * Has also: + * CEC_MSG_USER_CONTROL_PRESSED + * CEC_MSG_USER_CONTROL_RELEASED + */ + + +/* Power Status Feature */ +#define CEC_MSG_GIVE_DEVICE_POWER_STATUS 0x8f +#define CEC_MSG_REPORT_POWER_STATUS 0x90 +/* Power Status Operand (pwr_state) */ +#define CEC_OP_POWER_STATUS_ON 0 +#define CEC_OP_POWER_STATUS_STANDBY 1 +#define CEC_OP_POWER_STATUS_TO_ON 2 +#define CEC_OP_POWER_STATUS_TO_STANDBY 3 + + +/* General Protocol Messages */ +#define CEC_MSG_FEATURE_ABORT 0x00 +/* Abort Reason Operand (reason) */ +#define CEC_OP_ABORT_UNRECOGNIZED_OP 0 +#define CEC_OP_ABORT_INCORRECT_MODE 1 +#define CEC_OP_ABORT_NO_SOURCE 2 +#define CEC_OP_ABORT_INVALID_OP 3 +#define CEC_OP_ABORT_REFUSED 4 +#define CEC_OP_ABORT_UNDETERMINED 5 + +#define CEC_MSG_ABORT 0xff + + +/* System Audio Control Feature */ + +/* + * Has also: + * CEC_MSG_USER_CONTROL_PRESSED + * CEC_MSG_USER_CONTROL_RELEASED + */ +#define CEC_MSG_GIVE_AUDIO_STATUS 0x71 +#define CEC_MSG_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7d +#define CEC_MSG_REPORT_AUDIO_STATUS 0x7a +/* Audio Mute Status Operand (aud_mute_status) */ +#define CEC_OP_AUD_MUTE_STATUS_OFF 0 +#define CEC_OP_AUD_MUTE_STATUS_ON 1 + +#define CEC_MSG_REPORT_SHORT_AUDIO_DESCRIPTOR 0xa3 +#define CEC_MSG_REQUEST_SHORT_AUDIO_DESCRIPTOR 0xa4 +#define CEC_MSG_SET_SYSTEM_AUDIO_MODE 0x72 +/* System Audio Status Operand (sys_aud_status) */ +#define CEC_OP_SYS_AUD_STATUS_OFF 0 +#define CEC_OP_SYS_AUD_STATUS_ON 1 + +#define CEC_MSG_SYSTEM_AUDIO_MODE_REQUEST 0x70 +#define CEC_MSG_SYSTEM_AUDIO_MODE_STATUS 0x7e +/* Audio Format ID Operand (audio_format_id) */ +#define CEC_OP_AUD_FMT_ID_CEA861 0 +#define CEC_OP_AUD_FMT_ID_CEA861_CXT 1 + + +/* Audio Rate Control Feature */ +#define CEC_MSG_SET_AUDIO_RATE 0x9a +/* Audio Rate Operand (audio_rate) */ +#define CEC_OP_AUD_RATE_OFF 0 +#define CEC_OP_AUD_RATE_WIDE_STD 1 +#define CEC_OP_AUD_RATE_WIDE_FAST 2 +#define CEC_OP_AUD_RATE_WIDE_SLOW 3 +#define CEC_OP_AUD_RATE_NARROW_STD 4 +#define CEC_OP_AUD_RATE_NARROW_FAST 5 +#define CEC_OP_AUD_RATE_NARROW_SLOW 6 + + +/* Audio Return Channel Control Feature */ +#define CEC_MSG_INITIATE_ARC 0xc0 +#define CEC_MSG_REPORT_ARC_INITIATED 0xc1 +#define CEC_MSG_REPORT_ARC_TERMINATED 0xc2 +#define CEC_MSG_REQUEST_ARC_INITIATION 0xc3 +#define CEC_MSG_REQUEST_ARC_TERMINATION 0xc4 +#define CEC_MSG_TERMINATE_ARC 0xc5 + + +/* Dynamic Audio Lipsync Feature */ +/* Only for CEC 2.0 and up */ +#define CEC_MSG_REQUEST_CURRENT_LATENCY 0xa7 +#define CEC_MSG_REPORT_CURRENT_LATENCY 0xa8 +/* Low Latency Mode Operand (low_latency_mode) */ +#define CEC_OP_LOW_LATENCY_MODE_OFF 0 +#define CEC_OP_LOW_LATENCY_MODE_ON 1 +/* Audio Output Compensated Operand (audio_out_compensated) */ +#define CEC_OP_AUD_OUT_COMPENSATED_NA 0 +#define CEC_OP_AUD_OUT_COMPENSATED_DELAY 1 +#define CEC_OP_AUD_OUT_COMPENSATED_NO_DELAY 2 +#define CEC_OP_AUD_OUT_COMPENSATED_PARTIAL_DELAY 3 + + +/* Capability Discovery and Control Feature */ +#define CEC_MSG_CDC_MESSAGE 0xf8 +/* Ethernet-over-HDMI: nobody ever does this... */ +#define CEC_MSG_CDC_HEC_INQUIRE_STATE 0x00 +#define CEC_MSG_CDC_HEC_REPORT_STATE 0x01 +/* HEC Functionality State Operand (hec_func_state) */ +#define CEC_OP_HEC_FUNC_STATE_NOT_SUPPORTED 0 +#define CEC_OP_HEC_FUNC_STATE_INACTIVE 1 +#define CEC_OP_HEC_FUNC_STATE_ACTIVE 2 +#define CEC_OP_HEC_FUNC_STATE_ACTIVATION_FIELD 3 +/* Host Functionality State Operand (host_func_state) */ +#define CEC_OP_HOST_FUNC_STATE_NOT_SUPPORTED 0 +#define CEC_OP_HOST_FUNC_STATE_INACTIVE 1 +#define CEC_OP_HOST_FUNC_STATE_ACTIVE 2 +/* ENC Functionality State Operand (enc_func_state) */ +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_NOT_SUPPORTED 0 +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_INACTIVE 1 +#define CEC_OP_ENC_FUNC_STATE_EXT_CON_ACTIVE 2 +/* CDC Error Code Operand (cdc_errcode) */ +#define CEC_OP_CDC_ERROR_CODE_NONE 0 +#define CEC_OP_CDC_ERROR_CODE_CAP_UNSUPPORTED 1 +#define CEC_OP_CDC_ERROR_CODE_WRONG_STATE 2 +#define CEC_OP_CDC_ERROR_CODE_OTHER 3 +/* HEC Support Operand (hec_support) */ +#define CEC_OP_HEC_SUPPORT_NO 0 +#define CEC_OP_HEC_SUPPORT_YES 1 +/* HEC Activation Operand (hec_activation) */ +#define CEC_OP_HEC_ACTIVATION_ON 0 +#define CEC_OP_HEC_ACTIVATION_OFF 1 + +#define CEC_MSG_CDC_HEC_SET_STATE_ADJACENT 0x02 +#define CEC_MSG_CDC_HEC_SET_STATE 0x03 +/* HEC Set State Operand (hec_set_state) */ +#define CEC_OP_HEC_SET_STATE_DEACTIVATE 0 +#define CEC_OP_HEC_SET_STATE_ACTIVATE 1 + +#define CEC_MSG_CDC_HEC_REQUEST_DEACTIVATION 0x04 +#define CEC_MSG_CDC_HEC_NOTIFY_ALIVE 0x05 +#define CEC_MSG_CDC_HEC_DISCOVER 0x06 +/* Hotplug Detect messages */ +#define CEC_MSG_CDC_HPD_SET_STATE 0x10 +/* HPD State Operand (hpd_state) */ +#define CEC_OP_HPD_STATE_CP_EDID_DISABLE 0 +#define CEC_OP_HPD_STATE_CP_EDID_ENABLE 1 +#define CEC_OP_HPD_STATE_CP_EDID_DISABLE_ENABLE 2 +#define CEC_OP_HPD_STATE_EDID_DISABLE 3 +#define CEC_OP_HPD_STATE_EDID_ENABLE 4 +#define CEC_OP_HPD_STATE_EDID_DISABLE_ENABLE 5 +#define CEC_MSG_CDC_HPD_REPORT_STATE 0x11 +/* HPD Error Code Operand (hpd_error) */ +#define CEC_OP_HPD_ERROR_NONE 0 +#define CEC_OP_HPD_ERROR_INITIATOR_NOT_CAPABLE 1 +#define CEC_OP_HPD_ERROR_INITIATOR_WRONG_STATE 2 +#define CEC_OP_HPD_ERROR_OTHER 3 +#define CEC_OP_HPD_ERROR_NONE_NO_VIDEO 4 + +/* End of Messages */ + +/* Helper functions to identify the 'special' CEC devices */ + +static inline bool cec_is_2nd_tv(const struct cec_log_addrs *las) +{ + /* + * It is a second TV if the logical address is 14 or 15 and the + * primary device type is a TV. + */ + return las->num_log_addrs && + las->log_addr[0] >= CEC_LOG_ADDR_SPECIFIC && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_TV; +} + +static inline bool cec_is_processor(const struct cec_log_addrs *las) +{ + /* + * It is a processor if the logical address is 12-15 and the + * primary device type is a Processor. + */ + return las->num_log_addrs && + las->log_addr[0] >= CEC_LOG_ADDR_BACKUP_1 && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_PROCESSOR; +} + +static inline bool cec_is_switch(const struct cec_log_addrs *las) +{ + /* + * It is a switch if the logical address is 15 and the + * primary device type is a Switch and the CDC-Only flag is not set. + */ + return las->num_log_addrs == 1 && + las->log_addr[0] == CEC_LOG_ADDR_UNREGISTERED && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH && + !(las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY); +} + +static inline bool cec_is_cdc_only(const struct cec_log_addrs *las) +{ + /* + * It is a CDC-only device if the logical address is 15 and the + * primary device type is a Switch and the CDC-Only flag is set. + */ + return las->num_log_addrs == 1 && + las->log_addr[0] == CEC_LOG_ADDR_UNREGISTERED && + las->primary_device_type[0] == CEC_OP_PRIM_DEVTYPE_SWITCH && + (las->flags & CEC_LOG_ADDRS_FL_CDC_ONLY); +} + +#endif -- cgit v1.2.3 From 7ae2a888eedd5a6b03849614eddd55f31793eeae Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 4 Nov 2016 07:52:11 -0200 Subject: [media] cec: sanitize msg.flags The CEC_MSG_FL_REPLY_TO_FOLLOWERS message flag only makes sense for transmitted messages where you want to wait for the reply. Clear the flag in all other cases. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 4 ++++ drivers/media/cec/cec-api.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index 054cd06e2247..bcd19d41c166 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -595,6 +595,10 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg, /* Make sure the timeout isn't 0. */ msg->timeout = 1000; } + if (msg->timeout) + msg->flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; + else + msg->flags = 0; /* Sanity checks */ if (msg->len == 0 || msg->len > CEC_MAX_MSG_SIZE) { diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index d4bc4ee2c6e5..597fbb62d829 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -197,7 +197,6 @@ static long cec_transmit(struct cec_adapter *adap, struct cec_fh *fh, (msg.len == 1 || msg.msg[1] != CEC_MSG_CDC_MESSAGE)) return -EINVAL; - msg.flags &= CEC_MSG_FL_REPLY_TO_FOLLOWERS; mutex_lock(&adap->lock); if (!adap->is_configured) err = -ENONET; @@ -282,6 +281,7 @@ static long cec_receive(struct cec_adapter *adap, struct cec_fh *fh, err = cec_receive_msg(fh, &msg, block); if (err) return err; + msg.flags = 0; if (copy_to_user(parg, &msg, sizeof(msg))) return -EFAULT; return 0; -- cgit v1.2.3 From a161bef04286e1344cd469098213a972af8fa7d6 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 4 Nov 2016 10:52:10 -0200 Subject: [media] cec: an inner loop clobbered the outer loop variable An inner for-loop reused the outer loop variable. This was only noticeable with CEC adapters supporting more than one logical address. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index bcd19d41c166..ed76d7050b8a 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -1416,6 +1416,7 @@ int __cec_s_log_addrs(struct cec_adapter *adap, const u8 feature_sz = ARRAY_SIZE(log_addrs->features[0]); u8 *features = log_addrs->features[i]; bool op_is_dev_features = false; + unsigned j; log_addrs->log_addr[i] = CEC_LOG_ADDR_INVALID; if (type_mask & (1 << log_addrs->log_addr_type[i])) { @@ -1442,19 +1443,19 @@ int __cec_s_log_addrs(struct cec_adapter *adap, dprintk(1, "unknown logical address type\n"); return -EINVAL; } - for (i = 0; i < feature_sz; i++) { - if ((features[i] & 0x80) == 0) { + for (j = 0; j < feature_sz; j++) { + if ((features[j] & 0x80) == 0) { if (op_is_dev_features) break; op_is_dev_features = true; } } - if (!op_is_dev_features || i == feature_sz) { + if (!op_is_dev_features || j == feature_sz) { dprintk(1, "malformed features\n"); return -EINVAL; } /* Zero unused part of the feature array */ - memset(features + i + 1, 0, feature_sz - i - 1); + memset(features + j + 1, 0, feature_sz - j - 1); } if (log_addrs->cec_version >= CEC_OP_CEC_VERSION_2_0) { -- cgit v1.2.3 From aee4c782df24557975c257058f69ac130f6f42bc Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 2 Nov 2016 08:34:53 -0200 Subject: [media] pulse8-cec: move out of staging Now that the CEC framework has been moved out of staging and into the mainline kernel we can do the same for the pulse8-cec driver. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/Kconfig | 5 + drivers/media/usb/Makefile | 1 + drivers/media/usb/pulse8-cec/Kconfig | 10 + drivers/media/usb/pulse8-cec/Makefile | 1 + drivers/media/usb/pulse8-cec/pulse8-cec.c | 761 ++++++++++++++++++++++++++ drivers/staging/media/Kconfig | 2 - drivers/staging/media/Makefile | 1 - drivers/staging/media/pulse8-cec/Kconfig | 10 - drivers/staging/media/pulse8-cec/Makefile | 1 - drivers/staging/media/pulse8-cec/TODO | 52 -- drivers/staging/media/pulse8-cec/pulse8-cec.c | 761 -------------------------- 11 files changed, 778 insertions(+), 827 deletions(-) create mode 100644 drivers/media/usb/pulse8-cec/Kconfig create mode 100644 drivers/media/usb/pulse8-cec/Makefile create mode 100644 drivers/media/usb/pulse8-cec/pulse8-cec.c delete mode 100644 drivers/staging/media/pulse8-cec/Kconfig delete mode 100644 drivers/staging/media/pulse8-cec/Makefile delete mode 100644 drivers/staging/media/pulse8-cec/TODO delete mode 100644 drivers/staging/media/pulse8-cec/pulse8-cec.c (limited to 'drivers') diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index 7496f332f3f5..c9644b62f91a 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -60,5 +60,10 @@ source "drivers/media/usb/hackrf/Kconfig" source "drivers/media/usb/msi2500/Kconfig" endif +if MEDIA_CEC_SUPPORT + comment "USB HDMI CEC adapters" +source "drivers/media/usb/pulse8-cec/Kconfig" +endif + endif #MEDIA_USB_SUPPORT endif #USB diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index 8874ba774a34..0f15e3351ddc 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -24,3 +24,4 @@ obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ obj-$(CONFIG_VIDEO_USBTV) += usbtv/ obj-$(CONFIG_VIDEO_GO7007) += go7007/ obj-$(CONFIG_DVB_AS102) += as102/ +obj-$(CONFIG_USB_PULSE8_CEC) += pulse8-cec/ diff --git a/drivers/media/usb/pulse8-cec/Kconfig b/drivers/media/usb/pulse8-cec/Kconfig new file mode 100644 index 000000000000..6ffc407de62f --- /dev/null +++ b/drivers/media/usb/pulse8-cec/Kconfig @@ -0,0 +1,10 @@ +config USB_PULSE8_CEC + tristate "Pulse Eight HDMI CEC" + depends on USB_ACM && MEDIA_CEC_SUPPORT + select SERIO + select SERIO_SERPORT + ---help--- + This is a cec driver for the Pulse Eight HDMI CEC device. + + To compile this driver as a module, choose M here: the + module will be called pulse8-cec. diff --git a/drivers/media/usb/pulse8-cec/Makefile b/drivers/media/usb/pulse8-cec/Makefile new file mode 100644 index 000000000000..9800690bc25a --- /dev/null +++ b/drivers/media/usb/pulse8-cec/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_PULSE8_CEC) += pulse8-cec.o diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c new file mode 100644 index 000000000000..9092494bb43c --- /dev/null +++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c @@ -0,0 +1,761 @@ +/* + * Pulse Eight HDMI CEC driver + * + * Copyright 2016 Hans Verkuil ["Power On"], ["Power] or ["Power Toggle"], or if it + * receives with its own physical address. It also does this + * if it receives [0x03 0x00] from an LG TV. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +MODULE_AUTHOR("Hans Verkuil "); +MODULE_DESCRIPTION("Pulse Eight HDMI CEC driver"); +MODULE_LICENSE("GPL"); + +static int debug; +static int persistent_config = 1; +module_param(debug, int, 0644); +module_param(persistent_config, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-1)"); +MODULE_PARM_DESC(persistent_config, "read config from persistent memory (0-1)"); + +enum pulse8_msgcodes { + MSGCODE_NOTHING = 0, + MSGCODE_PING, + MSGCODE_TIMEOUT_ERROR, + MSGCODE_HIGH_ERROR, + MSGCODE_LOW_ERROR, + MSGCODE_FRAME_START, + MSGCODE_FRAME_DATA, + MSGCODE_RECEIVE_FAILED, + MSGCODE_COMMAND_ACCEPTED, /* 0x08 */ + MSGCODE_COMMAND_REJECTED, + MSGCODE_SET_ACK_MASK, + MSGCODE_TRANSMIT, + MSGCODE_TRANSMIT_EOM, + MSGCODE_TRANSMIT_IDLETIME, + MSGCODE_TRANSMIT_ACK_POLARITY, + MSGCODE_TRANSMIT_LINE_TIMEOUT, + MSGCODE_TRANSMIT_SUCCEEDED, /* 0x10 */ + MSGCODE_TRANSMIT_FAILED_LINE, + MSGCODE_TRANSMIT_FAILED_ACK, + MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA, + MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE, + MSGCODE_FIRMWARE_VERSION, + MSGCODE_START_BOOTLOADER, + MSGCODE_GET_BUILDDATE, + MSGCODE_SET_CONTROLLED, /* 0x18 */ + MSGCODE_GET_AUTO_ENABLED, + MSGCODE_SET_AUTO_ENABLED, + MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS, + MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, + MSGCODE_GET_LOGICAL_ADDRESS_MASK, + MSGCODE_SET_LOGICAL_ADDRESS_MASK, + MSGCODE_GET_PHYSICAL_ADDRESS, + MSGCODE_SET_PHYSICAL_ADDRESS, /* 0x20 */ + MSGCODE_GET_DEVICE_TYPE, + MSGCODE_SET_DEVICE_TYPE, + MSGCODE_GET_HDMI_VERSION, + MSGCODE_SET_HDMI_VERSION, + MSGCODE_GET_OSD_NAME, + MSGCODE_SET_OSD_NAME, + MSGCODE_WRITE_EEPROM, + MSGCODE_GET_ADAPTER_TYPE, /* 0x28 */ + MSGCODE_SET_ACTIVE_SOURCE, + + MSGCODE_FRAME_EOM = 0x80, + MSGCODE_FRAME_ACK = 0x40, +}; + +#define MSGSTART 0xff +#define MSGEND 0xfe +#define MSGESC 0xfd +#define MSGOFFSET 3 + +#define DATA_SIZE 256 + +#define PING_PERIOD (15 * HZ) + +struct pulse8 { + struct device *dev; + struct serio *serio; + struct cec_adapter *adap; + unsigned int vers; + struct completion cmd_done; + struct work_struct work; + struct delayed_work ping_eeprom_work; + struct cec_msg rx_msg; + u8 data[DATA_SIZE]; + unsigned int len; + u8 buf[DATA_SIZE]; + unsigned int idx; + bool escape; + bool started; + struct mutex config_lock; + struct mutex write_lock; + bool config_pending; + bool restoring_config; + bool autonomous; +}; + +static void pulse8_ping_eeprom_work_handler(struct work_struct *work); + +static void pulse8_irq_work_handler(struct work_struct *work) +{ + struct pulse8 *pulse8 = + container_of(work, struct pulse8, work); + + switch (pulse8->data[0] & 0x3f) { + case MSGCODE_FRAME_DATA: + cec_received_msg(pulse8->adap, &pulse8->rx_msg); + break; + case MSGCODE_TRANSMIT_SUCCEEDED: + cec_transmit_done(pulse8->adap, CEC_TX_STATUS_OK, + 0, 0, 0, 0); + break; + case MSGCODE_TRANSMIT_FAILED_ACK: + cec_transmit_done(pulse8->adap, CEC_TX_STATUS_NACK, + 0, 1, 0, 0); + break; + case MSGCODE_TRANSMIT_FAILED_LINE: + case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA: + case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE: + cec_transmit_done(pulse8->adap, CEC_TX_STATUS_ERROR, + 0, 0, 0, 1); + break; + } +} + +static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data, + unsigned int flags) +{ + struct pulse8 *pulse8 = serio_get_drvdata(serio); + + if (!pulse8->started && data != MSGSTART) + return IRQ_HANDLED; + if (data == MSGESC) { + pulse8->escape = true; + return IRQ_HANDLED; + } + if (pulse8->escape) { + data += MSGOFFSET; + pulse8->escape = false; + } else if (data == MSGEND) { + struct cec_msg *msg = &pulse8->rx_msg; + + if (debug) + dev_info(pulse8->dev, "received: %*ph\n", + pulse8->idx, pulse8->buf); + pulse8->data[0] = pulse8->buf[0]; + switch (pulse8->buf[0] & 0x3f) { + case MSGCODE_FRAME_START: + msg->len = 1; + msg->msg[0] = pulse8->buf[1]; + break; + case MSGCODE_FRAME_DATA: + if (msg->len == CEC_MAX_MSG_SIZE) + break; + msg->msg[msg->len++] = pulse8->buf[1]; + if (pulse8->buf[0] & MSGCODE_FRAME_EOM) + schedule_work(&pulse8->work); + break; + case MSGCODE_TRANSMIT_SUCCEEDED: + case MSGCODE_TRANSMIT_FAILED_LINE: + case MSGCODE_TRANSMIT_FAILED_ACK: + case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA: + case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE: + schedule_work(&pulse8->work); + break; + case MSGCODE_HIGH_ERROR: + case MSGCODE_LOW_ERROR: + case MSGCODE_RECEIVE_FAILED: + case MSGCODE_TIMEOUT_ERROR: + break; + case MSGCODE_COMMAND_ACCEPTED: + case MSGCODE_COMMAND_REJECTED: + default: + if (pulse8->idx == 0) + break; + memcpy(pulse8->data, pulse8->buf, pulse8->idx); + pulse8->len = pulse8->idx; + complete(&pulse8->cmd_done); + break; + } + pulse8->idx = 0; + pulse8->started = false; + return IRQ_HANDLED; + } else if (data == MSGSTART) { + pulse8->idx = 0; + pulse8->started = true; + return IRQ_HANDLED; + } + + if (pulse8->idx >= DATA_SIZE) { + dev_dbg(pulse8->dev, + "throwing away %d bytes of garbage\n", pulse8->idx); + pulse8->idx = 0; + } + pulse8->buf[pulse8->idx++] = data; + return IRQ_HANDLED; +} + +static void pulse8_disconnect(struct serio *serio) +{ + struct pulse8 *pulse8 = serio_get_drvdata(serio); + + cec_unregister_adapter(pulse8->adap); + cancel_delayed_work_sync(&pulse8->ping_eeprom_work); + dev_info(&serio->dev, "disconnected\n"); + serio_close(serio); + serio_set_drvdata(serio, NULL); + kfree(pulse8); +} + +static int pulse8_send(struct serio *serio, const u8 *command, u8 cmd_len) +{ + int err = 0; + + err = serio_write(serio, MSGSTART); + if (err) + return err; + for (; !err && cmd_len; command++, cmd_len--) { + if (*command >= MSGESC) { + err = serio_write(serio, MSGESC); + if (!err) + err = serio_write(serio, *command - MSGOFFSET); + } else { + err = serio_write(serio, *command); + } + } + if (!err) + err = serio_write(serio, MSGEND); + + return err; +} + +static int pulse8_send_and_wait_once(struct pulse8 *pulse8, + const u8 *cmd, u8 cmd_len, + u8 response, u8 size) +{ + int err; + + /*dev_info(pulse8->dev, "transmit: %*ph\n", cmd_len, cmd);*/ + init_completion(&pulse8->cmd_done); + + err = pulse8_send(pulse8->serio, cmd, cmd_len); + if (err) + return err; + + if (!wait_for_completion_timeout(&pulse8->cmd_done, HZ)) + return -ETIMEDOUT; + if ((pulse8->data[0] & 0x3f) == MSGCODE_COMMAND_REJECTED && + cmd[0] != MSGCODE_SET_CONTROLLED && + cmd[0] != MSGCODE_SET_AUTO_ENABLED && + cmd[0] != MSGCODE_GET_BUILDDATE) + return -ENOTTY; + if (response && + ((pulse8->data[0] & 0x3f) != response || pulse8->len < size + 1)) { + dev_info(pulse8->dev, "transmit: failed %02x\n", + pulse8->data[0] & 0x3f); + return -EIO; + } + return 0; +} + +static int pulse8_send_and_wait(struct pulse8 *pulse8, + const u8 *cmd, u8 cmd_len, u8 response, u8 size) +{ + u8 cmd_sc[2]; + int err; + + mutex_lock(&pulse8->write_lock); + err = pulse8_send_and_wait_once(pulse8, cmd, cmd_len, response, size); + + if (err == -ENOTTY) { + cmd_sc[0] = MSGCODE_SET_CONTROLLED; + cmd_sc[1] = 1; + err = pulse8_send_and_wait_once(pulse8, cmd_sc, 2, + MSGCODE_COMMAND_ACCEPTED, 1); + if (err) + goto unlock; + err = pulse8_send_and_wait_once(pulse8, cmd, cmd_len, + response, size); + } + +unlock: + mutex_unlock(&pulse8->write_lock); + return err == -ENOTTY ? -EIO : err; +} + +static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio, + struct cec_log_addrs *log_addrs, u16 *pa) +{ + u8 *data = pulse8->data + 1; + u8 cmd[2]; + int err; + struct tm tm; + time_t date; + + pulse8->vers = 0; + + cmd[0] = MSGCODE_FIRMWARE_VERSION; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 2); + if (err) + return err; + pulse8->vers = (data[0] << 8) | data[1]; + dev_info(pulse8->dev, "Firmware version %04x\n", pulse8->vers); + if (pulse8->vers < 2) { + *pa = CEC_PHYS_ADDR_INVALID; + return 0; + } + + cmd[0] = MSGCODE_GET_BUILDDATE; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4); + if (err) + return err; + date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + time_to_tm(date, 0, &tm); + dev_info(pulse8->dev, "Firmware build date %04ld.%02d.%02d %02d:%02d:%02d\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + dev_dbg(pulse8->dev, "Persistent config:\n"); + cmd[0] = MSGCODE_GET_AUTO_ENABLED; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); + if (err) + return err; + pulse8->autonomous = data[0]; + dev_dbg(pulse8->dev, "Autonomous mode: %s", + data[0] ? "on" : "off"); + + cmd[0] = MSGCODE_GET_DEVICE_TYPE; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); + if (err) + return err; + log_addrs->primary_device_type[0] = data[0]; + dev_dbg(pulse8->dev, "Primary device type: %d\n", data[0]); + switch (log_addrs->primary_device_type[0]) { + case CEC_OP_PRIM_DEVTYPE_TV: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TV; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TV; + break; + case CEC_OP_PRIM_DEVTYPE_RECORD: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_RECORD; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_RECORD; + break; + case CEC_OP_PRIM_DEVTYPE_TUNER: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TUNER; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TUNER; + break; + case CEC_OP_PRIM_DEVTYPE_PLAYBACK: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_PLAYBACK; + break; + case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM; + break; + case CEC_OP_PRIM_DEVTYPE_SWITCH: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; + break; + case CEC_OP_PRIM_DEVTYPE_PROCESSOR: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_SPECIFIC; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; + break; + default: + log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; + log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; + dev_info(pulse8->dev, "Unknown Primary Device Type: %d\n", + log_addrs->primary_device_type[0]); + break; + } + + cmd[0] = MSGCODE_GET_LOGICAL_ADDRESS_MASK; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 2); + if (err) + return err; + log_addrs->log_addr_mask = (data[0] << 8) | data[1]; + dev_dbg(pulse8->dev, "Logical address ACK mask: %x\n", + log_addrs->log_addr_mask); + if (log_addrs->log_addr_mask) + log_addrs->num_log_addrs = 1; + + cmd[0] = MSGCODE_GET_PHYSICAL_ADDRESS; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); + if (err) + return err; + *pa = (data[0] << 8) | data[1]; + dev_dbg(pulse8->dev, "Physical address: %x.%x.%x.%x\n", + cec_phys_addr_exp(*pa)); + + cmd[0] = MSGCODE_GET_HDMI_VERSION; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); + if (err) + return err; + log_addrs->cec_version = data[0]; + dev_dbg(pulse8->dev, "CEC version: %d\n", log_addrs->cec_version); + + cmd[0] = MSGCODE_GET_OSD_NAME; + err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 0); + if (err) + return err; + strncpy(log_addrs->osd_name, data, 13); + dev_dbg(pulse8->dev, "OSD name: %s\n", log_addrs->osd_name); + + return 0; +} + +static int pulse8_apply_persistent_config(struct pulse8 *pulse8, + struct cec_log_addrs *log_addrs, + u16 pa) +{ + int err; + + err = cec_s_log_addrs(pulse8->adap, log_addrs, false); + if (err) + return err; + + cec_s_phys_addr(pulse8->adap, pa, false); + + return 0; +} + +static int pulse8_cec_adap_enable(struct cec_adapter *adap, bool enable) +{ + struct pulse8 *pulse8 = adap->priv; + u8 cmd[16]; + int err; + + cmd[0] = MSGCODE_SET_CONTROLLED; + cmd[1] = enable; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 1); + return enable ? err : 0; +} + +static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) +{ + struct pulse8 *pulse8 = adap->priv; + u16 mask = 0; + u16 pa = adap->phys_addr; + u8 cmd[16]; + int err = 0; + + mutex_lock(&pulse8->config_lock); + if (log_addr != CEC_LOG_ADDR_INVALID) + mask = 1 << log_addr; + cmd[0] = MSGCODE_SET_ACK_MASK; + cmd[1] = mask >> 8; + cmd[2] = mask & 0xff; + err = pulse8_send_and_wait(pulse8, cmd, 3, + MSGCODE_COMMAND_ACCEPTED, 0); + if ((err && mask != 0) || pulse8->restoring_config) + goto unlock; + + cmd[0] = MSGCODE_SET_AUTO_ENABLED; + cmd[1] = log_addr == CEC_LOG_ADDR_INVALID ? 0 : 1; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 0); + if (err) + goto unlock; + pulse8->autonomous = cmd[1]; + if (log_addr == CEC_LOG_ADDR_INVALID) + goto unlock; + + cmd[0] = MSGCODE_SET_DEVICE_TYPE; + cmd[1] = adap->log_addrs.primary_device_type[0]; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 0); + if (err) + goto unlock; + + switch (adap->log_addrs.primary_device_type[0]) { + case CEC_OP_PRIM_DEVTYPE_TV: + mask = CEC_LOG_ADDR_MASK_TV; + break; + case CEC_OP_PRIM_DEVTYPE_RECORD: + mask = CEC_LOG_ADDR_MASK_RECORD; + break; + case CEC_OP_PRIM_DEVTYPE_TUNER: + mask = CEC_LOG_ADDR_MASK_TUNER; + break; + case CEC_OP_PRIM_DEVTYPE_PLAYBACK: + mask = CEC_LOG_ADDR_MASK_PLAYBACK; + break; + case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM: + mask = CEC_LOG_ADDR_MASK_AUDIOSYSTEM; + break; + case CEC_OP_PRIM_DEVTYPE_SWITCH: + mask = CEC_LOG_ADDR_MASK_UNREGISTERED; + break; + case CEC_OP_PRIM_DEVTYPE_PROCESSOR: + mask = CEC_LOG_ADDR_MASK_SPECIFIC; + break; + default: + mask = 0; + break; + } + cmd[0] = MSGCODE_SET_LOGICAL_ADDRESS_MASK; + cmd[1] = mask >> 8; + cmd[2] = mask & 0xff; + err = pulse8_send_and_wait(pulse8, cmd, 3, + MSGCODE_COMMAND_ACCEPTED, 0); + if (err) + goto unlock; + + cmd[0] = MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS; + cmd[1] = log_addr; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 0); + if (err) + goto unlock; + + cmd[0] = MSGCODE_SET_PHYSICAL_ADDRESS; + cmd[1] = pa >> 8; + cmd[2] = pa & 0xff; + err = pulse8_send_and_wait(pulse8, cmd, 3, + MSGCODE_COMMAND_ACCEPTED, 0); + if (err) + goto unlock; + + cmd[0] = MSGCODE_SET_HDMI_VERSION; + cmd[1] = adap->log_addrs.cec_version; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 0); + if (err) + goto unlock; + + if (adap->log_addrs.osd_name[0]) { + size_t osd_len = strlen(adap->log_addrs.osd_name); + char *osd_str = cmd + 1; + + cmd[0] = MSGCODE_SET_OSD_NAME; + strncpy(cmd + 1, adap->log_addrs.osd_name, 13); + if (osd_len < 4) { + memset(osd_str + osd_len, ' ', 4 - osd_len); + osd_len = 4; + osd_str[osd_len] = '\0'; + strcpy(adap->log_addrs.osd_name, osd_str); + } + err = pulse8_send_and_wait(pulse8, cmd, 1 + osd_len, + MSGCODE_COMMAND_ACCEPTED, 0); + if (err) + goto unlock; + } + +unlock: + if (pulse8->restoring_config) + pulse8->restoring_config = false; + else + pulse8->config_pending = true; + mutex_unlock(&pulse8->config_lock); + return err; +} + +static int pulse8_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, + u32 signal_free_time, struct cec_msg *msg) +{ + struct pulse8 *pulse8 = adap->priv; + u8 cmd[2]; + unsigned int i; + int err; + + cmd[0] = MSGCODE_TRANSMIT_IDLETIME; + cmd[1] = signal_free_time; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 1); + cmd[0] = MSGCODE_TRANSMIT_ACK_POLARITY; + cmd[1] = cec_msg_is_broadcast(msg); + if (!err) + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 1); + cmd[0] = msg->len == 1 ? MSGCODE_TRANSMIT_EOM : MSGCODE_TRANSMIT; + cmd[1] = msg->msg[0]; + if (!err) + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 1); + if (!err && msg->len > 1) { + cmd[0] = msg->len == 2 ? MSGCODE_TRANSMIT_EOM : + MSGCODE_TRANSMIT; + cmd[1] = msg->msg[1]; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 1); + for (i = 0; !err && i + 2 < msg->len; i++) { + cmd[0] = (i + 2 == msg->len - 1) ? + MSGCODE_TRANSMIT_EOM : MSGCODE_TRANSMIT; + cmd[1] = msg->msg[i + 2]; + err = pulse8_send_and_wait(pulse8, cmd, 2, + MSGCODE_COMMAND_ACCEPTED, 1); + } + } + + return err; +} + +static int pulse8_received(struct cec_adapter *adap, struct cec_msg *msg) +{ + return -ENOMSG; +} + +static const struct cec_adap_ops pulse8_cec_adap_ops = { + .adap_enable = pulse8_cec_adap_enable, + .adap_log_addr = pulse8_cec_adap_log_addr, + .adap_transmit = pulse8_cec_adap_transmit, + .received = pulse8_received, +}; + +static int pulse8_connect(struct serio *serio, struct serio_driver *drv) +{ + u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PHYS_ADDR | + CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL; + struct pulse8 *pulse8; + int err = -ENOMEM; + struct cec_log_addrs log_addrs = {}; + u16 pa = CEC_PHYS_ADDR_INVALID; + + pulse8 = kzalloc(sizeof(*pulse8), GFP_KERNEL); + + if (!pulse8) + return -ENOMEM; + + pulse8->serio = serio; + pulse8->adap = cec_allocate_adapter(&pulse8_cec_adap_ops, pulse8, + "HDMI CEC", caps, 1, &serio->dev); + err = PTR_ERR_OR_ZERO(pulse8->adap); + if (err < 0) + goto free_device; + + pulse8->dev = &serio->dev; + serio_set_drvdata(serio, pulse8); + INIT_WORK(&pulse8->work, pulse8_irq_work_handler); + mutex_init(&pulse8->write_lock); + mutex_init(&pulse8->config_lock); + pulse8->config_pending = false; + + err = serio_open(serio, drv); + if (err) + goto delete_adap; + + err = pulse8_setup(pulse8, serio, &log_addrs, &pa); + if (err) + goto close_serio; + + err = cec_register_adapter(pulse8->adap); + if (err < 0) + goto close_serio; + + pulse8->dev = &pulse8->adap->devnode.dev; + + if (persistent_config && pulse8->autonomous) { + err = pulse8_apply_persistent_config(pulse8, &log_addrs, pa); + if (err) + goto close_serio; + pulse8->restoring_config = true; + } + + INIT_DELAYED_WORK(&pulse8->ping_eeprom_work, + pulse8_ping_eeprom_work_handler); + schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD); + + return 0; + +close_serio: + serio_close(serio); +delete_adap: + cec_delete_adapter(pulse8->adap); + serio_set_drvdata(serio, NULL); +free_device: + kfree(pulse8); + return err; +} + +static void pulse8_ping_eeprom_work_handler(struct work_struct *work) +{ + struct pulse8 *pulse8 = + container_of(work, struct pulse8, ping_eeprom_work.work); + u8 cmd; + + schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD); + cmd = MSGCODE_PING; + pulse8_send_and_wait(pulse8, &cmd, 1, + MSGCODE_COMMAND_ACCEPTED, 0); + + if (pulse8->vers < 2) + return; + + mutex_lock(&pulse8->config_lock); + if (pulse8->config_pending && persistent_config) { + dev_dbg(pulse8->dev, "writing pending config to EEPROM\n"); + cmd = MSGCODE_WRITE_EEPROM; + if (pulse8_send_and_wait(pulse8, &cmd, 1, + MSGCODE_COMMAND_ACCEPTED, 0)) + dev_info(pulse8->dev, "failed to write pending config to EEPROM\n"); + else + pulse8->config_pending = false; + } + mutex_unlock(&pulse8->config_lock); +} + +static struct serio_device_id pulse8_serio_ids[] = { + { + .type = SERIO_RS232, + .proto = SERIO_PULSE8_CEC, + .id = SERIO_ANY, + .extra = SERIO_ANY, + }, + { 0 } +}; + +MODULE_DEVICE_TABLE(serio, pulse8_serio_ids); + +static struct serio_driver pulse8_drv = { + .driver = { + .name = "pulse8-cec", + }, + .description = "Pulse Eight HDMI CEC driver", + .id_table = pulse8_serio_ids, + .interrupt = pulse8_interrupt, + .connect = pulse8_connect, + .disconnect = pulse8_disconnect, +}; + +module_serio_driver(pulse8_drv); diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig index 0abe5ffb4934..ffb8fa72c3da 100644 --- a/drivers/staging/media/Kconfig +++ b/drivers/staging/media/Kconfig @@ -27,8 +27,6 @@ source "drivers/staging/media/davinci_vpfe/Kconfig" source "drivers/staging/media/omap4iss/Kconfig" -source "drivers/staging/media/pulse8-cec/Kconfig" - source "drivers/staging/media/s5p-cec/Kconfig" # Keep LIRC at the end, as it has sub-menus diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile index 246299eff80d..a28e82cf6447 100644 --- a/drivers/staging/media/Makefile +++ b/drivers/staging/media/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_DVB_CXD2099) += cxd2099/ obj-$(CONFIG_LIRC_STAGING) += lirc/ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/ obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/ -obj-$(CONFIG_USB_PULSE8_CEC) += pulse8-cec/ obj-$(CONFIG_VIDEO_STI_HDMI_CEC) += st-cec/ diff --git a/drivers/staging/media/pulse8-cec/Kconfig b/drivers/staging/media/pulse8-cec/Kconfig deleted file mode 100644 index 6ffc407de62f..000000000000 --- a/drivers/staging/media/pulse8-cec/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config USB_PULSE8_CEC - tristate "Pulse Eight HDMI CEC" - depends on USB_ACM && MEDIA_CEC_SUPPORT - select SERIO - select SERIO_SERPORT - ---help--- - This is a cec driver for the Pulse Eight HDMI CEC device. - - To compile this driver as a module, choose M here: the - module will be called pulse8-cec. diff --git a/drivers/staging/media/pulse8-cec/Makefile b/drivers/staging/media/pulse8-cec/Makefile deleted file mode 100644 index 9800690bc25a..000000000000 --- a/drivers/staging/media/pulse8-cec/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_USB_PULSE8_CEC) += pulse8-cec.o diff --git a/drivers/staging/media/pulse8-cec/TODO b/drivers/staging/media/pulse8-cec/TODO deleted file mode 100644 index fa6660245e5f..000000000000 --- a/drivers/staging/media/pulse8-cec/TODO +++ /dev/null @@ -1,52 +0,0 @@ -This driver needs to mature a bit more and another round of -code cleanups. - -Otherwise it looks to be in good shape. And of course the fact -that the CEC framework is in staging at the moment also prevents -this driver from being mainlined. - -Some notes: - -1) Regarding the "autonomous" mode of the Pulse-Eight: currently this -is disabled, but the idea is that this allows basic functionality -when the PC is off, and it can wake-up the PC through USB. - -To prevent the device to go into autonomous mode the driver would -have to send MSGCODE_SET_CONTROLLED 1 and then send a ping every -30 seconds (in practice once every 15 seconds would be good). When -powering off or going to standby send MSGCODE_SET_CONTROLLED 0 to -turn the autonomous mode back on. - -This needs to be implemented in the driver. Autonomous mode was -added in firmware v2. - -2) Writing to the EEPROM can only be done once every 10 seconds. - -3) To use this driver you also need to patch the inputattach utility, -this patch will be submitted once this driver is moved out of staging. - -diff -urN linuxconsoletools-1.4.9/utils/inputattach.c linuxconsoletools-1.4.9.new/utils/inputattach.c ---- linuxconsoletools-1.4.9/utils/inputattach.c 2016-01-09 16:27:02.000000000 +0100 -+++ linuxconsoletools-1.4.9.new/utils/inputattach.c 2016-03-20 11:35:31.707788967 +0100 -@@ -861,6 +861,9 @@ - { "--wacom_iv", "-wacom_iv", "Wacom protocol IV tablet", - B9600, CS8 | CRTSCTS, - SERIO_WACOM_IV, 0x00, 0x00, 0, wacom_iv_init }, -+{ "--pulse8-cec", "-pulse8-cec", "Pulse Eight HDMI CEC dongle", -+ B9600, CS8, -+ SERIO_PULSE8_CEC, 0x00, 0x00, 0, NULL }, - { NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, NULL } - }; - -diff -urN linuxconsoletools-1.4.9/utils/serio-ids.h linuxconsoletools-1.4.9.new/utils/serio-ids.h ---- linuxconsoletools-1.4.9/utils/serio-ids.h 2015-04-26 18:29:42.000000000 +0200 -+++ linuxconsoletools-1.4.9.new/utils/serio-ids.h 2016-03-20 11:41:00.153558539 +0100 -@@ -131,5 +131,8 @@ - #ifndef SERIO_EASYPEN - # define SERIO_EASYPEN 0x3f - #endif -+#ifndef SERIO_PULSE8_CEC -+# define SERIO_PULSE8_CEC 0x40 -+#endif - - #endif diff --git a/drivers/staging/media/pulse8-cec/pulse8-cec.c b/drivers/staging/media/pulse8-cec/pulse8-cec.c deleted file mode 100644 index 9092494bb43c..000000000000 --- a/drivers/staging/media/pulse8-cec/pulse8-cec.c +++ /dev/null @@ -1,761 +0,0 @@ -/* - * Pulse Eight HDMI CEC driver - * - * Copyright 2016 Hans Verkuil ["Power On"], ["Power] or ["Power Toggle"], or if it - * receives with its own physical address. It also does this - * if it receives [0x03 0x00] from an LG TV. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -MODULE_AUTHOR("Hans Verkuil "); -MODULE_DESCRIPTION("Pulse Eight HDMI CEC driver"); -MODULE_LICENSE("GPL"); - -static int debug; -static int persistent_config = 1; -module_param(debug, int, 0644); -module_param(persistent_config, int, 0644); -MODULE_PARM_DESC(debug, "debug level (0-1)"); -MODULE_PARM_DESC(persistent_config, "read config from persistent memory (0-1)"); - -enum pulse8_msgcodes { - MSGCODE_NOTHING = 0, - MSGCODE_PING, - MSGCODE_TIMEOUT_ERROR, - MSGCODE_HIGH_ERROR, - MSGCODE_LOW_ERROR, - MSGCODE_FRAME_START, - MSGCODE_FRAME_DATA, - MSGCODE_RECEIVE_FAILED, - MSGCODE_COMMAND_ACCEPTED, /* 0x08 */ - MSGCODE_COMMAND_REJECTED, - MSGCODE_SET_ACK_MASK, - MSGCODE_TRANSMIT, - MSGCODE_TRANSMIT_EOM, - MSGCODE_TRANSMIT_IDLETIME, - MSGCODE_TRANSMIT_ACK_POLARITY, - MSGCODE_TRANSMIT_LINE_TIMEOUT, - MSGCODE_TRANSMIT_SUCCEEDED, /* 0x10 */ - MSGCODE_TRANSMIT_FAILED_LINE, - MSGCODE_TRANSMIT_FAILED_ACK, - MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA, - MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE, - MSGCODE_FIRMWARE_VERSION, - MSGCODE_START_BOOTLOADER, - MSGCODE_GET_BUILDDATE, - MSGCODE_SET_CONTROLLED, /* 0x18 */ - MSGCODE_GET_AUTO_ENABLED, - MSGCODE_SET_AUTO_ENABLED, - MSGCODE_GET_DEFAULT_LOGICAL_ADDRESS, - MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS, - MSGCODE_GET_LOGICAL_ADDRESS_MASK, - MSGCODE_SET_LOGICAL_ADDRESS_MASK, - MSGCODE_GET_PHYSICAL_ADDRESS, - MSGCODE_SET_PHYSICAL_ADDRESS, /* 0x20 */ - MSGCODE_GET_DEVICE_TYPE, - MSGCODE_SET_DEVICE_TYPE, - MSGCODE_GET_HDMI_VERSION, - MSGCODE_SET_HDMI_VERSION, - MSGCODE_GET_OSD_NAME, - MSGCODE_SET_OSD_NAME, - MSGCODE_WRITE_EEPROM, - MSGCODE_GET_ADAPTER_TYPE, /* 0x28 */ - MSGCODE_SET_ACTIVE_SOURCE, - - MSGCODE_FRAME_EOM = 0x80, - MSGCODE_FRAME_ACK = 0x40, -}; - -#define MSGSTART 0xff -#define MSGEND 0xfe -#define MSGESC 0xfd -#define MSGOFFSET 3 - -#define DATA_SIZE 256 - -#define PING_PERIOD (15 * HZ) - -struct pulse8 { - struct device *dev; - struct serio *serio; - struct cec_adapter *adap; - unsigned int vers; - struct completion cmd_done; - struct work_struct work; - struct delayed_work ping_eeprom_work; - struct cec_msg rx_msg; - u8 data[DATA_SIZE]; - unsigned int len; - u8 buf[DATA_SIZE]; - unsigned int idx; - bool escape; - bool started; - struct mutex config_lock; - struct mutex write_lock; - bool config_pending; - bool restoring_config; - bool autonomous; -}; - -static void pulse8_ping_eeprom_work_handler(struct work_struct *work); - -static void pulse8_irq_work_handler(struct work_struct *work) -{ - struct pulse8 *pulse8 = - container_of(work, struct pulse8, work); - - switch (pulse8->data[0] & 0x3f) { - case MSGCODE_FRAME_DATA: - cec_received_msg(pulse8->adap, &pulse8->rx_msg); - break; - case MSGCODE_TRANSMIT_SUCCEEDED: - cec_transmit_done(pulse8->adap, CEC_TX_STATUS_OK, - 0, 0, 0, 0); - break; - case MSGCODE_TRANSMIT_FAILED_ACK: - cec_transmit_done(pulse8->adap, CEC_TX_STATUS_NACK, - 0, 1, 0, 0); - break; - case MSGCODE_TRANSMIT_FAILED_LINE: - case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA: - case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE: - cec_transmit_done(pulse8->adap, CEC_TX_STATUS_ERROR, - 0, 0, 0, 1); - break; - } -} - -static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data, - unsigned int flags) -{ - struct pulse8 *pulse8 = serio_get_drvdata(serio); - - if (!pulse8->started && data != MSGSTART) - return IRQ_HANDLED; - if (data == MSGESC) { - pulse8->escape = true; - return IRQ_HANDLED; - } - if (pulse8->escape) { - data += MSGOFFSET; - pulse8->escape = false; - } else if (data == MSGEND) { - struct cec_msg *msg = &pulse8->rx_msg; - - if (debug) - dev_info(pulse8->dev, "received: %*ph\n", - pulse8->idx, pulse8->buf); - pulse8->data[0] = pulse8->buf[0]; - switch (pulse8->buf[0] & 0x3f) { - case MSGCODE_FRAME_START: - msg->len = 1; - msg->msg[0] = pulse8->buf[1]; - break; - case MSGCODE_FRAME_DATA: - if (msg->len == CEC_MAX_MSG_SIZE) - break; - msg->msg[msg->len++] = pulse8->buf[1]; - if (pulse8->buf[0] & MSGCODE_FRAME_EOM) - schedule_work(&pulse8->work); - break; - case MSGCODE_TRANSMIT_SUCCEEDED: - case MSGCODE_TRANSMIT_FAILED_LINE: - case MSGCODE_TRANSMIT_FAILED_ACK: - case MSGCODE_TRANSMIT_FAILED_TIMEOUT_DATA: - case MSGCODE_TRANSMIT_FAILED_TIMEOUT_LINE: - schedule_work(&pulse8->work); - break; - case MSGCODE_HIGH_ERROR: - case MSGCODE_LOW_ERROR: - case MSGCODE_RECEIVE_FAILED: - case MSGCODE_TIMEOUT_ERROR: - break; - case MSGCODE_COMMAND_ACCEPTED: - case MSGCODE_COMMAND_REJECTED: - default: - if (pulse8->idx == 0) - break; - memcpy(pulse8->data, pulse8->buf, pulse8->idx); - pulse8->len = pulse8->idx; - complete(&pulse8->cmd_done); - break; - } - pulse8->idx = 0; - pulse8->started = false; - return IRQ_HANDLED; - } else if (data == MSGSTART) { - pulse8->idx = 0; - pulse8->started = true; - return IRQ_HANDLED; - } - - if (pulse8->idx >= DATA_SIZE) { - dev_dbg(pulse8->dev, - "throwing away %d bytes of garbage\n", pulse8->idx); - pulse8->idx = 0; - } - pulse8->buf[pulse8->idx++] = data; - return IRQ_HANDLED; -} - -static void pulse8_disconnect(struct serio *serio) -{ - struct pulse8 *pulse8 = serio_get_drvdata(serio); - - cec_unregister_adapter(pulse8->adap); - cancel_delayed_work_sync(&pulse8->ping_eeprom_work); - dev_info(&serio->dev, "disconnected\n"); - serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(pulse8); -} - -static int pulse8_send(struct serio *serio, const u8 *command, u8 cmd_len) -{ - int err = 0; - - err = serio_write(serio, MSGSTART); - if (err) - return err; - for (; !err && cmd_len; command++, cmd_len--) { - if (*command >= MSGESC) { - err = serio_write(serio, MSGESC); - if (!err) - err = serio_write(serio, *command - MSGOFFSET); - } else { - err = serio_write(serio, *command); - } - } - if (!err) - err = serio_write(serio, MSGEND); - - return err; -} - -static int pulse8_send_and_wait_once(struct pulse8 *pulse8, - const u8 *cmd, u8 cmd_len, - u8 response, u8 size) -{ - int err; - - /*dev_info(pulse8->dev, "transmit: %*ph\n", cmd_len, cmd);*/ - init_completion(&pulse8->cmd_done); - - err = pulse8_send(pulse8->serio, cmd, cmd_len); - if (err) - return err; - - if (!wait_for_completion_timeout(&pulse8->cmd_done, HZ)) - return -ETIMEDOUT; - if ((pulse8->data[0] & 0x3f) == MSGCODE_COMMAND_REJECTED && - cmd[0] != MSGCODE_SET_CONTROLLED && - cmd[0] != MSGCODE_SET_AUTO_ENABLED && - cmd[0] != MSGCODE_GET_BUILDDATE) - return -ENOTTY; - if (response && - ((pulse8->data[0] & 0x3f) != response || pulse8->len < size + 1)) { - dev_info(pulse8->dev, "transmit: failed %02x\n", - pulse8->data[0] & 0x3f); - return -EIO; - } - return 0; -} - -static int pulse8_send_and_wait(struct pulse8 *pulse8, - const u8 *cmd, u8 cmd_len, u8 response, u8 size) -{ - u8 cmd_sc[2]; - int err; - - mutex_lock(&pulse8->write_lock); - err = pulse8_send_and_wait_once(pulse8, cmd, cmd_len, response, size); - - if (err == -ENOTTY) { - cmd_sc[0] = MSGCODE_SET_CONTROLLED; - cmd_sc[1] = 1; - err = pulse8_send_and_wait_once(pulse8, cmd_sc, 2, - MSGCODE_COMMAND_ACCEPTED, 1); - if (err) - goto unlock; - err = pulse8_send_and_wait_once(pulse8, cmd, cmd_len, - response, size); - } - -unlock: - mutex_unlock(&pulse8->write_lock); - return err == -ENOTTY ? -EIO : err; -} - -static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio, - struct cec_log_addrs *log_addrs, u16 *pa) -{ - u8 *data = pulse8->data + 1; - u8 cmd[2]; - int err; - struct tm tm; - time_t date; - - pulse8->vers = 0; - - cmd[0] = MSGCODE_FIRMWARE_VERSION; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 2); - if (err) - return err; - pulse8->vers = (data[0] << 8) | data[1]; - dev_info(pulse8->dev, "Firmware version %04x\n", pulse8->vers); - if (pulse8->vers < 2) { - *pa = CEC_PHYS_ADDR_INVALID; - return 0; - } - - cmd[0] = MSGCODE_GET_BUILDDATE; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4); - if (err) - return err; - date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; - time_to_tm(date, 0, &tm); - dev_info(pulse8->dev, "Firmware build date %04ld.%02d.%02d %02d:%02d:%02d\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec); - - dev_dbg(pulse8->dev, "Persistent config:\n"); - cmd[0] = MSGCODE_GET_AUTO_ENABLED; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); - if (err) - return err; - pulse8->autonomous = data[0]; - dev_dbg(pulse8->dev, "Autonomous mode: %s", - data[0] ? "on" : "off"); - - cmd[0] = MSGCODE_GET_DEVICE_TYPE; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); - if (err) - return err; - log_addrs->primary_device_type[0] = data[0]; - dev_dbg(pulse8->dev, "Primary device type: %d\n", data[0]); - switch (log_addrs->primary_device_type[0]) { - case CEC_OP_PRIM_DEVTYPE_TV: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TV; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TV; - break; - case CEC_OP_PRIM_DEVTYPE_RECORD: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_RECORD; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_RECORD; - break; - case CEC_OP_PRIM_DEVTYPE_TUNER: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_TUNER; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_TUNER; - break; - case CEC_OP_PRIM_DEVTYPE_PLAYBACK: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_PLAYBACK; - break; - case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_PLAYBACK; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_AUDIOSYSTEM; - break; - case CEC_OP_PRIM_DEVTYPE_SWITCH: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; - break; - case CEC_OP_PRIM_DEVTYPE_PROCESSOR: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_SPECIFIC; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; - break; - default: - log_addrs->log_addr_type[0] = CEC_LOG_ADDR_TYPE_UNREGISTERED; - log_addrs->all_device_types[0] = CEC_OP_ALL_DEVTYPE_SWITCH; - dev_info(pulse8->dev, "Unknown Primary Device Type: %d\n", - log_addrs->primary_device_type[0]); - break; - } - - cmd[0] = MSGCODE_GET_LOGICAL_ADDRESS_MASK; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 2); - if (err) - return err; - log_addrs->log_addr_mask = (data[0] << 8) | data[1]; - dev_dbg(pulse8->dev, "Logical address ACK mask: %x\n", - log_addrs->log_addr_mask); - if (log_addrs->log_addr_mask) - log_addrs->num_log_addrs = 1; - - cmd[0] = MSGCODE_GET_PHYSICAL_ADDRESS; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); - if (err) - return err; - *pa = (data[0] << 8) | data[1]; - dev_dbg(pulse8->dev, "Physical address: %x.%x.%x.%x\n", - cec_phys_addr_exp(*pa)); - - cmd[0] = MSGCODE_GET_HDMI_VERSION; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 1); - if (err) - return err; - log_addrs->cec_version = data[0]; - dev_dbg(pulse8->dev, "CEC version: %d\n", log_addrs->cec_version); - - cmd[0] = MSGCODE_GET_OSD_NAME; - err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 0); - if (err) - return err; - strncpy(log_addrs->osd_name, data, 13); - dev_dbg(pulse8->dev, "OSD name: %s\n", log_addrs->osd_name); - - return 0; -} - -static int pulse8_apply_persistent_config(struct pulse8 *pulse8, - struct cec_log_addrs *log_addrs, - u16 pa) -{ - int err; - - err = cec_s_log_addrs(pulse8->adap, log_addrs, false); - if (err) - return err; - - cec_s_phys_addr(pulse8->adap, pa, false); - - return 0; -} - -static int pulse8_cec_adap_enable(struct cec_adapter *adap, bool enable) -{ - struct pulse8 *pulse8 = adap->priv; - u8 cmd[16]; - int err; - - cmd[0] = MSGCODE_SET_CONTROLLED; - cmd[1] = enable; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 1); - return enable ? err : 0; -} - -static int pulse8_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr) -{ - struct pulse8 *pulse8 = adap->priv; - u16 mask = 0; - u16 pa = adap->phys_addr; - u8 cmd[16]; - int err = 0; - - mutex_lock(&pulse8->config_lock); - if (log_addr != CEC_LOG_ADDR_INVALID) - mask = 1 << log_addr; - cmd[0] = MSGCODE_SET_ACK_MASK; - cmd[1] = mask >> 8; - cmd[2] = mask & 0xff; - err = pulse8_send_and_wait(pulse8, cmd, 3, - MSGCODE_COMMAND_ACCEPTED, 0); - if ((err && mask != 0) || pulse8->restoring_config) - goto unlock; - - cmd[0] = MSGCODE_SET_AUTO_ENABLED; - cmd[1] = log_addr == CEC_LOG_ADDR_INVALID ? 0 : 1; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 0); - if (err) - goto unlock; - pulse8->autonomous = cmd[1]; - if (log_addr == CEC_LOG_ADDR_INVALID) - goto unlock; - - cmd[0] = MSGCODE_SET_DEVICE_TYPE; - cmd[1] = adap->log_addrs.primary_device_type[0]; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 0); - if (err) - goto unlock; - - switch (adap->log_addrs.primary_device_type[0]) { - case CEC_OP_PRIM_DEVTYPE_TV: - mask = CEC_LOG_ADDR_MASK_TV; - break; - case CEC_OP_PRIM_DEVTYPE_RECORD: - mask = CEC_LOG_ADDR_MASK_RECORD; - break; - case CEC_OP_PRIM_DEVTYPE_TUNER: - mask = CEC_LOG_ADDR_MASK_TUNER; - break; - case CEC_OP_PRIM_DEVTYPE_PLAYBACK: - mask = CEC_LOG_ADDR_MASK_PLAYBACK; - break; - case CEC_OP_PRIM_DEVTYPE_AUDIOSYSTEM: - mask = CEC_LOG_ADDR_MASK_AUDIOSYSTEM; - break; - case CEC_OP_PRIM_DEVTYPE_SWITCH: - mask = CEC_LOG_ADDR_MASK_UNREGISTERED; - break; - case CEC_OP_PRIM_DEVTYPE_PROCESSOR: - mask = CEC_LOG_ADDR_MASK_SPECIFIC; - break; - default: - mask = 0; - break; - } - cmd[0] = MSGCODE_SET_LOGICAL_ADDRESS_MASK; - cmd[1] = mask >> 8; - cmd[2] = mask & 0xff; - err = pulse8_send_and_wait(pulse8, cmd, 3, - MSGCODE_COMMAND_ACCEPTED, 0); - if (err) - goto unlock; - - cmd[0] = MSGCODE_SET_DEFAULT_LOGICAL_ADDRESS; - cmd[1] = log_addr; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 0); - if (err) - goto unlock; - - cmd[0] = MSGCODE_SET_PHYSICAL_ADDRESS; - cmd[1] = pa >> 8; - cmd[2] = pa & 0xff; - err = pulse8_send_and_wait(pulse8, cmd, 3, - MSGCODE_COMMAND_ACCEPTED, 0); - if (err) - goto unlock; - - cmd[0] = MSGCODE_SET_HDMI_VERSION; - cmd[1] = adap->log_addrs.cec_version; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 0); - if (err) - goto unlock; - - if (adap->log_addrs.osd_name[0]) { - size_t osd_len = strlen(adap->log_addrs.osd_name); - char *osd_str = cmd + 1; - - cmd[0] = MSGCODE_SET_OSD_NAME; - strncpy(cmd + 1, adap->log_addrs.osd_name, 13); - if (osd_len < 4) { - memset(osd_str + osd_len, ' ', 4 - osd_len); - osd_len = 4; - osd_str[osd_len] = '\0'; - strcpy(adap->log_addrs.osd_name, osd_str); - } - err = pulse8_send_and_wait(pulse8, cmd, 1 + osd_len, - MSGCODE_COMMAND_ACCEPTED, 0); - if (err) - goto unlock; - } - -unlock: - if (pulse8->restoring_config) - pulse8->restoring_config = false; - else - pulse8->config_pending = true; - mutex_unlock(&pulse8->config_lock); - return err; -} - -static int pulse8_cec_adap_transmit(struct cec_adapter *adap, u8 attempts, - u32 signal_free_time, struct cec_msg *msg) -{ - struct pulse8 *pulse8 = adap->priv; - u8 cmd[2]; - unsigned int i; - int err; - - cmd[0] = MSGCODE_TRANSMIT_IDLETIME; - cmd[1] = signal_free_time; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 1); - cmd[0] = MSGCODE_TRANSMIT_ACK_POLARITY; - cmd[1] = cec_msg_is_broadcast(msg); - if (!err) - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 1); - cmd[0] = msg->len == 1 ? MSGCODE_TRANSMIT_EOM : MSGCODE_TRANSMIT; - cmd[1] = msg->msg[0]; - if (!err) - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 1); - if (!err && msg->len > 1) { - cmd[0] = msg->len == 2 ? MSGCODE_TRANSMIT_EOM : - MSGCODE_TRANSMIT; - cmd[1] = msg->msg[1]; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 1); - for (i = 0; !err && i + 2 < msg->len; i++) { - cmd[0] = (i + 2 == msg->len - 1) ? - MSGCODE_TRANSMIT_EOM : MSGCODE_TRANSMIT; - cmd[1] = msg->msg[i + 2]; - err = pulse8_send_and_wait(pulse8, cmd, 2, - MSGCODE_COMMAND_ACCEPTED, 1); - } - } - - return err; -} - -static int pulse8_received(struct cec_adapter *adap, struct cec_msg *msg) -{ - return -ENOMSG; -} - -static const struct cec_adap_ops pulse8_cec_adap_ops = { - .adap_enable = pulse8_cec_adap_enable, - .adap_log_addr = pulse8_cec_adap_log_addr, - .adap_transmit = pulse8_cec_adap_transmit, - .received = pulse8_received, -}; - -static int pulse8_connect(struct serio *serio, struct serio_driver *drv) -{ - u32 caps = CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PHYS_ADDR | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC | CEC_CAP_MONITOR_ALL; - struct pulse8 *pulse8; - int err = -ENOMEM; - struct cec_log_addrs log_addrs = {}; - u16 pa = CEC_PHYS_ADDR_INVALID; - - pulse8 = kzalloc(sizeof(*pulse8), GFP_KERNEL); - - if (!pulse8) - return -ENOMEM; - - pulse8->serio = serio; - pulse8->adap = cec_allocate_adapter(&pulse8_cec_adap_ops, pulse8, - "HDMI CEC", caps, 1, &serio->dev); - err = PTR_ERR_OR_ZERO(pulse8->adap); - if (err < 0) - goto free_device; - - pulse8->dev = &serio->dev; - serio_set_drvdata(serio, pulse8); - INIT_WORK(&pulse8->work, pulse8_irq_work_handler); - mutex_init(&pulse8->write_lock); - mutex_init(&pulse8->config_lock); - pulse8->config_pending = false; - - err = serio_open(serio, drv); - if (err) - goto delete_adap; - - err = pulse8_setup(pulse8, serio, &log_addrs, &pa); - if (err) - goto close_serio; - - err = cec_register_adapter(pulse8->adap); - if (err < 0) - goto close_serio; - - pulse8->dev = &pulse8->adap->devnode.dev; - - if (persistent_config && pulse8->autonomous) { - err = pulse8_apply_persistent_config(pulse8, &log_addrs, pa); - if (err) - goto close_serio; - pulse8->restoring_config = true; - } - - INIT_DELAYED_WORK(&pulse8->ping_eeprom_work, - pulse8_ping_eeprom_work_handler); - schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD); - - return 0; - -close_serio: - serio_close(serio); -delete_adap: - cec_delete_adapter(pulse8->adap); - serio_set_drvdata(serio, NULL); -free_device: - kfree(pulse8); - return err; -} - -static void pulse8_ping_eeprom_work_handler(struct work_struct *work) -{ - struct pulse8 *pulse8 = - container_of(work, struct pulse8, ping_eeprom_work.work); - u8 cmd; - - schedule_delayed_work(&pulse8->ping_eeprom_work, PING_PERIOD); - cmd = MSGCODE_PING; - pulse8_send_and_wait(pulse8, &cmd, 1, - MSGCODE_COMMAND_ACCEPTED, 0); - - if (pulse8->vers < 2) - return; - - mutex_lock(&pulse8->config_lock); - if (pulse8->config_pending && persistent_config) { - dev_dbg(pulse8->dev, "writing pending config to EEPROM\n"); - cmd = MSGCODE_WRITE_EEPROM; - if (pulse8_send_and_wait(pulse8, &cmd, 1, - MSGCODE_COMMAND_ACCEPTED, 0)) - dev_info(pulse8->dev, "failed to write pending config to EEPROM\n"); - else - pulse8->config_pending = false; - } - mutex_unlock(&pulse8->config_lock); -} - -static struct serio_device_id pulse8_serio_ids[] = { - { - .type = SERIO_RS232, - .proto = SERIO_PULSE8_CEC, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { 0 } -}; - -MODULE_DEVICE_TABLE(serio, pulse8_serio_ids); - -static struct serio_driver pulse8_drv = { - .driver = { - .name = "pulse8-cec", - }, - .description = "Pulse Eight HDMI CEC driver", - .id_table = pulse8_serio_ids, - .interrupt = pulse8_interrupt, - .connect = pulse8_connect, - .disconnect = pulse8_disconnect, -}; - -module_serio_driver(pulse8_drv); -- cgit v1.2.3 From 764040c49cbb58857815b0ebaae97273faad3143 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 2 Nov 2016 08:37:15 -0200 Subject: [media] s5p-cec/st-cec: update TODOs Update the TODOs explaining why these two drivers remain in staging. The reason is that these drivers rely on userspace to set the physical address, but that should come from the HDMI output driver. This in turn needs the upcoming HDMI notifier framework. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/s5p-cec/TODO | 12 ++++++------ drivers/staging/media/st-cec/TODO | 7 +++++++ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 drivers/staging/media/st-cec/TODO (limited to 'drivers') diff --git a/drivers/staging/media/s5p-cec/TODO b/drivers/staging/media/s5p-cec/TODO index f51d5268ac40..64f21bab38f5 100644 --- a/drivers/staging/media/s5p-cec/TODO +++ b/drivers/staging/media/s5p-cec/TODO @@ -1,7 +1,7 @@ -This driver depends on the CEC framework, which is currently in -staging, so therefor this driver is in staging as well. +This driver requires that userspace sets the physical address. +However, this should be passed on from the corresponding +Samsung HDMI driver. -In addition, this driver requires that userspace sets the physical -address. However, this should be passed on from the corresponding -samsung HDMI driver. It is very annoying if userspace has to do this, -and other than USB CEC adapters this must be handled automatically. +We have to wait until the HDMI notifier framework has been merged +in order to handle this gracefully, until that time this driver +has to remain in staging. diff --git a/drivers/staging/media/st-cec/TODO b/drivers/staging/media/st-cec/TODO new file mode 100644 index 000000000000..c61289742c5c --- /dev/null +++ b/drivers/staging/media/st-cec/TODO @@ -0,0 +1,7 @@ +This driver requires that userspace sets the physical address. +However, this should be passed on from the corresponding +ST HDMI driver. + +We have to wait until the HDMI notifier framework has been merged +in order to handle this gracefully, until that time this driver +has to remain in staging. -- cgit v1.2.3 From 8991a63d1a8a01938932319c8b98f5a3420a0bb2 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Wed, 9 Nov 2016 12:10:59 -0200 Subject: [media] cec: zero counters in cec_received_msg() Make sure the TX counters are zeroed in the cec_msg struct. Non-zero TX counters make no sense when a message is received, and applications should not see non-zero values here. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index ed76d7050b8a..d9c6f2c1c6fa 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -874,6 +874,10 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) msg->sequence = msg->reply = msg->timeout = 0; msg->tx_status = 0; msg->tx_ts = 0; + msg->tx_arb_lost_cnt = 0; + msg->tx_nack_cnt = 0; + msg->tx_low_drive_cnt = 0; + msg->tx_error_cnt = 0; msg->flags = 0; memset(msg->msg + msg->len, 0, sizeof(msg->msg) - msg->len); -- cgit v1.2.3 From 03c47aaeffec8e91ff4207d4814061a24fe51afb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Mon, 7 Nov 2016 18:15:47 -0200 Subject: [media] uvcvideo: add support for Oculus Rift Sensor The Rift CV1 Sensor has bInterfaceClass set to vendor specific, so we need an entry in uvc_ids to probe it. Just as the Rift DK2 IR tracker, it misreports the pixel format as YUYV instead of Y8. The sensor is configured with a low exposure time and high black level by default, so that only bright IR sources can be seen. Signed-off-by: Philipp Zabel Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 87b2fc3b0ac2..11744f92097b 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -2670,6 +2670,15 @@ static struct usb_device_id uvc_ids[] = { .bInterfaceSubClass = 1, .bInterfaceProtocol = 0, .driver_info = UVC_QUIRK_FORCE_Y8 }, + /* Oculus VR Rift Sensor */ + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE + | USB_DEVICE_ID_MATCH_INT_INFO, + .idVendor = 0x2833, + .idProduct = 0x0211, + .bInterfaceClass = USB_CLASS_VENDOR_SPEC, + .bInterfaceSubClass = 1, + .bInterfaceProtocol = 0, + .driver_info = UVC_QUIRK_FORCE_Y8 }, /* Generic USB Video Class */ { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) }, { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) }, -- cgit v1.2.3 From 04b96d1a6954309eb562ef2736c019b3cf2dad2a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 29 Sep 2016 05:41:24 -0300 Subject: [media] v4l: omap3isp: Fix OF node double put when parsing OF graph When parsing the graph the driver loops over all endpoints using of_graph_get_next_endpoint(). The function handles reference counting of the passed and returned nodes, so the returned node's reference count must not be decreased manually in the normal path. Move the offending of_node_put() call to the error path that requires manual reference count handling. Reported-by: H. Nikolaus Schaller Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isp.c | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c index 2e1b17ef82a3..084ecf4aa9a4 100644 --- a/drivers/media/platform/omap3isp/isp.c +++ b/drivers/media/platform/omap3isp/isp.c @@ -2117,23 +2117,18 @@ static int isp_of_parse_nodes(struct device *dev, struct isp_async_subdev *isd; isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL); - if (!isd) { - of_node_put(node); - return -ENOMEM; - } + if (!isd) + goto error; notifier->subdevs[notifier->num_subdevs] = &isd->asd; - if (isp_of_parse_node(dev, node, isd)) { - of_node_put(node); - return -EINVAL; - } + if (isp_of_parse_node(dev, node, isd)) + goto error; isd->asd.match.of.node = of_graph_get_remote_port_parent(node); - of_node_put(node); if (!isd->asd.match.of.node) { dev_warn(dev, "bad remote port parent\n"); - return -EINVAL; + goto error; } isd->asd.match_type = V4L2_ASYNC_MATCH_OF; @@ -2141,6 +2136,10 @@ static int isp_of_parse_nodes(struct device *dev, } return notifier->num_subdevs; + +error: + of_node_put(node); + return -EINVAL; } static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async, -- cgit v1.2.3 From a9943f6b6b77cf974d8d602be9cc92863e46b5f4 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Fri, 4 Nov 2016 05:58:02 -0200 Subject: [media] v4l: omap3isp: Use dma_request_chan_by_mask() to request the DMA channel When requesting the DMA channel it was mandatory that we do not have DMA resource nor valid DMA channel via DT. In this case the dma_request_slave_channel_compat() would fall back and request any channel with SW trigger. The same can be achieved with the dma_request_chan_by_mask() without the misleading use of the DMAengine API - implying that the omap3isp does need to have DMA resource or valid dma binding in DT. Signed-off-by: Peter Ujfalusi Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/omap3isp/isphist.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/omap3isp/isphist.c b/drivers/media/platform/omap3isp/isphist.c index 7138b043a4aa..a4ed5d140d48 100644 --- a/drivers/media/platform/omap3isp/isphist.c +++ b/drivers/media/platform/omap3isp/isphist.c @@ -18,7 +18,6 @@ #include #include #include -#include #include #include @@ -486,27 +485,30 @@ int omap3isp_hist_init(struct isp_device *isp) hist->isp = isp; if (HIST_CONFIG_DMA) { - struct platform_device *pdev = to_platform_device(isp->dev); - struct resource *res; - unsigned int sig = 0; dma_cap_mask_t mask; + /* + * We need slave capable channel without DMA request line for + * reading out the data. + * For this we can use dma_request_chan_by_mask() as we are + * happy with any channel as long as it is capable of slave + * configuration. + */ dma_cap_zero(mask); dma_cap_set(DMA_SLAVE, mask); + hist->dma_ch = dma_request_chan_by_mask(&mask); + if (IS_ERR(hist->dma_ch)) { + ret = PTR_ERR(hist->dma_ch); + if (ret == -EPROBE_DEFER) + return ret; - res = platform_get_resource_byname(pdev, IORESOURCE_DMA, - "hist"); - if (res) - sig = res->start; - - hist->dma_ch = dma_request_slave_channel_compat(mask, - omap_dma_filter_fn, &sig, isp->dev, "hist"); - if (!hist->dma_ch) + hist->dma_ch = NULL; dev_warn(isp->dev, "hist: DMA channel request failed, using PIO\n"); - else + } else { dev_dbg(isp->dev, "hist: using DMA channel %s\n", dma_chan_name(hist->dma_ch)); + } } hist->ops = &hist_ops; -- cgit v1.2.3 From 446e412597217e937d33296e77eeba7379ab3008 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 4 Aug 2016 13:14:02 -0300 Subject: [media] v4l: ctrls: Add deinterlacing mode control The menu control selects the operation mode of a video deinterlacer. The menu entries are driver specific. Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Acked-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/v4l/extended-controls.rst | 4 ++++ Documentation/media/v4l-drivers/index.rst | 2 ++ drivers/media/v4l2-core/v4l2-ctrls.c | 2 ++ include/uapi/linux/v4l2-controls.h | 1 + 4 files changed, 9 insertions(+) (limited to 'drivers') diff --git a/Documentation/media/uapi/v4l/extended-controls.rst b/Documentation/media/uapi/v4l/extended-controls.rst index 7725c33d8b69..40071ea5d90e 100644 --- a/Documentation/media/uapi/v4l/extended-controls.rst +++ b/Documentation/media/uapi/v4l/extended-controls.rst @@ -3017,6 +3017,10 @@ Image Process Control IDs test pattern images. These hardware specific test patterns can be used to test if a device is working properly. +``V4L2_CID_DEINTERLACING_MODE (menu)`` + The video deinterlacing mode (such as Bob, Weave, ...). The menu items are + driver specific and are documented in :ref:`v4l-drivers`. + .. _dv-controls: diff --git a/Documentation/media/v4l-drivers/index.rst b/Documentation/media/v4l-drivers/index.rst index aac566f88833..acde3ed7860f 100644 --- a/Documentation/media/v4l-drivers/index.rst +++ b/Documentation/media/v4l-drivers/index.rst @@ -2,6 +2,8 @@ .. include:: +.. _v4l-drivers: + ################################################ Video4Linux (V4L) driver-specific documentation ################################################ diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index adc2147fcff7..47001e25fd9e 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -885,6 +885,7 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_LINK_FREQ: return "Link Frequency"; case V4L2_CID_PIXEL_RATE: return "Pixel Rate"; case V4L2_CID_TEST_PATTERN: return "Test Pattern"; + case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode"; /* DV controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1058,6 +1059,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_DV_RX_RGB_RANGE: case V4L2_CID_DV_RX_IT_CONTENT_TYPE: case V4L2_CID_TEST_PATTERN: + case V4L2_CID_DEINTERLACING_MODE: case V4L2_CID_TUNE_DEEMPHASIS: case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL: case V4L2_CID_DETECT_MD_MODE: diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index b6a357a5f053..0d2e1e01fbd5 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -892,6 +892,7 @@ enum v4l2_jpeg_chroma_subsampling { #define V4L2_CID_LINK_FREQ (V4L2_CID_IMAGE_PROC_CLASS_BASE + 1) #define V4L2_CID_PIXEL_RATE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 2) #define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3) +#define V4L2_CID_DEINTERLACING_MODE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 4) /* DV-class control IDs defined by V4L2 */ -- cgit v1.2.3 From 4710b752e029f3f82dd4a84d9dc61fe72c97bf82 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Thu, 30 Jun 2016 10:41:23 -0300 Subject: [media] v4l: Add Renesas R-Car FDP1 Driver The FDP1 driver performs advanced de-interlacing on a memory 2 memory based video stream, and supports conversion from YCbCr/YUV to RGB pixel formats Signed-off-by: Kieran Bingham Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/v4l-drivers/index.rst | 1 + Documentation/media/v4l-drivers/rcar-fdp1.rst | 37 + MAINTAINERS | 9 + drivers/media/platform/Kconfig | 13 + drivers/media/platform/Makefile | 1 + drivers/media/platform/rcar_fdp1.c | 2445 +++++++++++++++++++++++++ 6 files changed, 2506 insertions(+) create mode 100644 Documentation/media/v4l-drivers/rcar-fdp1.rst create mode 100644 drivers/media/platform/rcar_fdp1.c (limited to 'drivers') diff --git a/Documentation/media/v4l-drivers/index.rst b/Documentation/media/v4l-drivers/index.rst index acde3ed7860f..a606d1cdac13 100644 --- a/Documentation/media/v4l-drivers/index.rst +++ b/Documentation/media/v4l-drivers/index.rst @@ -48,6 +48,7 @@ For more details see the file COPYING in the source distribution of Linux. pvrusb2 pxa_camera radiotrack + rcar-fdp1 saa7134 sh_mobile_ceu_camera si470x diff --git a/Documentation/media/v4l-drivers/rcar-fdp1.rst b/Documentation/media/v4l-drivers/rcar-fdp1.rst new file mode 100644 index 000000000000..a59b1e8e3e9c --- /dev/null +++ b/Documentation/media/v4l-drivers/rcar-fdp1.rst @@ -0,0 +1,37 @@ +Renesas R-Car Fine Display Processor (FDP1) Driver +================================================== + +The R-Car FDP1 driver implements driver-specific controls as follows. + +``V4L2_CID_DEINTERLACING_MODE (menu)`` + The video deinterlacing mode (such as Bob, Weave, ...). The R-Car FDP1 + driver implements the following modes. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + :widths: 1 4 + + * - ``"Progressive" (0)`` + - The input image video stream is progressive (not interlaced). No + deinterlacing is performed. Apart from (optional) format and encoding + conversion output frames are identical to the input frames. + * - ``"Adaptive 2D/3D" (1)`` + - Motion adaptive version of 2D and 3D deinterlacing. Use 3D deinterlacing + in the presence of fast motion and 2D deinterlacing with diagonal + interpolation otherwise. + * - ``"Fixed 2D" (2)`` + - The current field is scaled vertically by averaging adjacent lines to + recover missing lines. This method is also known as blending or Line + Averaging (LAV). + * - ``"Fixed 3D" (3)`` + - The previous and next fields are averaged to recover lines missing from + the current field. This method is also known as Field Averaging (FAV). + * - ``"Previous field" (4)`` + - The current field is weaved with the previous field, i.e. the previous + field is used to fill missing lines from the current field. This method + is also known as weave deinterlacing. + * - ``"Next field" (5)`` + - The current field is weaved with the next field, i.e. the next field is + used to fill missing lines from the current field. This method is also + known as weave deinterlacing. diff --git a/MAINTAINERS b/MAINTAINERS index 5106590190f5..78ec26e84c5b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7712,6 +7712,15 @@ F: Documentation/devicetree/bindings/media/renesas,fcp.txt F: drivers/media/platform/rcar-fcp.c F: include/media/rcar-fcp.h +MEDIA DRIVERS FOR RENESAS - FDP1 +M: Kieran Bingham +L: linux-media@vger.kernel.org +L: linux-renesas-soc@vger.kernel.org +T: git git://linuxtv.org/media_tree.git +S: Supported +F: Documentation/devicetree/bindings/media/renesas,fdp1.txt +F: drivers/media/platform/rcar_fdp1.c + MEDIA DRIVERS FOR RENESAS - VIN M: Niklas Söderlund L: linux-media@vger.kernel.org diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 754edbf1a326..84f44098dc99 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -307,6 +307,19 @@ config VIDEO_SH_VEU Support for the Video Engine Unit (VEU) on SuperH and SH-Mobile SoCs. +config VIDEO_RENESAS_FDP1 + tristate "Renesas Fine Display Processor" + depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA + depends on ARCH_SHMOBILE || COMPILE_TEST + select VIDEOBUF2_DMA_CONTIG + select V4L2_MEM2MEM_DEV + ---help--- + This is a V4L2 driver for the Renesas Fine Display Processor + providing colour space conversion, and de-interlacing features. + + To compile this driver as a module, choose M here: the module + will be called rcar_fdp1. + config VIDEO_RENESAS_JPU tristate "Renesas JPEG Processing Unit" depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile index f842933d17de..5b3cb271d2b8 100644 --- a/drivers/media/platform/Makefile +++ b/drivers/media/platform/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o obj-$(CONFIG_SOC_CAMERA) += soc_camera/ obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o +obj-$(CONFIG_VIDEO_RENESAS_FDP1) += rcar_fdp1.o obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c new file mode 100644 index 000000000000..dd1a6ea17f22 --- /dev/null +++ b/drivers/media/platform/rcar_fdp1.c @@ -0,0 +1,2445 @@ +/* + * Renesas RCar Fine Display Processor + * + * Video format converter and frame deinterlacer device. + * + * Author: Kieran Bingham, + * Copyright (c) 2016 Renesas Electronics Corporation. + * + * This code is developed and inspired from the vim2m, rcar_jpu, + * m2m-deinterlace, and vsp1 drivers. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the + * License, or (at your option) any later version + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned int debug; +module_param(debug, uint, 0644); +MODULE_PARM_DESC(debug, "activate debug info"); + +/* Minimum and maximum frame width/height */ +#define FDP1_MIN_W 80U +#define FDP1_MIN_H 80U + +#define FDP1_MAX_W 3840U +#define FDP1_MAX_H 2160U + +#define FDP1_MAX_PLANES 3U +#define FDP1_MAX_STRIDE 8190U + +/* Flags that indicate a format can be used for capture/output */ +#define FDP1_CAPTURE BIT(0) +#define FDP1_OUTPUT BIT(1) + +#define DRIVER_NAME "rcar_fdp1" + +/* Number of Job's to have available on the processing queue */ +#define FDP1_NUMBER_JOBS 8 + +#define dprintk(fdp1, fmt, arg...) \ + v4l2_dbg(1, debug, &fdp1->v4l2_dev, "%s: " fmt, __func__, ## arg) + +/* + * FDP1 registers and bits + */ + +/* FDP1 start register - Imm */ +#define FD1_CTL_CMD 0x0000 +#define FD1_CTL_CMD_STRCMD BIT(0) + +/* Sync generator register - Imm */ +#define FD1_CTL_SGCMD 0x0004 +#define FD1_CTL_SGCMD_SGEN BIT(0) + +/* Register set end register - Imm */ +#define FD1_CTL_REGEND 0x0008 +#define FD1_CTL_REGEND_REGEND BIT(0) + +/* Channel activation register - Vupdt */ +#define FD1_CTL_CHACT 0x000c +#define FD1_CTL_CHACT_SMW BIT(9) +#define FD1_CTL_CHACT_WR BIT(8) +#define FD1_CTL_CHACT_SMR BIT(3) +#define FD1_CTL_CHACT_RD2 BIT(2) +#define FD1_CTL_CHACT_RD1 BIT(1) +#define FD1_CTL_CHACT_RD0 BIT(0) + +/* Operation Mode Register - Vupdt */ +#define FD1_CTL_OPMODE 0x0010 +#define FD1_CTL_OPMODE_PRG BIT(4) +#define FD1_CTL_OPMODE_VIMD_INTERRUPT (0 << 0) +#define FD1_CTL_OPMODE_VIMD_BESTEFFORT (1 << 0) +#define FD1_CTL_OPMODE_VIMD_NOINTERRUPT (2 << 0) + +#define FD1_CTL_VPERIOD 0x0014 +#define FD1_CTL_CLKCTRL 0x0018 +#define FD1_CTL_CLKCTRL_CSTP_N BIT(0) + +/* Software reset register */ +#define FD1_CTL_SRESET 0x001c +#define FD1_CTL_SRESET_SRST BIT(0) + +/* Control status register (V-update-status) */ +#define FD1_CTL_STATUS 0x0024 +#define FD1_CTL_STATUS_VINT_CNT_MASK GENMASK(31, 16) +#define FD1_CTL_STATUS_VINT_CNT_SHIFT 16 +#define FD1_CTL_STATUS_SGREGSET BIT(10) +#define FD1_CTL_STATUS_SGVERR BIT(9) +#define FD1_CTL_STATUS_SGFREND BIT(8) +#define FD1_CTL_STATUS_BSY BIT(0) + +#define FD1_CTL_VCYCLE_STAT 0x0028 + +/* Interrupt enable register */ +#define FD1_CTL_IRQENB 0x0038 +/* Interrupt status register */ +#define FD1_CTL_IRQSTA 0x003c +/* Interrupt control register */ +#define FD1_CTL_IRQFSET 0x0040 + +/* Common IRQ Bit settings */ +#define FD1_CTL_IRQ_VERE BIT(16) +#define FD1_CTL_IRQ_VINTE BIT(4) +#define FD1_CTL_IRQ_FREE BIT(0) +#define FD1_CTL_IRQ_MASK (FD1_CTL_IRQ_VERE | \ + FD1_CTL_IRQ_VINTE | \ + FD1_CTL_IRQ_FREE) + +/* RPF */ +#define FD1_RPF_SIZE 0x0060 +#define FD1_RPF_SIZE_MASK GENMASK(12, 0) +#define FD1_RPF_SIZE_H_SHIFT 16 +#define FD1_RPF_SIZE_V_SHIFT 0 + +#define FD1_RPF_FORMAT 0x0064 +#define FD1_RPF_FORMAT_CIPM BIT(16) +#define FD1_RPF_FORMAT_RSPYCS BIT(13) +#define FD1_RPF_FORMAT_RSPUVS BIT(12) +#define FD1_RPF_FORMAT_CF BIT(8) + +#define FD1_RPF_PSTRIDE 0x0068 +#define FD1_RPF_PSTRIDE_Y_SHIFT 16 +#define FD1_RPF_PSTRIDE_C_SHIFT 0 + +/* RPF0 Source Component Y Address register */ +#define FD1_RPF0_ADDR_Y 0x006c + +/* RPF1 Current Picture Registers */ +#define FD1_RPF1_ADDR_Y 0x0078 +#define FD1_RPF1_ADDR_C0 0x007c +#define FD1_RPF1_ADDR_C1 0x0080 + +/* RPF2 next picture register */ +#define FD1_RPF2_ADDR_Y 0x0084 + +#define FD1_RPF_SMSK_ADDR 0x0090 +#define FD1_RPF_SWAP 0x0094 + +/* WPF */ +#define FD1_WPF_FORMAT 0x00c0 +#define FD1_WPF_FORMAT_PDV_SHIFT 24 +#define FD1_WPF_FORMAT_FCNL BIT(20) +#define FD1_WPF_FORMAT_WSPYCS BIT(15) +#define FD1_WPF_FORMAT_WSPUVS BIT(14) +#define FD1_WPF_FORMAT_WRTM_601_16 (0 << 9) +#define FD1_WPF_FORMAT_WRTM_601_0 (1 << 9) +#define FD1_WPF_FORMAT_WRTM_709_16 (2 << 9) +#define FD1_WPF_FORMAT_CSC BIT(8) + +#define FD1_WPF_RNDCTL 0x00c4 +#define FD1_WPF_RNDCTL_CBRM BIT(28) +#define FD1_WPF_RNDCTL_CLMD_NOCLIP (0 << 12) +#define FD1_WPF_RNDCTL_CLMD_CLIP_16_235 (1 << 12) +#define FD1_WPF_RNDCTL_CLMD_CLIP_1_254 (2 << 12) + +#define FD1_WPF_PSTRIDE 0x00c8 +#define FD1_WPF_PSTRIDE_Y_SHIFT 16 +#define FD1_WPF_PSTRIDE_C_SHIFT 0 + +/* WPF Destination picture */ +#define FD1_WPF_ADDR_Y 0x00cc +#define FD1_WPF_ADDR_C0 0x00d0 +#define FD1_WPF_ADDR_C1 0x00d4 +#define FD1_WPF_SWAP 0x00d8 +#define FD1_WPF_SWAP_OSWAP_SHIFT 0 +#define FD1_WPF_SWAP_SSWAP_SHIFT 4 + +/* WPF/RPF Common */ +#define FD1_RWPF_SWAP_BYTE BIT(0) +#define FD1_RWPF_SWAP_WORD BIT(1) +#define FD1_RWPF_SWAP_LWRD BIT(2) +#define FD1_RWPF_SWAP_LLWD BIT(3) + +/* IPC */ +#define FD1_IPC_MODE 0x0100 +#define FD1_IPC_MODE_DLI BIT(8) +#define FD1_IPC_MODE_DIM_ADAPT2D3D (0 << 0) +#define FD1_IPC_MODE_DIM_FIXED2D (1 << 0) +#define FD1_IPC_MODE_DIM_FIXED3D (2 << 0) +#define FD1_IPC_MODE_DIM_PREVFIELD (3 << 0) +#define FD1_IPC_MODE_DIM_NEXTFIELD (4 << 0) + +#define FD1_IPC_SMSK_THRESH 0x0104 +#define FD1_IPC_SMSK_THRESH_CONST 0x00010002 + +#define FD1_IPC_COMB_DET 0x0108 +#define FD1_IPC_COMB_DET_CONST 0x00200040 + +#define FD1_IPC_MOTDEC 0x010c +#define FD1_IPC_MOTDEC_CONST 0x00008020 + +/* DLI registers */ +#define FD1_IPC_DLI_BLEND 0x0120 +#define FD1_IPC_DLI_BLEND_CONST 0x0080ff02 + +#define FD1_IPC_DLI_HGAIN 0x0124 +#define FD1_IPC_DLI_HGAIN_CONST 0x001000ff + +#define FD1_IPC_DLI_SPRS 0x0128 +#define FD1_IPC_DLI_SPRS_CONST 0x009004ff + +#define FD1_IPC_DLI_ANGLE 0x012c +#define FD1_IPC_DLI_ANGLE_CONST 0x0004080c + +#define FD1_IPC_DLI_ISOPIX0 0x0130 +#define FD1_IPC_DLI_ISOPIX0_CONST 0xff10ff10 + +#define FD1_IPC_DLI_ISOPIX1 0x0134 +#define FD1_IPC_DLI_ISOPIX1_CONST 0x0000ff10 + +/* Sensor registers */ +#define FD1_IPC_SENSOR_TH0 0x0140 +#define FD1_IPC_SENSOR_TH0_CONST 0x20208080 + +#define FD1_IPC_SENSOR_TH1 0x0144 +#define FD1_IPC_SENSOR_TH1_CONST 0 + +#define FD1_IPC_SENSOR_CTL0 0x0170 +#define FD1_IPC_SENSOR_CTL0_CONST 0x00002201 + +#define FD1_IPC_SENSOR_CTL1 0x0174 +#define FD1_IPC_SENSOR_CTL1_CONST 0 + +#define FD1_IPC_SENSOR_CTL2 0x0178 +#define FD1_IPC_SENSOR_CTL2_X_SHIFT 16 +#define FD1_IPC_SENSOR_CTL2_Y_SHIFT 0 + +#define FD1_IPC_SENSOR_CTL3 0x017c +#define FD1_IPC_SENSOR_CTL3_0_SHIFT 16 +#define FD1_IPC_SENSOR_CTL3_1_SHIFT 0 + +/* Line memory pixel number register */ +#define FD1_IPC_LMEM 0x01e0 +#define FD1_IPC_LMEM_LINEAR 1024 +#define FD1_IPC_LMEM_TILE 960 + +/* Internal Data (HW Version) */ +#define FD1_IP_INTDATA 0x0800 +#define FD1_IP_H3 0x02010101 +#define FD1_IP_M3W 0x02010202 + +/* LUTs */ +#define FD1_LUT_DIF_ADJ 0x1000 +#define FD1_LUT_SAD_ADJ 0x1400 +#define FD1_LUT_BLD_GAIN 0x1800 +#define FD1_LUT_DIF_GAIN 0x1c00 +#define FD1_LUT_MDET 0x2000 + +/** + * struct fdp1_fmt - The FDP1 internal format data + * @fourcc: the fourcc code, to match the V4L2 API + * @bpp: bits per pixel per plane + * @num_planes: number of planes + * @hsub: horizontal subsampling factor + * @vsub: vertical subsampling factor + * @fmt: 7-bit format code for the fdp1 hardware + * @swap_yc: the Y and C components are swapped (Y comes before C) + * @swap_uv: the U and V components are swapped (V comes before U) + * @swap: swap register control + * @types: types of queue this format is applicable to + */ +struct fdp1_fmt { + u32 fourcc; + u8 bpp[3]; + u8 num_planes; + u8 hsub; + u8 vsub; + u8 fmt; + bool swap_yc; + bool swap_uv; + u8 swap; + u8 types; +}; + +static const struct fdp1_fmt fdp1_formats[] = { + /* RGB formats are only supported by the Write Pixel Formatter */ + + { V4L2_PIX_FMT_RGB332, { 8, 0, 0 }, 1, 1, 1, 0x00, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_XRGB444, { 16, 0, 0 }, 1, 1, 1, 0x01, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_XRGB555, { 16, 0, 0 }, 1, 1, 1, 0x04, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_RGB565, { 16, 0, 0 }, 1, 1, 1, 0x06, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_ABGR32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_XBGR32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_ARGB32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_XRGB32, { 32, 0, 0 }, 1, 1, 1, 0x13, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_RGB24, { 24, 0, 0 }, 1, 1, 1, 0x15, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_BGR24, { 24, 0, 0 }, 1, 1, 1, 0x18, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_ARGB444, { 16, 0, 0 }, 1, 1, 1, 0x19, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD, + FDP1_CAPTURE }, + { V4L2_PIX_FMT_ARGB555, { 16, 0, 0 }, 1, 1, 1, 0x1b, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD, + FDP1_CAPTURE }, + + /* YUV Formats are supported by Read and Write Pixel Formatters */ + + { V4L2_PIX_FMT_NV16M, { 8, 16, 0 }, 2, 2, 1, 0x41, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_NV61M, { 8, 16, 0 }, 2, 2, 1, 0x41, false, true, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_NV12M, { 8, 16, 0 }, 2, 2, 2, 0x42, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_NV21M, { 8, 16, 0 }, 2, 2, 2, 0x42, false, true, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_UYVY, { 16, 0, 0 }, 1, 2, 1, 0x47, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_VYUY, { 16, 0, 0 }, 1, 2, 1, 0x47, false, true, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YUYV, { 16, 0, 0 }, 1, 2, 1, 0x47, true, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YVYU, { 16, 0, 0 }, 1, 2, 1, 0x47, true, true, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YUV444M, { 8, 8, 8 }, 3, 1, 1, 0x4a, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YVU444M, { 8, 8, 8 }, 3, 1, 1, 0x4a, false, true, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YUV422M, { 8, 8, 8 }, 3, 2, 1, 0x4b, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YVU422M, { 8, 8, 8 }, 3, 2, 1, 0x4b, false, true, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YUV420M, { 8, 8, 8 }, 3, 2, 2, 0x4c, false, false, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, + { V4L2_PIX_FMT_YVU420M, { 8, 8, 8 }, 3, 2, 2, 0x4c, false, true, + FD1_RWPF_SWAP_LLWD | FD1_RWPF_SWAP_LWRD | + FD1_RWPF_SWAP_WORD | FD1_RWPF_SWAP_BYTE, + FDP1_CAPTURE | FDP1_OUTPUT }, +}; + +static int fdp1_fmt_is_rgb(const struct fdp1_fmt *fmt) +{ + return fmt->fmt <= 0x1b; /* Last RGB code */ +} + +/* + * FDP1 Lookup tables range from 0...255 only + * + * Each table must be less than 256 entries, and all tables + * are padded out to 256 entries by duplicating the last value. + */ +static const u8 fdp1_diff_adj[] = { + 0x00, 0x24, 0x43, 0x5e, 0x76, 0x8c, 0x9e, 0xaf, + 0xbd, 0xc9, 0xd4, 0xdd, 0xe4, 0xea, 0xef, 0xf3, + 0xf6, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, +}; + +static const u8 fdp1_sad_adj[] = { + 0x00, 0x24, 0x43, 0x5e, 0x76, 0x8c, 0x9e, 0xaf, + 0xbd, 0xc9, 0xd4, 0xdd, 0xe4, 0xea, 0xef, 0xf3, + 0xf6, 0xf9, 0xfb, 0xfc, 0xfd, 0xfe, 0xfe, 0xff, +}; + +static const u8 fdp1_bld_gain[] = { + 0x80, +}; + +static const u8 fdp1_dif_gain[] = { + 0x80, +}; + +static const u8 fdp1_mdet[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, + 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, + 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, + 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, + 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, + 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, + 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, + 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, + 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, + 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, + 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, + 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, + 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, + 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, + 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, + 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +/* Per-queue, driver-specific private data */ +struct fdp1_q_data { + const struct fdp1_fmt *fmt; + struct v4l2_pix_format_mplane format; + + unsigned int vsize; + unsigned int stride_y; + unsigned int stride_c; +}; + +static const struct fdp1_fmt *fdp1_find_format(u32 pixelformat) +{ + const struct fdp1_fmt *fmt; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(fdp1_formats); i++) { + fmt = &fdp1_formats[i]; + if (fmt->fourcc == pixelformat) + return fmt; + } + + return NULL; +} + +enum fdp1_deint_mode { + FDP1_PROGRESSIVE = 0, /* Must be zero when !deinterlacing */ + FDP1_ADAPT2D3D, + FDP1_FIXED2D, + FDP1_FIXED3D, + FDP1_PREVFIELD, + FDP1_NEXTFIELD, +}; + +#define FDP1_DEINT_MODE_USES_NEXT(mode) \ + (mode == FDP1_ADAPT2D3D || \ + mode == FDP1_FIXED3D || \ + mode == FDP1_NEXTFIELD) + +#define FDP1_DEINT_MODE_USES_PREV(mode) \ + (mode == FDP1_ADAPT2D3D || \ + mode == FDP1_FIXED3D || \ + mode == FDP1_PREVFIELD) + +/* + * FDP1 operates on potentially 3 fields, which are tracked + * from the VB buffers using this context structure. + * Will always be a field or a full frame, never two fields. + */ +struct fdp1_field_buffer { + struct vb2_v4l2_buffer *vb; + dma_addr_t addrs[3]; + + /* Should be NONE:TOP:BOTTOM only */ + enum v4l2_field field; + + /* Flag to indicate this is the last field in the vb */ + bool last_field; + + /* Buffer queue lists */ + struct list_head list; +}; + +struct fdp1_buffer { + struct v4l2_m2m_buffer m2m_buf; + struct fdp1_field_buffer fields[2]; + unsigned int num_fields; +}; + +static inline struct fdp1_buffer *to_fdp1_buffer(struct vb2_v4l2_buffer *vb) +{ + return container_of(vb, struct fdp1_buffer, m2m_buf.vb); +} + +struct fdp1_job { + struct fdp1_field_buffer *previous; + struct fdp1_field_buffer *active; + struct fdp1_field_buffer *next; + struct fdp1_field_buffer *dst; + + /* A job can only be on one list at a time */ + struct list_head list; +}; + +struct fdp1_dev { + struct v4l2_device v4l2_dev; + struct video_device vfd; + + struct mutex dev_mutex; + spinlock_t irqlock; + spinlock_t device_process_lock; + + void __iomem *regs; + unsigned int irq; + struct device *dev; + + /* Job Queues */ + struct fdp1_job jobs[FDP1_NUMBER_JOBS]; + struct list_head free_job_list; + struct list_head queued_job_list; + struct list_head hw_job_list; + + unsigned int clk_rate; + + struct rcar_fcp_device *fcp; + struct v4l2_m2m_dev *m2m_dev; +}; + +struct fdp1_ctx { + struct v4l2_fh fh; + struct fdp1_dev *fdp1; + + struct v4l2_ctrl_handler hdl; + unsigned int sequence; + + /* Processed buffers in this transaction */ + u8 num_processed; + + /* Transaction length (i.e. how many buffers per transaction) */ + u32 translen; + + /* Abort requested by m2m */ + int aborting; + + /* Deinterlace processing mode */ + enum fdp1_deint_mode deint_mode; + + /* + * Adaptive 2D/3D mode uses a shared mask + * This is allocated at streamon, if the ADAPT2D3D mode + * is requested + */ + unsigned int smsk_size; + dma_addr_t smsk_addr[2]; + void *smsk_cpu; + + /* Capture pipeline, can specify an alpha value + * for supported formats. 0-255 only + */ + unsigned char alpha; + + /* Source and destination queue data */ + struct fdp1_q_data out_q; /* HW Source */ + struct fdp1_q_data cap_q; /* HW Destination */ + + /* + * Field Queues + * Interlaced fields are used on 3 occasions, and tracked in this list. + * + * V4L2 Buffers are tracked inside the fdp1_buffer + * and released when the last 'field' completes + */ + struct list_head fields_queue; + unsigned int buffers_queued; + + /* + * For de-interlacing we need to track our previous buffer + * while preparing our job lists. + */ + struct fdp1_field_buffer *previous; +}; + +static inline struct fdp1_ctx *fh_to_ctx(struct v4l2_fh *fh) +{ + return container_of(fh, struct fdp1_ctx, fh); +} + +static struct fdp1_q_data *get_q_data(struct fdp1_ctx *ctx, + enum v4l2_buf_type type) +{ + if (V4L2_TYPE_IS_OUTPUT(type)) + return &ctx->out_q; + else + return &ctx->cap_q; +} + +/* + * list_remove_job: Take the first item off the specified job list + * + * Returns: pointer to a job, or NULL if the list is empty. + */ +static struct fdp1_job *list_remove_job(struct fdp1_dev *fdp1, + struct list_head *list) +{ + struct fdp1_job *job; + unsigned long flags; + + spin_lock_irqsave(&fdp1->irqlock, flags); + job = list_first_entry_or_null(list, struct fdp1_job, list); + if (job) + list_del(&job->list); + spin_unlock_irqrestore(&fdp1->irqlock, flags); + + return job; +} + +/* + * list_add_job: Add a job to the specified job list + * + * Returns: void - always succeeds + */ +static void list_add_job(struct fdp1_dev *fdp1, + struct list_head *list, + struct fdp1_job *job) +{ + unsigned long flags; + + spin_lock_irqsave(&fdp1->irqlock, flags); + list_add_tail(&job->list, list); + spin_unlock_irqrestore(&fdp1->irqlock, flags); +} + +static struct fdp1_job *fdp1_job_alloc(struct fdp1_dev *fdp1) +{ + return list_remove_job(fdp1, &fdp1->free_job_list); +} + +static void fdp1_job_free(struct fdp1_dev *fdp1, struct fdp1_job *job) +{ + /* Ensure that all residue from previous jobs is gone */ + memset(job, 0, sizeof(struct fdp1_job)); + + list_add_job(fdp1, &fdp1->free_job_list, job); +} + +static void queue_job(struct fdp1_dev *fdp1, struct fdp1_job *job) +{ + list_add_job(fdp1, &fdp1->queued_job_list, job); +} + +static struct fdp1_job *get_queued_job(struct fdp1_dev *fdp1) +{ + return list_remove_job(fdp1, &fdp1->queued_job_list); +} + +static void queue_hw_job(struct fdp1_dev *fdp1, struct fdp1_job *job) +{ + list_add_job(fdp1, &fdp1->hw_job_list, job); +} + +static struct fdp1_job *get_hw_queued_job(struct fdp1_dev *fdp1) +{ + return list_remove_job(fdp1, &fdp1->hw_job_list); +} + +/* + * Buffer lists handling + */ +static void fdp1_field_complete(struct fdp1_ctx *ctx, + struct fdp1_field_buffer *fbuf) +{ + /* job->previous may be on the first field */ + if (!fbuf) + return; + + if (fbuf->last_field) + v4l2_m2m_buf_done(fbuf->vb, VB2_BUF_STATE_DONE); +} + +static void fdp1_queue_field(struct fdp1_ctx *ctx, + struct fdp1_field_buffer *fbuf) +{ + unsigned long flags; + + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); + list_add_tail(&fbuf->list, &ctx->fields_queue); + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); + + ctx->buffers_queued++; +} + +static struct fdp1_field_buffer *fdp1_dequeue_field(struct fdp1_ctx *ctx) +{ + struct fdp1_field_buffer *fbuf; + unsigned long flags; + + ctx->buffers_queued--; + + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); + fbuf = list_first_entry_or_null(&ctx->fields_queue, + struct fdp1_field_buffer, list); + if (fbuf) + list_del(&fbuf->list); + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); + + return fbuf; +} + +/* + * Return the next field in the queue - or NULL, + * without removing the item from the list + */ +static struct fdp1_field_buffer *fdp1_peek_queued_field(struct fdp1_ctx *ctx) +{ + struct fdp1_field_buffer *fbuf; + unsigned long flags; + + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); + fbuf = list_first_entry_or_null(&ctx->fields_queue, + struct fdp1_field_buffer, list); + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); + + return fbuf; +} + +static u32 fdp1_read(struct fdp1_dev *fdp1, unsigned int reg) +{ + u32 value = ioread32(fdp1->regs + reg); + + if (debug >= 2) + dprintk(fdp1, "Read 0x%08x from 0x%04x\n", value, reg); + + return value; +} + +static void fdp1_write(struct fdp1_dev *fdp1, u32 val, unsigned int reg) +{ + if (debug >= 2) + dprintk(fdp1, "Write 0x%08x to 0x%04x\n", val, reg); + + iowrite32(val, fdp1->regs + reg); +} + +/* IPC registers are to be programmed with constant values */ +static void fdp1_set_ipc_dli(struct fdp1_ctx *ctx) +{ + struct fdp1_dev *fdp1 = ctx->fdp1; + + fdp1_write(fdp1, FD1_IPC_SMSK_THRESH_CONST, FD1_IPC_SMSK_THRESH); + fdp1_write(fdp1, FD1_IPC_COMB_DET_CONST, FD1_IPC_COMB_DET); + fdp1_write(fdp1, FD1_IPC_MOTDEC_CONST, FD1_IPC_MOTDEC); + + fdp1_write(fdp1, FD1_IPC_DLI_BLEND_CONST, FD1_IPC_DLI_BLEND); + fdp1_write(fdp1, FD1_IPC_DLI_HGAIN_CONST, FD1_IPC_DLI_HGAIN); + fdp1_write(fdp1, FD1_IPC_DLI_SPRS_CONST, FD1_IPC_DLI_SPRS); + fdp1_write(fdp1, FD1_IPC_DLI_ANGLE_CONST, FD1_IPC_DLI_ANGLE); + fdp1_write(fdp1, FD1_IPC_DLI_ISOPIX0_CONST, FD1_IPC_DLI_ISOPIX0); + fdp1_write(fdp1, FD1_IPC_DLI_ISOPIX1_CONST, FD1_IPC_DLI_ISOPIX1); +} + + +static void fdp1_set_ipc_sensor(struct fdp1_ctx *ctx) +{ + struct fdp1_dev *fdp1 = ctx->fdp1; + struct fdp1_q_data *src_q_data = &ctx->out_q; + unsigned int x0, x1; + unsigned int hsize = src_q_data->format.width; + unsigned int vsize = src_q_data->format.height; + + x0 = hsize / 3; + x1 = 2 * hsize / 3; + + fdp1_write(fdp1, FD1_IPC_SENSOR_TH0_CONST, FD1_IPC_SENSOR_TH0); + fdp1_write(fdp1, FD1_IPC_SENSOR_TH1_CONST, FD1_IPC_SENSOR_TH1); + fdp1_write(fdp1, FD1_IPC_SENSOR_CTL0_CONST, FD1_IPC_SENSOR_CTL0); + fdp1_write(fdp1, FD1_IPC_SENSOR_CTL1_CONST, FD1_IPC_SENSOR_CTL1); + + fdp1_write(fdp1, ((hsize - 1) << FD1_IPC_SENSOR_CTL2_X_SHIFT) | + ((vsize - 1) << FD1_IPC_SENSOR_CTL2_Y_SHIFT), + FD1_IPC_SENSOR_CTL2); + + fdp1_write(fdp1, (x0 << FD1_IPC_SENSOR_CTL3_0_SHIFT) | + (x1 << FD1_IPC_SENSOR_CTL3_1_SHIFT), + FD1_IPC_SENSOR_CTL3); +} + +/* + * fdp1_write_lut: Write a padded LUT to the hw + * + * FDP1 uses constant data for de-interlacing processing, + * with large tables. These hardware tables are all 256 bytes + * long, however they often contain repeated data at the end. + * + * The last byte of the table is written to all remaining entries. + */ +static void fdp1_write_lut(struct fdp1_dev *fdp1, const u8 *lut, + unsigned int len, unsigned int base) +{ + unsigned int i; + u8 pad; + + /* Tables larger than the hw are clipped */ + len = min(len, 256u); + + for (i = 0; i < len; i++) + fdp1_write(fdp1, lut[i], base + (i*4)); + + /* Tables are padded with the last entry */ + pad = lut[i-1]; + + for (; i < 256; i++) + fdp1_write(fdp1, pad, base + (i*4)); +} + +static void fdp1_set_lut(struct fdp1_dev *fdp1) +{ + fdp1_write_lut(fdp1, fdp1_diff_adj, ARRAY_SIZE(fdp1_diff_adj), + FD1_LUT_DIF_ADJ); + fdp1_write_lut(fdp1, fdp1_sad_adj, ARRAY_SIZE(fdp1_sad_adj), + FD1_LUT_SAD_ADJ); + fdp1_write_lut(fdp1, fdp1_bld_gain, ARRAY_SIZE(fdp1_bld_gain), + FD1_LUT_BLD_GAIN); + fdp1_write_lut(fdp1, fdp1_dif_gain, ARRAY_SIZE(fdp1_dif_gain), + FD1_LUT_DIF_GAIN); + fdp1_write_lut(fdp1, fdp1_mdet, ARRAY_SIZE(fdp1_mdet), + FD1_LUT_MDET); +} + +static void fdp1_configure_rpf(struct fdp1_ctx *ctx, + struct fdp1_job *job) +{ + struct fdp1_dev *fdp1 = ctx->fdp1; + u32 picture_size; + u32 pstride; + u32 format; + u32 smsk_addr; + + struct fdp1_q_data *q_data = &ctx->out_q; + + /* Picture size is common to Source and Destination frames */ + picture_size = (q_data->format.width << FD1_RPF_SIZE_H_SHIFT) + | (q_data->vsize << FD1_RPF_SIZE_V_SHIFT); + + /* Strides */ + pstride = q_data->stride_y << FD1_RPF_PSTRIDE_Y_SHIFT; + if (q_data->format.num_planes > 1) + pstride |= q_data->stride_c << FD1_RPF_PSTRIDE_C_SHIFT; + + /* Format control */ + format = q_data->fmt->fmt; + if (q_data->fmt->swap_yc) + format |= FD1_RPF_FORMAT_RSPYCS; + + if (q_data->fmt->swap_uv) + format |= FD1_RPF_FORMAT_RSPUVS; + + if (job->active->field == V4L2_FIELD_BOTTOM) { + format |= FD1_RPF_FORMAT_CF; /* Set for Bottom field */ + smsk_addr = ctx->smsk_addr[0]; + } else { + smsk_addr = ctx->smsk_addr[1]; + } + + /* Deint mode is non-zero when deinterlacing */ + if (ctx->deint_mode) + format |= FD1_RPF_FORMAT_CIPM; + + fdp1_write(fdp1, format, FD1_RPF_FORMAT); + fdp1_write(fdp1, q_data->fmt->swap, FD1_RPF_SWAP); + fdp1_write(fdp1, picture_size, FD1_RPF_SIZE); + fdp1_write(fdp1, pstride, FD1_RPF_PSTRIDE); + fdp1_write(fdp1, smsk_addr, FD1_RPF_SMSK_ADDR); + + /* Previous Field Channel (CH0) */ + if (job->previous) + fdp1_write(fdp1, job->previous->addrs[0], FD1_RPF0_ADDR_Y); + + /* Current Field Channel (CH1) */ + fdp1_write(fdp1, job->active->addrs[0], FD1_RPF1_ADDR_Y); + fdp1_write(fdp1, job->active->addrs[1], FD1_RPF1_ADDR_C0); + fdp1_write(fdp1, job->active->addrs[2], FD1_RPF1_ADDR_C1); + + /* Next Field Channel (CH2) */ + if (job->next) + fdp1_write(fdp1, job->next->addrs[0], FD1_RPF2_ADDR_Y); +} + +static void fdp1_configure_wpf(struct fdp1_ctx *ctx, + struct fdp1_job *job) +{ + struct fdp1_dev *fdp1 = ctx->fdp1; + struct fdp1_q_data *src_q_data = &ctx->out_q; + struct fdp1_q_data *q_data = &ctx->cap_q; + u32 pstride; + u32 format; + u32 swap; + u32 rndctl; + + pstride = q_data->format.plane_fmt[0].bytesperline + << FD1_WPF_PSTRIDE_Y_SHIFT; + + if (q_data->format.num_planes > 1) + pstride |= q_data->format.plane_fmt[1].bytesperline + << FD1_WPF_PSTRIDE_C_SHIFT; + + format = q_data->fmt->fmt; /* Output Format Code */ + + if (q_data->fmt->swap_yc) + format |= FD1_WPF_FORMAT_WSPYCS; + + if (q_data->fmt->swap_uv) + format |= FD1_WPF_FORMAT_WSPUVS; + + if (fdp1_fmt_is_rgb(q_data->fmt)) { + /* Enable Colour Space conversion */ + format |= FD1_WPF_FORMAT_CSC; + + /* Set WRTM */ + if (src_q_data->format.ycbcr_enc == V4L2_YCBCR_ENC_709) + format |= FD1_WPF_FORMAT_WRTM_709_16; + else if (src_q_data->format.quantization == + V4L2_QUANTIZATION_FULL_RANGE) + format |= FD1_WPF_FORMAT_WRTM_601_0; + else + format |= FD1_WPF_FORMAT_WRTM_601_16; + } + + /* Set an alpha value into the Pad Value */ + format |= ctx->alpha << FD1_WPF_FORMAT_PDV_SHIFT; + + /* Determine picture rounding and clipping */ + rndctl = FD1_WPF_RNDCTL_CBRM; /* Rounding Off */ + rndctl |= FD1_WPF_RNDCTL_CLMD_NOCLIP; + + /* WPF Swap needs both ISWAP and OSWAP setting */ + swap = q_data->fmt->swap << FD1_WPF_SWAP_OSWAP_SHIFT; + swap |= src_q_data->fmt->swap << FD1_WPF_SWAP_SSWAP_SHIFT; + + fdp1_write(fdp1, format, FD1_WPF_FORMAT); + fdp1_write(fdp1, rndctl, FD1_WPF_RNDCTL); + fdp1_write(fdp1, swap, FD1_WPF_SWAP); + fdp1_write(fdp1, pstride, FD1_WPF_PSTRIDE); + + fdp1_write(fdp1, job->dst->addrs[0], FD1_WPF_ADDR_Y); + fdp1_write(fdp1, job->dst->addrs[1], FD1_WPF_ADDR_C0); + fdp1_write(fdp1, job->dst->addrs[2], FD1_WPF_ADDR_C1); +} + +static void fdp1_configure_deint_mode(struct fdp1_ctx *ctx, + struct fdp1_job *job) +{ + struct fdp1_dev *fdp1 = ctx->fdp1; + u32 opmode = FD1_CTL_OPMODE_VIMD_NOINTERRUPT; + u32 ipcmode = FD1_IPC_MODE_DLI; /* Always set */ + u32 channels = FD1_CTL_CHACT_WR | FD1_CTL_CHACT_RD1; /* Always on */ + + /* De-interlacing Mode */ + switch (ctx->deint_mode) { + default: + case FDP1_PROGRESSIVE: + dprintk(fdp1, "Progressive Mode\n"); + opmode |= FD1_CTL_OPMODE_PRG; + ipcmode |= FD1_IPC_MODE_DIM_FIXED2D; + break; + case FDP1_ADAPT2D3D: + dprintk(fdp1, "Adapt2D3D Mode\n"); + if (ctx->sequence == 0 || ctx->aborting) + ipcmode |= FD1_IPC_MODE_DIM_FIXED2D; + else + ipcmode |= FD1_IPC_MODE_DIM_ADAPT2D3D; + + if (ctx->sequence > 1) { + channels |= FD1_CTL_CHACT_SMW; + channels |= FD1_CTL_CHACT_RD0 | FD1_CTL_CHACT_RD2; + } + + if (ctx->sequence > 2) + channels |= FD1_CTL_CHACT_SMR; + + break; + case FDP1_FIXED3D: + dprintk(fdp1, "Fixed 3D Mode\n"); + ipcmode |= FD1_IPC_MODE_DIM_FIXED3D; + /* Except for first and last frame, enable all channels */ + if (!(ctx->sequence == 0 || ctx->aborting)) + channels |= FD1_CTL_CHACT_RD0 | FD1_CTL_CHACT_RD2; + break; + case FDP1_FIXED2D: + dprintk(fdp1, "Fixed 2D Mode\n"); + ipcmode |= FD1_IPC_MODE_DIM_FIXED2D; + /* No extra channels enabled */ + break; + case FDP1_PREVFIELD: + dprintk(fdp1, "Previous Field Mode\n"); + ipcmode |= FD1_IPC_MODE_DIM_PREVFIELD; + channels |= FD1_CTL_CHACT_RD0; /* Previous */ + break; + case FDP1_NEXTFIELD: + dprintk(fdp1, "Next Field Mode\n"); + ipcmode |= FD1_IPC_MODE_DIM_NEXTFIELD; + channels |= FD1_CTL_CHACT_RD2; /* Next */ + break; + } + + fdp1_write(fdp1, channels, FD1_CTL_CHACT); + fdp1_write(fdp1, opmode, FD1_CTL_OPMODE); + fdp1_write(fdp1, ipcmode, FD1_IPC_MODE); +} + +/* + * fdp1_device_process() - Run the hardware + * + * Configure and start the hardware to generate a single frame + * of output given our input parameters. + */ +static int fdp1_device_process(struct fdp1_ctx *ctx) + +{ + struct fdp1_dev *fdp1 = ctx->fdp1; + struct fdp1_job *job; + unsigned long flags; + + spin_lock_irqsave(&fdp1->device_process_lock, flags); + + /* Get a job to process */ + job = get_queued_job(fdp1); + if (!job) { + /* + * VINT can call us to see if we can queue another job. + * If we have no work to do, we simply return. + */ + spin_unlock_irqrestore(&fdp1->device_process_lock, flags); + return 0; + } + + /* First Frame only? ... */ + fdp1_write(fdp1, FD1_CTL_CLKCTRL_CSTP_N, FD1_CTL_CLKCTRL); + + /* Set the mode, and configuration */ + fdp1_configure_deint_mode(ctx, job); + + /* DLI Static Configuration */ + fdp1_set_ipc_dli(ctx); + + /* Sensor Configuration */ + fdp1_set_ipc_sensor(ctx); + + /* Setup the source picture */ + fdp1_configure_rpf(ctx, job); + + /* Setup the destination picture */ + fdp1_configure_wpf(ctx, job); + + /* Line Memory Pixel Number Register for linear access */ + fdp1_write(fdp1, FD1_IPC_LMEM_LINEAR, FD1_IPC_LMEM); + + /* Enable Interrupts */ + fdp1_write(fdp1, FD1_CTL_IRQ_MASK, FD1_CTL_IRQENB); + + /* Finally, the Immediate Registers */ + + /* This job is now in the HW queue */ + queue_hw_job(fdp1, job); + + /* Start the command */ + fdp1_write(fdp1, FD1_CTL_CMD_STRCMD, FD1_CTL_CMD); + + /* Registers will update to HW at next VINT */ + fdp1_write(fdp1, FD1_CTL_REGEND_REGEND, FD1_CTL_REGEND); + + /* Enable VINT Generator */ + fdp1_write(fdp1, FD1_CTL_SGCMD_SGEN, FD1_CTL_SGCMD); + + spin_unlock_irqrestore(&fdp1->device_process_lock, flags); + + return 0; +} + +/* + * mem2mem callbacks + */ + +/** + * job_ready() - check whether an instance is ready to be scheduled to run + */ +static int fdp1_m2m_job_ready(void *priv) +{ + struct fdp1_ctx *ctx = priv; + struct fdp1_q_data *src_q_data = &ctx->out_q; + int srcbufs = 1; + int dstbufs = 1; + + dprintk(ctx->fdp1, "+ Src: %d : Dst: %d\n", + v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx), + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx)); + + /* One output buffer is required for each field */ + if (V4L2_FIELD_HAS_BOTH(src_q_data->format.field)) + dstbufs = 2; + + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < srcbufs + || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < dstbufs) { + dprintk(ctx->fdp1, "Not enough buffers available\n"); + return 0; + } + + return 1; +} + +static void fdp1_m2m_job_abort(void *priv) +{ + struct fdp1_ctx *ctx = priv; + + dprintk(ctx->fdp1, "+\n"); + + /* Will cancel the transaction in the next interrupt handler */ + ctx->aborting = 1; + + /* Immediate abort sequence */ + fdp1_write(ctx->fdp1, 0, FD1_CTL_SGCMD); + fdp1_write(ctx->fdp1, FD1_CTL_SRESET_SRST, FD1_CTL_SRESET); +} + +/* + * fdp1_prepare_job: Prepare and queue a new job for a single action of work + * + * Prepare the next field, (or frame in progressive) and an output + * buffer for the hardware to perform a single operation. + */ +static struct fdp1_job *fdp1_prepare_job(struct fdp1_ctx *ctx) +{ + struct vb2_v4l2_buffer *vbuf; + struct fdp1_buffer *fbuf; + struct fdp1_dev *fdp1 = ctx->fdp1; + struct fdp1_job *job; + unsigned int buffers_required = 1; + + dprintk(fdp1, "+\n"); + + if (FDP1_DEINT_MODE_USES_NEXT(ctx->deint_mode)) + buffers_required = 2; + + if (ctx->buffers_queued < buffers_required) + return NULL; + + job = fdp1_job_alloc(fdp1); + if (!job) { + dprintk(fdp1, "No free jobs currently available\n"); + return NULL; + } + + job->active = fdp1_dequeue_field(ctx); + if (!job->active) { + /* Buffer check should prevent this ever happening */ + dprintk(fdp1, "No input buffers currently available\n"); + + fdp1_job_free(fdp1, job); + return NULL; + } + + dprintk(fdp1, "+ Buffer en-route...\n"); + + /* Source buffers have been prepared on our buffer_queue + * Prepare our Output buffer + */ + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + fbuf = to_fdp1_buffer(vbuf); + job->dst = &fbuf->fields[0]; + + job->active->vb->sequence = ctx->sequence; + job->dst->vb->sequence = ctx->sequence; + ctx->sequence++; + + if (FDP1_DEINT_MODE_USES_PREV(ctx->deint_mode)) { + job->previous = ctx->previous; + + /* Active buffer becomes the next job's previous buffer */ + ctx->previous = job->active; + } + + if (FDP1_DEINT_MODE_USES_NEXT(ctx->deint_mode)) { + /* Must be called after 'active' is dequeued */ + job->next = fdp1_peek_queued_field(ctx); + } + + /* Transfer timestamps and flags from src->dst */ + + job->dst->vb->vb2_buf.timestamp = job->active->vb->vb2_buf.timestamp; + + job->dst->vb->flags = job->active->vb->flags & + V4L2_BUF_FLAG_TSTAMP_SRC_MASK; + + /* Ideally, the frame-end function will just 'check' to see + * if there are more jobs instead + */ + ctx->translen++; + + /* Finally, Put this job on the processing queue */ + queue_job(fdp1, job); + + dprintk(fdp1, "Job Queued translen = %d\n", ctx->translen); + + return job; +} + +/* fdp1_m2m_device_run() - prepares and starts the device for an M2M task + * + * A single input buffer is taken and serialised into our fdp1_buffer + * queue. The queue is then processed to create as many jobs as possible + * from our available input. + */ +static void fdp1_m2m_device_run(void *priv) +{ + struct fdp1_ctx *ctx = priv; + struct fdp1_dev *fdp1 = ctx->fdp1; + struct vb2_v4l2_buffer *src_vb; + struct fdp1_buffer *buf; + unsigned int i; + + dprintk(fdp1, "+\n"); + + ctx->translen = 0; + + /* Get our incoming buffer of either one or two fields, or one frame */ + src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + buf = to_fdp1_buffer(src_vb); + + for (i = 0; i < buf->num_fields; i++) { + struct fdp1_field_buffer *fbuf = &buf->fields[i]; + + fdp1_queue_field(ctx, fbuf); + dprintk(fdp1, "Queued Buffer [%d] last_field:%d\n", + i, fbuf->last_field); + } + + /* Queue as many jobs as our data provides for */ + while (fdp1_prepare_job(ctx)) + ; + + if (ctx->translen == 0) { + dprintk(fdp1, "No jobs were processed. M2M action complete\n"); + v4l2_m2m_job_finish(fdp1->m2m_dev, ctx->fh.m2m_ctx); + return; + } + + /* Kick the job processing action */ + fdp1_device_process(ctx); +} + +/* + * device_frame_end: + * + * Handles the M2M level after a buffer completion event. + */ +static void device_frame_end(struct fdp1_dev *fdp1, + enum vb2_buffer_state state) +{ + struct fdp1_ctx *ctx; + unsigned long flags; + struct fdp1_job *job = get_hw_queued_job(fdp1); + + dprintk(fdp1, "+\n"); + + ctx = v4l2_m2m_get_curr_priv(fdp1->m2m_dev); + + if (ctx == NULL) { + v4l2_err(&fdp1->v4l2_dev, + "Instance released before the end of transaction\n"); + return; + } + + ctx->num_processed++; + + /* + * fdp1_field_complete will call buf_done only when the last vb2_buffer + * reference is complete + */ + if (FDP1_DEINT_MODE_USES_PREV(ctx->deint_mode)) + fdp1_field_complete(ctx, job->previous); + else + fdp1_field_complete(ctx, job->active); + + spin_lock_irqsave(&fdp1->irqlock, flags); + v4l2_m2m_buf_done(job->dst->vb, state); + job->dst = NULL; + spin_unlock_irqrestore(&fdp1->irqlock, flags); + + /* Move this job back to the free job list */ + fdp1_job_free(fdp1, job); + + dprintk(fdp1, "curr_ctx->num_processed %d curr_ctx->translen %d\n", + ctx->num_processed, ctx->translen); + + if (ctx->num_processed == ctx->translen || + ctx->aborting) { + dprintk(ctx->fdp1, "Finishing transaction\n"); + ctx->num_processed = 0; + v4l2_m2m_job_finish(fdp1->m2m_dev, ctx->fh.m2m_ctx); + } else { + /* + * For pipelined performance support, this would + * be called from a VINT handler + */ + fdp1_device_process(ctx); + } +} + +/* + * video ioctls + */ +static int fdp1_vidioc_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + strlcpy(cap->driver, DRIVER_NAME, sizeof(cap->driver)); + strlcpy(cap->card, DRIVER_NAME, sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", DRIVER_NAME); + return 0; +} + +static int fdp1_enum_fmt(struct v4l2_fmtdesc *f, u32 type) +{ + unsigned int i, num; + + num = 0; + + for (i = 0; i < ARRAY_SIZE(fdp1_formats); ++i) { + if (fdp1_formats[i].types & type) { + if (num == f->index) + break; + ++num; + } + } + + /* Format not found */ + if (i >= ARRAY_SIZE(fdp1_formats)) + return -EINVAL; + + /* Format found */ + f->pixelformat = fdp1_formats[i].fourcc; + + return 0; +} + +static int fdp1_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return fdp1_enum_fmt(f, FDP1_CAPTURE); +} + +static int fdp1_enum_fmt_vid_out(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + return fdp1_enum_fmt(f, FDP1_OUTPUT); +} + +static int fdp1_g_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct fdp1_q_data *q_data; + struct fdp1_ctx *ctx = fh_to_ctx(priv); + + if (!v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type)) + return -EINVAL; + + q_data = get_q_data(ctx, f->type); + f->fmt.pix_mp = q_data->format; + + return 0; +} + +static void fdp1_compute_stride(struct v4l2_pix_format_mplane *pix, + const struct fdp1_fmt *fmt) +{ + unsigned int i; + + /* Compute and clamp the stride and image size. */ + for (i = 0; i < min_t(unsigned int, fmt->num_planes, 2U); ++i) { + unsigned int hsub = i > 0 ? fmt->hsub : 1; + unsigned int vsub = i > 0 ? fmt->vsub : 1; + /* From VSP : TODO: Confirm alignment limits for FDP1 */ + unsigned int align = 128; + unsigned int bpl; + + bpl = clamp_t(unsigned int, pix->plane_fmt[i].bytesperline, + pix->width / hsub * fmt->bpp[i] / 8, + round_down(FDP1_MAX_STRIDE, align)); + + pix->plane_fmt[i].bytesperline = round_up(bpl, align); + pix->plane_fmt[i].sizeimage = pix->plane_fmt[i].bytesperline + * pix->height / vsub; + + memset(pix->plane_fmt[i].reserved, 0, + sizeof(pix->plane_fmt[i].reserved)); + } + + if (fmt->num_planes == 3) { + /* The two chroma planes must have the same stride. */ + pix->plane_fmt[2].bytesperline = pix->plane_fmt[1].bytesperline; + pix->plane_fmt[2].sizeimage = pix->plane_fmt[1].sizeimage; + + memset(pix->plane_fmt[2].reserved, 0, + sizeof(pix->plane_fmt[2].reserved)); + } +} + +static void fdp1_try_fmt_output(struct fdp1_ctx *ctx, + const struct fdp1_fmt **fmtinfo, + struct v4l2_pix_format_mplane *pix) +{ + const struct fdp1_fmt *fmt; + unsigned int width; + unsigned int height; + + /* Validate the pixel format to ensure the output queue supports it. */ + fmt = fdp1_find_format(pix->pixelformat); + if (!fmt || !(fmt->types & FDP1_OUTPUT)) + fmt = fdp1_find_format(V4L2_PIX_FMT_YUYV); + + if (fmtinfo) + *fmtinfo = fmt; + + pix->pixelformat = fmt->fourcc; + pix->num_planes = fmt->num_planes; + + /* + * Progressive video and all interlaced field orders are acceptable. + * Default to V4L2_FIELD_INTERLACED. + */ + if (pix->field != V4L2_FIELD_NONE && + pix->field != V4L2_FIELD_ALTERNATE && + !V4L2_FIELD_HAS_BOTH(pix->field)) + pix->field = V4L2_FIELD_INTERLACED; + + /* + * The deinterlacer doesn't care about the colorspace, accept all values + * and default to V4L2_COLORSPACE_SMPTE170M. The YUV to RGB conversion + * at the output of the deinterlacer supports a subset of encodings and + * quantization methods and will only be available when the colorspace + * allows it. + */ + if (pix->colorspace == V4L2_COLORSPACE_DEFAULT) + pix->colorspace = V4L2_COLORSPACE_SMPTE170M; + + /* + * Align the width and height for YUV 4:2:2 and 4:2:0 formats and clamp + * them to the supported frame size range. The height boundary are + * related to the full frame, divide them by two when the format passes + * fields in separate buffers. + */ + width = round_down(pix->width, fmt->hsub); + pix->width = clamp(width, FDP1_MIN_W, FDP1_MAX_W); + + height = round_down(pix->height, fmt->vsub); + if (pix->field == V4L2_FIELD_ALTERNATE) + pix->height = clamp(height, FDP1_MIN_H / 2, FDP1_MAX_H / 2); + else + pix->height = clamp(height, FDP1_MIN_H, FDP1_MAX_H); + + fdp1_compute_stride(pix, fmt); +} + +static void fdp1_try_fmt_capture(struct fdp1_ctx *ctx, + const struct fdp1_fmt **fmtinfo, + struct v4l2_pix_format_mplane *pix) +{ + struct fdp1_q_data *src_data = &ctx->out_q; + enum v4l2_colorspace colorspace; + enum v4l2_ycbcr_encoding ycbcr_enc; + enum v4l2_quantization quantization; + const struct fdp1_fmt *fmt; + bool allow_rgb; + + /* + * Validate the pixel format. We can only accept RGB output formats if + * the input encoding and quantization are compatible with the format + * conversions supported by the hardware. The supported combinations are + * + * V4L2_YCBCR_ENC_601 + V4L2_QUANTIZATION_LIM_RANGE + * V4L2_YCBCR_ENC_601 + V4L2_QUANTIZATION_FULL_RANGE + * V4L2_YCBCR_ENC_709 + V4L2_QUANTIZATION_LIM_RANGE + */ + colorspace = src_data->format.colorspace; + + ycbcr_enc = src_data->format.ycbcr_enc; + if (ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) + ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(colorspace); + + quantization = src_data->format.quantization; + if (quantization == V4L2_QUANTIZATION_DEFAULT) + quantization = V4L2_MAP_QUANTIZATION_DEFAULT(false, colorspace, + ycbcr_enc); + + allow_rgb = ycbcr_enc == V4L2_YCBCR_ENC_601 || + (ycbcr_enc == V4L2_YCBCR_ENC_709 && + quantization == V4L2_QUANTIZATION_LIM_RANGE); + + fmt = fdp1_find_format(pix->pixelformat); + if (!fmt || (!allow_rgb && fdp1_fmt_is_rgb(fmt))) + fmt = fdp1_find_format(V4L2_PIX_FMT_YUYV); + + if (fmtinfo) + *fmtinfo = fmt; + + pix->pixelformat = fmt->fourcc; + pix->num_planes = fmt->num_planes; + pix->field = V4L2_FIELD_NONE; + + /* + * The colorspace on the capture queue is copied from the output queue + * as the hardware can't change the colorspace. It can convert YCbCr to + * RGB though, in which case the encoding and quantization are set to + * default values as anything else wouldn't make sense. + */ + pix->colorspace = src_data->format.colorspace; + pix->xfer_func = src_data->format.xfer_func; + + if (fdp1_fmt_is_rgb(fmt)) { + pix->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + pix->quantization = V4L2_QUANTIZATION_DEFAULT; + } else { + pix->ycbcr_enc = src_data->format.ycbcr_enc; + pix->quantization = src_data->format.quantization; + } + + /* + * The frame width is identical to the output queue, and the height is + * either doubled or identical depending on whether the output queue + * field order contains one or two fields per frame. + */ + pix->width = src_data->format.width; + if (src_data->format.field == V4L2_FIELD_ALTERNATE) + pix->height = 2 * src_data->format.height; + else + pix->height = src_data->format.height; + + fdp1_compute_stride(pix, fmt); +} + +static int fdp1_try_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct fdp1_ctx *ctx = fh_to_ctx(priv); + + if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + fdp1_try_fmt_output(ctx, NULL, &f->fmt.pix_mp); + else + fdp1_try_fmt_capture(ctx, NULL, &f->fmt.pix_mp); + + dprintk(ctx->fdp1, "Try %s format: %4s (0x%08x) %ux%u field %u\n", + V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture", + (char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field); + + return 0; +} + +static void fdp1_set_format(struct fdp1_ctx *ctx, + struct v4l2_pix_format_mplane *pix, + enum v4l2_buf_type type) +{ + struct fdp1_q_data *q_data = get_q_data(ctx, type); + const struct fdp1_fmt *fmtinfo; + + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) + fdp1_try_fmt_output(ctx, &fmtinfo, pix); + else + fdp1_try_fmt_capture(ctx, &fmtinfo, pix); + + q_data->fmt = fmtinfo; + q_data->format = *pix; + + q_data->vsize = pix->height; + if (pix->field != V4L2_FIELD_NONE) + q_data->vsize /= 2; + + q_data->stride_y = pix->plane_fmt[0].bytesperline; + q_data->stride_c = pix->plane_fmt[1].bytesperline; + + /* Adjust strides for interleaved buffers */ + if (pix->field == V4L2_FIELD_INTERLACED || + pix->field == V4L2_FIELD_INTERLACED_TB || + pix->field == V4L2_FIELD_INTERLACED_BT) { + q_data->stride_y *= 2; + q_data->stride_c *= 2; + } + + /* Propagate the format from the output node to the capture node. */ + if (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + struct fdp1_q_data *dst_data = &ctx->cap_q; + + /* + * Copy the format, clear the per-plane bytes per line and image + * size, override the field and double the height if needed. + */ + dst_data->format = q_data->format; + memset(dst_data->format.plane_fmt, 0, + sizeof(dst_data->format.plane_fmt)); + + dst_data->format.field = V4L2_FIELD_NONE; + if (pix->field == V4L2_FIELD_ALTERNATE) + dst_data->format.height *= 2; + + fdp1_try_fmt_capture(ctx, &dst_data->fmt, &dst_data->format); + + dst_data->vsize = dst_data->format.height; + dst_data->stride_y = dst_data->format.plane_fmt[0].bytesperline; + dst_data->stride_c = dst_data->format.plane_fmt[1].bytesperline; + } +} + +static int fdp1_s_fmt(struct file *file, void *priv, struct v4l2_format *f) +{ + struct fdp1_ctx *ctx = fh_to_ctx(priv); + struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx; + struct vb2_queue *vq = v4l2_m2m_get_vq(m2m_ctx, f->type); + + if (vb2_is_busy(vq)) { + v4l2_err(&ctx->fdp1->v4l2_dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + fdp1_set_format(ctx, &f->fmt.pix_mp, f->type); + + dprintk(ctx->fdp1, "Set %s format: %4s (0x%08x) %ux%u field %u\n", + V4L2_TYPE_IS_OUTPUT(f->type) ? "output" : "capture", + (char *)&f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.pixelformat, + f->fmt.pix_mp.width, f->fmt.pix_mp.height, f->fmt.pix_mp.field); + + return 0; +} + +static int fdp1_g_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fdp1_ctx *ctx = + container_of(ctrl->handler, struct fdp1_ctx, hdl); + struct fdp1_q_data *src_q_data = &ctx->out_q; + + switch (ctrl->id) { + case V4L2_CID_MIN_BUFFERS_FOR_CAPTURE: + if (V4L2_FIELD_HAS_BOTH(src_q_data->format.field)) + ctrl->val = 2; + else + ctrl->val = 1; + return 0; + } + + return 1; +} + +static int fdp1_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct fdp1_ctx *ctx = + container_of(ctrl->handler, struct fdp1_ctx, hdl); + + switch (ctrl->id) { + case V4L2_CID_ALPHA_COMPONENT: + ctx->alpha = ctrl->val; + break; + + case V4L2_CID_DEINTERLACING_MODE: + ctx->deint_mode = ctrl->val; + break; + } + + return 0; +} + +static const struct v4l2_ctrl_ops fdp1_ctrl_ops = { + .s_ctrl = fdp1_s_ctrl, + .g_volatile_ctrl = fdp1_g_ctrl, +}; + +static const char * const fdp1_ctrl_deint_menu[] = { + "Progressive", + "Adaptive 2D/3D", + "Fixed 2D", + "Fixed 3D", + "Previous field", + "Next field", + NULL +}; + +static const struct v4l2_ioctl_ops fdp1_ioctl_ops = { + .vidioc_querycap = fdp1_vidioc_querycap, + + .vidioc_enum_fmt_vid_cap_mplane = fdp1_enum_fmt_vid_cap, + .vidioc_enum_fmt_vid_out_mplane = fdp1_enum_fmt_vid_out, + .vidioc_g_fmt_vid_cap_mplane = fdp1_g_fmt, + .vidioc_g_fmt_vid_out_mplane = fdp1_g_fmt, + .vidioc_try_fmt_vid_cap_mplane = fdp1_try_fmt, + .vidioc_try_fmt_vid_out_mplane = fdp1_try_fmt, + .vidioc_s_fmt_vid_cap_mplane = fdp1_s_fmt, + .vidioc_s_fmt_vid_out_mplane = fdp1_s_fmt, + + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, + + .vidioc_streamon = v4l2_m2m_ioctl_streamon, + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +/* + * Queue operations + */ + +static int fdp1_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_ctxs[]) +{ + struct fdp1_ctx *ctx = vb2_get_drv_priv(vq); + struct fdp1_q_data *q_data; + unsigned int i; + + q_data = get_q_data(ctx, vq->type); + + if (*nplanes) { + if (*nplanes > FDP1_MAX_PLANES) + return -EINVAL; + + return 0; + } + + *nplanes = q_data->format.num_planes; + + for (i = 0; i < *nplanes; i++) + sizes[i] = q_data->format.plane_fmt[i].sizeimage; + + return 0; +} + +static void fdp1_buf_prepare_field(struct fdp1_q_data *q_data, + struct vb2_v4l2_buffer *vbuf, + unsigned int field_num) +{ + struct fdp1_buffer *buf = to_fdp1_buffer(vbuf); + struct fdp1_field_buffer *fbuf = &buf->fields[field_num]; + unsigned int num_fields; + unsigned int i; + + num_fields = V4L2_FIELD_HAS_BOTH(vbuf->field) ? 2 : 1; + + fbuf->vb = vbuf; + fbuf->last_field = (field_num + 1) == num_fields; + + for (i = 0; i < vbuf->vb2_buf.num_planes; ++i) + fbuf->addrs[i] = vb2_dma_contig_plane_dma_addr(&vbuf->vb2_buf, i); + + switch (vbuf->field) { + case V4L2_FIELD_INTERLACED: + /* + * Interlaced means bottom-top for 60Hz TV standards (NTSC) and + * top-bottom for 50Hz. As TV standards are not applicable to + * the mem-to-mem API, use the height as a heuristic. + */ + fbuf->field = (q_data->format.height < 576) == field_num + ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; + break; + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_SEQ_TB: + fbuf->field = field_num ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP; + break; + case V4L2_FIELD_INTERLACED_BT: + case V4L2_FIELD_SEQ_BT: + fbuf->field = field_num ? V4L2_FIELD_TOP : V4L2_FIELD_BOTTOM; + break; + default: + fbuf->field = vbuf->field; + break; + } + + /* Buffer is completed */ + if (!field_num) + return; + + /* Adjust buffer addresses for second field */ + switch (vbuf->field) { + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + for (i = 0; i < vbuf->vb2_buf.num_planes; i++) + fbuf->addrs[i] += + (i == 0 ? q_data->stride_y : q_data->stride_c); + break; + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + for (i = 0; i < vbuf->vb2_buf.num_planes; i++) + fbuf->addrs[i] += q_data->vsize * + (i == 0 ? q_data->stride_y : q_data->stride_c); + break; + } +} + +static int fdp1_buf_prepare(struct vb2_buffer *vb) +{ + struct fdp1_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + struct fdp1_q_data *q_data = get_q_data(ctx, vb->vb2_queue->type); + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct fdp1_buffer *buf = to_fdp1_buffer(vbuf); + unsigned int i; + + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + bool field_valid = true; + + /* Validate the buffer field. */ + switch (q_data->format.field) { + case V4L2_FIELD_NONE: + if (vbuf->field != V4L2_FIELD_NONE) + field_valid = false; + break; + + case V4L2_FIELD_ALTERNATE: + if (vbuf->field != V4L2_FIELD_TOP && + vbuf->field != V4L2_FIELD_BOTTOM) + field_valid = false; + break; + + case V4L2_FIELD_INTERLACED: + case V4L2_FIELD_SEQ_TB: + case V4L2_FIELD_SEQ_BT: + case V4L2_FIELD_INTERLACED_TB: + case V4L2_FIELD_INTERLACED_BT: + if (vbuf->field != q_data->format.field) + field_valid = false; + break; + } + + if (!field_valid) { + dprintk(ctx->fdp1, + "buffer field %u invalid for format field %u\n", + vbuf->field, q_data->format.field); + return -EINVAL; + } + } else { + vbuf->field = V4L2_FIELD_NONE; + } + + /* Validate the planes sizes. */ + for (i = 0; i < q_data->format.num_planes; i++) { + unsigned long size = q_data->format.plane_fmt[i].sizeimage; + + if (vb2_plane_size(vb, i) < size) { + dprintk(ctx->fdp1, + "data will not fit into plane [%u/%u] (%lu < %lu)\n", + i, q_data->format.num_planes, + vb2_plane_size(vb, i), size); + return -EINVAL; + } + + /* We have known size formats all around */ + vb2_set_plane_payload(vb, i, size); + } + + buf->num_fields = V4L2_FIELD_HAS_BOTH(vbuf->field) ? 2 : 1; + for (i = 0; i < buf->num_fields; ++i) + fdp1_buf_prepare_field(q_data, vbuf, i); + + return 0; +} + +static void fdp1_buf_queue(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct fdp1_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); + + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); +} + +static int fdp1_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct fdp1_ctx *ctx = vb2_get_drv_priv(q); + struct fdp1_q_data *q_data = get_q_data(ctx, q->type); + + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + /* + * Force our deint_mode when we are progressive, + * ignoring any setting on the device from the user, + * Otherwise, lock in the requested de-interlace mode. + */ + if (q_data->format.field == V4L2_FIELD_NONE) + ctx->deint_mode = FDP1_PROGRESSIVE; + + if (ctx->deint_mode == FDP1_ADAPT2D3D) { + u32 stride; + dma_addr_t smsk_base; + const u32 bpp = 2; /* bytes per pixel */ + + stride = round_up(q_data->format.width, 8); + + ctx->smsk_size = bpp * stride * q_data->vsize; + + ctx->smsk_cpu = dma_alloc_coherent(ctx->fdp1->dev, + ctx->smsk_size, &smsk_base, GFP_KERNEL); + + if (ctx->smsk_cpu == NULL) { + dprintk(ctx->fdp1, "Failed to alloc smsk\n"); + return -ENOMEM; + } + + ctx->smsk_addr[0] = smsk_base; + ctx->smsk_addr[1] = smsk_base + (ctx->smsk_size/2); + } + } + + return 0; +} + +static void fdp1_stop_streaming(struct vb2_queue *q) +{ + struct fdp1_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vbuf; + unsigned long flags; + + while (1) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (vbuf == NULL) + break; + spin_lock_irqsave(&ctx->fdp1->irqlock, flags); + v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&ctx->fdp1->irqlock, flags); + } + + /* Empty Output queues */ + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + /* Empty our internal queues */ + struct fdp1_field_buffer *fbuf; + + /* Free any queued buffers */ + fbuf = fdp1_dequeue_field(ctx); + while (fbuf != NULL) { + fdp1_field_complete(ctx, fbuf); + fbuf = fdp1_dequeue_field(ctx); + } + + /* Free smsk_data */ + if (ctx->smsk_cpu) { + dma_free_coherent(ctx->fdp1->dev, ctx->smsk_size, + ctx->smsk_cpu, ctx->smsk_addr[0]); + ctx->smsk_addr[0] = ctx->smsk_addr[1] = 0; + ctx->smsk_cpu = NULL; + } + + WARN(!list_empty(&ctx->fields_queue), + "Buffer queue not empty"); + } else { + /* Empty Capture queues (Jobs) */ + struct fdp1_job *job; + + job = get_queued_job(ctx->fdp1); + while (job) { + if (FDP1_DEINT_MODE_USES_PREV(ctx->deint_mode)) + fdp1_field_complete(ctx, job->previous); + else + fdp1_field_complete(ctx, job->active); + + v4l2_m2m_buf_done(job->dst->vb, VB2_BUF_STATE_ERROR); + job->dst = NULL; + + job = get_queued_job(ctx->fdp1); + } + + /* Free any held buffer in the ctx */ + fdp1_field_complete(ctx, ctx->previous); + + WARN(!list_empty(&ctx->fdp1->queued_job_list), + "Queued Job List not empty"); + + WARN(!list_empty(&ctx->fdp1->hw_job_list), + "HW Job list not empty"); + } +} + +static struct vb2_ops fdp1_qops = { + .queue_setup = fdp1_queue_setup, + .buf_prepare = fdp1_buf_prepare, + .buf_queue = fdp1_buf_queue, + .start_streaming = fdp1_start_streaming, + .stop_streaming = fdp1_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int queue_init(void *priv, struct vb2_queue *src_vq, + struct vb2_queue *dst_vq) +{ + struct fdp1_ctx *ctx = priv; + int ret; + + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; + src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + src_vq->drv_priv = ctx; + src_vq->buf_struct_size = sizeof(struct fdp1_buffer); + src_vq->ops = &fdp1_qops; + src_vq->mem_ops = &vb2_dma_contig_memops; + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + src_vq->lock = &ctx->fdp1->dev_mutex; + src_vq->dev = ctx->fdp1->dev; + + ret = vb2_queue_init(src_vq); + if (ret) + return ret; + + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; + dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + dst_vq->drv_priv = ctx; + dst_vq->buf_struct_size = sizeof(struct fdp1_buffer); + dst_vq->ops = &fdp1_qops; + dst_vq->mem_ops = &vb2_dma_contig_memops; + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; + dst_vq->lock = &ctx->fdp1->dev_mutex; + dst_vq->dev = ctx->fdp1->dev; + + return vb2_queue_init(dst_vq); +} + +/* + * File operations + */ +static int fdp1_open(struct file *file) +{ + struct fdp1_dev *fdp1 = video_drvdata(file); + struct v4l2_pix_format_mplane format; + struct fdp1_ctx *ctx = NULL; + struct v4l2_ctrl *ctrl; + int ret = 0; + + if (mutex_lock_interruptible(&fdp1->dev_mutex)) + return -ERESTARTSYS; + + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); + if (!ctx) { + ret = -ENOMEM; + goto done; + } + + v4l2_fh_init(&ctx->fh, video_devdata(file)); + file->private_data = &ctx->fh; + ctx->fdp1 = fdp1; + + /* Initialise Queues */ + INIT_LIST_HEAD(&ctx->fields_queue); + + ctx->translen = 1; + ctx->sequence = 0; + + /* Initialise controls */ + + v4l2_ctrl_handler_init(&ctx->hdl, 3); + v4l2_ctrl_new_std_menu_items(&ctx->hdl, &fdp1_ctrl_ops, + V4L2_CID_DEINTERLACING_MODE, + FDP1_NEXTFIELD, BIT(0), FDP1_FIXED3D, + fdp1_ctrl_deint_menu); + + ctrl = v4l2_ctrl_new_std(&ctx->hdl, &fdp1_ctrl_ops, + V4L2_CID_MIN_BUFFERS_FOR_CAPTURE, 1, 2, 1, 1); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + + v4l2_ctrl_new_std(&ctx->hdl, &fdp1_ctrl_ops, + V4L2_CID_ALPHA_COMPONENT, 0, 255, 1, 255); + + if (ctx->hdl.error) { + ret = ctx->hdl.error; + v4l2_ctrl_handler_free(&ctx->hdl); + goto done; + } + + ctx->fh.ctrl_handler = &ctx->hdl; + v4l2_ctrl_handler_setup(&ctx->hdl); + + /* Configure default parameters. */ + memset(&format, 0, sizeof(format)); + fdp1_set_format(ctx, &format, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); + + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fdp1->m2m_dev, ctx, &queue_init); + + if (IS_ERR(ctx->fh.m2m_ctx)) { + ret = PTR_ERR(ctx->fh.m2m_ctx); + + v4l2_ctrl_handler_free(&ctx->hdl); + kfree(ctx); + goto done; + } + + /* Perform any power management required */ + pm_runtime_get_sync(fdp1->dev); + + v4l2_fh_add(&ctx->fh); + + dprintk(fdp1, "Created instance: %p, m2m_ctx: %p\n", + ctx, ctx->fh.m2m_ctx); + +done: + mutex_unlock(&fdp1->dev_mutex); + return ret; +} + +static int fdp1_release(struct file *file) +{ + struct fdp1_dev *fdp1 = video_drvdata(file); + struct fdp1_ctx *ctx = fh_to_ctx(file->private_data); + + dprintk(fdp1, "Releasing instance %p\n", ctx); + + v4l2_fh_del(&ctx->fh); + v4l2_fh_exit(&ctx->fh); + v4l2_ctrl_handler_free(&ctx->hdl); + mutex_lock(&fdp1->dev_mutex); + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); + mutex_unlock(&fdp1->dev_mutex); + kfree(ctx); + + pm_runtime_put(fdp1->dev); + + return 0; +} + +static const struct v4l2_file_operations fdp1_fops = { + .owner = THIS_MODULE, + .open = fdp1_open, + .release = fdp1_release, + .poll = v4l2_m2m_fop_poll, + .unlocked_ioctl = video_ioctl2, + .mmap = v4l2_m2m_fop_mmap, +}; + +static const struct video_device fdp1_videodev = { + .name = DRIVER_NAME, + .vfl_dir = VFL_DIR_M2M, + .fops = &fdp1_fops, + .device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING, + .ioctl_ops = &fdp1_ioctl_ops, + .minor = -1, + .release = video_device_release_empty, +}; + +static const struct v4l2_m2m_ops m2m_ops = { + .device_run = fdp1_m2m_device_run, + .job_ready = fdp1_m2m_job_ready, + .job_abort = fdp1_m2m_job_abort, +}; + +static irqreturn_t fdp1_irq_handler(int irq, void *dev_id) +{ + struct fdp1_dev *fdp1 = dev_id; + u32 int_status; + u32 ctl_status; + u32 vint_cnt; + u32 cycles; + + int_status = fdp1_read(fdp1, FD1_CTL_IRQSTA); + cycles = fdp1_read(fdp1, FD1_CTL_VCYCLE_STAT); + ctl_status = fdp1_read(fdp1, FD1_CTL_STATUS); + vint_cnt = (ctl_status & FD1_CTL_STATUS_VINT_CNT_MASK) >> + FD1_CTL_STATUS_VINT_CNT_SHIFT; + + /* Clear interrupts */ + fdp1_write(fdp1, ~(int_status) & FD1_CTL_IRQ_MASK, FD1_CTL_IRQSTA); + + if (debug >= 2) { + dprintk(fdp1, "IRQ: 0x%x %s%s%s\n", int_status, + int_status & FD1_CTL_IRQ_VERE ? "[Error]" : "[!E]", + int_status & FD1_CTL_IRQ_VINTE ? "[VSync]" : "[!V]", + int_status & FD1_CTL_IRQ_FREE ? "[FrameEnd]" : "[!F]"); + + dprintk(fdp1, "CycleStatus = %d (%dms)\n", + cycles, cycles/(fdp1->clk_rate/1000)); + + dprintk(fdp1, + "Control Status = 0x%08x : VINT_CNT = %d %s:%s:%s:%s\n", + ctl_status, vint_cnt, + ctl_status & FD1_CTL_STATUS_SGREGSET ? "RegSet" : "", + ctl_status & FD1_CTL_STATUS_SGVERR ? "Vsync Error" : "", + ctl_status & FD1_CTL_STATUS_SGFREND ? "FrameEnd" : "", + ctl_status & FD1_CTL_STATUS_BSY ? "Busy" : ""); + dprintk(fdp1, "***********************************\n"); + } + + /* Spurious interrupt */ + if (!(FD1_CTL_IRQ_MASK & int_status)) + return IRQ_NONE; + + /* Work completed, release the frame */ + if (FD1_CTL_IRQ_VERE & int_status) + device_frame_end(fdp1, VB2_BUF_STATE_ERROR); + else if (FD1_CTL_IRQ_FREE & int_status) + device_frame_end(fdp1, VB2_BUF_STATE_DONE); + + return IRQ_HANDLED; +} + +static int fdp1_probe(struct platform_device *pdev) +{ + struct fdp1_dev *fdp1; + struct video_device *vfd; + struct device_node *fcp_node; + struct resource *res; + struct clk *clk; + unsigned int i; + + int ret; + int hw_version; + + fdp1 = devm_kzalloc(&pdev->dev, sizeof(*fdp1), GFP_KERNEL); + if (!fdp1) + return -ENOMEM; + + INIT_LIST_HEAD(&fdp1->free_job_list); + INIT_LIST_HEAD(&fdp1->queued_job_list); + INIT_LIST_HEAD(&fdp1->hw_job_list); + + /* Initialise the jobs on the free list */ + for (i = 0; i < ARRAY_SIZE(fdp1->jobs); i++) + list_add(&fdp1->jobs[i].list, &fdp1->free_job_list); + + mutex_init(&fdp1->dev_mutex); + + spin_lock_init(&fdp1->irqlock); + spin_lock_init(&fdp1->device_process_lock); + fdp1->dev = &pdev->dev; + platform_set_drvdata(pdev, fdp1); + + /* Memory-mapped registers */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + fdp1->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(fdp1->regs)) + return PTR_ERR(fdp1->regs); + + /* Interrupt service routine registration */ + fdp1->irq = ret = platform_get_irq(pdev, 0); + if (ret < 0) { + dev_err(&pdev->dev, "cannot find IRQ\n"); + return ret; + } + + ret = devm_request_irq(&pdev->dev, fdp1->irq, fdp1_irq_handler, 0, + dev_name(&pdev->dev), fdp1); + if (ret) { + dev_err(&pdev->dev, "cannot claim IRQ %d\n", fdp1->irq); + return ret; + } + + /* FCP */ + fcp_node = of_parse_phandle(pdev->dev.of_node, "renesas,fcp", 0); + if (fcp_node) { + fdp1->fcp = rcar_fcp_get(fcp_node); + of_node_put(fcp_node); + if (IS_ERR(fdp1->fcp)) { + dev_err(&pdev->dev, "FCP not found (%ld)\n", + PTR_ERR(fdp1->fcp)); + return PTR_ERR(fdp1->fcp); + } + } + + /* Determine our clock rate */ + clk = clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) + return PTR_ERR(clk); + + fdp1->clk_rate = clk_get_rate(clk); + clk_put(clk); + + /* V4L2 device registration */ + ret = v4l2_device_register(&pdev->dev, &fdp1->v4l2_dev); + if (ret) { + v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n"); + return ret; + } + + /* M2M registration */ + fdp1->m2m_dev = v4l2_m2m_init(&m2m_ops); + if (IS_ERR(fdp1->m2m_dev)) { + v4l2_err(&fdp1->v4l2_dev, "Failed to init mem2mem device\n"); + ret = PTR_ERR(fdp1->m2m_dev); + goto unreg_dev; + } + + /* Video registration */ + fdp1->vfd = fdp1_videodev; + vfd = &fdp1->vfd; + vfd->lock = &fdp1->dev_mutex; + vfd->v4l2_dev = &fdp1->v4l2_dev; + video_set_drvdata(vfd, fdp1); + strlcpy(vfd->name, fdp1_videodev.name, sizeof(vfd->name)); + + ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0); + if (ret) { + v4l2_err(&fdp1->v4l2_dev, "Failed to register video device\n"); + goto release_m2m; + } + + v4l2_info(&fdp1->v4l2_dev, + "Device registered as /dev/video%d\n", vfd->num); + + /* Power up the cells to read HW */ + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(fdp1->dev); + + hw_version = fdp1_read(fdp1, FD1_IP_INTDATA); + switch (hw_version) { + case FD1_IP_H3: + dprintk(fdp1, "FDP1 Version R-Car H3\n"); + break; + case FD1_IP_M3W: + dprintk(fdp1, "FDP1 Version R-Car M3-W\n"); + break; + default: + dev_err(fdp1->dev, "FDP1 Unidentifiable (0x%08x)\n", + hw_version); + } + + /* Allow the hw to sleep until an open call puts it to use */ + pm_runtime_put(fdp1->dev); + + return 0; + +release_m2m: + v4l2_m2m_release(fdp1->m2m_dev); + +unreg_dev: + v4l2_device_unregister(&fdp1->v4l2_dev); + + return ret; +} + +static int fdp1_remove(struct platform_device *pdev) +{ + struct fdp1_dev *fdp1 = platform_get_drvdata(pdev); + + v4l2_m2m_release(fdp1->m2m_dev); + video_unregister_device(&fdp1->vfd); + v4l2_device_unregister(&fdp1->v4l2_dev); + pm_runtime_disable(&pdev->dev); + + return 0; +} + +static int fdp1_pm_runtime_suspend(struct device *dev) +{ + struct fdp1_dev *fdp1 = dev_get_drvdata(dev); + + rcar_fcp_disable(fdp1->fcp); + + return 0; +} + +static int fdp1_pm_runtime_resume(struct device *dev) +{ + struct fdp1_dev *fdp1 = dev_get_drvdata(dev); + + /* Program in the static LUTs */ + fdp1_set_lut(fdp1); + + return rcar_fcp_enable(fdp1->fcp); +} + +static const struct dev_pm_ops fdp1_pm_ops = { + SET_RUNTIME_PM_OPS(fdp1_pm_runtime_suspend, + fdp1_pm_runtime_resume, + NULL) +}; + +static const struct of_device_id fdp1_dt_ids[] = { + { .compatible = "renesas,fdp1" }, + { }, +}; +MODULE_DEVICE_TABLE(of, fdp1_dt_ids); + +static struct platform_driver fdp1_pdrv = { + .probe = fdp1_probe, + .remove = fdp1_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = fdp1_dt_ids, + .pm = &fdp1_pm_ops, + }, +}; + +module_platform_driver(fdp1_pdrv); + +MODULE_DESCRIPTION("Renesas R-Car Fine Display Processor Driver"); +MODULE_AUTHOR("Kieran Bingham "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRIVER_NAME); -- cgit v1.2.3 From 90b4c9c65ab41d4d20ab5121dd0a536f84565ad5 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Wed, 26 Mar 2014 19:48:39 -0300 Subject: [media] exynos4-is: fimc: Roundup imagesize to row size for tiled formats For tiled format, we need to allocated a multiple of the row size. A good example is for 1280x720, wich get adjusted to 1280x736. In tiles, this mean Y plane is 20x23 and UV plane 20x12. Because of the rounding, the previous code would only have enough space to fit half of the last row. [mchehab@s-opensource.com: fix coding style] Signed-off-by: Nicolas Dufresne Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos4-is/fimc-core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c index 8f89ca21b631..099c735a39b7 100644 --- a/drivers/media/platform/exynos4-is/fimc-core.c +++ b/drivers/media/platform/exynos4-is/fimc-core.c @@ -736,6 +736,7 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, for (i = 0; i < pix->num_planes; ++i) { struct v4l2_plane_pix_format *plane_fmt = &pix->plane_fmt[i]; u32 bpl = plane_fmt->bytesperline; + u32 sizeimage; if (fmt->colplanes > 1 && (bpl == 0 || bpl < pix->width)) bpl = pix->width; /* Planar */ @@ -755,8 +756,17 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, bytesperline /= 2; plane_fmt->bytesperline = bytesperline; - plane_fmt->sizeimage = max((pix->width * pix->height * - fmt->depth[i]) / 8, plane_fmt->sizeimage); + sizeimage = pix->width * pix->height * fmt->depth[i] / 8; + + /* Ensure full last row for tiled formats */ + if (tiled_fmt(fmt)) { + /* 64 * 32 * plane_fmt->bytesperline / 64 */ + u32 row_size = plane_fmt->bytesperline * 32; + + sizeimage = roundup(sizeimage, row_size); + } + + plane_fmt->sizeimage = max(sizeimage, plane_fmt->sizeimage); } } -- cgit v1.2.3 From 0f7a55b4e09fc51413cb9175ee6e701aa6878308 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 18 Oct 2016 21:28:22 -0200 Subject: [media] s5p-mfc: Collapse two error message into one s5p_mfc_alloc_priv_buf() prints two message to report invalid memory configuration error. Collapse them into a single message. Signed-off-by: Shuah Khan Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index 1e7250260a9a..f0f5e8ce5416 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -50,8 +50,7 @@ int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, } if (b->dma < base) { - mfc_err("Invaling memory configuration!\n"); - mfc_err("Allocated buffer (%pad) is lower than memory base address (%pad)\n", + mfc_err("Invalid memory configuration - buffer (%pad) is below base memory address(%pad)\n", &b->dma, &base); dma_free_coherent(dev, b->size, b->virt, b->dma); return -ENOMEM; -- cgit v1.2.3 From def2cc8c4094d89db8289c51decf5a0b00569c16 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 30 Sep 2016 18:16:41 -0300 Subject: [media] exynos-gsc: change spamming try_fmt log message to debug The driver try_fmt handler prints a message each time that the image size has been changed due the maximum and minimum width and height. Since user-space can try different format and sizes, this logs a lot of unnecessary messages. Change the message log level to debug and while being there, also add a new line to the message. Signed-off-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 787bd16c19e5..fac0c0246ad4 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -441,7 +441,7 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f) v4l_bound_align_image(&pix_mp->width, min_w, max_w, mod_x, &pix_mp->height, min_h, max_h, mod_y, 0); if (tmp_w != pix_mp->width || tmp_h != pix_mp->height) - pr_info("Image size has been modified from %dx%d to %dx%d", + pr_debug("Image size has been modified from %dx%d to %dx%d\n", tmp_w, tmp_h, pix_mp->width, pix_mp->height); pix_mp->num_planes = fmt->num_planes; -- cgit v1.2.3 From daba4dfbd298ac76e4064a97b88c717cacf43a6f Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 30 Sep 2016 18:16:42 -0300 Subject: [media] exynos-gsc: don't clear format when freeing buffers with REQBUFS(0) User-space applications can use the VIDIOC_REQBUFS ioctl to determine if a memory mapped, user pointer or DMABUF based I/O is supported by a driver. For example, GStreamer attempts to determine the I/O methods supported by the driver by doing many VIDIOC_REQBUFS ioctl calls with different memory types and count 0. And then the real VIDIOC_REQBUFS call with count == n is be made to allocate the buffers. But for count 0, the driver not only frees the buffers but also clears the format set before with VIDIOC_S_FMT. This is a problem since STREAMON fails if a format isn't set but GStreamer first sets a format and then tries to determine the supported I/O methods, so the format will be cleared on REQBUFS(0), before the call to STREAMON. To avoid this issue, only free the buffers on VIDIOC_REQBUFS(0) but don't clear the format. Since is completely valid to set the format and then do different calls to REQBUFS before a call to STREAMON. Signed-off-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index 9f03b791b711..e2a16b52f87d 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -365,14 +365,8 @@ static int gsc_m2m_reqbufs(struct file *file, void *fh, max_cnt = (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? gsc->variant->in_buf_cnt : gsc->variant->out_buf_cnt; - if (reqbufs->count > max_cnt) { + if (reqbufs->count > max_cnt) return -EINVAL; - } else if (reqbufs->count == 0) { - if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) - gsc_ctx_state_lock_clear(GSC_SRC_FMT, ctx); - else - gsc_ctx_state_lock_clear(GSC_DST_FMT, ctx); - } return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs); } -- cgit v1.2.3 From 8a661745b7adb0e3680af3840d4e5dac54afa3d8 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 30 Sep 2016 18:16:43 -0300 Subject: [media] exynos-gsc: fix supported RGB pixel format The driver exposes 32-bit A/XRGB 8-8-8-8 as supported format but testing shows that using this format produces frames with wrong colors. The test was done with the following GStreamer pipeline: $ gst-launch-1.0 videotestsrc num-buffers=20 ! video/x-raw,format=UYVY \ ! v4l2video3convert ! video/x-raw,format=xRGB ! videoconvert ! kmssink The manual seems to state that the Pixel Format are in Little Endianness so instead use the 32-bit BGRA/X 8-8-8-8 pixel format. This format works correctly when using the following pipeline: $ gst-launch-1.0 videotestsrc num-buffers=20 ! video/x-raw,format=UYVY \ ! v4l2video3convert ! video/x-raw,format=BGRx ! kmssink This change is similar to commit 7f2816e51ea1 ("[media] s5p-fimc: Changed RGB32 to BGR32") that fixed the same issue on a different Samsung driver. Suggested-by: Nicolas Dufresne Signed-off-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index fac0c0246ad4..8bb1d2be7234 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -39,8 +39,8 @@ static const struct gsc_fmt gsc_formats[] = { .num_planes = 1, .num_comp = 1, }, { - .name = "XRGB-8-8-8-8, 32 bpp", - .pixelformat = V4L2_PIX_FMT_RGB32, + .name = "BGRX-8-8-8-8, 32 bpp", + .pixelformat = V4L2_PIX_FMT_BGR32, .depth = { 32 }, .color = GSC_RGB, .num_planes = 1, -- cgit v1.2.3 From 652bb68018a557c795db9a24cf8e84280340b38e Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 30 Sep 2016 18:16:44 -0300 Subject: [media] exynos-gsc: do proper bytesperline and sizeimage calculation The driver don't take into account the differences between packed, semi planar and multi planar formats when calculating the pixel format bytes per lines and image size values. This makes GStreamer to fail when the following formats are used NV12, NV21, NV16, NV61, YV12, I420 and Y42B: "gst_video_frame_map_id: failed to map video frame plane 1" Nicolas suggested to use the logic found in the Exynos FIMC v4l2 driver since does this correctly. So this patch changes the bytes per line and image size calculation according to what's done in this media driver. After this patch most supported formats work correctly. There are still issues with the NV21 and NV61 formats, but that seems to be a separate problem since NV12 and NV16 work and these formats use the same values. So this can be fixed as a follow-up and shouldn't be a blocker for this change that improves the driver's support. Suggested-by: Nicolas Dufresne Signed-off-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 8bb1d2be7234..a6c47deba3b7 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -451,12 +451,25 @@ int gsc_try_fmt_mplane(struct gsc_ctx *ctx, struct v4l2_format *f) else /* SD */ pix_mp->colorspace = V4L2_COLORSPACE_SMPTE170M; - for (i = 0; i < pix_mp->num_planes; ++i) { - int bpl = (pix_mp->width * fmt->depth[i]) >> 3; - pix_mp->plane_fmt[i].bytesperline = bpl; - pix_mp->plane_fmt[i].sizeimage = bpl * pix_mp->height; + struct v4l2_plane_pix_format *plane_fmt = &pix_mp->plane_fmt[i]; + u32 bpl = plane_fmt->bytesperline; + + if (fmt->num_comp == 1 && /* Packed */ + (bpl == 0 || (bpl * 8 / fmt->depth[i]) < pix_mp->width)) + bpl = pix_mp->width * fmt->depth[i] / 8; + + if (fmt->num_comp > 1 && /* Planar */ + (bpl == 0 || bpl < pix_mp->width)) + bpl = pix_mp->width; + + if (i != 0 && fmt->num_comp == 3) + bpl /= 2; + plane_fmt->bytesperline = bpl; + plane_fmt->sizeimage = max(pix_mp->width * pix_mp->height * + fmt->depth[i] / 8, + plane_fmt->sizeimage); pr_debug("[%d]: bpl: %d, sizeimage: %d", i, bpl, pix_mp->plane_fmt[i].sizeimage); } -- cgit v1.2.3 From f4ca5030b3a34bc7017c195e89181deaa5ee9a42 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 7 Oct 2016 17:39:17 -0300 Subject: [media] exynos-gsc: don't release a non-dynamically allocated video_device The struct v4l2_device instance for the G-Scaler is not dyanmically allocated but a member of the struct gsc_dev. In fact, the assigned .release callback is video_device_release_empty(). But gsc_register_m2m_device() attempts to release the v4l2_device by calling video_device_release() in its error path. This is wrong since the v4l2_device wasn't allocated directly and will be freed once its parent struct gsc_dev is freed. While being there, rename the remaining goto label in the error path to something that better explains the error path cleanup. Signed-off-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index e2a16b52f87d..a1cac52ea230 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -760,24 +760,21 @@ int gsc_register_m2m_device(struct gsc_dev *gsc) gsc->m2m.m2m_dev = v4l2_m2m_init(&gsc_m2m_ops); if (IS_ERR(gsc->m2m.m2m_dev)) { dev_err(&pdev->dev, "failed to initialize v4l2-m2m device\n"); - ret = PTR_ERR(gsc->m2m.m2m_dev); - goto err_m2m_r1; + return PTR_ERR(gsc->m2m.m2m_dev); } ret = video_register_device(&gsc->vdev, VFL_TYPE_GRABBER, -1); if (ret) { dev_err(&pdev->dev, "%s(): failed to register video device\n", __func__); - goto err_m2m_r2; + goto err_m2m_release; } pr_debug("gsc m2m driver registered as /dev/video%d", gsc->vdev.num); return 0; -err_m2m_r2: +err_m2m_release: v4l2_m2m_release(gsc->m2m.m2m_dev); -err_m2m_r1: - video_device_release(gsc->m2m.vfd); return ret; } -- cgit v1.2.3 From 115a16ba3fa492a13b5530c982fec1ecac5666a1 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 7 Oct 2016 17:39:18 -0300 Subject: [media] exynos-gsc: unregister video device node on driver removal The driver doesn't unregister the video device node when the driver is removed, this keeps video device nodes that makes the machine to crash with a NULL pointer dereference when nodes are attempted to be opened: [ 36.530006] Unable to handle kernel paging request at virtual address bf1f8200 [ 36.535985] pgd = edbbc000 [ 36.538486] [bf1f8200] *pgd=6d99a811, *pte=00000000, *ppte=00000000 [ 36.544727] Internal error: Oops: 7 [#1] PREEMPT SMP ARM [ 36.550016] Modules linked in: s5p_jpeg s5p_mfc v4l2_mem2mem videobuf2_dma_contig [ 36.566303] CPU: 6 PID: 533 Comm: v4l2-ctl Not tainted 4.8.0 [ 36.574466] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 36.580526] task: ee3cc600 task.stack: ed626000 [ 36.585046] PC is at try_module_get+0x1c/0xac [ 36.589364] LR is at try_module_get+0x1c/0xac [ 36.593698] pc : [] lr : [] psr: 80070013 [ 36.593698] sp : ed627de0 ip : a0070013 fp : 00000000 [ 36.605156] r10: 00000002 r9 : ed627ed0 r8 : 00000000 [ 36.610331] r7 : c01e5f14 r6 : ed57be00 r5 : bf1f8200 r4 : bf1f8200 [ 36.616834] r3 : 00000002 r2 : 00000002 r1 : 01930192 r0 : 00000001 .. [ 36.785004] [] (try_module_get) from [] (cdev_get+0x1c/0x4c) [ 36.792362] [] (cdev_get) from [] (chrdev_open+0x2c/0x178) [ 36.799555] [] (chrdev_open) from [] (do_dentry_open+0x1e0/0x300) [ 36.807360] [] (do_dentry_open) from [] (path_openat+0x35c/0xf58) [ 36.815154] [] (path_openat) from [] (do_filp_open+0x5c/0xc0) [ 36.822606] [] (do_filp_open) from [] (do_sys_open+0x10c/0x1bc) [ 36.830235] [] (do_sys_open) from [] (ret_fast_syscall+0x0/0x3c) [ 36.837942] Code: 0a00001c e1a04000 e3a00001 ebfec92d (e5943000) Signed-off-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index a1cac52ea230..c8c0bcec35ed 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -781,6 +781,8 @@ err_m2m_release: void gsc_unregister_m2m_device(struct gsc_dev *gsc) { - if (gsc) + if (gsc) { v4l2_m2m_release(gsc->m2m.m2m_dev); + video_unregister_device(&gsc->vdev); + } } -- cgit v1.2.3 From 76ca0824afef3d18c555ab01fcdd222075e0b14d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 7 Oct 2016 17:39:19 -0300 Subject: [media] exynos-gsc: cleanup m2m src and dst vb2 queues on STREAMOFF Media drivers that use the videobuf2 framework have to give back to vb2 all the buffers that received from vb2 using its .buf_queue callback. But the exynos-gsc driver isn't doing a proper cleanup so vb2 complains that the number of buffers enqueued and received are not balanced: WARNING: CPU: 2 PID: 660 at drivers/media/v4l2-core/videobuf2-core.c:1654 __vb2_queue_cancel+0xec/0x150 [videobuf2_core] Modules linked in: mwifiex_sdio mwifiex uvcvideo exynos_gsc videobuf2_vmalloc s5p_mfc s5p_jpeg CPU: 2 PID: 660 Comm: lt-gst-validate Not tainted 4.8.0 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [] (unwind_backtrace) from [] (show_stack+0x10/0x14) [] (show_stack) from [] (dump_stack+0x88/0x9c) [] (dump_stack) from [] (__warn+0xe8/0x100) [] (__warn) from [] (warn_slowpath_null+0x20/0x28) [] (warn_slowpath_null) from [] (__vb2_queue_cancel+0xec/0x150 [videobuf2_core]) [] (__vb2_queue_cancel [videobuf2_core]) from [] (vb2_core_streamoff+0x34/0x9c [videobuf2_core]) [] (vb2_core_streamoff [videobuf2_core]) from [] (v4l2_m2m_streamoff+0x2c/0xe4 [v4l2_mem2mem]) [] (v4l2_m2m_streamoff [v4l2_mem2mem]) from [] (__video_do_ioctl+0x298/0x30c [videodev]) [] (__video_do_ioctl [videodev]) from [] (video_usercopy+0x174/0x4e8 [videodev]) [] (video_usercopy [videodev]) from [] (v4l2_ioctl+0xc4/0xd8 [videodev]) [] (v4l2_ioctl [videodev]) from [] (do_vfs_ioctl+0x9c/0x8f4) [] (do_vfs_ioctl) from [] (SyS_ioctl+0x34/0x5c) [] (SyS_ioctl) from [] (ret_fast_syscall+0x0/0x3c) Fix this by passing back to vb2 all the received buffers that were not processed. Signed-off-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-m2m.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c index c8c0bcec35ed..f49f24b4462a 100644 --- a/drivers/media/platform/exynos-gsc/gsc-m2m.c +++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c @@ -66,12 +66,29 @@ static int gsc_m2m_start_streaming(struct vb2_queue *q, unsigned int count) return ret > 0 ? 0 : ret; } +static void __gsc_m2m_cleanup_queue(struct gsc_ctx *ctx) +{ + struct vb2_v4l2_buffer *src_vb, *dst_vb; + + while (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) > 0) { + src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR); + } + + while (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) > 0) { + dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx); + v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR); + } +} + static void gsc_m2m_stop_streaming(struct vb2_queue *q) { struct gsc_ctx *ctx = q->drv_priv; __gsc_m2m_job_abort(ctx); + __gsc_m2m_cleanup_queue(ctx); + pm_runtime_put(&ctx->gsc_dev->pdev->dev); } -- cgit v1.2.3 From 43e6347f400d8bf8beff56a164c6a7e8c3d0ba5f Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Mon, 7 Nov 2016 21:39:25 -0200 Subject: [media] s5p-mfc: include buffer size in error message Include buffer size in s5p_mfc_alloc_priv_buf() the error message when it fails to allocate the buffer. Signed-off-by: Shuah Khan Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_opr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c index f0f5e8ce5416..99f65a92a6be 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr.c @@ -45,7 +45,8 @@ int s5p_mfc_alloc_priv_buf(struct device *dev, dma_addr_t base, b->virt = dma_alloc_coherent(dev, b->size, &b->dma, GFP_KERNEL); if (!b->virt) { - mfc_err("Allocating private buffer failed\n"); + mfc_err("Allocating private buffer of size %zu failed\n", + b->size); return -ENOMEM; } -- cgit v1.2.3 From d83db90456d5d1bbf6a73e9cf7848afcdfff205c Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 12:23:50 -0200 Subject: [media] exynos-gsc: Simplify clock management Instead of having separate functions that fetches, prepares and unprepares the clock, let's encapsulate this code into ->probe(). This makes error handling easier and decreases the lines of code. [mszyprow: rebased onto v4.9-rc4] Signed-off-by: Ulf Hansson Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 49 ++++++++-------------------- 1 file changed, 14 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index a6c47deba3b7..183c6e4e915f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1001,36 +1001,6 @@ static void *gsc_get_drv_data(struct platform_device *pdev) return driver_data; } -static void gsc_clk_put(struct gsc_dev *gsc) -{ - if (!IS_ERR(gsc->clock)) - clk_unprepare(gsc->clock); -} - -static int gsc_clk_get(struct gsc_dev *gsc) -{ - int ret; - - dev_dbg(&gsc->pdev->dev, "gsc_clk_get Called\n"); - - gsc->clock = devm_clk_get(&gsc->pdev->dev, GSC_CLOCK_GATE_NAME); - if (IS_ERR(gsc->clock)) { - dev_err(&gsc->pdev->dev, "failed to get clock~~~: %s\n", - GSC_CLOCK_GATE_NAME); - return PTR_ERR(gsc->clock); - } - - ret = clk_prepare(gsc->clock); - if (ret < 0) { - dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n", - GSC_CLOCK_GATE_NAME); - gsc->clock = ERR_PTR(-EINVAL); - return ret; - } - - return 0; -} - static int gsc_m2m_suspend(struct gsc_dev *gsc) { unsigned long flags; @@ -1098,7 +1068,6 @@ static int gsc_probe(struct platform_device *pdev) init_waitqueue_head(&gsc->irq_queue); spin_lock_init(&gsc->slock); mutex_init(&gsc->lock); - gsc->clock = ERR_PTR(-EINVAL); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); gsc->regs = devm_ioremap_resource(dev, res); @@ -1111,9 +1080,19 @@ static int gsc_probe(struct platform_device *pdev) return -ENXIO; } - ret = gsc_clk_get(gsc); - if (ret) + gsc->clock = devm_clk_get(dev, GSC_CLOCK_GATE_NAME); + if (IS_ERR(gsc->clock)) { + dev_err(dev, "failed to get clock~~~: %s\n", + GSC_CLOCK_GATE_NAME); + return PTR_ERR(gsc->clock); + } + + ret = clk_prepare(gsc->clock); + if (ret) { + dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n", + GSC_CLOCK_GATE_NAME); return ret; + } ret = devm_request_irq(dev, res->start, gsc_irq_handler, 0, pdev->name, gsc); @@ -1148,7 +1127,7 @@ err_m2m: err_v4l2: v4l2_device_unregister(&gsc->v4l2_dev); err_clk: - gsc_clk_put(gsc); + clk_unprepare(gsc->clock); return ret; } @@ -1161,7 +1140,7 @@ static int gsc_remove(struct platform_device *pdev) vb2_dma_contig_clear_max_seg_size(&pdev->dev); pm_runtime_disable(&pdev->dev); - gsc_clk_put(gsc); + clk_unprepare(gsc->clock); dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); return 0; -- cgit v1.2.3 From f9fd6ee6fb504b99c63831ae1f166f6bdda47d0b Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 12:23:51 -0200 Subject: [media] exynos-gsc: Convert gsc_m2m_resume() from int to void Since gsc_m2m_resume() always returns 0, convert it to a void instead. [mszyprow: rebased onto v4.9-rc4] Signed-off-by: Ulf Hansson Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 183c6e4e915f..945042c346e7 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1023,7 +1023,7 @@ static int gsc_m2m_suspend(struct gsc_dev *gsc) return timeout == 0 ? -EAGAIN : 0; } -static int gsc_m2m_resume(struct gsc_dev *gsc) +static void gsc_m2m_resume(struct gsc_dev *gsc) { struct gsc_ctx *ctx; unsigned long flags; @@ -1036,8 +1036,6 @@ static int gsc_m2m_resume(struct gsc_dev *gsc) if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state)) gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); - - return 0; } static int gsc_probe(struct platform_device *pdev) @@ -1159,8 +1157,9 @@ static int gsc_runtime_resume(struct device *dev) gsc_hw_set_sw_reset(gsc); gsc_wait_reset(gsc); + gsc_m2m_resume(gsc); - return gsc_m2m_resume(gsc); + return 0; } static int gsc_runtime_suspend(struct device *dev) -- cgit v1.2.3 From 15f90ab57acc318a90578a2e05b7b450e0e3cfe0 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 12:23:52 -0200 Subject: [media] exynos-gsc: Make driver functional when CONFIG_PM is unset The driver depended on CONFIG_PM to be functional. Let's remove that dependency, by enable the runtime PM resourses during ->probe() and update the device's runtime PM status to reflect this. [mszyprow: rebased onto v4.9-rc4] Signed-off-by: Ulf Hansson Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 945042c346e7..7539bb3e318f 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1085,7 +1085,7 @@ static int gsc_probe(struct platform_device *pdev) return PTR_ERR(gsc->clock); } - ret = clk_prepare(gsc->clock); + ret = clk_prepare_enable(gsc->clock); if (ret) { dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n", GSC_CLOCK_GATE_NAME); @@ -1108,24 +1108,23 @@ static int gsc_probe(struct platform_device *pdev) goto err_v4l2; platform_set_drvdata(pdev, gsc); - pm_runtime_enable(dev); - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) - goto err_m2m; + + gsc_hw_set_sw_reset(gsc); + gsc_wait_reset(gsc); vb2_dma_contig_set_max_seg_size(dev, DMA_BIT_MASK(32)); dev_dbg(dev, "gsc-%d registered successfully\n", gsc->id); - pm_runtime_put(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + return 0; -err_m2m: - gsc_unregister_m2m_device(gsc); err_v4l2: v4l2_device_unregister(&gsc->v4l2_dev); err_clk: - clk_unprepare(gsc->clock); + clk_disable_unprepare(gsc->clock); return ret; } -- cgit v1.2.3 From 81aa8d141f84868f3523eeab6ced4991819e7f18 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Mon, 14 Nov 2016 08:27:32 -0200 Subject: [media] exynos-gsc: Make PM callbacks available conditionally There are no need to set up the PM callbacks (runtime and system) unless they are being used. It also causes compiler warnings about unused functions. Silence the warnings by making them available for CONFIG_PM (runtime callbacks) and CONFIG_PM_SLEEP (system sleep callbacks). [mszyprow: squashed two patches into one to avoid potential build break, changed patch subject and updated commit message] Signed-off-by: Ulf Hansson Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 84 ++++++++++++++-------------- 1 file changed, 43 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 7539bb3e318f..19fcbc7424fc 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1001,43 +1001,6 @@ static void *gsc_get_drv_data(struct platform_device *pdev) return driver_data; } -static int gsc_m2m_suspend(struct gsc_dev *gsc) -{ - unsigned long flags; - int timeout; - - spin_lock_irqsave(&gsc->slock, flags); - if (!gsc_m2m_pending(gsc)) { - spin_unlock_irqrestore(&gsc->slock, flags); - return 0; - } - clear_bit(ST_M2M_SUSPENDED, &gsc->state); - set_bit(ST_M2M_SUSPENDING, &gsc->state); - spin_unlock_irqrestore(&gsc->slock, flags); - - timeout = wait_event_timeout(gsc->irq_queue, - test_bit(ST_M2M_SUSPENDED, &gsc->state), - GSC_SHUTDOWN_TIMEOUT); - - clear_bit(ST_M2M_SUSPENDING, &gsc->state); - return timeout == 0 ? -EAGAIN : 0; -} - -static void gsc_m2m_resume(struct gsc_dev *gsc) -{ - struct gsc_ctx *ctx; - unsigned long flags; - - spin_lock_irqsave(&gsc->slock, flags); - /* Clear for full H/W setup in first run after resume */ - ctx = gsc->m2m.ctx; - gsc->m2m.ctx = NULL; - spin_unlock_irqrestore(&gsc->slock, flags); - - if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state)) - gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); -} - static int gsc_probe(struct platform_device *pdev) { struct gsc_dev *gsc; @@ -1143,6 +1106,44 @@ static int gsc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM +static int gsc_m2m_suspend(struct gsc_dev *gsc) +{ + unsigned long flags; + int timeout; + + spin_lock_irqsave(&gsc->slock, flags); + if (!gsc_m2m_pending(gsc)) { + spin_unlock_irqrestore(&gsc->slock, flags); + return 0; + } + clear_bit(ST_M2M_SUSPENDED, &gsc->state); + set_bit(ST_M2M_SUSPENDING, &gsc->state); + spin_unlock_irqrestore(&gsc->slock, flags); + + timeout = wait_event_timeout(gsc->irq_queue, + test_bit(ST_M2M_SUSPENDED, &gsc->state), + GSC_SHUTDOWN_TIMEOUT); + + clear_bit(ST_M2M_SUSPENDING, &gsc->state); + return timeout == 0 ? -EAGAIN : 0; +} + +static void gsc_m2m_resume(struct gsc_dev *gsc) +{ + struct gsc_ctx *ctx; + unsigned long flags; + + spin_lock_irqsave(&gsc->slock, flags); + /* Clear for full H/W setup in first run after resume */ + ctx = gsc->m2m.ctx; + gsc->m2m.ctx = NULL; + spin_unlock_irqrestore(&gsc->slock, flags); + + if (test_and_clear_bit(ST_M2M_SUSPENDED, &gsc->state)) + gsc_m2m_job_finish(ctx, VB2_BUF_STATE_ERROR); +} + static int gsc_runtime_resume(struct device *dev) { struct gsc_dev *gsc = dev_get_drvdata(dev); @@ -1173,7 +1174,9 @@ static int gsc_runtime_suspend(struct device *dev) pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state); return ret; } +#endif +#ifdef CONFIG_PM_SLEEP static int gsc_resume(struct device *dev) { struct gsc_dev *gsc = dev_get_drvdata(dev); @@ -1210,12 +1213,11 @@ static int gsc_suspend(struct device *dev) return 0; } +#endif static const struct dev_pm_ops gsc_pm_ops = { - .suspend = gsc_suspend, - .resume = gsc_resume, - .runtime_suspend = gsc_runtime_suspend, - .runtime_resume = gsc_runtime_resume, + SET_SYSTEM_SLEEP_PM_OPS(gsc_suspend, gsc_resume) + SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL) }; static struct platform_driver gsc_driver = { -- cgit v1.2.3 From a006c04e6218bb82c11888d9b99ef642bd64cf93 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 12:23:54 -0200 Subject: [media] exynos-gsc: Fixup clock management at ->remove() To make sure the clock is fully gated in ->remove(), we first need to to bring the device into full power by invoking pm_runtime_get_sync(). Then, let's both unprepare and disable the clock. [mszyprow: rebased onto v4.9-rc4] Signed-off-by: Ulf Hansson Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 19fcbc7424fc..e62765328848 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1095,12 +1095,15 @@ static int gsc_remove(struct platform_device *pdev) { struct gsc_dev *gsc = platform_get_drvdata(pdev); + pm_runtime_get_sync(&pdev->dev); + gsc_unregister_m2m_device(gsc); v4l2_device_unregister(&gsc->v4l2_dev); vb2_dma_contig_clear_max_seg_size(&pdev->dev); - pm_runtime_disable(&pdev->dev); - clk_unprepare(gsc->clock); + clk_disable_unprepare(gsc->clock); + + pm_runtime_put_noidle(&pdev->dev); dev_dbg(&pdev->dev, "%s driver unloaded\n", pdev->name); return 0; -- cgit v1.2.3 From 7ebcb3e842bd933fa6792414a3b369a661d99665 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 12:23:55 -0200 Subject: [media] exynos-gsc: Do full clock gating at runtime PM suspend To potentially save more power in runtime PM suspend state, let's also prepare/unprepare the clock from the runtime PM callbacks. [mszyprow: rebased onto v4.9-rc4] Signed-off-by: Ulf Hansson Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index e62765328848..3ac588f5c558 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1154,7 +1154,7 @@ static int gsc_runtime_resume(struct device *dev) pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state); - ret = clk_enable(gsc->clock); + ret = clk_prepare_enable(gsc->clock); if (ret) return ret; @@ -1172,7 +1172,7 @@ static int gsc_runtime_suspend(struct device *dev) ret = gsc_m2m_suspend(gsc); if (!ret) - clk_disable(gsc->clock); + clk_disable_unprepare(gsc->clock); pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state); return ret; -- cgit v1.2.3 From 701a8de6ef4ee1a5000144cc7d66ecc343598e14 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 9 Nov 2016 12:23:57 -0200 Subject: [media] exynos-gsc: Simplify system PM It's not needed to keep a local flag about the current system PM state. Let's just remove that code and the corresponding debug print. [mszyprow: rebased onto v4.9-rc4] Signed-off-by: Ulf Hansson Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 21 --------------------- drivers/media/platform/exynos-gsc/gsc-core.h | 3 --- 2 files changed, 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 3ac588f5c558..5aeb8b44eacd 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1182,20 +1182,6 @@ static int gsc_runtime_suspend(struct device *dev) #ifdef CONFIG_PM_SLEEP static int gsc_resume(struct device *dev) { - struct gsc_dev *gsc = dev_get_drvdata(dev); - unsigned long flags; - - pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state); - - /* Do not resume if the device was idle before system suspend */ - spin_lock_irqsave(&gsc->slock, flags); - if (!test_and_clear_bit(ST_SUSPEND, &gsc->state) || - !gsc_m2m_opened(gsc)) { - spin_unlock_irqrestore(&gsc->slock, flags); - return 0; - } - spin_unlock_irqrestore(&gsc->slock, flags); - if (!pm_runtime_suspended(dev)) return gsc_runtime_resume(dev); @@ -1204,13 +1190,6 @@ static int gsc_resume(struct device *dev) static int gsc_suspend(struct device *dev) { - struct gsc_dev *gsc = dev_get_drvdata(dev); - - pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state); - - if (test_and_set_bit(ST_SUSPEND, &gsc->state)) - return 0; - if (!pm_runtime_suspended(dev)) return gsc_runtime_suspend(dev); diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 7ad7b9dc2243..8480aec05441 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -48,9 +48,6 @@ #define GSC_CTX_ABORT (1 << 7) enum gsc_dev_flags { - /* for global */ - ST_SUSPEND, - /* for m2m node */ ST_M2M_OPEN, ST_M2M_RUN, -- cgit v1.2.3 From 8098f9ca949006578d8127cbaa46a84699066959 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Nov 2016 12:23:58 -0200 Subject: [media] exynos-gsc: Simplify system PM even more System PM callbacks only ensure that device is runtime suspended/resumed, so remove them and use generic pm_runtime_force_suspend/resume helper. Signed-off-by: Marek Szyprowski Reviewed-by: Ulf Hansson Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 5aeb8b44eacd..45a62216385a 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1179,26 +1179,9 @@ static int gsc_runtime_suspend(struct device *dev) } #endif -#ifdef CONFIG_PM_SLEEP -static int gsc_resume(struct device *dev) -{ - if (!pm_runtime_suspended(dev)) - return gsc_runtime_resume(dev); - - return 0; -} - -static int gsc_suspend(struct device *dev) -{ - if (!pm_runtime_suspended(dev)) - return gsc_runtime_suspend(dev); - - return 0; -} -#endif - static const struct dev_pm_ops gsc_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(gsc_suspend, gsc_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) SET_RUNTIME_PM_OPS(gsc_runtime_suspend, gsc_runtime_resume, NULL) }; -- cgit v1.2.3 From d641cf26941ecfe75b99472738447b692775944a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Nov 2016 12:23:59 -0200 Subject: [media] exynos-gsc: Remove unused lclk_freqency entry Remove dead, unused code. Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 1 - drivers/media/platform/exynos-gsc/gsc-core.h | 2 -- 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index 45a62216385a..aa4db1dfc438 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -977,7 +977,6 @@ static struct gsc_driverdata gsc_v_100_drvdata = { [3] = &gsc_v_100_variant, }, .num_entities = 4, - .lclk_frequency = 266000000UL, }; static const struct of_device_id exynos_gsc_match[] = { diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index 8480aec05441..e5aa8f42f11e 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -303,12 +303,10 @@ struct gsc_variant { * struct gsc_driverdata - per device type driver data for init time. * * @variant: the variant information for this driver. - * @lclk_frequency: G-Scaler clock frequency * @num_entities: the number of g-scalers */ struct gsc_driverdata { struct gsc_variant *variant[GSC_MAX_DEVS]; - unsigned long lclk_frequency; int num_entities; }; -- cgit v1.2.3 From e0f013990e5bb68aec8d70dd5b35a6b81da836f7 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Nov 2016 12:24:00 -0200 Subject: [media] exynos-gsc: Add missing newline char in debug messages Fix missing newline char in debug messages. Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index aa4db1dfc438..c7693c6296bf 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -1151,7 +1151,7 @@ static int gsc_runtime_resume(struct device *dev) struct gsc_dev *gsc = dev_get_drvdata(dev); int ret = 0; - pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state); + pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); ret = clk_prepare_enable(gsc->clock); if (ret) @@ -1173,7 +1173,7 @@ static int gsc_runtime_suspend(struct device *dev) if (!ret) clk_disable_unprepare(gsc->clock); - pr_debug("gsc%d: state: 0x%lx", gsc->id, gsc->state); + pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); return ret; } #endif -- cgit v1.2.3 From aa7929f5954ce7232bdd9a5fe01d7458f95d104b Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Nov 2016 12:24:01 -0200 Subject: [media] exynos-gsc: Use of_device_get_match_data() helper Replace open-coded driver data extraction code with generic helper. Signed-off-by: Marek Szyprowski Tested-by: Javier Martinez Canillas Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/exynos-gsc/gsc-core.c | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index c7693c6296bf..f0d8e2433299 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "gsc-core.h" @@ -988,24 +989,12 @@ static const struct of_device_id exynos_gsc_match[] = { }; MODULE_DEVICE_TABLE(of, exynos_gsc_match); -static void *gsc_get_drv_data(struct platform_device *pdev) -{ - struct gsc_driverdata *driver_data = NULL; - const struct of_device_id *match; - - match = of_match_node(exynos_gsc_match, pdev->dev.of_node); - if (match) - driver_data = (struct gsc_driverdata *)match->data; - - return driver_data; -} - static int gsc_probe(struct platform_device *pdev) { struct gsc_dev *gsc; struct resource *res; - struct gsc_driverdata *drv_data = gsc_get_drv_data(pdev); struct device *dev = &pdev->dev; + const struct gsc_driverdata *drv_data = of_device_get_match_data(dev); int ret; gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL); -- cgit v1.2.3 From 6f99e1b85af48275f9d4cbcfd86275220c055ac9 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Nov 2016 12:29:37 -0200 Subject: [media] exynos-gsc: Enable driver on ARCH_EXYNOS This driver can be also used on Exynos5433, which is ARM64-based platform, which selects only ARCH_EXYNOS symbol. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 84f44098dc99..3c5a0b6b23a9 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -266,7 +266,7 @@ config VIDEO_MX2_EMMAPRP 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 ARCH_EXYNOS || COMPILE_TEST depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV -- cgit v1.2.3 From 92955ea0baf4315342d66eaf824deffed431c3be Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 9 Nov 2016 12:29:38 -0200 Subject: [media] exynos-gsc: Add support for Exynos5433 specific version This patch adds support for Exynos5433 specific version of the GScaler module. The main difference between Exynos 5433 and earlier is addition of new clocks that have to be controlled. Signed-off-by: Marek Szyprowski Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Acked-by: Krzysztof Kozlowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/exynos5-gsc.txt | 3 +- drivers/media/platform/exynos-gsc/gsc-core.c | 74 ++++++++++++++++------ drivers/media/platform/exynos-gsc/gsc-core.h | 6 +- 3 files changed, 62 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/media/exynos5-gsc.txt b/Documentation/devicetree/bindings/media/exynos5-gsc.txt index 5fe9372abb37..26ca25b6d264 100644 --- a/Documentation/devicetree/bindings/media/exynos5-gsc.txt +++ b/Documentation/devicetree/bindings/media/exynos5-gsc.txt @@ -3,7 +3,8 @@ G-Scaler is used for scaling and color space conversion on EXYNOS5 SoCs. Required properties: -- compatible: should be "samsung,exynos5-gsc" +- compatible: should be "samsung,exynos5-gsc" (for Exynos 5250, 5420 and + 5422 SoCs) or "samsung,exynos5433-gsc" (Exynos 5433) - reg: should contain G-Scaler physical address location and length. - interrupts: should contain G-Scaler interrupt number diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c index f0d8e2433299..cbf75b6194b4 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.c +++ b/drivers/media/platform/exynos-gsc/gsc-core.c @@ -29,8 +29,6 @@ #include "gsc-core.h" -#define GSC_CLOCK_GATE_NAME "gscl" - static const struct gsc_fmt gsc_formats[] = { { .name = "RGB565", @@ -978,6 +976,19 @@ static struct gsc_driverdata gsc_v_100_drvdata = { [3] = &gsc_v_100_variant, }, .num_entities = 4, + .clk_names = { "gscl" }, + .num_clocks = 1, +}; + +static struct gsc_driverdata gsc_5433_drvdata = { + .variant = { + [0] = &gsc_v_100_variant, + [1] = &gsc_v_100_variant, + [2] = &gsc_v_100_variant, + }, + .num_entities = 3, + .clk_names = { "pclk", "aclk", "aclk_xiu", "aclk_gsclbend" }, + .num_clocks = 4, }; static const struct of_device_id exynos_gsc_match[] = { @@ -985,6 +996,10 @@ static const struct of_device_id exynos_gsc_match[] = { .compatible = "samsung,exynos5-gsc", .data = &gsc_v_100_drvdata, }, + { + .compatible = "samsung,exynos5433-gsc", + .data = &gsc_5433_drvdata, + }, {}, }; MODULE_DEVICE_TABLE(of, exynos_gsc_match); @@ -996,6 +1011,7 @@ static int gsc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; const struct gsc_driverdata *drv_data = of_device_get_match_data(dev); int ret; + int i; gsc = devm_kzalloc(dev, sizeof(struct gsc_dev), GFP_KERNEL); if (!gsc) @@ -1011,6 +1027,7 @@ static int gsc_probe(struct platform_device *pdev) return -EINVAL; } + gsc->num_clocks = drv_data->num_clocks; gsc->variant = drv_data->variant[gsc->id]; gsc->pdev = pdev; @@ -1029,18 +1046,24 @@ static int gsc_probe(struct platform_device *pdev) return -ENXIO; } - gsc->clock = devm_clk_get(dev, GSC_CLOCK_GATE_NAME); - if (IS_ERR(gsc->clock)) { - dev_err(dev, "failed to get clock~~~: %s\n", - GSC_CLOCK_GATE_NAME); - return PTR_ERR(gsc->clock); + for (i = 0; i < gsc->num_clocks; i++) { + gsc->clock[i] = devm_clk_get(dev, drv_data->clk_names[i]); + if (IS_ERR(gsc->clock[i])) { + dev_err(dev, "failed to get clock: %s\n", + drv_data->clk_names[i]); + return PTR_ERR(gsc->clock[i]); + } } - ret = clk_prepare_enable(gsc->clock); - if (ret) { - dev_err(&gsc->pdev->dev, "clock prepare failed for clock: %s\n", - GSC_CLOCK_GATE_NAME); - return ret; + for (i = 0; i < gsc->num_clocks; i++) { + ret = clk_prepare_enable(gsc->clock[i]); + if (ret) { + dev_err(dev, "clock prepare failed for clock: %s\n", + drv_data->clk_names[i]); + while (--i >= 0) + clk_disable_unprepare(gsc->clock[i]); + return ret; + } } ret = devm_request_irq(dev, res->start, gsc_irq_handler, @@ -1075,13 +1098,15 @@ static int gsc_probe(struct platform_device *pdev) err_v4l2: v4l2_device_unregister(&gsc->v4l2_dev); err_clk: - clk_disable_unprepare(gsc->clock); + for (i = gsc->num_clocks - 1; i >= 0; i--) + clk_disable_unprepare(gsc->clock[i]); return ret; } static int gsc_remove(struct platform_device *pdev) { struct gsc_dev *gsc = platform_get_drvdata(pdev); + int i; pm_runtime_get_sync(&pdev->dev); @@ -1089,7 +1114,8 @@ static int gsc_remove(struct platform_device *pdev) v4l2_device_unregister(&gsc->v4l2_dev); vb2_dma_contig_clear_max_seg_size(&pdev->dev); - clk_disable_unprepare(gsc->clock); + for (i = 0; i < gsc->num_clocks; i++) + clk_disable_unprepare(gsc->clock[i]); pm_runtime_put_noidle(&pdev->dev); @@ -1139,12 +1165,18 @@ static int gsc_runtime_resume(struct device *dev) { struct gsc_dev *gsc = dev_get_drvdata(dev); int ret = 0; + int i; pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); - ret = clk_prepare_enable(gsc->clock); - if (ret) - return ret; + for (i = 0; i < gsc->num_clocks; i++) { + ret = clk_prepare_enable(gsc->clock[i]); + if (ret) { + while (--i >= 0) + clk_disable_unprepare(gsc->clock[i]); + return ret; + } + } gsc_hw_set_sw_reset(gsc); gsc_wait_reset(gsc); @@ -1157,10 +1189,14 @@ static int gsc_runtime_suspend(struct device *dev) { struct gsc_dev *gsc = dev_get_drvdata(dev); int ret = 0; + int i; ret = gsc_m2m_suspend(gsc); - if (!ret) - clk_disable_unprepare(gsc->clock); + if (ret) + return ret; + + for (i = gsc->num_clocks - 1; i >= 0; i--) + clk_disable_unprepare(gsc->clock[i]); pr_debug("gsc%d: state: 0x%lx\n", gsc->id, gsc->state); return ret; diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h index e5aa8f42f11e..696217e9af66 100644 --- a/drivers/media/platform/exynos-gsc/gsc-core.h +++ b/drivers/media/platform/exynos-gsc/gsc-core.h @@ -33,6 +33,7 @@ #define GSC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) #define GSC_MAX_DEVS 4 +#define GSC_MAX_CLOCKS 4 #define GSC_M2M_BUF_NUM 0 #define GSC_MAX_CTRL_NUM 10 #define GSC_SC_ALIGN_4 4 @@ -307,6 +308,8 @@ struct gsc_variant { */ struct gsc_driverdata { struct gsc_variant *variant[GSC_MAX_DEVS]; + const char *clk_names[GSC_MAX_CLOCKS]; + int num_clocks; int num_entities; }; @@ -330,7 +333,8 @@ struct gsc_dev { struct platform_device *pdev; struct gsc_variant *variant; u16 id; - struct clk *clock; + int num_clocks; + struct clk *clock[GSC_MAX_CLOCKS]; void __iomem *regs; wait_queue_head_t irq_queue; struct gsc_m2m_device m2m; -- cgit v1.2.3 From f662f1b7e5b630c6c95e59c4fe3ff70489c5f8ee Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Thu, 10 Nov 2016 08:31:20 -0200 Subject: [media] s5p-mfc: Correct scratch buffer size of H.263 decoder Driver complains about too small scratch buffer size. After adjusting it according to vendor code, decoding works. [mszyprow: moved the change to the header file] Signed-off-by: Andrzej Hajda Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v6.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h index 83e01f3466e9..d2cd35916dc5 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h @@ -386,7 +386,8 @@ ((w) * 144 + 8192 * (h) + 49216 + 1048576) #define S5P_FIMV_SCRATCH_BUF_SIZE_VC1_DEC_V6(w, h) \ (2096 * ((w) + (h) + 1)) -#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) ((w) * 400) +#define S5P_FIMV_SCRATCH_BUF_SIZE_H263_DEC_V6(w, h) \ + S5P_FIMV_SCRATCH_BUF_SIZE_MPEG4_DEC_V6(w, h) #define S5P_FIMV_SCRATCH_BUF_SIZE_VP8_DEC_V6(w, h) \ ((w) * 32 + (h) * 128 + (((w) + 1) / 2) * 64 + 2112) #define S5P_FIMV_SCRATCH_BUF_SIZE_H264_ENC_V6(w, h) \ -- cgit v1.2.3 From dd62b8f1a39334c6efbcf06c071def9760700d96 Mon Sep 17 00:00:00 2001 From: Ingi Kim Date: Thu, 10 Nov 2016 08:31:21 -0200 Subject: [media] s5p-mfc: Fix MFC context buffer size When video file was decoded by H/W MFCv8. It occurred IOMMU page fault because of accessing abnormal memory of mfc ctx buf. So this patch supports buffer size of mfc context more. Relevant page fault error is below. [ 3524.617147] PAGE FAULT occurred at 0x10108000 by 11200000.sysmmu(Page table base: 0x6d86c000) [ 3524.624192] Lv1 entry: 0x6c27d001 [ 3524.627567] Lv2 entry: 0x0 [ 3524.630482] ------------[ cut here ]------------ [ 3524.635020] kernel BUG at drivers/iommu/exynos-iommu.c:358! [ 3524.640567] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [ 3524.646373] Modules linked in: [ 3524.649410] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.0.0-00001-g0ff9b87-dirty #18 [ 3524.657117] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 3524.663184] task: c0e4aff0 ti: c0e3c000 task.ti: c0e3c000 [ 3524.668566] PC is at exynos_sysmmu_irq+0x1b8/0x2c4 [ 3524.673330] LR is at vprintk_emit+0x2b8/0x58c [ 3524.677657] pc : [] lr : [] psr: 600d0193 [ 3524.677657] sp : c0e3dd90 ip : 00000000 fp : c0e3ddcc [ 3524.689092] r10: ee29a110 r9 : 00000000 r8 : ee29a128 [ 3524.694292] r7 : ed812810 r6 : 10108000 r5 : ed86c000 r4 : 00000000 [ 3524.700791] r3 : c0ec9bd8 r2 : 00000000 r1 : 00000000 r0 : ed82ff00 [ 3524.707292] Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment kernel [ 3524.714656] Control: 10c5387d Table: 6b08c06a DAC: 00000015 [ 3524.720375] Process swapper/0 (pid: 0, stack limit = 0xc0e3c210) [ 3524.726354] Stack: (0xc0e3dd90 to 0xc0e3e000) [ 3524.730689] dd80: c0e3dd9c c0069d68 ee58c338 6d86c000 [ 3524.738836] dda0: ee58c338 ee298c40 ee2915a0 0000003b c0e64ef4 c0e3c000 00000000 00000000 [ 3524.746981] ddc0: c0e3de14 c0e3ddd0 c0071ef4 c037cacc ffffffff a00d0193 c0e3ddf4 ee291540 [ 3524.755126] dde0: c0ec793c c0ec7928 7fffffff ee291540 ee2915a0 ee298c40 c0e64ef4 ee004660 [ 3524.763272] de00: ee010800 c0e3df00 c0e3de34 c0e3de18 c0072138 c0071e9c 00020000 ee291540 [ 3524.771418] de20: ee2915a0 00000016 c0e3de4c c0e3de38 c0075130 c00720f8 0000003b ee028300 [ 3524.779563] de40: c0e3de64 c0e3de50 c0071450 c0075068 00000100 00000012 c0e3de8c c0e3de68 [ 3524.787708] de60: c030d240 c0071420 c030d19c 00000016 00000000 00000016 00000000 00000001 [ 3524.795854] de80: c0e3dea4 c0e3de90 c0071450 c030d1a8 00000092 c0e37a1c c0e3ded4 c0e3dea8 [ 3524.804000] dea0: c0071790 c0071420 c0e3df00 f000200c 00000016 c0e440a8 c0e3df00 f0002000 [ 3524.812145] dec0: c095bc8c 00000001 c0e3defc c0e3ded8 c0008730 c0071710 c0010d88 c0010d8c [ 3524.820290] dee0: 600d0013 ffffffff c0e3df34 c0ec7eb4 c0e3df54 c0e3df00 c0014780 c00086fc [ 3524.828436] df00: 00000001 00000000 00000000 c0020780 c0e3c000 c0e43530 00000000 00000000 [ 3524.836581] df20: c0ec7eb4 c095bc8c 00000001 c0e3df54 c0e3df58 c0e3df48 c0010d88 c0010d8c [ 3524.844727] df40: 600d0013 ffffffff c0e3df94 c0e3df58 c0062690 c0010d50 c0ec75f0 00000001 [ 3524.852872] df60: c0e3df84 c0e4353c c0e39580 c0e43e84 c0e3c000 00000002 c0e3df58 c0e38b88 [ 3524.861018] df80: c0952b9c ffffffff c0e3dfac c0e3df98 c094d1b8 c00622d4 c0e3c000 c0e43e10 [ 3524.869163] dfa0: c0e3dff4 c0e3dfb0 c0d86d30 c094d130 ffffffff ffffffff c0d866f0 00000000 [ 3524.877309] dfc0: 00000000 c0df06d8 00000000 c0ee3f14 c0e434c0 c0df06d4 c0e4c20c 4000406a [ 3524.885454] dfe0: 410fc073 00000000 00000000 c0e3dff8 40008074 c0d86970 00000000 00000000 [ 3524.893610] [] (exynos_sysmmu_irq) from [] (handle_irq_event_percpu+0x64/0x25c) [ 3524.902615] [] (handle_irq_event_percpu) from [] (handle_irq_event+0x4c/0x6c) [ 3524.911454] [] (handle_irq_event) from [] (handle_level_irq+0xd4/0x14c) [ 3524.919773] [] (handle_level_irq) from [] (generic_handle_irq+0x3c/0x4c) [ 3524.928180] [] (generic_handle_irq) from [] (combiner_handle_cascade_irq+0xa4/0x110) [ 3524.937624] [] (combiner_handle_cascade_irq) from [] (generic_handle_irq+0x3c/0x4c) [ 3524.946981] [] (generic_handle_irq) from [] (__handle_domain_irq+0x8c/0xfc) [ 3524.955646] [] (__handle_domain_irq) from [] (gic_handle_irq+0x40/0x78) [ 3524.963966] [] (gic_handle_irq) from [] (__irq_svc+0x40/0x74) [ 3524.971412] Exception stack(0xc0e3df00 to 0xc0e3df48) [ 3524.976441] df00: 00000001 00000000 00000000 c0020780 c0e3c000 c0e43530 00000000 00000000 [ 3524.984586] df20: c0ec7eb4 c095bc8c 00000001 c0e3df54 c0e3df58 c0e3df48 c0010d88 c0010d8c [ 3524.992729] df40: 600d0013 ffffffff [ 3524.996205] [] (__irq_svc) from [] (arch_cpu_idle+0x48/0x4c) [ 3525.003567] [] (arch_cpu_idle) from [] (cpu_startup_entry+0x3c8/0x4a4) [ 3525.011805] [] (cpu_startup_entry) from [] (rest_init+0x94/0x98) [ 3525.019516] [] (rest_init) from [] (start_kernel+0x3cc/0x3d8) [ 3525.026963] Code: e34c30ec e5932004 e3520000 ca000018 (e7f001f2) [ 3525.033028] ---[ end trace 71ed544f653b4d46 ]--- Signed-off-by: Ingi Kim Signed-off-by: Seung-Woo Kim Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc-v8.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h index cc7cbec51b5e..4d1c3750eb5e 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc-v8.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc-v8.h @@ -90,7 +90,7 @@ #define S5P_FIMV_E_H264_OPTIONS_V8 0xfb54 /* MFCv8 Context buffer sizes */ -#define MFC_CTX_BUF_SIZE_V8 (30 * SZ_1K) /* 30KB */ +#define MFC_CTX_BUF_SIZE_V8 (36 * SZ_1K) /* 36KB */ #define MFC_H264_DEC_CTX_BUF_SIZE_V8 (2 * SZ_1M) /* 2MB */ #define MFC_OTHER_DEC_CTX_BUF_SIZE_V8 (20 * SZ_1K) /* 20KB */ #define MFC_H264_ENC_CTX_BUF_SIZE_V8 (100 * SZ_1K) /* 100KB */ -- cgit v1.2.3 From 5d1ec73184e657fb2b429f8742cd7cb42336bc45 Mon Sep 17 00:00:00 2001 From: Donghwa Lee Date: Thu, 10 Nov 2016 08:31:22 -0200 Subject: [media] s5p-mfc: Skip incomplete frame Currently, when incomplete frame is received in the middle of decoding, driver treats it as an error, so src/dst queue and clock are cleaned. Although it is obviously error case, it is needed to maintain video decoding in case of necessity. This patch supports skip incomplete frame to next. Signed-off-by: Donghwa Lee Signed-off-by: Seung-Woo Kim Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/regs-mfc.h | 3 +++ drivers/media/platform/s5p-mfc/s5p_mfc.c | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/regs-mfc.h b/drivers/media/platform/s5p-mfc/regs-mfc.h index 6ccc3f8c122a..57b7e0be0596 100644 --- a/drivers/media/platform/s5p-mfc/regs-mfc.h +++ b/drivers/media/platform/s5p-mfc/regs-mfc.h @@ -393,6 +393,9 @@ #define S5P_FIMV_REG_CLEAR_COUNT 0 /* Error handling defines */ +#define S5P_FIMV_ERR_NO_VALID_SEQ_HDR 67 +#define S5P_FIMV_ERR_INCOMPLETE_FRAME 124 +#define S5P_FIMV_ERR_TIMEOUT 140 #define S5P_FIMV_ERR_WARNINGS_START 145 #define S5P_FIMV_ERR_DEC_MASK 0xFFFF #define S5P_FIMV_ERR_DEC_SHIFT 0 diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 3436eda58855..9f73ba1cc9c3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -641,8 +641,11 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) case S5P_MFC_R2H_CMD_ERR_RET: /* An error has occurred */ if (ctx->state == MFCINST_RUNNING && - s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= - dev->warn_start) + (s5p_mfc_hw_call(dev->mfc_ops, err_dec, err) >= + dev->warn_start || + err == S5P_FIMV_ERR_NO_VALID_SEQ_HDR || + err == S5P_FIMV_ERR_INCOMPLETE_FRAME || + err == S5P_FIMV_ERR_TIMEOUT)) s5p_mfc_handle_frame(ctx, reason, err); else s5p_mfc_handle_error(dev, ctx, reason, err); -- cgit v1.2.3 From c5086f130a77009dd1dcacf0fbc2ca83f09ebca4 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Thu, 10 Nov 2016 08:31:23 -0200 Subject: [media] s5p-mfc: Use clock gating only on MFC v5 hardware Newer MFC hardware have internal clock gating feature, so additional software-triggered clock gating sometimes causes misbehavior of the MFC firmware and results in freeze or crash. This patch changes the driver to use software-triggered clock gating only when working with v5 MFC hardware, where it has been proven to work properly. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 1 + drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 2 ++ drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 17 +++++++++++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 9f73ba1cc9c3..ba6e2c5bca05 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1442,6 +1442,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .buf_size = &buf_size_v5, .buf_align = &mfc_buf_align_v5, .fw_name[0] = "s5p-mfc.fw", + .use_clock_gating = true, }; static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 46b99f28cbd7..c068ee3ece6e 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -199,6 +199,7 @@ struct s5p_mfc_buf { struct s5p_mfc_pm { struct clk *clock; struct clk *clock_gate; + bool use_clock_gating; atomic_t power; struct device *device; }; @@ -235,6 +236,7 @@ struct s5p_mfc_variant { struct s5p_mfc_buf_size *buf_size; struct s5p_mfc_buf_align *buf_align; char *fw_name[MFC_FW_MAX_VERSIONS]; + bool use_clock_gating; }; /** diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 930dc2dddae6..b5806ab7ac31 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -37,6 +37,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) pm = &dev->pm; p_dev = dev; + pm->use_clock_gating = dev->variant->use_clock_gating; pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); if (IS_ERR(pm->clock_gate)) { mfc_err("Failed to get clock-gating control\n"); @@ -108,6 +109,8 @@ int s5p_mfc_clock_on(void) atomic_inc(&clk_ref); mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); #endif + if (!pm->use_clock_gating) + return 0; if (!IS_ERR_OR_NULL(pm->clock_gate)) ret = clk_enable(pm->clock_gate); return ret; @@ -119,22 +122,32 @@ void s5p_mfc_clock_off(void) atomic_dec(&clk_ref); mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); #endif + if (!pm->use_clock_gating) + return; if (!IS_ERR_OR_NULL(pm->clock_gate)) clk_disable(pm->clock_gate); } int s5p_mfc_power_on(void) { + int ret = 0; + #ifdef CONFIG_PM - return pm_runtime_get_sync(pm->device); + ret = pm_runtime_get_sync(pm->device); + if (ret) + return ret; #else atomic_set(&pm->power, 1); - return 0; #endif + if (!pm->use_clock_gating && !IS_ERR_OR_NULL(pm->clock_gate)) + ret = clk_enable(pm->clock_gate); + return ret; } int s5p_mfc_power_off(void) { + if (!pm->use_clock_gating && !IS_ERR_OR_NULL(pm->clock_gate)) + clk_disable(pm->clock_gate); #ifdef CONFIG_PM return pm_runtime_put_sync(pm->device); #else -- cgit v1.2.3 From c0026c7bfb95c250c3e34fde59f96ad72fd730d6 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Mon, 14 Nov 2016 12:09:26 -0200 Subject: [media] s5p-mfc: Fix clock management in s5p_mfc_release() function Clock control indirectly requires access to MFC device, so call it only if we are sure that the device exists in s5p_mfc_release function. s5p_mfc_remove() calls s5p_mfc_final_pm(), which releases all PM related resources, including clocks, so any call to clocks related functions is not valid after s5p_mfc_final_pm(). Fixes: d695c12 ("[media] media: s5p-mfc fix invalid memory access from s5p_mfc_release()") Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index ba6e2c5bca05..320124352e82 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -929,10 +929,11 @@ static int s5p_mfc_release(struct file *file) mfc_debug_enter(); if (dev) mutex_lock(&dev->mfc_mutex); - s5p_mfc_clock_on(); vb2_queue_release(&ctx->vq_src); vb2_queue_release(&ctx->vq_dst); if (dev) { + s5p_mfc_clock_on(); + /* Mark context as idle */ clear_work_bit_irqsave(ctx); /* @@ -954,9 +955,9 @@ static int s5p_mfc_release(struct file *file) if (s5p_mfc_power_off() < 0) mfc_err("Power off failed\n"); } + mfc_debug(2, "Shutting down clock\n"); + s5p_mfc_clock_off(); } - mfc_debug(2, "Shutting down clock\n"); - s5p_mfc_clock_off(); if (dev) dev->ctx[ctx->num] = NULL; s5p_mfc_dec_ctrls_delete(ctx); -- cgit v1.2.3 From 8286e96d95f2dd01a72e3500322ad95153a469c2 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Thu, 10 Nov 2016 07:17:48 +0000 Subject: PCI: hv: Use the correct buffer size in new_pcichild_device() We don't really need such a big on-stack buffer. vmbus_sendpacket() here only uses sizeof(struct pci_child_message). Signed-off-by: Dexuan Cui Signed-off-by: Bjorn Helgaas Reviewed-by: Jake Oshins --- drivers/pci/host/pci-hyperv.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 06c98695c06c..9ea63b4b0e58 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -1271,9 +1271,9 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus, struct hv_pci_dev *hpdev; struct pci_child_message *res_req; struct q_res_req_compl comp_pkt; - union { - struct pci_packet init_packet; - u8 buffer[0x100]; + struct { + struct pci_packet init_packet; + u8 buffer[sizeof(struct pci_child_message)]; } pkt; unsigned long flags; int ret; -- cgit v1.2.3 From 17978524a636d007e6b929304ae3eb5ea0371019 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Thu, 10 Nov 2016 07:18:47 +0000 Subject: PCI: hv: Fix hv_pci_remove() for hot-remove 1. We don't really need such a big on-stack buffer when sending the teardown_packet: vmbus_sendpacket() here only uses sizeof(struct pci_message). 2. In the hot-remove case (PCI_EJECT), after we send PCI_EJECTION_COMPLETE to the host, the host will send a RESCIND_CHANNEL message to us and the host won't access the per-channel ringbuffer any longer, so we needn't send PCI_RESOURCES_RELEASED/PCI_BUS_D0EXIT to the host, and we shouldn't expect the host's completion message of PCI_BUS_D0EXIT, which will never come. 3. We should send PCI_BUS_D0EXIT after hv_send_resources_released(). Signed-off-by: Dexuan Cui Signed-off-by: Bjorn Helgaas Reviewed-by: Jake Oshins Acked-by: K. Y. Srinivasan CC: Haiyang Zhang CC: Vitaly Kuznetsov --- drivers/pci/host/pci-hyperv.c | 53 +++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index 9ea63b4b0e58..b1747469a32c 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -2266,24 +2266,32 @@ free_bus: return ret; } -/** - * hv_pci_remove() - Remove routine for this VMBus channel - * @hdev: VMBus's tracking struct for this root PCI bus - * - * Return: 0 on success, -errno on failure - */ -static int hv_pci_remove(struct hv_device *hdev) +static void hv_pci_bus_exit(struct hv_device *hdev) { - int ret; - struct hv_pcibus_device *hbus; - union { + struct hv_pcibus_device *hbus = hv_get_drvdata(hdev); + struct { struct pci_packet teardown_packet; - u8 buffer[0x100]; + u8 buffer[sizeof(struct pci_message)]; } pkt; struct pci_bus_relations relations; struct hv_pci_compl comp_pkt; + int ret; - hbus = hv_get_drvdata(hdev); + /* + * After the host sends the RESCIND_CHANNEL message, it doesn't + * access the per-channel ringbuffer any longer. + */ + if (hdev->channel->rescind) + return; + + /* Delete any children which might still exist. */ + memset(&relations, 0, sizeof(relations)); + hv_pci_devices_present(hbus, &relations); + + ret = hv_send_resources_released(hdev); + if (ret) + dev_err(&hdev->device, + "Couldn't send resources released packet(s)\n"); memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet)); init_completion(&comp_pkt.host_event); @@ -2298,7 +2306,19 @@ static int hv_pci_remove(struct hv_device *hdev) VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); if (!ret) wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ); +} + +/** + * hv_pci_remove() - Remove routine for this VMBus channel + * @hdev: VMBus's tracking struct for this root PCI bus + * + * Return: 0 on success, -errno on failure + */ +static int hv_pci_remove(struct hv_device *hdev) +{ + struct hv_pcibus_device *hbus; + hbus = hv_get_drvdata(hdev); if (hbus->state == hv_pcibus_installed) { /* Remove the bus from PCI's point of view. */ pci_lock_rescan_remove(); @@ -2307,17 +2327,10 @@ static int hv_pci_remove(struct hv_device *hdev) pci_unlock_rescan_remove(); } - ret = hv_send_resources_released(hdev); - if (ret) - dev_err(&hdev->device, - "Couldn't send resources released packet(s)\n"); + hv_pci_bus_exit(hdev); vmbus_close(hdev->channel); - /* Delete any children which might still exist. */ - memset(&relations, 0, sizeof(relations)); - hv_pci_devices_present(hbus, &relations); - iounmap(hbus->cfg_addr); hv_free_config_window(hbus); pci_free_resource_list(&hbus->resources_for_children); -- cgit v1.2.3 From e74d2ebdda33b3bdd1826b5b92e9aa45bdf92bb3 Mon Sep 17 00:00:00 2001 From: Dexuan Cui Date: Thu, 10 Nov 2016 07:19:52 +0000 Subject: PCI: hv: Delete the device earlier from hbus->children for hot-remove After we send a PCI_EJECTION_COMPLETE message to the host, the host will immediately send us a PCI_BUS_RELATIONS message with relations->device_count == 0, so pci_devices_present_work(), running on another thread, can find the being-ejected device, mark the hpdev->reported_missing to true, and run list_move_tail()/list_del() for the device -- this races hv_eject_device_work() -> list_del(). Move the list_del() in hv_eject_device_work() to an earlier place, i.e., before we send PCI_EJECTION_COMPLETE, so later the pci_devices_present_work() can't see the device. Signed-off-by: Dexuan Cui Signed-off-by: Bjorn Helgaas Reviewed-by: Jake Oshins Acked-by: K. Y. Srinivasan CC: Haiyang Zhang CC: Vitaly Kuznetsov --- drivers/pci/host/pci-hyperv.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index b1747469a32c..a63c3a4f6c7c 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -1582,6 +1582,10 @@ static void hv_eject_device_work(struct work_struct *work) pci_dev_put(pdev); } + spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags); + list_del(&hpdev->list_entry); + spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags); + memset(&ctxt, 0, sizeof(ctxt)); ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message; ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE; @@ -1590,10 +1594,6 @@ static void hv_eject_device_work(struct work_struct *work) sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt, VM_PKT_DATA_INBAND, 0); - spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags); - list_del(&hpdev->list_entry); - spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags); - put_pcichild(hpdev, hv_pcidev_ref_childlist); put_pcichild(hpdev, hv_pcidev_ref_pnp); put_hvpcibus(hpdev->hbus); -- cgit v1.2.3 From baf28d91e7b1c9946d6b13a0c6cecf67d761037d Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Mon, 14 Nov 2016 10:51:36 -0800 Subject: Input: bma150 - avoid binding to bma180 if IIO bma180 driver present commit ef3714fdbc8d ("Input: bma150 - extend chip detection for bma180"), adds bma180 chip-ids to the input bma150 driver, assuming that they are 100% compatible, but the bma180 is not compatible with the bma150 at all, it has 14 bits resolution instead of 10, and it has quite different control registers too. Treating the bma180 as a bma150 wrt its data registers will just result in throwing away the lowest 4 bits, which is not too bad. But the ctrl registers are a different story. Things happen to just work but supporting that certainly does not make treating the bma180 the same as the bma150 right. Since some setups depend on the evdev interface the bma150 driver offers on top of the bma180, we cannot simply remove the bma180 ids. So this commit only removes the bma180 id when the bma180 iio driver, which does treat the bma180 properly, is enabled. Signed-off-by: Hans de Goede Signed-off-by: Dmitry Torokhov --- drivers/input/misc/bma150.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/bma150.c b/drivers/input/misc/bma150.c index b0d445390ee4..2124390ec38c 100644 --- a/drivers/input/misc/bma150.c +++ b/drivers/input/misc/bma150.c @@ -538,8 +538,13 @@ static int bma150_probe(struct i2c_client *client, return -EIO; } + /* + * Note if the IIO CONFIG_BMA180 driver is enabled we want to fail + * the probe for the bma180 as the iio driver is preferred. + */ chip_id = i2c_smbus_read_byte_data(client, BMA150_CHIP_ID_REG); - if (chip_id != BMA150_CHIP_ID && chip_id != BMA180_CHIP_ID) { + if (chip_id != BMA150_CHIP_ID && + (IS_ENABLED(CONFIG_BMA180) || chip_id != BMA180_CHIP_ID)) { dev_err(&client->dev, "BMA150 chip id error: %d\n", chip_id); return -EINVAL; } @@ -643,7 +648,9 @@ static UNIVERSAL_DEV_PM_OPS(bma150_pm, bma150_suspend, bma150_resume, NULL); static const struct i2c_device_id bma150_id[] = { { "bma150", 0 }, +#if !IS_ENABLED(CONFIG_BMA180) { "bma180", 0 }, +#endif { "smb380", 0 }, { "bma023", 0 }, { } -- cgit v1.2.3 From 6f6deb4866a4e65bc266ca003817b6ab685f999a Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 16 Nov 2016 09:37:08 -0800 Subject: Input: silead - add regulator support On some tablets the touchscreen controller is powered by separate regulators, add support for this. Signed-off-by: Hans de Goede Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/silead_gsl1680.txt | 2 ++ drivers/input/touchscreen/silead.c | 29 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt index 820fee4b77b6..ce85ee508238 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/silead_gsl1680.txt @@ -18,6 +18,8 @@ Optional properties: - touchscreen-inverted-y : See touchscreen.txt - touchscreen-swapped-x-y : See touchscreen.txt - silead,max-fingers : maximum number of fingers the touchscreen can detect +- vddio-supply : regulator phandle for controller VDDIO +- avdd-supply : regulator phandle for controller AVDD Example: diff --git a/drivers/input/touchscreen/silead.c b/drivers/input/touchscreen/silead.c index f502c8488be8..404830a4a366 100644 --- a/drivers/input/touchscreen/silead.c +++ b/drivers/input/touchscreen/silead.c @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -73,6 +74,7 @@ struct silead_ts_data { struct i2c_client *client; struct gpio_desc *gpio_power; struct input_dev *input; + struct regulator_bulk_data regulators[2]; char fw_name[64]; struct touchscreen_properties prop; u32 max_fingers; @@ -433,6 +435,13 @@ static int silead_ts_set_default_fw_name(struct silead_ts_data *data, } #endif +static void silead_disable_regulator(void *arg) +{ + struct silead_ts_data *data = arg; + + regulator_bulk_disable(ARRAY_SIZE(data->regulators), data->regulators); +} + static int silead_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -465,6 +474,26 @@ static int silead_ts_probe(struct i2c_client *client, if (client->irq <= 0) return -ENODEV; + data->regulators[0].supply = "vddio"; + data->regulators[1].supply = "avdd"; + error = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->regulators), + data->regulators); + if (error) + return error; + + /* + * Enable regulators at probe and disable them at remove, we need + * to keep the chip powered otherwise it forgets its firmware. + */ + error = regulator_bulk_enable(ARRAY_SIZE(data->regulators), + data->regulators); + if (error) + return error; + + error = devm_add_action_or_reset(dev, silead_disable_regulator, data); + if (error) + return error; + /* Power GPIO pin */ data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); if (IS_ERR(data->gpio_power)) { -- cgit v1.2.3 From 8ecc7985b4b15f1f14bce31d8ab45dc426df7da3 Mon Sep 17 00:00:00 2001 From: Mark Bloch Date: Thu, 27 Oct 2016 16:36:30 +0300 Subject: IB/core: Save QP in ib_flow structure When we create flow steering rule, we need to save the related QP in the ib_flow struct. this QP is used in destroy flow. Move the QP assignment from ib_uverbs_ex_create_flow into ib_create_flow, this would allow both kernel and userspace consumers to use it. This bug wasn't seen in the wild because there are no kernel consumers currently in the kernel. Fixes: 319a441d1361 ("IB/core: Add receive flow steering support") Signed-off-by: Mark Bloch Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 1 - drivers/infiniband/core/verbs.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index cb3f515a2285..2690c9263ee4 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -3745,7 +3745,6 @@ int ib_uverbs_ex_create_flow(struct ib_uverbs_file *file, err = PTR_ERR(flow_id); goto err_free; } - flow_id->qp = qp; flow_id->uobject = uobj; uobj->object = flow_id; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 83687646da68..b7f9f3d95975 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1734,8 +1734,10 @@ struct ib_flow *ib_create_flow(struct ib_qp *qp, return ERR_PTR(-ENOSYS); flow_id = qp->device->create_flow(qp, flow_attr, domain); - if (!IS_ERR(flow_id)) + if (!IS_ERR(flow_id)) { atomic_inc(&qp->usecnt); + flow_id->qp = qp; + } return flow_id; } EXPORT_SYMBOL(ib_create_flow); -- cgit v1.2.3 From 2d2215888d758c194efb38332aaf5e2069ac578e Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Thu, 27 Oct 2016 16:36:36 +0300 Subject: IB/mlx5: Replace numerical constant with predefined MACRO Replace the pre-defined macro signifying inline umr instead of the numerical constant. Signed-off-by: Max Gurtovoy Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/qp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 41f4c2afbcdd..00cffbfe6c35 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -3068,7 +3068,7 @@ static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr) { memset(umr, 0, sizeof(*umr)); umr->mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE); - umr->flags = 1 << 7; + umr->flags = MLX5_UMR_INLINE; } static __be64 get_umr_reg_mr_mask(void) -- cgit v1.2.3 From 578e72647ba5a77a09004606cb572f0881c34e0d Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Thu, 27 Oct 2016 16:36:37 +0300 Subject: IB/mlx5: Fix atomic cap in indirect UMR Remove from the driver the limitation imposed by firmware check to not allow change of atomic permissions for indirect UMRs. In order to avoid failures on old firmware, we only ask for change of atomic permissions if atomic operations are supported. Fixes: 968e78dd9644 ('IB/mlx5: Enhance UMR support to allow partial page table update') Signed-off-by: Eli Cohen Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/qp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 00cffbfe6c35..5bdf20c676fe 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -3071,7 +3071,7 @@ static void set_linv_umr_seg(struct mlx5_wqe_umr_ctrl_seg *umr) umr->flags = MLX5_UMR_INLINE; } -static __be64 get_umr_reg_mr_mask(void) +static __be64 get_umr_reg_mr_mask(int atomic) { u64 result; @@ -3084,9 +3084,11 @@ static __be64 get_umr_reg_mr_mask(void) MLX5_MKEY_MASK_KEY | MLX5_MKEY_MASK_RR | MLX5_MKEY_MASK_RW | - MLX5_MKEY_MASK_A | MLX5_MKEY_MASK_FREE; + if (atomic) + result |= MLX5_MKEY_MASK_A; + return cpu_to_be64(result); } @@ -3147,7 +3149,7 @@ static __be64 get_umr_update_pd_mask(void) } static void set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr, - struct ib_send_wr *wr) + struct ib_send_wr *wr, int atomic) { struct mlx5_umr_wr *umrwr = umr_wr(wr); @@ -3172,7 +3174,7 @@ static void set_reg_umr_segment(struct mlx5_wqe_umr_ctrl_seg *umr, if (wr->send_flags & MLX5_IB_SEND_UMR_UPDATE_PD) umr->mkey_mask |= get_umr_update_pd_mask(); if (!umr->mkey_mask) - umr->mkey_mask = get_umr_reg_mr_mask(); + umr->mkey_mask = get_umr_reg_mr_mask(atomic); } else { umr->mkey_mask = get_umr_unreg_mr_mask(); } @@ -4025,7 +4027,7 @@ int mlx5_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, } qp->sq.wr_data[idx] = MLX5_IB_WR_UMR; ctrl->imm = cpu_to_be32(umr_wr(wr)->mkey); - set_reg_umr_segment(seg, wr); + set_reg_umr_segment(seg, wr, !!(MLX5_CAP_GEN(mdev, atomic))); seg += sizeof(struct mlx5_wqe_umr_ctrl_seg); size += sizeof(struct mlx5_wqe_umr_ctrl_seg) / 16; if (unlikely((seg == qend))) -- cgit v1.2.3 From 86695a6582e3b1c4895de2bde4e1022b3a8fbda0 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Thu, 27 Oct 2016 16:36:38 +0300 Subject: IB/mlx5: Put non zero value in max_ah We put INT_MAX since this is the max value that can be held. Though there is no hardware limitation, this is practically a large enough number so we can use it. Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Maor Gottlieb Reviewed-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 8e0dbd51944e..16ac41d89dfc 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -643,6 +643,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * props->max_mcast_grp; props->max_map_per_fmr = INT_MAX; /* no limit in ConnectIB */ + props->max_ah = INT_MAX; props->hca_core_clock = MLX5_CAP_GEN(mdev, device_frequency_khz); props->timestamp_mask = 0x7FFFFFFFFFFFFFFFULL; -- cgit v1.2.3 From acbda523884dcf45613bf6818d8ead5180df35c2 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 27 Oct 2016 16:36:43 +0300 Subject: IB/mlx5: Wait for all async command completions to complete Wait before continuing unload till all pending mkey async creation requests are done. Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Eli Cohen Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/mr.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index d4ad672b905b..881166a9d868 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -645,6 +645,33 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) return 0; } +static void wait_for_async_commands(struct mlx5_ib_dev *dev) +{ + struct mlx5_mr_cache *cache = &dev->cache; + struct mlx5_cache_ent *ent; + int total = 0; + int i; + int j; + + for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { + ent = &cache->ent[i]; + for (j = 0 ; j < 1000; j++) { + if (!ent->pending) + break; + msleep(50); + } + } + for (i = 0; i < MAX_MR_CACHE_ENTRIES; i++) { + ent = &cache->ent[i]; + total += ent->pending; + } + + if (total) + mlx5_ib_warn(dev, "aborted while there are %d pending mr requests\n", total); + else + mlx5_ib_warn(dev, "done with all pending requests\n"); +} + int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev) { int i; @@ -658,6 +685,7 @@ int mlx5_mr_cache_cleanup(struct mlx5_ib_dev *dev) clean_keys(dev, i); destroy_workqueue(dev->cache.wq); + wait_for_async_commands(dev); del_timer_sync(&dev->delay_timer); return 0; -- cgit v1.2.3 From 288c01b746aab484651391ca6d64b585d3eb5ec6 Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Thu, 27 Oct 2016 16:36:45 +0300 Subject: IB/mlx5: Fix reported max SGE calculation Add the 512 bytes limit of RDMA READ and the size of remote address to the max SGE calculation. Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Eli Cohen Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 8 +++++--- drivers/infiniband/hw/mlx5/qp.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 16ac41d89dfc..46facd30e672 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -496,6 +496,7 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, struct mlx5_ib_dev *dev = to_mdev(ibdev); struct mlx5_core_dev *mdev = dev->mdev; int err = -ENOMEM; + int max_sq_desc; int max_rq_sg; int max_sq_sg; u64 min_page_size = 1ull << MLX5_CAP_GEN(mdev, log_pg_sz); @@ -618,9 +619,10 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, props->max_qp_wr = 1 << MLX5_CAP_GEN(mdev, log_max_qp_sz); max_rq_sg = MLX5_CAP_GEN(mdev, max_wqe_sz_rq) / sizeof(struct mlx5_wqe_data_seg); - max_sq_sg = (MLX5_CAP_GEN(mdev, max_wqe_sz_sq) - - sizeof(struct mlx5_wqe_ctrl_seg)) / - sizeof(struct mlx5_wqe_data_seg); + max_sq_desc = min_t(int, MLX5_CAP_GEN(mdev, max_wqe_sz_sq), 512); + max_sq_sg = (max_sq_desc - sizeof(struct mlx5_wqe_ctrl_seg) - + sizeof(struct mlx5_wqe_raddr_seg)) / + sizeof(struct mlx5_wqe_data_seg); props->max_sge = min(max_rq_sg, max_sq_sg); props->max_sge_rd = MLX5_MAX_SGE_RD; props->max_cq = 1 << MLX5_CAP_GEN(mdev, log_max_cq); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 5bdf20c676fe..c84b07f9f111 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -352,6 +352,29 @@ static int calc_send_wqe(struct ib_qp_init_attr *attr) return ALIGN(max_t(int, inl_size, size), MLX5_SEND_WQE_BB); } +static int get_send_sge(struct ib_qp_init_attr *attr, int wqe_size) +{ + int max_sge; + + if (attr->qp_type == IB_QPT_RC) + max_sge = (min_t(int, wqe_size, 512) - + sizeof(struct mlx5_wqe_ctrl_seg) - + sizeof(struct mlx5_wqe_raddr_seg)) / + sizeof(struct mlx5_wqe_data_seg); + else if (attr->qp_type == IB_QPT_XRC_INI) + max_sge = (min_t(int, wqe_size, 512) - + sizeof(struct mlx5_wqe_ctrl_seg) - + sizeof(struct mlx5_wqe_xrc_seg) - + sizeof(struct mlx5_wqe_raddr_seg)) / + sizeof(struct mlx5_wqe_data_seg); + else + max_sge = (wqe_size - sq_overhead(attr)) / + sizeof(struct mlx5_wqe_data_seg); + + return min_t(int, max_sge, wqe_size - sq_overhead(attr) / + sizeof(struct mlx5_wqe_data_seg)); +} + static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, struct mlx5_ib_qp *qp) { @@ -388,7 +411,11 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, return -ENOMEM; } qp->sq.wqe_shift = ilog2(MLX5_SEND_WQE_BB); - qp->sq.max_gs = attr->cap.max_send_sge; + qp->sq.max_gs = get_send_sge(attr, wqe_size); + if (qp->sq.max_gs < attr->cap.max_send_sge) + return -ENOMEM; + + attr->cap.max_send_sge = qp->sq.max_gs; qp->sq.max_post = wq_size / wqe_size; attr->cap.max_send_wr = qp->sq.max_post; -- cgit v1.2.3 From 762f899ae7875554284af92b821be8c083227092 Mon Sep 17 00:00:00 2001 From: Majd Dibbiny Date: Thu, 27 Oct 2016 16:36:47 +0300 Subject: IB/mlx5: Limit mkey page size to 2GB The maximum page size in the mkey context is 2GB. Until today, we didn't enforce this requirement in the code, and therefore, if we got a page size larger than 2GB, we have passed zeros in the log_page_shift instead of the actual value and the registration failed. This patch limits the driver to use compound pages of 2GB for mkeys. Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Maor Gottlieb Signed-off-by: Majd Dibbiny Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/cq.c | 4 ++-- drivers/infiniband/hw/mlx5/mem.c | 7 ++++++- drivers/infiniband/hw/mlx5/mlx5_ib.h | 6 +++++- drivers/infiniband/hw/mlx5/mr.c | 3 ++- drivers/infiniband/hw/mlx5/qp.c | 4 ++-- drivers/infiniband/hw/mlx5/srq.c | 2 +- 6 files changed, 18 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 79d017baf6f4..9e0598b5615f 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -770,7 +770,7 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, if (err) goto err_umem; - mlx5_ib_cont_pages(cq->buf.umem, ucmd.buf_addr, &npages, &page_shift, + mlx5_ib_cont_pages(cq->buf.umem, ucmd.buf_addr, 0, &npages, &page_shift, &ncont, NULL); mlx5_ib_dbg(dev, "addr 0x%llx, size %u, npages %d, page_shift %d, ncont %d\n", ucmd.buf_addr, entries * ucmd.cqe_size, npages, page_shift, ncont); @@ -1125,7 +1125,7 @@ static int resize_user(struct mlx5_ib_dev *dev, struct mlx5_ib_cq *cq, return err; } - mlx5_ib_cont_pages(umem, ucmd.buf_addr, &npages, page_shift, + mlx5_ib_cont_pages(umem, ucmd.buf_addr, 0, &npages, page_shift, npas, NULL); cq->resize_umem = umem; diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c index 996b54e366b0..6851357c16f4 100644 --- a/drivers/infiniband/hw/mlx5/mem.c +++ b/drivers/infiniband/hw/mlx5/mem.c @@ -37,12 +37,15 @@ /* @umem: umem object to scan * @addr: ib virtual address requested by the user + * @max_page_shift: high limit for page_shift - 0 means no limit * @count: number of PAGE_SIZE pages covered by umem * @shift: page shift for the compound pages found in the region * @ncont: number of compund pages * @order: log2 of the number of compound pages */ -void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, +void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, + unsigned long max_page_shift, + int *count, int *shift, int *ncont, int *order) { unsigned long tmp; @@ -72,6 +75,8 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, addr = addr >> page_shift; tmp = (unsigned long)addr; m = find_first_bit(&tmp, BITS_PER_LONG); + if (max_page_shift) + m = min_t(unsigned long, max_page_shift - page_shift, m); skip = 1 << m; mask = skip - 1; i = 0; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index d5d007740159..95937e7d2584 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -63,6 +63,8 @@ pr_warn("%s:%s:%d:(pid %d): " format, (dev)->ib_dev.name, __func__, \ #define MLX5_IB_DEFAULT_UIDX 0xffffff #define MLX5_USER_ASSIGNED_UIDX_MASK __mlx5_mask(qpc, user_index) +#define MLX5_MKEY_PAGE_SHIFT_MASK __mlx5_mask(mkc, log_page_size) + enum { MLX5_IB_MMAP_CMD_SHIFT = 8, MLX5_IB_MMAP_CMD_MASK = 0xff, @@ -823,7 +825,9 @@ int mlx5_ib_query_port(struct ib_device *ibdev, u8 port, struct ib_port_attr *props); int mlx5_ib_init_fmr(struct mlx5_ib_dev *dev); void mlx5_ib_cleanup_fmr(struct mlx5_ib_dev *dev); -void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift, +void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, + unsigned long max_page_shift, + int *count, int *shift, int *ncont, int *order); void __mlx5_ib_populate_pas(struct mlx5_ib_dev *dev, struct ib_umem *umem, int page_shift, size_t offset, size_t num_pages, diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 881166a9d868..6cbda901f259 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -855,7 +855,8 @@ static struct ib_umem *mr_umem_get(struct ib_pd *pd, u64 start, u64 length, return (void *)umem; } - mlx5_ib_cont_pages(umem, start, npages, page_shift, ncont, order); + mlx5_ib_cont_pages(umem, start, MLX5_MKEY_PAGE_SHIFT_MASK, npages, + page_shift, ncont, order); if (!*npages) { mlx5_ib_warn(dev, "avoid zero region\n"); ib_umem_release(umem); diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index c84b07f9f111..aa27688f5ae9 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -675,7 +675,7 @@ static int mlx5_ib_umem_get(struct mlx5_ib_dev *dev, return PTR_ERR(*umem); } - mlx5_ib_cont_pages(*umem, addr, npages, page_shift, ncont, NULL); + mlx5_ib_cont_pages(*umem, addr, 0, npages, page_shift, ncont, NULL); err = mlx5_ib_get_buf_offset(addr, *page_shift, offset); if (err) { @@ -728,7 +728,7 @@ static int create_user_rq(struct mlx5_ib_dev *dev, struct ib_pd *pd, return err; } - mlx5_ib_cont_pages(rwq->umem, ucmd->buf_addr, &npages, &page_shift, + mlx5_ib_cont_pages(rwq->umem, ucmd->buf_addr, 0, &npages, &page_shift, &ncont, NULL); err = mlx5_ib_get_buf_offset(ucmd->buf_addr, page_shift, &rwq->rq_page_offset); diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 3857dbd9c956..f384db5367fb 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -118,7 +118,7 @@ static int create_srq_user(struct ib_pd *pd, struct mlx5_ib_srq *srq, return err; } - mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, &npages, + mlx5_ib_cont_pages(srq->umem, ucmd.buf_addr, 0, &npages, &page_shift, &ncont, NULL); err = mlx5_ib_get_buf_offset(ucmd.buf_addr, page_shift, &offset); -- cgit v1.2.3 From 0b59970e7d96edcb3c7f651d9d48e1a59af3c3b0 Mon Sep 17 00:00:00 2001 From: Kamal Heib Date: Thu, 10 Nov 2016 10:16:48 +0200 Subject: IB/IPoIB: Remove can't use GFP_NOIO warning Remove the warning print of "can't use of GFP_NOIO" to avoid prints in each QP creation when devices aren't supporting IB_QP_CREATE_USE_GFP_NOIO. This print become more annoying when the IPoIB interface is configured to work in connected mode. Fixes: 09b93088d750 ('IB: Add a QP creation flag to use GFP_NOIO allocations') Signed-off-by: Kamal Heib Signed-off-by: Leon Romanovsky Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 4ad297d3de89..50c9772bde32 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1053,8 +1053,6 @@ static struct ib_qp *ipoib_cm_create_tx_qp(struct net_device *dev, struct ipoib_ tx_qp = ib_create_qp(priv->pd, &attr); if (PTR_ERR(tx_qp) == -EINVAL) { - ipoib_warn(priv, "can't use GFP_NOIO for QPs on device %s, using GFP_KERNEL\n", - priv->ca->name); attr.create_flags &= ~IB_QP_CREATE_USE_GFP_NOIO; tx_qp = ib_create_qp(priv->pd, &attr); } -- cgit v1.2.3 From af4295c117b82a521b05d0daf39ce879d26e6cb1 Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Thu, 10 Nov 2016 11:30:53 +0200 Subject: IB/mlx4: Set traffic class in AH Set traffic class within sl_tclass_flowlabel when create iboe AH. Without this the TOS value will be empty when running VLAN tagged traffic, because the TOS value is taken from the traffic class in the address handle attributes. Fixes: 9106c4106974 ('IB/mlx4: Fix SL to 802.1Q priority-bits mapping for IBoE') Signed-off-by: Maor Gottlieb Signed-off-by: Daniel Jurgens Reviewed-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/ah.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c index 5fc623362731..6be7dc320ff7 100644 --- a/drivers/infiniband/hw/mlx4/ah.c +++ b/drivers/infiniband/hw/mlx4/ah.c @@ -111,7 +111,9 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr !(1 << ah->av.eth.stat_rate & dev->caps.stat_rate_support)) --ah->av.eth.stat_rate; } - + ah->av.eth.sl_tclass_flowlabel |= + cpu_to_be32((ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label); /* * HW requires multicast LID so we just choose one. */ @@ -119,7 +121,7 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr ah->av.ib.dlid = cpu_to_be16(0xc000); memcpy(ah->av.eth.dgid, ah_attr->grh.dgid.raw, 16); - ah->av.eth.sl_tclass_flowlabel = cpu_to_be32(ah_attr->sl << 29); + ah->av.eth.sl_tclass_flowlabel |= cpu_to_be32(ah_attr->sl << 29); return &ah->ibah; } -- cgit v1.2.3 From 850d8fd765079d223d47de89f1f03ab95d1036cb Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Thu, 10 Nov 2016 11:30:56 +0200 Subject: IB/mlx4: Handle IPv4 header when demultiplexing MAD When MAD arrives to the hypervisor, we need to identify which slave it should be sent by destination GID. When L3 protocol is IPv4 the GRH is replaced by an IPv4 header. This patch detects when IPv4 header needs to be parsed instead of GRH. Fixes: b6ffaeffaea4 ('mlx4: In RoCE allow guests to have multiple GIDS') Signed-off-by: Moni Shoua Signed-off-by: Daniel Jurgens Reviewed-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/verbs.c | 16 +++++++++------- drivers/infiniband/hw/mlx4/mad.c | 33 ++++++++++++++++++++++++++++++--- include/rdma/ib_verbs.h | 19 +++++++++++++++++++ 3 files changed, 58 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index b7f9f3d95975..98e10c5f2a96 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -328,7 +328,7 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) } EXPORT_SYMBOL(ib_create_ah); -static int ib_get_header_version(const union rdma_network_hdr *hdr) +int ib_get_rdma_header_version(const union rdma_network_hdr *hdr) { const struct iphdr *ip4h = (struct iphdr *)&hdr->roce4grh; struct iphdr ip4h_checked; @@ -359,6 +359,7 @@ static int ib_get_header_version(const union rdma_network_hdr *hdr) return 4; return 6; } +EXPORT_SYMBOL(ib_get_rdma_header_version); static enum rdma_network_type ib_get_net_type_by_grh(struct ib_device *device, u8 port_num, @@ -369,7 +370,7 @@ static enum rdma_network_type ib_get_net_type_by_grh(struct ib_device *device, if (rdma_protocol_ib(device, port_num)) return RDMA_NETWORK_IB; - grh_version = ib_get_header_version((union rdma_network_hdr *)grh); + grh_version = ib_get_rdma_header_version((union rdma_network_hdr *)grh); if (grh_version == 4) return RDMA_NETWORK_IPV4; @@ -415,9 +416,9 @@ static int get_sgid_index_from_eth(struct ib_device *device, u8 port_num, &context, gid_index); } -static int get_gids_from_rdma_hdr(union rdma_network_hdr *hdr, - enum rdma_network_type net_type, - union ib_gid *sgid, union ib_gid *dgid) +int ib_get_gids_from_rdma_hdr(const union rdma_network_hdr *hdr, + enum rdma_network_type net_type, + union ib_gid *sgid, union ib_gid *dgid) { struct sockaddr_in src_in; struct sockaddr_in dst_in; @@ -447,6 +448,7 @@ static int get_gids_from_rdma_hdr(union rdma_network_hdr *hdr, return -EINVAL; } } +EXPORT_SYMBOL(ib_get_gids_from_rdma_hdr); int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, const struct ib_wc *wc, const struct ib_grh *grh, @@ -469,8 +471,8 @@ int ib_init_ah_from_wc(struct ib_device *device, u8 port_num, net_type = ib_get_net_type_by_grh(device, port_num, grh); gid_type = ib_network_to_gid_type(net_type); } - ret = get_gids_from_rdma_hdr((union rdma_network_hdr *)grh, net_type, - &sgid, &dgid); + ret = ib_get_gids_from_rdma_hdr((union rdma_network_hdr *)grh, net_type, + &sgid, &dgid); if (ret) return ret; diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 1672907ff219..b8e90130db37 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include "mlx4_ib.h" @@ -480,6 +482,23 @@ static int find_slave_port_pkey_ix(struct mlx4_ib_dev *dev, int slave, return -EINVAL; } +static int get_gids_from_l3_hdr(struct ib_grh *grh, union ib_gid *sgid, + union ib_gid *dgid) +{ + int version = ib_get_rdma_header_version((const union rdma_network_hdr *)grh); + enum rdma_network_type net_type; + + if (version == 4) + net_type = RDMA_NETWORK_IPV4; + else if (version == 6) + net_type = RDMA_NETWORK_IPV6; + else + return -EINVAL; + + return ib_get_gids_from_rdma_hdr((union rdma_network_hdr *)grh, net_type, + sgid, dgid); +} + int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, enum ib_qp_type dest_qpt, struct ib_wc *wc, struct ib_grh *grh, struct ib_mad *mad) @@ -538,7 +557,10 @@ int mlx4_ib_send_to_slave(struct mlx4_ib_dev *dev, int slave, u8 port, memset(&attr, 0, sizeof attr); attr.port_num = port; if (is_eth) { - memcpy(&attr.grh.dgid.raw[0], &grh->dgid.raw[0], 16); + union ib_gid sgid; + + if (get_gids_from_l3_hdr(grh, &sgid, &attr.grh.dgid)) + return -EINVAL; attr.ah_flags = IB_AH_GRH; } ah = ib_create_ah(tun_ctx->pd, &attr); @@ -651,6 +673,11 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port, is_eth = 1; if (is_eth) { + union ib_gid dgid; + union ib_gid sgid; + + if (get_gids_from_l3_hdr(grh, &sgid, &dgid)) + return -EINVAL; if (!(wc->wc_flags & IB_WC_GRH)) { mlx4_ib_warn(ibdev, "RoCE grh not present.\n"); return -EINVAL; @@ -659,10 +686,10 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port, mlx4_ib_warn(ibdev, "RoCE mgmt class is not CM\n"); return -EINVAL; } - err = mlx4_get_slave_from_roce_gid(dev->dev, port, grh->dgid.raw, &slave); + err = mlx4_get_slave_from_roce_gid(dev->dev, port, dgid.raw, &slave); if (err && mlx4_is_mf_bonded(dev->dev)) { other_port = (port == 1) ? 2 : 1; - err = mlx4_get_slave_from_roce_gid(dev->dev, other_port, grh->dgid.raw, &slave); + err = mlx4_get_slave_from_roce_gid(dev->dev, other_port, dgid.raw, &slave); if (!err) { port = other_port; pr_debug("resolved slave %d from gid %pI6 wire port %d other %d\n", diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 5ad43a487745..467a4b476e29 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -2580,6 +2580,24 @@ void ib_dealloc_pd(struct ib_pd *pd); */ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); +/** + * ib_get_gids_from_rdma_hdr - Get sgid and dgid from GRH or IPv4 header + * work completion. + * @hdr: the L3 header to parse + * @net_type: type of header to parse + * @sgid: place to store source gid + * @dgid: place to store destination gid + */ +int ib_get_gids_from_rdma_hdr(const union rdma_network_hdr *hdr, + enum rdma_network_type net_type, + union ib_gid *sgid, union ib_gid *dgid); + +/** + * ib_get_rdma_header_version - Get the header version + * @hdr: the L3 header to parse + */ +int ib_get_rdma_header_version(const union rdma_network_hdr *hdr); + /** * ib_init_ah_from_wc - Initializes address handle attributes from a * work completion. @@ -3357,4 +3375,5 @@ int ib_sg_to_pages(struct ib_mr *mr, struct scatterlist *sgl, int sg_nents, void ib_drain_rq(struct ib_qp *qp); void ib_drain_sq(struct ib_qp *qp); void ib_drain_qp(struct ib_qp *qp); + #endif /* IB_VERBS_H */ -- cgit v1.2.3 From befcabcd530e4ffb6f016638f693b7d94986d2ba Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Thu, 10 Nov 2016 11:30:57 +0200 Subject: IB/mlx4: Handle well-known-gid in mad_demux processing If OpenSM runs over a ConnectX-3, and there are ConnectX-4 or Connect-IB VFs active on the network, the OpenSM will receive QP1 packets containing a GRH where the destination GID is the "Well-Known GID" -- which is not a GID in the HCA Port's GID Table. This GID must be tested-for separately -- and packets which contain this destination GID should be routed to slave 0 (the PF). Fixes: 37bfc7c1e83f ('IB/mlx4: SR-IOV multiplex and demultiplex MADs') Signed-off-by: Jack Morgenstein Signed-off-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/mad.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index b8e90130db37..7bcae4115408 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -729,10 +729,18 @@ static int mlx4_ib_demux_mad(struct ib_device *ibdev, u8 port, /* If a grh is present, we demux according to it */ if (wc->wc_flags & IB_WC_GRH) { - slave = mlx4_ib_find_real_gid(ibdev, port, grh->dgid.global.interface_id); - if (slave < 0) { - mlx4_ib_warn(ibdev, "failed matching grh\n"); - return -ENOENT; + if (grh->dgid.global.interface_id == + cpu_to_be64(IB_SA_WELL_KNOWN_GUID) && + grh->dgid.global.subnet_prefix == cpu_to_be64( + atomic64_read(&dev->sriov.demux[port - 1].subnet_prefix))) { + slave = 0; + } else { + slave = mlx4_ib_find_real_gid(ibdev, port, + grh->dgid.global.interface_id); + if (slave < 0) { + mlx4_ib_warn(ibdev, "failed matching grh\n"); + return -ENOENT; + } } } /* Class-specific handling */ -- cgit v1.2.3 From 731e0415b4af3a133d0316e4dc8ef0ea57dc3fdf Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Thu, 10 Nov 2016 11:30:58 +0200 Subject: IB/mlx4: Put non zero value in max_ah device attribute Use INT_MAX since this is the max value the attribute can hold, though hardware capability is unlimited. Fixes: 225c7b1feef1 ('IB/mlx4: Add a driver Mellanox ConnectX InfiniBand adapters') Signed-off-by: Maor Gottlieb Signed-off-by: Daniel Jurgens Reviewed-by: Mark Bloch Reviewed-by: Yuval Shaia Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index b597e8227591..05ab3cb34cb3 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -547,6 +547,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, props->max_map_per_fmr = dev->dev->caps.max_fmr_maps; props->hca_core_clock = dev->dev->caps.hca_core_clock * 1000UL; props->timestamp_mask = 0xFFFFFFFFFFFFULL; + props->max_ah = INT_MAX; if (!mlx4_is_slave(dev->dev)) err = mlx4_get_internal_clock_params(dev->dev, &clock_params); -- cgit v1.2.3 From 6fa26208206c406fa529cd73f7ae6bf4181e270b Mon Sep 17 00:00:00 2001 From: Saeed Mahameed Date: Thu, 10 Nov 2016 11:30:59 +0200 Subject: IB/mlx4: Fix port query for 56Gb Ethernet links Report the correct speed in the port attributes when using a 56Gbps ethernet link. Without this change the field is incorrectly set to 10. Fixes: a9c766bb75ee ('IB/mlx4: Fix info returned when querying IBoE ports') Fixes: 2e96691c31ec ('IB: Use central enum for speed instead of hard-coded values') Signed-off-by: Saeed Mahameed Signed-off-by: Yishai Hadas Signed-off-by: Daniel Jurgens Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 05ab3cb34cb3..4054a1bfabb5 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -698,9 +698,11 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port, if (err) goto out; - props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) ? - IB_WIDTH_4X : IB_WIDTH_1X; - props->active_speed = IB_SPEED_QDR; + props->active_width = (((u8 *)mailbox->buf)[5] == 0x40) || + (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ? + IB_WIDTH_4X : IB_WIDTH_1X; + props->active_speed = (((u8 *)mailbox->buf)[5] == 0x20 /*56Gb*/) ? + IB_SPEED_FDR : IB_SPEED_QDR; props->port_cap_flags = IB_PORT_CM_SUP | IB_PORT_IP_BASED_GIDS; props->gid_tbl_len = mdev->dev->caps.gid_table_len[port]; props->max_msg_sz = mdev->dev->caps.max_msg_sz; -- cgit v1.2.3 From fac96cc9f8679e31a244f98bed5983fe220e295c Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 16 Nov 2016 17:19:57 -0800 Subject: Input: raydium_i2c_ts - fix spelling mistake in dev_err message Trivial fix to spelling mistake "failied" to "failed" in dev_err message. Signed-off-by: Colin Ian King Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/raydium_i2c_ts.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/raydium_i2c_ts.c b/drivers/input/touchscreen/raydium_i2c_ts.c index a99fb5cac5a0..2658afa016c9 100644 --- a/drivers/input/touchscreen/raydium_i2c_ts.c +++ b/drivers/input/touchscreen/raydium_i2c_ts.c @@ -669,7 +669,7 @@ static int raydium_i2c_do_update_firmware(struct raydium_data *ts, if (ts->boot_mode == RAYDIUM_TS_MAIN) { dev_err(&client->dev, - "failied to jump to boot loader: %d\n", + "failed to jump to boot loader: %d\n", error); return -EIO; } -- cgit v1.2.3 From 792f497b22afd0563b94dd8fa129a05f762a2c25 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Nov 2016 17:23:22 -0800 Subject: Input: synaptics-rmi4 - unlock on error We should unlock before returning on this error path. Fixes: 3a762dbd5347 ('[media] Input: synaptics-rmi4 - add support for F54 diagnostics') Signed-off-by: Dan Carpenter Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f54.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index cf805b960866..2e934aef3d2a 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -200,7 +200,7 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type) error = rmi_write(rmi_dev, fn->fd.command_base_addr, F54_GET_REPORT); if (error < 0) - return error; + goto unlock; init_completion(&f54->cmd_done); @@ -209,9 +209,10 @@ static int rmi_f54_request_report(struct rmi_function *fn, u8 report_type) queue_delayed_work(f54->workqueue, &f54->work, 0); +unlock: mutex_unlock(&f54->data_mutex); - return 0; + return error; } static size_t rmi_f54_get_report_size(struct f54_data *f54) -- cgit v1.2.3 From da6f8ca13fb7d40f263ef647ebb41ff0a575d194 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 10 Nov 2016 16:17:49 +0100 Subject: dmaengine: pl08x: Add support for the DMA slave map This patch adds support for the new channel request API introduced in commit a8135d0d79e9d0ad3a4ff494fceeaae83 "dmaengine: core: Introduce new, universal API to request a channel". param field of struct dma_slave_map type entries in the platform data structure should be pointing to struct pl08x_channel_data of related DMA channel. Signed-off-by: Sylwester Nawrocki Tested-by: Charles Keepax Acked-by: Arnd Bergmann Signed-off-by: Vinod Koul --- drivers/dma/amba-pl08x.c | 11 +++++++++++ include/linux/amba/pl08x.h | 4 ++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c index 939a7c31f760..0b7c6ce629a6 100644 --- a/drivers/dma/amba-pl08x.c +++ b/drivers/dma/amba-pl08x.c @@ -1793,6 +1793,13 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id) } EXPORT_SYMBOL_GPL(pl08x_filter_id); +static bool pl08x_filter_fn(struct dma_chan *chan, void *chan_id) +{ + struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); + + return plchan->cd == chan_id; +} + /* * Just check that the device is there and active * TODO: turn this bit on/off depending on the number of physical channels @@ -2307,6 +2314,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id) ret = -EINVAL; goto out_no_platdata; } + } else { + pl08x->slave.filter.map = pl08x->pd->slave_map; + pl08x->slave.filter.mapcnt = pl08x->pd->slave_map_len; + pl08x->slave.filter.fn = pl08x_filter_fn; } /* By default, AHB1 only. If dualmaster, from platform */ diff --git a/include/linux/amba/pl08x.h b/include/linux/amba/pl08x.h index 27e9ec8778eb..5308eae9ce35 100644 --- a/include/linux/amba/pl08x.h +++ b/include/linux/amba/pl08x.h @@ -84,6 +84,8 @@ struct pl08x_channel_data { * running any DMA transfer and multiplexing can be recycled * @lli_buses: buses which LLIs can be fetched from: PL08X_AHB1 | PL08X_AHB2 * @mem_buses: buses which memory can be accessed from: PL08X_AHB1 | PL08X_AHB2 + * @slave_map: DMA slave matching table + * @slave_map_len: number of elements in @slave_map */ struct pl08x_platform_data { struct pl08x_channel_data *slave_channels; @@ -93,6 +95,8 @@ struct pl08x_platform_data { void (*put_xfer_signal)(const struct pl08x_channel_data *, int); u8 lli_buses; u8 mem_buses; + const struct dma_slave_map *slave_map; + int slave_map_len; }; #ifdef CONFIG_AMBA_PL08X -- cgit v1.2.3 From 6f8dc9d481759b428a8cb6a17b83821451415ba9 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 10 Nov 2016 16:17:51 +0100 Subject: spi: s3c64xx: Do not use platform_data for DMA parameters All related platforms use either devicetree or the DMA slave map API for mapping DMA channels to DMA slaves so we can now stop using platform_data for passing DMA details. Signed-off-by: Sylwester Nawrocki Tested-by: Andi Shyti Tested-by: Charles Keepax Acked-by: Mark Brown Acked-by: Arnd Bergmann Signed-off-by: Vinod Koul --- drivers/spi/spi-s3c64xx.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index 3c09e94cf827..28dfdce4beae 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c @@ -341,27 +341,20 @@ static void s3c64xx_spi_set_cs(struct spi_device *spi, bool enable) static int s3c64xx_spi_prepare_transfer(struct spi_master *spi) { struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(spi); - dma_filter_fn filter = sdd->cntrlr_info->filter; struct device *dev = &sdd->pdev->dev; - dma_cap_mask_t mask; if (is_polling(sdd)) return 0; - dma_cap_zero(mask); - dma_cap_set(DMA_SLAVE, mask); - /* Acquire DMA channels */ - sdd->rx_dma.ch = dma_request_slave_channel_compat(mask, filter, - sdd->cntrlr_info->dma_rx, dev, "rx"); + sdd->rx_dma.ch = dma_request_slave_channel(dev, "rx"); if (!sdd->rx_dma.ch) { dev_err(dev, "Failed to get RX DMA channel\n"); return -EBUSY; } spi->dma_rx = sdd->rx_dma.ch; - sdd->tx_dma.ch = dma_request_slave_channel_compat(mask, filter, - sdd->cntrlr_info->dma_tx, dev, "tx"); + sdd->tx_dma.ch = dma_request_slave_channel(dev, "tx"); if (!sdd->tx_dma.ch) { dev_err(dev, "Failed to get TX DMA channel\n"); dma_release_channel(sdd->rx_dma.ch); @@ -1091,11 +1084,6 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) sdd->cur_bpw = 8; - if (!sdd->pdev->dev.of_node && (!sci->dma_tx || !sci->dma_rx)) { - dev_warn(&pdev->dev, "Unable to get SPI tx/rx DMA data. Switching to poll mode\n"); - sdd->port_conf->quirks = S3C64XX_SPI_QUIRK_POLL; - } - sdd->tx_dma.direction = DMA_MEM_TO_DEV; sdd->rx_dma.direction = DMA_DEV_TO_MEM; @@ -1205,9 +1193,8 @@ static int s3c64xx_spi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d with %d Slaves attached\n", sdd->port_id, master->num_chipselect); - dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\tDMA=[Rx-%p, Tx-%p]\n", - mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1, - sci->dma_rx, sci->dma_tx); + dev_dbg(&pdev->dev, "\tIOmem=[%pR]\tFIFO %dbytes\n", + mem_res, (FIFO_LVL_MASK(sdd) >> 1) + 1); pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); -- cgit v1.2.3 From cabcf4f6be658b2d4bea26dee89d08fdf67d6811 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Nov 2016 12:47:37 +0000 Subject: i2c: Add the ability to match device to compatible string without an of_node A great deal of I2C devices are currently matched via DT node name, and as such the compatible naming convention of ',' has gone somewhat awry - some nodes don't supply one, some supply an arbitrary string and others the correct device name with an arbitrary vendor prefix. In an effort to correct this problem we have to supply a mechanism to match a device by compatible string AND by simple device name. This function strips off the ',' part of a supplied compatible string and attempts to match without it. It is also used for sysfs, where a user can choose to instantiate a device on an i2c bus using the sysfs interface by providing a string and address to match and communicate with the device on the bus. Presently this string is only matched against the old i2c device id style strings, even in the presence of full device tree compatible strings with vendor prefixes. Providing a vendor-prefixed string to the sysfs interface will not match against the device tree of_match_device() calls as there is no device tree node to parse from the sysfs interface. This function can match both vendor prefixed and stripped compatible strings on the sysfs interface. Acked-by: Grant Likely Signed-off-by: Lee Jones Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Kieran Bingham Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 86083e5e5520..c588a8504c99 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1769,6 +1769,36 @@ struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) return adapter; } EXPORT_SYMBOL(of_get_i2c_adapter_by_node); + +static const struct of_device_id* +i2c_of_match_device_sysfs(const struct of_device_id *matches, + struct i2c_client *client) +{ + const char *name; + + for (; matches->compatible[0]; matches++) { + /* + * Adding devices through the i2c sysfs interface provides us + * a string to match which may be compatible with the device + * tree compatible strings, however with no actual of_node the + * of_match_device() will not match + */ + if (sysfs_streq(client->name, matches->compatible)) + return matches; + + name = strchr(matches->compatible, ','); + if (!name) + name = matches->compatible; + else + name++; + + if (sysfs_streq(client->name, name)) + return matches; + } + + return NULL; +} + #else static void of_i2c_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_OF */ -- cgit v1.2.3 From 298d4de1ed003ad91cb49e068d744db0343cacb6 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Nov 2016 12:47:38 +0000 Subject: i2c: Match using traditional OF methods, then by vendor-less compatible strings This function provides a single call for all I2C devices which need to match firstly using traditional OF means i.e by of_node, then if that fails we attempt to match using the supplied I2C client name with a list of supplied compatible strings with the ',' string removed. The latter is required due to the unruly naming conventions used currently by I2C devices. Acked-by: Grant Likely Signed-off-by: Lee Jones [Kieran: Fix static inline usage on !CONFIG_OF] Tested-by: Kieran Bingham Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Kieran Bingham Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 16 ++++++++++++++++ include/linux/i2c.h | 12 ++++++++++++ 2 files changed, 28 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index c588a8504c99..2151d0b353b3 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -1799,6 +1799,22 @@ i2c_of_match_device_sysfs(const struct of_device_id *matches, return NULL; } +const struct of_device_id +*i2c_of_match_device(const struct of_device_id *matches, + struct i2c_client *client) +{ + const struct of_device_id *match; + + if (!(client && matches)) + return NULL; + + match = of_match_device(matches, &client->dev); + if (match) + return match; + + return i2c_of_match_device_sysfs(matches, client); +} +EXPORT_SYMBOL_GPL(i2c_of_match_device); #else static void of_i2c_register_devices(struct i2c_adapter *adap) { } #endif /* CONFIG_OF */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 6422eef428c4..c0a4a12815aa 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -774,6 +774,10 @@ extern struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) /* must call i2c_put_adapter() when done with returned i2c_adapter device */ struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node); +extern const struct of_device_id +*i2c_of_match_device(const struct of_device_id *matches, + struct i2c_client *client); + #else static inline struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) @@ -790,6 +794,14 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node { return NULL; } + +static inline const struct of_device_id +*i2c_of_match_device(const struct of_device_id *matches, + struct i2c_client *client) +{ + return NULL; +} + #endif /* CONFIG_OF */ #if IS_ENABLED(CONFIG_ACPI) -- cgit v1.2.3 From da10c06a044b3752f9162a88b7d26ed2409c5314 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Nov 2016 12:47:39 +0000 Subject: i2c: Make I2C ID tables non-mandatory for DT'ed devices Currently the I2C framework insists on devices supplying an I2C ID table. Many of the devices which do so unnecessarily adding quite a few wasted lines to kernel code. This patch allows drivers a means to 'not' supply the aforementioned table and match on DT match tables instead. Acked-by: Grant Likely Signed-off-by: Lee Jones Tested-by: Kieran Bingham Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Kieran Bingham Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 2151d0b353b3..a97f7a0b0d6e 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -697,7 +697,7 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) /* Attempt an OF style match */ - if (of_driver_match_device(dev, drv)) + if (i2c_of_match_device(drv->of_match_table, client)) return 1; /* Then ACPI style match */ @@ -923,7 +923,15 @@ static int i2c_device_probe(struct device *dev) } driver = to_i2c_driver(dev->driver); - if (!driver->probe || !driver->id_table) + if (!driver->probe) + return -EINVAL; + + /* + * An I2C ID table is not mandatory, if and only if, a suitable Device + * Tree match table entry is supplied for the probing device. + */ + if (!driver->id_table && + !i2c_of_match_device(dev->driver->of_match_table, client)) return -ENODEV; if (client->flags & I2C_CLIENT_WAKE) { -- cgit v1.2.3 From 5f441fcaa3ce54681923475cf0040216d190e646 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Nov 2016 12:47:40 +0000 Subject: i2c: Export i2c_match_id() for direct use by device drivers When there was no other way to match a I2C device to driver i2c_match_id() was exclusively used. However, now there are other types of tables which are commonly supplied, matching on an i2c_device_id table is used less frequently. Instead of _always_ calling i2c_match_id() from within the framework, we only need to do so from drivers which have no other way of matching. This patch makes i2c_match_id() available to the aforementioned device drivers. Acked-by: Grant Likely Signed-off-by: Lee Jones Tested-by: Kieran Bingham Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Kieran Bingham Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 3 ++- include/linux/i2c.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index a97f7a0b0d6e..52b2cd4ac8b2 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -676,7 +676,7 @@ static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) /* ------------------------------------------------------------------------- */ -static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, +const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, const struct i2c_client *client) { if (!(id && client)) @@ -689,6 +689,7 @@ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, } return NULL; } +EXPORT_SYMBOL_GPL(i2c_match_id); static int i2c_device_match(struct device *dev, struct device_driver *drv) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index c0a4a12815aa..7e00efd6a62f 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -243,6 +243,8 @@ struct i2c_client { extern struct i2c_client *i2c_verify_client(struct device *dev); extern struct i2c_adapter *i2c_verify_adapter(struct device *dev); +extern const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, + const struct i2c_client *client); static inline struct i2c_client *kobj_to_i2c_client(struct kobject *kobj) { -- cgit v1.2.3 From b8a1a4cd5a98a2adf8dfd6902cd98e57d910ee12 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Nov 2016 12:47:41 +0000 Subject: i2c: Provide a temporary .probe_new() call-back type This will aid the seamless removal of the current probe()'s, more commonly unused than used second parameter. Most I2C drivers can simply switch over to the new interface, others which have DT support can use its own matching instead and others can call i2c_match_id() themselves. This brings I2C's device probe method into line with other similar interfaces in the kernel and prevents the requirement to pass an i2c_device_id table. Suggested-by: Grant Likely Signed-off-by: Lee Jones [Kieran: fix rebase conflicts and adapt for dev_pm_domain_{attach,detach}] Tested-by: Kieran Bingham Reviewed-by: Javier Martinez Canillas Tested-by: Javier Martinez Canillas Signed-off-by: Kieran Bingham Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 15 ++++++++++++--- include/linux/i2c.h | 8 +++++++- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 52b2cd4ac8b2..8b93a262e237 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -924,8 +924,6 @@ static int i2c_device_probe(struct device *dev) } driver = to_i2c_driver(dev->driver); - if (!driver->probe) - return -EINVAL; /* * An I2C ID table is not mandatory, if and only if, a suitable Device @@ -967,7 +965,18 @@ static int i2c_device_probe(struct device *dev) if (status == -EPROBE_DEFER) goto err_clear_wakeup_irq; - status = driver->probe(client, i2c_match_id(driver->id_table, client)); + /* + * When there are no more users of probe(), + * rename probe_new to probe. + */ + if (driver->probe_new) + status = driver->probe_new(client); + else if (driver->probe) + status = driver->probe(client, + i2c_match_id(driver->id_table, client)); + else + status = -EINVAL; + if (status) goto err_detach_pm_domain; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 7e00efd6a62f..82cf90945bb8 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -135,7 +135,8 @@ enum i2c_alert_protocol { * struct i2c_driver - represent an I2C device driver * @class: What kind of i2c device we instantiate (for detect) * @attach_adapter: Callback for bus addition (deprecated) - * @probe: Callback for device binding + * @probe: Callback for device binding - soon to be deprecated + * @probe_new: New callback for device binding * @remove: Callback for device unbinding * @shutdown: Callback for device shutdown * @alert: Alert callback, for example for the SMBus alert protocol @@ -178,6 +179,11 @@ struct i2c_driver { int (*probe)(struct i2c_client *, const struct i2c_device_id *); int (*remove)(struct i2c_client *); + /* New driver model interface to aid the seamless removal of the + * current probe()'s, more commonly unused than used second parameter. + */ + int (*probe_new)(struct i2c_client *); + /* driver model interfaces that don't relate to enumeration */ void (*shutdown)(struct i2c_client *); -- cgit v1.2.3 From 1e98dcd779705dbf9f9b2a5177674361649931e3 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 7 Nov 2016 12:47:44 +0000 Subject: mfd: 88pm860x: Move over to new I2C device .probe() call As part of an effort to rid the mostly unused second parameter for I2C related .probe() functions and to conform to other existing frameworks we're moving over to a temporary replacement .probe() call-back. Acked-by: Grant Likely Signed-off-by: Lee Jones Signed-off-by: Kieran Bingham Reviewed-by: Javier Martinez Canillas Signed-off-by: Wolfram Sang --- drivers/mfd/88pm860x-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 25e1aafae60c..227b99018657 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -1132,8 +1132,7 @@ static int pm860x_dt_init(struct device_node *np, return 0; } -static int pm860x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pm860x_probe(struct i2c_client *client) { struct pm860x_platform_data *pdata = dev_get_platdata(&client->dev); struct device_node *node = client->dev.of_node; @@ -1259,7 +1258,7 @@ static struct i2c_driver pm860x_driver = { .pm = &pm860x_pm_ops, .of_match_table = pm860x_dt_ids, }, - .probe = pm860x_probe, + .probe_new = pm860x_probe, .remove = pm860x_remove, .id_table = pm860x_id_table, }; -- cgit v1.2.3 From 9b50184ea56dbae613587ec4c0112aa07f288a79 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 11 Nov 2016 20:50:38 +0800 Subject: crypto: nx - drop duplicate header types.h Drop duplicate header types.h from nx.c. Signed-off-by: Geliang Tang Signed-off-by: Herbert Xu --- drivers/crypto/nx/nx.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 42f0f229f7f7..036057abb257 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c @@ -32,7 +32,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From b516b88a7946c92d418c8ad2673b94ea568d1cf5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 11 Nov 2016 14:56:47 +0000 Subject: hwrng: atmel - use clk_disable_unprepare instead of clk_disable Since clk_prepare_enable() is used to get trng->clk, we should use clk_disable_unprepare() to release it for the error path. Signed-off-by: Wei Yongjun Acked-by: Nicolas Ferre Signed-off-by: Herbert Xu --- drivers/char/hw_random/atmel-rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/atmel-rng.c b/drivers/char/hw_random/atmel-rng.c index ae7cae579eac..661c82cde0f2 100644 --- a/drivers/char/hw_random/atmel-rng.c +++ b/drivers/char/hw_random/atmel-rng.c @@ -94,7 +94,7 @@ static int atmel_trng_probe(struct platform_device *pdev) return 0; err_register: - clk_disable(trng->clk); + clk_disable_unprepare(trng->clk); return ret; } -- cgit v1.2.3 From 18f47f5e4737d5466a0e2774349bbb58d5512676 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Wed, 16 Nov 2016 20:41:46 +0530 Subject: crypto: vmx - various build fixes First up, clean up the generated .S files properly on a 'make clean'. Secondly, force re-generation of these files when building for different endian-ness than what was built previously. Finally, generate the new files in the build tree, rather than the source tree. Signed-off-by: Naveen N. Rao Signed-off-by: Michael Ellerman Signed-off-by: Herbert Xu --- drivers/crypto/vmx/Makefile | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/vmx/Makefile b/drivers/crypto/vmx/Makefile index de6e241b0866..55f7c392582f 100644 --- a/drivers/crypto/vmx/Makefile +++ b/drivers/crypto/vmx/Makefile @@ -10,10 +10,12 @@ endif quiet_cmd_perl = PERL $@ cmd_perl = $(PERL) $(<) $(TARGET) > $(@) -$(src)/aesp8-ppc.S: $(src)/aesp8-ppc.pl - $(call cmd,perl) +targets += aesp8-ppc.S ghashp8-ppc.S + +$(obj)/aesp8-ppc.S: $(src)/aesp8-ppc.pl FORCE + $(call if_changed,perl) -$(src)/ghashp8-ppc.S: $(src)/ghashp8-ppc.pl - $(call cmd,perl) +$(obj)/ghashp8-ppc.S: $(src)/ghashp8-ppc.pl FORCE + $(call if_changed,perl) -.PRECIOUS: $(obj)/aesp8-ppc.S $(obj)/ghashp8-ppc.S +clean-files := aesp8-ppc.S ghashp8-ppc.S -- cgit v1.2.3 From 8358c6b5fc8c160d0af8654f313b8a7745f8e304 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 19 Oct 2016 14:51:10 +0200 Subject: firmware: arm_scpi: add support for pre-v1.0 SCPI compatible This patch adds new DT match table to setup the support for SCPI protocol versions prior to v1.0 releases. It also adds "arm,scpi-pre-1.0" to the SCPI match entry. Signed-off-by: Sudeep Holla --- drivers/firmware/arm_scpi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index 902233642bd3..70e13230d8db 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c @@ -871,6 +871,11 @@ static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch) return 0; } +static const struct of_device_id legacy_scpi_of_match[] = { + {.compatible = "arm,scpi-pre-1.0"}, + {}, +}; + static int scpi_probe(struct platform_device *pdev) { int count, idx, ret; @@ -883,6 +888,9 @@ static int scpi_probe(struct platform_device *pdev) if (!scpi_info) return -ENOMEM; + if (of_match_device(legacy_scpi_of_match, &pdev->dev)) + scpi_info->is_legacy = true; + count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); if (count < 0) { dev_err(dev, "no mboxes property in '%s'\n", np->full_name); @@ -984,6 +992,7 @@ err: static const struct of_device_id scpi_of_match[] = { {.compatible = "arm,scpi"}, + {.compatible = "arm,scpi-pre-1.0"}, {}, }; -- cgit v1.2.3 From dadbb0aa363bf1233f75cab23977add69d197e23 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 16 Nov 2016 17:01:26 -0800 Subject: Input: gpio_keys - set input direction explicitly Commit 700a38b27eef ("Input: gpio_keys - switch to using generic device properties") switched to use generic device properties for GPIO keys and commit 5feeca3c1e39 ("Input: gpio_keys - add support for GPIO descriptors") switched from legacy GPIO numbers to GPIO descriptors. Previously devm_gpio_request_one was explicitly passed GPIOF_DIR_IN flag to set the GPIO direction as input. However devm_get_gpiod_from_child doesn't have such provisions and hence fwnode_get_named_gpiod can't set it as input. This breaks few platforms with the following error: " gpiochip_lock_as_irq: tried to flag a GPIO set as output for IRQ unable to lock HW IRQ for IRQ genirq: Failed to request resources for POWER (irq ) on irqchip gpio_keys: Unable to claim irq ; error -22 gpio-keys: probe failed with error -22 " This patch fixes the issue by setting input direction explicitly for gpio lines described by generic properties. Fixes: 700a38b27eef ("Input: gpio_keys - switch to using generic device properties") Signed-off-by: Sudeep Holla Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/gpio_keys.c | 7 +++++++ drivers/input/keyboard/gpio_keys_polled.c | 8 ++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 5576f2ae0b71..582462d0af75 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -496,6 +496,13 @@ static int gpio_keys_setup_key(struct platform_device *pdev, error); return error; } + } else { + error = gpiod_direction_input(bdata->gpiod); + if (error) { + dev_err(dev, "Failed to configure GPIO %d as input: %d\n", + desc_to_gpio(bdata->gpiod), error); + return error; + } } } else if (gpio_is_valid(button->gpio)) { /* diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c index 72b350315d43..bed4f2086158 100644 --- a/drivers/input/keyboard/gpio_keys_polled.c +++ b/drivers/input/keyboard/gpio_keys_polled.c @@ -314,6 +314,14 @@ static int gpio_keys_polled_probe(struct platform_device *pdev) fwnode_handle_put(child); return error; } + + error = gpiod_direction_input(bdata->gpiod); + if (error) { + dev_err(dev, "Failed to configure GPIO %d as input: %d\n", + desc_to_gpio(bdata->gpiod), error); + fwnode_handle_put(child); + return error; + } } else if (gpio_is_valid(button->gpio)) { /* * Legacy GPIO number so request the GPIO here and -- cgit v1.2.3 From 787b3c4f2e7d0888e211376c7c6a1617e8cc0f46 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:35 -0700 Subject: PCI: iproc: Add PAXC v2 support Add support for the second generation of the iProc PCIe PAXC host controller. Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Anup Patel Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc-platform.c | 3 + drivers/pci/host/pcie-iproc.c | 176 ++++++++++++++++++++++++++++++++- drivers/pci/host/pcie-iproc.h | 4 + 3 files changed, 180 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index a3de087976b3..f24315006835 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -33,6 +33,9 @@ static const struct of_device_id iproc_pcie_of_match_table[] = { }, { .compatible = "brcm,iproc-pcie-paxc", .data = (int *)IPROC_PCIE_PAXC, + }, { + .compatible = "brcm,iproc-pcie-paxc-v2", + .data = (int *)IPROC_PCIE_PAXC_V2, }, { /* sentinel */ } }; diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 15aafbfec7f1..d4ba1f2f4e39 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,12 @@ #define RC_PCIE_RST_OUTPUT BIT(RC_PCIE_RST_OUTPUT_SHIFT) #define PAXC_RESET_MASK 0x7f +#define GIC_V3_CFG_SHIFT 0 +#define GIC_V3_CFG BIT(GIC_V3_CFG_SHIFT) + +#define MSI_ENABLE_CFG_SHIFT 0 +#define MSI_ENABLE_CFG BIT(MSI_ENABLE_CFG_SHIFT) + #define CFG_IND_ADDR_MASK 0x00001ffc #define CFG_ADDR_BUS_NUM_SHIFT 20 @@ -79,6 +86,31 @@ enum iproc_pcie_reg { /* clock/reset signal control */ IPROC_PCIE_CLK_CTRL = 0, + /* + * To allow MSI to be steered to an external MSI controller (e.g., ARM + * GICv3 ITS) + */ + IPROC_PCIE_MSI_GIC_MODE, + + /* + * IPROC_PCIE_MSI_BASE_ADDR and IPROC_PCIE_MSI_WINDOW_SIZE define the + * window where the MSI posted writes are written, for the writes to be + * interpreted as MSI writes. + */ + IPROC_PCIE_MSI_BASE_ADDR, + IPROC_PCIE_MSI_WINDOW_SIZE, + + /* + * To hold the address of the register where the MSI writes are + * programed. When ARM GICv3 ITS is used, this should be programmed + * with the address of the GITS_TRANSLATER register. + */ + IPROC_PCIE_MSI_ADDR_LO, + IPROC_PCIE_MSI_ADDR_HI, + + /* enable MSI */ + IPROC_PCIE_MSI_EN_CFG, + /* allow access to root complex configuration space */ IPROC_PCIE_CFG_IND_ADDR, IPROC_PCIE_CFG_IND_DATA, @@ -142,6 +174,20 @@ static const u16 iproc_pcie_reg_paxc[] = { [IPROC_PCIE_CFG_DATA] = 0x1fc, }; +/* iProc PCIe PAXC v2 registers */ +static const u16 iproc_pcie_reg_paxc_v2[] = { + [IPROC_PCIE_MSI_GIC_MODE] = 0x050, + [IPROC_PCIE_MSI_BASE_ADDR] = 0x074, + [IPROC_PCIE_MSI_WINDOW_SIZE] = 0x078, + [IPROC_PCIE_MSI_ADDR_LO] = 0x07c, + [IPROC_PCIE_MSI_ADDR_HI] = 0x080, + [IPROC_PCIE_MSI_EN_CFG] = 0x09c, + [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, + [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, + [IPROC_PCIE_CFG_ADDR] = 0x1f8, + [IPROC_PCIE_CFG_DATA] = 0x1fc, +}; + static inline struct iproc_pcie *iproc_data(struct pci_bus *bus) { struct iproc_pcie *pcie; @@ -506,13 +552,131 @@ static int iproc_pcie_map_ranges(struct iproc_pcie *pcie, return 0; } +static int iproce_pcie_get_msi(struct iproc_pcie *pcie, + struct device_node *msi_node, + u64 *msi_addr) +{ + struct device *dev = pcie->dev; + int ret; + struct resource res; + + /* + * Check if 'msi-map' points to ARM GICv3 ITS, which is the only + * supported external MSI controller that requires steering. + */ + if (!of_device_is_compatible(msi_node, "arm,gic-v3-its")) { + dev_err(dev, "unable to find compatible MSI controller\n"); + return -ENODEV; + } + + /* derive GITS_TRANSLATER address from GICv3 */ + ret = of_address_to_resource(msi_node, 0, &res); + if (ret < 0) { + dev_err(dev, "unable to obtain MSI controller resources\n"); + return ret; + } + + *msi_addr = res.start + GITS_TRANSLATER; + return 0; +} + +static void iproc_pcie_paxc_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) +{ + u32 val; + + /* + * Program bits [43:13] of address of GITS_TRANSLATER register into + * bits [30:0] of the MSI base address register. In fact, in all iProc + * based SoCs, all I/O register bases are well below the 32-bit + * boundary, so we can safely assume bits [43:32] are always zeros. + */ + iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_BASE_ADDR, + (u32)(msi_addr >> 13)); + + /* use a default 8K window size */ + iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_WINDOW_SIZE, 0); + + /* steering MSI to GICv3 ITS */ + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_GIC_MODE); + val |= GIC_V3_CFG; + iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_GIC_MODE, val); + + /* + * Program bits [43:2] of address of GITS_TRANSLATER register into the + * iProc MSI address registers. + */ + msi_addr >>= 2; + iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_ADDR_HI, + upper_32_bits(msi_addr)); + iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_ADDR_LO, + lower_32_bits(msi_addr)); + + /* enable MSI */ + val = iproc_pcie_read_reg(pcie, IPROC_PCIE_MSI_EN_CFG); + val |= MSI_ENABLE_CFG; + iproc_pcie_write_reg(pcie, IPROC_PCIE_MSI_EN_CFG, val); +} + +static int iproc_pcie_msi_steer(struct iproc_pcie *pcie, + struct device_node *msi_node) +{ + struct device *dev = pcie->dev; + int ret; + u64 msi_addr; + + ret = iproce_pcie_get_msi(pcie, msi_node, &msi_addr); + if (ret < 0) { + dev_err(dev, "msi steering failed\n"); + return ret; + } + + switch (pcie->type) { + case IPROC_PCIE_PAXC_V2: + iproc_pcie_paxc_v2_msi_steer(pcie, msi_addr); + break; + default: + return -EINVAL; + } + + return 0; +} + static int iproc_pcie_msi_enable(struct iproc_pcie *pcie) { struct device_node *msi_node; + int ret; + + /* + * Either the "msi-parent" or the "msi-map" phandle needs to exist + * for us to obtain the MSI node. + */ msi_node = of_parse_phandle(pcie->dev->of_node, "msi-parent", 0); - if (!msi_node) - return -ENODEV; + if (!msi_node) { + const __be32 *msi_map = NULL; + int len; + u32 phandle; + + msi_map = of_get_property(pcie->dev->of_node, "msi-map", &len); + if (!msi_map) + return -ENODEV; + + phandle = be32_to_cpup(msi_map + 1); + msi_node = of_find_node_by_phandle(phandle); + if (!msi_node) + return -ENODEV; + } + + /* + * Certain revisions of the iProc PCIe controller require additional + * configurations to steer the MSI writes towards an external MSI + * controller. + */ + if (pcie->need_msi_steer) { + ret = iproc_pcie_msi_steer(pcie, msi_node); + if (ret) + return ret; + } /* * If another MSI controller is being used, the call below should fail @@ -544,6 +708,11 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) regs = iproc_pcie_reg_paxc; pcie->ep_is_internal = true; break; + case IPROC_PCIE_PAXC_V2: + regs = iproc_pcie_reg_paxc_v2; + pcie->ep_is_internal = true; + pcie->need_msi_steer = true; + break; default: dev_err(dev, "incompatible iProc PCIe interface\n"); return -EINVAL; @@ -556,7 +725,8 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) return -ENOMEM; /* go through the register table and populate all valid registers */ - pcie->reg_offsets[0] = regs[0]; + pcie->reg_offsets[0] = (pcie->type == IPROC_PCIE_PAXC_V2) ? + IPROC_PCIE_REG_INVALID : regs[0]; for (reg_idx = 1; reg_idx < IPROC_PCIE_MAX_NUM_REG; reg_idx++) pcie->reg_offsets[reg_idx] = regs[reg_idx] ? regs[reg_idx] : IPROC_PCIE_REG_INVALID; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 711dd3a5f55b..c2da14029040 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -27,6 +27,7 @@ enum iproc_pcie_type { IPROC_PCIE_PAXB_BCMA = 0, IPROC_PCIE_PAXB, IPROC_PCIE_PAXC, + IPROC_PCIE_PAXC_V2, }; /** @@ -61,6 +62,8 @@ struct iproc_msi; * unsupported request from being forwarded as an APB bus error * @need_ob_cfg: indicates SW needs to configure the outbound mapping window * @ob: outbound mapping parameters + * @need_msi_steer: indicates additional configuration of the iProc PCIe + * controller is required to steer MSI writes to external interrupt controller * @msi: MSI data */ struct iproc_pcie { @@ -79,6 +82,7 @@ struct iproc_pcie { bool has_apb_err_disable; bool need_ob_cfg; struct iproc_pcie_ob ob; + bool need_msi_steer; struct iproc_msi *msi; }; -- cgit v1.2.3 From 4213e15c364e74fa0593a6b3e1e24e52f932eb85 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:37 -0700 Subject: PCI: iproc: Make outbound mapping code more generic Improve the iProc PCIe outbound mapping code by making it more generic and removing redundant device tree properties 'brcm,pcie-ob-window-size' and 'brcm,pcie-ob-oarr-size'. The driver is still backward compatible to device tree binaries with the two properties specified. The driver now automatically configures the correct mapping window size and number of mapping windows based on the value of device tree property 'ranges' and the capability of of the iProc PCIe controller. Signed-off-by: Oza Oza Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc-platform.c | 13 -- drivers/pci/host/pcie-iproc.c | 247 +++++++++++++++++++++++---------- drivers/pci/host/pcie-iproc.h | 15 +- 3 files changed, 186 insertions(+), 89 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index f24315006835..47329d34267c 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -87,19 +87,6 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) return ret; } pcie->ob.axi_offset = val; - - ret = of_property_read_u32(np, "brcm,pcie-ob-window-size", - &val); - if (ret) { - dev_err(dev, - "missing brcm,pcie-ob-window-size property\n"); - return ret; - } - pcie->ob.window_size = (resource_size_t)val * SZ_1M; - - if (of_property_read_bool(np, "brcm,pcie-ob-oarr-size")) - pcie->ob.set_oarr_size = true; - pcie->need_ob_cfg = true; } diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index d4ba1f2f4e39..2db60abe2a4a 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -68,17 +68,47 @@ #define APB_ERR_EN_SHIFT 0 #define APB_ERR_EN BIT(APB_ERR_EN_SHIFT) +/* derive the enum index of the outbound/inbound mapping registers */ +#define MAP_REG(base_reg, index) ((base_reg) + (index) * 2) + +/* + * Maximum number of outbound mapping window sizes that can be supported by any + * OARR/OMAP mapping pair + */ +#define MAX_NUM_OB_WINDOW_SIZES 4 + #define OARR_VALID_SHIFT 0 #define OARR_VALID BIT(OARR_VALID_SHIFT) #define OARR_SIZE_CFG_SHIFT 1 -#define OARR_SIZE_CFG BIT(OARR_SIZE_CFG_SHIFT) #define PCI_EXP_CAP 0xac -#define MAX_NUM_OB_WINDOWS 2 - #define IPROC_PCIE_REG_INVALID 0xffff +/** + * iProc PCIe outbound mapping controller specific parameters + * + * @window_sizes: list of supported outbound mapping window sizes in MB + * @nr_sizes: number of supported outbound mapping window sizes + */ +struct iproc_pcie_ob_map { + resource_size_t window_sizes[MAX_NUM_OB_WINDOW_SIZES]; + unsigned int nr_sizes; +}; + +static const struct iproc_pcie_ob_map paxb_ob_map[] = { + { + /* OARR0/OMAP0 */ + .window_sizes = { 128, 256 }, + .nr_sizes = 2, + }, + { + /* OARR1/OMAP1 */ + .window_sizes = { 128, 256 }, + .nr_sizes = 2, + }, +}; + /* * iProc PCIe host registers */ @@ -123,10 +153,14 @@ enum iproc_pcie_reg { IPROC_PCIE_INTX_EN, /* outbound address mapping */ - IPROC_PCIE_OARR_LO, - IPROC_PCIE_OARR_HI, - IPROC_PCIE_OMAP_LO, - IPROC_PCIE_OMAP_HI, + IPROC_PCIE_OARR0, + IPROC_PCIE_OMAP0, + IPROC_PCIE_OARR1, + IPROC_PCIE_OMAP1, + IPROC_PCIE_OARR2, + IPROC_PCIE_OMAP2, + IPROC_PCIE_OARR3, + IPROC_PCIE_OMAP3, /* link status */ IPROC_PCIE_LINK_STATUS, @@ -151,27 +185,27 @@ static const u16 iproc_pcie_reg_paxb_bcma[] = { /* iProc PCIe PAXB registers */ static const u16 iproc_pcie_reg_paxb[] = { - [IPROC_PCIE_CLK_CTRL] = 0x000, - [IPROC_PCIE_CFG_IND_ADDR] = 0x120, - [IPROC_PCIE_CFG_IND_DATA] = 0x124, - [IPROC_PCIE_CFG_ADDR] = 0x1f8, - [IPROC_PCIE_CFG_DATA] = 0x1fc, - [IPROC_PCIE_INTX_EN] = 0x330, - [IPROC_PCIE_OARR_LO] = 0xd20, - [IPROC_PCIE_OARR_HI] = 0xd24, - [IPROC_PCIE_OMAP_LO] = 0xd40, - [IPROC_PCIE_OMAP_HI] = 0xd44, - [IPROC_PCIE_LINK_STATUS] = 0xf0c, - [IPROC_PCIE_APB_ERR_EN] = 0xf40, + [IPROC_PCIE_CLK_CTRL] = 0x000, + [IPROC_PCIE_CFG_IND_ADDR] = 0x120, + [IPROC_PCIE_CFG_IND_DATA] = 0x124, + [IPROC_PCIE_CFG_ADDR] = 0x1f8, + [IPROC_PCIE_CFG_DATA] = 0x1fc, + [IPROC_PCIE_INTX_EN] = 0x330, + [IPROC_PCIE_OARR0] = 0xd20, + [IPROC_PCIE_OMAP0] = 0xd40, + [IPROC_PCIE_OARR1] = 0xd28, + [IPROC_PCIE_OMAP1] = 0xd48, + [IPROC_PCIE_LINK_STATUS] = 0xf0c, + [IPROC_PCIE_APB_ERR_EN] = 0xf40, }; /* iProc PCIe PAXC v1 registers */ static const u16 iproc_pcie_reg_paxc[] = { - [IPROC_PCIE_CLK_CTRL] = 0x000, - [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, - [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, - [IPROC_PCIE_CFG_ADDR] = 0x1f8, - [IPROC_PCIE_CFG_DATA] = 0x1fc, + [IPROC_PCIE_CLK_CTRL] = 0x000, + [IPROC_PCIE_CFG_IND_ADDR] = 0x1f0, + [IPROC_PCIE_CFG_IND_DATA] = 0x1f4, + [IPROC_PCIE_CFG_ADDR] = 0x1f8, + [IPROC_PCIE_CFG_DATA] = 0x1fc, }; /* iProc PCIe PAXC v2 registers */ @@ -256,18 +290,6 @@ static inline void iproc_pcie_apb_err_disable(struct pci_bus *bus, } } -static inline void iproc_pcie_ob_write(struct iproc_pcie *pcie, - enum iproc_pcie_reg reg, - unsigned window, u32 val) -{ - u16 offset = iproc_pcie_reg_offset(pcie, reg); - - if (iproc_pcie_reg_is_invalid(offset)) - return; - - writel(val, pcie->base + offset + (window * 8)); -} - /** * Note access to the configuration registers are protected at the higher layer * by 'pci_lock' in drivers/pci/access.c @@ -452,6 +474,58 @@ static void iproc_pcie_enable(struct iproc_pcie *pcie) iproc_pcie_write_reg(pcie, IPROC_PCIE_INTX_EN, SYS_RC_INTX_MASK); } +static inline bool iproc_pcie_ob_is_valid(struct iproc_pcie *pcie, + int window_idx) +{ + u32 val; + + val = iproc_pcie_read_reg(pcie, MAP_REG(IPROC_PCIE_OARR0, window_idx)); + + return !!(val & OARR_VALID); +} + +static inline int iproc_pcie_ob_write(struct iproc_pcie *pcie, int window_idx, + int size_idx, u64 axi_addr, u64 pci_addr) +{ + struct device *dev = pcie->dev; + u16 oarr_offset, omap_offset; + + /* + * Derive the OARR/OMAP offset from the first pair (OARR0/OMAP0) based + * on window index. + */ + oarr_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_OARR0, + window_idx)); + omap_offset = iproc_pcie_reg_offset(pcie, MAP_REG(IPROC_PCIE_OMAP0, + window_idx)); + if (iproc_pcie_reg_is_invalid(oarr_offset) || + iproc_pcie_reg_is_invalid(omap_offset)) + return -EINVAL; + + /* + * Program the OARR registers. The upper 32-bit OARR register is + * always right after the lower 32-bit OARR register. + */ + writel(lower_32_bits(axi_addr) | (size_idx << OARR_SIZE_CFG_SHIFT) | + OARR_VALID, pcie->base + oarr_offset); + writel(upper_32_bits(axi_addr), pcie->base + oarr_offset + 4); + + /* now program the OMAP registers */ + writel(lower_32_bits(pci_addr), pcie->base + omap_offset); + writel(upper_32_bits(pci_addr), pcie->base + omap_offset + 4); + + dev_info(dev, "ob window [%d]: offset 0x%x axi %pap pci %pap\n", + window_idx, oarr_offset, &axi_addr, &pci_addr); + dev_info(dev, "oarr lo 0x%x oarr hi 0x%x\n", + readl(pcie->base + oarr_offset), + readl(pcie->base + oarr_offset + 4)); + dev_info(dev, "omap lo 0x%x omap hi 0x%x\n", + readl(pcie->base + omap_offset), + readl(pcie->base + omap_offset + 4)); + + return 0; +} + /** * Some iProc SoCs require the SW to configure the outbound address mapping * @@ -468,24 +542,7 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, { struct iproc_pcie_ob *ob = &pcie->ob; struct device *dev = pcie->dev; - unsigned i; - u64 max_size = (u64)ob->window_size * MAX_NUM_OB_WINDOWS; - u64 remainder; - - if (size > max_size) { - dev_err(dev, - "res size %pap exceeds max supported size 0x%llx\n", - &size, max_size); - return -EINVAL; - } - - div64_u64_rem(size, ob->window_size, &remainder); - if (remainder) { - dev_err(dev, - "res size %pap needs to be multiple of window size %pap\n", - &size, &ob->window_size); - return -EINVAL; - } + int ret = -EINVAL, window_idx, size_idx; if (axi_addr < ob->axi_offset) { dev_err(dev, "axi address %pap less than offset %pap\n", @@ -499,26 +556,70 @@ static int iproc_pcie_setup_ob(struct iproc_pcie *pcie, u64 axi_addr, */ axi_addr -= ob->axi_offset; - for (i = 0; i < MAX_NUM_OB_WINDOWS; i++) { - iproc_pcie_ob_write(pcie, IPROC_PCIE_OARR_LO, i, - lower_32_bits(axi_addr) | OARR_VALID | - (ob->set_oarr_size ? 1 : 0)); - iproc_pcie_ob_write(pcie, IPROC_PCIE_OARR_HI, i, - upper_32_bits(axi_addr)); - iproc_pcie_ob_write(pcie, IPROC_PCIE_OMAP_LO, i, - lower_32_bits(pci_addr)); - iproc_pcie_ob_write(pcie, IPROC_PCIE_OMAP_HI, i, - upper_32_bits(pci_addr)); - - size -= ob->window_size; - if (size == 0) + /* iterate through all OARR/OMAP mapping windows */ + for (window_idx = ob->nr_windows - 1; window_idx >= 0; window_idx--) { + const struct iproc_pcie_ob_map *ob_map = + &pcie->ob_map[window_idx]; + + /* + * If current outbound window is already in use, move on to the + * next one. + */ + if (iproc_pcie_ob_is_valid(pcie, window_idx)) + continue; + + /* + * Iterate through all supported window sizes within the + * OARR/OMAP pair to find a match. Go through the window sizes + * in a descending order. + */ + for (size_idx = ob_map->nr_sizes - 1; size_idx >= 0; + size_idx--) { + resource_size_t window_size = + ob_map->window_sizes[size_idx] * SZ_1M; + + if (size < window_size) + continue; + + if (!IS_ALIGNED(axi_addr, window_size) || + !IS_ALIGNED(pci_addr, window_size)) { + dev_err(dev, + "axi %pap or pci %pap not aligned\n", + &axi_addr, &pci_addr); + return -EINVAL; + } + + /* + * Match found! Program both OARR and OMAP and mark + * them as a valid entry. + */ + ret = iproc_pcie_ob_write(pcie, window_idx, size_idx, + axi_addr, pci_addr); + if (ret) + goto err_ob; + + size -= window_size; + if (size == 0) + return 0; + + /* + * If we are here, we are done with the current window, + * but not yet finished all mappings. Need to move on + * to the next window. + */ + axi_addr += window_size; + pci_addr += window_size; break; - - axi_addr += ob->window_size; - pci_addr += ob->window_size; + } } - return 0; +err_ob: + dev_err(dev, "unable to configure outbound mapping\n"); + dev_err(dev, + "axi %pap, axi offset %pap, pci %pap, res size %pap\n", + &axi_addr, &ob->axi_offset, &pci_addr, &size); + + return ret; } static int iproc_pcie_map_ranges(struct iproc_pcie *pcie, @@ -703,6 +804,10 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) case IPROC_PCIE_PAXB: regs = iproc_pcie_reg_paxb; pcie->has_apb_err_disable = true; + if (pcie->need_ob_cfg) { + pcie->ob_map = paxb_ob_map; + pcie->ob.nr_windows = ARRAY_SIZE(paxb_ob_map); + } break; case IPROC_PCIE_PAXC: regs = iproc_pcie_reg_paxc; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index c2da14029040..861b526c171b 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -32,17 +32,16 @@ enum iproc_pcie_type { /** * iProc PCIe outbound mapping - * @set_oarr_size: indicates the OARR size bit needs to be set * @axi_offset: offset from the AXI address to the internal address used by * the iProc PCIe core - * @window_size: outbound window size + * @nr_windows: total number of supported outbound mapping windows */ struct iproc_pcie_ob { - bool set_oarr_size; resource_size_t axi_offset; - resource_size_t window_size; + unsigned int nr_windows; }; +struct iproc_pcie_ob_map; struct iproc_msi; /** @@ -60,8 +59,11 @@ struct iproc_msi; * @ep_is_internal: indicates an internal emulated endpoint device is connected * @has_apb_err_disable: indicates the controller can be configured to prevent * unsupported request from being forwarded as an APB bus error + * * @need_ob_cfg: indicates SW needs to configure the outbound mapping window - * @ob: outbound mapping parameters + * @ob: outbound mapping related parameters + * @ob_map: outbound mapping related parameters specific to the controller + * * @need_msi_steer: indicates additional configuration of the iProc PCIe * controller is required to steer MSI writes to external interrupt controller * @msi: MSI data @@ -80,8 +82,11 @@ struct iproc_pcie { int (*map_irq)(const struct pci_dev *, u8, u8); bool ep_is_internal; bool has_apb_err_disable; + bool need_ob_cfg; struct iproc_pcie_ob ob; + const struct iproc_pcie_ob_map *ob_map; + bool need_msi_steer; struct iproc_msi *msi; }; -- cgit v1.2.3 From dd9d4e7498de37d79f00cfe562db1daf77bc2651 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:39 -0700 Subject: PCI: iproc: Add inbound DMA mapping support Add support for inbound DMA mapping. The range of the inbound mapping is configured by the optional device tree property 'dma-ranges'. While inbound mapping is done automatically in the ASIC on most iProc-based SoCs, newer ASICs (e.g., Stingray) require inbound mapping to be configured explicitly in software. [bhelgaas: fold in fixes to avoid 32-bit division in iproc_pcie_ib_write() and uninitialized return value in iproc_pcie_setup_ib() from Arnd Bergmann ] Signed-off-by: Oza Oza Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc.c | 237 ++++++++++++++++++++++++++++++++++++++++++ drivers/pci/host/pcie-iproc.h | 15 +++ 2 files changed, 252 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 2db60abe2a4a..cbbbeaa46dad 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -81,6 +81,15 @@ #define OARR_VALID BIT(OARR_VALID_SHIFT) #define OARR_SIZE_CFG_SHIFT 1 +/* + * Maximum number of inbound mapping region sizes that can be supported by an + * IARR + */ +#define MAX_NUM_IB_REGION_SIZES 9 + +#define IMAP_VALID_SHIFT 0 +#define IMAP_VALID BIT(IMAP_VALID_SHIFT) + #define PCI_EXP_CAP 0xac #define IPROC_PCIE_REG_INVALID 0xffff @@ -109,6 +118,44 @@ static const struct iproc_pcie_ob_map paxb_ob_map[] = { }, }; +/** + * iProc PCIe inbound mapping type + */ +enum iproc_pcie_ib_map_type { + /* for DDR memory */ + IPROC_PCIE_IB_MAP_MEM = 0, + + /* for device I/O memory */ + IPROC_PCIE_IB_MAP_IO, + + /* invalid or unused */ + IPROC_PCIE_IB_MAP_INVALID +}; + +/** + * iProc PCIe inbound mapping controller specific parameters + * + * @type: inbound mapping region type + * @size_unit: inbound mapping region size unit, could be SZ_1K, SZ_1M, or + * SZ_1G + * @region_sizes: list of supported inbound mapping region sizes in KB, MB, or + * GB, depedning on the size unit + * @nr_sizes: number of supported inbound mapping region sizes + * @nr_windows: number of supported inbound mapping windows for the region + * @imap_addr_offset: register offset between the upper and lower 32-bit + * IMAP address registers + * @imap_window_offset: register offset between each IMAP window + */ +struct iproc_pcie_ib_map { + enum iproc_pcie_ib_map_type type; + unsigned int size_unit; + resource_size_t region_sizes[MAX_NUM_IB_REGION_SIZES]; + unsigned int nr_sizes; + unsigned int nr_windows; + u16 imap_addr_offset; + u16 imap_window_offset; +}; + /* * iProc PCIe host registers */ @@ -162,6 +209,18 @@ enum iproc_pcie_reg { IPROC_PCIE_OARR3, IPROC_PCIE_OMAP3, + /* inbound address mapping */ + IPROC_PCIE_IARR0, + IPROC_PCIE_IMAP0, + IPROC_PCIE_IARR1, + IPROC_PCIE_IMAP1, + IPROC_PCIE_IARR2, + IPROC_PCIE_IMAP2, + IPROC_PCIE_IARR3, + IPROC_PCIE_IMAP3, + IPROC_PCIE_IARR4, + IPROC_PCIE_IMAP4, + /* link status */ IPROC_PCIE_LINK_STATUS, @@ -653,6 +712,180 @@ static int iproc_pcie_map_ranges(struct iproc_pcie *pcie, return 0; } +static inline bool iproc_pcie_ib_is_in_use(struct iproc_pcie *pcie, + int region_idx) +{ + const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx]; + u32 val; + + val = iproc_pcie_read_reg(pcie, MAP_REG(IPROC_PCIE_IARR0, region_idx)); + + return !!(val & (BIT(ib_map->nr_sizes) - 1)); +} + +static inline bool iproc_pcie_ib_check_type(const struct iproc_pcie_ib_map *ib_map, + enum iproc_pcie_ib_map_type type) +{ + return !!(ib_map->type == type); +} + +static int iproc_pcie_ib_write(struct iproc_pcie *pcie, int region_idx, + int size_idx, int nr_windows, u64 axi_addr, + u64 pci_addr, resource_size_t size) +{ + struct device *dev = pcie->dev; + const struct iproc_pcie_ib_map *ib_map = &pcie->ib_map[region_idx]; + u16 iarr_offset, imap_offset; + u32 val; + int window_idx; + + iarr_offset = iproc_pcie_reg_offset(pcie, + MAP_REG(IPROC_PCIE_IARR0, region_idx)); + imap_offset = iproc_pcie_reg_offset(pcie, + MAP_REG(IPROC_PCIE_IMAP0, region_idx)); + if (iproc_pcie_reg_is_invalid(iarr_offset) || + iproc_pcie_reg_is_invalid(imap_offset)) + return -EINVAL; + + dev_info(dev, "ib region [%d]: offset 0x%x axi %pap pci %pap\n", + region_idx, iarr_offset, &axi_addr, &pci_addr); + + /* + * Program the IARR registers. The upper 32-bit IARR register is + * always right after the lower 32-bit IARR register. + */ + writel(lower_32_bits(pci_addr) | BIT(size_idx), + pcie->base + iarr_offset); + writel(upper_32_bits(pci_addr), pcie->base + iarr_offset + 4); + + dev_info(dev, "iarr lo 0x%x iarr hi 0x%x\n", + readl(pcie->base + iarr_offset), + readl(pcie->base + iarr_offset + 4)); + + /* + * Now program the IMAP registers. Each IARR region may have one or + * more IMAP windows. + */ + size >>= ilog2(nr_windows); + for (window_idx = 0; window_idx < nr_windows; window_idx++) { + val = readl(pcie->base + imap_offset); + val |= lower_32_bits(axi_addr) | IMAP_VALID; + writel(val, pcie->base + imap_offset); + writel(upper_32_bits(axi_addr), + pcie->base + imap_offset + ib_map->imap_addr_offset); + + dev_info(dev, "imap window [%d] lo 0x%x hi 0x%x\n", + window_idx, readl(pcie->base + imap_offset), + readl(pcie->base + imap_offset + + ib_map->imap_addr_offset)); + + imap_offset += ib_map->imap_window_offset; + axi_addr += size; + } + + return 0; +} + +static int iproc_pcie_setup_ib(struct iproc_pcie *pcie, + struct of_pci_range *range, + enum iproc_pcie_ib_map_type type) +{ + struct device *dev = pcie->dev; + struct iproc_pcie_ib *ib = &pcie->ib; + int ret; + unsigned int region_idx, size_idx; + u64 axi_addr = range->cpu_addr, pci_addr = range->pci_addr; + resource_size_t size = range->size; + + /* iterate through all IARR mapping regions */ + for (region_idx = 0; region_idx < ib->nr_regions; region_idx++) { + const struct iproc_pcie_ib_map *ib_map = + &pcie->ib_map[region_idx]; + + /* + * If current inbound region is already in use or not a + * compatible type, move on to the next. + */ + if (iproc_pcie_ib_is_in_use(pcie, region_idx) || + !iproc_pcie_ib_check_type(ib_map, type)) + continue; + + /* iterate through all supported region sizes to find a match */ + for (size_idx = 0; size_idx < ib_map->nr_sizes; size_idx++) { + resource_size_t region_size = + ib_map->region_sizes[size_idx] * ib_map->size_unit; + + if (size != region_size) + continue; + + if (!IS_ALIGNED(axi_addr, region_size) || + !IS_ALIGNED(pci_addr, region_size)) { + dev_err(dev, + "axi %pap or pci %pap not aligned\n", + &axi_addr, &pci_addr); + return -EINVAL; + } + + /* Match found! Program IARR and all IMAP windows. */ + ret = iproc_pcie_ib_write(pcie, region_idx, size_idx, + ib_map->nr_windows, axi_addr, + pci_addr, size); + if (ret) + goto err_ib; + else + return 0; + + } + } + ret = -EINVAL; + +err_ib: + dev_err(dev, "unable to configure inbound mapping\n"); + dev_err(dev, "axi %pap, pci %pap, res size %pap\n", + &axi_addr, &pci_addr, &size); + + return ret; +} + +static int pci_dma_range_parser_init(struct of_pci_range_parser *parser, + struct device_node *node) +{ + const int na = 3, ns = 2; + int rlen; + + parser->node = node; + parser->pna = of_n_addr_cells(node); + parser->np = parser->pna + na + ns; + + parser->range = of_get_property(node, "dma-ranges", &rlen); + if (!parser->range) + return -ENOENT; + + parser->end = parser->range + rlen / sizeof(__be32); + return 0; +} + +static int iproc_pcie_map_dma_ranges(struct iproc_pcie *pcie) +{ + struct of_pci_range range; + struct of_pci_range_parser parser; + int ret; + + /* Get the dma-ranges from DT */ + ret = pci_dma_range_parser_init(&parser, pcie->dev->of_node); + if (ret) + return ret; + + for_each_of_pci_range(&parser, &range) { + /* Each range entry corresponds to an inbound mapping region */ + ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_MEM); + if (ret) + return ret; + } + + return 0; +} + static int iproce_pcie_get_msi(struct iproc_pcie *pcie, struct device_node *msi_node, u64 *msi_addr) @@ -880,6 +1113,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) } } + ret = iproc_pcie_map_dma_ranges(pcie); + if (ret && ret != -ENOENT) + goto err_power_off_phy; + #ifdef CONFIG_ARM pcie->sysdata.private_data = pcie; sysdata = &pcie->sysdata; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 861b526c171b..3f2709af1a50 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -41,7 +41,16 @@ struct iproc_pcie_ob { unsigned int nr_windows; }; +/** + * iProc PCIe inbound mapping + * @nr_regions: total number of supported inbound mapping regions + */ +struct iproc_pcie_ib { + unsigned int nr_regions; +}; + struct iproc_pcie_ob_map; +struct iproc_pcie_ib_map; struct iproc_msi; /** @@ -64,6 +73,9 @@ struct iproc_msi; * @ob: outbound mapping related parameters * @ob_map: outbound mapping related parameters specific to the controller * + * @ib: inbound mapping related parameters + * @ib_map: outbound mapping region related parameters + * * @need_msi_steer: indicates additional configuration of the iProc PCIe * controller is required to steer MSI writes to external interrupt controller * @msi: MSI data @@ -87,6 +99,9 @@ struct iproc_pcie { struct iproc_pcie_ob ob; const struct iproc_pcie_ob_map *ob_map; + struct iproc_pcie_ib ib; + const struct iproc_pcie_ib_map *ib_map; + bool need_msi_steer; struct iproc_msi *msi; }; -- cgit v1.2.3 From c02b7bf532f7e46f1f9a0e9c3c27ca3f6f134e8d Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 10 Nov 2016 21:26:23 +0000 Subject: i2c: mux: mellanox: add driver This driver allows I2C routing controlled through CPLD select registers on a wide range of Mellanox systems (CPLD Lattice device). MUX selection is provided by digital and analog HW. Analog part is not under SW control. Digital part is under CPLD control (channel selection/de-selection). Connectivity schema. .---. .-------------. | l | | |-- i2cx1 -- i2cx8 | i |-- i2cn --+--| mlxcpld mux | | n | | | |-- i2cy1 -- i2cy8 | u | | '-------------' | x | | | '---' '---------' i2c-mux-mlxpcld does not necessarily require i2c-mlxcpld. It can be used along with another bus driver, and still control i2c routing through CPLD mux selection, in case the system is equipped with CPLD capable of mux selection control. The Kconfig currently controlling compilation of this code is: drivers/i2c/muxes/Kconfig:config I2C_MUX_MLXCPLD Signed-off-by: Michael Shych Signed-off-by: Vadim Pasternak Reviewed-by: Jiri Pirko Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- MAINTAINERS | 7 ++ drivers/i2c/muxes/Kconfig | 11 ++ drivers/i2c/muxes/Makefile | 1 + drivers/i2c/muxes/i2c-mux-mlxcpld.c | 220 ++++++++++++++++++++++++++++++++++++ include/linux/i2c/mlxcpld.h | 52 +++++++++ 5 files changed, 291 insertions(+) create mode 100644 drivers/i2c/muxes/i2c-mux-mlxcpld.c create mode 100644 include/linux/i2c/mlxcpld.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 411e3b87b8c2..22ee29a8f403 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7881,6 +7881,13 @@ W: http://www.mellanox.com Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/mellanox/mlxsw/ +MELLANOX MLXCPLD I2C MUX DRIVER +M: Vadim Pasternak +M: Michael Shych +L: linux-i2c@vger.kernel.org +S: Supported +F: drivers/i2c/muxes/i2c-mux-mlxcpld.c + MELLANOX MLXCPLD LED DRIVER M: Vadim Pasternak L: linux-leds@vger.kernel.org diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index e280c8ecc0b5..d03340203615 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -81,4 +81,15 @@ config I2C_DEMUX_PINCTRL demultiplexer that uses the pinctrl subsystem. This is useful if you want to change the I2C master at run-time depending on features. +config I2C_MUX_MLXCPLD + tristate "Mellanox CPLD based I2C multiplexer" + help + If you say yes to this option, support will be included for a + CPLD based I2C multiplexer. This driver provides access to + I2C busses connected through a MUX, which is controlled + by a CPLD register. + + This driver can also be built as a module. If so, the module + will be called i2c-mux-mlxcpld. + endmenu diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 7c267c29b191..9948fa45037f 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o +obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c new file mode 100644 index 000000000000..3ab654bbfab5 --- /dev/null +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -0,0 +1,220 @@ +/* + * drivers/i2c/muxes/i2c-mux-mlxcpld.c + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016 Michael Shych + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CPLD_MUX_MAX_NCHANS 8 + +/* mlxcpld_mux - mux control structure: + * @last_chan - last register value + * @client - I2C device client + */ +struct mlxcpld_mux { + u8 last_chan; + struct i2c_client *client; +}; + +/* MUX logic description. + * Driver can support different mux control logic, according to CPLD + * implementation. + * + * Connectivity schema. + * + * i2c-mlxcpld Digital Analog + * driver + * *--------* * -> mux1 (virt bus2) -> mux -> | + * | I2CLPC | i2c physical * -> mux2 (virt bus3) -> mux -> | + * | bridge | bus 1 *---------* | + * | logic |---------------------> * mux reg * | + * | in CPLD| *---------* | + * *--------* i2c-mux-mlxpcld ^ * -> muxn (virt busn) -> mux -> | + * | driver | | + * | *---------------* | Devices + * | * CPLD (i2c bus)* select | + * | * registers for *--------* + * | * mux selection * deselect + * | *---------------* + * | | + * <--------> <-----------> + * i2c cntrl Board cntrl reg + * reg space space (mux select, + * IO, LED, WD, info) + * + */ + +static const struct i2c_device_id mlxcpld_mux_id[] = { + { "mlxcpld_mux_module", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mlxcpld_mux_id); + +/* Write to mux register. Don't use i2c_transfer() and i2c_smbus_xfer() + * for this as they will try to lock adapter a second time. + */ +static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, + struct i2c_client *client, u8 val) +{ + struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + u8 msgbuf[] = {pdata->sel_reg_addr, val}; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2; + msg.buf = msgbuf; + return __i2c_transfer(adap, &msg, 1); + } else if (adap->algo->smbus_xfer) { + union i2c_smbus_data data; + + data.byte = val; + return adap->algo->smbus_xfer(adap, client->addr, + client->flags, I2C_SMBUS_WRITE, + pdata->sel_reg_addr, + I2C_SMBUS_BYTE_DATA, &data); + } else + return -ENODEV; +} + +static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct mlxcpld_mux *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + u8 regval = chan + 1; + int err = 0; + + /* Only select the channel if its different from the last channel */ + if (data->last_chan != regval) { + err = mlxcpld_mux_reg_write(muxc->parent, client, regval); + if (err) + data->last_chan = 0; + else + data->last_chan = regval; + } + + return err; +} + +static int mlxcpld_mux_deselect(struct i2c_mux_core *muxc, u32 chan) +{ + struct mlxcpld_mux *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + + /* Deselect active channel */ + data->last_chan = 0; + + return mlxcpld_mux_reg_write(muxc->parent, client, data->last_chan); +} + +/* Probe/reomove functions */ +static int mlxcpld_mux_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); + struct i2c_mux_core *muxc; + int num, force; + struct mlxcpld_mux *data; + int err; + + if (!pdata) + return -EINVAL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) + return -ENODEV; + + muxc = i2c_mux_alloc(adap, &client->dev, CPLD_MUX_MAX_NCHANS, + sizeof(*data), 0, mlxcpld_mux_select_chan, + mlxcpld_mux_deselect); + if (!muxc) + return -ENOMEM; + + data = i2c_mux_priv(muxc); + i2c_set_clientdata(client, muxc); + data->client = client; + data->last_chan = 0; /* force the first selection */ + + /* Create an adapter for each channel. */ + for (num = 0; num < CPLD_MUX_MAX_NCHANS; num++) { + if (num >= pdata->num_adaps) + /* discard unconfigured channels */ + break; + + force = pdata->adap_ids[num]; + + err = i2c_mux_add_adapter(muxc, force, num, 0); + if (err) + goto virt_reg_failed; + } + + return 0; + +virt_reg_failed: + i2c_mux_del_adapters(muxc); + return err; +} + +static int mlxcpld_mux_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + + i2c_mux_del_adapters(muxc); + return 0; +} + +static struct i2c_driver mlxcpld_mux_driver = { + .driver = { + .name = "mlxcpld-mux", + }, + .probe = mlxcpld_mux_probe, + .remove = mlxcpld_mux_remove, + .id_table = mlxcpld_mux_id, +}; + +module_i2c_driver(mlxcpld_mux_driver); + +MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)"); +MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:i2c-mux-mlxcpld"); diff --git a/include/linux/i2c/mlxcpld.h b/include/linux/i2c/mlxcpld.h new file mode 100644 index 000000000000..b08dcb183fca --- /dev/null +++ b/include/linux/i2c/mlxcpld.h @@ -0,0 +1,52 @@ +/* + * mlxcpld.h - Mellanox I2C multiplexer support in CPLD + * + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016 Michael Shych + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _LINUX_I2C_MLXCPLD_H +#define _LINUX_I2C_MLXCPLD_H + +/* Platform data for the CPLD I2C multiplexers */ + +/* mlxcpld_mux_plat_data - per mux data, used with i2c_register_board_info + * @adap_ids - adapter array + * @num_adaps - number of adapters + * @sel_reg_addr - mux select register offset in CPLD space + */ +struct mlxcpld_mux_plat_data { + int *adap_ids; + int num_adaps; + int sel_reg_addr; +}; + +#endif /* _LINUX_I2C_MLXCPLD_H */ -- cgit v1.2.3 From c19e4b9037fa8a0477525a64e93847f534e8cc17 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Thu, 17 Nov 2016 16:11:39 -0600 Subject: net/mlx4_core: Use device ID defines We added a bunch of new Mellanox device ID definitions because they'll be used by INTx quirks. Use them in the mlx4 ID table also so grep can find both places. No functional change intended. Signed-off-by: Bjorn Helgaas Acked-by: Tariq Toukan --- drivers/net/ethernet/mellanox/mlx4/main.c | 84 ++++++++++++++++--------------- 1 file changed, 43 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c index 7183ac4135d2..62788b7c728d 100644 --- a/drivers/net/ethernet/mellanox/mlx4/main.c +++ b/drivers/net/ethernet/mellanox/mlx4/main.c @@ -4012,49 +4012,51 @@ int mlx4_restart_one(struct pci_dev *pdev) return err; } +#define MLX_SP(id) { PCI_VDEVICE(MELLANOX, id), MLX4_PCI_DEV_FORCE_SENSE_PORT } +#define MLX_VF(id) { PCI_VDEVICE(MELLANOX, id), MLX4_PCI_DEV_IS_VF } +#define MLX_GN(id) { PCI_VDEVICE(MELLANOX, id), 0 } + static const struct pci_device_id mlx4_pci_table[] = { - /* MT25408 "Hermon" SDR */ - { PCI_VDEVICE(MELLANOX, 0x6340), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" DDR */ - { PCI_VDEVICE(MELLANOX, 0x634a), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" QDR */ - { PCI_VDEVICE(MELLANOX, 0x6354), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" DDR PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x6732), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" QDR PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x673c), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" EN 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x6368), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25408 "Hermon" EN 10GigE PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x6750), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25458 ConnectX EN 10GBASE-T 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x6372), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25458 ConnectX EN 10GBASE-T+Gen2 10GigE */ - { PCI_VDEVICE(MELLANOX, 0x675a), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26468 ConnectX EN 10GigE PCIe gen2*/ - { PCI_VDEVICE(MELLANOX, 0x6764), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26438 ConnectX EN 40GigE PCIe gen2 5GT/s */ - { PCI_VDEVICE(MELLANOX, 0x6746), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT26478 ConnectX2 40GigE PCIe gen2 */ - { PCI_VDEVICE(MELLANOX, 0x676e), MLX4_PCI_DEV_FORCE_SENSE_PORT }, - /* MT25400 Family [ConnectX-2 Virtual Function] */ - { PCI_VDEVICE(MELLANOX, 0x1002), MLX4_PCI_DEV_IS_VF }, + /* MT25408 "Hermon" */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_HERMON_SDR), /* SDR */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_HERMON_DDR), /* DDR */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_HERMON_QDR), /* QDR */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_HERMON_DDR_GEN2), /* DDR Gen2 */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_HERMON_QDR_GEN2), /* QDR Gen2 */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_HERMON_EN), /* EN 10GigE */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_HERMON_EN_GEN2), /* EN 10GigE Gen2 */ + /* MT25458 ConnectX EN 10GBASE-T */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_CONNECTX_EN), + MLX_SP(PCI_DEVICE_ID_MELLANOX_CONNECTX_EN_T_GEN2), /* Gen2 */ + /* MT26468 ConnectX EN 10GigE PCIe Gen2*/ + MLX_SP(PCI_DEVICE_ID_MELLANOX_CONNECTX_EN_GEN2), + /* MT26438 ConnectX EN 40GigE PCIe Gen2 5GT/s */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_CONNECTX_EN_5_GEN2), + /* MT26478 ConnectX2 40GigE PCIe Gen2 */ + MLX_SP(PCI_DEVICE_ID_MELLANOX_CONNECTX2), + /* MT25400 Family [ConnectX-2] */ + MLX_VF(0x1002), /* Virtual Function */ /* MT27500 Family [ConnectX-3] */ - { PCI_VDEVICE(MELLANOX, 0x1003), 0 }, - /* MT27500 Family [ConnectX-3 Virtual Function] */ - { PCI_VDEVICE(MELLANOX, 0x1004), MLX4_PCI_DEV_IS_VF }, - { PCI_VDEVICE(MELLANOX, 0x1005), 0 }, /* MT27510 Family */ - { PCI_VDEVICE(MELLANOX, 0x1006), 0 }, /* MT27511 Family */ - { PCI_VDEVICE(MELLANOX, 0x1007), 0 }, /* MT27520 Family */ - { PCI_VDEVICE(MELLANOX, 0x1008), 0 }, /* MT27521 Family */ - { PCI_VDEVICE(MELLANOX, 0x1009), 0 }, /* MT27530 Family */ - { PCI_VDEVICE(MELLANOX, 0x100a), 0 }, /* MT27531 Family */ - { PCI_VDEVICE(MELLANOX, 0x100b), 0 }, /* MT27540 Family */ - { PCI_VDEVICE(MELLANOX, 0x100c), 0 }, /* MT27541 Family */ - { PCI_VDEVICE(MELLANOX, 0x100d), 0 }, /* MT27550 Family */ - { PCI_VDEVICE(MELLANOX, 0x100e), 0 }, /* MT27551 Family */ - { PCI_VDEVICE(MELLANOX, 0x100f), 0 }, /* MT27560 Family */ - { PCI_VDEVICE(MELLANOX, 0x1010), 0 }, /* MT27561 Family */ + MLX_GN(PCI_DEVICE_ID_MELLANOX_CONNECTX3), + MLX_VF(0x1004), /* Virtual Function */ + MLX_GN(0x1005), /* MT27510 Family */ + MLX_GN(0x1006), /* MT27511 Family */ + MLX_GN(PCI_DEVICE_ID_MELLANOX_CONNECTX3_PRO), /* MT27520 Family */ + MLX_GN(0x1008), /* MT27521 Family */ + MLX_GN(0x1009), /* MT27530 Family */ + MLX_GN(0x100a), /* MT27531 Family */ + MLX_GN(0x100b), /* MT27540 Family */ + MLX_GN(0x100c), /* MT27541 Family */ + MLX_GN(0x100d), /* MT27550 Family */ + MLX_GN(0x100e), /* MT27551 Family */ + MLX_GN(0x100f), /* MT27560 Family */ + MLX_GN(0x1010), /* MT27561 Family */ + + /* + * See the mellanox_check_broken_intx_masking() quirk when + * adding devices + */ + { 0, } }; -- cgit v1.2.3 From 738a7edbfc7b623e276686dead046c9f3aae6b2e Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: PCI: Don't acquire ref on parent in pci_bridge_d3_update() This function is always called with an existing pci_dev struct, which holds a reference on the pci_bus struct it resides on, which in turn holds a reference on pci_bus->bridge, which is the pci_dev's parent. Hence there's no need to acquire an additional ref on the parent. More specifically, the pci_dev exists until pci_destroy_dev() drops the final reference on it, so all calls to pci_bridge_d3_update() must be finished before that. It is arguably the caller's responsibility to ensure that it doesn't call pci_bridge_d3_update() with a pci_dev that might suddenly disappear, but in any case the existing callers are all safe: - The call in pci_destroy_dev() happens before the call to put_device(). - The call in pci_bus_add_device() is synchronized with pci_destroy_dev() using pci_lock_rescan_remove(). - The calls to pci_d3cold_disable() from the xhci and nouveau drivers are safe because a ref on the pci_dev is held as long as it's bound to a driver. - The calls to pci_d3cold_enable() / pci_d3cold_disable() when modifying the sysfs "d3cold_allowed" entry are also safe because kernfs_drain() waits for existing sysfs users to finish before removing the entry, and pci_destroy_dev() is called way after that. No functional change intended. Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pci.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index eda6a7cf0e54..5d6f2970fd6f 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2296,7 +2296,6 @@ static void pci_bridge_d3_update(struct pci_dev *dev, bool remove) if (!bridge || !pci_bridge_d3_possible(bridge)) return; - pci_dev_get(bridge); /* * If the device is removed we do not care about its D3cold * capabilities. @@ -2318,8 +2317,6 @@ static void pci_bridge_d3_update(struct pci_dev *dev, bool remove) /* Propagate change to upstream bridges */ pci_bridge_d3_update(bridge, false); } - - pci_dev_put(bridge); } /** -- cgit v1.2.3 From ff3a98be794d13dc0104c0a1fbab2b52f1a3299b Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Mon, 31 Oct 2016 13:59:47 -0400 Subject: i2c: i2c-pxa-pci; make explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/i2c/busses/Kconfig:config I2C_PXA_PCI drivers/i2c/busses/Kconfig: def_bool I2C_PXA && X86_32 && PCI && OF ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_pci_driver() uses the same init level priority as builtin_pci_driver() the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Signed-off-by: Paul Gortmaker Acked-by: Sebastian Andrzej Siewior Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa-pci.c | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 417464e9ea2a..004deb96afe3 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -1,9 +1,13 @@ /* + * CE4100 PCI-I2C glue code for PXA's driver + * Author: Sebastian Andrzej Siewior + * License: GPL v2 + * * The CE4100's I2C device is more or less the same one as found on PXA. * It does not support slave mode, the register slightly moved. This PCI * device provides three bars, every contains a single I2C controller. */ -#include +#include #include #include #include @@ -134,35 +138,17 @@ err_mem: return ret; } -static void ce4100_i2c_remove(struct pci_dev *dev) -{ - struct ce4100_devices *sds; - unsigned int i; - - sds = pci_get_drvdata(dev); - - for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) - platform_device_unregister(sds->pdev[i]); - - pci_disable_device(dev); - kfree(sds); -} - static const struct pci_device_id ce4100_i2c_devices[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, { }, }; -MODULE_DEVICE_TABLE(pci, ce4100_i2c_devices); static struct pci_driver ce4100_i2c_driver = { + .driver = { + .suppress_bind_attrs = true, + }, .name = "ce4100_i2c", .id_table = ce4100_i2c_devices, .probe = ce4100_i2c_probe, - .remove = ce4100_i2c_remove, }; - -module_pci_driver(ce4100_i2c_driver); - -MODULE_DESCRIPTION("CE4100 PCI-I2C glue code for PXA's driver"); -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Sebastian Andrzej Siewior "); +builtin_pci_driver(ce4100_i2c_driver); -- cgit v1.2.3 From 1ed276a7b9d84626e5243fc54863440c74a4100a Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: PCI: Autosense device removal in pci_bridge_d3_update() The algorithm to update the flag indicating whether a bridge may go to D3 makes a few optimizations based on whether the update was caused by the removal of a device on the one hand, versus the addition of a device or the change of its D3cold flags on the other hand. The information whether the update pertains to a removal is currently passed in by the caller, but the function may as well determine that itself by examining the device in question, thereby allowing for a considerable simplification and reduction of the code. Out of several options to determine removal, I've chosen the function device_is_registered() because it's cheap: It merely returns the dev->kobj.state_in_sysfs flag. That flag is set through device_add() when the root bus is scanned and cleared through device_remove(). The call to pci_bridge_d3_update() happens after each of these calls, respectively, so the ordering is correct. No functional change intended. Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/bus.c | 2 +- drivers/pci/pci.c | 35 +++++------------------------------ drivers/pci/pci.h | 3 +-- drivers/pci/remove.c | 2 +- 4 files changed, 8 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c index c288e5a52575..bc56cf19afd3 100644 --- a/drivers/pci/bus.c +++ b/drivers/pci/bus.c @@ -320,7 +320,7 @@ void pci_bus_add_device(struct pci_dev *dev) pci_fixup_device(pci_fixup_final, dev); pci_create_sysfs_dev_files(dev); pci_proc_attach_device(dev); - pci_bridge_d3_device_changed(dev); + pci_bridge_d3_update(dev); dev->match_driver = true; retval = device_attach(&dev->dev); diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 5d6f2970fd6f..8200874ef5fc 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2281,14 +2281,14 @@ static int pci_dev_check_d3cold(struct pci_dev *dev, void *data) /* * pci_bridge_d3_update - Update bridge D3 capabilities * @dev: PCI device which is changed - * @remove: Is the device being removed * * Update upstream bridge PM capabilities accordingly depending on if the * device PM configuration was changed or the device is being removed. The * change is also propagated upstream. */ -static void pci_bridge_d3_update(struct pci_dev *dev, bool remove) +void pci_bridge_d3_update(struct pci_dev *dev) { + bool remove = !device_is_registered(&dev->dev); struct pci_dev *bridge; bool d3cold_ok = true; @@ -2315,35 +2315,10 @@ static void pci_bridge_d3_update(struct pci_dev *dev, bool remove) if (bridge->bridge_d3 != d3cold_ok) { bridge->bridge_d3 = d3cold_ok; /* Propagate change to upstream bridges */ - pci_bridge_d3_update(bridge, false); + pci_bridge_d3_update(bridge); } } -/** - * pci_bridge_d3_device_changed - Update bridge D3 capabilities on change - * @dev: PCI device that was changed - * - * If a device is added or its PM configuration, such as is it allowed to - * enter D3cold, is changed this function updates upstream bridge PM - * capabilities accordingly. - */ -void pci_bridge_d3_device_changed(struct pci_dev *dev) -{ - pci_bridge_d3_update(dev, false); -} - -/** - * pci_bridge_d3_device_removed - Update bridge D3 capabilities on remove - * @dev: PCI device being removed - * - * Function updates upstream bridge PM capabilities based on other devices - * still left on the bus. - */ -void pci_bridge_d3_device_removed(struct pci_dev *dev) -{ - pci_bridge_d3_update(dev, true); -} - /** * pci_d3cold_enable - Enable D3cold for device * @dev: PCI device to handle @@ -2356,7 +2331,7 @@ void pci_d3cold_enable(struct pci_dev *dev) { if (dev->no_d3cold) { dev->no_d3cold = false; - pci_bridge_d3_device_changed(dev); + pci_bridge_d3_update(dev); } } EXPORT_SYMBOL_GPL(pci_d3cold_enable); @@ -2373,7 +2348,7 @@ void pci_d3cold_disable(struct pci_dev *dev) { if (!dev->no_d3cold) { dev->no_d3cold = true; - pci_bridge_d3_device_changed(dev); + pci_bridge_d3_update(dev); } } EXPORT_SYMBOL_GPL(pci_d3cold_disable); diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 451856210e18..27048bb88783 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -85,8 +85,7 @@ void pci_pm_init(struct pci_dev *dev); void pci_ea_init(struct pci_dev *dev); void pci_allocate_cap_save_buffers(struct pci_dev *dev); void pci_free_cap_save_buffers(struct pci_dev *dev); -void pci_bridge_d3_device_changed(struct pci_dev *dev); -void pci_bridge_d3_device_removed(struct pci_dev *dev); +void pci_bridge_d3_update(struct pci_dev *dev); static inline void pci_wakeup_event(struct pci_dev *dev) { diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c index f9357e09e9b3..73a03d382590 100644 --- a/drivers/pci/remove.c +++ b/drivers/pci/remove.c @@ -40,7 +40,7 @@ static void pci_destroy_dev(struct pci_dev *dev) list_del(&dev->bus_list); up_write(&pci_bus_sem); - pci_bridge_d3_device_removed(dev); + pci_bridge_d3_update(dev); pci_free_resources(dev); put_device(&dev->dev); } -- cgit v1.2.3 From e8559b7100324494acbde6e26bcdc6a5a5b4a4ed Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: PCI: Speed up algorithm in pci_bridge_d3_update() After a device has been added, removed or had its D3cold attributes changed, we recheck whether its parent bridge may runtime suspend to D3hot with pci_bridge_d3_update(). The most naive algorithm would be to iterate over the bridge's children and check if any of them are blocking D3. The function already tries to be a bit smarter than that by first checking the device that was changed. If this device already blocks D3 on the bridge, then walking over all the other children can be skipped. A drawback of this approach is that if the device is *not* blocking D3, it will be checked a second time by pci_walk_bus(). But that's cheap and is outweighed by the performance gain of potentially skipping pci_walk_bus() altogether. The algorithm can be optimized further by taking into account if D3 is currently allowed for the bridge, as shown in the following truth table: (a) remove && bridge_d3: D3 is currently allowed for the bridge and removing one of its children won't change that. No action necessary. (b) remove && !bridge_d3: D3 may now be allowed for the bridge if the removed child was the only one blocking it. Check all its siblings to verify that. (c) !remove && bridge_d3: D3 may now be disallowed but this can only be caused by the added/changed child, not any of its siblings. Check only that single device. (d) !remove && !bridge_d3: D3 may now be allowed for the bridge if the changed child was the only one blocking it. Check all its siblings to verify that. By checking beforehand if the changed child is blocking D3, we may be able to skip checking its siblings. Currently we do not special-case option (a) and in case of option (c) we gratuitously call pci_walk_bus(). Speed up the algorithm by adding these optimizations. Reword the comments a bit in an attempt to improve clarity. No functional change intended. Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pci.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8200874ef5fc..4a7f6f54d669 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2297,20 +2297,32 @@ void pci_bridge_d3_update(struct pci_dev *dev) return; /* - * If the device is removed we do not care about its D3cold - * capabilities. + * If D3 is currently allowed for the bridge, removing one of its + * children won't change that. + */ + if (remove && bridge->bridge_d3) + return; + + /* + * If D3 is currently allowed for the bridge and a child is added or + * changed, disallowance of D3 can only be caused by that child, so + * we only need to check that single device, not any of its siblings. + * + * If D3 is currently not allowed for the bridge, checking the device + * first may allow us to skip checking its siblings. */ if (!remove) pci_dev_check_d3cold(dev, &d3cold_ok); - if (d3cold_ok) { - /* - * We need to go through all children to find out if all of - * them can still go to D3cold. - */ + /* + * If D3 is currently not allowed for the bridge, this may be caused + * either by the device being changed/removed or any of its siblings, + * so we need to go through all children to find out if one of them + * continues to block D3. + */ + if (d3cold_ok && !bridge->bridge_d3) pci_walk_bus(bridge->subordinate, pci_dev_check_d3cold, &d3cold_ok); - } if (bridge->bridge_d3 != d3cold_ok) { bridge->bridge_d3 = d3cold_ok; -- cgit v1.2.3 From c6a6330706148e7d5265c3dd658d25843c83390f Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: PCI: Activate runtime PM on a PCIe port only if it can suspend Currently pcie_portdrv_probe() activates runtime PM on a PCIe port even if it will never actually suspend because the BIOS is too old or the "pcie_port_pm=off" option was specified on the kernel command line. A few CPU cycles can be saved by not activating runtime PM at all in these cases, because rpm_idle() and rpm_suspend() will bail out right at the beginning when calling rpm_check_suspend_allowed(), instead of carrying out various locking and assignments, invoking rpm_callback(), getting back -EBUSY and rolling everything back. The conditions checked in pci_bridge_d3_possible() are all static, they never change during uptime of the system, hence it's safe to call this to determine if runtime PM should be activated. No functional change intended. Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pci.c | 2 +- drivers/pci/pci.h | 1 + drivers/pci/pcie/portdrv_pci.c | 5 +++-- 3 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 4a7f6f54d669..720f7e27c3a8 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2230,7 +2230,7 @@ void pci_config_pm_runtime_put(struct pci_dev *pdev) * This function checks if it is possible to move the bridge to D3. * Currently we only allow D3 for recent enough PCIe ports. */ -static bool pci_bridge_d3_possible(struct pci_dev *bridge) +bool pci_bridge_d3_possible(struct pci_dev *bridge) { unsigned int year; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 27048bb88783..ffffef37ab61 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -85,6 +85,7 @@ void pci_pm_init(struct pci_dev *dev); void pci_ea_init(struct pci_dev *dev); void pci_allocate_cap_save_buffers(struct pci_dev *dev); void pci_free_cap_save_buffers(struct pci_dev *dev); +bool pci_bridge_d3_possible(struct pci_dev *dev); void pci_bridge_d3_update(struct pci_dev *dev); static inline void pci_wakeup_event(struct pci_dev *dev) diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 79327cc14e7d..1ae712cb22ec 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -19,6 +19,7 @@ #include #include +#include "../pci.h" #include "portdrv.h" #include "aer/aerdrv.h" @@ -157,7 +158,7 @@ static int pcie_portdrv_probe(struct pci_dev *dev, * subordinate devices). We can't be sure for native PCIe hotplug * either so prevent that as well. */ - if (!dev->is_hotplug_bridge) { + if (pci_bridge_d3_possible(dev) && !dev->is_hotplug_bridge) { /* * Keep the port resumed 100ms to make sure things like * config space accesses from userspace (lspci) will not @@ -175,7 +176,7 @@ static int pcie_portdrv_probe(struct pci_dev *dev, static void pcie_portdrv_remove(struct pci_dev *dev) { - if (!dev->is_hotplug_bridge) { + if (pci_bridge_d3_possible(dev) && !dev->is_hotplug_bridge) { pm_runtime_forbid(&dev->dev); pm_runtime_get_noresume(&dev->dev); pm_runtime_dont_use_autosuspend(&dev->dev); -- cgit v1.2.3 From 97a90aee5dab33aea0cd3f6802b3661990496262 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: PCI: Consolidate conditions to allow runtime PM on PCIe ports The conditions to allow runtime PM on PCIe ports are currently spread across two different files: The condition relating to hotplug ports is located in portdrv_pci.c whereas all other conditions are located in pci.c. Consolidate all conditions in a single place in pci.c, thus making it easier to follow the logic and amend conditions down the road. Note that the condition relating to hotplug ports is inserted *before* the condition relating to the "pcie_port_pm=force" command line option, so runtime PM is not afforded to hotplug ports even if this option is given. That's exactly how the code behaved up until now. If this is not desired, the ordering of the conditions can simply be reversed. No functional change intended. Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/pci.c | 11 +++++++++++ drivers/pci/pcie/portdrv_pci.c | 12 ++---------- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 720f7e27c3a8..a40ba0225265 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2243,6 +2243,17 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge) case PCI_EXP_TYPE_DOWNSTREAM: if (pci_bridge_d3_disable) return false; + + /* + * Hotplug interrupts cannot be delivered if the link is down, + * so parents of a hotplug port must stay awake. In addition, + * hotplug ports handled by firmware in System Management Mode + * may not be put into D3 by the OS (Thunderbolt on non-Macs). + * For simplicity, disallow in general for now. + */ + if (bridge->is_hotplug_bridge) + return false; + if (pci_bridge_d3_force) return true; diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c index 1ae712cb22ec..8aa3f14bc87d 100644 --- a/drivers/pci/pcie/portdrv_pci.c +++ b/drivers/pci/pcie/portdrv_pci.c @@ -150,15 +150,7 @@ static int pcie_portdrv_probe(struct pci_dev *dev, pci_save_state(dev); - /* - * Prevent runtime PM if the port is advertising support for PCIe - * hotplug. Otherwise the BIOS hotplug SMI code might not be able - * to enumerate devices behind this port properly (the port is - * powered down preventing all config space accesses to the - * subordinate devices). We can't be sure for native PCIe hotplug - * either so prevent that as well. - */ - if (pci_bridge_d3_possible(dev) && !dev->is_hotplug_bridge) { + if (pci_bridge_d3_possible(dev)) { /* * Keep the port resumed 100ms to make sure things like * config space accesses from userspace (lspci) will not @@ -176,7 +168,7 @@ static int pcie_portdrv_probe(struct pci_dev *dev, static void pcie_portdrv_remove(struct pci_dev *dev) { - if (pci_bridge_d3_possible(dev) && !dev->is_hotplug_bridge) { + if (pci_bridge_d3_possible(dev)) { pm_runtime_forbid(&dev->dev); pm_runtime_get_noresume(&dev->dev); pm_runtime_dont_use_autosuspend(&dev->dev); -- cgit v1.2.3 From 718a0609ae263b291848ecd0fa88bcf15ad49280 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: PCI: Unfold conditions to block runtime PM on PCIe ports The conditions to block D3 on parent ports are currently condensed into a single expression in pci_dev_check_d3cold(). Upcoming commits will add further conditions for hotplug ports, making this expression fairly large and impenetrable. Unfold the conditions to maintain readability when they are amended. No functional change intended. Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas CC: Mika Westerberg CC: Rafael J. Wysocki --- drivers/pci/pci.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a40ba0225265..d86351a2fe6e 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2274,19 +2274,20 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge) static int pci_dev_check_d3cold(struct pci_dev *dev, void *data) { bool *d3cold_ok = data; - bool no_d3cold; - /* - * The device needs to be allowed to go D3cold and if it is wake - * capable to do so from D3cold. - */ - no_d3cold = dev->no_d3cold || !dev->d3cold_allowed || - (device_may_wakeup(&dev->dev) && !pci_pme_capable(dev, PCI_D3cold)) || - !pci_power_manageable(dev); + if (/* The device needs to be allowed to go D3cold ... */ + dev->no_d3cold || !dev->d3cold_allowed || + + /* ... and if it is wakeup capable to do so from D3cold. */ + (device_may_wakeup(&dev->dev) && + !pci_pme_capable(dev, PCI_D3cold)) || + + /* If it is a bridge it must be allowed to go to D3. */ + !pci_power_manageable(dev)) - *d3cold_ok = !no_d3cold; + *d3cold_ok = false; - return no_d3cold; + return !*d3cold_ok; } /* -- cgit v1.2.3 From 6ef13824e0d897858ea4510a2c61b00445922fad Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: ACPI / hotplug / PCI: Use cached copy of PCI_EXP_SLTCAP_HPC bit We cache the PCI_EXP_SLTCAP_HPC bit in pci_dev->is_hotplug_bridge on device probe, so there's no need to read it again when adding the ACPI hotplug context. Here's the call chain to prove that no ordering issue is introduced: pci_scan_child_bus [drivers/pci/probe.c] pci_scan_slot pci_scan_single_device pci_scan_device pci_setup_device set_pcie_hotplug_bridge [is_hotplug_bridge bit is set here] pci_scan_bridge pci_add_new_bus pci_alloc_child_bus pcibios_add_bus [arch/(x86|arm64|ia64)/...] acpi_pci_add_bus [drivers/pci/pci-acpi.c] acpiphp_enumerate_slots [drivers/pci/hotplug/acpiphp_glue.c] acpiphp_add_context device_is_managed_by_native_pciehp [is_hotplug_bridge bit is queried here] No functional change intended. Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index a46b585fae31..b286a56e84b3 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -225,14 +225,11 @@ static void acpiphp_post_dock_fixup(struct acpi_device *adev) /* Check whether the PCI device is managed by native PCIe hotplug driver */ static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) { - u32 reg32; acpi_handle tmp; struct acpi_pci_root *root; /* Check whether the PCIe port supports native PCIe hotplug */ - if (pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, ®32)) - return false; - if (!(reg32 & PCI_EXP_SLTCAP_HPC)) + if (!pdev->is_hotplug_bridge) return false; /* -- cgit v1.2.3 From 437eb7bf7b28472f8b7689e166dc1dd691367121 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: ACPI / hotplug / PCI: Make device_is_managed_by_native_pciehp() public We're about to add runtime PM of hotplug ports, but we need to restrict it to ports that are handled natively by the OS: If they're handled by the firmware (which is the case for Thunderbolt on non-Macs), things would break if the OS put the ports into D3hot behind the firmware's back. To determine if a hotplug port is handled natively, one has to walk up from the port to the root bridge and check the cached _OSC Control Field for the value of the "PCI Express Native Hot Plug control" bit. There's already a function to do that, device_is_managed_by_native_pciehp(), but it's private to drivers/pci/hotplug/acpiphp_glue.c and only compiled in if CONFIG_HOTPLUG_PCI_ACPI is enabled. Make it public and move it to drivers/pci/pci-acpi.c, so that it is available in the more general CONFIG_ACPI case. The function contains a check if the device in question is a hotplug port and returns false if it's not. The caller we're going to add doesn't need this as it only calls the function if it actually *is* a hotplug port. Move the check out of the function into the single existing caller. Rename it to pciehp_is_native() and add some kerneldoc and polish. No functional change intended. Tested-by: Mika Westerberg Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki --- drivers/pci/hotplug/acpiphp_glue.c | 28 +--------------------------- drivers/pci/pci-acpi.c | 24 ++++++++++++++++++++++++ include/linux/pci_hotplug.h | 2 ++ 3 files changed, 27 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index b286a56e84b3..5ed2dcaa8e27 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -222,32 +222,6 @@ static void acpiphp_post_dock_fixup(struct acpi_device *adev) acpiphp_let_context_go(context); } -/* Check whether the PCI device is managed by native PCIe hotplug driver */ -static bool device_is_managed_by_native_pciehp(struct pci_dev *pdev) -{ - acpi_handle tmp; - struct acpi_pci_root *root; - - /* Check whether the PCIe port supports native PCIe hotplug */ - if (!pdev->is_hotplug_bridge) - return false; - - /* - * Check whether native PCIe hotplug has been enabled for - * this PCIe hierarchy. - */ - tmp = acpi_find_root_bridge_handle(pdev); - if (!tmp) - return false; - root = acpi_pci_find_root(tmp); - if (!root) - return false; - if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL)) - return false; - - return true; -} - /** * acpiphp_add_context - Add ACPIPHP context to an ACPI device object. * @handle: ACPI handle of the object to add a context to. @@ -331,7 +305,7 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, * expose slots to user space in those cases. */ if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev)) - && !(pdev && device_is_managed_by_native_pciehp(pdev))) { + && !(pdev && pdev->is_hotplug_bridge && pciehp_is_native(pdev))) { unsigned long long sun; int retval; diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index d966d47c9e80..ed3daa8e7658 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -293,6 +293,30 @@ int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp) } EXPORT_SYMBOL_GPL(pci_get_hp_params); +/** + * pciehp_is_native - Check whether a hotplug port is handled by the OS + * @pdev: Hotplug port to check + * + * Walk up from @pdev to the host bridge, obtain its cached _OSC Control Field + * and return the value of the "PCI Express Native Hot Plug control" bit. + * On failure to obtain the _OSC Control Field return %false. + */ +bool pciehp_is_native(struct pci_dev *pdev) +{ + struct acpi_pci_root *root; + acpi_handle handle; + + handle = acpi_find_root_bridge_handle(pdev); + if (!handle) + return false; + + root = acpi_pci_find_root(handle); + if (!root) + return false; + + return root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL; +} + /** * pci_acpi_wake_bus - Root bus wakeup notification fork function. * @work: Work item to handle. diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h index 8c7895061121..2e855afa0212 100644 --- a/include/linux/pci_hotplug.h +++ b/include/linux/pci_hotplug.h @@ -176,6 +176,7 @@ struct hotplug_params { #ifdef CONFIG_ACPI #include int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp); +bool pciehp_is_native(struct pci_dev *pdev); int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags); int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle); int acpi_pci_detect_ejectable(acpi_handle handle); @@ -185,5 +186,6 @@ static inline int pci_get_hp_params(struct pci_dev *dev, { return -ENODEV; } +static inline bool pciehp_is_native(struct pci_dev *pdev) { return true; } #endif #endif -- cgit v1.2.3 From 68db9bc814362e7f24371c27d12a4f34477d9356 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Fri, 28 Oct 2016 10:52:06 +0200 Subject: PCI: pciehp: Add runtime PM support for PCIe hotplug ports Linux 4.8 added support for runtime suspending PCIe ports to D3hot with commit 006d44e49a25 ("PCI: Add runtime PM support for PCIe ports"), but excluded hotplug ports. Those are now afforded runtime PM by the present commit. Hotplug ports require a few extra considerations: - The configuration space of the port remains accessible in D3hot, so all the functions to read or modify the Slot Status and Slot Control registers need not be modified. Even turning on slot power doesn't seem to require the port to be in D0, at least the PCIe spec doesn't say so and I confirmed that by testing with a Thunderbolt controller. - However D0 is required to access devices on the secondary bus. This happens in pciehp_check_link_status() and pciehp_configure_device() (both called from board_added()) and in pciehp_unconfigure_device() (called from remove_board()), so acquire a runtime PM ref for their invocation. - The hotplug port stays active as long as it has active children. If all hotplugged devices below the port runtime suspend, the port is allowed to runtime suspend as well. Plug and unplug detection continues to work in D3hot. - Hotplug interrupts are delivered in-band, so while the hotplug port itself is allowed to go to D3hot, its parent ports must stay in D0 for interrupts to come through. Add a corresponding restriction to pci_dev_check_d3cold(). - Runtime PM may only be allowed if the hotplug port is handled natively by the OS. On ACPI systems, the port may alternatively be handled by the firmware and things break if the OS puts the port into D3 behind the firmware's back: E.g. Thunderbolt hotplug ports on non-Macs are handled by Intel's firmware in System Management Mode and the firmware is known to access devices on the port's secondary bus without checking first if the port is in D0: https://bugzilla.kernel.org/show_bug.cgi?id=53811 Signed-off-by: Lukas Wunner Signed-off-by: Bjorn Helgaas Reviewed-by: Rafael J. Wysocki CC: Mika Westerberg --- drivers/pci/hotplug/pciehp_ctrl.c | 6 ++++++ drivers/pci/pci.c | 12 ++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index efe69e879455..ffd3fe6646c2 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "../pci.h" #include "pciehp.h" @@ -98,6 +99,7 @@ static int board_added(struct slot *p_slot) pciehp_green_led_blink(p_slot); /* Check link training status */ + pm_runtime_get_sync(&ctrl->pcie->port->dev); retval = pciehp_check_link_status(ctrl); if (retval) { ctrl_err(ctrl, "Failed to check link status\n"); @@ -118,12 +120,14 @@ static int board_added(struct slot *p_slot) if (retval != -EEXIST) goto err_exit; } + pm_runtime_put(&ctrl->pcie->port->dev); pciehp_green_led_on(p_slot); pciehp_set_attention_status(p_slot, 0); return 0; err_exit: + pm_runtime_put(&ctrl->pcie->port->dev); set_slot_off(ctrl, p_slot); return retval; } @@ -137,7 +141,9 @@ static int remove_board(struct slot *p_slot) int retval; struct controller *ctrl = p_slot->ctrl; + pm_runtime_get_sync(&ctrl->pcie->port->dev); retval = pciehp_unconfigure_device(p_slot); + pm_runtime_put(&ctrl->pcie->port->dev); if (retval) return retval; diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index d86351a2fe6e..1eb622cc8645 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -2245,13 +2245,10 @@ bool pci_bridge_d3_possible(struct pci_dev *bridge) return false; /* - * Hotplug interrupts cannot be delivered if the link is down, - * so parents of a hotplug port must stay awake. In addition, - * hotplug ports handled by firmware in System Management Mode + * Hotplug ports handled by firmware in System Management Mode * may not be put into D3 by the OS (Thunderbolt on non-Macs). - * For simplicity, disallow in general for now. */ - if (bridge->is_hotplug_bridge) + if (bridge->is_hotplug_bridge && !pciehp_is_native(bridge)) return false; if (pci_bridge_d3_force) @@ -2283,7 +2280,10 @@ static int pci_dev_check_d3cold(struct pci_dev *dev, void *data) !pci_pme_capable(dev, PCI_D3cold)) || /* If it is a bridge it must be allowed to go to D3. */ - !pci_power_manageable(dev)) + !pci_power_manageable(dev) || + + /* Hotplug interrupts cannot be delivered if the link is down. */ + dev->is_hotplug_bridge) *d3cold_ok = false; -- cgit v1.2.3 From 379883cc67d890e0412d6e6c952d7eb0614b915a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 15 Oct 2016 19:32:01 +0200 Subject: i2c: constify i2c_adapter_quirks structures Check for i2c_adapter_quirks structures that are only stored in the quirks field of an i2c_adapter structure. This field is declared const, so i2c_adapter_quirks structures that have this property can be declared as const also. Signed-off-by: Julia Lawall Acked-by: Ray Jui # for bcm-iproc Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-axxia.c | 2 +- drivers/i2c/busses/i2c-bcm-iproc.c | 2 +- drivers/i2c/busses/i2c-dln2.c | 2 +- drivers/i2c/busses/i2c-viperboard.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index 4351a9343058..13f07482ec68 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -489,7 +489,7 @@ static const struct i2c_algorithm axxia_i2c_algo = { .functionality = axxia_i2c_func, }; -static struct i2c_adapter_quirks axxia_i2c_quirks = { +static const struct i2c_adapter_quirks axxia_i2c_quirks = { .max_read_len = 255, .max_write_len = 255, }; diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 326b3db02c48..318df559adc5 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -395,7 +395,7 @@ static const struct i2c_algorithm bcm_iproc_algo = { .functionality = bcm_iproc_i2c_functionality, }; -static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { +static const struct i2c_adapter_quirks bcm_iproc_i2c_quirks = { /* need to reserve one byte in the FIFO for the slave address */ .max_read_len = M_TX_RX_FIFO_SIZE - 1, }; diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index 8acda2aa1558..69075a32073e 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -182,7 +182,7 @@ static const struct i2c_algorithm dln2_i2c_usb_algorithm = { .functionality = dln2_i2c_func, }; -static struct i2c_adapter_quirks dln2_i2c_quirks = { +static const struct i2c_adapter_quirks dln2_i2c_quirks = { .max_read_len = DLN2_I2C_MAX_XFER_SIZE, .max_write_len = DLN2_I2C_MAX_XFER_SIZE, }; diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 543456a0a338..e4be86b3de9a 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -354,7 +354,7 @@ static const struct i2c_algorithm vprbrd_algorithm = { .functionality = vprbrd_i2c_func, }; -static struct i2c_adapter_quirks vprbrd_quirks = { +static const struct i2c_adapter_quirks vprbrd_quirks = { .max_read_len = 2048, .max_write_len = 2048, }; -- cgit v1.2.3 From c3ae106050b949d6c776c5434046c888a5a6298a Mon Sep 17 00:00:00 2001 From: Tin Huynh Date: Thu, 10 Nov 2016 09:56:33 +0700 Subject: i2c: designware: Implement support for SMBus block read and write Free and Open IPMI use SMBUS BLOCK Read/Write to support SSIF protocol. However, I2C Designware Core Driver doesn't handle the case at the moment. The below patch supports this feature. Signed-off-by: Tin Huynh Acked-by: Jarkko Nikula Reviewed-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 46 +++++++++++++++++++++++++++-- drivers/i2c/busses/i2c-designware-pcidrv.c | 1 + drivers/i2c/busses/i2c-designware-platdrv.c | 1 + 3 files changed, 45 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 11e866d05368..4f56328b906f 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -554,6 +554,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) intr_mask = DW_IC_INTR_DEFAULT_MASK; for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) { + u32 flags = msgs[dev->msg_write_idx].flags; + /* * if target address has changed, we need to * reprogram the target address in the i2c @@ -599,8 +601,15 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) * detected from the registers so we set it always * when writing/reading the last byte. */ + + /* + * i2c-core.c always sets the buffer length of + * I2C_FUNC_SMBUS_BLOCK_DATA to 1. The length will + * be adjusted when receiving the first byte. + * Thus we can't stop the transaction here. + */ if (dev->msg_write_idx == dev->msgs_num - 1 && - buf_len == 1) + buf_len == 1 && !(flags & I2C_M_RECV_LEN)) cmd |= BIT(9); if (need_restart) { @@ -625,7 +634,12 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) dev->tx_buf = buf; dev->tx_buf_len = buf_len; - if (buf_len > 0) { + /* + * Because we don't know the buffer length in the + * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop + * the transaction here. + */ + if (buf_len > 0 || flags & I2C_M_RECV_LEN) { /* more bytes to be written */ dev->status |= STATUS_WRITE_IN_PROGRESS; break; @@ -646,6 +660,24 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) dw_writel(dev, intr_mask, DW_IC_INTR_MASK); } +static u8 +i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len) +{ + struct i2c_msg *msgs = dev->msgs; + u32 flags = msgs[dev->msg_read_idx].flags; + + /* + * Adjust the buffer length and mask the flag + * after receiving the first byte. + */ + len += (flags & I2C_CLIENT_PEC) ? 2 : 1; + dev->tx_buf_len = len - min_t(u8, len, dev->rx_outstanding); + msgs[dev->msg_read_idx].len = len; + msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN; + + return len; +} + static void i2c_dw_read(struct dw_i2c_dev *dev) { @@ -670,7 +702,15 @@ i2c_dw_read(struct dw_i2c_dev *dev) rx_valid = dw_readl(dev, DW_IC_RXFLR); for (; len > 0 && rx_valid > 0; len--, rx_valid--) { - *buf++ = dw_readl(dev, DW_IC_DATA_CMD); + u32 flags = msgs[dev->msg_read_idx].flags; + + *buf = dw_readl(dev, DW_IC_DATA_CMD); + /* Ensure length byte is a valid value */ + if (flags & I2C_M_RECV_LEN && + *buf <= I2C_SMBUS_BLOCK_MAX && *buf > 0) { + len = i2c_dw_recv_len(dev, *buf); + } + buf++; dev->rx_outstanding--; } diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 96f8230cd2d3..8ffe2da6ca2f 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -75,6 +75,7 @@ struct dw_pci_controller { I2C_FUNC_SMBUS_BYTE | \ I2C_FUNC_SMBUS_BYTE_DATA | \ I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_BLOCK_DATA | \ I2C_FUNC_SMBUS_I2C_BLOCK) /* Merrifield HCNT/LCNT/SDA hold time */ diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 0b42a12171f3..886fb622ca38 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -220,6 +220,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK; dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | -- cgit v1.2.3 From 973652db6f1406e556613b7bb252f1a005005f04 Mon Sep 17 00:00:00 2001 From: Jarkko Nikula Date: Thu, 10 Nov 2016 13:37:20 +0200 Subject: i2c: designware: Allow reduce bus speed by "clock-frequency" property Allow more flexibility to bus speed selection. Now if there are I2C slave connections defined in ACPI the speed of slowest device on the bus will define the bus speed. However if also "clock-frequency" device property is defined we should use the slowest of these two. This is targeted to maker boards where developer may want to connect slower I2C slave devices to the bus than defined in existing ACPI I2C slave connections. Signed-off-by: Jarkko Nikula Reviewed-by: Mika Westerberg Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 886fb622ca38..7429dfa39440 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -176,9 +176,6 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) dev->irq = irq; platform_set_drvdata(pdev, dev); - /* fast mode by default because of legacy reasons */ - dev->clk_freq = 400000; - if (pdata) { dev->clk_freq = pdata->i2c_scl_freq; } else { @@ -193,8 +190,16 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) } acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev); - if (acpi_speed) - dev->clk_freq = acpi_speed; + /* + * Find bus speed from the "clock-frequency" device property, ACPI + * or by using fast mode if neither is set. + */ + if (acpi_speed && dev->clk_freq) + dev->clk_freq = min(dev->clk_freq, acpi_speed); + else if (acpi_speed || dev->clk_freq) + dev->clk_freq = max(dev->clk_freq, acpi_speed); + else + dev->clk_freq = 400000; if (has_acpi_companion(&pdev->dev)) dw_i2c_acpi_configure(pdev); -- cgit v1.2.3 From a837bad6f213669b967b56a4a6f81d8dfdf40428 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:49:20 +0900 Subject: i2c: uniphier: rename jump label to follow coding style guideline Documentation/CodingStyle recommends to use label names which say what the goto does or why the goto exists. Signed-off-by: Masahiro Yamada Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-uniphier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index 56e92af46ddc..777c0fe93653 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -373,7 +373,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) if (!clk_rate) { dev_err(dev, "input clock rate should not be zero\n"); ret = -EINVAL; - goto err; + goto disable_clk; } init_completion(&priv->comp); @@ -392,11 +392,11 @@ static int uniphier_i2c_probe(struct platform_device *pdev) priv); if (ret) { dev_err(dev, "failed to request irq %d\n", irq); - goto err; + goto disable_clk; } ret = i2c_add_adapter(&priv->adap); -err: +disable_clk: if (ret) clk_disable_unprepare(priv->clk); -- cgit v1.2.3 From b92b7dbc714f3e604102ad0f056124fd5f8c00ce Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Fri, 4 Nov 2016 19:49:21 +0900 Subject: i2c: uniphier-f: rename jump label to follow coding style guideline Documentation/CodingStyle recommends to use label names which say what the goto does or why the goto exists. Signed-off-by: Masahiro Yamada Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-uniphier-f.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index db9105e52c79..beee31892295 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -528,7 +528,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) if (!clk_rate) { dev_err(dev, "input clock rate should not be zero\n"); ret = -EINVAL; - goto err; + goto disable_clk; } init_completion(&priv->comp); @@ -547,11 +547,11 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) pdev->name, priv); if (ret) { dev_err(dev, "failed to request irq %d\n", irq); - goto err; + goto disable_clk; } ret = i2c_add_adapter(&priv->adap); -err: +disable_clk: if (ret) clk_disable_unprepare(priv->clk); -- cgit v1.2.3 From 254df038e5ca275be437d5fa562d7f59beab6ef5 Mon Sep 17 00:00:00 2001 From: Tanmay Jagdale Date: Fri, 16 Sep 2016 00:57:39 +0530 Subject: i2c: xlp9xx: ACPI support for I2C clients The ACPI companion of the adapter has to be set for I2C controller code to read and attach the slave devices described in the ACPI table with the I2CSerialBus resource descriptor. Used ACPI_COMPANION_SET macro to set this. Signed-off-by: Tanmay Jagdale Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xlp9xx.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index e29ff37a43bd..84a8b2eccffb 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -393,6 +393,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) init_completion(&priv->msg_complete); priv->adapter.dev.parent = &pdev->dev; priv->adapter.algo = &xlp9xx_i2c_algo; + ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&pdev->dev)); priv->adapter.dev.of_node = pdev->dev.of_node; priv->dev = &pdev->dev; -- cgit v1.2.3 From a8cd47d3608e47de0be8cc36a2546e5930c17d2f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 15:39:45 -0300 Subject: [media] stb0899_drv: get rid of continuation lines This driver has printk continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups'")', this won't work as expected anymore. So, use %*ph and get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stb0899_drv.c | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index 3d171b0e00c2..8e7cafb8f36a 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -485,15 +485,8 @@ int stb0899_read_regs(struct stb0899_state *state, unsigned int reg, u8 *buf, u3 (((reg & 0xff00) == 0xf200) || ((reg & 0xff00) == 0xf600))) _stb0899_read_reg(state, (reg | 0x00ff)); - if (unlikely(*state->verbose >= FE_DEBUGREG)) { - int i; - - printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); - for (i = 0; i < count; i++) { - printk(" %02x", buf[i]); - } - printk("\n"); - } + dprintk(state->verbose, FE_DEBUGREG, 1, + "%s [0x%04x]: %*ph", __func__, reg, count, buf); return 0; err: @@ -522,14 +515,8 @@ int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, buf[1] = reg & 0xff; memcpy(&buf[2], data, count); - if (unlikely(*state->verbose >= FE_DEBUGREG)) { - int i; - - printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); - for (i = 0; i < count; i++) - printk(" %02x", data[i]); - printk("\n"); - } + dprintk(state->verbose, FE_DEBUGREG, 1, + "%s [0x%04x]: %*ph", __func__, reg, count, data); ret = i2c_transfer(state->i2c, &i2c_msg, 1); /* -- cgit v1.2.3 From fed9d8f3cd6b7e8dbb697377065ee3b88b6baa45 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 15:42:47 -0300 Subject: [media] stv090x: get rid of continuation lines This driver has printk continuation lines for debugging purposes. Since commit 563873318d32 ("Merge branch 'printk-cleanups'")', this won't work as expected anymore. So, use %*ph and get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv090x.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index 25bdf6e0f963..42d62cc9a357 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -739,14 +739,8 @@ static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 buf[1] = reg & 0xff; memcpy(&buf[2], data, count); - if (unlikely(*state->verbose >= FE_DEBUGREG)) { - int i; - - printk(KERN_DEBUG "%s [0x%04x]:", __func__, reg); - for (i = 0; i < count; i++) - printk(" %02x", data[i]); - printk("\n"); - } + dprintk(FE_DEBUGREG, 1, "%s [0x%04x]: %*ph", + __func__, reg, count, data); ret = i2c_transfer(state->i2c, &i2c_msg, 1); if (ret != 1) { -- cgit v1.2.3 From 7c646913530e2dc7fc679f31c1e5624277ef3c19 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 13 Oct 2016 15:57:58 -0300 Subject: [media] bt8xx/dst: use a more standard way to print messages This driver uses a weird, non-standard macro to print errors. It allows hiding all messages, including error ones, with doesn't seem a good idea. Instead, replace it to pr_foo(), and, for error messages, use pr_err(). The remaining messages were previouly classified as notice, info or debug, but they all looked like debug messages. So, add a dprintk() macro using the "verbose" modprobe argument to select what will be displayed. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/dst.c | 262 +++++++++++++++++++----------------------- 1 file changed, 118 insertions(+), 144 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c index 35bc9b2287b4..faea3f06e350 100644 --- a/drivers/media/pci/bt8xx/dst.c +++ b/drivers/media/pci/bt8xx/dst.c @@ -18,6 +18,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -30,9 +32,9 @@ #include "dst_priv.h" #include "dst_common.h" -static unsigned int verbose = 1; +static unsigned int verbose; module_param(verbose, int, 0644); -MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)"); +MODULE_PARM_DESC(verbose, "verbosity level (0 to 3)"); static unsigned int dst_addons; module_param(dst_addons, int, 0644); @@ -46,29 +48,10 @@ MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); #define ATTEMPT_TUNE 2 #define HAS_POWER 4 -#define DST_ERROR 0 -#define DST_NOTICE 1 -#define DST_INFO 2 -#define DST_DEBUG 3 - -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > DST_ERROR) && (x > y)) \ - printk(KERN_ERR "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_INFO) && (x > y)) \ - printk(KERN_INFO "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - else if ((x > DST_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "dst(%d) %s: " format "\n", \ - state->bt->nr, __func__ , ##arg); \ - } else { \ - if (x > y) \ - printk(format, ##arg); \ - } \ +#define dprintk(level, fmt, arg...) do { \ + if (level >= verbose) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ } while(0) static int dst_command(struct dst_state *state, u8 *data, u8 len); @@ -91,9 +74,11 @@ static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, enb.enb.mask = mask; enb.enb.enable = enbb; - dprintk(verbose, DST_INFO, 1, "mask=[%04x], enbb=[%04x], outhigh=[%04x]", mask, enbb, outhigh); + dprintk(2, "mask=[%04x], enbb=[%04x], outhigh=[%04x]\n", + mask, enbb, outhigh); if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk(verbose, DST_INFO, 1, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)", err, mask, enbb); + dprintk(2, "dst_gpio_enb error (err == %i, mask == %02x, enb == %02x)\n", + err, mask, enbb); return -EREMOTEIO; } udelay(1000); @@ -105,7 +90,8 @@ static int dst_gpio_outb(struct dst_state *state, u32 mask, u32 enbb, bits.outp.mask = enbb; bits.outp.highvals = outhigh; if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk(verbose, DST_INFO, 1, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)", err, enbb, outhigh); + dprintk(2, "dst_gpio_outb error (err == %i, enbb == %02x, outhigh == %02x)\n", + err, enbb, outhigh); return -EREMOTEIO; } @@ -119,7 +105,7 @@ static int dst_gpio_inb(struct dst_state *state, u8 *result) *result = 0; if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err); + pr_err("dst_gpio_inb error (err == %i)\n", err); return -EREMOTEIO; } *result = (u8) rd_packet.rd.value; @@ -129,14 +115,14 @@ static int dst_gpio_inb(struct dst_state *state, u8 *result) int rdc_reset_state(struct dst_state *state) { - dprintk(verbose, DST_INFO, 1, "Resetting state machine"); + dprintk(2, "Resetting state machine\n"); if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + pr_err("dst_gpio_outb ERROR !\n"); return -1; } msleep(10); if (dst_gpio_outb(state, RDC_8820_INT, RDC_8820_INT, RDC_8820_INT, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + pr_err("dst_gpio_outb ERROR !\n"); msleep(10); return -1; } @@ -147,14 +133,14 @@ EXPORT_SYMBOL(rdc_reset_state); static int rdc_8820_reset(struct dst_state *state) { - dprintk(verbose, DST_DEBUG, 1, "Resetting DST"); + dprintk(3, "Resetting DST\n"); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + pr_err("dst_gpio_outb ERROR !\n"); return -1; } udelay(1000); if (dst_gpio_outb(state, RDC_8820_RESET, RDC_8820_RESET, RDC_8820_RESET, DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + pr_err("dst_gpio_outb ERROR !\n"); return -1; } @@ -164,7 +150,7 @@ static int rdc_8820_reset(struct dst_state *state) static int dst_pio_enable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_ENABLE, 0, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + pr_err("dst_gpio_outb ERROR !\n"); return -1; } udelay(1000); @@ -175,7 +161,7 @@ static int dst_pio_enable(struct dst_state *state) int dst_pio_disable(struct dst_state *state) { if (dst_gpio_outb(state, ~0, RDC_8820_PIO_0_DISABLE, RDC_8820_PIO_0_DISABLE, NO_DELAY) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_outb ERROR !"); + pr_err("dst_gpio_outb ERROR !\n"); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) @@ -192,16 +178,16 @@ int dst_wait_dst_ready(struct dst_state *state, u8 delay_mode) for (i = 0; i < 200; i++) { if (dst_gpio_inb(state, &reply) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb ERROR !"); + pr_err("dst_gpio_inb ERROR !\n"); return -1; } if ((reply & RDC_8820_PIO_0_ENABLE) == 0) { - dprintk(verbose, DST_INFO, 1, "dst wait ready after %d", i); + dprintk(2, "dst wait ready after %d\n", i); return 1; } msleep(10); } - dprintk(verbose, DST_NOTICE, 1, "dst wait NOT ready after %d", i); + dprintk(1, "dst wait NOT ready after %d\n", i); return 0; } @@ -209,7 +195,7 @@ EXPORT_SYMBOL(dst_wait_dst_ready); int dst_error_recovery(struct dst_state *state) { - dprintk(verbose, DST_NOTICE, 1, "Trying to return from previous errors."); + dprintk(1, "Trying to return from previous errors.\n"); dst_pio_disable(state); msleep(10); dst_pio_enable(state); @@ -221,7 +207,7 @@ EXPORT_SYMBOL(dst_error_recovery); int dst_error_bailout(struct dst_state *state) { - dprintk(verbose, DST_INFO, 1, "Trying to bailout from previous error."); + dprintk(2, "Trying to bailout from previous error.\n"); rdc_8820_reset(state); dst_pio_disable(state); msleep(10); @@ -232,13 +218,13 @@ EXPORT_SYMBOL(dst_error_bailout); int dst_comm_init(struct dst_state *state) { - dprintk(verbose, DST_INFO, 1, "Initializing DST."); + dprintk(2, "Initializing DST.\n"); if ((dst_pio_enable(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "PIO Enable Failed"); + pr_err("PIO Enable Failed\n"); return -1; } if ((rdc_reset_state(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "RDC 8820 State RESET Failed."); + pr_err("RDC 8820 State RESET Failed.\n"); return -1; } if (state->type_flags & DST_TYPE_HAS_FW_1) @@ -260,23 +246,21 @@ int write_dst(struct dst_state *state, u8 *data, u8 len) }; int err; - u8 cnt, i; + u8 cnt; - dprintk(verbose, DST_NOTICE, 0, "writing [ "); - for (i = 0; i < len; i++) - dprintk(verbose, DST_NOTICE, 0, "%02x ", data[i]); - dprintk(verbose, DST_NOTICE, 0, "]\n"); + dprintk(1, "writing [ %*ph ]\n", len, data); for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk(verbose, DST_INFO, 1, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, data[0]); + dprintk(2, "_write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", + err, len, data[0]); dst_error_recovery(state); continue; } else break; } if (cnt >= 2) { - dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); + dprintk(2, "RDC 8820 RESET\n"); dst_error_bailout(state); return -1; @@ -300,23 +284,20 @@ int read_dst(struct dst_state *state, u8 *ret, u8 len) for (cnt = 0; cnt < 2; cnt++) { if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { - dprintk(verbose, DST_INFO, 1, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)", err, len, ret[0]); + dprintk(2, "read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", + err, len, ret[0]); dst_error_recovery(state); continue; } else break; } if (cnt >= 2) { - dprintk(verbose, DST_INFO, 1, "RDC 8820 RESET"); + dprintk(2, "RDC 8820 RESET\n"); dst_error_bailout(state); return -1; } - dprintk(verbose, DST_DEBUG, 1, "reply is 0x%x", ret[0]); - for (err = 1; err < len; err++) - dprintk(verbose, DST_DEBUG, 0, " 0x%x", ret[err]); - if (err > 1) - dprintk(verbose, DST_DEBUG, 0, "\n"); + dprintk(3, "reply is %*ph\n", len, ret); return 0; } @@ -326,11 +307,11 @@ static int dst_set_polarization(struct dst_state *state) { switch (state->voltage) { case SEC_VOLTAGE_13: /* Vertical */ - dprintk(verbose, DST_INFO, 1, "Polarization=[Vertical]"); + dprintk(2, "Polarization=[Vertical]\n"); state->tx_tuna[8] &= ~0x40; break; case SEC_VOLTAGE_18: /* Horizontal */ - dprintk(verbose, DST_INFO, 1, "Polarization=[Horizontal]"); + dprintk(2, "Polarization=[Horizontal]\n"); state->tx_tuna[8] |= 0x40; break; case SEC_VOLTAGE_OFF: @@ -343,7 +324,7 @@ static int dst_set_polarization(struct dst_state *state) static int dst_set_freq(struct dst_state *state, u32 freq) { state->frequency = freq; - dprintk(verbose, DST_INFO, 1, "set Frequency %u", freq); + dprintk(2, "set Frequency %u\n", freq); if (state->dst_type == DST_TYPE_IS_SAT) { freq = freq / 1000; @@ -463,7 +444,7 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) if (state->dst_type == DST_TYPE_IS_TERR) { return -EOPNOTSUPP; } - dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); + dprintk(2, "set symrate %u\n", srate); srate /= 1000; if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_SYMDIV) { @@ -471,7 +452,7 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) sval <<= 20; do_div(sval, 88000); symcalc = (u32) sval; - dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); + dprintk(2, "set symcalc %u\n", symcalc); state->tx_tuna[5] = (u8) (symcalc >> 12); state->tx_tuna[6] = (u8) (symcalc >> 4); state->tx_tuna[7] = (u8) (symcalc << 4); @@ -486,7 +467,7 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) state->tx_tuna[8] |= 0x20; } } else if (state->dst_type == DST_TYPE_IS_CABLE) { - dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name); + dprintk(3, "%s\n", state->fw_name); if (!strncmp(state->fw_name, "DCTNEW", 6)) { state->tx_tuna[5] = (u8) (srate >> 8); state->tx_tuna[6] = (u8) srate; @@ -561,24 +542,24 @@ static void dst_type_flags_print(struct dst_state *state) { u32 type_flags = state->type_flags; - dprintk(verbose, DST_ERROR, 0, "DST type flags :"); + pr_err("DST type flags :\n"); if (type_flags & DST_TYPE_HAS_TS188) - dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188); + pr_err(" 0x%x newtuner\n", DST_TYPE_HAS_TS188); if (type_flags & DST_TYPE_HAS_NEWTUNE_2) - dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2); + pr_err(" 0x%x newtuner 2\n", DST_TYPE_HAS_NEWTUNE_2); if (type_flags & DST_TYPE_HAS_TS204) - dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); + pr_err(" 0x%x ts204\n", DST_TYPE_HAS_TS204); if (type_flags & DST_TYPE_HAS_VLF) - dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF); + pr_err(" 0x%x VLF\n", DST_TYPE_HAS_VLF); if (type_flags & DST_TYPE_HAS_SYMDIV) - dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + pr_err(" 0x%x symdiv\n", DST_TYPE_HAS_SYMDIV); if (type_flags & DST_TYPE_HAS_FW_1) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 1", DST_TYPE_HAS_FW_1); + pr_err(" 0x%x firmware version = 1\n", DST_TYPE_HAS_FW_1); if (type_flags & DST_TYPE_HAS_FW_2) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 2", DST_TYPE_HAS_FW_2); + pr_err(" 0x%x firmware version = 2\n", DST_TYPE_HAS_FW_2); if (type_flags & DST_TYPE_HAS_FW_3) - dprintk(verbose, DST_ERROR, 0, " 0x%x firmware version = 3", DST_TYPE_HAS_FW_3); - dprintk(verbose, DST_ERROR, 0, "\n"); + pr_err(" 0x%x firmware version = 3\n", DST_TYPE_HAS_FW_3); + pr_err("\n"); } @@ -603,10 +584,10 @@ static int dst_type_print(struct dst_state *state, u8 type) break; default: - dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); + dprintk(2, "invalid dst type %d\n", type); return -EINVAL; } - dprintk(verbose, DST_INFO, 1, "DST type: %s", otype); + dprintk(2, "DST type: %s\n", otype); return 0; } @@ -914,12 +895,12 @@ static int dst_get_mac(struct dst_state *state) u8 get_mac[] = { 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; get_mac[7] = dst_check_sum(get_mac, 7); if (dst_command(state, get_mac, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + dprintk(2, "Unsupported Command\n"); return -1; } memset(&state->mac_address, '\0', 8); memcpy(&state->mac_address, &state->rxbuffer, 6); - dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); + pr_err("MAC Address=[%pM]\n", state->mac_address); return 0; } @@ -929,11 +910,11 @@ static int dst_fw_ver(struct dst_state *state) u8 get_ver[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; get_ver[7] = dst_check_sum(get_ver, 7); if (dst_command(state, get_ver, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + dprintk(2, "Unsupported Command\n"); return -1; } memcpy(&state->fw_version, &state->rxbuffer, 8); - dprintk(verbose, DST_ERROR, 1, "Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x", + pr_err("Firmware Ver = %x.%x Build = %02x, on %x:%x, %x-%x-20%02x\n", state->fw_version[0] >> 4, state->fw_version[0] & 0x0f, state->fw_version[1], state->fw_version[5], state->fw_version[6], @@ -950,17 +931,17 @@ static int dst_card_type(struct dst_state *state) u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; get_type[7] = dst_check_sum(get_type, 7); if (dst_command(state, get_type, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + dprintk(2, "Unsupported Command\n"); return -1; } memset(&state->card_info, '\0', 8); memcpy(&state->card_info, &state->rxbuffer, 7); - dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); + pr_err("Device Model=[%s]\n", &state->card_info[0]); for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { state->tuner_type = p_tuner_list->tuner_type; - dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]", + pr_err("DST has [%s] tuner, tuner type=[%d]\n", p_tuner_list->tuner_name, p_tuner_list->tuner_type); } } @@ -973,26 +954,19 @@ static int dst_get_vendor(struct dst_state *state) u8 get_vendor[] = { 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; get_vendor[7] = dst_check_sum(get_vendor, 7); if (dst_command(state, get_vendor, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); + dprintk(2, "Unsupported Command\n"); return -1; } memset(&state->vendor, '\0', 8); memcpy(&state->vendor, &state->rxbuffer, 7); - dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); + pr_err("Vendor=[%s]\n", &state->vendor[0]); return 0; } static void debug_dst_buffer(struct dst_state *state) { - int i; - - if (verbose > 2) { - printk("%s: [", __func__); - for (i = 0; i < 8; i++) - printk(" %02x", state->rxbuffer[i]); - printk("]\n"); - } + dprintk(3, "%s: [ %*ph ]\n", __func__, 8, state->rxbuffer); } static int dst_check_stv0299(struct dst_state *state) @@ -1001,13 +975,13 @@ static int dst_check_stv0299(struct dst_state *state) check_stv0299[7] = dst_check_sum(check_stv0299, 7); if (dst_command(state, check_stv0299, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed"); + pr_err("Cmd=[0x04] failed\n"); return -1; } debug_dst_buffer(state); if (memcmp(&check_stv0299, &state->rxbuffer, 8)) { - dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM"); + pr_err("Found a STV0299 NIM\n"); state->tuner_type = TUNER_TYPE_STV0299; return 0; } @@ -1021,13 +995,13 @@ static int dst_check_mb86a15(struct dst_state *state) check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); if (dst_command(state, check_mb86a15, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed"); + pr_err("Cmd=[0x10], failed\n"); return -1; } debug_dst_buffer(state); if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) { - dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM"); + pr_err("Found a MB86A15 NIM\n"); state->tuner_type = TUNER_TYPE_MB86A15; return 0; } @@ -1042,21 +1016,21 @@ static int dst_get_tuner_info(struct dst_state *state) get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); - dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE"); + pr_err("DST TYpe = MULTI FE\n"); if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { if (dst_command(state, get_tuner_1, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported"); + dprintk(2, "Cmd=[0x13], Unsupported\n"); goto force; } } else { if (dst_command(state, get_tuner_2, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported"); + dprintk(2, "Cmd=[0xb], Unsupported\n"); goto force; } } memcpy(&state->board_info, &state->rxbuffer, 8); if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { - dprintk(verbose, DST_ERROR, 1, "DST type has TS=188"); + pr_err("DST type has TS=188\n"); } if (state->board_info[0] == 0xbc) { if (state->dst_type != DST_TYPE_IS_ATSC) @@ -1066,7 +1040,7 @@ static int dst_get_tuner_info(struct dst_state *state) if (state->board_info[1] == 0x01) { state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; - dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard"); + pr_err("DST has Daughterboard\n"); } } @@ -1074,7 +1048,7 @@ static int dst_get_tuner_info(struct dst_state *state) force: if (!strncmp(state->fw_name, "DCT-CI", 6)) { state->type_flags |= DST_TYPE_HAS_TS204; - dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name); + pr_err("Forcing [%s] to TS188\n", state->fw_name); } return -1; @@ -1103,7 +1077,7 @@ static int dst_get_device_id(struct dst_state *state) if (read_dst(state, &reply, GET_ACK)) return -1; /* Read failure */ if (reply != ACK) { - dprintk(verbose, DST_INFO, 1, "Write not Acknowledged! [Reply=0x%02x]", reply); + dprintk(2, "Write not Acknowledged! [Reply=0x%02x]\n", reply); return -1; /* Unack'd write */ } if (!dst_wait_dst_ready(state, DEVICE_INIT)) @@ -1113,7 +1087,7 @@ static int dst_get_device_id(struct dst_state *state) dst_pio_disable(state); if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk(verbose, DST_INFO, 1, "Checksum failure!"); + dprintk(2, "Checksum failure!\n"); return -1; /* Checksum failure */ } state->rxbuffer[7] = '\0'; @@ -1125,7 +1099,7 @@ static int dst_get_device_id(struct dst_state *state) /* Card capabilities */ state->dst_hw_cap = p_dst_type->dst_feature; - dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id); + pr_err("Recognise [%s]\n", p_dst_type->device_id); strncpy(&state->fw_name[0], p_dst_type->device_id, 6); /* Multiple tuners */ if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { @@ -1133,7 +1107,7 @@ static int dst_get_device_id(struct dst_state *state) case DST_TYPE_IS_SAT: /* STV0299 check */ if (dst_check_stv0299(state) < 0) { - dprintk(verbose, DST_ERROR, 1, "Unsupported"); + pr_err("Unsupported\n"); state->tuner_type = TUNER_TYPE_MB86A15; } break; @@ -1141,7 +1115,7 @@ static int dst_get_device_id(struct dst_state *state) break; } if (dst_check_mb86a15(state) < 0) - dprintk(verbose, DST_ERROR, 1, "Unsupported"); + pr_err("Unsupported\n"); /* Single tuner */ } else { state->tuner_type = p_dst_type->tuner_type; @@ -1149,7 +1123,7 @@ static int dst_get_device_id(struct dst_state *state) for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && p_tuner_list->tuner_type == state->tuner_type) { - dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]", + pr_err("[%s] has a [%s]\n", p_dst_type->device_id, p_tuner_list->tuner_name); } } @@ -1158,8 +1132,8 @@ static int dst_get_device_id(struct dst_state *state) } if (i >= ARRAY_SIZE(dst_tlist)) { - dprintk(verbose, DST_ERROR, 1, "Unable to recognize %s or %s", &state->rxbuffer[0], &state->rxbuffer[1]); - dprintk(verbose, DST_ERROR, 1, "please email linux-dvb@linuxtv.org with this type in"); + pr_err("Unable to recognize %s or %s\n", &state->rxbuffer[0], &state->rxbuffer[1]); + pr_err("please email linux-dvb@linuxtv.org with this type in"); use_dst_type = DST_TYPE_IS_SAT; use_type_flags = DST_TYPE_HAS_SYMDIV; } @@ -1176,7 +1150,7 @@ static int dst_probe(struct dst_state *state) mutex_init(&state->dst_mutex); if (dst_addons & DST_TYPE_HAS_CA) { if ((rdc_8820_reset(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); + pr_err("RDC 8820 RESET Failed.\n"); return -1; } msleep(4000); @@ -1184,35 +1158,35 @@ static int dst_probe(struct dst_state *state) msleep(100); } if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); + pr_err("DST Initialization Failed.\n"); return -1; } msleep(100); if (dst_get_device_id(state) < 0) { - dprintk(verbose, DST_ERROR, 1, "unknown device."); + pr_err("unknown device.\n"); return -1; } if (dst_get_mac(state) < 0) { - dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); + dprintk(2, "MAC: Unsupported command\n"); } if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { if (dst_get_tuner_info(state) < 0) - dprintk(verbose, DST_INFO, 1, "Tuner: Unsupported command"); + dprintk(2, "Tuner: Unsupported command\n"); } if (state->type_flags & DST_TYPE_HAS_TS204) { dst_packsize(state, 204); } if (state->type_flags & DST_TYPE_HAS_FW_BUILD) { if (dst_fw_ver(state) < 0) { - dprintk(verbose, DST_INFO, 1, "FW: Unsupported command"); + dprintk(2, "FW: Unsupported command\n"); return 0; } if (dst_card_type(state) < 0) { - dprintk(verbose, DST_INFO, 1, "Card: Unsupported command"); + dprintk(2, "Card: Unsupported command\n"); return 0; } if (dst_get_vendor(state) < 0) { - dprintk(verbose, DST_INFO, 1, "Vendor: Unsupported command"); + dprintk(2, "Vendor: Unsupported command\n"); return 0; } } @@ -1226,33 +1200,33 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len) mutex_lock(&state->dst_mutex); if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_NOTICE, 1, "DST Communication Initialization Failed."); + dprintk(1, "DST Communication Initialization Failed.\n"); goto error; } if (write_dst(state, data, len)) { - dprintk(verbose, DST_INFO, 1, "Trying to recover.. "); + dprintk(2, "Trying to recover..\n"); if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "Recovery Failed."); + pr_err("Recovery Failed.\n"); goto error; } goto error; } if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "PIO Disable Failed."); + pr_err("PIO Disable Failed.\n"); goto error; } if (state->type_flags & DST_TYPE_HAS_FW_1) mdelay(3); if (read_dst(state, &reply, GET_ACK)) { - dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); + dprintk(3, "Trying to recover..\n"); if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_INFO, 1, "Recovery Failed."); + dprintk(2, "Recovery Failed.\n"); goto error; } goto error; } if (reply != ACK) { - dprintk(verbose, DST_INFO, 1, "write not acknowledged 0x%02x ", reply); + dprintk(2, "write not acknowledged 0x%02x\n", reply); goto error; } if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) @@ -1264,15 +1238,15 @@ static int dst_command(struct dst_state *state, u8 *data, u8 len) if (!dst_wait_dst_ready(state, NO_DELAY)) goto error; if (read_dst(state, state->rxbuffer, FIXED_COMM)) { - dprintk(verbose, DST_DEBUG, 1, "Trying to recover.. "); + dprintk(3, "Trying to recover..\n"); if ((dst_error_recovery(state)) < 0) { - dprintk(verbose, DST_INFO, 1, "Recovery failed."); + dprintk(2, "Recovery failed.\n"); goto error; } goto error; } if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { - dprintk(verbose, DST_INFO, 1, "checksum failure"); + dprintk(2, "checksum failure\n"); goto error; } mutex_unlock(&state->dst_mutex); @@ -1348,19 +1322,19 @@ static int dst_get_tuna(struct dst_state *state) else retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); if (retval < 0) { - dprintk(verbose, DST_DEBUG, 1, "read not successful"); + dprintk(3, "read not successful\n"); return retval; } if ((state->type_flags & DST_TYPE_HAS_VLF) && !(state->dst_type == DST_TYPE_IS_ATSC)) { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { - dprintk(verbose, DST_INFO, 1, "checksum failure ? "); + dprintk(2, "checksum failure ?\n"); return -EIO; } } else { if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { - dprintk(verbose, DST_INFO, 1, "checksum failure? "); + dprintk(2, "checksum failure?\n"); return -EIO; } } @@ -1387,7 +1361,7 @@ static int dst_write_tuna(struct dvb_frontend *fe) int retval; u8 reply; - dprintk(verbose, DST_INFO, 1, "type_flags 0x%x ", state->type_flags); + dprintk(2, "type_flags 0x%x\n", state->type_flags); state->decode_freq = 0; state->decode_lock = state->decode_strength = state->decode_snr = 0; if (state->dst_type == DST_TYPE_IS_SAT) { @@ -1397,7 +1371,7 @@ static int dst_write_tuna(struct dvb_frontend *fe) state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); mutex_lock(&state->dst_mutex); if ((dst_comm_init(state)) < 0) { - dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); + dprintk(3, "DST Communication initialization failed.\n"); goto error; } // if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { @@ -1412,19 +1386,19 @@ static int dst_write_tuna(struct dvb_frontend *fe) } if (retval < 0) { dst_pio_disable(state); - dprintk(verbose, DST_DEBUG, 1, "write not successful"); + dprintk(3, "write not successful\n"); goto werr; } if ((dst_pio_disable(state)) < 0) { - dprintk(verbose, DST_DEBUG, 1, "DST PIO disable failed !"); + dprintk(3, "DST PIO disable failed !\n"); goto error; } if ((read_dst(state, &reply, GET_ACK) < 0)) { - dprintk(verbose, DST_DEBUG, 1, "read verify not successful."); + dprintk(3, "read verify not successful.\n"); goto error; } if (reply != ACK) { - dprintk(verbose, DST_DEBUG, 1, "write not acknowledged 0x%02x ", reply); + dprintk(3, "write not acknowledged 0x%02x\n", reply); goto error; } state->diseq_flags |= ATTEMPT_TUNE; @@ -1622,7 +1596,7 @@ static int dst_set_frontend(struct dvb_frontend *fe) retval = dst_set_freq(state, p->frequency); if(retval != 0) return retval; - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + dprintk(3, "Set Frequency=[%d]\n", p->frequency); if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) @@ -1630,7 +1604,7 @@ static int dst_set_frontend(struct dvb_frontend *fe) dst_set_fec(state, p->fec_inner); dst_set_symbolrate(state, p->symbol_rate); dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); + dprintk(3, "Set Symbolrate=[%d]\n", p->symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) dst_set_bandwidth(state, p->bandwidth_hz); @@ -1656,7 +1630,7 @@ static int dst_tune_frontend(struct dvb_frontend* fe, if (re_tune) { dst_set_freq(state, p->frequency); - dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + dprintk(3, "Set Frequency=[%d]\n", p->frequency); if (state->dst_type == DST_TYPE_IS_SAT) { if (state->type_flags & DST_TYPE_HAS_OBS_REGS) @@ -1664,7 +1638,7 @@ static int dst_tune_frontend(struct dvb_frontend* fe, dst_set_fec(state, p->fec_inner); dst_set_symbolrate(state, p->symbol_rate); dst_set_polarization(state); - dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", p->symbol_rate); + dprintk(3, "Set Symbolrate=[%d]\n", p->symbol_rate); } else if (state->dst_type == DST_TYPE_IS_TERR) dst_set_bandwidth(state, p->bandwidth_hz); @@ -1750,7 +1724,7 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); break; default: - dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); + pr_err("unknown DST type. please report to the LinuxTV.org DVB mailinglist.\n"); kfree(state); return NULL; } -- cgit v1.2.3 From fa132a64e2003c72c149725ffa7bae06b0cc9054 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 06:33:25 -0300 Subject: [media] bt8xx: use pr_foo() macros instead of printk() Replace printk() macros by their pr_foo() counterparts, using pr_cont() for continuation lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/bt8xx/btcx-risc.c | 46 +++++++++++++++++++++---------------- drivers/media/pci/bt8xx/dvb-bt8xx.c | 25 +++++++++++--------- 2 files changed, 40 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c index 57c7f58c3af2..70bdf93fc020 100644 --- a/drivers/media/pci/bt8xx/btcx-risc.c +++ b/drivers/media/pci/bt8xx/btcx-risc.c @@ -22,6 +22,8 @@ */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -36,6 +38,13 @@ static unsigned int btcx_debug; module_param(btcx_debug, int, 0644); MODULE_PARM_DESC(btcx_debug,"debug messages, default is 0 (no)"); +#define dprintk(fmt, arg...) do { \ + if (btcx_debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) + + /* ---------------------------------------------------------- */ /* allocate/free risc memory */ @@ -46,11 +55,11 @@ void btcx_riscmem_free(struct pci_dev *pci, { if (NULL == risc->cpu) return; - if (btcx_debug) { - memcnt--; - printk("btcx: riscmem free [%d] dma=%lx\n", - memcnt, (unsigned long)risc->dma); - } + + memcnt--; + dprintk("btcx: riscmem free [%d] dma=%lx\n", + memcnt, (unsigned long)risc->dma); + pci_free_consistent(pci, risc->size, risc->cpu, risc->dma); memset(risc,0,sizeof(*risc)); } @@ -71,11 +80,10 @@ int btcx_riscmem_alloc(struct pci_dev *pci, risc->cpu = cpu; risc->dma = dma; risc->size = size; - if (btcx_debug) { - memcnt++; - printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", - memcnt, (unsigned long)dma, cpu, size); - } + + memcnt++; + dprintk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n", + memcnt, (unsigned long)dma, cpu, size); } memset(risc->cpu,0,risc->size); return 0; @@ -137,9 +145,8 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m dx = nx - win->left; win->left = nx; win->width = nw; - if (btcx_debug) - printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n", - win->width, win->height, win->left, win->top, dx); + dprintk("btcx: window align %dx%d+%d+%d [dx=%d]\n", + win->width, win->height, win->left, win->top, dx); /* fixup clips */ for (i = 0; i < n; i++) { @@ -149,10 +156,9 @@ btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int m nw += mask+1; clips[i].c.left = nx; clips[i].c.width = nw; - if (btcx_debug) - printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n", - clips[i].c.width, clips[i].c.height, - clips[i].c.left, clips[i].c.top); + dprintk("btcx: clip align %dx%d+%d+%d\n", + clips[i].c.width, clips[i].c.height, + clips[i].c.left, clips[i].c.top); } return 0; } @@ -228,10 +234,10 @@ btcx_calc_skips(int line, int width, int *maxy, *maxy = maxline; if (btcx_debug) { - printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline); + dprintk("btcx: skips line %d-%d:", line, maxline); for (skip = 0; skip < *nskips; skip++) { - printk(" %d-%d",skips[skip].start,skips[skip].end); + pr_cont(" %d-%d", skips[skip].start, skips[skip].end); } - printk("\n"); + pr_cont("\n"); } } diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c index e69d338ab9be..6100fa71ece8 100644 --- a/drivers/media/pci/bt8xx/dvb-bt8xx.c +++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c @@ -19,7 +19,7 @@ * */ -#define pr_fmt(fmt) "dvb_bt8xx: " fmt +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include #include @@ -44,10 +44,12 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define dprintk( args... ) \ - do { \ - if (debug) printk(KERN_DEBUG args); \ - } while (0) +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ @@ -55,7 +57,7 @@ static void dvb_bt8xx_task(unsigned long data) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data; - //printk("%d ", card->bt->finished_block); + dprintk("%d\n", card->bt->finished_block); while (card->bt->last_block != card->bt->finished_block) { (card->bt->TS_Size ? dvb_dmx_swfilter_204 : dvb_dmx_swfilter) @@ -443,7 +445,7 @@ static void or51211_reset(struct dvb_frontend * fe) /* reset & PRM1,2&4 are outputs */ int ret = bttv_gpio_enable(bt->bttv_nr, 0x001F, 0x001F); if (ret != 0) - printk(KERN_WARNING "or51211: Init Error - Can't Reset DVR (%i)\n", ret); + pr_warn("or51211: Init Error - Can't Reset DVR (%i)\n", ret); bttv_write_gpio(bt->bttv_nr, 0x001F, 0x0000); /* Reset */ msleep(20); /* Now set for normal operation */ @@ -560,7 +562,8 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) int ret = bttv_gpio_enable(bt->bttv_nr, 0x08, 0x08); if (ret != 0) - printk(KERN_WARNING "digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", ret); + pr_warn("digitv_alps_tded4: Init Error - Can't Reset DVR (%i)\n", + ret); /* Pulse the reset line */ bttv_write_gpio(bt->bttv_nr, 0x08, 0x08); /* High */ @@ -620,7 +623,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) dvb_attach(simple_tuner_attach, card->fe, card->i2c_adapter, 0x61, TUNER_LG_TDVS_H06XF); - dprintk ("dvb_bt8xx: lgdt330x detected\n"); + dprintk("dvb_bt8xx: lgdt330x detected\n"); } break; @@ -635,7 +638,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) card->fe = dvb_attach(nxt6000_attach, &vp3021_alps_tded4_config, card->i2c_adapter); if (card->fe != NULL) { card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; - dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); + dprintk("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); break; } @@ -645,7 +648,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) if (card->fe != NULL) { card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; - dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); + dprintk("dvb_bt8xx: an mt352 was detected on your digitv card\n"); } break; -- cgit v1.2.3 From 09f8be263c9c5fa0ee33e24e1f89b8cde68ec056 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 06:50:56 -0300 Subject: [media] cx23885: use KERN_CONT where needed Some continuation messages are not using KERN_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups'"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. While here, add missing log level annotations. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/cx23885-core.c | 8 ++++---- drivers/media/pci/cx23885/cx23885-i2c.c | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 5020a60a4f1f..0d97da3be90b 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -407,12 +407,12 @@ static int cx23885_risc_decode(u32 risc) }; int i; - printk("0x%08x [ %s", risc, + printk(KERN_DEBUG "0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(" %s", bits[i]); - printk(" count=%d ]\n", risc & 0xfff); + printk(KERN_CONT " %s", bits[i]); + printk(KERN_CONT " count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } @@ -2003,7 +2003,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, pci_set_master(pci_dev); err = pci_set_dma_mask(pci_dev, 0xffffffff); if (err) { - printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); + printk(KERN_ERR "%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); goto fail_ctrl; } diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 61591225be9a..19faf9a611ed 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -119,9 +119,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (!i2c_wait_done(i2c_adap)) goto eio; if (i2c_debug) { - printk(" addr << 1, msg->buf[0]); + printk(KERN_DEBUG " addr << 1, msg->buf[0]); if (!(ctrl & I2C_NOSTOP)) - printk(" >\n"); + printk(KERN_CONT " >\n"); } for (cnt = 1; cnt < msg->len; cnt++) { @@ -141,9 +141,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (!i2c_wait_done(i2c_adap)) goto eio; if (i2c_debug) { - dprintk(1, " %02x", msg->buf[cnt]); + printk(KERN_CONT " %02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) - dprintk(1, " >\n"); + printk(KERN_CONT " >\n"); } } return msg->len; -- cgit v1.2.3 From f1dc10b6e18df849429c1625bbcdf04ecc25d5c3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 14 Nov 2016 11:14:37 -0200 Subject: gp8psk-fe: add missing MODULE_foo() macros This file was converted to a separate module at commit 7a0786c19d65 ("gp8psk: Fix DVB frontend attach"), because the DVB attach routines require it to work. However, I forgot to copy the MODULE_foo() macros from the original module, causing this warning: WARNING: modpost: missing MODULE_LICENSE() in drivers/media/dvb-frontends/gp8psk-fe.o Reported-by: Stephen Rothwell Fixes: 7a0786c19d65 ("gp8psk: Fix DVB frontend attach") Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Linus Torvalds --- drivers/media/dvb-frontends/gp8psk-fe.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/gp8psk-fe.c b/drivers/media/dvb-frontends/gp8psk-fe.c index be19afeed7a9..93f59bfea092 100644 --- a/drivers/media/dvb-frontends/gp8psk-fe.c +++ b/drivers/media/dvb-frontends/gp8psk-fe.c @@ -1,5 +1,5 @@ -/* DVB USB compliant Linux driver for the - * - GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module +/* + * Frontend driver for the GENPIX 8pks/qpsk/DCII USB2.0 DVB-S module * * Copyright (C) 2006,2007 Alan Nisota (alannisota@gmail.com) * Copyright (C) 2006,2007 Genpix Electronics (genpix@genpix-electronics.com) @@ -8,11 +8,9 @@ * * This module is based off the vp7045 and vp702x modules * - * 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. - * - * see Documentation/dvb/README.dvb-usb for more information + * 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. */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt @@ -395,3 +393,8 @@ static struct dvb_frontend_ops gp8psk_fe_ops = { .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, .enable_high_lnb_voltage = gp8psk_fe_enable_high_lnb_voltage }; + +MODULE_AUTHOR("Alan Nisota "); +MODULE_DESCRIPTION("Frontend Driver for Genpix DVB-S"); +MODULE_VERSION("1.1"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e39682b5d96ae7a33a0f6b5578911913be8f14b6 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Nov 2016 09:46:11 -0200 Subject: [media] cx23885: convert it to use pr_foo() macros Instead of calling printk() directly, use pr_foo() macros, as suggested at the Kernel's coding style. Please notice that a conversion to dev_foo() is not trivial, as several parts on this driver uses pr_cont(). Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx23885/altera-ci.c | 15 ++-- drivers/media/pci/cx23885/altera-ci.h | 14 +-- drivers/media/pci/cx23885/cimax2.c | 8 +- drivers/media/pci/cx23885/cx23885-417.c | 57 ++++++------- drivers/media/pci/cx23885/cx23885-alsa.c | 21 ++--- drivers/media/pci/cx23885/cx23885-cards.c | 49 ++++++----- drivers/media/pci/cx23885/cx23885-core.c | 137 ++++++++++++++---------------- drivers/media/pci/cx23885/cx23885-dvb.c | 40 ++++----- drivers/media/pci/cx23885/cx23885-f300.c | 2 +- drivers/media/pci/cx23885/cx23885-i2c.c | 25 +++--- drivers/media/pci/cx23885/cx23885-input.c | 6 +- drivers/media/pci/cx23885/cx23885-ir.c | 4 +- drivers/media/pci/cx23885/cx23885-vbi.c | 7 +- drivers/media/pci/cx23885/cx23885-video.c | 23 ++--- drivers/media/pci/cx23885/cx23885.h | 2 + drivers/media/pci/cx23885/cx23888-ir.c | 6 +- drivers/media/pci/cx23885/netup-eeprom.c | 4 +- drivers/media/pci/cx23885/netup-init.c | 8 +- 18 files changed, 209 insertions(+), 219 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx23885/altera-ci.c b/drivers/media/pci/cx23885/altera-ci.c index aaf4e46ff3e9..5c94e312cba3 100644 --- a/drivers/media/pci/cx23885/altera-ci.c +++ b/drivers/media/pci/cx23885/altera-ci.c @@ -48,6 +48,9 @@ * | DATA7| DATA6| DATA5| DATA4| DATA3| DATA2| DATA1| DATA0| * +-------+-------+-------+-------+-------+-------+-------+-------+ */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include "altera-ci.h" @@ -84,16 +87,18 @@ MODULE_DESCRIPTION("altera FPGA CI module"); MODULE_AUTHOR("Igor M. Liplianin "); MODULE_LICENSE("GPL"); -#define ci_dbg_print(args...) \ +#define ci_dbg_print(fmt, args...) \ do { \ if (ci_dbg) \ - printk(KERN_DEBUG args); \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##args); \ } while (0) -#define pid_dbg_print(args...) \ +#define pid_dbg_print(fmt, args...) \ do { \ if (pid_dbg) \ - printk(KERN_DEBUG args); \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##args); \ } while (0) struct altera_ci_state; @@ -718,7 +723,7 @@ int altera_ci_init(struct altera_ci_config *config, int ci_nr) if (temp_int != NULL) { inter = temp_int->internal; (inter->cis_used)++; - inter->fpga_rw = config->fpga_rw; + inter->fpga_rw = config->fpga_rw; ci_dbg_print("%s: Find Internal Structure!\n", __func__); } else { inter = kzalloc(sizeof(struct fpga_internal), GFP_KERNEL); diff --git a/drivers/media/pci/cx23885/altera-ci.h b/drivers/media/pci/cx23885/altera-ci.h index 57a40c84b46e..ababd80fee93 100644 --- a/drivers/media/pci/cx23885/altera-ci.h +++ b/drivers/media/pci/cx23885/altera-ci.h @@ -48,24 +48,24 @@ extern int altera_ci_tuner_reset(void *dev, int ci_nr); static inline int altera_ci_init(struct altera_ci_config *config, int ci_nr) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + pr_warn("%s: driver disabled by Kconfig\n", __func__); return 0; } static inline void altera_ci_release(void *dev, int ci_nr) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + pr_warn("%s: driver disabled by Kconfig\n", __func__); } static inline int altera_ci_irq(void *dev) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + pr_warn("%s: driver disabled by Kconfig\n", __func__); return 0; } static inline int altera_ci_tuner_reset(void *dev, int ci_nr) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + pr_warn("%s: driver disabled by Kconfig\n", __func__); return 0; } @@ -74,19 +74,19 @@ static inline int altera_ci_tuner_reset(void *dev, int ci_nr) static inline int altera_hw_filt_init(struct altera_ci_config *config, int hw_filt_nr) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + pr_warn("%s: driver disabled by Kconfig\n", __func__); return 0; } static inline void altera_hw_filt_release(void *dev, int filt_nr) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + pr_warn("%s: driver disabled by Kconfig\n", __func__); } static inline int altera_pid_feed_control(void *dev, int filt_nr, struct dvb_demux_feed *dvbdmxfeed, int onoff) { - printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__); + pr_warn("%s: driver disabled by Kconfig\n", __func__); return 0; } diff --git a/drivers/media/pci/cx23885/cimax2.c b/drivers/media/pci/cx23885/cimax2.c index d644c65622e2..5e8e134d81c2 100644 --- a/drivers/media/pci/cx23885/cimax2.c +++ b/drivers/media/pci/cx23885/cimax2.c @@ -65,10 +65,11 @@ static unsigned int ci_irq_enable; module_param(ci_irq_enable, int, 0644); MODULE_PARM_DESC(ci_irq_enable, "Enable IRQ from CAM"); -#define ci_dbg_print(args...) \ +#define ci_dbg_print(fmt, args...) \ do { \ if (ci_dbg) \ - printk(KERN_DEBUG args); \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##args); \ } while (0) #define ci_irq_flags() (ci_irq_enable ? NETUP_IRQ_IRQAM : 0) @@ -135,8 +136,7 @@ static int netup_write_i2c(struct i2c_adapter *i2c_adap, u8 addr, u8 reg, }; if (1 + len > sizeof(buffer)) { - printk(KERN_WARNING - "%s: i2c wr reg=%04x: len=%d is too big!\n", + pr_warn("%s: i2c wr reg=%04x: len=%d is too big!\n", KBUILD_MODNAME, reg, len); return -EINVAL; } diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c index 0c122585a1f0..2ff1d1e274be 100644 --- a/drivers/media/pci/cx23885/cx23885-417.c +++ b/drivers/media/pci/cx23885/cx23885-417.c @@ -20,6 +20,9 @@ * GNU General Public License for more details. */ +#include "cx23885.h" +#include "cx23885-ioctl.h" + #include #include #include @@ -32,9 +35,6 @@ #include #include -#include "cx23885.h" -#include "cx23885-ioctl.h" - #define CX23885_FIRM_IMAGE_SIZE 376836 #define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw" @@ -55,8 +55,8 @@ MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages"); #define dprintk(level, fmt, arg...)\ do { if (v4l_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, \ - (dev) ? dev->name : "cx23885[?]", ## arg); \ + printk(KERN_DEBUG pr_fmt("%s: 417:" fmt), \ + __func__, ##arg); \ } while (0) static struct cx23885_tvnorm cx23885_tvnorms[] = { @@ -769,8 +769,7 @@ static int cx23885_mbox_func(void *priv, without side effects */ mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value); if (value != 0x12345678) { - printk(KERN_ERR - "Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n", + pr_err("Firmware and/or mailbox pointer not initialized or corrupted, signature = 0x%x, cmd = %s\n", value, cmd_to_str(command)); return -1; } @@ -780,7 +779,7 @@ static int cx23885_mbox_func(void *priv, */ mc417_memory_read(dev, dev->cx23417_mailbox, &flag); if (flag) { - printk(KERN_ERR "ERROR: Mailbox appears to be in use (%x), cmd = %s\n", + pr_err("ERROR: Mailbox appears to be in use (%x), cmd = %s\n", flag, cmd_to_str(command)); return -1; } @@ -810,7 +809,7 @@ static int cx23885_mbox_func(void *priv, if (0 != (flag & 4)) break; if (time_after(jiffies, timeout)) { - printk(KERN_ERR "ERROR: API Mailbox timeout\n"); + pr_err("ERROR: API Mailbox timeout\n"); return -1; } udelay(10); @@ -887,7 +886,7 @@ static int cx23885_find_mailbox(struct cx23885_dev *dev) return i+1; } } - printk(KERN_ERR "Mailbox signature values not found!\n"); + pr_err("Mailbox signature values not found!\n"); return -1; } @@ -922,7 +921,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) IVTV_REG_APU, 0); if (retval != 0) { - printk(KERN_ERR "%s: Error with mc417_register_write\n", + pr_err("%s: Error with mc417_register_write\n", __func__); return -1; } @@ -931,23 +930,21 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) &dev->pci->dev); if (retval != 0) { - printk(KERN_ERR - "ERROR: Hotplug firmware request failed (%s).\n", - CX23885_FIRM_IMAGE_NAME); - printk(KERN_ERR "Please fix your hotplug setup, the board will not work without firmware loaded!\n"); + pr_err("ERROR: Hotplug firmware request failed (%s).\n", + CX23885_FIRM_IMAGE_NAME); + pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n"); return -1; } if (firmware->size != CX23885_FIRM_IMAGE_SIZE) { - printk(KERN_ERR "ERROR: Firmware size mismatch (have %zu, expected %d)\n", - firmware->size, CX23885_FIRM_IMAGE_SIZE); + pr_err("ERROR: Firmware size mismatch (have %zu, expected %d)\n", + firmware->size, CX23885_FIRM_IMAGE_SIZE); release_firmware(firmware); return -1; } if (0 != memcmp(firmware->data, magic, 8)) { - printk(KERN_ERR - "ERROR: Firmware magic mismatch, wrong file?\n"); + pr_err("ERROR: Firmware magic mismatch, wrong file?\n"); release_firmware(firmware); return -1; } @@ -959,7 +956,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) value = *dataptr; checksum += ~value; if (mc417_memory_write(dev, i, value) != 0) { - printk(KERN_ERR "ERROR: Loading firmware failed!\n"); + pr_err("ERROR: Loading firmware failed!\n"); release_firmware(firmware); return -1; } @@ -970,15 +967,14 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) dprintk(1, "Verifying firmware ...\n"); for (i--; i >= 0; i--) { if (mc417_memory_read(dev, i, &value) != 0) { - printk(KERN_ERR "ERROR: Reading firmware failed!\n"); + pr_err("ERROR: Reading firmware failed!\n"); release_firmware(firmware); return -1; } checksum -= ~value; } if (checksum) { - printk(KERN_ERR - "ERROR: Firmware load failed (checksum mismatch).\n"); + pr_err("ERROR: Firmware load failed (checksum mismatch).\n"); release_firmware(firmware); return -1; } @@ -1003,7 +999,7 @@ static int cx23885_load_firmware(struct cx23885_dev *dev) mc417_register_read(dev, 0x900C, &gpio_value); if (retval < 0) - printk(KERN_ERR "%s: Error with mc417_register_write\n", + pr_err("%s: Error with mc417_register_write\n", __func__); return 0; } @@ -1055,26 +1051,25 @@ static int cx23885_initialize_codec(struct cx23885_dev *dev, int startencoder) dprintk(2, "%s() PING OK\n", __func__); retval = cx23885_load_firmware(dev); if (retval < 0) { - printk(KERN_ERR "%s() f/w load failed\n", __func__); + pr_err("%s() f/w load failed\n", __func__); return retval; } retval = cx23885_find_mailbox(dev); if (retval < 0) { - printk(KERN_ERR "%s() mailbox < 0, error\n", + pr_err("%s() mailbox < 0, error\n", __func__); return -1; } dev->cx23417_mailbox = retval; retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); if (retval < 0) { - printk(KERN_ERR - "ERROR: cx23417 firmware ping failed!\n"); + pr_err("ERROR: cx23417 firmware ping failed!\n"); return -1; } retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version); if (retval < 0) { - printk(KERN_ERR "ERROR: cx23417 firmware get encoder :version failed!\n"); + pr_err("ERROR: cx23417 firmware get encoder :version failed!\n"); return -1; } dprintk(1, "cx23417 firmware version is 0x%08x\n", version); @@ -1559,11 +1554,11 @@ int cx23885_417_register(struct cx23885_dev *dev) err = video_register_device(dev->v4l_device, VFL_TYPE_GRABBER, -1); if (err < 0) { - printk(KERN_INFO "%s: can't register mpeg device\n", dev->name); + pr_info("%s: can't register mpeg device\n", dev->name); return err; } - printk(KERN_INFO "%s: registered device %s [mpeg]\n", + pr_info("%s: registered device %s [mpeg]\n", dev->name, video_device_node_name(dev->v4l_device)); /* ST: Configure the encoder paramaters, but don't begin diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c index 9d2a4e2dc54f..c148f9a4a9ac 100644 --- a/drivers/media/pci/cx23885/cx23885-alsa.c +++ b/drivers/media/pci/cx23885/cx23885-alsa.c @@ -17,6 +17,9 @@ * GNU General Public License for more details. */ +#include "cx23885.h" +#include "cx23885-reg.h" + #include #include #include @@ -35,20 +38,14 @@ #include - -#include "cx23885.h" -#include "cx23885-reg.h" - #define AUDIO_SRAM_CHANNEL SRAM_CH07 #define dprintk(level, fmt, arg...) do { \ if (audio_debug + 1 > level) \ - printk(KERN_INFO "%s: " fmt, chip->dev->name , ## arg); \ + printk(KERN_DEBUG pr_fmt("%s: alsa: " fmt), \ + chip->dev->name, ##arg); \ } while(0) -#define dprintk_core(level, fmt, arg...) if (audio_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, chip->dev->name , ## arg) - /**************************************************************************** Module global static vars ****************************************************************************/ @@ -247,7 +244,7 @@ int cx23885_audio_irq(struct cx23885_dev *dev, u32 status, u32 mask) /* risc op code error */ if (status & AUD_INT_OPC_ERR) { - printk(KERN_WARNING "%s/1: Audio risc op code error\n", + pr_warn("%s/1: Audio risc op code error\n", dev->name); cx_clear(AUD_INT_DMA_CTL, 0x11); cx23885_sram_channel_dump(dev, @@ -327,7 +324,7 @@ static int snd_cx23885_pcm_open(struct snd_pcm_substream *substream) int err; if (!chip) { - printk(KERN_ERR "BUG: cx23885 can't find device struct. Can't proceed with open\n"); + pr_err("BUG: cx23885 can't find device struct. Can't proceed with open\n"); return -ENODEV; } @@ -554,7 +551,7 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) return NULL; if (dev->sram_channels[AUDIO_SRAM_CHANNEL].cmds_start == 0) { - printk(KERN_WARNING "%s(): Missing SRAM channel configuration for analog TV Audio\n", + pr_warn("%s(): Missing SRAM channel configuration for analog TV Audio\n", __func__); return NULL; } @@ -589,7 +586,7 @@ struct cx23885_audio_dev *cx23885_audio_register(struct cx23885_dev *dev) error: snd_card_free(card); - printk(KERN_ERR "%s(): Failed to register analog audio adapter\n", + pr_err("%s(): Failed to register analog audio adapter\n", __func__); return NULL; diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c index e2c4edbfbdb7..0350f13c5a9f 100644 --- a/drivers/media/pci/cx23885/cx23885-cards.c +++ b/drivers/media/pci/cx23885/cx23885-cards.c @@ -15,6 +15,8 @@ * GNU General Public License for more details. */ +#include "cx23885.h" + #include #include #include @@ -23,7 +25,6 @@ #include #include -#include "cx23885.h" #include "tuner-xc2028.h" #include "netup-eeprom.h" #include "netup-init.h" @@ -1096,26 +1097,24 @@ void cx23885_card_list(struct cx23885_dev *dev) if (0 == dev->pci->subsystem_vendor && 0 == dev->pci->subsystem_device) { - printk(KERN_INFO - "%s: Board has no valid PCIe Subsystem ID and can't\n" - "%s: be autodetected. Pass card= insmod option\n" - "%s: to workaround that. Redirect complaints to the\n" - "%s: vendor of the TV card. Best regards,\n" - "%s: -- tux\n", - dev->name, dev->name, dev->name, dev->name, dev->name); + pr_info("%s: Board has no valid PCIe Subsystem ID and can't\n" + "%s: be autodetected. Pass card= insmod option\n" + "%s: to workaround that. Redirect complaints to the\n" + "%s: vendor of the TV card. Best regards,\n" + "%s: -- tux\n", + dev->name, dev->name, dev->name, dev->name, dev->name); } else { - printk(KERN_INFO - "%s: Your board isn't known (yet) to the driver.\n" - "%s: Try to pick one of the existing card configs via\n" - "%s: card= insmod option. Updating to the latest\n" - "%s: version might help as well.\n", - dev->name, dev->name, dev->name, dev->name); + pr_info("%s: Your board isn't known (yet) to the driver.\n" + "%s: Try to pick one of the existing card configs via\n" + "%s: card= insmod option. Updating to the latest\n" + "%s: version might help as well.\n", + dev->name, dev->name, dev->name, dev->name); } - printk(KERN_INFO "%s: Here is a list of valid choices for the card= insmod option:\n", + pr_info("%s: Here is a list of valid choices for the card= insmod option:\n", dev->name); for (i = 0; i < cx23885_bcount; i++) - printk(KERN_INFO "%s: card=%d -> %s\n", - dev->name, i, cx23885_boards[i].name); + pr_info("%s: card=%d -> %s\n", + dev->name, i, cx23885_boards[i].name); } static void viewcast_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) @@ -1304,13 +1303,13 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data) */ break; default: - printk(KERN_WARNING "%s: warning: unknown hauppauge model #%d\n", + pr_warn("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model); break; } - printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n", - dev->name, tv.model); + pr_info("%s: hauppauge eeprom: model=%d\n", + dev->name, tv.model); } /* Some TBS cards require initing a chip using a bitbanged SPI attached @@ -1352,8 +1351,8 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg) return 0; if (command != 0) { - printk(KERN_ERR "%s(): Unknown command 0x%x.\n", - __func__, command); + pr_err("%s(): Unknown command 0x%x.\n", + __func__, command); return -EINVAL; } @@ -2336,12 +2335,12 @@ void cx23885_card_setup(struct cx23885_dev *dev) filename = "dvb-netup-altera-01.fw"; break; } - printk(KERN_INFO "NetUP card rev=0x%x fw_filename=%s\n", - cinfo.rev, filename); + pr_info("NetUP card rev=0x%x fw_filename=%s\n", + cinfo.rev, filename); ret = request_firmware(&fw, filename, &dev->pci->dev); if (ret != 0) - printk(KERN_ERR "did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems.", + pr_err("did not find the firmware file. (%s) Please see linux/Documentation/dvb/ for more details on firmware-problems.", filename); else altera_init(&netup_config, fw); diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c index 0d97da3be90b..02b5ec549369 100644 --- a/drivers/media/pci/cx23885/cx23885-core.c +++ b/drivers/media/pci/cx23885/cx23885-core.c @@ -15,6 +15,8 @@ * GNU General Public License for more details. */ +#include "cx23885.h" + #include #include #include @@ -27,7 +29,6 @@ #include #include -#include "cx23885.h" #include "cimax2.h" #include "altera-ci.h" #include "cx23888-ir.h" @@ -50,7 +51,8 @@ MODULE_PARM_DESC(card, "card type"); #define dprintk(level, fmt, arg...)\ do { if (debug >= level)\ - printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ } while (0) static unsigned int cx23885_devcount; @@ -411,15 +413,14 @@ static int cx23885_risc_decode(u32 risc) instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(KERN_CONT " %s", bits[i]); - printk(KERN_CONT " count=%d ]\n", risc & 0xfff); + pr_cont(" %s", bits[i]); + pr_cont(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } static void cx23885_wakeup(struct cx23885_tsport *port, struct cx23885_dmaqueue *q, u32 count) { - struct cx23885_dev *dev = port->dev; struct cx23885_buffer *buf; if (list_empty(&q->active)) @@ -530,44 +531,44 @@ void cx23885_sram_channel_dump(struct cx23885_dev *dev, u32 risc; unsigned int i, j, n; - printk(KERN_WARNING "%s: %s - dma channel status dump\n", - dev->name, ch->name); + pr_warn("%s: %s - dma channel status dump\n", + dev->name, ch->name); for (i = 0; i < ARRAY_SIZE(name); i++) - printk(KERN_WARNING "%s: cmds: %-15s: 0x%08x\n", - dev->name, name[i], - cx_read(ch->cmds_start + 4*i)); + pr_warn("%s: cmds: %-15s: 0x%08x\n", + dev->name, name[i], + cx_read(ch->cmds_start + 4*i)); for (i = 0; i < 4; i++) { risc = cx_read(ch->cmds_start + 4 * (i + 14)); - printk(KERN_WARNING "%s: risc%d: ", dev->name, i); + pr_warn("%s: risc%d: ", dev->name, i); cx23885_risc_decode(risc); } for (i = 0; i < (64 >> 2); i += n) { risc = cx_read(ch->ctrl_start + 4 * i); /* No consideration for bits 63-32 */ - printk(KERN_WARNING "%s: (0x%08x) iq %x: ", dev->name, - ch->ctrl_start + 4 * i, i); + pr_warn("%s: (0x%08x) iq %x: ", dev->name, + ch->ctrl_start + 4 * i, i); n = cx23885_risc_decode(risc); for (j = 1; j < n; j++) { risc = cx_read(ch->ctrl_start + 4 * (i + j)); - printk(KERN_WARNING "%s: iq %x: 0x%08x [ arg #%d ]\n", - dev->name, i+j, risc, j); + pr_warn("%s: iq %x: 0x%08x [ arg #%d ]\n", + dev->name, i+j, risc, j); } } - printk(KERN_WARNING "%s: fifo: 0x%08x -> 0x%x\n", - dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); - printk(KERN_WARNING "%s: ctrl: 0x%08x -> 0x%x\n", - dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); - printk(KERN_WARNING "%s: ptr1_reg: 0x%08x\n", - dev->name, cx_read(ch->ptr1_reg)); - printk(KERN_WARNING "%s: ptr2_reg: 0x%08x\n", - dev->name, cx_read(ch->ptr2_reg)); - printk(KERN_WARNING "%s: cnt1_reg: 0x%08x\n", - dev->name, cx_read(ch->cnt1_reg)); - printk(KERN_WARNING "%s: cnt2_reg: 0x%08x\n", - dev->name, cx_read(ch->cnt2_reg)); + pr_warn("%s: fifo: 0x%08x -> 0x%x\n", + dev->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); + pr_warn("%s: ctrl: 0x%08x -> 0x%x\n", + dev->name, ch->ctrl_start, ch->ctrl_start + 6*16); + pr_warn("%s: ptr1_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr1_reg)); + pr_warn("%s: ptr2_reg: 0x%08x\n", + dev->name, cx_read(ch->ptr2_reg)); + pr_warn("%s: cnt1_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt1_reg)); + pr_warn("%s: cnt2_reg: 0x%08x\n", + dev->name, cx_read(ch->cnt2_reg)); } static void cx23885_risc_disasm(struct cx23885_tsport *port, @@ -576,14 +577,14 @@ static void cx23885_risc_disasm(struct cx23885_tsport *port, struct cx23885_dev *dev = port->dev; unsigned int i, j, n; - printk(KERN_INFO "%s: risc disasm: %p [dma=0x%08lx]\n", + pr_info("%s: risc disasm: %p [dma=0x%08lx]\n", dev->name, risc->cpu, (unsigned long)risc->dma); for (i = 0; i < (risc->size >> 2); i += n) { - printk(KERN_INFO "%s: %04d: ", dev->name, i); + pr_info("%s: %04d: ", dev->name, i); n = cx23885_risc_decode(le32_to_cpu(risc->cpu[i])); for (j = 1; j < n; j++) - printk(KERN_INFO "%s: %04d: 0x%08x [ arg #%d ]\n", - dev->name, i + j, risc->cpu[i + j], j); + pr_info("%s: %04d: 0x%08x [ arg #%d ]\n", + dev->name, i + j, risc->cpu[i + j], j); if (risc->cpu[i] == cpu_to_le32(RISC_JUMP)) break; } @@ -674,8 +675,8 @@ static int get_resources(struct cx23885_dev *dev) dev->name)) return 0; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", - dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); + pr_err("%s: can't get MMIO memory @ 0x%llx\n", + dev->name, (unsigned long long)pci_resource_start(dev->pci, 0)); return -EBUSY; } @@ -793,15 +794,15 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev) dev->hwrevision = 0xb1; break; default: - printk(KERN_ERR "%s() New hardware revision found 0x%x\n", - __func__, dev->hwrevision); + pr_err("%s() New hardware revision found 0x%x\n", + __func__, dev->hwrevision); } if (dev->hwrevision) - printk(KERN_INFO "%s() Hardware revision = 0x%02x\n", + pr_info("%s() Hardware revision = 0x%02x\n", __func__, dev->hwrevision); else - printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n", - __func__, dev->hwrevision); + pr_err("%s() Hardware revision unknown 0x%x\n", + __func__, dev->hwrevision); } /* Find the first v4l2_subdev member of the group id in hw */ @@ -915,7 +916,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) cx23885_init_tsport(dev, &dev->ts2, 2); if (get_resources(dev) < 0) { - printk(KERN_ERR "CORE %s No more PCIe resources for subsystem: %04x:%04x\n", + pr_err("CORE %s No more PCIe resources for subsystem: %04x:%04x\n", dev->name, dev->pci->subsystem_vendor, dev->pci->subsystem_device); @@ -929,11 +930,11 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->bmmio = (u8 __iomem *)dev->lmmio; - printk(KERN_INFO "CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, cx23885_boards[dev->board].name, - dev->board, card[dev->nr] == dev->board ? - "insmod option" : "autodetected"); + pr_info("CORE %s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->name, dev->pci->subsystem_vendor, + dev->pci->subsystem_device, cx23885_boards[dev->board].name, + dev->board, card[dev->nr] == dev->board ? + "insmod option" : "autodetected"); cx23885_pci_quirks(dev); @@ -979,7 +980,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) { if (cx23885_video_register(dev) < 0) { - printk(KERN_ERR "%s() Failed to register analog video adapters on VID_A\n", + pr_err("%s() Failed to register analog video adapters on VID_A\n", __func__); } } @@ -989,14 +990,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->ts1.num_frontends = cx23885_boards[dev->board].num_fds_portb; if (cx23885_dvb_register(&dev->ts1) < 0) { - printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n", + pr_err("%s() Failed to register dvb adapters on VID_B\n", __func__); } } else if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) { if (cx23885_417_register(dev) < 0) { - printk(KERN_ERR - "%s() Failed to register 417 on VID_B\n", + pr_err("%s() Failed to register 417 on VID_B\n", __func__); } } @@ -1006,15 +1006,13 @@ static int cx23885_dev_setup(struct cx23885_dev *dev) dev->ts2.num_frontends = cx23885_boards[dev->board].num_fds_portc; if (cx23885_dvb_register(&dev->ts2) < 0) { - printk(KERN_ERR - "%s() Failed to register dvb on VID_C\n", + pr_err("%s() Failed to register dvb on VID_C\n", __func__); } } else if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) { if (cx23885_417_register(dev) < 0) { - printk(KERN_ERR - "%s() Failed to register 417 on VID_C\n", + pr_err("%s() Failed to register 417 on VID_C\n", __func__); } } @@ -1343,7 +1341,7 @@ int cx23885_start_dma(struct cx23885_tsport *port, if ((!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) && (!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB))) { - printk("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", + pr_err("%s() Unsupported .portb/c (0x%08x)/(0x%08x)\n", __func__, cx23885_boards[dev->board].portb, cx23885_boards[dev->board].portc); @@ -1530,7 +1528,6 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf) static void do_cancel_buffers(struct cx23885_tsport *port, char *reason) { - struct cx23885_dev *dev = port->dev; struct cx23885_dmaqueue *q = &port->mpegq; struct cx23885_buffer *buf; unsigned long flags; @@ -1550,8 +1547,6 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason) void cx23885_cancel_buffers(struct cx23885_tsport *port) { - struct cx23885_dev *dev = port->dev; - dprintk(1, "%s()\n", __func__); cx23885_stop_dma(port); do_cancel_buffers(port, "cancel"); @@ -1578,7 +1573,7 @@ int cx23885_irq_417(struct cx23885_dev *dev, u32 status) (status & VID_B_MSK_VBI_SYNC) || (status & VID_B_MSK_OF) || (status & VID_B_MSK_VBI_OF)) { - printk(KERN_ERR "%s: V4L mpeg risc op code error, status = 0x%x\n", + pr_err("%s: V4L mpeg risc op code error, status = 0x%x\n", dev->name, status); if (status & VID_B_MSK_BAD_PKT) dprintk(1, " VID_B_MSK_BAD_PKT\n"); @@ -1640,7 +1635,7 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status) dprintk(7, " (VID_BC_MSK_OF 0x%08x)\n", VID_BC_MSK_OF); - printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name); + pr_err("%s: mpeg risc op code error\n", dev->name); cx_clear(port->reg_dma_ctl, port->dma_ctl_val); cx23885_sram_channel_dump(dev, @@ -1880,15 +1875,14 @@ void cx23885_gpio_set(struct cx23885_dev *dev, u32 mask) if (mask & 0x0007fff8) { if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Setting GPIO on encoder ports\n", + pr_err("%s: Setting GPIO on encoder ports\n", dev->name); cx_set(MC417_RWD, (mask & 0x0007fff8) >> 3); } /* TODO: 23-19 */ if (mask & 0x00f80000) - printk(KERN_INFO "%s: Unsupported\n", dev->name); + pr_info("%s: Unsupported\n", dev->name); } void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) @@ -1898,15 +1892,14 @@ void cx23885_gpio_clear(struct cx23885_dev *dev, u32 mask) if (mask & 0x0007fff8) { if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Clearing GPIO moving on encoder ports\n", + pr_err("%s: Clearing GPIO moving on encoder ports\n", dev->name); cx_clear(MC417_RWD, (mask & 0x7fff8) >> 3); } /* TODO: 23-19 */ if (mask & 0x00f80000) - printk(KERN_INFO "%s: Unsupported\n", dev->name); + pr_info("%s: Unsupported\n", dev->name); } u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask) @@ -1916,15 +1909,14 @@ u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask) if (mask & 0x0007fff8) { if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Reading GPIO moving on encoder ports\n", + pr_err("%s: Reading GPIO moving on encoder ports\n", dev->name); return (cx_read(MC417_RWD) & ((mask & 0x7fff8) >> 3)) << 3; } /* TODO: 23-19 */ if (mask & 0x00f80000) - printk(KERN_INFO "%s: Unsupported\n", dev->name); + pr_info("%s: Unsupported\n", dev->name); return 0; } @@ -1938,8 +1930,7 @@ void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask, int asoutput) if (mask & 0x0007fff8) { if (encoder_on_portb(dev) || encoder_on_portc(dev)) - printk(KERN_ERR - "%s: Enabling GPIO on encoder ports\n", + pr_err("%s: Enabling GPIO on encoder ports\n", dev->name); } @@ -1994,7 +1985,7 @@ static int cx23885_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + pr_info("%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, @@ -2003,14 +1994,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev, pci_set_master(pci_dev); err = pci_set_dma_mask(pci_dev, 0xffffffff); if (err) { - printk(KERN_ERR "%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); + pr_err("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name); goto fail_ctrl; } err = request_irq(pci_dev->irq, cx23885_irq, IRQF_SHARED, dev->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); goto fail_irq; } @@ -2096,7 +2087,7 @@ static struct pci_driver cx23885_pci_driver = { static int __init cx23885_init(void) { - printk(KERN_INFO "cx23885 driver version %s loaded\n", + pr_info("cx23885 driver version %s loaded\n", CX23885_VERSION); return pci_register_driver(&cx23885_pci_driver); } diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c index 42413fa423b4..589a168d1df4 100644 --- a/drivers/media/pci/cx23885/cx23885-dvb.c +++ b/drivers/media/pci/cx23885/cx23885-dvb.c @@ -15,6 +15,8 @@ * GNU General Public License for more details. */ +#include "cx23885.h" + #include #include #include @@ -23,7 +25,6 @@ #include #include -#include "cx23885.h" #include #include "dvb_ca_en50221.h" @@ -80,7 +81,8 @@ static unsigned int debug; #define dprintk(level, fmt, arg...)\ do { if (debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG pr_fmt("%s dvb: " fmt), \ + __func__, ##arg); \ } while (0) /* ------------------------------------------------------------------ */ @@ -1101,7 +1103,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port) netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo); memcpy(port->frontends.adapter.proposed_mac, cinfo.port[port->nr - 1].mac, 6); - printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", + pr_info("NetUP Dual DVB-S2 CI card port%d MAC=%pM\n", port->nr, port->frontends.adapter.proposed_mac); netup_ci_init(port); @@ -1127,7 +1129,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port) /* Read entire EEPROM */ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); - printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0); + pr_info("TeVii S470 MAC= %pM\n", eeprom + 0xa0); memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6); return 0; } @@ -1144,7 +1146,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port) dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); - printk(KERN_INFO "%s port %d MAC address: %pM\n", + pr_info("%s port %d MAC address: %pM\n", cx23885_boards[dev->board].name, port->nr, eeprom + 0xc0 + (port->nr-1) * 8); memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 + @@ -1185,7 +1187,7 @@ static int dvb_register_ci_mac(struct cx23885_tsport *port) dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1; tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom)); - printk(KERN_INFO "%s MAC address: %pM\n", + pr_info("%s MAC address: %pM\n", cx23885_boards[dev->board].name, eeprom + 0xc0); memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0, 6); return 0; @@ -1464,7 +1466,7 @@ static int dvb_register(struct cx23885_tsport *port) return -ENODEV; if (dib7000p_ops.i2c_enumeration(&i2c_bus->i2c_adap, 1, 0x12, &dib7070p_dib7000p_config) < 0) { - printk(KERN_WARNING "Unable to enumerate dib7000p\n"); + pr_warn("Unable to enumerate dib7000p\n"); return -ENODEV; } fe0->dvb.frontend = dib7000p_ops.init(&i2c_bus->i2c_adap, 0x80, &dib7070p_dib7000p_config); @@ -1524,7 +1526,7 @@ static int dvb_register(struct cx23885_tsport *port) fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->i2c_bus[1].i2c_adap, &cfg); if (!fe) { - printk(KERN_ERR "%s/2: xc4000 attach failed\n", + pr_err("%s/2: xc4000 attach failed\n", dev->name); goto frontend_detach; } @@ -1597,8 +1599,7 @@ static int dvb_register(struct cx23885_tsport *port) &i2c_bus->i2c_adap, LNBH24_PCL | LNBH24_TTX, LNBH24_TEN, 0x09)) - printk(KERN_ERR - "No LNBH24 found!\n"); + pr_err("No LNBH24 found!\n"); } } @@ -1618,8 +1619,7 @@ static int dvb_register(struct cx23885_tsport *port) &i2c_bus->i2c_adap, LNBH24_PCL | LNBH24_TTX, LNBH24_TEN, 0x0a)) - printk(KERN_ERR - "No LNBH24 found!\n"); + pr_err("No LNBH24 found!\n"); } } @@ -2482,13 +2482,13 @@ static int dvb_register(struct cx23885_tsport *port) break; default: - printk(KERN_INFO "%s: The frontend of your DVB/ATSC card isn't supported yet\n", - dev->name); + pr_info("%s: The frontend of your DVB/ATSC card isn't supported yet\n", + dev->name); break; } if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { - printk(KERN_ERR "%s: frontend initialization failed\n", + pr_err("%s: frontend initialization failed\n", dev->name); goto frontend_detach; } @@ -2569,7 +2569,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) * are for safety, and should provide a good foundation for the * future addition of any multi-frontend cx23885 based boards. */ - printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, + pr_info("%s() allocating %d frontend(s)\n", __func__, port->num_frontends); for (i = 1; i <= port->num_frontends; i++) { @@ -2577,7 +2577,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) if (vb2_dvb_alloc_frontend( &port->frontends, i) == NULL) { - printk(KERN_ERR "%s() failed to alloc\n", __func__); + pr_err("%s() failed to alloc\n", __func__); return -ENOMEM; } @@ -2596,7 +2596,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port) /* dvb stuff */ /* We have to init the queue for each frontend on a port. */ - printk(KERN_INFO "%s: cx23885 based dvb card\n", dev->name); + pr_info("%s: cx23885 based dvb card\n", dev->name); q = &fe0->dvb.dvbq; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ; @@ -2616,8 +2616,8 @@ int cx23885_dvb_register(struct cx23885_tsport *port) } err = dvb_register(port); if (err != 0) - printk(KERN_ERR "%s() dvb_register failed err = %d\n", - __func__, err); + pr_err("%s() dvb_register failed err = %d\n", + __func__, err); return err; } diff --git a/drivers/media/pci/cx23885/cx23885-f300.c b/drivers/media/pci/cx23885/cx23885-f300.c index a6c45eb0a105..460cb8f314b2 100644 --- a/drivers/media/pci/cx23885/cx23885-f300.c +++ b/drivers/media/pci/cx23885/cx23885-f300.c @@ -122,7 +122,7 @@ static u8 f300_xfer(struct dvb_frontend *fe, u8 *buf) } if (i > 7) { - printk(KERN_ERR "%s: timeout, the slave no response\n", + pr_err("%s: timeout, the slave no response\n", __func__); ret = 1; /* timeout, the slave no response */ } else { /* the slave not busy, prepare for getting data */ diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c index 19faf9a611ed..8528032090f2 100644 --- a/drivers/media/pci/cx23885/cx23885-i2c.c +++ b/drivers/media/pci/cx23885/cx23885-i2c.c @@ -15,14 +15,14 @@ * GNU General Public License for more details. */ +#include "cx23885.h" + #include #include #include #include #include -#include "cx23885.h" - #include static unsigned int i2c_debug; @@ -35,7 +35,8 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); #define dprintk(level, fmt, arg...)\ do { if (i2c_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG pr_fmt("%s: i2c:" fmt), \ + __func__, ##arg); \ } while (0) #define I2C_WAIT_DELAY 32 @@ -121,7 +122,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (i2c_debug) { printk(KERN_DEBUG " addr << 1, msg->buf[0]); if (!(ctrl & I2C_NOSTOP)) - printk(KERN_CONT " >\n"); + pr_cont(" >\n"); } for (cnt = 1; cnt < msg->len; cnt++) { @@ -141,9 +142,9 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, if (!i2c_wait_done(i2c_adap)) goto eio; if (i2c_debug) { - printk(KERN_CONT " %02x", msg->buf[cnt]); + pr_cont(" %02x", msg->buf[cnt]); if (!(ctrl & I2C_NOSTOP)) - printk(KERN_CONT " >\n"); + pr_cont(" >\n"); } } return msg->len; @@ -151,7 +152,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; if (i2c_debug) - printk(KERN_ERR " ERR: %d\n", retval); + pr_err(" ERR: %d\n", retval); return retval; } @@ -212,15 +213,13 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap, eio: retval = -EIO; if (i2c_debug) - printk(KERN_ERR " ERR: %d\n", retval); + pr_err(" ERR: %d\n", retval); return retval; } static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num) { - struct cx23885_i2c *bus = i2c_adap->algo_data; - struct cx23885_dev *dev = bus->dev; int i, retval = 0; dprintk(1, "%s(num = %d)\n", __func__, num); @@ -302,7 +301,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%04x [%s]\n", + pr_info("%s: i2c scan: found device @ 0x%04x [%s]\n", name, i, i2c_devs[i] ? i2c_devs[i] : "???"); } } @@ -330,12 +329,12 @@ int cx23885_i2c_register(struct cx23885_i2c *bus) if (0 == bus->i2c_rc) { dprintk(1, "%s: i2c bus %d registered\n", dev->name, bus->nr); if (i2c_scan) { - printk(KERN_INFO "%s: scan bus %d:\n", + pr_info("%s: scan bus %d:\n", dev->name, bus->nr); do_i2c_scan(dev->name, &bus->i2c_client); } } else - printk(KERN_WARNING "%s: i2c bus %d register FAILED\n", + pr_warn("%s: i2c bus %d register FAILED\n", dev->name, bus->nr); /* Instantiate the IR receiver device, if present */ diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c index 410c3141c163..1f092febdbd1 100644 --- a/drivers/media/pci/cx23885/cx23885-input.c +++ b/drivers/media/pci/cx23885/cx23885-input.c @@ -30,13 +30,13 @@ * GNU General Public License for more details. */ +#include "cx23885.h" +#include "cx23885-input.h" + #include #include #include -#include "cx23885.h" -#include "cx23885-input.h" - #define MODULE_NAME "cx23885" static void cx23885_input_process_measurements(struct cx23885_dev *dev, diff --git a/drivers/media/pci/cx23885/cx23885-ir.c b/drivers/media/pci/cx23885/cx23885-ir.c index 89dc4cc3e1ce..2cd5ac41ab75 100644 --- a/drivers/media/pci/cx23885/cx23885-ir.c +++ b/drivers/media/pci/cx23885/cx23885-ir.c @@ -16,12 +16,12 @@ * GNU General Public License for more details. */ -#include - #include "cx23885.h" #include "cx23885-ir.h" #include "cx23885-input.h" +#include + #define CX23885_IR_RX_FIFO_SERVICE_REQ 0 #define CX23885_IR_RX_END_OF_RX_DETECTED 1 #define CX23885_IR_RX_HW_FIFO_OVERRUN 2 diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c index 75e7fa7b1121..369e545cac04 100644 --- a/drivers/media/pci/cx23885/cx23885-vbi.c +++ b/drivers/media/pci/cx23885/cx23885-vbi.c @@ -15,13 +15,13 @@ * GNU General Public License for more details. */ +#include "cx23885.h" + #include #include #include #include -#include "cx23885.h" - static unsigned int vbibufs = 4; module_param(vbibufs, int, 0644); MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32"); @@ -32,7 +32,8 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); #define dprintk(level, fmt, arg...)\ do { if (vbi_debug >= level)\ - printk(KERN_DEBUG "%s/0: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG pr_fmt("%s: vbi:" fmt), \ + __func__, ##arg); \ } while (0) /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c index 92ff452e5886..ecc580af0148 100644 --- a/drivers/media/pci/cx23885/cx23885-video.c +++ b/drivers/media/pci/cx23885/cx23885-video.c @@ -15,6 +15,9 @@ * GNU General Public License for more details. */ +#include "cx23885.h" +#include "cx23885-video.h" + #include #include #include @@ -27,8 +30,6 @@ #include #include -#include "cx23885.h" -#include "cx23885-video.h" #include #include #include @@ -66,7 +67,8 @@ MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); #define dprintk(level, fmt, arg...)\ do { if (video_debug >= level)\ - printk(KERN_DEBUG "%s: " fmt, dev->name, ## arg);\ + printk(KERN_DEBUG pr_fmt("%s: video:" fmt), \ + __func__, ##arg); \ } while (0) /* ------------------------------------------------------------------- */ @@ -194,7 +196,7 @@ u8 cx23885_flatiron_read(struct cx23885_dev *dev, u8 reg) ret = i2c_transfer(&dev->i2c_bus[2].i2c_adap, &msg[0], 2); if (ret != 2) - printk(KERN_ERR "%s() error\n", __func__); + pr_err("%s() error\n", __func__); return b1[0]; } @@ -811,7 +813,6 @@ static int vidioc_log_status(struct file *file, void *priv) static int cx23885_query_audinput(struct file *file, void *priv, struct v4l2_audio *i) { - struct cx23885_dev *dev = video_drvdata(file); static const char *iname[] = { [0] = "Baseband L/R 1", [1] = "Baseband L/R 2", @@ -1000,7 +1001,7 @@ static int cx23885_set_freq_via_ops(struct cx23885_dev *dev, fe->ops.tuner_ops.set_analog_params(fe, ¶ms); } else - printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__); + pr_err("%s() No analog tuner, aborting\n", __func__); /* When changing channels it is required to reset TVAUDIO */ msleep(100); @@ -1058,7 +1059,7 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status) if (status & VID_BC_MSK_OPC_ERR) { dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR); - printk(KERN_WARNING "%s: video risc op code error\n", + pr_warn("%s: video risc op code error\n", dev->name); cx23885_sram_channel_dump(dev, &dev->sram_channels[SRAM_CH01]); @@ -1296,11 +1297,11 @@ int cx23885_video_register(struct cx23885_dev *dev) err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, video_nr[dev->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_info("%s: can't register video device\n", dev->name); goto fail_unreg; } - printk(KERN_INFO "%s: registered device %s [v4l2]\n", + pr_info("%s: registered device %s [v4l2]\n", dev->name, video_device_node_name(dev->video_dev)); /* register VBI device */ @@ -1310,11 +1311,11 @@ int cx23885_video_register(struct cx23885_dev *dev) err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->nr]); if (err < 0) { - printk(KERN_INFO "%s: can't register vbi device\n", + pr_info("%s: can't register vbi device\n", dev->name); goto fail_unreg; } - printk(KERN_INFO "%s: registered device %s\n", + pr_info("%s: registered device %s\n", dev->name, video_device_node_name(dev->vbi_dev)); /* Register ALSA audio device */ diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h index a6735afe2269..cb714ab60d69 100644 --- a/drivers/media/pci/cx23885/cx23885.h +++ b/drivers/media/pci/cx23885/cx23885.h @@ -15,6 +15,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c index 3115cfddab95..040323b0f945 100644 --- a/drivers/media/pci/cx23885/cx23888-ir.c +++ b/drivers/media/pci/cx23885/cx23888-ir.c @@ -16,15 +16,15 @@ * GNU General Public License for more details. */ +#include "cx23885.h" +#include "cx23888-ir.h" + #include #include #include #include -#include "cx23885.h" -#include "cx23888-ir.h" - static unsigned int ir_888_debug; module_param(ir_888_debug, int, 0644); MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]"); diff --git a/drivers/media/pci/cx23885/netup-eeprom.c b/drivers/media/pci/cx23885/netup-eeprom.c index b6542ee4385b..6384c12aa38e 100644 --- a/drivers/media/pci/cx23885/netup-eeprom.c +++ b/drivers/media/pci/cx23885/netup-eeprom.c @@ -52,7 +52,7 @@ int netup_eeprom_read(struct i2c_adapter *i2c_adap, u8 addr) ret = i2c_transfer(i2c_adap, msg, 2); if (ret != 2) { - printk(KERN_ERR "eeprom i2c read error, status=%d\n", ret); + pr_err("eeprom i2c read error, status=%d\n", ret); return -1; } @@ -80,7 +80,7 @@ int netup_eeprom_write(struct i2c_adapter *i2c_adap, u8 addr, u8 data) ret = i2c_transfer(i2c_adap, msg, 1); if (ret != 1) { - printk(KERN_ERR "eeprom i2c write error, status=%d\n", ret); + pr_err("eeprom i2c write error, status=%d\n", ret); return -1; } diff --git a/drivers/media/pci/cx23885/netup-init.c b/drivers/media/pci/cx23885/netup-init.c index 76d9487aafc8..6a27ef5d9ec2 100644 --- a/drivers/media/pci/cx23885/netup-init.c +++ b/drivers/media/pci/cx23885/netup-init.c @@ -40,7 +40,7 @@ static void i2c_av_write(struct i2c_adapter *i2c, u16 reg, u8 val) ret = i2c_transfer(i2c, &msg, 1); if (ret != 1) - printk(KERN_ERR "%s: i2c write error!\n", __func__); + pr_err("%s: i2c write error!\n", __func__); } static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val) @@ -64,7 +64,7 @@ static void i2c_av_write4(struct i2c_adapter *i2c, u16 reg, u32 val) ret = i2c_transfer(i2c, &msg, 1); if (ret != 1) - printk(KERN_ERR "%s: i2c write error!\n", __func__); + pr_err("%s: i2c write error!\n", __func__); } static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg) @@ -84,7 +84,7 @@ static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg) ret = i2c_transfer(i2c, &msg, 1); if (ret != 1) - printk(KERN_ERR "%s: i2c write error!\n", __func__); + pr_err("%s: i2c write error!\n", __func__); msg.flags = I2C_M_RD; msg.len = 1; @@ -92,7 +92,7 @@ static u8 i2c_av_read(struct i2c_adapter *i2c, u16 reg) ret = i2c_transfer(i2c, &msg, 1); if (ret != 1) - printk(KERN_ERR "%s: i2c read error!\n", __func__); + pr_err("%s: i2c read error!\n", __func__); return buf[0]; } -- cgit v1.2.3 From 3b0cb24f96dc06d0c5c049e8327aad50c8b6ddb4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 06:58:14 -0300 Subject: [media] cx88: use KERN_CONT where needed Some continuation messages are not using KERN_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups'"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. While here, add missing log level annotations. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-core.c | 38 +++++++++++++++++++------------------- drivers/media/pci/cx88/cx88-dsp.c | 7 +------ 2 files changed, 20 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 46fe8c1eb9d4..1ffd341f990d 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -399,12 +399,12 @@ static int cx88_risc_decode(u32 risc) }; int i; - printk("0x%08x [ %s", risc, + printk(KERN_DEBUG "0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(" %s",bits[i]); - printk(" count=%d ]\n", risc & 0xfff); + printk(KERN_CONT " %s", bits[i]); + printk(KERN_CONT " count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } @@ -428,42 +428,42 @@ void cx88_sram_channel_dump(struct cx88_core *core, u32 risc; unsigned int i,j,n; - printk("%s: %s - dma channel status dump\n", + printk(KERN_DEBUG "%s: %s - dma channel status dump\n", core->name,ch->name); for (i = 0; i < ARRAY_SIZE(name); i++) - printk("%s: cmds: %-12s: 0x%08x\n", + printk(KERN_DEBUG "%s: cmds: %-12s: 0x%08x\n", core->name,name[i], cx_read(ch->cmds_start + 4*i)); for (n = 1, i = 0; i < 4; i++) { risc = cx_read(ch->cmds_start + 4 * (i+11)); - printk("%s: risc%d: ", core->name, i); + printk(KERN_CONT "%s: risc%d: ", core->name, i); if (--n) - printk("0x%08x [ arg #%d ]\n", risc, n); + printk(KERN_CONT "0x%08x [ arg #%d ]\n", risc, n); else n = cx88_risc_decode(risc); } for (i = 0; i < 16; i += n) { risc = cx_read(ch->ctrl_start + 4 * i); - printk("%s: iq %x: ", core->name, i); + printk(KERN_DEBUG "%s: iq %x: ", core->name, i); n = cx88_risc_decode(risc); for (j = 1; j < n; j++) { risc = cx_read(ch->ctrl_start + 4 * (i+j)); - printk("%s: iq %x: 0x%08x [ arg #%d ]\n", + printk(KERN_CONT "%s: iq %x: 0x%08x [ arg #%d ]\n", core->name, i+j, risc, j); } } - printk("%s: fifo: 0x%08x -> 0x%x\n", + printk(KERN_DEBUG "%s: fifo: 0x%08x -> 0x%x\n", core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); - printk("%s: ctrl: 0x%08x -> 0x%x\n", + printk(KERN_DEBUG "%s: ctrl: 0x%08x -> 0x%x\n", core->name, ch->ctrl_start, ch->ctrl_start+6*16); - printk("%s: ptr1_reg: 0x%08x\n", + printk(KERN_DEBUG "%s: ptr1_reg: 0x%08x\n", core->name,cx_read(ch->ptr1_reg)); - printk("%s: ptr2_reg: 0x%08x\n", + printk(KERN_DEBUG "%s: ptr2_reg: 0x%08x\n", core->name,cx_read(ch->ptr2_reg)); - printk("%s: cnt1_reg: 0x%08x\n", + printk(KERN_DEBUG "%s: cnt1_reg: 0x%08x\n", core->name,cx_read(ch->cnt1_reg)); - printk("%s: cnt2_reg: 0x%08x\n", + printk(KERN_DEBUG "%s: cnt2_reg: 0x%08x\n", core->name,cx_read(ch->cnt2_reg)); } @@ -484,14 +484,14 @@ void cx88_print_irqbits(const char *name, const char *tag, const char *strings[] if (!(bits & (1 << i))) continue; if (strings[i]) - printk(" %s", strings[i]); + printk(KERN_CONT " %s", strings[i]); else - printk(" %d", i); + printk(KERN_CONT " %d", i); if (!(mask & (1 << i))) continue; - printk("*"); + printk(KERN_CONT "*"); } - printk("\n"); + printk(KERN_CONT "\n"); } /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index 33f3c58f8197..57380c750702 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -257,12 +257,7 @@ static s16 *read_rds_samples(struct cx88_core *core, u32 *N) offset += 4; } - if (dsp_debug >= 2) { - dprintk(2, "RDS samples dump: "); - for (i = 0; i < sample_count; i++) - printk("%hd ", samples[i]); - printk(".\n"); - } + dprintk(2, "RDS samples dump: %*ph\n", sample_count, samples); return samples; } -- cgit v1.2.3 From 65bc2fe86e667077b38a63ce6cb40677be09bc4f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Nov 2016 10:07:38 -0200 Subject: [media] cx88: convert it to use pr_foo() macros Instead of calling printk() directly, use pr_foo() macros, as suggested at the Kernel's coding style. Please notice that a conversion to dev_foo() is not trivial, as several parts on this driver uses pr_cont(). Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-alsa.c | 26 ++---- drivers/media/pci/cx88/cx88-blackbird.c | 31 +++---- drivers/media/pci/cx88/cx88-cards.c | 103 +++++++++------------ drivers/media/pci/cx88/cx88-core.c | 126 +++++++++++++------------ drivers/media/pci/cx88/cx88-dsp.c | 17 ++-- drivers/media/pci/cx88/cx88-dvb.c | 61 ++++++------ drivers/media/pci/cx88/cx88-i2c.c | 19 ++-- drivers/media/pci/cx88/cx88-input.c | 3 +- drivers/media/pci/cx88/cx88-mpeg.c | 153 ++++++++++++++----------------- drivers/media/pci/cx88/cx88-tvaudio.c | 15 +-- drivers/media/pci/cx88/cx88-vbi.c | 12 ++- drivers/media/pci/cx88/cx88-video.c | 71 +++++++------- drivers/media/pci/cx88/cx88-vp3054-i2c.c | 8 +- drivers/media/pci/cx88/cx88.h | 9 +- 14 files changed, 311 insertions(+), 343 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 495f9a0569e0..d2f1880a157e 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -24,6 +24,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" +#include "cx88-reg.h" + #include #include #include @@ -42,18 +45,11 @@ #include #include -#include "cx88.h" -#include "cx88-reg.h" - #define dprintk(level, fmt, arg...) do { \ if (debug + 1 > level) \ - printk(KERN_INFO "%s/1: " fmt, chip->core->name , ## arg);\ -} while(0) - -#define dprintk_core(level, fmt, arg...) do { \ - if (debug + 1 > level) \ - printk(KERN_DEBUG "%s/1: " fmt, chip->core->name , ## arg);\ -} while(0) + printk(KERN_DEBUG pr_fmt("%s: alsa: " fmt), \ + chip->core->name, ##arg); \ +} while (0) /**************************************************************************** Data type declarations - Can be moded to a header file later @@ -230,12 +226,12 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) return; cx_write(MO_AUD_INTSTAT, status); if (debug > 1 || (status & mask & ~0xff)) - cx88_print_irqbits(core->name, "irq aud", + cx88_print_irqbits("irq aud", cx88_aud_irqs, ARRAY_SIZE(cx88_aud_irqs), status, mask); /* risc op code error */ if (status & AUD_INT_OPC_ERR) { - printk(KERN_WARNING "%s/1: Audio risc op code error\n",core->name); + pr_warn("Audio risc op code error\n"); cx_clear(MO_AUD_DMACNTRL, 0x11); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH25]); } @@ -279,9 +275,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) } if (MAX_IRQ_LOOP == loop) { - printk(KERN_ERR - "%s/1: IRQ loop detected, disabling interrupts\n", - core->name); + pr_err("IRQ loop detected, disabling interrupts\n"); cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } @@ -423,7 +417,7 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) int err; if (!chip) { - printk(KERN_ERR "BUG: cx88 can't find device struct. Can't proceed with open\n"); + pr_err("BUG: cx88 can't find device struct. Can't proceed with open\n"); return -ENODEV; } diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index b532e49e8f33..4163e777825d 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -26,6 +26,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" + #include #include #include @@ -38,8 +40,6 @@ #include #include -#include "cx88.h" - MODULE_DESCRIPTION("driver for cx2388x/cx23416 based mpeg encoder cards"); MODULE_AUTHOR("Jelle Foks , Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); @@ -49,10 +49,11 @@ static unsigned int debug; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); -#define dprintk(level, fmt, arg...) do { \ - if (debug + 1 > level) \ - printk(KERN_DEBUG "%s/2-bb: " fmt, dev->core->name , ## arg); \ -} while(0) +#define dprintk(level, fmt, arg...) do { \ + if (debug + 1 > level) \ + printk(KERN_DEBUG pr_fmt("%s: blackbird:" fmt), \ + __func__, ##arg); \ +} while (0) /* ------------------------------------------------------------------ */ @@ -446,14 +447,14 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) if (retval != 0) { pr_err("Hotplug firmware request failed (%s).\n", - CX2341X_FIRM_ENC_FILENAME); + CX2341X_FIRM_ENC_FILENAME); pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n"); return -EIO; } if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) { pr_err("Firmware size mismatch (have %zd, expected %d)\n", - firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); + firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE); release_firmware(firmware); return -EINVAL; } @@ -1118,12 +1119,11 @@ static int blackbird_register_video(struct cx8802_dev *dev) dev->mpeg_dev.queue = &dev->vb2_mpegq; err = video_register_device(&dev->mpeg_dev, VFL_TYPE_GRABBER, -1); if (err < 0) { - printk(KERN_INFO "%s/2: can't register mpeg device\n", - dev->core->name); + pr_info("can't register mpeg device\n"); return err; } - printk(KERN_INFO "%s/2: registered device %s [mpeg]\n", - dev->core->name, video_device_node_name(&dev->mpeg_dev)); + pr_info("registered device %s [mpeg]\n", + video_device_node_name(&dev->mpeg_dev)); return 0; } @@ -1158,8 +1158,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl, NULL); /* blackbird stuff */ - printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", - core->name); + pr_info("cx23416 based mpeg encoder (blackbird reference design)\n"); host_setup(dev->core); blackbird_initialize_codec(dev); @@ -1219,8 +1218,8 @@ static struct cx8802_driver cx8802_blackbird_driver = { static int __init blackbird_init(void) { - printk(KERN_INFO "cx2388x blackbird driver version %s loaded\n", - CX88_VERSION); + pr_info("cx2388x blackbird driver version %s loaded\n", + CX88_VERSION); return cx8802_register_driver(&cx8802_blackbird_driver); } diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 31295b36dafc..1a65db957dcb 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -20,16 +20,16 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" +#include "tea5767.h" +#include "xc4000.h" + #include #include #include #include #include -#include "cx88.h" -#include "tea5767.h" -#include "xc4000.h" - static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET }; @@ -50,19 +50,11 @@ static int disable_ir; module_param(disable_ir, int, 0444); MODULE_PARM_DESC(disable_ir, "Disable IR support"); -#define info_printk(core, fmt, arg...) \ - printk(KERN_INFO "%s: " fmt, core->name , ## arg) - -#define warn_printk(core, fmt, arg...) \ - printk(KERN_WARNING "%s: " fmt, core->name , ## arg) - -#define err_printk(core, fmt, arg...) \ - printk(KERN_ERR "%s: " fmt, core->name , ## arg) - #define dprintk(level,fmt, arg...) do { \ if (cx88_core_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, core->name , ## arg); \ - } while(0) + printk(KERN_DEBUG pr_fmt("%s: core:" fmt), \ + __func__, ##arg); \ +} while (0) /* ------------------------------------------------------------------ */ @@ -2829,7 +2821,7 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) if (eeprom_data[4] != 0x7d || eeprom_data[5] != 0x10 || eeprom_data[7] != 0x66) { - warn_printk(core, "Leadtek eeprom invalid.\n"); + pr_warn("Leadtek eeprom invalid.\n"); return; } @@ -2847,8 +2839,8 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) break; } - info_printk(core, "Leadtek Winfast 2000XP Expert config: tuner=%d, eeprom[0]=0x%02x\n", - core->board.tuner_type, eeprom_data[0]); + pr_info("Leadtek Winfast 2000XP Expert config: tuner=%d, eeprom[0]=0x%02x\n", + core->board.tuner_type, eeprom_data[0]); } static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) @@ -2904,12 +2896,11 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) cx_set(MO_GP0_IO, 0x008989FF); break; default: - warn_printk(core, "warning: unknown hauppauge model #%d\n", - tv.model); + pr_warn("warning: unknown hauppauge model #%d\n", tv.model); break; } - info_printk(core, "hauppauge eeprom: model=%d\n", tv.model); + pr_info("hauppauge eeprom: model=%d\n", tv.model); } /* ----------------------------------------------------------------------- */ @@ -2955,7 +2946,7 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) const char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner)) ? gdi_tuner[eeprom_data[0x0d]].name : NULL; - info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown"); + pr_info("GDI: tuner=%s\n", name ? name : "unknown"); if (NULL == name) return; core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; @@ -3106,8 +3097,8 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) msg.len = (i != 12 ? 5 : 2); err = i2c_transfer(&core->i2c_adap, &msg, 1); if (err != 1) { - warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", - i, err); + pr_warn("dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", + i, err); return; } } @@ -3229,14 +3220,14 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg) struct cx88_core *core; if (!i2c_algo) { - printk(KERN_ERR "cx88: Error - i2c private data undefined.\n"); + pr_err("Error - i2c private data undefined.\n"); return -EINVAL; } core = i2c_algo->data; if (!core) { - printk(KERN_ERR "cx88: Error - device struct undefined.\n"); + pr_err("Error - device struct undefined.\n"); return -EINVAL; } @@ -3254,8 +3245,8 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg) dprintk(1, "Calling XC5000 callback\n"); return cx88_xc5000_tuner_callback(core, command, arg); } - err_printk(core, "Error: Calling callback for tuner %d\n", - core->board.tuner_type); + pr_err("Error: Calling callback for tuner %d\n", + core->board.tuner_type); return -EINVAL; } EXPORT_SYMBOL(cx88_tuner_callback); @@ -3268,25 +3259,19 @@ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) if (0 == pci->subsystem_vendor && 0 == pci->subsystem_device) { - printk(KERN_ERR - "%s: Your board has no valid PCI Subsystem ID and thus can't\n" - "%s: be autodetected. Please pass card= insmod option to\n" - "%s: workaround that. Redirect complaints to the vendor of\n" - "%s: the TV card. Best regards,\n" - "%s: -- tux\n", - core->name,core->name,core->name,core->name,core->name); + pr_err("Your board has no valid PCI Subsystem ID and thus can't\n"); + pr_err("be autodetected. Please pass card= insmod option to\n"); + pr_err("workaround that. Redirect complaints to the vendor of\n"); + pr_err("the TV card\n"); } else { - printk(KERN_ERR - "%s: Your board isn't known (yet) to the driver. You can\n" - "%s: try to pick one of the existing card configs via\n" - "%s: card= insmod option. Updating to the latest\n" - "%s: version might help as well.\n", - core->name,core->name,core->name,core->name); + pr_err("Your board isn't known (yet) to the driver. You can\n"); + pr_err("try to pick one of the existing card configs via\n"); + pr_err("card= insmod option. Updating to the latest\n"); + pr_err("version might help as well.\n"); } - err_printk(core, "Here is a list of valid choices for the card= insmod option:\n"); + pr_err("Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < ARRAY_SIZE(cx88_boards); i++) - printk(KERN_ERR "%s: card=%d -> %s\n", - core->name, i, cx88_boards[i].name); + pr_err(" card=%d -> %s\n", i, cx88_boards[i].name); } static void cx88_card_setup_pre_i2c(struct cx88_core *core) @@ -3508,8 +3493,8 @@ static void cx88_card_setup(struct cx88_core *core) for (i = 0; i < ARRAY_SIZE(buffer); i++) if (2 != i2c_master_send(&core->i2c_client, buffer[i],2)) - warn_printk(core, "Unable to enable tuner(%i).\n", - i); + pr_warn("Unable to enable tuner(%i).\n", + i); } break; case CX88_BOARD_MSI_TVANYWHERE_MASTER: @@ -3608,29 +3593,24 @@ static int cx88_pci_quirks(const char *name, struct pci_dev *pci) /* check pci quirks */ if (pci_pci_problems & PCIPCI_TRITON) { - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON -- set TBFX\n", - name); + pr_info("quirk: PCIPCI_TRITON -- set TBFX\n"); ctrl |= CX88X_EN_TBFX; } if (pci_pci_problems & PCIPCI_NATOMA) { - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA -- set TBFX\n", - name); + pr_info("quirk: PCIPCI_NATOMA -- set TBFX\n"); ctrl |= CX88X_EN_TBFX; } if (pci_pci_problems & PCIPCI_VIAETBF) { - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF -- set TBFX\n", - name); + pr_info("quirk: PCIPCI_VIAETBF -- set TBFX\n"); ctrl |= CX88X_EN_TBFX; } if (pci_pci_problems & PCIPCI_VSFX) { - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX -- set VSFX\n", - name); + pr_info("quirk: PCIPCI_VSFX -- set VSFX\n"); ctrl |= CX88X_EN_VSFX; } #ifdef PCIPCI_ALIMAGIK if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n", - name); + pr_info("quirk: PCIPCI_ALIMAGIK -- latency fixup\n"); lat = 0x0A; } #endif @@ -3646,8 +3626,8 @@ static int cx88_pci_quirks(const char *name, struct pci_dev *pci) pci_write_config_byte(pci, CX88X_DEVCTRL, value); } if (UNSET != lat) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", - name, latency); + pr_info("setting pci latency timer to %d\n", + latency); pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); } return 0; @@ -3659,9 +3639,8 @@ int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) pci_resource_len(pci,0), core->name)) return 0; - printk(KERN_ERR - "%s/%d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", - core->name, PCI_FUNC(pci->devfn), + pr_err("func %d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", + PCI_FUNC(pci->devfn), (unsigned long long)pci_resource_start(pci, 0), pci->subsystem_vendor, pci->subsystem_device); return -EBUSY; @@ -3755,7 +3734,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (!core->board.num_frontends && (core->board.mpeg & CX88_MPEG_DVB)) core->board.num_frontends = 1; - info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n", + pr_info("subsystem: %04x:%04x, board: %s [card=%d,%s], frontend(s): %d\n", pci->subsystem_vendor, pci->subsystem_device, core->board.name, core->boardnr, card[core->nr] == core->boardnr ? "insmod option" : "autodetected", diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 1ffd341f990d..27203e094655 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -25,6 +25,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" + #include #include #include @@ -38,7 +40,6 @@ #include #include -#include "cx88.h" #include #include @@ -60,10 +61,15 @@ static unsigned int nocomb; module_param(nocomb,int,0644); MODULE_PARM_DESC(nocomb,"disable comb filter"); -#define dprintk(level,fmt, arg...) do { \ - if (cx88_core_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, core->name , ## arg); \ - } while(0) +#define dprintk0(fmt, arg...) \ + printk(KERN_DEBUG pr_fmt("%s: core:" fmt), \ + __func__, ##arg) \ + +#define dprintk(level, fmt, arg...) do { \ + if (cx88_core_debug >= level) \ + printk(KERN_DEBUG pr_fmt("%s: core:" fmt), \ + __func__, ##arg); \ +} while (0) static unsigned int cx88_devcount; static LIST_HEAD(cx88_devlist); @@ -363,7 +369,7 @@ int cx88_sram_channel_setup(struct cx88_core *core, cx_write(ch->cnt1_reg, (bpl >> 3) -1); cx_write(ch->cnt2_reg, (lines*16) >> 3); - dprintk(2,"sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines); + dprintk(2, "sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines); return 0; } @@ -399,12 +405,12 @@ static int cx88_risc_decode(u32 risc) }; int i; - printk(KERN_DEBUG "0x%08x [ %s", risc, + dprintk0("0x%08x [ %s", risc, instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) if (risc & (1 << (i + 12))) - printk(KERN_CONT " %s", bits[i]); - printk(KERN_CONT " count=%d ]\n", risc & 0xfff); + pr_cont(" %s", bits[i]); + pr_cont(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } @@ -428,43 +434,39 @@ void cx88_sram_channel_dump(struct cx88_core *core, u32 risc; unsigned int i,j,n; - printk(KERN_DEBUG "%s: %s - dma channel status dump\n", - core->name,ch->name); + dprintk0("%s - dma channel status dump\n", + ch->name); for (i = 0; i < ARRAY_SIZE(name); i++) - printk(KERN_DEBUG "%s: cmds: %-12s: 0x%08x\n", - core->name,name[i], - cx_read(ch->cmds_start + 4*i)); + dprintk0(" cmds: %-12s: 0x%08x\n", + name[i], + cx_read(ch->cmds_start + 4*i)); for (n = 1, i = 0; i < 4; i++) { risc = cx_read(ch->cmds_start + 4 * (i+11)); - printk(KERN_CONT "%s: risc%d: ", core->name, i); + pr_cont(" risc%d: ", i); if (--n) - printk(KERN_CONT "0x%08x [ arg #%d ]\n", risc, n); + pr_cont("0x%08x [ arg #%d ]\n", risc, n); else n = cx88_risc_decode(risc); } for (i = 0; i < 16; i += n) { risc = cx_read(ch->ctrl_start + 4 * i); - printk(KERN_DEBUG "%s: iq %x: ", core->name, i); + dprintk0(" iq %x: ", i); n = cx88_risc_decode(risc); for (j = 1; j < n; j++) { risc = cx_read(ch->ctrl_start + 4 * (i+j)); - printk(KERN_CONT "%s: iq %x: 0x%08x [ arg #%d ]\n", - core->name, i+j, risc, j); + pr_cont(" iq %x: 0x%08x [ arg #%d ]\n", + i + j, risc, j); } } - printk(KERN_DEBUG "%s: fifo: 0x%08x -> 0x%x\n", - core->name, ch->fifo_start, ch->fifo_start+ch->fifo_size); - printk(KERN_DEBUG "%s: ctrl: 0x%08x -> 0x%x\n", - core->name, ch->ctrl_start, ch->ctrl_start+6*16); - printk(KERN_DEBUG "%s: ptr1_reg: 0x%08x\n", - core->name,cx_read(ch->ptr1_reg)); - printk(KERN_DEBUG "%s: ptr2_reg: 0x%08x\n", - core->name,cx_read(ch->ptr2_reg)); - printk(KERN_DEBUG "%s: cnt1_reg: 0x%08x\n", - core->name,cx_read(ch->cnt1_reg)); - printk(KERN_DEBUG "%s: cnt2_reg: 0x%08x\n", - core->name,cx_read(ch->cnt2_reg)); + dprintk0("fifo: 0x%08x -> 0x%x\n", + ch->fifo_start, ch->fifo_start+ch->fifo_size); + dprintk0("ctrl: 0x%08x -> 0x%x\n", + ch->ctrl_start, ch->ctrl_start + 6 * 16); + dprintk0(" ptr1_reg: 0x%08x\n", cx_read(ch->ptr1_reg)); + dprintk0(" ptr2_reg: 0x%08x\n", cx_read(ch->ptr2_reg)); + dprintk0(" cnt1_reg: 0x%08x\n", cx_read(ch->cnt1_reg)); + dprintk0(" cnt2_reg: 0x%08x\n", cx_read(ch->cnt2_reg)); } static const char *cx88_pci_irqs[32] = { @@ -474,24 +476,24 @@ static const char *cx88_pci_irqs[32] = { "i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1" }; -void cx88_print_irqbits(const char *name, const char *tag, const char *strings[], +void cx88_print_irqbits(const char *tag, const char *strings[], int len, u32 bits, u32 mask) { unsigned int i; - printk(KERN_DEBUG "%s: %s [0x%x]", name, tag, bits); + dprintk0("%s [0x%x]", tag, bits); for (i = 0; i < len; i++) { if (!(bits & (1 << i))) continue; if (strings[i]) - printk(KERN_CONT " %s", strings[i]); + pr_cont(" %s", strings[i]); else - printk(KERN_CONT " %d", i); + pr_cont(" %d", i); if (!(mask & (1 << i))) continue; - printk(KERN_CONT "*"); + pr_cont("*"); } - printk(KERN_CONT "\n"); + pr_cont("\n"); } /* ------------------------------------------------------------------ */ @@ -505,7 +507,7 @@ int cx88_core_irq(struct cx88_core *core, u32 status) handled++; } if (!handled) - cx88_print_irqbits(core->name, "irq pci", + cx88_print_irqbits("irq pci", cx88_pci_irqs, ARRAY_SIZE(cx88_pci_irqs), status, core->pci_irqmask); return handled; @@ -551,7 +553,7 @@ void cx88_shutdown(struct cx88_core *core) int cx88_reset(struct cx88_core *core) { - dprintk(1,"%s\n",__func__); + dprintk(1, ""); cx88_shutdown(core); /* clear irq status */ @@ -663,7 +665,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig unsigned int sheight = norm_maxh(core->tvnorm); u32 value; - dprintk(1,"set_scale: %dx%d [%s%s,%s]\n", width, height, + dprintk(1, "set_scale: %dx%d [%s%s,%s]\n", width, height, V4L2_FIELD_HAS_TOP(field) ? "T" : "", V4L2_FIELD_HAS_BOTTOM(field) ? "B" : "", v4l2_norm_to_name(core->tvnorm)); @@ -675,30 +677,30 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig value &= 0x3fe; cx_write(MO_HDELAY_EVEN, value); cx_write(MO_HDELAY_ODD, value); - dprintk(1,"set_scale: hdelay 0x%04x (width %d)\n", value,swidth); + dprintk(1, "set_scale: hdelay 0x%04x (width %d)\n", value, swidth); value = (swidth * 4096 / width) - 4096; cx_write(MO_HSCALE_EVEN, value); cx_write(MO_HSCALE_ODD, value); - dprintk(1,"set_scale: hscale 0x%04x\n", value); + dprintk(1, "set_scale: hscale 0x%04x\n", value); cx_write(MO_HACTIVE_EVEN, width); cx_write(MO_HACTIVE_ODD, width); - dprintk(1,"set_scale: hactive 0x%04x\n", width); + dprintk(1, "set_scale: hactive 0x%04x\n", width); // recalc V scale Register (delay is constant) cx_write(MO_VDELAY_EVEN, norm_vdelay(core->tvnorm)); cx_write(MO_VDELAY_ODD, norm_vdelay(core->tvnorm)); - dprintk(1,"set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm)); + dprintk(1, "set_scale: vdelay 0x%04x\n", norm_vdelay(core->tvnorm)); value = (0x10000 - (sheight * 512 / height - 512)) & 0x1fff; cx_write(MO_VSCALE_EVEN, value); cx_write(MO_VSCALE_ODD, value); - dprintk(1,"set_scale: vscale 0x%04x\n", value); + dprintk(1, "set_scale: vscale 0x%04x\n", value); cx_write(MO_VACTIVE_EVEN, sheight); cx_write(MO_VACTIVE_ODD, sheight); - dprintk(1,"set_scale: vactive 0x%04x\n", sheight); + dprintk(1, "set_scale: vactive 0x%04x\n", sheight); // setup filters value = 0; @@ -720,7 +722,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig cx_andor(MO_FILTER_EVEN, 0x7ffc7f, value); /* preserve PEAKEN, PSEL */ cx_andor(MO_FILTER_ODD, 0x7ffc7f, value); - dprintk(1,"set_scale: filter 0x%04x\n", value); + dprintk(1, "set_scale: filter 0x%04x\n", value); return 0; } @@ -743,11 +745,11 @@ static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) do_div(pll,xtal); reg = (pll & 0x3ffffff) | (pre[prescale] << 26); if (((reg >> 20) & 0x3f) < 14) { - printk("%s/0: pll out of range\n",core->name); + pr_err("pll out of range\n"); return -1; } - dprintk(1,"set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n", + dprintk(1, "set_pll: MO_PLL_REG 0x%08x [old=0x%08x,freq=%d]\n", reg, cx_read(MO_PLL_REG), ofreq); cx_write(MO_PLL_REG, reg); for (i = 0; i < 100; i++) { @@ -757,10 +759,10 @@ static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) prescale,ofreq); return 0; } - dprintk(1,"pll not locked yet, waiting ...\n"); + dprintk(1, "pll not locked yet, waiting ...\n"); msleep(10); } - dprintk(1,"pll NOT locked [pre=%d,ofreq=%d]\n",prescale,ofreq); + dprintk(1, "pll NOT locked [pre=%d,ofreq=%d]\n", prescale, ofreq); return -1; } @@ -836,8 +838,8 @@ static int set_tvaudio(struct cx88_core *core) core->tvaudio = WW_EIAJ; } else { - printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n", - core->name, v4l2_norm_to_name(core->tvnorm)); + pr_info("tvaudio support needs work for this tv norm [%s], sorry\n", + v4l2_norm_to_name(core->tvnorm)); core->tvaudio = WW_NONE; return 0; } @@ -912,12 +914,12 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) cxoformat = 0x181f0008; } - dprintk(1,"set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n", + dprintk(1, "set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n", v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock, step_db, step_dr); set_pll(core,2,vdec_clock); - dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n", + dprintk(1, "set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n", cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); /* Chroma AGC must be disabled if SECAM is used, we enable it by default on PAL and NTSC */ @@ -925,35 +927,36 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400); // FIXME: as-is from DScaler - dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n", + dprintk(1, "set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n", cxoformat, cx_read(MO_OUTPUT_FORMAT)); cx_write(MO_OUTPUT_FORMAT, cxoformat); // MO_SCONV_REG = adc clock / video dec clock * 2^17 tmp64 = adc_clock * (u64)(1 << 17); do_div(tmp64, vdec_clock); - dprintk(1,"set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n", + dprintk(1, "set_tvnorm: MO_SCONV_REG 0x%08x [old=0x%08x]\n", (u32)tmp64, cx_read(MO_SCONV_REG)); cx_write(MO_SCONV_REG, (u32)tmp64); // MO_SUB_STEP = 8 * fsc / video dec clock * 2^22 tmp64 = step_db * (u64)(1 << 22); do_div(tmp64, vdec_clock); - dprintk(1,"set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n", + dprintk(1, "set_tvnorm: MO_SUB_STEP 0x%08x [old=0x%08x]\n", (u32)tmp64, cx_read(MO_SUB_STEP)); cx_write(MO_SUB_STEP, (u32)tmp64); // MO_SUB_STEP_DR = 8 * 4406250 / video dec clock * 2^22 tmp64 = step_dr * (u64)(1 << 22); do_div(tmp64, vdec_clock); - dprintk(1,"set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n", + dprintk(1, "set_tvnorm: MO_SUB_STEP_DR 0x%08x [old=0x%08x]\n", (u32)tmp64, cx_read(MO_SUB_STEP_DR)); cx_write(MO_SUB_STEP_DR, (u32)tmp64); // bdelay + agcdelay bdelay = vdec_clock * 65 / 20000000 + 21; agcdelay = vdec_clock * 68 / 20000000 + 15; - dprintk(1,"set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n", + dprintk(1, + "set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n", (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay); cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay); @@ -961,7 +964,8 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) tmp64 = norm_htotal(norm) * (u64)vdec_clock; do_div(tmp64, fsc8); htotal = (u32)tmp64; - dprintk(1,"set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n", + dprintk(1, + "set_tvnorm: MO_HTOTAL 0x%08x [old=0x%08x,htotal=%d]\n", htotal, cx_read(MO_HTOTAL), (u32)tmp64); cx_andor(MO_HTOTAL, 0x07ff, htotal); diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index 57380c750702..4f1ec8d13389 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -19,15 +19,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" +#include "cx88-reg.h" + #include #include #include #include #include -#include "cx88.h" -#include "cx88-reg.h" - #define INT_PI ((s32)(3.141592653589 * 32768.0)) #define compat_remainder(a, b) \ @@ -71,8 +71,11 @@ static unsigned int dsp_debug; module_param(dsp_debug, int, 0644); MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages"); -#define dprintk(level, fmt, arg...) if (dsp_debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (dsp_debug >= level) \ + printk(KERN_DEBUG pr_fmt("%s: dsp:" fmt), \ + __func__, ##arg); \ +} while (0) static s32 int_cos(u32 x) { @@ -176,8 +179,8 @@ static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) dual_freq = FREQ_EIAJ_DUAL; break; default: - printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n", - core->name, core->tvaudio, __func__); + pr_warn("unsupported audio mode %d for %s\n", + core->tvaudio, __func__); return UNSET; } diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 157bc14874eb..378135ddb6fb 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -21,6 +21,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" +#include "dvb-pll.h" + #include #include #include @@ -29,8 +32,6 @@ #include #include -#include "cx88.h" -#include "dvb-pll.h" #include #include "mt352.h" @@ -77,8 +78,11 @@ MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define dprintk(level,fmt, arg...) if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + printk(KERN_DEBUG pr_fmt("%s: dvb:" fmt), \ + __func__, ##arg); \ +} while (0) /* ------------------------------------------------------------------ */ @@ -178,7 +182,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) fe_id = vb2_dvb_find_frontend(&dev->frontends, fe); if (!fe_id) { - printk(KERN_ERR "%s() No frontend found\n", __func__); + pr_err("%s() No frontend found\n", __func__); return -EINVAL; } @@ -625,8 +629,7 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) return -EINVAL; if (!fe0->dvb.frontend) { - printk(KERN_ERR "%s/2: dvb frontend not attached. Can't attach xc3028\n", - dev->core->name); + pr_err("dvb frontend not attached. Can't attach xc3028\n"); return -EINVAL; } @@ -639,16 +642,14 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev) fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); if (!fe) { - printk(KERN_ERR "%s/2: xc3028 attach failed\n", - dev->core->name); + pr_err("xc3028 attach failed\n"); dvb_frontend_detach(fe0->dvb.frontend); dvb_unregister_frontend(fe0->dvb.frontend); fe0->dvb.frontend = NULL; return -EINVAL; } - printk(KERN_INFO "%s/2: xc3028 attached\n", - dev->core->name); + pr_info("xc3028 attached\n"); return 0; } @@ -664,23 +665,21 @@ static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg) return -EINVAL; if (!fe0->dvb.frontend) { - printk(KERN_ERR "%s/2: dvb frontend not attached. Can't attach xc4000\n", - dev->core->name); + pr_err("dvb frontend not attached. Can't attach xc4000\n"); return -EINVAL; } fe = dvb_attach(xc4000_attach, fe0->dvb.frontend, &dev->core->i2c_adap, cfg); if (!fe) { - printk(KERN_ERR "%s/2: xc4000 attach failed\n", - dev->core->name); + pr_err("xc4000 attach failed\n"); dvb_frontend_detach(fe0->dvb.frontend); dvb_unregister_frontend(fe0->dvb.frontend); fe0->dvb.frontend = NULL; return -EINVAL; } - printk(KERN_INFO "%s/2: xc4000 attached\n", dev->core->name); + pr_info("xc4000 attached\n"); return 0; } @@ -798,12 +797,12 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev) if (!core->board.num_frontends) return -ENODEV; - printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__, - core->board.num_frontends); + pr_info("%s: allocating %d frontend(s)\n", __func__, + core->board.num_frontends); for (i = 1; i <= core->board.num_frontends; i++) { fe = vb2_dvb_alloc_frontend(&dev->frontends, i); if (!fe) { - printk(KERN_ERR "%s() failed to alloc\n", __func__); + pr_err("%s() failed to alloc\n", __func__); vb2_dvb_dealloc_frontends(&dev->frontends); return -ENOMEM; } @@ -1007,7 +1006,7 @@ static int dvb_register(struct cx8802_dev *dev) int res = -EINVAL; if (0 != core->i2c_rc) { - printk(KERN_ERR "%s/2: no i2c-bus available, cannot attach dvb drivers\n", core->name); + pr_err("no i2c-bus available, cannot attach dvb drivers\n"); goto frontend_detach; } @@ -1182,8 +1181,7 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; } #else - printk(KERN_ERR "%s/2: built without vp3054 support\n", - core->name); + pr_err("built without vp3054 support\n"); #endif break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID: @@ -1615,15 +1613,12 @@ static int dvb_register(struct cx8802_dev *dev) break; default: - printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n", - core->name); + pr_err("The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) { - printk(KERN_ERR - "%s/2: frontend initialization failed\n", - core->name); + pr_err("frontend initialization failed\n"); goto frontend_detach; } /* define general-purpose callback pointer */ @@ -1762,7 +1757,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) goto fail_core; /* dvb stuff */ - printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name); + pr_info("cx2388x based DVB/ATSC card\n"); dev->ts_gen_cntrl = 0x0c; err = cx8802_alloc_frontends(dev); @@ -1774,8 +1769,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) fe = vb2_dvb_get_frontend(&core->dvbdev->frontends, i); if (fe == NULL) { - printk(KERN_ERR "%s() failed to get frontend(%d)\n", - __func__, i); + pr_err("%s() failed to get frontend(%d)\n", + __func__, i); err = -ENODEV; goto fail_probe; } @@ -1803,8 +1798,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) err = dvb_register(dev); if (err) /* frontends/adapter de-allocated in dvb_register */ - printk(KERN_ERR "%s/2: dvb_register failed (err = %d)\n", - core->name, err); + pr_err("dvb_register failed (err = %d)\n", err); return err; fail_probe: vb2_dvb_dealloc_frontends(&core->dvbdev->frontends); @@ -1839,8 +1833,7 @@ static struct cx8802_driver cx8802_dvb_driver = { static int __init dvb_init(void) { - printk(KERN_INFO "cx88/2: cx2388x dvb driver version %s loaded\n", - CX88_VERSION); + pr_info("cx2388x dvb driver version %s loaded\n", CX88_VERSION); return cx8802_register_driver(&cx8802_dvb_driver); } diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c index 804f7417d19f..831f8db5150e 100644 --- a/drivers/media/pci/cx88/cx88-i2c.c +++ b/drivers/media/pci/cx88/cx88-i2c.c @@ -27,12 +27,13 @@ */ +#include "cx88.h" + #include #include #include -#include "cx88.h" #include static unsigned int i2c_debug; @@ -47,8 +48,11 @@ static unsigned int i2c_udelay = 5; module_param(i2c_udelay, int, 0644); MODULE_PARM_DESC(i2c_udelay, "i2c delay at insmod time, in usecs (should be 5 or higher). Lower value means higher bus speed."); -#define dprintk(level,fmt, arg...) if (i2c_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, core->name , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (i2c_debug >= level) \ + printk(KERN_DEBUG pr_fmt("%s: i2c:" fmt), \ + __func__, ##arg); \ +} while (0) /* ----------------------------------------------------------------------- */ @@ -126,8 +130,8 @@ static void do_i2c_scan(const char *name, struct i2c_client *c) rc = i2c_master_recv(c,&buf,0); if (rc < 0) continue; - printk("%s: i2c scan: found device @ 0x%x [%s]\n", - name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); + pr_info("i2c scan: found device @ 0x%x [%s]\n", + i << 1, i2c_devs[i] ? i2c_devs[i] : "???"); } } @@ -166,8 +170,7 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) case CX88_BOARD_HAUPPAUGE_HVR1300: case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR4000: - printk("%s: i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n", - core->name); + pr_info("i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n"); i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1); break; default: @@ -176,7 +179,7 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) if (i2c_scan) do_i2c_scan(core->name,&core->i2c_client); } else - printk("%s: i2c register FAILED\n", core->name); + pr_err("i2c register FAILED\n"); return core->i2c_rc; } diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index cd7687183381..3a05629ba6e4 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -22,13 +22,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "cx88.h" + #include #include #include #include #include -#include "cx88.h" #include #define MODULE_NAME "cx88xx" diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 86b46b62d985..ed3fcc8149bd 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -22,6 +22,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" + #include #include #include @@ -30,8 +32,6 @@ #include #include -#include "cx88.h" - /* ------------------------------------------------------------------ */ MODULE_DESCRIPTION("mpeg driver for cx2388x based TV cards"); @@ -45,15 +45,11 @@ static unsigned int debug; module_param(debug,int,0644); MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); -#define dprintk(level, fmt, arg...) do { \ - if (debug + 1 > level) \ - printk(KERN_DEBUG "%s/2-mpeg: " fmt, dev->core->name, ## arg); \ -} while(0) - -#define mpeg_dbg(level, fmt, arg...) do { \ - if (debug + 1 > level) \ - printk(KERN_DEBUG "%s/2-mpeg: " fmt, core->name, ## arg); \ -} while(0) +#define dprintk(level, fmt, arg...) do { \ + if (debug + 1 > level) \ + printk(KERN_DEBUG pr_fmt("%s: mpeg:" fmt), \ + __func__, ##arg); \ +} while (0) #if defined(CONFIG_MODULES) && defined(MODULE) static void request_module_async(struct work_struct *work) @@ -92,7 +88,7 @@ int cx8802_start_dma(struct cx8802_dev *dev, { struct cx88_core *core = dev->core; - dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n", + dprintk(1, "w: %d, h: %d, f: %d\n", core->width, core->height, core->field); /* setup fifo + format */ @@ -105,12 +101,12 @@ int cx8802_start_dma(struct cx8802_dev *dev, /* FIXME: this needs a review. * also: move to cx88-blackbird + cx88-dvb source files? */ - dprintk( 1, "core->active_type_id = 0x%08x\n", core->active_type_id); + dprintk(1, "core->active_type_id = 0x%08x\n", core->active_type_id); if ( (core->active_type_id == CX88_MPEG_DVB) && (core->board.mpeg & CX88_MPEG_DVB) ) { - dprintk( 1, "cx8802_start_dma doing .dvb\n"); + dprintk(1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); @@ -154,7 +150,7 @@ int cx8802_start_dma(struct cx8802_dev *dev, udelay(100); } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) { - dprintk( 1, "cx8802_start_dma doing .blackbird\n"); + dprintk(1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ @@ -166,8 +162,8 @@ int cx8802_start_dma(struct cx8802_dev *dev, cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ udelay(100); } else { - printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__, - core->board.mpeg ); + pr_err("%s() Failed. Unsupported value in .mpeg (0x%08x)\n", + __func__, core->board.mpeg); return -EINVAL; } @@ -176,7 +172,7 @@ int cx8802_start_dma(struct cx8802_dev *dev, q->count = 0; /* enable irqs */ - dprintk( 1, "setting the interrupt mask\n" ); + dprintk(1, "setting the interrupt mask\n"); cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_TSINT); cx_set(MO_TS_INTMSK, 0x1f0011); @@ -189,7 +185,7 @@ int cx8802_start_dma(struct cx8802_dev *dev, static int cx8802_stop_dma(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; - dprintk( 1, "cx8802_stop_dma\n" ); + dprintk(1, "\n"); /* stop dma */ cx_clear(MO_TS_DMACNTRL, 0x11); @@ -208,7 +204,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, { struct cx88_buffer *buf; - dprintk( 1, "cx8802_restart_queue\n" ); + dprintk(1, "\n"); if (list_empty(&q->active)) return 0; @@ -249,25 +245,25 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) struct cx88_buffer *prev; struct cx88_dmaqueue *cx88q = &dev->mpegq; - dprintk( 1, "cx8802_buf_queue\n" ); + dprintk(1, "\n"); /* add jump to start */ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 8); buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 8); if (list_empty(&cx88q->active)) { - dprintk( 1, "queue is empty - first active\n" ); + dprintk(1, "queue is empty - first active\n"); list_add_tail(&buf->list, &cx88q->active); dprintk(1,"[%p/%d] %s - first active\n", buf, buf->vb.vb2_buf.index, __func__); } else { buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1); - dprintk( 1, "queue is not empty - append to active\n" ); + dprintk(1, "queue is not empty - append to active\n"); prev = list_entry(cx88q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &cx88q->active); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk( 1, "[%p/%d] %s - append to active\n", + dprintk(1, "[%p/%d] %s - append to active\n", buf, buf->vb.vb2_buf.index, __func__); } } @@ -291,7 +287,7 @@ static void do_cancel_buffers(struct cx8802_dev *dev) void cx8802_cancel_buffers(struct cx8802_dev *dev) { - dprintk( 1, "cx8802_cancel_buffers" ); + dprintk(1, "\n"); cx8802_stop_dma(dev); do_cancel_buffers(dev); } @@ -310,7 +306,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) struct cx88_core *core = dev->core; u32 status, mask, count; - dprintk( 1, "cx8802_mpeg_irq\n" ); + dprintk(1, "\n"); status = cx_read(MO_TS_INTSTAT); mask = cx_read(MO_TS_INTMSK); if (0 == (status & mask)) @@ -319,20 +315,20 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) cx_write(MO_TS_INTSTAT, status); if (debug || (status & mask & ~0xff)) - cx88_print_irqbits(core->name, "irq mpeg ", + cx88_print_irqbits("irq mpeg ", cx88_mpeg_irqs, ARRAY_SIZE(cx88_mpeg_irqs), status, mask); /* risc op code error */ if (status & (1 << 16)) { - printk(KERN_WARNING "%s: mpeg risc op code error\n",core->name); + pr_warn("mpeg risc op code error\n"); cx_clear(MO_TS_DMACNTRL, 0x11); cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]); } /* risc1 y */ if (status & 0x01) { - dprintk( 1, "wake up\n" ); + dprintk(1, "wake up\n"); spin_lock(&dev->slock); count = cx_read(MO_TS_GPCNT); cx88_wakeup(dev->core, &dev->mpegq, count); @@ -341,7 +337,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) /* other general errors */ if (status & 0x1f0100) { - dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 ); + dprintk(0, "general errors: 0x%08x\n", status & 0x1f0100); spin_lock(&dev->slock); cx8802_stop_dma(dev); spin_unlock(&dev->slock); @@ -362,9 +358,9 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) (core->pci_irqmask | PCI_INT_TSINT); if (0 == status) goto out; - dprintk( 1, "cx8802_irq\n" ); - dprintk( 1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP ); - dprintk( 1, " status: %d\n", status ); + dprintk(1, "cx8802_irq\n"); + dprintk(1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP); + dprintk(1, " status: %d\n", status); handled = 1; cx_write(MO_PCI_INTSTAT, status); @@ -374,9 +370,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) cx8802_mpeg_irq(dev); } if (MAX_IRQ_LOOP == loop) { - dprintk( 0, "clearing mask\n" ); - printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", - core->name); + dprintk(0, "clearing mask\n"); + pr_warn("irq loop -- clearing mask\n"); cx_write(MO_PCI_INTMSK,0); } @@ -395,16 +390,16 @@ static int cx8802_init_common(struct cx8802_dev *dev) pci_set_master(dev->pci); err = pci_set_dma_mask(dev->pci,DMA_BIT_MASK(32)); if (err) { - printk("%s/2: Oops: no 32bit PCI DMA ???\n",dev->core->name); + pr_err("Oops: no 32bit PCI DMA ???\n"); return -EIO; } dev->pci_rev = dev->pci->revision; pci_read_config_byte(dev->pci, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/2: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", - dev->core->name, - pci_name(dev->pci), dev->pci_rev, dev->pci->irq, - dev->pci_lat,(unsigned long long)pci_resource_start(dev->pci,0)); + pr_info("found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + pci_name(dev->pci), dev->pci_rev, dev->pci->irq, + dev->pci_lat, + (unsigned long long)pci_resource_start(dev->pci, 0)); /* initialize driver struct */ spin_lock_init(&dev->slock); @@ -416,8 +411,7 @@ static int cx8802_init_common(struct cx8802_dev *dev) err = request_irq(dev->pci->irq, cx8802_irq, IRQF_SHARED, dev->core->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", - dev->core->name, dev->pci->irq); + pr_err("can't get IRQ %d\n", dev->pci->irq); return err; } cx_set(MO_PCI_INTMSK, core->pci_irqmask); @@ -429,7 +423,7 @@ static int cx8802_init_common(struct cx8802_dev *dev) static void cx8802_fini_common(struct cx8802_dev *dev) { - dprintk( 2, "cx8802_fini_common\n" ); + dprintk(2, "\n"); cx8802_stop_dma(dev); pci_disable_device(dev->pci); @@ -442,14 +436,13 @@ static void cx8802_fini_common(struct cx8802_dev *dev) static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - struct cx88_core *core = dev->core; unsigned long flags; /* stop mpeg dma */ spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->mpegq.active)) { - dprintk( 2, "suspend\n" ); - printk("%s: suspend mpeg\n", core->name); + dprintk(2, "suspend\n"); + pr_info("suspend mpeg\n"); cx8802_stop_dma(dev); } spin_unlock_irqrestore(&dev->slock, flags); @@ -468,23 +461,20 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) static int cx8802_resume_common(struct pci_dev *pci_dev) { struct cx8802_dev *dev = pci_get_drvdata(pci_dev); - struct cx88_core *core = dev->core; unsigned long flags; int err; if (dev->state.disabled) { err=pci_enable_device(pci_dev); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - dev->core->name); + pr_err("can't enable device\n"); return err; } dev->state.disabled = 0; } err=pci_set_power_state(pci_dev, PCI_D0); if (err) { - printk(KERN_ERR "%s: can't enable device\n", - dev->core->name); + pr_err("can't enable device\n"); pci_disable_device(pci_dev); dev->state.disabled = 1; @@ -498,7 +488,7 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) /* restart video+vbi capture */ spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->mpegq.active)) { - printk("%s: resume mpeg\n", core->name); + pr_info("resume mpeg\n"); cx8802_restart_queue(dev,&dev->mpegq); } spin_unlock_irqrestore(&dev->slock, flags); @@ -550,7 +540,7 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) drv->advise_acquire(drv); } - mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); + dprintk(1, "Post acquire GPIO=%x\n", cx_read(MO_GP0_IO)); } return 0; @@ -571,7 +561,7 @@ static int cx8802_request_release(struct cx8802_driver *drv) drv->advise_release(drv); core->active_type_id = CX88_BOARD_NONE; - mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO)); + dprintk(1, "Post release GPIO=%x\n", cx_read(MO_GP0_IO)); } return 0; @@ -605,24 +595,22 @@ int cx8802_register_driver(struct cx8802_driver *drv) struct cx8802_driver *driver; int err, i = 0; - printk(KERN_INFO - "cx88/2: registering cx8802 driver, type: %s access: %s\n", - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + pr_info("registering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); if ((err = cx8802_check_driver(drv)) != 0) { - printk(KERN_ERR "cx88/2: cx8802_driver is invalid\n"); + pr_err("cx8802_driver is invalid\n"); return err; } mutex_lock(&cx8802_mutex); list_for_each_entry(dev, &cx8802_devlist, devlist) { - printk(KERN_INFO - "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", - dev->core->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, dev->core->board.name, - dev->core->boardnr); + pr_info("subsystem: %04x:%04x, board: %s [card=%d]\n", + dev->pci->subsystem_vendor, + dev->pci->subsystem_device, dev->core->board.name, + dev->core->boardnr); /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv),GFP_KERNEL); @@ -645,9 +633,7 @@ int cx8802_register_driver(struct cx8802_driver *drv) i++; list_add_tail(&driver->drvlist, &dev->drvlist); } else { - printk(KERN_ERR - "%s/2: cx8802 probe failed, err = %d\n", - dev->core->name, err); + pr_err("cx8802 probe failed, err = %d\n", err); } mutex_unlock(&drv->core->lock); } @@ -664,19 +650,17 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) struct cx8802_driver *d, *dtmp; int err = 0; - printk(KERN_INFO - "cx88/2: unregistering cx8802 driver, type: %s access: %s\n", - drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + pr_info("unregistering cx8802 driver, type: %s access: %s\n", + drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", + drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); mutex_lock(&cx8802_mutex); list_for_each_entry(dev, &cx8802_devlist, devlist) { - printk(KERN_INFO - "%s/2: subsystem: %04x:%04x, board: %s [card=%d]\n", - dev->core->name, dev->pci->subsystem_vendor, - dev->pci->subsystem_device, dev->core->board.name, - dev->core->boardnr); + pr_info("subsystem: %04x:%04x, board: %s [card=%d]\n", + dev->pci->subsystem_vendor, + dev->pci->subsystem_device, dev->core->board.name, + dev->core->boardnr); mutex_lock(&dev->core->lock); @@ -690,8 +674,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) list_del(&d->drvlist); kfree(d); } else - printk(KERN_ERR "%s/2: cx8802 driver remove failed (%d)\n", - dev->core->name, err); + pr_err("cx8802 driver remove failed (%d)\n", + err); } mutex_unlock(&dev->core->lock); @@ -715,7 +699,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, if (NULL == core) return -EINVAL; - printk("%s/2: cx2388x 8802 Driver Manager\n", core->name); + pr_info("cx2388x 8802 Driver Manager\n"); err = -ENODEV; if (!core->board.mpeg) @@ -758,7 +742,7 @@ static void cx8802_remove(struct pci_dev *pci_dev) dev = pci_get_drvdata(pci_dev); - dprintk( 1, "%s\n", __func__); + dprintk(1, "%s\n", __func__); flush_request_modules(dev); @@ -768,16 +752,15 @@ static void cx8802_remove(struct pci_dev *pci_dev) struct cx8802_driver *drv, *tmp; int err; - printk(KERN_WARNING "%s/2: Trying to remove cx8802 driver while cx8802 sub-drivers still loaded?!\n", - dev->core->name); + pr_warn("Trying to remove cx8802 driver while cx8802 sub-drivers still loaded?!\n"); list_for_each_entry_safe(drv, tmp, &dev->drvlist, drvlist) { err = drv->remove(drv); if (err == 0) { list_del(&drv->drvlist); } else - printk(KERN_ERR "%s/2: cx8802 driver remove failed (%d)\n", - dev->core->name, err); + pr_err("cx8802 driver remove failed (%d)\n", + err); kfree(drv); } } diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index dd8e6f324204..b1d8680235e6 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -35,6 +35,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" + #include #include #include @@ -50,8 +52,6 @@ #include #include -#include "cx88.h" - static unsigned int audio_debug; module_param(audio_debug, int, 0644); MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]"); @@ -64,9 +64,11 @@ static unsigned int radio_deemphasis; module_param(radio_deemphasis,int,0644); MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, 0=None, 1=50us (elsewhere), 2=75us (USA)"); -#define dprintk(fmt, arg...) if (audio_debug) \ - printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) - +#define dprintk(fmt, arg...) do { \ + if (audio_debug) \ + printk(KERN_DEBUG pr_fmt("%s: tvaudio:" fmt), \ + __func__, ##arg); \ +} while (0) /* ----------------------------------------------------------- */ static const char * const aud_ctl_names[64] = { @@ -797,8 +799,7 @@ void cx88_set_tvaudio(struct cx88_core *core) break; case WW_NONE: case WW_I2SPT: - printk("%s/0: unknown tv audio mode [%d]\n", - core->name, core->tvaudio); + pr_info("unknown tv audio mode [%d]\n", core->tvaudio); break; } return; diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index d3237cf8ffa3..227f0f66e015 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -1,17 +1,21 @@ /* */ + +#include "cx88.h" + #include #include #include -#include "cx88.h" - static unsigned int vbi_debug; module_param(vbi_debug,int,0644); MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); -#define dprintk(level,fmt, arg...) if (vbi_debug >= level) \ - printk(KERN_DEBUG "%s: " fmt, dev->core->name , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (vbi_debug >= level) \ + printk(KERN_DEBUG pr_fmt("%s: vbi:" fmt), \ + __func__, ##arg); \ +} while (0) /* ------------------------------------------------------------------ */ diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 418e2db40b39..3d349dfb23ff 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -25,6 +25,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include "cx88.h" + #include #include #include @@ -37,7 +39,6 @@ #include #include -#include "cx88.h" #include #include #include @@ -70,8 +71,12 @@ static unsigned int irq_debug; module_param(irq_debug,int,0644); MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); -#define dprintk(level,fmt, arg...) if (video_debug >= level) \ - printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) +#define dprintk(level, fmt, arg...) do { \ + if (video_debug >= level) \ + printk(KERN_DEBUG pr_fmt("%s: video:" fmt), \ + __func__, ##arg); \ +} while (0) + /* ------------------------------------------------------------------- */ /* static data */ @@ -414,7 +419,6 @@ static int stop_video_dma(struct cx8800_dev *dev) static int restart_video_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q) { - struct cx88_core *core = dev->core; struct cx88_buffer *buf; if (!list_empty(&q->active)) { @@ -513,7 +517,6 @@ static void buffer_queue(struct vb2_buffer *vb) struct cx8800_dev *dev = vb->vb2_queue->drv_priv; struct cx88_buffer *buf = container_of(vbuf, struct cx88_buffer, vb); struct cx88_buffer *prev; - struct cx88_core *core = dev->core; struct cx88_dmaqueue *q = &dev->vidq; /* add jump to start */ @@ -1090,13 +1093,13 @@ static void cx8800_vid_irq(struct cx8800_dev *dev) return; cx_write(MO_VID_INTSTAT, status); if (irq_debug || (status & mask & ~0xff)) - cx88_print_irqbits(core->name, "irq vid", + cx88_print_irqbits("irq vid", cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), status, mask); /* risc op code error */ if (status & (1 << 16)) { - printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); + pr_warn("video risc op code error\n"); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); @@ -1140,8 +1143,7 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) cx8800_vid_irq(dev); } if (10 == loop) { - printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n", - core->name); + pr_warn("irq loop -- clearing mask\n"); cx_write(MO_PCI_INTMSK,0); } @@ -1307,15 +1309,15 @@ static int cx8800_initdev(struct pci_dev *pci_dev, /* print pci info */ dev->pci_rev = pci_dev->revision; pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", - core->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, - dev->pci_lat,(unsigned long long)pci_resource_start(pci_dev,0)); + pr_info("found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, + (unsigned long long)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); err = pci_set_dma_mask(pci_dev,DMA_BIT_MASK(32)); if (err) { - printk("%s/0: Oops: no 32bit PCI DMA ???\n",core->name); + pr_err("Oops: no 32bit PCI DMA ???\n"); goto fail_core; } @@ -1332,8 +1334,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, err = request_irq(pci_dev->irq, cx8800_irq, IRQF_SHARED, core->name, dev); if (err < 0) { - printk(KERN_ERR "%s/0: can't get IRQ %d\n", - core->name,pci_dev->irq); + pr_err("can't get IRQ %d\n", pci_dev->irq); goto fail_core; } cx_set(MO_PCI_INTMSK, core->pci_irqmask); @@ -1470,12 +1471,11 @@ static int cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(&dev->video_dev, VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { - printk(KERN_ERR "%s/0: can't register video device\n", - core->name); + pr_err("can't register video device\n"); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device %s [v4l2]\n", - core->name, video_device_node_name(&dev->video_dev)); + pr_info("registered device %s [v4l2]\n", + video_device_node_name(&dev->video_dev)); cx88_vdev_init(core, dev->pci, &dev->vbi_dev, &cx8800_vbi_template, "vbi"); @@ -1484,12 +1484,11 @@ static int cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(&dev->vbi_dev, VFL_TYPE_VBI, vbi_nr[core->nr]); if (err < 0) { - printk(KERN_ERR "%s/0: can't register vbi device\n", - core->name); + pr_err("can't register vbi device\n"); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device %s\n", - core->name, video_device_node_name(&dev->vbi_dev)); + pr_info("registered device %s\n", + video_device_node_name(&dev->vbi_dev)); if (core->board.radio.type == CX88_RADIO) { cx88_vdev_init(core, dev->pci, &dev->radio_dev, @@ -1499,12 +1498,11 @@ static int cx8800_initdev(struct pci_dev *pci_dev, err = video_register_device(&dev->radio_dev, VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { - printk(KERN_ERR "%s/0: can't register radio device\n", - core->name); + pr_err("can't register radio device\n"); goto fail_unreg; } - printk(KERN_INFO "%s/0: registered device %s\n", - core->name, video_device_node_name(&dev->radio_dev)); + pr_info("registered device %s\n", + video_device_node_name(&dev->radio_dev)); } /* start tvaudio thread */ @@ -1512,8 +1510,8 @@ static int cx8800_initdev(struct pci_dev *pci_dev, core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); - printk(KERN_ERR "%s/0: failed to create cx88 audio thread, err=%d\n", - core->name, err); + pr_err("failed to create cx88 audio thread, err=%d\n", + err); } } mutex_unlock(&core->lock); @@ -1571,11 +1569,11 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) /* stop video+vbi capture */ spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->vidq.active)) { - printk("%s/0: suspend video\n", core->name); + pr_info("suspend video\n"); stop_video_dma(dev); } if (!list_empty(&dev->vbiq.active)) { - printk("%s/0: suspend vbi\n", core->name); + pr_info("suspend vbi\n"); cx8800_stop_vbi_dma(dev); } spin_unlock_irqrestore(&dev->slock, flags); @@ -1603,8 +1601,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) if (dev->state.disabled) { err=pci_enable_device(pci_dev); if (err) { - printk(KERN_ERR "%s/0: can't enable device\n", - core->name); + pr_err("can't enable device\n"); return err; } @@ -1612,7 +1609,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) } err= pci_set_power_state(pci_dev, PCI_D0); if (err) { - printk(KERN_ERR "%s/0: can't set power state\n", core->name); + pr_err("can't set power state\n"); pci_disable_device(pci_dev); dev->state.disabled = 1; @@ -1630,11 +1627,11 @@ static int cx8800_resume(struct pci_dev *pci_dev) /* restart video+vbi capture */ spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->vidq.active)) { - printk("%s/0: resume video\n", core->name); + pr_info("resume video\n"); restart_video_queue(dev,&dev->vidq); } if (!list_empty(&dev->vbiq.active)) { - printk("%s/0: resume vbi\n", core->name); + pr_info("resume vbi\n"); cx8800_restart_vbi_queue(dev,&dev->vbiq); } spin_unlock_irqrestore(&dev->slock, flags); diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.c b/drivers/media/pci/cx88/cx88-vp3054-i2c.c index deede6e25d94..4f47ea2ae344 100644 --- a/drivers/media/pci/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.c @@ -22,15 +22,15 @@ */ +#include "cx88.h" +#include "cx88-vp3054-i2c.h" + #include #include #include #include -#include "cx88.h" -#include "cx88-vp3054-i2c.h" - MODULE_DESCRIPTION("driver for cx2388x VP3054 design"); MODULE_AUTHOR("Chris Pascoe "); MODULE_LICENSE("GPL"); @@ -133,7 +133,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) rc = i2c_bit_add_bus(&vp3054_i2c->adap); if (0 != rc) { - printk("%s: vp3054_i2c register FAILED\n", core->name); + pr_err("vp3054_i2c register FAILED\n"); kfree(dev->vp3054); dev->vp3054 = NULL; diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index ecd4b7bece99..01c1287baf93 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -19,6 +19,11 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#ifndef CX88_H +#define CX88_H + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -614,7 +619,7 @@ struct cx8802_dev { extern unsigned int cx88_core_debug; -extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[], +extern void cx88_print_irqbits(const char *tag, const char *strings[], int len, u32 bits, u32 mask); extern int cx88_core_irq(struct cx88_core *core, u32 status); @@ -738,3 +743,5 @@ int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f); int cx88_video_mux(struct cx88_core *core, unsigned int input); void cx88_querycap(struct file *file, struct cx88_core *core, struct v4l2_capability *cap); + +#endif -- cgit v1.2.3 From 7b61ba8ff838dbee422d428fbd882ab83db4b2d9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Nov 2016 06:59:49 -0200 Subject: [media] cx88: make checkpatch happier This driver is old, and have lots of checkpatch violations. As we're touching a lot on this driver due to the printk conversions, let's run checkpatch --fix on it, in order to solve some of those issues. Also, do a few manual adjustments: - remove the FSF address and use the usual coding style for the initial comments; - use WARN_ON() instead of BUG_ON(); - remove an unused typedef; - break a few long lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-alsa.c | 79 +++++++------ drivers/media/pci/cx88/cx88-blackbird.c | 94 +++++++-------- drivers/media/pci/cx88/cx88-cards.c | 85 +++++++------- drivers/media/pci/cx88/cx88-core.c | 121 +++++++++---------- drivers/media/pci/cx88/cx88-dsp.c | 11 +- drivers/media/pci/cx88/cx88-dvb.c | 112 +++++++++--------- drivers/media/pci/cx88/cx88-i2c.c | 95 ++++++++------- drivers/media/pci/cx88/cx88-input.c | 18 ++- drivers/media/pci/cx88/cx88-mpeg.c | 63 +++++----- drivers/media/pci/cx88/cx88-reg.h | 13 +-- drivers/media/pci/cx88/cx88-tvaudio.c | 87 +++++++------- drivers/media/pci/cx88/cx88-vbi.c | 20 ++-- drivers/media/pci/cx88/cx88-video.c | 195 +++++++++++++++---------------- drivers/media/pci/cx88/cx88-vp3054-i2c.c | 44 +++---- drivers/media/pci/cx88/cx88.h | 37 +++--- 15 files changed, 515 insertions(+), 559 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index d2f1880a157e..56770e84b3d5 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -1,5 +1,4 @@ /* - * * Support for audio capture * PCI function #1 of the cx2388x. * @@ -18,10 +17,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx88.h" @@ -118,8 +113,8 @@ MODULE_VERSION(CX88_VERSION); MODULE_SUPPORTED_DEVICE("{{Conexant,23881},{{Conexant,23882},{{Conexant,23883}"); static unsigned int debug; -module_param(debug,int,0644); -MODULE_PARM_DESC(debug,"enable debug messages"); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages"); /**************************************************************************** Module specific funtions @@ -132,7 +127,7 @@ MODULE_PARM_DESC(debug,"enable debug messages"); static int _cx88_start_audio_dma(snd_cx88_card_t *chip) { struct cx88_audio_buffer *buf = chip->buf; - struct cx88_core *core=chip->core; + struct cx88_core *core = chip->core; const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25]; /* Make sure RISC/FIFO are off before changing FIFO/RISC settings */ @@ -177,7 +172,8 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) */ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) { - struct cx88_core *core=chip->core; + struct cx88_core *core = chip->core; + dprintk(1, "Stopping audio DMA\n"); /* stop dma */ @@ -261,7 +257,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | PCI_INT_AUDINT); - if (0 == status) + if (status == 0) goto out; dprintk(3, "cx8801_irq loop %d/%d, status %x\n", loop, MAX_IRQ_LOOP, status); @@ -274,7 +270,7 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id) cx8801_aud_irq(chip); } - if (MAX_IRQ_LOOP == loop) { + if (loop == MAX_IRQ_LOOP) { pr_err("IRQ loop detected, disabling interrupts\n"); cx_clear(MO_PCI_INTMSK, PCI_INT_AUDINT); } @@ -290,7 +286,7 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages) int i; buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); - if (NULL == buf->vaddr) { + if (buf->vaddr == NULL) { dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); return -ENOMEM; } @@ -303,13 +299,13 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages) buf->nr_pages = nr_pages; buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); - if (NULL == buf->sglist) + if (buf->sglist == NULL) goto vzalloc_err; sg_init_table(buf->sglist, buf->nr_pages); for (i = 0; i < buf->nr_pages; i++) { pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE); - if (NULL == pg) + if (pg == NULL) goto vmalloc_to_page_err; sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0); } @@ -331,7 +327,7 @@ static int cx88_alsa_dma_map(struct cx88_audio_dev *dev) buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist, buf->nr_pages, PCI_DMA_FROMDEVICE); - if (0 == buf->sglen) { + if (buf->sglen == 0) { pr_warn("%s: cx88_alsa_map_sg failed\n", __func__); return -ENOMEM; } @@ -366,7 +362,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) BUG_ON(!chip->dma_size); - dprintk(2,"Freeing buffer\n"); + dprintk(2, "Freeing buffer\n"); cx88_alsa_dma_unmap(chip); cx88_alsa_dma_free(chip->buf); if (risc->cpu) @@ -431,6 +427,7 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) if (cx88_sram_channels[SRAM_CH25].fifo_size != DEFAULT_FIFO_SIZE) { unsigned int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4; + bpl &= ~7; /* must be multiple of 8 */ runtime->hw.period_bytes_min = bpl; runtime->hw.period_bytes_max = bpl; @@ -438,7 +435,7 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) return 0; _error: - dprintk(1,"Error opening PCM!\n"); + dprintk(1, "Error opening PCM!\n"); return err; } @@ -453,8 +450,8 @@ static int snd_cx88_close(struct snd_pcm_substream *substream) /* * hw_params callback */ -static int snd_cx88_hw_params(struct snd_pcm_substream * substream, - struct snd_pcm_hw_params * hw_params) +static int snd_cx88_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); @@ -474,7 +471,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream, BUG_ON(chip->num_periods & (chip->num_periods-1)); buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (NULL == buf) + if (buf == NULL) return -ENOMEM; chip->buf = buf; @@ -511,7 +508,7 @@ error: /* * hw free callback */ -static int snd_cx88_hw_free(struct snd_pcm_substream * substream) +static int snd_cx88_hw_free(struct snd_pcm_substream *substream) { snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); @@ -545,13 +542,13 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - err=_cx88_start_audio_dma(chip); + err = _cx88_start_audio_dma(chip); break; case SNDRV_PCM_TRIGGER_STOP: - err=_cx88_stop_audio_dma(chip); + err = _cx88_stop_audio_dma(chip); break; default: - err=-EINVAL; + err = -EINVAL; break; } @@ -584,6 +581,7 @@ static struct page *snd_cx88_page(struct snd_pcm_substream *substream, unsigned long offset) { void *pageptr = substream->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); } @@ -638,7 +636,7 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core=chip->core; + struct cx88_core *core = chip->core; int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), bal = cx_read(AUD_BAL_CTL); @@ -675,7 +673,7 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); - struct cx88_core *core=chip->core; + struct cx88_core *core = chip->core; int left, right, v, b; int changed = 0; u32 old; @@ -814,8 +812,8 @@ static struct snd_kcontrol_new snd_cx88_alc_switch = { */ static const struct pci_device_id cx88_audio_pci_tbl[] = { - {0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, - {0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0}, + {0x14f1, 0x8801, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x14f1, 0x8811, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, {0, } }; MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl); @@ -830,7 +828,7 @@ static int snd_cx88_free(snd_cx88_card_t *chip) if (chip->irq >= 0) free_irq(chip->irq, chip); - cx88_core_put(chip->core,chip->pci); + cx88_core_put(chip->core, chip->pci); pci_disable_device(chip->pci); return 0; @@ -839,7 +837,7 @@ static int snd_cx88_free(snd_cx88_card_t *chip) /* * Component Destructor */ -static void snd_cx88_dev_free(struct snd_card * card) +static void snd_cx88_dev_free(struct snd_card *card) { snd_cx88_card_t *chip = card->private_data; @@ -872,14 +870,14 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, chip = card->private_data; core = cx88_core_get(pci); - if (NULL == core) { + if (core == NULL) { err = -EINVAL; return err; } - err = pci_set_dma_mask(pci,DMA_BIT_MASK(32)); + err = pci_set_dma_mask(pci, DMA_BIT_MASK(32)); if (err) { - dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n",core->name); + dprintk(0, "%s/1: Oops: no 32bit PCI DMA ???\n", core->name); cx88_core_put(core, pci); return err; } @@ -908,7 +906,7 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, dprintk(1, "ALSA %s/%i: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", core->name, devno, pci_name(pci), pci->revision, pci->irq, - pci_lat, (unsigned long long)pci_resource_start(pci,0)); + pci_lat, (unsigned long long)pci_resource_start(pci, 0)); chip->irq = pci->irq; synchronize_irq(chip->irq); @@ -964,19 +962,20 @@ static int cx88_audio_initdev(struct pci_dev *pci, if (core->sd_wm8775) snd_ctl_add(card, snd_ctl_new1(&snd_cx88_alc_switch, chip)); - strcpy (card->driver, "CX88x"); + strcpy(card->driver, "CX88x"); sprintf(card->shortname, "Conexant CX%x", pci->device); sprintf(card->longname, "%s at %#llx", - card->shortname,(unsigned long long)pci_resource_start(pci, 0)); - strcpy (card->mixername, "CX88"); + card->shortname, + (unsigned long long)pci_resource_start(pci, 0)); + strcpy(card->mixername, "CX88"); - dprintk (0, "%s/%i: ALSA support for cx2388x boards\n", - card->driver,devno); + dprintk(0, "%s/%i: ALSA support for cx2388x boards\n", + card->driver, devno); err = snd_card_register(card); if (err < 0) goto error; - pci_set_drvdata(pci,card); + pci_set_drvdata(pci, card); devno++; return 0; diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index 4163e777825d..bffd064daff5 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -1,5 +1,4 @@ /* - * * Support for a cx23416 mpeg encoder via cx2388x host port. * "blackbird" reference design. * @@ -20,10 +19,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 "cx88.h" @@ -46,8 +41,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(CX88_VERSION); static unsigned int debug; -module_param(debug,int,0644); -MODULE_PARM_DESC(debug,"enable debug messages [blackbird]"); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages [blackbird]"); #define dprintk(level, fmt, arg...) do { \ if (debug + 1 > level) \ @@ -216,14 +211,14 @@ static void host_setup(struct cx88_core *core) static int wait_ready_gpio0_bit1(struct cx88_core *core, u32 state) { unsigned long timeout = jiffies + msecs_to_jiffies(1); - u32 gpio0,need; + u32 gpio0, need; need = state ? 2 : 0; for (;;) { gpio0 = cx_read(MO_GP0_IO) & 2; if (need == gpio0) return 0; - if (time_after(jiffies,timeout)) + if (time_after(jiffies, timeout)) return -1; udelay(1); } @@ -242,7 +237,7 @@ static int memory_write(struct cx88_core *core, u32 address, u32 value) cx_read(P1_MDATA0); cx_read(P1_MADDR0); - return wait_ready_gpio0_bit1(core,1); + return wait_ready_gpio0_bit1(core, 1); } static int memory_read(struct cx88_core *core, u32 address, u32 *value) @@ -256,7 +251,7 @@ static int memory_read(struct cx88_core *core, u32 address, u32 *value) cx_writeb(P1_MADDR0, (unsigned int)address); cx_read(P1_MADDR0); - retval = wait_ready_gpio0_bit1(core,1); + retval = wait_ready_gpio0_bit1(core, 1); cx_writeb(P1_MDATA3, 0); val = (unsigned char)cx_read(P1_MDATA3) << 24; @@ -283,7 +278,7 @@ static int register_write(struct cx88_core *core, u32 address, u32 value) cx_read(P1_RDATA0); cx_read(P1_RADDR0); - return wait_ready_gpio0_bit1(core,1); + return wait_ready_gpio0_bit1(core, 1); } @@ -297,7 +292,7 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value) cx_writeb(P1_RRDWR, 0); cx_read(P1_RADDR0); - retval = wait_ready_gpio0_bit1(core,1); + retval = wait_ready_gpio0_bit1(core, 1); val = (unsigned char)cx_read(P1_RDATA0); val |= (unsigned char)cx_read(P1_RDATA1) << 8; val |= (unsigned char)cx_read(P1_RDATA2) << 16; @@ -316,7 +311,7 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat u32 value, flag, retval; int i; - dprintk(1,"%s: 0x%X\n", __func__, command); + dprintk(1, "%s: 0x%X\n", __func__, command); /* this may not be 100% safe if we can't read any memory location without side effects */ @@ -354,7 +349,7 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat memory_read(dev->core, dev->mailbox, &flag); if (0 != (flag & 4)) break; - if (time_after(jiffies,timeout)) { + if (time_after(jiffies, timeout)) { dprintk(0, "ERROR: API Mailbox timeout %x\n", command); return -EIO; } @@ -368,7 +363,7 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat } memory_read(dev->core, dev->mailbox + 2, &retval); - dprintk(1, "API result = %d\n",retval); + dprintk(1, "API result = %d\n", retval); flag = 0; memory_write(dev->core, dev->mailbox, flag); @@ -400,8 +395,8 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command, static int blackbird_find_mailbox(struct cx8802_dev *dev) { - u32 signature[4]={0x12345678, 0x34567812, 0x56781234, 0x78123456}; - int signaturecnt=0; + u32 signature[4] = {0x12345678, 0x34567812, 0x56781234, 0x78123456}; + int signaturecnt = 0; u32 value; int i; @@ -411,7 +406,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev) signaturecnt++; else signaturecnt = 0; - if (4 == signaturecnt) { + if (signaturecnt == 4) { dprintk(1, "Mailbox signature found\n"); return i+1; } @@ -459,14 +454,14 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) return -EINVAL; } - if (0 != memcmp(firmware->data, magic, 8)) { + if (memcmp(firmware->data, magic, 8) != 0) { pr_err("Firmware magic mismatch, wrong file?\n"); release_firmware(firmware); return -EINVAL; } /* transfer to the chip */ - dprintk(1,"Loading firmware ...\n"); + dprintk(1, "Loading firmware ...\n"); dataptr = (__le32 *)firmware->data; for (i = 0; i < (firmware->size >> 2); i++) { value = le32_to_cpu(*dataptr); @@ -534,7 +529,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) int version; int retval; - dprintk(1,"Initialize codec\n"); + dprintk(1, "Initialize codec\n"); retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ if (retval < 0) { /* ping was not successful, reset and upload firmware */ @@ -782,7 +777,7 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (f->index != 0) @@ -815,7 +810,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - unsigned maxw, maxh; + unsigned int maxw, maxh; enum v4l2_field field; f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; @@ -871,14 +866,14 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, return 0; } -static int vidioc_s_frequency (struct file *file, void *priv, +static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; bool streaming; - if (unlikely(UNSET == core->board.tuner_type)) + if (unlikely(core->board.tuner_type == UNSET)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; @@ -886,7 +881,7 @@ static int vidioc_s_frequency (struct file *file, void *priv, if (streaming) blackbird_stop_codec(dev); - cx88_set_freq (core,f); + cx88_set_freq(core, f); blackbird_initialize_codec(dev); cx88_set_scale(core, core->width, core->height, core->field); @@ -895,7 +890,7 @@ static int vidioc_s_frequency (struct file *file, void *priv, return 0; } -static int vidioc_log_status (struct file *file, void *priv) +static int vidioc_log_status(struct file *file, void *priv) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -907,21 +902,22 @@ static int vidioc_log_status (struct file *file, void *priv) return 0; } -static int vidioc_enum_input (struct file *file, void *priv, +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - return cx88_enum_input (core,i); + + return cx88_enum_input(core, i); } -static int vidioc_g_frequency (struct file *file, void *priv, +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - if (unlikely(UNSET == core->board.tuner_type)) + if (unlikely(core->board.tuner_type == UNSET)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; @@ -932,7 +928,7 @@ static int vidioc_g_frequency (struct file *file, void *priv, return 0; } -static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -941,7 +937,7 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input (struct file *file, void *priv, unsigned int i) +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -952,20 +948,20 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) return -EINVAL; cx88_newstation(core); - cx88_video_mux(core,i); + cx88_video_mux(core, i); return 0; } -static int vidioc_g_tuner (struct file *file, void *priv, +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; u32 reg; - if (unlikely(UNSET == core->board.tuner_type)) + if (unlikely(core->board.tuner_type == UNSET)) return -EINVAL; - if (0 != t->index) + if (t->index != 0) return -EINVAL; strcpy(t->name, "Television"); @@ -973,21 +969,21 @@ static int vidioc_g_tuner (struct file *file, void *priv, t->rangehigh = 0xffffffffUL; call_all(core, tuner, g_tuner, t); - cx88_get_stereo(core ,t); + cx88_get_stereo(core, t); reg = cx_read(MO_DEVICE_STATUS); t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; return 0; } -static int vidioc_s_tuner (struct file *file, void *priv, +static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - if (UNSET == core->board.tuner_type) + if (core->board.tuner_type == UNSET) return -EINVAL; - if (0 != t->index) + if (t->index != 0) return -EINVAL; cx88_set_stereo(core, t->audmode, 1); @@ -1011,8 +1007,8 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) return cx88_set_tvnorm(core, id); } -static const struct v4l2_file_operations mpeg_fops = -{ +static const struct v4l2_file_operations mpeg_fops = { + .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -1051,7 +1047,7 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { static struct video_device cx8802_mpeg_template = { .name = "cx8802", .fops = &mpeg_fops, - .ioctl_ops = &mpeg_ioctl_ops, + .ioctl_ops = &mpeg_ioctl_ops, .tvnorms = CX88_NORMS, }; @@ -1136,8 +1132,8 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) struct vb2_queue *q; int err; - dprintk( 1, "%s\n", __func__); - dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dprintk(1, "%s\n", __func__); + dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", core->boardnr, core->name, core->pci_bus, @@ -1165,8 +1161,8 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) /* initial device configuration: needed ? */ // init_controls(core); - cx88_set_tvnorm(core,core->tvnorm); - cx88_video_mux(core,0); + cx88_set_tvnorm(core, core->tvnorm); + cx88_video_mux(core, 0); cx2341x_handler_set_50hz(&dev->cxhdl, core->height == 576); cx2341x_handler_setup(&dev->cxhdl); diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 1a65db957dcb..269179142cd8 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -1,5 +1,4 @@ /* - * * device driver for Conexant 2388x based TV cards * card-specific stuff. * @@ -14,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx88.h" @@ -38,19 +33,19 @@ module_param_array(tuner, int, NULL, 0444); module_param_array(radio, int, NULL, 0444); module_param_array(card, int, NULL, 0444); -MODULE_PARM_DESC(tuner,"tuner type"); -MODULE_PARM_DESC(radio,"radio tuner type"); -MODULE_PARM_DESC(card,"card type"); +MODULE_PARM_DESC(tuner, "tuner type"); +MODULE_PARM_DESC(radio, "radio tuner type"); +MODULE_PARM_DESC(card, "card type"); static unsigned int latency = UNSET; -module_param(latency,int,0444); -MODULE_PARM_DESC(latency,"pci latency timer"); +module_param(latency, int, 0444); +MODULE_PARM_DESC(latency, "pci latency timer"); static int disable_ir; module_param(disable_ir, int, 0444); MODULE_PARM_DESC(disable_ir, "Disable IR support"); -#define dprintk(level,fmt, arg...) do { \ +#define dprintk(level, fmt, arg...) do { \ if (cx88_core_debug >= level) \ printk(KERN_DEBUG pr_fmt("%s: core:" fmt), \ __func__, ##arg); \ @@ -2911,33 +2906,33 @@ static const struct { int fm; const char *name; } gdi_tuner[] = { - [ 0x01 ] = { .id = UNSET, + [0x01] = { .id = UNSET, .name = "NTSC_M" }, - [ 0x02 ] = { .id = UNSET, + [0x02] = { .id = UNSET, .name = "PAL_B" }, - [ 0x03 ] = { .id = UNSET, + [0x03] = { .id = UNSET, .name = "PAL_I" }, - [ 0x04 ] = { .id = UNSET, + [0x04] = { .id = UNSET, .name = "PAL_D" }, - [ 0x05 ] = { .id = UNSET, + [0x05] = { .id = UNSET, .name = "SECAM" }, - [ 0x10 ] = { .id = UNSET, + [0x10] = { .id = UNSET, .fm = 1, .name = "TEMIC_4049" }, - [ 0x11 ] = { .id = TUNER_TEMIC_4136FY5, + [0x11] = { .id = TUNER_TEMIC_4136FY5, .name = "TEMIC_4136" }, - [ 0x12 ] = { .id = UNSET, + [0x12] = { .id = UNSET, .name = "TEMIC_4146" }, - [ 0x20 ] = { .id = TUNER_PHILIPS_FQ1216ME, + [0x20] = { .id = TUNER_PHILIPS_FQ1216ME, .fm = 1, .name = "PHILIPS_FQ1216_MK3" }, - [ 0x21 ] = { .id = UNSET, .fm = 1, + [0x21] = { .id = UNSET, .fm = 1, .name = "PHILIPS_FQ1236_MK3" }, - [ 0x22 ] = { .id = UNSET, + [0x22] = { .id = UNSET, .name = "PHILIPS_FI1236_MK3" }, - [ 0x23 ] = { .id = UNSET, + [0x23] = { .id = UNSET, .name = "PHILIPS_FI1216_MK3" }, }; @@ -2947,7 +2942,7 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) ? gdi_tuner[eeprom_data[0x0d]].name : NULL; pr_info("GDI: tuner=%s\n", name ? name : "unknown"); - if (NULL == name) + if (name == NULL) return; core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? @@ -3167,7 +3162,7 @@ static int cx88_xc4000_tuner_callback(struct cx88_core *core, } /* ----------------------------------------------------------------------- */ -/* Tuner callback function. Currently only needed for the Pinnacle * +/* Tuner callback function. Currently only needed for the Pinnacle * * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ @@ -3401,7 +3396,7 @@ static void cx88_card_setup(struct cx88_core *core) memset(&tun_setup, 0, sizeof(tun_setup)); - if (0 == core->i2c_rc) { + if (core->i2c_rc == 0) { core->i2c_client.addr = 0xa0 >> 1; tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom)); } @@ -3409,17 +3404,17 @@ static void cx88_card_setup(struct cx88_core *core) switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: - if (0 == core->i2c_rc) + if (core->i2c_rc == 0) hauppauge_eeprom(core, eeprom+8); break; case CX88_BOARD_GDI: - if (0 == core->i2c_rc) + if (core->i2c_rc == 0) gdi_eeprom(core, eeprom); break; case CX88_BOARD_LEADTEK_PVR2000: case CX88_BOARD_WINFAST_DV2000: case CX88_BOARD_WINFAST2000XP_EXPERT: - if (0 == core->i2c_rc) + if (core->i2c_rc == 0) leadtek_eeprom(core, eeprom); break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: @@ -3432,7 +3427,7 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR4000: case CX88_BOARD_HAUPPAUGE_HVR4000LITE: case CX88_BOARD_HAUPPAUGE_IRONLY: - if (0 == core->i2c_rc) + if (core->i2c_rc == 0) hauppauge_eeprom(core, eeprom); break; case CX88_BOARD_KWORLD_DVBS_100: @@ -3478,21 +3473,21 @@ static void cx88_card_setup(struct cx88_core *core) cx_write(MO_GP0_IO, 0x00080808); break; case CX88_BOARD_ATI_HDTVWONDER: - if (0 == core->i2c_rc) { + if (core->i2c_rc == 0) { /* enable tuner */ int i; - static const u8 buffer [][2] = { - {0x10,0x12}, - {0x13,0x04}, - {0x16,0x00}, - {0x14,0x04}, - {0x17,0x00} + static const u8 buffer[][2] = { + {0x10, 0x12}, + {0x13, 0x04}, + {0x16, 0x00}, + {0x14, 0x04}, + {0x17, 0x00} }; core->i2c_client.addr = 0x0a; for (i = 0; i < ARRAY_SIZE(buffer); i++) if (2 != i2c_master_send(&core->i2c_client, - buffer[i],2)) + buffer[i], 2)) pr_warn("Unable to enable tuner(%i).\n", i); } @@ -3616,7 +3611,7 @@ static int cx88_pci_quirks(const char *name, struct pci_dev *pci) #endif /* check insmod options */ - if (UNSET != latency) + if (latency != UNSET) lat = latency; /* apply stuff */ @@ -3625,7 +3620,7 @@ static int cx88_pci_quirks(const char *name, struct pci_dev *pci) value |= ctrl; pci_write_config_byte(pci, CX88X_DEVCTRL, value); } - if (UNSET != lat) { + if (lat != UNSET) { pr_info("setting pci latency timer to %d\n", latency); pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); @@ -3635,8 +3630,8 @@ static int cx88_pci_quirks(const char *name, struct pci_dev *pci) int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) { - if (request_mem_region(pci_resource_start(pci,0), - pci_resource_len(pci,0), + if (request_mem_region(pci_resource_start(pci, 0), + pci_resource_len(pci, 0), core->name)) return 0; pr_err("func %d: Can't get MMIO memory @ 0x%llx, subsystem: %04x:%04x\n", @@ -3692,7 +3687,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) return NULL; } - if (0 != cx88_get_resources(core, pci)) { + if (cx88_get_resources(core, pci) != 0) { v4l2_ctrl_handler_free(&core->video_hdl); v4l2_ctrl_handler_free(&core->audio_hdl); v4l2_device_unregister(&core->v4l2_dev); @@ -3724,7 +3719,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) if (pci->subsystem_vendor == cx88_subids[i].subvendor && pci->subsystem_device == cx88_subids[i].subdevice) core->boardnr = cx88_subids[i].card; - if (UNSET == core->boardnr) { + if (core->boardnr == UNSET) { core->boardnr = CX88_BOARD_UNKNOWN; cx88_card_list(core, pci); } @@ -3754,7 +3749,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) cx88_i2c_init(core, pci); /* load tuner module, if needed */ - if (UNSET != core->board.tuner_type) { + if (core->board.tuner_type != UNSET) { /* Ignore 0x6b and 0x6f on cx88 boards. * FusionHDTV5 RT Gold has an ir receiver at 0x6b * and an RTC at 0x6f which can get corrupted if probed. */ diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 27203e094655..33719f0b06a5 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -1,5 +1,4 @@ /* - * * device driver for Conexant 2388x based TV cards * driver core * @@ -19,10 +18,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "cx88.h" @@ -54,12 +49,12 @@ module_param_named(core_debug, cx88_core_debug, int, 0644); MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); static unsigned int nicam; -module_param(nicam,int,0644); -MODULE_PARM_DESC(nicam,"tv audio is nicam"); +module_param(nicam, int, 0644); +MODULE_PARM_DESC(nicam, "tv audio is nicam"); static unsigned int nocomb; -module_param(nocomb,int,0644); -MODULE_PARM_DESC(nocomb,"disable comb filter"); +module_param(nocomb, int, 0644); +MODULE_PARM_DESC(nocomb, "disable comb filter"); #define dprintk0(fmt, arg...) \ printk(KERN_DEBUG pr_fmt("%s: core:" fmt), \ @@ -79,13 +74,13 @@ static DEFINE_MUTEX(devlist); /* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be generated _after_ lpi lines are transferred. */ -static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist, +static __le32 *cx88_risc_field(__le32 *rp, struct scatterlist *sglist, unsigned int offset, u32 sync_line, unsigned int bpl, unsigned int padding, unsigned int lines, unsigned int lpi, bool jump) { struct scatterlist *sg; - unsigned int line,todo,sol; + unsigned int line, todo, sol; if (jump) { (*rp++) = cpu_to_le32(RISC_JUMP); @@ -103,33 +98,33 @@ static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist, offset -= sg_dma_len(sg); sg = sg_next(sg); } - if (lpi && line>0 && !(line % lpi)) + if (lpi && line > 0 && !(line % lpi)) sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; else sol = RISC_SOL; if (bpl <= sg_dma_len(sg)-offset) { /* fits into current chunk */ - *(rp++)=cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); - offset+=bpl; + *(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); + offset += bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++)=cpu_to_le32(RISC_WRITE|sol| + *(rp++) = cpu_to_le32(RISC_WRITE|sol| (sg_dma_len(sg)-offset)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); todo -= (sg_dma_len(sg)-offset); offset = 0; sg = sg_next(sg); while (todo > sg_dma_len(sg)) { - *(rp++)=cpu_to_le32(RISC_WRITE| + *(rp++) = cpu_to_le32(RISC_WRITE| sg_dma_len(sg)); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); todo -= sg_dma_len(sg); sg = sg_next(sg); } - *(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo); - *(rp++)=cpu_to_le32(sg_dma_address(sg)); + *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++) = cpu_to_le32(sg_dma_address(sg)); offset += todo; } offset += padding; @@ -143,13 +138,13 @@ int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc, unsigned int top_offset, unsigned int bottom_offset, unsigned int bpl, unsigned int padding, unsigned int lines) { - u32 instructions,fields; + u32 instructions, fields; __le32 *rp; fields = 0; - if (UNSET != top_offset) + if (top_offset != UNSET) fields++; - if (UNSET != bottom_offset) + if (bottom_offset != UNSET) fields++; /* estimate risc mem: worst case is one write per page border + @@ -161,21 +156,21 @@ int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc, risc->size = instructions * 8; risc->dma = 0; risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma); - if (NULL == risc->cpu) + if (risc->cpu == NULL) return -ENOMEM; /* write risc instructions */ rp = risc->cpu; - if (UNSET != top_offset) + if (top_offset != UNSET) rp = cx88_risc_field(rp, sglist, top_offset, 0, bpl, padding, lines, 0, true); - if (UNSET != bottom_offset) + if (bottom_offset != UNSET) rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200, bpl, padding, lines, 0, top_offset == UNSET); /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -195,7 +190,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc, risc->size = instructions * 8; risc->dma = 0; risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma); - if (NULL == risc->cpu) + if (risc->cpu == NULL) return -ENOMEM; /* write risc instructions */ @@ -204,7 +199,7 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc, /* save pointer to jmp instruction address */ risc->jmp = rp; - BUG_ON((risc->jmp - risc->cpu + 2) * sizeof (*risc->cpu) > risc->size); + WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } @@ -340,7 +335,7 @@ int cx88_sram_channel_setup(struct cx88_core *core, const struct sram_channel *ch, unsigned int bpl, u32 risc) { - unsigned int i,lines; + unsigned int i, lines; u32 cdt; bpl = (bpl + 7) & ~7; /* alignment */ @@ -348,7 +343,7 @@ int cx88_sram_channel_setup(struct cx88_core *core, lines = ch->fifo_size / bpl; if (lines > 6) lines = 6; - BUG_ON(lines < 2); + WARN_ON(lines < 2); /* write CDT */ for (i = 0; i < lines; i++) @@ -366,7 +361,7 @@ int cx88_sram_channel_setup(struct cx88_core *core, /* fill registers */ cx_write(ch->ptr1_reg, ch->fifo_start); cx_write(ch->ptr2_reg, cdt); - cx_write(ch->cnt1_reg, (bpl >> 3) -1); + cx_write(ch->cnt1_reg, (bpl >> 3) - 1); cx_write(ch->cnt2_reg, (lines*16) >> 3); dprintk(2, "sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines); @@ -379,23 +374,23 @@ int cx88_sram_channel_setup(struct cx88_core *core, static int cx88_risc_decode(u32 risc) { static const char * const instr[16] = { - [ RISC_SYNC >> 28 ] = "sync", - [ RISC_WRITE >> 28 ] = "write", - [ RISC_WRITEC >> 28 ] = "writec", - [ RISC_READ >> 28 ] = "read", - [ RISC_READC >> 28 ] = "readc", - [ RISC_JUMP >> 28 ] = "jump", - [ RISC_SKIP >> 28 ] = "skip", - [ RISC_WRITERM >> 28 ] = "writerm", - [ RISC_WRITECM >> 28 ] = "writecm", - [ RISC_WRITECR >> 28 ] = "writecr", + [RISC_SYNC >> 28] = "sync", + [RISC_WRITE >> 28] = "write", + [RISC_WRITEC >> 28] = "writec", + [RISC_READ >> 28] = "read", + [RISC_READC >> 28] = "readc", + [RISC_JUMP >> 28] = "jump", + [RISC_SKIP >> 28] = "skip", + [RISC_WRITERM >> 28] = "writerm", + [RISC_WRITECM >> 28] = "writecm", + [RISC_WRITECR >> 28] = "writecr", }; static int const incr[16] = { - [ RISC_WRITE >> 28 ] = 2, - [ RISC_JUMP >> 28 ] = 2, - [ RISC_WRITERM >> 28 ] = 3, - [ RISC_WRITECM >> 28 ] = 3, - [ RISC_WRITECR >> 28 ] = 4, + [RISC_WRITE >> 28] = 2, + [RISC_JUMP >> 28] = 2, + [RISC_WRITERM >> 28] = 3, + [RISC_WRITECM >> 28] = 3, + [RISC_WRITECR >> 28] = 4, }; static const char * const bits[] = { "12", "13", "14", "resync", @@ -432,7 +427,7 @@ void cx88_sram_channel_dump(struct cx88_core *core, "line / byte", }; u32 risc; - unsigned int i,j,n; + unsigned int i, j, n; dprintk0("%s - dma channel status dump\n", ch->name); @@ -645,7 +640,7 @@ static inline unsigned int norm_fsc8(v4l2_std_id norm) static inline unsigned int norm_htotal(v4l2_std_id norm) { - unsigned int fsc4=norm_fsc8(norm)/2; + unsigned int fsc4 = norm_fsc8(norm)/2; /* returns 4*FSC / vtotal / frames per seconds */ return (norm & V4L2_STD_625_50) ? @@ -711,7 +706,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig } if (INPUT(core->input).type == CX88_VMUX_SVIDEO) value |= (1 << 13) | (1 << 5); - if (V4L2_FIELD_INTERLACED == field) + if (field == V4L2_FIELD_INTERLACED) value |= (1 << 3); // VINT (interlaced vertical scaling) if (width < 385) value |= (1 << 0); // 3-tap interpolation @@ -742,7 +737,7 @@ static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) prescale = 5; pll = ofreq * 8 * prescale * (u64)(1 << 20); - do_div(pll,xtal); + do_div(pll, xtal); reg = (pll & 0x3ffffff) | (pre[prescale] << 26); if (((reg >> 20) & 0x3f) < 14) { pr_err("pll out of range\n"); @@ -755,8 +750,8 @@ static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) for (i = 0; i < 100; i++) { reg = cx_read(MO_DEVICE_STATUS); if (reg & (1<<2)) { - dprintk(1,"pll locked [pre=%d,ofreq=%d]\n", - prescale,ofreq); + dprintk(1, "pll locked [pre=%d,ofreq=%d]\n", + prescale, ofreq); return 0; } dprintk(1, "pll not locked yet, waiting ...\n"); @@ -863,9 +858,9 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) u32 fsc8; u32 adc_clock; u32 vdec_clock; - u32 step_db,step_dr; + u32 step_db, step_dr; u64 tmp64; - u32 bdelay,agcdelay,htotal; + u32 bdelay, agcdelay, htotal; u32 cxiformat, cxoformat; if (norm == core->tvnorm) @@ -917,7 +912,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) dprintk(1, "set_tvnorm: \"%s\" fsc8=%d adc=%d vdec=%d db/dr=%d/%d\n", v4l2_norm_to_name(core->tvnorm), fsc8, adc_clock, vdec_clock, step_db, step_dr); - set_pll(core,2,vdec_clock); + set_pll(core, 2, vdec_clock); dprintk(1, "set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n", cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); @@ -1013,7 +1008,7 @@ void cx88_vdev_init(struct cx88_core *core, core->name, type, core->board.name); } -struct cx88_core* cx88_core_get(struct pci_dev *pci) +struct cx88_core *cx88_core_get(struct pci_dev *pci) { struct cx88_core *core; @@ -1024,7 +1019,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) if (PCI_SLOT(pci->devfn) != core->pci_slot) continue; - if (0 != cx88_get_resources(core, pci)) { + if (cx88_get_resources(core, pci) != 0) { mutex_unlock(&devlist); return NULL; } @@ -1034,7 +1029,7 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) } core = cx88_core_create(pci, cx88_devcount); - if (NULL != core) { + if (core != NULL) { cx88_devcount++; list_add_tail(&core->devlist, &cx88_devlist); } @@ -1045,15 +1040,15 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci) void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) { - release_mem_region(pci_resource_start(pci,0), - pci_resource_len(pci,0)); + release_mem_region(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); if (!atomic_dec_and_test(&core->refcount)) return; mutex_lock(&devlist); cx88_ir_fini(core); - if (0 == core->i2c_rc) { + if (core->i2c_rc == 0) { if (core->i2c_rtc) i2c_unregister_device(core->i2c_rtc); i2c_del_adapter(&core->i2c_adap); diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index 4f1ec8d13389..235124e2a763 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -1,5 +1,4 @@ /* - * * Stereo and SAP detection for cx88 * * Copyright (c) 2009 Marton Balint @@ -13,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 "cx88.h" @@ -82,6 +77,7 @@ static s32 int_cos(u32 x) u32 t2, t4, t6, t8; s32 ret; u16 period = x / INT_PI; + if (period % 2) return -int_cos(x - INT_PI); x = x % INT_PI; @@ -111,6 +107,7 @@ static u32 int_goertzel(s16 x[], u32 N, u32 freq) for (i = 0; i < N; i++) { s32 s = x[i] + ((s64)coeff * s_prev / 32768) - s_prev2; + s_prev2 = s_prev; s_prev = s; } @@ -129,6 +126,7 @@ static u32 int_goertzel(s16 x[], u32 N, u32 freq) static u32 freq_magnitude(s16 x[], u32 N, u32 freq) { u32 sum = int_goertzel(x, N, freq); + return (u32)int_sqrt(sum); } @@ -225,6 +223,7 @@ static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N) s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP); s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF); s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL); + dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d\n", dual_ref, dual, sap_ref, sap); /* FIXME: Currently not supported */ @@ -307,7 +306,7 @@ s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core) kfree(samples); - if (UNSET != ret) + if (ret != UNSET) dprintk(1, "stereo/sap detection result:%s%s%s\n", (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 378135ddb6fb..5188f8f2d6dd 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -1,5 +1,4 @@ /* - * * device driver for Conexant 2388x based TV cards * MPEG Transport Stream (DVB) routines * @@ -15,10 +14,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 "cx88.h" @@ -70,7 +65,7 @@ MODULE_VERSION(CX88_VERSION); static unsigned int debug; module_param(debug, int, 0644); -MODULE_PARM_DESC(debug,"enable debug messages [dvb]"); +MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); static unsigned int dvb_buf_tscnt = 32; module_param(dvb_buf_tscnt, int, 0644); @@ -173,9 +168,9 @@ static const struct vb2_ops dvb_qops = { /* ------------------------------------------------------------------ */ -static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) +static int cx88_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; struct cx8802_driver *drv = NULL; int ret = 0; int fe_id; @@ -189,7 +184,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire) mutex_lock(&dev->core->lock); drv = cx8802_get_driver(dev, CX88_MPEG_DVB); if (drv) { - if (acquire){ + if (acquire) { dev->frontends.active_fe_id = fe_id; ret = drv->request_acquire(drv); } else { @@ -226,13 +221,13 @@ static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open) /* ------------------------------------------------------------------ */ -static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) +static int dvico_fusionhdtv_demod_init(struct dvb_frontend *fe) { - static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 }; - static const u8 reset [] = { RESET, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static const u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 }; - static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static const u8 clock_config[] = { CLOCK_CTL, 0x38, 0x39 }; + static const u8 reset[] = { RESET, 0x80 }; + static const u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static const u8 agc_cfg[] = { AGC_TARGET, 0x24, 0x20 }; + static const u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; mt352_write(fe, clock_config, sizeof(clock_config)); @@ -248,11 +243,11 @@ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe) static int dvico_dual_demod_init(struct dvb_frontend *fe) { - static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 }; - static const u8 reset [] = { RESET, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 }; - static const u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 }; - static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 }; + static const u8 clock_config[] = { CLOCK_CTL, 0x38, 0x38 }; + static const u8 reset[] = { RESET, 0x80 }; + static const u8 adc_ctl_1_cfg[] = { ADC_CTL_1, 0x40 }; + static const u8 agc_cfg[] = { AGC_TARGET, 0x28, 0x20 }; + static const u8 gpp_ctl_cfg[] = { GPP_CTL, 0x33 }; static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 }; mt352_write(fe, clock_config, sizeof(clock_config)); @@ -267,12 +262,12 @@ static int dvico_dual_demod_init(struct dvb_frontend *fe) return 0; } -static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe) +static int dntv_live_dvbt_demod_init(struct dvb_frontend *fe) { - static const u8 clock_config [] = { 0x89, 0x38, 0x39 }; - static const u8 reset [] = { 0x50, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static const u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + static const u8 clock_config[] = { 0x89, 0x38, 0x39 }; + static const u8 reset[] = { 0x50, 0x80 }; + static const u8 adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static const u8 agc_cfg[] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x40, 0x40 }; static const u8 dntv_extra[] = { 0xB5, 0x7A }; static const u8 capt_range_cfg[] = { 0x75, 0x32 }; @@ -316,12 +311,12 @@ static struct mb86a16_config twinhan_vp1027 = { }; #if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054) -static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe) +static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend *fe) { - static const u8 clock_config [] = { 0x89, 0x38, 0x38 }; - static const u8 reset [] = { 0x50, 0x80 }; - static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 }; - static const u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF, + static const u8 clock_config[] = { 0x89, 0x38, 0x38 }; + static const u8 reset[] = { 0x50, 0x80 }; + static const u8 adc_ctl_1_cfg[] = { 0x8E, 0x40 }; + static const u8 agc_cfg[] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF, 0x00, 0xFF, 0x00, 0x40, 0x40 }; static const u8 dntv_extra[] = { 0xB5, 0x7A }; static const u8 capt_range_cfg[] = { 0x75, 0x32 }; @@ -378,9 +373,10 @@ static const struct cx22702_config hauppauge_hvr_config = { .output_mode = CX22702_SERIAL_OUTPUT, }; -static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured) +static int or51132_set_ts_param(struct dvb_frontend *fe, int is_punctured) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; return 0; } @@ -390,9 +386,9 @@ static const struct or51132_config pchdtv_hd3000 = { .set_ts_params = or51132_set_ts_param, }; -static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index) +static int lgdt330x_pll_rf_set(struct dvb_frontend *fe, int index) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; dprintk(1, "%s: index = %d\n", __func__, index); @@ -403,9 +399,10 @@ static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index) return 0; } -static int lgdt330x_set_ts_param(struct dvb_frontend* fe, int is_punctured) +static int lgdt330x_set_ts_param(struct dvb_frontend *fe, int is_punctured) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; + if (is_punctured) dev->ts_gen_cntrl |= 0x04; else @@ -434,9 +431,10 @@ static const struct lgdt330x_config pchdtv_hd5500 = { .set_ts_params = lgdt330x_set_ts_param, }; -static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured) +static int nxt200x_set_ts_param(struct dvb_frontend *fe, int is_punctured) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = is_punctured ? 0x04 : 0x00; return 0; } @@ -446,18 +444,19 @@ static const struct nxt200x_config ati_hdtvwonder = { .set_ts_params = nxt200x_set_ts_param, }; -static int cx24123_set_ts_param(struct dvb_frontend* fe, +static int cx24123_set_ts_param(struct dvb_frontend *fe, int is_punctured) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 0x02; return 0; } -static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, +static int kworld_dvbs_100_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; if (voltage == SEC_VOLTAGE_OFF) @@ -473,11 +472,11 @@ static int kworld_dvbs_100_set_voltage(struct dvb_frontend* fe, static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; if (voltage == SEC_VOLTAGE_OFF) { - dprintk(1,"LNB Voltage OFF\n"); + dprintk(1, "LNB Voltage OFF\n"); cx_write(MO_GP0_IO, 0x0000efff); } @@ -489,7 +488,7 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe, static int tevii_dvbs_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) { - struct cx8802_dev *dev= fe->dvb->priv; + struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; cx_set(MO_GP0_IO, 0x6040); @@ -688,6 +687,7 @@ static int cx24116_set_ts_param(struct dvb_frontend *fe, int is_punctured) { struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 0x2; return 0; @@ -697,6 +697,7 @@ static int stv0900_set_ts_param(struct dvb_frontend *fe, int is_punctured) { struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 0; return 0; @@ -734,6 +735,7 @@ static int ds3000_set_ts_param(struct dvb_frontend *fe, int is_punctured) { struct cx8802_dev *dev = fe->dvb->priv; + dev->ts_gen_cntrl = 4; return 0; @@ -1005,7 +1007,7 @@ static int dvb_register(struct cx8802_dev *dev) int mfe_shared = 0; /* bus not shared by default */ int res = -EINVAL; - if (0 != core->i2c_rc) { + if (core->i2c_rc != 0) { pr_err("no i2c-bus available, cannot attach dvb drivers\n"); goto frontend_detach; } @@ -1423,7 +1425,7 @@ static int dvb_register(struct cx8802_dev *dev) if (attach_xc3028(0x61, dev) < 0) goto frontend_detach; break; - case CX88_BOARD_KWORLD_ATSC_120: + case CX88_BOARD_KWORLD_ATSC_120: fe0->dvb.frontend = dvb_attach(s5h1409_attach, &kworld_atsc_120_config, &core->i2c_adap); @@ -1617,7 +1619,7 @@ static int dvb_register(struct cx8802_dev *dev) break; } - if ( (NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend) ) { + if ((NULL == fe0->dvb.frontend) || (fe1 && NULL == fe1->dvb.frontend)) { pr_err("frontend initialization failed\n"); goto frontend_detach; } @@ -1653,7 +1655,8 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv) { struct cx88_core *core = drv->core; int err = 0; - dprintk( 1, "%s\n", __func__); + + dprintk(1, "%s\n", __func__); switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -1717,7 +1720,8 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv) { struct cx88_core *core = drv->core; int err = 0; - dprintk( 1, "%s\n", __func__); + + dprintk(1, "%s\n", __func__); switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -1740,8 +1744,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) struct vb2_dvb_frontend *fe; int i; - dprintk( 1, "%s\n", __func__); - dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", + dprintk(1, "%s\n", __func__); + dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n", core->boardnr, core->name, core->pci_bus, @@ -1753,7 +1757,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) /* If vp3054 isn't enabled, a stub will just return 0 */ err = vp3054_i2c_probe(dev); - if (0 != err) + if (err != 0) goto fail_core; /* dvb stuff */ @@ -1811,7 +1815,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv) struct cx88_core *core = drv->core; struct cx8802_dev *dev = drv->core->dvbdev; - dprintk( 1, "%s\n", __func__); + dprintk(1, "%s\n", __func__); vb2_dvb_unregister_bus(&dev->frontends); diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c index 831f8db5150e..99596fe56cd2 100644 --- a/drivers/media/pci/cx88/cx88-i2c.c +++ b/drivers/media/pci/cx88/cx88-i2c.c @@ -1,31 +1,26 @@ /* - - cx88-i2c.c -- all the i2c code is here - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - & Marcus Metzler (mocm@thp.uni-koeln.de) - (c) 2002 Yurij Sysoev - (c) 1999-2003 Gerd Knorr - - (c) 2005 Mauro Carvalho Chehab - - Multituner support and i2c address binding - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * + * cx88-i2c.c -- all the i2c code is here + * + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + * & Marcus Metzler (mocm@thp.uni-koeln.de) + * (c) 2002 Yurij Sysoev + * (c) 1999-2003 Gerd Knorr + * + * (c) 2005 Mauro Carvalho Chehab + * - Multituner support and i2c address binding + * + * 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 "cx88.h" @@ -38,11 +33,11 @@ static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); -MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]"); +MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]"); static unsigned int i2c_scan; module_param(i2c_scan, int, 0444); -MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time"); +MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); static unsigned int i2c_udelay = 5; module_param(i2c_udelay, int, 0644); @@ -112,22 +107,22 @@ static const struct i2c_algo_bit_data cx8800_i2c_algo_template = { /* ----------------------------------------------------------------------- */ static const char * const i2c_devs[128] = { - [ 0x1c >> 1 ] = "lgdt330x", - [ 0x86 >> 1 ] = "tda9887/cx22702", - [ 0xa0 >> 1 ] = "eeprom", - [ 0xc0 >> 1 ] = "tuner (analog)", - [ 0xc2 >> 1 ] = "tuner (analog/dvb)", - [ 0xc8 >> 1 ] = "xc5000", + [0x1c >> 1] = "lgdt330x", + [0x86 >> 1] = "tda9887/cx22702", + [0xa0 >> 1] = "eeprom", + [0xc0 >> 1] = "tuner (analog)", + [0xc2 >> 1] = "tuner (analog/dvb)", + [0xc8 >> 1] = "xc5000", }; static void do_i2c_scan(const char *name, struct i2c_client *c) { unsigned char buf; - int i,rc; + int i, rc; for (i = 0; i < ARRAY_SIZE(i2c_devs); i++) { c->addr = i; - rc = i2c_master_recv(c,&buf,0); + rc = i2c_master_recv(c, &buf, 0); if (rc < 0) continue; pr_info("i2c scan: found device @ 0x%x [%s]\n", @@ -139,14 +134,14 @@ static void do_i2c_scan(const char *name, struct i2c_client *c) int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) { /* Prevents usage of invalid delay values */ - if (i2c_udelay<5) - i2c_udelay=5; + if (i2c_udelay < 5) + i2c_udelay = 5; core->i2c_algo = cx8800_i2c_algo_template; core->i2c_adap.dev.parent = &pci->dev; - strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name)); + strlcpy(core->i2c_adap.name, core->name, sizeof(core->i2c_adap.name)); core->i2c_adap.owner = THIS_MODULE; core->i2c_algo.udelay = i2c_udelay; core->i2c_algo.data = core; @@ -155,18 +150,22 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) core->i2c_client.adapter = &core->i2c_adap; strlcpy(core->i2c_client.name, "cx88xx internal", I2C_NAME_SIZE); - cx8800_bit_setscl(core,1); - cx8800_bit_setsda(core,1); + cx8800_bit_setscl(core, 1); + cx8800_bit_setsda(core, 1); core->i2c_rc = i2c_bit_add_bus(&core->i2c_adap); - if (0 == core->i2c_rc) { - static u8 tuner_data[] = - { 0x0b, 0xdc, 0x86, 0x52 }; - static struct i2c_msg tuner_msg = - { .flags = 0, .addr = 0xc2 >> 1, .buf = tuner_data, .len = 4 }; + if (core->i2c_rc == 0) { + static u8 tuner_data[] = { + 0x0b, 0xdc, 0x86, 0x52 }; + static struct i2c_msg tuner_msg = { + .flags = 0, + .addr = 0xc2 >> 1, + .buf = tuner_data, + .len = 4 + }; dprintk(1, "i2c register ok\n"); - switch( core->boardnr ) { + switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: case CX88_BOARD_HAUPPAUGE_HVR3000: case CX88_BOARD_HAUPPAUGE_HVR4000: @@ -177,7 +176,7 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) break; } if (i2c_scan) - do_i2c_scan(core->name,&core->i2c_client); + do_i2c_scan(core->name, &core->i2c_client); } else pr_err("i2c register FAILED\n"); diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index 3a05629ba6e4..c072b7ecc8d6 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -16,10 +16,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "cx88.h" @@ -58,7 +54,7 @@ struct cx88_IR { u32 mask_keyup; }; -static unsigned ir_samplerate = 4; +static unsigned int ir_samplerate = 4; module_param(ir_samplerate, uint, 0444); MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4"); @@ -67,10 +63,10 @@ module_param(ir_debug, int, 0644); /* debug level [IR] */ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define ir_dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg) + printk(KERN_DEBUG "%s IR: " fmt, ir->core->name, ##arg) #define dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "cx88 IR: " fmt , ##arg) + printk(KERN_DEBUG "cx88 IR: " fmt, ##arg) /* ---------------------------------------------------------------------- */ @@ -97,7 +93,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) auxgpio = cx_read(MO_GP1_IO); /* Take out the parity part */ - gpio=(gpio & 0x7fd) + (auxgpio & 0xef); + gpio = (gpio & 0x7fd) + (auxgpio & 0xef); break; case CX88_BOARD_WINFAST_DTV1000: case CX88_BOARD_WINFAST_DTV1800H: @@ -512,7 +508,7 @@ int cx88_ir_fini(struct cx88_core *core) struct cx88_IR *ir = core->ir; /* skip detach on non attached boards */ - if (NULL == ir) + if (ir == NULL) return 0; cx88_ir_stop(core); @@ -530,7 +526,7 @@ void cx88_ir_irq(struct cx88_core *core) { struct cx88_IR *ir = core->ir; u32 samples; - unsigned todo, bits; + unsigned int todo, bits; struct ir_raw_event ev; if (!ir || !ir->sampling) @@ -602,7 +598,7 @@ void cx88_i2c_init_ir(struct cx88_core *core) const unsigned short *addr_list = default_addr_list; const unsigned short *addrp; /* Instantiate the IR receiver device, if present */ - if (0 != core->i2c_rc) + if (core->i2c_rc != 0) return; memset(&info, 0, sizeof(struct i2c_board_info)); diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index ed3fcc8149bd..4533e2c6cb9f 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -42,8 +42,8 @@ MODULE_LICENSE("GPL"); MODULE_VERSION(CX88_VERSION); static unsigned int debug; -module_param(debug,int,0644); -MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "enable debug messages [mpeg]"); #define dprintk(level, fmt, arg...) do { \ if (debug + 1 > level) \ @@ -54,7 +54,7 @@ MODULE_PARM_DESC(debug,"enable debug messages [mpeg]"); #if defined(CONFIG_MODULES) && defined(MODULE) static void request_module_async(struct work_struct *work) { - struct cx8802_dev *dev=container_of(work, struct cx8802_dev, request_module_wk); + struct cx8802_dev *dev = container_of(work, struct cx8802_dev, request_module_wk); if (dev->core->board.mpeg & CX88_MPEG_DVB) request_module("cx88-dvb"); @@ -103,8 +103,8 @@ int cx8802_start_dma(struct cx8802_dev *dev, dprintk(1, "core->active_type_id = 0x%08x\n", core->active_type_id); - if ( (core->active_type_id == CX88_MPEG_DVB) && - (core->board.mpeg & CX88_MPEG_DVB) ) { + if ((core->active_type_id == CX88_MPEG_DVB) && + (core->board.mpeg & CX88_MPEG_DVB)) { dprintk(1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ @@ -148,8 +148,8 @@ int cx8802_start_dma(struct cx8802_dev *dev, } cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl); udelay(100); - } else if ( (core->active_type_id == CX88_MPEG_BLACKBIRD) && - (core->board.mpeg & CX88_MPEG_BLACKBIRD) ) { + } else if ((core->active_type_id == CX88_MPEG_BLACKBIRD) && + (core->board.mpeg & CX88_MPEG_BLACKBIRD)) { dprintk(1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ @@ -185,6 +185,7 @@ int cx8802_start_dma(struct cx8802_dev *dev, static int cx8802_stop_dma(struct cx8802_dev *dev) { struct cx88_core *core = dev->core; + dprintk(1, "\n"); /* stop dma */ @@ -209,7 +210,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, return 0; buf = list_entry(q->active.next, struct cx88_buffer, list); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.vb2_buf.index); cx8802_start_dma(dev, q, buf); return 0; @@ -254,7 +255,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) if (list_empty(&cx88q->active)) { dprintk(1, "queue is empty - first active\n"); list_add_tail(&buf->list, &cx88q->active); - dprintk(1,"[%p/%d] %s - first active\n", + dprintk(1, "[%p/%d] %s - first active\n", buf, buf->vb.vb2_buf.index, __func__); } else { @@ -276,13 +277,13 @@ static void do_cancel_buffers(struct cx8802_dev *dev) struct cx88_buffer *buf; unsigned long flags; - spin_lock_irqsave(&dev->slock,flags); + spin_lock_irqsave(&dev->slock, flags); while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, list); list_del(&buf->list); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); } - spin_unlock_irqrestore(&dev->slock,flags); + spin_unlock_irqrestore(&dev->slock, flags); } void cx8802_cancel_buffers(struct cx8802_dev *dev) @@ -292,7 +293,7 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev) do_cancel_buffers(dev); } -static const char * cx88_mpeg_irqs[32] = { +static const char *cx88_mpeg_irqs[32] = { "ts_risci1", NULL, NULL, NULL, "ts_risci2", NULL, NULL, NULL, "ts_oflow", NULL, NULL, NULL, @@ -356,7 +357,7 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) for (loop = 0; loop < MAX_IRQ_LOOP; loop++) { status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | PCI_INT_TSINT); - if (0 == status) + if (status == 0) goto out; dprintk(1, "cx8802_irq\n"); dprintk(1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP); @@ -365,14 +366,14 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id) cx_write(MO_PCI_INTSTAT, status); if (status & core->pci_irqmask) - cx88_core_irq(core,status); + cx88_core_irq(core, status); if (status & PCI_INT_TSINT) cx8802_mpeg_irq(dev); } - if (MAX_IRQ_LOOP == loop) { + if (loop == MAX_IRQ_LOOP) { dprintk(0, "clearing mask\n"); pr_warn("irq loop -- clearing mask\n"); - cx_write(MO_PCI_INTMSK,0); + cx_write(MO_PCI_INTMSK, 0); } out: @@ -388,7 +389,7 @@ static int cx8802_init_common(struct cx8802_dev *dev) if (pci_enable_device(dev->pci)) return -EIO; pci_set_master(dev->pci); - err = pci_set_dma_mask(dev->pci,DMA_BIT_MASK(32)); + err = pci_set_dma_mask(dev->pci, DMA_BIT_MASK(32)); if (err) { pr_err("Oops: no 32bit PCI DMA ???\n"); return -EIO; @@ -417,7 +418,7 @@ static int cx8802_init_common(struct cx8802_dev *dev) cx_set(MO_PCI_INTMSK, core->pci_irqmask); /* everything worked */ - pci_set_drvdata(dev->pci,dev); + pci_set_drvdata(dev->pci, dev); return 0; } @@ -451,7 +452,7 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) cx88_shutdown(dev->core); pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { + if (pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)) != 0) { pci_disable_device(pci_dev); dev->state.disabled = 1; } @@ -465,14 +466,14 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) int err; if (dev->state.disabled) { - err=pci_enable_device(pci_dev); + err = pci_enable_device(pci_dev); if (err) { pr_err("can't enable device\n"); return err; } dev->state.disabled = 0; } - err=pci_set_power_state(pci_dev, PCI_D0); + err = pci_set_power_state(pci_dev, PCI_D0); if (err) { pr_err("can't enable device\n"); pci_disable_device(pci_dev); @@ -489,14 +490,14 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->mpegq.active)) { pr_info("resume mpeg\n"); - cx8802_restart_queue(dev,&dev->mpegq); + cx8802_restart_queue(dev, &dev->mpegq); } spin_unlock_irqrestore(&dev->slock, flags); return 0; } -struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) +struct cx8802_driver *cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) { struct cx8802_driver *d; @@ -613,7 +614,7 @@ int cx8802_register_driver(struct cx8802_driver *drv) dev->core->boardnr); /* Bring up a new struct for each driver instance */ - driver = kzalloc(sizeof(*drv),GFP_KERNEL); + driver = kzalloc(sizeof(*drv), GFP_KERNEL); if (driver == NULL) { err = -ENOMEM; goto out; @@ -696,7 +697,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, /* general setup */ core = cx88_core_get(pci_dev); - if (NULL == core) + if (core == NULL) return -EINVAL; pr_info("cx2388x 8802 Driver Manager\n"); @@ -706,8 +707,8 @@ static int cx8802_probe(struct pci_dev *pci_dev, goto fail_core; err = -ENOMEM; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) goto fail_core; dev->pci = pci_dev; dev->core = core; @@ -721,7 +722,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, INIT_LIST_HEAD(&dev->drvlist); mutex_lock(&cx8802_mutex); - list_add_tail(&dev->devlist,&cx8802_devlist); + list_add_tail(&dev->devlist, &cx8802_devlist); mutex_unlock(&cx8802_mutex); /* now autoload cx88-dvb or cx88-blackbird */ @@ -732,7 +733,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, kfree(dev); fail_core: core->dvbdev = NULL; - cx88_core_put(core,pci_dev); + cx88_core_put(core, pci_dev); return err; } @@ -772,7 +773,7 @@ static void cx8802_remove(struct pci_dev *pci_dev) /* common */ cx8802_fini_common(dev); - cx88_core_put(dev->core,dev->pci); + cx88_core_put(dev->core, dev->pci); kfree(dev); } @@ -782,7 +783,7 @@ static const struct pci_device_id cx8802_pci_tbl[] = { .device = 0x8802, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - },{ + }, { /* --- end of list --- */ } }; diff --git a/drivers/media/pci/cx88/cx88-reg.h b/drivers/media/pci/cx88/cx88-reg.h index 2ec52d1cdea0..88ed8a2e4ee1 100644 --- a/drivers/media/pci/cx88/cx88-reg.h +++ b/drivers/media/pci/cx88/cx88-reg.h @@ -576,7 +576,7 @@ #define RISC_CNT_INC 0x00010000 #define RISC_CNT_RSVR 0x00020000 #define RISC_CNT_RESET 0x00030000 -#define RISC_JMP_SRP 0x01 +#define RISC_JMP_SRP 0x01 /* ---------------------------------------------------------------------- */ @@ -822,15 +822,4 @@ #define DEFAULT_SAT_U_NTSC 0x7F #define DEFAULT_SAT_V_NTSC 0x5A -typedef enum -{ - SOURCE_TUNER = 0, - SOURCE_COMPOSITE, - SOURCE_SVIDEO, - SOURCE_OTHER1, - SOURCE_OTHER2, - SOURCE_COMPVIASVIDEO, - SOURCE_CCIR656 -} VIDEOSOURCETYPE; - #endif /* _CX88_REG_H_ */ diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index b1d8680235e6..20f6924abe35 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -1,39 +1,34 @@ /* - - cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver - - (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version] - (c) 2002 Yurij Sysoev - (c) 2003 Gerd Knorr - - ----------------------------------------------------------------------- - - Lot of voodoo here. Even the data sheet doesn't help to - understand what is going on here, the documentation for the audio - part of the cx2388x chip is *very* bad. - - Some of this comes from party done linux driver sources I got from - [undocumented]. - - Some comes from the dscaler sources, one of the dscaler driver guy works - for Conexant ... - - ----------------------------------------------------------------------- - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver + * + * (c) 2001 Michael Eskin, Tom Zakrajsek [Windows version] + * (c) 2002 Yurij Sysoev + * (c) 2003 Gerd Knorr + * + * ----------------------------------------------------------------------- + * + * Lot of voodoo here. Even the data sheet doesn't help to + * understand what is going on here, the documentation for the audio + * part of the cx2388x chip is *very* bad. + * + * Some of this comes from party done linux driver sources I got from + * [undocumented]. + * + * Some comes from the dscaler sources, one of the dscaler driver guy works + * for Conexant ... + * + * ----------------------------------------------------------------------- + * + * 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 "cx88.h" @@ -57,11 +52,11 @@ module_param(audio_debug, int, 0644); MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]"); static unsigned int always_analog; -module_param(always_analog,int,0644); -MODULE_PARM_DESC(always_analog,"force analog audio out"); +module_param(always_analog, int, 0644); +MODULE_PARM_DESC(always_analog, "force analog audio out"); static unsigned int radio_deemphasis; -module_param(radio_deemphasis,int,0644); +module_param(radio_deemphasis, int, 0644); MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, 0=None, 1=50us (elsewhere), 2=75us (USA)"); #define dprintk(fmt, arg...) do { \ @@ -350,7 +345,7 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode) { /* end of list */ }, }; - set_audio_start(core,SEL_NICAM); + set_audio_start(core, SEL_NICAM); switch (core->tvaudio) { case WW_L: dprintk("%s SECAM-L NICAM (status: devel)\n", __func__); @@ -770,7 +765,7 @@ void cx88_set_tvaudio(struct cx88_core *core) /* set nicam mode - otherwise AUD_NICAM_STATUS2 contains wrong values */ set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO); - if (0 == cx88_detect_nicam(core)) { + if (cx88_detect_nicam(core) == 0) { /* fall back to fm / am mono */ set_audio_standard_A2(core, EN_A2_FORCE_MONO1); core->audiomode_current = V4L2_TUNER_MODE_MONO; @@ -869,11 +864,11 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) } /* If software stereo detection is not supported... */ - if (UNSET == t->rxsubchans) { + if (t->rxsubchans == UNSET) { t->rxsubchans = V4L2_TUNER_SUB_MONO; /* If the hardware itself detected stereo, also return stereo as an available subchannel */ - if (V4L2_TUNER_MODE_STEREO == t->audmode) + if (t->audmode == V4L2_TUNER_MODE_STEREO) t->rxsubchans |= V4L2_TUNER_SUB_STEREO; } return; @@ -887,7 +882,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) if (manual) { core->audiomode_manual = mode; } else { - if (UNSET != core->audiomode_manual) + if (core->audiomode_manual != UNSET) return; } core->audiomode_current = mode; @@ -915,7 +910,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) case WW_M: case WW_I: case WW_L: - if (1 == core->use_nicam) { + if (core->use_nicam == 1) { switch (mode) { case V4L2_TUNER_MODE_MONO: case V4L2_TUNER_MODE_LANG1: @@ -975,7 +970,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) break; } - if (UNSET != ctl) { + if (ctl != UNSET) { dprintk("cx88_set_stereo: mask 0x%x, ctl 0x%x [status=0x%x,ctl=0x%x,vol=0x%x]\n", mask, ctl, cx_read(AUD_STATUS), cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); @@ -1011,7 +1006,7 @@ int cx88_audio_thread(void *data) memset(&t, 0, sizeof(t)); cx88_get_stereo(core, &t); - if (UNSET != core->audiomode_manual) + if (core->audiomode_manual != UNSET) /* manually set, don't do anything. */ continue; diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 227f0f66e015..9028822f507e 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -8,8 +8,8 @@ #include static unsigned int vbi_debug; -module_param(vbi_debug,int,0644); -MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); +module_param(vbi_debug, int, 0644); +MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); #define dprintk(level, fmt, arg...) do { \ if (vbi_debug >= level) \ @@ -19,7 +19,7 @@ MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]"); /* ------------------------------------------------------------------ */ -int cx8800_vbi_fmt (struct file *file, void *priv, +int cx8800_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct cx8800_dev *dev = video_drvdata(file); @@ -57,9 +57,9 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24], VBI_LINE_LENGTH, buf->risc.dma); - cx_write(MO_VBOS_CONTROL, ( (1 << 18) | // comb filter delay fixup + cx_write(MO_VBOS_CONTROL, ((1 << 18) | // comb filter delay fixup (1 << 15) | // enable vbi capture - (1 << 11) )); + (1 << 11))); /* reset counter */ cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET); @@ -70,7 +70,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, cx_set(MO_VID_INTMSK, 0x0f0088); /* enable capture */ - cx_set(VID_CAPTURE_CONTROL,0x18); + cx_set(VID_CAPTURE_CONTROL, 0x18); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); @@ -87,7 +87,7 @@ void cx8800_stop_vbi_dma(struct cx8800_dev *dev) cx_clear(MO_VID_DMACNTRL, 0x88); /* disable capture */ - cx_clear(VID_CAPTURE_CONTROL,0x18); + cx_clear(VID_CAPTURE_CONTROL, 0x18); /* disable irqs */ cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); @@ -103,7 +103,7 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, return 0; buf = list_entry(q->active.next, struct cx88_buffer, list); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.vb2_buf.index); cx8800_start_vbi_dma(dev, q, buf); return 0; @@ -179,7 +179,7 @@ static void buffer_queue(struct vb2_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->list, &q->active); cx8800_start_vbi_dma(dev, q, buf); - dprintk(2,"[%p/%d] vbi_queue - first active\n", + dprintk(2, "[%p/%d] vbi_queue - first active\n", buf, buf->vb.vb2_buf.index); } else { @@ -187,7 +187,7 @@ static void buffer_queue(struct vb2_buffer *vb) prev = list_entry(q->active.prev, struct cx88_buffer, list); list_add_tail(&buf->list, &q->active); prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(2,"[%p/%d] buffer_queue - append to active\n", + dprintk(2, "[%p/%d] buffer_queue - append to active\n", buf, buf->vb.vb2_buf.index); } } diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 3d349dfb23ff..797d5d0a4060 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -19,10 +19,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 "cx88.h" @@ -59,17 +55,17 @@ module_param_array(video_nr, int, NULL, 0444); module_param_array(vbi_nr, int, NULL, 0444); module_param_array(radio_nr, int, NULL, 0444); -MODULE_PARM_DESC(video_nr,"video device numbers"); -MODULE_PARM_DESC(vbi_nr,"vbi device numbers"); -MODULE_PARM_DESC(radio_nr,"radio device numbers"); +MODULE_PARM_DESC(video_nr, "video device numbers"); +MODULE_PARM_DESC(vbi_nr, "vbi device numbers"); +MODULE_PARM_DESC(radio_nr, "radio device numbers"); static unsigned int video_debug; -module_param(video_debug,int,0644); -MODULE_PARM_DESC(video_debug,"enable debug messages [video]"); +module_param(video_debug, int, 0644); +MODULE_PARM_DESC(video_debug, "enable debug messages [video]"); static unsigned int irq_debug; -module_param(irq_debug,int,0644); -MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); +module_param(irq_debug, int, 0644); +MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); #define dprintk(level, fmt, arg...) do { \ if (video_debug >= level) \ @@ -88,55 +84,55 @@ static const struct cx8800_fmt formats[] = { .cxformat = ColorFormatY8, .depth = 8, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "15 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB555, .cxformat = ColorFormatRGB15, .depth = 16, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "15 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB555X, .cxformat = ColorFormatRGB15 | ColorFormatBSWAP, .depth = 16, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "16 bpp RGB, le", .fourcc = V4L2_PIX_FMT_RGB565, .cxformat = ColorFormatRGB16, .depth = 16, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "16 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB565X, .cxformat = ColorFormatRGB16 | ColorFormatBSWAP, .depth = 16, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "24 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR24, .cxformat = ColorFormatRGB24, .depth = 24, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "32 bpp RGB, le", .fourcc = V4L2_PIX_FMT_BGR32, .cxformat = ColorFormatRGB32, .depth = 32, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, .depth = 32, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "4:2:2, packed, YUYV", .fourcc = V4L2_PIX_FMT_YUYV, .cxformat = ColorFormatYUY2, .depth = 16, .flags = FORMAT_FLAGS_PACKED, - },{ + }, { .name = "4:2:2, packed, UYVY", .fourcc = V4L2_PIX_FMT_UYVY, .cxformat = ColorFormatYUY2 | ColorFormatBSWAP, @@ -145,7 +141,7 @@ static const struct cx8800_fmt formats[] = { }, }; -static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) +static const struct cx8800_fmt *format_by_fourcc(unsigned int fourcc) { unsigned int i; @@ -185,7 +181,7 @@ static const struct cx88_ctrl cx8800_vid_ctls[] = { .reg = MO_CONTR_BRIGHT, .mask = 0x00ff, .shift = 0, - },{ + }, { .id = V4L2_CID_CONTRAST, .minimum = 0, .maximum = 0xff, @@ -195,7 +191,7 @@ static const struct cx88_ctrl cx8800_vid_ctls[] = { .reg = MO_CONTR_BRIGHT, .mask = 0xff00, .shift = 8, - },{ + }, { .id = V4L2_CID_HUE, .minimum = 0, .maximum = 0xff, @@ -205,7 +201,7 @@ static const struct cx88_ctrl cx8800_vid_ctls[] = { .reg = MO_HUE, .mask = 0x00ff, .shift = 0, - },{ + }, { /* strictly, this only describes only U saturation. * V saturation is handled specially through code. */ @@ -270,7 +266,7 @@ static const struct cx88_ctrl cx8800_aud_ctls[] = { .sreg = SHADOW_AUD_VOL_CTL, .mask = (1 << 6), .shift = 6, - },{ + }, { .id = V4L2_CID_AUDIO_VOLUME, .minimum = 0, .maximum = 0x3f, @@ -280,7 +276,7 @@ static const struct cx88_ctrl cx8800_aud_ctls[] = { .sreg = SHADOW_AUD_VOL_CTL, .mask = 0x3f, .shift = 0, - },{ + }, { .id = V4L2_CID_AUDIO_BALANCE, .minimum = 0, .maximum = 0x7f, @@ -304,10 +300,10 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) { /* struct cx88_core *core = dev->core; */ - dprintk(1,"video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", + dprintk(1, "video_mux: %d [vmux=%d,gpio=0x%x,0x%x,0x%x,0x%x]\n", input, INPUT(input).vmux, - INPUT(input).gpio0,INPUT(input).gpio1, - INPUT(input).gpio2,INPUT(input).gpio3); + INPUT(input).gpio0, INPUT(input).gpio1, + INPUT(input).gpio2, INPUT(input).gpio3); core->input = input; cx_andor(MO_INPUT_FORMAT, 0x03 << 14, INPUT(input).vmux << 14); cx_write(MO_GP3_IO, INPUT(input).gpio3); @@ -374,7 +370,7 @@ static int start_video_dma(struct cx8800_dev *dev, cx_write(MO_COLOR_CTRL, dev->fmt->cxformat | ColorFormatGamma); /* reset counter */ - cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET); + cx_write(MO_VIDY_GPCNTRL, GP_COUNT_CONTROL_RESET); q->count = 0; /* enable irqs */ @@ -390,7 +386,7 @@ static int start_video_dma(struct cx8800_dev *dev, cx_set(MO_VID_INTMSK, 0x0f0011); /* enable capture */ - cx_set(VID_CAPTURE_CONTROL,0x06); + cx_set(VID_CAPTURE_CONTROL, 0x06); /* start dma */ cx_set(MO_DEV_CNTRL2, (1<<5)); @@ -408,7 +404,7 @@ static int stop_video_dma(struct cx8800_dev *dev) cx_clear(MO_VID_DMACNTRL, 0x11); /* disable capture */ - cx_clear(VID_CAPTURE_CONTROL,0x06); + cx_clear(VID_CAPTURE_CONTROL, 0x06); /* disable irqs */ cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT); @@ -423,7 +419,7 @@ static int restart_video_queue(struct cx8800_dev *dev, if (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, list); - dprintk(2,"restart_queue [%p/%d]: restart dma\n", + dprintk(2, "restart_queue [%p/%d]: restart dma\n", buf, buf->vb.vb2_buf.index); start_video_dma(dev, q, buf); } @@ -492,7 +488,7 @@ static int buffer_prepare(struct vb2_buffer *vb) core->height >> 1); break; } - dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + dprintk(2, "[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", buf, buf->vb.vb2_buf.index, core->width, core->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); @@ -526,7 +522,7 @@ static void buffer_queue(struct vb2_buffer *vb) if (list_empty(&q->active)) { list_add_tail(&buf->list, &q->active); - dprintk(2,"[%p/%d] buffer_queue - first active\n", + dprintk(2, "[%p/%d] buffer_queue - first active\n", buf, buf->vb.vb2_buf.index); } else { @@ -668,7 +664,7 @@ static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) struct cx88_core *core = container_of(ctrl->handler, struct cx88_core, audio_hdl); const struct cx88_ctrl *cc = ctrl->priv; - u32 value,mask; + u32 value, mask; /* Pass changes onto any WM8775 */ if (core->sd_wm8775) { @@ -700,7 +696,7 @@ static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; } - dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", ctrl->id, ctrl->name, ctrl->val, cc->reg, value, mask, cc->sreg ? " [shadowed]" : ""); if (cc->sreg) @@ -741,7 +737,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, unsigned int maxw, maxh; fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (NULL == fmt) + if (fmt == NULL) return -EINVAL; maxw = norm_maxw(core->tvnorm); @@ -782,9 +778,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - int err = vidioc_try_fmt_vid_cap (file,priv,f); + int err = vidioc_try_fmt_vid_cap(file, priv, f); - if (0 != err) + if (err != 0) return err; if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq)) return -EBUSY; @@ -804,7 +800,7 @@ void cx88_querycap(struct file *file, struct cx88_core *core, strlcpy(cap->card, core->board.name, sizeof(cap->card)); cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; - if (UNSET != core->board.tuner_type) + if (core->board.tuner_type != UNSET) cap->device_caps |= V4L2_CAP_TUNER; switch (vdev->vfl_type) { case VFL_TYPE_RADIO: @@ -836,13 +832,13 @@ static int vidioc_querycap(struct file *file, void *priv, return 0; } -static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, +static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, struct v4l2_fmtdesc *f) { if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; - strlcpy(f->description,formats[f->index].name,sizeof(f->description)); + strlcpy(f->description, formats[f->index].name, sizeof(f->description)); f->pixelformat = formats[f->index].fourcc; return 0; @@ -866,18 +862,18 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms) } /* only one input in this sample driver */ -int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) +int cx88_enum_input(struct cx88_core *core, struct v4l2_input *i) { static const char * const iname[] = { - [ CX88_VMUX_COMPOSITE1 ] = "Composite1", - [ CX88_VMUX_COMPOSITE2 ] = "Composite2", - [ CX88_VMUX_COMPOSITE3 ] = "Composite3", - [ CX88_VMUX_COMPOSITE4 ] = "Composite4", - [ CX88_VMUX_SVIDEO ] = "S-Video", - [ CX88_VMUX_TELEVISION ] = "Television", - [ CX88_VMUX_CABLE ] = "Cable TV", - [ CX88_VMUX_DVB ] = "DVB", - [ CX88_VMUX_DEBUG ] = "for debug only", + [CX88_VMUX_COMPOSITE1] = "Composite1", + [CX88_VMUX_COMPOSITE2] = "Composite2", + [CX88_VMUX_COMPOSITE3] = "Composite3", + [CX88_VMUX_COMPOSITE4] = "Composite4", + [CX88_VMUX_SVIDEO] = "S-Video", + [CX88_VMUX_TELEVISION] = "Television", + [CX88_VMUX_CABLE] = "Cable TV", + [CX88_VMUX_DVB] = "DVB", + [CX88_VMUX_DEBUG] = "for debug only", }; unsigned int n = i->index; @@ -886,7 +882,7 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) if (0 == INPUT(n).type) return -EINVAL; i->type = V4L2_INPUT_TYPE_CAMERA; - strcpy(i->name,iname[INPUT(n).type]); + strcpy(i->name, iname[INPUT(n).type]); if ((CX88_VMUX_TELEVISION == INPUT(n).type) || (CX88_VMUX_CABLE == INPUT(n).type)) { i->type = V4L2_INPUT_TYPE_TUNER; @@ -896,15 +892,16 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) } EXPORT_SYMBOL(cx88_enum_input); -static int vidioc_enum_input (struct file *file, void *priv, +static int vidioc_enum_input(struct file *file, void *priv, struct v4l2_input *i) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - return cx88_enum_input (core,i); + + return cx88_enum_input(core, i); } -static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) +static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -913,7 +910,7 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *i) return 0; } -static int vidioc_s_input (struct file *file, void *priv, unsigned int i) +static int vidioc_s_input(struct file *file, void *priv, unsigned int i) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -924,20 +921,20 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) return -EINVAL; cx88_newstation(core); - cx88_video_mux(core,i); + cx88_video_mux(core, i); return 0; } -static int vidioc_g_tuner (struct file *file, void *priv, +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; u32 reg; - if (unlikely(UNSET == core->board.tuner_type)) + if (unlikely(core->board.tuner_type == UNSET)) return -EINVAL; - if (0 != t->index) + if (t->index != 0) return -EINVAL; strcpy(t->name, "Television"); @@ -945,34 +942,34 @@ static int vidioc_g_tuner (struct file *file, void *priv, t->rangehigh = 0xffffffffUL; call_all(core, tuner, g_tuner, t); - cx88_get_stereo(core ,t); + cx88_get_stereo(core, t); reg = cx_read(MO_DEVICE_STATUS); t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; return 0; } -static int vidioc_s_tuner (struct file *file, void *priv, +static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - if (UNSET == core->board.tuner_type) + if (core->board.tuner_type == UNSET) return -EINVAL; - if (0 != t->index) + if (t->index != 0) return -EINVAL; cx88_set_stereo(core, t->audmode, 1); return 0; } -static int vidioc_g_frequency (struct file *file, void *priv, +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - if (unlikely(UNSET == core->board.tuner_type)) + if (unlikely(core->board.tuner_type == UNSET)) return -EINVAL; if (f->tuner) return -EINVAL; @@ -984,12 +981,12 @@ static int vidioc_g_frequency (struct file *file, void *priv, return 0; } -int cx88_set_freq (struct cx88_core *core, +int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f) { struct v4l2_frequency new_freq = *f; - if (unlikely(UNSET == core->board.tuner_type)) + if (unlikely(core->board.tuner_type == UNSET)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; @@ -1000,14 +997,14 @@ int cx88_set_freq (struct cx88_core *core, core->freq = new_freq.frequency; /* When changing channels it is required to reset TVAUDIO */ - msleep (10); + usleep_range(10000, 20000); cx88_set_tvaudio(core); return 0; } EXPORT_SYMBOL(cx88_set_freq); -static int vidioc_s_frequency (struct file *file, void *priv, +static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *f) { struct cx8800_dev *dev = video_drvdata(file); @@ -1017,7 +1014,7 @@ static int vidioc_s_frequency (struct file *file, void *priv, } #ifdef CONFIG_VIDEO_ADV_DEBUG -static int vidioc_g_register (struct file *file, void *fh, +static int vidioc_g_register(struct file *file, void *fh, struct v4l2_dbg_register *reg) { struct cx8800_dev *dev = video_drvdata(file); @@ -1029,7 +1026,7 @@ static int vidioc_g_register (struct file *file, void *fh, return 0; } -static int vidioc_s_register (struct file *file, void *fh, +static int vidioc_s_register(struct file *file, void *fh, const struct v4l2_dbg_register *reg) { struct cx8800_dev *dev = video_drvdata(file); @@ -1044,7 +1041,7 @@ static int vidioc_s_register (struct file *file, void *fh, /* RADIO ESPECIFIC IOCTLS */ /* ----------------------------------------------------------- */ -static int radio_g_tuner (struct file *file, void *priv, +static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); @@ -1059,13 +1056,13 @@ static int radio_g_tuner (struct file *file, void *priv, return 0; } -static int radio_s_tuner (struct file *file, void *priv, +static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; - if (0 != t->index) + if (t->index != 0) return -EINVAL; call_all(core, tuner, s_tuner, t); @@ -1132,19 +1129,19 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) for (loop = 0; loop < 10; loop++) { status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | PCI_INT_VIDINT); - if (0 == status) + if (status == 0) goto out; cx_write(MO_PCI_INTSTAT, status); handled = 1; if (status & core->pci_irqmask) - cx88_core_irq(core,status); + cx88_core_irq(core, status); if (status & PCI_INT_VIDINT) cx8800_vid_irq(dev); } - if (10 == loop) { + if (loop == 10) { pr_warn("irq loop -- clearing mask\n"); - cx_write(MO_PCI_INTMSK,0); + cx_write(MO_PCI_INTMSK, 0); } out: @@ -1154,8 +1151,8 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) /* ----------------------------------------------------------- */ /* exported stuff */ -static const struct v4l2_file_operations video_fops = -{ +static const struct v4l2_file_operations video_fops = { + .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -1197,7 +1194,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { static const struct video_device cx8800_video_template = { .name = "cx8800-video", .fops = &video_fops, - .ioctl_ops = &video_ioctl_ops, + .ioctl_ops = &video_ioctl_ops, .tvnorms = CX88_NORMS, }; @@ -1234,8 +1231,8 @@ static const struct video_device cx8800_vbi_template = { .tvnorms = CX88_NORMS, }; -static const struct v4l2_file_operations radio_fops = -{ +static const struct v4l2_file_operations radio_fops = { + .owner = THIS_MODULE, .open = radio_open, .poll = v4l2_ctrl_poll, @@ -1260,7 +1257,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = { static const struct video_device cx8800_radio_template = { .name = "cx8800-radio", .fops = &radio_fops, - .ioctl_ops = &radio_ioctl_ops, + .ioctl_ops = &radio_ioctl_ops, }; static const struct v4l2_ctrl_ops cx8800_ctrl_vid_ops = { @@ -1289,8 +1286,8 @@ static int cx8800_initdev(struct pci_dev *pci_dev, int err; int i; - dev = kzalloc(sizeof(*dev),GFP_KERNEL); - if (NULL == dev) + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) return -ENOMEM; /* pci init */ @@ -1300,7 +1297,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, goto fail_free; } core = cx88_core_get(dev->pci); - if (NULL == core) { + if (core == NULL) { err = -EINVAL; goto fail_free; } @@ -1315,7 +1312,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, (unsigned long long)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); - err = pci_set_dma_mask(pci_dev,DMA_BIT_MASK(32)); + err = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); if (err) { pr_err("Oops: no 32bit PCI DMA ???\n"); goto fail_core; @@ -1524,7 +1521,7 @@ fail_unreg: mutex_unlock(&core->lock); fail_core: core->v4ldev = NULL; - cx88_core_put(core,dev->pci); + cx88_core_put(core, dev->pci); fail_free: kfree(dev); return err; @@ -1555,7 +1552,7 @@ static void cx8800_finidev(struct pci_dev *pci_dev) core->v4ldev = NULL; /* free memory */ - cx88_core_put(core,dev->pci); + cx88_core_put(core, dev->pci); kfree(dev); } @@ -1584,7 +1581,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) cx88_shutdown(core); pci_save_state(pci_dev); - if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) { + if (pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)) != 0) { pci_disable_device(pci_dev); dev->state.disabled = 1; } @@ -1599,7 +1596,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) int err; if (dev->state.disabled) { - err=pci_enable_device(pci_dev); + err = pci_enable_device(pci_dev); if (err) { pr_err("can't enable device\n"); return err; @@ -1607,7 +1604,7 @@ static int cx8800_resume(struct pci_dev *pci_dev) dev->state.disabled = 0; } - err= pci_set_power_state(pci_dev, PCI_D0); + err = pci_set_power_state(pci_dev, PCI_D0); if (err) { pr_err("can't set power state\n"); pci_disable_device(pci_dev); @@ -1628,11 +1625,11 @@ static int cx8800_resume(struct pci_dev *pci_dev) spin_lock_irqsave(&dev->slock, flags); if (!list_empty(&dev->vidq.active)) { pr_info("resume video\n"); - restart_video_queue(dev,&dev->vidq); + restart_video_queue(dev, &dev->vidq); } if (!list_empty(&dev->vbiq.active)) { pr_info("resume vbi\n"); - cx8800_restart_vbi_queue(dev,&dev->vbiq); + cx8800_restart_vbi_queue(dev, &dev->vbiq); } spin_unlock_irqrestore(&dev->slock, flags); @@ -1648,7 +1645,7 @@ static const struct pci_device_id cx8800_pci_tbl[] = { .device = 0x8800, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, - },{ + }, { /* --- end of list --- */ } }; diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.c b/drivers/media/pci/cx88/cx88-vp3054-i2c.c index 4f47ea2ae344..eea56ae9071e 100644 --- a/drivers/media/pci/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.c @@ -1,26 +1,20 @@ /* - - cx88-vp3054-i2c.c -- support for the secondary I2C bus of the - DNTV Live! DVB-T Pro (VP-3054), wired as: - GPIO[0] -> SCL, GPIO[1] -> SDA - - (c) 2005 Chris Pascoe - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * cx88-vp3054-i2c.c -- support for the secondary I2C bus of the + * DNTV Live! DVB-T Pro (VP-3054), wired as: + * GPIO[0] -> SCL, GPIO[1] -> SDA + * + * (c) 2005 Chris Pascoe + * + * 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 "cx88.h" #include "cx88-vp3054-i2c.h" @@ -128,11 +122,11 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) i2c_set_adapdata(&vp3054_i2c->adap, dev); vp3054_i2c->adap.algo_data = &vp3054_i2c->algo; - vp3054_bit_setscl(dev,1); - vp3054_bit_setsda(dev,1); + vp3054_bit_setscl(dev, 1); + vp3054_bit_setsda(dev, 1); rc = i2c_bit_add_bus(&vp3054_i2c->adap); - if (0 != rc) { + if (rc != 0) { pr_err("vp3054_i2c register FAILED\n"); kfree(dev->vp3054); diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index 01c1287baf93..ac1fb9fb340e 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -13,10 +13,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef CX88_H @@ -58,7 +54,7 @@ /* defines and enums */ /* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM/LC */ -#define CX88_NORMS (V4L2_STD_ALL \ +#define CX88_NORMS (V4L2_STD_ALL \ & ~V4L2_STD_PAL_H \ & ~V4L2_STD_NTSC_M_KR \ & ~V4L2_STD_SECAM_LC) @@ -366,12 +362,12 @@ struct cx88_core { u32 i2c_state, i2c_rc; /* config info -- analog */ - struct v4l2_device v4l2_dev; + struct v4l2_device v4l2_dev; struct v4l2_ctrl_handler video_hdl; struct v4l2_ctrl *chroma_agc; struct v4l2_ctrl_handler audio_hdl; struct v4l2_subdev *sd_wm8775; - struct i2c_client *i2c_rtc; + struct i2c_client *i2c_rtc; unsigned int boardnr; struct cx88_board board; @@ -388,8 +384,8 @@ struct cx88_core { /* state info */ struct task_struct *kthread; v4l2_std_id tvnorm; - unsigned width, height; - unsigned field; + unsigned int width, height; + unsigned int field; enum cx88_tvaudio tvaudio; u32 audiomode_manual; u32 audiomode_current; @@ -489,7 +485,7 @@ struct cx8800_dev { /* pci i/o */ struct pci_dev *pci; - unsigned char pci_rev,pci_lat; + unsigned char pci_rev, pci_lat; const struct cx8800_fmt *fmt; @@ -552,7 +548,7 @@ struct cx8802_dev { /* pci i/o */ struct pci_dev *pci; - unsigned char pci_rev,pci_lat; + unsigned char pci_rev, pci_lat; /* dma queues */ struct cx88_dmaqueue mpegq; @@ -594,23 +590,23 @@ struct cx8802_dev { /* ----------------------------------------------------------- */ #define cx_read(reg) readl(core->lmmio + ((reg)>>2)) -#define cx_write(reg,value) writel((value), core->lmmio + ((reg)>>2)) -#define cx_writeb(reg,value) writeb((value), core->bmmio + (reg)) +#define cx_write(reg, value) writel((value), core->lmmio + ((reg)>>2)) +#define cx_writeb(reg, value) writeb((value), core->bmmio + (reg)) -#define cx_andor(reg,mask,value) \ +#define cx_andor(reg, mask, value) \ writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\ ((value) & (mask)), core->lmmio+((reg)>>2)) -#define cx_set(reg,bit) cx_andor((reg),(bit),(bit)) -#define cx_clear(reg,bit) cx_andor((reg),(bit),0) +#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) +#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) #define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); } /* shadow registers */ #define cx_sread(sreg) (core->shadow[sreg]) -#define cx_swrite(sreg,reg,value) \ +#define cx_swrite(sreg, reg, value) \ (core->shadow[sreg] = value, \ writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) -#define cx_sandor(sreg,reg,mask,value) \ +#define cx_sandor(sreg, reg, mask, value) \ (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \ writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) @@ -667,7 +663,7 @@ extern int cx88_stop_audio_dma(struct cx88_core *core); /* cx88-vbi.c */ /* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */ -int cx8800_vbi_fmt (struct file *file, void *priv, +int cx8800_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f); /* @@ -708,7 +704,8 @@ int cx8802_register_driver(struct cx8802_driver *drv); int cx8802_unregister_driver(struct cx8802_driver *drv); /* Caller must hold core->lock */ -struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); +struct cx8802_driver *cx8802_get_driver(struct cx8802_dev *dev, + enum cx88_board_type btype); /* ----------------------------------------------------------- */ /* cx88-dsp.c */ -- cgit v1.2.3 From 7c66e12136c2fa421ae75497e02728f252108a1b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:14:37 -0300 Subject: [media] pluto2: use KERN_CONT where needed Some continuation messages are not using KERN_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/pluto2/pluto2.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/pluto2/pluto2.c b/drivers/media/pci/pluto2/pluto2.c index 655d6854a8d7..65afb71ff79f 100644 --- a/drivers/media/pci/pluto2/pluto2.c +++ b/drivers/media/pci/pluto2/pluto2.c @@ -577,12 +577,12 @@ static int pluto_read_serial(struct pluto *pluto) for (j = 0; j < 32; j += 8) { if ((val & 0xff) == 0xff) goto out; - printk("%c", val & 0xff); + printk(KERN_CONT "%c", val & 0xff); val >>= 8; } } out: - printk("\n"); + printk(KERN_CONT "\n"); pci_iounmap(pdev, cis); return 0; -- cgit v1.2.3 From 623b2f4a67f9539b1c9fef0fa4e118c5349a2753 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:27:36 -0300 Subject: [media] zoran: use KERN_CONT where needed Some continuation messages are not using KERN_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/zoran/zoran_device.c | 35 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/zoran/zoran_device.c b/drivers/media/pci/zoran/zoran_device.c index 4d47ddac97dc..35b552c178da 100644 --- a/drivers/media/pci/zoran/zoran_device.c +++ b/drivers/media/pci/zoran/zoran_device.c @@ -173,12 +173,8 @@ dump_guests (struct zoran *zr) guest[i] = post_office_read(zr, i, 0); } - printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr)); - - for (i = 1; i < 8; i++) { - printk(" 0x%02x", guest[i]); - } - printk("\n"); + printk(KERN_INFO "%s: Guests: %*ph\n", + ZR_DEVNAME(zr), 8, guest); } } @@ -216,12 +212,9 @@ detect_guest_activity (struct zoran *zr) if (j >= 8) break; } - printk(KERN_INFO "%s: Guests:", ZR_DEVNAME(zr)); - for (i = 1; i < 8; i++) { - printk(" 0x%02x", guest0[i]); - } - printk("\n"); + printk(KERN_INFO "%s: Guests: %*ph\n", ZR_DEVNAME(zr), 8, guest0); + if (j == 0) { printk(KERN_INFO "%s: No activity detected.\n", ZR_DEVNAME(zr)); return; @@ -822,39 +815,39 @@ print_interrupts (struct zoran *zr) printk(KERN_INFO "%s: interrupts received:", ZR_DEVNAME(zr)); if ((res = zr->field_counter) < -1 || res > 1) { - printk(" FD:%d", res); + printk(KERN_CONT " FD:%d", res); } if ((res = zr->intr_counter_GIRQ1) != 0) { - printk(" GIRQ1:%d", res); + printk(KERN_CONT " GIRQ1:%d", res); noerr++; } if ((res = zr->intr_counter_GIRQ0) != 0) { - printk(" GIRQ0:%d", res); + printk(KERN_CONT " GIRQ0:%d", res); noerr++; } if ((res = zr->intr_counter_CodRepIRQ) != 0) { - printk(" CodRepIRQ:%d", res); + printk(KERN_CONT " CodRepIRQ:%d", res); noerr++; } if ((res = zr->intr_counter_JPEGRepIRQ) != 0) { - printk(" JPEGRepIRQ:%d", res); + printk(KERN_CONT " JPEGRepIRQ:%d", res); noerr++; } if (zr->JPEG_max_missed) { - printk(" JPEG delays: max=%d min=%d", zr->JPEG_max_missed, + printk(KERN_CONT " JPEG delays: max=%d min=%d", zr->JPEG_max_missed, zr->JPEG_min_missed); } if (zr->END_event_missed) { - printk(" ENDs missed: %d", zr->END_event_missed); + printk(KERN_CONT " ENDs missed: %d", zr->END_event_missed); } //if (zr->jpg_queued_num) { - printk(" queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail, + printk(KERN_CONT " queue_state=%ld/%ld/%ld/%ld", zr->jpg_que_tail, zr->jpg_dma_tail, zr->jpg_dma_head, zr->jpg_que_head); //} if (!noerr) { - printk(": no interrupts detected."); + printk(KERN_CONT ": no interrupts detected."); } - printk("\n"); + printk(KERN_CONT "\n"); } void -- cgit v1.2.3 From ac2ac8376eae2c7c7abb90732c967942510410b4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:33:00 -0300 Subject: [media] wl128x: use KERNEL_CONT where needed Some continuation messages are not using KERNEL_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/radio/wl128x/fmdrv_common.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c index 6f254e80ffa6..4be07656fbc0 100644 --- a/drivers/media/radio/wl128x/fmdrv_common.c +++ b/drivers/media/radio/wl128x/fmdrv_common.c @@ -212,14 +212,14 @@ inline void dump_tx_skb_data(struct sk_buff *skb) len_org = skb->len - FM_CMD_MSG_HDR_SIZE; if (len_org > 0) { - printk("\n data(%d): ", cmd_hdr->dlen); + printk(KERN_CONT "\n data(%d): ", cmd_hdr->dlen); len = min(len_org, 14); for (index = 0; index < len; index++) - printk("%x ", + printk(KERN_CONT "%x ", skb->data[FM_CMD_MSG_HDR_SIZE + index]); - printk("%s", (len_org > 14) ? ".." : ""); + printk(KERN_CONT "%s", (len_org > 14) ? ".." : ""); } - printk("\n"); + printk(KERN_CONT "\n"); } /* To dump incoming FM Channel-8 packets */ @@ -237,14 +237,14 @@ inline void dump_rx_skb_data(struct sk_buff *skb) len_org = skb->len - FM_EVT_MSG_HDR_SIZE; if (len_org > 0) { - printk("\n data(%d): ", evt_hdr->dlen); + printk(KERN_CONT "\n data(%d): ", evt_hdr->dlen); len = min(len_org, 14); for (index = 0; index < len; index++) - printk("%x ", + printk(KERN_CONT "%x ", skb->data[FM_EVT_MSG_HDR_SIZE + index]); - printk("%s", (len_org > 14) ? ".." : ""); + printk(KERN_CONT "%s", (len_org > 14) ? ".." : ""); } - printk("\n"); + printk(KERN_CONT "\n"); } #endif -- cgit v1.2.3 From 6dc3a355633b97c03950478563807ab72b18f94b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:39:46 -0300 Subject: [media] pvrusb2: use KERNEL_CONT where needed Some continuation messages are not using KERNEL_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c index 48d837e39a9c..cc63e5f4c26c 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c @@ -491,18 +491,18 @@ static int pvr2_i2c_xfer(struct i2c_adapter *i2c_adap, "read" : "write")); if ((ret > 0) || !(msgs[idx].flags & I2C_M_RD)) { if (cnt > 8) cnt = 8; - printk(" ["); + printk(KERN_CONT " ["); for (offs = 0; offs < (cnt>8?8:cnt); offs++) { - if (offs) printk(" "); - printk("%02x",msgs[idx].buf[offs]); + if (offs) printk(KERN_CONT " "); + printk(KERN_CONT "%02x",msgs[idx].buf[offs]); } - if (offs < cnt) printk(" ..."); - printk("]"); + if (offs < cnt) printk(KERN_CONT " ..."); + printk(KERN_CONT "]"); } if (idx+1 == num) { - printk(" result=%d",ret); + printk(KERN_CONT " result=%d",ret); } - printk("\n"); + printk(KERN_CONT "\n"); } if (!num) { printk(KERN_INFO -- cgit v1.2.3 From 61fc87498bc6a5becd30162e23928168b1e32318 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:44:05 -0300 Subject: [media] ttusb_dec: use KERNEL_CONT where needed Some continuation messages are not using KERNEL_CONT. Since commit 563873318d32 ("Merge branch 'printk-cleanups"), this won't work as expected anymore. So, let's add KERN_CONT to those lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/ttusb-dec/ttusb_dec.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c index 559c823a4fe8..fc0219f1b7df 100644 --- a/drivers/media/usb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c @@ -329,7 +329,7 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, int param_length, const u8 params[], int *result_length, u8 cmd_result[]) { - int result, actual_len, i; + int result, actual_len; u8 *b; dprintk("%s\n", __func__); @@ -353,10 +353,8 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, memcpy(&b[4], params, param_length); if (debug) { - printk("%s: command: ", __func__); - for (i = 0; i < param_length + 4; i++) - printk("0x%02X ", b[i]); - printk("\n"); + printk(KERN_DEBUG "%s: command: %*ph\n", + __func__, param_length, b); } result = usb_bulk_msg(dec->udev, dec->command_pipe, b, @@ -381,10 +379,8 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, return result; } else { if (debug) { - printk("%s: result: ", __func__); - for (i = 0; i < actual_len; i++) - printk("0x%02X ", b[i]); - printk("\n"); + printk(KERN_DEBUG "%s: result: %*ph\n", + __func__, actual_len, b); } if (result_length) -- cgit v1.2.3 From a80e1d965cb9a77f20a493021e816761f8785faf Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 07:58:43 -0300 Subject: [media] ttpci: cleanup debug macros and remove dead code Continuation lines without KERN_CONT won't work anymore. However, the way dprintk() was defined leads to the usage of continuation lines, with should be avoided when possible. So, redefine those macros. While hre, remove some dead code at av7110.c with also relies on continuation lines. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/ttpci/av7110.c | 15 --------------- drivers/media/pci/ttpci/av7110.h | 7 +++++-- drivers/media/pci/ttpci/budget.h | 8 ++++++-- 3 files changed, 11 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c index 37e7e6684e3c..6e63949d6ad0 100644 --- a/drivers/media/pci/ttpci/av7110.c +++ b/drivers/media/pci/ttpci/av7110.c @@ -443,21 +443,6 @@ static void debiirq(unsigned long cookie) case DATA_COMMON_INTERFACE: CI_handle(av7110, (u8 *)av7110->debi_virt, av7110->debilen); -#if 0 - { - int i; - - printk("av7110%d: ", av7110->num); - printk("%02x ", *(u8 *)av7110->debi_virt); - printk("%02x ", *(1+(u8 *)av7110->debi_virt)); - for (i = 2; i < av7110->debilen; i++) - printk("%02x ", (*(i+(unsigned char *)av7110->debi_virt))); - for (i = 2; i < av7110->debilen; i++) - printk("%c", chtrans(*(i+(unsigned char *)av7110->debi_virt))); - - printk("\n"); - } -#endif xfer = RX_BUFF; break; diff --git a/drivers/media/pci/ttpci/av7110.h b/drivers/media/pci/ttpci/av7110.h index 3707ccd02732..824c1e262fbb 100644 --- a/drivers/media/pci/ttpci/av7110.h +++ b/drivers/media/pci/ttpci/av7110.h @@ -40,8 +40,11 @@ extern int av7110_debug; -#define dprintk(level,args...) \ - do { if ((av7110_debug & level)) { printk("dvb-ttpci: %s(): ", __func__); printk(args); } } while (0) +#define dprintk(level, fmt, arg...) do { \ + if (level & av7110_debug) \ + printk(KERN_DEBUG KBUILD_MODNAME ": %s(): " fmt, \ + __func__, ##arg); \ +} while (0) #define MAXFILT 32 diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h index 655eef5236ca..d5ae4438153e 100644 --- a/drivers/media/pci/ttpci/budget.h +++ b/drivers/media/pci/ttpci/budget.h @@ -21,8 +21,12 @@ extern int budget_debug; #undef dprintk #endif -#define dprintk(level,args...) \ - do { if ((budget_debug & level)) { printk("%s: %s(): ", KBUILD_MODNAME, __func__); printk(args); } } while (0) +#define dprintk(level, fmt, arg...) do { \ + if (level & budget_debug) \ + printk(KERN_DEBUG KBUILD_MODNAME ": %s(): " fmt, \ + __func__, ##arg); \ +} while (0) + struct budget_info { char *name; -- cgit v1.2.3 From 5cd4f5cec2374d2c09299211d2b357cc160e49a0 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Sun, 30 Oct 2016 20:35:57 +0100 Subject: cxl: Fix memory allocation failure test 'cxl_context_alloc()' does not return an error pointer. It is just a shortcut for a call to 'kzalloc' with 'sizeof(struct cxl_context)' as the size parameter. So its return value should be compared with NULL. While fixing it, simplify a bit the code. Signed-off-by: Christophe JAILLET Reviewed-by: Andrew Donnellan Acked-by: Frederic Barrat Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 2e5233b60971..2b88ad8a2a89 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -30,10 +30,8 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) return ERR_CAST(afu); ctx = cxl_context_alloc(); - if (IS_ERR(ctx)) { - rc = PTR_ERR(ctx); - goto err_dev; - } + if (!ctx) + return ERR_PTR(-ENOMEM); ctx->kernelapi = true; @@ -61,7 +59,6 @@ err_mapping: kfree(mapping); err_ctx: kfree(ctx); -err_dev: return ERR_PTR(rc); } EXPORT_SYMBOL_GPL(cxl_dev_context_init); -- cgit v1.2.3 From 28e323e5a0b21b3665eb6e136ca8bbce10fd29d7 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Sun, 30 Oct 2016 22:34:51 +0100 Subject: cxl: Fix error handling in _cxl_cx4_setup_msi_irqs() 'cxl_dev_context_init()' returns an error pointer in case of error, not NULL. So test it with IS_ERR. Signed-off-by: Christophe JAILLET Reviewed-by: Andrew Donnellan Acked-by: Frederic Barrat Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index 2b88ad8a2a89..e2efc6489c6e 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -538,7 +538,7 @@ int _cxl_cx4_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type) if (remaining > 0) { new_ctx = cxl_dev_context_init(pdev); - if (!new_ctx) { + if (IS_ERR(new_ctx)) { pr_warn("%s: Failed to allocate enough contexts for MSIs\n", pci_name(pdev)); return -ENOSPC; } -- cgit v1.2.3 From bb81733de28c99e10b61dcaff1592142abe53442 Mon Sep 17 00:00:00 2001 From: Christophe Jaillet Date: Sun, 30 Oct 2016 22:40:47 +0100 Subject: cxl: Fix error handling in _cxl_pci_associate_default_context() 'cxl_dev_context_init()' returns an error pointer in case of error, not NULL. So test it with IS_ERR. Signed-off-by: Christophe JAILLET Reviewed-by: Andrew Donnellan Acked-by: Frederic Barrat Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/pci.c | 2 +- drivers/misc/cxl/phb.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c index e96be9ca4e60..80a87ab25b83 100644 --- a/drivers/misc/cxl/pci.c +++ b/drivers/misc/cxl/pci.c @@ -1921,7 +1921,7 @@ static pci_ers_result_t cxl_pci_slot_reset(struct pci_dev *pdev) goto err; ctx = cxl_dev_context_init(afu_dev); - if (!ctx) + if (IS_ERR(ctx)) goto err; afu_dev->dev.archdata.cxl_ctx = ctx; diff --git a/drivers/misc/cxl/phb.c b/drivers/misc/cxl/phb.c index 0935d44c1770..6ec69ada19f4 100644 --- a/drivers/misc/cxl/phb.c +++ b/drivers/misc/cxl/phb.c @@ -20,7 +20,7 @@ bool _cxl_pci_associate_default_context(struct pci_dev *dev, struct cxl_afu *afu * in the virtual phb, we'll need a default context to attach them to. */ ctx = cxl_dev_context_init(dev); - if (!ctx) + if (IS_ERR(ctx)) return false; dev->dev.archdata.cxl_ctx = ctx; -- cgit v1.2.3 From abf051be684be768c1ee079514f4d07de9389d54 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Wed, 16 Nov 2016 19:39:33 +0530 Subject: cxl: Do adapter fence check before handling afu interrupt If an afu interrupt is in flight when an eeh error is triggered the control still reaches the function native_irq_multiplexed and the PE-Handle read from the CXL_PSL_PEHandle_An register is 0xffff. The function then erroneously assumes that the interrupt belonged to a detached context and generates a warning with full stack dump in the kernel log complaining: "Unable to demultiplex CXL PSL IRQ for PE 65535 DSISR ffffffff DAR ffffffff. (Possible AFU HW issue - was a term/remove acked with outstanding transactions" To fix this the patch adds new code to the function native_irq_multiplexed function to compares the read value of register CXL_PSL_PEHandle_An to ~0ULL. If true then logs a warning message saying that the interrupt is being ignored and returns IRQ_HANDLED from the irq handler. Reviewed-by: Andrew Donnellan Acked-by: Frederic Barrat Acked-by: Ian Munsie Signed-off-by: Vaibhav Jain Signed-off-by: Michael Ellerman --- drivers/misc/cxl/native.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index a217a74ccc98..c336350ede94 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -931,9 +931,18 @@ static irqreturn_t native_irq_multiplexed(int irq, void *data) struct cxl_afu *afu = data; struct cxl_context *ctx; struct cxl_irq_info irq_info; - int ph = cxl_p2n_read(afu, CXL_PSL_PEHandle_An) & 0xffff; - int ret; - + u64 phreg = cxl_p2n_read(afu, CXL_PSL_PEHandle_An); + int ph, ret; + + /* check if eeh kicked in while the interrupt was in flight */ + if (unlikely(phreg == ~0ULL)) { + dev_warn(&afu->dev, + "Ignoring slice interrupt(%d) due to fenced card", + irq); + return IRQ_HANDLED; + } + /* Mask the pe-handle from register value */ + ph = phreg & 0xffff; if ((ret = native_get_irq_info(afu, &irq_info))) { WARN(1, "Unable to get CXL IRQ Info: %i\n", ret); return fail_psl_irq(afu, &irq_info); -- cgit v1.2.3 From fb11cbd1a9b84ee008c759a6075717f9273a2b3c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 08:10:15 -0300 Subject: [media] dib0070: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups"). So, instead of directly calling printk(), use pr_foo() macros, adding a \n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib0070.c | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c index ee7d66997ccd..016ad09a8754 100644 --- a/drivers/media/dvb-frontends/dib0070.c +++ b/drivers/media/dvb-frontends/dib0070.c @@ -24,6 +24,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -38,12 +40,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { \ - if (debug) { \ - printk(KERN_DEBUG "DiB0070: "); \ - printk(args); \ - printk("\n"); \ - } \ +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ } while (0) #define DIB0070_P1D 0x00 @@ -87,7 +87,7 @@ static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg) u16 ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -104,7 +104,7 @@ static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg) state->msg[1].len = 2; if (i2c_transfer(state->i2c, state->msg, 2) != 2) { - printk(KERN_WARNING "DiB0070 I2C read failed\n"); + pr_warn("DiB0070 I2C read failed\n"); ret = 0; } else ret = (state->i2c_read_buffer[0] << 8) @@ -119,7 +119,7 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) int ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } state->i2c_write_buffer[0] = reg; @@ -133,7 +133,7 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) state->msg[0].len = 3; if (i2c_transfer(state->i2c, state->msg, 1) != 1) { - printk(KERN_WARNING "DiB0070 I2C write failed\n"); + pr_warn("DiB0070 I2C write failed\n"); ret = -EREMOTEIO; } else ret = 0; @@ -205,7 +205,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state adc = dib0070_read_reg(state, 0x19); - dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024); + dprintk("CAPTRIM=%hd; ADC = %hd (ADC) & %dmV\n", state->captrim, adc, (u32) adc*(u32)1800/(u32)1024); if (adc >= 400) { adc -= 400; @@ -216,7 +216,7 @@ static int dib0070_captrim(struct dib0070_state *state, enum frontend_tune_state } if (adc < state->adc_diff) { - dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)", state->captrim, adc, state->adc_diff); + dprintk("CAPTRIM=%hd is closer to target (%hd/%hd)\n", state->captrim, adc, state->adc_diff); state->adc_diff = adc; state->fcaptrim = state->captrim; } @@ -241,7 +241,7 @@ static int dib0070_set_ctrl_lo5(struct dvb_frontend *fe, u8 vco_bias_trim, u8 hf struct dib0070_state *state = fe->tuner_priv; u16 lo5 = (third_order_filt << 14) | (0 << 13) | (1 << 12) | (3 << 9) | (cp_current << 6) | (hf_div_trim << 3) | (vco_bias_trim << 0); - dprintk("CTRL_LO5: 0x%x", lo5); + dprintk("CTRL_LO5: 0x%x\n", lo5); return dib0070_write_reg(state, 0x15, lo5); } @@ -256,7 +256,7 @@ void dib0070_ctrl_agc_filter(struct dvb_frontend *fe, u8 open) dib0070_write_reg(state, 0x1b, 0x4112); if (state->cfg->vga_filter != 0) { dib0070_write_reg(state, 0x1a, state->cfg->vga_filter); - dprintk("vga filter register is set to %x", state->cfg->vga_filter); + dprintk("vga filter register is set to %x\n", state->cfg->vga_filter); } else dib0070_write_reg(state, 0x1a, 0x0009); } @@ -380,7 +380,7 @@ static int dib0070_tune_digital(struct dvb_frontend *fe) } if (*tune_state == CT_TUNER_START) { - dprintk("Tuning for Band: %hd (%d kHz)", band, freq); + dprintk("Tuning for Band: %hd (%d kHz)\n", band, freq); if (state->current_rf != freq) { u8 REFDIV; u32 FBDiv, Rest, FREF, VCOF_kHz; @@ -458,12 +458,12 @@ static int dib0070_tune_digital(struct dvb_frontend *fe) dib0070_write_reg(state, 0x20, 0x0040 | 0x0020 | 0x0010 | 0x0008 | 0x0002 | 0x0001 | state->current_tune_table_index->tuner_enable); - dprintk("REFDIV: %hd, FREF: %d", REFDIV, FREF); - dprintk("FBDIV: %d, Rest: %d", FBDiv, Rest); - dprintk("Num: %hd, Den: %hd, SD: %hd", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); - dprintk("HFDIV code: %hd", state->current_tune_table_index->hfdiv); - dprintk("VCO = %hd", state->current_tune_table_index->vco_band); - dprintk("VCOF: ((%hd*%d) << 1))", state->current_tune_table_index->vco_multi, freq); + dprintk("REFDIV: %hd, FREF: %d\n", REFDIV, FREF); + dprintk("FBDIV: %d, Rest: %d\n", FBDiv, Rest); + dprintk("Num: %hd, Den: %hd, SD: %hd\n", (u16) Rest, Den, (state->lo4 >> 12) & 0x1); + dprintk("HFDIV code: %hd\n", state->current_tune_table_index->hfdiv); + dprintk("VCO = %hd\n", state->current_tune_table_index->vco_band); + dprintk("VCOF: ((%hd*%d) << 1))\n", state->current_tune_table_index->vco_multi, freq); *tune_state = CT_TUNER_STEP_0; } else { /* we are already tuned to this frequency - the configuration is correct */ @@ -625,7 +625,7 @@ static void dib0070_wbd_offset_calibration(struct dib0070_state *state) u8 gain; for (gain = 6; gain < 8; gain++) { state->wbd_offset_3_3[gain - 6] = ((dib0070_read_wbd_offset(state, gain) * 8 * 18 / 33 + 1) / 2); - dprintk("Gain: %d, WBDOffset (3.3V) = %hd", gain, state->wbd_offset_3_3[gain-6]); + dprintk("Gain: %d, WBDOffset (3.3V) = %hd\n", gain, state->wbd_offset_3_3[gain-6]); } } @@ -665,10 +665,10 @@ static int dib0070_reset(struct dvb_frontend *fe) state->revision = DIB0070S_P1A; /* P1F or not */ - dprintk("Revision: %x", state->revision); + dprintk("Revision: %x\n", state->revision); if (state->revision == DIB0070_P1D) { - dprintk("Error: this driver is not to be used meant for P1D or earlier"); + dprintk("Error: this driver is not to be used meant for P1D or earlier\n"); return -EINVAL; } @@ -761,7 +761,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter if (dib0070_reset(fe) != 0) goto free_mem; - printk(KERN_INFO "DiB0070: successfully identified\n"); + pr_info("DiB0070: successfully identified\n"); memcpy(&fe->ops.tuner_ops, &dib0070_ops, sizeof(struct dvb_tuner_ops)); fe->tuner_priv = state; -- cgit v1.2.3 From 4bd1a8ddadfbfaea1cb4b5f9fc7004958a043f45 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 08:16:43 -0300 Subject: [media] dib0090: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups"). So, instead of directly calling printk(), use pr_foo() macros, adding a \n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib0090.c | 162 +++++++++++++++++----------------- 1 file changed, 82 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 14c403254fe0..16200582f089 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -24,6 +24,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -38,12 +40,10 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { \ - if (debug) { \ - printk(KERN_DEBUG "DiB0090: "); \ - printk(args); \ - printk("\n"); \ - } \ +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ } while (0) #define CONFIG_SYS_DVBT @@ -218,7 +218,7 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) u16 ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -235,7 +235,7 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) state->msg[1].len = 2; if (i2c_transfer(state->i2c, state->msg, 2) != 2) { - printk(KERN_WARNING "DiB0090 I2C read failed\n"); + pr_warn("DiB0090 I2C read failed\n"); ret = 0; } else ret = (state->i2c_read_buffer[0] << 8) @@ -250,7 +250,7 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) int ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -265,7 +265,7 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) state->msg[0].len = 3; if (i2c_transfer(state->i2c, state->msg, 1) != 1) { - printk(KERN_WARNING "DiB0090 I2C write failed\n"); + pr_warn("DiB0090 I2C write failed\n"); ret = -EREMOTEIO; } else ret = 0; @@ -279,7 +279,7 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) u16 ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -291,7 +291,7 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) state->msg.buf = state->i2c_read_buffer; state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { - printk(KERN_WARNING "DiB0090 I2C read failed\n"); + pr_warn("DiB0090 I2C read failed\n"); ret = 0; } else ret = (state->i2c_read_buffer[0] << 8) @@ -306,7 +306,7 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) int ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -319,7 +319,7 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) state->msg.buf = state->i2c_write_buffer; state->msg.len = 2; if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { - printk(KERN_WARNING "DiB0090 I2C write failed\n"); + pr_warn("DiB0090 I2C write failed\n"); ret = -EREMOTEIO; } else ret = 0; @@ -351,7 +351,7 @@ static int dib0090_identify(struct dvb_frontend *fe) identity->p1g = 0; identity->in_soc = 0; - dprintk("Tuner identification (Version = 0x%04x)", v); + dprintk("Tuner identification (Version = 0x%04x)\n", v); /* without PLL lock info */ v &= ~KROSUS_PLL_LOCKED; @@ -366,19 +366,19 @@ static int dib0090_identify(struct dvb_frontend *fe) identity->in_soc = 1; switch (identity->version) { case SOC_8090_P1G_11R1: - dprintk("SOC 8090 P1-G11R1 Has been detected"); + dprintk("SOC 8090 P1-G11R1 Has been detected\n"); identity->p1g = 1; break; case SOC_8090_P1G_21R1: - dprintk("SOC 8090 P1-G21R1 Has been detected"); + dprintk("SOC 8090 P1-G21R1 Has been detected\n"); identity->p1g = 1; break; case SOC_7090_P1G_11R1: - dprintk("SOC 7090 P1-G11R1 Has been detected"); + dprintk("SOC 7090 P1-G11R1 Has been detected\n"); identity->p1g = 1; break; case SOC_7090_P1G_21R1: - dprintk("SOC 7090 P1-G21R1 Has been detected"); + dprintk("SOC 7090 P1-G21R1 Has been detected\n"); identity->p1g = 1; break; default: @@ -387,16 +387,16 @@ static int dib0090_identify(struct dvb_frontend *fe) } else { switch ((identity->version >> 5) & 0x7) { case MP001: - dprintk("MP001 : 9090/8096"); + dprintk("MP001 : 9090/8096\n"); break; case MP005: - dprintk("MP005 : Single Sband"); + dprintk("MP005 : Single Sband\n"); break; case MP008: - dprintk("MP008 : diversity VHF-UHF-LBAND"); + dprintk("MP008 : diversity VHF-UHF-LBAND\n"); break; case MP009: - dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); + dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND\n"); break; default: goto identification_error; @@ -404,21 +404,21 @@ static int dib0090_identify(struct dvb_frontend *fe) switch (identity->version & 0x1f) { case P1G_21R2: - dprintk("P1G_21R2 detected"); + dprintk("P1G_21R2 detected\n"); identity->p1g = 1; break; case P1G: - dprintk("P1G detected"); + dprintk("P1G detected\n"); identity->p1g = 1; break; case P1D_E_F: - dprintk("P1D/E/F detected"); + dprintk("P1D/E/F detected\n"); break; case P1C: - dprintk("P1C detected"); + dprintk("P1C detected\n"); break; case P1A_B: - dprintk("P1-A/B detected: driver is deactivated - not available"); + dprintk("P1-A/B detected: driver is deactivated - not available\n"); goto identification_error; break; default: @@ -441,7 +441,7 @@ static int dib0090_fw_identify(struct dvb_frontend *fe) identity->p1g = 0; identity->in_soc = 0; - dprintk("FE: Tuner identification (Version = 0x%04x)", v); + dprintk("FE: Tuner identification (Version = 0x%04x)\n", v); /* without PLL lock info */ v &= ~KROSUS_PLL_LOCKED; @@ -456,19 +456,19 @@ static int dib0090_fw_identify(struct dvb_frontend *fe) identity->in_soc = 1; switch (identity->version) { case SOC_8090_P1G_11R1: - dprintk("SOC 8090 P1-G11R1 Has been detected"); + dprintk("SOC 8090 P1-G11R1 Has been detected\n"); identity->p1g = 1; break; case SOC_8090_P1G_21R1: - dprintk("SOC 8090 P1-G21R1 Has been detected"); + dprintk("SOC 8090 P1-G21R1 Has been detected\n"); identity->p1g = 1; break; case SOC_7090_P1G_11R1: - dprintk("SOC 7090 P1-G11R1 Has been detected"); + dprintk("SOC 7090 P1-G11R1 Has been detected\n"); identity->p1g = 1; break; case SOC_7090_P1G_21R1: - dprintk("SOC 7090 P1-G21R1 Has been detected"); + dprintk("SOC 7090 P1-G21R1 Has been detected\n"); identity->p1g = 1; break; default: @@ -477,16 +477,16 @@ static int dib0090_fw_identify(struct dvb_frontend *fe) } else { switch ((identity->version >> 5) & 0x7) { case MP001: - dprintk("MP001 : 9090/8096"); + dprintk("MP001 : 9090/8096\n"); break; case MP005: - dprintk("MP005 : Single Sband"); + dprintk("MP005 : Single Sband\n"); break; case MP008: - dprintk("MP008 : diversity VHF-UHF-LBAND"); + dprintk("MP008 : diversity VHF-UHF-LBAND\n"); break; case MP009: - dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND"); + dprintk("MP009 : diversity 29098 CBAND-UHF-LBAND-SBAND\n"); break; default: goto identification_error; @@ -494,21 +494,21 @@ static int dib0090_fw_identify(struct dvb_frontend *fe) switch (identity->version & 0x1f) { case P1G_21R2: - dprintk("P1G_21R2 detected"); + dprintk("P1G_21R2 detected\n"); identity->p1g = 1; break; case P1G: - dprintk("P1G detected"); + dprintk("P1G detected\n"); identity->p1g = 1; break; case P1D_E_F: - dprintk("P1D/E/F detected"); + dprintk("P1D/E/F detected\n"); break; case P1C: - dprintk("P1C detected"); + dprintk("P1C detected\n"); break; case P1A_B: - dprintk("P1-A/B detected: driver is deactivated - not available"); + dprintk("P1-A/B detected: driver is deactivated - not available\n"); goto identification_error; break; default: @@ -574,7 +574,7 @@ static void dib0090_reset_digital(struct dvb_frontend *fe, const struct dib0090_ } while (--i); if (i == 0) { - dprintk("Pll: Unable to lock Pll"); + dprintk("Pll: Unable to lock Pll\n"); return; } @@ -596,7 +596,7 @@ static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib009 u16 v; int i; - dprintk("fw reset digital"); + dprintk("fw reset digital\n"); HARD_RESET(state); dib0090_fw_write_reg(state, 0x24, EN_PLL | EN_CRYSTAL); @@ -645,7 +645,7 @@ static int dib0090_fw_reset_digital(struct dvb_frontend *fe, const struct dib009 } while (--i); if (i == 0) { - dprintk("Pll: Unable to lock Pll"); + dprintk("Pll: Unable to lock Pll\n"); return -EIO; } @@ -922,7 +922,7 @@ static void dib0090_wbd_target(struct dib0090_state *state, u32 rf) #endif state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + offset); - dprintk("wbd-target: %d dB", (u32) state->wbd_target); + dprintk("wbd-target: %d dB\n", (u32) state->wbd_target); } static const int gain_reg_addr[4] = { @@ -1019,7 +1019,7 @@ static void dib0090_gain_apply(struct dib0090_state *state, s16 gain_delta, s16 gain_reg[3] |= ((bb % 10) * 100) / 125; #ifdef DEBUG_AGC - dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x", rf, bb, rf + bb, + dprintk("GA CALC: DB: %3d(rf) + %3d(bb) = %3d gain_reg[0]=%04x gain_reg[1]=%04x gain_reg[2]=%04x gain_reg[0]=%04x\n", rf, bb, rf + bb, gain_reg[0], gain_reg[1], gain_reg[2], gain_reg[3]); #endif @@ -1050,7 +1050,7 @@ static void dib0090_set_rframp_pwm(struct dib0090_state *state, const u16 * cfg) dib0090_write_reg(state, 0x2a, 0xffff); - dprintk("total RF gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); + dprintk("total RF gain: %ddB, step: %d\n", (u32) cfg[0], dib0090_read_reg(state, 0x2a)); dib0090_write_regs(state, 0x2c, cfg + 3, 6); dib0090_write_regs(state, 0x3e, cfg + 9, 2); @@ -1069,7 +1069,7 @@ static void dib0090_set_bbramp_pwm(struct dib0090_state *state, const u16 * cfg) dib0090_set_boost(state, cfg[0] > 500); /* we want the boost if the gain is higher that 50dB */ dib0090_write_reg(state, 0x33, 0xffff); - dprintk("total BB gain: %ddB, step: %d", (u32) cfg[0], dib0090_read_reg(state, 0x33)); + dprintk("total BB gain: %ddB, step: %d\n", (u32) cfg[0], dib0090_read_reg(state, 0x33)); dib0090_write_regs(state, 0x35, cfg + 3, 4); } @@ -1122,7 +1122,7 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) /* activate the ramp generator using PWM control */ if (state->rf_ramp) - dprintk("ramp RF gain = %d BAND = %s version = %d", + dprintk("ramp RF gain = %d BAND = %s version = %d\n", state->rf_ramp[0], (state->current_band == BAND_CBAND) ? "CBAND" : "NOT CBAND", state->identity.version & 0x1f); @@ -1130,10 +1130,10 @@ void dib0090_pwm_gain_reset(struct dvb_frontend *fe) if (rf_ramp && ((state->rf_ramp && state->rf_ramp[0] == 0) || (state->current_band == BAND_CBAND && (state->identity.version & 0x1f) <= P1D_E_F))) { - dprintk("DE-Engage mux for direct gain reg control"); + dprintk("DE-Engage mux for direct gain reg control\n"); en_pwm_rf_mux = 0; } else - dprintk("Engage mux for PWM control"); + dprintk("Engage mux for PWM control\n"); dib0090_write_reg(state, 0x32, (en_pwm_rf_mux << 12) | (en_pwm_rf_mux << 11)); @@ -1352,7 +1352,7 @@ u16 dib0090_get_wbd_target(struct dvb_frontend *fe) while (f_MHz > wbd->max_freq) wbd++; - dprintk("using wbd-table-entry with max freq %d", wbd->max_freq); + dprintk("using wbd-table-entry with max freq %d\n", wbd->max_freq); if (current_temp < 0) current_temp = 0; @@ -1373,8 +1373,8 @@ u16 dib0090_get_wbd_target(struct dvb_frontend *fe) wbd_tcold += ((wbd_thot - wbd_tcold) * current_temp) >> 7; state->wbd_target = dib0090_wbd_to_db(state, state->wbd_offset + wbd_tcold); - dprintk("wbd-target: %d dB", (u32) state->wbd_target); - dprintk("wbd offset applied is %d", wbd_tcold); + dprintk("wbd-target: %d dB\n", (u32) state->wbd_target); + dprintk("wbd offset applied is %d\n", wbd_tcold); return state->wbd_offset + wbd_tcold; } @@ -1415,7 +1415,7 @@ int dib0090_update_rframp_7090(struct dvb_frontend *fe, u8 cfg_sensitivity) if ((!state->identity.p1g) || (!state->identity.in_soc) || ((state->identity.version != SOC_7090_P1G_21R1) && (state->identity.version != SOC_7090_P1G_11R1))) { - dprintk("%s() function can only be used for dib7090P", __func__); + dprintk("%s() function can only be used for dib7090P\n", __func__); return -ENODEV; } @@ -1598,7 +1598,7 @@ static int dib0090_reset(struct dvb_frontend *fe) dib0090_write_reg(state, 0x14, 1); else dib0090_write_reg(state, 0x14, 2); - dprintk("Pll lock : %d", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); + dprintk("Pll lock : %d\n", (dib0090_read_reg(state, 0x1a) >> 11) & 0x1); state->calibrate = DC_CAL | WBD_CAL | TEMP_CAL; /* enable iq-offset-calibration and wbd-calibration when tuning next time */ @@ -1711,7 +1711,8 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front /* fall through */ case CT_TUNER_STEP_0: - dprintk("Start/continue DC calibration for %s path", (state->dc->i == 1) ? "I" : "Q"); + dprintk("Start/continue DC calibration for %s path\n", + (state->dc->i == 1) ? "I" : "Q"); dib0090_write_reg(state, 0x01, state->dc->bb1); dib0090_write_reg(state, 0x07, state->bb7 | (state->dc->i << 7)); @@ -1733,13 +1734,13 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front break; case CT_TUNER_STEP_5: /* found an offset */ - dprintk("adc_diff = %d, current step= %d", (u32) state->adc_diff, state->step); + dprintk("adc_diff = %d, current step= %d\n", (u32) state->adc_diff, state->step); if (state->step == 0 && state->adc_diff < 0) { state->min_adc_diff = -1023; - dprintk("Change of sign of the minimum adc diff"); + dprintk("Change of sign of the minimum adc diff\n"); } - dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d", state->adc_diff, state->min_adc_diff, state->step); + dprintk("adc_diff = %d, min_adc_diff = %d current_step = %d\n", state->adc_diff, state->min_adc_diff, state->step); /* first turn for this frequency */ if (state->step == 0) { @@ -1758,12 +1759,12 @@ static int dib0090_dc_offset_calibration(struct dib0090_state *state, enum front } else { /* the minimum was what we have seen in the step before */ if (ABS(state->adc_diff) > ABS(state->min_adc_diff)) { - dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step", state->adc_diff, state->min_adc_diff); + dprintk("Since adc_diff N = %d > adc_diff step N-1 = %d, Come back one step\n", state->adc_diff, state->min_adc_diff); state->step--; } dib0090_set_trim(state); - dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd", state->dc->addr, state->adc_diff, state->step); + dprintk("BB Offset Cal, BBreg=%hd,Offset=%hd,Value Set=%hd\n", state->dc->addr, state->adc_diff, state->step); state->dc++; if (state->dc->addr == 0) /* done */ @@ -1819,7 +1820,7 @@ static int dib0090_wbd_calibration(struct dib0090_state *state, enum frontend_tu case CT_TUNER_STEP_0: state->wbd_offset = dib0090_get_slow_adc_val(state); - dprintk("WBD calibration offset = %d", state->wbd_offset); + dprintk("WBD calibration offset = %d\n", state->wbd_offset); *tune_state = CT_TUNER_START; /* reset done -> real tuning can now begin */ state->calibrate &= ~WBD_CAL; break; @@ -2064,7 +2065,7 @@ int dib0090_update_tuning_table_7090(struct dvb_frontend *fe, if ((!state->identity.p1g) || (!state->identity.in_soc) || ((state->identity.version != SOC_7090_P1G_21R1) && (state->identity.version != SOC_7090_P1G_11R1))) { - dprintk("%s() function can only be used for dib7090", __func__); + dprintk("%s() function can only be used for dib7090\n", __func__); return -ENODEV; } @@ -2098,7 +2099,8 @@ static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tun force_soft_search = 1; if (*tune_state == CT_TUNER_START) { - dprintk("Start Captrim search : %s", (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO"); + dprintk("Start Captrim search : %s\n", + (force_soft_search == 1) ? "FORCE SOFT SEARCH" : "AUTO"); dib0090_write_reg(state, 0x10, 0x2B1); dib0090_write_reg(state, 0x1e, 0x0032); @@ -2140,13 +2142,13 @@ static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tun dib0090_read_reg(state, 0x40); state->fcaptrim = dib0090_read_reg(state, 0x18) & 0x7F; - dprintk("***Final Captrim= 0x%x", state->fcaptrim); + dprintk("***Final Captrim= 0x%x\n", state->fcaptrim); *tune_state = CT_TUNER_STEP_3; } else { /* MERGE for all krosus before P1G */ adc = dib0090_get_slow_adc_val(state); - dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024); + dprintk("CAPTRIM=%d; ADC = %d (ADC) & %dmV\n", (u32) state->captrim, (u32) adc, (u32) (adc) * (u32) 1800 / (u32) 1024); if (state->rest == 0 || state->identity.in_soc) { /* Just for 8090P SOCS where auto captrim HW bug : TO CHECK IN ACI for SOCS !!! if 400 for 8090p SOC => tune issue !!! */ adc_target = 200; @@ -2162,7 +2164,7 @@ static int dib0090_captrim_search(struct dib0090_state *state, enum frontend_tun } if (adc < state->adc_diff) { - dprintk("CAPTRIM=%d is closer to target (%d/%d)", (u32) state->captrim, (u32) adc, (u32) state->adc_diff); + dprintk("CAPTRIM=%d is closer to target (%d/%d)\n", (u32) state->captrim, (u32) adc, (u32) state->adc_diff); state->adc_diff = adc; state->fcaptrim = state->captrim; } @@ -2216,7 +2218,7 @@ static int dib0090_get_temperature(struct dib0090_state *state, enum frontend_tu val = dib0090_get_slow_adc_val(state); state->temperature = ((s16) ((val - state->adc_diff) * 180) >> 8) + 55; - dprintk("temperature: %d C", state->temperature - 30); + dprintk("temperature: %d C\n", state->temperature - 30); *tune_state = CT_TUNER_STEP_2; break; @@ -2478,13 +2480,13 @@ static int dib0090_tune(struct dvb_frontend *fe) wbd++; dib0090_write_reg(state, 0x1e, 0x07ff); - dprintk("Final Captrim: %d", (u32) state->fcaptrim); - dprintk("HFDIV code: %d", (u32) pll->hfdiv_code); - dprintk("VCO = %d", (u32) pll->vco_band); - dprintk("VCOF in kHz: %d ((%d*%d) << 1))", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request); - dprintk("REFDIV: %d, FREF: %d", (u32) 1, (u32) state->config->io.clock_khz); - dprintk("FBDIV: %d, Rest: %d", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); - dprintk("Num: %d, Den: %d, SD: %d", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8), + dprintk("Final Captrim: %d\n", (u32) state->fcaptrim); + dprintk("HFDIV code: %d\n", (u32) pll->hfdiv_code); + dprintk("VCO = %d\n", (u32) pll->vco_band); + dprintk("VCOF in kHz: %d ((%d*%d) << 1))\n", (u32) ((pll->hfdiv * state->rf_request) * 2), (u32) pll->hfdiv, (u32) state->rf_request); + dprintk("REFDIV: %d, FREF: %d\n", (u32) 1, (u32) state->config->io.clock_khz); + dprintk("FBDIV: %d, Rest: %d\n", (u32) dib0090_read_reg(state, 0x15), (u32) dib0090_read_reg(state, 0x17)); + dprintk("Num: %d, Den: %d, SD: %d\n", (u32) dib0090_read_reg(state, 0x17), (u32) (dib0090_read_reg(state, 0x16) >> 8), (u32) dib0090_read_reg(state, 0x1c) & 0x3); #define WBD 0x781 /* 1 1 1 1 0000 0 0 1 */ @@ -2498,7 +2500,7 @@ static int dib0090_tune(struct dvb_frontend *fe) dib0090_write_reg(state, 0x10, state->wbdmux); if ((tune->tuner_enable == EN_CAB) && state->identity.p1g) { - dprintk("P1G : The cable band is selected and lna_tune = %d", tune->lna_tune); + dprintk("P1G : The cable band is selected and lna_tune = %d\n", tune->lna_tune); dib0090_write_reg(state, 0x09, tune->lna_bias); dib0090_write_reg(state, 0x0b, 0xb800 | (tune->lna_tune << 6) | (tune->switch_trim)); } else @@ -2643,7 +2645,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte if (dib0090_reset(fe) != 0) goto free_mem; - printk(KERN_INFO "DiB0090: successfully identified\n"); + pr_info("DiB0090: successfully identified\n"); memcpy(&fe->ops.tuner_ops, &dib0090_ops, sizeof(struct dvb_tuner_ops)); return fe; @@ -2670,7 +2672,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada if (dib0090_fw_reset_digital(fe, st->config) != 0) goto free_mem; - dprintk("DiB0090 FW: successfully identified"); + dprintk("DiB0090 FW: successfully identified\n"); memcpy(&fe->ops.tuner_ops, &dib0090_fw_ops, sizeof(struct dvb_tuner_ops)); return fe; -- cgit v1.2.3 From 585e3227ec583217b323cec121d3fc188ca4d23e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 08:44:10 -0300 Subject: [media] dib3000mb: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, instead of directly calling printk(), use pr_foo() macros, adding a \n leading char on each macro call. The frontend settings also rely on continuation lines. Change it to avoid the need of adding pr_cont() calls. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib3000mb.c | 137 +++++++++++++-------------- drivers/media/dvb-frontends/dib3000mb_priv.h | 16 ++-- 2 files changed, 71 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c index 6821ecb53d63..bf9762783be4 100644 --- a/drivers/media/dvb-frontends/dib3000mb.c +++ b/drivers/media/dvb-frontends/dib3000mb.c @@ -21,6 +21,8 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -42,13 +44,13 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able))."); -#define deb_info(args...) dprintk(0x01,args) -#define deb_i2c(args...) dprintk(0x02,args) -#define deb_srch(args...) dprintk(0x04,args) -#define deb_info(args...) dprintk(0x01,args) -#define deb_xfer(args...) dprintk(0x02,args) -#define deb_setf(args...) dprintk(0x04,args) -#define deb_getf(args...) dprintk(0x08,args) +#define deb_info(args...) dprintk(0x01, args) +#define deb_i2c(args...) dprintk(0x02, args) +#define deb_srch(args...) dprintk(0x04, args) +#define deb_info(args...) dprintk(0x01, args) +#define deb_xfer(args...) dprintk(0x02, args) +#define deb_setf(args...) dprintk(0x04, args) +#define deb_getf(args...) dprintk(0x08, args) static int dib3000_read_reg(struct dib3000_state *state, u16 reg) { @@ -126,103 +128,96 @@ static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner) fe->ops.tuner_ops.set_params(fe); if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); - deb_setf("bandwidth: "); switch (c->bandwidth_hz) { case 8000000: - deb_setf("8 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[2]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_8mhz); break; case 7000000: - deb_setf("7 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[1]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_7mhz); break; case 6000000: - deb_setf("6 MHz\n"); wr_foreach(dib3000mb_reg_timing_freq, dib3000mb_timing_freq[0]); wr_foreach(dib3000mb_reg_bandwidth, dib3000mb_bandwidth_6mhz); break; case 0: return -EOPNOTSUPP; default: - err("unknown bandwidth value."); + pr_err("unknown bandwidth value.\n"); return -EINVAL; } + deb_setf("bandwidth: %d MHZ\n", c->bandwidth_hz / 1000000); } wr(DIB3000MB_REG_LOCK1_MASK, DIB3000MB_LOCK1_SEARCH_4); - deb_setf("transmission mode: "); switch (c->transmission_mode) { case TRANSMISSION_MODE_2K: - deb_setf("2k\n"); + deb_setf("transmission mode: 2k\n"); wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_2K); break; case TRANSMISSION_MODE_8K: - deb_setf("8k\n"); + deb_setf("transmission mode: 8k\n"); wr(DIB3000MB_REG_FFT, DIB3000_TRANSMISSION_MODE_8K); break; case TRANSMISSION_MODE_AUTO: - deb_setf("auto\n"); + deb_setf("transmission mode: auto\n"); break; default: return -EINVAL; } - deb_setf("guard: "); switch (c->guard_interval) { case GUARD_INTERVAL_1_32: - deb_setf("1_32\n"); + deb_setf("guard 1_32\n"); wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_32); break; case GUARD_INTERVAL_1_16: - deb_setf("1_16\n"); + deb_setf("guard 1_16\n"); wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_16); break; case GUARD_INTERVAL_1_8: - deb_setf("1_8\n"); + deb_setf("guard 1_8\n"); wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_8); break; case GUARD_INTERVAL_1_4: - deb_setf("1_4\n"); + deb_setf("guard 1_4\n"); wr(DIB3000MB_REG_GUARD_TIME, DIB3000_GUARD_TIME_1_4); break; case GUARD_INTERVAL_AUTO: - deb_setf("auto\n"); + deb_setf("guard auto\n"); break; default: return -EINVAL; } - deb_setf("inversion: "); switch (c->inversion) { case INVERSION_OFF: - deb_setf("off\n"); + deb_setf("inversion off\n"); wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_OFF); break; case INVERSION_AUTO: - deb_setf("auto "); + deb_setf("inversion auto\n"); break; case INVERSION_ON: - deb_setf("on\n"); + deb_setf("inversion on\n"); wr(DIB3000MB_REG_DDS_INV, DIB3000_DDS_INVERSION_ON); break; default: return -EINVAL; } - deb_setf("modulation: "); switch (c->modulation) { case QPSK: - deb_setf("qpsk\n"); + deb_setf("modulation: qpsk\n"); wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_QPSK); break; case QAM_16: - deb_setf("qam16\n"); + deb_setf("modulation: qam16\n"); wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_16QAM); break; case QAM_64: - deb_setf("qam64\n"); + deb_setf("modulation: qam64\n"); wr(DIB3000MB_REG_QAM, DIB3000_CONSTELLATION_64QAM); break; case QAM_AUTO: @@ -230,69 +225,64 @@ static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner) default: return -EINVAL; } - deb_setf("hierarchy: "); switch (c->hierarchy) { case HIERARCHY_NONE: - deb_setf("none "); + deb_setf("hierarchy: none\n"); /* fall through */ case HIERARCHY_1: - deb_setf("alpha=1\n"); + deb_setf("hierarchy: alpha=1\n"); wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_1); break; case HIERARCHY_2: - deb_setf("alpha=2\n"); + deb_setf("hierarchy: alpha=2\n"); wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_2); break; case HIERARCHY_4: - deb_setf("alpha=4\n"); + deb_setf("hierarchy: alpha=4\n"); wr(DIB3000MB_REG_VIT_ALPHA, DIB3000_ALPHA_4); break; case HIERARCHY_AUTO: - deb_setf("alpha=auto\n"); + deb_setf("hierarchy: alpha=auto\n"); break; default: return -EINVAL; } - deb_setf("hierarchy: "); if (c->hierarchy == HIERARCHY_NONE) { - deb_setf("none\n"); wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_OFF); wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_HP); fe_cr = c->code_rate_HP; } else if (c->hierarchy != HIERARCHY_AUTO) { - deb_setf("on\n"); wr(DIB3000MB_REG_VIT_HRCH, DIB3000_HRCH_ON); wr(DIB3000MB_REG_VIT_HP, DIB3000_SELECT_LP); fe_cr = c->code_rate_LP; } - deb_setf("fec: "); switch (fe_cr) { case FEC_1_2: - deb_setf("1_2\n"); + deb_setf("fec: 1_2\n"); wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_1_2); break; case FEC_2_3: - deb_setf("2_3\n"); + deb_setf("fec: 2_3\n"); wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_2_3); break; case FEC_3_4: - deb_setf("3_4\n"); + deb_setf("fec: 3_4\n"); wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_3_4); break; case FEC_5_6: - deb_setf("5_6\n"); + deb_setf("fec: 5_6\n"); wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_5_6); break; case FEC_7_8: - deb_setf("7_8\n"); + deb_setf("fec: 7_8\n"); wr(DIB3000MB_REG_VIT_CODE_RATE, DIB3000_FEC_7_8); break; case FEC_NONE: - deb_setf("none "); + deb_setf("fec: none\n"); break; case FEC_AUTO: - deb_setf("auto\n"); + deb_setf("fec: auto\n"); break; default: return -EINVAL; @@ -357,7 +347,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend *fe, int tuner) rd(DIB3000MB_REG_LOCK2_VALUE))) < 0 && as_count++ < 100) msleep(1); - deb_setf("search_state after autosearch %d after %d checks\n",search_state,as_count); + deb_setf("search_state after autosearch %d after %d checks\n", + search_state, as_count); if (search_state == 1) { if (dib3000mb_get_frontend(fe, c) == 0) { @@ -464,7 +455,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, return 0; dds_val = ((rd(DIB3000MB_REG_DDS_VALUE_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_VALUE_LSB); - deb_getf("DDS_VAL: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB)); + deb_getf("DDS_VAL: %x %x %x\n", dds_val, rd(DIB3000MB_REG_DDS_VALUE_MSB), rd(DIB3000MB_REG_DDS_VALUE_LSB)); if (dds_val < threshold) inv_test1 = 0; else if (dds_val == threshold) @@ -473,7 +464,7 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, inv_test1 = 2; dds_val = ((rd(DIB3000MB_REG_DDS_FREQ_MSB) & 0xff) << 16) + rd(DIB3000MB_REG_DDS_FREQ_LSB); - deb_getf("DDS_FREQ: %x %x %x",dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB)); + deb_getf("DDS_FREQ: %x %x %x\n", dds_val, rd(DIB3000MB_REG_DDS_FREQ_MSB), rd(DIB3000MB_REG_DDS_FREQ_LSB)); if (dds_val < threshold) inv_test2 = 0; else if (dds_val == threshold) @@ -490,19 +481,19 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, switch ((tps_val = rd(DIB3000MB_REG_TPS_QAM))) { case DIB3000_CONSTELLATION_QPSK: - deb_getf("QPSK "); + deb_getf("QPSK\n"); c->modulation = QPSK; break; case DIB3000_CONSTELLATION_16QAM: - deb_getf("QAM16 "); + deb_getf("QAM16\n"); c->modulation = QAM_16; break; case DIB3000_CONSTELLATION_64QAM: - deb_getf("QAM64 "); + deb_getf("QAM64\n"); c->modulation = QAM_64; break; default: - err("Unexpected constellation returned by TPS (%d)", tps_val); + pr_err("Unexpected constellation returned by TPS (%d)\n", tps_val); break; } deb_getf("TPS: %d\n", tps_val); @@ -513,23 +504,23 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, c->code_rate_HP = FEC_NONE; switch ((tps_val = rd(DIB3000MB_REG_TPS_VIT_ALPHA))) { case DIB3000_ALPHA_0: - deb_getf("HIERARCHY_NONE "); + deb_getf("HIERARCHY_NONE\n"); c->hierarchy = HIERARCHY_NONE; break; case DIB3000_ALPHA_1: - deb_getf("HIERARCHY_1 "); + deb_getf("HIERARCHY_1\n"); c->hierarchy = HIERARCHY_1; break; case DIB3000_ALPHA_2: - deb_getf("HIERARCHY_2 "); + deb_getf("HIERARCHY_2\n"); c->hierarchy = HIERARCHY_2; break; case DIB3000_ALPHA_4: - deb_getf("HIERARCHY_4 "); + deb_getf("HIERARCHY_4\n"); c->hierarchy = HIERARCHY_4; break; default: - err("Unexpected ALPHA value returned by TPS (%d)", tps_val); + pr_err("Unexpected ALPHA value returned by TPS (%d)\n", tps_val); break; } deb_getf("TPS: %d\n", tps_val); @@ -546,65 +537,65 @@ static int dib3000mb_get_frontend(struct dvb_frontend* fe, switch (tps_val) { case DIB3000_FEC_1_2: - deb_getf("FEC_1_2 "); + deb_getf("FEC_1_2\n"); *cr = FEC_1_2; break; case DIB3000_FEC_2_3: - deb_getf("FEC_2_3 "); + deb_getf("FEC_2_3\n"); *cr = FEC_2_3; break; case DIB3000_FEC_3_4: - deb_getf("FEC_3_4 "); + deb_getf("FEC_3_4\n"); *cr = FEC_3_4; break; case DIB3000_FEC_5_6: - deb_getf("FEC_5_6 "); + deb_getf("FEC_5_6\n"); *cr = FEC_4_5; break; case DIB3000_FEC_7_8: - deb_getf("FEC_7_8 "); + deb_getf("FEC_7_8\n"); *cr = FEC_7_8; break; default: - err("Unexpected FEC returned by TPS (%d)", tps_val); + pr_err("Unexpected FEC returned by TPS (%d)\n", tps_val); break; } deb_getf("TPS: %d\n",tps_val); switch ((tps_val = rd(DIB3000MB_REG_TPS_GUARD_TIME))) { case DIB3000_GUARD_TIME_1_32: - deb_getf("GUARD_INTERVAL_1_32 "); + deb_getf("GUARD_INTERVAL_1_32\n"); c->guard_interval = GUARD_INTERVAL_1_32; break; case DIB3000_GUARD_TIME_1_16: - deb_getf("GUARD_INTERVAL_1_16 "); + deb_getf("GUARD_INTERVAL_1_16\n"); c->guard_interval = GUARD_INTERVAL_1_16; break; case DIB3000_GUARD_TIME_1_8: - deb_getf("GUARD_INTERVAL_1_8 "); + deb_getf("GUARD_INTERVAL_1_8\n"); c->guard_interval = GUARD_INTERVAL_1_8; break; case DIB3000_GUARD_TIME_1_4: - deb_getf("GUARD_INTERVAL_1_4 "); + deb_getf("GUARD_INTERVAL_1_4\n"); c->guard_interval = GUARD_INTERVAL_1_4; break; default: - err("Unexpected Guard Time returned by TPS (%d)", tps_val); + pr_err("Unexpected Guard Time returned by TPS (%d)\n", tps_val); break; } deb_getf("TPS: %d\n", tps_val); switch ((tps_val = rd(DIB3000MB_REG_TPS_FFT))) { case DIB3000_TRANSMISSION_MODE_2K: - deb_getf("TRANSMISSION_MODE_2K "); + deb_getf("TRANSMISSION_MODE_2K\n"); c->transmission_mode = TRANSMISSION_MODE_2K; break; case DIB3000_TRANSMISSION_MODE_8K: - deb_getf("TRANSMISSION_MODE_8K "); + deb_getf("TRANSMISSION_MODE_8K\n"); c->transmission_mode = TRANSMISSION_MODE_8K; break; default: - err("unexpected transmission mode return by TPS (%d)", tps_val); + pr_err("unexpected transmission mode return by TPS (%d)\n", tps_val); break; } deb_getf("TPS: %d\n", tps_val); diff --git a/drivers/media/dvb-frontends/dib3000mb_priv.h b/drivers/media/dvb-frontends/dib3000mb_priv.h index 0459d5c84314..ef7f5d136c6b 100644 --- a/drivers/media/dvb-frontends/dib3000mb_priv.h +++ b/drivers/media/dvb-frontends/dib3000mb_priv.h @@ -13,20 +13,15 @@ #ifndef __DIB3000MB_PRIV_H_INCLUDED__ #define __DIB3000MB_PRIV_H_INCLUDED__ -/* info and err, taken from usb.h, if there is anything available like by default. */ -#define err(format, arg...) printk(KERN_ERR "dib3000: " format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO "dib3000: " format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "dib3000: " format "\n" , ## arg) - /* handy shortcuts */ #define rd(reg) dib3000_read_reg(state,reg) #define wr(reg,val) if (dib3000_write_reg(state,reg,val)) \ - { err("while sending 0x%04x to 0x%04x.",val,reg); return -EREMOTEIO; } + { pr_err("while sending 0x%04x to 0x%04x.", val, reg); return -EREMOTEIO; } #define wr_foreach(a,v) { int i; \ if (sizeof(a) != sizeof(v)) \ - err("sizeof: %zu %zu is different",sizeof(a),sizeof(v));\ + pr_err("sizeof: %zu %zu is different", sizeof(a), sizeof(v));\ for (i=0; i < sizeof(a)/sizeof(u16); i++) \ wr(a[i],v[i]); \ } @@ -37,8 +32,11 @@ /* debug */ -#define dprintk(level,args...) \ - do { if ((debug & level)) { printk(args); } } while (0) +#define dprintk(level, fmt, arg...) do { \ + if (debug & level) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) /* mask for enabling a specific pid for the pid_filter */ #define DIB3000_ACTIVATE_PID_FILTERING (0x2000) -- cgit v1.2.3 From 441d54e3431d7956bca9cae0e23b16ed0d7b0e4e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 08:55:41 -0300 Subject: [media] dib3000mc: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, instead of directly calling printk(), use pr_foo() macros, adding a \n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib3000mc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib3000mc.c b/drivers/media/dvb-frontends/dib3000mc.c index da0f1dc5aaf7..0f7793455da7 100644 --- a/drivers/media/dvb-frontends/dib3000mc.c +++ b/drivers/media/dvb-frontends/dib3000mc.c @@ -11,6 +11,8 @@ * published by the Free Software Foundation, version 2. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -27,7 +29,11 @@ static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB3000MC/P:"); printk(args); printk("\n"); } } while (0) +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) struct dib3000mc_state { struct dvb_frontend demod; -- cgit v1.2.3 From 7570227724405694f407a2c5e3dd3f4f8d9c2d92 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 08:57:27 -0300 Subject: [media] dib7000m: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, instead of directly calling printk(), use pr_foo() macros, adding a \n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib7000m.c | 73 +++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c index b3ddae8885ac..c9ebb0ff746a 100644 --- a/drivers/media/dvb-frontends/dib7000m.c +++ b/drivers/media/dvb-frontends/dib7000m.c @@ -8,6 +8,9 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -21,7 +24,11 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000M: "); printk(args); printk("\n"); } } while (0) +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) struct dib7000m_state { struct dvb_frontend demod; @@ -74,7 +81,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) u16 ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -92,7 +99,7 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) state->msg[1].len = 2; if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) - dprintk("i2c read error on %d",reg); + dprintk("i2c read error on %d\n", reg); ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; mutex_unlock(&state->i2c_buffer_lock); @@ -105,7 +112,7 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val) int ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -154,7 +161,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000m_read_word(state, 294 + state->reg_offs) & 0x0010) | (1 << 1); - dprintk( "setting output mode for demod %p to %d", &state->demod, mode); + dprintk("setting output mode for demod %p to %d\n", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: // STBs with parallel gated clock @@ -181,7 +188,7 @@ static int dib7000m_set_output_mode(struct dib7000m_state *state, int mode) outreg = 0; break; default: - dprintk( "Unhandled output_mode passed to be set for demod %p",&state->demod); + dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod); break; } @@ -302,7 +309,7 @@ static int dib7000m_set_adc_state(struct dib7000m_state *state, enum dibx000_adc break; } -// dprintk( "913: %x, 914: %x", reg_913, reg_914); +// dprintk("913: %x, 914: %x\n", reg_913, reg_914); ret |= dib7000m_write_word(state, 913, reg_913); ret |= dib7000m_write_word(state, 914, reg_914); @@ -320,10 +327,10 @@ static int dib7000m_set_bandwidth(struct dib7000m_state *state, u32 bw) state->current_bandwidth = bw; if (state->timf == 0) { - dprintk( "using default timf"); + dprintk("using default timf\n"); timf = state->timf_default; } else { - dprintk( "using updated timf"); + dprintk("using updated timf\n"); timf = state->timf; } @@ -340,7 +347,7 @@ static int dib7000m_set_diversity_in(struct dvb_frontend *demod, int onoff) struct dib7000m_state *state = demod->demodulator_priv; if (state->div_force_off) { - dprintk( "diversity combination deactivated - forced by COFDM parameters"); + dprintk("diversity combination deactivated - forced by COFDM parameters\n"); onoff = 0; } state->div_state = (u8)onoff; @@ -580,10 +587,10 @@ static int dib7000m_demod_reset(struct dib7000m_state *state) dib7000mc_reset_pll(state); if (dib7000m_reset_gpio(state) != 0) - dprintk( "GPIO reset was not successful."); + dprintk("GPIO reset was not successful.\n"); if (dib7000m_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk( "OUTPUT_MODE could not be reset."); + dprintk("OUTPUT_MODE could not be reset.\n"); /* unforce divstr regardless whether i2c enumeration was done or not */ dib7000m_write_word(state, 1794, dib7000m_read_word(state, 1794) & ~(1 << 1) ); @@ -650,7 +657,7 @@ static int dib7000m_agc_soft_split(struct dib7000m_state *state) (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - dprintk( "AGC split_offset: %d",split_offset); + dprintk("AGC split_offset: %d\n", split_offset); // P_agc_force_split and P_agc_split_offset return dib7000m_write_word(state, 103, (dib7000m_read_word(state, 103) & 0xff00) | split_offset); @@ -687,7 +694,7 @@ static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) } if (agc == NULL) { - dprintk( "no valid AGC configuration found for band 0x%02x",band); + dprintk("no valid AGC configuration found for band 0x%02x\n", band); return -EINVAL; } @@ -703,7 +710,7 @@ static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) dib7000m_write_word(state, 98, (agc->alpha_mant << 5) | agc->alpha_exp); dib7000m_write_word(state, 99, (agc->beta_mant << 6) | agc->beta_exp); - dprintk( "WBD: ref: %d, sel: %d, active: %d, alpha: %d", + dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); /* AGC continued */ @@ -724,7 +731,7 @@ static int dib7000m_set_agc_config(struct dib7000m_state *state, u8 band) if (state->revision > 0x4000) { // settings for the MC dib7000m_write_word(state, 71, agc->agc1_pt3); -// dprintk( "929: %x %d %d", +// dprintk("929: %x %d %d\n", // (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2), agc->wbd_inv, agc->wbd_sel); dib7000m_write_word(state, 929, (dib7000m_read_word(state, 929) & 0xffe3) | (agc->wbd_inv << 4) | (agc->wbd_sel << 2)); } else { @@ -742,7 +749,7 @@ static void dib7000m_update_timf(struct dib7000m_state *state) state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000m_write_word(state, 23, (u16) (timf >> 16)); dib7000m_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk( "updated timf_frequency: %d (default: %d)",state->timf, state->timf_default); + dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->timf_default); } static int dib7000m_agc_startup(struct dvb_frontend *demod) @@ -804,7 +811,7 @@ static int dib7000m_agc_startup(struct dvb_frontend *demod) dib7000m_restart_agc(state); - dprintk( "SPLIT %p: %hd", demod, agc_split); + dprintk("SPLIT %p: %hd\n", demod, agc_split); (*agc_state)++; ret = 5; @@ -1013,12 +1020,12 @@ static int dib7000m_autosearch_irq(struct dib7000m_state *state, u16 reg) u16 irq_pending = dib7000m_read_word(state, reg); if (irq_pending & 0x1) { // failed - dprintk( "autosearch failed"); + dprintk("autosearch failed\n"); return 1; } if (irq_pending & 0x2) { // succeeded - dprintk( "autosearch succeeded"); + dprintk("autosearch succeeded\n"); return 2; } return 0; // still pending @@ -1102,7 +1109,7 @@ static int dib7000m_wakeup(struct dvb_frontend *demod) dib7000m_set_power_mode(state, DIB7000M_POWER_ALL); if (dib7000m_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk( "could not start Slow ADC"); + dprintk("could not start Slow ADC\n"); return 0; } @@ -1121,7 +1128,7 @@ static int dib7000m_identify(struct dib7000m_state *state) u16 value; if ((value = dib7000m_read_word(state, 896)) != 0x01b3) { - dprintk( "wrong Vendor ID (0x%x)",value); + dprintk("wrong Vendor ID (0x%x)\n", value); return -EREMOTEIO; } @@ -1130,21 +1137,21 @@ static int dib7000m_identify(struct dib7000m_state *state) state->revision != 0x4001 && state->revision != 0x4002 && state->revision != 0x4003) { - dprintk( "wrong Device ID (0x%x)",value); + dprintk("wrong Device ID (0x%x)\n", value); return -EREMOTEIO; } /* protect this driver to be used with 7000PC */ if (state->revision == 0x4000 && dib7000m_read_word(state, 769) == 0x4000) { - dprintk( "this driver does not work with DiB7000PC"); + dprintk("this driver does not work with DiB7000PC\n"); return -EREMOTEIO; } switch (state->revision) { - case 0x4000: dprintk( "found DiB7000MA/PA/MB/PB"); break; - case 0x4001: state->reg_offs = 1; dprintk( "found DiB7000HC"); break; - case 0x4002: state->reg_offs = 1; dprintk( "found DiB7000MC"); break; - case 0x4003: state->reg_offs = 1; dprintk( "found DiB9000"); break; + case 0x4000: dprintk("found DiB7000MA/PA/MB/PB\n"); break; + case 0x4001: state->reg_offs = 1; dprintk("found DiB7000HC\n"); break; + case 0x4002: state->reg_offs = 1; dprintk("found DiB7000MC\n"); break; + case 0x4003: state->reg_offs = 1; dprintk("found DiB9000\n"); break; } return 0; @@ -1242,7 +1249,7 @@ static int dib7000m_set_frontend(struct dvb_frontend *fe) found = dib7000m_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d",found); + dprintk("autosearch returns: %d\n", found); if (found == 0 || found == 1) return 0; // no channel found @@ -1330,7 +1337,7 @@ int dib7000m_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) struct dib7000m_state *state = fe->demodulator_priv; u16 val = dib7000m_read_word(state, 294 + state->reg_offs) & 0xffef; val |= (onoff & 0x1) << 4; - dprintk("PID filter enabled %d", onoff); + dprintk("PID filter enabled %d\n", onoff); return dib7000m_write_word(state, 294 + state->reg_offs, val); } EXPORT_SYMBOL(dib7000m_pid_filter_ctrl); @@ -1338,7 +1345,7 @@ EXPORT_SYMBOL(dib7000m_pid_filter_ctrl); int dib7000m_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib7000m_state *state = fe->demodulator_priv; - dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); + dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff); return dib7000m_write_word(state, 300 + state->reg_offs + id, onoff ? (1 << 13) | pid : 0); } @@ -1362,7 +1369,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, if (dib7000m_identify(&st) != 0) { st.i2c_addr = default_addr; if (dib7000m_identify(&st) != 0) { - dprintk("DiB7000M #%d: not identified", k); + dprintk("DiB7000M #%d: not identified\n", k); return -EIO; } } @@ -1375,7 +1382,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, /* set new i2c address and force divstart */ dib7000m_write_word(&st, 1794, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); } for (k = 0; k < no_of_demods; k++) { -- cgit v1.2.3 From 5a0e2a4e936d04a1e987077729d8d01adbc78a9f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 09:35:33 -0300 Subject: [media] dib7000p: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, instead of directly calling printk(), use pr_foo() macros, adding a \n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib7000p.c | 127 +++++++++++++++++---------------- 1 file changed, 67 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index b861d4437f2a..2cee51c08a5a 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -7,6 +7,9 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -26,7 +29,11 @@ static int buggy_sfn_workaround; module_param(buggy_sfn_workaround, int, 0644); MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB7000P: "); printk(args); printk("\n"); } } while (0) +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) struct i2c_device { struct i2c_adapter *i2c_adap; @@ -98,7 +105,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) u16 ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -116,7 +123,7 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) state->msg[1].len = 2; if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2) - dprintk("i2c read error on %d", reg); + dprintk("i2c read error on %d\n", reg); ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; mutex_unlock(&state->i2c_buffer_lock); @@ -128,7 +135,7 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val) int ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -174,7 +181,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) fifo_threshold = 1792; smo_mode = (dib7000p_read_word(state, 235) & 0x0050) | (1 << 1); - dprintk("setting output mode for demod %p to %d", &state->demod, mode); + dprintk("setting output mode for demod %p to %d\n", &state->demod, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: @@ -204,7 +211,7 @@ static int dib7000p_set_output_mode(struct dib7000p_state *state, int mode) outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p", &state->demod); + dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->demod); break; } @@ -224,7 +231,7 @@ static int dib7000p_set_diversity_in(struct dvb_frontend *demod, int onoff) struct dib7000p_state *state = demod->demodulator_priv; if (state->div_force_off) { - dprintk("diversity combination deactivated - forced by COFDM parameters"); + dprintk("diversity combination deactivated - forced by COFDM parameters\n"); onoff = 0; dib7000p_write_word(state, 207, 0); } else @@ -374,10 +381,10 @@ static int dib7000p_set_bandwidth(struct dib7000p_state *state, u32 bw) state->current_bandwidth = bw; if (state->timf == 0) { - dprintk("using default timf"); + dprintk("using default timf\n"); timf = state->cfg.bw->timf; } else { - dprintk("using updated timf"); + dprintk("using updated timf\n"); timf = state->timf; } @@ -494,7 +501,7 @@ static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth loopdiv = (reg_1856 >> 6) & 0x3f; if ((bw != NULL) && (bw->pll_prediv != prediv || bw->pll_ratio != loopdiv)) { - dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, bw->pll_prediv, loopdiv, bw->pll_ratio); reg_1856 &= 0xf000; reg_1857 = dib7000p_read_word(state, 1857); dib7000p_write_word(state, 1857, reg_1857 & ~(1 << 15)); @@ -511,7 +518,7 @@ static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth dib7000p_write_word(state, 1857, reg_1857 | (1 << 15)); while (((dib7000p_read_word(state, 1856) >> 15) & 0x1) != 1) - dprintk("Waiting for PLL to lock"); + dprintk("Waiting for PLL to lock\n"); return 0; } @@ -521,7 +528,7 @@ static int dib7000p_update_pll(struct dvb_frontend *fe, struct dibx000_bandwidth static int dib7000p_reset_gpio(struct dib7000p_state *st) { /* reset the GPIOs */ - dprintk("gpio dir: %x: val: %x, pwm_pos: %x", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos); + dprintk("gpio dir: %x: val: %x, pwm_pos: %x\n", st->gpio_dir, st->gpio_val, st->cfg.gpio_pwm_pos); dib7000p_write_word(st, 1029, st->gpio_dir); dib7000p_write_word(st, 1030, st->gpio_val); @@ -669,7 +676,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_reset_pll(state); if (dib7000p_reset_gpio(state) != 0) - dprintk("GPIO reset was not successful."); + dprintk("GPIO reset was not successful.\n"); if (state->version == SOC7090) { dib7000p_write_word(state, 899, 0); @@ -681,7 +688,7 @@ static int dib7000p_demod_reset(struct dib7000p_state *state) dib7000p_write_word(state, 273, (0<<6) | 30); } if (dib7000p_set_output_mode(state, OUTMODE_HIGH_Z) != 0) - dprintk("OUTPUT_MODE could not be reset."); + dprintk("OUTPUT_MODE could not be reset.\n"); dib7000p_set_adc_state(state, DIBX000_SLOW_ADC_ON); dib7000p_sad_calib(state); @@ -759,7 +766,7 @@ static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) } if (agc == NULL) { - dprintk("no valid AGC configuration found for band 0x%02x", band); + dprintk("no valid AGC configuration found for band 0x%02x\n", band); return -EINVAL; } @@ -776,7 +783,7 @@ static int dib7000p_set_agc_config(struct dib7000p_state *state, u8 band) dib7000p_write_word(state, 102, (agc->beta_mant << 6) | agc->beta_exp); /* AGC continued */ - dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", + dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); if (state->wbd_ref != 0) @@ -806,7 +813,7 @@ static void dib7000p_set_dds(struct dib7000p_state *state, s32 offset_khz) u32 dds = state->cfg.bw->ifreq & 0x1ffffff; u8 invert = !!(state->cfg.bw->ifreq & (1 << 25)); - dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d", offset_khz, internal, invert); + dprintk("setting a frequency offset of %dkHz internal freq = %d invert = %d\n", offset_khz, internal, invert); if (offset_khz < 0) unit_khz_dds_val *= -1; @@ -902,7 +909,7 @@ static int dib7000p_agc_startup(struct dvb_frontend *demod) dib7000p_restart_agc(state); - dprintk("SPLIT %p: %hd", demod, agc_split); + dprintk("SPLIT %p: %hd\n", demod, agc_split); (*agc_state)++; ret = 5; @@ -934,7 +941,7 @@ static void dib7000p_update_timf(struct dib7000p_state *state) state->timf = timf * 160 / (state->current_bandwidth / 50); dib7000p_write_word(state, 23, (u16) (timf >> 16)); dib7000p_write_word(state, 24, (u16) (timf & 0xffff)); - dprintk("updated timf_frequency: %d (default: %d)", state->timf, state->cfg.bw->timf); + dprintk("updated timf_frequency: %d (default: %d)\n", state->timf, state->cfg.bw->timf); } @@ -1202,7 +1209,7 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 int bw_khz = bw; u32 pha; - dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)", f_rel, rf_khz, xtal); + dprintk("relative position of the Spur: %dk (RF: %dk, XTAL: %dk)\n", f_rel, rf_khz, xtal); if (f_rel < -bw_khz / 2 || f_rel > bw_khz / 2) return; @@ -1252,7 +1259,7 @@ static void dib7000p_spur_protect(struct dib7000p_state *state, u32 rf_khz, u32 coef_im[k] = (1 << 24) - 1; coef_im[k] /= (1 << 15); - dprintk("PALF COEF: %d re: %d im: %d", k, coef_re[k], coef_im[k]); + dprintk("PALF COEF: %d re: %d im: %d\n", k, coef_re[k], coef_im[k]); dib7000p_write_word(state, 143, (0 << 14) | (k << 10) | (coef_re[k] & 0x3ff)); dib7000p_write_word(state, 144, coef_im[k] & 0x3ff); @@ -1280,7 +1287,7 @@ static int dib7000p_tune(struct dvb_frontend *demod) /* P_ctrl_inh_cor=0, P_ctrl_alpha_cor=4, P_ctrl_inh_isi=0, P_ctrl_alpha_isi=3, P_ctrl_inh_cor4=1, P_ctrl_alpha_cor4=3 */ tmp = (0 << 14) | (4 << 10) | (0 << 9) | (3 << 5) | (1 << 4) | (0x3); if (state->sfn_workaround_active) { - dprintk("SFN workaround is active"); + dprintk("SFN workaround is active\n"); tmp |= (1 << 9); dib7000p_write_word(state, 166, 0x4000); } else { @@ -1390,15 +1397,15 @@ static int dib7000p_sleep(struct dvb_frontend *demod) static int dib7000p_identify(struct dib7000p_state *st) { u16 value; - dprintk("checking demod on I2C address: %d (%x)", st->i2c_addr, st->i2c_addr); + dprintk("checking demod on I2C address: %d (%x)\n", st->i2c_addr, st->i2c_addr); if ((value = dib7000p_read_word(st, 768)) != 0x01b3) { - dprintk("wrong Vendor ID (read=0x%x)", value); + dprintk("wrong Vendor ID (read=0x%x)\n", value); return -EREMOTEIO; } if ((value = dib7000p_read_word(st, 769)) != 0x4000) { - dprintk("wrong Device ID (%x)", value); + dprintk("wrong Device ID (%x)\n", value); return -EREMOTEIO; } @@ -1536,7 +1543,7 @@ static int dib7000p_set_frontend(struct dvb_frontend *fe) found = dib7000p_autosearch_is_irq(fe); } while (found == 0 && i--); - dprintk("autosearch returns: %d", found); + dprintk("autosearch returns: %d\n", found); if (found == 0 || found == 1) return 0; @@ -1951,7 +1958,7 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, enum fe_status stat) time_us = dib7000p_get_time_us(demod); state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000); - dprintk("Next all layers stats available in %u us.", time_us); + dprintk("Next all layers stats available in %u us.\n", time_us); dib7000p_read_ber(demod, &val); c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; @@ -2019,7 +2026,7 @@ static int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected"); + dprintk("-D- DiB7000PC detected\n"); return 1; } @@ -2027,11 +2034,11 @@ static int dib7000pc_detection(struct i2c_adapter *i2c_adap) if (i2c_transfer(i2c_adap, msg, 2) == 2) if (rx[0] == 0x01 && rx[1] == 0xb3) { - dprintk("-D- DiB7000PC detected"); + dprintk("-D- DiB7000PC detected\n"); return 1; } - dprintk("-D- DiB7000PC not detected"); + dprintk("-D- DiB7000PC not detected\n"); kfree(rx); rx_memory_error: @@ -2050,14 +2057,14 @@ static int dib7000p_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) struct dib7000p_state *state = fe->demodulator_priv; u16 val = dib7000p_read_word(state, 235) & 0xffef; val |= (onoff & 0x1) << 4; - dprintk("PID filter enabled %d", onoff); + dprintk("PID filter enabled %d\n", onoff); return dib7000p_write_word(state, 235, val); } static int dib7000p_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib7000p_state *state = fe->demodulator_priv; - dprintk("PID filter: index %x, PID %d, OnOff %d", id, pid, onoff); + dprintk("PID filter: index %x, PID %d, OnOff %d\n", id, pid, onoff); return dib7000p_write_word(state, 241 + id, onoff ? (1 << 13) | pid : 0); } @@ -2100,7 +2107,7 @@ static int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u /* set new i2c address and force divstart */ dib7000p_write_word(dpst, 1285, (new_addr << 2) | 0x2); - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -2136,21 +2143,21 @@ static s32 dib7000p_get_adc_power(struct dvb_frontend *fe) buf[0] = dib7000p_read_word(state, 0x184); buf[1] = dib7000p_read_word(state, 0x185); pow_i = (buf[0] << 16) | buf[1]; - dprintk("raw pow_i = %d", pow_i); + dprintk("raw pow_i = %d\n", pow_i); tmp_val = pow_i; while (tmp_val >>= 1) exp++; mant = (pow_i * 1000 / (1 << exp)); - dprintk(" mant = %d exp = %d", mant / 1000, exp); + dprintk(" mant = %d exp = %d\n", mant / 1000, exp); ix = (u8) ((mant - 1000) / 100); /* index of the LUT */ - dprintk(" ix = %d", ix); + dprintk(" ix = %d\n", ix); pow_i = (lut_1000ln_mant[ix] + 693 * (exp - 20) - 6908); pow_i = (pow_i << 8) / 1000; - dprintk(" pow_i = %d", pow_i); + dprintk(" pow_i = %d\n", pow_i); return pow_i; } @@ -2185,7 +2192,7 @@ static int w7090p_tuner_write_serpar(struct i2c_adapter *i2c_adap, struct i2c_ms n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; i--; if (i == 0) - dprintk("Tuner ITF: write busy (overflow)"); + dprintk("Tuner ITF: write busy (overflow)\n"); } dib7000p_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); dib7000p_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); @@ -2205,7 +2212,7 @@ static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg n_overflow = (dib7000p_read_word(state, 1984) >> 1) & 0x1; i--; if (i == 0) - dprintk("TunerITF: read busy (overflow)"); + dprintk("TunerITF: read busy (overflow)\n"); } dib7000p_write_word(state, 1985, (0 << 6) | (serpar_num & 0x3f)); @@ -2214,7 +2221,7 @@ static int w7090p_tuner_read_serpar(struct i2c_adapter *i2c_adap, struct i2c_msg n_empty = dib7000p_read_word(state, 1984) & 0x1; i--; if (i == 0) - dprintk("TunerITF: read busy (empty)"); + dprintk("TunerITF: read busy (empty)\n"); } read_word = dib7000p_read_word(state, 1987); msg[1].buf[0] = (read_word >> 8) & 0xff; @@ -2435,7 +2442,7 @@ static u32 dib7090_calcSyncFreq(u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 static int dib7090_cfg_DibTx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) { - dprintk("Configure DibStream Tx"); + dprintk("Configure DibStream Tx\n"); dib7000p_write_word(state, 1615, 1); dib7000p_write_word(state, 1603, P_Kin); @@ -2455,7 +2462,7 @@ static int dib7090_cfg_DibRx(struct dib7000p_state *state, u32 P_Kin, u32 P_Kout { u32 syncFreq; - dprintk("Configure DibStream Rx"); + dprintk("Configure DibStream Rx\n"); if ((P_Kin != 0) && (P_Kout != 0)) { syncFreq = dib7090_calcSyncFreq(P_Kin, P_Kout, insertExtSynchro, syncSize); dib7000p_write_word(state, 1542, syncFreq); @@ -2492,7 +2499,7 @@ static void dib7090_enMpegMux(struct dib7000p_state *state, int onoff) static void dib7090_configMpegMux(struct dib7000p_state *state, u16 pulseWidth, u16 enSerialMode, u16 enSerialClkDiv2) { - dprintk("Enable Mpeg mux"); + dprintk("Enable Mpeg mux\n"); dib7090_enMpegMux(state, 0); @@ -2513,17 +2520,17 @@ static void dib7090_setDibTxMux(struct dib7000p_state *state, int mode) switch (mode) { case MPEG_ON_DIBTX: - dprintk("SET MPEG ON DIBSTREAM TX"); + dprintk("SET MPEG ON DIBSTREAM TX\n"); dib7090_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); reg_1288 |= (1<<9); break; case DIV_ON_DIBTX: - dprintk("SET DIV_OUT ON DIBSTREAM TX"); + dprintk("SET DIV_OUT ON DIBSTREAM TX\n"); dib7090_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); reg_1288 |= (1<<8); break; case ADC_ON_DIBTX: - dprintk("SET ADC_OUT ON DIBSTREAM TX"); + dprintk("SET ADC_OUT ON DIBSTREAM TX\n"); dib7090_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); reg_1288 |= (1<<7); break; @@ -2539,17 +2546,17 @@ static void dib7090_setHostBusMux(struct dib7000p_state *state, int mode) switch (mode) { case DEMOUT_ON_HOSTBUS: - dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); + dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n"); dib7090_enMpegMux(state, 0); reg_1288 |= (1<<6); break; case DIBTX_ON_HOSTBUS: - dprintk("SET DIBSTREAM TX ON HOST BUS"); + dprintk("SET DIBSTREAM TX ON HOST BUS\n"); dib7090_enMpegMux(state, 0); reg_1288 |= (1<<5); break; case MPEG_ON_HOSTBUS: - dprintk("SET MPEG MUX ON HOST BUS"); + dprintk("SET MPEG MUX ON HOST BUS\n"); reg_1288 |= (1<<4); break; default: @@ -2565,7 +2572,7 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) switch (onoff) { case 0: /* only use the internal way - not the diversity input */ - dprintk("%s mode OFF : by default Enable Mpeg INPUT", __func__); + dprintk("%s mode OFF : by default Enable Mpeg INPUT\n", __func__); dib7090_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); /* Do not divide the serial clock of MPEG MUX */ @@ -2581,7 +2588,7 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff) break; case 1: /* both ways */ case 2: /* only the diversity input */ - dprintk("%s ON : Enable diversity INPUT", __func__); + dprintk("%s ON : Enable diversity INPUT\n", __func__); dib7090_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); state->input_mode_mpeg = 0; break; @@ -2612,11 +2619,11 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_SERIAL: if (prefer_mpeg_mux_use) { - dprintk("setting output mode TS_SERIAL using Mpeg Mux"); + dprintk("setting output mode TS_SERIAL using Mpeg Mux\n"); dib7090_configMpegMux(state, 3, 1, 1); dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); } else {/* Use Smooth block */ - dprintk("setting output mode TS_SERIAL using Smooth bloc"); + dprintk("setting output mode TS_SERIAL using Smooth bloc\n"); dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (2<<6) | (0 << 1); } @@ -2624,24 +2631,24 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_PAR_GATED_CLK: if (prefer_mpeg_mux_use) { - dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dprintk("setting output mode TS_PARALLEL_GATED using Mpeg Mux\n"); dib7090_configMpegMux(state, 2, 0, 0); dib7090_setHostBusMux(state, MPEG_ON_HOSTBUS); } else { /* Use Smooth block */ - dprintk("setting output mode TS_PARALLEL_GATED using Smooth block"); + dprintk("setting output mode TS_PARALLEL_GATED using Smooth block\n"); dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (0<<6); } break; case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ - dprintk("setting output mode TS_PARALLEL_CONT using Smooth block"); + dprintk("setting output mode TS_PARALLEL_CONT using Smooth block\n"); dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (1<<6); break; case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ - dprintk("setting output mode TS_FIFO using Smooth block"); + dprintk("setting output mode TS_FIFO using Smooth block\n"); dib7090_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (5<<6); smo_mode |= (3 << 1); @@ -2649,13 +2656,13 @@ static int dib7090_set_output_mode(struct dvb_frontend *fe, int mode) break; case OUTMODE_DIVERSITY: - dprintk("setting output mode MODE_DIVERSITY"); + dprintk("setting output mode MODE_DIVERSITY\n"); dib7090_setDibTxMux(state, DIV_ON_DIBTX); dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; case OUTMODE_ANALOG_ADC: - dprintk("setting output mode MODE_ANALOG_ADC"); + dprintk("setting output mode MODE_ANALOG_ADC\n"); dib7090_setDibTxMux(state, ADC_ON_DIBTX); dib7090_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; @@ -2678,7 +2685,7 @@ static int dib7090_tuner_sleep(struct dvb_frontend *fe, int onoff) struct dib7000p_state *state = fe->demodulator_priv; u16 en_cur_state; - dprintk("sleep dib7090: %d", onoff); + dprintk("sleep dib7090: %d\n", onoff); en_cur_state = dib7000p_read_word(state, 1922); -- cgit v1.2.3 From 8af16adfbb45dfa3b75a4217dcc631d7414854e5 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 10:05:46 -0300 Subject: [media] dib8000: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, instead of directly calling printk(), use pr_foo() macros, adding a\n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib8000.c | 261 +++++++++++++++++----------------- 1 file changed, 134 insertions(+), 127 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index ddf9c44877a2..e501ec964df1 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -7,6 +7,9 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -31,7 +34,11 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB8000: "); printk(args); printk("\n"); } } while (0) +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) struct i2c_device { struct i2c_adapter *adap; @@ -147,7 +154,7 @@ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) }; if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -157,7 +164,7 @@ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) msg[1].buf = i2c->i2c_read_buffer; if (i2c_transfer(i2c->adap, msg, 2) != 2) - dprintk("i2c read error on %d", reg); + dprintk("i2c read error on %d\n", reg); ret = (msg[1].buf[0] << 8) | msg[1].buf[1]; mutex_unlock(i2c->i2c_buffer_lock); @@ -182,7 +189,7 @@ static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg) state->msg[1].len = 2; if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2) - dprintk("i2c read error on %d", reg); + dprintk("i2c read error on %d\n", reg); ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; @@ -194,7 +201,7 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) u16 ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -210,7 +217,7 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg) u16 rw[2]; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -228,7 +235,7 @@ static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val) int ret = 0; if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -249,7 +256,7 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) int ret; if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -395,7 +402,7 @@ static void dib8000_set_acquisition_mode(struct dib8000_state *state) { u16 nud = dib8000_read_word(state, 298); nud |= (1 << 3) | (1 << 0); - dprintk("acquisition mode activated"); + dprintk("acquisition mode activated\n"); dib8000_write_word(state, 298, nud); } static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) @@ -408,7 +415,7 @@ static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) fifo_threshold = 1792; smo_mode = (dib8000_read_word(state, 299) & 0x0050) | (1 << 1); - dprintk("-I- Setting output mode for demod %p to %d", + dprintk("-I- Setting output mode for demod %p to %d\n", &state->fe[0], mode); switch (mode) { @@ -443,7 +450,7 @@ static int dib8000_set_output_mode(struct dvb_frontend *fe, int mode) break; default: - dprintk("Unhandled output_mode passed to be set for demod %p", + dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->fe[0]); return -EINVAL; } @@ -464,7 +471,7 @@ static int dib8000_set_diversity_in(struct dvb_frontend *fe, int onoff) struct dib8000_state *state = fe->demodulator_priv; u16 tmp, sync_wait = dib8000_read_word(state, 273) & 0xfff0; - dprintk("set diversity input to %i", onoff); + dprintk("set diversity input to %i\n", onoff); if (!state->differential_constellation) { dib8000_write_word(state, 272, 1 << 9); //dvsy_off_lmod4 = 1 dib8000_write_word(state, 273, sync_wait | (1 << 2) | 2); // sync_enable = 1; comb_mode = 2 @@ -531,7 +538,7 @@ static void dib8000_set_power_mode(struct dib8000_state *state, enum dib8000_pow break; } - dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x", reg_774, reg_775, reg_776, reg_900, reg_1280); + dprintk("powermode : 774 : %x ; 775 : %x; 776 : %x ; 900 : %x; 1280 : %x\n", reg_774, reg_775, reg_776, reg_900, reg_1280); dib8000_write_word(state, 774, reg_774); dib8000_write_word(state, 775, reg_775); dib8000_write_word(state, 776, reg_776); @@ -619,10 +626,10 @@ static int dib8000_set_bandwidth(struct dvb_frontend *fe, u32 bw) bw = 6000; if (state->timf == 0) { - dprintk("using default timf"); + dprintk("using default timf\n"); timf = state->timf_default; } else { - dprintk("using updated timf"); + dprintk("using updated timf\n"); timf = state->timf; } @@ -667,7 +674,7 @@ static int dib8000_set_wbd_ref(struct dvb_frontend *fe, u16 value) static void dib8000_reset_pll_common(struct dib8000_state *state, const struct dibx000_bandwidth_config *bw) { - dprintk("ifreq: %d %x, inversion: %d", bw->ifreq, bw->ifreq, bw->ifreq >> 25); + dprintk("ifreq: %d %x, inversion: %d\n", bw->ifreq, bw->ifreq, bw->ifreq >> 25); if (state->revision != 0x8090) { dib8000_write_word(state, 23, (u16) (((bw->internal * 1000) >> 16) & 0xffff)); @@ -704,7 +711,7 @@ static void dib8000_reset_pll(struct dib8000_state *state) clk_cfg1 = (clk_cfg1 & 0xfff7) | (pll->pll_bypass << 3); dib8000_write_word(state, 902, clk_cfg1); - dprintk("clk_cfg1: 0x%04x", clk_cfg1); + dprintk("clk_cfg1: 0x%04x\n", clk_cfg1); /* smpl_cfg: P_refclksel=2, P_ensmplsel=1 nodivsmpl=1 */ if (state->cfg.pll->ADClkSrc == 0) @@ -754,7 +761,7 @@ static int dib8000_update_pll(struct dvb_frontend *fe, pll->pll_ratio == loopdiv)) return -EINVAL; - dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); + dprintk("Updating pll (prediv: old = %d new = %d ; loopdiv : old = %d new = %d)\n", prediv, pll->pll_prediv, loopdiv, pll->pll_ratio); if (state->revision == 0x8090) { reg_1856 &= 0xf000; reg_1857 = dib8000_read_word(state, 1857); @@ -767,11 +774,11 @@ static int dib8000_update_pll(struct dvb_frontend *fe, /* write new system clk into P_sec_len */ internal = dib8000_read32(state, 23) / 1000; - dprintk("Old Internal = %d", internal); + dprintk("Old Internal = %d\n", internal); xtal = 2 * (internal / loopdiv) * prediv; internal = 1000 * (xtal/pll->pll_prediv) * pll->pll_ratio; - dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d", xtal, internal/1000, internal/2000, internal/8000); - dprintk("New Internal = %d", internal); + dprintk("Xtal = %d , New Fmem = %d New Fdemod = %d, New Fsampling = %d\n", xtal, internal/1000, internal/2000, internal/8000); + dprintk("New Internal = %d\n", internal); dib8000_write_word(state, 23, (u16) (((internal / 2) >> 16) & 0xffff)); @@ -780,22 +787,22 @@ static int dib8000_update_pll(struct dvb_frontend *fe, dib8000_write_word(state, 1857, reg_1857 | (1 << 15)); while (((dib8000_read_word(state, 1856)>>15)&0x1) != 1) - dprintk("Waiting for PLL to lock"); + dprintk("Waiting for PLL to lock\n"); /* verify */ reg_1856 = dib8000_read_word(state, 1856); - dprintk("PLL Updated with prediv = %d and loopdiv = %d", + dprintk("PLL Updated with prediv = %d and loopdiv = %d\n", reg_1856&0x3f, (reg_1856>>6)&0x3f); } else { if (bw != state->current_demod_bw) { /** Bandwidth change => force PLL update **/ - dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv); + dprintk("PLL: Bandwidth Change %d MHz -> %d MHz (prediv: %d->%d)\n", state->current_demod_bw / 1000, bw / 1000, oldprediv, state->cfg.pll->pll_prediv); if (state->cfg.pll->pll_prediv != oldprediv) { /** Full PLL change only if prediv is changed **/ /** full update => bypass and reconfigure **/ - dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio); + dprintk("PLL: New Setting for %d MHz Bandwidth (prediv: %d, ratio: %d)\n", bw/1000, state->cfg.pll->pll_prediv, state->cfg.pll->pll_ratio); dib8000_write_word(state, 902, dib8000_read_word(state, 902) | (1<<3)); /* bypass PLL */ dib8000_reset_pll(state); dib8000_write_word(state, 898, 0x0004); /* sad */ @@ -807,7 +814,7 @@ static int dib8000_update_pll(struct dvb_frontend *fe, if (ratio != 0) { /** ratio update => only change ratio **/ - dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio); + dprintk("PLL: Update ratio (prediv: %d, ratio: %d)\n", state->cfg.pll->pll_prediv, ratio); dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */ } } @@ -841,7 +848,7 @@ static int dib8000_cfg_gpio(struct dib8000_state *st, u8 num, u8 dir, u8 val) st->cfg.gpio_val |= (val & 0x01) << num; /* set the new value */ dib8000_write_word(st, 1030, st->cfg.gpio_val); - dprintk("gpio dir: %x: gpio val: %x", st->cfg.gpio_dir, st->cfg.gpio_val); + dprintk("gpio dir: %x: gpio val: %x\n", st->cfg.gpio_dir, st->cfg.gpio_val); return 0; } @@ -958,29 +965,29 @@ static u16 dib8000_identify(struct i2c_device *client) value = dib8000_i2c_read16(client, 896); if ((value = dib8000_i2c_read16(client, 896)) != 0x01b3) { - dprintk("wrong Vendor ID (read=0x%x)", value); + dprintk("wrong Vendor ID (read=0x%x)\n", value); return 0; } value = dib8000_i2c_read16(client, 897); if (value != 0x8000 && value != 0x8001 && value != 0x8002 && value != 0x8090) { - dprintk("wrong Device ID (%x)", value); + dprintk("wrong Device ID (%x)\n", value); return 0; } switch (value) { case 0x8000: - dprintk("found DiB8000A"); + dprintk("found DiB8000A\n"); break; case 0x8001: - dprintk("found DiB8000B"); + dprintk("found DiB8000B\n"); break; case 0x8002: - dprintk("found DiB8000C"); + dprintk("found DiB8000C\n"); break; case 0x8090: - dprintk("found DiB8096P"); + dprintk("found DiB8096P\n"); break; } return value; @@ -1037,7 +1044,7 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_write_word(state, 1287, 0x0003); if (state->revision == 0x8000) - dprintk("error : dib8000 MA not supported"); + dprintk("error : dib8000 MA not supported\n"); dibx000_reset_i2c_master(&state->i2c_master); @@ -1069,7 +1076,7 @@ static int dib8000_reset(struct dvb_frontend *fe) if (state->cfg.drives) dib8000_write_word(state, 906, state->cfg.drives); else { - dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal."); + dprintk("using standard PAD-drive-settings, please adjust settings in config-struct to be optimal.\n"); /* min drive SDRAM - not optimal - adjust */ dib8000_write_word(state, 906, 0x2d98); } @@ -1080,11 +1087,11 @@ static int dib8000_reset(struct dvb_frontend *fe) dib8000_write_word(state, 898, 0x0004); if (dib8000_reset_gpio(state) != 0) - dprintk("GPIO reset was not successful."); + dprintk("GPIO reset was not successful.\n"); if ((state->revision != 0x8090) && (dib8000_set_output_mode(fe, OUTMODE_HIGH_Z) != 0)) - dprintk("OUTPUT_MODE could not be resetted."); + dprintk("OUTPUT_MODE could not be resetted.\n"); state->current_agc = NULL; @@ -1176,7 +1183,7 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) } if (agc == NULL) { - dprintk("no valid AGC configuration found for band 0x%02x", band); + dprintk("no valid AGC configuration found for band 0x%02x\n", band); return -EINVAL; } @@ -1192,7 +1199,7 @@ static int dib8000_set_agc_config(struct dib8000_state *state, u8 band) dib8000_write_word(state, 102, (agc->alpha_mant << 5) | agc->alpha_exp); dib8000_write_word(state, 103, (agc->beta_mant << 6) | agc->beta_exp); - dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d", + dprintk("WBD: ref: %d, sel: %d, active: %d, alpha: %d\n", state->wbd_ref != 0 ? state->wbd_ref : agc->wbd_ref, agc->wbd_sel, !agc->perform_agc_softsplit, agc->wbd_sel); /* AGC continued */ @@ -1251,7 +1258,7 @@ static int dib8000_agc_soft_split(struct dib8000_state *state) (agc - state->current_agc->split.min_thres) / (state->current_agc->split.max_thres - state->current_agc->split.min_thres); - dprintk("AGC split_offset: %d", split_offset); + dprintk("AGC split_offset: %d\n", split_offset); // P_agc_force_split and P_agc_split_offset dib8000_write_word(state, 107, (dib8000_read_word(state, 107) & 0xff00) | split_offset); @@ -1395,7 +1402,7 @@ static void dib8096p_cfg_DibTx(struct dib8000_state *state, u32 P_Kin, u32 P_Kout, u32 insertExtSynchro, u32 synchroMode, u32 syncWord, u32 syncSize) { - dprintk("Configure DibStream Tx"); + dprintk("Configure DibStream Tx\n"); dib8000_write_word(state, 1615, 1); dib8000_write_word(state, 1603, P_Kin); @@ -1414,7 +1421,7 @@ static void dib8096p_cfg_DibRx(struct dib8000_state *state, u32 P_Kin, { u32 syncFreq; - dprintk("Configure DibStream Rx synchroMode = %d", synchroMode); + dprintk("Configure DibStream Rx synchroMode = %d\n", synchroMode); if ((P_Kin != 0) && (P_Kout != 0)) { syncFreq = dib8096p_calcSyncFreq(P_Kin, P_Kout, @@ -1456,7 +1463,7 @@ static void dib8096p_configMpegMux(struct dib8000_state *state, { u16 reg_1287; - dprintk("Enable Mpeg mux"); + dprintk("Enable Mpeg mux\n"); dib8096p_enMpegMux(state, 0); @@ -1477,15 +1484,15 @@ static void dib8096p_setDibTxMux(struct dib8000_state *state, int mode) switch (mode) { case MPEG_ON_DIBTX: - dprintk("SET MPEG ON DIBSTREAM TX"); + dprintk("SET MPEG ON DIBSTREAM TX\n"); dib8096p_cfg_DibTx(state, 8, 5, 0, 0, 0, 0); reg_1288 |= (1 << 9); break; case DIV_ON_DIBTX: - dprintk("SET DIV_OUT ON DIBSTREAM TX"); + dprintk("SET DIV_OUT ON DIBSTREAM TX\n"); dib8096p_cfg_DibTx(state, 5, 5, 0, 0, 0, 0); reg_1288 |= (1 << 8); break; case ADC_ON_DIBTX: - dprintk("SET ADC_OUT ON DIBSTREAM TX"); + dprintk("SET ADC_OUT ON DIBSTREAM TX\n"); dib8096p_cfg_DibTx(state, 20, 5, 10, 0, 0, 0); reg_1288 |= (1 << 7); break; default: @@ -1500,17 +1507,17 @@ static void dib8096p_setHostBusMux(struct dib8000_state *state, int mode) switch (mode) { case DEMOUT_ON_HOSTBUS: - dprintk("SET DEM OUT OLD INTERF ON HOST BUS"); + dprintk("SET DEM OUT OLD INTERF ON HOST BUS\n"); dib8096p_enMpegMux(state, 0); reg_1288 |= (1 << 6); break; case DIBTX_ON_HOSTBUS: - dprintk("SET DIBSTREAM TX ON HOST BUS"); + dprintk("SET DIBSTREAM TX ON HOST BUS\n"); dib8096p_enMpegMux(state, 0); reg_1288 |= (1 << 5); break; case MPEG_ON_HOSTBUS: - dprintk("SET MPEG MUX ON HOST BUS"); + dprintk("SET MPEG MUX ON HOST BUS\n"); reg_1288 |= (1 << 4); break; default: @@ -1526,7 +1533,7 @@ static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff) switch (onoff) { case 0: /* only use the internal way - not the diversity input */ - dprintk("%s mode OFF : by default Enable Mpeg INPUT", + dprintk("%s mode OFF : by default Enable Mpeg INPUT\n", __func__); /* outputRate = 8 */ dib8096p_cfg_DibRx(state, 8, 5, 0, 0, 0, 8, 0); @@ -1544,7 +1551,7 @@ static int dib8096p_set_diversity_in(struct dvb_frontend *fe, int onoff) break; case 1: /* both ways */ case 2: /* only the diversity input */ - dprintk("%s ON : Enable diversity INPUT", __func__); + dprintk("%s ON : Enable diversity INPUT\n", __func__); dib8096p_cfg_DibRx(state, 5, 5, 0, 0, 0, 0, 0); state->input_mode_mpeg = 0; break; @@ -1576,11 +1583,11 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_SERIAL: if (prefer_mpeg_mux_use) { - dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux"); + dprintk("dib8096P setting output mode TS_SERIAL using Mpeg Mux\n"); dib8096p_configMpegMux(state, 3, 1, 1); dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); } else {/* Use Smooth block */ - dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc"); + dprintk("dib8096P setting output mode TS_SERIAL using Smooth bloc\n"); dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (2 << 6) | (0 << 1); @@ -1589,11 +1596,11 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_PAR_GATED_CLK: if (prefer_mpeg_mux_use) { - dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux"); + dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Mpeg Mux\n"); dib8096p_configMpegMux(state, 2, 0, 0); dib8096p_setHostBusMux(state, MPEG_ON_HOSTBUS); } else { /* Use Smooth block */ - dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block"); + dprintk("dib8096P setting output mode TS_PARALLEL_GATED using Smooth block\n"); dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (0 << 6); @@ -1601,7 +1608,7 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) break; case OUTMODE_MPEG2_PAR_CONT_CLK: /* Using Smooth block only */ - dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block"); + dprintk("dib8096P setting output mode TS_PARALLEL_CONT using Smooth block\n"); dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (1 << 6); break; @@ -1609,7 +1616,7 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) case OUTMODE_MPEG2_FIFO: /* Using Smooth block because not supported by new Mpeg Mux bloc */ - dprintk("dib8096P setting output mode TS_FIFO using Smooth block"); + dprintk("dib8096P setting output mode TS_FIFO using Smooth block\n"); dib8096p_setHostBusMux(state, DEMOUT_ON_HOSTBUS); outreg |= (5 << 6); smo_mode |= (3 << 1); @@ -1617,13 +1624,13 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) break; case OUTMODE_DIVERSITY: - dprintk("dib8096P setting output mode MODE_DIVERSITY"); + dprintk("dib8096P setting output mode MODE_DIVERSITY\n"); dib8096p_setDibTxMux(state, DIV_ON_DIBTX); dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; case OUTMODE_ANALOG_ADC: - dprintk("dib8096P setting output mode MODE_ANALOG_ADC"); + dprintk("dib8096P setting output mode MODE_ANALOG_ADC\n"); dib8096p_setDibTxMux(state, ADC_ON_DIBTX); dib8096p_setHostBusMux(state, DIBTX_ON_HOSTBUS); break; @@ -1632,7 +1639,7 @@ static int dib8096p_set_output_mode(struct dvb_frontend *fe, int mode) if (mode != OUTMODE_HIGH_Z) outreg |= (1<<10); - dprintk("output_mpeg2_in_188_bytes = %d", + dprintk("output_mpeg2_in_188_bytes = %d\n", state->cfg.output_mpeg2_in_188_bytes); if (state->cfg.output_mpeg2_in_188_bytes) smo_mode |= (1 << 5); @@ -1678,7 +1685,7 @@ static int dib8096p_tuner_write_serpar(struct i2c_adapter *i2c_adap, n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; i--; if (i == 0) - dprintk("Tuner ITF: write busy (overflow)"); + dprintk("Tuner ITF: write busy (overflow)\n"); } dib8000_write_word(state, 1985, (1 << 6) | (serpar_num & 0x3f)); dib8000_write_word(state, 1986, (msg[0].buf[1] << 8) | msg[0].buf[2]); @@ -1699,7 +1706,7 @@ static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap, n_overflow = (dib8000_read_word(state, 1984) >> 1) & 0x1; i--; if (i == 0) - dprintk("TunerITF: read busy (overflow)"); + dprintk("TunerITF: read busy (overflow)\n"); } dib8000_write_word(state, 1985, (0<<6) | (serpar_num&0x3f)); @@ -1708,7 +1715,7 @@ static int dib8096p_tuner_read_serpar(struct i2c_adapter *i2c_adap, n_empty = dib8000_read_word(state, 1984)&0x1; i--; if (i == 0) - dprintk("TunerITF: read busy (empty)"); + dprintk("TunerITF: read busy (empty)\n"); } read_word = dib8000_read_word(state, 1987); @@ -1889,7 +1896,7 @@ static int dib8096p_tuner_sleep(struct dvb_frontend *fe, int onoff) struct dib8000_state *state = fe->demodulator_priv; u16 en_cur_state; - dprintk("sleep dib8096p: %d", onoff); + dprintk("sleep dib8096p: %d\n", onoff); en_cur_state = dib8000_read_word(state, 1922); @@ -1958,7 +1965,7 @@ static void dib8000_update_timf(struct dib8000_state *state) dib8000_write_word(state, 29, (u16) (timf >> 16)); dib8000_write_word(state, 30, (u16) (timf & 0xffff)); - dprintk("Updated timing frequency: %d (default: %d)", state->timf, state->timf_default); + dprintk("Updated timing frequency: %d (default: %d)\n", state->timf, state->timf_default); } static u32 dib8000_ctrl_timf(struct dvb_frontend *fe, uint8_t op, uint32_t timf) @@ -2118,7 +2125,7 @@ static u16 dib8000_get_init_prbs(struct dib8000_state *state, u16 subchannel) int sub_channel_prbs_group = 0; sub_channel_prbs_group = (subchannel / 3) + 1; - dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]); + dprintk("sub_channel_prbs_group = %d , subchannel =%d prbs = 0x%04x\n", sub_channel_prbs_group, subchannel, lut_prbs_8k[sub_channel_prbs_group]); switch (state->fe[0]->dtv_property_cache.transmission_mode) { case TRANSMISSION_MODE_2K: @@ -2604,7 +2611,7 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) slist = 0; } } - dprintk("Using list for autosearch : %d", slist); + dprintk("Using list for autosearch : %d\n", slist); dib8000_set_isdbt_common_channel(state, slist, 1); @@ -2638,17 +2645,17 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe) if ((state->revision >= 0x8002) && (state->autosearch_state == AS_SEARCHING_FFT)) { if (irq_pending & 0x1) { - dprintk("dib8000_autosearch_irq: max correlation result available"); + dprintk("dib8000_autosearch_irq: max correlation result available\n"); return 3; } } else { if (irq_pending & 0x1) { /* failed */ - dprintk("dib8000_autosearch_irq failed"); + dprintk("dib8000_autosearch_irq failed\n"); return 1; } if (irq_pending & 0x2) { /* succeeded */ - dprintk("dib8000_autosearch_irq succeeded"); + dprintk("dib8000_autosearch_irq succeeded\n"); return 2; } } @@ -2699,7 +2706,7 @@ static void dib8000_set_dds(struct dib8000_state *state, s32 offset_khz) dds += abs_offset_khz * unit_khz_dds_val; } - dprintk("setting a DDS frequency offset of %c%dkHz", invert ? '-' : ' ', dds / unit_khz_dds_val); + dprintk("setting a DDS frequency offset of %c%dkHz\n", invert ? '-' : ' ', dds / unit_khz_dds_val); if (abs_offset_khz <= (state->cfg.pll->internal / ratio)) { /* Max dds offset is the half of the demod freq */ @@ -2738,7 +2745,7 @@ static void dib8000_set_frequency_offset(struct dib8000_state *state) } } - dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz); + dprintk("%dkhz tuner offset (frequency = %dHz & current_rf = %dHz) total_dds_offset_hz = %d\n", c->frequency - current_rf, c->frequency, current_rf, total_dds_offset_khz); /* apply dds offset now */ dib8000_set_dds(state, total_dds_offset_khz); @@ -2890,7 +2897,7 @@ static u16 dib8000_read_lock(struct dvb_frontend *fe) static int dib8090p_init_sdram(struct dib8000_state *state) { u16 reg = 0; - dprintk("init sdram"); + dprintk("init sdram\n"); reg = dib8000_read_word(state, 274) & 0xfff0; dib8000_write_word(state, 274, reg | 0x7); /* P_dintlv_delay_ram = 7 because of MobileSdram */ @@ -2931,7 +2938,7 @@ static int is_manual_mode(struct dtv_frontend_properties *c) * Transmission mode is only detected on auto mode, currently */ if (c->transmission_mode == TRANSMISSION_MODE_AUTO) { - dprintk("transmission mode auto"); + dprintk("transmission mode auto\n"); return 0; } @@ -2939,7 +2946,7 @@ static int is_manual_mode(struct dtv_frontend_properties *c) * Guard interval is only detected on auto mode, currently */ if (c->guard_interval == GUARD_INTERVAL_AUTO) { - dprintk("guard interval auto"); + dprintk("guard interval auto\n"); return 0; } @@ -2948,7 +2955,7 @@ static int is_manual_mode(struct dtv_frontend_properties *c) * layer should be enabled */ if (!c->isdbt_layer_enabled) { - dprintk("no layer modulation specified"); + dprintk("no layer modulation specified\n"); return 0; } @@ -2970,7 +2977,7 @@ static int is_manual_mode(struct dtv_frontend_properties *c) if ((c->layer[i].modulation == QAM_AUTO) || (c->layer[i].fec == FEC_AUTO)) { - dprintk("layer %c has either modulation or FEC auto", + dprintk("layer %c has either modulation or FEC auto\n", 'A' + i); return 0; } @@ -2981,7 +2988,7 @@ static int is_manual_mode(struct dtv_frontend_properties *c) * fallback to auto mode. */ if (n_segs == 0 || n_segs > 13) { - dprintk("number of segments is invalid"); + dprintk("number of segments is invalid\n"); return 0; } @@ -3009,7 +3016,7 @@ static int dib8000_tune(struct dvb_frontend *fe) #if 0 if (*tune_state < CT_DEMOD_STOP) - dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu", + dprintk("IN: context status = %d, TUNE_STATE %d autosearch step = %u jiffies = %lu\n", state->channel_parameters_set, *tune_state, state->autosearch_state, now); #endif @@ -3022,7 +3029,7 @@ static int dib8000_tune(struct dvb_frontend *fe) state->status = FE_STATUS_TUNE_PENDING; state->channel_parameters_set = is_manual_mode(c); - dprintk("Tuning channel on %s search mode", + dprintk("Tuning channel on %s search mode\n", state->channel_parameters_set ? "manual" : "auto"); dib8000_viterbi_state(state, 0); /* force chan dec in restart */ @@ -3102,7 +3109,7 @@ static int dib8000_tune(struct dvb_frontend *fe) corm[1] = (dib8000_read_word(state, 596) << 16) | (dib8000_read_word(state, 597)); corm[0] = (dib8000_read_word(state, 598) << 16) | (dib8000_read_word(state, 599)); } - /* dprintk("corm fft: %u %u %u", corm[0], corm[1], corm[2]); */ + /* dprintk("corm fft: %u %u %u\n", corm[0], corm[1], corm[2]); */ max_value = 0; for (find_index = 1 ; find_index < 3 ; find_index++) { @@ -3122,7 +3129,7 @@ static int dib8000_tune(struct dvb_frontend *fe) state->found_nfft = TRANSMISSION_MODE_8K; break; } - /* dprintk("Autosearch FFT has found Mode %d", max_value + 1); */ + /* dprintk("Autosearch FFT has found Mode %d\n", max_value + 1); */ *tune_state = CT_DEMOD_SEARCH_NEXT; state->autosearch_state = AS_SEARCHING_GUARD; @@ -3137,7 +3144,7 @@ static int dib8000_tune(struct dvb_frontend *fe) state->found_guard = dib8000_read_word(state, 572) & 0x3; else state->found_guard = dib8000_read_word(state, 570) & 0x3; - /* dprintk("guard interval found=%i", state->found_guard); */ + /* dprintk("guard interval found=%i\n", state->found_guard); */ *tune_state = CT_DEMOD_STEP_3; break; @@ -3233,7 +3240,7 @@ static int dib8000_tune(struct dvb_frontend *fe) /* defines timeout for mpeg lock depending on interleaver length of longest layer */ for (i = 0; i < 3; i++) { if (c->layer[i].interleaving >= deeper_interleaver) { - dprintk("layer%i: time interleaver = %d ", i, c->layer[i].interleaving); + dprintk("layer%i: time interleaver = %d\n", i, c->layer[i].interleaving); if (c->layer[i].segment_count > 0) { /* valid layer */ deeper_interleaver = c->layer[0].interleaving; state->longest_intlv_layer = i; @@ -3252,7 +3259,7 @@ static int dib8000_tune(struct dvb_frontend *fe) locks *= 2; *timeout = now + msecs_to_jiffies(200 * locks); /* give the mpeg lock 800ms if sram is present */ - dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld", + dprintk("Deeper interleaver mode = %d on layer %d : timeout mult factor = %d => will use timeout = %ld\n", deeper_interleaver, state->longest_intlv_layer, locks, *timeout); *tune_state = CT_DEMOD_STEP_10; @@ -3263,7 +3270,7 @@ static int dib8000_tune(struct dvb_frontend *fe) case CT_DEMOD_STEP_10: /* 40 */ locks = dib8000_read_lock(fe); if (locks&(1<<(7-state->longest_intlv_layer))) { /* mpeg lock : check the longest one */ - dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s", + dprintk("ISDB-T layer locks: Layer A %s, Layer B %s, Layer C %s\n", c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", c->layer[2].segment_count ? (locks >> 5) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled"); @@ -3283,7 +3290,7 @@ static int dib8000_tune(struct dvb_frontend *fe) *tune_state = CT_DEMOD_STEP_11; } else { /* we are done mpeg of the longest interleaver xas not locking but let's try if an other layer has locked in the same time */ if (locks & (0x7 << 5)) { - dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s", + dprintk("Not all ISDB-T layers locked in %d ms: Layer A %s, Layer B %s, Layer C %s\n", jiffies_to_msecs(now - *timeout), c->layer[0].segment_count ? (locks >> 7) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", c->layer[1].segment_count ? (locks >> 6) & 0x1 ? "locked" : "NOT LOCKED" : "not enabled", @@ -3348,7 +3355,7 @@ static int dib8000_wakeup(struct dvb_frontend *fe) dib8000_set_power_mode(state, DIB8000_POWER_ALL); dib8000_set_adc_state(state, DIBX000_ADC_ON); if (dib8000_set_adc_state(state, DIBX000_SLOW_ADC_ON) != 0) - dprintk("could not start Slow ADC"); + dprintk("could not start Slow ADC\n"); if (state->revision == 0x8090) dib8000_sad_calib(state); @@ -3401,11 +3408,11 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, if (!(stat & FE_HAS_SYNC)) return 0; - dprintk("dib8000_get_frontend: TMCC lock"); + dprintk("dib8000_get_frontend: TMCC lock\n"); for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); if (stat&FE_HAS_SYNC) { - dprintk("TMCC lock on the slave%i", index_frontend); + dprintk("TMCC lock on the slave%i\n", index_frontend); /* synchronize the cache with the other frontends */ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c); for (sub_index_frontend = 0; (sub_index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[sub_index_frontend] != NULL); sub_index_frontend++) { @@ -3437,41 +3444,41 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, switch ((val & 0x30) >> 4) { case 1: c->transmission_mode = TRANSMISSION_MODE_2K; - dprintk("dib8000_get_frontend: transmission mode 2K"); + dprintk("dib8000_get_frontend: transmission mode 2K\n"); break; case 2: c->transmission_mode = TRANSMISSION_MODE_4K; - dprintk("dib8000_get_frontend: transmission mode 4K"); + dprintk("dib8000_get_frontend: transmission mode 4K\n"); break; case 3: default: c->transmission_mode = TRANSMISSION_MODE_8K; - dprintk("dib8000_get_frontend: transmission mode 8K"); + dprintk("dib8000_get_frontend: transmission mode 8K\n"); break; } switch (val & 0x3) { case 0: c->guard_interval = GUARD_INTERVAL_1_32; - dprintk("dib8000_get_frontend: Guard Interval = 1/32 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/32\n"); break; case 1: c->guard_interval = GUARD_INTERVAL_1_16; - dprintk("dib8000_get_frontend: Guard Interval = 1/16 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/16\n"); break; case 2: - dprintk("dib8000_get_frontend: Guard Interval = 1/8 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/8\n"); c->guard_interval = GUARD_INTERVAL_1_8; break; case 3: - dprintk("dib8000_get_frontend: Guard Interval = 1/4 "); + dprintk("dib8000_get_frontend: Guard Interval = 1/4\n"); c->guard_interval = GUARD_INTERVAL_1_4; break; } val = dib8000_read_word(state, 505); c->isdbt_partial_reception = val & 1; - dprintk("dib8000_get_frontend: partial_reception = %d ", c->isdbt_partial_reception); + dprintk("dib8000_get_frontend: partial_reception = %d\n", c->isdbt_partial_reception); for (i = 0; i < 3; i++) { int show; @@ -3485,7 +3492,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, show = 1; if (show) - dprintk("dib8000_get_frontend: Layer %d segments = %d ", + dprintk("dib8000_get_frontend: Layer %d segments = %d\n", i, c->layer[i].segment_count); val = dib8000_read_word(state, 499 + i) & 0x3; @@ -3494,7 +3501,7 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, val = 4; c->layer[i].interleaving = val; if (show) - dprintk("dib8000_get_frontend: Layer %d time_intlv = %d ", + dprintk("dib8000_get_frontend: Layer %d time_intlv = %d\n", i, c->layer[i].interleaving); val = dib8000_read_word(state, 481 + i); @@ -3502,27 +3509,27 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, case 1: c->layer[i].fec = FEC_1_2; if (show) - dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2 ", i); + dprintk("dib8000_get_frontend: Layer %d Code Rate = 1/2\n", i); break; case 2: c->layer[i].fec = FEC_2_3; if (show) - dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3 ", i); + dprintk("dib8000_get_frontend: Layer %d Code Rate = 2/3\n", i); break; case 3: c->layer[i].fec = FEC_3_4; if (show) - dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4 ", i); + dprintk("dib8000_get_frontend: Layer %d Code Rate = 3/4\n", i); break; case 5: c->layer[i].fec = FEC_5_6; if (show) - dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6 ", i); + dprintk("dib8000_get_frontend: Layer %d Code Rate = 5/6\n", i); break; default: c->layer[i].fec = FEC_7_8; if (show) - dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8 ", i); + dprintk("dib8000_get_frontend: Layer %d Code Rate = 7/8\n", i); break; } @@ -3531,23 +3538,23 @@ static int dib8000_get_frontend(struct dvb_frontend *fe, case 0: c->layer[i].modulation = DQPSK; if (show) - dprintk("dib8000_get_frontend: Layer %d DQPSK ", i); + dprintk("dib8000_get_frontend: Layer %d DQPSK\n", i); break; case 1: c->layer[i].modulation = QPSK; if (show) - dprintk("dib8000_get_frontend: Layer %d QPSK ", i); + dprintk("dib8000_get_frontend: Layer %d QPSK\n", i); break; case 2: c->layer[i].modulation = QAM_16; if (show) - dprintk("dib8000_get_frontend: Layer %d QAM16 ", i); + dprintk("dib8000_get_frontend: Layer %d QAM16\n", i); break; case 3: default: c->layer[i].modulation = QAM_64; if (show) - dprintk("dib8000_get_frontend: Layer %d QAM64 ", i); + dprintk("dib8000_get_frontend: Layer %d QAM64\n", i); break; } } @@ -3578,12 +3585,12 @@ static int dib8000_set_frontend(struct dvb_frontend *fe) unsigned long delay, callback_time; if (c->frequency == 0) { - dprintk("dib8000: must at least specify frequency "); + dprintk("dib8000: must at least specify frequency\n"); return 0; } if (c->bandwidth_hz == 0) { - dprintk("dib8000: no bandwidth specified, set to default "); + dprintk("dib8000: no bandwidth specified, set to default\n"); c->bandwidth_hz = 6000000; } @@ -3671,7 +3678,7 @@ static int dib8000_set_frontend(struct dvb_frontend *fe) /* we are in autosearch */ if (state->channel_parameters_set == 0) { /* searching */ if ((dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_DEMOD_SUCCESS) || (dib8000_get_status(state->fe[index_frontend]) == FE_STATUS_FFT_SUCCESS)) { - dprintk("autosearch succeeded on fe%i", index_frontend); + dprintk("autosearch succeeded on fe%i\n", index_frontend); dib8000_get_frontend(state->fe[index_frontend], c); /* we read the channel parameters from the frontend which was successful */ state->channel_parameters_set = 1; @@ -3708,11 +3715,11 @@ static int dib8000_set_frontend(struct dvb_frontend *fe) active = 1; } if (active == 0) - dprintk("tuning done with status %d", dib8000_get_status(state->fe[0])); + dprintk("tuning done with status %d\n", dib8000_get_status(state->fe[0])); } if ((active == 1) && (callback_time == 0)) { - dprintk("strange callback time something went wrong"); + dprintk("strange callback time something went wrong\n"); active = 0; } @@ -4172,7 +4179,7 @@ static int dib8000_get_stats(struct dvb_frontend *fe, enum fe_status stat) time_us = dib8000_get_time_us(fe, -1); state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000); - dprintk("Next all layers stats available in %u us.", time_us); + dprintk("Next all layers stats available in %u us.\n", time_us); dib8000_read_ber(fe, &val); c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; @@ -4239,12 +4246,12 @@ static int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_fronte while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) index_frontend++; if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { - dprintk("set slave fe %p to index %i", fe_slave, index_frontend); + dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend); state->fe[index_frontend] = fe_slave; return 0; } - dprintk("too many slave frontend"); + dprintk("too many slave frontend\n"); return -ENOMEM; } @@ -4256,12 +4263,12 @@ static int dib8000_remove_slave_frontend(struct dvb_frontend *fe) while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) index_frontend++; if (index_frontend != 1) { - dprintk("remove slave fe %p (index %i)", state->fe[index_frontend-1], index_frontend-1); + dprintk("remove slave fe %p (index %i)\n", state->fe[index_frontend-1], index_frontend-1); state->fe[index_frontend] = NULL; return 0; } - dprintk("no frontend to be removed"); + dprintk("no frontend to be removed\n"); return -ENODEV; } @@ -4283,18 +4290,18 @@ static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); if (!client.i2c_write_buffer) { - dprintk("%s: not enough memory", __func__); + dprintk("%s: not enough memory\n", __func__); return -ENOMEM; } client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); if (!client.i2c_read_buffer) { - dprintk("%s: not enough memory", __func__); + dprintk("%s: not enough memory\n", __func__); ret = -ENOMEM; goto error_memory_read; } client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL); if (!client.i2c_buffer_lock) { - dprintk("%s: not enough memory", __func__); + dprintk("%s: not enough memory\n", __func__); ret = -ENOMEM; goto error_memory_lock; } @@ -4313,7 +4320,7 @@ static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, dib8000_i2c_write16(&client, 1287, 0x0003); client.addr = default_addr; if (dib8000_identify(&client) == 0) { - dprintk("#%d: not identified", k); + dprintk("#%d: not identified\n", k); ret = -EINVAL; goto error; } @@ -4327,7 +4334,7 @@ static int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, client.addr = new_addr; dib8000_identify(&client); - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -4385,14 +4392,14 @@ static int dib8000_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) u16 val = dib8000_read_word(st, 299) & 0xffef; val |= (onoff & 0x1) << 4; - dprintk("pid filter enabled %d", onoff); + dprintk("pid filter enabled %d\n", onoff); return dib8000_write_word(st, 299, val); } static int dib8000_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) { struct dib8000_state *st = fe->demodulator_priv; - dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff); return dib8000_write_word(st, 305 + id, onoff ? (1 << 13) | pid : 0); } @@ -4431,7 +4438,7 @@ static struct dvb_frontend *dib8000_init(struct i2c_adapter *i2c_adap, u8 i2c_ad struct dvb_frontend *fe; struct dib8000_state *state; - dprintk("dib8000_init"); + dprintk("dib8000_init\n"); state = kzalloc(sizeof(struct dib8000_state), GFP_KERNEL); if (state == NULL) -- cgit v1.2.3 From 3dd722622f1d2a795d8cb196eb245fab1946bee2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 10:08:40 -0300 Subject: [media] dib9000: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, instead of directly calling printk(), use pr_foo() macros, adding a\n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dib9000.c | 171 ++++++++++++++++++---------------- 1 file changed, 89 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 5897977d2d00..3c76ceb6c374 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -7,6 +7,9 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation, version 2. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -21,7 +24,12 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiB9000: "); printk(args); printk("\n"); } } while (0) +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) + #define MAX_NUMBER_OF_FRONTENDS 6 struct i2c_device { @@ -258,7 +266,7 @@ static int dib9000_read16_attr(struct dib9000_state *state, u16 reg, u8 *b, u32 state->msg[1].buf = b; ret = i2c_transfer(state->i2c.i2c_adap, state->msg, 2) != 2 ? -EREMOTEIO : 0; if (ret != 0) { - dprintk("i2c read error on %d", reg); + dprintk("i2c read error on %d\n", reg); return -EREMOTEIO; } @@ -285,7 +293,7 @@ static u16 dib9000_i2c_read16(struct i2c_device *i2c, u16 reg) i2c->i2c_write_buffer[1] = reg & 0xff; if (i2c_transfer(i2c->i2c_adap, msg, 2) != 2) { - dprintk("read register %x error", reg); + dprintk("read register %x error\n", reg); return 0; } @@ -440,7 +448,7 @@ static int dib9000_risc_mem_read(struct dib9000_state *state, u8 cmd, u8 * b, u1 return -EIO; if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } dib9000_risc_mem_setup(state, cmd | 0x80); @@ -456,7 +464,7 @@ static int dib9000_risc_mem_write(struct dib9000_state *state, u8 cmd, const u8 return -EIO; if (mutex_lock_interruptible(&state->platform.risc.mem_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } dib9000_risc_mem_setup(state, cmd); @@ -479,13 +487,13 @@ static int dib9000_firmware_download(struct dib9000_state *state, u8 risc_id, u1 dib9000_write_word(state, 1025 + offs, 0); dib9000_write_word(state, 1031 + offs, key); - dprintk("going to download %dB of microcode", len); + dprintk("going to download %dB of microcode\n", len); if (dib9000_write16_noinc(state, 1026 + offs, (u8 *) code, (u16) len) != 0) { - dprintk("error while downloading microcode for RISC %c", 'A' + risc_id); + dprintk("error while downloading microcode for RISC %c\n", 'A' + risc_id); return -EIO; } - dprintk("Microcode for RISC %c loaded", 'A' + risc_id); + dprintk("Microcode for RISC %c loaded\n", 'A' + risc_id); return 0; } @@ -511,10 +519,10 @@ static int dib9000_mbx_host_init(struct dib9000_state *state, u8 risc_id) } while ((reset_reg & 0x8000) && --tries); if (reset_reg & 0x8000) { - dprintk("MBX: init ERROR, no response from RISC %c", 'A' + risc_id); + dprintk("MBX: init ERROR, no response from RISC %c\n", 'A' + risc_id); return -EIO; } - dprintk("MBX: initialized"); + dprintk("MBX: initialized\n"); return 0; } @@ -531,30 +539,27 @@ static int dib9000_mbx_send_attr(struct dib9000_state *state, u8 id, u16 * data, return -EINVAL; if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } tmp = MAX_MAILBOX_TRY; do { size = dib9000_read_word_attr(state, 1043, attr) & 0xff; if ((size + len + 1) > MBX_MAX_WORDS && --tmp) { - dprintk("MBX: RISC mbx full, retrying"); + dprintk("MBX: RISC mbx full, retrying\n"); msleep(100); } else break; } while (1); - /*dprintk( "MBX: size: %d", size); */ + /*dprintk( "MBX: size: %d\n", size); */ if (tmp == 0) { ret = -EINVAL; goto out; } #ifdef DUMP_MSG - dprintk("--> %02x %d ", id, len + 1); - for (i = 0; i < len; i++) - dprintk("%04x ", data[i]); - dprintk("\n"); + dprintk("--> %02x %d %*ph\n", id, len + 1, len, data); #endif /* byte-order conversion - works on big (where it is not necessary) or little endian */ @@ -596,7 +601,7 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, return 0; if (mutex_lock_interruptible(&state->platform.risc.mbx_if_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return 0; } if (risc_id == 1) @@ -622,13 +627,13 @@ static u8 dib9000_mbx_read(struct dib9000_state *state, u16 * data, u8 risc_id, } #ifdef DUMP_MSG - dprintk("<-- "); + dprintk("<--\n"); for (i = 0; i < size + 1; i++) - dprintk("%04x ", d[i]); + dprintk("%04x\n", d[i]); dprintk("\n"); #endif } else { - dprintk("MBX: message is too big for message cache (%d), flushing message", size); + dprintk("MBX: message is too big for message cache (%d), flushing message\n", size); size--; /* Initial word already read */ while (size--) dib9000_read16_noinc_attr(state, 1029 + mc_base, (u8 *) data, 2, attr); @@ -649,9 +654,11 @@ static int dib9000_risc_debug_buf(struct dib9000_state *state, u16 * data, u8 si b[2 * (size - 2) - 1] = '\0'; /* Bullet proof the buffer */ if (*b == '~') { b++; - dprintk("%s", b); + dprintk("%s\n", b); } else - dprintk("RISC%d: %d.%04d %s", state->fe_id, ts / 10000, ts % 10000, *b ? b : ""); + dprintk("RISC%d: %d.%04d %s\n", + state->fe_id, + ts / 10000, ts % 10000, *b ? b : ""); return 1; } @@ -666,7 +673,7 @@ static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) if (*block == 0) { size = dib9000_mbx_read(state, block, 1, attr); -/* dprintk( "MBX: fetched %04x message to cache", *block); */ +/* dprintk( "MBX: fetched %04x message to cache\n", *block); */ switch (*block >> 8) { case IN_MSG_DEBUG_BUF: @@ -686,7 +693,7 @@ static int dib9000_mbx_fetch_to_cache(struct dib9000_state *state, u16 attr) return 1; } } - dprintk("MBX: no free cache-slot found for new message..."); + dprintk("MBX: no free cache-slot found for new message...\n"); return -1; } @@ -706,7 +713,7 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) return -1; if (mutex_lock_interruptible(&state->platform.risc.mbx_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -1; } @@ -715,7 +722,7 @@ static int dib9000_mbx_process(struct dib9000_state *state, u16 attr) dib9000_read_word_attr(state, 1229, attr); /* Clear the IRQ */ /* if (tmp) */ -/* dprintk( "cleared IRQ: %x", tmp); */ +/* dprintk( "cleared IRQ: %x\n", tmp); */ mutex_unlock(&state->platform.risc.mbx_lock); return ret; @@ -750,7 +757,7 @@ static int dib9000_mbx_get_message_attr(struct dib9000_state *state, u16 id, u16 } while (--timeout); if (timeout == 0) { - dprintk("waiting for message %d timed out", id); + dprintk("waiting for message %d timed out\n", id); return -1; } @@ -770,7 +777,7 @@ static int dib9000_risc_check_version(struct dib9000_state *state) return -EIO; fw_version = (r[0] << 8) | r[1]; - dprintk("RISC: ver: %d.%02d (IC: %d)", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]); + dprintk("RISC: ver: %d.%02d (IC: %d)\n", fw_version >> 10, fw_version & 0x3ff, (r[2] << 8) | r[3]); if ((fw_version >> 10) != 7) return -EINVAL; @@ -850,40 +857,40 @@ static u16 dib9000_identify(struct i2c_device *client) value = dib9000_i2c_read16(client, 896); if (value != 0x01b3) { - dprintk("wrong Vendor ID (0x%x)", value); + dprintk("wrong Vendor ID (0x%x)\n", value); return 0; } value = dib9000_i2c_read16(client, 897); if (value != 0x4000 && value != 0x4001 && value != 0x4002 && value != 0x4003 && value != 0x4004 && value != 0x4005) { - dprintk("wrong Device ID (0x%x)", value); + dprintk("wrong Device ID (0x%x)\n", value); return 0; } /* protect this driver to be used with 7000PC */ if (value == 0x4000 && dib9000_i2c_read16(client, 769) == 0x4000) { - dprintk("this driver does not work with DiB7000PC"); + dprintk("this driver does not work with DiB7000PC\n"); return 0; } switch (value) { case 0x4000: - dprintk("found DiB7000MA/PA/MB/PB"); + dprintk("found DiB7000MA/PA/MB/PB\n"); break; case 0x4001: - dprintk("found DiB7000HC"); + dprintk("found DiB7000HC\n"); break; case 0x4002: - dprintk("found DiB7000MC"); + dprintk("found DiB7000MC\n"); break; case 0x4003: - dprintk("found DiB9000A"); + dprintk("found DiB9000A\n"); break; case 0x4004: - dprintk("found DiB9000H"); + dprintk("found DiB9000H\n"); break; case 0x4005: - dprintk("found DiB9000M"); + dprintk("found DiB9000M\n"); break; } @@ -1013,7 +1020,7 @@ static int dib9000_risc_apb_access_read(struct dib9000_state *state, u32 address if (address >= 1024 || !state->platform.risc.fw_is_running) return -EINVAL; - /* dprintk( "APB access thru rd fw %d %x", address, attribute); */ + /* dprintk( "APB access thru rd fw %d %x\n", address, attribute); */ mb[0] = (u16) address; mb[1] = len / 2; @@ -1043,7 +1050,7 @@ static int dib9000_risc_apb_access_write(struct dib9000_state *state, u32 addres if (len > 18) return -EINVAL; - /* dprintk( "APB access thru wr fw %d %x", address, attribute); */ + /* dprintk( "APB access thru wr fw %d %x\n", address, attribute); */ mb[0] = (u16)address; for (i = 0; i + 1 < len; i += 2) @@ -1191,7 +1198,7 @@ static int dib9000_fw_get_channel(struct dvb_frontend *fe) int ret = 0; if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { @@ -1534,7 +1541,7 @@ static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) struct dib9000_state *state = fe->demodulator_priv; u16 outreg, smo_mode; - dprintk("setting output mode for demod %p to %d", fe, mode); + dprintk("setting output mode for demod %p to %d\n", fe, mode); switch (mode) { case OUTMODE_MPEG2_PAR_GATED_CLK: @@ -1556,7 +1563,7 @@ static int dib9000_fw_set_output_mode(struct dvb_frontend *fe, int mode) outreg = 0; break; default: - dprintk("Unhandled output_mode passed to be set for demod %p", &state->fe[0]); + dprintk("Unhandled output_mode passed to be set for demod %p\n", &state->fe[0]); return -EINVAL; } @@ -1590,7 +1597,7 @@ static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] len = 16; if (dib9000_read_word(state, 790) != 0) - dprintk("TunerITF: read busy"); + dprintk("TunerITF: read busy\n"); dib9000_write_word(state, 784, (u16) (msg[index_msg].addr)); dib9000_write_word(state, 787, (len / 2) - 1); @@ -1601,7 +1608,7 @@ static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] i--; if (i == 0) - dprintk("TunerITF: read failed"); + dprintk("TunerITF: read failed\n"); for (i = 0; i < len; i += 2) { t = dib9000_read_word(state, 785); @@ -1609,13 +1616,13 @@ static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] msg[index_msg].buf[i + 1] = (t) & 0xff; } if (dib9000_read_word(state, 790) != 0) - dprintk("TunerITF: read more data than expected"); + dprintk("TunerITF: read more data than expected\n"); } else { i = 1000; while (dib9000_read_word(state, 789) && i) i--; if (i == 0) - dprintk("TunerITF: write busy"); + dprintk("TunerITF: write busy\n"); len = msg[index_msg].len; if (len > 16) @@ -1631,7 +1638,7 @@ static int dib9000_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[] while (dib9000_read_word(state, 791) > 0 && i) i--; if (i == 0) - dprintk("TunerITF: write failed"); + dprintk("TunerITF: write failed\n"); } } return num; @@ -1676,7 +1683,7 @@ static int dib9000_fw_component_bus_xfer(struct i2c_adapter *i2c_adap, struct i2 } if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return 0; } @@ -1759,7 +1766,7 @@ static int dib9000_cfg_gpio(struct dib9000_state *st, u8 num, u8 dir, u8 val) st->gpio_val |= (val & 0x01) << num; /* set the new value */ dib9000_write_word(st, 774, st->gpio_val); - dprintk("gpio dir: %04x: gpio val: %04x", st->gpio_dir, st->gpio_val); + dprintk("gpio dir: %04x: gpio val: %04x\n", st->gpio_dir, st->gpio_val); return 0; } @@ -1779,7 +1786,7 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) { /* postpone the pid filtering cmd */ - dprintk("pid filter cmd postpone"); + dprintk("pid filter cmd postpone\n"); state->pid_ctrl_index++; state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL; state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; @@ -1787,14 +1794,14 @@ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff) } if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } val = dib9000_read_word(state, 294 + 1) & 0xffef; val |= (onoff & 0x1) << 4; - dprintk("PID filter enabled %d", onoff); + dprintk("PID filter enabled %d\n", onoff); ret = dib9000_write_word(state, 294 + 1, val); mutex_unlock(&state->demod_lock); return ret; @@ -1809,7 +1816,7 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) if (state->pid_ctrl_index != -2) { /* postpone the pid filtering cmd */ - dprintk("pid filter postpone"); + dprintk("pid filter postpone\n"); if (state->pid_ctrl_index < 9) { state->pid_ctrl_index++; state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER; @@ -1817,15 +1824,15 @@ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff) state->pid_ctrl[state->pid_ctrl_index].pid = pid; state->pid_ctrl[state->pid_ctrl_index].onoff = onoff; } else - dprintk("can not add any more pid ctrl cmd"); + dprintk("can not add any more pid ctrl cmd\n"); return 0; } if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } - dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff); + dprintk("Index %x, PID %d, OnOff %d\n", id, pid, onoff); ret = dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0); mutex_unlock(&state->demod_lock); @@ -1868,7 +1875,7 @@ static int dib9000_sleep(struct dvb_frontend *fe) int ret = 0; if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { @@ -1899,7 +1906,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, if (state->get_frontend_internal == 0) { if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } } @@ -1907,7 +1914,7 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) { state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat); if (stat & FE_HAS_SYNC) { - dprintk("TPS lock on the slave%i", index_frontend); + dprintk("TPS lock on the slave%i\n", index_frontend); /* synchronize the cache with the other frontends */ state->fe[index_frontend]->ops.get_frontend(state->fe[index_frontend], c); @@ -1995,18 +2002,18 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) /* check that the correct parameters are set */ if (state->fe[0]->dtv_property_cache.frequency == 0) { - dprintk("dib9000: must specify frequency "); + dprintk("dib9000: must specify frequency\n"); return 0; } if (state->fe[0]->dtv_property_cache.bandwidth_hz == 0) { - dprintk("dib9000: must specify bandwidth "); + dprintk("dib9000: must specify bandwidth\n"); return 0; } state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */ if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return 0; } @@ -2073,14 +2080,14 @@ static int dib9000_set_frontend(struct dvb_frontend *fe) /* check the tune result */ if (exit_condition == 1) { /* tune failed */ - dprintk("tune failed"); + dprintk("tune failed\n"); mutex_unlock(&state->demod_lock); /* tune failed; put all the pid filtering cmd to junk */ state->pid_ctrl_index = -1; return 0; } - dprintk("tune success on frontend%i", index_frontend_success); + dprintk("tune success on frontend%i\n", index_frontend_success); /* synchronize all the channel cache */ state->get_frontend_internal = 1; @@ -2169,7 +2176,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, enum fe_status *stat) u16 lock = 0, lock_slave = 0; if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) @@ -2202,11 +2209,11 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber) int ret = 0; if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); ret = -EINTR; goto error; } @@ -2237,7 +2244,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) int ret = 0; if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } *strength = 0; @@ -2250,7 +2257,7 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength) } if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); ret = -EINTR; goto error; } @@ -2281,7 +2288,7 @@ static u32 dib9000_get_snr(struct dvb_frontend *fe) u16 val; if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return 0; } if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) { @@ -2320,7 +2327,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr) u32 snr_master; if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } snr_master = dib9000_get_snr(fe); @@ -2345,11 +2352,11 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc) int ret = 0; if (mutex_lock_interruptible(&state->demod_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); return -EINTR; } if (mutex_lock_interruptible(&state->platform.risc.mem_mbx_lock) < 0) { - dprintk("could not get the lock"); + dprintk("could not get the lock\n"); ret = -EINTR; goto error; } @@ -2376,12 +2383,12 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul client.i2c_write_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); if (!client.i2c_write_buffer) { - dprintk("%s: not enough memory", __func__); + dprintk("%s: not enough memory\n", __func__); return -ENOMEM; } client.i2c_read_buffer = kzalloc(4 * sizeof(u8), GFP_KERNEL); if (!client.i2c_read_buffer) { - dprintk("%s: not enough memory", __func__); + dprintk("%s: not enough memory\n", __func__); ret = -ENOMEM; goto error_memory; } @@ -2408,7 +2415,7 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul if (dib9000_identify(&client) == 0) { client.i2c_addr = default_addr; if (dib9000_identify(&client) == 0) { - dprintk("DiB9000 #%d: not identified", k); + dprintk("DiB9000 #%d: not identified\n", k); ret = -EIO; goto error; } @@ -2417,7 +2424,7 @@ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defaul dib9000_i2c_write16(&client, 1795, (1 << 10) | (4 << 6)); dib9000_i2c_write16(&client, 1794, (new_addr << 2) | 2); - dprintk("IC %d initialized (to i2c_address 0x%x)", k, new_addr); + dprintk("IC %d initialized (to i2c_address 0x%x)\n", k, new_addr); } for (k = 0; k < no_of_demods; k++) { @@ -2445,12 +2452,12 @@ int dib9000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_ while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) index_frontend++; if (index_frontend < MAX_NUMBER_OF_FRONTENDS) { - dprintk("set slave fe %p to index %i", fe_slave, index_frontend); + dprintk("set slave fe %p to index %i\n", fe_slave, index_frontend); state->fe[index_frontend] = fe_slave; return 0; } - dprintk("too many slave frontend"); + dprintk("too many slave frontend\n"); return -ENOMEM; } EXPORT_SYMBOL(dib9000_set_slave_frontend); @@ -2463,12 +2470,12 @@ int dib9000_remove_slave_frontend(struct dvb_frontend *fe) while ((index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL)) index_frontend++; if (index_frontend != 1) { - dprintk("remove slave fe %p (index %i)", state->fe[index_frontend - 1], index_frontend - 1); + dprintk("remove slave fe %p (index %i)\n", state->fe[index_frontend - 1], index_frontend - 1); state->fe[index_frontend] = NULL; return 0; } - dprintk("no frontend to be removed"); + dprintk("no frontend to be removed\n"); return -ENODEV; } EXPORT_SYMBOL(dib9000_remove_slave_frontend); -- cgit v1.2.3 From 0a6dc89ae403cb41872249d3d85efa6d50f7f097 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 10:28:42 -0300 Subject: [media] dibx000_common: use pr_foo() instead of printk() The dprintk() macro relies on continuation lines. This is not a good practice and will break after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, instead of directly calling printk(), use pr_foo() macros, adding a \n leading char on each macro call. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dibx000_common.c | 36 +++++++++++++++------------- 1 file changed, 19 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c index 723358d7ca84..7db908ed87f6 100644 --- a/drivers/media/dvb-frontends/dibx000_common.c +++ b/drivers/media/dvb-frontends/dibx000_common.c @@ -1,3 +1,5 @@ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -8,14 +10,18 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); -#define dprintk(args...) do { if (debug) { printk(KERN_DEBUG "DiBX000: "); printk(args); printk("\n"); } } while (0) +#define dprintk(fmt, arg...) do { \ + if (debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), \ + __func__, ##arg); \ +} while (0) static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val) { int ret; if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -41,7 +47,7 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) u16 ret; if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return 0; } @@ -59,7 +65,7 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) mst->msg[1].len = 2; if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2) - dprintk("i2c read error on %d", reg); + dprintk("i2c read error on %d\n", reg); ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1]; mutex_unlock(&mst->i2c_buffer_lock); @@ -192,7 +198,7 @@ static int dibx000_i2c_select_interface(struct dibx000_i2c_master *mst, enum dibx000_i2c_interface intf) { if (mst->device_rev > DIB3000MC && mst->selected_interface != intf) { - dprintk("selecting interface: %d", intf); + dprintk("selecting interface: %d\n", intf); mst->selected_interface = intf; return dibx000_write_word(mst, mst->base_reg + 4, intf); } @@ -290,7 +296,7 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } @@ -337,7 +343,7 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num)); @@ -391,7 +397,7 @@ struct i2c_adapter *dibx000_get_i2c_adapter(struct dibx000_i2c_master *mst, i2c = &mst->master_i2c_adap_gpio67; break; default: - printk(KERN_ERR "DiBX000: incorrect I2C interface selected\n"); + pr_err("incorrect I2C interface selected\n"); break; } @@ -434,7 +440,7 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, mutex_init(&mst->i2c_buffer_lock); if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) { - dprintk("could not acquire lock"); + dprintk("could not acquire lock\n"); return -EINVAL; } memset(mst->msg, 0, sizeof(struct i2c_msg)); @@ -456,29 +462,25 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, if (i2c_adapter_init (&mst->gated_tuner_i2c_adap, &dibx000_i2c_gated_tuner_algo, "DiBX000 tuner I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the tuner i2c_adapter\n"); + pr_err("could not initialize the tuner i2c_adapter\n"); mst->master_i2c_adap_gpio12.dev.parent = mst->i2c_adap->dev.parent; if (i2c_adapter_init (&mst->master_i2c_adap_gpio12, &dibx000_i2c_master_gpio12_xfer_algo, "DiBX000 master GPIO12 I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the master i2c_adapter\n"); + pr_err("could not initialize the master i2c_adapter\n"); mst->master_i2c_adap_gpio34.dev.parent = mst->i2c_adap->dev.parent; if (i2c_adapter_init (&mst->master_i2c_adap_gpio34, &dibx000_i2c_master_gpio34_xfer_algo, "DiBX000 master GPIO34 I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the master i2c_adapter\n"); + pr_err("could not initialize the master i2c_adapter\n"); mst->master_i2c_adap_gpio67.dev.parent = mst->i2c_adap->dev.parent; if (i2c_adapter_init (&mst->master_i2c_adap_gpio67, &dibx000_i2c_gated_gpio67_algo, "DiBX000 master GPIO67 I2C bus", mst) != 0) - printk(KERN_ERR - "DiBX000: could not initialize the master i2c_adapter\n"); + pr_err("could not initialize the master i2c_adapter\n"); /* initialize the i2c-master by closing the gate */ dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0); -- cgit v1.2.3 From bdecf76e319a29735d828575f4a9269f0e17c547 Mon Sep 17 00:00:00 2001 From: Frederic Barrat Date: Fri, 18 Nov 2016 23:00:31 +1100 Subject: cxl: Fix coredump generation when cxl_get_fd() is used If a process dumps core while owning a cxl file descriptor obtained from an AFU driver (e.g. cxlflash) through the cxl_get_fd() API, the following error occurs: [ 868.027591] Unable to handle kernel paging request for data at address ... [ 868.027778] Faulting instruction address: 0xc00000000035edb0 cpu 0x8c: Vector: 300 (Data Access) at [c000003c688275e0] pc: c00000000035edb0: elf_core_dump+0xd60/0x1300 lr: c00000000035ed80: elf_core_dump+0xd30/0x1300 sp: c000003c68827860 msr: 9000000100009033 dar: c dsisr: 40000000 current = 0xc000003c68780000 paca = 0xc000000001b73200 softe: 0 irq_happened: 0x01 pid = 46725, comm = hxesurelock enter ? for help [c000003c68827a60] c00000000036948c do_coredump+0xcec/0x11e0 [c000003c68827c20] c0000000000ce9e0 get_signal+0x540/0x7b0 [c000003c68827d10] c000000000017354 do_signal+0x54/0x2b0 [c000003c68827e00] c00000000001777c do_notify_resume+0xbc/0xd0 [c000003c68827e30] c000000000009838 ret_from_except_lite+0x64/0x68 --- Exception: 300 (Data Access) at 00003fff98ad2918 The root cause is that the address_space structure for the file doesn't define a 'host' member. When cxl allocates a file descriptor, it's using the anonymous inode to back the file, but allocates a private address_space for each context. The private address_space allows to track memory allocation for each context. cxl doesn't define the 'host' member of the address space, i.e. the inode. We don't want to define it as the anonymous inode, since there's no longer a 1-to-1 relation between address_space and inode. To fix it, instead of using the anonymous inode, we introduce a simple pseudo filesystem so that cxl can allocate its own inodes. So we now have one inode for each file and address_space. The pseudo filesystem is only mounted on the first allocation of a file descriptor by cxl_get_fd(). Tested with cxlflash. Signed-off-by: Frederic Barrat Reviewed-by: Matthew R. Ochs Signed-off-by: Michael Ellerman --- drivers/misc/cxl/api.c | 138 +++++++++++++++++++++++++++++++++++++-------- drivers/misc/cxl/context.c | 17 ++++-- drivers/misc/cxl/cxl.h | 6 +- drivers/misc/cxl/file.c | 5 +- 4 files changed, 135 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/api.c b/drivers/misc/cxl/api.c index e2efc6489c6e..1b35e33d2434 100644 --- a/drivers/misc/cxl/api.c +++ b/drivers/misc/cxl/api.c @@ -9,18 +9,119 @@ #include #include -#include #include #include -#include #include #include +#include +#include #include "cxl.h" +/* + * Since we want to track memory mappings to be able to force-unmap + * when the AFU is no longer reachable, we need an inode. For devices + * opened through the cxl user API, this is not a problem, but a + * userland process can also get a cxl fd through the cxl_get_fd() + * API, which is used by the cxlflash driver. + * + * Therefore we implement our own simple pseudo-filesystem and inode + * allocator. We don't use the anonymous inode, as we need the + * meta-data associated with it (address_space) and it is shared by + * other drivers/processes, so it could lead to cxl unmapping VMAs + * from random processes. + */ + +#define CXL_PSEUDO_FS_MAGIC 0x1697697f + +static int cxl_fs_cnt; +static struct vfsmount *cxl_vfs_mount; + +static const struct dentry_operations cxl_fs_dops = { + .d_dname = simple_dname, +}; + +static struct dentry *cxl_fs_mount(struct file_system_type *fs_type, int flags, + const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "cxl:", NULL, &cxl_fs_dops, + CXL_PSEUDO_FS_MAGIC); +} + +static struct file_system_type cxl_fs_type = { + .name = "cxl", + .owner = THIS_MODULE, + .mount = cxl_fs_mount, + .kill_sb = kill_anon_super, +}; + + +void cxl_release_mapping(struct cxl_context *ctx) +{ + if (ctx->kernelapi && ctx->mapping) + simple_release_fs(&cxl_vfs_mount, &cxl_fs_cnt); +} + +static struct file *cxl_getfile(const char *name, + const struct file_operations *fops, + void *priv, int flags) +{ + struct qstr this; + struct path path; + struct file *file; + struct inode *inode = NULL; + int rc; + + /* strongly inspired by anon_inode_getfile() */ + + if (fops->owner && !try_module_get(fops->owner)) + return ERR_PTR(-ENOENT); + + rc = simple_pin_fs(&cxl_fs_type, &cxl_vfs_mount, &cxl_fs_cnt); + if (rc < 0) { + pr_err("Cannot mount cxl pseudo filesystem: %d\n", rc); + file = ERR_PTR(rc); + goto err_module; + } + + inode = alloc_anon_inode(cxl_vfs_mount->mnt_sb); + if (IS_ERR(inode)) { + file = ERR_CAST(inode); + goto err_fs; + } + + file = ERR_PTR(-ENOMEM); + this.name = name; + this.len = strlen(name); + this.hash = 0; + path.dentry = d_alloc_pseudo(cxl_vfs_mount->mnt_sb, &this); + if (!path.dentry) + goto err_inode; + + path.mnt = mntget(cxl_vfs_mount); + d_instantiate(path.dentry, inode); + + file = alloc_file(&path, OPEN_FMODE(flags), fops); + if (IS_ERR(file)) + goto err_dput; + file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); + file->private_data = priv; + + return file; + +err_dput: + path_put(&path); +err_inode: + iput(inode); +err_fs: + simple_release_fs(&cxl_vfs_mount, &cxl_fs_cnt); +err_module: + module_put(fops->owner); + return file; +} + struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) { - struct address_space *mapping; struct cxl_afu *afu; struct cxl_context *ctx; int rc; @@ -35,28 +136,13 @@ struct cxl_context *cxl_dev_context_init(struct pci_dev *dev) ctx->kernelapi = true; - /* - * Make our own address space since we won't have one from the - * filesystem like the user api has, and even if we do associate a file - * with this context we don't want to use the global anonymous inode's - * address space as that can invalidate unrelated users: - */ - mapping = kmalloc(sizeof(struct address_space), GFP_KERNEL); - if (!mapping) { - rc = -ENOMEM; - goto err_ctx; - } - address_space_init_once(mapping); - /* Make it a slave context. We can promote it later? */ - rc = cxl_context_init(ctx, afu, false, mapping); + rc = cxl_context_init(ctx, afu, false); if (rc) - goto err_mapping; + goto err_ctx; return ctx; -err_mapping: - kfree(mapping); err_ctx: kfree(ctx); return ERR_PTR(rc); @@ -337,6 +423,11 @@ struct file *cxl_get_fd(struct cxl_context *ctx, struct file_operations *fops, { struct file *file; int rc, flags, fdtmp; + char *name = NULL; + + /* only allow one per context */ + if (ctx->mapping) + return ERR_PTR(-EEXIST); flags = O_RDWR | O_CLOEXEC; @@ -360,12 +451,13 @@ struct file *cxl_get_fd(struct cxl_context *ctx, struct file_operations *fops, } else /* use default ops */ fops = (struct file_operations *)&afu_fops; - file = anon_inode_getfile("cxl", fops, ctx, flags); + name = kasprintf(GFP_KERNEL, "cxl:%d", ctx->pe); + file = cxl_getfile(name, fops, ctx, flags); + kfree(name); if (IS_ERR(file)) goto err_fd; - file->f_mapping = ctx->mapping; - + cxl_context_set_mapping(ctx, file->f_mapping); *fd = fdtmp; return file; diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 5e506c19108a..ff5e7e8cb1d1 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -34,8 +34,7 @@ struct cxl_context *cxl_context_alloc(void) /* * Initialises a CXL context. */ -int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, - struct address_space *mapping) +int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master) { int i; @@ -44,7 +43,7 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, ctx->master = master; ctx->pid = ctx->glpid = NULL; /* Set in start work ioctl */ mutex_init(&ctx->mapping_lock); - ctx->mapping = mapping; + ctx->mapping = NULL; /* * Allocate the segment table before we put it in the IDR so that we @@ -114,6 +113,14 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, return 0; } +void cxl_context_set_mapping(struct cxl_context *ctx, + struct address_space *mapping) +{ + mutex_lock(&ctx->mapping_lock); + ctx->mapping = mapping; + mutex_unlock(&ctx->mapping_lock); +} + static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct cxl_context *ctx = vma->vm_file->private_data; @@ -300,8 +307,6 @@ static void reclaim_ctx(struct rcu_head *rcu) if (ctx->ff_page) __free_page(ctx->ff_page); ctx->sstp = NULL; - if (ctx->kernelapi) - kfree(ctx->mapping); kfree(ctx->irq_bitmap); @@ -313,6 +318,8 @@ static void reclaim_ctx(struct rcu_head *rcu) void cxl_context_free(struct cxl_context *ctx) { + if (ctx->kernelapi && ctx->mapping) + cxl_release_mapping(ctx); mutex_lock(&ctx->afu->contexts_lock); idr_remove(&ctx->afu->contexts_idr, ctx->pe); mutex_unlock(&ctx->afu->contexts_lock); diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h index a144073593fa..b24d76723fb0 100644 --- a/drivers/misc/cxl/cxl.h +++ b/drivers/misc/cxl/cxl.h @@ -817,8 +817,9 @@ void cxl_dump_debug_buffer(void *addr, size_t size); void init_cxl_native(void); struct cxl_context *cxl_context_alloc(void); -int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, - struct address_space *mapping); +int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master); +void cxl_context_set_mapping(struct cxl_context *ctx, + struct address_space *mapping); void cxl_context_free(struct cxl_context *ctx); int cxl_context_iomap(struct cxl_context *ctx, struct vm_area_struct *vma); unsigned int cxl_map_irq(struct cxl *adapter, irq_hw_number_t hwirq, @@ -877,6 +878,7 @@ void cxl_native_err_irq_dump_regs(struct cxl *adapter); void cxl_stop_trace(struct cxl *cxl); int cxl_pci_vphb_add(struct cxl_afu *afu); void cxl_pci_vphb_remove(struct cxl_afu *afu); +void cxl_release_mapping(struct cxl_context *ctx); extern struct pci_driver cxl_pci_driver; extern struct platform_driver cxl_of_driver; diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c index 77080cc5fa0a..859959f19f10 100644 --- a/drivers/misc/cxl/file.c +++ b/drivers/misc/cxl/file.c @@ -86,9 +86,12 @@ static int __afu_open(struct inode *inode, struct file *file, bool master) goto err_put_afu; } - if ((rc = cxl_context_init(ctx, afu, master, inode->i_mapping))) + rc = cxl_context_init(ctx, afu, master); + if (rc) goto err_put_afu; + cxl_context_set_mapping(ctx, inode->i_mapping); + pr_devel("afu_open pe: %i\n", ctx->pe); file->private_data = ctx; cxl_ctx_get(); -- cgit v1.2.3 From cc8e7ff440668d3934e12139d5daae94f4be356e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 14 Oct 2016 10:44:04 -0300 Subject: [media] af9005: remove a printk that would require a KERN_CONT The dvb-usb system has its own macro to print hexa dumps (debug_dump). Such macro doesn't support messages with KERN_CONT after commit 563873318d32 ("Merge branch 'printk-cleanups'"). So, let's get rid of a printk() that would be assuming that this would work. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/af9005.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c index 7853261906b1..f5f476841aea 100644 --- a/drivers/media/usb/dvb-usb/af9005.c +++ b/drivers/media/usb/dvb-usb/af9005.c @@ -826,7 +826,6 @@ static int af9005_frontend_attach(struct dvb_usb_adapter *adap) printk("EEPROM DUMP\n"); for (i = 0; i < 255; i += 8) { af9005_read_eeprom(adap->dev, i, buf, 8); - printk("ADDR %x ", i); debug_dump(buf, 8, printk); } } -- cgit v1.2.3 From 680d87c0a9e3aa4a13ac54aa968173c8623c0f47 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 19 Oct 2016 18:12:03 -0200 Subject: [media] tuner-core: use pr_foo, instead of internal printk macros Tuner core uses its own printk internal macros, instead of the standard debug ones, for no good reason. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/tuner-core.c | 112 +++++++++++++++-------------------- 1 file changed, 49 insertions(+), 63 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/tuner-core.c b/drivers/media/v4l2-core/tuner-core.c index d3a6236b6b02..05b5c6652cfa 100644 --- a/drivers/media/v4l2-core/tuner-core.c +++ b/drivers/media/v4l2-core/tuner-core.c @@ -84,30 +84,16 @@ static const struct v4l2_subdev_ops tuner_ops; * Debug macros */ -#define tuner_warn(fmt, arg...) do { \ - printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_info(fmt, arg...) do { \ - printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_err(fmt, arg...) do { \ - printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) - -#define tuner_dbg(fmt, arg...) do { \ - if (tuner_debug) \ - printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \ - i2c_adapter_id(t->i2c->adapter), \ - t->i2c->addr, ##arg); \ - } while (0) +#undef pr_fmt + +#define pr_fmt(fmt) KBUILD_MODNAME ": %d-%04x: " fmt, \ + i2c_adapter_id(t->i2c->adapter), t->i2c->addr + + +#define dprintk(fmt, arg...) do { \ + if (tuner_debug) \ + printk(KERN_DEBUG pr_fmt("%s: " fmt), __func__, ##arg); \ +} while (0) /* * Internal struct used inside the driver @@ -208,7 +194,7 @@ static void fe_set_params(struct dvb_frontend *fe, struct tuner *t = fe->analog_demod_priv; if (NULL == fe_tuner_ops->set_analog_params) { - tuner_warn("Tuner frontend module has no way to set freq\n"); + pr_warn("Tuner frontend module has no way to set freq\n"); return; } fe_tuner_ops->set_analog_params(fe, params); @@ -230,7 +216,7 @@ static int fe_set_config(struct dvb_frontend *fe, void *priv_cfg) if (fe_tuner_ops->set_config) return fe_tuner_ops->set_config(fe, priv_cfg); - tuner_warn("Tuner frontend module has no way to set config\n"); + pr_warn("Tuner frontend module has no way to set config\n"); return 0; } @@ -273,14 +259,14 @@ static void set_type(struct i2c_client *c, unsigned int type, int tune_now = 1; if (type == UNSET || type == TUNER_ABSENT) { - tuner_dbg("tuner 0x%02x: Tuner type absent\n", c->addr); + dprintk("tuner 0x%02x: Tuner type absent\n", c->addr); return; } t->type = type; t->config = new_config; if (tuner_callback != NULL) { - tuner_dbg("defining GPIO callback\n"); + dprintk("defining GPIO callback\n"); t->fe.callback = tuner_callback; } @@ -442,7 +428,7 @@ static void set_type(struct i2c_client *c, unsigned int type, t->sd.entity.name = t->name; #endif - tuner_dbg("type set to %s\n", t->name); + dprintk("type set to %s\n", t->name); t->mode_mask = new_mode_mask; @@ -459,13 +445,13 @@ static void set_type(struct i2c_client *c, unsigned int type, set_tv_freq(c, t->tv_freq); } - tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", + dprintk("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n", c->adapter->name, c->dev.driver->name, c->addr << 1, type, t->mode_mask); return; attach_failed: - tuner_dbg("Tuner attach for type = %d failed.\n", t->type); + dprintk("Tuner attach for type = %d failed.\n", t->type); t->type = TUNER_ABSENT; return; @@ -491,7 +477,7 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd, struct tuner *t = to_tuner(sd); struct i2c_client *c = v4l2_get_subdevdata(sd); - tuner_dbg("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=%p\n", + dprintk("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x, config=%p\n", tun_setup->type, tun_setup->addr, tun_setup->mode_mask, @@ -503,7 +489,7 @@ static int tuner_s_type_addr(struct v4l2_subdev *sd, set_type(c, tun_setup->type, tun_setup->mode_mask, tun_setup->config, tun_setup->tuner_callback); } else - tuner_dbg("set addr discarded for type %i, mask %x. Asked to change tuner at addr 0x%02x, with mask %x\n", + dprintk("set addr discarded for type %i, mask %x. Asked to change tuner at addr 0x%02x, with mask %x\n", t->type, t->mode_mask, tun_setup->addr, tun_setup->mode_mask); @@ -533,7 +519,7 @@ static int tuner_s_config(struct v4l2_subdev *sd, return 0; } - tuner_dbg("Tuner frontend module has no way to set config\n"); + dprintk("Tuner frontend module has no way to set config\n"); return 0; } @@ -622,7 +608,7 @@ static int tuner_probe(struct i2c_client *client, memset(buffer, 0, sizeof(buffer)); rc = i2c_master_recv(client, buffer, sizeof(buffer)); if (rc >= 0) - tuner_info("I2C RECV = %*ph\n", rc, buffer); + pr_info("I2C RECV = %*ph\n", rc, buffer); } /* autodetection code based on the i2c addr */ @@ -650,7 +636,7 @@ static int tuner_probe(struct i2c_client *client, since it can be tda9887*/ if (tuner_symbol_probe(tda829x_probe, t->i2c->adapter, t->i2c->addr) >= 0) { - tuner_dbg("tda829x detected\n"); + dprintk("tda829x detected\n"); } else { /* Default is being tda9887 */ t->type = TUNER_TDA9887; @@ -687,7 +673,7 @@ static int tuner_probe(struct i2c_client *client, t->mode_mask = T_ANALOG_TV; if (radio == NULL) t->mode_mask |= T_RADIO; - tuner_dbg("Setting mode_mask to 0x%02x\n", t->mode_mask); + dprintk("Setting mode_mask to 0x%02x\n", t->mode_mask); } /* Should be just before return */ @@ -716,7 +702,7 @@ register_client: } if (ret < 0) { - tuner_err("failed to initialize media entity!\n"); + pr_err("failed to initialize media entity!\n"); kfree(t); return ret; } @@ -729,7 +715,7 @@ register_client: set_type(client, t->type, t->mode_mask, t->config, t->fe.callback); list_add_tail(&t->list, &tuner_list); - tuner_info("Tuner %d found with type(s)%s%s.\n", + pr_info("Tuner %d found with type(s)%s%s.\n", t->type, t->mode_mask & T_RADIO ? " Radio" : "", t->mode_mask & T_ANALOG_TV ? " TV" : ""); @@ -806,7 +792,7 @@ static int set_mode(struct tuner *t, enum v4l2_tuner_type mode) if (mode != t->mode) { if (check_mode(t, mode) == -EINVAL) { - tuner_dbg("Tuner doesn't support mode %d. Putting tuner to sleep\n", + dprintk("Tuner doesn't support mode %d. Putting tuner to sleep\n", mode); t->standby = true; if (analog_ops->standby) @@ -814,7 +800,7 @@ static int set_mode(struct tuner *t, enum v4l2_tuner_type mode) return -EINVAL; } t->mode = mode; - tuner_dbg("Changing to mode %d\n", mode); + dprintk("Changing to mode %d\n", mode); } return 0; } @@ -861,15 +847,15 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) }; if (t->type == UNSET) { - tuner_warn("tuner type not set\n"); + pr_warn("tuner type not set\n"); return; } if (NULL == analog_ops->set_params) { - tuner_warn("Tuner has no way to set tv freq\n"); + pr_warn("Tuner has no way to set tv freq\n"); return; } if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) { - tuner_dbg("TV freq (%d.%02d) out of range (%d-%d)\n", + dprintk("TV freq (%d.%02d) out of range (%d-%d)\n", freq / 16, freq % 16 * 100 / 16, tv_range[0], tv_range[1]); /* V4L2 spec: if the freq is not possible then the closest @@ -880,7 +866,7 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq) freq = tv_range[1] * 16; } params.frequency = freq; - tuner_dbg("tv freq set to %d.%02d\n", + dprintk("tv freq set to %d.%02d\n", freq / 16, freq % 16 * 100 / 16); t->tv_freq = freq; t->standby = false; @@ -930,7 +916,7 @@ static v4l2_std_id tuner_fixup_std(struct tuner *t, v4l2_std_id std) return V4L2_STD_PAL_Nc; return V4L2_STD_PAL_N; default: - tuner_warn("pal= argument not recognised\n"); + pr_warn("pal= argument not recognised\n"); break; } } @@ -956,7 +942,7 @@ static v4l2_std_id tuner_fixup_std(struct tuner *t, v4l2_std_id std) return V4L2_STD_SECAM_LC; return V4L2_STD_SECAM_L; default: - tuner_warn("secam= argument not recognised\n"); + pr_warn("secam= argument not recognised\n"); break; } } @@ -973,7 +959,7 @@ static v4l2_std_id tuner_fixup_std(struct tuner *t, v4l2_std_id std) case 'K': return V4L2_STD_NTSC_M_KR; default: - tuner_info("ntsc= argument not recognised\n"); + pr_info("ntsc= argument not recognised\n"); break; } } @@ -1002,15 +988,15 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) }; if (t->type == UNSET) { - tuner_warn("tuner type not set\n"); + pr_warn("tuner type not set\n"); return; } if (NULL == analog_ops->set_params) { - tuner_warn("tuner has no way to set radio frequency\n"); + pr_warn("tuner has no way to set radio frequency\n"); return; } if (freq < radio_range[0] * 16000 || freq > radio_range[1] * 16000) { - tuner_dbg("radio freq (%d.%02d) out of range (%d-%d)\n", + dprintk("radio freq (%d.%02d) out of range (%d-%d)\n", freq / 16000, freq % 16000 * 100 / 16000, radio_range[0], radio_range[1]); /* V4L2 spec: if the freq is not possible then the closest @@ -1021,7 +1007,7 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq) freq = radio_range[1] * 16000; } params.frequency = freq; - tuner_dbg("radio freq set to %d.%02d\n", + dprintk("radio freq set to %d.%02d\n", freq / 16000, freq % 16000 * 100 / 16000); t->radio_freq = freq; t->standby = false; @@ -1072,10 +1058,10 @@ static void tuner_status(struct dvb_frontend *fe) freq = t->tv_freq / 16; freq_fraction = (t->tv_freq % 16) * 100 / 16; } - tuner_info("Tuner mode: %s%s\n", p, + pr_info("Tuner mode: %s%s\n", p, t->standby ? " on standby mode" : ""); - tuner_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); - tuner_info("Standard: 0x%08lx\n", (unsigned long)t->std); + pr_info("Frequency: %lu.%02lu MHz\n", freq, freq_fraction); + pr_info("Standard: 0x%08lx\n", (unsigned long)t->std); if (t->mode != V4L2_TUNER_RADIO) return; if (fe_tuner_ops->get_status) { @@ -1083,15 +1069,15 @@ static void tuner_status(struct dvb_frontend *fe) fe_tuner_ops->get_status(&t->fe, &tuner_status); if (tuner_status & TUNER_STATUS_LOCKED) - tuner_info("Tuner is locked.\n"); + pr_info("Tuner is locked.\n"); if (tuner_status & TUNER_STATUS_STEREO) - tuner_info("Stereo: yes\n"); + pr_info("Stereo: yes\n"); } if (analog_ops->has_signal) { u16 signal; if (!analog_ops->has_signal(fe, &signal)) - tuner_info("Signal strength: %hu\n", signal); + pr_info("Signal strength: %hu\n", signal); } } @@ -1124,13 +1110,13 @@ static int tuner_s_power(struct v4l2_subdev *sd, int on) if (on) { if (t->standby && set_mode(t, t->mode) == 0) { - tuner_dbg("Waking up tuner\n"); + dprintk("Waking up tuner\n"); set_freq(t, 0); } return 0; } - tuner_dbg("Putting tuner to sleep\n"); + dprintk("Putting tuner to sleep\n"); t->standby = true; if (analog_ops->standby) analog_ops->standby(&t->fe); @@ -1146,7 +1132,7 @@ static int tuner_s_std(struct v4l2_subdev *sd, v4l2_std_id std) t->std = tuner_fixup_std(t, std); if (t->std != std) - tuner_dbg("Fixup standard %llx to %llx\n", std, t->std); + dprintk("Fixup standard %llx to %llx\n", std, t->std); set_freq(t, 0); return 0; } @@ -1295,7 +1281,7 @@ static int tuner_suspend(struct device *dev) struct tuner *t = to_tuner(i2c_get_clientdata(c)); struct analog_demod_ops *analog_ops = &t->fe.ops.analog_ops; - tuner_dbg("suspend\n"); + dprintk("suspend\n"); if (t->fe.ops.tuner_ops.suspend) t->fe.ops.tuner_ops.suspend(&t->fe); @@ -1310,7 +1296,7 @@ static int tuner_resume(struct device *dev) struct i2c_client *c = to_i2c_client(dev); struct tuner *t = to_tuner(i2c_get_clientdata(c)); - tuner_dbg("resume\n"); + dprintk("resume\n"); if (t->fe.ops.tuner_ops.resume) t->fe.ops.tuner_ops.resume(&t->fe); -- cgit v1.2.3 From b68d75b955a62a6ade9e004b656415f346c3ad40 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Oct 2016 08:03:00 -0200 Subject: [media] msp3400-driver: don't use KERN_CONT Drivers using dev_foo() macro should not use KERN_CONT, as, internally, those macros work as if all strings were terminated by a \n. So, doing: dev_info(&client->dev, "%s ", client->name); printk(KERN_CONT "supports radio, mode is autodetect and autoselect"); Would produce the following output: msp3400 6-0044: msp3400 supports radio, mode is autodetect and autoselect As there's no good reason to use KERN_CONT, let's rewrite the code to avoid that, allowing this driver to be converted to dev_foo(). Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/msp3400-driver.c | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index 503b7c4f0a9b..ae396b965ef2 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -670,6 +670,13 @@ static const struct v4l2_subdev_ops msp_ops = { /* ----------------------------------------------------------------------- */ + +static const char * const opmode_str[] = { + [OPMODE_MANUAL] = "manual", + [OPMODE_AUTODETECT] = "autodetect", + [OPMODE_AUTOSELECT] = "autodetect and autoselect", +}; + static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct msp_state *state; @@ -791,7 +798,8 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) msp_family == 3 && msp_revision == 'G' && msp_prod_hi == 3; state->opmode = opmode; - if (state->opmode == OPMODE_AUTO) { + if (state->opmode < OPMODE_MANUAL + || state->opmode > OPMODE_AUTOSELECT) { /* MSP revision G and up have both autodetect and autoselect */ if (msp_revision >= 'G') state->opmode = OPMODE_AUTOSELECT; @@ -829,36 +837,28 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) v4l2_ctrl_cluster(2, &state->volume); v4l2_ctrl_handler_setup(hdl); - /* hello world :-) */ - v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n", - msp_family, msp_product, - msp_revision, msp_hard, msp_rom, - client->addr << 1, client->adapter->name); - v4l_info(client, "%s ", client->name); - if (state->has_nicam && state->has_radio) - printk(KERN_CONT "supports nicam and radio, "); - else if (state->has_nicam) - printk(KERN_CONT "supports nicam, "); - else if (state->has_radio) - printk(KERN_CONT "supports radio, "); - printk(KERN_CONT "mode is "); + dev_info(&client->dev, + "MSP%d4%02d%c-%c%d found on %s: supports %s%s%s, mode is %s\n", + msp_family, msp_product, + msp_revision, msp_hard, msp_rom, + client->adapter->name, + (state->has_nicam) ? "nicam" : "", + (state->has_nicam && state->has_radio) ? " and " : "", + (state->has_radio) ? "radio" : "", + opmode_str[state->opmode]); /* version-specific initialization */ switch (state->opmode) { case OPMODE_MANUAL: - printk(KERN_CONT "manual"); thread_func = msp3400c_thread; break; case OPMODE_AUTODETECT: - printk(KERN_CONT "autodetect"); thread_func = msp3410d_thread; break; case OPMODE_AUTOSELECT: - printk(KERN_CONT "autodetect and autoselect"); thread_func = msp34xxg_thread; break; } - printk(KERN_CONT "\n"); /* startup control thread if needed */ if (thread_func) { -- cgit v1.2.3 From 39ad799a85e2afb2eeb0295cabe81e183b011b95 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Nov 2016 09:10:14 -0200 Subject: [media] msp3400: convert it to use dev_foo() macros Instead of using the v4l_foo() macros, just use the kernel-wide dev_foo() macros, as there's no good reason to use something else. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/msp3400-driver.c | 54 ++++++++-------- drivers/media/i2c/msp3400-kthreads.c | 115 +++++++++++++++++------------------ 2 files changed, 84 insertions(+), 85 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c index ae396b965ef2..201a9800ea52 100644 --- a/drivers/media/i2c/msp3400-driver.c +++ b/drivers/media/i2c/msp3400-driver.c @@ -146,11 +146,11 @@ int msp_reset(struct i2c_client *client) }, }; - v4l_dbg(3, msp_debug, client, "msp_reset\n"); + dev_dbg_lvl(&client->dev, 3, msp_debug, "msp_reset\n"); if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || i2c_transfer(client->adapter, &reset[1], 1) != 1 || i2c_transfer(client->adapter, test, 2) != 2) { - v4l_err(client, "chip reset failed\n"); + dev_err(&client->dev, "chip reset failed\n"); return -1; } return 0; @@ -182,17 +182,17 @@ static int msp_read(struct i2c_client *client, int dev, int addr) for (err = 0; err < 3; err++) { if (i2c_transfer(client->adapter, msgs, 2) == 2) break; - v4l_warn(client, "I/O error #%d (read 0x%02x/0x%02x)\n", err, + dev_warn(&client->dev, "I/O error #%d (read 0x%02x/0x%02x)\n", err, dev, addr); schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "resetting chip, sound will go off.\n"); + dev_warn(&client->dev, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } retval = read[0] << 8 | read[1]; - v4l_dbg(3, msp_debug, client, "msp_read(0x%x, 0x%x): 0x%x\n", + dev_dbg_lvl(&client->dev, 3, msp_debug, "msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); return retval; } @@ -218,17 +218,17 @@ static int msp_write(struct i2c_client *client, int dev, int addr, int val) buffer[3] = val >> 8; buffer[4] = val & 0xff; - v4l_dbg(3, msp_debug, client, "msp_write(0x%x, 0x%x, 0x%x)\n", + dev_dbg_lvl(&client->dev, 3, msp_debug, "msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); for (err = 0; err < 3; err++) { if (i2c_master_send(client, buffer, 5) == 5) break; - v4l_warn(client, "I/O error #%d (write 0x%02x/0x%02x)\n", err, + dev_warn(&client->dev, "I/O error #%d (write 0x%02x/0x%02x)\n", err, dev, addr); schedule_timeout_interruptible(msecs_to_jiffies(10)); } if (err == 3) { - v4l_warn(client, "resetting chip, sound will go off.\n"); + dev_warn(&client->dev, "resetting chip, sound will go off.\n"); msp_reset(client); return -1; } @@ -301,7 +301,7 @@ void msp_set_scart(struct i2c_client *client, int in, int out) } else state->acb = 0xf60; /* Mute Input and SCART 1 Output */ - v4l_dbg(1, msp_debug, client, "scart switch: %s => %d (ACB=0x%04x)\n", + dev_dbg_lvl(&client->dev, 1, msp_debug, "scart switch: %s => %d (ACB=0x%04x)\n", scart_names[in], out, state->acb); msp_write_dsp(client, 0x13, state->acb); @@ -359,7 +359,7 @@ static int msp_s_ctrl(struct v4l2_ctrl *ctrl) if (!reallymuted) val = (val * 0x7f / 65535) << 8; - v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n", + dev_dbg_lvl(&client->dev, 1, msp_debug, "mute=%s scanning=%s volume=%d\n", state->muted->val ? "on" : "off", state->scan_in_progress ? "yes" : "no", state->volume->val); @@ -426,7 +426,7 @@ static int msp_s_radio(struct v4l2_subdev *sd) if (state->radio) return 0; state->radio = 1; - v4l_dbg(1, msp_debug, client, "switching to radio mode\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "switching to radio mode\n"); state->watch_stereo = 0; switch (state->opmode) { case OPMODE_MANUAL: @@ -461,7 +461,7 @@ static int msp_querystd(struct v4l2_subdev *sd, v4l2_std_id *id) *id &= state->detected_std; - v4l_dbg(2, msp_debug, client, + dev_dbg_lvl(&client->dev, 2, msp_debug, "detected standard: %s(0x%08Lx)\n", msp_standard_std_name(state->std), state->detected_std); @@ -555,7 +555,7 @@ static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq) struct msp_state *state = to_state(sd); struct i2c_client *client = v4l2_get_subdevdata(sd); - v4l_dbg(1, msp_debug, client, "Setting I2S speed to %d\n", freq); + dev_dbg_lvl(&client->dev, 1, msp_debug, "Setting I2S speed to %d\n", freq); switch (freq) { case 1024000: @@ -579,7 +579,7 @@ static int msp_log_status(struct v4l2_subdev *sd) if (state->opmode == OPMODE_AUTOSELECT) msp_detect_stereo(client); - v4l_info(client, "%s rev1 = 0x%04x rev2 = 0x%04x\n", + dev_info(&client->dev, "%s rev1 = 0x%04x rev2 = 0x%04x\n", client->name, state->rev1, state->rev2); snprintf(prefix, sizeof(prefix), "%s: Audio: ", sd->name); v4l2_ctrl_handler_log_status(&state->hdl, prefix); @@ -596,23 +596,23 @@ static int msp_log_status(struct v4l2_subdev *sd) default: p = "unknown"; break; } if (state->mode == MSP_MODE_EXTERN) { - v4l_info(client, "Mode: %s\n", p); + dev_info(&client->dev, "Mode: %s\n", p); } else if (state->opmode == OPMODE_MANUAL) { - v4l_info(client, "Mode: %s (%s%s)\n", p, + dev_info(&client->dev, "Mode: %s (%s%s)\n", p, (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); } else { if (state->opmode == OPMODE_AUTODETECT) - v4l_info(client, "Mode: %s\n", p); - v4l_info(client, "Standard: %s (%s%s)\n", + dev_info(&client->dev, "Mode: %s\n", p); + dev_info(&client->dev, "Standard: %s (%s%s)\n", msp_standard_std_name(state->std), (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); } - v4l_info(client, "Audmode: 0x%04x\n", state->audmode); - v4l_info(client, "Routing: 0x%08x (input) 0x%08x (output)\n", + dev_info(&client->dev, "Audmode: 0x%04x\n", state->audmode); + dev_info(&client->dev, "Routing: 0x%08x (input) 0x%08x (output)\n", state->route_in, state->route_out); - v4l_info(client, "ACB: 0x%04x\n", state->acb); + dev_info(&client->dev, "ACB: 0x%04x\n", state->acb); return 0; } @@ -620,7 +620,7 @@ static int msp_log_status(struct v4l2_subdev *sd) static int msp_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - v4l_dbg(1, msp_debug, client, "suspend\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "suspend\n"); msp_reset(client); return 0; } @@ -628,7 +628,7 @@ static int msp_suspend(struct device *dev) static int msp_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - v4l_dbg(1, msp_debug, client, "resume\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "resume\n"); msp_wake_thread(client); return 0; } @@ -696,7 +696,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) strlcpy(client->name, "msp3400", sizeof(client->name)); if (msp_reset(client) == -1) { - v4l_dbg(1, msp_debug, client, "msp3400 not found\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "msp3400 not found\n"); return -ENODEV; } @@ -731,10 +731,10 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) state->rev1 = msp_read_dsp(client, 0x1e); if (state->rev1 != -1) state->rev2 = msp_read_dsp(client, 0x1f); - v4l_dbg(1, msp_debug, client, "rev1=0x%04x, rev2=0x%04x\n", + dev_dbg_lvl(&client->dev, 1, msp_debug, "rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "not an msp3400 (cannot read chip version)\n"); return -ENODEV; } @@ -865,7 +865,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id) state->kthread = kthread_run(thread_func, client, "msp34xx"); if (IS_ERR(state->kthread)) - v4l_warn(client, "kernel_thread() failed\n"); + dev_warn(&client->dev, "kernel_thread() failed\n"); msp_wake_thread(client); } return 0; diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c index 17120804fab7..eec7aa4c6f98 100644 --- a/drivers/media/i2c/msp3400-kthreads.c +++ b/drivers/media/i2c/msp3400-kthreads.c @@ -220,7 +220,7 @@ void msp3400c_set_mode(struct i2c_client *client, int mode) int tuner = (state->route_in >> 3) & 1; int i; - v4l_dbg(1, msp_debug, client, "set_mode: %d\n", mode); + dev_dbg_lvl(&client->dev, 1, msp_debug, "set_mode: %d\n", mode); state->mode = mode; state->rxsubchans = V4L2_TUNER_SUB_MONO; @@ -266,7 +266,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) /* this method would break everything, let's make sure * it's never called */ - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "set_audmode called with mode=%d instead of set_source (ignored)\n", state->audmode); return; @@ -295,7 +295,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) /* switch demodulator */ switch (state->mode) { case MSP_MODE_FM_TERRA: - v4l_dbg(1, msp_debug, client, "FM set_audmode: %s\n", modestr); + dev_dbg_lvl(&client->dev, 1, msp_debug, "FM set_audmode: %s\n", modestr); switch (audmode) { case V4L2_TUNER_MODE_STEREO: msp_write_dsp(client, 0x000e, 0x3001); @@ -309,7 +309,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) } break; case MSP_MODE_FM_SAT: - v4l_dbg(1, msp_debug, client, "SAT set_audmode: %s\n", modestr); + dev_dbg_lvl(&client->dev, 1, msp_debug, "SAT set_audmode: %s\n", modestr); switch (audmode) { case V4L2_TUNER_MODE_MONO: msp3400c_set_carrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); @@ -329,31 +329,31 @@ static void msp3400c_set_audmode(struct i2c_client *client) case MSP_MODE_FM_NICAM1: case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "NICAM set_audmode: %s\n", modestr); if (state->nicam_on) src = 0x0100; /* NICAM */ break; case MSP_MODE_BTSC: - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "BTSC set_audmode: %s\n", modestr); break; case MSP_MODE_EXTERN: - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "extern set_audmode: %s\n", modestr); src = 0x0200; /* SCART */ break; case MSP_MODE_FM_RADIO: - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "FM-Radio set_audmode: %s\n", modestr); break; default: - v4l_dbg(1, msp_debug, client, "mono set_audmode\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "mono set_audmode\n"); return; } /* switch audio */ - v4l_dbg(1, msp_debug, client, "set audmode %d\n", audmode); + dev_dbg_lvl(&client->dev, 1, msp_debug, "set audmode %d\n", audmode); switch (audmode) { case V4L2_TUNER_MODE_STEREO: case V4L2_TUNER_MODE_LANG1_LANG2: @@ -361,7 +361,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) break; case V4L2_TUNER_MODE_MONO: if (state->mode == MSP_MODE_AM_NICAM) { - v4l_dbg(1, msp_debug, client, "switching to AM mono\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "switching to AM mono\n"); /* AM mono decoding is handled by tuner, not MSP chip */ /* SCART switching control register */ msp_set_scart(client, SCART_MONO, 0); @@ -377,7 +377,7 @@ static void msp3400c_set_audmode(struct i2c_client *client) src |= 0x0010; break; } - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "set_audmode final source/matrix = 0x%x\n", src); msp_set_source(client, src); @@ -388,23 +388,23 @@ static void msp3400c_print_mode(struct i2c_client *client) struct msp_state *state = to_state(i2c_get_clientdata(client)); if (state->main == state->second) - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "mono sound carrier: %d.%03d MHz\n", state->main / 910000, (state->main / 910) % 1000); else - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "main sound carrier: %d.%03d MHz\n", state->main / 910000, (state->main / 910) % 1000); if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "NICAM/FM carrier : %d.%03d MHz\n", state->second / 910000, (state->second/910) % 1000); if (state->mode == MSP_MODE_AM_NICAM) - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "NICAM/AM carrier : %d.%03d MHz\n", state->second / 910000, (state->second / 910) % 1000); if (state->mode == MSP_MODE_FM_TERRA && state->main != state->second) { - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "FM-stereo carrier : %d.%03d MHz\n", state->second / 910000, (state->second / 910) % 1000); } @@ -425,7 +425,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client) val = msp_read_dsp(client, 0x18); if (val > 32767) val -= 65536; - v4l_dbg(2, msp_debug, client, + dev_dbg_lvl(&client->dev, 2, msp_debug, "stereo detect register: %d\n", val); if (val > 8192) { rxsubchans = V4L2_TUNER_SUB_STEREO; @@ -440,7 +440,7 @@ static int msp3400c_detect_stereo(struct i2c_client *client) case MSP_MODE_FM_NICAM2: case MSP_MODE_AM_NICAM: val = msp_read_dem(client, 0x23); - v4l_dbg(2, msp_debug, client, "nicam sync=%d, mode=%d\n", + dev_dbg_lvl(&client->dev, 2, msp_debug, "nicam sync=%d, mode=%d\n", val & 1, (val & 0x1e) >> 1); if (val & 1) { @@ -471,14 +471,14 @@ static int msp3400c_detect_stereo(struct i2c_client *client) } if (rxsubchans != state->rxsubchans) { update = 1; - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "watch: rxsubchans %02x => %02x\n", state->rxsubchans, rxsubchans); state->rxsubchans = rxsubchans; } if (newnicam != state->nicam_on) { update = 1; - v4l_dbg(1, msp_debug, client, "watch: nicam %d => %d\n", + dev_dbg_lvl(&client->dev, 1, msp_debug, "watch: nicam %d => %d\n", state->nicam_on, newnicam); state->nicam_on = newnicam; } @@ -508,23 +508,23 @@ int msp3400c_thread(void *data) struct msp3400c_carrier_detect *cd; int count, max1, max2, val1, val2, val, i; - v4l_dbg(1, msp_debug, client, "msp3400 daemon started\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "msp3400 daemon started\n"); state->detected_std = V4L2_STD_ALL; set_freezable(); for (;;) { - v4l_dbg(2, msp_debug, client, "msp3400 thread: sleep\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "msp3400 thread: sleep\n"); msp_sleep(state, -1); - v4l_dbg(2, msp_debug, client, "msp3400 thread: wakeup\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "msp3400 thread: wakeup\n"); restart: - v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) break; if (state->radio || MSP_MODE_EXTERN == state->mode) { /* no carrier scan, just unmute */ - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_update_volume(state); @@ -553,7 +553,7 @@ restart: /* autodetect doesn't work well with AM ... */ max1 = 3; count = 0; - v4l_dbg(1, msp_debug, client, "AM sound override\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "AM sound override\n"); } for (i = 0; i < count; i++) { @@ -565,7 +565,7 @@ restart: val -= 65536; if (val1 < val) val1 = val, max1 = i; - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "carrier1 val: %5d / %s\n", val, cd[i].name); } @@ -602,7 +602,7 @@ restart: val -= 65536; if (val2 < val) val2 = val, max2 = i; - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "carrier2 val: %5d / %s\n", val, cd[i].name); } @@ -687,7 +687,7 @@ no_second: watch_stereo(client); } } - v4l_dbg(1, msp_debug, client, "thread: exit\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: exit\n"); return 0; } @@ -698,23 +698,23 @@ int msp3410d_thread(void *data) struct msp_state *state = to_state(i2c_get_clientdata(client)); int val, i, std, count; - v4l_dbg(1, msp_debug, client, "msp3410 daemon started\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "msp3410 daemon started\n"); state->detected_std = V4L2_STD_ALL; set_freezable(); for (;;) { - v4l_dbg(2, msp_debug, client, "msp3410 thread: sleep\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "msp3410 thread: sleep\n"); msp_sleep(state, -1); - v4l_dbg(2, msp_debug, client, "msp3410 thread: wakeup\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "msp3410 thread: wakeup\n"); restart: - v4l_dbg(2, msp_debug, client, "thread: restart scan\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) break; if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_update_volume(state); @@ -740,7 +740,7 @@ restart: goto restart; if (msp_debug) - v4l_dbg(2, msp_debug, client, + dev_dbg_lvl(&client->dev, 2, msp_debug, "setting standard: %s (0x%04x)\n", msp_standard_std_name(std), std); @@ -758,14 +758,14 @@ restart: val = msp_read_dem(client, 0x7e); if (val < 0x07ff) break; - v4l_dbg(2, msp_debug, client, + dev_dbg_lvl(&client->dev, 2, msp_debug, "detection still in progress\n"); } } for (i = 0; msp_stdlist[i].name != NULL; i++) if (msp_stdlist[i].retval == val) break; - v4l_dbg(1, msp_debug, client, "current standard: %s (0x%04x)\n", + dev_dbg_lvl(&client->dev, 1, msp_debug, "current standard: %s (0x%04x)\n", msp_standard_std_name(val), val); state->main = msp_stdlist[i].main; state->second = msp_stdlist[i].second; @@ -775,8 +775,7 @@ restart: if (msp_amsound && !state->radio && (state->v4l2_std & V4L2_STD_SECAM) && (val != 0x0009)) { /* autodetection has failed, let backup */ - v4l_dbg(1, msp_debug, client, "autodetection failed," - " switching to backup standard: %s (0x%04x)\n", + dev_dbg_lvl(&client->dev, 1, msp_debug, "autodetection failed, switching to backup standard: %s (0x%04x)\n", msp_stdlist[8].name ? msp_stdlist[8].name : "unknown", val); state->std = val = 0x0009; @@ -850,7 +849,7 @@ restart: watch_stereo(client); } } - v4l_dbg(1, msp_debug, client, "thread: exit\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: exit\n"); return 0; } @@ -867,23 +866,23 @@ static int msp34xxg_modus(struct i2c_client *client) struct msp_state *state = to_state(i2c_get_clientdata(client)); if (state->radio) { - v4l_dbg(1, msp_debug, client, "selected radio modus\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "selected radio modus\n"); return 0x0001; } if (state->v4l2_std == V4L2_STD_NTSC_M_JP) { - v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "selected M (EIA-J) modus\n"); return 0x4001; } if (state->v4l2_std == V4L2_STD_NTSC_M_KR) { - v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "selected M (A2) modus\n"); return 0x0001; } if (state->v4l2_std == V4L2_STD_SECAM_L) { - v4l_dbg(1, msp_debug, client, "selected SECAM-L modus\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "selected SECAM-L modus\n"); return 0x6001; } if (state->v4l2_std & V4L2_STD_MN) { - v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "selected M (BTSC) modus\n"); return 0x2001; } return 0x7001; @@ -927,7 +926,7 @@ static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in) else source = (in << 8) | matrix; - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "set source to %d (0x%x) for output %02x\n", in, source, reg); msp_write_dsp(client, reg, source); } @@ -996,23 +995,23 @@ int msp34xxg_thread(void *data) struct msp_state *state = to_state(i2c_get_clientdata(client)); int val, i; - v4l_dbg(1, msp_debug, client, "msp34xxg daemon started\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "msp34xxg daemon started\n"); state->detected_std = V4L2_STD_ALL; set_freezable(); for (;;) { - v4l_dbg(2, msp_debug, client, "msp34xxg thread: sleep\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "msp34xxg thread: sleep\n"); msp_sleep(state, -1); - v4l_dbg(2, msp_debug, client, "msp34xxg thread: wakeup\n"); + dev_dbg_lvl(&client->dev, 2, msp_debug, "msp34xxg thread: wakeup\n"); restart: - v4l_dbg(1, msp_debug, client, "thread: restart scan\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: restart scan\n"); state->restart = 0; if (kthread_should_stop()) break; if (state->mode == MSP_MODE_EXTERN) { /* no carrier scan needed, just unmute */ - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: no carrier scan\n"); state->scan_in_progress = 0; msp_update_volume(state); @@ -1029,7 +1028,7 @@ restart: goto unmute; /* watch autodetect */ - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "started autodetect, waiting for result\n"); for (i = 0; i < 10; i++) { if (msp_sleep(state, 100)) @@ -1041,17 +1040,17 @@ restart: state->std = val; break; } - v4l_dbg(2, msp_debug, client, + dev_dbg_lvl(&client->dev, 2, msp_debug, "detection still in progress\n"); } if (state->std == 1) { - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "detection still in progress after 10 tries. giving up.\n"); continue; } unmute: - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "detected standard: %s (0x%04x)\n", msp_standard_std_name(state->std), state->std); state->detected_std = msp_standard_std(state->std); @@ -1084,7 +1083,7 @@ unmute: goto restart; } } - v4l_dbg(1, msp_debug, client, "thread: exit\n"); + dev_dbg_lvl(&client->dev, 1, msp_debug, "thread: exit\n"); return 0; } @@ -1111,7 +1110,7 @@ static int msp34xxg_detect_stereo(struct i2c_client *client) state->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; } - v4l_dbg(1, msp_debug, client, + dev_dbg_lvl(&client->dev, 1, msp_debug, "status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", status, is_stereo, is_bilingual, state->rxsubchans); return (oldrx != state->rxsubchans); -- cgit v1.2.3 From ce8591ff023ef8e04750c2cc2882523619a80b58 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Oct 2016 08:42:03 -0200 Subject: [media] em28xx: convert it from pr_foo() to dev_foo() Instead of using pr_foo(), use dev_foo(), with provides a better output. As this device is a multi-interface one, we'll set the device name to show the chipset and the driver used. While here, get rid of printk continuation messages. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 64 ++++--- drivers/media/usb/em28xx/em28xx-camera.c | 60 ++++--- drivers/media/usb/em28xx/em28xx-cards.c | 131 +++++++------- drivers/media/usb/em28xx/em28xx-core.c | 154 +++++++++-------- drivers/media/usb/em28xx/em28xx-dvb.c | 89 ++++++---- drivers/media/usb/em28xx/em28xx-i2c.c | 284 ++++++++++++++++--------------- drivers/media/usb/em28xx/em28xx-input.c | 42 +++-- drivers/media/usb/em28xx/em28xx-vbi.c | 6 +- drivers/media/usb/em28xx/em28xx-video.c | 127 ++++++++------ drivers/media/usb/em28xx/em28xx.h | 3 - 10 files changed, 536 insertions(+), 424 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 06e495615296..cd2545ca5e39 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -55,9 +55,10 @@ MODULE_PARM_DESC(debug, "activates debug info"); #define EM28XX_MIN_AUDIO_PACKETS 64 #define dprintk(fmt, arg...) do { \ - if (debug) \ - printk(KERN_DEBUG pr_fmt("audio: %s: " fmt), \ - __func__, ##arg); } while (0) + if (debug) \ + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "video: %s: " fmt, __func__, ## arg); \ +} while (0) static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -91,7 +92,8 @@ static void em28xx_audio_isocirq(struct urb *urb) struct snd_pcm_runtime *runtime; if (dev->disconnected) { - dprintk("device disconnected while streaming. URB status=%d.\n", urb->status); + dprintk("device disconnected while streaming. URB status=%d.\n", + urb->status); atomic_set(&dev->adev.stream_started, 0); return; } @@ -164,8 +166,9 @@ static void em28xx_audio_isocirq(struct urb *urb) status = usb_submit_urb(urb, GFP_ATOMIC); if (status < 0) - pr_err("resubmit of audio urb failed (error=%i)\n", - status); + dev_err(&dev->udev->dev, + "resubmit of audio urb failed (error=%i)\n", + status); return; } @@ -182,8 +185,9 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { - pr_err("submit of audio urb failed (error=%i)\n", - errCode); + dev_err(&dev->udev->dev, + "submit of audio urb failed (error=%i)\n", + errCode); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); return errCode; @@ -197,6 +201,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) { + struct em28xx *dev = snd_pcm_substream_chip(subs); struct snd_pcm_runtime *runtime = subs->runtime; dprintk("Allocating vbuffer\n"); @@ -254,7 +259,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) int nonblock, ret = 0; if (!dev) { - pr_err("BUG: em28xx can't find device struct. Can't proceed with open\n"); + dev_err(&dev->udev->dev, + "BUG: em28xx can't find device struct. Can't proceed with open\n"); return -ENODEV; } @@ -317,7 +323,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) err: mutex_unlock(&dev->lock); - pr_err("Error while configuring em28xx mixer\n"); + dev_err(&dev->udev->dev, + "Error while configuring em28xx mixer\n"); return ret; } @@ -755,7 +762,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) intf = usb_ifnum_to_if(dev->udev, dev->ifnum); if (intf->num_altsetting <= alt) { - pr_err("alt %d doesn't exist on interface %d\n", + dev_err(&dev->udev->dev, "alt %d doesn't exist on interface %d\n", dev->ifnum, alt); return -ENODEV; } @@ -771,18 +778,17 @@ static int em28xx_audio_urb_init(struct em28xx *dev) } if (!ep) { - pr_err("Couldn't find an audio endpoint"); + dev_err(&dev->udev->dev, "Couldn't find an audio endpoint"); return -ENODEV; } ep_size = em28xx_audio_ep_packet_size(dev->udev, ep); interval = 1 << (ep->bInterval - 1); - pr_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", - EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed), - dev->ifnum, alt, - interval, - ep_size); + dev_info(&dev->udev->dev, + "Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", + EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed), + dev->ifnum, alt, interval, ep_size); /* Calculate the number and size of URBs to better fit the audio samples */ @@ -819,8 +825,9 @@ static int em28xx_audio_urb_init(struct em28xx *dev) if (urb_size > ep_size * npackets) npackets = DIV_ROUND_UP(urb_size, ep_size); - pr_info("Number of URBs: %d, with %d packets and %d size\n", - num_urb, npackets, urb_size); + dev_info(&dev->udev->dev, + "Number of URBs: %d, with %d packets and %d size\n", + num_urb, npackets, urb_size); /* Estimate the bytes per period */ dev->adev.period = urb_size * npackets; @@ -857,7 +864,8 @@ static int em28xx_audio_urb_init(struct em28xx *dev) buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC, &urb->transfer_dma); if (!buf) { - pr_err("usb_alloc_coherent failed!\n"); + dev_err(&dev->udev->dev, + "usb_alloc_coherent failed!\n"); em28xx_audio_free_urb(dev); return -ENOMEM; } @@ -897,12 +905,14 @@ static int em28xx_audio_init(struct em28xx *dev) return 0; } - pr_info("Binding audio extension\n"); + dev_info(&dev->udev->dev, "Binding audio extension\n"); kref_get(&dev->ref); - pr_info("em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); - pr_info("em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n"); + dev_info(&dev->udev->dev, + "em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); + dev_info(&dev->udev->dev, + "em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n"); err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio", THIS_MODULE, 0, &card); @@ -952,7 +962,7 @@ static int em28xx_audio_init(struct em28xx *dev) if (err < 0) goto urb_free; - pr_info("Audio extension successfully initialized\n"); + dev_info(&dev->udev->dev, "Audio extension successfully initialized\n"); return 0; urb_free: @@ -977,7 +987,7 @@ static int em28xx_audio_fini(struct em28xx *dev) return 0; } - pr_info("Closing audio extension\n"); + dev_info(&dev->udev->dev, "Closing audio extension\n"); if (dev->adev.sndcard) { snd_card_disconnect(dev->adev.sndcard); @@ -1001,7 +1011,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - pr_info("Suspending audio extension\n"); + dev_info(&dev->udev->dev, "Suspending audio extension\n"); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); return 0; @@ -1015,7 +1025,7 @@ static int em28xx_audio_resume(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - pr_info("Resuming audio extension\n"); + dev_info(&dev->udev->dev, "Resuming audio extension\n"); /* Nothing to do other than schedule_work() ?? */ schedule_work(&dev->adev.wq_trigger); return 0; diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index a24695474212..2e24b65901ec 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -22,6 +22,7 @@ #include "em28xx.h" #include +#include #include #include #include @@ -120,14 +121,16 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) ret = i2c_master_send(&client, ®, 1); if (ret < 0) { if (ret != -ENXIO) - pr_err("couldn't read from i2c device 0x%02x: error %i\n", + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { - pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); continue; } id = be16_to_cpu(id_be); @@ -135,14 +138,16 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) reg = 0xff; ret = i2c_master_send(&client, ®, 1); if (ret < 0) { - pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { - pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); continue; } /* Validate chip ID to be sure we have a Micron device */ @@ -180,14 +185,17 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) dev->em28xx_sensor = EM28XX_MT9M001; break; default: - pr_info("unknown Micron sensor detected: 0x%04x\n", id); + dev_info(&dev->udev->dev, + "unknown Micron sensor detected: 0x%04x\n", id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - pr_info("unsupported sensor detected: %s\n", name); + dev_info(&dev->udev->dev, + "unsupported sensor detected: %s\n", name); else - pr_info("sensor %s detected\n", name); + dev_info(&dev->udev->dev, + "sensor %s detected\n", name); dev->i2c_client[dev->def_i2c_bus].addr = client.addr; return 0; @@ -217,16 +225,18 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { if (ret != -ENXIO) - pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); continue; } id = ret << 8; reg = 0x1d; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); continue; } id += ret; @@ -237,16 +247,18 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x0a; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); continue; } id = ret << 8; reg = 0x0b; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - pr_err("couldn't read from i2c device 0x%02x: error %i\n", - client.addr << 1, ret); + dev_err(&dev->udev->dev, + "couldn't read from i2c device 0x%02x: error %i\n", + client.addr << 1, ret); continue; } id += ret; @@ -284,15 +296,18 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) name = "OV9655"; break; default: - pr_info("unknown OmniVision sensor detected: 0x%04x\n", + dev_info(&dev->udev->dev, + "unknown OmniVision sensor detected: 0x%04x\n", id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - pr_info("unsupported sensor detected: %s\n", name); + dev_info(&dev->udev->dev, + "unsupported sensor detected: %s\n", name); else - pr_info("sensor %s detected\n", name); + dev_info(&dev->udev->dev, + "sensor %s detected\n", name); dev->i2c_client[dev->def_i2c_bus].addr = client.addr; return 0; @@ -316,7 +331,8 @@ int em28xx_detect_sensor(struct em28xx *dev) */ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { - pr_info("No sensor detected\n"); + dev_info(&dev->udev->dev, + "No sensor detected\n"); return -ENODEV; } diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 898fab136534..b516c691b9eb 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2677,7 +2677,7 @@ static int em28xx_wait_until_ac97_features_equals(struct em28xx *dev, msleep(50); } - pr_warn("AC97 registers access is not reliable !\n"); + dev_warn(&dev->udev->dev, "AC97 registers access is not reliable !\n"); return -ETIMEDOUT; } @@ -2831,12 +2831,13 @@ static int em28xx_hint_board(struct em28xx *dev) dev->model = em28xx_eeprom_hash[i].model; dev->tuner_type = em28xx_eeprom_hash[i].tuner; - pr_err("Your board has no unique USB ID.\n"); - pr_err("A hint were successfully done, based on eeprom hash.\n"); - pr_err("This method is not 100%% failproof.\n"); - pr_err("If the board were missdetected, please email this log to:\n"); - pr_err("\tV4L Mailing List \n"); - pr_err("Board detected as %s\n", + dev_err(&dev->udev->dev, + "Your board has no unique USB ID.\n" + "A hint were successfully done, based on eeprom hash.\n" + "This method is not 100%% failproof.\n" + "If the board were missdetected, please email this log to:\n" + "\tV4L Mailing List \n" + "Board detected as %s\n", em28xx_boards[dev->model].name); return 0; @@ -2860,28 +2861,33 @@ static int em28xx_hint_board(struct em28xx *dev) if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { dev->model = em28xx_i2c_hash[i].model; dev->tuner_type = em28xx_i2c_hash[i].tuner; - pr_err("Your board has no unique USB ID.\n"); - pr_err("A hint were successfully done, based on i2c devicelist hash.\n"); - pr_err("This method is not 100%% failproof.\n"); - pr_err("If the board were missdetected, please email this log to:\n"); - pr_err("\tV4L Mailing List \n"); - pr_err("Board detected as %s\n", - em28xx_boards[dev->model].name); + dev_err(&dev->udev->dev, + "Your board has no unique USB ID.\n" + "A hint were successfully done, based on i2c devicelist hash.\n" + "This method is not 100%% failproof.\n" + "If the board were missdetected, please email this log to:\n" + "\tV4L Mailing List \n" + "Board detected as %s\n", + em28xx_boards[dev->model].name); return 0; } } - pr_err("Your board has no unique USB ID and thus need a hint to be detected.\n"); - pr_err("You may try to use card= insmod option to workaround that.\n"); - pr_err("Please send an email with this log to:\n"); - pr_err("\tV4L Mailing List \n"); - pr_err("Board eeprom hash is 0x%08lx\n", dev->hash); - pr_err("Board i2c devicelist hash is 0x%08lx\n", dev->i2c_hash); - - pr_err("Here is a list of valid choices for the card= insmod option:\n"); + dev_err(&dev->udev->dev, + "Your board has no unique USB ID and thus need a hint to be detected.\n" + "You may try to use card= insmod option to workaround that.\n" + "Please send an email with this log to:\n" + "\tV4L Mailing List \n" + "Board eeprom hash is 0x%08lx\n" + "Board i2c devicelist hash is 0x%08lx\n", + dev->hash, dev->i2c_hash); + + dev_err(&dev->udev->dev, + "Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < em28xx_bcount; i++) { - pr_err(" card=%d -> %s\n", i, em28xx_boards[i].name); + dev_err(&dev->udev->dev, + " card=%d -> %s\n", i, em28xx_boards[i].name); } return -1; } @@ -2915,7 +2921,7 @@ static void em28xx_card_setup(struct em28xx *dev) * hash identities which has not been determined as yet. */ if (em28xx_hint_board(dev) < 0) - pr_err("Board not discovered\n"); + dev_err(&dev->udev->dev, "Board not discovered\n"); else { em28xx_set_model(dev); em28xx_pre_card_setup(dev); @@ -2925,7 +2931,7 @@ static void em28xx_card_setup(struct em28xx *dev) em28xx_set_model(dev); } - pr_info("Identified as %s (card=%d)\n", + dev_info(&dev->udev->dev, "Identified as %s (card=%d)\n", dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; @@ -3024,10 +3030,11 @@ static void em28xx_card_setup(struct em28xx *dev) } if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) { - pr_err("\n\n"); - pr_err("The support for this board weren't valid yet.\n"); - pr_err("Please send a report of having this working\n"); - pr_err("not to V4L mailing list (and/or to other addresses)\n\n"); + dev_err(&dev->udev->dev, + "\n\n" + "The support for this board weren't valid yet.\n" + "Please send a report of having this working\n" + "not to V4L mailing list (and/or to other addresses)\n\n"); } /* Free eeprom data memory */ @@ -3154,7 +3161,7 @@ static int em28xx_media_device_init(struct em28xx *dev, else if (udev->manufacturer) media_device_usb_init(mdev, udev, udev->manufacturer); else - media_device_usb_init(mdev, udev, dev->name); + media_device_usb_init(mdev, udev, dev_name(&dev->udev->dev)); dev->media_dev = mdev; #endif @@ -3210,7 +3217,7 @@ void em28xx_free_device(struct kref *ref) { struct em28xx *dev = kref_to_dev(ref); - pr_info("Freeing device\n"); + dev_info(&dev->udev->dev, "Freeing device\n"); if (!dev->disconnected) em28xx_release_resources(dev); @@ -3315,19 +3322,18 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, dev->wait_after_write = 0; dev->eeprom_addrwidth_16bit = 1; break; - default: - pr_info("unknown em28xx chip ID (%d)\n", dev->chip_id); } } - if (chip_name != default_chip_name) - pr_info("chip ID is %s\n", chip_name); + dev_set_name(&dev->udev->dev, "%d-%s: %s#%d", + dev->udev->bus->busnum, dev->udev->devpath, + chip_name, dev->devno); - /* - * For em2820/em2710, the name may change latter, after checking - * if the device has a sensor (so, it is em2710) or not. - */ - snprintf(dev->name, sizeof(dev->name), "%s #%d", chip_name, dev->devno); + if (chip_name == default_chip_name) + dev_info(&dev->udev->dev, + "unknown em28xx chip ID (%d)\n", dev->chip_id); + else + dev_info(&dev->udev->dev, "chip ID is %s\n", chip_name); em28xx_media_device_init(dev, udev); @@ -3346,7 +3352,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, /* Resets I2C speed */ retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { - pr_err("%s: em28xx_write_reg failed! retval [%d]\n", + dev_err(&dev->udev->dev, + "%s: em28xx_write_reg failed! retval [%d]\n", __func__, retval); return retval; } @@ -3360,7 +3367,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, else retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { - pr_err("%s: em28xx_i2c_register bus 0 - error [%d]!\n", + dev_err(&dev->udev->dev, + "%s: em28xx_i2c_register bus 0 - error [%d]!\n", __func__, retval); return retval; } @@ -3374,7 +3382,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, retval = em28xx_i2c_register(dev, 1, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { - pr_err("%s: em28xx_i2c_register bus 1 - error [%d]!\n", + dev_err(&dev->udev->dev, + "%s: em28xx_i2c_register bus 1 - error [%d]!\n", __func__, retval); em28xx_i2c_unregister(dev, 0); @@ -3414,7 +3423,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ - pr_err("Driver supports up to %i em28xx boards.\n", + dev_err(&udev->dev, + "Driver supports up to %i em28xx boards.\n", EM28XX_MAXBOARDS); retval = -ENOMEM; goto err_no_slot; @@ -3423,7 +3433,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - pr_err("audio device (%04x:%04x): interface %i, class %i\n", + dev_err(&udev->dev, + "audio device (%04x:%04x): interface %i, class %i\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), ifnum, @@ -3483,7 +3494,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (usb_endpoint_xfer_isoc(e)) { has_vendor_audio = true; } else { - pr_err("error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); + dev_err(&udev->dev, + "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); } break; case 0x84: @@ -3556,7 +3568,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, speed = "unknown"; } - pr_info("New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", + dev_err(&udev->dev, + "New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", udev->manufacturer ? udev->manufacturer : "", udev->product ? udev->product : "", speed, @@ -3571,8 +3584,9 @@ static int em28xx_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - pr_err("Device initialization failed.\n"); - pr_err("Device must be connected to a high-speed USB 2.0 port.\n"); + dev_err(&udev->dev, "Device initialization failed.\n"); + dev_err(&udev->dev, + "Device must be connected to a high-speed USB 2.0 port.\n"); retval = -ENODEV; goto err_free; } @@ -3585,7 +3599,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->ifnum = ifnum; if (has_vendor_audio) { - pr_info("Audio interface %i found (Vendor Class)\n", ifnum); + dev_err(&udev->dev, + "Audio interface %i found (Vendor Class)\n", ifnum); dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR; } /* Checks if audio is provided by a USB Audio Class interface */ @@ -3594,7 +3609,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { if (has_vendor_audio) - pr_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n" + dev_err(&udev->dev, + "em28xx: device seems to have vendor AND usb audio class interfaces !\n" "\t\tThe vendor interface will be ignored. Please contact the developers \n"); dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; break; @@ -3602,12 +3618,12 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if (has_video) - pr_info("Video interface %i found:%s%s\n", + dev_err(&udev->dev, "Video interface %i found:%s%s\n", ifnum, dev->analog_ep_bulk ? " bulk" : "", dev->analog_ep_isoc ? " isoc" : ""); if (has_dvb) - pr_info("DVB interface %i found:%s%s\n", + dev_err(&udev->dev, "DVB interface %i found:%s%s\n", ifnum, dev->dvb_ep_bulk ? " bulk" : "", dev->dvb_ep_isoc ? " isoc" : ""); @@ -3639,7 +3655,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Disable V4L2 if the device doesn't have a decoder */ if (has_video && dev->board.decoder == EM28XX_NODECODER && !dev->board.is_webcam) { - pr_err("Currently, V4L2 is not supported on this model\n"); + dev_err(&udev->dev, + "Currently, V4L2 is not supported on this model\n"); has_video = false; dev->has_video = false; } @@ -3648,13 +3665,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video) { if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) dev->analog_xfer_bulk = 1; - pr_info("analog set to %s mode.\n", + dev_err(&udev->dev, "analog set to %s mode.\n", dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) dev->dvb_xfer_bulk = 1; - pr_info("dvb set to %s mode.\n", + dev_err(&udev->dev, "dvb set to %s mode.\n", dev->dvb_xfer_bulk ? "bulk" : "isoc"); } @@ -3702,7 +3719,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) dev->disconnected = 1; - pr_info("Disconnecting %s\n", dev->name); + dev_err(&dev->udev->dev, "Disconnecting\n"); flush_request_modules(dev); diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index a413ff7c30d7..7f1fe5d9d685 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -50,25 +50,29 @@ static unsigned int core_debug; module_param(core_debug, int, 0644); MODULE_PARM_DESC(core_debug, "enable debug messages [core and isoc]"); -#define em28xx_coredbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_DEBUG pr_fmt("core: %s: " fmt), \ - __func__, ##arg); } while (0) +#define em28xx_coredbg(fmt, arg...) do { \ + if (core_debug) \ + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "core: %s: " fmt, __func__, ## arg); \ +} while (0) static unsigned int reg_debug; module_param(reg_debug, int, 0644); MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); -#define em28xx_regdbg(fmt, arg...) do {\ - if (reg_debug) \ - printk(KERN_DEBUG pr_fmt("reg: %s: " fmt), \ - __func__, ##arg); } while (0) -/* FIXME */ -#define em28xx_isocdbg(fmt, arg...) do {\ - if (core_debug) \ - printk(KERN_DEBUG pr_fmt("isoc: %s: " fmt), \ - __func__, ##arg); } while (0) +#define em28xx_regdbg(fmt, arg...) do { \ + if (reg_debug) \ + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "reg: %s: " fmt, __func__, ## arg); \ +} while (0) + +/* FIXME: don't abuse core_debug */ +#define em28xx_isocdbg(fmt, arg...) do { \ + if (core_debug) \ + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "core: %s: " fmt, __func__, ## arg); \ +} while (0) /* * em28xx_read_reg_req() @@ -86,23 +90,22 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, if (len > URB_MAX_CTRL_SIZE) return -EINVAL; - if (reg_debug) { - printk(KERN_DEBUG - "(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x ", - pipe, - USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8); - } + em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x ", + pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8); mutex_lock(&dev->ctrl_urb_lock); ret = usb_control_msg(dev->udev, pipe, req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { - if (reg_debug) - pr_cont(" failed!\n"); + em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x failed\n", + pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8); mutex_unlock(&dev->ctrl_urb_lock); return usb_translate_errors(ret); } @@ -112,14 +115,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, mutex_unlock(&dev->ctrl_urb_lock); - if (reg_debug) { - int byte; - - pr_cont("<<<"); - for (byte = 0; byte < len; byte++) - pr_cont(" %02x", (unsigned char)buf[byte]); - pr_cont("\n"); - } + em28xx_regdbg("(pipe 0x%08x): IN: %02x %02x %02x %02x %02x %02x %02x %02x failed <<< %*ph\n", + pipe, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8, len, buf); return ret; } @@ -162,21 +162,12 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, if ((len < 1) || (len > URB_MAX_CTRL_SIZE)) return -EINVAL; - if (reg_debug) { - int byte; - - printk(KERN_DEBUG - "(pipe 0x%08x): OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>>", - pipe, - USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, - req, 0, 0, - reg & 0xff, reg >> 8, - len & 0xff, len >> 8); - - for (byte = 0; byte < len; byte++) - pr_cont(" %02x", (unsigned char)buf[byte]); - pr_cont("\n"); - } + em28xx_regdbg("(pipe 0x%08x): OUT: %02x %02x %02x %02x %02x %02x %02x %02x >>> %*ph\n", + pipe, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + req, 0, 0, + reg & 0xff, reg >> 8, + len & 0xff, len >> 8, len, buf); mutex_lock(&dev->ctrl_urb_lock); memcpy(dev->urb_buf, buf, len); @@ -267,7 +258,8 @@ static int em28xx_is_ac97_ready(struct em28xx *dev) msleep(5); } - pr_warn("AC97 command still being executed: not handled properly!\n"); + dev_warn(&dev->udev->dev, + "AC97 command still being executed: not handled properly!\n"); return -EBUSY; } @@ -360,8 +352,9 @@ static int set_ac97_input(struct em28xx *dev) ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); if (ret < 0) - pr_warn("couldn't setup AC97 register %d\n", - inputs[i].reg); + dev_warn(&dev->udev->dev, + "couldn't setup AC97 register %d\n", + inputs[i].reg); } return 0; } @@ -444,8 +437,9 @@ int em28xx_audio_analog_set(struct em28xx *dev) for (i = 0; i < ARRAY_SIZE(outputs); i++) { ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000); if (ret < 0) - pr_warn("couldn't setup AC97 register %d\n", - outputs[i].reg); + dev_warn(&dev->udev->dev, + "couldn't setup AC97 register %d\n", + outputs[i].reg); } } @@ -482,8 +476,9 @@ int em28xx_audio_analog_set(struct em28xx *dev) ret = em28xx_write_ac97(dev, outputs[i].reg, vol); if (ret < 0) - pr_warn("couldn't setup AC97 register %d\n", - outputs[i].reg); + dev_warn(&dev->udev->dev, + "couldn't setup AC97 register %d\n", + outputs[i].reg); } if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) { @@ -519,7 +514,7 @@ int em28xx_audio_setup(struct em28xx *dev) /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); - pr_info("Config register raw data: 0x%02x\n", cfg); + dev_info(&dev->udev->dev, "Config register raw data: 0x%02x\n", cfg); if (cfg < 0) { /* Register read error */ /* Be conservative */ dev->int_audio_type = EM28XX_INT_AUDIO_AC97; @@ -540,7 +535,7 @@ int em28xx_audio_setup(struct em28xx *dev) i2s_samplerates = 5; else i2s_samplerates = 3; - pr_info("I2S Audio (%d sample rate(s))\n", + dev_info(&dev->udev->dev, "I2S Audio (%d sample rate(s))\n", i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; @@ -558,7 +553,8 @@ int em28xx_audio_setup(struct em28xx *dev) * Note: (some) em2800 devices without eeprom reports 0x91 on * CHIPCFG register, even not having an AC97 chip */ - pr_warn("AC97 chip type couldn't be determined\n"); + dev_warn(&dev->udev->dev, + "AC97 chip type couldn't be determined\n"); dev->audio_mode.ac97 = EM28XX_NO_AC97; if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR) dev->usb_audio_type = EM28XX_USB_AUDIO_NONE; @@ -571,13 +567,13 @@ int em28xx_audio_setup(struct em28xx *dev) goto init_audio; vid = vid1 << 16 | vid2; - pr_warn("AC97 vendor ID = 0x%08x\n", vid); + dev_warn(&dev->udev->dev, "AC97 vendor ID = 0x%08x\n", vid); feat = em28xx_read_ac97(dev, AC97_RESET); if (feat < 0) goto init_audio; - pr_warn("AC97 features = 0x%04x\n", feat); + dev_warn(&dev->udev->dev, "AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90)) @@ -589,17 +585,20 @@ init_audio: /* Reports detected AC97 processor */ switch (dev->audio_mode.ac97) { case EM28XX_NO_AC97: - pr_info("No AC97 audio processor\n"); + dev_info(&dev->udev->dev, "No AC97 audio processor\n"); break; case EM28XX_AC97_EM202: - pr_info("Empia 202 AC97 audio processor detected\n"); + dev_info(&dev->udev->dev, + "Empia 202 AC97 audio processor detected\n"); break; case EM28XX_AC97_SIGMATEL: - pr_info("Sigmatel audio processor detected (stac 97%02x)\n", - vid & 0xff); + dev_info(&dev->udev->dev, + "Sigmatel audio processor detected (stac 97%02x)\n", + vid & 0xff); break; case EM28XX_AC97_OTHER: - pr_warn("Unknown AC97 audio processor detected!\n"); + dev_warn(&dev->udev->dev, + "Unknown AC97 audio processor detected!\n"); break; default: break; @@ -883,21 +882,23 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, if (mode == EM28XX_DIGITAL_MODE) { if ((xfer_bulk && !dev->dvb_ep_bulk) || (!xfer_bulk && !dev->dvb_ep_isoc)) { - pr_err("no endpoint for DVB mode and transfer type %d\n", - xfer_bulk > 0); + dev_err(&dev->udev->dev, + "no endpoint for DVB mode and transfer type %d\n", + xfer_bulk > 0); return -EINVAL; } usb_bufs = &dev->usb_ctl.digital_bufs; } else if (mode == EM28XX_ANALOG_MODE) { if ((xfer_bulk && !dev->analog_ep_bulk) || (!xfer_bulk && !dev->analog_ep_isoc)) { - pr_err("no endpoint for analog mode and transfer type %d\n", - xfer_bulk > 0); + dev_err(&dev->udev->dev, + "no endpoint for analog mode and transfer type %d\n", + xfer_bulk > 0); return -EINVAL; } usb_bufs = &dev->usb_ctl.analog_bufs; } else { - pr_err("invalid mode selected\n"); + dev_err(&dev->udev->dev, "invalid mode selected\n"); return -EINVAL; } @@ -939,7 +940,8 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!usb_bufs->transfer_buffer[i]) { - pr_err("unable to allocate %i bytes for transfer buffer %i%s\n", + dev_err(&dev->udev->dev, + "unable to allocate %i bytes for transfer buffer %i%s\n", sb_size, i, in_interrupt() ? " while in int" : ""); em28xx_uninit_usb_xfer(dev, mode); @@ -1021,7 +1023,8 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, if (xfer_bulk) { rc = usb_clear_halt(dev->udev, usb_bufs->urb[0]->pipe); if (rc < 0) { - pr_err("failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", + dev_err(&dev->udev->dev, + "failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", rc); em28xx_uninit_usb_xfer(dev, mode); return rc; @@ -1037,7 +1040,8 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, for (i = 0; i < usb_bufs->num_bufs; i++) { rc = usb_submit_urb(usb_bufs->urb[i], GFP_ATOMIC); if (rc) { - pr_err("submit of urb %i failed (error=%i)\n", i, rc); + dev_err(&dev->udev->dev, + "submit of urb %i failed (error=%i)\n", i, rc); em28xx_uninit_usb_xfer(dev, mode); return rc; } @@ -1085,7 +1089,7 @@ void em28xx_unregister_extension(struct em28xx_ops *ops) } list_del(&ops->next); mutex_unlock(&em28xx_devlist_mutex); - pr_info("Em28xx: Removed (%s) extension\n", ops->name); + pr_info("em28xx: Removed (%s) extension\n", ops->name); } EXPORT_SYMBOL(em28xx_unregister_extension); @@ -1119,7 +1123,7 @@ int em28xx_suspend_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - pr_info("Suspending extensions\n"); + dev_info(&dev->udev->dev, "Suspending extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) @@ -1133,7 +1137,7 @@ int em28xx_resume_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - pr_info("Resuming extensions\n"); + dev_info(&dev->udev->dev, "Resuming extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 6feb0e416eac..445e51db636f 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -73,9 +73,10 @@ MODULE_PARM_DESC(debug, "enable debug messages [dvb]"); DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); -#define dprintk(level, fmt, arg...) do { \ -if (debug >= level) \ - printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \ +#define dprintk(level, fmt, arg...) do { \ + if (debug >= level) \ + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "dvb: " fmt, ## arg); \ } while (0) struct em28xx_dvb { @@ -735,7 +736,7 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) ret = gpio_request_one(dvb->lna_gpio, flags, NULL); if (ret) - pr_err("gpio request failed %d\n", ret); + dev_err(&dev->udev->dev, "gpio request failed %d\n", ret); else gpio_free(dvb->lna_gpio); @@ -935,19 +936,20 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) cfg.ctrl = &ctl; if (!dev->dvb->fe[0]) { - pr_err("dvb frontend not attached. Can't attach xc3028\n"); + dev_err(&dev->udev->dev, + "dvb frontend not attached. Can't attach xc3028\n"); return -EINVAL; } fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg); if (!fe) { - pr_err("xc3028 attach failed\n"); + dev_err(&dev->udev->dev, "xc3028 attach failed\n"); dvb_frontend_detach(dev->dvb->fe[0]); dev->dvb->fe[0] = NULL; return -EINVAL; } - pr_info("xc3028 attached\n"); + dev_info(&dev->udev->dev, "xc3028 attached\n"); return 0; } @@ -963,11 +965,13 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, mutex_init(&dvb->lock); /* register adapter */ - result = dvb_register_adapter(&dvb->adapter, dev->name, module, device, - adapter_nr); + result = dvb_register_adapter(&dvb->adapter, + dev_name(&dev->udev->dev), module, + device, adapter_nr); if (result < 0) { - pr_warn("dvb_register_adapter failed (errno = %d)\n", - result); + dev_warn(&dev->udev->dev, + "dvb_register_adapter failed (errno = %d)\n", + result); goto fail_adapter; } #ifdef CONFIG_MEDIA_CONTROLLER_DVB @@ -984,8 +988,9 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, /* register frontend */ result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]); if (result < 0) { - pr_warn("dvb_register_frontend failed (errno = %d)\n", - result); + dev_warn(&dev->udev->dev, + "dvb_register_frontend failed (errno = %d)\n", + result); goto fail_frontend0; } @@ -993,8 +998,9 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, if (dvb->fe[1]) { result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]); if (result < 0) { - pr_warn("2nd dvb_register_frontend failed (errno = %d)\n", - result); + dev_warn(&dev->udev->dev, + "2nd dvb_register_frontend failed (errno = %d)\n", + result); goto fail_frontend1; } } @@ -1011,7 +1017,9 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, result = dvb_dmx_init(&dvb->demux); if (result < 0) { - pr_warn("dvb_dmx_init failed (errno = %d)\n", result); + dev_warn(&dev->udev->dev, + "dvb_dmx_init failed (errno = %d)\n", + result); goto fail_dmx; } @@ -1020,29 +1028,35 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, dvb->dmxdev.capabilities = 0; result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); if (result < 0) { - pr_warn("dvb_dmxdev_init failed (errno = %d)\n", result); + dev_warn(&dev->udev->dev, + "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) { - pr_warn("add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", - result); + dev_warn(&dev->udev->dev, + "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) { - pr_warn("add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", - result); + dev_warn(&dev->udev->dev, + "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) { - pr_warn("connect_frontend failed (errno = %d)\n", result); + dev_warn(&dev->udev->dev, + "connect_frontend failed (errno = %d)\n", + result); goto fail_fe_conn; } @@ -1114,7 +1128,7 @@ static int em28xx_dvb_init(struct em28xx *dev) return 0; } - pr_info("Binding DVB extension\n"); + dev_info(&dev->udev->dev, "Binding DVB extension\n"); dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); if (!dvb) @@ -1138,7 +1152,8 @@ static int em28xx_dvb_init(struct em28xx *dev) EM28XX_DVB_NUM_ISOC_PACKETS); } if (result) { - pr_err("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n"); + dev_err(&dev->udev->dev, + "failed to pre-allocate USB transfer buffers for DVB.\n"); kfree(dvb); dev->dvb = NULL; return result; @@ -1317,8 +1332,9 @@ static int em28xx_dvb_init(struct em28xx *dev) result = gpio_request_one(dvb->lna_gpio, GPIOF_OUT_INIT_LOW, NULL); if (result) - pr_err("gpio request failed %d\n", - result); + dev_err(&dev->udev->dev, + "gpio request failed %d\n", + result); else gpio_free(dvb->lna_gpio); @@ -1933,11 +1949,12 @@ static int em28xx_dvb_init(struct em28xx *dev) } break; default: - pr_err("The frontend of your DVB/ATSC card isn't supported yet\n"); + dev_err(&dev->udev->dev, + "The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if (NULL == dvb->fe[0]) { - pr_err("frontend initialization failed\n"); + dev_err(&dev->udev->dev, "frontend initialization failed\n"); result = -EINVAL; goto out_free; } @@ -1952,7 +1969,7 @@ static int em28xx_dvb_init(struct em28xx *dev) if (result < 0) goto out_free; - pr_info("DVB extension successfully initialized\n"); + dev_info(&dev->udev->dev, "DVB extension successfully initialized\n"); kref_get(&dev->ref); @@ -1992,7 +2009,7 @@ static int em28xx_dvb_fini(struct em28xx *dev) if (!dev->dvb) return 0; - pr_info("Closing DVB extension\n"); + dev_info(&dev->udev->dev, "Closing DVB extension\n"); dvb = dev->dvb; @@ -2050,17 +2067,17 @@ static int em28xx_dvb_suspend(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - pr_info("Suspending DVB extension\n"); + dev_info(&dev->udev->dev, "Suspending DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_suspend(dvb->fe[0]); - pr_info("fe0 suspend %d\n", ret); + dev_info(&dev->udev->dev, "fe0 suspend %d\n", ret); } if (dvb->fe[1]) { dvb_frontend_suspend(dvb->fe[1]); - pr_info("fe1 suspend %d\n", ret); + dev_info(&dev->udev->dev, "fe1 suspend %d\n", ret); } } @@ -2077,18 +2094,18 @@ static int em28xx_dvb_resume(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - pr_info("Resuming DVB extension\n"); + dev_info(&dev->udev->dev, "Resuming DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_resume(dvb->fe[0]); - pr_info("fe0 resume %d\n", ret); + dev_info(&dev->udev->dev, "fe0 resume %d\n", ret); } if (dvb->fe[1]) { ret = dvb_frontend_resume(dvb->fe[1]); - pr_info("fe1 resume %d\n", ret); + dev_info(&dev->udev->dev, "fe1 resume %d\n", ret); } } diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index b7a5b4c5ceff..00e39edc0837 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -44,6 +44,13 @@ static unsigned int i2c_debug; module_param(i2c_debug, int, 0644); MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)"); +#define dprintk(level, fmt, arg...) do { \ + if (i2c_debug > level) \ + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "i2c: %s: " fmt, __func__, ## arg); \ +} while (0) + + /* * em2800_i2c_send_bytes() * send up to 4 bytes to the em2800 i2c device @@ -71,7 +78,8 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) /* trigger write */ ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); if (ret != 2 + len) { - pr_warn("failed to trigger write to i2c address 0x%x (error=%i)\n", + dev_warn(&dev->udev->dev, + "failed to trigger write to i2c address 0x%x (error=%i)\n", addr, ret); return (ret < 0) ? ret : -EIO; } @@ -81,20 +89,18 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) if (ret == 0x80 + len - 1) return len; if (ret == 0x94 + len - 1) { - if (i2c_debug == 1) - pr_warn("R05 returned 0x%02x: I2C ACK error\n", - ret); + dprintk(1, "R05 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } if (ret < 0) { - pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", + dev_warn(&dev->udev->dev, + "failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; } msleep(5); } - if (i2c_debug) - pr_warn("write to i2c device at 0x%x timed out\n", addr); + dprintk(0, "write to i2c device at 0x%x timed out\n", addr); return -ETIMEDOUT; } @@ -117,8 +123,9 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) buf2[0] = addr; ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2); if (ret != 2) { - pr_warn("failed to trigger read from i2c address 0x%x (error=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "failed to trigger read from i2c address 0x%x (error=%i)\n", + addr, ret); return (ret < 0) ? ret : -EIO; } @@ -128,29 +135,28 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) if (ret == 0x84 + len - 1) break; if (ret == 0x94 + len - 1) { - if (i2c_debug == 1) - pr_warn("R05 returned 0x%02x: I2C ACK error\n", - ret); + dprintk(1, "R05 returned 0x%02x: I2C ACK error\n", + ret); return -ENXIO; } if (ret < 0) { - pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); + dev_warn(&dev->udev->dev, + "failed to get i2c transfer status from bridge register (error=%i)\n", + ret); return ret; } msleep(5); } if (ret != 0x84 + len - 1) { - if (i2c_debug) - pr_warn("read from i2c device at 0x%x timed out\n", - addr); + dprintk(0, "read from i2c device at 0x%x timed out\n", addr); } /* get the received message */ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); if (ret != len) { - pr_warn("reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", + addr, ret); return (ret < 0) ? ret : -EIO; } for (i = 0; i < len; i++) @@ -194,12 +200,14 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); if (ret != len) { if (ret < 0) { - pr_warn("writing to i2c device at 0x%x failed (error=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "writing to i2c device at 0x%x failed (error=%i)\n", + addr, ret); return ret; } else { - pr_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); + dev_warn(&dev->udev->dev, + "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + len, addr, ret); return -EIO; } } @@ -210,14 +218,14 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (ret == 0) /* success */ return len; if (ret == 0x10) { - if (i2c_debug == 1) - pr_warn("I2C ACK error on writing to addr 0x%02x\n", - addr); + dprintk(1, "I2C ACK error on writing to addr 0x%02x\n", + addr); return -ENXIO; } if (ret < 0) { - pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); + dev_warn(&dev->udev->dev, + "failed to get i2c transfer status from bridge register (error=%i)\n", + ret); return ret; } msleep(5); @@ -230,14 +238,15 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (ret == 0x02 || ret == 0x04) { /* NOTE: these errors seem to be related to clock stretching */ - if (i2c_debug) - pr_warn("write to i2c device at 0x%x timed out (status=%i)\n", - addr, ret); + dprintk(0, + "write to i2c device at 0x%x timed out (status=%i)\n", + addr, ret); return -ETIMEDOUT; } - pr_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "write to i2c device at 0x%x failed with unknown error (status=%i)\n", + addr, ret); return -EIO; } @@ -259,8 +268,9 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) /* Read data from i2c device */ ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); if (ret < 0) { - pr_warn("reading from i2c device at 0x%x failed (error=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "reading from i2c device at 0x%x failed (error=%i)\n", + addr, ret); return ret; } /* @@ -277,27 +287,28 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) if (ret == 0) /* success */ return len; if (ret < 0) { - pr_warn("failed to get i2c transfer status from bridge register (error=%i)\n", - ret); + dev_warn(&dev->udev->dev, + "failed to get i2c transfer status from bridge register (error=%i)\n", + ret); return ret; } if (ret == 0x10) { - if (i2c_debug == 1) - pr_warn("I2C ACK error on writing to addr 0x%02x\n", - addr); + dprintk(1, "I2C ACK error on writing to addr 0x%02x\n", + addr); return -ENXIO; } if (ret == 0x02 || ret == 0x04) { /* NOTE: these errors seem to be related to clock stretching */ - if (i2c_debug) - pr_warn("write to i2c device at 0x%x timed out (status=%i)\n", - addr, ret); + dprintk(0, + "write to i2c device at 0x%x timed out (status=%i)\n", + addr, ret); return -ETIMEDOUT; } - pr_warn("write to i2c device at 0x%x failed with unknown error (status=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "write to i2c device at 0x%x failed with unknown error (status=%i)\n", + addr, ret); return -EIO; } @@ -336,12 +347,14 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len); if (ret != len) { if (ret < 0) { - pr_warn("writing to i2c device at 0x%x failed (error=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "writing to i2c device at 0x%x failed (error=%i)\n", + addr, ret); return ret; } else { - pr_warn("%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", - len, addr, ret); + dev_warn(&dev->udev->dev, + "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", + len, addr, ret); return -EIO; } } @@ -354,9 +367,7 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (!ret) return len; else if (ret > 0) { - if (i2c_debug == 1) - pr_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", - ret); + dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -387,8 +398,9 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, /* Read value */ ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len); if (ret < 0) { - pr_warn("reading from i2c device at 0x%x failed (error=%i)\n", - addr, ret); + dev_warn(&dev->udev->dev, + "reading from i2c device at 0x%x failed (error=%i)\n", + addr, ret); return ret; } /* @@ -409,9 +421,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, if (!ret) return len; else if (ret > 0) { - if (i2c_debug == 1) - pr_warn("Bus B R08 returned 0x%02x: I2C ACK error\n", - ret); + dprintk(1, "Bus B R08 returned 0x%02x: I2C ACK error\n", ret); return -ENXIO; } @@ -529,57 +539,46 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap, } for (i = 0; i < num; i++) { addr = msgs[i].addr << 1; - if (i2c_debug > 1) - printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:", - dev->name, __func__ , - (msgs[i].flags & I2C_M_RD) ? "read" : "write", - i == num - 1 ? "stop" : "nonstop", - addr, msgs[i].len); if (!msgs[i].len) { /* * no len: check only for device presence * This code is only called during device probe. */ rc = i2c_check_for_device(i2c_bus, addr); - if (rc < 0) { - if (rc == -ENXIO) { - if (i2c_debug > 1) - pr_cont(" no device\n"); - rc = -ENODEV; - } else { - if (i2c_debug > 1) - pr_cont(" ERROR: %i\n", rc); - } - rt_mutex_unlock(&dev->i2c_bus_lock); - return rc; - } + + if (rc == -ENXIO) + rc = -ENODEV; } else if (msgs[i].flags & I2C_M_RD) { /* read bytes */ rc = i2c_recv_bytes(i2c_bus, msgs[i]); - - if (i2c_debug > 1 && rc >= 0) - pr_cont(" %*ph", - msgs[i].len, msgs[i].buf); } else { - if (i2c_debug > 1) - pr_cont(" %*ph", - msgs[i].len, msgs[i].buf); - /* write bytes */ rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1); } - if (rc < 0) { - if (i2c_debug > 1) - pr_cont(" ERROR: %i\n", rc); - rt_mutex_unlock(&dev->i2c_bus_lock); - return rc; - } - if (i2c_debug > 1) - pr_cont("\n"); + + if (rc < 0) + goto error; + + dprintk(2, "%s %s addr=%02x len=%d: %*ph\n", + (msgs[i].flags & I2C_M_RD) ? "read" : "write", + i == num - 1 ? "stop" : "nonstop", + addr, msgs[i].len, + msgs[i].len, msgs[i].buf); } rt_mutex_unlock(&dev->i2c_bus_lock); return num; + +error: + dprintk(2, "%s %s addr=%02x len=%d: %sERROR: %i\n", + (msgs[i].flags & I2C_M_RD) ? "read" : "write", + i == num - 1 ? "stop" : "nonstop", + addr, msgs[i].len, + (rc == -ENODEV) ? "no device " : "", + rc); + + rt_mutex_unlock(&dev->i2c_bus_lock); + return rc; } /* @@ -673,7 +672,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, /* Check if board has eeprom */ err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0); if (err < 0) { - pr_info("board has no eeprom\n"); + dev_info(&dev->udev->dev, "board has no eeprom\n"); return -ENODEV; } @@ -686,17 +685,19 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, dev->eeprom_addrwidth_16bit, len, data); if (err != len) { - pr_err("failed to read eeprom (err=%d)\n", err); + dev_err(&dev->udev->dev, + "failed to read eeprom (err=%d)\n", err); goto error; } if (i2c_debug) { /* Display eeprom content */ - print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET, + print_hex_dump(KERN_DEBUG, "em28xx eeprom ", DUMP_PREFIX_OFFSET, 16, 1, data, len, true); if (dev->eeprom_addrwidth_16bit) - pr_info("eeprom %06x: ... (skipped)\n", 256); + dev_info(&dev->udev->dev, + "eeprom %06x: ... (skipped)\n", 256); } if (dev->eeprom_addrwidth_16bit && @@ -708,11 +709,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, dev->hash = em28xx_hash_mem(data, len, 32); mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ - pr_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); - pr_info("EEPROM info:\n"); - pr_info("\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", - mc_start, data[2]); + dev_info(&dev->udev->dev, + "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", + data[0], data[1], data[2], data[3], dev->hash); + dev_info(&dev->udev->dev, + "EEPROM info:\n"); + dev_info(&dev->udev->dev, + "\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", + mc_start, data[2]); /* * boot configuration (address 0x0002): * [0] microcode download speed: 1 = 400 kHz; 0 = 100 kHz @@ -730,8 +734,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2, data); if (err != 2) { - pr_err("failed to read hardware configuration data from eeprom (err=%d)\n", - err); + dev_err(&dev->udev->dev, + "failed to read hardware configuration data from eeprom (err=%d)\n", + err); goto error; } @@ -748,8 +753,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len, data); if (err != len) { - pr_err("failed to read hardware configuration data from eeprom (err=%d)\n", - err); + dev_err(&dev->udev->dev, + "failed to read hardware configuration data from eeprom (err=%d)\n", + err); goto error; } @@ -757,7 +763,8 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, /* NOTE: not all devices provide this type of dataset */ if (data[0] != 0x1a || data[1] != 0xeb || data[2] != 0x67 || data[3] != 0x95) { - pr_info("\tno hardware configuration dataset found in eeprom\n"); + dev_info(&dev->udev->dev, + "\tno hardware configuration dataset found in eeprom\n"); kfree(data); return 0; } @@ -768,11 +775,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data[0] == 0x1a && data[1] == 0xeb && data[2] == 0x67 && data[3] == 0x95) { dev->hash = em28xx_hash_mem(data, len, 32); - pr_info("EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", - data[0], data[1], data[2], data[3], dev->hash); - pr_info("EEPROM info:\n"); + dev_info(&dev->udev->dev, + "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", + data[0], data[1], data[2], data[3], dev->hash); + dev_info(&dev->udev->dev, + "EEPROM info:\n"); } else { - pr_info("unknown eeprom format or eeprom corrupted !\n"); + dev_info(&dev->udev->dev, + "unknown eeprom format or eeprom corrupted !\n"); err = -ENODEV; goto error; } @@ -783,50 +793,55 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) { case 0: - pr_info("\tNo audio on board.\n"); + dev_info(&dev->udev->dev, "\tNo audio on board.\n"); break; case 1: - pr_info("\tAC97 audio (5 sample rates)\n"); + dev_info(&dev->udev->dev, "\tAC97 audio (5 sample rates)\n"); break; case 2: if (dev->chip_id < CHIP_ID_EM2860) - pr_info("\tI2S audio, sample rate=32k\n"); + dev_info(&dev->udev->dev, + "\tI2S audio, sample rate=32k\n"); else - pr_info("\tI2S audio, 3 sample rates\n"); + dev_info(&dev->udev->dev, + "\tI2S audio, 3 sample rates\n"); break; case 3: if (dev->chip_id < CHIP_ID_EM2860) - pr_info("\tI2S audio, 3 sample rates\n"); + dev_info(&dev->udev->dev, + "\tI2S audio, 3 sample rates\n"); else - pr_info("\tI2S audio, 5 sample rates\n"); + dev_info(&dev->udev->dev, + "\tI2S audio, 5 sample rates\n"); break; } if (le16_to_cpu(dev_config->chip_conf) & 1 << 3) - pr_info("\tUSB Remote wakeup capable\n"); + dev_info(&dev->udev->dev, "\tUSB Remote wakeup capable\n"); if (le16_to_cpu(dev_config->chip_conf) & 1 << 2) - pr_info("\tUSB Self power capable\n"); + dev_info(&dev->udev->dev, "\tUSB Self power capable\n"); switch (le16_to_cpu(dev_config->chip_conf) & 0x3) { case 0: - pr_info("\t500mA max power\n"); + dev_info(&dev->udev->dev, "\t500mA max power\n"); break; case 1: - pr_info("\t400mA max power\n"); + dev_info(&dev->udev->dev, "\t400mA max power\n"); break; case 2: - pr_info("\t300mA max power\n"); + dev_info(&dev->udev->dev, "\t300mA max power\n"); break; case 3: - pr_info("\t200mA max power\n"); + dev_info(&dev->udev->dev, "\t200mA max power\n"); break; } - pr_info("\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", - dev_config->string_idx_table, - le16_to_cpu(dev_config->string1), - le16_to_cpu(dev_config->string2), - le16_to_cpu(dev_config->string3)); + dev_info(&dev->udev->dev, + "\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", + dev_config->string_idx_table, + le16_to_cpu(dev_config->string1), + le16_to_cpu(dev_config->string2), + le16_to_cpu(dev_config->string3)); return 0; @@ -915,8 +930,9 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) if (rc < 0) continue; i2c_devicelist[i] = i; - pr_info("found i2c device @ 0x%x on bus %d [%s]\n", - i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???"); + dev_info(&dev->udev->dev, + "found i2c device @ 0x%x on bus %d [%s]\n", + i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???"); } if (bus == dev->def_i2c_bus) @@ -941,7 +957,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, dev->i2c_adap[bus] = em28xx_adap_template; dev->i2c_adap[bus].dev.parent = &dev->udev->dev; - strcpy(dev->i2c_adap[bus].name, dev->name); + strcpy(dev->i2c_adap[bus].name, dev_name(&dev->udev->dev)); dev->i2c_bus[bus].bus = bus; dev->i2c_bus[bus].algo_type = algo_type; @@ -950,8 +966,9 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, retval = i2c_add_adapter(&dev->i2c_adap[bus]); if (retval < 0) { - pr_err("%s: i2c_add_adapter failed! retval [%d]\n", - __func__, retval); + dev_err(&dev->udev->dev, + "%s: i2c_add_adapter failed! retval [%d]\n", + __func__, retval); return retval; } @@ -962,8 +979,9 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, if (!bus) { retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len); if ((retval < 0) && (retval != -ENODEV)) { - pr_err("%s: em28xx_i2_eeprom failed! retval [%d]\n", - __func__, retval); + dev_err(&dev->udev->dev, + "%s: em28xx_i2_eeprom failed! retval [%d]\n", + __func__, retval); return retval; } diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 0e23e65eff15..a1904e2230ea 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -41,10 +41,11 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define MODULE_NAME "em28xx" -#define dprintk(fmt, arg...) \ - if (ir_debug) { \ - printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \ - } +#define dprintk( fmt, arg...) do { \ + if (ir_debug) \ + dev_printk(KERN_DEBUG, &ir->dev->udev->dev, \ + "input: %s: " fmt, __func__, ## arg); \ +} while (0) /********************************************************** Polling structure used by em28xx IR's @@ -458,8 +459,9 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) case CHIP_ID_EM28178: return em2874_ir_change_protocol(rc_dev, rc_type); default: - pr_err("Unrecognized em28xx chip id 0x%02x: IR not supported\n", - dev->chip_id); + dev_err(&ir->dev->udev->dev, + "Unrecognized em28xx chip id 0x%02x: IR not supported\n", + dev->chip_id); return -EINVAL; } } @@ -567,7 +569,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) struct input_dev *input_dev; int err; - pr_info("Registering snapshot button...\n"); + dev_info(&dev->udev->dev, "Registering snapshot button...\n"); input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; @@ -591,7 +593,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) err = input_register_device(input_dev); if (err) { - pr_err("input_register_device failed\n"); + dev_err(&dev->udev->dev, "input_register_device failed\n"); input_free_device(input_dev); return err; } @@ -631,7 +633,8 @@ static void em28xx_init_buttons(struct em28xx *dev) } else if (button->role == EM28XX_BUTTON_ILLUMINATION) { /* Check sanity */ if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) { - pr_err("BUG: illumination button defined, but no illumination LED.\n"); + dev_err(&dev->udev->dev, + "BUG: illumination button defined, but no illumination LED.\n"); goto next_button; } } @@ -667,7 +670,7 @@ static void em28xx_shutdown_buttons(struct em28xx *dev) dev->num_button_polling_addresses = 0; /* Deregister input devices */ if (dev->sbutton_input_dev != NULL) { - pr_info("Deregistering snapshot button\n"); + dev_info(&dev->udev->dev, "Deregistering snapshot button\n"); input_unregister_device(dev->sbutton_input_dev); dev->sbutton_input_dev = NULL; } @@ -696,18 +699,20 @@ static int em28xx_ir_init(struct em28xx *dev) i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev); if (!i2c_rc_dev_addr) { dev->board.has_ir_i2c = 0; - pr_warn("No i2c IR remote control device found.\n"); + dev_warn(&dev->udev->dev, + "No i2c IR remote control device found.\n"); return -ENODEV; } } if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) { /* No remote control support */ - pr_warn("Remote control support is not available for this card.\n"); + dev_warn(&dev->udev->dev, + "Remote control support is not available for this card.\n"); return 0; } - pr_info("Registering input extension\n"); + dev_info(&dev->udev->dev, "Registering input extension\n"); ir = kzalloc(sizeof(*ir), GFP_KERNEL); if (!ir) @@ -791,7 +796,8 @@ static int em28xx_ir_init(struct em28xx *dev) ir->polling = 100; /* ms */ /* init input device */ - snprintf(ir->name, sizeof(ir->name), "em28xx IR (%s)", dev->name); + snprintf(ir->name, sizeof(ir->name), "%s IR", + dev_name(&dev->udev->dev)); usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); @@ -810,7 +816,7 @@ static int em28xx_ir_init(struct em28xx *dev) if (err) goto error; - pr_info("Input extension successfully initalized\n"); + dev_info(&dev->udev->dev, "Input extension successfully initalized\n"); return 0; @@ -831,7 +837,7 @@ static int em28xx_ir_fini(struct em28xx *dev) return 0; } - pr_info("Closing input extension\n"); + dev_info(&dev->udev->dev, "Closing input extension\n"); em28xx_shutdown_buttons(dev); @@ -860,7 +866,7 @@ static int em28xx_ir_suspend(struct em28xx *dev) if (dev->is_audio_only) return 0; - pr_info("Suspending input extension\n"); + dev_info(&dev->udev->dev, "Suspending input extension\n"); if (ir) cancel_delayed_work_sync(&ir->work); cancel_delayed_work_sync(&dev->buttons_query_work); @@ -877,7 +883,7 @@ static int em28xx_ir_resume(struct em28xx *dev) if (dev->is_audio_only) return 0; - pr_info("Resuming input extension\n"); + dev_info(&dev->udev->dev, "Resuming input extension\n"); /* if suspend calls ir_raw_event_unregister(), the should call ir_raw_event_register() */ if (ir) diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 744b3300b153..1b21d001cc7e 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "em28xx-v4l.h" @@ -64,8 +65,9 @@ static int vbi_buffer_prepare(struct vb2_buffer *vb) size = v4l2->vbi_width * v4l2->vbi_height * 2; if (vb2_plane_size(vb, 0) < size) { - pr_info("%s data will not fit into plane (%lu < %lu)\n", - __func__, vb2_plane_size(vb, 0), size); + dev_info(&dev->udev->dev, + "%s data will not fit into plane (%lu < %lu)\n", + __func__, vb2_plane_size(vb, 0), size); return -EINVAL; } vb2_set_plane_payload(vb, 0, size); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 8b5e13bbfb07..2d282ed9aac0 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -64,15 +64,17 @@ static int alt; module_param(alt, int, 0644); MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); -#define em28xx_videodbg(fmt, arg...) do {\ - if (video_debug) \ - printk(KERN_DEBUG pr_fmt("video: %s: " fmt), \ - __func__, ##arg); } while (0) +#define em28xx_videodbg(fmt, arg...) do { \ + if (video_debug) \ + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "video: %s: " fmt, __func__, ## arg); \ +} while (0) #define em28xx_isocdbg(fmt, arg...) do {\ if (isoc_debug) \ - printk(KERN_DEBUG pr_fmt("isoc: %s: " fmt), \ - __func__, ##arg); } while (0) + dev_printk(KERN_DEBUG, &dev->udev->dev, \ + "isoc: %s: " fmt, __func__, ## arg); \ +} while (0) MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface"); @@ -411,8 +413,9 @@ set_alt: dev->alt, dev->max_pkt_size); errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); if (errCode < 0) { - pr_err("cannot change alternate number to %d (error=%i)\n", - dev->alt, errCode); + dev_err(&dev->udev->dev, + "cannot change alternate number to %d (error=%i)\n", + dev->alt, errCode); return errCode; } return 0; @@ -923,10 +926,11 @@ static int em28xx_enable_analog_tuner(struct em28xx *dev) ret = media_entity_setup_link(link, flags); if (ret) { - pr_err("Couldn't change link %s->%s to %s. Error %d\n", - source->name, sink->name, - flags ? "enabled" : "disabled", - ret); + dev_err(&dev->udev->dev, + "Couldn't change link %s->%s to %s. Error %d\n", + source->name, sink->name, + flags ? "enabled" : "disabled", + ret); return ret; } else em28xx_videodbg("link %s->%s was %s\n", @@ -954,14 +958,16 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) v4l2->video_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&v4l2->vdev.entity, 1, &v4l2->video_pad); if (ret < 0) - pr_err("failed to initialize video media entity!\n"); + dev_err(&dev->udev->dev, + "failed to initialize video media entity!\n"); if (em28xx_vbi_supported(dev)) { v4l2->vbi_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&v4l2->vbi_dev.entity, 1, &v4l2->vbi_pad); if (ret < 0) - pr_err("failed to initialize vbi media entity!\n"); + dev_err(&dev->udev->dev, + "failed to initialize vbi media entity!\n"); } /* Webcams don't have input connectors */ @@ -994,11 +1000,13 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]); if (ret < 0) - pr_err("failed to initialize input pad[%d]!\n", i); + dev_err(&dev->udev->dev, + "failed to initialize input pad[%d]!\n", i); ret = media_device_register_entity(dev->media_dev, ent); if (ret < 0) - pr_err("failed to register input entity %d!\n", i); + dev_err(&dev->udev->dev, + "failed to register input entity %d!\n", i); } #endif } @@ -2045,7 +2053,8 @@ static int em28xx_v4l2_open(struct file *filp) ret = v4l2_fh_open(filp); if (ret) { - pr_err("%s: v4l2_fh_open() returned error %d\n", + dev_err(&dev->udev->dev, + "%s: v4l2_fh_open() returned error %d\n", __func__, ret); mutex_unlock(&dev->lock); return ret; @@ -2100,7 +2109,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (v4l2 == NULL) return 0; - pr_info("Closing video extension\n"); + dev_info(&dev->udev->dev, "Closing video extension\n"); mutex_lock(&dev->lock); @@ -2111,17 +2120,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev) em28xx_v4l2_media_release(dev); if (video_is_registered(&v4l2->radio_dev)) { - pr_info("V4L2 device %s deregistered\n", + dev_info(&dev->udev->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { - pr_info("V4L2 device %s deregistered\n", + dev_info(&dev->udev->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { - pr_info("V4L2 device %s deregistered\n", + dev_info(&dev->udev->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } @@ -2151,7 +2160,7 @@ static int em28xx_v4l2_suspend(struct em28xx *dev) if (!dev->has_video) return 0; - pr_info("Suspending video extension\n"); + dev_info(&dev->udev->dev, "Suspending video extension\n"); em28xx_stop_urbs(dev); return 0; } @@ -2164,7 +2173,7 @@ static int em28xx_v4l2_resume(struct em28xx *dev) if (!dev->has_video) return 0; - pr_info("Resuming video extension\n"); + dev_info(&dev->udev->dev, "Resuming video extension\n"); /* what do we do here */ return 0; } @@ -2201,8 +2210,9 @@ static int em28xx_v4l2_close(struct file *filp) em28xx_videodbg("setting alternate 0\n"); errCode = usb_set_interface(dev->udev, 0, 0); if (errCode < 0) { - pr_err("cannot change alternate number to 0 (error=%i)\n", - errCode); + dev_err(&dev->udev->dev, + "cannot change alternate number to 0 (error=%i)\n", + errCode); } } @@ -2335,7 +2345,7 @@ static void em28xx_vdev_init(struct em28xx *dev, vfd->tvnorms = 0; snprintf(vfd->name, sizeof(vfd->name), "%s %s", - dev->name, type_name); + dev_name(&dev->udev->dev), type_name); video_set_drvdata(vfd, dev); } @@ -2419,7 +2429,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) return 0; } - pr_info("Registering V4L2 extension\n"); + dev_info(&dev->udev->dev, "Registering V4L2 extension\n"); mutex_lock(&dev->lock); @@ -2437,7 +2447,8 @@ static int em28xx_v4l2_init(struct em28xx *dev) #endif ret = v4l2_device_register(&dev->udev->dev, &v4l2->v4l2_dev); if (ret < 0) { - pr_err("Call to v4l2_device_register() failed!\n"); + dev_err(&dev->udev->dev, + "Call to v4l2_device_register() failed!\n"); goto err; } @@ -2521,8 +2532,9 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Configure audio */ ret = em28xx_audio_setup(dev); if (ret < 0) { - pr_err("%s: Error while setting audio - error [%d]!\n", - __func__, ret); + dev_err(&dev->udev->dev, + "%s: Error while setting audio - error [%d]!\n", + __func__, ret); goto unregister_dev; } if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { @@ -2549,16 +2561,18 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Send a reset to other chips via gpio */ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); if (ret < 0) { - pr_err("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", - __func__, ret); + dev_err(&dev->udev->dev, + "%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", + __func__, ret); goto unregister_dev; } msleep(3); ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); if (ret < 0) { - pr_err("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", - __func__, ret); + dev_err(&dev->udev->dev, + "%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", + __func__, ret); goto unregister_dev; } msleep(3); @@ -2659,7 +2673,8 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); if (ret) { - pr_err("unable to register video device (error=%i).\n", ret); + dev_err(&dev->udev->dev, + "unable to register video device (error=%i).\n", ret); goto unregister_dev; } @@ -2688,7 +2703,8 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); if (ret < 0) { - pr_err("unable to register vbi device\n"); + dev_err(&dev->udev->dev, + "unable to register vbi device\n"); goto unregister_dev; } } @@ -2699,11 +2715,13 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { - pr_err("can't register radio device\n"); + dev_err(&dev->udev->dev, + "can't register radio device\n"); goto unregister_dev; } - pr_info("Registered radio device as %s\n", - video_device_node_name(&v4l2->radio_dev)); + dev_info(&dev->udev->dev, + "Registered radio device as %s\n", + video_device_node_name(&v4l2->radio_dev)); } /* Init entities at the Media Controller */ @@ -2712,18 +2730,21 @@ static int em28xx_v4l2_init(struct em28xx *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = v4l2_mc_create_media_graph(dev->media_dev); if (ret) { - pr_err("failed to create media graph\n"); + dev_err(&dev->udev->dev, + "failed to create media graph\n"); em28xx_v4l2_media_release(dev); goto unregister_dev; } #endif - pr_info("V4L2 video device registered as %s\n", - video_device_node_name(&v4l2->vdev)); + dev_info(&dev->udev->dev, + "V4L2 video device registered as %s\n", + video_device_node_name(&v4l2->vdev)); if (video_is_registered(&v4l2->vbi_dev)) - pr_info("V4L2 VBI device registered as %s\n", - video_device_node_name(&v4l2->vbi_dev)); + dev_info(&dev->udev->dev, + "V4L2 VBI device registered as %s\n", + video_device_node_name(&v4l2->vbi_dev)); /* Save some power by putting tuner to sleep */ v4l2_device_call_all(&v4l2->v4l2_dev, 0, core, s_power, 0); @@ -2731,7 +2752,8 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* initialize videobuf2 stuff */ em28xx_vb2_setup(dev); - pr_info("V4L2 extension successfully initialized\n"); + dev_info(&dev->udev->dev, + "V4L2 extension successfully initialized\n"); kref_get(&dev->ref); @@ -2740,18 +2762,21 @@ static int em28xx_v4l2_init(struct em28xx *dev) unregister_dev: if (video_is_registered(&v4l2->radio_dev)) { - pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->radio_dev)); + dev_info(&dev->udev->dev, + "V4L2 device %s deregistered\n", + video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { - pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vbi_dev)); + dev_info(&dev->udev->dev, + "V4L2 device %s deregistered\n", + video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { - pr_info("V4L2 device %s deregistered\n", - video_device_node_name(&v4l2->vdev)); + dev_info(&dev->udev->dev, + "V4L2 device %s deregistered\n", + video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 0f6830f5078b..3e5ace497a4e 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -29,8 +29,6 @@ #define EM28XX_VERSION "0.2.2" #define DRIVER_DESC "Empia em28xx device driver" -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - #include #include #include @@ -612,7 +610,6 @@ struct em28xx { struct em28xx_IR *ir; /* generic device properties */ - char name[30]; /* name (including minor) of the device */ int model; /* index in the device_data struct */ int devno; /* marks the number of this device */ enum em28xx_chip_id chip_id; -- cgit v1.2.3 From 257e29f84e377d00f29fbb3a78bad25b7e4eb915 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Nov 2016 08:58:05 -0200 Subject: [media] tvp5150: convert it to use dev_foo() macros Instead of using v4l_foo(), use the dev_foo() macros, as most modern media drivers. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 49 ++++++++++++++++----------------- drivers/media/usb/em28xx/em28xx-audio.c | 3 +- 2 files changed, 25 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 4740da39d698..569eb7c0968a 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -74,11 +74,11 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr) rc = i2c_smbus_read_byte_data(c, addr); if (rc < 0) { - v4l2_err(sd, "i2c i/o error: rc == %d\n", rc); + dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc); return rc; } - v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, rc); + dev_dbg_lvl(sd->dev, 2, debug, "tvp5150: read 0x%02x = %02x\n", addr, rc); return rc; } @@ -89,10 +89,10 @@ static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, struct i2c_client *c = v4l2_get_subdevdata(sd); int rc; - v4l2_dbg(2, debug, sd, "tvp5150: writing 0x%02x 0x%02x\n", addr, value); + dev_dbg_lvl(sd->dev, 2, debug, "tvp5150: writing %02x %02x\n", addr, value); rc = i2c_smbus_write_byte_data(c, addr, value); if (rc < 0) - v4l2_err(sd, "i2c i/o error: rc == %d\n", rc); + dev_err(sd->dev, "i2c i/o error: rc == %d\n", rc); return rc; } @@ -280,8 +280,7 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd) break; } - v4l2_dbg(1, debug, sd, "Selecting video route: route input=%i, output=%i " - "=> tvp5150 input=%i, opmode=%i\n", + dev_dbg_lvl(sd->dev, 1, debug, "Selecting video route: route input=%i, output=%i => tvp5150 input=%i, opmode=%i\n", decoder->input, decoder->output, input, opmode); @@ -293,7 +292,7 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd) */ val = tvp5150_read(sd, TVP5150_MISC_CTL); if (val < 0) { - v4l2_err(sd, "%s: failed with error = %d\n", __func__, val); + dev_err(sd->dev, "%s: failed with error = %d\n", __func__, val); return; } @@ -611,7 +610,7 @@ static int tvp5150_g_sliced_vbi_cap(struct v4l2_subdev *sd, const struct i2c_vbi_ram_value *regs = vbi_ram_default; int line; - v4l2_dbg(1, debug, sd, "g_sliced_vbi_cap\n"); + dev_dbg_lvl(sd->dev, 1, debug, "g_sliced_vbi_cap\n"); memset(cap, 0, sizeof *cap); while (regs->reg != (u16)-1 ) { @@ -649,7 +648,7 @@ static int tvp5150_set_vbi(struct v4l2_subdev *sd, int pos=0; if (std == V4L2_STD_ALL) { - v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); + dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); return 0; } else if (std & V4L2_STD_625_50) { /* Don't follow NTSC Line number convension */ @@ -697,7 +696,7 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd, int i, ret = 0; if (std == V4L2_STD_ALL) { - v4l2_err(sd, "VBI can't be configured without knowing number of lines\n"); + dev_err(sd->dev, "VBI can't be configured without knowing number of lines\n"); return 0; } else if (std & V4L2_STD_625_50) { /* Don't follow NTSC Line number convension */ @@ -712,7 +711,7 @@ static int tvp5150_get_vbi(struct v4l2_subdev *sd, for (i = 0; i <= 1; i++) { ret = tvp5150_read(sd, reg + i); if (ret < 0) { - v4l2_err(sd, "%s: failed with error = %d\n", + dev_err(sd->dev, "%s: failed with error = %d\n", __func__, ret); return 0; } @@ -749,7 +748,7 @@ static int tvp5150_set_std(struct v4l2_subdev *sd, v4l2_std_id std) fmt = VIDEO_STD_SECAM_BIT; } - v4l2_dbg(1, debug, sd, "Set video std register to %d.\n", fmt); + dev_dbg_lvl(sd->dev, 1, debug, "Set video std register to %d.\n", fmt); tvp5150_write(sd, TVP5150_VIDEO_STD, fmt); return 0; } @@ -866,7 +865,7 @@ static int tvp5150_fill_fmt(struct v4l2_subdev *sd, f->field = V4L2_FIELD_ALTERNATE; f->colorspace = V4L2_COLORSPACE_SMPTE170M; - v4l2_dbg(1, debug, sd, "width = %d, height = %d\n", f->width, + dev_dbg_lvl(sd->dev, 1, debug, "width = %d, height = %d\n", f->width, f->height); return 0; } @@ -884,7 +883,7 @@ static int tvp5150_set_selection(struct v4l2_subdev *sd, sel->target != V4L2_SEL_TGT_CROP) return -EINVAL; - v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n", + dev_dbg_lvl(sd->dev, 1, debug, "%s left=%d, top=%d, width=%d, height=%d\n", __func__, rect.left, rect.top, rect.width, rect.height); /* tvp5150 has some special limits */ @@ -1148,7 +1147,7 @@ static int tvp5150_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register * res = tvp5150_read(sd, reg->reg & 0xff); if (res < 0) { - v4l2_err(sd, "%s: failed with error = %d\n", __func__, res); + dev_err(sd->dev, "%s: failed with error = %d\n", __func__, res); return res; } @@ -1288,21 +1287,21 @@ static int tvp5150_detect_version(struct tvp5150 *core) core->dev_id = (regs[0] << 8) | regs[1]; core->rom_ver = (regs[2] << 8) | regs[3]; - v4l2_info(sd, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", + dev_info(sd->dev, "tvp%04x (%u.%u) chip found @ 0x%02x (%s)\n", core->dev_id, regs[2], regs[3], c->addr << 1, c->adapter->name); if (core->dev_id == 0x5150 && core->rom_ver == 0x0321) { - v4l2_info(sd, "tvp5150a detected.\n"); + dev_info(sd->dev, "tvp5150a detected.\n"); } else if (core->dev_id == 0x5150 && core->rom_ver == 0x0400) { - v4l2_info(sd, "tvp5150am1 detected.\n"); + dev_info(sd->dev, "tvp5150am1 detected.\n"); /* ITU-T BT.656.4 timing */ tvp5150_write(sd, TVP5150_REV_SELECT, 0); } else if (core->dev_id == 0x5151 && core->rom_ver == 0x0100) { - v4l2_info(sd, "tvp5151 detected.\n"); + dev_info(sd->dev, "tvp5151 detected.\n"); } else { - v4l2_info(sd, "*** unknown tvp%04x chip detected.\n", + dev_info(sd->dev, "*** unknown tvp%04x chip detected.\n", core->dev_id); } @@ -1381,7 +1380,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) for_each_available_child_of_node(connectors, child) { ret = of_property_read_u32(child, "input", &input_type); if (ret) { - v4l2_err(&decoder->sd, + dev_err(decoder->sd.dev, "missing type property in node %s\n", child->name); goto err_connector; @@ -1396,7 +1395,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) /* Each input connector can only be defined once */ if (input->name) { - v4l2_err(&decoder->sd, + dev_err(decoder->sd.dev, "input %s with same type already exists\n", input->name); ret = -EINVAL; @@ -1417,7 +1416,7 @@ static int tvp5150_parse_dt(struct tvp5150 *decoder, struct device_node *np) ret = of_property_read_string(child, "label", &name); if (ret < 0) { - v4l2_err(&decoder->sd, + dev_err(decoder->sd.dev, "missing label property in node %s\n", child->name); goto err_connector; @@ -1465,7 +1464,7 @@ static int tvp5150_probe(struct i2c_client *c, if (IS_ENABLED(CONFIG_OF) && np) { res = tvp5150_parse_dt(core, np); if (res) { - v4l2_err(sd, "DT parsing error: %d\n", res); + dev_err(sd->dev, "DT parsing error: %d\n", res); return res; } } else { @@ -1549,7 +1548,7 @@ static int tvp5150_remove(struct i2c_client *c) struct v4l2_subdev *sd = i2c_get_clientdata(c); struct tvp5150 *decoder = to_tvp5150(sd); - v4l2_dbg(1, debug, sd, + dev_dbg_lvl(sd->dev, 1, debug, "tvp5150.c: removing tvp5150 adapter on address 0x%x\n", c->addr << 1); diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index cd2545ca5e39..7060e5146e31 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -259,8 +259,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) int nonblock, ret = 0; if (!dev) { - dev_err(&dev->udev->dev, - "BUG: em28xx can't find device struct. Can't proceed with open\n"); + pr_err("em28xx-audio: BUG: em28xx can't find device struct. Can't proceed with open\n"); return -ENODEV; } -- cgit v1.2.3 From ad0e374470684692d7ec1f31ac23065dab4d9d53 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 13 Nov 2016 05:34:12 -0200 Subject: [media] tvp5150: Get rid of direct calls to printk() When returning results via v4l2_subdev_core_ops.log_status, use dev_foo() call, instead of just calling printk() directly, without even specifying the log message level. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 218 ++++++++++++++++++++++---------------------- 1 file changed, 110 insertions(+), 108 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 569eb7c0968a..d0dbdd7ea233 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -36,6 +36,8 @@ static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Debug level (0-2)"); +#define dprintk0(__dev, __arg...) dev_dbg_lvl(__dev, 0, 0, __arg) + struct tvp5150 { struct v4l2_subdev sd; #ifdef CONFIG_MEDIA_CONTROLLER @@ -118,120 +120,120 @@ static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, static int tvp5150_log_status(struct v4l2_subdev *sd) { - printk("tvp5150: Video input source selection #1 = 0x%02x\n", - tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); - printk("tvp5150: Analog channel controls = 0x%02x\n", - tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); - printk("tvp5150: Operation mode controls = 0x%02x\n", - tvp5150_read(sd, TVP5150_OP_MODE_CTL)); - printk("tvp5150: Miscellaneous controls = 0x%02x\n", - tvp5150_read(sd, TVP5150_MISC_CTL)); - printk("tvp5150: Autoswitch mask= 0x%02x\n", - tvp5150_read(sd, TVP5150_AUTOSW_MSK)); - printk("tvp5150: Color killer threshold control = 0x%02x\n", - tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); - printk("tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", - tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), - tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), - tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); - printk("tvp5150: Brightness control = 0x%02x\n", - tvp5150_read(sd, TVP5150_BRIGHT_CTL)); - printk("tvp5150: Color saturation control = 0x%02x\n", - tvp5150_read(sd, TVP5150_SATURATION_CTL)); - printk("tvp5150: Hue control = 0x%02x\n", - tvp5150_read(sd, TVP5150_HUE_CTL)); - printk("tvp5150: Contrast control = 0x%02x\n", - tvp5150_read(sd, TVP5150_CONTRAST_CTL)); - printk("tvp5150: Outputs and data rates select = 0x%02x\n", - tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); - printk("tvp5150: Configuration shared pins = 0x%02x\n", - tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); - printk("tvp5150: Active video cropping start = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), - tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); - printk("tvp5150: Active video cropping stop = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), - tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); - printk("tvp5150: Genlock/RTC = 0x%02x\n", - tvp5150_read(sd, TVP5150_GENLOCK)); - printk("tvp5150: Horizontal sync start = 0x%02x\n", - tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); - printk("tvp5150: Vertical blanking start = 0x%02x\n", - tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); - printk("tvp5150: Vertical blanking stop = 0x%02x\n", - tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); - printk("tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", - tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), - tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); - printk("tvp5150: Interrupt reset register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); - printk("tvp5150: Interrupt enable register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); - printk("tvp5150: Interrupt configuration register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); - printk("tvp5150: Video standard = 0x%02x\n", - tvp5150_read(sd, TVP5150_VIDEO_STD)); - printk("tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", - tvp5150_read(sd, TVP5150_CB_GAIN_FACT), - tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); - printk("tvp5150: Macrovision on counter = 0x%02x\n", - tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); - printk("tvp5150: Macrovision off counter = 0x%02x\n", - tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); - printk("tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", - (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); - printk("tvp5150: Device ID = %02x%02x\n", - tvp5150_read(sd, TVP5150_MSB_DEV_ID), - tvp5150_read(sd, TVP5150_LSB_DEV_ID)); - printk("tvp5150: ROM version = (hex) %02x.%02x\n", - tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), - tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); - printk("tvp5150: Vertical line count = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), - tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); - printk("tvp5150: Interrupt status register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); - printk("tvp5150: Interrupt active register B = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); - printk("tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", - tvp5150_read(sd, TVP5150_STATUS_REG_1), - tvp5150_read(sd, TVP5150_STATUS_REG_2), - tvp5150_read(sd, TVP5150_STATUS_REG_3), - tvp5150_read(sd, TVP5150_STATUS_REG_4), - tvp5150_read(sd, TVP5150_STATUS_REG_5)); + dprintk0(sd->dev, "tvp5150: Video input source selection #1 = 0x%02x\n", + tvp5150_read(sd, TVP5150_VD_IN_SRC_SEL_1)); + dprintk0(sd->dev, "tvp5150: Analog channel controls = 0x%02x\n", + tvp5150_read(sd, TVP5150_ANAL_CHL_CTL)); + dprintk0(sd->dev, "tvp5150: Operation mode controls = 0x%02x\n", + tvp5150_read(sd, TVP5150_OP_MODE_CTL)); + dprintk0(sd->dev, "tvp5150: Miscellaneous controls = 0x%02x\n", + tvp5150_read(sd, TVP5150_MISC_CTL)); + dprintk0(sd->dev, "tvp5150: Autoswitch mask= 0x%02x\n", + tvp5150_read(sd, TVP5150_AUTOSW_MSK)); + dprintk0(sd->dev, "tvp5150: Color killer threshold control = 0x%02x\n", + tvp5150_read(sd, TVP5150_COLOR_KIL_THSH_CTL)); + dprintk0(sd->dev, "tvp5150: Luminance processing controls #1 #2 and #3 = %02x %02x %02x\n", + tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_1), + tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_2), + tvp5150_read(sd, TVP5150_LUMA_PROC_CTL_3)); + dprintk0(sd->dev, "tvp5150: Brightness control = 0x%02x\n", + tvp5150_read(sd, TVP5150_BRIGHT_CTL)); + dprintk0(sd->dev, "tvp5150: Color saturation control = 0x%02x\n", + tvp5150_read(sd, TVP5150_SATURATION_CTL)); + dprintk0(sd->dev, "tvp5150: Hue control = 0x%02x\n", + tvp5150_read(sd, TVP5150_HUE_CTL)); + dprintk0(sd->dev, "tvp5150: Contrast control = 0x%02x\n", + tvp5150_read(sd, TVP5150_CONTRAST_CTL)); + dprintk0(sd->dev, "tvp5150: Outputs and data rates select = 0x%02x\n", + tvp5150_read(sd, TVP5150_DATA_RATE_SEL)); + dprintk0(sd->dev, "tvp5150: Configuration shared pins = 0x%02x\n", + tvp5150_read(sd, TVP5150_CONF_SHARED_PIN)); + dprintk0(sd->dev, "tvp5150: Active video cropping start = 0x%02x%02x\n", + tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_MSB), + tvp5150_read(sd, TVP5150_ACT_VD_CROP_ST_LSB)); + dprintk0(sd->dev, "tvp5150: Active video cropping stop = 0x%02x%02x\n", + tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_MSB), + tvp5150_read(sd, TVP5150_ACT_VD_CROP_STP_LSB)); + dprintk0(sd->dev, "tvp5150: Genlock/RTC = 0x%02x\n", + tvp5150_read(sd, TVP5150_GENLOCK)); + dprintk0(sd->dev, "tvp5150: Horizontal sync start = 0x%02x\n", + tvp5150_read(sd, TVP5150_HORIZ_SYNC_START)); + dprintk0(sd->dev, "tvp5150: Vertical blanking start = 0x%02x\n", + tvp5150_read(sd, TVP5150_VERT_BLANKING_START)); + dprintk0(sd->dev, "tvp5150: Vertical blanking stop = 0x%02x\n", + tvp5150_read(sd, TVP5150_VERT_BLANKING_STOP)); + dprintk0(sd->dev, "tvp5150: Chrominance processing control #1 and #2 = %02x %02x\n", + tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_1), + tvp5150_read(sd, TVP5150_CHROMA_PROC_CTL_2)); + dprintk0(sd->dev, "tvp5150: Interrupt reset register B = 0x%02x\n", + tvp5150_read(sd, TVP5150_INT_RESET_REG_B)); + dprintk0(sd->dev, "tvp5150: Interrupt enable register B = 0x%02x\n", + tvp5150_read(sd, TVP5150_INT_ENABLE_REG_B)); + dprintk0(sd->dev, "tvp5150: Interrupt configuration register B = 0x%02x\n", + tvp5150_read(sd, TVP5150_INTT_CONFIG_REG_B)); + dprintk0(sd->dev, "tvp5150: Video standard = 0x%02x\n", + tvp5150_read(sd, TVP5150_VIDEO_STD)); + dprintk0(sd->dev, "tvp5150: Chroma gain factor: Cb=0x%02x Cr=0x%02x\n", + tvp5150_read(sd, TVP5150_CB_GAIN_FACT), + tvp5150_read(sd, TVP5150_CR_GAIN_FACTOR)); + dprintk0(sd->dev, "tvp5150: Macrovision on counter = 0x%02x\n", + tvp5150_read(sd, TVP5150_MACROVISION_ON_CTR)); + dprintk0(sd->dev, "tvp5150: Macrovision off counter = 0x%02x\n", + tvp5150_read(sd, TVP5150_MACROVISION_OFF_CTR)); + dprintk0(sd->dev, "tvp5150: ITU-R BT.656.%d timing(TVP5150AM1 only)\n", + (tvp5150_read(sd, TVP5150_REV_SELECT) & 1) ? 3 : 4); + dprintk0(sd->dev, "tvp5150: Device ID = %02x%02x\n", + tvp5150_read(sd, TVP5150_MSB_DEV_ID), + tvp5150_read(sd, TVP5150_LSB_DEV_ID)); + dprintk0(sd->dev, "tvp5150: ROM version = (hex) %02x.%02x\n", + tvp5150_read(sd, TVP5150_ROM_MAJOR_VER), + tvp5150_read(sd, TVP5150_ROM_MINOR_VER)); + dprintk0(sd->dev, "tvp5150: Vertical line count = 0x%02x%02x\n", + tvp5150_read(sd, TVP5150_VERT_LN_COUNT_MSB), + tvp5150_read(sd, TVP5150_VERT_LN_COUNT_LSB)); + dprintk0(sd->dev, "tvp5150: Interrupt status register B = 0x%02x\n", + tvp5150_read(sd, TVP5150_INT_STATUS_REG_B)); + dprintk0(sd->dev, "tvp5150: Interrupt active register B = 0x%02x\n", + tvp5150_read(sd, TVP5150_INT_ACTIVE_REG_B)); + dprintk0(sd->dev, "tvp5150: Status regs #1 to #5 = %02x %02x %02x %02x %02x\n", + tvp5150_read(sd, TVP5150_STATUS_REG_1), + tvp5150_read(sd, TVP5150_STATUS_REG_2), + tvp5150_read(sd, TVP5150_STATUS_REG_3), + tvp5150_read(sd, TVP5150_STATUS_REG_4), + tvp5150_read(sd, TVP5150_STATUS_REG_5)); dump_reg_range(sd, "Teletext filter 1", TVP5150_TELETEXT_FIL1_INI, TVP5150_TELETEXT_FIL1_END, 8); dump_reg_range(sd, "Teletext filter 2", TVP5150_TELETEXT_FIL2_INI, TVP5150_TELETEXT_FIL2_END, 8); - printk("tvp5150: Teletext filter enable = 0x%02x\n", - tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); - printk("tvp5150: Interrupt status register A = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); - printk("tvp5150: Interrupt enable register A = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); - printk("tvp5150: Interrupt configuration = 0x%02x\n", - tvp5150_read(sd, TVP5150_INT_CONF)); - printk("tvp5150: VDP status register = 0x%02x\n", - tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); - printk("tvp5150: FIFO word count = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); - printk("tvp5150: FIFO interrupt threshold = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); - printk("tvp5150: FIFO reset = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_RESET)); - printk("tvp5150: Line number interrupt = 0x%02x\n", - tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); - printk("tvp5150: Pixel alignment register = 0x%02x%02x\n", - tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), - tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); - printk("tvp5150: FIFO output control = 0x%02x\n", - tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); - printk("tvp5150: Full field enable = 0x%02x\n", - tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); - printk("tvp5150: Full field mode register = 0x%02x\n", - tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); + dprintk0(sd->dev, "tvp5150: Teletext filter enable = 0x%02x\n", + tvp5150_read(sd, TVP5150_TELETEXT_FIL_ENA)); + dprintk0(sd->dev, "tvp5150: Interrupt status register A = 0x%02x\n", + tvp5150_read(sd, TVP5150_INT_STATUS_REG_A)); + dprintk0(sd->dev, "tvp5150: Interrupt enable register A = 0x%02x\n", + tvp5150_read(sd, TVP5150_INT_ENABLE_REG_A)); + dprintk0(sd->dev, "tvp5150: Interrupt configuration = 0x%02x\n", + tvp5150_read(sd, TVP5150_INT_CONF)); + dprintk0(sd->dev, "tvp5150: VDP status register = 0x%02x\n", + tvp5150_read(sd, TVP5150_VDP_STATUS_REG)); + dprintk0(sd->dev, "tvp5150: FIFO word count = 0x%02x\n", + tvp5150_read(sd, TVP5150_FIFO_WORD_COUNT)); + dprintk0(sd->dev, "tvp5150: FIFO interrupt threshold = 0x%02x\n", + tvp5150_read(sd, TVP5150_FIFO_INT_THRESHOLD)); + dprintk0(sd->dev, "tvp5150: FIFO reset = 0x%02x\n", + tvp5150_read(sd, TVP5150_FIFO_RESET)); + dprintk0(sd->dev, "tvp5150: Line number interrupt = 0x%02x\n", + tvp5150_read(sd, TVP5150_LINE_NUMBER_INT)); + dprintk0(sd->dev, "tvp5150: Pixel alignment register = 0x%02x%02x\n", + tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_HIGH), + tvp5150_read(sd, TVP5150_PIX_ALIGN_REG_LOW)); + dprintk0(sd->dev, "tvp5150: FIFO output control = 0x%02x\n", + tvp5150_read(sd, TVP5150_FIFO_OUT_CTRL)); + dprintk0(sd->dev, "tvp5150: Full field enable = 0x%02x\n", + tvp5150_read(sd, TVP5150_FULL_FIELD_ENA)); + dprintk0(sd->dev, "tvp5150: Full field mode register = 0x%02x\n", + tvp5150_read(sd, TVP5150_FULL_FIELD_MODE_REG)); dump_reg_range(sd, "CC data", TVP5150_CC_DATA_INI, TVP5150_CC_DATA_END, 8); -- cgit v1.2.3 From e513411489202fc642c0d651479b9ccdff961ed0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Oct 2016 11:36:42 -0200 Subject: [media] tvp5150: get rid of KERN_CONT Unfortunately, KERN_CONT doesn't work with dev_foo(), producing weird messages like: tvp5150 6-005c: tvp5150: read 0xf6 = 0xff ff So, we need to get rid of it. As we're always printing read/write in hexa when dumping multiple register values, also remove the "0x" from the read/write debug messages too. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index d0dbdd7ea233..6737685d5be5 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -102,20 +102,22 @@ static int tvp5150_write(struct v4l2_subdev *sd, unsigned char addr, static void dump_reg_range(struct v4l2_subdev *sd, char *s, u8 init, const u8 end, int max_line) { - int i = 0; + u8 buf[16]; + int i = 0, j, len; - while (init != (u8)(end + 1)) { - if ((i % max_line) == 0) { - if (i > 0) - printk("\n"); - printk("tvp5150: %s reg 0x%02x = ", s, init); - } - printk("%02x ", tvp5150_read(sd, init)); + if (max_line > 16) { + dprintk0(sd->dev, "too much data to dump\n"); + return; + } + + for (i = init; i < end; i += max_line) { + len = (end - i > max_line) ? max_line : end - i; + + for (j = 0; j < len; j++) + buf[j] = tvp5150_read(sd, i + j); - init++; - i++; + dprintk0(sd->dev, "%s reg %02x = %*ph\n", s, i, len, buf); } - printk("\n"); } static int tvp5150_log_status(struct v4l2_subdev *sd) -- cgit v1.2.3 From d3d96820d0deb86de3d8237b4026c9c15cb0e47f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 20 Oct 2016 15:04:39 -0200 Subject: [media] rc-main: use pr_foo() macros Instead of calling printk() directly, use pr_foo() macro. That should make the rc_core messages be formatted with the right prefix. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index 5087e76dfb03..adb10fac63e4 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -12,6 +12,8 @@ * GNU General Public License for more details. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -66,7 +68,7 @@ struct rc_map *rc_map_get(const char *name) if (!map) { int rc = request_module("%s", name); if (rc < 0) { - printk(KERN_ERR "Couldn't load IR keymap %s\n", name); + pr_err("Couldn't load IR keymap %s\n", name); return NULL; } msleep(20); /* Give some time for IR to register */ @@ -75,7 +77,7 @@ struct rc_map *rc_map_get(const char *name) } #endif if (!map) { - printk(KERN_ERR "IR keymap %s not found\n", name); + pr_err("IR keymap %s not found\n", name); return NULL; } @@ -1620,7 +1622,7 @@ static int __init rc_core_init(void) { int rc = class_register(&rc_class); if (rc) { - printk(KERN_ERR "rc_core: unable to register rc class\n"); + pr_err("rc_core: unable to register rc class\n"); return rc; } -- cgit v1.2.3 From 6037b3ca28f4258d913dbe77248fd77827702ae3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 16 Nov 2016 14:21:48 -0200 Subject: [media] tveeprom: print log messages using pr_foo() Unfortunately, the callers of tveeprom don't do the right thing to initialize the device. So, it produces log messages like: [ 267.533010] (null): Hauppauge model 42012, rev C186, serial# 2819348 [ 267.533012] (null): tuner model is Philips FQ1236 MK3 (idx 86, type 43) [ 267.533013] (null): TV standards NTSC(M) (eeprom 0x08) [ 267.533014] (null): audio processor is MSP3445 (idx 12) [ 267.533015] (null): has radio So, replace it to pr_foo(), as it should work fine. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/tveeprom.c | 42 +++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c index e7d0d86f19aa..11976031aff8 100644 --- a/drivers/media/common/tveeprom.c +++ b/drivers/media/common/tveeprom.c @@ -28,6 +28,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -496,12 +498,12 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, len = eeprom_data[i] & 0x07; ++i; } else { - dev_warn(&c->dev, "Encountered bad packet header [%02x]. Corrupt or not a Hauppauge eeprom.\n", + pr_warn("Encountered bad packet header [%02x]. Corrupt or not a Hauppauge eeprom.\n", eeprom_data[i]); return; } - dev_dbg(&c->dev, "Tag [%02x] + %d bytes: %*ph\n", + pr_debug("Tag [%02x] + %d bytes: %*ph\n", eeprom_data[i], len - 1, len, &eeprom_data[i]); /* process by tag */ @@ -642,14 +644,14 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, /* case 0x12: tag 'InfoBits' */ default: - dev_dbg(&c->dev, "Not sure what to do with tag [%02x]\n", + pr_debug("Not sure what to do with tag [%02x]\n", tag); /* dump the rest of the packet? */ } } if (!done) { - dev_warn(&c->dev, "Ran out of data!\n"); + pr_warn("Ran out of data!\n"); return; } @@ -662,8 +664,8 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, } if (hasRadioTuner(tuner1) && !tvee->has_radio) { - dev_info(&c->dev, "The eeprom says no radio is present, but the tuner type\n"); - dev_info(&c->dev, "indicates otherwise. I will assume that radio is present.\n"); + pr_info("The eeprom says no radio is present, but the tuner type\n"); + pr_info("indicates otherwise. I will assume that radio is present.\n"); tvee->has_radio = 1; } @@ -698,46 +700,46 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee, } } - dev_info(&c->dev, "Hauppauge model %d, rev %s, serial# %u\n", + pr_info("Hauppauge model %d, rev %s, serial# %u\n", tvee->model, tvee->rev_str, tvee->serial_number); if (tvee->has_MAC_address == 1) - dev_info(&c->dev, "MAC address is %pM\n", tvee->MAC_address); - dev_info(&c->dev, "tuner model is %s (idx %d, type %d)\n", + pr_info("MAC address is %pM\n", tvee->MAC_address); + pr_info("tuner model is %s (idx %d, type %d)\n", t_name1, tuner1, tvee->tuner_type); - dev_info(&c->dev, "TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + pr_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", t_fmt_name1[0], t_fmt_name1[1], t_fmt_name1[2], t_fmt_name1[3], t_fmt_name1[4], t_fmt_name1[5], t_fmt_name1[6], t_fmt_name1[7], t_format1); if (tuner2) - dev_info(&c->dev, "second tuner model is %s (idx %d, type %d)\n", + pr_info("second tuner model is %s (idx %d, type %d)\n", t_name2, tuner2, tvee->tuner2_type); if (t_format2) - dev_info(&c->dev, "TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", + pr_info("TV standards%s%s%s%s%s%s%s%s (eeprom 0x%02x)\n", t_fmt_name2[0], t_fmt_name2[1], t_fmt_name2[2], t_fmt_name2[3], t_fmt_name2[4], t_fmt_name2[5], t_fmt_name2[6], t_fmt_name2[7], t_format2); if (audioic < 0) { - dev_info(&c->dev, "audio processor is unknown (no idx)\n"); + pr_info("audio processor is unknown (no idx)\n"); tvee->audio_processor = TVEEPROM_AUDPROC_OTHER; } else { if (audioic < ARRAY_SIZE(audio_ic)) - dev_info(&c->dev, "audio processor is %s (idx %d)\n", + pr_info("audio processor is %s (idx %d)\n", audio_ic[audioic].name, audioic); else - dev_info(&c->dev, "audio processor is unknown (idx %d)\n", + pr_info("audio processor is unknown (idx %d)\n", audioic); } if (tvee->decoder_processor) - dev_info(&c->dev, "decoder processor is %s (idx %d)\n", + pr_info("decoder processor is %s (idx %d)\n", STRM(decoderIC, tvee->decoder_processor), tvee->decoder_processor); if (tvee->has_ir) - dev_info(&c->dev, "has %sradio, has %sIR receiver, has %sIR transmitter\n", + pr_info("has %sradio, has %sIR receiver, has %sIR transmitter\n", tvee->has_radio ? "" : "no ", (tvee->has_ir & 2) ? "" : "no ", (tvee->has_ir & 4) ? "" : "no "); else - dev_info(&c->dev, "has %sradio\n", + pr_info("has %sradio\n", tvee->has_radio ? "" : "no "); } EXPORT_SYMBOL(tveeprom_hauppauge_analog); @@ -753,12 +755,12 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len) buf = 0; err = i2c_master_send(c, &buf, 1); if (err != 1) { - dev_info(&c->dev, "Huh, no eeprom present (err=%d)?\n", err); + pr_info("Huh, no eeprom present (err=%d)?\n", err); return -1; } err = i2c_master_recv(c, eedata, len); if (err != len) { - dev_warn(&c->dev, "i2c eeprom read error (err=%d)\n", err); + pr_warn("i2c eeprom read error (err=%d)\n", err); return -1; } -- cgit v1.2.3 From 0bebaa5f01bc018cd0246997d2b00f1ed44964a8 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 13 Oct 2016 03:35:57 -0300 Subject: [media] RedRat3: Use kcalloc() in two functions * Multiplications for the size determination of memory allocations indicated that array data structures should be processed. Thus use the corresponding function "kcalloc". This issue was detected by using the Coccinelle software. * Replace the specification of data types by pointer dereferences to make the corresponding size determination a bit safer according to the Linux coding style convention. Signed-off-by: Markus Elfring Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 3b0ed1c3f2d8..67f35200b9eb 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -588,7 +588,7 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) int rc = 0; char *buffer; - buffer = kzalloc(sizeof(char) * (RR3_FW_VERSION_LEN + 1), GFP_KERNEL); + buffer = kcalloc(RR3_FW_VERSION_LEN + 1, sizeof(*buffer), GFP_KERNEL); if (!buffer) { dev_err(rr3->dev, "Memory allocation failure\n"); return; @@ -780,7 +780,9 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, /* rr3 will disable rc detector on transmit */ rr3->transmitting = true; - sample_lens = kzalloc(sizeof(int) * RR3_DRIVER_MAXLENS, GFP_KERNEL); + sample_lens = kcalloc(RR3_DRIVER_MAXLENS, + sizeof(*sample_lens), + GFP_KERNEL); if (!sample_lens) { ret = -ENOMEM; goto out; -- cgit v1.2.3 From 559f64d4de35c6ff5a89599bc209452e24b4fba4 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 13 Oct 2016 08:20:19 -0300 Subject: [media] RedRat3: Delete six messages for a failed memory allocation The script "checkpatch.pl" pointed information out like the following. WARNING: Possible unnecessary 'out of memory' message Thus remove such a logging statement in five functions. Signed-off-by: Markus Elfring Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 67f35200b9eb..5e43766757fd 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -480,10 +480,8 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3) len = sizeof(*tmp); tmp = kzalloc(len, GFP_KERNEL); - if (!tmp) { - dev_warn(rr3->dev, "Memory allocation faillure\n"); + if (!tmp) return timeout; - } pipe = usb_rcvctrlpipe(rr3->udev, 0); ret = usb_control_msg(rr3->udev, pipe, RR3_GET_IR_PARAM, @@ -544,10 +542,8 @@ static void redrat3_reset(struct redrat3_dev *rr3) txpipe = usb_sndctrlpipe(udev, 0); val = kmalloc(len, GFP_KERNEL); - if (!val) { - dev_err(dev, "Memory allocation failure\n"); + if (!val) return; - } *val = 0x01; rc = usb_control_msg(udev, rxpipe, RR3_RESET, @@ -589,10 +585,8 @@ static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) char *buffer; buffer = kcalloc(RR3_FW_VERSION_LEN + 1, sizeof(*buffer), GFP_KERNEL); - if (!buffer) { - dev_err(rr3->dev, "Memory allocation failure\n"); + if (!buffer) return; - } rc = usb_control_msg(rr3->udev, usb_rcvctrlpipe(rr3->udev, 0), RR3_FW_VERSION, @@ -909,10 +903,8 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct); rc = rc_allocate_device(); - if (!rc) { - dev_err(dev, "remote input dev allocation failed\n"); + if (!rc) goto out; - } snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s Infrared Remote Transceiver (%04x:%04x)", prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "", @@ -1001,10 +993,8 @@ static int redrat3_dev_probe(struct usb_interface *intf, /* allocate memory for our device state and initialize it */ rr3 = kzalloc(sizeof(*rr3), GFP_KERNEL); - if (rr3 == NULL) { - dev_err(dev, "Memory allocation failure\n"); + if (!rr3) goto no_endpoints; - } rr3->dev = &intf->dev; @@ -1016,10 +1006,8 @@ static int redrat3_dev_probe(struct usb_interface *intf, rr3->ep_in = ep_in; rr3->bulk_in_buf = usb_alloc_coherent(udev, le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in); - if (!rr3->bulk_in_buf) { - dev_err(dev, "Read buffer allocation failure\n"); + if (!rr3->bulk_in_buf) goto error; - } pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf, -- cgit v1.2.3 From 576df632f24f7db40b7266cada96ed1b76f1255d Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 13 Oct 2016 08:23:22 -0300 Subject: [media] RedRat3: Improve another size determination in redrat3_reset() Replace the specification of a data type by a pointer dereference as the parameter for the operator "sizeof" to make the corresponding size determination a bit safer. Signed-off-by: Markus Elfring Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 5e43766757fd..342a85d02887 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -536,7 +536,7 @@ static void redrat3_reset(struct redrat3_dev *rr3) struct device *dev = rr3->dev; int rc, rxpipe, txpipe; u8 *val; - int len = sizeof(u8); + size_t const len = sizeof(*val); rxpipe = usb_rcvctrlpipe(udev, 0); txpipe = usb_sndctrlpipe(udev, 0); -- cgit v1.2.3 From fac59136bc22fd9b3a04ed4f29977da8e045ee6b Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 13 Oct 2016 05:34:29 -0300 Subject: [media] RedRat3: Return directly after a failed kcalloc() in redrat3_transmit_ir() * Return directly after a call of the function "kcalloc" failed at the beginning. * Reorder two calls for the function "kfree" at the end. Signed-off-by: Markus Elfring Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 342a85d02887..966f43a7e2c2 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -777,10 +777,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, sample_lens = kcalloc(RR3_DRIVER_MAXLENS, sizeof(*sample_lens), GFP_KERNEL); - if (!sample_lens) { - ret = -ENOMEM; - goto out; - } + if (!sample_lens) + return -ENOMEM; irdata = kzalloc(sizeof(*irdata), GFP_KERNEL); if (!irdata) { @@ -848,8 +846,8 @@ static int redrat3_transmit_ir(struct rc_dev *rcdev, unsigned *txbuf, ret = count; out: - kfree(sample_lens); kfree(irdata); + kfree(sample_lens); rr3->transmitting = false; /* rr3 re-enables rc detector because it was enabled before */ -- cgit v1.2.3 From 7aa20afea649fa1e3cb81bf40c25ddf53cc1328f Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 13 Oct 2016 08:21:55 -0300 Subject: [media] RedRat3: Delete an unnecessary variable initialisation in redrat3_get_firmware_rev() The local variable "rc" will be set to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 966f43a7e2c2..dc8b88a256f2 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -581,7 +581,7 @@ static void redrat3_reset(struct redrat3_dev *rr3) static void redrat3_get_firmware_rev(struct redrat3_dev *rr3) { - int rc = 0; + int rc; char *buffer; buffer = kcalloc(RR3_FW_VERSION_LEN + 1, sizeof(*buffer), GFP_KERNEL); -- cgit v1.2.3 From 9d45d5fbeb4672648926c8fd2c1f2c08105ee7c3 Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 13 Oct 2016 09:17:43 -0300 Subject: [media] RedRat3: Delete an unnecessary variable initialisation in redrat3_init_rc_dev() The local variable "ret" will be set to an appropriate value a bit later. Thus omit the explicit initialisation at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index dc8b88a256f2..689df034dcfe 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -897,7 +897,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) { struct device *dev = rr3->dev; struct rc_dev *rc; - int ret = -ENODEV; + int ret; u16 prod = le16_to_cpu(rr3->udev->descriptor.idProduct); rc = rc_allocate_device(); -- cgit v1.2.3 From 3f81678d8e4918788b17ab007f41b86aea030bdc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Thu, 13 Oct 2016 09:54:46 -0300 Subject: [media] RedRat3: Return directly after a failed rc_allocate_device() in redrat3_init_rc_dev() Return directly after a call of the function "rc_allocate_device" failed at the beginning. Signed-off-by: Markus Elfring Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 689df034dcfe..d3c81619cd87 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -902,7 +902,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc = rc_allocate_device(); if (!rc) - goto out; + return NULL; snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s Infrared Remote Transceiver (%04x:%04x)", prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "", -- cgit v1.2.3 From ce3aeaf22c9f6d9dbbad00600b26ddd0263f8cbc Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 14 Oct 2016 02:19:00 -0300 Subject: [media] winbond-cir: Use kmalloc_array() in wbcir_tx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A multiplication for the size determination of a memory allocation indicated that an array data structure should be processed. Thus use the corresponding function "kmalloc_array". This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: David Härdeman Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/winbond-cir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index cdcd6e38b295..8c1f9225d358 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -658,7 +658,7 @@ wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count) unsigned i; unsigned long flags; - buf = kmalloc(count * sizeof(*b), GFP_KERNEL); + buf = kmalloc_array(count, sizeof(*b), GFP_KERNEL); if (!buf) return -ENOMEM; -- cgit v1.2.3 From 0fe88461a0ec95a71950b4841f139a62ed63dc81 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 19 Aug 2016 19:19:39 +0200 Subject: mailbox: Add Tegra HSP driver This driver exposes a mailbox interface for interprocessor communication using the Hardware Synchronization Primitives (HSP) module's doorbell mechanism. There are multiple HSP instances and they provide additional features such as shared mailboxes, shared and arbitrated semaphores. A driver for a remote processor can use the mailbox client provided by the HSP driver and build an IPC protocol on top of this synchronization mechanism. Based on work by Joseph Lo . Acked-by: Jassi Brar Signed-off-by: Thierry Reding --- drivers/mailbox/Kconfig | 9 + drivers/mailbox/Makefile | 2 + drivers/mailbox/tegra-hsp.c | 479 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 490 insertions(+) create mode 100644 drivers/mailbox/tegra-hsp.c (limited to 'drivers') diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig index 11eebfe8a4cb..ceff415f201c 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -124,6 +124,15 @@ config MAILBOX_TEST Test client to help with testing new Controller driver implementations. +config TEGRA_HSP_MBOX + bool "Tegra HSP (Hardware Synchronization Primitives) Driver" + depends on ARCH_TEGRA_186_SOC + help + The Tegra HSP driver is used for the interprocessor communication + between different remote processors and host processors on Tegra186 + and later SoCs. Say Y here if you want to have this support. + If unsure say N. + config XGENE_SLIMPRO_MBOX tristate "APM SoC X-Gene SLIMpro Mailbox Controller" depends on ARCH_XGENE diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile index ace6fed8fea9..7dde4f609ae8 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -29,3 +29,5 @@ obj-$(CONFIG_XGENE_SLIMPRO_MBOX) += mailbox-xgene-slimpro.o obj-$(CONFIG_HI6220_MBOX) += hi6220-mailbox.o obj-$(CONFIG_BCM_PDC_MBOX) += bcm-pdc-mailbox.o + +obj-$(CONFIG_TEGRA_HSP_MBOX) += tegra-hsp.o diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c new file mode 100644 index 000000000000..3724f2fcd371 --- /dev/null +++ b/drivers/mailbox/tegra-hsp.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define HSP_INT_DIMENSIONING 0x380 +#define HSP_nSM_SHIFT 0 +#define HSP_nSS_SHIFT 4 +#define HSP_nAS_SHIFT 8 +#define HSP_nDB_SHIFT 12 +#define HSP_nSI_SHIFT 16 +#define HSP_nINT_MASK 0xf + +#define HSP_DB_TRIGGER 0x0 +#define HSP_DB_ENABLE 0x4 +#define HSP_DB_RAW 0x8 +#define HSP_DB_PENDING 0xc + +#define HSP_DB_CCPLEX 1 +#define HSP_DB_BPMP 3 +#define HSP_DB_MAX 7 + +struct tegra_hsp_channel; +struct tegra_hsp; + +struct tegra_hsp_channel { + struct tegra_hsp *hsp; + struct mbox_chan *chan; + void __iomem *regs; +}; + +struct tegra_hsp_doorbell { + struct tegra_hsp_channel channel; + struct list_head list; + const char *name; + unsigned int master; + unsigned int index; +}; + +struct tegra_hsp_db_map { + const char *name; + unsigned int master; + unsigned int index; +}; + +struct tegra_hsp_soc { + const struct tegra_hsp_db_map *map; +}; + +struct tegra_hsp { + const struct tegra_hsp_soc *soc; + struct mbox_controller mbox; + void __iomem *regs; + unsigned int irq; + unsigned int num_sm; + unsigned int num_as; + unsigned int num_ss; + unsigned int num_db; + unsigned int num_si; + spinlock_t lock; + + struct list_head doorbells; +}; + +static inline struct tegra_hsp * +to_tegra_hsp(struct mbox_controller *mbox) +{ + return container_of(mbox, struct tegra_hsp, mbox); +} + +static inline u32 tegra_hsp_readl(struct tegra_hsp *hsp, unsigned int offset) +{ + return readl(hsp->regs + offset); +} + +static inline void tegra_hsp_writel(struct tegra_hsp *hsp, u32 value, + unsigned int offset) +{ + writel(value, hsp->regs + offset); +} + +static inline u32 tegra_hsp_channel_readl(struct tegra_hsp_channel *channel, + unsigned int offset) +{ + return readl(channel->regs + offset); +} + +static inline void tegra_hsp_channel_writel(struct tegra_hsp_channel *channel, + u32 value, unsigned int offset) +{ + writel(value, channel->regs + offset); +} + +static bool tegra_hsp_doorbell_can_ring(struct tegra_hsp_doorbell *db) +{ + u32 value; + + value = tegra_hsp_channel_readl(&db->channel, HSP_DB_ENABLE); + + return (value & BIT(TEGRA_HSP_DB_MASTER_CCPLEX)) != 0; +} + +static struct tegra_hsp_doorbell * +__tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master) +{ + struct tegra_hsp_doorbell *entry; + + list_for_each_entry(entry, &hsp->doorbells, list) + if (entry->master == master) + return entry; + + return NULL; +} + +static struct tegra_hsp_doorbell * +tegra_hsp_doorbell_get(struct tegra_hsp *hsp, unsigned int master) +{ + struct tegra_hsp_doorbell *db; + unsigned long flags; + + spin_lock_irqsave(&hsp->lock, flags); + db = __tegra_hsp_doorbell_get(hsp, master); + spin_unlock_irqrestore(&hsp->lock, flags); + + return db; +} + +static irqreturn_t tegra_hsp_doorbell_irq(int irq, void *data) +{ + struct tegra_hsp *hsp = data; + struct tegra_hsp_doorbell *db; + unsigned long master, value; + + db = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX); + if (!db) + return IRQ_NONE; + + value = tegra_hsp_channel_readl(&db->channel, HSP_DB_PENDING); + tegra_hsp_channel_writel(&db->channel, value, HSP_DB_PENDING); + + spin_lock(&hsp->lock); + + for_each_set_bit(master, &value, hsp->mbox.num_chans) { + struct tegra_hsp_doorbell *db; + + db = __tegra_hsp_doorbell_get(hsp, master); + /* + * Depending on the bootloader chain, the CCPLEX doorbell will + * have some doorbells enabled, which means that requesting an + * interrupt will immediately fire. + * + * In that case, db->channel.chan will still be NULL here and + * cause a crash if not properly guarded. + * + * It remains to be seen if ignoring the doorbell in that case + * is the correct solution. + */ + if (db && db->channel.chan) + mbox_chan_received_data(db->channel.chan, NULL); + } + + spin_unlock(&hsp->lock); + + return IRQ_HANDLED; +} + +static struct tegra_hsp_channel * +tegra_hsp_doorbell_create(struct tegra_hsp *hsp, const char *name, + unsigned int master, unsigned int index) +{ + struct tegra_hsp_doorbell *db; + unsigned int offset; + unsigned long flags; + + db = kzalloc(sizeof(*db), GFP_KERNEL); + if (!db) + return ERR_PTR(-ENOMEM); + + offset = (1 + (hsp->num_sm / 2) + hsp->num_ss + hsp->num_as) << 16; + offset += index * 0x100; + + db->channel.regs = hsp->regs + offset; + db->channel.hsp = hsp; + + db->name = kstrdup_const(name, GFP_KERNEL); + db->master = master; + db->index = index; + + spin_lock_irqsave(&hsp->lock, flags); + list_add_tail(&db->list, &hsp->doorbells); + spin_unlock_irqrestore(&hsp->lock, flags); + + return &db->channel; +} + +static void __tegra_hsp_doorbell_destroy(struct tegra_hsp_doorbell *db) +{ + list_del(&db->list); + kfree_const(db->name); + kfree(db); +} + +static int tegra_hsp_doorbell_send_data(struct mbox_chan *chan, void *data) +{ + struct tegra_hsp_doorbell *db = chan->con_priv; + + tegra_hsp_channel_writel(&db->channel, 1, HSP_DB_TRIGGER); + + return 0; +} + +static int tegra_hsp_doorbell_startup(struct mbox_chan *chan) +{ + struct tegra_hsp_doorbell *db = chan->con_priv; + struct tegra_hsp *hsp = db->channel.hsp; + struct tegra_hsp_doorbell *ccplex; + unsigned long flags; + u32 value; + + if (db->master >= hsp->mbox.num_chans) { + dev_err(hsp->mbox.dev, + "invalid master ID %u for HSP channel\n", + db->master); + return -EINVAL; + } + + ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX); + if (!ccplex) + return -ENODEV; + + if (!tegra_hsp_doorbell_can_ring(db)) + return -ENODEV; + + spin_lock_irqsave(&hsp->lock, flags); + + value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE); + value |= BIT(db->master); + tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE); + + spin_unlock_irqrestore(&hsp->lock, flags); + + return 0; +} + +static void tegra_hsp_doorbell_shutdown(struct mbox_chan *chan) +{ + struct tegra_hsp_doorbell *db = chan->con_priv; + struct tegra_hsp *hsp = db->channel.hsp; + struct tegra_hsp_doorbell *ccplex; + unsigned long flags; + u32 value; + + ccplex = tegra_hsp_doorbell_get(hsp, TEGRA_HSP_DB_MASTER_CCPLEX); + if (!ccplex) + return; + + spin_lock_irqsave(&hsp->lock, flags); + + value = tegra_hsp_channel_readl(&ccplex->channel, HSP_DB_ENABLE); + value &= ~BIT(db->master); + tegra_hsp_channel_writel(&ccplex->channel, value, HSP_DB_ENABLE); + + spin_unlock_irqrestore(&hsp->lock, flags); +} + +static const struct mbox_chan_ops tegra_hsp_doorbell_ops = { + .send_data = tegra_hsp_doorbell_send_data, + .startup = tegra_hsp_doorbell_startup, + .shutdown = tegra_hsp_doorbell_shutdown, +}; + +static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox, + const struct of_phandle_args *args) +{ + struct tegra_hsp_channel *channel = ERR_PTR(-ENODEV); + struct tegra_hsp *hsp = to_tegra_hsp(mbox); + unsigned int type = args->args[0]; + unsigned int master = args->args[1]; + struct tegra_hsp_doorbell *db; + struct mbox_chan *chan; + unsigned long flags; + unsigned int i; + + switch (type) { + case TEGRA_HSP_MBOX_TYPE_DB: + db = tegra_hsp_doorbell_get(hsp, master); + if (db) + channel = &db->channel; + + break; + + default: + break; + } + + if (IS_ERR(channel)) + return ERR_CAST(channel); + + spin_lock_irqsave(&hsp->lock, flags); + + for (i = 0; i < hsp->mbox.num_chans; i++) { + chan = &hsp->mbox.chans[i]; + if (!chan->con_priv) { + chan->con_priv = channel; + channel->chan = chan; + break; + } + + chan = NULL; + } + + spin_unlock_irqrestore(&hsp->lock, flags); + + return chan ?: ERR_PTR(-EBUSY); +} + +static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp) +{ + struct tegra_hsp_doorbell *db; + unsigned long flags; + + spin_lock_irqsave(&hsp->lock, flags); + + list_for_each_entry(db, &hsp->doorbells, list) + __tegra_hsp_doorbell_destroy(db); + + spin_unlock_irqrestore(&hsp->lock, flags); +} + +static int tegra_hsp_add_doorbells(struct tegra_hsp *hsp) +{ + const struct tegra_hsp_db_map *map = hsp->soc->map; + struct tegra_hsp_channel *channel; + + while (map->name) { + channel = tegra_hsp_doorbell_create(hsp, map->name, + map->master, map->index); + if (IS_ERR(channel)) { + tegra_hsp_remove_doorbells(hsp); + return PTR_ERR(channel); + } + + map++; + } + + return 0; +} + +static int tegra_hsp_probe(struct platform_device *pdev) +{ + struct tegra_hsp *hsp; + struct resource *res; + u32 value; + int err; + + hsp = devm_kzalloc(&pdev->dev, sizeof(*hsp), GFP_KERNEL); + if (!hsp) + return -ENOMEM; + + hsp->soc = of_device_get_match_data(&pdev->dev); + INIT_LIST_HEAD(&hsp->doorbells); + spin_lock_init(&hsp->lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hsp->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(hsp->regs)) + return PTR_ERR(hsp->regs); + + value = tegra_hsp_readl(hsp, HSP_INT_DIMENSIONING); + hsp->num_sm = (value >> HSP_nSM_SHIFT) & HSP_nINT_MASK; + hsp->num_ss = (value >> HSP_nSS_SHIFT) & HSP_nINT_MASK; + hsp->num_as = (value >> HSP_nAS_SHIFT) & HSP_nINT_MASK; + hsp->num_db = (value >> HSP_nDB_SHIFT) & HSP_nINT_MASK; + hsp->num_si = (value >> HSP_nSI_SHIFT) & HSP_nINT_MASK; + + err = platform_get_irq_byname(pdev, "doorbell"); + if (err < 0) { + dev_err(&pdev->dev, "failed to get doorbell IRQ: %d\n", err); + return err; + } + + hsp->irq = err; + + hsp->mbox.of_xlate = of_tegra_hsp_xlate; + hsp->mbox.num_chans = 32; + hsp->mbox.dev = &pdev->dev; + hsp->mbox.txdone_irq = false; + hsp->mbox.txdone_poll = false; + hsp->mbox.ops = &tegra_hsp_doorbell_ops; + + hsp->mbox.chans = devm_kcalloc(&pdev->dev, hsp->mbox.num_chans, + sizeof(*hsp->mbox.chans), + GFP_KERNEL); + if (!hsp->mbox.chans) + return -ENOMEM; + + err = tegra_hsp_add_doorbells(hsp); + if (err < 0) { + dev_err(&pdev->dev, "failed to add doorbells: %d\n", err); + return err; + } + + platform_set_drvdata(pdev, hsp); + + err = mbox_controller_register(&hsp->mbox); + if (err) { + dev_err(&pdev->dev, "failed to register mailbox: %d\n", err); + tegra_hsp_remove_doorbells(hsp); + return err; + } + + err = devm_request_irq(&pdev->dev, hsp->irq, tegra_hsp_doorbell_irq, + IRQF_NO_SUSPEND, dev_name(&pdev->dev), hsp); + if (err < 0) { + dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", + hsp->irq, err); + return err; + } + + return 0; +} + +static int tegra_hsp_remove(struct platform_device *pdev) +{ + struct tegra_hsp *hsp = platform_get_drvdata(pdev); + + mbox_controller_unregister(&hsp->mbox); + tegra_hsp_remove_doorbells(hsp); + + return 0; +} + +static const struct tegra_hsp_db_map tegra186_hsp_db_map[] = { + { "ccplex", TEGRA_HSP_DB_MASTER_CCPLEX, HSP_DB_CCPLEX, }, + { "bpmp", TEGRA_HSP_DB_MASTER_BPMP, HSP_DB_BPMP, }, + { /* sentinel */ } +}; + +static const struct tegra_hsp_soc tegra186_hsp_soc = { + .map = tegra186_hsp_db_map, +}; + +static const struct of_device_id tegra_hsp_match[] = { + { .compatible = "nvidia,tegra186-hsp", .data = &tegra186_hsp_soc }, + { } +}; + +static struct platform_driver tegra_hsp_driver = { + .driver = { + .name = "tegra-hsp", + .of_match_table = tegra_hsp_match, + }, + .probe = tegra_hsp_probe, + .remove = tegra_hsp_remove, +}; + +static int __init tegra_hsp_init(void) +{ + return platform_driver_register(&tegra_hsp_driver); +} +core_initcall(tegra_hsp_init); -- cgit v1.2.3 From 68050eb6c611527232fe5574c7306e97e47499ef Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 18 Nov 2016 14:34:10 +0300 Subject: mailbox: tegra-hsp: Use after free in tegra_hsp_remove_doorbells() We have to use the _safe version of list_for_each() because we're freeing the pointer as we go along. (This might not show up testing depending on what config options you have enabled). Fixes: 0fe88461a0ec ("mailbox: Add Tegra HSP driver") Signed-off-by: Dan Carpenter Signed-off-by: Thierry Reding --- drivers/mailbox/tegra-hsp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c index 3724f2fcd371..0cde356c11ab 100644 --- a/drivers/mailbox/tegra-hsp.c +++ b/drivers/mailbox/tegra-hsp.c @@ -334,12 +334,12 @@ static struct mbox_chan *of_tegra_hsp_xlate(struct mbox_controller *mbox, static void tegra_hsp_remove_doorbells(struct tegra_hsp *hsp) { - struct tegra_hsp_doorbell *db; + struct tegra_hsp_doorbell *db, *tmp; unsigned long flags; spin_lock_irqsave(&hsp->lock, flags); - list_for_each_entry(db, &hsp->doorbells, list) + list_for_each_entry_safe(db, tmp, &hsp->doorbells, list) __tegra_hsp_doorbell_destroy(db); spin_unlock_irqrestore(&hsp->lock, flags); -- cgit v1.2.3 From ca791d7f425635b63706e00896a141f85f7de463 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 19 Aug 2016 19:05:04 +0200 Subject: firmware: tegra: Add IVC library The Inter-VM communication (IVC) is a communication protocol which is designed for interprocessor communication (IPC) or the communication between the hypervisor and the virtual machine with a guest OS. Message channels are used to communicate between processors. They are backed by DRAM or SRAM, so care must be taken to maintain coherence of data. The IVC library maintains memory-based descriptors for the transmission and reception channels as well as the data coherence of the counter and payload. Clients, such as the driver for the BPMP firmware, can use the library to exchange messages with remote processors. Based on work by Peter Newman and Joseph Lo . Signed-off-by: Thierry Reding --- drivers/firmware/Kconfig | 1 + drivers/firmware/Makefile | 1 + drivers/firmware/tegra/Kconfig | 13 + drivers/firmware/tegra/Makefile | 1 + drivers/firmware/tegra/ivc.c | 695 ++++++++++++++++++++++++++++++++++++++++ include/soc/tegra/ivc.h | 109 +++++++ 6 files changed, 820 insertions(+) create mode 100644 drivers/firmware/tegra/Kconfig create mode 100644 drivers/firmware/tegra/Makefile create mode 100644 drivers/firmware/tegra/ivc.c create mode 100644 include/soc/tegra/ivc.h (limited to 'drivers') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index bca172d42c74..9968de04d1d5 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -210,5 +210,6 @@ source "drivers/firmware/broadcom/Kconfig" source "drivers/firmware/google/Kconfig" source "drivers/firmware/efi/Kconfig" source "drivers/firmware/meson/Kconfig" +source "drivers/firmware/tegra/Kconfig" endmenu diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 898ac41fa8b3..2afe75c52ac2 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -26,3 +26,4 @@ obj-y += meson/ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ obj-$(CONFIG_EFI) += efi/ obj-$(CONFIG_UEFI_CPER) += efi/ +obj-y += tegra/ diff --git a/drivers/firmware/tegra/Kconfig b/drivers/firmware/tegra/Kconfig new file mode 100644 index 000000000000..1fa3e4e136a5 --- /dev/null +++ b/drivers/firmware/tegra/Kconfig @@ -0,0 +1,13 @@ +menu "Tegra firmware driver" + +config TEGRA_IVC + bool "Tegra IVC protocol" + depends on ARCH_TEGRA + help + IVC (Inter-VM Communication) protocol is part of the IPC + (Inter Processor Communication) framework on Tegra. It maintains the + data and the different commuication channels in SysRAM or RAM and + keeps the content is synchronization between host CPU and remote + processors. + +endmenu diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile new file mode 100644 index 000000000000..92e2153e8173 --- /dev/null +++ b/drivers/firmware/tegra/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_TEGRA_IVC) += ivc.o diff --git a/drivers/firmware/tegra/ivc.c b/drivers/firmware/tegra/ivc.c new file mode 100644 index 000000000000..29ecfd815320 --- /dev/null +++ b/drivers/firmware/tegra/ivc.c @@ -0,0 +1,695 @@ +/* + * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include + +#define TEGRA_IVC_ALIGN 64 + +/* + * IVC channel reset protocol. + * + * Each end uses its tx_channel.state to indicate its synchronization state. + */ +enum tegra_ivc_state { + /* + * This value is zero for backwards compatibility with services that + * assume channels to be initially zeroed. Such channels are in an + * initially valid state, but cannot be asynchronously reset, and must + * maintain a valid state at all times. + * + * The transmitting end can enter the established state from the sync or + * ack state when it observes the receiving endpoint in the ack or + * established state, indicating that has cleared the counters in our + * rx_channel. + */ + TEGRA_IVC_STATE_ESTABLISHED = 0, + + /* + * If an endpoint is observed in the sync state, the remote endpoint is + * allowed to clear the counters it owns asynchronously with respect to + * the current endpoint. Therefore, the current endpoint is no longer + * allowed to communicate. + */ + TEGRA_IVC_STATE_SYNC, + + /* + * When the transmitting end observes the receiving end in the sync + * state, it can clear the w_count and r_count and transition to the ack + * state. If the remote endpoint observes us in the ack state, it can + * return to the established state once it has cleared its counters. + */ + TEGRA_IVC_STATE_ACK +}; + +/* + * This structure is divided into two-cache aligned parts, the first is only + * written through the tx.channel pointer, while the second is only written + * through the rx.channel pointer. This delineates ownership of the cache + * lines, which is critical to performance and necessary in non-cache coherent + * implementations. + */ +struct tegra_ivc_header { + union { + struct { + /* fields owned by the transmitting end */ + u32 count; + u32 state; + }; + + u8 pad[TEGRA_IVC_ALIGN]; + } tx; + + union { + /* fields owned by the receiving end */ + u32 count; + u8 pad[TEGRA_IVC_ALIGN]; + } rx; +}; + +static inline void tegra_ivc_invalidate(struct tegra_ivc *ivc, dma_addr_t phys) +{ + if (!ivc->peer) + return; + + dma_sync_single_for_cpu(ivc->peer, phys, TEGRA_IVC_ALIGN, + DMA_FROM_DEVICE); +} + +static inline void tegra_ivc_flush(struct tegra_ivc *ivc, dma_addr_t phys) +{ + if (!ivc->peer) + return; + + dma_sync_single_for_device(ivc->peer, phys, TEGRA_IVC_ALIGN, + DMA_TO_DEVICE); +} + +static inline bool tegra_ivc_empty(struct tegra_ivc *ivc, + struct tegra_ivc_header *header) +{ + /* + * This function performs multiple checks on the same values with + * security implications, so create snapshots with ACCESS_ONCE() to + * ensure that these checks use the same values. + */ + u32 tx = ACCESS_ONCE(header->tx.count); + u32 rx = ACCESS_ONCE(header->rx.count); + + /* + * Perform an over-full check to prevent denial of service attacks + * where a server could be easily fooled into believing that there's + * an extremely large number of frames ready, since receivers are not + * expected to check for full or over-full conditions. + * + * Although the channel isn't empty, this is an invalid case caused by + * a potentially malicious peer, so returning empty is safer, because + * it gives the impression that the channel has gone silent. + */ + if (tx - rx > ivc->num_frames) + return true; + + return tx == rx; +} + +static inline bool tegra_ivc_full(struct tegra_ivc *ivc, + struct tegra_ivc_header *header) +{ + u32 tx = ACCESS_ONCE(header->tx.count); + u32 rx = ACCESS_ONCE(header->rx.count); + + /* + * Invalid cases where the counters indicate that the queue is over + * capacity also appear full. + */ + return tx - rx >= ivc->num_frames; +} + +static inline u32 tegra_ivc_available(struct tegra_ivc *ivc, + struct tegra_ivc_header *header) +{ + u32 tx = ACCESS_ONCE(header->tx.count); + u32 rx = ACCESS_ONCE(header->rx.count); + + /* + * This function isn't expected to be used in scenarios where an + * over-full situation can lead to denial of service attacks. See the + * comment in tegra_ivc_empty() for an explanation about special + * over-full considerations. + */ + return tx - rx; +} + +static inline void tegra_ivc_advance_tx(struct tegra_ivc *ivc) +{ + ACCESS_ONCE(ivc->tx.channel->tx.count) = + ACCESS_ONCE(ivc->tx.channel->tx.count) + 1; + + if (ivc->tx.position == ivc->num_frames - 1) + ivc->tx.position = 0; + else + ivc->tx.position++; +} + +static inline void tegra_ivc_advance_rx(struct tegra_ivc *ivc) +{ + ACCESS_ONCE(ivc->rx.channel->rx.count) = + ACCESS_ONCE(ivc->rx.channel->rx.count) + 1; + + if (ivc->rx.position == ivc->num_frames - 1) + ivc->rx.position = 0; + else + ivc->rx.position++; +} + +static inline int tegra_ivc_check_read(struct tegra_ivc *ivc) +{ + unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); + + /* + * tx.channel->state is set locally, so it is not synchronized with + * state from the remote peer. The remote peer cannot reset its + * transmit counters until we've acknowledged its synchronization + * request, so no additional synchronization is required because an + * asynchronous transition of rx.channel->state to + * TEGRA_IVC_STATE_ACK is not allowed. + */ + if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) + return -ECONNRESET; + + /* + * Avoid unnecessary invalidations when performing repeated accesses + * to an IVC channel by checking the old queue pointers first. + * + * Synchronization is only necessary when these pointers indicate + * empty or full. + */ + if (!tegra_ivc_empty(ivc, ivc->rx.channel)) + return 0; + + tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); + + if (tegra_ivc_empty(ivc, ivc->rx.channel)) + return -ENOSPC; + + return 0; +} + +static inline int tegra_ivc_check_write(struct tegra_ivc *ivc) +{ + unsigned int offset = offsetof(struct tegra_ivc_header, rx.count); + + if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) + return -ECONNRESET; + + if (!tegra_ivc_full(ivc, ivc->tx.channel)) + return 0; + + tegra_ivc_invalidate(ivc, ivc->tx.phys + offset); + + if (tegra_ivc_full(ivc, ivc->tx.channel)) + return -ENOSPC; + + return 0; +} + +static void *tegra_ivc_frame_virt(struct tegra_ivc *ivc, + struct tegra_ivc_header *header, + unsigned int frame) +{ + if (WARN_ON(frame >= ivc->num_frames)) + return ERR_PTR(-EINVAL); + + return (void *)(header + 1) + ivc->frame_size * frame; +} + +static inline dma_addr_t tegra_ivc_frame_phys(struct tegra_ivc *ivc, + dma_addr_t phys, + unsigned int frame) +{ + unsigned long offset; + + offset = sizeof(struct tegra_ivc_header) + ivc->frame_size * frame; + + return phys + offset; +} + +static inline void tegra_ivc_invalidate_frame(struct tegra_ivc *ivc, + dma_addr_t phys, + unsigned int frame, + unsigned int offset, + size_t size) +{ + if (!ivc->peer || WARN_ON(frame >= ivc->num_frames)) + return; + + phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset; + + dma_sync_single_for_cpu(ivc->peer, phys, size, DMA_FROM_DEVICE); +} + +static inline void tegra_ivc_flush_frame(struct tegra_ivc *ivc, + dma_addr_t phys, + unsigned int frame, + unsigned int offset, + size_t size) +{ + if (!ivc->peer || WARN_ON(frame >= ivc->num_frames)) + return; + + phys = tegra_ivc_frame_phys(ivc, phys, frame) + offset; + + dma_sync_single_for_device(ivc->peer, phys, size, DMA_TO_DEVICE); +} + +/* directly peek at the next frame rx'ed */ +void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc) +{ + int err; + + if (WARN_ON(ivc == NULL)) + return ERR_PTR(-EINVAL); + + err = tegra_ivc_check_read(ivc); + if (err < 0) + return ERR_PTR(err); + + /* + * Order observation of ivc->rx.position potentially indicating new + * data before data read. + */ + smp_rmb(); + + tegra_ivc_invalidate_frame(ivc, ivc->rx.phys, ivc->rx.position, 0, + ivc->frame_size); + + return tegra_ivc_frame_virt(ivc, ivc->rx.channel, ivc->rx.position); +} +EXPORT_SYMBOL(tegra_ivc_read_get_next_frame); + +int tegra_ivc_read_advance(struct tegra_ivc *ivc) +{ + unsigned int rx = offsetof(struct tegra_ivc_header, rx.count); + unsigned int tx = offsetof(struct tegra_ivc_header, tx.count); + int err; + + /* + * No read barriers or synchronization here: the caller is expected to + * have already observed the channel non-empty. This check is just to + * catch programming errors. + */ + err = tegra_ivc_check_read(ivc); + if (err < 0) + return err; + + tegra_ivc_advance_rx(ivc); + + tegra_ivc_flush(ivc, ivc->rx.phys + rx); + + /* + * Ensure our write to ivc->rx.position occurs before our read from + * ivc->tx.position. + */ + smp_mb(); + + /* + * Notify only upon transition from full to non-full. The available + * count can only asynchronously increase, so the worst possible + * side-effect will be a spurious notification. + */ + tegra_ivc_invalidate(ivc, ivc->rx.phys + tx); + + if (tegra_ivc_available(ivc, ivc->rx.channel) == ivc->num_frames - 1) + ivc->notify(ivc, ivc->notify_data); + + return 0; +} +EXPORT_SYMBOL(tegra_ivc_read_advance); + +/* directly poke at the next frame to be tx'ed */ +void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc) +{ + int err; + + err = tegra_ivc_check_write(ivc); + if (err < 0) + return ERR_PTR(err); + + return tegra_ivc_frame_virt(ivc, ivc->tx.channel, ivc->tx.position); +} +EXPORT_SYMBOL(tegra_ivc_write_get_next_frame); + +/* advance the tx buffer */ +int tegra_ivc_write_advance(struct tegra_ivc *ivc) +{ + unsigned int tx = offsetof(struct tegra_ivc_header, tx.count); + unsigned int rx = offsetof(struct tegra_ivc_header, rx.count); + int err; + + err = tegra_ivc_check_write(ivc); + if (err < 0) + return err; + + tegra_ivc_flush_frame(ivc, ivc->tx.phys, ivc->tx.position, 0, + ivc->frame_size); + + /* + * Order any possible stores to the frame before update of + * ivc->tx.position. + */ + smp_wmb(); + + tegra_ivc_advance_tx(ivc); + tegra_ivc_flush(ivc, ivc->tx.phys + tx); + + /* + * Ensure our write to ivc->tx.position occurs before our read from + * ivc->rx.position. + */ + smp_mb(); + + /* + * Notify only upon transition from empty to non-empty. The available + * count can only asynchronously decrease, so the worst possible + * side-effect will be a spurious notification. + */ + tegra_ivc_invalidate(ivc, ivc->tx.phys + rx); + + if (tegra_ivc_available(ivc, ivc->tx.channel) == 1) + ivc->notify(ivc, ivc->notify_data); + + return 0; +} +EXPORT_SYMBOL(tegra_ivc_write_advance); + +void tegra_ivc_reset(struct tegra_ivc *ivc) +{ + unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); + + ivc->tx.channel->tx.state = TEGRA_IVC_STATE_SYNC; + tegra_ivc_flush(ivc, ivc->tx.phys + offset); + ivc->notify(ivc, ivc->notify_data); +} +EXPORT_SYMBOL(tegra_ivc_reset); + +/* + * ======================================================= + * IVC State Transition Table - see tegra_ivc_notified() + * ======================================================= + * + * local remote action + * ----- ------ ----------------------------------- + * SYNC EST + * SYNC ACK reset counters; move to EST; notify + * SYNC SYNC reset counters; move to ACK; notify + * ACK EST move to EST; notify + * ACK ACK move to EST; notify + * ACK SYNC reset counters; move to ACK; notify + * EST EST + * EST ACK + * EST SYNC reset counters; move to ACK; notify + * + * =============================================================== + */ + +int tegra_ivc_notified(struct tegra_ivc *ivc) +{ + unsigned int offset = offsetof(struct tegra_ivc_header, tx.count); + enum tegra_ivc_state state; + + /* Copy the receiver's state out of shared memory. */ + tegra_ivc_invalidate(ivc, ivc->rx.phys + offset); + state = ACCESS_ONCE(ivc->rx.channel->tx.state); + + if (state == TEGRA_IVC_STATE_SYNC) { + offset = offsetof(struct tegra_ivc_header, tx.count); + + /* + * Order observation of TEGRA_IVC_STATE_SYNC before stores + * clearing tx.channel. + */ + smp_rmb(); + + /* + * Reset tx.channel counters. The remote end is in the SYNC + * state and won't make progress until we change our state, + * so the counters are not in use at this time. + */ + ivc->tx.channel->tx.count = 0; + ivc->rx.channel->rx.count = 0; + + ivc->tx.position = 0; + ivc->rx.position = 0; + + /* + * Ensure that counters appear cleared before new state can be + * observed. + */ + smp_wmb(); + + /* + * Move to ACK state. We have just cleared our counters, so it + * is now safe for the remote end to start using these values. + */ + ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ACK; + tegra_ivc_flush(ivc, ivc->tx.phys + offset); + + /* + * Notify remote end to observe state transition. + */ + ivc->notify(ivc, ivc->notify_data); + + } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_SYNC && + state == TEGRA_IVC_STATE_ACK) { + offset = offsetof(struct tegra_ivc_header, tx.count); + + /* + * Order observation of ivc_state_sync before stores clearing + * tx_channel. + */ + smp_rmb(); + + /* + * Reset tx.channel counters. The remote end is in the ACK + * state and won't make progress until we change our state, + * so the counters are not in use at this time. + */ + ivc->tx.channel->tx.count = 0; + ivc->rx.channel->rx.count = 0; + + ivc->tx.position = 0; + ivc->rx.position = 0; + + /* + * Ensure that counters appear cleared before new state can be + * observed. + */ + smp_wmb(); + + /* + * Move to ESTABLISHED state. We know that the remote end has + * already cleared its counters, so it is safe to start + * writing/reading on this channel. + */ + ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; + tegra_ivc_flush(ivc, ivc->tx.phys + offset); + + /* + * Notify remote end to observe state transition. + */ + ivc->notify(ivc, ivc->notify_data); + + } else if (ivc->tx.channel->tx.state == TEGRA_IVC_STATE_ACK) { + offset = offsetof(struct tegra_ivc_header, tx.count); + + /* + * At this point, we have observed the peer to be in either + * the ACK or ESTABLISHED state. Next, order observation of + * peer state before storing to tx.channel. + */ + smp_rmb(); + + /* + * Move to ESTABLISHED state. We know that we have previously + * cleared our counters, and we know that the remote end has + * cleared its counters, so it is safe to start writing/reading + * on this channel. + */ + ivc->tx.channel->tx.state = TEGRA_IVC_STATE_ESTABLISHED; + tegra_ivc_flush(ivc, ivc->tx.phys + offset); + + /* + * Notify remote end to observe state transition. + */ + ivc->notify(ivc, ivc->notify_data); + + } else { + /* + * There is no need to handle any further action. Either the + * channel is already fully established, or we are waiting for + * the remote end to catch up with our current state. Refer + * to the diagram in "IVC State Transition Table" above. + */ + } + + if (ivc->tx.channel->tx.state != TEGRA_IVC_STATE_ESTABLISHED) + return -EAGAIN; + + return 0; +} +EXPORT_SYMBOL(tegra_ivc_notified); + +size_t tegra_ivc_align(size_t size) +{ + return ALIGN(size, TEGRA_IVC_ALIGN); +} +EXPORT_SYMBOL(tegra_ivc_align); + +unsigned tegra_ivc_total_queue_size(unsigned queue_size) +{ + if (!IS_ALIGNED(queue_size, TEGRA_IVC_ALIGN)) { + pr_err("%s: queue_size (%u) must be %u-byte aligned\n", + __func__, queue_size, TEGRA_IVC_ALIGN); + return 0; + } + + return queue_size + sizeof(struct tegra_ivc_header); +} +EXPORT_SYMBOL(tegra_ivc_total_queue_size); + +static int tegra_ivc_check_params(unsigned long rx, unsigned long tx, + unsigned int num_frames, size_t frame_size) +{ + BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, tx.count), + TEGRA_IVC_ALIGN)); + BUILD_BUG_ON(!IS_ALIGNED(offsetof(struct tegra_ivc_header, rx.count), + TEGRA_IVC_ALIGN)); + BUILD_BUG_ON(!IS_ALIGNED(sizeof(struct tegra_ivc_header), + TEGRA_IVC_ALIGN)); + + if ((uint64_t)num_frames * (uint64_t)frame_size >= 0x100000000UL) { + pr_err("num_frames * frame_size overflows\n"); + return -EINVAL; + } + + if (!IS_ALIGNED(frame_size, TEGRA_IVC_ALIGN)) { + pr_err("frame size not adequately aligned: %zu\n", frame_size); + return -EINVAL; + } + + /* + * The headers must at least be aligned enough for counters + * to be accessed atomically. + */ + if (!IS_ALIGNED(rx, TEGRA_IVC_ALIGN)) { + pr_err("IVC channel start not aligned: %#lx\n", rx); + return -EINVAL; + } + + if (!IS_ALIGNED(tx, TEGRA_IVC_ALIGN)) { + pr_err("IVC channel start not aligned: %#lx\n", tx); + return -EINVAL; + } + + if (rx < tx) { + if (rx + frame_size * num_frames > tx) { + pr_err("queue regions overlap: %#lx + %zx > %#lx\n", + rx, frame_size * num_frames, tx); + return -EINVAL; + } + } else { + if (tx + frame_size * num_frames > rx) { + pr_err("queue regions overlap: %#lx + %zx > %#lx\n", + tx, frame_size * num_frames, rx); + return -EINVAL; + } + } + + return 0; +} + +int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, + dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys, + unsigned int num_frames, size_t frame_size, + void (*notify)(struct tegra_ivc *ivc, void *data), + void *data) +{ + size_t queue_size; + int err; + + if (WARN_ON(!ivc || !notify)) + return -EINVAL; + + /* + * All sizes that can be returned by communication functions should + * fit in an int. + */ + if (frame_size > INT_MAX) + return -E2BIG; + + err = tegra_ivc_check_params((unsigned long)rx, (unsigned long)tx, + num_frames, frame_size); + if (err < 0) + return err; + + queue_size = tegra_ivc_total_queue_size(num_frames * frame_size); + + if (peer) { + ivc->rx.phys = dma_map_single(peer, rx, queue_size, + DMA_BIDIRECTIONAL); + if (ivc->rx.phys == DMA_ERROR_CODE) + return -ENOMEM; + + ivc->tx.phys = dma_map_single(peer, tx, queue_size, + DMA_BIDIRECTIONAL); + if (ivc->tx.phys == DMA_ERROR_CODE) { + dma_unmap_single(peer, ivc->rx.phys, queue_size, + DMA_BIDIRECTIONAL); + return -ENOMEM; + } + } else { + ivc->rx.phys = rx_phys; + ivc->tx.phys = tx_phys; + } + + ivc->rx.channel = rx; + ivc->tx.channel = tx; + ivc->peer = peer; + ivc->notify = notify; + ivc->notify_data = data; + ivc->frame_size = frame_size; + ivc->num_frames = num_frames; + + /* + * These values aren't necessarily correct until the channel has been + * reset. + */ + ivc->tx.position = 0; + ivc->rx.position = 0; + + return 0; +} +EXPORT_SYMBOL(tegra_ivc_init); + +void tegra_ivc_cleanup(struct tegra_ivc *ivc) +{ + if (ivc->peer) { + size_t size = tegra_ivc_total_queue_size(ivc->num_frames * + ivc->frame_size); + + dma_unmap_single(ivc->peer, ivc->rx.phys, size, + DMA_BIDIRECTIONAL); + dma_unmap_single(ivc->peer, ivc->tx.phys, size, + DMA_BIDIRECTIONAL); + } +} +EXPORT_SYMBOL(tegra_ivc_cleanup); diff --git a/include/soc/tegra/ivc.h b/include/soc/tegra/ivc.h new file mode 100644 index 000000000000..b13cc43ad9d8 --- /dev/null +++ b/include/soc/tegra/ivc.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __TEGRA_IVC_H + +#include +#include +#include + +struct tegra_ivc_header; + +struct tegra_ivc { + struct device *peer; + + struct { + struct tegra_ivc_header *channel; + unsigned int position; + dma_addr_t phys; + } rx, tx; + + void (*notify)(struct tegra_ivc *ivc, void *data); + void *notify_data; + + unsigned int num_frames; + size_t frame_size; +}; + +/** + * tegra_ivc_read_get_next_frame - Peek at the next frame to receive + * @ivc pointer of the IVC channel + * + * Peek at the next frame to be received, without removing it from + * the queue. + * + * Returns a pointer to the frame, or an error encoded pointer. + */ +void *tegra_ivc_read_get_next_frame(struct tegra_ivc *ivc); + +/** + * tegra_ivc_read_advance - Advance the read queue + * @ivc pointer of the IVC channel + * + * Advance the read queue + * + * Returns 0, or a negative error value if failed. + */ +int tegra_ivc_read_advance(struct tegra_ivc *ivc); + +/** + * tegra_ivc_write_get_next_frame - Poke at the next frame to transmit + * @ivc pointer of the IVC channel + * + * Get access to the next frame. + * + * Returns a pointer to the frame, or an error encoded pointer. + */ +void *tegra_ivc_write_get_next_frame(struct tegra_ivc *ivc); + +/** + * tegra_ivc_write_advance - Advance the write queue + * @ivc pointer of the IVC channel + * + * Advance the write queue + * + * Returns 0, or a negative error value if failed. + */ +int tegra_ivc_write_advance(struct tegra_ivc *ivc); + +/** + * tegra_ivc_notified - handle internal messages + * @ivc pointer of the IVC channel + * + * This function must be called following every notification. + * + * Returns 0 if the channel is ready for communication, or -EAGAIN if a channel + * reset is in progress. + */ +int tegra_ivc_notified(struct tegra_ivc *ivc); + +/** + * tegra_ivc_reset - initiates a reset of the shared memory state + * @ivc pointer of the IVC channel + * + * This function must be called after a channel is reserved before it is used + * for communication. The channel will be ready for use when a subsequent call + * to notify the remote of the channel reset. + */ +void tegra_ivc_reset(struct tegra_ivc *ivc); + +size_t tegra_ivc_align(size_t size); +unsigned tegra_ivc_total_queue_size(unsigned queue_size); +int tegra_ivc_init(struct tegra_ivc *ivc, struct device *peer, void *rx, + dma_addr_t rx_phys, void *tx, dma_addr_t tx_phys, + unsigned int num_frames, size_t frame_size, + void (*notify)(struct tegra_ivc *ivc, void *data), + void *data); +void tegra_ivc_cleanup(struct tegra_ivc *ivc); + +#endif /* __TEGRA_IVC_H */ -- cgit v1.2.3 From 983de5f97169ab59d4cb0f60d9d9157778ce4a5e Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 19 Aug 2016 19:05:35 +0200 Subject: firmware: tegra: Add BPMP support The Boot and Power Management Processor (BPMP) is a co-processor found on Tegra SoCs. It is designed to handle the early stages of the boot process and offload power management tasks (such as clocks, resets, powergates, ...) as well as system control services. Compared to the ARM SCPI, the services provided by BPMP are message- based rather than method-based. The BPMP firmware driver provides the services to transmit data to and receive data from the BPMP. Users can also register a Message ReQuest (MRQ), for which a service routine will be run when a corresponding event is received from the firmware. A set of messages, called the BPMP ABI, are specified for a number of different services provided by the BPMP (such as clocks or resets). Based on work by Sivaram Nair and Joseph Lo . Signed-off-by: Thierry Reding --- drivers/firmware/tegra/Kconfig | 12 + drivers/firmware/tegra/Makefile | 1 + drivers/firmware/tegra/bpmp.c | 868 +++++++++++++++++++++ include/soc/tegra/bpmp-abi.h | 1601 +++++++++++++++++++++++++++++++++++++++ include/soc/tegra/bpmp.h | 141 ++++ 5 files changed, 2623 insertions(+) create mode 100644 drivers/firmware/tegra/bpmp.c create mode 100644 include/soc/tegra/bpmp-abi.h create mode 100644 include/soc/tegra/bpmp.h (limited to 'drivers') diff --git a/drivers/firmware/tegra/Kconfig b/drivers/firmware/tegra/Kconfig index 1fa3e4e136a5..ff2730d5c468 100644 --- a/drivers/firmware/tegra/Kconfig +++ b/drivers/firmware/tegra/Kconfig @@ -10,4 +10,16 @@ config TEGRA_IVC keeps the content is synchronization between host CPU and remote processors. +config TEGRA_BPMP + bool "Tegra BPMP driver" + depends on ARCH_TEGRA && TEGRA_HSP_MBOX && TEGRA_IVC + help + BPMP (Boot and Power Management Processor) is designed to off-loading + the PM functions which include clock/DVFS/thermal/power from the CPU. + It needs HSP as the HW synchronization and notification module and + IVC module as the message communication protocol. + + This driver manages the IPC interface between host CPU and the + firmware running on BPMP. + endmenu diff --git a/drivers/firmware/tegra/Makefile b/drivers/firmware/tegra/Makefile index 92e2153e8173..e34a2f79e1ad 100644 --- a/drivers/firmware/tegra/Makefile +++ b/drivers/firmware/tegra/Makefile @@ -1 +1,2 @@ +obj-$(CONFIG_TEGRA_BPMP) += bpmp.o obj-$(CONFIG_TEGRA_IVC) += ivc.o diff --git a/drivers/firmware/tegra/bpmp.c b/drivers/firmware/tegra/bpmp.c new file mode 100644 index 000000000000..4ff02d310868 --- /dev/null +++ b/drivers/firmware/tegra/bpmp.c @@ -0,0 +1,868 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define MSG_ACK BIT(0) +#define MSG_RING BIT(1) + +static inline struct tegra_bpmp * +mbox_client_to_bpmp(struct mbox_client *client) +{ + return container_of(client, struct tegra_bpmp, mbox.client); +} + +struct tegra_bpmp *tegra_bpmp_get(struct device *dev) +{ + struct platform_device *pdev; + struct tegra_bpmp *bpmp; + struct device_node *np; + + np = of_parse_phandle(dev->of_node, "nvidia,bpmp", 0); + if (!np) + return ERR_PTR(-ENOENT); + + pdev = of_find_device_by_node(np); + if (!pdev) { + bpmp = ERR_PTR(-ENODEV); + goto put; + } + + bpmp = platform_get_drvdata(pdev); + if (!bpmp) { + bpmp = ERR_PTR(-EPROBE_DEFER); + put_device(&pdev->dev); + goto put; + } + +put: + of_node_put(np); + return bpmp; +} +EXPORT_SYMBOL_GPL(tegra_bpmp_get); + +void tegra_bpmp_put(struct tegra_bpmp *bpmp) +{ + if (bpmp) + put_device(bpmp->dev); +} +EXPORT_SYMBOL_GPL(tegra_bpmp_put); + +static int tegra_bpmp_channel_get_index(struct tegra_bpmp_channel *channel) +{ + return channel - channel->bpmp->channels; +} + +static int +tegra_bpmp_channel_get_thread_index(struct tegra_bpmp_channel *channel) +{ + struct tegra_bpmp *bpmp = channel->bpmp; + unsigned int offset, count; + int index; + + offset = bpmp->soc->channels.thread.offset; + count = bpmp->soc->channels.thread.count; + + index = tegra_bpmp_channel_get_index(channel); + if (index < 0) + return index; + + if (index < offset || index >= offset + count) + return -EINVAL; + + return index - offset; +} + +static struct tegra_bpmp_channel * +tegra_bpmp_channel_get_thread(struct tegra_bpmp *bpmp, unsigned int index) +{ + unsigned int offset = bpmp->soc->channels.thread.offset; + unsigned int count = bpmp->soc->channels.thread.count; + + if (index >= count) + return NULL; + + return &bpmp->channels[offset + index]; +} + +static struct tegra_bpmp_channel * +tegra_bpmp_channel_get_tx(struct tegra_bpmp *bpmp) +{ + unsigned int offset = bpmp->soc->channels.cpu_tx.offset; + + return &bpmp->channels[offset + smp_processor_id()]; +} + +static struct tegra_bpmp_channel * +tegra_bpmp_channel_get_rx(struct tegra_bpmp *bpmp) +{ + unsigned int offset = bpmp->soc->channels.cpu_rx.offset; + + return &bpmp->channels[offset]; +} + +static bool tegra_bpmp_message_valid(const struct tegra_bpmp_message *msg) +{ + return (msg->tx.size <= MSG_DATA_MIN_SZ) && + (msg->rx.size <= MSG_DATA_MIN_SZ) && + (msg->tx.size == 0 || msg->tx.data) && + (msg->rx.size == 0 || msg->rx.data); +} + +static bool tegra_bpmp_master_acked(struct tegra_bpmp_channel *channel) +{ + void *frame; + + frame = tegra_ivc_read_get_next_frame(channel->ivc); + if (IS_ERR(frame)) { + channel->ib = NULL; + return false; + } + + channel->ib = frame; + + return true; +} + +static int tegra_bpmp_wait_ack(struct tegra_bpmp_channel *channel) +{ + unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout; + ktime_t end; + + end = ktime_add_us(ktime_get(), timeout); + + do { + if (tegra_bpmp_master_acked(channel)) + return 0; + } while (ktime_before(ktime_get(), end)); + + return -ETIMEDOUT; +} + +static bool tegra_bpmp_master_free(struct tegra_bpmp_channel *channel) +{ + void *frame; + + frame = tegra_ivc_write_get_next_frame(channel->ivc); + if (IS_ERR(frame)) { + channel->ob = NULL; + return false; + } + + channel->ob = frame; + + return true; +} + +static int tegra_bpmp_wait_master_free(struct tegra_bpmp_channel *channel) +{ + unsigned long timeout = channel->bpmp->soc->channels.cpu_tx.timeout; + ktime_t start, now; + + start = ns_to_ktime(local_clock()); + + do { + if (tegra_bpmp_master_free(channel)) + return 0; + + now = ns_to_ktime(local_clock()); + } while (ktime_us_delta(now, start) < timeout); + + return -ETIMEDOUT; +} + +static ssize_t __tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, + void *data, size_t size) +{ + if (data && size > 0) + memcpy(data, channel->ib->data, size); + + return tegra_ivc_read_advance(channel->ivc); +} + +static ssize_t tegra_bpmp_channel_read(struct tegra_bpmp_channel *channel, + void *data, size_t size) +{ + struct tegra_bpmp *bpmp = channel->bpmp; + unsigned long flags; + ssize_t err; + int index; + + index = tegra_bpmp_channel_get_thread_index(channel); + if (index < 0) + return index; + + spin_lock_irqsave(&bpmp->lock, flags); + err = __tegra_bpmp_channel_read(channel, data, size); + clear_bit(index, bpmp->threaded.allocated); + spin_unlock_irqrestore(&bpmp->lock, flags); + + up(&bpmp->threaded.lock); + + return err; +} + +static ssize_t __tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, + unsigned int mrq, unsigned long flags, + const void *data, size_t size) +{ + channel->ob->code = mrq; + channel->ob->flags = flags; + + if (data && size > 0) + memcpy(channel->ob->data, data, size); + + return tegra_ivc_write_advance(channel->ivc); +} + +static struct tegra_bpmp_channel * +tegra_bpmp_write_threaded(struct tegra_bpmp *bpmp, unsigned int mrq, + const void *data, size_t size) +{ + unsigned long timeout = bpmp->soc->channels.thread.timeout; + unsigned int count = bpmp->soc->channels.thread.count; + struct tegra_bpmp_channel *channel; + unsigned long flags; + unsigned int index; + int err; + + err = down_timeout(&bpmp->threaded.lock, usecs_to_jiffies(timeout)); + if (err < 0) + return ERR_PTR(err); + + spin_lock_irqsave(&bpmp->lock, flags); + + index = find_first_zero_bit(bpmp->threaded.allocated, count); + if (index == count) { + channel = ERR_PTR(-EBUSY); + goto unlock; + } + + channel = tegra_bpmp_channel_get_thread(bpmp, index); + if (!channel) { + channel = ERR_PTR(-EINVAL); + goto unlock; + } + + if (!tegra_bpmp_master_free(channel)) { + channel = ERR_PTR(-EBUSY); + goto unlock; + } + + set_bit(index, bpmp->threaded.allocated); + + err = __tegra_bpmp_channel_write(channel, mrq, MSG_ACK | MSG_RING, + data, size); + if (err < 0) { + clear_bit(index, bpmp->threaded.allocated); + goto unlock; + } + + set_bit(index, bpmp->threaded.busy); + +unlock: + spin_unlock_irqrestore(&bpmp->lock, flags); + return channel; +} + +static ssize_t tegra_bpmp_channel_write(struct tegra_bpmp_channel *channel, + unsigned int mrq, unsigned long flags, + const void *data, size_t size) +{ + int err; + + err = tegra_bpmp_wait_master_free(channel); + if (err < 0) + return err; + + return __tegra_bpmp_channel_write(channel, mrq, flags, data, size); +} + +int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, + struct tegra_bpmp_message *msg) +{ + struct tegra_bpmp_channel *channel; + int err; + + if (WARN_ON(!irqs_disabled())) + return -EPERM; + + if (!tegra_bpmp_message_valid(msg)) + return -EINVAL; + + channel = tegra_bpmp_channel_get_tx(bpmp); + + err = tegra_bpmp_channel_write(channel, msg->mrq, MSG_ACK, + msg->tx.data, msg->tx.size); + if (err < 0) + return err; + + err = mbox_send_message(bpmp->mbox.channel, NULL); + if (err < 0) + return err; + + mbox_client_txdone(bpmp->mbox.channel, 0); + + err = tegra_bpmp_wait_ack(channel); + if (err < 0) + return err; + + return __tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size); +} +EXPORT_SYMBOL_GPL(tegra_bpmp_transfer_atomic); + +int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, + struct tegra_bpmp_message *msg) +{ + struct tegra_bpmp_channel *channel; + unsigned long timeout; + int err; + + if (WARN_ON(irqs_disabled())) + return -EPERM; + + if (!tegra_bpmp_message_valid(msg)) + return -EINVAL; + + channel = tegra_bpmp_write_threaded(bpmp, msg->mrq, msg->tx.data, + msg->tx.size); + if (IS_ERR(channel)) + return PTR_ERR(channel); + + err = mbox_send_message(bpmp->mbox.channel, NULL); + if (err < 0) + return err; + + mbox_client_txdone(bpmp->mbox.channel, 0); + + timeout = usecs_to_jiffies(bpmp->soc->channels.thread.timeout); + + err = wait_for_completion_timeout(&channel->completion, timeout); + if (err == 0) + return -ETIMEDOUT; + + return tegra_bpmp_channel_read(channel, msg->rx.data, msg->rx.size); +} +EXPORT_SYMBOL_GPL(tegra_bpmp_transfer); + +static struct tegra_bpmp_mrq *tegra_bpmp_find_mrq(struct tegra_bpmp *bpmp, + unsigned int mrq) +{ + struct tegra_bpmp_mrq *entry; + + list_for_each_entry(entry, &bpmp->mrqs, list) + if (entry->mrq == mrq) + return entry; + + return NULL; +} + +static void tegra_bpmp_mrq_return(struct tegra_bpmp_channel *channel, + int code, const void *data, size_t size) +{ + unsigned long flags = channel->ib->flags; + struct tegra_bpmp *bpmp = channel->bpmp; + struct tegra_bpmp_mb_data *frame; + int err; + + if (WARN_ON(size > MSG_DATA_MIN_SZ)) + return; + + err = tegra_ivc_read_advance(channel->ivc); + if (WARN_ON(err < 0)) + return; + + if ((flags & MSG_ACK) == 0) + return; + + frame = tegra_ivc_write_get_next_frame(channel->ivc); + if (WARN_ON(IS_ERR(frame))) + return; + + frame->code = code; + + if (data && size > 0) + memcpy(frame->data, data, size); + + err = tegra_ivc_write_advance(channel->ivc); + if (WARN_ON(err < 0)) + return; + + if (flags & MSG_RING) { + err = mbox_send_message(bpmp->mbox.channel, NULL); + if (WARN_ON(err < 0)) + return; + + mbox_client_txdone(bpmp->mbox.channel, 0); + } +} + +static void tegra_bpmp_handle_mrq(struct tegra_bpmp *bpmp, + unsigned int mrq, + struct tegra_bpmp_channel *channel) +{ + struct tegra_bpmp_mrq *entry; + u32 zero = 0; + + spin_lock(&bpmp->lock); + + entry = tegra_bpmp_find_mrq(bpmp, mrq); + if (!entry) { + spin_unlock(&bpmp->lock); + tegra_bpmp_mrq_return(channel, -EINVAL, &zero, sizeof(zero)); + return; + } + + entry->handler(mrq, channel, entry->data); + + spin_unlock(&bpmp->lock); +} + +int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, + tegra_bpmp_mrq_handler_t handler, void *data) +{ + struct tegra_bpmp_mrq *entry; + unsigned long flags; + + if (!handler) + return -EINVAL; + + entry = devm_kzalloc(bpmp->dev, sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + + spin_lock_irqsave(&bpmp->lock, flags); + + entry->mrq = mrq; + entry->handler = handler; + entry->data = data; + list_add(&entry->list, &bpmp->mrqs); + + spin_unlock_irqrestore(&bpmp->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(tegra_bpmp_request_mrq); + +void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, void *data) +{ + struct tegra_bpmp_mrq *entry; + unsigned long flags; + + spin_lock_irqsave(&bpmp->lock, flags); + + entry = tegra_bpmp_find_mrq(bpmp, mrq); + if (!entry) + goto unlock; + + list_del(&entry->list); + devm_kfree(bpmp->dev, entry); + +unlock: + spin_unlock_irqrestore(&bpmp->lock, flags); +} +EXPORT_SYMBOL_GPL(tegra_bpmp_free_mrq); + +static void tegra_bpmp_mrq_handle_ping(unsigned int mrq, + struct tegra_bpmp_channel *channel, + void *data) +{ + struct mrq_ping_request *request; + struct mrq_ping_response response; + + request = (struct mrq_ping_request *)channel->ib->data; + + memset(&response, 0, sizeof(response)); + response.reply = request->challenge << 1; + + tegra_bpmp_mrq_return(channel, 0, &response, sizeof(response)); +} + +static int tegra_bpmp_ping(struct tegra_bpmp *bpmp) +{ + struct mrq_ping_response response; + struct mrq_ping_request request; + struct tegra_bpmp_message msg; + unsigned long flags; + ktime_t start, end; + int err; + + memset(&request, 0, sizeof(request)); + request.challenge = 1; + + memset(&response, 0, sizeof(response)); + + memset(&msg, 0, sizeof(msg)); + msg.mrq = MRQ_PING; + msg.tx.data = &request; + msg.tx.size = sizeof(request); + msg.rx.data = &response; + msg.rx.size = sizeof(response); + + local_irq_save(flags); + start = ktime_get(); + err = tegra_bpmp_transfer_atomic(bpmp, &msg); + end = ktime_get(); + local_irq_restore(flags); + + if (!err) + dev_dbg(bpmp->dev, + "ping ok: challenge: %u, response: %u, time: %lld\n", + request.challenge, response.reply, + ktime_to_us(ktime_sub(end, start))); + + return err; +} + +static int tegra_bpmp_get_firmware_tag(struct tegra_bpmp *bpmp, char *tag, + size_t size) +{ + struct mrq_query_tag_request request; + struct tegra_bpmp_message msg; + unsigned long flags; + dma_addr_t phys; + void *virt; + int err; + + virt = dma_alloc_coherent(bpmp->dev, MSG_DATA_MIN_SZ, &phys, + GFP_KERNEL | GFP_DMA32); + if (!virt) + return -ENOMEM; + + memset(&request, 0, sizeof(request)); + request.addr = phys; + + memset(&msg, 0, sizeof(msg)); + msg.mrq = MRQ_QUERY_TAG; + msg.tx.data = &request; + msg.tx.size = sizeof(request); + + local_irq_save(flags); + err = tegra_bpmp_transfer_atomic(bpmp, &msg); + local_irq_restore(flags); + + if (err == 0) + strlcpy(tag, virt, size); + + dma_free_coherent(bpmp->dev, MSG_DATA_MIN_SZ, virt, phys); + + return err; +} + +static void tegra_bpmp_channel_signal(struct tegra_bpmp_channel *channel) +{ + unsigned long flags = channel->ob->flags; + + if ((flags & MSG_RING) == 0) + return; + + complete(&channel->completion); +} + +static void tegra_bpmp_handle_rx(struct mbox_client *client, void *data) +{ + struct tegra_bpmp *bpmp = mbox_client_to_bpmp(client); + struct tegra_bpmp_channel *channel; + unsigned int i, count; + unsigned long *busy; + + channel = tegra_bpmp_channel_get_rx(bpmp); + count = bpmp->soc->channels.thread.count; + busy = bpmp->threaded.busy; + + if (tegra_bpmp_master_acked(channel)) + tegra_bpmp_handle_mrq(bpmp, channel->ib->code, channel); + + spin_lock(&bpmp->lock); + + for_each_set_bit(i, busy, count) { + struct tegra_bpmp_channel *channel; + + channel = tegra_bpmp_channel_get_thread(bpmp, i); + if (!channel) + continue; + + if (tegra_bpmp_master_acked(channel)) { + tegra_bpmp_channel_signal(channel); + clear_bit(i, busy); + } + } + + spin_unlock(&bpmp->lock); +} + +static void tegra_bpmp_ivc_notify(struct tegra_ivc *ivc, void *data) +{ + struct tegra_bpmp *bpmp = data; + int err; + + if (WARN_ON(bpmp->mbox.channel == NULL)) + return; + + err = mbox_send_message(bpmp->mbox.channel, NULL); + if (err < 0) + return; + + mbox_client_txdone(bpmp->mbox.channel, 0); +} + +static int tegra_bpmp_channel_init(struct tegra_bpmp_channel *channel, + struct tegra_bpmp *bpmp, + unsigned int index) +{ + size_t message_size, queue_size; + unsigned int offset; + int err; + + channel->ivc = devm_kzalloc(bpmp->dev, sizeof(*channel->ivc), + GFP_KERNEL); + if (!channel->ivc) + return -ENOMEM; + + message_size = tegra_ivc_align(MSG_MIN_SZ); + queue_size = tegra_ivc_total_queue_size(message_size); + offset = queue_size * index; + + err = tegra_ivc_init(channel->ivc, NULL, + bpmp->rx.virt + offset, bpmp->rx.phys + offset, + bpmp->tx.virt + offset, bpmp->tx.phys + offset, + 1, message_size, tegra_bpmp_ivc_notify, + bpmp); + if (err < 0) { + dev_err(bpmp->dev, "failed to setup IVC for channel %u: %d\n", + index, err); + return err; + } + + init_completion(&channel->completion); + channel->bpmp = bpmp; + + return 0; +} + +static void tegra_bpmp_channel_reset(struct tegra_bpmp_channel *channel) +{ + /* reset the channel state */ + tegra_ivc_reset(channel->ivc); + + /* sync the channel state with BPMP */ + while (tegra_ivc_notified(channel->ivc)) + ; +} + +static void tegra_bpmp_channel_cleanup(struct tegra_bpmp_channel *channel) +{ + tegra_ivc_cleanup(channel->ivc); +} + +static int tegra_bpmp_probe(struct platform_device *pdev) +{ + struct tegra_bpmp_channel *channel; + struct tegra_bpmp *bpmp; + unsigned int i; + char tag[32]; + size_t size; + int err; + + bpmp = devm_kzalloc(&pdev->dev, sizeof(*bpmp), GFP_KERNEL); + if (!bpmp) + return -ENOMEM; + + bpmp->soc = of_device_get_match_data(&pdev->dev); + bpmp->dev = &pdev->dev; + + bpmp->tx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 0); + if (!bpmp->tx.pool) { + dev_err(&pdev->dev, "TX shmem pool not found\n"); + return -ENOMEM; + } + + bpmp->tx.virt = gen_pool_dma_alloc(bpmp->tx.pool, 4096, &bpmp->tx.phys); + if (!bpmp->tx.virt) { + dev_err(&pdev->dev, "failed to allocate from TX pool\n"); + return -ENOMEM; + } + + bpmp->rx.pool = of_gen_pool_get(pdev->dev.of_node, "shmem", 1); + if (!bpmp->rx.pool) { + dev_err(&pdev->dev, "RX shmem pool not found\n"); + err = -ENOMEM; + goto free_tx; + } + + bpmp->rx.virt = gen_pool_dma_alloc(bpmp->rx.pool, 4096, &bpmp->rx.phys); + if (!bpmp->rx.pool) { + dev_err(&pdev->dev, "failed to allocate from RX pool\n"); + err = -ENOMEM; + goto free_tx; + } + + INIT_LIST_HEAD(&bpmp->mrqs); + spin_lock_init(&bpmp->lock); + + bpmp->threaded.count = bpmp->soc->channels.thread.count; + sema_init(&bpmp->threaded.lock, bpmp->threaded.count); + + size = BITS_TO_LONGS(bpmp->threaded.count) * sizeof(long); + + bpmp->threaded.allocated = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!bpmp->threaded.allocated) { + err = -ENOMEM; + goto free_rx; + } + + bpmp->threaded.busy = devm_kzalloc(&pdev->dev, size, GFP_KERNEL); + if (!bpmp->threaded.busy) { + err = -ENOMEM; + goto free_rx; + } + + bpmp->num_channels = bpmp->soc->channels.cpu_tx.count + + bpmp->soc->channels.thread.count + + bpmp->soc->channels.cpu_rx.count; + + bpmp->channels = devm_kcalloc(&pdev->dev, bpmp->num_channels, + sizeof(*channel), GFP_KERNEL); + if (!bpmp->channels) { + err = -ENOMEM; + goto free_rx; + } + + /* message channel initialization */ + for (i = 0; i < bpmp->num_channels; i++) { + struct tegra_bpmp_channel *channel = &bpmp->channels[i]; + + err = tegra_bpmp_channel_init(channel, bpmp, i); + if (err < 0) + goto cleanup_channels; + } + + /* mbox registration */ + bpmp->mbox.client.dev = &pdev->dev; + bpmp->mbox.client.rx_callback = tegra_bpmp_handle_rx; + bpmp->mbox.client.tx_block = false; + bpmp->mbox.client.knows_txdone = false; + + bpmp->mbox.channel = mbox_request_channel(&bpmp->mbox.client, 0); + if (IS_ERR(bpmp->mbox.channel)) { + err = PTR_ERR(bpmp->mbox.channel); + dev_err(&pdev->dev, "failed to get HSP mailbox: %d\n", err); + goto cleanup_channels; + } + + /* reset message channels */ + for (i = 0; i < bpmp->num_channels; i++) { + struct tegra_bpmp_channel *channel = &bpmp->channels[i]; + + tegra_bpmp_channel_reset(channel); + } + + err = tegra_bpmp_request_mrq(bpmp, MRQ_PING, + tegra_bpmp_mrq_handle_ping, bpmp); + if (err < 0) + goto free_mbox; + + err = tegra_bpmp_ping(bpmp); + if (err < 0) { + dev_err(&pdev->dev, "failed to ping BPMP: %d\n", err); + goto free_mrq; + } + + err = tegra_bpmp_get_firmware_tag(bpmp, tag, sizeof(tag) - 1); + if (err < 0) { + dev_err(&pdev->dev, "failed to get firmware tag: %d\n", err); + goto free_mrq; + } + + dev_info(&pdev->dev, "firmware: %s\n", tag); + + err = of_platform_default_populate(pdev->dev.of_node, NULL, &pdev->dev); + if (err < 0) + goto free_mrq; + + err = tegra_bpmp_init_clocks(bpmp); + if (err < 0) + goto free_mrq; + + err = tegra_bpmp_init_resets(bpmp); + if (err < 0) + goto free_mrq; + + platform_set_drvdata(pdev, bpmp); + + return 0; + +free_mrq: + tegra_bpmp_free_mrq(bpmp, MRQ_PING, bpmp); +free_mbox: + mbox_free_channel(bpmp->mbox.channel); +cleanup_channels: + while (i--) + tegra_bpmp_channel_cleanup(&bpmp->channels[i]); +free_rx: + gen_pool_free(bpmp->rx.pool, (unsigned long)bpmp->rx.virt, 4096); +free_tx: + gen_pool_free(bpmp->tx.pool, (unsigned long)bpmp->tx.virt, 4096); + return err; +} + +static const struct tegra_bpmp_soc tegra186_soc = { + .channels = { + .cpu_tx = { + .offset = 0, + .count = 6, + .timeout = 60 * USEC_PER_SEC, + }, + .thread = { + .offset = 6, + .count = 7, + .timeout = 600 * USEC_PER_SEC, + }, + .cpu_rx = { + .offset = 13, + .count = 1, + .timeout = 0, + }, + }, + .num_resets = 193, +}; + +static const struct of_device_id tegra_bpmp_match[] = { + { .compatible = "nvidia,tegra186-bpmp", .data = &tegra186_soc }, + { } +}; + +static struct platform_driver tegra_bpmp_driver = { + .driver = { + .name = "tegra-bpmp", + .of_match_table = tegra_bpmp_match, + }, + .probe = tegra_bpmp_probe, +}; + +static int __init tegra_bpmp_init(void) +{ + return platform_driver_register(&tegra_bpmp_driver); +} +core_initcall(tegra_bpmp_init); diff --git a/include/soc/tegra/bpmp-abi.h b/include/soc/tegra/bpmp-abi.h new file mode 100644 index 000000000000..0aaef5960e29 --- /dev/null +++ b/include/soc/tegra/bpmp-abi.h @@ -0,0 +1,1601 @@ +/* + * Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef _ABI_BPMP_ABI_H_ +#define _ABI_BPMP_ABI_H_ + +#ifdef LK +#include +#endif + +#ifndef __ABI_PACKED +#define __ABI_PACKED __attribute__((packed)) +#endif + +#ifdef NO_GCC_EXTENSIONS +#define EMPTY char empty; +#define EMPTY_ARRAY 1 +#else +#define EMPTY +#define EMPTY_ARRAY 0 +#endif + +#ifndef __UNION_ANON +#define __UNION_ANON +#endif +/** + * @file + */ + + +/** + * @defgroup MRQ MRQ Messages + * @brief Messages sent to/from BPMP via IPC + * @{ + * @defgroup MRQ_Format Message Format + * @defgroup MRQ_Codes Message Request (MRQ) Codes + * @defgroup MRQ_Payloads Message Payloads + * @defgroup Error_Codes Error Codes + * @} + */ + +/** + * @addtogroup MRQ_Format Message Format + * @{ + * The CPU requests the BPMP to perform a particular service by + * sending it an IVC frame containing a single MRQ message. An MRQ + * message consists of a @ref mrq_request followed by a payload whose + * format depends on mrq_request::mrq. + * + * The BPMP processes the data and replies with an IVC frame (on the + * same IVC channel) containing and MRQ response. An MRQ response + * consists of a @ref mrq_response followed by a payload whose format + * depends on the associated mrq_request::mrq. + * + * A well-defined subset of the MRQ messages that the CPU sends to the + * BPMP can lead to BPMP eventually sending an MRQ message to the + * CPU. For example, when the CPU uses an #MRQ_THERMAL message to set + * a thermal trip point, the BPMP may eventually send a single + * #MRQ_THERMAL message of its own to the CPU indicating that the trip + * point has been crossed. + * @} + */ + +/** + * @ingroup MRQ_Format + * @brief header for an MRQ message + * + * Provides the MRQ number for the MRQ message: #mrq. The remainder of + * the MRQ message is a payload (immediately following the + * mrq_request) whose format depends on mrq. + * + * @todo document the flags + */ +struct mrq_request { + /** @brief MRQ number of the request */ + uint32_t mrq; + /** @brief flags for the request */ + uint32_t flags; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Format + * @brief header for an MRQ response + * + * Provides an error code for the associated MRQ message. The + * remainder of the MRQ response is a payload (immediately following + * the mrq_response) whose format depends on the associated + * mrq_request::mrq + * + * @todo document the flags + */ +struct mrq_response { + /** @brief error code for the MRQ request itself */ + int32_t err; + /** @brief flags for the response */ + uint32_t flags; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Format + * Minimum needed size for an IPC message buffer + */ +#define MSG_MIN_SZ 128 +/** + * @ingroup MRQ_Format + * Minimum size guaranteed for data in an IPC message buffer + */ +#define MSG_DATA_MIN_SZ 120 + +/** + * @ingroup MRQ_Codes + * @name Legal MRQ codes + * These are the legal values for mrq_request::mrq + * @{ + */ + +#define MRQ_PING 0 +#define MRQ_QUERY_TAG 1 +#define MRQ_MODULE_LOAD 4 +#define MRQ_MODULE_UNLOAD 5 +#define MRQ_TRACE_MODIFY 7 +#define MRQ_WRITE_TRACE 8 +#define MRQ_THREADED_PING 9 +#define MRQ_MODULE_MAIL 11 +#define MRQ_DEBUGFS 19 +#define MRQ_RESET 20 +#define MRQ_I2C 21 +#define MRQ_CLK 22 +#define MRQ_QUERY_ABI 23 +#define MRQ_PG_READ_STATE 25 +#define MRQ_PG_UPDATE_STATE 26 +#define MRQ_THERMAL 27 +#define MRQ_CPU_VHINT 28 +#define MRQ_ABI_RATCHET 29 +#define MRQ_EMC_DVFS_LATENCY 31 +#define MRQ_TRACE_ITER 64 + +/** @} */ + +/** + * @ingroup MRQ_Codes + * @brief Maximum MRQ code to be sent by CPU software to + * BPMP. Subject to change in future + */ +#define MAX_CPU_MRQ_ID 64 + +/** + * @addtogroup MRQ_Payloads Message Payloads + * @{ + * @defgroup Ping + * @defgroup Query_Tag Query Tag + * @defgroup Module Loadable Modules + * @defgroup Trace + * @defgroup Debugfs + * @defgroup Reset + * @defgroup I2C + * @defgroup Clocks + * @defgroup ABI_info ABI Info + * @defgroup MC_Flush MC Flush + * @defgroup Powergating + * @defgroup Thermal + * @defgroup Vhint CPU Voltage hint + * @defgroup MRQ_Deprecated Deprecated MRQ messages + * @defgroup EMC + * @} + */ + + +/** + * @ingroup MRQ_Codes + * @def MRQ_PING + * @brief A simple ping + * + * * Platforms: All + * * Initiators: Any + * * Targets: Any + * * Request Payload: @ref mrq_ping_request + * * Response Payload: @ref mrq_ping_response + * + * @ingroup MRQ_Codes + * @def MRQ_THREADED_PING + * @brief A deeper ping + * + * * Platforms: All + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_ping_request + * * Response Payload: @ref mrq_ping_response + * + * Behavior is equivalent to a simple #MRQ_PING except that BPMP + * responds from a thread context (providing a slightly more robust + * sign of life). + * + */ + +/** + * @ingroup Ping + * @brief request with #MRQ_PING + * + * Used by the sender of an #MRQ_PING message to request a pong from + * recipient. The response from the recipient is computed based on + * #challenge. + */ +struct mrq_ping_request { +/** @brief arbitrarily chosen value */ + uint32_t challenge; +} __ABI_PACKED; + +/** + * @ingroup Ping + * @brief response to #MRQ_PING + * + * Sent in response to an #MRQ_PING message. #reply should be the + * mrq_ping_request challenge left shifted by 1 with the carry-bit + * dropped. + * + */ +struct mrq_ping_response { + /** @brief response to the MRQ_PING challege */ + uint32_t reply; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_QUERY_TAG + * @brief Query BPMP firmware's tag (i.e. version information) + * + * * Platforms: All + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_query_tag_request + * * Response Payload: N/A + * + */ + +/** + * @ingroup Query_Tag + * @brief request with #MRQ_QUERY_TAG + * + * Used by #MRQ_QUERY_TAG call to ask BPMP to fill in the memory + * pointed by #addr with BPMP firmware header. + * + * The sender is reponsible for ensuring that #addr is mapped in to + * the recipient's address map. + */ +struct mrq_query_tag_request { + /** @brief base address to store the firmware header */ + uint32_t addr; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_MODULE_LOAD + * @brief dynamically load a BPMP code module + * + * * Platforms: All + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_module_load_request + * * Response Payload: @ref mrq_module_load_response + * + * @note This MRQ is disabled on production systems + * + */ + +/** + * @ingroup Module + * @brief request with #MRQ_MODULE_LOAD + * + * Used by #MRQ_MODULE_LOAD calls to ask the recipient to dynamically + * load the code located at #phys_addr and having size #size + * bytes. #phys_addr is treated as a void pointer. + * + * The recipient copies the code from #phys_addr to locally allocated + * memory prior to responding to this message. + * + * @todo document the module header format + * + * The sender is responsible for ensuring that the code is mapped in + * the recipient's address map. + * + */ +struct mrq_module_load_request { + /** @brief base address of the code to load. Treated as (void *) */ + uint32_t phys_addr; /* (void *) */ + /** @brief size in bytes of code to load */ + uint32_t size; +} __ABI_PACKED; + +/** + * @ingroup Module + * @brief response to #MRQ_MODULE_LOAD + * + * @todo document mrq_response::err + */ +struct mrq_module_load_response { + /** @brief handle to the loaded module */ + uint32_t base; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_MODULE_UNLOAD + * @brief unload a previously loaded code module + * + * * Platforms: All + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_module_unload_request + * * Response Payload: N/A + * + * @note This MRQ is disabled on production systems + */ + +/** + * @ingroup Module + * @brief request with #MRQ_MODULE_UNLOAD + * + * Used by #MRQ_MODULE_UNLOAD calls to request that a previously loaded + * module be unloaded. + */ +struct mrq_module_unload_request { + /** @brief handle of the module to unload */ + uint32_t base; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_TRACE_MODIFY + * @brief modify the set of enabled trace events + * + * * Platforms: All + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_trace_modify_request + * * Response Payload: @ref mrq_trace_modify_response + * + * @note This MRQ is disabled on production systems + */ + +/** + * @ingroup Trace + * @brief request with #MRQ_TRACE_MODIFY + * + * Used by %MRQ_TRACE_MODIFY calls to enable or disable specify trace + * events. #set takes precedence for any bit set in both #set and + * #clr. + */ +struct mrq_trace_modify_request { + /** @brief bit mask of trace events to disable */ + uint32_t clr; + /** @brief bit mask of trace events to enable */ + uint32_t set; +} __ABI_PACKED; + +/** + * @ingroup Trace + * @brief response to #MRQ_TRACE_MODIFY + * + * Sent in repsonse to an #MRQ_TRACE_MODIFY message. #mask reflects the + * state of which events are enabled after the recipient acted on the + * message. + * + */ +struct mrq_trace_modify_response { + /** @brief bit mask of trace event enable states */ + uint32_t mask; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_WRITE_TRACE + * @brief Write trace data to a buffer + * + * * Platforms: All + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_write_trace_request + * * Response Payload: @ref mrq_write_trace_response + * + * mrq_response::err depends on the @ref mrq_write_trace_request field + * values. err is -#BPMP_EINVAL if size is zero or area is NULL or + * area is in an illegal range. A positive value for err indicates the + * number of bytes written to area. + * + * @note This MRQ is disabled on production systems + */ + +/** + * @ingroup Trace + * @brief request with #MRQ_WRITE_TRACE + * + * Used by MRQ_WRITE_TRACE calls to ask the recipient to copy trace + * data from the recipient's local buffer to the output buffer. #area + * is treated as a byte-aligned pointer in the recipient's address + * space. + * + * The sender is responsible for ensuring that the output + * buffer is mapped in the recipient's address map. The recipient is + * responsible for protecting its own code and data from accidental + * overwrites. + */ +struct mrq_write_trace_request { + /** @brief base address of output buffer */ + uint32_t area; + /** @brief size in bytes of the output buffer */ + uint32_t size; +} __ABI_PACKED; + +/** + * @ingroup Trace + * @brief response to #MRQ_WRITE_TRACE + * + * Once this response is sent, the respondent will not access the + * output buffer further. + */ +struct mrq_write_trace_response { + /** + * @brief flag whether more data remains in local buffer + * + * Value is 1 if the entire local trace buffer has been + * drained to the outputbuffer. Value is 0 otherwise. + */ + uint32_t eof; +} __ABI_PACKED; + +/** @private */ +struct mrq_threaded_ping_request { + uint32_t challenge; +} __ABI_PACKED; + +/** @private */ +struct mrq_threaded_ping_response { + uint32_t reply; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_MODULE_MAIL + * @brief send a message to a loadable module + * + * * Platforms: All + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_module_mail_request + * * Response Payload: @ref mrq_module_mail_response + * + * @note This MRQ is disabled on production systems + */ + +/** + * @ingroup Module + * @brief request with #MRQ_MODULE_MAIL + */ +struct mrq_module_mail_request { + /** @brief handle to the previously loaded module */ + uint32_t base; + /** @brief module-specific mail payload + * + * The length of data[ ] is unknown to the BPMP core firmware + * but it is limited to the size of an IPC message. + */ + uint8_t data[EMPTY_ARRAY]; +} __ABI_PACKED; + +/** + * @ingroup Module + * @brief response to #MRQ_MODULE_MAIL + */ +struct mrq_module_mail_response { + /** @brief module-specific mail payload + * + * The length of data[ ] is unknown to the BPMP core firmware + * but it is limited to the size of an IPC message. + */ + uint8_t data[EMPTY_ARRAY]; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_DEBUGFS + * @brief Interact with BPMP's debugfs file nodes + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_debugfs_request + * * Response Payload: @ref mrq_debugfs_response + */ + +/** + * @addtogroup Debugfs + * @{ + * + * The BPMP firmware implements a pseudo-filesystem called + * debugfs. Any driver within the firmware may register with debugfs + * to expose an arbitrary set of "files" in the filesystem. When + * software on the CPU writes to a debugfs file, debugfs passes the + * written data to a callback provided by the driver. When software on + * the CPU reads a debugfs file, debugfs queries the driver for the + * data to return to the CPU. The intention of the debugfs filesystem + * is to provide information useful for debugging the system at + * runtime. + * + * @note The files exposed via debugfs are not part of the + * BPMP firmware's ABI. debugfs files may be added or removed in any + * given version of the firmware. Typically the semantics of a debugfs + * file are consistent from version to version but even that is not + * guaranteed. + * + * @} + */ +/** @ingroup Debugfs */ +enum mrq_debugfs_commands { + CMD_DEBUGFS_READ = 1, + CMD_DEBUGFS_WRITE = 2, + CMD_DEBUGFS_DUMPDIR = 3, + CMD_DEBUGFS_MAX +}; + +/** + * @ingroup Debugfs + * @brief parameters for CMD_DEBUGFS_READ/WRITE command + */ +struct cmd_debugfs_fileop_request { + /** @brief physical address pointing at filename */ + uint32_t fnameaddr; + /** @brief length in bytes of filename buffer */ + uint32_t fnamelen; + /** @brief physical address pointing to data buffer */ + uint32_t dataaddr; + /** @brief length in bytes of data buffer */ + uint32_t datalen; +} __ABI_PACKED; + +/** + * @ingroup Debugfs + * @brief parameters for CMD_DEBUGFS_READ/WRITE command + */ +struct cmd_debugfs_dumpdir_request { + /** @brief physical address pointing to data buffer */ + uint32_t dataaddr; + /** @brief length in bytes of data buffer */ + uint32_t datalen; +} __ABI_PACKED; + +/** + * @ingroup Debugfs + * @brief response data for CMD_DEBUGFS_READ/WRITE command + */ +struct cmd_debugfs_fileop_response { + /** @brief always 0 */ + uint32_t reserved; + /** @brief number of bytes read from or written to data buffer */ + uint32_t nbytes; +} __ABI_PACKED; + +/** + * @ingroup Debugfs + * @brief response data for CMD_DEBUGFS_DUMPDIR command + */ +struct cmd_debugfs_dumpdir_response { + /** @brief always 0 */ + uint32_t reserved; + /** @brief number of bytes read from or written to data buffer */ + uint32_t nbytes; +} __ABI_PACKED; + +/** + * @ingroup Debugfs + * @brief request with #MRQ_DEBUGFS. + * + * The sender of an MRQ_DEBUGFS message uses #cmd to specify a debugfs + * command to execute. Legal commands are the values of @ref + * mrq_debugfs_commands. Each command requires a specific additional + * payload of data. + * + * |command |payload| + * |-------------------|-------| + * |CMD_DEBUGFS_READ |fop | + * |CMD_DEBUGFS_WRITE |fop | + * |CMD_DEBUGFS_DUMPDIR|dumpdir| + */ +struct mrq_debugfs_request { + uint32_t cmd; + union { + struct cmd_debugfs_fileop_request fop; + struct cmd_debugfs_dumpdir_request dumpdir; + } __UNION_ANON; +} __ABI_PACKED; + +/** + * @ingroup Debugfs + */ +struct mrq_debugfs_response { + /** @brief always 0 */ + int32_t reserved; + union { + /** @brief response data for CMD_DEBUGFS_READ OR + * CMD_DEBUGFS_WRITE command + */ + struct cmd_debugfs_fileop_response fop; + /** @brief response data for CMD_DEBUGFS_DUMPDIR command */ + struct cmd_debugfs_dumpdir_response dumpdir; + } __UNION_ANON; +} __ABI_PACKED; + +/** + * @addtogroup Debugfs + * @{ + */ +#define DEBUGFS_S_ISDIR (1 << 9) +#define DEBUGFS_S_IRUSR (1 << 8) +#define DEBUGFS_S_IWUSR (1 << 7) +/** @} */ + + +/** + * @ingroup MRQ_Codes + * @def MRQ_RESET + * @brief reset an IP block + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_reset_request + * * Response Payload: N/A + */ + +/** + * @ingroup Reset + */ +enum mrq_reset_commands { + CMD_RESET_ASSERT = 1, + CMD_RESET_DEASSERT = 2, + CMD_RESET_MODULE = 3, + CMD_RESET_MAX, /* not part of ABI and subject to change */ +}; + +/** + * @ingroup Reset + * @brief request with MRQ_RESET + * + * Used by the sender of an #MRQ_RESET message to request BPMP to + * assert or or deassert a given reset line. + */ +struct mrq_reset_request { + /** @brief reset action to perform (@enum mrq_reset_commands) */ + uint32_t cmd; + /** @brief id of the reset to affected */ + uint32_t reset_id; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_I2C + * @brief issue an i2c transaction + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_i2c_request + * * Response Payload: @ref mrq_i2c_response + */ + +/** + * @addtogroup I2C + * @{ + */ +#define TEGRA_I2C_IPC_MAX_IN_BUF_SIZE (MSG_DATA_MIN_SZ - 12) +#define TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE (MSG_DATA_MIN_SZ - 4) +/** @} */ + +/** + * @ingroup I2C + * @name Serial I2C flags + * Use these flags with serial_i2c_request::flags + * @{ + */ +#define SERIALI2C_TEN 0x0010 +#define SERIALI2C_RD 0x0001 +#define SERIALI2C_STOP 0x8000 +#define SERIALI2C_NOSTART 0x4000 +#define SERIALI2C_REV_DIR_ADDR 0x2000 +#define SERIALI2C_IGNORE_NAK 0x1000 +#define SERIALI2C_NO_RD_ACK 0x0800 +#define SERIALI2C_RECV_LEN 0x0400 +/** @} */ +/** @ingroup I2C */ +enum { + CMD_I2C_XFER = 1 +}; + +/** + * @ingroup I2C + * @brief serializable i2c request + * + * Instances of this structure are packed (little-endian) into + * cmd_i2c_xfer_request::data_buf. Each instance represents a single + * transaction (or a portion of a transaction with repeated starts) on + * an i2c bus. + * + * Because these structures are packed, some instances are likely to + * be misaligned. Additionally because #data is variable length, it is + * not possible to iterate through a serialized list of these + * structures without inspecting #len in each instance. It may be + * easier to serialize or deserialize cmd_i2c_xfer_request::data_buf + * manually rather than using this structure definition. +*/ +struct serial_i2c_request { + /** @brief I2C slave address */ + uint16_t addr; + /** @brief bitmask of SERIALI2C_ flags */ + uint16_t flags; + /** @brief length of I2C transaction in bytes */ + uint16_t len; + /** @brief for write transactions only, #len bytes of data */ + uint8_t data[]; +} __ABI_PACKED; + +/** + * @ingroup I2C + * @brief trigger one or more i2c transactions + */ +struct cmd_i2c_xfer_request { + /** @brief valid bus number from mach-t186/i2c-t186.h*/ + uint32_t bus_id; + + /** @brief count of valid bytes in #data_buf*/ + uint32_t data_size; + + /** @brief serialized packed instances of @ref serial_i2c_request*/ + uint8_t data_buf[TEGRA_I2C_IPC_MAX_IN_BUF_SIZE]; +} __ABI_PACKED; + +/** + * @ingroup I2C + * @brief container for data read from the i2c bus + * + * Processing an cmd_i2c_xfer_request::data_buf causes BPMP to execute + * zero or more I2C reads. The data read from the bus is serialized + * into #data_buf. + */ +struct cmd_i2c_xfer_response { + /** @brief count of valid bytes in #data_buf*/ + uint32_t data_size; + /** @brief i2c read data */ + uint8_t data_buf[TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE]; +} __ABI_PACKED; + +/** + * @ingroup I2C + * @brief request with #MRQ_I2C + */ +struct mrq_i2c_request { + /** @brief always CMD_I2C_XFER (i.e. 1) */ + uint32_t cmd; + /** @brief parameters of the transfer request */ + struct cmd_i2c_xfer_request xfer; +} __ABI_PACKED; + +/** + * @ingroup I2C + * @brief response to #MRQ_I2C + */ +struct mrq_i2c_response { + struct cmd_i2c_xfer_response xfer; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_CLK + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_clk_request + * * Response Payload: @ref mrq_clk_response + * @addtogroup Clocks + * @{ + */ + +/** + * @name MRQ_CLK sub-commands + * @{ + */ +enum { + CMD_CLK_GET_RATE = 1, + CMD_CLK_SET_RATE = 2, + CMD_CLK_ROUND_RATE = 3, + CMD_CLK_GET_PARENT = 4, + CMD_CLK_SET_PARENT = 5, + CMD_CLK_IS_ENABLED = 6, + CMD_CLK_ENABLE = 7, + CMD_CLK_DISABLE = 8, + CMD_CLK_GET_ALL_INFO = 14, + CMD_CLK_GET_MAX_CLK_ID = 15, + CMD_CLK_MAX, +}; +/** @} */ + +#define MRQ_CLK_NAME_MAXLEN 40 +#define MRQ_CLK_MAX_PARENTS 16 + +/** @private */ +struct cmd_clk_get_rate_request { + EMPTY +} __ABI_PACKED; + +struct cmd_clk_get_rate_response { + int64_t rate; +} __ABI_PACKED; + +struct cmd_clk_set_rate_request { + int32_t unused; + int64_t rate; +} __ABI_PACKED; + +struct cmd_clk_set_rate_response { + int64_t rate; +} __ABI_PACKED; + +struct cmd_clk_round_rate_request { + int32_t unused; + int64_t rate; +} __ABI_PACKED; + +struct cmd_clk_round_rate_response { + int64_t rate; +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_get_parent_request { + EMPTY +} __ABI_PACKED; + +struct cmd_clk_get_parent_response { + uint32_t parent_id; +} __ABI_PACKED; + +struct cmd_clk_set_parent_request { + uint32_t parent_id; +} __ABI_PACKED; + +struct cmd_clk_set_parent_response { + uint32_t parent_id; +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_is_enabled_request { + EMPTY +} __ABI_PACKED; + +struct cmd_clk_is_enabled_response { + int32_t state; +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_enable_request { + EMPTY +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_enable_response { + EMPTY +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_disable_request { + EMPTY +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_disable_response { + EMPTY +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_get_all_info_request { + EMPTY +} __ABI_PACKED; + +struct cmd_clk_get_all_info_response { + uint32_t flags; + uint32_t parent; + uint32_t parents[MRQ_CLK_MAX_PARENTS]; + uint8_t num_parents; + uint8_t name[MRQ_CLK_NAME_MAXLEN]; +} __ABI_PACKED; + +/** @private */ +struct cmd_clk_get_max_clk_id_request { + EMPTY +} __ABI_PACKED; + +struct cmd_clk_get_max_clk_id_response { + uint32_t max_id; +} __ABI_PACKED; +/** @} */ + +/** + * @ingroup Clocks + * @brief request with #MRQ_CLK + * + * Used by the sender of an #MRQ_CLK message to control clocks. The + * clk_request is split into several sub-commands. Some sub-commands + * require no additional data. Others have a sub-command specific + * payload + * + * |sub-command |payload | + * |----------------------------|-----------------------| + * |CMD_CLK_GET_RATE |- | + * |CMD_CLK_SET_RATE |clk_set_rate | + * |CMD_CLK_ROUND_RATE |clk_round_rate | + * |CMD_CLK_GET_PARENT |- | + * |CMD_CLK_SET_PARENT |clk_set_parent | + * |CMD_CLK_IS_ENABLED |- | + * |CMD_CLK_ENABLE |- | + * |CMD_CLK_DISABLE |- | + * |CMD_CLK_GET_ALL_INFO |- | + * |CMD_CLK_GET_MAX_CLK_ID |- | + * + */ + +struct mrq_clk_request { + /** @brief sub-command and clock id concatenated to 32-bit word. + * - bits[31..24] is the sub-cmd. + * - bits[23..0] is the clock id + */ + uint32_t cmd_and_id; + + union { + /** @private */ + struct cmd_clk_get_rate_request clk_get_rate; + struct cmd_clk_set_rate_request clk_set_rate; + struct cmd_clk_round_rate_request clk_round_rate; + /** @private */ + struct cmd_clk_get_parent_request clk_get_parent; + struct cmd_clk_set_parent_request clk_set_parent; + /** @private */ + struct cmd_clk_enable_request clk_enable; + /** @private */ + struct cmd_clk_disable_request clk_disable; + /** @private */ + struct cmd_clk_is_enabled_request clk_is_enabled; + /** @private */ + struct cmd_clk_get_all_info_request clk_get_all_info; + /** @private */ + struct cmd_clk_get_max_clk_id_request clk_get_max_clk_id; + } __UNION_ANON; +} __ABI_PACKED; + +/** + * @ingroup Clocks + * @brief response to MRQ_CLK + * + * Each sub-command supported by @ref mrq_clk_request may return + * sub-command-specific data. Some do and some do not as indicated in + * the following table + * + * |sub-command |payload | + * |----------------------------|------------------------| + * |CMD_CLK_GET_RATE |clk_get_rate | + * |CMD_CLK_SET_RATE |clk_set_rate | + * |CMD_CLK_ROUND_RATE |clk_round_rate | + * |CMD_CLK_GET_PARENT |clk_get_parent | + * |CMD_CLK_SET_PARENT |clk_set_parent | + * |CMD_CLK_IS_ENABLED |clk_is_enabled | + * |CMD_CLK_ENABLE |- | + * |CMD_CLK_DISABLE |- | + * |CMD_CLK_GET_ALL_INFO |clk_get_all_info | + * |CMD_CLK_GET_MAX_CLK_ID |clk_get_max_id | + * + */ + +struct mrq_clk_response { + union { + struct cmd_clk_get_rate_response clk_get_rate; + struct cmd_clk_set_rate_response clk_set_rate; + struct cmd_clk_round_rate_response clk_round_rate; + struct cmd_clk_get_parent_response clk_get_parent; + struct cmd_clk_set_parent_response clk_set_parent; + /** @private */ + struct cmd_clk_enable_response clk_enable; + /** @private */ + struct cmd_clk_disable_response clk_disable; + struct cmd_clk_is_enabled_response clk_is_enabled; + struct cmd_clk_get_all_info_response clk_get_all_info; + struct cmd_clk_get_max_clk_id_response clk_get_max_clk_id; + } __UNION_ANON; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_QUERY_ABI + * @brief check if an MRQ is implemented + * + * * Platforms: All + * * Initiators: Any + * * Targets: Any + * * Request Payload: @ref mrq_query_abi_request + * * Response Payload: @ref mrq_query_abi_response + */ + +/** + * @ingroup ABI_info + * @brief request with MRQ_QUERY_ABI + * + * Used by #MRQ_QUERY_ABI call to check if MRQ code #mrq is supported + * by the recipient. + */ +struct mrq_query_abi_request { + /** @brief MRQ code to query */ + uint32_t mrq; +} __ABI_PACKED; + +/** + * @ingroup ABI_info + * @brief response to MRQ_QUERY_ABI + */ +struct mrq_query_abi_response { + /** @brief 0 if queried MRQ is supported. Else, -#BPMP_ENODEV */ + int32_t status; +} __ABI_PACKED; + +/** + * @ingroup MRQ_Codes + * @def MRQ_PG_READ_STATE + * @brief read the power-gating state of a partition + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_pg_read_state_request + * * Response Payload: @ref mrq_pg_read_state_response + * @addtogroup Powergating + * @{ + */ + +/** + * @brief request with #MRQ_PG_READ_STATE + * + * Used by MRQ_PG_READ_STATE call to read the current state of a + * partition. + */ +struct mrq_pg_read_state_request { + /** @brief ID of partition */ + uint32_t partition_id; +} __ABI_PACKED; + +/** + * @brief response to MRQ_PG_READ_STATE + * @todo define possible errors. + */ +struct mrq_pg_read_state_response { + /** @brief read as don't care */ + uint32_t sram_state; + /** @brief state of power partition + * * 0 : off + * * 1 : on + */ + uint32_t logic_state; +} __ABI_PACKED; + +/** @} */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_PG_UPDATE_STATE + * @brief modify the power-gating state of a partition + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_pg_update_state_request + * * Response Payload: N/A + * @addtogroup Powergating + * @{ + */ + +/** + * @brief request with mrq_pg_update_state_request + * + * Used by #MRQ_PG_UPDATE_STATE call to request BPMP to change the + * state of a power partition #partition_id. + */ +struct mrq_pg_update_state_request { + /** @brief ID of partition */ + uint32_t partition_id; + /** @brief secondary control of power partition + * @details Ignored by many versions of the BPMP + * firmware. For maximum compatibility, set the value + * according to @logic_state + * * 0x1: power ON partition (@ref logic_state == 0x3) + * * 0x3: power OFF partition (@ref logic_state == 0x1) + */ + uint32_t sram_state; + /** @brief controls state of power partition, legal values are + * * 0x1 : power OFF partition + * * 0x3 : power ON partition + */ + uint32_t logic_state; + /** @brief change state of clocks of the power partition, legal values + * * 0x0 : do not change clock state + * * 0x1 : disable partition clocks (only applicable when + * @ref logic_state == 0x1) + * * 0x3 : enable partition clocks (only applicable when + * @ref logic_state == 0x3) + */ + uint32_t clock_state; +} __ABI_PACKED; +/** @} */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_THERMAL + * @brief interact with BPMP thermal framework + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: Any + * * Request Payload: TODO + * * Response Payload: TODO + * + * @addtogroup Thermal + * + * The BPMP firmware includes a thermal framework. Drivers within the + * bpmp firmware register with the framework to provide thermal + * zones. Each thermal zone corresponds to an entity whose temperature + * can be measured. The framework also has a notion of trip points. A + * trip point consists of a thermal zone id, a temperature, and a + * callback routine. The framework invokes the callback when the zone + * hits the indicated temperature. The BPMP firmware uses this thermal + * framework interally to implement various temperature-dependent + * functions. + * + * Software on the CPU can use #MRQ_THERMAL (with payload @ref + * mrq_thermal_host_to_bpmp_request) to interact with the BPMP thermal + * framework. The CPU must It can query the number of supported zones, + * query zone temperatures, and set trip points. + * + * When a trip point set by the CPU gets crossed, BPMP firmware issues + * an IPC to the CPU having mrq_request::mrq = #MRQ_THERMAL and a + * payload of @ref mrq_thermal_bpmp_to_host_request. + * @{ + */ +enum mrq_thermal_host_to_bpmp_cmd { + /** + * @brief Check whether the BPMP driver supports the specified + * request type. + * + * Host needs to supply request parameters. + * + * mrq_response::err is 0 if the specified request is + * supported and -#BPMP_ENODEV otherwise. + */ + CMD_THERMAL_QUERY_ABI = 0, + + /** + * @brief Get the current temperature of the specified zone. + * + * Host needs to supply request parameters. + * + * mrq_response::err is + * * 0: Temperature query succeeded. + * * -#BPMP_EINVAL: Invalid request parameters. + * * -#BPMP_ENOENT: No driver registered for thermal zone.. + * * -#BPMP_EFAULT: Problem reading temperature measurement. + */ + CMD_THERMAL_GET_TEMP = 1, + + /** + * @brief Enable or disable and set the lower and upper + * thermal limits for a thermal trip point. Each zone has + * one trip point. + * + * Host needs to supply request parameters. Once the + * temperature hits a trip point, the BPMP will send a message + * to the CPU having MRQ=MRQ_THERMAL and + * type=CMD_THERMAL_HOST_TRIP_REACHED + * + * mrq_response::err is + * * 0: Trip successfully set. + * * -#BPMP_EINVAL: Invalid request parameters. + * * -#BPMP_ENOENT: No driver registered for thermal zone. + * * -#BPMP_EFAULT: Problem setting trip point. + */ + CMD_THERMAL_SET_TRIP = 2, + + /** + * @brief Get the number of supported thermal zones. + * + * No request parameters required. + * + * mrq_response::err is always 0, indicating success. + */ + CMD_THERMAL_GET_NUM_ZONES = 3, + + /** @brief: number of supported host-to-bpmp commands. May + * increase in future + */ + CMD_THERMAL_HOST_TO_BPMP_NUM +}; + +enum mrq_thermal_bpmp_to_host_cmd { + /** + * @brief Indication that the temperature for a zone has + * exceeded the range indicated in the thermal trip point + * for the zone. + * + * BPMP needs to supply request parameters. Host only needs to + * acknowledge. + */ + CMD_THERMAL_HOST_TRIP_REACHED = 100, + + /** @brief: number of supported bpmp-to-host commands. May + * increase in future + */ + CMD_THERMAL_BPMP_TO_HOST_NUM +}; + +/* + * Host->BPMP request data for request type CMD_THERMAL_QUERY_ABI + * + * zone: Request type for which to check existence. + */ +struct cmd_thermal_query_abi_request { + uint32_t type; +} __ABI_PACKED; + +/* + * Host->BPMP request data for request type CMD_THERMAL_GET_TEMP + * + * zone: Number of thermal zone. + */ +struct cmd_thermal_get_temp_request { + uint32_t zone; +} __ABI_PACKED; + +/* + * BPMP->Host reply data for request CMD_THERMAL_GET_TEMP + * + * error: 0 if request succeeded. + * -BPMP_EINVAL if request parameters were invalid. + * -BPMP_ENOENT if no driver was registered for the specified thermal zone. + * -BPMP_EFAULT for other thermal zone driver errors. + * temp: Current temperature in millicelsius. + */ +struct cmd_thermal_get_temp_response { + int32_t temp; +} __ABI_PACKED; + +/* + * Host->BPMP request data for request type CMD_THERMAL_SET_TRIP + * + * zone: Number of thermal zone. + * low: Temperature of lower trip point in millicelsius + * high: Temperature of upper trip point in millicelsius + * enabled: 1 to enable trip point, 0 to disable trip point + */ +struct cmd_thermal_set_trip_request { + uint32_t zone; + int32_t low; + int32_t high; + uint32_t enabled; +} __ABI_PACKED; + +/* + * BPMP->Host request data for request type CMD_THERMAL_HOST_TRIP_REACHED + * + * zone: Number of thermal zone where trip point was reached. + */ +struct cmd_thermal_host_trip_reached_request { + uint32_t zone; +} __ABI_PACKED; + +/* + * BPMP->Host reply data for request type CMD_THERMAL_GET_NUM_ZONES + * + * num: Number of supported thermal zones. The thermal zones are indexed + * starting from zero. + */ +struct cmd_thermal_get_num_zones_response { + uint32_t num; +} __ABI_PACKED; + +/* + * Host->BPMP request data. + * + * Reply type is union mrq_thermal_bpmp_to_host_response. + * + * type: Type of request. Values listed in enum mrq_thermal_type. + * data: Request type specific parameters. + */ +struct mrq_thermal_host_to_bpmp_request { + uint32_t type; + union { + struct cmd_thermal_query_abi_request query_abi; + struct cmd_thermal_get_temp_request get_temp; + struct cmd_thermal_set_trip_request set_trip; + } __UNION_ANON; +} __ABI_PACKED; + +/* + * BPMP->Host request data. + * + * type: Type of request. Values listed in enum mrq_thermal_type. + * data: Request type specific parameters. + */ +struct mrq_thermal_bpmp_to_host_request { + uint32_t type; + union { + struct cmd_thermal_host_trip_reached_request host_trip_reached; + } __UNION_ANON; +} __ABI_PACKED; + +/* + * Data in reply to a Host->BPMP request. + */ +union mrq_thermal_bpmp_to_host_response { + struct cmd_thermal_get_temp_response get_temp; + struct cmd_thermal_get_num_zones_response get_num_zones; +} __ABI_PACKED; +/** @} */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_CPU_VHINT + * @brief Query CPU voltage hint data + * + * * Platforms: T186 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: @ref mrq_cpu_vhint_request + * * Response Payload: N/A + * + * @addtogroup Vhint CPU Voltage hint + * @{ + */ + +/** + * @brief request with #MRQ_CPU_VHINT + * + * Used by #MRQ_CPU_VHINT call by CCPLEX to retrieve voltage hint data + * from BPMP to memory space pointed by #addr. CCPLEX is responsible + * to allocate sizeof(cpu_vhint_data) sized block of memory and + * appropriately map it for BPMP before sending the request. + */ +struct mrq_cpu_vhint_request { + /** @brief IOVA address for the #cpu_vhint_data */ + uint32_t addr; /* struct cpu_vhint_data * */ + /** @brief ID of the cluster whose data is requested */ + uint32_t cluster_id; /* enum cluster_id */ +} __ABI_PACKED; + +/** + * @brief description of the CPU v/f relation + * + * Used by #MRQ_CPU_VHINT call to carry data pointed by #addr of + * struct mrq_cpu_vhint_request + */ +struct cpu_vhint_data { + uint32_t ref_clk_hz; /**< reference frequency in Hz */ + uint16_t pdiv; /**< post divider value */ + uint16_t mdiv; /**< input divider value */ + uint16_t ndiv_max; /**< fMAX expressed with max NDIV value */ + /** table of ndiv values as a function of vINDEX (voltage index) */ + uint16_t ndiv[80]; + /** minimum allowed NDIV value */ + uint16_t ndiv_min; + /** minimum allowed voltage hint value (as in vINDEX) */ + uint16_t vfloor; + /** maximum allowed voltage hint value (as in vINDEX) */ + uint16_t vceil; + /** post-multiplier for vindex value */ + uint16_t vindex_mult; + /** post-divider for vindex value */ + uint16_t vindex_div; + /** reserved for future use */ + uint16_t reserved[328]; +} __ABI_PACKED; + +/** @} */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_ABI_RATCHET + * @brief ABI ratchet value query + * + * * Platforms: T186 + * * Initiators: Any + * * Targets: BPMP + * * Request Payload: @ref mrq_abi_ratchet_request + * * Response Payload: @ref mrq_abi_ratchet_response + * @addtogroup ABI_info + * @{ + */ + +/** + * @brief an ABI compatibility mechanism + * + * BPMP_ABI_RATCHET_VALUE may increase for various reasons in a future + * revision of this header file. + * 1. That future revision deprecates some MRQ + * 2. That future revision introduces a breaking change to an existing + * MRQ or + * 3. A bug is discovered in an existing implementation of the BPMP-FW + * (or possibly one of its clients) which warrants deprecating that + * implementation. + */ +#define BPMP_ABI_RATCHET_VALUE 3 + +/** + * @brief request with #MRQ_ABI_RATCHET. + * + * #ratchet should be #BPMP_ABI_RATCHET_VALUE from the ABI header + * against which the requester was compiled. + * + * If ratchet is less than BPMP's #BPMP_ABI_RATCHET_VALUE, BPMP may + * reply with mrq_response::err = -#BPMP_ERANGE to indicate that + * BPMP-FW cannot interoperate correctly with the requester. Requester + * should cease further communication with BPMP. + * + * Otherwise, err shall be 0. + */ +struct mrq_abi_ratchet_request { + /** @brief requester's ratchet value */ + uint16_t ratchet; +}; + +/** + * @brief response to #MRQ_ABI_RATCHET + * + * #ratchet shall be #BPMP_ABI_RATCHET_VALUE from the ABI header + * against which BPMP firwmare was compiled. + * + * If #ratchet is less than the requester's #BPMP_ABI_RATCHET_VALUE, + * the requster must either interoperate with BPMP according to an ABI + * header version with BPMP_ABI_RATCHET_VALUE = ratchet or cease + * communication with BPMP. + * + * If mrq_response::err is 0 and ratchet is greater than or equal to the + * requester's BPMP_ABI_RATCHET_VALUE, the requester should continue + * normal operation. + */ +struct mrq_abi_ratchet_response { + /** @brief BPMP's ratchet value */ + uint16_t ratchet; +}; +/** @} */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_EMC_DVFS_LATENCY + * @brief query frequency dependent EMC DVFS latency + * + * * Platforms: T186 + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: N/A + * * Response Payload: @ref mrq_emc_dvfs_latency_response + * @addtogroup EMC + * @{ + */ + +/** + * @brief used by @ref mrq_emc_dvfs_latency_response + */ +struct emc_dvfs_latency { + /** @brief EMC frequency in kHz */ + uint32_t freq; + /** @brief EMC DVFS latency in nanoseconds */ + uint32_t latency; +} __ABI_PACKED; + +#define EMC_DVFS_LATENCY_MAX_SIZE 14 +/** + * @brief response to #MRQ_EMC_DVFS_LATENCY + */ +struct mrq_emc_dvfs_latency_response { + /** @brief the number valid entries in #pairs */ + uint32_t num_pairs; + /** @brief EMC information */ + struct emc_dvfs_latency pairs[EMC_DVFS_LATENCY_MAX_SIZE]; +} __ABI_PACKED; + +/** @} */ + +/** + * @ingroup MRQ_Codes + * @def MRQ_TRACE_ITER + * @brief manage the trace iterator + * + * * Platforms: All + * * Initiators: CCPLEX + * * Targets: BPMP + * * Request Payload: N/A + * * Response Payload: @ref mrq_trace_iter_request + * @addtogroup Trace + * @{ + */ +enum { + /** @brief (re)start the tracing now. Ignore older events */ + TRACE_ITER_INIT = 0, + /** @brief clobber all events in the trace buffer */ + TRACE_ITER_CLEAN = 1 +}; + +/** + * @brief request with #MRQ_TRACE_ITER + */ +struct mrq_trace_iter_request { + /** @brief TRACE_ITER_INIT or TRACE_ITER_CLEAN */ + uint32_t cmd; +} __ABI_PACKED; + +/** @} */ + +/* + * 4. Enumerations + */ + +/* + * 4.1 CPU enumerations + * + * See + * + * 4.2 CPU Cluster enumerations + * + * See + * + * 4.3 System low power state enumerations + * + * See + */ + +/* + * 4.4 Clock enumerations + * + * For clock enumerations, see + */ + +/* + * 4.5 Reset enumerations + * + * For reset enumerations, see + */ + +/* + * 4.6 Thermal sensor enumerations + * + * For thermal sensor enumerations, see + */ + +/** + * @defgroup Error_Codes + * Negative values for mrq_response::err generally indicate some + * error. The ABI defines the following error codes. Negating these + * defines is an exercise left to the user. + * @{ + */ +/** @brief No such file or directory */ +#define BPMP_ENOENT 2 +/** @brief No MRQ handler */ +#define BPMP_ENOHANDLER 3 +/** @brief I/O error */ +#define BPMP_EIO 5 +/** @brief Bad sub-MRQ command */ +#define BPMP_EBADCMD 6 +/** @brief Not enough memory */ +#define BPMP_ENOMEM 12 +/** @brief Permission denied */ +#define BPMP_EACCES 13 +/** @brief Bad address */ +#define BPMP_EFAULT 14 +/** @brief No such device */ +#define BPMP_ENODEV 19 +/** @brief Argument is a directory */ +#define BPMP_EISDIR 21 +/** @brief Invalid argument */ +#define BPMP_EINVAL 22 +/** @brief Timeout during operation */ +#define BPMP_ETIMEDOUT 23 +/** @brief Out of range */ +#define BPMP_ERANGE 34 +/** @} */ +/** @} */ +#endif diff --git a/include/soc/tegra/bpmp.h b/include/soc/tegra/bpmp.h new file mode 100644 index 000000000000..13dcd44e91bb --- /dev/null +++ b/include/soc/tegra/bpmp.h @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __SOC_TEGRA_BPMP_H +#define __SOC_TEGRA_BPMP_H + +#include +#include +#include +#include + +#include + +struct tegra_bpmp_clk; + +struct tegra_bpmp_soc { + struct { + struct { + unsigned int offset; + unsigned int count; + unsigned int timeout; + } cpu_tx, thread, cpu_rx; + } channels; + unsigned int num_resets; +}; + +struct tegra_bpmp_mb_data { + u32 code; + u32 flags; + u8 data[MSG_DATA_MIN_SZ]; +} __packed; + +struct tegra_bpmp_channel { + struct tegra_bpmp *bpmp; + struct tegra_bpmp_mb_data *ib; + struct tegra_bpmp_mb_data *ob; + struct completion completion; + struct tegra_ivc *ivc; +}; + +typedef void (*tegra_bpmp_mrq_handler_t)(unsigned int mrq, + struct tegra_bpmp_channel *channel, + void *data); + +struct tegra_bpmp_mrq { + struct list_head list; + unsigned int mrq; + tegra_bpmp_mrq_handler_t handler; + void *data; +}; + +struct tegra_bpmp { + const struct tegra_bpmp_soc *soc; + struct device *dev; + + struct { + struct gen_pool *pool; + dma_addr_t phys; + void *virt; + } tx, rx; + + struct { + struct mbox_client client; + struct mbox_chan *channel; + } mbox; + + struct tegra_bpmp_channel *channels; + unsigned int num_channels; + + struct { + unsigned long *allocated; + unsigned long *busy; + unsigned int count; + struct semaphore lock; + } threaded; + + struct list_head mrqs; + spinlock_t lock; + + struct tegra_bpmp_clk **clocks; + unsigned int num_clocks; + + struct reset_controller_dev rstc; +}; + +struct tegra_bpmp *tegra_bpmp_get(struct device *dev); +void tegra_bpmp_put(struct tegra_bpmp *bpmp); + +struct tegra_bpmp_message { + unsigned int mrq; + + struct { + const void *data; + size_t size; + } tx; + + struct { + void *data; + size_t size; + } rx; +}; + +int tegra_bpmp_transfer_atomic(struct tegra_bpmp *bpmp, + struct tegra_bpmp_message *msg); +int tegra_bpmp_transfer(struct tegra_bpmp *bpmp, + struct tegra_bpmp_message *msg); + +int tegra_bpmp_request_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, + tegra_bpmp_mrq_handler_t handler, void *data); +void tegra_bpmp_free_mrq(struct tegra_bpmp *bpmp, unsigned int mrq, + void *data); + +#if IS_ENABLED(CONFIG_CLK_TEGRA_BPMP) +int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp); +#else +static inline int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp) +{ + return 0; +} +#endif + +#if IS_ENABLED(CONFIG_RESET_TEGRA_BPMP) +int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp); +#else +static inline int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp) +{ + return 0; +} +#endif + +#endif /* __SOC_TEGRA_BPMP_H */ -- cgit v1.2.3 From dc606c5205536a828c17bd96f06559dafaf75fb7 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 18 Aug 2016 15:50:09 +0200 Subject: reset: Add Tegra BPMP reset driver This driver uses the services provided by the BPMP firmware driver to implement a reset driver based on the MRQ_RESET request. Acked-by: Philipp Zabel Signed-off-by: Thierry Reding --- drivers/reset/Kconfig | 1 + drivers/reset/Makefile | 1 + drivers/reset/tegra/Kconfig | 2 ++ drivers/reset/tegra/Makefile | 1 + drivers/reset/tegra/reset-bpmp.c | 71 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+) create mode 100644 drivers/reset/tegra/Kconfig create mode 100644 drivers/reset/tegra/Makefile create mode 100644 drivers/reset/tegra/reset-bpmp.c (limited to 'drivers') diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig index 06d9fa2f3bc0..172dc966a01f 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig @@ -94,5 +94,6 @@ config RESET_ZYNQ source "drivers/reset/sti/Kconfig" source "drivers/reset/hisilicon/Kconfig" +source "drivers/reset/tegra/Kconfig" endif diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile index bbe7026617fc..13b346e03d84 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -1,6 +1,7 @@ obj-y += core.o obj-y += hisilicon/ obj-$(CONFIG_ARCH_STI) += sti/ +obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-$(CONFIG_RESET_ATH79) += reset-ath79.o obj-$(CONFIG_RESET_BERLIN) += reset-berlin.o obj-$(CONFIG_RESET_LPC18XX) += reset-lpc18xx.o diff --git a/drivers/reset/tegra/Kconfig b/drivers/reset/tegra/Kconfig new file mode 100644 index 000000000000..d2afa293df7d --- /dev/null +++ b/drivers/reset/tegra/Kconfig @@ -0,0 +1,2 @@ +config RESET_TEGRA_BPMP + def_bool TEGRA_BPMP diff --git a/drivers/reset/tegra/Makefile b/drivers/reset/tegra/Makefile new file mode 100644 index 000000000000..775243ab7383 --- /dev/null +++ b/drivers/reset/tegra/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_RESET_TEGRA_BPMP) += reset-bpmp.o diff --git a/drivers/reset/tegra/reset-bpmp.c b/drivers/reset/tegra/reset-bpmp.c new file mode 100644 index 000000000000..5daf2ee1a396 --- /dev/null +++ b/drivers/reset/tegra/reset-bpmp.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2016 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include + +#include +#include + +static struct tegra_bpmp *to_tegra_bpmp(struct reset_controller_dev *rstc) +{ + return container_of(rstc, struct tegra_bpmp, rstc); +} + +static int tegra_bpmp_reset_common(struct reset_controller_dev *rstc, + enum mrq_reset_commands command, + unsigned int id) +{ + struct tegra_bpmp *bpmp = to_tegra_bpmp(rstc); + struct mrq_reset_request request; + struct tegra_bpmp_message msg; + + memset(&request, 0, sizeof(request)); + request.cmd = command; + request.reset_id = id; + + memset(&msg, 0, sizeof(msg)); + msg.mrq = MRQ_RESET; + msg.tx.data = &request; + msg.tx.size = sizeof(request); + + return tegra_bpmp_transfer(bpmp, &msg); +} + +static int tegra_bpmp_reset_module(struct reset_controller_dev *rstc, + unsigned long id) +{ + return tegra_bpmp_reset_common(rstc, CMD_RESET_MODULE, id); +} + +static int tegra_bpmp_reset_assert(struct reset_controller_dev *rstc, + unsigned long id) +{ + return tegra_bpmp_reset_common(rstc, CMD_RESET_ASSERT, id); +} + +static int tegra_bpmp_reset_deassert(struct reset_controller_dev *rstc, + unsigned long id) +{ + return tegra_bpmp_reset_common(rstc, CMD_RESET_DEASSERT, id); +} + +static const struct reset_control_ops tegra_bpmp_reset_ops = { + .reset = tegra_bpmp_reset_module, + .assert = tegra_bpmp_reset_assert, + .deassert = tegra_bpmp_reset_deassert, +}; + +int tegra_bpmp_init_resets(struct tegra_bpmp *bpmp) +{ + bpmp->rstc.ops = &tegra_bpmp_reset_ops; + bpmp->rstc.owner = THIS_MODULE; + bpmp->rstc.of_node = bpmp->dev->of_node; + bpmp->rstc.nr_resets = bpmp->soc->num_resets; + + return devm_reset_controller_register(bpmp->dev, &bpmp->rstc); +} -- cgit v1.2.3 From e5269794d2e9046dd45be15bdb213a229df46b7e Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Thu, 17 Nov 2016 15:32:54 +0000 Subject: of: base: add support to get machine model name Currently platforms/drivers needing to get the machine model name are replicating the same snippet of code. In some case, the OF reference counting is either missing or incorrect. This patch adds support to read the machine model name either using the "model" or the "compatible" property in the device tree root node to the core OF/DT code. This can be used to remove all the duplicate code snippets doing exactly same thing later. Cc: Rob Herring Cc: Frank Rowand Cc: Arnd Bergmann Signed-off-by: Sudeep Holla Signed-off-by: Rob Herring --- drivers/of/base.c | 32 ++++++++++++++++++++++++++++++++ include/linux/of.h | 6 ++++++ 2 files changed, 38 insertions(+) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index d687e6de24a0..128e114f9210 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -545,6 +545,38 @@ int of_machine_is_compatible(const char *compat) } EXPORT_SYMBOL(of_machine_is_compatible); +/** + * of_machine_get_model_name - Find and read the model name or the compatible + * value for the machine. + * @model: pointer to null terminated return string, modified only if + * return value is 0. + * + * Returns a string containing either the model name or the compatible value + * of the machine if found, else return error. + * + * Search for a machine model name or the compatible if model name is missing + * in a device tree node and retrieve a null terminated string value (pointer + * to data, not a copy). Returns 0 on success, -EINVAL if root of the device + * tree is not found and other error returned by of_property_read_string on + * failure. + */ +int of_machine_get_model_name(const char **model) +{ + int error; + + if (!of_node_get(of_root)) + return -EINVAL; + + error = of_property_read_string(of_root, "model", model); + if (error) + error = of_property_read_string_index(of_root, "compatible", + 0, model); + of_node_put(of_root); + + return error; +} +EXPORT_SYMBOL(of_machine_get_model_name); + /** * __of_device_is_available - check if a device is available for use * diff --git a/include/linux/of.h b/include/linux/of.h index 299aeb192727..9eb8eb3c587e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -367,6 +367,7 @@ extern int of_alias_get_id(struct device_node *np, const char *stem); extern int of_alias_get_highest_id(const char *stem); extern int of_machine_is_compatible(const char *compat); +extern int of_machine_get_model_name(const char **model); extern int of_add_property(struct device_node *np, struct property *prop); extern int of_remove_property(struct device_node *np, struct property *prop); @@ -788,6 +789,11 @@ static inline int of_machine_is_compatible(const char *compat) return 0; } +static inline int of_machine_get_model_name(const char **model) +{ + return -EINVAL; +} + static inline bool of_console_check(const struct device_node *dn, const char *name, int index) { return false; -- cgit v1.2.3 From 24dc974d1c1d745e38aff94ce37ee3dd3f4febce Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Abbadie Date: Wed, 19 Oct 2016 18:47:12 -0200 Subject: [media] Staging: media: radio-bcm2048: Fix symbolic permissions This replaces the S_* style permissions by numbers for the __ATTR macros Signed-off-by: Jean-Baptiste Abbadie Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.c | 58 +++++++++++++-------------- 1 file changed, 29 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 4d9bd02ede47..9fc2c13ce0ff 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -2059,67 +2059,67 @@ property_signed_read(fm_rssi, int, "%d") DEFINE_SYSFS_PROPERTY(region, unsigned, int, "%u", 0) static struct device_attribute attrs[] = { - __ATTR(power_state, S_IRUGO | S_IWUSR, bcm2048_power_state_read, + __ATTR(power_state, 0644, bcm2048_power_state_read, bcm2048_power_state_write), - __ATTR(mute, S_IRUGO | S_IWUSR, bcm2048_mute_read, + __ATTR(mute, 0644, bcm2048_mute_read, bcm2048_mute_write), - __ATTR(audio_route, S_IRUGO | S_IWUSR, bcm2048_audio_route_read, + __ATTR(audio_route, 0644, bcm2048_audio_route_read, bcm2048_audio_route_write), - __ATTR(dac_output, S_IRUGO | S_IWUSR, bcm2048_dac_output_read, + __ATTR(dac_output, 0644, bcm2048_dac_output_read, bcm2048_dac_output_write), - __ATTR(fm_hi_lo_injection, S_IRUGO | S_IWUSR, + __ATTR(fm_hi_lo_injection, 0644, bcm2048_fm_hi_lo_injection_read, bcm2048_fm_hi_lo_injection_write), - __ATTR(fm_frequency, S_IRUGO | S_IWUSR, bcm2048_fm_frequency_read, + __ATTR(fm_frequency, 0644, bcm2048_fm_frequency_read, bcm2048_fm_frequency_write), - __ATTR(fm_af_frequency, S_IRUGO | S_IWUSR, + __ATTR(fm_af_frequency, 0644, bcm2048_fm_af_frequency_read, bcm2048_fm_af_frequency_write), - __ATTR(fm_deemphasis, S_IRUGO | S_IWUSR, bcm2048_fm_deemphasis_read, + __ATTR(fm_deemphasis, 0644, bcm2048_fm_deemphasis_read, bcm2048_fm_deemphasis_write), - __ATTR(fm_rds_mask, S_IRUGO | S_IWUSR, bcm2048_fm_rds_mask_read, + __ATTR(fm_rds_mask, 0644, bcm2048_fm_rds_mask_read, bcm2048_fm_rds_mask_write), - __ATTR(fm_best_tune_mode, S_IRUGO | S_IWUSR, + __ATTR(fm_best_tune_mode, 0644, bcm2048_fm_best_tune_mode_read, bcm2048_fm_best_tune_mode_write), - __ATTR(fm_search_rssi_threshold, S_IRUGO | S_IWUSR, + __ATTR(fm_search_rssi_threshold, 0644, bcm2048_fm_search_rssi_threshold_read, bcm2048_fm_search_rssi_threshold_write), - __ATTR(fm_search_mode_direction, S_IRUGO | S_IWUSR, + __ATTR(fm_search_mode_direction, 0644, bcm2048_fm_search_mode_direction_read, bcm2048_fm_search_mode_direction_write), - __ATTR(fm_search_tune_mode, S_IRUGO | S_IWUSR, + __ATTR(fm_search_tune_mode, 0644, bcm2048_fm_search_tune_mode_read, bcm2048_fm_search_tune_mode_write), - __ATTR(rds, S_IRUGO | S_IWUSR, bcm2048_rds_read, + __ATTR(rds, 0644, bcm2048_rds_read, bcm2048_rds_write), - __ATTR(rds_b_block_mask, S_IRUGO | S_IWUSR, + __ATTR(rds_b_block_mask, 0644, bcm2048_rds_b_block_mask_read, bcm2048_rds_b_block_mask_write), - __ATTR(rds_b_block_match, S_IRUGO | S_IWUSR, + __ATTR(rds_b_block_match, 0644, bcm2048_rds_b_block_match_read, bcm2048_rds_b_block_match_write), - __ATTR(rds_pi_mask, S_IRUGO | S_IWUSR, bcm2048_rds_pi_mask_read, + __ATTR(rds_pi_mask, 0644, bcm2048_rds_pi_mask_read, bcm2048_rds_pi_mask_write), - __ATTR(rds_pi_match, S_IRUGO | S_IWUSR, bcm2048_rds_pi_match_read, + __ATTR(rds_pi_match, 0644, bcm2048_rds_pi_match_read, bcm2048_rds_pi_match_write), - __ATTR(rds_wline, S_IRUGO | S_IWUSR, bcm2048_rds_wline_read, + __ATTR(rds_wline, 0644, bcm2048_rds_wline_read, bcm2048_rds_wline_write), - __ATTR(rds_pi, S_IRUGO, bcm2048_rds_pi_read, NULL), - __ATTR(rds_rt, S_IRUGO, bcm2048_rds_rt_read, NULL), - __ATTR(rds_ps, S_IRUGO, bcm2048_rds_ps_read, NULL), - __ATTR(fm_rds_flags, S_IRUGO, bcm2048_fm_rds_flags_read, NULL), - __ATTR(region_bottom_frequency, S_IRUGO, + __ATTR(rds_pi, 0444, bcm2048_rds_pi_read, NULL), + __ATTR(rds_rt, 0444, bcm2048_rds_rt_read, NULL), + __ATTR(rds_ps, 0444, bcm2048_rds_ps_read, NULL), + __ATTR(fm_rds_flags, 0444, bcm2048_fm_rds_flags_read, NULL), + __ATTR(region_bottom_frequency, 0444, bcm2048_region_bottom_frequency_read, NULL), - __ATTR(region_top_frequency, S_IRUGO, + __ATTR(region_top_frequency, 0444, bcm2048_region_top_frequency_read, NULL), - __ATTR(fm_carrier_error, S_IRUGO, + __ATTR(fm_carrier_error, 0444, bcm2048_fm_carrier_error_read, NULL), - __ATTR(fm_rssi, S_IRUGO, + __ATTR(fm_rssi, 0444, bcm2048_fm_rssi_read, NULL), - __ATTR(region, S_IRUGO | S_IWUSR, bcm2048_region_read, + __ATTR(region, 0644, bcm2048_region_read, bcm2048_region_write), - __ATTR(rds_data, S_IRUGO, bcm2048_rds_data_read, NULL), + __ATTR(rds_data, 0444, bcm2048_rds_data_read, NULL), }; static int bcm2048_sysfs_unregister_properties(struct bcm2048_device *bdev, -- cgit v1.2.3 From 3194e858c5b84008ead92c0c6ee80f94e1c0606d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Abbadie Date: Wed, 19 Oct 2016 18:47:13 -0200 Subject: [media] Staging: media: radio-bcm2048: Fix indentation Align multiple lines statement with parentheses Signed-off-by: Jean-Baptiste Abbadie Acked-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index 9fc2c13ce0ff..e35ceceb6c7b 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -999,7 +999,7 @@ static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev, timeout = BCM2048_AUTO_SEARCH_TIMEOUT; if (!wait_for_completion_timeout(&bdev->compl, - msecs_to_jiffies(timeout))) + msecs_to_jiffies(timeout))) dev_err(&bdev->client->dev, "IRQ timeout.\n"); if (value) @@ -2204,7 +2204,7 @@ static ssize_t bcm2048_fops_read(struct file *file, char __user *buf, } /* interruptible_sleep_on(&bdev->read_queue); */ if (wait_event_interruptible(bdev->read_queue, - bdev->rds_data_available) < 0) { + bdev->rds_data_available) < 0) { retval = -EINTR; goto done; } -- cgit v1.2.3 From 8be135d052dd88870e1db177a53ac75a4ced04a5 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Abbadie Date: Wed, 19 Oct 2016 18:47:14 -0200 Subject: [media] Staging: media: radio-bcm2048: Remove FSF address from GPL notice Removes the superfluous statement about writing to the FSF in the GPL notice Signed-off-by: Jean-Baptiste Abbadie Acked-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/bcm2048/radio-bcm2048.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c index e35ceceb6c7b..0a9f8589ecfb 100644 --- a/drivers/staging/media/bcm2048/radio-bcm2048.c +++ b/drivers/staging/media/bcm2048/radio-bcm2048.c @@ -17,10 +17,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA */ /* -- cgit v1.2.3 From bfc303e7bef819acf2f83a1805d7dc15b5c8eebf Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Fri, 21 Oct 2016 06:55:32 -0200 Subject: [media] c8sectpfe: Remove clk_disable_unprepare hacks Now that CLK_PROC_STFE is defined as a critical clock in DT, we can remove the commented clk_disable_unprepare from the c8sectpfe driver. This means we now have balanced clk*enable/disable calls in the driver, but on STiH407 family the clock in reality will never actually be disabled. This is due to a HW bug where once the IP has been configured and the SLIM core is running, disabling the clock causes a unrecoverable bus lockup. Signed-off-by: Peter Griffin Acked-by: Patrice Chotard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 42b123ff2953..22fd8b91809a 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -885,8 +885,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) return 0; err_clk_disable: - /* TODO uncomment when upstream has taken a reference on this clk */ - /*clk_disable_unprepare(fei->c8sectpfeclk);*/ + clk_disable_unprepare(fei->c8sectpfeclk); return ret; } @@ -921,11 +920,8 @@ static int c8sectpfe_remove(struct platform_device *pdev) if (readl(fei->io + SYS_OTHER_CLKEN)) writel(0, fei->io + SYS_OTHER_CLKEN); - /* TODO uncomment when upstream has taken a reference on this clk */ - /* if (fei->c8sectpfeclk) clk_disable_unprepare(fei->c8sectpfeclk); - */ return 0; } -- cgit v1.2.3 From 5fa88151ecdbfc9f2092cf1add7966c546b95dfa Mon Sep 17 00:00:00 2001 From: CrazyCat Date: Fri, 21 Oct 2016 17:35:40 -0200 Subject: [media] dvb-usb-cxusb: Geniatech T230 - resync TS FIFO after lock This patch fix streaming issue for Geniatech T230/PT360. Signed-off-by: CrazyCat Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/cxusb.c | 26 ++++++++++++++++++++++++++ drivers/media/usb/dvb-usb/cxusb.h | 5 +++++ 2 files changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index 243403081fa5..9b8771eb31d4 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -369,6 +369,26 @@ static int cxusb_aver_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff) return 0; } +static int cxusb_read_status(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct dvb_usb_adapter *adap = (struct dvb_usb_adapter *)fe->dvb->priv; + struct cxusb_state *state = (struct cxusb_state *)adap->dev->priv; + int ret; + + ret = state->fe_read_status(fe, status); + + /* it need resync slave fifo when signal change from unlock to lock.*/ + if ((*status & FE_HAS_LOCK) && (!state->last_lock)) { + mutex_lock(&state->stream_mutex); + cxusb_streaming_ctrl(adap, 1); + mutex_unlock(&state->stream_mutex); + } + + state->last_lock = (*status & FE_HAS_LOCK) ? 1 : 0; + return ret; +} + static void cxusb_d680_dmb_drain_message(struct dvb_usb_device *d) { int ep = d->props.generic_bulk_ctrl_endpoint; @@ -1372,6 +1392,12 @@ static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap) st->i2c_client_tuner = client_tuner; + /* hook fe: need to resync the slave fifo when signal locks. */ + mutex_init(&st->stream_mutex); + st->last_lock = 0; + st->fe_read_status = adap->fe_adap[0].fe->ops.read_status; + adap->fe_adap[0].fe->ops.read_status = cxusb_read_status; + return 0; } diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index 18acda19527a..66429d7f69b5 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -37,6 +37,11 @@ struct cxusb_state { struct i2c_client *i2c_client_tuner; unsigned char data[MAX_XFER_SIZE]; + + struct mutex stream_mutex; + u8 last_lock; + int (*fe_read_status)(struct dvb_frontend *fe, + enum fe_status *status); }; #endif -- cgit v1.2.3 From 5a91206ff0d0548939f3e85a65fb76b400fb0e89 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Sat, 2 Jul 2016 20:27:46 -0300 Subject: [media] saa7134: fix warm Medion 7134 EEPROM read When saa7134 module driving a Medion 7134 card is reloaded reads of this card EEPROM (required for automatic detection of tuner model) will be corrupted due to I2C gate in DVB-T demod being left closed. This sometimes also happens on first saa7134 module load after a warm reboot. Fix this by opening this I2C gate before doing EEPROM read during i2c initialization. Signed-off-by: Maciej S. Szmigiero Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/saa7134/saa7134-i2c.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'drivers') diff --git a/drivers/media/pci/saa7134/saa7134-i2c.c b/drivers/media/pci/saa7134/saa7134-i2c.c index 2dac48fa1386..dca0592c5f47 100644 --- a/drivers/media/pci/saa7134/saa7134-i2c.c +++ b/drivers/media/pci/saa7134/saa7134-i2c.c @@ -355,12 +355,43 @@ static struct i2c_client saa7134_client_template = { /* ----------------------------------------------------------- */ +/* On Medion 7134 reading EEPROM needs DVB-T demod i2c gate open */ +static void saa7134_i2c_eeprom_md7134_gate(struct saa7134_dev *dev) +{ + u8 subaddr = 0x7, dmdregval; + u8 data[2]; + int ret; + struct i2c_msg i2cgatemsg_r[] = { {.addr = 0x08, .flags = 0, + .buf = &subaddr, .len = 1}, + {.addr = 0x08, + .flags = I2C_M_RD, + .buf = &dmdregval, .len = 1} + }; + struct i2c_msg i2cgatemsg_w[] = { {.addr = 0x08, .flags = 0, + .buf = data, .len = 2} }; + + ret = i2c_transfer(&dev->i2c_adap, i2cgatemsg_r, 2); + if ((ret == 2) && (dmdregval & 0x2)) { + pr_debug("%s: DVB-T demod i2c gate was left closed\n", + dev->name); + + data[0] = subaddr; + data[1] = (dmdregval & ~0x2); + if (i2c_transfer(&dev->i2c_adap, i2cgatemsg_w, 1) != 1) + pr_err("%s: EEPROM i2c gate open failure\n", + dev->name); + } +} + static int saa7134_i2c_eeprom(struct saa7134_dev *dev, unsigned char *eedata, int len) { unsigned char buf; int i,err; + if (dev->board == SAA7134_BOARD_MD7134) + saa7134_i2c_eeprom_md7134_gate(dev); + dev->i2c_client.addr = 0xa0 >> 1; buf = 0; if (1 != (err = i2c_master_send(&dev->i2c_client,&buf,1))) { -- cgit v1.2.3 From 5911f629266d577c7697dd3e9797b2d1e947a40b Mon Sep 17 00:00:00 2001 From: Andi Shyti Date: Wed, 6 Jul 2016 06:01:22 -0300 Subject: [media] lirc_dev: remove compat_ioctl assignment There is no need to check for CONFIG_COMPAT and consequently assign the compat_ioctl. Signed-off-by: Andi Shyti Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 91f9bb87ce68..809a8671e3d6 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -150,9 +150,6 @@ static const struct file_operations lirc_dev_fops = { .write = lirc_dev_fop_write, .poll = lirc_dev_fop_poll, .unlocked_ioctl = lirc_dev_fop_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_dev_fop_ioctl, -#endif .open = lirc_dev_fop_open, .release = lirc_dev_fop_close, .llseek = noop_llseek, -- cgit v1.2.3 From c9205e18b41a6ef5ad73e1c4b86a78b2ea3ccb9b Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 14 Jul 2016 07:18:14 -0300 Subject: [media] blackfin: check devm_pinctrl_get() for errors devm_pinctrl_get() can fail so we should check for that. Fixes: 0a6824bc10de ('[media] v4l2: blackfin: select proper pinctrl state in ppi_set_params if CONFIG_PINCTRL is enabled') Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/blackfin/ppi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/blackfin/ppi.c b/drivers/media/platform/blackfin/ppi.c index cff63e511e6d..b8f3d9fa66e9 100644 --- a/drivers/media/platform/blackfin/ppi.c +++ b/drivers/media/platform/blackfin/ppi.c @@ -214,6 +214,8 @@ static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params) if (params->dlen > 24 || params->dlen <= 0) return -EINVAL; pctrl = devm_pinctrl_get(ppi->dev); + if (IS_ERR(pctrl)) + return PTR_ERR(pctrl); pstate = pinctrl_lookup_state(pctrl, pin_state[(params->dlen + 7) / 8 - 1]); if (pinctrl_select_state(pctrl, pstate)) -- cgit v1.2.3 From b68002db13f57b16b6b9f9841d40b867c298ffe4 Mon Sep 17 00:00:00 2001 From: Peter Chen Date: Fri, 15 Jul 2016 06:33:06 -0300 Subject: [media] media: platform: ti-vpe: call of_node_put on non-null pointer It should call of_node_put on non-null poiner. Cc: Mauro Carvalho Chehab Signed-off-by: Peter Chen Acked-by: Benoit Parrot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/cal.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c index b2d166b2221a..7a058b6e03d0 100644 --- a/drivers/media/platform/ti-vpe/cal.c +++ b/drivers/media/platform/ti-vpe/cal.c @@ -1745,13 +1745,13 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst) } cleanup_exit: - if (!remote_ep) + if (remote_ep) of_node_put(remote_ep); - if (!sensor_node) + if (sensor_node) of_node_put(sensor_node); - if (!ep_node) + if (ep_node) of_node_put(ep_node); - if (!port) + if (port) of_node_put(port); return ret; -- cgit v1.2.3 From c183d3584b1777be55b4c576385143210dc0dbd5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:06 -0300 Subject: [media] rc-main: clear rc_map.name in ir_free_table() rc_unregister_device() will first call ir_free_table(), and later device_del(); however, the latter causes a call to rc_dev_uevent(), which prints rc_map.name, which at this point has already bee freed. This fixes a use-after-free bug found with KASAN. As reported by Shuah: "I am seeing the following when I do rmmod on au0828 BUG: KASAN: use-after-free in string+0x170/0x1f0 at addr ffff8801bd513000 Read of size 1 by task rmmod/1831 CPU: 1 PID: 1831 Comm: rmmod Tainted: G W 4.9.0-rc5 #5 Hardware name: Hewlett-Packard HP ProBook 6475b/180F, BIOS 68TTU Ver. F.04 08/03/2012 ffff8801aea2f680 ffffffff81b37ad3 ffff8801fa403b80 ffff8801bd513000 ffff8801aea2f6a8 ffffffff8156c301 ffff8801aea2f738 ffff8801bd513000 ffff8801fa403b80 ffff8801aea2f728 ffffffff8156c59a ffff8801aea2f770 Call Trace: dump_stack+0x67/0x94 [] kasan_object_err+0x21/0x70 [] kasan_report_error+0x1fa/0x4d0 [] ? au0828_exit+0x10/0x21 [au0828] [] __asan_report_load1_noabort+0x43/0x50 [] ? string+0x170/0x1f0 [] string+0x170/0x1f0 [] vsnprintf+0x374/0x1c50 [] ? pointer+0xa80/0xa80 [] ? save_stack+0x46/0xd0 [] ? __kmalloc+0x14a/0x2a0 [] ? kobject_get_path+0x9a/0x200 [] ? kobject_uevent_env+0x282/0xca0 [] ? kobject_uevent+0xb/0x10 [] ? device_del+0x434/0x6d0 [] ? rc_unregister_device+0x177/0x240 [rc_core] [] ? au0828_rc_unregister+0x60/0xb0 [au0828] The problem is fixed with this patch on Linux 4.9-rc4" Signed-off-by: Max Kellermann Tested-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/rc-main.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c index adb10fac63e4..dedaf38c5ff6 100644 --- a/drivers/media/rc/rc-main.c +++ b/drivers/media/rc/rc-main.c @@ -161,6 +161,7 @@ static void ir_free_table(struct rc_map *rc_map) { rc_map->size = 0; kfree(rc_map->name); + rc_map->name = NULL; kfree(rc_map->scan); rc_map->scan = NULL; } -- cgit v1.2.3 From bd336e63441bcdeeccca6a698087d913a32478c5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:21 -0300 Subject: [media] dvb: make DVB frontend *_ops instances "const" These are immutable. Making them "const" allows the compiler to move them to the "rodata" section. Note that cxd2841er_t_c_ops cannot be made "const", because cxd2841er_attach() modifies it. Ouch! [mchehab@s-opensource.com: fix merge conflicts] Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/siano/smsdvb-main.c | 2 +- drivers/media/dvb-frontends/af9013.c | 4 ++-- drivers/media/dvb-frontends/af9033.c | 2 +- drivers/media/dvb-frontends/as102_fe.c | 2 +- drivers/media/dvb-frontends/atbm8830.c | 2 +- drivers/media/dvb-frontends/au8522_dig.c | 4 ++-- drivers/media/dvb-frontends/bcm3510.c | 4 ++-- drivers/media/dvb-frontends/cx22700.c | 4 ++-- drivers/media/dvb-frontends/cx24110.c | 4 ++-- drivers/media/dvb-frontends/cx24116.c | 4 ++-- drivers/media/dvb-frontends/cx24117.c | 4 ++-- drivers/media/dvb-frontends/cx24120.c | 4 ++-- drivers/media/dvb-frontends/cx24123.c | 4 ++-- drivers/media/dvb-frontends/cxd2841er.c | 6 +++--- drivers/media/dvb-frontends/dib3000mb.c | 4 ++-- drivers/media/dvb-frontends/dib3000mc.c | 4 ++-- drivers/media/dvb-frontends/dib7000m.c | 4 ++-- drivers/media/dvb-frontends/dib7000p.c | 4 ++-- drivers/media/dvb-frontends/dib9000.c | 4 ++-- drivers/media/dvb-frontends/drx39xyj/drxj.c | 4 ++-- drivers/media/dvb-frontends/drxd_hard.c | 2 +- drivers/media/dvb-frontends/drxk_hard.c | 2 +- drivers/media/dvb-frontends/ds3000.c | 4 ++-- drivers/media/dvb-frontends/dvb_dummy_fe.c | 12 ++++++------ drivers/media/dvb-frontends/ec100.c | 4 ++-- drivers/media/dvb-frontends/gp8psk-fe.c | 4 ++-- drivers/media/dvb-frontends/hd29l2.c | 4 ++-- drivers/media/dvb-frontends/l64781.c | 4 ++-- drivers/media/dvb-frontends/lg2160.c | 4 ++-- drivers/media/dvb-frontends/lgdt3305.c | 8 ++++---- drivers/media/dvb-frontends/lgdt3306a.c | 4 ++-- drivers/media/dvb-frontends/lgdt330x.c | 8 ++++---- drivers/media/dvb-frontends/lgs8gl5.c | 4 ++-- drivers/media/dvb-frontends/lgs8gxx.c | 2 +- drivers/media/dvb-frontends/m88ds3103.c | 4 ++-- drivers/media/dvb-frontends/m88rs2000.c | 2 +- drivers/media/dvb-frontends/mb86a16.c | 2 +- drivers/media/dvb-frontends/mb86a20s.c | 4 ++-- drivers/media/dvb-frontends/mn88472.c | 2 +- drivers/media/dvb-frontends/mt312.c | 2 +- drivers/media/dvb-frontends/mt352.c | 4 ++-- drivers/media/dvb-frontends/nxt200x.c | 4 ++-- drivers/media/dvb-frontends/nxt6000.c | 4 ++-- drivers/media/dvb-frontends/or51132.c | 4 ++-- drivers/media/dvb-frontends/or51211.c | 4 ++-- drivers/media/dvb-frontends/rtl2830.c | 2 +- drivers/media/dvb-frontends/rtl2832.c | 2 +- drivers/media/dvb-frontends/s5h1409.c | 4 ++-- drivers/media/dvb-frontends/s5h1411.c | 4 ++-- drivers/media/dvb-frontends/s5h1420.c | 4 ++-- drivers/media/dvb-frontends/s5h1432.c | 4 ++-- drivers/media/dvb-frontends/s921.c | 4 ++-- drivers/media/dvb-frontends/si2165.c | 2 +- drivers/media/dvb-frontends/si21xx.c | 2 +- drivers/media/dvb-frontends/sp8870.c | 4 ++-- drivers/media/dvb-frontends/sp887x.c | 4 ++-- drivers/media/dvb-frontends/stb0899_drv.c | 2 +- drivers/media/dvb-frontends/stv0288.c | 2 +- drivers/media/dvb-frontends/stv0297.c | 4 ++-- drivers/media/dvb-frontends/stv0299.c | 4 ++-- drivers/media/dvb-frontends/stv0367.c | 4 ++-- drivers/media/dvb-frontends/stv0900_core.c | 2 +- drivers/media/dvb-frontends/stv090x.c | 2 +- drivers/media/dvb-frontends/tda10021.c | 4 ++-- drivers/media/dvb-frontends/tda10023.c | 4 ++-- drivers/media/dvb-frontends/tda10048.c | 4 ++-- drivers/media/dvb-frontends/tda1004x.c | 4 ++-- drivers/media/dvb-frontends/tda10071.c | 4 ++-- drivers/media/dvb-frontends/tda10086.c | 2 +- drivers/media/dvb-frontends/tda8083.c | 4 ++-- drivers/media/dvb-frontends/ves1820.c | 4 ++-- drivers/media/dvb-frontends/ves1x93.c | 4 ++-- drivers/media/dvb-frontends/zl10353.c | 4 ++-- drivers/media/pci/bt8xx/dst.c | 16 ++++++++-------- drivers/media/pci/pt1/va1j5jf8007s.c | 2 +- drivers/media/pci/pt1/va1j5jf8007t.c | 2 +- drivers/media/tuners/tda8290.c | 4 ++-- drivers/media/tuners/tda9887.c | 2 +- drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c | 2 +- drivers/media/usb/dvb-usb/af9005-fe.c | 4 ++-- drivers/media/usb/dvb-usb/cinergyT2-fe.c | 4 ++-- drivers/media/usb/dvb-usb/dtt200u-fe.c | 4 ++-- drivers/media/usb/dvb-usb/friio-fe.c | 4 ++-- drivers/media/usb/dvb-usb/vp702x-fe.c | 4 ++-- drivers/media/usb/dvb-usb/vp7045-fe.c | 4 ++-- drivers/media/usb/ttusb-dec/ttusbdecfe.c | 8 ++++---- 86 files changed, 165 insertions(+), 165 deletions(-) (limited to 'drivers') diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c index 9148e14c9d07..affde1426b7a 100644 --- a/drivers/media/common/siano/smsdvb-main.c +++ b/drivers/media/common/siano/smsdvb-main.c @@ -1044,7 +1044,7 @@ static void smsdvb_release(struct dvb_frontend *fe) /* do nothing */ } -static struct dvb_frontend_ops smsdvb_fe_ops = { +static const struct dvb_frontend_ops smsdvb_fe_ops = { .info = { .name = "Siano Mobile Digital MDTV Receiver", .frequency_min = 44250000, diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index 8bcde336ffd7..c6cb3bbc912a 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -1351,7 +1351,7 @@ static void af9013_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops af9013_ops; +static const struct dvb_frontend_ops af9013_ops; static int af9013_download_firmware(struct af9013_state *state) { @@ -1516,7 +1516,7 @@ err: } EXPORT_SYMBOL(af9013_attach); -static struct dvb_frontend_ops af9013_ops = { +static const struct dvb_frontend_ops af9013_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Afatech AF9013", diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index 9a8157a5f49d..f8818028752e 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -1198,7 +1198,7 @@ err: return ret; } -static struct dvb_frontend_ops af9033_ops = { +static const struct dvb_frontend_ops af9033_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Afatech AF9033 (DVB-T)", diff --git a/drivers/media/dvb-frontends/as102_fe.c b/drivers/media/dvb-frontends/as102_fe.c index 9412fcd1bddb..98d575f2744c 100644 --- a/drivers/media/dvb-frontends/as102_fe.c +++ b/drivers/media/dvb-frontends/as102_fe.c @@ -415,7 +415,7 @@ static void as102_fe_release(struct dvb_frontend *fe) } -static struct dvb_frontend_ops as102_fe_ops = { +static const struct dvb_frontend_ops as102_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Abilis AS102 DVB-T", diff --git a/drivers/media/dvb-frontends/atbm8830.c b/drivers/media/dvb-frontends/atbm8830.c index 47248b868e38..07ce05578278 100644 --- a/drivers/media/dvb-frontends/atbm8830.c +++ b/drivers/media/dvb-frontends/atbm8830.c @@ -428,7 +428,7 @@ static int atbm8830_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return atbm8830_write_reg(priv, REG_I2C_GATE, enable ? 1 : 0); } -static struct dvb_frontend_ops atbm8830_ops = { +static const struct dvb_frontend_ops atbm8830_ops = { .delsys = { SYS_DTMB }, .info = { .name = "AltoBeam ATBM8830/8831 DMB-TH", diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c index e676b9461a59..7ed326e43fc4 100644 --- a/drivers/media/dvb-frontends/au8522_dig.c +++ b/drivers/media/dvb-frontends/au8522_dig.c @@ -834,7 +834,7 @@ static int au8522_get_tune_settings(struct dvb_frontend *fe, return 0; } -static struct dvb_frontend_ops au8522_ops; +static const struct dvb_frontend_ops au8522_ops; static void au8522_release(struct dvb_frontend *fe) @@ -894,7 +894,7 @@ error: } EXPORT_SYMBOL(au8522_attach); -static struct dvb_frontend_ops au8522_ops = { +static const struct dvb_frontend_ops au8522_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Auvitek AU8522 QAM/8VSB Frontend", diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index bb698839e477..617c5e29f919 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -788,7 +788,7 @@ static int bcm3510_init(struct dvb_frontend* fe) } -static struct dvb_frontend_ops bcm3510_ops; +static const struct dvb_frontend_ops bcm3510_ops; struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, struct i2c_adapter *i2c) @@ -834,7 +834,7 @@ error: } EXPORT_SYMBOL(bcm3510_attach); -static struct dvb_frontend_ops bcm3510_ops = { +static const struct dvb_frontend_ops bcm3510_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Broadcom BCM3510 VSB/QAM frontend", diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c index 5cad925609e0..2b629e23ceeb 100644 --- a/drivers/media/dvb-frontends/cx22700.c +++ b/drivers/media/dvb-frontends/cx22700.c @@ -380,7 +380,7 @@ static void cx22700_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops cx22700_ops; +static const struct dvb_frontend_ops cx22700_ops; struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, struct i2c_adapter* i2c) @@ -408,7 +408,7 @@ error: return NULL; } -static struct dvb_frontend_ops cx22700_ops = { +static const struct dvb_frontend_ops cx22700_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Conexant CX22700 DVB-T", diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c index 92a08c7bf794..cf1bc99d1f32 100644 --- a/drivers/media/dvb-frontends/cx24110.c +++ b/drivers/media/dvb-frontends/cx24110.c @@ -592,7 +592,7 @@ static void cx24110_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops cx24110_ops; +static const struct dvb_frontend_ops cx24110_ops; struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, struct i2c_adapter* i2c) @@ -625,7 +625,7 @@ error: return NULL; } -static struct dvb_frontend_ops cx24110_ops = { +static const struct dvb_frontend_ops cx24110_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Conexant CX24110 DVB-S", diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c index ae5a7f9f5a72..e105532bfba8 100644 --- a/drivers/media/dvb-frontends/cx24116.c +++ b/drivers/media/dvb-frontends/cx24116.c @@ -1116,7 +1116,7 @@ static void cx24116_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops cx24116_ops; +static const struct dvb_frontend_ops cx24116_ops; struct dvb_frontend *cx24116_attach(const struct cx24116_config *config, struct i2c_adapter *i2c) @@ -1467,7 +1467,7 @@ static int cx24116_get_algo(struct dvb_frontend *fe) return DVBFE_ALGO_HW; } -static struct dvb_frontend_ops cx24116_ops = { +static const struct dvb_frontend_ops cx24116_ops = { .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "Conexant CX24116/CX24118", diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c index bc3cd698303f..d37cb7762bd6 100644 --- a/drivers/media/dvb-frontends/cx24117.c +++ b/drivers/media/dvb-frontends/cx24117.c @@ -1164,7 +1164,7 @@ static void cx24117_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops cx24117_ops; +static const struct dvb_frontend_ops cx24117_ops; struct dvb_frontend *cx24117_attach(const struct cx24117_config *config, struct i2c_adapter *i2c) @@ -1618,7 +1618,7 @@ static int cx24117_get_frontend(struct dvb_frontend *fe, return 0; } -static struct dvb_frontend_ops cx24117_ops = { +static const struct dvb_frontend_ops cx24117_ops = { .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "Conexant CX24117/CX24132", diff --git a/drivers/media/dvb-frontends/cx24120.c b/drivers/media/dvb-frontends/cx24120.c index 3112a3206d46..7f11dcc94d85 100644 --- a/drivers/media/dvb-frontends/cx24120.c +++ b/drivers/media/dvb-frontends/cx24120.c @@ -267,7 +267,7 @@ out: return ret; } -static struct dvb_frontend_ops cx24120_ops; +static const struct dvb_frontend_ops cx24120_ops; struct dvb_frontend *cx24120_attach(const struct cx24120_config *config, struct i2c_adapter *i2c) @@ -1551,7 +1551,7 @@ static int cx24120_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) return 0; } -static struct dvb_frontend_ops cx24120_ops = { +static const struct dvb_frontend_ops cx24120_ops = { .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "Conexant CX24120/CX24118", diff --git a/drivers/media/dvb-frontends/cx24123.c b/drivers/media/dvb-frontends/cx24123.c index b1287de98e86..8aed8cc9f93d 100644 --- a/drivers/media/dvb-frontends/cx24123.c +++ b/drivers/media/dvb-frontends/cx24123.c @@ -1049,7 +1049,7 @@ struct i2c_adapter * } EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter); -static struct dvb_frontend_ops cx24123_ops; +static const struct dvb_frontend_ops cx24123_ops; struct dvb_frontend *cx24123_attach(const struct cx24123_config *config, struct i2c_adapter *i2c) @@ -1111,7 +1111,7 @@ error: } EXPORT_SYMBOL(cx24123_attach); -static struct dvb_frontend_ops cx24123_ops = { +static const struct dvb_frontend_ops cx24123_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Conexant CX24123/CX24109", diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c index 5afb9c508f65..614bfb3740f1 100644 --- a/drivers/media/dvb-frontends/cxd2841er.c +++ b/drivers/media/dvb-frontends/cxd2841er.c @@ -3719,7 +3719,7 @@ static int cxd2841er_init_tc(struct dvb_frontend *fe) return 0; } -static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops; +static const struct dvb_frontend_ops cxd2841er_dvbs_s2_ops; static struct dvb_frontend_ops cxd2841er_t_c_ops; static struct dvb_frontend *cxd2841er_attach(struct cxd2841er_config *cfg, @@ -3801,7 +3801,7 @@ struct dvb_frontend *cxd2841er_attach_t_c(struct cxd2841er_config *cfg, } EXPORT_SYMBOL(cxd2841er_attach_t_c); -static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { +static const struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "Sony CXD2841ER DVB-S/S2 demodulator", @@ -3829,7 +3829,7 @@ static struct dvb_frontend_ops cxd2841er_dvbs_s2_ops = { .tune = cxd2841er_tune_s }; -static struct dvb_frontend_ops cxd2841er_t_c_ops = { +static struct dvb_frontend_ops cxd2841er_t_c_ops = { .delsys = { SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A }, .info = { .name = "", /* will set in attach function */ diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c index bf9762783be4..068bec104e29 100644 --- a/drivers/media/dvb-frontends/dib3000mb.c +++ b/drivers/media/dvb-frontends/dib3000mb.c @@ -742,7 +742,7 @@ static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_ return 0; } -static struct dvb_frontend_ops dib3000mb_ops; +static const struct dvb_frontend_ops dib3000mb_ops; struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, struct i2c_adapter* i2c, struct dib_fe_xfer_ops *xfer_ops) @@ -782,7 +782,7 @@ error: return NULL; } -static struct dvb_frontend_ops dib3000mb_ops = { +static const struct dvb_frontend_ops dib3000mb_ops = { .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 3000M-B DVB-T", diff --git a/drivers/media/dvb-frontends/dib3000mc.c b/drivers/media/dvb-frontends/dib3000mc.c index 0f7793455da7..224283fe100a 100644 --- a/drivers/media/dvb-frontends/dib3000mc.c +++ b/drivers/media/dvb-frontends/dib3000mc.c @@ -879,7 +879,7 @@ int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defa } EXPORT_SYMBOL(dib3000mc_i2c_enumeration); -static struct dvb_frontend_ops dib3000mc_ops; +static const struct dvb_frontend_ops dib3000mc_ops; struct dvb_frontend * dib3000mc_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib3000mc_config *cfg) { @@ -912,7 +912,7 @@ error: } EXPORT_SYMBOL(dib3000mc_attach); -static struct dvb_frontend_ops dib3000mc_ops = { +static const struct dvb_frontend_ops dib3000mc_ops = { .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 3000MC/P", diff --git a/drivers/media/dvb-frontends/dib7000m.c b/drivers/media/dvb-frontends/dib7000m.c index c9ebb0ff746a..5ce9f93a65c3 100644 --- a/drivers/media/dvb-frontends/dib7000m.c +++ b/drivers/media/dvb-frontends/dib7000m.c @@ -1401,7 +1401,7 @@ int dib7000m_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, EXPORT_SYMBOL(dib7000m_i2c_enumeration); #endif -static struct dvb_frontend_ops dib7000m_ops; +static const struct dvb_frontend_ops dib7000m_ops; struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000m_config *cfg) { struct dvb_frontend *demod; @@ -1439,7 +1439,7 @@ error: } EXPORT_SYMBOL(dib7000m_attach); -static struct dvb_frontend_ops dib7000m_ops = { +static const struct dvb_frontend_ops dib7000m_ops = { .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 7000MA/MB/PA/PB/MC", diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c index 2cee51c08a5a..a27c0001f2d6 100644 --- a/drivers/media/dvb-frontends/dib7000p.c +++ b/drivers/media/dvb-frontends/dib7000p.c @@ -2721,7 +2721,7 @@ static int dib7090_slave_reset(struct dvb_frontend *fe) return 0; } -static struct dvb_frontend_ops dib7000p_ops; +static const struct dvb_frontend_ops dib7000p_ops; static struct dvb_frontend *dib7000p_init(struct i2c_adapter *i2c_adap, u8 i2c_addr, struct dib7000p_config *cfg) { struct dvb_frontend *demod; @@ -2811,7 +2811,7 @@ void *dib7000p_attach(struct dib7000p_ops *ops) } EXPORT_SYMBOL(dib7000p_attach); -static struct dvb_frontend_ops dib7000p_ops = { +static const struct dvb_frontend_ops dib7000p_ops = { .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 7000PC", diff --git a/drivers/media/dvb-frontends/dib9000.c b/drivers/media/dvb-frontends/dib9000.c index 3c76ceb6c374..c95fff4f9582 100644 --- a/drivers/media/dvb-frontends/dib9000.c +++ b/drivers/media/dvb-frontends/dib9000.c @@ -2490,7 +2490,7 @@ struct dvb_frontend *dib9000_get_slave_frontend(struct dvb_frontend *fe, int sla } EXPORT_SYMBOL(dib9000_get_slave_frontend); -static struct dvb_frontend_ops dib9000_ops; +static const struct dvb_frontend_ops dib9000_ops; struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, const struct dib9000_config *cfg) { struct dvb_frontend *fe; @@ -2567,7 +2567,7 @@ error: } EXPORT_SYMBOL(dib9000_attach); -static struct dvb_frontend_ops dib9000_ops = { +static const struct dvb_frontend_ops dib9000_ops = { .delsys = { SYS_DVBT }, .info = { .name = "DiBcom 9000", diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c index bd6d2ee0f7c9..f1c3e3b09b65 100644 --- a/drivers/media/dvb-frontends/drx39xyj/drxj.c +++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c @@ -12264,7 +12264,7 @@ static void drx39xxj_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops drx39xxj_ops; +static const struct dvb_frontend_ops drx39xxj_ops; struct dvb_frontend *drx39xxj_attach(struct i2c_adapter *i2c) { @@ -12363,7 +12363,7 @@ error: } EXPORT_SYMBOL(drx39xxj_attach); -static struct dvb_frontend_ops drx39xxj_ops = { +static const struct dvb_frontend_ops drx39xxj_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Micronas DRX39xxj family Frontend", diff --git a/drivers/media/dvb-frontends/drxd_hard.c b/drivers/media/dvb-frontends/drxd_hard.c index 445a15c2714f..4143f0326684 100644 --- a/drivers/media/dvb-frontends/drxd_hard.c +++ b/drivers/media/dvb-frontends/drxd_hard.c @@ -2912,7 +2912,7 @@ static void drxd_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops drxd_ops = { +static const struct dvb_frontend_ops drxd_ops = { .delsys = { SYS_DVBT}, .info = { .name = "Micronas DRXD DVB-T", diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c index c595adc61c6f..146edf344dd8 100644 --- a/drivers/media/dvb-frontends/drxk_hard.c +++ b/drivers/media/dvb-frontends/drxk_hard.c @@ -6737,7 +6737,7 @@ static int drxk_get_tune_settings(struct dvb_frontend *fe, } } -static struct dvb_frontend_ops drxk_ops = { +static const struct dvb_frontend_ops drxk_ops = { /* .delsys will be filled dynamically */ .info = { .name = "DRXK", diff --git a/drivers/media/dvb-frontends/ds3000.c b/drivers/media/dvb-frontends/ds3000.c index 6dc79d4528c2..0b17a45c5640 100644 --- a/drivers/media/dvb-frontends/ds3000.c +++ b/drivers/media/dvb-frontends/ds3000.c @@ -830,7 +830,7 @@ static void ds3000_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops ds3000_ops; +static const struct dvb_frontend_ops ds3000_ops; struct dvb_frontend *ds3000_attach(const struct ds3000_config *config, struct i2c_adapter *i2c) @@ -1104,7 +1104,7 @@ static int ds3000_initfe(struct dvb_frontend *fe) return 0; } -static struct dvb_frontend_ops ds3000_ops = { +static const struct dvb_frontend_ops ds3000_ops = { .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "Montage Technology DS3000", diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c index e5bd8c62ad3a..efc3c31a7635 100644 --- a/drivers/media/dvb-frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c @@ -119,7 +119,7 @@ static void dvb_dummy_fe_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; +static const struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops; struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) { @@ -136,7 +136,7 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) return &state->frontend; } -static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; +static const struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops; struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) { @@ -153,7 +153,7 @@ struct dvb_frontend *dvb_dummy_fe_qpsk_attach(void) return &state->frontend; } -static struct dvb_frontend_ops dvb_dummy_fe_qam_ops; +static const struct dvb_frontend_ops dvb_dummy_fe_qam_ops; struct dvb_frontend *dvb_dummy_fe_qam_attach(void) { @@ -170,7 +170,7 @@ struct dvb_frontend *dvb_dummy_fe_qam_attach(void) return &state->frontend; } -static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { +static const struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Dummy DVB-T", @@ -201,7 +201,7 @@ static struct dvb_frontend_ops dvb_dummy_fe_ofdm_ops = { .read_ucblocks = dvb_dummy_fe_read_ucblocks, }; -static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { +static const struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "Dummy DVB-C", @@ -230,7 +230,7 @@ static struct dvb_frontend_ops dvb_dummy_fe_qam_ops = { .read_ucblocks = dvb_dummy_fe_read_ucblocks, }; -static struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { +static const struct dvb_frontend_ops dvb_dummy_fe_qpsk_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Dummy DVB-S", diff --git a/drivers/media/dvb-frontends/ec100.c b/drivers/media/dvb-frontends/ec100.c index c9012e677cd1..d97ce21e26e1 100644 --- a/drivers/media/dvb-frontends/ec100.c +++ b/drivers/media/dvb-frontends/ec100.c @@ -280,7 +280,7 @@ static void ec100_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops ec100_ops; +static const struct dvb_frontend_ops ec100_ops; struct dvb_frontend *ec100_attach(const struct ec100_config *config, struct i2c_adapter *i2c) @@ -315,7 +315,7 @@ error: } EXPORT_SYMBOL(ec100_attach); -static struct dvb_frontend_ops ec100_ops = { +static const struct dvb_frontend_ops ec100_ops = { .delsys = { SYS_DVBT }, .info = { .name = "E3C EC100 DVB-T", diff --git a/drivers/media/dvb-frontends/gp8psk-fe.c b/drivers/media/dvb-frontends/gp8psk-fe.c index 93f59bfea092..efe015df7f1d 100644 --- a/drivers/media/dvb-frontends/gp8psk-fe.c +++ b/drivers/media/dvb-frontends/gp8psk-fe.c @@ -323,7 +323,7 @@ static void gp8psk_fe_release(struct dvb_frontend* fe) kfree(st); } -static struct dvb_frontend_ops gp8psk_fe_ops; +static const struct dvb_frontend_ops gp8psk_fe_ops; struct dvb_frontend *gp8psk_fe_attach(const struct gp8psk_fe_ops *ops, void *priv, bool is_rev1) @@ -351,7 +351,7 @@ struct dvb_frontend *gp8psk_fe_attach(const struct gp8psk_fe_ops *ops, } EXPORT_SYMBOL_GPL(gp8psk_fe_attach); -static struct dvb_frontend_ops gp8psk_fe_ops = { +static const struct dvb_frontend_ops gp8psk_fe_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Genpix DVB-S", diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c index 1c7eb477e2cd..8b53633cf325 100644 --- a/drivers/media/dvb-frontends/hd29l2.c +++ b/drivers/media/dvb-frontends/hd29l2.c @@ -793,7 +793,7 @@ static void hd29l2_release(struct dvb_frontend *fe) kfree(priv); } -static struct dvb_frontend_ops hd29l2_ops; +static const struct dvb_frontend_ops hd29l2_ops; struct dvb_frontend *hd29l2_attach(const struct hd29l2_config *config, struct i2c_adapter *i2c) @@ -828,7 +828,7 @@ err: } EXPORT_SYMBOL(hd29l2_attach); -static struct dvb_frontend_ops hd29l2_ops = { +static const struct dvb_frontend_ops hd29l2_ops = { .delsys = { SYS_DVBT }, .info = { .name = "HDIC HD29L2 DMB-TH", diff --git a/drivers/media/dvb-frontends/l64781.c b/drivers/media/dvb-frontends/l64781.c index 2f3d0519e19b..68923c84679a 100644 --- a/drivers/media/dvb-frontends/l64781.c +++ b/drivers/media/dvb-frontends/l64781.c @@ -496,7 +496,7 @@ static void l64781_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops l64781_ops; +static const struct dvb_frontend_ops l64781_ops; struct dvb_frontend* l64781_attach(const struct l64781_config* config, struct i2c_adapter* i2c) @@ -571,7 +571,7 @@ error: return NULL; } -static struct dvb_frontend_ops l64781_ops = { +static const struct dvb_frontend_ops l64781_ops = { .delsys = { SYS_DVBT }, .info = { .name = "LSI L64781 DVB-T", diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c index f51a3a0b3949..3b31e5f20f46 100644 --- a/drivers/media/dvb-frontends/lg2160.c +++ b/drivers/media/dvb-frontends/lg2160.c @@ -1359,7 +1359,7 @@ static void lg216x_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops lg2160_ops = { +static const struct dvb_frontend_ops lg2160_ops = { .delsys = { SYS_ATSCMH }, .info = { .name = "LG Electronics LG2160 ATSC/MH Frontend", @@ -1387,7 +1387,7 @@ static struct dvb_frontend_ops lg2160_ops = { .release = lg216x_release, }; -static struct dvb_frontend_ops lg2161_ops = { +static const struct dvb_frontend_ops lg2161_ops = { .delsys = { SYS_ATSCMH }, .info = { .name = "LG Electronics LG2161 ATSC/MH Frontend", diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c index 4503e8852fd1..9f5d9380bf5f 100644 --- a/drivers/media/dvb-frontends/lgdt3305.c +++ b/drivers/media/dvb-frontends/lgdt3305.c @@ -1103,8 +1103,8 @@ static void lgdt3305_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops lgdt3304_ops; -static struct dvb_frontend_ops lgdt3305_ops; +static const struct dvb_frontend_ops lgdt3304_ops; +static const struct dvb_frontend_ops lgdt3305_ops; struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config, struct i2c_adapter *i2c_adap) @@ -1164,7 +1164,7 @@ fail: } EXPORT_SYMBOL(lgdt3305_attach); -static struct dvb_frontend_ops lgdt3304_ops = { +static const struct dvb_frontend_ops lgdt3304_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "LG Electronics LGDT3304 VSB/QAM Frontend", @@ -1187,7 +1187,7 @@ static struct dvb_frontend_ops lgdt3304_ops = { .release = lgdt3305_release, }; -static struct dvb_frontend_ops lgdt3305_ops = { +static const struct dvb_frontend_ops lgdt3305_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "LG Electronics LGDT3305 VSB/QAM Frontend", diff --git a/drivers/media/dvb-frontends/lgdt3306a.c b/drivers/media/dvb-frontends/lgdt3306a.c index 0ca4e810e9d8..19dca46b1171 100644 --- a/drivers/media/dvb-frontends/lgdt3306a.c +++ b/drivers/media/dvb-frontends/lgdt3306a.c @@ -1767,7 +1767,7 @@ static void lgdt3306a_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops lgdt3306a_ops; +static const struct dvb_frontend_ops lgdt3306a_ops; struct dvb_frontend *lgdt3306a_attach(const struct lgdt3306a_config *config, struct i2c_adapter *i2c_adap) @@ -2103,7 +2103,7 @@ static void lgdt3306a_DumpRegs(struct lgdt3306a_state *state) -static struct dvb_frontend_ops lgdt3306a_ops = { +static const struct dvb_frontend_ops lgdt3306a_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "LG Electronics LGDT3306A VSB/QAM Frontend", diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c index 8cb6c56d220a..2f4a0316f89c 100644 --- a/drivers/media/dvb-frontends/lgdt330x.c +++ b/drivers/media/dvb-frontends/lgdt330x.c @@ -728,8 +728,8 @@ static void lgdt330x_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops lgdt3302_ops; -static struct dvb_frontend_ops lgdt3303_ops; +static const struct dvb_frontend_ops lgdt3302_ops; +static const struct dvb_frontend_ops lgdt3303_ops; struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, struct i2c_adapter* i2c) @@ -774,7 +774,7 @@ error: return NULL; } -static struct dvb_frontend_ops lgdt3302_ops = { +static const struct dvb_frontend_ops lgdt3302_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name= "LG Electronics LGDT3302 VSB/QAM Frontend", @@ -797,7 +797,7 @@ static struct dvb_frontend_ops lgdt3302_ops = { .release = lgdt330x_release, }; -static struct dvb_frontend_ops lgdt3303_ops = { +static const struct dvb_frontend_ops lgdt3303_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name= "LG Electronics LGDT3303 VSB/QAM Frontend", diff --git a/drivers/media/dvb-frontends/lgs8gl5.c b/drivers/media/dvb-frontends/lgs8gl5.c index fbfd87b5b803..970e42fdbc1b 100644 --- a/drivers/media/dvb-frontends/lgs8gl5.c +++ b/drivers/media/dvb-frontends/lgs8gl5.c @@ -376,7 +376,7 @@ lgs8gl5_release(struct dvb_frontend *fe) } -static struct dvb_frontend_ops lgs8gl5_ops; +static const struct dvb_frontend_ops lgs8gl5_ops; struct dvb_frontend* @@ -412,7 +412,7 @@ error: EXPORT_SYMBOL(lgs8gl5_attach); -static struct dvb_frontend_ops lgs8gl5_ops = { +static const struct dvb_frontend_ops lgs8gl5_ops = { .delsys = { SYS_DTMB }, .info = { .name = "Legend Silicon LGS-8GL5 DMB-TH", diff --git a/drivers/media/dvb-frontends/lgs8gxx.c b/drivers/media/dvb-frontends/lgs8gxx.c index 919daeb96747..6d2e62469d58 100644 --- a/drivers/media/dvb-frontends/lgs8gxx.c +++ b/drivers/media/dvb-frontends/lgs8gxx.c @@ -985,7 +985,7 @@ static int lgs8gxx_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) return lgs8gxx_write_reg(priv, 0x01, 0); } -static struct dvb_frontend_ops lgs8gxx_ops = { +static const struct dvb_frontend_ops lgs8gxx_ops = { .delsys = { SYS_DTMB }, .info = { .name = "Legend Silicon LGS8913/LGS8GXX DMB-TH", diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c index e0fe5bc9dbce..50bce68ffd66 100644 --- a/drivers/media/dvb-frontends/m88ds3103.c +++ b/drivers/media/dvb-frontends/m88ds3103.c @@ -16,7 +16,7 @@ #include "m88ds3103_priv.h" -static struct dvb_frontend_ops m88ds3103_ops; +static const struct dvb_frontend_ops m88ds3103_ops; /* write single register with mask */ static int m88ds3103_update_bits(struct m88ds3103_dev *dev, @@ -1295,7 +1295,7 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg, } EXPORT_SYMBOL(m88ds3103_attach); -static struct dvb_frontend_ops m88ds3103_ops = { +static const struct dvb_frontend_ops m88ds3103_ops = { .delsys = {SYS_DVBS, SYS_DVBS2}, .info = { .name = "Montage Technology M88DS3103", diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c index 3669c906ba01..ce6c21d405ee 100644 --- a/drivers/media/dvb-frontends/m88rs2000.c +++ b/drivers/media/dvb-frontends/m88rs2000.c @@ -752,7 +752,7 @@ static void m88rs2000_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops m88rs2000_ops = { +static const struct dvb_frontend_ops m88rs2000_ops = { .delsys = { SYS_DVBS }, .info = { .name = "M88RS2000 DVB-S", diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c index 79bc671e8769..9bb122c39c1b 100644 --- a/drivers/media/dvb-frontends/mb86a16.c +++ b/drivers/media/dvb-frontends/mb86a16.c @@ -1816,7 +1816,7 @@ static enum dvbfe_algo mb86a16_frontend_algo(struct dvb_frontend *fe) return DVBFE_ALGO_CUSTOM; } -static struct dvb_frontend_ops mb86a16_ops = { +static const struct dvb_frontend_ops mb86a16_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Fujitsu MB86A16 DVB-S", diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 27f425137ce6..e8ac8c3e2ec0 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -2060,7 +2060,7 @@ static int mb86a20s_get_frontend_algo(struct dvb_frontend *fe) return DVBFE_ALGO_HW; } -static struct dvb_frontend_ops mb86a20s_ops; +static const struct dvb_frontend_ops mb86a20s_ops; struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config, struct i2c_adapter *i2c) @@ -2108,7 +2108,7 @@ error: } EXPORT_SYMBOL(mb86a20s_attach); -static struct dvb_frontend_ops mb86a20s_ops = { +static const struct dvb_frontend_ops mb86a20s_ops = { .delsys = { SYS_ISDBT }, /* Use dib8000 values per default */ .info = { diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index 18fb2df1e2bd..b6f5f8337cfd 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c @@ -411,7 +411,7 @@ err: return ret; } -static struct dvb_frontend_ops mn88472_ops = { +static const struct dvb_frontend_ops mn88472_ops = { .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A}, .info = { .name = "Panasonic MN88472", diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index fdee75b1b99a..961b9a2508e0 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -748,7 +748,7 @@ static void mt312_release(struct dvb_frontend *fe) } #define MT312_SYS_CLK 90000000UL /* 90 MHz */ -static struct dvb_frontend_ops mt312_ops = { +static const struct dvb_frontend_ops mt312_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Zarlink ???? DVB-S", diff --git a/drivers/media/dvb-frontends/mt352.c b/drivers/media/dvb-frontends/mt352.c index c0bb6328956b..48ea0408f02a 100644 --- a/drivers/media/dvb-frontends/mt352.c +++ b/drivers/media/dvb-frontends/mt352.c @@ -538,7 +538,7 @@ static void mt352_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops mt352_ops; +static const struct dvb_frontend_ops mt352_ops; struct dvb_frontend* mt352_attach(const struct mt352_config* config, struct i2c_adapter* i2c) @@ -566,7 +566,7 @@ error: return NULL; } -static struct dvb_frontend_ops mt352_ops = { +static const struct dvb_frontend_ops mt352_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Zarlink MT352 DVB-T", diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c index 7c23f0499f23..2fe40372ca07 100644 --- a/drivers/media/dvb-frontends/nxt200x.c +++ b/drivers/media/dvb-frontends/nxt200x.c @@ -1149,7 +1149,7 @@ static void nxt200x_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops nxt200x_ops; +static const struct dvb_frontend_ops nxt200x_ops; struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, struct i2c_adapter* i2c) @@ -1212,7 +1212,7 @@ error: return NULL; } -static struct dvb_frontend_ops nxt200x_ops = { +static const struct dvb_frontend_ops nxt200x_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Nextwave NXT200X VSB/QAM frontend", diff --git a/drivers/media/dvb-frontends/nxt6000.c b/drivers/media/dvb-frontends/nxt6000.c index 1545d898b125..1ce5ea28489b 100644 --- a/drivers/media/dvb-frontends/nxt6000.c +++ b/drivers/media/dvb-frontends/nxt6000.c @@ -564,7 +564,7 @@ static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) } } -static struct dvb_frontend_ops nxt6000_ops; +static const struct dvb_frontend_ops nxt6000_ops; struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, struct i2c_adapter* i2c) @@ -592,7 +592,7 @@ error: return NULL; } -static struct dvb_frontend_ops nxt6000_ops = { +static const struct dvb_frontend_ops nxt6000_ops = { .delsys = { SYS_DVBT }, .info = { .name = "NxtWave NXT6000 DVB-T", diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c index bacea20822ea..17bdadd7d0e1 100644 --- a/drivers/media/dvb-frontends/or51132.c +++ b/drivers/media/dvb-frontends/or51132.c @@ -559,7 +559,7 @@ static void or51132_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops or51132_ops; +static const struct dvb_frontend_ops or51132_ops; struct dvb_frontend* or51132_attach(const struct or51132_config* config, struct i2c_adapter* i2c) @@ -583,7 +583,7 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, return &state->frontend; } -static struct dvb_frontend_ops or51132_ops = { +static const struct dvb_frontend_ops or51132_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Oren OR51132 VSB/QAM Frontend", diff --git a/drivers/media/dvb-frontends/or51211.c b/drivers/media/dvb-frontends/or51211.c index 839479eab3b3..27eb73aa4f62 100644 --- a/drivers/media/dvb-frontends/or51211.c +++ b/drivers/media/dvb-frontends/or51211.c @@ -507,7 +507,7 @@ static void or51211_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops or51211_ops; +static const struct dvb_frontend_ops or51211_ops; struct dvb_frontend* or51211_attach(const struct or51211_config* config, struct i2c_adapter* i2c) @@ -531,7 +531,7 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, return &state->frontend; } -static struct dvb_frontend_ops or51211_ops = { +static const struct dvb_frontend_ops or51211_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Oren OR51211 VSB Frontend", diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index 87226056f226..7bbfe11d11ed 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c @@ -548,7 +548,7 @@ static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength) return 0; } -static struct dvb_frontend_ops rtl2830_ops = { +static const struct dvb_frontend_ops rtl2830_ops = { .delsys = {SYS_DVBT}, .info = { .name = "Realtek RTL2830 (DVB-T)", diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index 0ced01f1012e..94bf5b7d6f3f 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -837,7 +837,7 @@ static int rtl2832_deselect(struct i2c_mux_core *muxc, u32 chan_id) return 0; } -static struct dvb_frontend_ops rtl2832_ops = { +static const struct dvb_frontend_ops rtl2832_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Realtek RTL2832 (DVB-T)", diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c index 56c3fb442d6c..f370c6df0a8b 100644 --- a/drivers/media/dvb-frontends/s5h1409.c +++ b/drivers/media/dvb-frontends/s5h1409.c @@ -949,7 +949,7 @@ static void s5h1409_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops s5h1409_ops; +static const struct dvb_frontend_ops s5h1409_ops; struct dvb_frontend *s5h1409_attach(const struct s5h1409_config *config, struct i2c_adapter *i2c) @@ -995,7 +995,7 @@ error: } EXPORT_SYMBOL(s5h1409_attach); -static struct dvb_frontend_ops s5h1409_ops = { +static const struct dvb_frontend_ops s5h1409_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Samsung S5H1409 QAM/8VSB Frontend", diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c index a861854981b7..f29750a96196 100644 --- a/drivers/media/dvb-frontends/s5h1411.c +++ b/drivers/media/dvb-frontends/s5h1411.c @@ -864,7 +864,7 @@ static void s5h1411_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops s5h1411_ops; +static const struct dvb_frontend_ops s5h1411_ops; struct dvb_frontend *s5h1411_attach(const struct s5h1411_config *config, struct i2c_adapter *i2c) @@ -914,7 +914,7 @@ error: } EXPORT_SYMBOL(s5h1411_attach); -static struct dvb_frontend_ops s5h1411_ops = { +static const struct dvb_frontend_ops s5h1411_ops = { .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B }, .info = { .name = "Samsung S5H1411 QAM/8VSB Frontend", diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c index d7d0b7d57ad7..f9a18fe94d88 100644 --- a/drivers/media/dvb-frontends/s5h1420.c +++ b/drivers/media/dvb-frontends/s5h1420.c @@ -880,7 +880,7 @@ struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe) } EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter); -static struct dvb_frontend_ops s5h1420_ops; +static const struct dvb_frontend_ops s5h1420_ops; struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config, struct i2c_adapter *i2c) @@ -934,7 +934,7 @@ error: } EXPORT_SYMBOL(s5h1420_attach); -static struct dvb_frontend_ops s5h1420_ops = { +static const struct dvb_frontend_ops s5h1420_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S", diff --git a/drivers/media/dvb-frontends/s5h1432.c b/drivers/media/dvb-frontends/s5h1432.c index 5de79739cf63..a32fd9bc51a9 100644 --- a/drivers/media/dvb-frontends/s5h1432.c +++ b/drivers/media/dvb-frontends/s5h1432.c @@ -341,7 +341,7 @@ static void s5h1432_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops s5h1432_ops; +static const struct dvb_frontend_ops s5h1432_ops; struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, struct i2c_adapter *i2c) @@ -370,7 +370,7 @@ struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config, } EXPORT_SYMBOL(s5h1432_attach); -static struct dvb_frontend_ops s5h1432_ops = { +static const struct dvb_frontend_ops s5h1432_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Samsung s5h1432 DVB-T Frontend", diff --git a/drivers/media/dvb-frontends/s921.c b/drivers/media/dvb-frontends/s921.c index 98cceb149b91..274544a3ae0e 100644 --- a/drivers/media/dvb-frontends/s921.c +++ b/drivers/media/dvb-frontends/s921.c @@ -477,7 +477,7 @@ static void s921_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops s921_ops; +static const struct dvb_frontend_ops s921_ops; struct dvb_frontend *s921_attach(const struct s921_config *config, struct i2c_adapter *i2c) @@ -505,7 +505,7 @@ struct dvb_frontend *s921_attach(const struct s921_config *config, } EXPORT_SYMBOL(s921_attach); -static struct dvb_frontend_ops s921_ops = { +static const struct dvb_frontend_ops s921_ops = { .delsys = { SYS_ISDBT }, /* Use dib8000 values per default */ .info = { diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 78669ea68c61..528b82a5dd46 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -978,7 +978,7 @@ static int si2165_set_frontend(struct dvb_frontend *fe) return 0; } -static struct dvb_frontend_ops si2165_ops = { +static const struct dvb_frontend_ops si2165_ops = { .info = { .name = "Silicon Labs ", /* For DVB-C */ diff --git a/drivers/media/dvb-frontends/si21xx.c b/drivers/media/dvb-frontends/si21xx.c index 32ebfb78bfdd..4e8c3ac4303f 100644 --- a/drivers/media/dvb-frontends/si21xx.c +++ b/drivers/media/dvb-frontends/si21xx.c @@ -866,7 +866,7 @@ static void si21xx_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops si21xx_ops = { +static const struct dvb_frontend_ops si21xx_ops = { .delsys = { SYS_DVBS }, .info = { .name = "SL SI21XX DVB-S", diff --git a/drivers/media/dvb-frontends/sp8870.c b/drivers/media/dvb-frontends/sp8870.c index e87ac30d7fb8..04454cb78467 100644 --- a/drivers/media/dvb-frontends/sp8870.c +++ b/drivers/media/dvb-frontends/sp8870.c @@ -551,7 +551,7 @@ static void sp8870_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops sp8870_ops; +static const struct dvb_frontend_ops sp8870_ops; struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, struct i2c_adapter* i2c) @@ -580,7 +580,7 @@ error: return NULL; } -static struct dvb_frontend_ops sp8870_ops = { +static const struct dvb_frontend_ops sp8870_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Spase SP8870 DVB-T", diff --git a/drivers/media/dvb-frontends/sp887x.c b/drivers/media/dvb-frontends/sp887x.c index f9194b7b7fec..7c511c3cd4ca 100644 --- a/drivers/media/dvb-frontends/sp887x.c +++ b/drivers/media/dvb-frontends/sp887x.c @@ -561,7 +561,7 @@ static void sp887x_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops sp887x_ops; +static const struct dvb_frontend_ops sp887x_ops; struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, struct i2c_adapter* i2c) @@ -590,7 +590,7 @@ error: return NULL; } -static struct dvb_frontend_ops sp887x_ops = { +static const struct dvb_frontend_ops sp887x_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Spase SP887x DVB-T", diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index 8e7cafb8f36a..cc18891f9b45 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -1573,7 +1573,7 @@ static enum dvbfe_algo stb0899_frontend_algo(struct dvb_frontend *fe) return DVBFE_ALGO_CUSTOM; } -static struct dvb_frontend_ops stb0899_ops = { +static const struct dvb_frontend_ops stb0899_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STB0899 Multistandard", diff --git a/drivers/media/dvb-frontends/stv0288.c b/drivers/media/dvb-frontends/stv0288.c index 12f6a4205e3e..45cbc898ad25 100644 --- a/drivers/media/dvb-frontends/stv0288.c +++ b/drivers/media/dvb-frontends/stv0288.c @@ -535,7 +535,7 @@ static void stv0288_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops stv0288_ops = { +static const struct dvb_frontend_ops stv0288_ops = { .delsys = { SYS_DVBS }, .info = { .name = "ST STV0288 DVB-S", diff --git a/drivers/media/dvb-frontends/stv0297.c b/drivers/media/dvb-frontends/stv0297.c index 73b4d4243b74..db94d4d109f9 100644 --- a/drivers/media/dvb-frontends/stv0297.c +++ b/drivers/media/dvb-frontends/stv0297.c @@ -658,7 +658,7 @@ static void stv0297_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops stv0297_ops; +static const struct dvb_frontend_ops stv0297_ops; struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, struct i2c_adapter *i2c) @@ -690,7 +690,7 @@ error: return NULL; } -static struct dvb_frontend_ops stv0297_ops = { +static const struct dvb_frontend_ops stv0297_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0297 DVB-C", diff --git a/drivers/media/dvb-frontends/stv0299.c b/drivers/media/dvb-frontends/stv0299.c index a9b28ceb80d8..b36b21a13201 100644 --- a/drivers/media/dvb-frontends/stv0299.c +++ b/drivers/media/dvb-frontends/stv0299.c @@ -673,7 +673,7 @@ static void stv0299_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops stv0299_ops; +static const struct dvb_frontend_ops stv0299_ops; struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, struct i2c_adapter* i2c) @@ -713,7 +713,7 @@ error: return NULL; } -static struct dvb_frontend_ops stv0299_ops = { +static const struct dvb_frontend_ops stv0299_ops = { .delsys = { SYS_DVBS }, .info = { .name = "ST STV0299 DVB-S", diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index abc379aea713..4ac1ce2831ba 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -2272,7 +2272,7 @@ static void stv0367_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops stv0367ter_ops = { +static const struct dvb_frontend_ops stv0367ter_ops = { .delsys = { SYS_DVBT }, .info = { .name = "ST STV0367 DVB-T", @@ -3390,7 +3390,7 @@ static int stv0367cab_read_ucblcks(struct dvb_frontend *fe, u32 *ucblocks) return 0; }; -static struct dvb_frontend_ops stv0367cab_ops = { +static const struct dvb_frontend_ops stv0367cab_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "ST STV0367 DVB-C", diff --git a/drivers/media/dvb-frontends/stv0900_core.c b/drivers/media/dvb-frontends/stv0900_core.c index f667005a6661..43a0f69b4b14 100644 --- a/drivers/media/dvb-frontends/stv0900_core.c +++ b/drivers/media/dvb-frontends/stv0900_core.c @@ -1875,7 +1875,7 @@ static int stv0900_get_frontend(struct dvb_frontend *fe, return 0; } -static struct dvb_frontend_ops stv0900_ops = { +static const struct dvb_frontend_ops stv0900_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STV0900 frontend", diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index 42d62cc9a357..b586d2a49737 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -4880,7 +4880,7 @@ static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg); } -static struct dvb_frontend_ops stv090x_ops = { +static const struct dvb_frontend_ops stv090x_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STV090x Multistandard", diff --git a/drivers/media/dvb-frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c index 4c514e6bffda..32ba8401e743 100644 --- a/drivers/media/dvb-frontends/tda10021.c +++ b/drivers/media/dvb-frontends/tda10021.c @@ -443,7 +443,7 @@ static void tda10021_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops tda10021_ops; +static const struct dvb_frontend_ops tda10021_ops; struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config, struct i2c_adapter* i2c, @@ -483,7 +483,7 @@ error: return NULL; } -static struct dvb_frontend_ops tda10021_ops = { +static const struct dvb_frontend_ops tda10021_ops = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, .info = { .name = "Philips TDA10021 DVB-C", diff --git a/drivers/media/dvb-frontends/tda10023.c b/drivers/media/dvb-frontends/tda10023.c index 0c416be76d65..8028007c68eb 100644 --- a/drivers/media/dvb-frontends/tda10023.c +++ b/drivers/media/dvb-frontends/tda10023.c @@ -514,7 +514,7 @@ static void tda10023_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops tda10023_ops; +static const struct dvb_frontend_ops tda10023_ops; struct dvb_frontend *tda10023_attach(const struct tda10023_config *config, struct i2c_adapter *i2c, @@ -571,7 +571,7 @@ error: return NULL; } -static struct dvb_frontend_ops tda10023_ops = { +static const struct dvb_frontend_ops tda10023_ops = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C }, .info = { .name = "Philips TDA10023 DVB-C", diff --git a/drivers/media/dvb-frontends/tda10048.c b/drivers/media/dvb-frontends/tda10048.c index 7cb23f89a03b..92ab34c3e0be 100644 --- a/drivers/media/dvb-frontends/tda10048.c +++ b/drivers/media/dvb-frontends/tda10048.c @@ -1090,7 +1090,7 @@ static void tda10048_establish_defaults(struct dvb_frontend *fe) } } -static struct dvb_frontend_ops tda10048_ops; +static const struct dvb_frontend_ops tda10048_ops; struct dvb_frontend *tda10048_attach(const struct tda10048_config *config, struct i2c_adapter *i2c) @@ -1152,7 +1152,7 @@ error: } EXPORT_SYMBOL(tda10048_attach); -static struct dvb_frontend_ops tda10048_ops = { +static const struct dvb_frontend_ops tda10048_ops = { .delsys = { SYS_DVBT }, .info = { .name = "NXP TDA10048HN DVB-T", diff --git a/drivers/media/dvb-frontends/tda1004x.c b/drivers/media/dvb-frontends/tda1004x.c index b89848313fb9..e674508c349c 100644 --- a/drivers/media/dvb-frontends/tda1004x.c +++ b/drivers/media/dvb-frontends/tda1004x.c @@ -1245,7 +1245,7 @@ static void tda1004x_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops tda10045_ops = { +static const struct dvb_frontend_ops tda10045_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Philips TDA10045H DVB-T", @@ -1315,7 +1315,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, return &state->frontend; } -static struct dvb_frontend_ops tda10046_ops = { +static const struct dvb_frontend_ops tda10046_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Philips TDA10046H DVB-T", diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c index 37ebeef2bbd0..a59f4fd09df6 100644 --- a/drivers/media/dvb-frontends/tda10071.c +++ b/drivers/media/dvb-frontends/tda10071.c @@ -20,7 +20,7 @@ #include "tda10071_priv.h" -static struct dvb_frontend_ops tda10071_ops; +static const struct dvb_frontend_ops tda10071_ops; /* * XXX: regmap_update_bits() does not fit our needs as it does not support @@ -1102,7 +1102,7 @@ static int tda10071_get_tune_settings(struct dvb_frontend *fe, return 0; } -static struct dvb_frontend_ops tda10071_ops = { +static const struct dvb_frontend_ops tda10071_ops = { .delsys = { SYS_DVBS, SYS_DVBS2 }, .info = { .name = "NXP TDA10071", diff --git a/drivers/media/dvb-frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c index 31d0acb54fe8..b6d16c05904d 100644 --- a/drivers/media/dvb-frontends/tda10086.c +++ b/drivers/media/dvb-frontends/tda10086.c @@ -706,7 +706,7 @@ static void tda10086_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops tda10086_ops = { +static const struct dvb_frontend_ops tda10086_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Philips TDA10086 DVB-S", diff --git a/drivers/media/dvb-frontends/tda8083.c b/drivers/media/dvb-frontends/tda8083.c index 9072d6463094..aa3200d3c352 100644 --- a/drivers/media/dvb-frontends/tda8083.c +++ b/drivers/media/dvb-frontends/tda8083.c @@ -421,7 +421,7 @@ static void tda8083_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops tda8083_ops; +static const struct dvb_frontend_ops tda8083_ops; struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, struct i2c_adapter* i2c) @@ -449,7 +449,7 @@ error: return NULL; } -static struct dvb_frontend_ops tda8083_ops = { +static const struct dvb_frontend_ops tda8083_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Philips TDA8083 DVB-S", diff --git a/drivers/media/dvb-frontends/ves1820.c b/drivers/media/dvb-frontends/ves1820.c index 24ac54b3b967..178363704bd4 100644 --- a/drivers/media/dvb-frontends/ves1820.c +++ b/drivers/media/dvb-frontends/ves1820.c @@ -369,7 +369,7 @@ static void ves1820_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops ves1820_ops; +static const struct dvb_frontend_ops ves1820_ops; struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, struct i2c_adapter* i2c, @@ -408,7 +408,7 @@ error: return NULL; } -static struct dvb_frontend_ops ves1820_ops = { +static const struct dvb_frontend_ops ves1820_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "VLSI VES1820 DVB-C", diff --git a/drivers/media/dvb-frontends/ves1x93.c b/drivers/media/dvb-frontends/ves1x93.c index ed113e216e14..d0ee52f66a8e 100644 --- a/drivers/media/dvb-frontends/ves1x93.c +++ b/drivers/media/dvb-frontends/ves1x93.c @@ -454,7 +454,7 @@ static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) } } -static struct dvb_frontend_ops ves1x93_ops; +static const struct dvb_frontend_ops ves1x93_ops; struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, struct i2c_adapter* i2c) @@ -512,7 +512,7 @@ error: return NULL; } -static struct dvb_frontend_ops ves1x93_ops = { +static const struct dvb_frontend_ops ves1x93_ops = { .delsys = { SYS_DVBS }, .info = { .name = "VLSI VES1x93 DVB-S", diff --git a/drivers/media/dvb-frontends/zl10353.c b/drivers/media/dvb-frontends/zl10353.c index 3b08176d7bec..4f3ff3e853ac 100644 --- a/drivers/media/dvb-frontends/zl10353.c +++ b/drivers/media/dvb-frontends/zl10353.c @@ -602,7 +602,7 @@ static void zl10353_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops zl10353_ops; +static const struct dvb_frontend_ops zl10353_ops; struct dvb_frontend *zl10353_attach(const struct zl10353_config *config, struct i2c_adapter *i2c) @@ -634,7 +634,7 @@ error: return NULL; } -static struct dvb_frontend_ops zl10353_ops = { +static const struct dvb_frontend_ops zl10353_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Zarlink ZL10353 DVB-T", diff --git a/drivers/media/pci/bt8xx/dst.c b/drivers/media/pci/bt8xx/dst.c index faea3f06e350..7166d2279465 100644 --- a/drivers/media/pci/bt8xx/dst.c +++ b/drivers/media/pci/bt8xx/dst.c @@ -1696,10 +1696,10 @@ static void bt8xx_dst_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops dst_dvbt_ops; -static struct dvb_frontend_ops dst_dvbs_ops; -static struct dvb_frontend_ops dst_dvbc_ops; -static struct dvb_frontend_ops dst_atsc_ops; +static const struct dvb_frontend_ops dst_dvbt_ops; +static const struct dvb_frontend_ops dst_dvbs_ops; +static const struct dvb_frontend_ops dst_dvbc_ops; +static const struct dvb_frontend_ops dst_atsc_ops; struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) { @@ -1735,7 +1735,7 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad EXPORT_SYMBOL(dst_attach); -static struct dvb_frontend_ops dst_dvbt_ops = { +static const struct dvb_frontend_ops dst_dvbt_ops = { .delsys = { SYS_DVBT }, .info = { .name = "DST DVB-T", @@ -1764,7 +1764,7 @@ static struct dvb_frontend_ops dst_dvbt_ops = { .read_snr = dst_read_snr, }; -static struct dvb_frontend_ops dst_dvbs_ops = { +static const struct dvb_frontend_ops dst_dvbs_ops = { .delsys = { SYS_DVBS }, .info = { .name = "DST DVB-S", @@ -1793,7 +1793,7 @@ static struct dvb_frontend_ops dst_dvbs_ops = { .set_tone = dst_set_tone, }; -static struct dvb_frontend_ops dst_dvbc_ops = { +static const struct dvb_frontend_ops dst_dvbc_ops = { .delsys = { SYS_DVBC_ANNEX_A }, .info = { .name = "DST DVB-C", @@ -1822,7 +1822,7 @@ static struct dvb_frontend_ops dst_dvbc_ops = { .read_snr = dst_read_snr, }; -static struct dvb_frontend_ops dst_atsc_ops = { +static const struct dvb_frontend_ops dst_atsc_ops = { .delsys = { SYS_ATSC }, .info = { .name = "DST ATSC", diff --git a/drivers/media/pci/pt1/va1j5jf8007s.c b/drivers/media/pci/pt1/va1j5jf8007s.c index d0e70dc0e16f..249273b2e0f2 100644 --- a/drivers/media/pci/pt1/va1j5jf8007s.c +++ b/drivers/media/pci/pt1/va1j5jf8007s.c @@ -578,7 +578,7 @@ static void va1j5jf8007s_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops va1j5jf8007s_ops = { +static const struct dvb_frontend_ops va1j5jf8007s_ops = { .delsys = { SYS_ISDBS }, .info = { .name = "VA1J5JF8007/VA1J5JF8011 ISDB-S", diff --git a/drivers/media/pci/pt1/va1j5jf8007t.c b/drivers/media/pci/pt1/va1j5jf8007t.c index 0268f20b8097..e0766e69a370 100644 --- a/drivers/media/pci/pt1/va1j5jf8007t.c +++ b/drivers/media/pci/pt1/va1j5jf8007t.c @@ -427,7 +427,7 @@ static void va1j5jf8007t_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops va1j5jf8007t_ops = { +static const struct dvb_frontend_ops va1j5jf8007t_ops = { .delsys = { SYS_ISDBT }, .info = { .name = "VA1J5JF8007/VA1J5JF8011 ISDB-T", diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c index 6b75415b75a5..a59c567c55d6 100644 --- a/drivers/media/tuners/tda8290.c +++ b/drivers/media/tuners/tda8290.c @@ -721,7 +721,7 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props) return -ENODEV; } -static struct analog_demod_ops tda8290_ops = { +static const struct analog_demod_ops tda8290_ops = { .set_params = tda8290_set_params, .has_signal = tda8290_has_signal, .standby = tda8290_standby, @@ -729,7 +729,7 @@ static struct analog_demod_ops tda8290_ops = { .i2c_gate_ctrl = tda8290_i2c_bridge, }; -static struct analog_demod_ops tda8295_ops = { +static const struct analog_demod_ops tda8295_ops = { .set_params = tda8295_set_params, .has_signal = tda8295_has_signal, .standby = tda8295_standby, diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c index 56be6c29399b..c0e815f8b951 100644 --- a/drivers/media/tuners/tda9887.c +++ b/drivers/media/tuners/tda9887.c @@ -659,7 +659,7 @@ static void tda9887_release(struct dvb_frontend *fe) fe->analog_demod_priv = NULL; } -static struct analog_demod_ops tda9887_ops = { +static const struct analog_demod_ops tda9887_ops = { .info = { .name = "tda9887", }, diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c index 047a32fe43ea..639e156e0c1b 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c @@ -549,7 +549,7 @@ static void mxl111sf_demod_release(struct dvb_frontend *fe) fe->demodulator_priv = NULL; } -static struct dvb_frontend_ops mxl111sf_demod_ops = { +static const struct dvb_frontend_ops mxl111sf_demod_ops = { .delsys = { SYS_DVBT }, .info = { .name = "MaxLinear MxL111SF DVB-T demodulator", diff --git a/drivers/media/usb/dvb-usb/af9005-fe.c b/drivers/media/usb/dvb-usb/af9005-fe.c index 09db3d02bd82..9862d3e6b8e8 100644 --- a/drivers/media/usb/dvb-usb/af9005-fe.c +++ b/drivers/media/usb/dvb-usb/af9005-fe.c @@ -1430,7 +1430,7 @@ static void af9005_fe_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops af9005_fe_ops; +static const struct dvb_frontend_ops af9005_fe_ops; struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) { @@ -1455,7 +1455,7 @@ struct dvb_frontend *af9005_fe_attach(struct dvb_usb_device *d) return NULL; } -static struct dvb_frontend_ops af9005_fe_ops = { +static const struct dvb_frontend_ops af9005_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = "AF9005 USB DVB-T", diff --git a/drivers/media/usb/dvb-usb/cinergyT2-fe.c b/drivers/media/usb/dvb-usb/cinergyT2-fe.c index 2d29b4174dba..bbb10fab65bc 100644 --- a/drivers/media/usb/dvb-usb/cinergyT2-fe.c +++ b/drivers/media/usb/dvb-usb/cinergyT2-fe.c @@ -278,7 +278,7 @@ static void cinergyt2_fe_release(struct dvb_frontend *fe) kfree(state); } -static struct dvb_frontend_ops cinergyt2_fe_ops; +static const struct dvb_frontend_ops cinergyt2_fe_ops; struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) { @@ -295,7 +295,7 @@ struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) } -static struct dvb_frontend_ops cinergyt2_fe_ops = { +static const struct dvb_frontend_ops cinergyt2_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = DRIVER_NAME, diff --git a/drivers/media/usb/dvb-usb/dtt200u-fe.c b/drivers/media/usb/dvb-usb/dtt200u-fe.c index f5c042baa254..00f565fe7cc2 100644 --- a/drivers/media/usb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/usb/dvb-usb/dtt200u-fe.c @@ -202,7 +202,7 @@ static void dtt200u_fe_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops dtt200u_fe_ops; +static const struct dvb_frontend_ops dtt200u_fe_ops; struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) { @@ -226,7 +226,7 @@ error: return NULL; } -static struct dvb_frontend_ops dtt200u_fe_ops = { +static const struct dvb_frontend_ops dtt200u_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = "WideView USB DVB-T", diff --git a/drivers/media/usb/dvb-usb/friio-fe.c b/drivers/media/usb/dvb-usb/friio-fe.c index 979f05b4b87c..0251a4e91d47 100644 --- a/drivers/media/usb/dvb-usb/friio-fe.c +++ b/drivers/media/usb/dvb-usb/friio-fe.c @@ -401,7 +401,7 @@ static void jdvbt90502_release(struct dvb_frontend *fe) } -static struct dvb_frontend_ops jdvbt90502_ops; +static const struct dvb_frontend_ops jdvbt90502_ops; struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d) { @@ -432,7 +432,7 @@ error: return NULL; } -static struct dvb_frontend_ops jdvbt90502_ops = { +static const struct dvb_frontend_ops jdvbt90502_ops = { .delsys = { SYS_ISDBT }, .info = { .name = "Comtech JDVBT90502 ISDB-T", diff --git a/drivers/media/usb/dvb-usb/vp702x-fe.c b/drivers/media/usb/dvb-usb/vp702x-fe.c index 27398c08c69d..7ff31baa3682 100644 --- a/drivers/media/usb/dvb-usb/vp702x-fe.c +++ b/drivers/media/usb/dvb-usb/vp702x-fe.c @@ -323,7 +323,7 @@ static void vp702x_fe_release(struct dvb_frontend* fe) kfree(st); } -static struct dvb_frontend_ops vp702x_fe_ops; +static const struct dvb_frontend_ops vp702x_fe_ops; struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) { @@ -345,7 +345,7 @@ error: } -static struct dvb_frontend_ops vp702x_fe_ops = { +static const struct dvb_frontend_ops vp702x_fe_ops = { .delsys = { SYS_DVBS }, .info = { .name = "Twinhan DST-like frontend (VP7021/VP7020) DVB-S", diff --git a/drivers/media/usb/dvb-usb/vp7045-fe.c b/drivers/media/usb/dvb-usb/vp7045-fe.c index 7765602ea658..4520ad9c2014 100644 --- a/drivers/media/usb/dvb-usb/vp7045-fe.c +++ b/drivers/media/usb/dvb-usb/vp7045-fe.c @@ -140,7 +140,7 @@ static void vp7045_fe_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops vp7045_fe_ops; +static const struct dvb_frontend_ops vp7045_fe_ops; struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d) { @@ -158,7 +158,7 @@ error: } -static struct dvb_frontend_ops vp7045_fe_ops = { +static const struct dvb_frontend_ops vp7045_fe_ops = { .delsys = { SYS_DVBT }, .info = { .name = "Twinhan VP7045/46 USB DVB-T", diff --git a/drivers/media/usb/ttusb-dec/ttusbdecfe.c b/drivers/media/usb/ttusb-dec/ttusbdecfe.c index 8781335ab92f..2d9444905fdb 100644 --- a/drivers/media/usb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/usb/ttusb-dec/ttusbdecfe.c @@ -205,7 +205,7 @@ static void ttusbdecfe_release(struct dvb_frontend* fe) kfree(state); } -static struct dvb_frontend_ops ttusbdecfe_dvbt_ops; +static const struct dvb_frontend_ops ttusbdecfe_dvbt_ops; struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) { @@ -225,7 +225,7 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf return &state->frontend; } -static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; +static const struct dvb_frontend_ops ttusbdecfe_dvbs_ops; struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) { @@ -247,7 +247,7 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf return &state->frontend; } -static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { +static const struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { .delsys = { SYS_DVBT }, .info = { .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", @@ -270,7 +270,7 @@ static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { .read_status = ttusbdecfe_dvbt_read_status, }; -static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { +static const struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { .delsys = { SYS_DVBS }, .info = { .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", -- cgit v1.2.3 From 1f4ed6cd58f36574237926f35bdec50116669909 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:11 -0300 Subject: [media] dvbdev: split dvb_unregister_device() dvb_unregister_device() has a major problem: it combines unregistering with memory disposal. Sometimes, it is necessary to unregister a device, but no memory can be freed yet, because a process still has a (stale) file handle. Therefore, we need to split dvb_unregister_device(). This will allow sanitizing a few callers. With my new design, dvb_unregister_device() appears misnamed, but to reduce patch noise, I'm not renaming it just yet. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvbdev.c | 19 ++++++++++++++++++- drivers/media/dvb-core/dvbdev.h | 23 +++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index 0694d1d53c67..38c844667789 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -528,7 +528,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, EXPORT_SYMBOL(dvb_register_device); -void dvb_unregister_device(struct dvb_device *dvbdev) +void dvb_remove_device(struct dvb_device *dvbdev) { if (!dvbdev) return; @@ -542,9 +542,26 @@ void dvb_unregister_device(struct dvb_device *dvbdev) device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); list_del (&dvbdev->list_head); +} +EXPORT_SYMBOL(dvb_remove_device); + + +void dvb_free_device(struct dvb_device *dvbdev) +{ + if (!dvbdev) + return; + kfree (dvbdev->fops); kfree (dvbdev); } +EXPORT_SYMBOL(dvb_free_device); + + +void dvb_unregister_device(struct dvb_device *dvbdev) +{ + dvb_remove_device(dvbdev); + dvb_free_device(dvbdev); +} EXPORT_SYMBOL(dvb_unregister_device); diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index 4aff7bd3dea8..576bbd4445b5 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -211,9 +211,32 @@ int dvb_register_device(struct dvb_adapter *adap, int type, int demux_sink_pads); +/** + * dvb_remove_device - Remove a registered DVB device + * + * This does not free memory. To do that, call dvb_free_device(). + * + * @dvbdev: pointer to struct dvb_device + */ +void dvb_remove_device(struct dvb_device *dvbdev); + +/** + * dvb_free_device - Free memory occupied by a DVB device. + * + * Call dvb_unregister_device() before calling this function. + * + * @dvbdev: pointer to struct dvb_device + */ +void dvb_free_device(struct dvb_device *dvbdev); + /** * dvb_unregister_device - Unregisters a DVB device * + * This is a combination of dvb_remove_device() and dvb_free_device(). + * Using this function is usually a mistake, and is often an indicator + * for a use-after-free bug (when a userspace process keeps a file + * handle to a detached device). + * * @dvbdev: pointer to struct dvb_device */ void dvb_unregister_device(struct dvb_device *dvbdev); -- cgit v1.2.3 From 4d5030b69bb4880a760406a6d3d519f02b9351dc Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:16 -0300 Subject: [media] dvb-core/en50221: use dvb_remove_device() Commit da677fe14364 ("[media] dvb-core/en50221: use kref to manage struct dvb_ca_private") moved the dvb_unregister_device() call to the kref callback, but that left lots of stale device state visible to userspace (e.g. in sysfs). By using dvb_remove_device() and dvb_free_device() instead of dvb_unregister_device(), we can avoid that. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_ca_en50221.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c index 262a492e7c08..fd893141211c 100644 --- a/drivers/media/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb-core/dvb_ca_en50221.c @@ -171,7 +171,7 @@ static void dvb_ca_private_free(struct dvb_ca_private *ca) { unsigned int i; - dvb_unregister_device(ca->dvbdev); + dvb_free_device(ca->dvbdev); for (i = 0; i < ca->slot_count; i++) vfree(ca->slot_info[i].rx_buffer.data); @@ -1807,6 +1807,7 @@ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) for (i = 0; i < ca->slot_count; i++) { dvb_ca_en50221_slot_shutdown(ca, i); } + dvb_remove_device(ca->dvbdev); dvb_ca_private_put(ca); pubca->private = NULL; } -- cgit v1.2.3 From 22a613e89825ea7a3984a968463cc6d425bd8856 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:26 -0300 Subject: [media] dvb_frontend: merge duplicate dvb_tuner_ops.release implementations Most release callback functions are identical: free the "tuner_priv" and clear it. Let's eliminate some bloat by providing this simple implementation in the dvb_frontend library. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 9 +++++++++ drivers/media/dvb-core/dvb_frontend.h | 7 +++++++ drivers/media/dvb-frontends/dib0070.c | 9 +-------- drivers/media/dvb-frontends/dib0090.c | 11 ++--------- drivers/media/dvb-frontends/dvb-pll.c | 9 +-------- drivers/media/dvb-frontends/itd1000.c | 9 +-------- drivers/media/dvb-frontends/ix2505v.c | 12 +----------- drivers/media/dvb-frontends/stb6000.c | 9 +-------- drivers/media/dvb-frontends/stb6100.c | 14 +------------- drivers/media/dvb-frontends/stv6110.c | 9 +-------- drivers/media/dvb-frontends/stv6110x.c | 12 +----------- drivers/media/dvb-frontends/tda18271c2dd.c | 10 +--------- drivers/media/dvb-frontends/tda665x.c | 11 +---------- drivers/media/dvb-frontends/tda8261.c | 11 +---------- drivers/media/dvb-frontends/tda826x.c | 9 +-------- drivers/media/dvb-frontends/tua6100.c | 9 +-------- drivers/media/dvb-frontends/zl10036.c | 12 +----------- drivers/media/tuners/fc0011.c | 10 +--------- drivers/media/tuners/fc0012.c | 9 +-------- drivers/media/tuners/fc0013.c | 9 +-------- drivers/media/tuners/mc44s803.c | 12 +----------- drivers/media/tuners/mt2060.c | 9 +-------- drivers/media/tuners/mt20xx.c | 12 ++---------- drivers/media/tuners/mt2266.c | 9 +-------- drivers/media/tuners/qt1010.c | 9 +-------- drivers/media/tuners/tda18218.c | 9 +-------- drivers/media/tuners/tda827x.c | 11 ++--------- drivers/media/tuners/tea5761.c | 10 +--------- drivers/media/tuners/tea5767.c | 10 +--------- 29 files changed, 46 insertions(+), 245 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index cdb7048874c5..7c4a50b0b963 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -174,6 +174,15 @@ static bool has_get_frontend(struct dvb_frontend *fe) return fe->ops.get_frontend != NULL; } +int +dvb_tuner_simple_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} +EXPORT_SYMBOL(dvb_tuner_simple_release); + /* * Due to DVBv3 API calls, a delivery system should be mapped into one of * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC), diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index fb6e84811504..6b675a833520 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -266,6 +266,13 @@ struct dvb_tuner_ops { int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); }; +/** + * A common default implementation for dvb_tuner_ops.release. All it + * does is kfree() the tuner_priv and assign NULL to it. + */ +int +dvb_tuner_simple_release(struct dvb_frontend *fe); + /** * struct analog_demod_info - Information struct for analog TV part of the demod * diff --git a/drivers/media/dvb-frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c index 016ad09a8754..d9f1bc2f778c 100644 --- a/drivers/media/dvb-frontends/dib0070.c +++ b/drivers/media/dvb-frontends/dib0070.c @@ -722,13 +722,6 @@ static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int dib0070_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static const struct dvb_tuner_ops dib0070_ops = { .info = { .name = "DiBcom DiB0070", @@ -736,7 +729,7 @@ static const struct dvb_tuner_ops dib0070_ops = { .frequency_max = 860000000, .frequency_step = 1000, }, - .release = dib0070_release, + .release = dvb_tuner_simple_release, .init = dib0070_wakeup, .sleep = dib0070_sleep, diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 16200582f089..7b4bee5c8e34 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -2526,13 +2526,6 @@ static int dib0090_tune(struct dvb_frontend *fe) return ret; } -static int dib0090_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; @@ -2594,7 +2587,7 @@ static const struct dvb_tuner_ops dib0090_ops = { .frequency_max = 860000000, .frequency_step = 1000, }, - .release = dib0090_release, + .release = dvb_tuner_simple_release, .init = dib0090_wakeup, .sleep = dib0090_sleep, @@ -2609,7 +2602,7 @@ static const struct dvb_tuner_ops dib0090_fw_ops = { .frequency_max = 860000000, .frequency_step = 1000, }, - .release = dib0090_release, + .release = dvb_tuner_simple_release, .init = NULL, .sleep = NULL, diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index b6d199196b83..56832d6f47ae 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -606,13 +606,6 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, return (div * desc->entries[i].stepsize) - desc->iffreq; } -static int dvb_pll_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int dvb_pll_sleep(struct dvb_frontend *fe) { struct dvb_pll_priv *priv = fe->tuner_priv; @@ -745,7 +738,7 @@ static int dvb_pll_init(struct dvb_frontend *fe) } static const struct dvb_tuner_ops dvb_pll_tuner_ops = { - .release = dvb_pll_release, + .release = dvb_tuner_simple_release, .sleep = dvb_pll_sleep, .init = dvb_pll_init, .set_params = dvb_pll_set_params, diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c index cadcae4cff89..d09f718f8119 100644 --- a/drivers/media/dvb-frontends/itd1000.c +++ b/drivers/media/dvb-frontends/itd1000.c @@ -348,13 +348,6 @@ static int itd1000_sleep(struct dvb_frontend *fe) return 0; } -static int itd1000_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static const struct dvb_tuner_ops itd1000_tuner_ops = { .info = { .name = "Integrant ITD1000", @@ -363,7 +356,7 @@ static const struct dvb_tuner_ops itd1000_tuner_ops = { .frequency_step = 125, /* kHz for QPSK frontends */ }, - .release = itd1000_release, + .release = dvb_tuner_simple_release, .init = itd1000_init, .sleep = itd1000_sleep, diff --git a/drivers/media/dvb-frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c index 2826bbb36b73..7742a7a8cdbb 100644 --- a/drivers/media/dvb-frontends/ix2505v.c +++ b/drivers/media/dvb-frontends/ix2505v.c @@ -94,16 +94,6 @@ static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count) return 0; } -static int ix2505v_release(struct dvb_frontend *fe) -{ - struct ix2505v_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - - return 0; -} - /** * Data write format of the Sharp IX2505V B0017 * @@ -264,7 +254,7 @@ static const struct dvb_tuner_ops ix2505v_tuner_ops = { .frequency_min = 950000, .frequency_max = 2175000 }, - .release = ix2505v_release, + .release = dvb_tuner_simple_release, .set_params = ix2505v_set_params, .get_frequency = ix2505v_get_frequency, }; diff --git a/drivers/media/dvb-frontends/stb6000.c b/drivers/media/dvb-frontends/stb6000.c index 73347d51f340..5252d485439e 100644 --- a/drivers/media/dvb-frontends/stb6000.c +++ b/drivers/media/dvb-frontends/stb6000.c @@ -41,13 +41,6 @@ struct stb6000_priv { u32 frequency; }; -static int stb6000_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int stb6000_sleep(struct dvb_frontend *fe) { struct stb6000_priv *priv = fe->tuner_priv; @@ -192,7 +185,7 @@ static const struct dvb_tuner_ops stb6000_tuner_ops = { .frequency_min = 950000, .frequency_max = 2150000 }, - .release = stb6000_release, + .release = dvb_tuner_simple_release, .sleep = stb6000_sleep, .set_params = stb6000_set_params, .get_frequency = stb6000_get_frequency, diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index 5add1182c3ca..befd26bdfa0f 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -61,8 +61,6 @@ struct stb6100_lkup { u8 reg; }; -static int stb6100_release(struct dvb_frontend *fe); - static const struct stb6100_lkup lkup[] = { { 0, 950000, 0x0a }, { 950000, 1000000, 0x0a }, @@ -536,7 +534,7 @@ static const struct dvb_tuner_ops stb6100_ops = { .set_params = stb6100_set_params, .get_frequency = stb6100_get_frequency, .get_bandwidth = stb6100_get_bandwidth, - .release = stb6100_release + .release = dvb_tuner_simple_release }; struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, @@ -560,16 +558,6 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, return fe; } -static int stb6100_release(struct dvb_frontend *fe) -{ - struct stb6100_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - - return 0; -} - EXPORT_SYMBOL(stb6100_attach); MODULE_PARM_DESC(verbose, "Set Verbosity level"); diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c index 66a5a7f2295c..d9a88adc4c10 100644 --- a/drivers/media/dvb-frontends/stv6110.c +++ b/drivers/media/dvb-frontends/stv6110.c @@ -59,13 +59,6 @@ static s32 abssub(s32 a, s32 b) return b - a; }; -static int stv6110_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[], int start, int len) { @@ -390,7 +383,7 @@ static const struct dvb_tuner_ops stv6110_tuner_ops = { .frequency_step = 1000, }, .init = stv6110_init, - .release = stv6110_release, + .release = dvb_tuner_simple_release, .sleep = stv6110_sleep, .set_params = stv6110_set_params, .get_frequency = stv6110_get_frequency, diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c index c611ad210b5c..70d5641453c2 100644 --- a/drivers/media/dvb-frontends/stv6110x.c +++ b/drivers/media/dvb-frontends/stv6110x.c @@ -335,16 +335,6 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status) } -static int stv6110x_release(struct dvb_frontend *fe) -{ - struct stv6110x_state *stv6110x = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(stv6110x); - - return 0; -} - static const struct dvb_tuner_ops stv6110x_ops = { .info = { .name = "STV6110(A) Silicon Tuner", @@ -352,7 +342,7 @@ static const struct dvb_tuner_ops stv6110x_ops = { .frequency_max = 2150000, .frequency_step = 0, }, - .release = stv6110x_release + .release = dvb_tuner_simple_release, }; static const struct stv6110x_devctl stv6110x_ctl = { diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index bc247f9b553a..a324f30f7224 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -1126,14 +1126,6 @@ static int init(struct dvb_frontend *fe) return 0; } -static int release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - - static int set_params(struct dvb_frontend *fe) { struct tda_state *state = fe->tuner_priv; @@ -1227,7 +1219,7 @@ static const struct dvb_tuner_ops tuner_ops = { .init = init, .sleep = sleep, .set_params = set_params, - .release = release, + .release = dvb_tuner_simple_release, .get_if_frequency = get_if_frequency, .get_bandwidth = get_bandwidth, }; diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c index 7ca965987f40..39a1eb23ad04 100644 --- a/drivers/media/dvb-frontends/tda665x.c +++ b/drivers/media/dvb-frontends/tda665x.c @@ -197,20 +197,11 @@ static int tda665x_set_params(struct dvb_frontend *fe) return 0; } -static int tda665x_release(struct dvb_frontend *fe) -{ - struct tda665x_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - return 0; -} - static const struct dvb_tuner_ops tda665x_ops = { .get_status = tda665x_get_status, .set_params = tda665x_set_params, .get_frequency = tda665x_get_frequency, - .release = tda665x_release + .release = dvb_tuner_simple_release, }; struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c index e0df93191b9e..65f729ff27a9 100644 --- a/drivers/media/dvb-frontends/tda8261.c +++ b/drivers/media/dvb-frontends/tda8261.c @@ -152,15 +152,6 @@ static int tda8261_set_params(struct dvb_frontend *fe) return 0; } -static int tda8261_release(struct dvb_frontend *fe) -{ - struct tda8261_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - return 0; -} - static const struct dvb_tuner_ops tda8261_ops = { .info = { @@ -173,7 +164,7 @@ static const struct dvb_tuner_ops tda8261_ops = { .set_params = tda8261_set_params, .get_frequency = tda8261_get_frequency, .get_status = tda8261_get_status, - .release = tda8261_release + .release = dvb_tuner_simple_release, }; struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/tda826x.c b/drivers/media/dvb-frontends/tda826x.c index 2ec671df1441..bf8946c2c04a 100644 --- a/drivers/media/dvb-frontends/tda826x.c +++ b/drivers/media/dvb-frontends/tda826x.c @@ -41,13 +41,6 @@ struct tda826x_priv { u32 frequency; }; -static int tda826x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int tda826x_sleep(struct dvb_frontend *fe) { struct tda826x_priv *priv = fe->tuner_priv; @@ -135,7 +128,7 @@ static const struct dvb_tuner_ops tda826x_tuner_ops = { .frequency_min = 950000, .frequency_max = 2175000 }, - .release = tda826x_release, + .release = dvb_tuner_simple_release, .sleep = tda826x_sleep, .set_params = tda826x_set_params, .get_frequency = tda826x_get_frequency, diff --git a/drivers/media/dvb-frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c index 6da12b9e55eb..9e9a8ad7f37c 100644 --- a/drivers/media/dvb-frontends/tua6100.c +++ b/drivers/media/dvb-frontends/tua6100.c @@ -42,13 +42,6 @@ struct tua6100_priv { u32 frequency; }; -static int tua6100_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int tua6100_sleep(struct dvb_frontend *fe) { struct tua6100_priv *priv = fe->tuner_priv; @@ -164,7 +157,7 @@ static const struct dvb_tuner_ops tua6100_tuner_ops = { .frequency_max = 2150000, .frequency_step = 1000, }, - .release = tua6100_release, + .release = dvb_tuner_simple_release, .sleep = tua6100_sleep, .set_params = tua6100_set_params, .get_frequency = tua6100_get_frequency, diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c index df5d0fe24687..0116557c0f10 100644 --- a/drivers/media/dvb-frontends/zl10036.c +++ b/drivers/media/dvb-frontends/zl10036.c @@ -134,16 +134,6 @@ static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count) return 0; } -static int zl10036_release(struct dvb_frontend *fe) -{ - struct zl10036_state *state = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(state); - - return 0; -} - static int zl10036_sleep(struct dvb_frontend *fe) { struct zl10036_state *state = fe->tuner_priv; @@ -453,7 +443,7 @@ static const struct dvb_tuner_ops zl10036_tuner_ops = { .frequency_max = 2175000 }, .init = zl10036_init, - .release = zl10036_release, + .release = dvb_tuner_simple_release, .sleep = zl10036_sleep, .set_params = zl10036_set_params, .get_frequency = zl10036_get_frequency, diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c index 2dda8d993c14..5e9e2e694f98 100644 --- a/drivers/media/tuners/fc0011.c +++ b/drivers/media/tuners/fc0011.c @@ -112,14 +112,6 @@ static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) return 0; } -static int fc0011_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - static int fc0011_init(struct dvb_frontend *fe) { struct fc0011_priv *priv = fe->tuner_priv; @@ -483,7 +475,7 @@ static const struct dvb_tuner_ops fc0011_tuner_ops = { .frequency_max = 1000000000, }, - .release = fc0011_release, + .release = dvb_tuner_simple_release, .init = fc0011_init, .set_params = fc0011_set_params, diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c index d74e92056810..7faff84e5ea8 100644 --- a/drivers/media/tuners/fc0012.c +++ b/drivers/media/tuners/fc0012.c @@ -55,13 +55,6 @@ static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val) return 0; } -static int fc0012_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int fc0012_init(struct dvb_frontend *fe) { struct fc0012_priv *priv = fe->tuner_priv; @@ -427,7 +420,7 @@ static const struct dvb_tuner_ops fc0012_tuner_ops = { .frequency_step = 0, }, - .release = fc0012_release, + .release = dvb_tuner_simple_release, .init = fc0012_init, diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c index 522690d97b42..b068b9702cf7 100644 --- a/drivers/media/tuners/fc0013.c +++ b/drivers/media/tuners/fc0013.c @@ -52,13 +52,6 @@ static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val) return 0; } -static int fc0013_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int fc0013_init(struct dvb_frontend *fe) { struct fc0013_priv *priv = fe->tuner_priv; @@ -586,7 +579,7 @@ static const struct dvb_tuner_ops fc0013_tuner_ops = { .frequency_step = 0, }, - .release = fc0013_release, + .release = dvb_tuner_simple_release, .init = fc0013_init, .sleep = fc0013_sleep, diff --git a/drivers/media/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c index d5681669d3cd..86542cbd73fb 100644 --- a/drivers/media/tuners/mc44s803.c +++ b/drivers/media/tuners/mc44s803.c @@ -80,16 +80,6 @@ static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) return 0; } -static int mc44s803_release(struct dvb_frontend *fe) -{ - struct mc44s803_priv *priv = fe->tuner_priv; - - fe->tuner_priv = NULL; - kfree(priv); - - return 0; -} - static int mc44s803_init(struct dvb_frontend *fe) { struct mc44s803_priv *priv = fe->tuner_priv; @@ -312,7 +302,7 @@ static const struct dvb_tuner_ops mc44s803_tuner_ops = { .frequency_step = 100000, }, - .release = mc44s803_release, + .release = dvb_tuner_simple_release, .init = mc44s803_init, .set_params = mc44s803_set_params, .get_frequency = mc44s803_get_frequency, diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c index b87b2549d58d..14e7b64360cb 100644 --- a/drivers/media/tuners/mt2060.c +++ b/drivers/media/tuners/mt2060.c @@ -332,13 +332,6 @@ static int mt2060_sleep(struct dvb_frontend *fe) return ret; } -static int mt2060_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static const struct dvb_tuner_ops mt2060_tuner_ops = { .info = { .name = "Microtune MT2060", @@ -347,7 +340,7 @@ static const struct dvb_tuner_ops mt2060_tuner_ops = { .frequency_step = 50000, }, - .release = mt2060_release, + .release = dvb_tuner_simple_release, .init = mt2060_init, .sleep = mt2060_sleep, diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c index 29dadd171b31..4237d8f15919 100644 --- a/drivers/media/tuners/mt20xx.c +++ b/drivers/media/tuners/mt20xx.c @@ -49,14 +49,6 @@ struct microtune_priv { u32 frequency; }; -static int microtune_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct microtune_priv *priv = fe->tuner_priv; @@ -365,7 +357,7 @@ static int mt2032_set_params(struct dvb_frontend *fe, static const struct dvb_tuner_ops mt2032_tuner_ops = { .set_analog_params = mt2032_set_params, - .release = microtune_release, + .release = dvb_tuner_simple_release, .get_frequency = microtune_get_frequency, }; @@ -560,7 +552,7 @@ static int mt2050_set_params(struct dvb_frontend *fe, static const struct dvb_tuner_ops mt2050_tuner_ops = { .set_analog_params = mt2050_set_params, - .release = microtune_release, + .release = dvb_tuner_simple_release, .get_frequency = microtune_get_frequency, }; diff --git a/drivers/media/tuners/mt2266.c b/drivers/media/tuners/mt2266.c index bca4d75e42d4..35ea5e7975ac 100644 --- a/drivers/media/tuners/mt2266.c +++ b/drivers/media/tuners/mt2266.c @@ -296,13 +296,6 @@ static int mt2266_sleep(struct dvb_frontend *fe) return 0; } -static int mt2266_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static const struct dvb_tuner_ops mt2266_tuner_ops = { .info = { .name = "Microtune MT2266", @@ -310,7 +303,7 @@ static const struct dvb_tuner_ops mt2266_tuner_ops = { .frequency_max = 862000000, .frequency_step = 50000, }, - .release = mt2266_release, + .release = dvb_tuner_simple_release, .init = mt2266_init, .sleep = mt2266_sleep, .set_params = mt2266_set_params, diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c index ae8cbece6d2b..5a1662aeeb87 100644 --- a/drivers/media/tuners/qt1010.c +++ b/drivers/media/tuners/qt1010.c @@ -377,13 +377,6 @@ static int qt1010_init(struct dvb_frontend *fe) return qt1010_set_params(fe); } -static int qt1010_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct qt1010_priv *priv = fe->tuner_priv; @@ -405,7 +398,7 @@ static const struct dvb_tuner_ops qt1010_tuner_ops = { .frequency_step = QT1010_STEP, }, - .release = qt1010_release, + .release = dvb_tuner_simple_release, .init = qt1010_init, /* TODO: implement sleep */ diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c index 9300e9361e3b..4d2916fb9953 100644 --- a/drivers/media/tuners/tda18218.c +++ b/drivers/media/tuners/tda18218.c @@ -265,13 +265,6 @@ static int tda18218_init(struct dvb_frontend *fe) return ret; } -static int tda18218_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static const struct dvb_tuner_ops tda18218_tuner_ops = { .info = { .name = "NXP TDA18218", @@ -281,7 +274,7 @@ static const struct dvb_tuner_ops tda18218_tuner_ops = { .frequency_step = 1000, }, - .release = tda18218_release, + .release = dvb_tuner_simple_release, .init = tda18218_init, .sleep = tda18218_sleep, diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c index 5050ce9be423..4befb81f0c1a 100644 --- a/drivers/media/tuners/tda827x.c +++ b/drivers/media/tuners/tda827x.c @@ -767,13 +767,6 @@ static void tda827xa_agcf(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ -static int tda827x_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - return 0; -} - static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tda827x_priv *priv = fe->tuner_priv; @@ -825,7 +818,7 @@ static const struct dvb_tuner_ops tda827xo_tuner_ops = { .frequency_max = 860000000, .frequency_step = 250000 }, - .release = tda827x_release, + .release = dvb_tuner_simple_release, .init = tda827x_initial_init, .sleep = tda827x_initial_sleep, .set_params = tda827xo_set_params, @@ -841,7 +834,7 @@ static const struct dvb_tuner_ops tda827xa_tuner_ops = { .frequency_max = 906000000, .frequency_step = 62500 }, - .release = tda827x_release, + .release = dvb_tuner_simple_release, .init = tda827x_init, .sleep = tda827xa_sleep, .set_params = tda827xa_set_params, diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c index 12347aa95de3..82f25621d995 100644 --- a/drivers/media/tuners/tea5761.c +++ b/drivers/media/tuners/tea5761.c @@ -284,14 +284,6 @@ int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return 0; } -static int tea5761_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5761_priv *priv = fe->tuner_priv; @@ -305,7 +297,7 @@ static const struct dvb_tuner_ops tea5761_tuner_ops = { }, .set_analog_params = set_radio_freq, .sleep = set_radio_sleep, - .release = tea5761_release, + .release = dvb_tuner_simple_release, .get_frequency = tea5761_get_frequency, .get_status = tea5761_get_status, .get_rf_strength = tea5761_get_rf_strength, diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c index d62a6d6b1f42..a33c97de8b8a 100644 --- a/drivers/media/tuners/tea5767.c +++ b/drivers/media/tuners/tea5767.c @@ -401,14 +401,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return 0; } -static int tea5767_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; - - return 0; -} - static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5767_priv *priv = fe->tuner_priv; @@ -434,7 +426,7 @@ static const struct dvb_tuner_ops tea5767_tuner_ops = { .set_analog_params = set_radio_freq, .set_config = tea5767_set_config, .sleep = tea5767_standby, - .release = tea5767_release, + .release = dvb_tuner_simple_release, .get_frequency = tea5767_get_frequency, .get_status = tea5767_get_status, .get_rf_strength = tea5767_get_rf_strength, -- cgit v1.2.3 From 194ced7a5a99b303daf0bca6d0a1697731265602 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:31 -0300 Subject: [media] dvb_frontend: tuner_ops.release returns void It is not clear what this return value means. All implemenations return 0, and the one caller ignores the value. Let's remove this useless return value completely. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 3 +-- drivers/media/dvb-core/dvb_frontend.h | 4 ++-- drivers/media/dvb-frontends/ascot2e.c | 3 +-- drivers/media/dvb-frontends/cx24113.c | 3 +-- drivers/media/dvb-frontends/helene.c | 3 +-- drivers/media/dvb-frontends/horus3a.c | 3 +-- drivers/media/dvb-frontends/ts2020.c | 3 +-- drivers/media/dvb-frontends/zl10039.c | 3 +-- drivers/media/tuners/max2165.c | 4 +--- drivers/media/tuners/mt2063.c | 4 +--- drivers/media/tuners/mt2131.c | 3 +-- drivers/media/tuners/mxl5005s.c | 3 +-- drivers/media/tuners/mxl5007t.c | 4 +--- drivers/media/tuners/r820t.c | 4 +--- drivers/media/tuners/tda18271-fe.c | 4 +--- drivers/media/tuners/tuner-simple.c | 4 +--- drivers/media/tuners/tuner-xc2028.c | 4 +--- drivers/media/tuners/xc4000.c | 4 +--- drivers/media/tuners/xc5000.c | 4 +--- drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c | 3 +-- 20 files changed, 21 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 7c4a50b0b963..023a7e4e6168 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -174,12 +174,11 @@ static bool has_get_frontend(struct dvb_frontend *fe) return fe->ops.get_frontend != NULL; } -int +void dvb_tuner_simple_release(struct dvb_frontend *fe) { kfree(fe->tuner_priv); fe->tuner_priv = NULL; - return 0; } EXPORT_SYMBOL(dvb_tuner_simple_release); diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 6b675a833520..5bfb16bf188f 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -225,7 +225,7 @@ struct dvb_tuner_ops { struct dvb_tuner_info info; - int (*release)(struct dvb_frontend *fe); + void (*release)(struct dvb_frontend *fe); int (*init)(struct dvb_frontend *fe); int (*sleep)(struct dvb_frontend *fe); int (*suspend)(struct dvb_frontend *fe); @@ -270,7 +270,7 @@ struct dvb_tuner_ops { * A common default implementation for dvb_tuner_ops.release. All it * does is kfree() the tuner_priv and assign NULL to it. */ -int +void dvb_tuner_simple_release(struct dvb_frontend *fe); /** diff --git a/drivers/media/dvb-frontends/ascot2e.c b/drivers/media/dvb-frontends/ascot2e.c index ad304eed656d..0ee0df53b91b 100644 --- a/drivers/media/dvb-frontends/ascot2e.c +++ b/drivers/media/dvb-frontends/ascot2e.c @@ -254,14 +254,13 @@ static int ascot2e_init(struct dvb_frontend *fe) return ascot2e_leave_power_save(priv); } -static int ascot2e_release(struct dvb_frontend *fe) +static void ascot2e_release(struct dvb_frontend *fe) { struct ascot2e_priv *priv = fe->tuner_priv; dev_dbg(&priv->i2c->dev, "%s()\n", __func__); kfree(fe->tuner_priv); fe->tuner_priv = NULL; - return 0; } static int ascot2e_sleep(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/cx24113.c b/drivers/media/dvb-frontends/cx24113.c index 3812ef8cac08..db44ebb7c561 100644 --- a/drivers/media/dvb-frontends/cx24113.c +++ b/drivers/media/dvb-frontends/cx24113.c @@ -527,13 +527,12 @@ static int cx24113_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int cx24113_release(struct dvb_frontend *fe) +static void cx24113_release(struct dvb_frontend *fe) { struct cx24113_state *state = fe->tuner_priv; dprintk("\n"); fe->tuner_priv = NULL; kfree(state); - return 0; } static const struct dvb_tuner_ops cx24113_tuner_ops = { diff --git a/drivers/media/dvb-frontends/helene.c b/drivers/media/dvb-frontends/helene.c index dc43c5f6d0ea..ef35c2b30ea3 100644 --- a/drivers/media/dvb-frontends/helene.c +++ b/drivers/media/dvb-frontends/helene.c @@ -434,14 +434,13 @@ static int helene_init(struct dvb_frontend *fe) return helene_leave_power_save(priv); } -static int helene_release(struct dvb_frontend *fe) +static void helene_release(struct dvb_frontend *fe) { struct helene_priv *priv = fe->tuner_priv; dev_dbg(&priv->i2c->dev, "%s()\n", __func__); kfree(fe->tuner_priv); fe->tuner_priv = NULL; - return 0; } static int helene_sleep(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/horus3a.c b/drivers/media/dvb-frontends/horus3a.c index 0c089b5986a1..94bb4f7a2298 100644 --- a/drivers/media/dvb-frontends/horus3a.c +++ b/drivers/media/dvb-frontends/horus3a.c @@ -151,14 +151,13 @@ static int horus3a_init(struct dvb_frontend *fe) return 0; } -static int horus3a_release(struct dvb_frontend *fe) +static void horus3a_release(struct dvb_frontend *fe) { struct horus3a_priv *priv = fe->tuner_priv; dev_dbg(&priv->i2c->dev, "%s()\n", __func__); kfree(fe->tuner_priv); fe->tuner_priv = NULL; - return 0; } static int horus3a_sleep(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c index a9f6bbea6df3..931e5c98da8a 100644 --- a/drivers/media/dvb-frontends/ts2020.c +++ b/drivers/media/dvb-frontends/ts2020.c @@ -56,7 +56,7 @@ struct ts2020_reg_val { static void ts2020_stat_work(struct work_struct *work); -static int ts2020_release(struct dvb_frontend *fe) +static void ts2020_release(struct dvb_frontend *fe) { struct ts2020_priv *priv = fe->tuner_priv; struct i2c_client *client = priv->client; @@ -64,7 +64,6 @@ static int ts2020_release(struct dvb_frontend *fe) dev_dbg(&client->dev, "\n"); i2c_unregister_device(client); - return 0; } static int ts2020_sleep(struct dvb_frontend *fe) diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c index d6ded11fee49..60a2954f8ff8 100644 --- a/drivers/media/dvb-frontends/zl10039.c +++ b/drivers/media/dvb-frontends/zl10039.c @@ -244,14 +244,13 @@ error: return ret; } -static int zl10039_release(struct dvb_frontend *fe) +static void zl10039_release(struct dvb_frontend *fe) { struct zl10039_state *state = fe->tuner_priv; dprintk("%s\n", __func__); kfree(state); fe->tuner_priv = NULL; - return 0; } static const struct dvb_tuner_ops zl10039_ops = { diff --git a/drivers/media/tuners/max2165.c b/drivers/media/tuners/max2165.c index 353b178becf6..c3f10925b0d4 100644 --- a/drivers/media/tuners/max2165.c +++ b/drivers/media/tuners/max2165.c @@ -370,15 +370,13 @@ static int max2165_init(struct dvb_frontend *fe) return 0; } -static int max2165_release(struct dvb_frontend *fe) +static void max2165_release(struct dvb_frontend *fe) { struct max2165_priv *priv = fe->tuner_priv; dprintk("%s()\n", __func__); kfree(priv); fe->tuner_priv = NULL; - - return 0; } static const struct dvb_tuner_ops max2165_tuner_ops = { diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c index dfec23743afe..8b39d8dc97a0 100644 --- a/drivers/media/tuners/mt2063.c +++ b/drivers/media/tuners/mt2063.c @@ -2019,7 +2019,7 @@ static int mt2063_get_status(struct dvb_frontend *fe, u32 *tuner_status) return 0; } -static int mt2063_release(struct dvb_frontend *fe) +static void mt2063_release(struct dvb_frontend *fe) { struct mt2063_state *state = fe->tuner_priv; @@ -2027,8 +2027,6 @@ static int mt2063_release(struct dvb_frontend *fe) fe->tuner_priv = NULL; kfree(state); - - return 0; } static int mt2063_set_analog_params(struct dvb_frontend *fe, diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c index 6e2cdd2b6175..e7790e4afcfe 100644 --- a/drivers/media/tuners/mt2131.c +++ b/drivers/media/tuners/mt2131.c @@ -230,12 +230,11 @@ static int mt2131_init(struct dvb_frontend *fe) return ret; } -static int mt2131_release(struct dvb_frontend *fe) +static void mt2131_release(struct dvb_frontend *fe) { dprintk(1, "%s()\n", __func__); kfree(fe->tuner_priv); fe->tuner_priv = NULL; - return 0; } static const struct dvb_tuner_ops mt2131_tuner_ops = { diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c index 92a3be4fde87..353744fee053 100644 --- a/drivers/media/tuners/mxl5005s.c +++ b/drivers/media/tuners/mxl5005s.c @@ -4063,12 +4063,11 @@ static int mxl5005s_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int mxl5005s_release(struct dvb_frontend *fe) +static void mxl5005s_release(struct dvb_frontend *fe) { dprintk(1, "%s()\n", __func__); kfree(fe->tuner_priv); fe->tuner_priv = NULL; - return 0; } static const struct dvb_tuner_ops mxl5005s_tuner_ops = { diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c index 42569c6811e6..b16dfa5e85fb 100644 --- a/drivers/media/tuners/mxl5007t.c +++ b/drivers/media/tuners/mxl5007t.c @@ -776,7 +776,7 @@ static int mxl5007t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int mxl5007t_release(struct dvb_frontend *fe) +static void mxl5007t_release(struct dvb_frontend *fe) { struct mxl5007t_state *state = fe->tuner_priv; @@ -788,8 +788,6 @@ static int mxl5007t_release(struct dvb_frontend *fe) mutex_unlock(&mxl5007t_list_mutex); fe->tuner_priv = NULL; - - return 0; } /* ------------------------------------------------------------------------- */ diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c index 08dca40356d2..ba80376a3b86 100644 --- a/drivers/media/tuners/r820t.c +++ b/drivers/media/tuners/r820t.c @@ -2286,7 +2286,7 @@ static int r820t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } -static int r820t_release(struct dvb_frontend *fe) +static void r820t_release(struct dvb_frontend *fe) { struct r820t_priv *priv = fe->tuner_priv; @@ -2300,8 +2300,6 @@ static int r820t_release(struct dvb_frontend *fe) mutex_unlock(&r820t_list_mutex); fe->tuner_priv = NULL; - - return 0; } static const struct dvb_tuner_ops r820t_tuner_ops = { diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c index a4730610c0c6..b4e5fa2ff5e5 100644 --- a/drivers/media/tuners/tda18271-fe.c +++ b/drivers/media/tuners/tda18271-fe.c @@ -1048,7 +1048,7 @@ fail: return ret; } -static int tda18271_release(struct dvb_frontend *fe) +static void tda18271_release(struct dvb_frontend *fe) { struct tda18271_priv *priv = fe->tuner_priv; @@ -1060,8 +1060,6 @@ static int tda18271_release(struct dvb_frontend *fe) mutex_unlock(&tda18271_list_mutex); fe->tuner_priv = NULL; - - return 0; } static int tda18271_get_frequency(struct dvb_frontend *fe, u32 *frequency) diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c index 315f45cd0778..3339b13dd3f5 100644 --- a/drivers/media/tuners/tuner-simple.c +++ b/drivers/media/tuners/tuner-simple.c @@ -1001,7 +1001,7 @@ static int simple_sleep(struct dvb_frontend *fe) return 0; } -static int simple_release(struct dvb_frontend *fe) +static void simple_release(struct dvb_frontend *fe) { struct tuner_simple_priv *priv = fe->tuner_priv; @@ -1013,8 +1013,6 @@ static int simple_release(struct dvb_frontend *fe) mutex_unlock(&tuner_simple_list_mutex); fe->tuner_priv = NULL; - - return 0; } static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency) diff --git a/drivers/media/tuners/tuner-xc2028.c b/drivers/media/tuners/tuner-xc2028.c index e07c5fb59cc6..1a9665404ada 100644 --- a/drivers/media/tuners/tuner-xc2028.c +++ b/drivers/media/tuners/tuner-xc2028.c @@ -1321,7 +1321,7 @@ static int xc2028_sleep(struct dvb_frontend *fe) return rc; } -static int xc2028_dvb_release(struct dvb_frontend *fe) +static void xc2028_dvb_release(struct dvb_frontend *fe) { struct xc2028_data *priv = fe->tuner_priv; @@ -1342,8 +1342,6 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) mutex_unlock(&xc2028_list_mutex); fe->tuner_priv = NULL; - - return 0; } static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency) diff --git a/drivers/media/tuners/xc4000.c b/drivers/media/tuners/xc4000.c index ac98dea985c8..03eef9b87a24 100644 --- a/drivers/media/tuners/xc4000.c +++ b/drivers/media/tuners/xc4000.c @@ -1618,7 +1618,7 @@ static int xc4000_init(struct dvb_frontend *fe) return 0; } -static int xc4000_release(struct dvb_frontend *fe) +static void xc4000_release(struct dvb_frontend *fe) { struct xc4000_priv *priv = fe->tuner_priv; @@ -1632,8 +1632,6 @@ static int xc4000_release(struct dvb_frontend *fe) mutex_unlock(&xc4000_list_mutex); fe->tuner_priv = NULL; - - return 0; } static const struct dvb_tuner_ops xc4000_tuner_ops = { diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c index e6e5e90d8d95..796e7638b3b2 100644 --- a/drivers/media/tuners/xc5000.c +++ b/drivers/media/tuners/xc5000.c @@ -1326,7 +1326,7 @@ static int xc5000_init(struct dvb_frontend *fe) return 0; } -static int xc5000_release(struct dvb_frontend *fe) +static void xc5000_release(struct dvb_frontend *fe) { struct xc5000_priv *priv = fe->tuner_priv; @@ -1346,8 +1346,6 @@ static int xc5000_release(struct dvb_frontend *fe) mutex_unlock(&xc5000_list_mutex); fe->tuner_priv = NULL; - - return 0; } static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg) diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c index f141dcc55cc9..f84bef6034dc 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c @@ -455,13 +455,12 @@ static int mxl111sf_tuner_get_if_frequency(struct dvb_frontend *fe, return 0; } -static int mxl111sf_tuner_release(struct dvb_frontend *fe) +static void mxl111sf_tuner_release(struct dvb_frontend *fe) { struct mxl111sf_tuner_state *state = fe->tuner_priv; mxl_dbg("()"); kfree(state); fe->tuner_priv = NULL; - return 0; } /* ------------------------------------------------------------------------- */ -- cgit v1.2.3 From 967d8e8f4caca396e6c4c8a8cf18765aa16cfdaf Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:36 -0300 Subject: [media] dvb_frontend: merge the two dvb_frontend_detach() versions This code duplication is confusing and error prone. Let's merge them by moving the release/dvb_detach call into one function with one Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 42 ++++++++++------------------------- 1 file changed, 12 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 023a7e4e6168..2465b0d7f43c 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2740,40 +2740,22 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) } EXPORT_SYMBOL(dvb_unregister_frontend); -#ifdef CONFIG_MEDIA_ATTACH -void dvb_frontend_detach(struct dvb_frontend* fe) +static void dvb_frontend_invoke_release(struct dvb_frontend *fe, + void (*release)(struct dvb_frontend *fe)) { - void *ptr; - - if (fe->ops.release_sec) { - fe->ops.release_sec(fe); - dvb_detach(fe->ops.release_sec); - } - if (fe->ops.tuner_ops.release) { - fe->ops.tuner_ops.release(fe); - dvb_detach(fe->ops.tuner_ops.release); - } - if (fe->ops.analog_ops.release) { - fe->ops.analog_ops.release(fe); - dvb_detach(fe->ops.analog_ops.release); - } - ptr = (void*)fe->ops.release; - if (ptr) { - fe->ops.release(fe); - dvb_detach(ptr); + if (release) { + release(fe); +#ifdef CONFIG_MEDIA_ATTACH + dvb_detach(release); +#endif } } -#else + void dvb_frontend_detach(struct dvb_frontend* fe) { - if (fe->ops.release_sec) - fe->ops.release_sec(fe); - if (fe->ops.tuner_ops.release) - fe->ops.tuner_ops.release(fe); - if (fe->ops.analog_ops.release) - fe->ops.analog_ops.release(fe); - if (fe->ops.release) - fe->ops.release(fe); + dvb_frontend_invoke_release(fe, fe->ops.release_sec); + dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); + dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release); + dvb_frontend_invoke_release(fe, fe->ops.release); } -#endif EXPORT_SYMBOL(dvb_frontend_detach); -- cgit v1.2.3 From d812b3caea394a6c60e8d6a4ad46b941690435e3 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:41 -0300 Subject: [media] dvb_frontend: add "detach" callback Prepare for making "release" asynchronous (via kref). Some operations may need to be run synchronously in dvb_frontend_detach(), and that's why we need a "detach" callback. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 1 + drivers/media/dvb-core/dvb_frontend.h | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 2465b0d7f43c..667c5e7aaa3e 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -2756,6 +2756,7 @@ void dvb_frontend_detach(struct dvb_frontend* fe) dvb_frontend_invoke_release(fe, fe->ops.release_sec); dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release); + dvb_frontend_invoke_release(fe, fe->ops.detach); dvb_frontend_invoke_release(fe, fe->ops.release); } EXPORT_SYMBOL(dvb_frontend_detach); diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index 5bfb16bf188f..d5355718f365 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -330,7 +330,11 @@ struct dtv_frontend_properties; * * @info: embedded struct dvb_tuner_info with tuner properties * @delsys: Delivery systems supported by the frontend - * @release: callback function called when frontend is dettached. + * @detach: callback function called when frontend is detached. + * drivers should clean up, but not yet free the struct + * dvb_frontend allocation. + * @release: callback function called when frontend is ready to be + * freed. * drivers should free any allocated memory. * @release_sec: callback function requesting that the Satelite Equipment * Control (SEC) driver to release and free any memory @@ -415,6 +419,7 @@ struct dvb_frontend_ops { u8 delsys[MAX_DELSYS]; + void (*detach)(struct dvb_frontend *fe); void (*release)(struct dvb_frontend* fe); void (*release_sec)(struct dvb_frontend* fe); -- cgit v1.2.3 From f686c14364ade79a373ef65c0fecfc2953ca8da5 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:46 -0300 Subject: [media] stb0899: move code to "detach" callback Ensure that STB0899_POSTPROC_GPIO_POWER is set synchronously. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stb0899_drv.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index cc18891f9b45..02347598277a 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -601,13 +601,19 @@ static int stb0899_postproc(struct stb0899_state *state, u8 ctl, int enable) return 0; } -static void stb0899_release(struct dvb_frontend *fe) +static void stb0899_detach(struct dvb_frontend *fe) { struct stb0899_state *state = fe->demodulator_priv; - dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend"); /* post process event */ stb0899_postproc(state, STB0899_POSTPROC_GPIO_POWER, 0); +} + +static void stb0899_release(struct dvb_frontend *fe) +{ + struct stb0899_state *state = fe->demodulator_priv; + + dprintk(state->verbose, FE_DEBUG, 1, "Release Frontend"); kfree(state); } @@ -1590,6 +1596,7 @@ static const struct dvb_frontend_ops stb0899_ops = { FE_CAN_QPSK }, + .detach = stb0899_detach, .release = stb0899_release, .init = stb0899_init, .sleep = stb0899_sleep, -- cgit v1.2.3 From 1f862a68df2449bc7b1cf78dce616891697b4bdf Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:32:51 -0300 Subject: [media] dvb_frontend: move kref to struct dvb_frontend This commit amends my old commit fe35637b0a9f ("[media] dvb_frontend: eliminate blocking wait in dvb_unregister_frontend()"), which added kref to struct dvb_frontend_private. It turned out that there are several use-after-free bugs left, which affect the struct dvb_frontend. Protecting it with kref also protects struct dvb_frontend_private, so we can simply move it. This is how the use-after-free looks like in KASAN: BUG: KASAN: use-after-free in string+0x60/0xb1 at addr ffff880033bd9fc0 Read of size 1 by task kworker/0:2/617 CPU: 0 PID: 617 Comm: kworker/0:2 Not tainted 4.8.0-rc1-hosting+ #60 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Workqueue: usb_hub_wq hub_event 0000000000000000 ffff880033757218 ffffffff81394e50 ffff880033bd9fd0 ffff880035c03b00 ffff880033757240 ffffffff811f271d ffff880033bd9fc0 1ffff1000677b3f8 ffffed000677b3f8 ffff8800337572b8 ffffffff811f2afe Call Trace: [...] [] vsnprintf+0x39d/0x7e9 [] add_uevent_var+0x10f/0x1dc [] rc_dev_uevent+0x55/0x6f [] dev_uevent+0x2e1/0x316 [] kobject_uevent_env+0x27e/0x701 [] kobject_uevent+0xb/0xd [] device_del+0x322/0x383 [] rc_unregister_device+0x98/0xc3 [] dvb_usb_remote_exit+0x7a/0x90 [] dvb_usb_exit+0x1d/0xe5 [] dvb_usb_device_exit+0x69/0x7d [] pctv452e_usb_disconnect+0x7b/0x80 [...] Object at ffff880033bd9fc0, in cache kmalloc-16 size: 16 Allocated: [...] Freed: PID = 617 [...] [] kfree+0xd9/0x166 [] ir_free_table+0x2f/0x51 [] rc_unregister_device+0x4d/0xc3 [] dvb_usb_remote_exit+0x7a/0x90 [] dvb_usb_exit+0x1d/0xe5 [] dvb_usb_device_exit+0x69/0x7d [] pctv452e_usb_disconnect+0x7b/0x80 Another one: BUG: KASAN: use-after-free in do_sys_poll+0x336/0x6b8 at addr ffff88003563fcc0 Read of size 8 by task tuner on fronte/1042 CPU: 1 PID: 1042 Comm: tuner on fronte Tainted: G B 4.8.0-rc1-hosting+ #60 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 0000000000000000 ffff88003353f910 ffffffff81394e50 ffff88003563fd80 ffff880035c03200 ffff88003353f938 ffffffff811f271d ffff88003563fc80 1ffff10006ac7f98 ffffed0006ac7f98 ffff88003353f9b0 ffffffff811f2afe Call Trace: [...] [] do_sys_poll+0x336/0x6b8 [...] [] SyS_poll+0xa9/0x194 [...] Object at ffff88003563fc80, in cache kmalloc-256 size: 256 Allocated: [...] Freed: PID = 617 [...] [] kfree+0xd9/0x166 [] dvb_unregister_device+0xd6/0xe5 [] dvb_unregister_frontend+0x4b/0x66 [] dvb_usb_adapter_frontend_exit+0x69/0xac [] dvb_usb_exit+0x43/0xe5 [] dvb_usb_device_exit+0x69/0x7d [] pctv452e_usb_disconnect+0x7b/0x80 Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 46 +++++++++++++++++++++++------------ drivers/media/dvb-core/dvb_frontend.h | 1 + 2 files changed, 31 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 667c5e7aaa3e..87f1346e1fec 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -104,8 +104,6 @@ MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to seconds on open( static DEFINE_MUTEX(frontend_mutex); struct dvb_frontend_private { - struct kref refcount; - /* thread/frontend values */ struct dvb_device *dvbdev; struct dvb_frontend_parameters parameters_out; @@ -143,21 +141,30 @@ struct dvb_frontend_private { #endif }; -static void dvb_frontend_private_free(struct kref *ref) +static void dvb_frontend_invoke_release(struct dvb_frontend *fe, + void (*release)(struct dvb_frontend *fe)); + +static void dvb_frontend_free(struct kref *ref) { - struct dvb_frontend_private *fepriv = - container_of(ref, struct dvb_frontend_private, refcount); + struct dvb_frontend *fe = + container_of(ref, struct dvb_frontend, refcount); + struct dvb_frontend_private *fepriv = fe->frontend_priv; + + dvb_free_device(fepriv->dvbdev); + + dvb_frontend_invoke_release(fe, fe->ops.release); + kfree(fepriv); } -static void dvb_frontend_private_put(struct dvb_frontend_private *fepriv) +static void dvb_frontend_put(struct dvb_frontend *fe) { - kref_put(&fepriv->refcount, dvb_frontend_private_free); + kref_put(&fe->refcount, dvb_frontend_free); } -static void dvb_frontend_private_get(struct dvb_frontend_private *fepriv) +static void dvb_frontend_get(struct dvb_frontend *fe) { - kref_get(&fepriv->refcount); + kref_get(&fe->refcount); } static void dvb_frontend_wakeup(struct dvb_frontend *fe); @@ -2555,7 +2562,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) fepriv->events.eventr = fepriv->events.eventw = 0; } - dvb_frontend_private_get(fepriv); + dvb_frontend_get(fe); if (adapter->mfe_shared) mutex_unlock (&adapter->mfe_lock); @@ -2605,7 +2612,7 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) fe->ops.ts_bus_ctrl(fe, 0); } - dvb_frontend_private_put(fepriv); + dvb_frontend_put(fe); return ret; } @@ -2695,7 +2702,14 @@ int dvb_register_frontend(struct dvb_adapter* dvb, } fepriv = fe->frontend_priv; - kref_init(&fepriv->refcount); + kref_init(&fe->refcount); + + /* + * After initialization, there need to be two references: one + * for dvb_unregister_frontend(), and another one for + * dvb_frontend_detach(). + */ + dvb_frontend_get(fe); sema_init(&fepriv->sem, 1); init_waitqueue_head (&fepriv->wait_queue); @@ -2730,12 +2744,12 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) dev_dbg(fe->dvb->device, "%s:\n", __func__); mutex_lock(&frontend_mutex); - dvb_frontend_stop (fe); - dvb_unregister_device (fepriv->dvbdev); + dvb_frontend_stop(fe); + dvb_remove_device(fepriv->dvbdev); /* fe is invalid now */ mutex_unlock(&frontend_mutex); - dvb_frontend_private_put(fepriv); + dvb_frontend_put(fe); return 0; } EXPORT_SYMBOL(dvb_unregister_frontend); @@ -2757,6 +2771,6 @@ void dvb_frontend_detach(struct dvb_frontend* fe) dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release); dvb_frontend_invoke_release(fe, fe->ops.detach); - dvb_frontend_invoke_release(fe, fe->ops.release); + dvb_frontend_put(fe); } EXPORT_SYMBOL(dvb_frontend_detach); diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index d5355718f365..f21b255c61de 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -667,6 +667,7 @@ struct dtv_frontend_properties { */ struct dvb_frontend { + struct kref refcount; struct dvb_frontend_ops ops; struct dvb_adapter *dvb; void *demodulator_priv; -- cgit v1.2.3 From 6753743e11540b7fc54d03771458e2bd91ba411b Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 23:32:57 +0200 Subject: [media] media-entity: clear media_gobj.mdev in _destroy() media_gobj_destroy() may be called twice on one instance - once by media_device_unregister() and again by dvb_media_device_free(). The function media_remove_intf_links() establishes and documents the convention that mdev==NULL means that the object is not registered, but nobody ever NULLs this variable. So this patch really implements this behavior, and adds another mdev==NULL check to media_gobj_destroy() to protect against double removal. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-entity.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c index c68239e60487..f9f723f5e4f0 100644 --- a/drivers/media/media-entity.c +++ b/drivers/media/media-entity.c @@ -205,10 +205,16 @@ void media_gobj_destroy(struct media_gobj *gobj) { dev_dbg_obj(__func__, gobj); + /* Do nothing if the object is not linked. */ + if (gobj->mdev == NULL) + return; + gobj->mdev->topology_version++; /* Remove the object from mdev list */ list_del(&gobj->list); + + gobj->mdev = NULL; } int media_entity_pads_init(struct media_entity *entity, u16 num_pads, -- cgit v1.2.3 From e7cd17a29d72868aa5cfbbd4de7c54a28ed30ff0 Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Tue, 9 Aug 2016 18:33:03 -0300 Subject: [media] drivers/media/media-device: fix double free bug in _unregister() While removing all interfaces in media_device_unregister(), all media_interface pointers are freed. This is illegal and results in double kfree() if any media_interface is still linked at this point; maybe because a userspace process still has a file handle. Once the process closes the file handle, dvb_media_device_free() gets called, which frees the dvb_device.intf_devnode again. This patch removes the unnecessary kfree() call, and documents who's responsible for really freeing it. Signed-off-by: Max Kellermann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 2783531f9fc0..219ab5fc8b4c 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -801,9 +801,13 @@ void media_device_unregister(struct media_device *mdev) /* Remove all interfaces from the media device */ list_for_each_entry_safe(intf, tmp_intf, &mdev->interfaces, graph_obj.list) { + /* + * Unlink the interface, but don't free it here; the + * module which created it is responsible for freeing + * it + */ __media_remove_intf_links(intf); media_gobj_destroy(&intf->graph_obj); - kfree(intf); } mutex_unlock(&mdev->graph_mutex); -- cgit v1.2.3 From b24ccccaee5e6a73f461b1ca7bbb55d3dfc24a2d Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 25 Oct 2016 17:23:37 -0200 Subject: [media] media: rc: nuvoton: eliminate member pdev from struct nvt_dev Member pdev of struct nvt_dev is needed only to access &pdev->dev. We can get rid of this it by using rdev->dev.parent instead (both point to the same struct device). Setting rdev->dev.parent can be removed from the probe function as this is done by devm_rc_allocate_device now. Signed-off-by: Heiner Kallweit Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 27 ++++++++++++++------------- drivers/media/rc/nuvoton-cir.h | 1 - 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 3df3bd9aab7e..0705d51e4238 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -48,6 +48,11 @@ static const struct nvt_chip nvt_chips[] = { { "NCT6779D", NVT_6779D }, }; +static inline struct device *nvt_get_dev(const struct nvt_dev *nvt) +{ + return nvt->rdev->dev.parent; +} + static inline bool is_w83667hg(struct nvt_dev *nvt) { return nvt->chip_ver == NVT_W83667HG; @@ -385,6 +390,7 @@ static inline const char *nvt_find_chip(struct nvt_dev *nvt, int id) /* detect hardware features */ static int nvt_hw_detect(struct nvt_dev *nvt) { + struct device *dev = nvt_get_dev(nvt); const char *chip_name; int chip_id; @@ -405,8 +411,7 @@ static int nvt_hw_detect(struct nvt_dev *nvt) chip_id = nvt->chip_major << 8 | nvt->chip_minor; if (chip_id == NVT_INVALID) { - dev_err(&nvt->pdev->dev, - "No device found on either EFM port\n"); + dev_err(dev, "No device found on either EFM port\n"); return -ENODEV; } @@ -414,12 +419,11 @@ static int nvt_hw_detect(struct nvt_dev *nvt) /* warn, but still let the driver load, if we don't know this chip */ if (!chip_name) - dev_warn(&nvt->pdev->dev, + dev_warn(dev, "unknown chip, id: 0x%02x 0x%02x, it may not work...", nvt->chip_major, nvt->chip_minor); else - dev_info(&nvt->pdev->dev, - "found %s or compatible: chip id: 0x%02x 0x%02x", + dev_info(dev, "found %s or compatible: chip id: 0x%02x 0x%02x", chip_name, nvt->chip_major, nvt->chip_minor); return 0; @@ -616,7 +620,7 @@ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) duration *= SAMPLE_PERIOD; if (!count || !duration) { - dev_notice(&nvt->pdev->dev, + dev_notice(nvt_get_dev(nvt), "Unable to determine carrier! (c:%u, d:%u)", count, duration); return 0; @@ -781,7 +785,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt) static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt) { - dev_warn(&nvt->pdev->dev, "RX FIFO overrun detected, flushing data!"); + dev_warn(nvt_get_dev(nvt), "RX FIFO overrun detected, flushing data!"); nvt->pkts = 0; nvt_clear_cir_fifo(nvt); @@ -1009,9 +1013,10 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) return -ENOMEM; /* input device for IR remote (and tx) */ - rdev = devm_rc_allocate_device(&pdev->dev); - if (!rdev) + nvt->rdev = devm_rc_allocate_device(&pdev->dev); + if (!nvt->rdev) return -ENOMEM; + rdev = nvt->rdev; /* activate pnp device */ ret = pnp_activate_dev(pdev); @@ -1050,7 +1055,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) spin_lock_init(&nvt->tx.lock); pnp_set_drvdata(pdev, nvt); - nvt->pdev = pdev; init_waitqueue_head(&nvt->tx.queue); @@ -1085,7 +1089,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2; rdev->input_id.product = nvt->chip_major; rdev->input_id.version = nvt->chip_minor; - rdev->dev.parent = &pdev->dev; rdev->driver_name = NVT_DRIVER_NAME; rdev->map_name = RC_MAP_RC6_MCE; rdev->timeout = MS_TO_NS(100); @@ -1097,8 +1100,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) /* tx bits */ rdev->tx_resolution = XYZ; #endif - nvt->rdev = rdev; - ret = devm_rc_register_device(&pdev->dev, rdev); if (ret) return ret; diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index acf735fc7170..77102a9b7d7b 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -78,7 +78,6 @@ struct nvt_chip { }; struct nvt_dev { - struct pnp_dev *pdev; struct rc_dev *rdev; spinlock_t nvt_lock; -- cgit v1.2.3 From f7ceec4fa0f40a1e21b738fa5a4997f99f62d1d1 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 25 Oct 2016 17:23:45 -0200 Subject: [media] media: rc: nuvoton: eliminate nvt->tx.lock Using a separate spinlock to protect access to substruct tx of struct nvt_dev doesn't provide any actual benefit. We can use spinlock nvt_lock to protect all access to struct nvt_dev and get rid of nvt->tx.lock. Signed-off-by: Heiner Kallweit Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 35 +++++++++-------------------------- drivers/media/rc/nuvoton-cir.h | 1 - 2 files changed, 9 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 0705d51e4238..356f39953942 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -688,7 +688,7 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) u8 iren; int ret; - spin_lock_irqsave(&nvt->tx.lock, flags); + spin_lock_irqsave(&nvt->nvt_lock, flags); ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n); nvt->tx.buf_count = (ret * sizeof(unsigned)); @@ -712,13 +712,13 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) for (i = 0; i < 9; i++) nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO); - spin_unlock_irqrestore(&nvt->tx.lock, flags); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST); - spin_lock_irqsave(&nvt->tx.lock, flags); + spin_lock_irqsave(&nvt->nvt_lock, flags); nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->tx.lock, flags); + spin_unlock_irqrestore(&nvt->nvt_lock, flags); /* restore enabled interrupts to prior state */ nvt_cir_reg_write(nvt, iren, CIR_IREN); @@ -832,14 +832,7 @@ static void nvt_cir_log_irqs(u8 status, u8 iren) static bool nvt_cir_tx_inactive(struct nvt_dev *nvt) { - unsigned long flags; - u8 tx_state; - - spin_lock_irqsave(&nvt->tx.lock, flags); - tx_state = nvt->tx.tx_state; - spin_unlock_irqrestore(&nvt->tx.lock, flags); - - return tx_state == ST_TX_NONE; + return nvt->tx.tx_state == ST_TX_NONE; } /* interrupt service routine for incoming and outgoing CIR data */ @@ -902,8 +895,6 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) nvt_get_rx_ir_data(nvt); } - spin_unlock_irqrestore(&nvt->nvt_lock, flags); - if (status & CIR_IRSTS_TE) nvt_clear_tx_fifo(nvt); @@ -911,8 +902,6 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) unsigned int pos, count; u8 tmp; - spin_lock_irqsave(&nvt->tx.lock, flags); - pos = nvt->tx.cur_buf_num; count = nvt->tx.buf_count; @@ -925,20 +914,17 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) tmp = nvt_cir_reg_read(nvt, CIR_IREN); nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN); } - - spin_unlock_irqrestore(&nvt->tx.lock, flags); - } if (status & CIR_IRSTS_TFU) { - spin_lock_irqsave(&nvt->tx.lock, flags); if (nvt->tx.tx_state == ST_TX_REPLY) { nvt->tx.tx_state = ST_TX_REQUEST; wake_up(&nvt->tx.queue); } - spin_unlock_irqrestore(&nvt->tx.lock, flags); } + spin_unlock_irqrestore(&nvt->nvt_lock, flags); + nvt_dbg_verbose("%s done", __func__); return IRQ_HANDLED; } @@ -1052,7 +1038,6 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) nvt->cr_efdr = CR_EFDR; spin_lock_init(&nvt->nvt_lock); - spin_lock_init(&nvt->tx.lock); pnp_set_drvdata(pdev, nvt); @@ -1152,12 +1137,10 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) nvt_dbg("%s called", __func__); - spin_lock_irqsave(&nvt->tx.lock, flags); - nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->tx.lock, flags); - spin_lock_irqsave(&nvt->nvt_lock, flags); + nvt->tx.tx_state = ST_TX_NONE; + /* disable all CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index 77102a9b7d7b..a8569b66c214 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -87,7 +87,6 @@ struct nvt_dev { unsigned int pkts; struct { - spinlock_t lock; u8 buf[TX_BUF_LEN]; unsigned int buf_count; unsigned int cur_buf_num; -- cgit v1.2.3 From 73d4576d8ff4e418175c9b6e3059561ee0e46210 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 25 Oct 2016 17:23:49 -0200 Subject: [media] media: rc: nuvoton: rename spinlock nvt_lock Spinlock nvt_lock is a member of struct nvt_dev and there's no need to prefix it with nvt_. So remove this prefix. [mchehab@s-opensource.org: change the prefix also at the open function, as the patch removing it were not applied (yet?)] Signed-off-by: Heiner Kallweit Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 44 +++++++++++++++++++++--------------------- drivers/media/rc/nuvoton-cir.h | 2 +- 2 files changed, 23 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index 356f39953942..c335de4ca4b5 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -187,7 +187,7 @@ static ssize_t wakeup_data_show(struct device *dev, ssize_t buf_len = 0; int i; - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT); fifo_len = min(fifo_len, WAKEUP_MAX_SIZE); @@ -204,7 +204,7 @@ static ssize_t wakeup_data_show(struct device *dev, } buf_len += snprintf(buf + buf_len, PAGE_SIZE - buf_len, "\n"); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); return buf_len; } @@ -248,7 +248,7 @@ static ssize_t wakeup_data_store(struct device *dev, /* hardcode the tolerance to 10% */ tolerance = DIV_ROUND_UP(count, 10); - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); nvt_clear_cir_wake_fifo(nvt); nvt_cir_wake_reg_write(nvt, count, CIR_WAKE_FIFO_CMP_DEEP); @@ -265,7 +265,7 @@ static ssize_t wakeup_data_store(struct device *dev, nvt_cir_wake_reg_write(nvt, config, CIR_WAKE_IRCON); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); ret = len; out: @@ -590,7 +590,7 @@ static void nvt_enable_wake(struct nvt_dev *nvt) nvt_efm_disable(nvt); - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN | CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV | @@ -599,11 +599,11 @@ static void nvt_enable_wake(struct nvt_dev *nvt) nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS); nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); } #if 0 /* Currently unused */ -/* rx carrier detect only works in learning mode, must be called w/nvt_lock */ +/* rx carrier detect only works in learning mode, must be called w/lock */ static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt) { u32 count, carrier, duration = 0; @@ -688,7 +688,7 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) u8 iren; int ret; - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); ret = min((unsigned)(TX_BUF_LEN / sizeof(unsigned)), n); nvt->tx.buf_count = (ret * sizeof(unsigned)); @@ -712,13 +712,13 @@ static int nvt_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned n) for (i = 0; i < 9; i++) nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST); - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); nvt->tx.tx_state = ST_TX_NONE; - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* restore enabled interrupts to prior state */ nvt_cir_reg_write(nvt, iren, CIR_IREN); @@ -844,7 +844,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) nvt_dbg_verbose("%s firing", __func__); - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); /* * Get IR Status register contents. Write 1 to ack/clear @@ -866,7 +866,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) * logical device is being disabled. */ if (status == 0xff && iren == 0xff) { - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); nvt_dbg_verbose("Spurious interrupt detected"); return IRQ_HANDLED; } @@ -875,7 +875,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) * status bit whether the related interrupt source is enabled */ if (!(status & iren)) { - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); return IRQ_NONE; } @@ -923,7 +923,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) } } - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); nvt_dbg_verbose("%s done", __func__); return IRQ_HANDLED; @@ -933,7 +933,7 @@ static void nvt_disable_cir(struct nvt_dev *nvt) { unsigned long flags; - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); /* disable CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); @@ -948,7 +948,7 @@ static void nvt_disable_cir(struct nvt_dev *nvt) nvt_clear_cir_fifo(nvt); nvt_clear_tx_fifo(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* disable the CIR logical device */ nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); @@ -959,7 +959,7 @@ static int nvt_open(struct rc_dev *dev) struct nvt_dev *nvt = dev->priv; unsigned long flags; - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); /* set function enable flags */ nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN | @@ -972,7 +972,7 @@ static int nvt_open(struct rc_dev *dev) /* enable interrupts */ nvt_set_cir_iren(nvt); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* enable the CIR logical device */ nvt_enable_logical_dev(nvt, LOGICAL_DEV_CIR); @@ -1037,7 +1037,7 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id) nvt->cr_efir = CR_EFIR; nvt->cr_efdr = CR_EFDR; - spin_lock_init(&nvt->nvt_lock); + spin_lock_init(&nvt->lock); pnp_set_drvdata(pdev, nvt); @@ -1137,14 +1137,14 @@ static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state) nvt_dbg("%s called", __func__); - spin_lock_irqsave(&nvt->nvt_lock, flags); + spin_lock_irqsave(&nvt->lock, flags); nvt->tx.tx_state = ST_TX_NONE; /* disable all CIR interrupts */ nvt_cir_reg_write(nvt, 0, CIR_IREN); - spin_unlock_irqrestore(&nvt->nvt_lock, flags); + spin_unlock_irqrestore(&nvt->lock, flags); /* disable cir logical dev */ nvt_disable_logical_dev(nvt, LOGICAL_DEV_CIR); diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h index a8569b66c214..c41c5765e1d2 100644 --- a/drivers/media/rc/nuvoton-cir.h +++ b/drivers/media/rc/nuvoton-cir.h @@ -80,7 +80,7 @@ struct nvt_chip { struct nvt_dev { struct rc_dev *rdev; - spinlock_t nvt_lock; + spinlock_t lock; /* for rx */ u8 buf[RX_BUF_LEN]; -- cgit v1.2.3 From c044170fcfca3783f7dd8eb69ff8b06d66fad5d8 Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Tue, 25 Oct 2016 17:23:52 -0200 Subject: [media] media: rc: nuvoton: replace usage of spin_lock_irqsave in ISR Kernel takes care that interrupts from one source are serialized. So there's no need to use spinlock_irq_save. Signed-off-by: Heiner Kallweit Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/nuvoton-cir.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c index c335de4ca4b5..4b78c891eb77 100644 --- a/drivers/media/rc/nuvoton-cir.c +++ b/drivers/media/rc/nuvoton-cir.c @@ -840,11 +840,10 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) { struct nvt_dev *nvt = data; u8 status, iren; - unsigned long flags; nvt_dbg_verbose("%s firing", __func__); - spin_lock_irqsave(&nvt->lock, flags); + spin_lock(&nvt->lock); /* * Get IR Status register contents. Write 1 to ack/clear @@ -866,7 +865,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) * logical device is being disabled. */ if (status == 0xff && iren == 0xff) { - spin_unlock_irqrestore(&nvt->lock, flags); + spin_unlock(&nvt->lock); nvt_dbg_verbose("Spurious interrupt detected"); return IRQ_HANDLED; } @@ -875,7 +874,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) * status bit whether the related interrupt source is enabled */ if (!(status & iren)) { - spin_unlock_irqrestore(&nvt->lock, flags); + spin_unlock(&nvt->lock); nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__); return IRQ_NONE; } @@ -923,7 +922,7 @@ static irqreturn_t nvt_cir_isr(int irq, void *data) } } - spin_unlock_irqrestore(&nvt->lock, flags); + spin_unlock(&nvt->lock); nvt_dbg_verbose("%s done", __func__); return IRQ_HANDLED; -- cgit v1.2.3 From a4afb3ed430af793702c32ff2e68613263291e81 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 18 Nov 2016 17:47:41 -0200 Subject: [media] Kconfig: fix breakages when DVB_CORE is not selected On some weird randconfigs, it is possible to select DVB drivers, without having the DVB_CORE: CONFIG_DVB_AU8522=m CONFIG_DVB_AU8522_V4L=m CONFIG_DVB_TUNER_DIB0090=m This was never supposed to work, but changeset 22a613e89825 ("[media] dvb_frontend: merge duplicate dvb_tuner_ops.release implementations") caused it to be exposed: drivers/built-in.o: In function `fc0011_attach': (.text+0x1598fb): undefined reference to `dvb_tuner_simple_release' drivers/built-in.o:(.rodata+0x55e58): undefined reference to `dvb_tuner_simple_release' drivers/built-in.o:(.rodata+0x57398): undefined reference to `dvb_tuner_simple_release' Fixes: 22a613e89825 ("[media] dvb_frontend: merge duplicate dvb_tuner_ops.release implementations") Reported-by: kbuild test robot Signed-off-by: Mauro Carvalho Chehab --- drivers/media/Kconfig | 2 +- drivers/media/dvb-frontends/Kconfig | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig index bc643cbf813e..3512316e7a46 100644 --- a/drivers/media/Kconfig +++ b/drivers/media/Kconfig @@ -115,7 +115,7 @@ config MEDIA_CONTROLLER config MEDIA_CONTROLLER_DVB bool "Enable Media controller for DVB (EXPERIMENTAL)" - depends on MEDIA_CONTROLLER + depends on MEDIA_CONTROLLER && DVB_CORE ---help--- Enable the media controller API support for DVB. diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index b71b747ee0ba..c841fa1770be 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -642,7 +642,7 @@ config DVB_S5H1409 to support this frontend. config DVB_AU8522 - depends on I2C + depends on DVB_CORE && I2C tristate config DVB_AU8522_DTV @@ -656,7 +656,7 @@ config DVB_AU8522_DTV config DVB_AU8522_V4L tristate "Auvitek AU8522 based ATV demod" - depends on VIDEO_V4L2 && I2C + depends on VIDEO_V4L2 && DVB_CORE && I2C select DVB_AU8522 default m if !MEDIA_SUBDRV_AUTOSELECT help @@ -722,7 +722,7 @@ config DVB_PLL config DVB_TUNER_DIB0070 tristate "DiBcom DiB0070 silicon base-band tuner" - depends on I2C + depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon baseband tuner DiB0070 from DiBcom. @@ -731,7 +731,7 @@ config DVB_TUNER_DIB0070 config DVB_TUNER_DIB0090 tristate "DiBcom DiB0090 silicon base-band tuner" - depends on I2C + depends on DVB_CORE && I2C default m if !MEDIA_SUBDRV_AUTOSELECT help A driver for the silicon baseband tuner DiB0090 from DiBcom. @@ -879,5 +879,6 @@ comment "Tools to develop new frontends" config DVB_DUMMY_FE tristate "Dummy frontend driver" + depends on DVB_CORE default n endmenu -- cgit v1.2.3 From f2709c206d8a3e11729e68d80c57e7470bbe8e5e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 18 Nov 2016 20:30:51 -0200 Subject: Revert "[media] dvb_frontend: merge duplicate dvb_tuner_ops.release implementations" While this patch sounded a good idea, unfortunately, it causes bad dependencies, as drivers that would otherwise work without the DVB core will now break: ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/tea5767.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/tea5761.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/tda827x.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/tda18218.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/qt1010.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/mt2266.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/mt20xx.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/mt2060.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/mc44s803.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/fc0013.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/fc0012.ko] undefined! ERROR: "dvb_tuner_simple_release" [drivers/media/tuners/fc0011.ko] undefined! So, we have to revert it. Note: as the argument for the release ops changed from "int" to "void", we needed to change it at the revert patch, to avoid compilation issues like: drivers/media/tuners/tea5767.c:437:23: error: initialization from incompatible pointer type [-Werror=incompatible-pointer-types] .release = tea5767_release, ^~~~~~~~~~~~~~~ This reverts commit 22a613e89825ea7a3984a968463cc6d425bd8856. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_frontend.c | 8 -------- drivers/media/dvb-core/dvb_frontend.h | 7 ------- drivers/media/dvb-frontends/dib0070.c | 8 +++++++- drivers/media/dvb-frontends/dib0090.c | 10 ++++++++-- drivers/media/dvb-frontends/dvb-pll.c | 8 +++++++- drivers/media/dvb-frontends/itd1000.c | 8 +++++++- drivers/media/dvb-frontends/ix2505v.c | 11 ++++++++++- drivers/media/dvb-frontends/stb6000.c | 8 +++++++- drivers/media/dvb-frontends/stb6100.c | 12 +++++++++++- drivers/media/dvb-frontends/stv6110.c | 8 +++++++- drivers/media/dvb-frontends/stv6110x.c | 10 +++++++++- drivers/media/dvb-frontends/tda18271c2dd.c | 9 ++++++++- drivers/media/dvb-frontends/tda665x.c | 10 +++++++++- drivers/media/dvb-frontends/tda8261.c | 10 +++++++++- drivers/media/dvb-frontends/tda826x.c | 8 +++++++- drivers/media/dvb-frontends/tua6100.c | 8 +++++++- drivers/media/dvb-frontends/zl10036.c | 10 +++++++++- drivers/media/tuners/fc0011.c | 8 +++++++- drivers/media/tuners/fc0012.c | 8 +++++++- drivers/media/tuners/fc0013.c | 8 +++++++- drivers/media/tuners/mc44s803.c | 10 +++++++++- drivers/media/tuners/mt2060.c | 8 +++++++- drivers/media/tuners/mt20xx.c | 10 ++++++++-- drivers/media/tuners/mt2266.c | 8 +++++++- drivers/media/tuners/qt1010.c | 8 +++++++- drivers/media/tuners/tda18218.c | 8 +++++++- drivers/media/tuners/tda827x.c | 10 ++++++++-- drivers/media/tuners/tea5761.c | 8 +++++++- drivers/media/tuners/tea5767.c | 8 +++++++- 29 files changed, 210 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 87f1346e1fec..db74cb74d271 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -181,14 +181,6 @@ static bool has_get_frontend(struct dvb_frontend *fe) return fe->ops.get_frontend != NULL; } -void -dvb_tuner_simple_release(struct dvb_frontend *fe) -{ - kfree(fe->tuner_priv); - fe->tuner_priv = NULL; -} -EXPORT_SYMBOL(dvb_tuner_simple_release); - /* * Due to DVBv3 API calls, a delivery system should be mapped into one of * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC), diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h index f21b255c61de..482912d3b77a 100644 --- a/drivers/media/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb-core/dvb_frontend.h @@ -266,13 +266,6 @@ struct dvb_tuner_ops { int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); }; -/** - * A common default implementation for dvb_tuner_ops.release. All it - * does is kfree() the tuner_priv and assign NULL to it. - */ -void -dvb_tuner_simple_release(struct dvb_frontend *fe); - /** * struct analog_demod_info - Information struct for analog TV part of the demod * diff --git a/drivers/media/dvb-frontends/dib0070.c b/drivers/media/dvb-frontends/dib0070.c index d9f1bc2f778c..befc8172159d 100644 --- a/drivers/media/dvb-frontends/dib0070.c +++ b/drivers/media/dvb-frontends/dib0070.c @@ -722,6 +722,12 @@ static int dib0070_get_frequency(struct dvb_frontend *fe, u32 *frequency) return 0; } +static void dib0070_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static const struct dvb_tuner_ops dib0070_ops = { .info = { .name = "DiBcom DiB0070", @@ -729,7 +735,7 @@ static const struct dvb_tuner_ops dib0070_ops = { .frequency_max = 860000000, .frequency_step = 1000, }, - .release = dvb_tuner_simple_release, + .release = dib0070_release, .init = dib0070_wakeup, .sleep = dib0070_sleep, diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c index 7b4bee5c8e34..fd3b33296b15 100644 --- a/drivers/media/dvb-frontends/dib0090.c +++ b/drivers/media/dvb-frontends/dib0090.c @@ -2526,6 +2526,12 @@ static int dib0090_tune(struct dvb_frontend *fe) return ret; } +static void dib0090_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + enum frontend_tune_state dib0090_get_tune_state(struct dvb_frontend *fe) { struct dib0090_state *state = fe->tuner_priv; @@ -2587,7 +2593,7 @@ static const struct dvb_tuner_ops dib0090_ops = { .frequency_max = 860000000, .frequency_step = 1000, }, - .release = dvb_tuner_simple_release, + .release = dib0090_release, .init = dib0090_wakeup, .sleep = dib0090_sleep, @@ -2602,7 +2608,7 @@ static const struct dvb_tuner_ops dib0090_fw_ops = { .frequency_max = 860000000, .frequency_step = 1000, }, - .release = dvb_tuner_simple_release, + .release = dib0090_release, .init = NULL, .sleep = NULL, diff --git a/drivers/media/dvb-frontends/dvb-pll.c b/drivers/media/dvb-frontends/dvb-pll.c index 56832d6f47ae..ef976eb23344 100644 --- a/drivers/media/dvb-frontends/dvb-pll.c +++ b/drivers/media/dvb-frontends/dvb-pll.c @@ -606,6 +606,12 @@ static int dvb_pll_configure(struct dvb_frontend *fe, u8 *buf, return (div * desc->entries[i].stepsize) - desc->iffreq; } +static void dvb_pll_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int dvb_pll_sleep(struct dvb_frontend *fe) { struct dvb_pll_priv *priv = fe->tuner_priv; @@ -738,7 +744,7 @@ static int dvb_pll_init(struct dvb_frontend *fe) } static const struct dvb_tuner_ops dvb_pll_tuner_ops = { - .release = dvb_tuner_simple_release, + .release = dvb_pll_release, .sleep = dvb_pll_sleep, .init = dvb_pll_init, .set_params = dvb_pll_set_params, diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c index d09f718f8119..475525134327 100644 --- a/drivers/media/dvb-frontends/itd1000.c +++ b/drivers/media/dvb-frontends/itd1000.c @@ -348,6 +348,12 @@ static int itd1000_sleep(struct dvb_frontend *fe) return 0; } +static void itd1000_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static const struct dvb_tuner_ops itd1000_tuner_ops = { .info = { .name = "Integrant ITD1000", @@ -356,7 +362,7 @@ static const struct dvb_tuner_ops itd1000_tuner_ops = { .frequency_step = 125, /* kHz for QPSK frontends */ }, - .release = dvb_tuner_simple_release, + .release = itd1000_release, .init = itd1000_init, .sleep = itd1000_sleep, diff --git a/drivers/media/dvb-frontends/ix2505v.c b/drivers/media/dvb-frontends/ix2505v.c index 7742a7a8cdbb..ca371680a69f 100644 --- a/drivers/media/dvb-frontends/ix2505v.c +++ b/drivers/media/dvb-frontends/ix2505v.c @@ -94,6 +94,15 @@ static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count) return 0; } +static void ix2505v_release(struct dvb_frontend *fe) +{ + struct ix2505v_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); + +} + /** * Data write format of the Sharp IX2505V B0017 * @@ -254,7 +263,7 @@ static const struct dvb_tuner_ops ix2505v_tuner_ops = { .frequency_min = 950000, .frequency_max = 2175000 }, - .release = dvb_tuner_simple_release, + .release = ix2505v_release, .set_params = ix2505v_set_params, .get_frequency = ix2505v_get_frequency, }; diff --git a/drivers/media/dvb-frontends/stb6000.c b/drivers/media/dvb-frontends/stb6000.c index 5252d485439e..69c03892f2da 100644 --- a/drivers/media/dvb-frontends/stb6000.c +++ b/drivers/media/dvb-frontends/stb6000.c @@ -41,6 +41,12 @@ struct stb6000_priv { u32 frequency; }; +static void stb6000_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int stb6000_sleep(struct dvb_frontend *fe) { struct stb6000_priv *priv = fe->tuner_priv; @@ -185,7 +191,7 @@ static const struct dvb_tuner_ops stb6000_tuner_ops = { .frequency_min = 950000, .frequency_max = 2150000 }, - .release = dvb_tuner_simple_release, + .release = stb6000_release, .sleep = stb6000_sleep, .set_params = stb6000_set_params, .get_frequency = stb6000_get_frequency, diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index befd26bdfa0f..17a955d0031b 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -61,6 +61,8 @@ struct stb6100_lkup { u8 reg; }; +static void stb6100_release(struct dvb_frontend *fe); + static const struct stb6100_lkup lkup[] = { { 0, 950000, 0x0a }, { 950000, 1000000, 0x0a }, @@ -534,7 +536,7 @@ static const struct dvb_tuner_ops stb6100_ops = { .set_params = stb6100_set_params, .get_frequency = stb6100_get_frequency, .get_bandwidth = stb6100_get_bandwidth, - .release = dvb_tuner_simple_release + .release = stb6100_release }; struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, @@ -558,6 +560,14 @@ struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe, return fe; } +static void stb6100_release(struct dvb_frontend *fe) +{ + struct stb6100_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); +} + EXPORT_SYMBOL(stb6100_attach); MODULE_PARM_DESC(verbose, "Set Verbosity level"); diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c index d9a88adc4c10..6a72d0be2ec5 100644 --- a/drivers/media/dvb-frontends/stv6110.c +++ b/drivers/media/dvb-frontends/stv6110.c @@ -59,6 +59,12 @@ static s32 abssub(s32 a, s32 b) return b - a; }; +static void stv6110_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[], int start, int len) { @@ -383,7 +389,7 @@ static const struct dvb_tuner_ops stv6110_tuner_ops = { .frequency_step = 1000, }, .init = stv6110_init, - .release = dvb_tuner_simple_release, + .release = stv6110_release, .sleep = stv6110_sleep, .set_params = stv6110_set_params, .get_frequency = stv6110_get_frequency, diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c index 70d5641453c2..66eba38f1014 100644 --- a/drivers/media/dvb-frontends/stv6110x.c +++ b/drivers/media/dvb-frontends/stv6110x.c @@ -335,6 +335,14 @@ static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status) } +static void stv6110x_release(struct dvb_frontend *fe) +{ + struct stv6110x_state *stv6110x = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(stv6110x); +} + static const struct dvb_tuner_ops stv6110x_ops = { .info = { .name = "STV6110(A) Silicon Tuner", @@ -342,7 +350,7 @@ static const struct dvb_tuner_ops stv6110x_ops = { .frequency_max = 2150000, .frequency_step = 0, }, - .release = dvb_tuner_simple_release, + .release = stv6110x_release }; static const struct stv6110x_devctl stv6110x_ctl = { diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index a324f30f7224..6859fa5d5a85 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -1126,6 +1126,13 @@ static int init(struct dvb_frontend *fe) return 0; } +static void release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + + static int set_params(struct dvb_frontend *fe) { struct tda_state *state = fe->tuner_priv; @@ -1219,7 +1226,7 @@ static const struct dvb_tuner_ops tuner_ops = { .init = init, .sleep = sleep, .set_params = set_params, - .release = dvb_tuner_simple_release, + .release = release, .get_if_frequency = get_if_frequency, .get_bandwidth = get_bandwidth, }; diff --git a/drivers/media/dvb-frontends/tda665x.c b/drivers/media/dvb-frontends/tda665x.c index 39a1eb23ad04..a63dec44295b 100644 --- a/drivers/media/dvb-frontends/tda665x.c +++ b/drivers/media/dvb-frontends/tda665x.c @@ -197,11 +197,19 @@ static int tda665x_set_params(struct dvb_frontend *fe) return 0; } +static void tda665x_release(struct dvb_frontend *fe) +{ + struct tda665x_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); +} + static const struct dvb_tuner_ops tda665x_ops = { .get_status = tda665x_get_status, .set_params = tda665x_set_params, .get_frequency = tda665x_get_frequency, - .release = dvb_tuner_simple_release, + .release = tda665x_release }; struct dvb_frontend *tda665x_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/tda8261.c b/drivers/media/dvb-frontends/tda8261.c index 65f729ff27a9..4eb294f330bc 100644 --- a/drivers/media/dvb-frontends/tda8261.c +++ b/drivers/media/dvb-frontends/tda8261.c @@ -152,6 +152,14 @@ static int tda8261_set_params(struct dvb_frontend *fe) return 0; } +static void tda8261_release(struct dvb_frontend *fe) +{ + struct tda8261_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); +} + static const struct dvb_tuner_ops tda8261_ops = { .info = { @@ -164,7 +172,7 @@ static const struct dvb_tuner_ops tda8261_ops = { .set_params = tda8261_set_params, .get_frequency = tda8261_get_frequency, .get_status = tda8261_get_status, - .release = dvb_tuner_simple_release, + .release = tda8261_release }; struct dvb_frontend *tda8261_attach(struct dvb_frontend *fe, diff --git a/drivers/media/dvb-frontends/tda826x.c b/drivers/media/dvb-frontends/tda826x.c index bf8946c2c04a..da427b4c2aaa 100644 --- a/drivers/media/dvb-frontends/tda826x.c +++ b/drivers/media/dvb-frontends/tda826x.c @@ -41,6 +41,12 @@ struct tda826x_priv { u32 frequency; }; +static void tda826x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int tda826x_sleep(struct dvb_frontend *fe) { struct tda826x_priv *priv = fe->tuner_priv; @@ -128,7 +134,7 @@ static const struct dvb_tuner_ops tda826x_tuner_ops = { .frequency_min = 950000, .frequency_max = 2175000 }, - .release = dvb_tuner_simple_release, + .release = tda826x_release, .sleep = tda826x_sleep, .set_params = tda826x_set_params, .get_frequency = tda826x_get_frequency, diff --git a/drivers/media/dvb-frontends/tua6100.c b/drivers/media/dvb-frontends/tua6100.c index 9e9a8ad7f37c..05ee16d29851 100644 --- a/drivers/media/dvb-frontends/tua6100.c +++ b/drivers/media/dvb-frontends/tua6100.c @@ -42,6 +42,12 @@ struct tua6100_priv { u32 frequency; }; +static void tua6100_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int tua6100_sleep(struct dvb_frontend *fe) { struct tua6100_priv *priv = fe->tuner_priv; @@ -157,7 +163,7 @@ static const struct dvb_tuner_ops tua6100_tuner_ops = { .frequency_max = 2150000, .frequency_step = 1000, }, - .release = dvb_tuner_simple_release, + .release = tua6100_release, .sleep = tua6100_sleep, .set_params = tua6100_set_params, .get_frequency = tua6100_get_frequency, diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c index 0116557c0f10..a6d020fe9b8b 100644 --- a/drivers/media/dvb-frontends/zl10036.c +++ b/drivers/media/dvb-frontends/zl10036.c @@ -134,6 +134,14 @@ static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count) return 0; } +static void zl10036_release(struct dvb_frontend *fe) +{ + struct zl10036_state *state = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(state); +} + static int zl10036_sleep(struct dvb_frontend *fe) { struct zl10036_state *state = fe->tuner_priv; @@ -443,7 +451,7 @@ static const struct dvb_tuner_ops zl10036_tuner_ops = { .frequency_max = 2175000 }, .init = zl10036_init, - .release = dvb_tuner_simple_release, + .release = zl10036_release, .sleep = zl10036_sleep, .set_params = zl10036_set_params, .get_frequency = zl10036_get_frequency, diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c index 5e9e2e694f98..00489a9df4e4 100644 --- a/drivers/media/tuners/fc0011.c +++ b/drivers/media/tuners/fc0011.c @@ -112,6 +112,12 @@ static int fc0011_readreg(struct fc0011_priv *priv, u8 reg, u8 *val) return 0; } +static void fc0011_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int fc0011_init(struct dvb_frontend *fe) { struct fc0011_priv *priv = fe->tuner_priv; @@ -475,7 +481,7 @@ static const struct dvb_tuner_ops fc0011_tuner_ops = { .frequency_max = 1000000000, }, - .release = dvb_tuner_simple_release, + .release = fc0011_release, .init = fc0011_init, .set_params = fc0011_set_params, diff --git a/drivers/media/tuners/fc0012.c b/drivers/media/tuners/fc0012.c index 7faff84e5ea8..30508f44e5f9 100644 --- a/drivers/media/tuners/fc0012.c +++ b/drivers/media/tuners/fc0012.c @@ -55,6 +55,12 @@ static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val) return 0; } +static void fc0012_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int fc0012_init(struct dvb_frontend *fe) { struct fc0012_priv *priv = fe->tuner_priv; @@ -420,7 +426,7 @@ static const struct dvb_tuner_ops fc0012_tuner_ops = { .frequency_step = 0, }, - .release = dvb_tuner_simple_release, + .release = fc0012_release, .init = fc0012_init, diff --git a/drivers/media/tuners/fc0013.c b/drivers/media/tuners/fc0013.c index b068b9702cf7..f7cf0e9e7c99 100644 --- a/drivers/media/tuners/fc0013.c +++ b/drivers/media/tuners/fc0013.c @@ -52,6 +52,12 @@ static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val) return 0; } +static void fc0013_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int fc0013_init(struct dvb_frontend *fe) { struct fc0013_priv *priv = fe->tuner_priv; @@ -579,7 +585,7 @@ static const struct dvb_tuner_ops fc0013_tuner_ops = { .frequency_step = 0, }, - .release = dvb_tuner_simple_release, + .release = fc0013_release, .init = fc0013_init, .sleep = fc0013_sleep, diff --git a/drivers/media/tuners/mc44s803.c b/drivers/media/tuners/mc44s803.c index 86542cbd73fb..aba580b4ac2c 100644 --- a/drivers/media/tuners/mc44s803.c +++ b/drivers/media/tuners/mc44s803.c @@ -80,6 +80,14 @@ static int mc44s803_readreg(struct mc44s803_priv *priv, u8 reg, u32 *val) return 0; } +static void mc44s803_release(struct dvb_frontend *fe) +{ + struct mc44s803_priv *priv = fe->tuner_priv; + + fe->tuner_priv = NULL; + kfree(priv); +} + static int mc44s803_init(struct dvb_frontend *fe) { struct mc44s803_priv *priv = fe->tuner_priv; @@ -302,7 +310,7 @@ static const struct dvb_tuner_ops mc44s803_tuner_ops = { .frequency_step = 100000, }, - .release = dvb_tuner_simple_release, + .release = mc44s803_release, .init = mc44s803_init, .set_params = mc44s803_set_params, .get_frequency = mc44s803_get_frequency, diff --git a/drivers/media/tuners/mt2060.c b/drivers/media/tuners/mt2060.c index 14e7b64360cb..94077ea78dde 100644 --- a/drivers/media/tuners/mt2060.c +++ b/drivers/media/tuners/mt2060.c @@ -332,6 +332,12 @@ static int mt2060_sleep(struct dvb_frontend *fe) return ret; } +static void mt2060_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static const struct dvb_tuner_ops mt2060_tuner_ops = { .info = { .name = "Microtune MT2060", @@ -340,7 +346,7 @@ static const struct dvb_tuner_ops mt2060_tuner_ops = { .frequency_step = 50000, }, - .release = dvb_tuner_simple_release, + .release = mt2060_release, .init = mt2060_init, .sleep = mt2060_sleep, diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c index 4237d8f15919..129bf8e1aff8 100644 --- a/drivers/media/tuners/mt20xx.c +++ b/drivers/media/tuners/mt20xx.c @@ -49,6 +49,12 @@ struct microtune_priv { u32 frequency; }; +static void microtune_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int microtune_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct microtune_priv *priv = fe->tuner_priv; @@ -357,7 +363,7 @@ static int mt2032_set_params(struct dvb_frontend *fe, static const struct dvb_tuner_ops mt2032_tuner_ops = { .set_analog_params = mt2032_set_params, - .release = dvb_tuner_simple_release, + .release = microtune_release, .get_frequency = microtune_get_frequency, }; @@ -552,7 +558,7 @@ static int mt2050_set_params(struct dvb_frontend *fe, static const struct dvb_tuner_ops mt2050_tuner_ops = { .set_analog_params = mt2050_set_params, - .release = dvb_tuner_simple_release, + .release = microtune_release, .get_frequency = microtune_get_frequency, }; diff --git a/drivers/media/tuners/mt2266.c b/drivers/media/tuners/mt2266.c index 35ea5e7975ac..88edcc031e3c 100644 --- a/drivers/media/tuners/mt2266.c +++ b/drivers/media/tuners/mt2266.c @@ -296,6 +296,12 @@ static int mt2266_sleep(struct dvb_frontend *fe) return 0; } +static void mt2266_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static const struct dvb_tuner_ops mt2266_tuner_ops = { .info = { .name = "Microtune MT2266", @@ -303,7 +309,7 @@ static const struct dvb_tuner_ops mt2266_tuner_ops = { .frequency_max = 862000000, .frequency_step = 50000, }, - .release = dvb_tuner_simple_release, + .release = mt2266_release, .init = mt2266_init, .sleep = mt2266_sleep, .set_params = mt2266_set_params, diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c index 5a1662aeeb87..a2c6cd1c3923 100644 --- a/drivers/media/tuners/qt1010.c +++ b/drivers/media/tuners/qt1010.c @@ -377,6 +377,12 @@ static int qt1010_init(struct dvb_frontend *fe) return qt1010_set_params(fe); } +static void qt1010_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int qt1010_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct qt1010_priv *priv = fe->tuner_priv; @@ -398,7 +404,7 @@ static const struct dvb_tuner_ops qt1010_tuner_ops = { .frequency_step = QT1010_STEP, }, - .release = dvb_tuner_simple_release, + .release = qt1010_release, .init = qt1010_init, /* TODO: implement sleep */ diff --git a/drivers/media/tuners/tda18218.c b/drivers/media/tuners/tda18218.c index 4d2916fb9953..8357a3c08a70 100644 --- a/drivers/media/tuners/tda18218.c +++ b/drivers/media/tuners/tda18218.c @@ -265,6 +265,12 @@ static int tda18218_init(struct dvb_frontend *fe) return ret; } +static void tda18218_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static const struct dvb_tuner_ops tda18218_tuner_ops = { .info = { .name = "NXP TDA18218", @@ -274,7 +280,7 @@ static const struct dvb_tuner_ops tda18218_tuner_ops = { .frequency_step = 1000, }, - .release = dvb_tuner_simple_release, + .release = tda18218_release, .init = tda18218_init, .sleep = tda18218_sleep, diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c index 4befb81f0c1a..2137eadf30f1 100644 --- a/drivers/media/tuners/tda827x.c +++ b/drivers/media/tuners/tda827x.c @@ -767,6 +767,12 @@ static void tda827xa_agcf(struct dvb_frontend *fe) /* ------------------------------------------------------------------ */ +static void tda827x_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int tda827x_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tda827x_priv *priv = fe->tuner_priv; @@ -818,7 +824,7 @@ static const struct dvb_tuner_ops tda827xo_tuner_ops = { .frequency_max = 860000000, .frequency_step = 250000 }, - .release = dvb_tuner_simple_release, + .release = tda827x_release, .init = tda827x_initial_init, .sleep = tda827x_initial_sleep, .set_params = tda827xo_set_params, @@ -834,7 +840,7 @@ static const struct dvb_tuner_ops tda827xa_tuner_ops = { .frequency_max = 906000000, .frequency_step = 62500 }, - .release = dvb_tuner_simple_release, + .release = tda827x_release, .init = tda827x_init, .sleep = tda827xa_sleep, .set_params = tda827xa_set_params, diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c index 82f25621d995..a9b1bb134409 100644 --- a/drivers/media/tuners/tea5761.c +++ b/drivers/media/tuners/tea5761.c @@ -284,6 +284,12 @@ int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return 0; } +static void tea5761_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int tea5761_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5761_priv *priv = fe->tuner_priv; @@ -297,7 +303,7 @@ static const struct dvb_tuner_ops tea5761_tuner_ops = { }, .set_analog_params = set_radio_freq, .sleep = set_radio_sleep, - .release = dvb_tuner_simple_release, + .release = tea5761_release, .get_frequency = tea5761_get_frequency, .get_status = tea5761_get_status, .get_rf_strength = tea5761_get_rf_strength, diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c index a33c97de8b8a..525b7ab90c80 100644 --- a/drivers/media/tuners/tea5767.c +++ b/drivers/media/tuners/tea5767.c @@ -401,6 +401,12 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr) return 0; } +static void tea5767_release(struct dvb_frontend *fe) +{ + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; +} + static int tea5767_get_frequency(struct dvb_frontend *fe, u32 *frequency) { struct tea5767_priv *priv = fe->tuner_priv; @@ -426,7 +432,7 @@ static const struct dvb_tuner_ops tea5767_tuner_ops = { .set_analog_params = set_radio_freq, .set_config = tea5767_set_config, .sleep = tea5767_standby, - .release = dvb_tuner_simple_release, + .release = tea5767_release, .get_frequency = tea5767_get_frequency, .get_status = tea5767_get_status, .get_rf_strength = tea5767_get_rf_strength, -- cgit v1.2.3 From ef5327dc2597bbf806393d5edca54b2f059e0e69 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:20 +0900 Subject: mtd: nand: denali: remove unneeded includes The driver calls devm_kzalloc()/devm_kfree() to allocate/free memory. They are declared in , not in . Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 1 - drivers/mtd/nand/denali_dt.c | 1 - drivers/mtd/nand/denali_pci.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 0476ae8776d9..36a0454911fe 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -21,7 +21,6 @@ #include #include #include -#include #include #include diff --git a/drivers/mtd/nand/denali_dt.c b/drivers/mtd/nand/denali_dt.c index f821dc1c5739..5607fcd3b8ed 100644 --- a/drivers/mtd/nand/denali_dt.c +++ b/drivers/mtd/nand/denali_dt.c @@ -21,7 +21,6 @@ #include #include #include -#include #include "denali.h" diff --git a/drivers/mtd/nand/denali_pci.c b/drivers/mtd/nand/denali_pci.c index de31514df282..ac843238b77e 100644 --- a/drivers/mtd/nand/denali_pci.c +++ b/drivers/mtd/nand/denali_pci.c @@ -14,7 +14,6 @@ #include #include #include -#include #include "denali.h" -- cgit v1.2.3 From c4ae0977f57deff490f0232bf8f2a7689cbdcbee Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:21 +0900 Subject: mtd: nand: denali: remove unused struct member denali_nand_info::idx The struct member "idx" was used as an index for debug_array long ago, but the DEBUG_DENALI feature was removed by commit 7cfffac06ca0 ("nand/denali: use dev_xx debug function to replace nand_dbg_print and some printk"). Since then, this has been only initialized, but never referenced. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 2 -- drivers/mtd/nand/denali.h | 1 - 2 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 36a0454911fe..bf83a506177f 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1436,8 +1436,6 @@ static struct nand_bbt_descr bbt_mirror_descr = { /* initialize driver data structures */ static void denali_drv_init(struct denali_nand_info *denali) { - denali->idx = 0; - /* setup interrupt handler */ /* * the completion object will be used to notify diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index e7ab4866a5da..0ce73447ab3b 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -467,7 +467,6 @@ struct denali_nand_info { spinlock_t irq_lock; uint32_t irq_status; int irq_debug_array[32]; - int idx; int irq; uint32_t devnum; /* represent how many nands connected */ -- cgit v1.2.3 From 50d5f2a00aeb9778f9219f8df3fceb7a2071dc73 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:22 +0900 Subject: mtd: nand: denali: remove bogus comment about interrupt handler setup The interrupt handler is setup in denali_init(), not in denali_drv_init(). This comment is false. Such a comment adds no value, so just delete it instead of move. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index bf83a506177f..fde9413aed0b 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1436,7 +1436,6 @@ static struct nand_bbt_descr bbt_mirror_descr = { /* initialize driver data structures */ static void denali_drv_init(struct denali_nand_info *denali) { - /* setup interrupt handler */ /* * the completion object will be used to notify * the callee that the interrupt is done -- cgit v1.2.3 From c9e02584324285d5fbe3912a00a2383e0378f420 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:23 +0900 Subject: mtd: nand: denali: remove detect_partition_feature() The denali->fwblks is set by detect_partition_feature(), but it is not referenced from anywhere. That means the struct member fwblks and the whole of detect_partition_feature() are unneeded. The comment block implies this function is only for Intel platforms. I found drivers/staging/spectra used to exist, but it was deleted by commit be7f39c5ecf5 ("Staging: delete spectra driver") 5 years ago. So, I guess nobody would need this function any more. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 29 ----------------------------- drivers/mtd/nand/denali.h | 9 --------- 2 files changed, 38 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index fde9413aed0b..4699fff6940b 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -473,33 +473,6 @@ static void detect_max_banks(struct denali_nand_info *denali) denali->max_banks = 1 << (features & FEATURES__N_BANKS); } -static void detect_partition_feature(struct denali_nand_info *denali) -{ - /* - * For MRST platform, denali->fwblks represent the - * number of blocks firmware is taken, - * FW is in protect partition and MTD driver has no - * permission to access it. So let driver know how many - * blocks it can't touch. - */ - if (ioread32(denali->flash_reg + FEATURES) & FEATURES__PARTITION) { - if ((ioread32(denali->flash_reg + PERM_SRC_ID(1)) & - PERM_SRC_ID__SRCID) == SPECTRA_PARTITION_ID) { - denali->fwblks = - ((ioread32(denali->flash_reg + MIN_MAX_BANK(1)) & - MIN_MAX_BANK__MIN_VALUE) * - denali->blksperchip) - + - (ioread32(denali->flash_reg + MIN_BLK_ADDR(1)) & - MIN_BLK_ADDR__VALUE); - } else { - denali->fwblks = SPECTRA_START_BLOCK; - } - } else { - denali->fwblks = SPECTRA_START_BLOCK; - } -} - static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) { uint16_t status = PASS; @@ -551,8 +524,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) find_valid_banks(denali); - detect_partition_feature(denali); - /* * If the user specified to override the default timings * with a specific ONFI mode, we apply those changes here. diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 0ce73447ab3b..7c0800d9dd4c 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -383,14 +383,6 @@ #define CLK_X 5 #define CLK_MULTI 4 -/* spectraswconfig.h */ -#define CMD_DMA 0 - -#define SPECTRA_PARTITION_ID 0 -/**** Block Table and Reserved Block Parameters *****/ -#define SPECTRA_START_BLOCK 3 -#define NUM_FREE_BLOCKS_GATE 30 - /* KBV - Updated to LNW scratch register address */ #define SCRATCH_REG_ADDR CONFIG_MTD_NAND_DENALI_SCRATCH_REG_ADDR #define SCRATCH_REG_SIZE 64 @@ -470,7 +462,6 @@ struct denali_nand_info { int irq; uint32_t devnum; /* represent how many nands connected */ - uint32_t fwblks; /* represent how many blocks FW used */ uint32_t totalblks; uint32_t blksperchip; uint32_t bbtskipbytes; -- cgit v1.2.3 From 789ccf17754fe95cdd4de3cae7afb09a9bb43c94 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:24 +0900 Subject: mtd: nand: denali: remove "Spectra:" prefix from printk strings As far as I understood from the Kconfig menu deleted by commit be7f39c5ecf5 ("Staging: delete spectra driver"), the "Spectra" is specific to Intel Moorestown Platform. The Denali NAND controller IP is used for various SoCs such as Altera SOCFPGA, Socionext UniPhier, etc. The platform specific strings are not preferred in this driver. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4699fff6940b..c525995f927c 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -402,7 +402,7 @@ static void get_hynix_nand_para(struct denali_nand_info *denali, break; default: dev_warn(denali->dev, - "Spectra: Unknown Hynix NAND (Device ID: 0x%x).\n" + "Unknown Hynix NAND (Device ID: 0x%x).\n" "Will use default parameter values instead.\n", device_id); } @@ -1458,7 +1458,7 @@ int denali_init(struct denali_nand_info *denali) */ if (request_irq(denali->irq, denali_isr, IRQF_SHARED, DENALI_NAND_NAME, denali)) { - pr_err("Spectra: Unable to allocate IRQ\n"); + dev_err(denali->dev, "Unable to request IRQ\n"); return -ENODEV; } @@ -1495,7 +1495,7 @@ int denali_init(struct denali_nand_info *denali) /* Is 32-bit DMA supported? */ ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32)); if (ret) { - pr_err("Spectra: no usable DMA configuration\n"); + dev_err(denali->dev, "No usable DMA configuration\n"); goto failed_req_irq; } @@ -1503,7 +1503,7 @@ int denali_init(struct denali_nand_info *denali) mtd->writesize + mtd->oobsize, DMA_BIDIRECTIONAL); if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) { - dev_err(denali->dev, "Spectra: failed to map DMA buffer\n"); + dev_err(denali->dev, "Failed to map DMA buffer\n"); ret = -EIO; goto failed_req_irq; } @@ -1598,8 +1598,7 @@ int denali_init(struct denali_nand_info *denali) ret = mtd_device_register(mtd, NULL, 0); if (ret) { - dev_err(denali->dev, "Spectra: Failed to register MTD: %d\n", - ret); + dev_err(denali->dev, "Failed to register MTD: %d\n", ret); goto failed_req_irq; } return 0; -- cgit v1.2.3 From 376563917c23ec8e1d30475233f1111b307fd18b Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:25 +0900 Subject: mtd: nand: denali: remove unused struct member totalblks, blksperchip The denali->blksperchip is set, but not referenced any more. The denali->totalblks is used only for calculating denali->blksperchip. Both of them are unneeded. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 8 -------- drivers/mtd/nand/denali.h | 2 -- 2 files changed, 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index c525995f927c..98b21d230e62 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1573,14 +1573,6 @@ int denali_init(struct denali_nand_info *denali) denali->nand.ecc.bytes *= denali->devnum; denali->nand.ecc.strength *= denali->devnum; - /* - * Let driver know the total blocks number and how many blocks - * contained by each nand chip. blksperchip will help driver to - * know how many blocks is taken by FW. - */ - denali->totalblks = mtd->size >> denali->nand.phys_erase_shift; - denali->blksperchip = denali->totalblks / denali->nand.numchips; - /* override the default read operations */ denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum; denali->nand.ecc.read_page = denali_read_page; diff --git a/drivers/mtd/nand/denali.h b/drivers/mtd/nand/denali.h index 7c0800d9dd4c..ea22191e8515 100644 --- a/drivers/mtd/nand/denali.h +++ b/drivers/mtd/nand/denali.h @@ -462,8 +462,6 @@ struct denali_nand_info { int irq; uint32_t devnum; /* represent how many nands connected */ - uint32_t totalblks; - uint32_t blksperchip; uint32_t bbtskipbytes; uint32_t max_banks; }; -- cgit v1.2.3 From c1d0df192c3adb0a92a984f7f5ae1124027549dd Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:26 +0900 Subject: mtd: nand: denali: use managed devm_irq_request() Use the managed variant instead of request_irq() and free_irq(). Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 98b21d230e62..5b34d4a6dfa4 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -575,7 +575,6 @@ static void denali_irq_init(struct denali_nand_info *denali) static void denali_irq_cleanup(int irqnum, struct denali_nand_info *denali) { denali_set_intr_modes(denali, false); - free_irq(irqnum, denali); } static void denali_irq_enable(struct denali_nand_info *denali, @@ -1456,8 +1455,8 @@ int denali_init(struct denali_nand_info *denali) * denali_isr register is done after all the hardware * initilization is finished */ - if (request_irq(denali->irq, denali_isr, IRQF_SHARED, - DENALI_NAND_NAME, denali)) { + if (devm_request_irq(denali->dev, denali->irq, denali_isr, IRQF_SHARED, + DENALI_NAND_NAME, denali)) { dev_err(denali->dev, "Unable to request IRQ\n"); return -ENODEV; } -- cgit v1.2.3 From 7ebb8d06781f87f5c6c6e6bae42ab44ba0fe9012 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:27 +0900 Subject: mtd: nand: denali: return error code from devm_request_irq() on error The devm_request_irq() returns an appropriate error value when it fails. Use it instead of the fixed -ENODEV. While we are here, reword the comment to make it fit in a single line, fixing the misspelling of "initialization". Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 5b34d4a6dfa4..f636ac4222d0 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1451,14 +1451,12 @@ int denali_init(struct denali_nand_info *denali) denali_hw_init(denali); denali_drv_init(denali); - /* - * denali_isr register is done after all the hardware - * initilization is finished - */ - if (devm_request_irq(denali->dev, denali->irq, denali_isr, IRQF_SHARED, - DENALI_NAND_NAME, denali)) { + /* Request IRQ after all the hardware initialization is finished */ + ret = devm_request_irq(denali->dev, denali->irq, denali_isr, + IRQF_SHARED, DENALI_NAND_NAME, denali); + if (ret) { dev_err(denali->dev, "Unable to request IRQ\n"); - return -ENODEV; + return ret; } /* now that our ISR is registered, we can enable interrupts */ -- cgit v1.2.3 From a227d4e4c356c9be84daba80be282ec56ba46c6c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:28 +0900 Subject: mtd: nand: denali: return error code from nand_scan_ident/tail on error The nand_scan_ident/tail() returns an appropriate error value when it fails. Use it instead of the fixed -ENXIO. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index f636ac4222d0..bcb2bc79f0a1 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1474,10 +1474,9 @@ int denali_init(struct denali_nand_info *denali) * this is the first stage in a two step process to register * with the nand subsystem */ - if (nand_scan_ident(mtd, denali->max_banks, NULL)) { - ret = -ENXIO; + ret = nand_scan_ident(mtd, denali->max_banks, NULL); + if (ret) goto failed_req_irq; - } /* allocate the right size buffer now */ devm_kfree(denali->dev, denali->buf.buf); @@ -1580,10 +1579,9 @@ int denali_init(struct denali_nand_info *denali) denali->nand.ecc.write_oob = denali_write_oob; denali->nand.erase = denali_erase; - if (nand_scan_tail(mtd)) { - ret = -ENXIO; + ret = nand_scan_tail(mtd); + if (ret) goto failed_req_irq; - } ret = mtd_device_register(mtd, NULL, 0); if (ret) { -- cgit v1.2.3 From 01a1d524eb68c0395074dd1d661b119ac96edba1 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:29 +0900 Subject: mtd: nand: denali: remove unneeded parentheses Remove parentheses surrounding the whole right side of an assignment. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index bcb2bc79f0a1..4b0b51b987d4 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1510,16 +1510,16 @@ int denali_init(struct denali_nand_info *denali) * the real pagesize and anything necessery */ denali->devnum = ioread32(denali->flash_reg + DEVICES_CONNECTED); - denali->nand.chipsize <<= (denali->devnum - 1); - denali->nand.page_shift += (denali->devnum - 1); + denali->nand.chipsize <<= denali->devnum - 1; + denali->nand.page_shift += denali->devnum - 1; denali->nand.pagemask = (denali->nand.chipsize >> denali->nand.page_shift) - 1; - denali->nand.bbt_erase_shift += (denali->devnum - 1); + denali->nand.bbt_erase_shift += denali->devnum - 1; denali->nand.phys_erase_shift = denali->nand.bbt_erase_shift; - denali->nand.chip_shift += (denali->devnum - 1); - mtd->writesize <<= (denali->devnum - 1); - mtd->oobsize <<= (denali->devnum - 1); - mtd->erasesize <<= (denali->devnum - 1); + denali->nand.chip_shift += denali->devnum - 1; + mtd->writesize <<= denali->devnum - 1; + mtd->oobsize <<= denali->devnum - 1; + mtd->erasesize <<= denali->devnum - 1; mtd->size = denali->nand.numchips * denali->nand.chipsize; denali->bbtskipbytes *= denali->devnum; -- cgit v1.2.3 From fc80f21a11156dd01c5ef14153e6f9e1291ccb82 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 13:35:30 +0900 Subject: mtd: nand: denali: remove debug lines of __FILE__, __LINE__, __func__ Such debug lines might be useful when debugging the driver first, but should be deleted from the upstream code. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/nand/denali.c | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 4b0b51b987d4..73b9d4e2dca0 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -181,9 +181,6 @@ static uint16_t denali_nand_reset(struct denali_nand_info *denali) { int i; - dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - for (i = 0; i < denali->max_banks; i++) iowrite32(INTR_STATUS__RST_COMP | INTR_STATUS__TIME_OUT, denali->flash_reg + INTR_STATUS(i)); @@ -233,9 +230,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, uint16_t acc_clks; uint16_t addr_2_data, re_2_we, re_2_re, we_2_re, cs_cnt; - dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - en_lo = CEIL_DIV(Trp[mode], CLK_X); en_hi = CEIL_DIV(Treh[mode], CLK_X); #if ONFI_BLOOM_TIME @@ -480,9 +474,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) uint8_t maf_id, device_id; int i; - dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - /* * Use read id method to get device ID and other params. * For some NAND chips, controller can't report the correct @@ -537,9 +528,6 @@ static uint16_t denali_nand_timing_set(struct denali_nand_info *denali) static void denali_set_intr_modes(struct denali_nand_info *denali, uint16_t INT_ENABLE) { - dev_dbg(denali->dev, "%s, Line %d, Function: %s\n", - __FILE__, __LINE__, __func__); - if (INT_ENABLE) iowrite32(1, denali->flash_reg + GLOBAL_INT_ENABLE); else -- cgit v1.2.3 From 3371d663bb4579f1b2003a92162edd6d90edd089 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Tue, 15 Nov 2016 10:56:20 +0100 Subject: mtd: nand: Support controllers with custom page If your controller already sends the required NAND commands when reading or writing a page, then the framework is not supposed to send READ0 and SEQIN/PAGEPROG respectively. Signed-off-by: Marc Gonzalez Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nand_base.c | 34 +++++++++++++++++++++++++++++++--- include/linux/mtd/nand.h | 12 ++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 4d099d4f442c..96d242e2fe34 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -1961,7 +1961,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from, __func__, buf); read_retry: - chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page); /* * Now read the page into the buffer. Absent an error, @@ -2649,7 +2650,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, else subpage = 0; - chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page); if (unlikely(raw)) status = chip->ecc.write_page_raw(mtd, chip, buf, @@ -2672,7 +2674,8 @@ static int nand_write_page(struct mtd_info *mtd, struct nand_chip *chip, if (!cached || !NAND_HAS_CACHEPROG(chip)) { - chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + if (nand_standard_page_accessors(&chip->ecc)) + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); status = chip->waitfunc(mtd, chip); /* * See if operation failed and additional status checks are @@ -4511,6 +4514,26 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd) return corr >= ds_corr && ecc->strength >= chip->ecc_strength_ds; } +static bool invalid_ecc_page_accessors(struct nand_chip *chip) +{ + struct nand_ecc_ctrl *ecc = &chip->ecc; + + if (nand_standard_page_accessors(ecc)) + return false; + + /* + * NAND_ECC_CUSTOM_PAGE_ACCESS flag is set, make sure the NAND + * controller driver implements all the page accessors because + * default helpers are not suitable when the core does not + * send the READ0/PAGEPROG commands. + */ + return (!ecc->read_page || !ecc->write_page || + !ecc->read_page_raw || !ecc->write_page_raw || + (NAND_HAS_SUBPAGE_READ(chip) && !ecc->read_subpage) || + (NAND_HAS_SUBPAGE_WRITE(chip) && !ecc->write_subpage && + ecc->hwctl && ecc->calculate)); +} + /** * nand_scan_tail - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure @@ -4531,6 +4554,11 @@ int nand_scan_tail(struct mtd_info *mtd) !(chip->bbt_options & NAND_BBT_USE_FLASH))) return -EINVAL; + if (invalid_ecc_page_accessors(chip)) { + pr_err("Invalid ECC page accessors setup\n"); + return -EINVAL; + } + if (!(chip->options & NAND_OWN_BUFFERS)) { nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize + mtd->oobsize * 3, GFP_KERNEL); diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h index 970ceb948835..ed6fd1993be1 100644 --- a/include/linux/mtd/nand.h +++ b/include/linux/mtd/nand.h @@ -142,6 +142,12 @@ enum nand_ecc_algo { */ #define NAND_ECC_GENERIC_ERASED_CHECK BIT(0) #define NAND_ECC_MAXIMIZE BIT(1) +/* + * If your controller already sends the required NAND commands when + * reading or writing a page, then the framework is not supposed to + * send READ0 and SEQIN/PAGEPROG respectively. + */ +#define NAND_ECC_CUSTOM_PAGE_ACCESS BIT(2) /* Bit mask for flags passed to do_nand_read_ecc */ #define NAND_GET_DEVICE 0x80 @@ -186,6 +192,7 @@ enum nand_ecc_algo { /* Macros to identify the above */ #define NAND_HAS_CACHEPROG(chip) ((chip->options & NAND_CACHEPRG)) #define NAND_HAS_SUBPAGE_READ(chip) ((chip->options & NAND_SUBPAGE_READ)) +#define NAND_HAS_SUBPAGE_WRITE(chip) !((chip)->options & NAND_NO_SUBPAGE_WRITE) /* Non chip related options */ /* This option skips the bbt scan during initialization. */ @@ -568,6 +575,11 @@ struct nand_ecc_ctrl { int page); }; +static inline int nand_standard_page_accessors(struct nand_ecc_ctrl *ecc) +{ + return !(ecc->options & NAND_ECC_CUSTOM_PAGE_ACCESS); +} + /** * struct nand_buffers - buffer structure for read/write * @ecccalc: buffer pointer for calculated ECC, size is oobsize. -- cgit v1.2.3 From ff9e9eae0f50ab3f7d1763677b62db4a2ed24a88 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Tue, 15 Nov 2016 11:05:39 +0100 Subject: mtd: nand: tango: Enable custom page accessors Enable NAND_ECC_CUSTOM_PAGE_ACCESS in the tango NFC driver. Fixup the "raw" page accessors to send the proper NAND commands. Signed-off-by: Marc Gonzalez Signed-off-by: Boris Brezillon --- drivers/mtd/nand/tango_nand.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index fd8cf414cb2b..bacc2a02b7fe 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -402,13 +402,17 @@ static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf, int oob_required, int page) { + chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); return raw_read(chip, buf, chip->oob_poi); } static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, const u8 *buf, int oob_required, int page) { - return raw_write(chip, buf, chip->oob_poi); + chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0, page); + raw_write(chip, buf, chip->oob_poi); + chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1); + return 0; } static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, @@ -553,6 +557,7 @@ static int chip_init(struct device *dev, struct device_node *np) ecc->write_page = tango_write_page; ecc->read_oob = tango_read_oob; ecc->write_oob = tango_write_oob; + ecc->options = NAND_ECC_CUSTOM_PAGE_ACCESS; err = nand_scan_tail(mtd); if (err) -- cgit v1.2.3 From 37871abdd5ea73bde645c8f3d2e9fc04b5ffaf6b Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Tue, 15 Nov 2016 11:08:19 +0100 Subject: mtd: nand: tango: Cleanup raw_write and raw_read Drop raw_write return value (no longer used). Drop raw_read return value (for symmetry). Signed-off-by: Marc Gonzalez Signed-off-by: Boris Brezillon --- drivers/mtd/nand/tango_nand.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index bacc2a02b7fe..7ed35348993e 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -343,7 +343,7 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) * buf = | PKT_0 | ... | PKT_N | * +-----------------+-----+-----------------+ */ -static int raw_read(struct nand_chip *chip, u8 *buf, u8 *oob) +static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob) { u8 *oob_orig = oob; const int page_size = chip->mtd.writesize; @@ -367,11 +367,9 @@ static int raw_read(struct nand_chip *chip, u8 *buf, u8 *oob) aux_read(chip, &oob_orig, BBM_SIZE, &pos); aux_read(chip, &buf, pkt_size - rem, &pos); aux_read(chip, &oob, ecc_size, &pos); - - return 0; } -static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) +static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) { const u8 *oob_orig = oob; const int page_size = chip->mtd.writesize; @@ -395,15 +393,14 @@ static int raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) aux_write(chip, &oob_orig, BBM_SIZE, &pos); aux_write(chip, &buf, pkt_size - rem, &pos); aux_write(chip, &oob, ecc_size, &pos); - - return 0; } static int tango_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip, u8 *buf, int oob_required, int page) { chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - return raw_read(chip, buf, chip->oob_poi); + raw_read(chip, buf, chip->oob_poi); + return 0; } static int tango_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip, @@ -419,7 +416,8 @@ static int tango_read_oob(struct mtd_info *mtd, struct nand_chip *chip, int page) { chip->cmdfunc(mtd, NAND_CMD_READ0, 0, page); - return raw_read(chip, NULL, chip->oob_poi); + raw_read(chip, NULL, chip->oob_poi); + return 0; } static int tango_write_oob(struct mtd_info *mtd, struct nand_chip *chip, -- cgit v1.2.3 From 442168273ecf57cf4494e492a59f29991089ff42 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Wed, 16 Nov 2016 08:02:55 +0000 Subject: mtd: nand: nandsim: fix error check debugfs_create_dir() and debugfs_create_file() returns NULL on error or a pointer on success. They do not return the error value with ERR_PTR. So we should not check the return with IS_ERR_OR_NULL, instead we should just check for NULL. Signed-off-by: Sudip Mukherjee Signed-off-by: Boris Brezillon --- drivers/mtd/nand/nandsim.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c index c76287a69663..c84742671a5f 100644 --- a/drivers/mtd/nand/nandsim.c +++ b/drivers/mtd/nand/nandsim.c @@ -525,24 +525,20 @@ static int nandsim_debugfs_create(struct nandsim *dev) { struct nandsim_debug_info *dbg = &dev->dbg; struct dentry *dent; - int err; if (!IS_ENABLED(CONFIG_DEBUG_FS)) return 0; dent = debugfs_create_dir("nandsim", NULL); - if (IS_ERR_OR_NULL(dent)) { - int err = dent ? -ENODEV : PTR_ERR(dent); - - NS_ERR("cannot create \"nandsim\" debugfs directory, err %d\n", - err); - return err; + if (!dent) { + NS_ERR("cannot create \"nandsim\" debugfs directory\n"); + return -ENODEV; } dbg->dfs_root = dent; dent = debugfs_create_file("wear_report", S_IRUSR, dbg->dfs_root, dev, &dfs_fops); - if (IS_ERR_OR_NULL(dent)) + if (!dent) goto out_remove; dbg->dfs_wear_report = dent; @@ -550,8 +546,7 @@ static int nandsim_debugfs_create(struct nandsim *dev) out_remove: debugfs_remove_recursive(dbg->dfs_root); - err = dent ? PTR_ERR(dent) : -ENODEV; - return err; + return -ENODEV; } /** -- cgit v1.2.3 From 33e423c40ccf6eedbb5dc6e687524f9133368601 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 26 Oct 2016 07:43:43 -0200 Subject: [media] media: mtk-mdp: mark PM functions as __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A previous patch tried to fix a build error, but introduced another warning: drivers/media/platform/mtk-mdp/mtk_mdp_core.c:71:13: error: ‘mtk_mdp_clock_off’ defined but not used [-Werror=unused-function] drivers/media/platform/mtk-mdp/mtk_mdp_core.c:62:13: error: ‘mtk_mdp_clock_on’ defined but not used [-Werror=unused-function] This marks all the PM functions as __maybe_unused and removes the #ifdef around them, as that will always do the right thing. Fixes: 1b06fcf56aa6 ("[media] media: mtk-mdp: fix build error") Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_core.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c index 51f2b50e406f..9e4eb7dcc424 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c @@ -234,8 +234,7 @@ static int mtk_mdp_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM -static int mtk_mdp_pm_suspend(struct device *dev) +static int __maybe_unused mtk_mdp_pm_suspend(struct device *dev) { struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); @@ -244,7 +243,7 @@ static int mtk_mdp_pm_suspend(struct device *dev) return 0; } -static int mtk_mdp_pm_resume(struct device *dev) +static int __maybe_unused mtk_mdp_pm_resume(struct device *dev) { struct mtk_mdp_dev *mdp = dev_get_drvdata(dev); @@ -252,10 +251,8 @@ static int mtk_mdp_pm_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM */ -#ifdef CONFIG_PM_SLEEP -static int mtk_mdp_suspend(struct device *dev) +static int __maybe_unused mtk_mdp_suspend(struct device *dev) { if (pm_runtime_suspended(dev)) return 0; @@ -263,14 +260,13 @@ static int mtk_mdp_suspend(struct device *dev) return mtk_mdp_pm_suspend(dev); } -static int mtk_mdp_resume(struct device *dev) +static int __maybe_unused mtk_mdp_resume(struct device *dev) { if (pm_runtime_suspended(dev)) return 0; return mtk_mdp_pm_resume(dev); } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops mtk_mdp_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(mtk_mdp_suspend, mtk_mdp_resume) -- cgit v1.2.3 From 8e8fd4d1e83ef7d64f260b4d8d928ab44cc1ce07 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 11:08:08 +0900 Subject: mtd: remove unneeded initializer in mtd_ooblayout_{get, set}_bytes() There is no need to initialize oobregion and section since they will be filled by mtd_ooblayout_find_region(). Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index d46e4adf6d2b..cf85f2b2ca2c 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1274,8 +1274,8 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf, int section, struct mtd_oob_region *oobregion)) { - struct mtd_oob_region oobregion = { }; - int section = 0, ret; + struct mtd_oob_region oobregion; + int section, ret; ret = mtd_ooblayout_find_region(mtd, start, §ion, &oobregion, iter); @@ -1317,8 +1317,8 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf, int section, struct mtd_oob_region *oobregion)) { - struct mtd_oob_region oobregion = { }; - int section = 0, ret; + struct mtd_oob_region oobregion; + int section, ret; ret = mtd_ooblayout_find_region(mtd, start, §ion, &oobregion, iter); -- cgit v1.2.3 From 7c295ef9642c107203a485843853b12d6f5cdb39 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 11:08:09 +0900 Subject: mtd: use min_t() to refactor mtd_ooblayout_{get, set}_bytes() I hope this will make the code a little more readable. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index cf85f2b2ca2c..ca6a89ab4663 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1283,7 +1283,7 @@ static int mtd_ooblayout_get_bytes(struct mtd_info *mtd, u8 *buf, while (!ret) { int cnt; - cnt = oobregion.length > nbytes ? nbytes : oobregion.length; + cnt = min_t(int, nbytes, oobregion.length); memcpy(buf, oobbuf + oobregion.offset, cnt); buf += cnt; nbytes -= cnt; @@ -1326,7 +1326,7 @@ static int mtd_ooblayout_set_bytes(struct mtd_info *mtd, const u8 *buf, while (!ret) { int cnt; - cnt = oobregion.length > nbytes ? nbytes : oobregion.length; + cnt = min_t(int, nbytes, oobregion.length); memcpy(oobbuf + oobregion.offset, buf, cnt); buf += cnt; nbytes -= cnt; -- cgit v1.2.3 From 4d6aecfb7e26d2e8746e2eb1eab5e0fe378065ab Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 9 Nov 2016 11:08:10 +0900 Subject: mtd: remove unneeded initializer in mtd_ooblayout_count_bytes() There is no need to initialize oobregion since it will be filled by the iterator. This function is called with mtd_ooblayout_free or mtd_ooblayout_ecc for the iterator; both of them calls memset() to clear the oobregion. Signed-off-by: Masahiro Yamada Reviewed-by: Marek Vasut Signed-off-by: Boris Brezillon --- drivers/mtd/mtdcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index ca6a89ab4663..ca661cee9b77 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -1354,7 +1354,7 @@ static int mtd_ooblayout_count_bytes(struct mtd_info *mtd, int section, struct mtd_oob_region *oobregion)) { - struct mtd_oob_region oobregion = { }; + struct mtd_oob_region oobregion; int section = 0, ret, nbytes = 0; while (1) { -- cgit v1.2.3 From 8fcfba072420518fda4b2fe00a3f3c9c3e2774e2 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Mon, 21 Nov 2016 10:03:04 +0100 Subject: mtd: nand: tango: Use nand_to_mtd() instead of directly accessing chip->mtd The nand_to_mtd() helper is here to hide internal mtd_info <-> nand_chip association and ease future refactors. Make use of this helper instead of directly accessing chip->mtd. Signed-off-by: Boris Brezillon Acked-by: Marc Gonzalez --- drivers/mtd/nand/tango_nand.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index 7ed35348993e..ec87516b87f5 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -171,6 +171,7 @@ static void tango_select_chip(struct mtd_info *mtd, int idx) */ static int check_erased_page(struct nand_chip *chip, u8 *buf) { + struct mtd_info *mtd = nand_to_mtd(chip); u8 *meta = chip->oob_poi + BBM_SIZE; u8 *ecc = chip->oob_poi + BBM_SIZE + METADATA_SIZE; const int ecc_size = chip->ecc.bytes; @@ -183,7 +184,7 @@ static int check_erased_page(struct nand_chip *chip, u8 *buf) meta, meta_len, chip->ecc.strength); if (res < 0) - chip->mtd.ecc_stats.failed++; + mtd->ecc_stats.failed++; bitflips = max(res, bitflips); buf += pkt_size; @@ -300,26 +301,30 @@ static int tango_write_page(struct mtd_info *mtd, struct nand_chip *chip, static void aux_read(struct nand_chip *chip, u8 **buf, int len, int *pos) { + struct mtd_info *mtd = nand_to_mtd(chip); + *pos += len; if (!*buf) { /* skip over "len" bytes */ - chip->cmdfunc(&chip->mtd, NAND_CMD_RNDOUT, *pos, -1); + chip->cmdfunc(mtd, NAND_CMD_RNDOUT, *pos, -1); } else { - tango_read_buf(&chip->mtd, *buf, len); + tango_read_buf(mtd, *buf, len); *buf += len; } } static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) { + struct mtd_info *mtd = nand_to_mtd(chip); + *pos += len; if (!*buf) { /* skip over "len" bytes */ - chip->cmdfunc(&chip->mtd, NAND_CMD_SEQIN, *pos, -1); + chip->cmdfunc(mtd, NAND_CMD_SEQIN, *pos, -1); } else { - tango_write_buf(&chip->mtd, *buf, len); + tango_write_buf(mtd, *buf, len); *buf += len; } } @@ -345,8 +350,9 @@ static void aux_write(struct nand_chip *chip, const u8 **buf, int len, int *pos) */ static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob) { + struct mtd_info *mtd = nand_to_mtd(chip); u8 *oob_orig = oob; - const int page_size = chip->mtd.writesize; + const int page_size = mtd->writesize; const int ecc_size = chip->ecc.bytes; const int pkt_size = chip->ecc.size; int pos = 0; /* position within physical page */ @@ -371,8 +377,9 @@ static void raw_read(struct nand_chip *chip, u8 *buf, u8 *oob) static void raw_write(struct nand_chip *chip, const u8 *buf, const u8 *oob) { + struct mtd_info *mtd = nand_to_mtd(chip); const u8 *oob_orig = oob; - const int page_size = chip->mtd.writesize; + const int page_size = mtd->writesize; const int ecc_size = chip->ecc.bytes; const int pkt_size = chip->ecc.size; int pos = 0; /* position within physical page */ @@ -522,7 +529,7 @@ static int chip_init(struct device *dev, struct device_node *np) chip = &tchip->nand_chip; ecc = &chip->ecc; - mtd = &chip->mtd; + mtd = nand_to_mtd(chip); chip->read_byte = tango_read_byte; chip->write_buf = tango_write_buf; @@ -584,7 +591,7 @@ static int tango_nand_remove(struct platform_device *pdev) for (cs = 0; cs < MAX_CS; ++cs) { if (nfc->chips[cs]) - nand_release(&nfc->chips[cs]->nand_chip.mtd); + nand_release(nand_to_mtd(&nfc->chips[cs]->nand_chip)); } return 0; -- cgit v1.2.3 From 3f89586bc1ce1434b15f78e62b555c0619852295 Mon Sep 17 00:00:00 2001 From: Icenowy Zheng Date: Fri, 1 Jul 2016 17:29:23 +0800 Subject: mfd: axp20x: Add adc volatile ranges for axp22x AXP22x has also some different register map than axp20x, they're also added here. Signed-off-by: Icenowy Zheng Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 1 + include/linux/mfd/axp20x.h | 4 ++++ 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index ba130be32e61..98377d29b783 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -98,6 +98,7 @@ static const struct regmap_range axp22x_volatile_ranges[] = { regmap_reg_range(AXP20X_PWR_INPUT_STATUS, AXP20X_PWR_OP_MODE), regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ5_STATE), regmap_reg_range(AXP22X_GPIO_STATE, AXP22X_GPIO_STATE), + regmap_reg_range(AXP22X_PMIC_ADC_H, AXP20X_IPSOUT_V_HIGH_L), regmap_reg_range(AXP20X_FG_RES, AXP20X_FG_RES), }; diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index fec597fb34cb..6349496f09fc 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -226,6 +226,10 @@ enum { #define AXP20X_OCV_MAX 0xf /* AXP22X specific registers */ +#define AXP22X_PMIC_ADC_H 0x56 +#define AXP22X_PMIC_ADC_L 0x57 +#define AXP22X_TS_ADC_H 0x58 +#define AXP22X_TS_ADC_L 0x59 #define AXP22X_BATLOW_THRES1 0xe6 /* AXP288 specific registers */ -- cgit v1.2.3 From e420d6a1816bedc54575eef727073f89de53091e Mon Sep 17 00:00:00 2001 From: Dan Gora Date: Wed, 6 Jul 2016 22:35:02 -0300 Subject: mfd: lpc_ich: Use gpio-ich driver for 8-series and 9-series Intel PCH devices The Intel 8-series and 9-series PCH devices, described by the descriptors LPC_LPT and LPC_9S although codenamed 'lynxpoint' do not use the same GPIO register layout which is used by the gpio-lynxpoint driver. They use the same ICH_V5_GPIO layout as the gpio-ich driver. See: http://www.intel.com/content/www/us/en/chipsets/8-series-chipset-pch-datasheet.html http://www.intel.com/content/www/us/en/chipsets/9-series-chipset-pch-datasheet.html The devices described by "Mobile 4th Generation Intel Core Processor Family I/O" manual use the gpio-lynxpoint driver and are described by the LPC_LPT_LP descriptor. See: http://www.intel.com/content/www/us/en/processors/core/4th-gen-core-family-mobile-i-o-datasheet.html Signed-off-by: Dan Gora Signed-off-by: Lee Jones --- drivers/mfd/lpc_ich.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c index c8dee47b45d9..1ef7575547e6 100644 --- a/drivers/mfd/lpc_ich.c +++ b/drivers/mfd/lpc_ich.c @@ -493,6 +493,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_LPT] = { .name = "Lynx Point", .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, }, [LPC_LPT_LP] = { .name = "Lynx Point_LP", @@ -530,6 +531,7 @@ static struct lpc_ich_info lpc_chipset_info[] = { [LPC_9S] = { .name = "9 Series", .iTCO_version = 2, + .gpio_version = ICH_V5_GPIO, }, }; -- cgit v1.2.3 From b7c5005378f14793d7f4c19d2531684c733b5a64 Mon Sep 17 00:00:00 2001 From: Praveen Kumar Vegivada Date: Tue, 13 Sep 2016 14:19:39 +0100 Subject: mfd: arizona: Mark AIFx_TX_BCLK_RATE as readable for cs47l24 This register is used in the AIF code but is missing from the register tables. Signed-off-by: Praveen Kumar Vegivada Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/cs47l24-tables.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/cs47l24-tables.c b/drivers/mfd/cs47l24-tables.c index f6b78aafdb55..c090974340ad 100644 --- a/drivers/mfd/cs47l24-tables.c +++ b/drivers/mfd/cs47l24-tables.c @@ -292,6 +292,7 @@ static const struct reg_default cs47l24_reg_default[] = { { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */ { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */ { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */ + { 0x00000505, 0x0040 }, /* R1285 - AIF1 Tx BCLK Rate */ { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */ { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */ { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */ @@ -318,6 +319,7 @@ static const struct reg_default cs47l24_reg_default[] = { { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */ { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */ { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */ + { 0x00000545, 0x0040 }, /* R1349 - AIF2 Tx BCLK Rate */ { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */ { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */ { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */ @@ -340,6 +342,7 @@ static const struct reg_default cs47l24_reg_default[] = { { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */ { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */ { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */ + { 0x00000585, 0x0040 }, /* R1413 - AIF3 Tx BCLK Rate */ { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */ { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */ { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */ @@ -923,6 +926,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg) case ARIZONA_AIF1_RX_PIN_CTRL: case ARIZONA_AIF1_RATE_CTRL: case ARIZONA_AIF1_FORMAT: + case ARIZONA_AIF1_TX_BCLK_RATE: case ARIZONA_AIF1_RX_BCLK_RATE: case ARIZONA_AIF1_FRAME_CTRL_1: case ARIZONA_AIF1_FRAME_CTRL_2: @@ -949,6 +953,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg) case ARIZONA_AIF2_RX_PIN_CTRL: case ARIZONA_AIF2_RATE_CTRL: case ARIZONA_AIF2_FORMAT: + case ARIZONA_AIF2_TX_BCLK_RATE: case ARIZONA_AIF2_RX_BCLK_RATE: case ARIZONA_AIF2_FRAME_CTRL_1: case ARIZONA_AIF2_FRAME_CTRL_2: @@ -971,6 +976,7 @@ static bool cs47l24_readable_register(struct device *dev, unsigned int reg) case ARIZONA_AIF3_RX_PIN_CTRL: case ARIZONA_AIF3_RATE_CTRL: case ARIZONA_AIF3_FORMAT: + case ARIZONA_AIF3_TX_BCLK_RATE: case ARIZONA_AIF3_RX_BCLK_RATE: case ARIZONA_AIF3_FRAME_CTRL_1: case ARIZONA_AIF3_FRAME_CTRL_2: -- cgit v1.2.3 From 1f5ecaf985c46889278f51fcb7bc143f60f4eb14 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 23:36:24 -0200 Subject: [media] dibusb: fix possible memory leak in dibusb_rc_query() 'buf' is malloced in dibusb_rc_query() and should be freed before leaving from the error handling cases, otherwise it will cause memory leak. Fixes: ff1c123545d7 ("[media] dibusb: handle error code on RC query") Signed-off-by: Wei Yongjun Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dibusb-common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c index de3ee2547479..8207e6900656 100644 --- a/drivers/media/usb/dvb-usb/dibusb-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-common.c @@ -382,9 +382,9 @@ int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state) if (buf[0] != 0) deb_info("key: %*ph\n", 5, buf); +ret: kfree(buf); -ret: return ret; } EXPORT_SYMBOL(dibusb_rc_query); -- cgit v1.2.3 From 21098562a41ce24af1e105dc96179260ebcc980c Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 23:53:10 -0200 Subject: [media] c8sectpfe: fix error return code in c8sectpfe_probe() Fix to return error code -ENODEV from the error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Acked-by: Patrice Chotard Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c index 22fd8b91809a..7652ce2ec1dc 100644 --- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c +++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c @@ -813,6 +813,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) i2c_bus = of_parse_phandle(child, "i2c-bus", 0); if (!i2c_bus) { dev_err(&pdev->dev, "No i2c-bus found\n"); + ret = -ENODEV; goto err_clk_disable; } tsin->i2c_adapter = @@ -820,6 +821,7 @@ static int c8sectpfe_probe(struct platform_device *pdev) if (!tsin->i2c_adapter) { dev_err(&pdev->dev, "No i2c adapter found\n"); of_node_put(i2c_bus); + ret = -ENODEV; goto err_clk_disable; } of_node_put(i2c_bus); -- cgit v1.2.3 From 6932234fbe746223abf730cc89508492244fa64c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:19 -0200 Subject: [media] winbond-cir: use name without space for pnp driver Rename the pnp driver in sysfs from /sys/bus/pnp/drivers/Winbond CIR to /sys/bus/pnp/drivers/winbond-cir Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/winbond-cir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 8c1f9225d358..78491ed48d92 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c @@ -1185,7 +1185,7 @@ static const struct pnp_device_id wbcir_ids[] = { MODULE_DEVICE_TABLE(pnp, wbcir_ids); static struct pnp_driver wbcir_driver = { - .name = WBCIR_NAME, + .name = DRVNAME, .id_table = wbcir_ids, .probe = wbcir_probe, .remove = wbcir_remove, -- cgit v1.2.3 From da500033df2b7b532aa04c462ffdc203b9eabde4 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:20 -0200 Subject: [media] redrat3: don't include vendor/product id in name No need to duplicate these in the rc name. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index d3c81619cd87..236b686bffd6 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -904,9 +904,9 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) if (!rc) return NULL; - snprintf(rr3->name, sizeof(rr3->name), "RedRat3%s Infrared Remote Transceiver (%04x:%04x)", - prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : "", - le16_to_cpu(rr3->udev->descriptor.idVendor), prod); + snprintf(rr3->name, sizeof(rr3->name), + "RedRat3%s Infrared Remote Transceiver", + prod == USB_RR3IIUSB_PRODUCT_ID ? "-II" : ""); usb_make_path(rr3->udev, rr3->phys, sizeof(rr3->phys)); -- cgit v1.2.3 From d6aca6ea281d88ce1816fd6f5a57889c6ea9392b Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:21 -0200 Subject: [media] redrat3: remove dead code and pointless messages Cleanup the error logic, removing checks for things that should be always initialized when the routines are called, and remove some bogus messages. [mchehab@s-opensource.com: fix some merge conflicts] Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 236b686bffd6..09e34a73d663 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -363,11 +363,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) unsigned int i, sig_size, single_len, offset, val; u32 mod_freq; - if (!rr3) { - pr_err("%s called with no context!\n", __func__); - return; - } - dev = rr3->dev; mod_freq = redrat3_val_to_mod_freq(&rr3->irdata); @@ -693,19 +688,9 @@ out: /* callback function from USB when async USB request has completed */ static void redrat3_handle_async(struct urb *urb) { - struct redrat3_dev *rr3; + struct redrat3_dev *rr3 = urb->context; int ret; - if (!urb) - return; - - rr3 = urb->context; - if (!rr3) { - pr_err("%s called with invalid context!\n", __func__); - usb_unlink_urb(urb); - return; - } - switch (urb->status) { case 0: ret = redrat3_get_ir_data(rr3, urb->actual_length); @@ -1069,8 +1054,6 @@ error: redrat3_delete(rr3, rr3->udev); no_endpoints: - dev_err(dev, "%s: retval = %x", __func__, retval); - return retval; } @@ -1079,9 +1062,6 @@ static void redrat3_dev_disconnect(struct usb_interface *intf) struct usb_device *udev = interface_to_usbdev(intf); struct redrat3_dev *rr3 = usb_get_intfdata(intf); - if (!rr3) - return; - usb_set_intfdata(intf, NULL); rc_unregister_device(rr3->rc); led_classdev_unregister(&rr3->led); -- cgit v1.2.3 From 8a21ec9bb3ecea54ebbd8576460ec8ba2096a29e Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:22 -0200 Subject: [media] redrat3: fix error paths in probe If redrat3_delete() is called, ensure ep_in and udev members are set up so we don't dereference null in the error path. Also ensure that rc dev device exists before we enable the receiver and that the led urb exists before we create the led device. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 49 ++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 09e34a73d663..af562217a205 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -980,17 +980,19 @@ static int redrat3_dev_probe(struct usb_interface *intf, goto no_endpoints; rr3->dev = &intf->dev; + rr3->ep_in = ep_in; + rr3->ep_out = ep_out; + rr3->udev = udev; /* set up bulk-in endpoint */ rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL); if (!rr3->read_urb) - goto error; + goto redrat_free; - rr3->ep_in = ep_in; rr3->bulk_in_buf = usb_alloc_coherent(udev, le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in); if (!rr3->bulk_in_buf) - goto error; + goto redrat_free; pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf, @@ -998,34 +1000,16 @@ static int redrat3_dev_probe(struct usb_interface *intf, rr3->read_urb->transfer_dma = rr3->dma_in; rr3->read_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; - rr3->ep_out = ep_out; - rr3->udev = udev; - redrat3_reset(rr3); redrat3_get_firmware_rev(rr3); - /* might be all we need to do? */ - retval = redrat3_enable_detector(rr3); - if (retval < 0) - goto error; - /* default.. will get overridden by any sends with a freq defined */ rr3->carrier = 38000; - /* led control */ - rr3->led.name = "redrat3:red:feedback"; - rr3->led.default_trigger = "rc-feedback"; - rr3->led.brightness_set = redrat3_brightness_set; - retval = led_classdev_register(&intf->dev, &rr3->led); - if (retval) - goto error; - atomic_set(&rr3->flash, 0); rr3->flash_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rr3->flash_urb) { - retval = -ENOMEM; - goto led_free_error; - } + if (!rr3->flash_urb) + goto redrat_free; /* setup packet is 'c0 b9 0000 0000 0001' */ rr3->flash_control.bRequestType = 0xc0; @@ -1037,20 +1021,33 @@ static int redrat3_dev_probe(struct usb_interface *intf, &rr3->flash_in_buf, sizeof(rr3->flash_in_buf), redrat3_led_complete, rr3); + /* led control */ + rr3->led.name = "redrat3:red:feedback"; + rr3->led.default_trigger = "rc-feedback"; + rr3->led.brightness_set = redrat3_brightness_set; + retval = led_classdev_register(&intf->dev, &rr3->led); + if (retval) + goto redrat_free; + rr3->rc = redrat3_init_rc_dev(rr3); if (!rr3->rc) { retval = -ENOMEM; - goto led_free_error; + goto led_free; } + /* might be all we need to do? */ + retval = redrat3_enable_detector(rr3); + if (retval < 0) + goto led_free; + /* we can register the device now, as it is ready */ usb_set_intfdata(intf, rr3); return 0; -led_free_error: +led_free: led_classdev_unregister(&rr3->led); -error: +redrat_free: redrat3_delete(rr3, rr3->udev); no_endpoints: -- cgit v1.2.3 From c49fcdde38cba120005d6b86bcbbfacca51309f6 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 19:13:11 -0200 Subject: [media] redrat3: enable carrier reports using wideband receiver The wideband receiver is a little awkward on the redrat3. Data arrives on a different endpoint, and the learning command must be reissued every time data is learned. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 186 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 140 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index af562217a205..33fa1951733c 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -81,6 +81,8 @@ #define RR3_RC_DET_ENABLE 0xbb /* Stop capture with the RC receiver */ #define RR3_RC_DET_DISABLE 0xbc +/* Start capture with the wideband receiver */ +#define RR3_MODSIG_CAPTURE 0xb2 /* Return the status of RC detector capture */ #define RR3_RC_DET_STATUS 0xbd /* Reset redrat */ @@ -105,8 +107,10 @@ #define RR3_CLK_PER_COUNT 12 /* (RR3_CLK / RR3_CLK_PER_COUNT) */ #define RR3_CLK_CONV_FACTOR 2000000 -/* USB bulk-in IR data endpoint address */ -#define RR3_BULK_IN_EP_ADDR 0x82 +/* USB bulk-in wideband IR data endpoint address */ +#define RR3_WIDE_IN_EP_ADDR 0x81 +/* USB bulk-in narrowband IR data endpoint address */ +#define RR3_NARROW_IN_EP_ADDR 0x82 /* Size of the fixed-length portion of the signal */ #define RR3_DRIVER_MAXLENS 128 @@ -207,15 +211,22 @@ struct redrat3_dev { struct urb *flash_urb; u8 flash_in_buf; + /* learning */ + bool wideband; + struct usb_ctrlrequest learn_control; + struct urb *learn_urb; + u8 learn_buf; + /* save off the usb device pointer */ struct usb_device *udev; /* the receive endpoint */ - struct usb_endpoint_descriptor *ep_in; + struct usb_endpoint_descriptor *ep_narrow; /* the buffer to receive data */ void *bulk_in_buf; /* urb used to read ir data */ - struct urb *read_urb; + struct urb *narrow_urb; + struct urb *wide_urb; /* the send endpoint */ struct usb_endpoint_descriptor *ep_out; @@ -236,23 +247,6 @@ struct redrat3_dev { char phys[64]; }; -/* - * redrat3_issue_async - * - * Issues an async read to the ir data in port.. - * sets the callback to be redrat3_handle_async - */ -static void redrat3_issue_async(struct redrat3_dev *rr3) -{ - int res; - - res = usb_submit_urb(rr3->read_urb, GFP_ATOMIC); - if (res) - dev_dbg(rr3->dev, - "%s: receive request FAILED! (res %d, len %d)\n", - __func__, res, rr3->read_urb->transfer_buffer_length); -} - static void redrat3_dump_fw_error(struct redrat3_dev *rr3, int code) { if (!rr3->transmitting && (code != 0x40)) @@ -367,6 +361,14 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3) mod_freq = redrat3_val_to_mod_freq(&rr3->irdata); dev_dbg(dev, "Got mod_freq of %u\n", mod_freq); + if (mod_freq && rr3->wideband) { + DEFINE_IR_RAW_EVENT(ev); + + ev.carrier_report = 1; + ev.carrier = mod_freq; + + ir_raw_event_store(rr3->rc, &ev); + } /* process each rr3 encoded byte into an int */ sig_size = be16_to_cpu(rr3->irdata.sig_size); @@ -449,19 +451,31 @@ static int redrat3_enable_detector(struct redrat3_dev *rr3) return -EIO; } - redrat3_issue_async(rr3); + ret = usb_submit_urb(rr3->narrow_urb, GFP_KERNEL); + if (ret) { + dev_err(rr3->dev, "narrow band urb failed: %d", ret); + return ret; + } - return 0; + ret = usb_submit_urb(rr3->wide_urb, GFP_KERNEL); + if (ret) + dev_err(rr3->dev, "wide band urb failed: %d", ret); + + return ret; } static inline void redrat3_delete(struct redrat3_dev *rr3, struct usb_device *udev) { - usb_kill_urb(rr3->read_urb); + usb_kill_urb(rr3->narrow_urb); + usb_kill_urb(rr3->wide_urb); usb_kill_urb(rr3->flash_urb); - usb_free_urb(rr3->read_urb); + usb_kill_urb(rr3->learn_urb); + usb_free_urb(rr3->narrow_urb); + usb_free_urb(rr3->wide_urb); usb_free_urb(rr3->flash_urb); - usb_free_coherent(udev, le16_to_cpu(rr3->ep_in->wMaxPacketSize), + usb_free_urb(rr3->learn_urb); + usb_free_coherent(udev, le16_to_cpu(rr3->ep_narrow->wMaxPacketSize), rr3->bulk_in_buf, rr3->dma_in); kfree(rr3); @@ -694,9 +708,19 @@ static void redrat3_handle_async(struct urb *urb) switch (urb->status) { case 0: ret = redrat3_get_ir_data(rr3, urb->actual_length); + if (!ret && rr3->wideband && !rr3->learn_urb->hcpriv) { + ret = usb_submit_urb(rr3->learn_urb, GFP_ATOMIC); + if (ret) + dev_err(rr3->dev, "Failed to submit learning urb: %d", + ret); + } + if (!ret) { /* no error, prepare to read more */ - redrat3_issue_async(rr3); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret) + dev_err(rr3->dev, "Failed to resubmit urb: %d", + ret); } break; @@ -856,6 +880,42 @@ static void redrat3_brightness_set(struct led_classdev *led_dev, enum } } +static int redrat3_wideband_receiver(struct rc_dev *rcdev, int enable) +{ + struct redrat3_dev *rr3 = rcdev->priv; + int ret = 0; + + rr3->wideband = enable != 0; + + if (enable) { + ret = usb_submit_urb(rr3->learn_urb, GFP_KERNEL); + if (ret) + dev_err(rr3->dev, "Failed to submit learning urb: %d", + ret); + } + + return ret; +} + +static void redrat3_learn_complete(struct urb *urb) +{ + struct redrat3_dev *rr3 = urb->context; + + switch (urb->status) { + case 0: + break; + case -ECONNRESET: + case -ENOENT: + case -ESHUTDOWN: + usb_unlink_urb(urb); + return; + case -EPIPE: + default: + dev_err(rr3->dev, "Error: learn urb status = %d", urb->status); + break; + } +} + static void redrat3_led_complete(struct urb *urb) { struct redrat3_dev *rr3 = urb->context; @@ -908,6 +968,7 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3) rc->s_timeout = redrat3_set_timeout; rc->tx_ir = redrat3_transmit_ir; rc->s_tx_carrier = redrat3_set_tx_carrier; + rc->s_carrier_report = redrat3_wideband_receiver; rc->driver_name = DRIVER_NAME; rc->rx_resolution = US_TO_NS(2); rc->map_name = RC_MAP_HAUPPAUGE; @@ -933,7 +994,8 @@ static int redrat3_dev_probe(struct usb_interface *intf, struct usb_host_interface *uhi; struct redrat3_dev *rr3; struct usb_endpoint_descriptor *ep; - struct usb_endpoint_descriptor *ep_in = NULL; + struct usb_endpoint_descriptor *ep_narrow = NULL; + struct usb_endpoint_descriptor *ep_wide = NULL; struct usb_endpoint_descriptor *ep_out = NULL; u8 addr, attrs; int pipe, i; @@ -947,15 +1009,16 @@ static int redrat3_dev_probe(struct usb_interface *intf, addr = ep->bEndpointAddress; attrs = ep->bmAttributes; - if ((ep_in == NULL) && - ((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && + if (((addr & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) && ((attrs & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)) { dev_dbg(dev, "found bulk-in endpoint at 0x%02x\n", ep->bEndpointAddress); - /* data comes in on 0x82, 0x81 is for other data... */ - if (ep->bEndpointAddress == RR3_BULK_IN_EP_ADDR) - ep_in = ep; + /* data comes in on 0x82, 0x81 is for learning */ + if (ep->bEndpointAddress == RR3_NARROW_IN_EP_ADDR) + ep_narrow = ep; + if (ep->bEndpointAddress == RR3_WIDE_IN_EP_ADDR) + ep_wide = ep; } if ((ep_out == NULL) && @@ -968,8 +1031,8 @@ static int redrat3_dev_probe(struct usb_interface *intf, } } - if (!ep_in || !ep_out) { - dev_err(dev, "Couldn't find both in and out endpoints\n"); + if (!ep_narrow || !ep_out || !ep_wide) { + dev_err(dev, "Couldn't find all endpoints\n"); retval = -ENODEV; goto no_endpoints; } @@ -980,25 +1043,38 @@ static int redrat3_dev_probe(struct usb_interface *intf, goto no_endpoints; rr3->dev = &intf->dev; - rr3->ep_in = ep_in; + rr3->ep_narrow = ep_narrow; rr3->ep_out = ep_out; rr3->udev = udev; /* set up bulk-in endpoint */ - rr3->read_urb = usb_alloc_urb(0, GFP_KERNEL); - if (!rr3->read_urb) + rr3->narrow_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->narrow_urb) + goto redrat_free; + + rr3->wide_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->wide_urb) goto redrat_free; rr3->bulk_in_buf = usb_alloc_coherent(udev, - le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in); + le16_to_cpu(ep_narrow->wMaxPacketSize), + GFP_KERNEL, &rr3->dma_in); if (!rr3->bulk_in_buf) goto redrat_free; - pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress); - usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf, - le16_to_cpu(ep_in->wMaxPacketSize), redrat3_handle_async, rr3); - rr3->read_urb->transfer_dma = rr3->dma_in; - rr3->read_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + pipe = usb_rcvbulkpipe(udev, ep_narrow->bEndpointAddress); + usb_fill_bulk_urb(rr3->narrow_urb, udev, pipe, rr3->bulk_in_buf, + le16_to_cpu(ep_narrow->wMaxPacketSize), + redrat3_handle_async, rr3); + rr3->narrow_urb->transfer_dma = rr3->dma_in; + rr3->narrow_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + + pipe = usb_rcvbulkpipe(udev, ep_wide->bEndpointAddress); + usb_fill_bulk_urb(rr3->wide_urb, udev, pipe, rr3->bulk_in_buf, + le16_to_cpu(ep_narrow->wMaxPacketSize), + redrat3_handle_async, rr3); + rr3->wide_urb->transfer_dma = rr3->dma_in; + rr3->wide_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; redrat3_reset(rr3); redrat3_get_firmware_rev(rr3); @@ -1011,6 +1087,21 @@ static int redrat3_dev_probe(struct usb_interface *intf, if (!rr3->flash_urb) goto redrat_free; + /* learn urb */ + rr3->learn_urb = usb_alloc_urb(0, GFP_KERNEL); + if (!rr3->learn_urb) + goto redrat_free; + + /* setup packet is 'c0 b2 0000 0000 0001' */ + rr3->learn_control.bRequestType = 0xc0; + rr3->learn_control.bRequest = RR3_MODSIG_CAPTURE; + rr3->learn_control.wLength = cpu_to_le16(1); + + usb_fill_control_urb(rr3->learn_urb, udev, usb_rcvctrlpipe(udev, 0), + (unsigned char *)&rr3->learn_control, + &rr3->learn_buf, sizeof(rr3->learn_buf), + redrat3_learn_complete, rr3); + /* setup packet is 'c0 b9 0000 0000 0001' */ rr3->flash_control.bRequestType = 0xc0; rr3->flash_control.bRequest = RR3_BLINK_LED; @@ -1070,7 +1161,8 @@ static int redrat3_dev_suspend(struct usb_interface *intf, pm_message_t message) struct redrat3_dev *rr3 = usb_get_intfdata(intf); led_classdev_suspend(&rr3->led); - usb_kill_urb(rr3->read_urb); + usb_kill_urb(rr3->narrow_urb); + usb_kill_urb(rr3->wide_urb); usb_kill_urb(rr3->flash_urb); return 0; } @@ -1079,7 +1171,9 @@ static int redrat3_dev_resume(struct usb_interface *intf) { struct redrat3_dev *rr3 = usb_get_intfdata(intf); - if (usb_submit_urb(rr3->read_urb, GFP_ATOMIC)) + if (usb_submit_urb(rr3->narrow_urb, GFP_ATOMIC)) + return -EIO; + if (usb_submit_urb(rr3->wide_urb, GFP_ATOMIC)) return -EIO; led_classdev_resume(&rr3->led); return 0; -- cgit v1.2.3 From a48c4bbdff4f6fe10f9e853b01c8591d734a4e84 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:24 -0200 Subject: [media] redrat3: increase set size for lengths to maximum In learning mode, you can get much longer messages which can run out of lengths. The usb message will slightly larger. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/redrat3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c index 33fa1951733c..2784f5dae398 100644 --- a/drivers/media/rc/redrat3.c +++ b/drivers/media/rc/redrat3.c @@ -113,7 +113,7 @@ #define RR3_NARROW_IN_EP_ADDR 0x82 /* Size of the fixed-length portion of the signal */ -#define RR3_DRIVER_MAXLENS 128 +#define RR3_DRIVER_MAXLENS 255 #define RR3_MAX_SIG_SIZE 512 #define RR3_TIME_UNIT 50 #define RR3_END_OF_SIGNAL 0x7f -- cgit v1.2.3 From ed424bb3680b6e6167a44c5c195ec8f9aea3ab3b Mon Sep 17 00:00:00 2001 From: PrasannaKumar Muralidharan Date: Fri, 18 Nov 2016 23:00:10 +0530 Subject: hwrng: Make explicit that max >= 32 always As hw_random core calls ->read with max > 32 or more, make it explicit. Also remove checks involving 'max' being less than 8. Signed-off-by: PrasannaKumar Muralidharan Signed-off-by: Herbert Xu --- drivers/char/hw_random/msm-rng.c | 4 ---- drivers/char/hw_random/pic32-rng.c | 3 --- drivers/char/hw_random/pseries-rng.c | 5 ++--- include/linux/hw_random.h | 3 +-- 4 files changed, 3 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/char/hw_random/msm-rng.c b/drivers/char/hw_random/msm-rng.c index 96fb986402eb..841fee845ec9 100644 --- a/drivers/char/hw_random/msm-rng.c +++ b/drivers/char/hw_random/msm-rng.c @@ -90,10 +90,6 @@ static int msm_rng_read(struct hwrng *hwrng, void *data, size_t max, bool wait) /* calculate max size bytes to transfer back to caller */ maxsize = min_t(size_t, MAX_HW_FIFO_SIZE, max); - /* no room for word data */ - if (maxsize < WORD_SZ) - return 0; - ret = clk_prepare_enable(rng->clk); if (ret) return ret; diff --git a/drivers/char/hw_random/pic32-rng.c b/drivers/char/hw_random/pic32-rng.c index 11dc9b7c09ce..9b5e68a71d01 100644 --- a/drivers/char/hw_random/pic32-rng.c +++ b/drivers/char/hw_random/pic32-rng.c @@ -62,9 +62,6 @@ static int pic32_rng_read(struct hwrng *rng, void *buf, size_t max, u32 t; unsigned int timeout = RNG_TIMEOUT; - if (max < 8) - return 0; - do { t = readl(priv->base + RNGRCNT) & RCNT_MASK; if (t == 64) { diff --git a/drivers/char/hw_random/pseries-rng.c b/drivers/char/hw_random/pseries-rng.c index 63ce51d09af1..d9f46b437cc2 100644 --- a/drivers/char/hw_random/pseries-rng.c +++ b/drivers/char/hw_random/pseries-rng.c @@ -28,7 +28,6 @@ static int pseries_rng_read(struct hwrng *rng, void *data, size_t max, bool wait) { u64 buffer[PLPAR_HCALL_BUFSIZE]; - size_t size = max < 8 ? max : 8; int rc; rc = plpar_hcall(H_RANDOM, (unsigned long *)buffer); @@ -36,10 +35,10 @@ static int pseries_rng_read(struct hwrng *rng, void *data, size_t max, bool wait pr_err_ratelimited("H_RANDOM call failed %d\n", rc); return -EIO; } - memcpy(data, buffer, size); + memcpy(data, buffer, 8); /* The hypervisor interface returns 64 bits */ - return size; + return 8; } /** diff --git a/include/linux/hw_random.h b/include/linux/hw_random.h index 34a0dc18f327..bee0827766a3 100644 --- a/include/linux/hw_random.h +++ b/include/linux/hw_random.h @@ -30,8 +30,7 @@ * Must not be NULL. *OBSOLETE* * @read: New API. drivers can fill up to max bytes of data * into the buffer. The buffer is aligned for any type - * and max is guaranteed to be >= to that alignment - * (either 4 or 8 depending on architecture). + * and max is a multiple of 4 and >= 32 bytes. * @priv: Private data, for use by the RNG driver. * @quality: Estimation of true entropy in RNG's bitstream * (per mill). -- cgit v1.2.3 From 12accdcb92ca997ffc3bf1e76887fb991d5ac773 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:25 -0200 Subject: [media] lirc: might sleep error in lirc_dev_fop_read [ 101.457944] ------------[ cut here ]------------ [ 101.457954] WARNING: CPU: 3 PID: 1819 at kernel/sched/core.c:7708 __might_sleep+0x7e/0x80 [ 101.457960] do not call blocking ops when !TASK_RUNNING; state=1 set at [] lirc_dev_fop_read+0x292/0x4e0 [lirc_dev] Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 809a8671e3d6..bb2f47a21d68 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -681,7 +681,6 @@ ssize_t lirc_dev_fop_read(struct file *file, * between while condition checking and scheduling) */ add_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_INTERRUPTIBLE); /* * while we didn't provide 'length' bytes, device is opened in blocking @@ -706,13 +705,13 @@ ssize_t lirc_dev_fop_read(struct file *file, } mutex_unlock(&ir->irctl_lock); - schedule(); set_current_state(TASK_INTERRUPTIBLE); + schedule(); + set_current_state(TASK_RUNNING); if (mutex_lock_interruptible(&ir->irctl_lock)) { ret = -ERESTARTSYS; remove_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_RUNNING); goto out_unlocked; } @@ -732,7 +731,6 @@ ssize_t lirc_dev_fop_read(struct file *file, } remove_wait_queue(&ir->buf->wait_poll, &wait); - set_current_state(TASK_RUNNING); out_locked: mutex_unlock(&ir->irctl_lock); -- cgit v1.2.3 From afbb110172b93e44a3fd1b5afb3a71f7f9da4406 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:26 -0200 Subject: [media] lirc: prevent use-after free If you unplug an lirc device while reading from it, you will get an use after free as the cdev is freed while still in use. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index bb2f47a21d68..7215891da248 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -161,15 +161,15 @@ static int lirc_cdev_add(struct irctl *ir) struct lirc_driver *d = &ir->d; struct cdev *cdev; - cdev = kzalloc(sizeof(*cdev), GFP_KERNEL); + cdev = cdev_alloc(); if (!cdev) goto err_out; if (d->fops) { - cdev_init(cdev, d->fops); + cdev->ops = d->fops; cdev->owner = d->owner; } else { - cdev_init(cdev, &lirc_dev_fops); + cdev->ops = &lirc_dev_fops; cdev->owner = THIS_MODULE; } retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor); @@ -187,7 +187,7 @@ static int lirc_cdev_add(struct irctl *ir) return 0; err_out: - kfree(cdev); + cdev_del(cdev); return retval; } @@ -417,7 +417,6 @@ int lirc_unregister_driver(int minor) } else { lirc_irctl_cleanup(ir); cdev_del(cdev); - kfree(cdev); kfree(ir); irctls[minor] = NULL; } @@ -518,7 +517,6 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file) lirc_irctl_cleanup(ir); cdev_del(cdev); irctls[ir->d.minor] = NULL; - kfree(cdev); kfree(ir); } -- cgit v1.2.3 From c77d17c0985a70fa3cd2ecde1e4f4be0dd5e9e12 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 31 Oct 2016 15:52:27 -0200 Subject: [media] lirc: use-after free while reading from device and unplugging Many lirc drivers have their own receive buffers which are freed on unplug (e.g. ir_lirc_unregister). This means that ir->buf->wait_poll will be freed directly after unplug so do not remove yourself from the wait queue. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index 7215891da248..d3039efb4e7c 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -715,7 +715,7 @@ ssize_t lirc_dev_fop_read(struct file *file, if (!ir->attached) { ret = -ENODEV; - break; + goto out_locked; } } else { lirc_buffer_read(ir->buf, buf); -- cgit v1.2.3 From 8c1d254f2de803fc7d74269e8ded79047284c275 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 3 Nov 2016 07:38:01 -0200 Subject: [media] dvb-usb: remove another redundant #include Kernel source files need not include explicitly because the top Makefile forces to include it with: -include $(srctree)/include/linux/kconfig.h Remove another reduntdant include, that managed to sneak by commit 97139d4a6f26 ("treewide: remove redundant #include "). Signed-off-by: Paul Bolle Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/dvb-usb/dibusb-mc-common.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/dvb-usb/dibusb-mc-common.c b/drivers/media/usb/dvb-usb/dibusb-mc-common.c index d66f56cc46a5..c989cac9343d 100644 --- a/drivers/media/usb/dvb-usb/dibusb-mc-common.c +++ b/drivers/media/usb/dvb-usb/dibusb-mc-common.c @@ -9,7 +9,6 @@ * see Documentation/dvb/README.dvb-usb for more information */ -#include #include "dibusb.h" /* 3000MC/P stuff */ -- cgit v1.2.3 From 702ed3be1b1bf4dea05954168321741c0910c645 Mon Sep 17 00:00:00 2001 From: Emil Velikov Date: Mon, 21 Nov 2016 16:24:49 -0600 Subject: PCI: Create revision file in sysfs Currently the revision isn't available via sysfs/libudev thus if one wants to know the value one needs to read through the config file, which can be quite time-consuming because it wakes/powers up the device. There are at least two userspace components which could make use the new file: libpciaccess and libdrm. The former wakes up _every_ PCI device, which can be observed via glxinfo when using Mesa 10.0+ drivers. The latter, in association with Mesa 13.0, can lead to 2-3 second delays while starting firefox, thunderbird or chromium. Link: https://bugs.freedesktop.org/show_bug.cgi?id=98502 Tested-by: Mauro Santos Signed-off-by: Emil Velikov Signed-off-by: Bjorn Helgaas Reviewed-by: Alex Deucher Reviewed-by: Daniel Vetter --- Documentation/ABI/testing/sysfs-bus-pci | 7 +++++++ Documentation/filesystems/sysfs-pci.txt | 2 ++ drivers/pci/pci-sysfs.c | 2 ++ 3 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci index b3bc50f650ee..5a1732b78707 100644 --- a/Documentation/ABI/testing/sysfs-bus-pci +++ b/Documentation/ABI/testing/sysfs-bus-pci @@ -294,3 +294,10 @@ Description: a firmware bug to the system vendor. Writing to this file taints the kernel with TAINT_FIRMWARE_WORKAROUND, which reduces the supportability of your system. + +What: /sys/bus/pci/devices/.../revision +Date: November 2016 +Contact: Emil Velikov +Description: + This file contains the revision field of the the PCI device. + The value comes from device config space. The file is read only. diff --git a/Documentation/filesystems/sysfs-pci.txt b/Documentation/filesystems/sysfs-pci.txt index 74eaac26f8b8..6ea1ceda6f52 100644 --- a/Documentation/filesystems/sysfs-pci.txt +++ b/Documentation/filesystems/sysfs-pci.txt @@ -17,6 +17,7 @@ that support it. For example, a given bus might look like this: | |-- resource0 | |-- resource1 | |-- resource2 + | |-- revision | |-- rom | |-- subsystem_device | |-- subsystem_vendor @@ -41,6 +42,7 @@ files, each with their own function. resource PCI resource host addresses (ascii, ro) resource0..N PCI resource N, if present (binary, mmap, rw[1]) resource0_wc..N_wc PCI WC map resource N, if prefetchable (binary, mmap) + revision PCI revision (ascii, ro) rom PCI ROM resource, if present (binary, ro) subsystem_device PCI subsystem device (ascii, ro) subsystem_vendor PCI subsystem vendor (ascii, ro) diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index bcd10c795284..066628776e1b 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -50,6 +50,7 @@ pci_config_attr(vendor, "0x%04x\n"); pci_config_attr(device, "0x%04x\n"); pci_config_attr(subsystem_vendor, "0x%04x\n"); pci_config_attr(subsystem_device, "0x%04x\n"); +pci_config_attr(revision, "0x%02x\n"); pci_config_attr(class, "0x%06x\n"); pci_config_attr(irq, "%u\n"); @@ -568,6 +569,7 @@ static struct attribute *pci_dev_attrs[] = { &dev_attr_device.attr, &dev_attr_subsystem_vendor.attr, &dev_attr_subsystem_device.attr, + &dev_attr_revision.attr, &dev_attr_class.attr, &dev_attr_irq.attr, &dev_attr_local_cpus.attr, -- cgit v1.2.3 From fb26592301200dbbe4a9943fe188b57a46716900 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 31 Oct 2016 16:00:01 -0500 Subject: PCI: Warn on possible RW1C corruption for sub-32 bit config writes Hardware that supports only 32-bit config writes is not spec-compliant. For example, if software performs a 16-bit write, we must do a 32-bit read, merge in the 16 bits we intend to write, followed by a 32-bit write. If the 16 bits we *don't* intend to write happen to have any RW1C (write-one- to-clear) bits set, we just inadvertently cleared something we shouldn't have. Add a rate-limited warning when we do sub-32 bit config writes. Remove similar probe-time warnings from some of the affected host bridge drivers. Signed-off-by: Bjorn Helgaas Enthusiastically-Acked-by: Russell King Acked-by: Shawn Lin # rockchip Acked-by: Thierry Reding --- drivers/pci/access.c | 16 ++++++++++++++-- drivers/pci/host/pcie-hisi.c | 2 -- drivers/pci/host/pcie-rockchip.c | 3 --- 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/access.c b/drivers/pci/access.c index d11cdbb8fba3..db239547fefd 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c @@ -142,10 +142,22 @@ int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, if (size == 4) { writel(val, addr); return PCIBIOS_SUCCESSFUL; - } else { - mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); } + /* + * In general, hardware that supports only 32-bit writes on PCI is + * not spec-compliant. For example, software may perform a 16-bit + * write. If the hardware only supports 32-bit accesses, we must + * do a 32-bit read, merge in the 16 bits we intend to write, + * followed by a 32-bit write. If the 16 bits we *don't* intend to + * write happen to have any RW1C (write-one-to-clear) bits set, we + * just inadvertently cleared something we shouldn't have. + */ + dev_warn_ratelimited(&bus->dev, "%d-byte config write to %04x:%02x:%02x.%d offset %#x may corrupt adjacent RW1C bits\n", + size, pci_domain_nr(bus), bus->number, + PCI_SLOT(devfn), PCI_FUNC(devfn), where); + + mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8)); tmp = readl(addr) & mask; tmp |= val << ((where & 0x3) * 8); writel(tmp, addr); diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c index 56154c25980c..5b5901d361d8 100644 --- a/drivers/pci/host/pcie-hisi.c +++ b/drivers/pci/host/pcie-hisi.c @@ -194,8 +194,6 @@ static int hisi_pcie_probe(struct platform_device *pdev) if (ret) return ret; - dev_warn(dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n"); - return 0; } diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index e0b22dab9b7a..6419d8ca4a84 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -1187,9 +1187,6 @@ static int rockchip_pcie_probe(struct platform_device *pdev) pcie_bus_configure_settings(child); pci_bus_add_devices(bus); - - dev_warn(dev, "only 32-bit config accesses supported; smaller writes may corrupt adjacent RW1C fields\n"); - return err; err_vpcie: -- cgit v1.2.3 From 57907a73e0ff7ccd561d0202acaabe5537ed359e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 12 Nov 2016 17:01:30 +0000 Subject: soc/fsl: fix spelling mistakes in critical error messages Trivial fix to spelling mistake "uncommited" to "uncommitted" in critical error messages. Signed-off-by: Colin Ian King Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/bman.c | 2 +- drivers/soc/fsl/qbman/qman.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c index ffa48fdbb1a9..48b7eb698689 100644 --- a/drivers/soc/fsl/qbman/bman.c +++ b/drivers/soc/fsl/qbman/bman.c @@ -391,7 +391,7 @@ static void bm_rcr_finish(struct bm_portal *portal) i = bm_in(portal, BM_REG_RCR_PI_CINH) & (BM_RCR_SIZE - 1); if (i != rcr_ptr2idx(rcr->cursor)) - pr_crit("losing uncommited RCR entries\n"); + pr_crit("losing uncommitted RCR entries\n"); i = bm_in(portal, BM_REG_RCR_CI_CINH) & (BM_RCR_SIZE - 1); if (i != rcr->ci) diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 119054bc922b..deeacd5d123e 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -443,7 +443,7 @@ static inline void qm_eqcr_finish(struct qm_portal *portal) DPAA_ASSERT(!eqcr->busy); if (pi != eqcr_ptr2idx(eqcr->cursor)) - pr_crit("losing uncommited EQCR entries\n"); + pr_crit("losing uncommitted EQCR entries\n"); if (ci != eqcr->ci) pr_crit("missing existing EQCR completions\n"); if (eqcr->ci != eqcr_ptr2idx(eqcr->cursor)) -- cgit v1.2.3 From e04e581093d74249f27411ed95878b648b222e53 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 11 Nov 2016 11:40:20 -0200 Subject: [media] atmel-isc: fix error return code in atmel_isc_probe() Fix to return error code -ENODEV from the error handling case instead of 0, as done elsewhere in this function. Signed-off-by: Wei Yongjun Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/atmel/atmel-isc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c index 8e25d3f56438..fa68fe912c95 100644 --- a/drivers/media/platform/atmel/atmel-isc.c +++ b/drivers/media/platform/atmel/atmel-isc.c @@ -1424,6 +1424,7 @@ static int atmel_isc_probe(struct platform_device *pdev) if (list_empty(&isc->subdev_entities)) { dev_err(dev, "no subdev found\n"); + ret = -ENODEV; goto unregister_v4l2_device; } -- cgit v1.2.3 From db9ee88bb22e237a532fa4c8fda0975f8f045246 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 11 Nov 2016 22:23:56 -0200 Subject: [media] vivid: fix HDMI VSDB block in the EDID The maximum 'Max TMDS Rate' in the HDMI VSDB block is 340 MHz, not 600. Higher rates are advertised in the HDMI Forum VSDB block. So lower the Max TMDS rate in the HDMI VSDB block that the vivid driver uses to 300 MHz, which is typical of most HDMI 1.4b devices. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index 5464fefbaab9..b8ef836766df 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -183,7 +183,7 @@ static const u8 vivid_hdmi_edid[256] = { 0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21, 0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09, 0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03, - 0x0c, 0x00, 0x10, 0x00, 0x00, 0x78, 0x21, 0x00, + 0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00, 0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4, 0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xea, 0xe3, 0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d, @@ -194,7 +194,7 @@ static const u8 vivid_hdmi_edid[256] = { 0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51, 0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0, 0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, }; static int vidioc_querycap(struct file *file, void *priv, -- cgit v1.2.3 From 4c0c596adfca795af12e8e61625fd95b50e8f8f3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 12 Nov 2016 15:26:48 -0200 Subject: [media] zoran: fix spelling mistake in dprintk message Trivial fix to spelling mistake "unnsupported" to "unsupported" in debug message. Signed-off-by: Colin Ian King Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/zoran/zoran_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index d6b631add216..2170e174c335 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -1488,7 +1488,7 @@ zoran_set_input (struct zoran *zr, if (input < 0 || input >= zr->card.inputs) { dprintk(1, KERN_ERR - "%s: %s - unnsupported input %d\n", + "%s: %s - unsupported input %d\n", ZR_DEVNAME(zr), __func__, input); return -EINVAL; } -- cgit v1.2.3 From 7febb418a32a2caaef57bca91df41c658406670d Mon Sep 17 00:00:00 2001 From: Minghsiu Tsai Date: Mon, 14 Nov 2016 23:34:34 -0200 Subject: [media] mtk-mdp: allocate video_device dynamically It can fix known problems with embedded video_device structs. Signed-off-by: Minghsiu Tsai Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/mtk-mdp/mtk_mdp_core.h | 2 +- drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c | 33 ++++++++++++++++----------- 2 files changed, 21 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h index 848569d4ab90..ad1cff306efd 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.h +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.h @@ -167,7 +167,7 @@ struct mtk_mdp_dev { struct mtk_mdp_comp *comp[MTK_MDP_COMP_ID_MAX]; struct v4l2_m2m_dev *m2m_dev; struct list_head ctx_list; - struct video_device vdev; + struct video_device *vdev; struct v4l2_device v4l2_dev; struct workqueue_struct *job_wq; struct platform_device *vpu_dev; diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c index 9a747e7321cc..13afe48b9dc5 100644 --- a/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c +++ b/drivers/media/platform/mtk-mdp/mtk_mdp_m2m.c @@ -1236,16 +1236,22 @@ int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp) int ret; mdp->variant = &mtk_mdp_default_variant; - mdp->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; - mdp->vdev.fops = &mtk_mdp_m2m_fops; - mdp->vdev.ioctl_ops = &mtk_mdp_m2m_ioctl_ops; - mdp->vdev.release = video_device_release_empty; - mdp->vdev.lock = &mdp->lock; - mdp->vdev.vfl_dir = VFL_DIR_M2M; - mdp->vdev.v4l2_dev = &mdp->v4l2_dev; - snprintf(mdp->vdev.name, sizeof(mdp->vdev.name), "%s:m2m", + mdp->vdev = video_device_alloc(); + if (!mdp->vdev) { + dev_err(dev, "failed to allocate video device\n"); + ret = -ENOMEM; + goto err_video_alloc; + } + mdp->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; + mdp->vdev->fops = &mtk_mdp_m2m_fops; + mdp->vdev->ioctl_ops = &mtk_mdp_m2m_ioctl_ops; + mdp->vdev->release = video_device_release; + mdp->vdev->lock = &mdp->lock; + mdp->vdev->vfl_dir = VFL_DIR_M2M; + mdp->vdev->v4l2_dev = &mdp->v4l2_dev; + snprintf(mdp->vdev->name, sizeof(mdp->vdev->name), "%s:m2m", MTK_MDP_MODULE_NAME); - video_set_drvdata(&mdp->vdev, mdp); + video_set_drvdata(mdp->vdev, mdp); mdp->m2m_dev = v4l2_m2m_init(&mtk_mdp_m2m_ops); if (IS_ERR(mdp->m2m_dev)) { @@ -1254,26 +1260,27 @@ int mtk_mdp_register_m2m_device(struct mtk_mdp_dev *mdp) goto err_m2m_init; } - ret = video_register_device(&mdp->vdev, VFL_TYPE_GRABBER, 2); + ret = video_register_device(mdp->vdev, VFL_TYPE_GRABBER, 2); if (ret) { dev_err(dev, "failed to register video device\n"); goto err_vdev_register; } v4l2_info(&mdp->v4l2_dev, "driver registered as /dev/video%d", - mdp->vdev.num); + mdp->vdev->num); return 0; err_vdev_register: v4l2_m2m_release(mdp->m2m_dev); err_m2m_init: - video_device_release(&mdp->vdev); + video_device_release(mdp->vdev); +err_video_alloc: return ret; } void mtk_mdp_unregister_m2m_device(struct mtk_mdp_dev *mdp) { - video_device_release(&mdp->vdev); + video_unregister_device(mdp->vdev); v4l2_m2m_release(mdp->m2m_dev); } -- cgit v1.2.3 From 3f98da9636029486b86eb63f0b57b91dcbd880b0 Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 Nov 2016 13:15:45 -0200 Subject: [media] cec: ignore messages that we initiated Some CEC adapters will receive messages that they initiated. Add a check that will ignore such messages. Most hardware behaves correctly in this respect, but I have seen adapters that don't, so just filter this out in the framework. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/cec/cec-adap.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers') diff --git a/drivers/media/cec/cec-adap.c b/drivers/media/cec/cec-adap.c index d9c6f2c1c6fa..0ea4efb3de66 100644 --- a/drivers/media/cec/cec-adap.c +++ b/drivers/media/cec/cec-adap.c @@ -869,6 +869,21 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg) if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE)) return; + /* + * Some CEC adapters will receive the messages that they transmitted. + * This test filters out those messages by checking if we are the + * initiator, and just returning in that case. + * + * Note that this won't work if this is an Unregistered device. + * + * It is bad practice if the hardware receives the message that it + * transmitted and luckily most CEC adapters behave correctly in this + * respect. + */ + if (msg_init != CEC_LOG_ADDR_UNREGISTERED && + cec_has_log_addr(adap, msg_init)) + return; + msg->rx_ts = ktime_get_ns(); msg->rx_status = CEC_RX_STATUS_OK; msg->sequence = msg->reply = msg->timeout = 0; -- cgit v1.2.3 From b66db53f8d85f6e8ce1b2b827d3fb3b0f0bf64c6 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 21 Nov 2016 19:55:51 -0200 Subject: [media] lirc_serial: port to rc-core Tested with a homebrew serial ir. Remove last remmants of the nslu2 which could not be enabled, and fix checkpatch warnings. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_serial.c | 677 +++++++++++++------------------ 1 file changed, 274 insertions(+), 403 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index b798b311d32c..05a8a47aecef 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -9,6 +9,7 @@ * Copyright (C) 1998 Ben Pfaff * Copyright (C) 1999 Christoph Bartelmus * Copyright (C) 2007 Andrei Tanas (suspend/resume support) + * Copyright (C) 2016 Sean Young (port to rc-core) * 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 @@ -18,18 +19,13 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * */ /* * Steve's changes to improve transmission fidelity: * - for systems with the rdtsc instruction and the clock counter, a * send_pule that times the pulses directly using the counter. - * This means that the LIRC_SERIAL_TRANSMITTER_LATENCY fudge is + * This means that the IR_SERIAL_TRANSMITTER_LATENCY fudge is * not needed. Measurement shows very stable waveform, even where * PCI activity slows the access to the UART, which trips up other * versions. @@ -52,56 +48,34 @@ #include #include -#include -#include -#include #include -#include #include #include -#include -#include #include -#include -#include #include -#include #include -#include -#include -#include -#include #include +#include -/* From Intel IXP42X Developer's Manual (#252480-005): */ -/* ftp://download.intel.com/design/network/manuals/25248005.pdf */ -#define UART_IE_IXP42X_UUE 0x40 /* IXP42X UART Unit enable */ -#define UART_IE_IXP42X_RTOIE 0x10 /* IXP42X Receiver Data Timeout int.enable */ - -#include -#include - -#define LIRC_DRIVER_NAME "lirc_serial" - -struct lirc_serial { +struct serial_ir_hw { int signal_pin; int signal_pin_change; u8 on; u8 off; + unsigned set_send_carrier:1; + unsigned set_duty_cycle:1; long (*send_pulse)(unsigned long length); void (*send_space)(long length); - int features; spinlock_t lock; }; -#define LIRC_HOMEBREW 0 -#define LIRC_IRDEO 1 -#define LIRC_IRDEO_REMOTE 2 -#define LIRC_ANIMAX 3 -#define LIRC_IGOR 4 -#define LIRC_NSLU2 5 +#define IR_HOMEBREW 0 +#define IR_IRDEO 1 +#define IR_IRDEO_REMOTE 2 +#define IR_ANIMAX 3 +#define IR_IGOR 4 -/*** module parameters ***/ +/* module parameters */ static int type; static int io; static int irq; @@ -114,107 +88,89 @@ static bool txsense; /* 0 = active high, 1 = active low */ /* forward declarations */ static long send_pulse_irdeo(unsigned long length); -static long send_pulse_homebrew(unsigned long length); static void send_space_irdeo(long length); +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +static long send_pulse_homebrew(unsigned long length); static void send_space_homebrew(long length); +#endif -static struct lirc_serial hardware[] = { - [LIRC_HOMEBREW] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_HOMEBREW].lock), - .signal_pin = UART_MSR_DCD, +static struct serial_ir_hw hardware[] = { + [IR_HOMEBREW] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_HOMEBREW].lock), + .signal_pin = UART_MSR_DCD, .signal_pin_change = UART_MSR_DDCD, .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), .off = (UART_MCR_RTS | UART_MCR_OUT2), +#ifdef CONFIG_IR_SERIAL_TRANSMITTER .send_pulse = send_pulse_homebrew, .send_space = send_space_homebrew, -#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -#else - .features = LIRC_CAN_REC_MODE2 + .set_send_carrier = true, + .set_duty_cycle = true, #endif }, - [LIRC_IRDEO] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_IRDEO].lock), - .signal_pin = UART_MSR_DSR, + [IR_IRDEO] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO].lock), + .signal_pin = UART_MSR_DSR, .signal_pin_change = UART_MSR_DDSR, .on = UART_MCR_OUT2, .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = send_pulse_irdeo, - .send_space = send_space_irdeo, - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) + .send_pulse = send_pulse_irdeo, + .send_space = send_space_irdeo, + .set_duty_cycle = true, }, - [LIRC_IRDEO_REMOTE] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_IRDEO_REMOTE].lock), - .signal_pin = UART_MSR_DSR, + [IR_IRDEO_REMOTE] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO_REMOTE].lock), + .signal_pin = UART_MSR_DSR, .signal_pin_change = UART_MSR_DDSR, .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = send_pulse_irdeo, - .send_space = send_space_irdeo, - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) + .send_pulse = send_pulse_irdeo, + .send_space = send_space_irdeo, + .set_duty_cycle = true, }, - [LIRC_ANIMAX] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_ANIMAX].lock), - .signal_pin = UART_MSR_DCD, + [IR_ANIMAX] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_ANIMAX].lock), + .signal_pin = UART_MSR_DCD, .signal_pin_change = UART_MSR_DDCD, .on = 0, .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), .send_pulse = NULL, .send_space = NULL, - .features = LIRC_CAN_REC_MODE2 }, - [LIRC_IGOR] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[LIRC_IGOR].lock), - .signal_pin = UART_MSR_DSR, + [IR_IGOR] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IGOR].lock), + .signal_pin = UART_MSR_DSR, .signal_pin_change = UART_MSR_DDSR, .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), .off = (UART_MCR_RTS | UART_MCR_OUT2), +#ifdef CONFIG_IR_SERIAL_TRANSMITTER .send_pulse = send_pulse_homebrew, .send_space = send_space_homebrew, -#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER - .features = (LIRC_CAN_SET_SEND_DUTY_CYCLE | - LIRC_CAN_SET_SEND_CARRIER | - LIRC_CAN_SEND_PULSE | LIRC_CAN_REC_MODE2) -#else - .features = LIRC_CAN_REC_MODE2 + .set_send_carrier = true, + .set_duty_cycle = true, #endif }, }; #define RS_ISR_PASS_LIMIT 256 -/* - * A long pulse code from a remote might take up to 300 bytes. The - * daemon should read the bytes as soon as they are generated, so take - * the number of keys you think you can push before the daemon runs - * and multiply by 300. The driver will warn you if you overrun this - * buffer. If you have a slow computer or non-busmastering IDE disks, - * maybe you will need to increase this. - */ - -/* This MUST be a power of two! It has to be larger than 1 as well. */ - -#define RBUF_LEN 256 +struct serial_ir { + ktime_t lastkt; + struct rc_dev *rcdev; + struct platform_device *pdev; -static ktime_t lastkt; + unsigned int freq; + unsigned int duty_cycle; -static struct lirc_buffer rbuf; - -static unsigned int freq = 38000; -static unsigned int duty_cycle = 50; + unsigned long period; + unsigned long pulse_width, space_width; +}; -/* Initialized in init_timing_params() */ -static unsigned long period; -static unsigned long pulse_width; -static unsigned long space_width; +static struct serial_ir serial_ir; #if defined(__i386__) /* @@ -241,18 +197,18 @@ static unsigned long space_width; * changed from 400 to 450 as this works better on slower machines; * faster machines will use the rdtsc code anyway */ -#define LIRC_SERIAL_TRANSMITTER_LATENCY 450 +#define IR_SERIAL_TRANSMITTER_LATENCY 450 #else /* does anybody have information on other platforms ? */ /* 256 = 1<<8 */ -#define LIRC_SERIAL_TRANSMITTER_LATENCY 256 +#define IR_SERIAL_TRANSMITTER_LATENCY 256 -#endif /* __i386__ */ +#endif /* __i386__ */ /* * FIXME: should we be using hrtimers instead of this - * LIRC_SERIAL_TRANSMITTER_LATENCY nonsense? + * IR_SERIAL_TRANSMITTER_LATENCY nonsense? */ /* fetch serial input packet (1 byte) from register offset */ @@ -324,8 +280,8 @@ static int init_timing_params(unsigned int new_duty_cycle, { __u64 loops_per_sec, work; - duty_cycle = new_duty_cycle; - freq = new_freq; + serial_ir.duty_cycle = new_duty_cycle; + serial_ir.freq = new_freq; loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy); loops_per_sec *= HZ; @@ -338,12 +294,12 @@ static int init_timing_params(unsigned int new_duty_cycle, * Carrier period in clocks, approach good up to 32GHz clock, * gets carrier frequency within 8Hz */ - period = loops_per_sec >> 3; - period /= (freq >> 3); + serial_ir.period = loops_per_sec >> 3; + serial_ir.pperiod /= (freq >> 3); /* Derive pulse and space from the period */ - pulse_width = period * duty_cycle / 100; - space_width = period - pulse_width; + serial_ir.ppulse_width = serial_ir.period * serial.ir.duty_cycle / 100; + serial_ir.pspace_width = serial_ir.period - serial_ir.pulse_width; pr_debug("in init_timing_params, freq=%d, duty_cycle=%d, clk/jiffy=%ld, pulse=%ld, space=%ld, conv_us_to_clocks=%ld\n", freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy), pulse_width, space_width, conv_us_to_clocks); @@ -358,18 +314,19 @@ static int init_timing_params(unsigned int new_duty_cycle, * IE multiplied by 256. */ if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= - LIRC_SERIAL_TRANSMITTER_LATENCY) + IR_SERIAL_TRANSMITTER_LATENCY) return -EINVAL; if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= - LIRC_SERIAL_TRANSMITTER_LATENCY) + IR_SERIAL_TRANSMITTER_LATENCY) return -EINVAL; - duty_cycle = new_duty_cycle; - freq = new_freq; - period = 256 * 1000000L / freq; - pulse_width = period * duty_cycle / 100; - space_width = period - pulse_width; + serial_ir.duty_cycle = new_duty_cycle; + serial_ir.freq = new_freq; + serial_ir.period = 256 * 1000000L / serial_ir.freq; + serial_ir.pulse_width = serial_ir.period * serial_ir.duty_cycle / 100; + serial_ir.space_width = serial_ir.period - serial_ir.pulse_width; pr_debug("in init_timing_params, freq=%d pulse=%ld, space=%ld\n", - freq, pulse_width, space_width); + serial_ir.freq, serial_ir.pulse_width, + serial_ir.space_width); return 0; } #endif /* USE_RDTSC */ @@ -386,7 +343,7 @@ static long send_pulse_irdeo(unsigned long length) /* how many bits have to be sent ? */ rawbits = length * 1152 / 10000; - if (duty_cycle > 50) + if (serial_ir.duty_cycle > 50) chunk = 3; else chunk = 1; @@ -429,6 +386,15 @@ static long send_pulse_irdeo(unsigned long length) /* To match 8 fractional bits used for pulse/space length */ +static void send_space_irdeo(long length) +{ + if (length <= 0) + return; + + safe_udelay(length); +} + +#ifdef CONFIG_IR_SERIAL_TRANSMITTER static long send_pulse_homebrew_softcarrier(unsigned long length) { int flag; @@ -440,19 +406,19 @@ static long send_pulse_homebrew_softcarrier(unsigned long length) while (actual < length) { if (flag) { off(); - target += space_width; + target += serial_ir.space_width; } else { on(); - target += pulse_width; + target += serial_ir.pulse_width; } d = (target - actual - - LIRC_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; + IR_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; /* * Note - we've checked in ioctl that the pulse/space * widths are big enough so that d is > 0 */ udelay(d); - actual += (d << 8) + LIRC_SERIAL_TRANSMITTER_LATENCY; + actual += (d << 8) + IR_SERIAL_TRANSMITTER_LATENCY; flag = !flag; } return (actual-length) >> 8; @@ -471,14 +437,6 @@ static long send_pulse_homebrew(unsigned long length) return 0; } -static void send_space_irdeo(long length) -{ - if (length <= 0) - return; - - safe_udelay(length); -} - static void send_space_homebrew(long length) { off(); @@ -486,67 +444,70 @@ static void send_space_homebrew(long length) return; safe_udelay(length); } +#endif -static void rbwrite(int l) -{ - if (lirc_buffer_full(&rbuf)) { - /* no new signals will be accepted */ - pr_debug("Buffer overrun\n"); - return; - } - lirc_buffer_write(&rbuf, (void *)&l); -} - -static void frbwrite(int l) +static void frbwrite(unsigned int l, bool is_pulse) { /* simple noise filter */ - static int pulse, space; - static unsigned int ptr; - - if (ptr > 0 && (l & PULSE_BIT)) { - pulse += l & PULSE_MASK; - if (pulse > 250) { - rbwrite(space); - rbwrite(pulse | PULSE_BIT); + static unsigned int ptr, pulse, space; + DEFINE_IR_RAW_EVENT(ev); + + if (ptr > 0 && is_pulse) { + pulse += l; + if (pulse > 250000) { + ev.duration = space; + ev.pulse = false; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ev.duration = pulse; + ev.pulse = true; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); ptr = 0; pulse = 0; } return; } - if (!(l & PULSE_BIT)) { + if (!is_pulse) { if (ptr == 0) { - if (l > 20000) { + if (l > 20000000) { space = l; ptr++; return; } } else { - if (l > 20000) { + if (l > 20000000) { space += pulse; - if (space > PULSE_MASK) - space = PULSE_MASK; + if (space > IR_MAX_DURATION) + space = IR_MAX_DURATION; space += l; - if (space > PULSE_MASK) - space = PULSE_MASK; + if (space > IR_MAX_DURATION) + space = IR_MAX_DURATION; pulse = 0; return; } - rbwrite(space); - rbwrite(pulse | PULSE_BIT); + + ev.duration = space; + ev.pulse = false; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ev.duration = pulse; + ev.pulse = true; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); ptr = 0; pulse = 0; } } - rbwrite(l); + + ev.duration = l; + ev.pulse = is_pulse; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); } -static irqreturn_t lirc_irq_handler(int i, void *blah) +static irqreturn_t serial_ir_irq_handler(int i, void *blah) { ktime_t kt; int counter, dcd; u8 status; ktime_t delkt; - int data; + unsigned int data; static int last_dcd = -1; if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { @@ -559,7 +520,7 @@ static irqreturn_t lirc_irq_handler(int i, void *blah) counter++; status = sinp(UART_MSR); if (counter > RS_ISR_PASS_LIMIT) { - pr_warn("AIEEEE: We're caught!\n"); + dev_err(&serial_ir.pdev->dev, "Trapped in interrupt"); break; } if ((status & hardware[type].signal_pin_change) @@ -567,47 +528,32 @@ static irqreturn_t lirc_irq_handler(int i, void *blah) /* get current time */ kt = ktime_get(); - /* New mode, written by Trent Piepho - . */ - /* - * The old format was not very portable. - * We now use an int to pass pulses - * and spaces to user space. - * - * If PULSE_BIT is set a pulse has been - * received, otherwise a space has been - * received. The driver needs to know if your - * receiver is active high or active low, or - * the space/pulse sense could be - * inverted. The bits denoted by PULSE_MASK are - * the length in microseconds. Lengths greater - * than or equal to 16 seconds are clamped to - * PULSE_MASK. All other bits are unused. - * This is a much simpler interface for user - * programs, as well as eliminating "out of - * phase" errors with space/pulse - * autodetection. + * The driver needs to know if your receiver is + * active high or active low, or the space/pulse + * sense could be inverted. */ - /* calc time since last interrupt in microseconds */ + /* calc time since last interrupt in nanoseconds */ dcd = (status & hardware[type].signal_pin) ? 1 : 0; if (dcd == last_dcd) { - pr_warn("ignoring spike: %d %d %llx %llx\n", - dcd, sense, ktime_to_us(kt), - ktime_to_us(lastkt)); + dev_err(&serial_ir.pdev->dev, + "ignoring spike: %d %d %lldns %lldns\n", + dcd, sense, ktime_to_ns(kt), + ktime_to_ns(serial_ir.lastkt)); continue; } - delkt = ktime_sub(kt, lastkt); + delkt = ktime_sub(kt, serial_ir.lastkt); if (ktime_compare(delkt, ktime_set(15, 0)) > 0) { - data = PULSE_MASK; /* really long time */ + data = IR_MAX_DURATION; /* really long time */ if (!(dcd^sense)) { /* sanity check */ - pr_warn("AIEEEE: %d %d %llx %llx\n", - dcd, sense, ktime_to_us(kt), - ktime_to_us(lastkt)); + dev_err(&serial_ir.pdev->dev, + "dcd unexpected: %d %d %lldns %lldns\n", + dcd, sense, ktime_to_ns(kt), + ktime_to_ns(serial_ir.lastkt)); /* * detecting pulse while this * MUST be a space! @@ -615,11 +561,11 @@ static irqreturn_t lirc_irq_handler(int i, void *blah) sense = sense ? 0 : 1; } } else - data = (int) ktime_to_us(delkt); - frbwrite(dcd^sense ? data : (data|PULSE_BIT)); - lastkt = kt; + data = ktime_to_ns(delkt); + frbwrite(data, !(dcd ^ sense)); + serial_ir.lastkt = kt; last_dcd = dcd; - wake_up_interruptible(&rbuf.wait_poll); + ir_raw_event_handle(serial_ir.rcdev); } } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ return IRQ_HANDLED; @@ -652,8 +598,6 @@ static int hardware_init_port(void) return -ENODEV; } - - /* Set DLAB 0. */ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); @@ -677,8 +621,8 @@ static int hardware_init_port(void) sinp(UART_MSR); switch (type) { - case LIRC_IRDEO: - case LIRC_IRDEO_REMOTE: + case IR_IRDEO: + case IR_IRDEO_REMOTE: /* setup port to 7N1 @ 115200 Baud */ /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ @@ -698,13 +642,13 @@ static int hardware_init_port(void) return 0; } -static int lirc_serial_probe(struct platform_device *dev) +static int serial_ir_probe(struct platform_device *dev) { int i, nlow, nhigh, result; - result = devm_request_irq(&dev->dev, irq, lirc_irq_handler, - (share_irq ? IRQF_SHARED : 0), - LIRC_DRIVER_NAME, &hardware); + result = devm_request_irq(&dev->dev, irq, serial_ir_irq_handler, + share_irq ? IRQF_SHARED : 0, + KBUILD_MODNAME, &hardware); if (result < 0) { if (result == -EBUSY) dev_err(&dev->dev, "IRQ %d busy\n", irq); @@ -714,17 +658,12 @@ static int lirc_serial_probe(struct platform_device *dev) } /* Reserve io region. */ - /* - * Future MMAP-Developers: Attention! - * For memory mapped I/O you *might* need to use ioremap() first, - * for the NSLU2 it's done in boot code. - */ if (((iommap) && (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift, - LIRC_DRIVER_NAME) == NULL)) + KBUILD_MODNAME) == NULL)) || ((!iommap) && (devm_request_region(&dev->dev, io, 8, - LIRC_DRIVER_NAME) == NULL))) { + KBUILD_MODNAME) == NULL))) { dev_err(&dev->dev, "port %04x already in use\n", io); dev_warn(&dev->dev, "use 'setserial /dev/ttySX uart none'\n"); dev_warn(&dev->dev, @@ -738,7 +677,7 @@ static int lirc_serial_probe(struct platform_device *dev) return result; /* Initialize pulse/space widths */ - init_timing_params(duty_cycle, freq); + init_timing_params(50, 38000); /* If pin is high, then this must be an active low receiver. */ if (sense == -1) { @@ -769,12 +708,12 @@ static int lirc_serial_probe(struct platform_device *dev) return 0; } -static int set_use_inc(void *data) +static int serial_ir_open(struct rc_dev *rcdev) { unsigned long flags; /* initialize timestamp */ - lastkt = ktime_get(); + serial_ir.lastkt = ktime_get(); spin_lock_irqsave(&hardware[type].lock, flags); @@ -788,8 +727,9 @@ static int set_use_inc(void *data) return 0; } -static void set_use_dec(void *data) -{ unsigned long flags; +static void serial_ir_close(struct rc_dev *rcdev) +{ + unsigned long flags; spin_lock_irqsave(&hardware[type].lock, flags); @@ -802,136 +742,44 @@ static void set_use_dec(void *data) spin_unlock_irqrestore(&hardware[type].lock, flags); } -static ssize_t lirc_write(struct file *file, const char __user *buf, - size_t n, loff_t *ppos) +static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + unsigned int count) { - int i, count; unsigned long flags; long delta = 0; - int *wbuf; - - if (!(hardware[type].features & LIRC_CAN_SEND_PULSE)) - return -EPERM; + int i; - count = n / sizeof(int); - if (n % sizeof(int) || count % 2 == 0) - return -EINVAL; - wbuf = memdup_user(buf, n); - if (IS_ERR(wbuf)) - return PTR_ERR(wbuf); spin_lock_irqsave(&hardware[type].lock, flags); - if (type == LIRC_IRDEO) { + if (type == IR_IRDEO) { /* DTR, RTS down */ on(); } for (i = 0; i < count; i++) { if (i%2) - hardware[type].send_space(wbuf[i] - delta); + hardware[type].send_space(txbuf[i] - delta); else - delta = hardware[type].send_pulse(wbuf[i]); + delta = hardware[type].send_pulse(txbuf[i]); } off(); spin_unlock_irqrestore(&hardware[type].lock, flags); - kfree(wbuf); - return n; + return count; } -static long lirc_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) +static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle) { - int result; - u32 __user *uptr = (u32 __user *)arg; - u32 value; - - switch (cmd) { - case LIRC_GET_SEND_MODE: - if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) - return -ENOIOCTLCMD; - - result = put_user(LIRC_SEND2MODE - (hardware[type].features&LIRC_CAN_SEND_MASK), - uptr); - if (result) - return result; - break; - - case LIRC_SET_SEND_MODE: - if (!(hardware[type].features&LIRC_CAN_SEND_MASK)) - return -ENOIOCTLCMD; - - result = get_user(value, uptr); - if (result) - return result; - /* only LIRC_MODE_PULSE supported */ - if (value != LIRC_MODE_PULSE) - return -EINVAL; - break; - - case LIRC_GET_LENGTH: - return -ENOIOCTLCMD; - - case LIRC_SET_SEND_DUTY_CYCLE: - pr_debug("SET_SEND_DUTY_CYCLE\n"); - if (!(hardware[type].features&LIRC_CAN_SET_SEND_DUTY_CYCLE)) - return -ENOIOCTLCMD; - - result = get_user(value, uptr); - if (result) - return result; - if (value <= 0 || value > 100) - return -EINVAL; - return init_timing_params(value, freq); - - case LIRC_SET_SEND_CARRIER: - pr_debug("SET_SEND_CARRIER\n"); - if (!(hardware[type].features&LIRC_CAN_SET_SEND_CARRIER)) - return -ENOIOCTLCMD; - - result = get_user(value, uptr); - if (result) - return result; - if (value > 500000 || value < 20000) - return -EINVAL; - return init_timing_params(duty_cycle, value); - - default: - return lirc_dev_fop_ioctl(filep, cmd, arg); - } - return 0; + return init_timing_params(cycle, serial_ir.freq); } -static const struct file_operations lirc_fops = { - .owner = THIS_MODULE, - .write = lirc_write, - .unlocked_ioctl = lirc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = lirc_ioctl, -#endif - .read = lirc_dev_fop_read, - .poll = lirc_dev_fop_poll, - .open = lirc_dev_fop_open, - .release = lirc_dev_fop_close, - .llseek = no_llseek, -}; - -static struct lirc_driver driver = { - .name = LIRC_DRIVER_NAME, - .minor = -1, - .code_length = 1, - .sample_rate = 0, - .data = NULL, - .add_to_buf = NULL, - .rbuf = &rbuf, - .set_use_inc = set_use_inc, - .set_use_dec = set_use_dec, - .fops = &lirc_fops, - .dev = NULL, - .owner = THIS_MODULE, -}; +static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + if (carrier > 500000 || carrier < 20000) + return -EINVAL; -static struct platform_device *lirc_serial_dev; + return init_timing_params(serial_ir.duty_cycle, carrier); +} -static int lirc_serial_suspend(struct platform_device *dev, - pm_message_t state) +static int serial_ir_suspend(struct platform_device *dev, + pm_message_t state) { /* Set DLAB 0. */ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); @@ -949,10 +797,7 @@ static int lirc_serial_suspend(struct platform_device *dev, return 0; } -/* twisty maze... need a forward-declaration here... */ -static void lirc_serial_exit(void); - -static int lirc_serial_resume(struct platform_device *dev) +static int serial_ir_resume(struct platform_device *dev) { unsigned long flags; int result; @@ -963,79 +808,68 @@ static int lirc_serial_resume(struct platform_device *dev) spin_lock_irqsave(&hardware[type].lock, flags); /* Enable Interrupt */ - lastkt = ktime_get(); + serial_ir.lastkt = ktime_get(); soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); off(); - lirc_buffer_clear(&rbuf); - spin_unlock_irqrestore(&hardware[type].lock, flags); return 0; } -static struct platform_driver lirc_serial_driver = { - .probe = lirc_serial_probe, - .suspend = lirc_serial_suspend, - .resume = lirc_serial_resume, +static struct platform_driver serial_ir_driver = { + .probe = serial_ir_probe, + .suspend = serial_ir_suspend, + .resume = serial_ir_resume, .driver = { - .name = "lirc_serial", + .name = "serial_ir", }, }; -static int __init lirc_serial_init(void) +static int __init serial_ir_init(void) { int result; - /* Init read buffer. */ - result = lirc_buffer_init(&rbuf, sizeof(int), RBUF_LEN); - if (result < 0) + result = platform_driver_register(&serial_ir_driver); + if (result) return result; - result = platform_driver_register(&lirc_serial_driver); - if (result) { - printk("lirc register returned %d\n", result); - goto exit_buffer_free; - } - - lirc_serial_dev = platform_device_alloc("lirc_serial", 0); - if (!lirc_serial_dev) { + serial_ir.pdev = platform_device_alloc("serial_ir", 0); + if (!serial_ir.pdev) { result = -ENOMEM; goto exit_driver_unregister; } - result = platform_device_add(lirc_serial_dev); + result = platform_device_add(serial_ir.pdev); if (result) goto exit_device_put; return 0; exit_device_put: - platform_device_put(lirc_serial_dev); + platform_device_put(serial_ir.pdev); exit_driver_unregister: - platform_driver_unregister(&lirc_serial_driver); -exit_buffer_free: - lirc_buffer_free(&rbuf); + platform_driver_unregister(&serial_ir_driver); return result; } -static void lirc_serial_exit(void) +static void serial_ir_exit(void) { - platform_device_unregister(lirc_serial_dev); - platform_driver_unregister(&lirc_serial_driver); - lirc_buffer_free(&rbuf); + platform_device_unregister(serial_ir.pdev); + platform_driver_unregister(&serial_ir_driver); } -static int __init lirc_serial_init_module(void) +static int __init serial_ir_init_module(void) { + struct rc_dev *rcdev; int result; switch (type) { - case LIRC_HOMEBREW: - case LIRC_IRDEO: - case LIRC_IRDEO_REMOTE: - case LIRC_ANIMAX: - case LIRC_IGOR: + case IR_HOMEBREW: + case IR_IRDEO: + case IR_IRDEO_REMOTE: + case IR_ANIMAX: + case IR_IGOR: /* if nothing specified, use ttyS0/com1 and irq 4 */ io = io ? io : 0x3f8; irq = irq ? irq : 4; @@ -1045,11 +879,10 @@ static int __init lirc_serial_init_module(void) } if (!softcarrier) { switch (type) { - case LIRC_HOMEBREW: - case LIRC_IGOR: - hardware[type].features &= - ~(LIRC_CAN_SET_SEND_DUTY_CYCLE| - LIRC_CAN_SET_SEND_CARRIER); + case IR_HOMEBREW: + case IR_IGOR: + hardware[type].set_send_carrier = false; + hardware[type].set_duty_cycle = false; break; } } @@ -1058,73 +891,111 @@ static int __init lirc_serial_init_module(void) if (sense != -1) sense = !!sense; - result = lirc_serial_init(); + result = serial_ir_init(); if (result) return result; - driver.features = hardware[type].features; - driver.dev = &lirc_serial_dev->dev; - driver.minor = lirc_register_driver(&driver); - if (driver.minor < 0) { - pr_err("register_chrdev failed!\n"); - lirc_serial_exit(); - return driver.minor; + rcdev = devm_rc_allocate_device(&serial_ir.pdev->dev); + if (!rcdev) { + result = -ENOMEM; + goto serial_cleanup; } - return 0; + + if (hardware[type].send_pulse && hardware[type].send_space) + rcdev->tx_ir = serial_ir_tx; + if (hardware[type].set_send_carrier) + rcdev->s_tx_carrier = serial_ir_tx_carrier; + if (hardware[type].set_duty_cycle) + rcdev->s_tx_duty_cycle = serial_ir_tx_duty_cycle; + + switch (type) { + case IR_HOMEBREW: + rcdev->input_name = "Serial IR type home-brew"; + break; + case IR_IRDEO: + rcdev->input_name = "Serial IR type IRdeo"; + break; + case IR_IRDEO_REMOTE: + rcdev->input_name = "Serial IR type IRdeo remote"; + break; + case IR_ANIMAX: + rcdev->input_name = "Serial IR type AnimaX"; + break; + case IR_IGOR: + rcdev->input_name = "Serial IR type IgorPlug"; + break; + } + + rcdev->input_phys = KBUILD_MODNAME "/input0"; + rcdev->input_id.bustype = BUS_HOST; + rcdev->input_id.vendor = 0x0001; + rcdev->input_id.product = 0x0001; + rcdev->input_id.version = 0x0100; + rcdev->open = serial_ir_open; + rcdev->close = serial_ir_close; + rcdev->dev.parent = &serial_ir.pdev->dev; + rcdev->driver_type = RC_DRIVER_IR_RAW; + rcdev->allowed_protocols = RC_BIT_ALL; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->map_name = RC_MAP_RC6_MCE; + rcdev->timeout = IR_DEFAULT_TIMEOUT; + rcdev->rx_resolution = 250000; + + serial_ir.rcdev = rcdev; + + result = rc_register_device(rcdev); + + if (!result) + return 0; +serial_cleanup: + serial_ir_exit(); + return result; } -static void __exit lirc_serial_exit_module(void) +static void __exit serial_ir_exit_module(void) { - lirc_unregister_driver(driver.minor); - lirc_serial_exit(); - pr_debug("cleaned up module\n"); + rc_unregister_device(serial_ir.rcdev); + serial_ir_exit(); } - -module_init(lirc_serial_init_module); -module_exit(lirc_serial_exit_module); +module_init(serial_ir_init_module); +module_exit(serial_ir_exit_module); MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); -MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, " - "Christoph Bartelmus, Andrei Tanas"); +MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus, Andrei Tanas"); MODULE_LICENSE("GPL"); -module_param(type, int, S_IRUGO); -MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo," - " 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug," - " 5 = NSLU2 RX:CTS2/TX:GreenLED)"); +module_param(type, int, 0444); +MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo, 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug"); -module_param(io, int, S_IRUGO); +module_param(io, int, 0444); MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); /* some architectures (e.g. intel xscale) have memory mapped registers */ -module_param(iommap, bool, S_IRUGO); -MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O" - " (0 = no memory mapped io)"); +module_param(iommap, bool, 0444); +MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); /* * some architectures (e.g. intel xscale) align the 8bit serial registers * on 32bit word boundaries. * See linux-kernel/drivers/tty/serial/8250/8250.c serial_in()/out() */ -module_param(ioshift, int, S_IRUGO); +module_param(ioshift, int, 0444); MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); -module_param(irq, int, S_IRUGO); +module_param(irq, int, 0444); MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); -module_param(share_irq, bool, S_IRUGO); +module_param(share_irq, bool, 0444); MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); -module_param(sense, int, S_IRUGO); -MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit" - " (0 = active high, 1 = active low )"); +module_param(sense, int, 0444); +MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit (0 = active high, 1 = active low )"); -#ifdef CONFIG_LIRC_SERIAL_TRANSMITTER -module_param(txsense, bool, S_IRUGO); -MODULE_PARM_DESC(txsense, "Sense of transmitter circuit" - " (0 = active high, 1 = active low )"); +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +module_param(txsense, bool, 0444); +MODULE_PARM_DESC(txsense, "Sense of transmitter circuit (0 = active high, 1 = active low )"); #endif -module_param(softcarrier, bool, S_IRUGO); +module_param(softcarrier, bool, 0444); MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); -- cgit v1.2.3 From 0a847634849c64f6f477c68fb0e4baa24b09abd1 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 21 Nov 2016 19:55:52 -0200 Subject: [media] lirc_serial: use precision ktime rather than guessing This makes transmission more reliable and the code much cleaner. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_serial.c | 286 +++++++------------------------ 1 file changed, 65 insertions(+), 221 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index 05a8a47aecef..7d1c2afcfdb5 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -21,29 +21,6 @@ * GNU General Public License for more details. */ -/* - * Steve's changes to improve transmission fidelity: - * - for systems with the rdtsc instruction and the clock counter, a - * send_pule that times the pulses directly using the counter. - * This means that the IR_SERIAL_TRANSMITTER_LATENCY fudge is - * not needed. Measurement shows very stable waveform, even where - * PCI activity slows the access to the UART, which trips up other - * versions. - * - For other system, non-integer-microsecond pulse/space lengths, - * done using fixed point binary. So, much more accurate carrier - * frequency. - * - fine tuned transmitter latency, taking advantage of fractional - * microseconds in previous change - * - Fixed bug in the way transmitter latency was accounted for by - * tuning the pulse lengths down - the send_pulse routine ignored - * this overhead as it timed the overall pulse length - so the - * pulse frequency was right but overall pulse length was too - * long. Fixed by accounting for latency on each pulse/space - * iteration. - * - * Steve Davies July 2001 - */ - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include @@ -64,8 +41,8 @@ struct serial_ir_hw { u8 off; unsigned set_send_carrier:1; unsigned set_duty_cycle:1; - long (*send_pulse)(unsigned long length); - void (*send_space)(long length); + void (*send_pulse)(unsigned int length, ktime_t edge); + void (*send_space)(void); spinlock_t lock; }; @@ -87,11 +64,11 @@ static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ static bool txsense; /* 0 = active high, 1 = active low */ /* forward declarations */ -static long send_pulse_irdeo(unsigned long length); -static void send_space_irdeo(long length); +static void send_pulse_irdeo(unsigned int length, ktime_t edge); +static void send_space_irdeo(void); #ifdef CONFIG_IR_SERIAL_TRANSMITTER -static long send_pulse_homebrew(unsigned long length); -static void send_space_homebrew(long length); +static void send_pulse_homebrew(unsigned int length, ktime_t edge); +static void send_space_homebrew(void); #endif static struct serial_ir_hw hardware[] = { @@ -137,8 +114,6 @@ static struct serial_ir_hw hardware[] = { .signal_pin_change = UART_MSR_DDCD, .on = 0, .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = NULL, - .send_space = NULL, }, [IR_IGOR] = { @@ -166,51 +141,11 @@ struct serial_ir { unsigned int freq; unsigned int duty_cycle; - unsigned long period; - unsigned long pulse_width, space_width; + unsigned int pulse_width, space_width; }; static struct serial_ir serial_ir; -#if defined(__i386__) -/* - * From: - * Linux I/O port programming mini-HOWTO - * Author: Riku Saikkonen - * v, 28 December 1997 - * - * [...] - * Actually, a port I/O instruction on most ports in the 0-0x3ff range - * takes almost exactly 1 microsecond, so if you're, for example, using - * the parallel port directly, just do additional inb()s from that port - * to delay. - * [...] - */ -/* transmitter latency 1.5625us 0x1.90 - this figure arrived at from - * comment above plus trimming to match actual measured frequency. - * This will be sensitive to cpu speed, though hopefully most of the 1.5us - * is spent in the uart access. Still - for reference test machine was a - * 1.13GHz Athlon system - Steve - */ - -/* - * changed from 400 to 450 as this works better on slower machines; - * faster machines will use the rdtsc code anyway - */ -#define IR_SERIAL_TRANSMITTER_LATENCY 450 - -#else - -/* does anybody have information on other platforms ? */ -/* 256 = 1<<8 */ -#define IR_SERIAL_TRANSMITTER_LATENCY 256 - -#endif /* __i386__ */ -/* - * FIXME: should we be using hrtimers instead of this - * IR_SERIAL_TRANSMITTER_LATENCY nonsense? - */ - /* fetch serial input packet (1 byte) from register offset */ static u8 sinp(int offset) { @@ -247,96 +182,21 @@ static void off(void) soutp(UART_MCR, hardware[type].off); } -#ifndef MAX_UDELAY_MS -#define MAX_UDELAY_US 5000 -#else -#define MAX_UDELAY_US (MAX_UDELAY_MS*1000) -#endif - -static void safe_udelay(unsigned long usecs) +static void init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) { - while (usecs > MAX_UDELAY_US) { - udelay(MAX_UDELAY_US); - usecs -= MAX_UDELAY_US; - } - udelay(usecs); -} - -#ifdef USE_RDTSC -/* - * This is an overflow/precision juggle, complicated in that we can't - * do long long divide in the kernel - */ - -/* - * When we use the rdtsc instruction to measure clocks, we keep the - * pulse and space widths as clock cycles. As this is CPU speed - * dependent, the widths must be calculated in init_port and ioctl - * time - */ - -static int init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ - __u64 loops_per_sec, work; - serial_ir.duty_cycle = new_duty_cycle; serial_ir.freq = new_freq; - loops_per_sec = __this_cpu_read(cpu.info.loops_per_jiffy); - loops_per_sec *= HZ; - - /* How many clocks in a microsecond?, avoiding long long divide */ - work = loops_per_sec; - work *= 4295; /* 4295 = 2^32 / 1e6 */ - - /* - * Carrier period in clocks, approach good up to 32GHz clock, - * gets carrier frequency within 8Hz - */ - serial_ir.period = loops_per_sec >> 3; - serial_ir.pperiod /= (freq >> 3); - - /* Derive pulse and space from the period */ - serial_ir.ppulse_width = serial_ir.period * serial.ir.duty_cycle / 100; - serial_ir.pspace_width = serial_ir.period - serial_ir.pulse_width; - pr_debug("in init_timing_params, freq=%d, duty_cycle=%d, clk/jiffy=%ld, pulse=%ld, space=%ld, conv_us_to_clocks=%ld\n", - freq, duty_cycle, __this_cpu_read(cpu_info.loops_per_jiffy), - pulse_width, space_width, conv_us_to_clocks); - return 0; -} -#else /* ! USE_RDTSC */ -static int init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ -/* - * period, pulse/space width are kept with 8 binary places - - * IE multiplied by 256. - */ - if (256 * 1000000L / new_freq * new_duty_cycle / 100 <= - IR_SERIAL_TRANSMITTER_LATENCY) - return -EINVAL; - if (256 * 1000000L / new_freq * (100 - new_duty_cycle) / 100 <= - IR_SERIAL_TRANSMITTER_LATENCY) - return -EINVAL; - serial_ir.duty_cycle = new_duty_cycle; - serial_ir.freq = new_freq; - serial_ir.period = 256 * 1000000L / serial_ir.freq; - serial_ir.pulse_width = serial_ir.period * serial_ir.duty_cycle / 100; - serial_ir.space_width = serial_ir.period - serial_ir.pulse_width; - pr_debug("in init_timing_params, freq=%d pulse=%ld, space=%ld\n", - serial_ir.freq, serial_ir.pulse_width, - serial_ir.space_width); - return 0; + serial_ir.pulse_width = DIV_ROUND_CLOSEST( + new_duty_cycle * NSEC_PER_SEC, new_freq * 100l); + serial_ir.space_width = DIV_ROUND_CLOSEST( + (100l - new_duty_cycle) * NSEC_PER_SEC, new_freq * 100l); } -#endif /* USE_RDTSC */ - -/* return value: space length delta */ - -static long send_pulse_irdeo(unsigned long length) +static void send_pulse_irdeo(unsigned int length, ktime_t target) { - long rawbits, ret; + long rawbits; int i; unsigned char output; unsigned char chunk, shifted; @@ -365,84 +225,53 @@ static long send_pulse_irdeo(unsigned long length) while (!(sinp(UART_LSR) & UART_LSR_TEMT)) ; } - - if (i == 0) - ret = (-rawbits) * 10000 / 1152; - else - ret = (3 - i) * 3 * 10000 / 1152 + (-rawbits) * 10000 / 1152; - - return ret; } -/* Version using udelay() */ - -/* - * here we use fixed point arithmetic, with 8 - * fractional bits. that gets us within 0.1% or so of the right average - * frequency, albeit with some jitter in pulse length - Steve - * - * This should use ndelay instead. - */ - -/* To match 8 fractional bits used for pulse/space length */ - -static void send_space_irdeo(long length) +static void send_space_irdeo(void) { - if (length <= 0) - return; - - safe_udelay(length); } #ifdef CONFIG_IR_SERIAL_TRANSMITTER -static long send_pulse_homebrew_softcarrier(unsigned long length) +static void send_pulse_homebrew_softcarrier(unsigned int length, ktime_t edge) { - int flag; - unsigned long actual, target, d; - - length <<= 8; + ktime_t now, target = ktime_add_us(edge, length); + /* + * delta should never exceed 4 seconds and on m68k + * ndelay(s64) does not compile; so use s32 rather than s64. + */ + s32 delta; - actual = 0; target = 0; flag = 0; - while (actual < length) { - if (flag) { - off(); - target += serial_ir.space_width; - } else { - on(); - target += serial_ir.pulse_width; - } - d = (target - actual - - IR_SERIAL_TRANSMITTER_LATENCY + 128) >> 8; - /* - * Note - we've checked in ioctl that the pulse/space - * widths are big enough so that d is > 0 - */ - udelay(d); - actual += (d << 8) + IR_SERIAL_TRANSMITTER_LATENCY; - flag = !flag; + for (;;) { + now = ktime_get(); + if (ktime_compare(now, target) >= 0) + break; + on(); + edge = ktime_add_ns(edge, serial_ir.pulse_width); + delta = ktime_to_ns(ktime_sub(edge, now)); + if (delta > 0) + ndelay(delta); + now = ktime_get(); + off(); + if (ktime_compare(now, target) >= 0) + break; + edge = ktime_add_ns(edge, serial_ir.space_width); + delta = ktime_to_ns(ktime_sub(edge, now)); + if (delta > 0) + ndelay(delta); } - return (actual-length) >> 8; } -static long send_pulse_homebrew(unsigned long length) +static void send_pulse_homebrew(unsigned int length, ktime_t edge) { - if (length <= 0) - return 0; - if (softcarrier) - return send_pulse_homebrew_softcarrier(length); - - on(); - safe_udelay(length); - return 0; + send_pulse_homebrew_softcarrier(length, edge); + else + on(); } -static void send_space_homebrew(long length) +static void send_space_homebrew(void) { off(); - if (length <= 0) - return; - safe_udelay(length); } #endif @@ -746,7 +575,8 @@ static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, unsigned int count) { unsigned long flags; - long delta = 0; + ktime_t edge; + s64 delta; int i; spin_lock_irqsave(&hardware[type].lock, flags); @@ -754,11 +584,23 @@ static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, /* DTR, RTS down */ on(); } + + edge = ktime_get(); for (i = 0; i < count; i++) { if (i%2) - hardware[type].send_space(txbuf[i] - delta); + hardware[type].send_space(); else - delta = hardware[type].send_pulse(txbuf[i]); + hardware[type].send_pulse(txbuf[i], edge); + + edge = ktime_add_us(edge, txbuf[i]); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 25) { + spin_unlock_irqrestore(&hardware[type].lock, flags); + usleep_range(delta - 25, delta + 25); + spin_lock_irqsave(&hardware[type].lock, flags); + } + else if (delta > 0) + udelay(delta); } off(); spin_unlock_irqrestore(&hardware[type].lock, flags); @@ -767,7 +609,8 @@ static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle) { - return init_timing_params(cycle, serial_ir.freq); + init_timing_params(cycle, serial_ir.freq); + return 0; } static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) @@ -775,7 +618,8 @@ static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) if (carrier > 500000 || carrier < 20000) return -EINVAL; - return init_timing_params(serial_ir.duty_cycle, carrier); + init_timing_params(serial_ir.duty_cycle, carrier); + return 0; } static int serial_ir_suspend(struct platform_device *dev, -- cgit v1.2.3 From a6f6ad4173b31bb900d69689b6dfb0c01968abbd Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Nov 2016 05:46:14 -0200 Subject: lirc_serial: make checkpatch happy There are a few checkpatch complains here. As we're about to promote this driver out of staging, address them. Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_serial.c | 37 ++++++++++++++++---------------- 1 file changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c index 7d1c2afcfdb5..9691ba4d55b9 100644 --- a/drivers/staging/media/lirc/lirc_serial.c +++ b/drivers/staging/media/lirc/lirc_serial.c @@ -352,8 +352,8 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah) dev_err(&serial_ir.pdev->dev, "Trapped in interrupt"); break; } - if ((status & hardware[type].signal_pin_change) - && sense != -1) { + if ((status & hardware[type].signal_pin_change) && + sense != -1) { /* get current time */ kt = ktime_get(); @@ -377,7 +377,7 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah) delkt = ktime_sub(kt, serial_ir.lastkt); if (ktime_compare(delkt, ktime_set(15, 0)) > 0) { data = IR_MAX_DURATION; /* really long time */ - if (!(dcd^sense)) { + if (!(dcd ^ sense)) { /* sanity check */ dev_err(&serial_ir.pdev->dev, "dcd unexpected: %d %d %lldns %lldns\n", @@ -389,8 +389,9 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah) */ sense = sense ? 0 : 1; } - } else + } else { data = ktime_to_ns(delkt); + } frbwrite(data, !(dcd ^ sense)); serial_ir.lastkt = kt; last_dcd = dcd; @@ -400,7 +401,6 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah) return IRQ_HANDLED; } - static int hardware_init_port(void) { u8 scratch, scratch2, scratch3; @@ -432,7 +432,7 @@ static int hardware_init_port(void) /* First of all, disable all interrupts */ soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); /* Clear registers. */ sinp(UART_LSR); @@ -487,12 +487,11 @@ static int serial_ir_probe(struct platform_device *dev) } /* Reserve io region. */ - if (((iommap) - && (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift, - KBUILD_MODNAME) == NULL)) - || ((!iommap) - && (devm_request_region(&dev->dev, io, 8, - KBUILD_MODNAME) == NULL))) { + if ((iommap && + (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift, + KBUILD_MODNAME) == NULL)) || + (!iommap && (devm_request_region(&dev->dev, io, 8, + KBUILD_MODNAME) == NULL))) { dev_err(&dev->dev, "port %04x already in use\n", io); dev_warn(&dev->dev, "use 'setserial /dev/ttySX uart none'\n"); dev_warn(&dev->dev, @@ -549,7 +548,7 @@ static int serial_ir_open(struct rc_dev *rcdev) /* Set DLAB 0. */ soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); + soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); spin_unlock_irqrestore(&hardware[type].lock, flags); @@ -567,7 +566,7 @@ static void serial_ir_close(struct rc_dev *rcdev) /* First of all, disable all interrupts */ soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); spin_unlock_irqrestore(&hardware[type].lock, flags); } @@ -587,7 +586,7 @@ static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, edge = ktime_get(); for (i = 0; i < count; i++) { - if (i%2) + if (i % 2) hardware[type].send_space(); else hardware[type].send_pulse(txbuf[i], edge); @@ -598,9 +597,9 @@ static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, spin_unlock_irqrestore(&hardware[type].lock, flags); usleep_range(delta - 25, delta + 25); spin_lock_irqsave(&hardware[type].lock, flags); - } - else if (delta > 0) + } else if (delta > 0) { udelay(delta); + } } off(); spin_unlock_irqrestore(&hardware[type].lock, flags); @@ -630,7 +629,7 @@ static int serial_ir_suspend(struct platform_device *dev, /* Disable all interrupts */ soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI|UART_IER_RLSI|UART_IER_THRI|UART_IER_RDI))); + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); /* Clear registers. */ sinp(UART_LSR); @@ -653,7 +652,7 @@ static int serial_ir_resume(struct platform_device *dev) spin_lock_irqsave(&hardware[type].lock, flags); /* Enable Interrupt */ serial_ir.lastkt = ktime_get(); - soutp(UART_IER, sinp(UART_IER)|UART_IER_MSI); + soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); off(); spin_unlock_irqrestore(&hardware[type].lock, flags); -- cgit v1.2.3 From fa5dc29c1fcc9151c3bcfd9e291a2899ae15f61d Mon Sep 17 00:00:00 2001 From: Sean Young Date: Mon, 21 Nov 2016 19:55:53 -0200 Subject: [media] lirc_serial: move out of staging and rename to serial_ir Signed-off-by: Sean Young --- MAINTAINERS | 6 + drivers/media/rc/Kconfig | 17 + drivers/media/rc/Makefile | 1 + drivers/media/rc/serial_ir.c | 844 +++++++++++++++++++++++++++++++ drivers/staging/media/lirc/Kconfig | 13 - drivers/staging/media/lirc/Makefile | 1 - drivers/staging/media/lirc/lirc_serial.c | 844 ------------------------------- 7 files changed, 868 insertions(+), 858 deletions(-) create mode 100644 drivers/media/rc/serial_ir.c delete mode 100644 drivers/staging/media/lirc/lirc_serial.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 3db2078e0e47..52cc0775a799 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10631,6 +10631,12 @@ S: Maintained F: Documentation/devicetree/bindings/serial/ F: drivers/tty/serial/ +SERIAL IR RECEIVER +M: Sean Young +L: linux-media@vger.kernel.org +S: Maintained +F: drivers/media/rc/serial_ir.c + STI CEC DRIVER M: Benjamin Gaignard L: kernel@stlinux.com diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 370e16e07867..629e8ca15ab3 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -389,4 +389,21 @@ config IR_SUNXI To compile this driver as a module, choose M here: the module will be called sunxi-ir. +config IR_SERIAL + tristate "Homebrew Serial Port Receiver" + depends on RC_CORE + ---help--- + Say Y if you want to use Homebrew Serial Port Receivers and + Transceivers. + + To compile this driver as a module, choose M here: the module will + be called serial-ir. + +config IR_SERIAL_TRANSMITTER + bool "Serial Port Transmitter" + default y + depends on IR_SERIAL + ---help--- + Serial Port Transmitter support + endif #RC_DEVICES diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile index 379a5c0f1379..3a984ee301e2 100644 --- a/drivers/media/rc/Makefile +++ b/drivers/media/rc/Makefile @@ -37,3 +37,4 @@ obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o obj-$(CONFIG_RC_ST) += st_rc.o obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o obj-$(CONFIG_IR_IMG) += img-ir/ +obj-$(CONFIG_IR_SERIAL) += serial_ir.o diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c new file mode 100644 index 000000000000..ba83b20913cd --- /dev/null +++ b/drivers/media/rc/serial_ir.c @@ -0,0 +1,844 @@ +/* + * serial_ir.c + * + * serial_ir - Device driver that records pulse- and pause-lengths + * (space-lengths) between DDCD event on a serial port. + * + * Copyright (C) 1996,97 Ralph Metzler + * Copyright (C) 1998 Trent Piepho + * Copyright (C) 1998 Ben Pfaff + * Copyright (C) 1999 Christoph Bartelmus + * Copyright (C) 2007 Andrei Tanas (suspend/resume support) + * Copyright (C) 2016 Sean Young (port to rc-core) + * 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. + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct serial_ir_hw { + int signal_pin; + int signal_pin_change; + u8 on; + u8 off; + unsigned set_send_carrier:1; + unsigned set_duty_cycle:1; + void (*send_pulse)(unsigned int length, ktime_t edge); + void (*send_space)(void); + spinlock_t lock; +}; + +#define IR_HOMEBREW 0 +#define IR_IRDEO 1 +#define IR_IRDEO_REMOTE 2 +#define IR_ANIMAX 3 +#define IR_IGOR 4 + +/* module parameters */ +static int type; +static int io; +static int irq; +static bool iommap; +static int ioshift; +static bool softcarrier = true; +static bool share_irq; +static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ +static bool txsense; /* 0 = active high, 1 = active low */ + +/* forward declarations */ +static void send_pulse_irdeo(unsigned int length, ktime_t edge); +static void send_space_irdeo(void); +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +static void send_pulse_homebrew(unsigned int length, ktime_t edge); +static void send_space_homebrew(void); +#endif + +static struct serial_ir_hw hardware[] = { + [IR_HOMEBREW] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_HOMEBREW].lock), + .signal_pin = UART_MSR_DCD, + .signal_pin_change = UART_MSR_DDCD, + .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), + .off = (UART_MCR_RTS | UART_MCR_OUT2), +#ifdef CONFIG_IR_SERIAL_TRANSMITTER + .send_pulse = send_pulse_homebrew, + .send_space = send_space_homebrew, + .set_send_carrier = true, + .set_duty_cycle = true, +#endif + }, + + [IR_IRDEO] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO].lock), + .signal_pin = UART_MSR_DSR, + .signal_pin_change = UART_MSR_DDSR, + .on = UART_MCR_OUT2, + .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + .send_pulse = send_pulse_irdeo, + .send_space = send_space_irdeo, + .set_duty_cycle = true, + }, + + [IR_IRDEO_REMOTE] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO_REMOTE].lock), + .signal_pin = UART_MSR_DSR, + .signal_pin_change = UART_MSR_DDSR, + .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + .send_pulse = send_pulse_irdeo, + .send_space = send_space_irdeo, + .set_duty_cycle = true, + }, + + [IR_ANIMAX] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_ANIMAX].lock), + .signal_pin = UART_MSR_DCD, + .signal_pin_change = UART_MSR_DDCD, + .on = 0, + .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), + }, + + [IR_IGOR] = { + .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IGOR].lock), + .signal_pin = UART_MSR_DSR, + .signal_pin_change = UART_MSR_DDSR, + .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), + .off = (UART_MCR_RTS | UART_MCR_OUT2), +#ifdef CONFIG_IR_SERIAL_TRANSMITTER + .send_pulse = send_pulse_homebrew, + .send_space = send_space_homebrew, + .set_send_carrier = true, + .set_duty_cycle = true, +#endif + }, +}; + +#define RS_ISR_PASS_LIMIT 256 + +struct serial_ir { + ktime_t lastkt; + struct rc_dev *rcdev; + struct platform_device *pdev; + + unsigned int freq; + unsigned int duty_cycle; + + unsigned int pulse_width, space_width; +}; + +static struct serial_ir serial_ir; + +/* fetch serial input packet (1 byte) from register offset */ +static u8 sinp(int offset) +{ + if (iommap) + /* the register is memory-mapped */ + offset <<= ioshift; + + return inb(io + offset); +} + +/* write serial output packet (1 byte) of value to register offset */ +static void soutp(int offset, u8 value) +{ + if (iommap) + /* the register is memory-mapped */ + offset <<= ioshift; + + outb(value, io + offset); +} + +static void on(void) +{ + if (txsense) + soutp(UART_MCR, hardware[type].off); + else + soutp(UART_MCR, hardware[type].on); +} + +static void off(void) +{ + if (txsense) + soutp(UART_MCR, hardware[type].on); + else + soutp(UART_MCR, hardware[type].off); +} + +static void init_timing_params(unsigned int new_duty_cycle, + unsigned int new_freq) +{ + serial_ir.duty_cycle = new_duty_cycle; + serial_ir.freq = new_freq; + + serial_ir.pulse_width = DIV_ROUND_CLOSEST( + new_duty_cycle * NSEC_PER_SEC, new_freq * 100l); + serial_ir.space_width = DIV_ROUND_CLOSEST( + (100l - new_duty_cycle) * NSEC_PER_SEC, new_freq * 100l); +} + +static void send_pulse_irdeo(unsigned int length, ktime_t target) +{ + long rawbits; + int i; + unsigned char output; + unsigned char chunk, shifted; + + /* how many bits have to be sent ? */ + rawbits = length * 1152 / 10000; + if (serial_ir.duty_cycle > 50) + chunk = 3; + else + chunk = 1; + for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { + shifted = chunk << (i * 3); + shifted >>= 1; + output &= (~shifted); + i++; + if (i == 3) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_THRE)) + ; + output = 0x7f; + i = 0; + } + } + if (i != 0) { + soutp(UART_TX, output); + while (!(sinp(UART_LSR) & UART_LSR_TEMT)) + ; + } +} + +static void send_space_irdeo(void) +{ +} + +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +static void send_pulse_homebrew_softcarrier(unsigned int length, ktime_t edge) +{ + ktime_t now, target = ktime_add_us(edge, length); + /* + * delta should never exceed 4 seconds and on m68k + * ndelay(s64) does not compile; so use s32 rather than s64. + */ + s32 delta; + + for (;;) { + now = ktime_get(); + if (ktime_compare(now, target) >= 0) + break; + on(); + edge = ktime_add_ns(edge, serial_ir.pulse_width); + delta = ktime_to_ns(ktime_sub(edge, now)); + if (delta > 0) + ndelay(delta); + now = ktime_get(); + off(); + if (ktime_compare(now, target) >= 0) + break; + edge = ktime_add_ns(edge, serial_ir.space_width); + delta = ktime_to_ns(ktime_sub(edge, now)); + if (delta > 0) + ndelay(delta); + } +} + +static void send_pulse_homebrew(unsigned int length, ktime_t edge) +{ + if (softcarrier) + send_pulse_homebrew_softcarrier(length, edge); + else + on(); +} + +static void send_space_homebrew(void) +{ + off(); +} +#endif + +static void frbwrite(unsigned int l, bool is_pulse) +{ + /* simple noise filter */ + static unsigned int ptr, pulse, space; + DEFINE_IR_RAW_EVENT(ev); + + if (ptr > 0 && is_pulse) { + pulse += l; + if (pulse > 250000) { + ev.duration = space; + ev.pulse = false; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ev.duration = pulse; + ev.pulse = true; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ptr = 0; + pulse = 0; + } + return; + } + if (!is_pulse) { + if (ptr == 0) { + if (l > 20000000) { + space = l; + ptr++; + return; + } + } else { + if (l > 20000000) { + space += pulse; + if (space > IR_MAX_DURATION) + space = IR_MAX_DURATION; + space += l; + if (space > IR_MAX_DURATION) + space = IR_MAX_DURATION; + pulse = 0; + return; + } + + ev.duration = space; + ev.pulse = false; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ev.duration = pulse; + ev.pulse = true; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); + ptr = 0; + pulse = 0; + } + } + + ev.duration = l; + ev.pulse = is_pulse; + ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); +} + +static irqreturn_t serial_ir_irq_handler(int i, void *blah) +{ + ktime_t kt; + int counter, dcd; + u8 status; + ktime_t delkt; + unsigned int data; + static int last_dcd = -1; + + if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { + /* not our interrupt */ + return IRQ_NONE; + } + + counter = 0; + do { + counter++; + status = sinp(UART_MSR); + if (counter > RS_ISR_PASS_LIMIT) { + dev_err(&serial_ir.pdev->dev, "Trapped in interrupt"); + break; + } + if ((status & hardware[type].signal_pin_change) && + sense != -1) { + /* get current time */ + kt = ktime_get(); + + /* + * The driver needs to know if your receiver is + * active high or active low, or the space/pulse + * sense could be inverted. + */ + + /* calc time since last interrupt in nanoseconds */ + dcd = (status & hardware[type].signal_pin) ? 1 : 0; + + if (dcd == last_dcd) { + dev_err(&serial_ir.pdev->dev, + "ignoring spike: %d %d %lldns %lldns\n", + dcd, sense, ktime_to_ns(kt), + ktime_to_ns(serial_ir.lastkt)); + continue; + } + + delkt = ktime_sub(kt, serial_ir.lastkt); + if (ktime_compare(delkt, ktime_set(15, 0)) > 0) { + data = IR_MAX_DURATION; /* really long time */ + if (!(dcd ^ sense)) { + /* sanity check */ + dev_err(&serial_ir.pdev->dev, + "dcd unexpected: %d %d %lldns %lldns\n", + dcd, sense, ktime_to_ns(kt), + ktime_to_ns(serial_ir.lastkt)); + /* + * detecting pulse while this + * MUST be a space! + */ + sense = sense ? 0 : 1; + } + } else { + data = ktime_to_ns(delkt); + } + frbwrite(data, !(dcd ^ sense)); + serial_ir.lastkt = kt; + last_dcd = dcd; + ir_raw_event_handle(serial_ir.rcdev); + } + } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ + return IRQ_HANDLED; +} + +static int hardware_init_port(void) +{ + u8 scratch, scratch2, scratch3; + + /* + * This is a simple port existence test, borrowed from the autoconfig + * function in drivers/serial/8250.c + */ + scratch = sinp(UART_IER); + soutp(UART_IER, 0); +#ifdef __i386__ + outb(0xff, 0x080); +#endif + scratch2 = sinp(UART_IER) & 0x0f; + soutp(UART_IER, 0x0f); +#ifdef __i386__ + outb(0x00, 0x080); +#endif + scratch3 = sinp(UART_IER) & 0x0f; + soutp(UART_IER, scratch); + if (scratch2 != 0 || scratch3 != 0x0f) { + /* we fail, there's nothing here */ + pr_err("port existence test failed, cannot continue\n"); + return -ENODEV; + } + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + /* Set line for power source */ + off(); + + /* Clear registers again to be sure. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + switch (type) { + case IR_IRDEO: + case IR_IRDEO_REMOTE: + /* setup port to 7N1 @ 115200 Baud */ + /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ + + /* Set DLAB 1. */ + soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); + /* Set divisor to 1 => 115200 Baud */ + soutp(UART_DLM, 0); + soutp(UART_DLL, 1); + /* Set DLAB 0 + 7N1 */ + soutp(UART_LCR, UART_LCR_WLEN7); + /* THR interrupt already disabled at this point */ + break; + default: + break; + } + + return 0; +} + +static int serial_ir_probe(struct platform_device *dev) +{ + int i, nlow, nhigh, result; + + result = devm_request_irq(&dev->dev, irq, serial_ir_irq_handler, + share_irq ? IRQF_SHARED : 0, + KBUILD_MODNAME, &hardware); + if (result < 0) { + if (result == -EBUSY) + dev_err(&dev->dev, "IRQ %d busy\n", irq); + else if (result == -EINVAL) + dev_err(&dev->dev, "Bad irq number or handler\n"); + return result; + } + + /* Reserve io region. */ + if ((iommap && + (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift, + KBUILD_MODNAME) == NULL)) || + (!iommap && (devm_request_region(&dev->dev, io, 8, + KBUILD_MODNAME) == NULL))) { + dev_err(&dev->dev, "port %04x already in use\n", io); + dev_warn(&dev->dev, "use 'setserial /dev/ttySX uart none'\n"); + dev_warn(&dev->dev, + "or compile the serial port driver as module and\n"); + dev_warn(&dev->dev, "make sure this module is loaded first\n"); + return -EBUSY; + } + + result = hardware_init_port(); + if (result < 0) + return result; + + /* Initialize pulse/space widths */ + init_timing_params(50, 38000); + + /* If pin is high, then this must be an active low receiver. */ + if (sense == -1) { + /* wait 1/2 sec for the power supply */ + msleep(500); + + /* + * probe 9 times every 0.04s, collect "votes" for + * active high/low + */ + nlow = 0; + nhigh = 0; + for (i = 0; i < 9; i++) { + if (sinp(UART_MSR) & hardware[type].signal_pin) + nlow++; + else + nhigh++; + msleep(40); + } + sense = nlow >= nhigh ? 1 : 0; + dev_info(&dev->dev, "auto-detected active %s receiver\n", + sense ? "low" : "high"); + } else + dev_info(&dev->dev, "Manually using active %s receiver\n", + sense ? "low" : "high"); + + dev_dbg(&dev->dev, "Interrupt %d, port %04x obtained\n", irq, io); + return 0; +} + +static int serial_ir_open(struct rc_dev *rcdev) +{ + unsigned long flags; + + /* initialize timestamp */ + serial_ir.lastkt = ktime_get(); + + spin_lock_irqsave(&hardware[type].lock, flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); + + spin_unlock_irqrestore(&hardware[type].lock, flags); + + return 0; +} + +static void serial_ir_close(struct rc_dev *rcdev) +{ + unsigned long flags; + + spin_lock_irqsave(&hardware[type].lock, flags); + + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* First of all, disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); + spin_unlock_irqrestore(&hardware[type].lock, flags); +} + +static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, + unsigned int count) +{ + unsigned long flags; + ktime_t edge; + s64 delta; + int i; + + spin_lock_irqsave(&hardware[type].lock, flags); + if (type == IR_IRDEO) { + /* DTR, RTS down */ + on(); + } + + edge = ktime_get(); + for (i = 0; i < count; i++) { + if (i % 2) + hardware[type].send_space(); + else + hardware[type].send_pulse(txbuf[i], edge); + + edge = ktime_add_us(edge, txbuf[i]); + delta = ktime_us_delta(edge, ktime_get()); + if (delta > 25) { + spin_unlock_irqrestore(&hardware[type].lock, flags); + usleep_range(delta - 25, delta + 25); + spin_lock_irqsave(&hardware[type].lock, flags); + } else if (delta > 0) { + udelay(delta); + } + } + off(); + spin_unlock_irqrestore(&hardware[type].lock, flags); + return count; +} + +static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle) +{ + init_timing_params(cycle, serial_ir.freq); + return 0; +} + +static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) +{ + if (carrier > 500000 || carrier < 20000) + return -EINVAL; + + init_timing_params(serial_ir.duty_cycle, carrier); + return 0; +} + +static int serial_ir_suspend(struct platform_device *dev, + pm_message_t state) +{ + /* Set DLAB 0. */ + soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); + + /* Disable all interrupts */ + soutp(UART_IER, sinp(UART_IER) & + (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); + + /* Clear registers. */ + sinp(UART_LSR); + sinp(UART_RX); + sinp(UART_IIR); + sinp(UART_MSR); + + return 0; +} + +static int serial_ir_resume(struct platform_device *dev) +{ + unsigned long flags; + int result; + + result = hardware_init_port(); + if (result < 0) + return result; + + spin_lock_irqsave(&hardware[type].lock, flags); + /* Enable Interrupt */ + serial_ir.lastkt = ktime_get(); + soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); + off(); + + spin_unlock_irqrestore(&hardware[type].lock, flags); + + return 0; +} + +static struct platform_driver serial_ir_driver = { + .probe = serial_ir_probe, + .suspend = serial_ir_suspend, + .resume = serial_ir_resume, + .driver = { + .name = "serial_ir", + }, +}; + +static int __init serial_ir_init(void) +{ + int result; + + result = platform_driver_register(&serial_ir_driver); + if (result) + return result; + + serial_ir.pdev = platform_device_alloc("serial_ir", 0); + if (!serial_ir.pdev) { + result = -ENOMEM; + goto exit_driver_unregister; + } + + result = platform_device_add(serial_ir.pdev); + if (result) + goto exit_device_put; + + return 0; + +exit_device_put: + platform_device_put(serial_ir.pdev); +exit_driver_unregister: + platform_driver_unregister(&serial_ir_driver); + return result; +} + +static void serial_ir_exit(void) +{ + platform_device_unregister(serial_ir.pdev); + platform_driver_unregister(&serial_ir_driver); +} + +static int __init serial_ir_init_module(void) +{ + struct rc_dev *rcdev; + int result; + + switch (type) { + case IR_HOMEBREW: + case IR_IRDEO: + case IR_IRDEO_REMOTE: + case IR_ANIMAX: + case IR_IGOR: + /* if nothing specified, use ttyS0/com1 and irq 4 */ + io = io ? io : 0x3f8; + irq = irq ? irq : 4; + break; + default: + return -EINVAL; + } + if (!softcarrier) { + switch (type) { + case IR_HOMEBREW: + case IR_IGOR: + hardware[type].set_send_carrier = false; + hardware[type].set_duty_cycle = false; + break; + } + } + + /* make sure sense is either -1, 0, or 1 */ + if (sense != -1) + sense = !!sense; + + result = serial_ir_init(); + if (result) + return result; + + rcdev = devm_rc_allocate_device(&serial_ir.pdev->dev); + if (!rcdev) { + result = -ENOMEM; + goto serial_cleanup; + } + + if (hardware[type].send_pulse && hardware[type].send_space) + rcdev->tx_ir = serial_ir_tx; + if (hardware[type].set_send_carrier) + rcdev->s_tx_carrier = serial_ir_tx_carrier; + if (hardware[type].set_duty_cycle) + rcdev->s_tx_duty_cycle = serial_ir_tx_duty_cycle; + + switch (type) { + case IR_HOMEBREW: + rcdev->input_name = "Serial IR type home-brew"; + break; + case IR_IRDEO: + rcdev->input_name = "Serial IR type IRdeo"; + break; + case IR_IRDEO_REMOTE: + rcdev->input_name = "Serial IR type IRdeo remote"; + break; + case IR_ANIMAX: + rcdev->input_name = "Serial IR type AnimaX"; + break; + case IR_IGOR: + rcdev->input_name = "Serial IR type IgorPlug"; + break; + } + + rcdev->input_phys = KBUILD_MODNAME "/input0"; + rcdev->input_id.bustype = BUS_HOST; + rcdev->input_id.vendor = 0x0001; + rcdev->input_id.product = 0x0001; + rcdev->input_id.version = 0x0100; + rcdev->open = serial_ir_open; + rcdev->close = serial_ir_close; + rcdev->dev.parent = &serial_ir.pdev->dev; + rcdev->driver_type = RC_DRIVER_IR_RAW; + rcdev->allowed_protocols = RC_BIT_ALL; + rcdev->driver_name = KBUILD_MODNAME; + rcdev->map_name = RC_MAP_RC6_MCE; + rcdev->timeout = IR_DEFAULT_TIMEOUT; + rcdev->rx_resolution = 250000; + + serial_ir.rcdev = rcdev; + + result = rc_register_device(rcdev); + + if (!result) + return 0; +serial_cleanup: + serial_ir_exit(); + return result; +} + +static void __exit serial_ir_exit_module(void) +{ + rc_unregister_device(serial_ir.rcdev); + serial_ir_exit(); +} + +module_init(serial_ir_init_module); +module_exit(serial_ir_exit_module); + +MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); +MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus, Andrei Tanas"); +MODULE_LICENSE("GPL"); + +module_param(type, int, 0444); +MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo, 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug"); + +module_param(io, int, 0444); +MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); + +/* some architectures (e.g. intel xscale) have memory mapped registers */ +module_param(iommap, bool, 0444); +MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); + +/* + * some architectures (e.g. intel xscale) align the 8bit serial registers + * on 32bit word boundaries. + * See linux-kernel/drivers/tty/serial/8250/8250.c serial_in()/out() + */ +module_param(ioshift, int, 0444); +MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); + +module_param(irq, int, 0444); +MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); + +module_param(share_irq, bool, 0444); +MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); + +module_param(sense, int, 0444); +MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit (0 = active high, 1 = active low )"); + +#ifdef CONFIG_IR_SERIAL_TRANSMITTER +module_param(txsense, bool, 0444); +MODULE_PARM_DESC(txsense, "Sense of transmitter circuit (0 = active high, 1 = active low )"); +#endif + +module_param(softcarrier, bool, 0444); +MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig index 6879c4651b46..25b7e7ccf554 100644 --- a/drivers/staging/media/lirc/Kconfig +++ b/drivers/staging/media/lirc/Kconfig @@ -38,19 +38,6 @@ config LIRC_SASEM help Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module -config LIRC_SERIAL - tristate "Homebrew Serial Port Receiver" - depends on LIRC - help - Driver for Homebrew Serial Port Receivers - -config LIRC_SERIAL_TRANSMITTER - bool "Serial Port Transmitter" - default y - depends on LIRC_SERIAL - help - Serial Port Transmitter support - config LIRC_SIR tristate "Built-in SIR IrDA port" depends on LIRC diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile index 5430adf0475d..7f919eab1989 100644 --- a/drivers/staging/media/lirc/Makefile +++ b/drivers/staging/media/lirc/Makefile @@ -7,6 +7,5 @@ obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o obj-$(CONFIG_LIRC_IMON) += lirc_imon.o obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o -obj-$(CONFIG_LIRC_SERIAL) += lirc_serial.o obj-$(CONFIG_LIRC_SIR) += lirc_sir.o obj-$(CONFIG_LIRC_ZILOG) += lirc_zilog.o diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c deleted file mode 100644 index 9691ba4d55b9..000000000000 --- a/drivers/staging/media/lirc/lirc_serial.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * lirc_serial.c - * - * lirc_serial - Device driver that records pulse- and pause-lengths - * (space-lengths) between DDCD event on a serial port. - * - * Copyright (C) 1996,97 Ralph Metzler - * Copyright (C) 1998 Trent Piepho - * Copyright (C) 1998 Ben Pfaff - * Copyright (C) 1999 Christoph Bartelmus - * Copyright (C) 2007 Andrei Tanas (suspend/resume support) - * Copyright (C) 2016 Sean Young (port to rc-core) - * 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct serial_ir_hw { - int signal_pin; - int signal_pin_change; - u8 on; - u8 off; - unsigned set_send_carrier:1; - unsigned set_duty_cycle:1; - void (*send_pulse)(unsigned int length, ktime_t edge); - void (*send_space)(void); - spinlock_t lock; -}; - -#define IR_HOMEBREW 0 -#define IR_IRDEO 1 -#define IR_IRDEO_REMOTE 2 -#define IR_ANIMAX 3 -#define IR_IGOR 4 - -/* module parameters */ -static int type; -static int io; -static int irq; -static bool iommap; -static int ioshift; -static bool softcarrier = true; -static bool share_irq; -static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */ -static bool txsense; /* 0 = active high, 1 = active low */ - -/* forward declarations */ -static void send_pulse_irdeo(unsigned int length, ktime_t edge); -static void send_space_irdeo(void); -#ifdef CONFIG_IR_SERIAL_TRANSMITTER -static void send_pulse_homebrew(unsigned int length, ktime_t edge); -static void send_space_homebrew(void); -#endif - -static struct serial_ir_hw hardware[] = { - [IR_HOMEBREW] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_HOMEBREW].lock), - .signal_pin = UART_MSR_DCD, - .signal_pin_change = UART_MSR_DDCD, - .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), - .off = (UART_MCR_RTS | UART_MCR_OUT2), -#ifdef CONFIG_IR_SERIAL_TRANSMITTER - .send_pulse = send_pulse_homebrew, - .send_space = send_space_homebrew, - .set_send_carrier = true, - .set_duty_cycle = true, -#endif - }, - - [IR_IRDEO] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO].lock), - .signal_pin = UART_MSR_DSR, - .signal_pin_change = UART_MSR_DDSR, - .on = UART_MCR_OUT2, - .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = send_pulse_irdeo, - .send_space = send_space_irdeo, - .set_duty_cycle = true, - }, - - [IR_IRDEO_REMOTE] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IRDEO_REMOTE].lock), - .signal_pin = UART_MSR_DSR, - .signal_pin_change = UART_MSR_DDSR, - .on = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - .send_pulse = send_pulse_irdeo, - .send_space = send_space_irdeo, - .set_duty_cycle = true, - }, - - [IR_ANIMAX] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_ANIMAX].lock), - .signal_pin = UART_MSR_DCD, - .signal_pin_change = UART_MSR_DDCD, - .on = 0, - .off = (UART_MCR_RTS | UART_MCR_DTR | UART_MCR_OUT2), - }, - - [IR_IGOR] = { - .lock = __SPIN_LOCK_UNLOCKED(hardware[IR_IGOR].lock), - .signal_pin = UART_MSR_DSR, - .signal_pin_change = UART_MSR_DDSR, - .on = (UART_MCR_RTS | UART_MCR_OUT2 | UART_MCR_DTR), - .off = (UART_MCR_RTS | UART_MCR_OUT2), -#ifdef CONFIG_IR_SERIAL_TRANSMITTER - .send_pulse = send_pulse_homebrew, - .send_space = send_space_homebrew, - .set_send_carrier = true, - .set_duty_cycle = true, -#endif - }, -}; - -#define RS_ISR_PASS_LIMIT 256 - -struct serial_ir { - ktime_t lastkt; - struct rc_dev *rcdev; - struct platform_device *pdev; - - unsigned int freq; - unsigned int duty_cycle; - - unsigned int pulse_width, space_width; -}; - -static struct serial_ir serial_ir; - -/* fetch serial input packet (1 byte) from register offset */ -static u8 sinp(int offset) -{ - if (iommap) - /* the register is memory-mapped */ - offset <<= ioshift; - - return inb(io + offset); -} - -/* write serial output packet (1 byte) of value to register offset */ -static void soutp(int offset, u8 value) -{ - if (iommap) - /* the register is memory-mapped */ - offset <<= ioshift; - - outb(value, io + offset); -} - -static void on(void) -{ - if (txsense) - soutp(UART_MCR, hardware[type].off); - else - soutp(UART_MCR, hardware[type].on); -} - -static void off(void) -{ - if (txsense) - soutp(UART_MCR, hardware[type].on); - else - soutp(UART_MCR, hardware[type].off); -} - -static void init_timing_params(unsigned int new_duty_cycle, - unsigned int new_freq) -{ - serial_ir.duty_cycle = new_duty_cycle; - serial_ir.freq = new_freq; - - serial_ir.pulse_width = DIV_ROUND_CLOSEST( - new_duty_cycle * NSEC_PER_SEC, new_freq * 100l); - serial_ir.space_width = DIV_ROUND_CLOSEST( - (100l - new_duty_cycle) * NSEC_PER_SEC, new_freq * 100l); -} - -static void send_pulse_irdeo(unsigned int length, ktime_t target) -{ - long rawbits; - int i; - unsigned char output; - unsigned char chunk, shifted; - - /* how many bits have to be sent ? */ - rawbits = length * 1152 / 10000; - if (serial_ir.duty_cycle > 50) - chunk = 3; - else - chunk = 1; - for (i = 0, output = 0x7f; rawbits > 0; rawbits -= 3) { - shifted = chunk << (i * 3); - shifted >>= 1; - output &= (~shifted); - i++; - if (i == 3) { - soutp(UART_TX, output); - while (!(sinp(UART_LSR) & UART_LSR_THRE)) - ; - output = 0x7f; - i = 0; - } - } - if (i != 0) { - soutp(UART_TX, output); - while (!(sinp(UART_LSR) & UART_LSR_TEMT)) - ; - } -} - -static void send_space_irdeo(void) -{ -} - -#ifdef CONFIG_IR_SERIAL_TRANSMITTER -static void send_pulse_homebrew_softcarrier(unsigned int length, ktime_t edge) -{ - ktime_t now, target = ktime_add_us(edge, length); - /* - * delta should never exceed 4 seconds and on m68k - * ndelay(s64) does not compile; so use s32 rather than s64. - */ - s32 delta; - - for (;;) { - now = ktime_get(); - if (ktime_compare(now, target) >= 0) - break; - on(); - edge = ktime_add_ns(edge, serial_ir.pulse_width); - delta = ktime_to_ns(ktime_sub(edge, now)); - if (delta > 0) - ndelay(delta); - now = ktime_get(); - off(); - if (ktime_compare(now, target) >= 0) - break; - edge = ktime_add_ns(edge, serial_ir.space_width); - delta = ktime_to_ns(ktime_sub(edge, now)); - if (delta > 0) - ndelay(delta); - } -} - -static void send_pulse_homebrew(unsigned int length, ktime_t edge) -{ - if (softcarrier) - send_pulse_homebrew_softcarrier(length, edge); - else - on(); -} - -static void send_space_homebrew(void) -{ - off(); -} -#endif - -static void frbwrite(unsigned int l, bool is_pulse) -{ - /* simple noise filter */ - static unsigned int ptr, pulse, space; - DEFINE_IR_RAW_EVENT(ev); - - if (ptr > 0 && is_pulse) { - pulse += l; - if (pulse > 250000) { - ev.duration = space; - ev.pulse = false; - ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); - ev.duration = pulse; - ev.pulse = true; - ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); - ptr = 0; - pulse = 0; - } - return; - } - if (!is_pulse) { - if (ptr == 0) { - if (l > 20000000) { - space = l; - ptr++; - return; - } - } else { - if (l > 20000000) { - space += pulse; - if (space > IR_MAX_DURATION) - space = IR_MAX_DURATION; - space += l; - if (space > IR_MAX_DURATION) - space = IR_MAX_DURATION; - pulse = 0; - return; - } - - ev.duration = space; - ev.pulse = false; - ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); - ev.duration = pulse; - ev.pulse = true; - ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); - ptr = 0; - pulse = 0; - } - } - - ev.duration = l; - ev.pulse = is_pulse; - ir_raw_event_store_with_filter(serial_ir.rcdev, &ev); -} - -static irqreturn_t serial_ir_irq_handler(int i, void *blah) -{ - ktime_t kt; - int counter, dcd; - u8 status; - ktime_t delkt; - unsigned int data; - static int last_dcd = -1; - - if ((sinp(UART_IIR) & UART_IIR_NO_INT)) { - /* not our interrupt */ - return IRQ_NONE; - } - - counter = 0; - do { - counter++; - status = sinp(UART_MSR); - if (counter > RS_ISR_PASS_LIMIT) { - dev_err(&serial_ir.pdev->dev, "Trapped in interrupt"); - break; - } - if ((status & hardware[type].signal_pin_change) && - sense != -1) { - /* get current time */ - kt = ktime_get(); - - /* - * The driver needs to know if your receiver is - * active high or active low, or the space/pulse - * sense could be inverted. - */ - - /* calc time since last interrupt in nanoseconds */ - dcd = (status & hardware[type].signal_pin) ? 1 : 0; - - if (dcd == last_dcd) { - dev_err(&serial_ir.pdev->dev, - "ignoring spike: %d %d %lldns %lldns\n", - dcd, sense, ktime_to_ns(kt), - ktime_to_ns(serial_ir.lastkt)); - continue; - } - - delkt = ktime_sub(kt, serial_ir.lastkt); - if (ktime_compare(delkt, ktime_set(15, 0)) > 0) { - data = IR_MAX_DURATION; /* really long time */ - if (!(dcd ^ sense)) { - /* sanity check */ - dev_err(&serial_ir.pdev->dev, - "dcd unexpected: %d %d %lldns %lldns\n", - dcd, sense, ktime_to_ns(kt), - ktime_to_ns(serial_ir.lastkt)); - /* - * detecting pulse while this - * MUST be a space! - */ - sense = sense ? 0 : 1; - } - } else { - data = ktime_to_ns(delkt); - } - frbwrite(data, !(dcd ^ sense)); - serial_ir.lastkt = kt; - last_dcd = dcd; - ir_raw_event_handle(serial_ir.rcdev); - } - } while (!(sinp(UART_IIR) & UART_IIR_NO_INT)); /* still pending ? */ - return IRQ_HANDLED; -} - -static int hardware_init_port(void) -{ - u8 scratch, scratch2, scratch3; - - /* - * This is a simple port existence test, borrowed from the autoconfig - * function in drivers/serial/8250.c - */ - scratch = sinp(UART_IER); - soutp(UART_IER, 0); -#ifdef __i386__ - outb(0xff, 0x080); -#endif - scratch2 = sinp(UART_IER) & 0x0f; - soutp(UART_IER, 0x0f); -#ifdef __i386__ - outb(0x00, 0x080); -#endif - scratch3 = sinp(UART_IER) & 0x0f; - soutp(UART_IER, scratch); - if (scratch2 != 0 || scratch3 != 0x0f) { - /* we fail, there's nothing here */ - pr_err("port existence test failed, cannot continue\n"); - return -ENODEV; - } - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* First of all, disable all interrupts */ - soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); - - /* Clear registers. */ - sinp(UART_LSR); - sinp(UART_RX); - sinp(UART_IIR); - sinp(UART_MSR); - - /* Set line for power source */ - off(); - - /* Clear registers again to be sure. */ - sinp(UART_LSR); - sinp(UART_RX); - sinp(UART_IIR); - sinp(UART_MSR); - - switch (type) { - case IR_IRDEO: - case IR_IRDEO_REMOTE: - /* setup port to 7N1 @ 115200 Baud */ - /* 7N1+start = 9 bits at 115200 ~ 3 bits at 38kHz */ - - /* Set DLAB 1. */ - soutp(UART_LCR, sinp(UART_LCR) | UART_LCR_DLAB); - /* Set divisor to 1 => 115200 Baud */ - soutp(UART_DLM, 0); - soutp(UART_DLL, 1); - /* Set DLAB 0 + 7N1 */ - soutp(UART_LCR, UART_LCR_WLEN7); - /* THR interrupt already disabled at this point */ - break; - default: - break; - } - - return 0; -} - -static int serial_ir_probe(struct platform_device *dev) -{ - int i, nlow, nhigh, result; - - result = devm_request_irq(&dev->dev, irq, serial_ir_irq_handler, - share_irq ? IRQF_SHARED : 0, - KBUILD_MODNAME, &hardware); - if (result < 0) { - if (result == -EBUSY) - dev_err(&dev->dev, "IRQ %d busy\n", irq); - else if (result == -EINVAL) - dev_err(&dev->dev, "Bad irq number or handler\n"); - return result; - } - - /* Reserve io region. */ - if ((iommap && - (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift, - KBUILD_MODNAME) == NULL)) || - (!iommap && (devm_request_region(&dev->dev, io, 8, - KBUILD_MODNAME) == NULL))) { - dev_err(&dev->dev, "port %04x already in use\n", io); - dev_warn(&dev->dev, "use 'setserial /dev/ttySX uart none'\n"); - dev_warn(&dev->dev, - "or compile the serial port driver as module and\n"); - dev_warn(&dev->dev, "make sure this module is loaded first\n"); - return -EBUSY; - } - - result = hardware_init_port(); - if (result < 0) - return result; - - /* Initialize pulse/space widths */ - init_timing_params(50, 38000); - - /* If pin is high, then this must be an active low receiver. */ - if (sense == -1) { - /* wait 1/2 sec for the power supply */ - msleep(500); - - /* - * probe 9 times every 0.04s, collect "votes" for - * active high/low - */ - nlow = 0; - nhigh = 0; - for (i = 0; i < 9; i++) { - if (sinp(UART_MSR) & hardware[type].signal_pin) - nlow++; - else - nhigh++; - msleep(40); - } - sense = nlow >= nhigh ? 1 : 0; - dev_info(&dev->dev, "auto-detected active %s receiver\n", - sense ? "low" : "high"); - } else - dev_info(&dev->dev, "Manually using active %s receiver\n", - sense ? "low" : "high"); - - dev_dbg(&dev->dev, "Interrupt %d, port %04x obtained\n", irq, io); - return 0; -} - -static int serial_ir_open(struct rc_dev *rcdev) -{ - unsigned long flags; - - /* initialize timestamp */ - serial_ir.lastkt = ktime_get(); - - spin_lock_irqsave(&hardware[type].lock, flags); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); - - spin_unlock_irqrestore(&hardware[type].lock, flags); - - return 0; -} - -static void serial_ir_close(struct rc_dev *rcdev) -{ - unsigned long flags; - - spin_lock_irqsave(&hardware[type].lock, flags); - - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* First of all, disable all interrupts */ - soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); - spin_unlock_irqrestore(&hardware[type].lock, flags); -} - -static int serial_ir_tx(struct rc_dev *dev, unsigned int *txbuf, - unsigned int count) -{ - unsigned long flags; - ktime_t edge; - s64 delta; - int i; - - spin_lock_irqsave(&hardware[type].lock, flags); - if (type == IR_IRDEO) { - /* DTR, RTS down */ - on(); - } - - edge = ktime_get(); - for (i = 0; i < count; i++) { - if (i % 2) - hardware[type].send_space(); - else - hardware[type].send_pulse(txbuf[i], edge); - - edge = ktime_add_us(edge, txbuf[i]); - delta = ktime_us_delta(edge, ktime_get()); - if (delta > 25) { - spin_unlock_irqrestore(&hardware[type].lock, flags); - usleep_range(delta - 25, delta + 25); - spin_lock_irqsave(&hardware[type].lock, flags); - } else if (delta > 0) { - udelay(delta); - } - } - off(); - spin_unlock_irqrestore(&hardware[type].lock, flags); - return count; -} - -static int serial_ir_tx_duty_cycle(struct rc_dev *dev, u32 cycle) -{ - init_timing_params(cycle, serial_ir.freq); - return 0; -} - -static int serial_ir_tx_carrier(struct rc_dev *dev, u32 carrier) -{ - if (carrier > 500000 || carrier < 20000) - return -EINVAL; - - init_timing_params(serial_ir.duty_cycle, carrier); - return 0; -} - -static int serial_ir_suspend(struct platform_device *dev, - pm_message_t state) -{ - /* Set DLAB 0. */ - soutp(UART_LCR, sinp(UART_LCR) & (~UART_LCR_DLAB)); - - /* Disable all interrupts */ - soutp(UART_IER, sinp(UART_IER) & - (~(UART_IER_MSI | UART_IER_RLSI | UART_IER_THRI | UART_IER_RDI))); - - /* Clear registers. */ - sinp(UART_LSR); - sinp(UART_RX); - sinp(UART_IIR); - sinp(UART_MSR); - - return 0; -} - -static int serial_ir_resume(struct platform_device *dev) -{ - unsigned long flags; - int result; - - result = hardware_init_port(); - if (result < 0) - return result; - - spin_lock_irqsave(&hardware[type].lock, flags); - /* Enable Interrupt */ - serial_ir.lastkt = ktime_get(); - soutp(UART_IER, sinp(UART_IER) | UART_IER_MSI); - off(); - - spin_unlock_irqrestore(&hardware[type].lock, flags); - - return 0; -} - -static struct platform_driver serial_ir_driver = { - .probe = serial_ir_probe, - .suspend = serial_ir_suspend, - .resume = serial_ir_resume, - .driver = { - .name = "serial_ir", - }, -}; - -static int __init serial_ir_init(void) -{ - int result; - - result = platform_driver_register(&serial_ir_driver); - if (result) - return result; - - serial_ir.pdev = platform_device_alloc("serial_ir", 0); - if (!serial_ir.pdev) { - result = -ENOMEM; - goto exit_driver_unregister; - } - - result = platform_device_add(serial_ir.pdev); - if (result) - goto exit_device_put; - - return 0; - -exit_device_put: - platform_device_put(serial_ir.pdev); -exit_driver_unregister: - platform_driver_unregister(&serial_ir_driver); - return result; -} - -static void serial_ir_exit(void) -{ - platform_device_unregister(serial_ir.pdev); - platform_driver_unregister(&serial_ir_driver); -} - -static int __init serial_ir_init_module(void) -{ - struct rc_dev *rcdev; - int result; - - switch (type) { - case IR_HOMEBREW: - case IR_IRDEO: - case IR_IRDEO_REMOTE: - case IR_ANIMAX: - case IR_IGOR: - /* if nothing specified, use ttyS0/com1 and irq 4 */ - io = io ? io : 0x3f8; - irq = irq ? irq : 4; - break; - default: - return -EINVAL; - } - if (!softcarrier) { - switch (type) { - case IR_HOMEBREW: - case IR_IGOR: - hardware[type].set_send_carrier = false; - hardware[type].set_duty_cycle = false; - break; - } - } - - /* make sure sense is either -1, 0, or 1 */ - if (sense != -1) - sense = !!sense; - - result = serial_ir_init(); - if (result) - return result; - - rcdev = devm_rc_allocate_device(&serial_ir.pdev->dev); - if (!rcdev) { - result = -ENOMEM; - goto serial_cleanup; - } - - if (hardware[type].send_pulse && hardware[type].send_space) - rcdev->tx_ir = serial_ir_tx; - if (hardware[type].set_send_carrier) - rcdev->s_tx_carrier = serial_ir_tx_carrier; - if (hardware[type].set_duty_cycle) - rcdev->s_tx_duty_cycle = serial_ir_tx_duty_cycle; - - switch (type) { - case IR_HOMEBREW: - rcdev->input_name = "Serial IR type home-brew"; - break; - case IR_IRDEO: - rcdev->input_name = "Serial IR type IRdeo"; - break; - case IR_IRDEO_REMOTE: - rcdev->input_name = "Serial IR type IRdeo remote"; - break; - case IR_ANIMAX: - rcdev->input_name = "Serial IR type AnimaX"; - break; - case IR_IGOR: - rcdev->input_name = "Serial IR type IgorPlug"; - break; - } - - rcdev->input_phys = KBUILD_MODNAME "/input0"; - rcdev->input_id.bustype = BUS_HOST; - rcdev->input_id.vendor = 0x0001; - rcdev->input_id.product = 0x0001; - rcdev->input_id.version = 0x0100; - rcdev->open = serial_ir_open; - rcdev->close = serial_ir_close; - rcdev->dev.parent = &serial_ir.pdev->dev; - rcdev->driver_type = RC_DRIVER_IR_RAW; - rcdev->allowed_protocols = RC_BIT_ALL; - rcdev->driver_name = KBUILD_MODNAME; - rcdev->map_name = RC_MAP_RC6_MCE; - rcdev->timeout = IR_DEFAULT_TIMEOUT; - rcdev->rx_resolution = 250000; - - serial_ir.rcdev = rcdev; - - result = rc_register_device(rcdev); - - if (!result) - return 0; -serial_cleanup: - serial_ir_exit(); - return result; -} - -static void __exit serial_ir_exit_module(void) -{ - rc_unregister_device(serial_ir.rcdev); - serial_ir_exit(); -} - -module_init(serial_ir_init_module); -module_exit(serial_ir_exit_module); - -MODULE_DESCRIPTION("Infra-red receiver driver for serial ports."); -MODULE_AUTHOR("Ralph Metzler, Trent Piepho, Ben Pfaff, Christoph Bartelmus, Andrei Tanas"); -MODULE_LICENSE("GPL"); - -module_param(type, int, 0444); -MODULE_PARM_DESC(type, "Hardware type (0 = home-brew, 1 = IRdeo, 2 = IRdeo Remote, 3 = AnimaX, 4 = IgorPlug"); - -module_param(io, int, 0444); -MODULE_PARM_DESC(io, "I/O address base (0x3f8 or 0x2f8)"); - -/* some architectures (e.g. intel xscale) have memory mapped registers */ -module_param(iommap, bool, 0444); -MODULE_PARM_DESC(iommap, "physical base for memory mapped I/O (0 = no memory mapped io)"); - -/* - * some architectures (e.g. intel xscale) align the 8bit serial registers - * on 32bit word boundaries. - * See linux-kernel/drivers/tty/serial/8250/8250.c serial_in()/out() - */ -module_param(ioshift, int, 0444); -MODULE_PARM_DESC(ioshift, "shift I/O register offset (0 = no shift)"); - -module_param(irq, int, 0444); -MODULE_PARM_DESC(irq, "Interrupt (4 or 3)"); - -module_param(share_irq, bool, 0444); -MODULE_PARM_DESC(share_irq, "Share interrupts (0 = off, 1 = on)"); - -module_param(sense, int, 0444); -MODULE_PARM_DESC(sense, "Override autodetection of IR receiver circuit (0 = active high, 1 = active low )"); - -#ifdef CONFIG_IR_SERIAL_TRANSMITTER -module_param(txsense, bool, 0444); -MODULE_PARM_DESC(txsense, "Sense of transmitter circuit (0 = active high, 1 = active low )"); -#endif - -module_param(softcarrier, bool, 0444); -MODULE_PARM_DESC(softcarrier, "Software carrier (0 = off, 1 = on, default on)"); -- cgit v1.2.3 From c60b4088108c44529e6f679d9e991e3d3c945950 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Nov 2016 06:17:44 -0200 Subject: [media] serial_ir: fix reference to 8250 serial code While checking why we need i386 checking, I noticed that the serial code referred at the driver was moved to another place. Update it to make clear from where such code came from. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/serial_ir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c index ba83b20913cd..436bd58b5f05 100644 --- a/drivers/media/rc/serial_ir.c +++ b/drivers/media/rc/serial_ir.c @@ -407,7 +407,7 @@ static int hardware_init_port(void) /* * This is a simple port existence test, borrowed from the autoconfig - * function in drivers/serial/8250.c + * function in drivers/tty/serial/8250/8250_port.c */ scratch = sinp(UART_IER); soutp(UART_IER, 0); -- cgit v1.2.3 From e4e9aeaf8c2f6b2c4a5ca5049b9326de05384185 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:11 -0200 Subject: [media] media: ti-vpe: vpdma: Make vpdma library into its own module The VPDMA (Video Port DMA) as found in devices such as DRA7xx is used for both the Video Processing Engine (VPE) and the Video Input Port (VIP). In preparation for this we need to turn vpdma into its own kernel module. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 6 ++++++ drivers/media/platform/ti-vpe/Makefile | 4 +++- drivers/media/platform/ti-vpe/vpdma.c | 28 +++++++++++++++++++++++++++- 3 files changed, 36 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 3c5a0b6b23a9..b52b6771fc4d 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -364,6 +364,7 @@ config VIDEO_TI_VPE depends on HAS_DMA select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV + select VIDEO_TI_VPDMA default n ---help--- Support for the TI VPE(Video Processing Engine) block @@ -377,6 +378,11 @@ config VIDEO_TI_VPE_DEBUG endif # V4L_MEM2MEM_DRIVERS +# TI VIDEO PORT Helper Modules +# These will be selected by VPE and VIP +config VIDEO_TI_VPDMA + tristate + menuconfig V4L_TEST_DRIVERS bool "Media test drivers" depends on MEDIA_CAMERA_SUPPORT diff --git a/drivers/media/platform/ti-vpe/Makefile b/drivers/media/platform/ti-vpe/Makefile index e236059a60ad..faca5e115c1d 100644 --- a/drivers/media/platform/ti-vpe/Makefile +++ b/drivers/media/platform/ti-vpe/Makefile @@ -1,6 +1,8 @@ obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o +obj-$(CONFIG_VIDEO_TI_VPDMA) += ti-vpdma.o -ti-vpe-y := vpe.o sc.o csc.o vpdma.o +ti-vpe-y := vpe.o sc.o csc.o +ti-vpdma-y := vpdma.o ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 4aff05915051..7de0f3f55dcc 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -75,6 +75,7 @@ const struct vpdma_data_format vpdma_yuv_fmts[] = { .depth = 16, }, }; +EXPORT_SYMBOL(vpdma_yuv_fmts); const struct vpdma_data_format vpdma_rgb_fmts[] = { [VPDMA_DATA_FMT_RGB565] = { @@ -178,6 +179,7 @@ const struct vpdma_data_format vpdma_rgb_fmts[] = { .depth = 32, }, }; +EXPORT_SYMBOL(vpdma_rgb_fmts); const struct vpdma_data_format vpdma_misc_fmts[] = { [VPDMA_DATA_FMT_MV] = { @@ -186,6 +188,7 @@ const struct vpdma_data_format vpdma_misc_fmts[] = { .depth = 4, }, }; +EXPORT_SYMBOL(vpdma_misc_fmts); struct vpdma_channel_info { int num; /* VPDMA channel number */ @@ -317,6 +320,7 @@ void vpdma_dump_regs(struct vpdma_data *vpdma) DUMPREG(VIP_UP_UV_CSTAT); DUMPREG(VPI_CTL_CSTAT); } +EXPORT_SYMBOL(vpdma_dump_regs); /* * Allocate a DMA buffer @@ -333,6 +337,7 @@ int vpdma_alloc_desc_buf(struct vpdma_buf *buf, size_t size) return 0; } +EXPORT_SYMBOL(vpdma_alloc_desc_buf); void vpdma_free_desc_buf(struct vpdma_buf *buf) { @@ -341,6 +346,7 @@ void vpdma_free_desc_buf(struct vpdma_buf *buf) buf->addr = NULL; buf->size = 0; } +EXPORT_SYMBOL(vpdma_free_desc_buf); /* * map descriptor/payload DMA buffer, enabling DMA access @@ -361,6 +367,7 @@ int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) return 0; } +EXPORT_SYMBOL(vpdma_map_desc_buf); /* * unmap descriptor/payload DMA buffer, disabling DMA access and @@ -375,6 +382,7 @@ void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) buf->mapped = false; } +EXPORT_SYMBOL(vpdma_unmap_desc_buf); /* * create a descriptor list, the user of this list will append configuration, @@ -396,6 +404,7 @@ int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type) return 0; } +EXPORT_SYMBOL(vpdma_create_desc_list); /* * once a descriptor list is parsed by VPDMA, we reset the list by emptying it, @@ -405,6 +414,7 @@ void vpdma_reset_desc_list(struct vpdma_desc_list *list) { list->next = list->buf.addr; } +EXPORT_SYMBOL(vpdma_reset_desc_list); /* * free the buffer allocated fot the VPDMA descriptor list, this should be @@ -416,11 +426,13 @@ void vpdma_free_desc_list(struct vpdma_desc_list *list) list->next = NULL; } +EXPORT_SYMBOL(vpdma_free_desc_list); -static bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num) +bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num) { return read_reg(vpdma, VPDMA_LIST_STAT_SYNC) & BIT(list_num + 16); } +EXPORT_SYMBOL(vpdma_list_busy); /* * submit a list of DMA descriptors to the VPE VPDMA, do not wait for completion @@ -446,6 +458,7 @@ int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list) return 0; } +EXPORT_SYMBOL(vpdma_submit_descs); static void dump_cfd(struct vpdma_cfd *cfd) { @@ -498,6 +511,7 @@ void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, dump_cfd(cfd); } +EXPORT_SYMBOL(vpdma_add_cfd_block); /* * append a configuration descriptor to the given descriptor list, where the @@ -526,6 +540,7 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, dump_cfd(cfd); }; +EXPORT_SYMBOL(vpdma_add_cfd_adb); /* * control descriptor format change based on what type of control descriptor it @@ -563,6 +578,7 @@ void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, dump_ctd(ctd); } +EXPORT_SYMBOL(vpdma_add_sync_on_channel_ctd); static void dump_dtd(struct vpdma_dtd *dtd) { @@ -672,6 +688,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, dump_dtd(dtd); } +EXPORT_SYMBOL(vpdma_add_out_dtd); /* * append an inbound data transfer descriptor to the given descriptor list, @@ -745,6 +762,7 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, dump_dtd(dtd); } +EXPORT_SYMBOL(vpdma_add_in_dtd); /* set or clear the mask for list complete interrupt */ void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num, @@ -759,6 +777,7 @@ void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num, val &= ~(1 << (list_num * 2)); write_reg(vpdma, VPDMA_INT_LIST0_MASK, val); } +EXPORT_SYMBOL(vpdma_enable_list_complete_irq); /* clear previosuly occured list intterupts in the LIST_STAT register */ void vpdma_clear_list_stat(struct vpdma_data *vpdma) @@ -766,6 +785,7 @@ void vpdma_clear_list_stat(struct vpdma_data *vpdma) write_reg(vpdma, VPDMA_INT_LIST0_STAT, read_reg(vpdma, VPDMA_INT_LIST0_STAT)); } +EXPORT_SYMBOL(vpdma_clear_list_stat); /* * configures the output mode of the line buffer for the given client, the @@ -780,6 +800,7 @@ void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, write_field_reg(vpdma, client_cstat, line_mode, VPDMA_CSTAT_LINE_MODE_MASK, VPDMA_CSTAT_LINE_MODE_SHIFT); } +EXPORT_SYMBOL(vpdma_set_line_mode); /* * configures the event which should trigger VPDMA transfer for the given @@ -794,6 +815,7 @@ void vpdma_set_frame_start_event(struct vpdma_data *vpdma, write_field_reg(vpdma, client_cstat, fs_event, VPDMA_CSTAT_FRAME_START_MASK, VPDMA_CSTAT_FRAME_START_SHIFT); } +EXPORT_SYMBOL(vpdma_set_frame_start_event); static void vpdma_firmware_cb(const struct firmware *f, void *context) { @@ -907,4 +929,8 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev, return vpdma; } +EXPORT_SYMBOL(vpdma_create); + +MODULE_AUTHOR("Texas Instruments Inc."); MODULE_FIRMWARE(VPDMA_FIRMWARE); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 2f88703a0bfd1a4e88e1a7cf2542880ef72fdcc0 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:12 -0200 Subject: [media] media: ti-vpe: vpdma: Add multi-instance and multi-client support The VPDMA (Video Port DMA) as found in devices such as DRA7xx is used for both the Video Processing Engine (VPE) and the Video Input Port (VIP). Some devices may have multiple VIP instances each with its own VPDMA engine. Within VIP two slices can use a single VPDMA engine simultaneously. So support for multi instances and multiple clients has been added to VPDMA. Needed modification to the existing helper functions were then reflected to VPE. Multi-clients registers offset have also been added in preparation. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 104 +++++++++++++++++++++++++---- drivers/media/platform/ti-vpe/vpdma.h | 25 +++++-- drivers/media/platform/ti-vpe/vpdma_priv.h | 15 ++++- drivers/media/platform/ti-vpe/vpe.c | 8 +-- 4 files changed, 128 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 7de0f3f55dcc..2b094016b470 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -437,10 +437,9 @@ EXPORT_SYMBOL(vpdma_list_busy); /* * submit a list of DMA descriptors to the VPE VPDMA, do not wait for completion */ -int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list) +int vpdma_submit_descs(struct vpdma_data *vpdma, + struct vpdma_desc_list *list, int list_num) { - /* we always use the first list */ - int list_num = 0; int list_size; if (vpdma_list_busy(vpdma, list_num)) @@ -460,6 +459,40 @@ int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list) } EXPORT_SYMBOL(vpdma_submit_descs); +static void dump_dtd(struct vpdma_dtd *dtd); + +void vpdma_update_dma_addr(struct vpdma_data *vpdma, + struct vpdma_desc_list *list, dma_addr_t dma_addr, + void *write_dtd, int drop, int idx) +{ + struct vpdma_dtd *dtd = list->buf.addr; + dma_addr_t write_desc_addr; + int offset; + + dtd += idx; + vpdma_unmap_desc_buf(vpdma, &list->buf); + + dtd->start_addr = dma_addr; + + /* Calculate write address from the offset of write_dtd from start + * of the list->buf + */ + offset = (void *)write_dtd - list->buf.addr; + write_desc_addr = list->buf.dma_addr + offset; + + if (drop) + dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, + 1, 1, 0); + else + dtd->desc_write_addr = dtd_desc_write_addr(write_desc_addr, + 1, 0, 0); + + vpdma_map_desc_buf(vpdma, &list->buf); + + dump_dtd(dtd); +} +EXPORT_SYMBOL(vpdma_update_dma_addr); + static void dump_cfd(struct vpdma_cfd *cfd) { int class; @@ -641,6 +674,16 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, enum vpdma_channel chan, u32 flags) +{ + vpdma_rawchan_add_out_dtd(list, width, c_rect, fmt, dma_addr, + chan_info[chan].num, flags); +} +EXPORT_SYMBOL(vpdma_add_out_dtd); + +void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, + const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + int raw_vpdma_chan, u32 flags) { int priority = 0; int field = 0; @@ -651,7 +694,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, int stride; struct vpdma_dtd *dtd; - channel = next_chan = chan_info[chan].num; + channel = next_chan = raw_vpdma_chan; if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV && fmt->data_type == DATA_TYPE_C420) { @@ -688,7 +731,7 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, dump_dtd(dtd); } -EXPORT_SYMBOL(vpdma_add_out_dtd); +EXPORT_SYMBOL(vpdma_rawchan_add_out_dtd); /* * append an inbound data transfer descriptor to the given descriptor list, @@ -765,25 +808,62 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, EXPORT_SYMBOL(vpdma_add_in_dtd); /* set or clear the mask for list complete interrupt */ -void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num, - bool enable) +void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, + int list_num, bool enable) { + u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; u32 val; - val = read_reg(vpdma, VPDMA_INT_LIST0_MASK); + val = read_reg(vpdma, reg_addr); if (enable) val |= (1 << (list_num * 2)); else val &= ~(1 << (list_num * 2)); - write_reg(vpdma, VPDMA_INT_LIST0_MASK, val); + write_reg(vpdma, reg_addr, val); } EXPORT_SYMBOL(vpdma_enable_list_complete_irq); +/* set or clear the mask for list complete interrupt */ +void vpdma_enable_list_notify_irq(struct vpdma_data *vpdma, int irq_num, + int list_num, bool enable) +{ + u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; + u32 val; + + val = read_reg(vpdma, reg_addr); + if (enable) + val |= (1 << ((list_num * 2) + 1)); + else + val &= ~(1 << ((list_num * 2) + 1)); + write_reg(vpdma, reg_addr, val); +} +EXPORT_SYMBOL(vpdma_enable_list_notify_irq); + +/* get the LIST_STAT register */ +unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num) +{ + u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; + + return read_reg(vpdma, reg_addr); +} +EXPORT_SYMBOL(vpdma_get_list_stat); + +/* get the LIST_MASK register */ +unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num) +{ + u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; + + return read_reg(vpdma, reg_addr); +} +EXPORT_SYMBOL(vpdma_get_list_mask); + /* clear previosuly occured list intterupts in the LIST_STAT register */ -void vpdma_clear_list_stat(struct vpdma_data *vpdma) +void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num) { - write_reg(vpdma, VPDMA_INT_LIST0_STAT, - read_reg(vpdma, VPDMA_INT_LIST0_STAT)); + u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; + + write_reg(vpdma, reg_addr, + read_reg(vpdma, reg_addr)); } EXPORT_SYMBOL(vpdma_clear_list_stat); diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 2bd8fb050381..83325d887546 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -134,6 +134,11 @@ enum vpdma_channel { VPE_CHAN_RGB_OUT, }; +#define VIP_CHAN_VIP2_OFFSET 70 +#define VIP_CHAN_MULT_PORTB_OFFSET 16 +#define VIP_CHAN_YUV_PORTB_OFFSET 2 +#define VIP_CHAN_RGB_PORTB_OFFSET 1 + /* flags for VPDMA data descriptors */ #define VPDMA_DATA_ODD_LINE_SKIP (1 << 0) #define VPDMA_DATA_EVEN_LINE_SKIP (1 << 1) @@ -177,8 +182,12 @@ void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf); int vpdma_create_desc_list(struct vpdma_desc_list *list, size_t size, int type); void vpdma_reset_desc_list(struct vpdma_desc_list *list); void vpdma_free_desc_list(struct vpdma_desc_list *list); -int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list); - +int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, + int list_num); +bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num); +void vpdma_update_dma_addr(struct vpdma_data *vpdma, + struct vpdma_desc_list *list, dma_addr_t dma_addr, + void *write_dtd, int drop, int idx); /* helpers for creating vpdma descriptors */ void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, struct vpdma_buf *blk, u32 dest_offset); @@ -190,6 +199,10 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, enum vpdma_channel chan, u32 flags); +void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, + const struct v4l2_rect *c_rect, + const struct vpdma_data_format *fmt, dma_addr_t dma_addr, + int raw_vpdma_chan, u32 flags); void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, @@ -197,9 +210,11 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, int frame_height, int start_h, int start_v); /* vpdma list interrupt management */ -void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int list_num, - bool enable); -void vpdma_clear_list_stat(struct vpdma_data *vpdma); +void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, + int list_num, bool enable); +void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num); +unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num); +unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num); /* vpdma client configuration */ void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index c1a6ce1884f3..65f0c067bed1 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h @@ -39,9 +39,11 @@ #define VPDMA_INT_LIST0_STAT 0x88 #define VPDMA_INT_LIST0_MASK 0x8c +#define VPDMA_INTX_OFFSET 0x50 + #define VPDMA_PERFMON(i) (0x200 + i * 4) -/* VPE specific client registers */ +/* VIP/VPE client registers */ #define VPDMA_DEI_CHROMA1_CSTAT 0x0300 #define VPDMA_DEI_LUMA1_CSTAT 0x0304 #define VPDMA_DEI_LUMA2_CSTAT 0x0308 @@ -50,6 +52,8 @@ #define VPDMA_DEI_CHROMA3_CSTAT 0x0314 #define VPDMA_DEI_MV_IN_CSTAT 0x0330 #define VPDMA_DEI_MV_OUT_CSTAT 0x033c +#define VPDMA_VIP_LO_Y_CSTAT 0x0388 +#define VPDMA_VIP_LO_UV_CSTAT 0x038c #define VPDMA_VIP_UP_Y_CSTAT 0x0390 #define VPDMA_VIP_UP_UV_CSTAT 0x0394 #define VPDMA_VPI_CTL_CSTAT 0x03d0 @@ -103,7 +107,7 @@ #define DATA_TYPE_MV 0x3 -/* VPDMA channel numbers(only VPE channels for now) */ +/* VPDMA channel numbers, some are common between VIP/VPE and appear twice */ #define VPE_CHAN_NUM_LUMA1_IN 0 #define VPE_CHAN_NUM_CHROMA1_IN 1 #define VPE_CHAN_NUM_LUMA2_IN 2 @@ -112,10 +116,15 @@ #define VPE_CHAN_NUM_CHROMA3_IN 5 #define VPE_CHAN_NUM_MV_IN 12 #define VPE_CHAN_NUM_MV_OUT 15 +#define VIP1_CHAN_NUM_MULT_PORT_A_SRC0 38 +#define VIP1_CHAN_NUM_MULT_ANC_A_SRC0 70 #define VPE_CHAN_NUM_LUMA_OUT 102 #define VPE_CHAN_NUM_CHROMA_OUT 103 +#define VIP1_CHAN_NUM_PORT_A_LUMA 102 +#define VIP1_CHAN_NUM_PORT_A_CHROMA 103 #define VPE_CHAN_NUM_RGB_OUT 106 - +#define VIP1_CHAN_NUM_PORT_A_RGB 106 +#define VIP1_CHAN_NUM_PORT_B_RGB 107 /* * a VPDMA address data block payload for a configuration descriptor needs to * have each sub block length as a multiple of 16 bytes. Therefore, the overall diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1cf4a4c1b899..bd385c5bae2f 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1077,7 +1077,7 @@ static void enable_irqs(struct vpe_ctx *ctx) write_reg(ctx->dev, VPE_INT0_ENABLE1_SET, VPE_DEI_ERROR_INT | VPE_DS1_UV_ERROR_INT); - vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, true); + vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, true); } static void disable_irqs(struct vpe_ctx *ctx) @@ -1085,7 +1085,7 @@ static void disable_irqs(struct vpe_ctx *ctx) write_reg(ctx->dev, VPE_INT0_ENABLE0_CLR, 0xffffffff); write_reg(ctx->dev, VPE_INT0_ENABLE1_CLR, 0xffffffff); - vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, false); + vpdma_enable_list_complete_irq(ctx->dev->vpdma, 0, 0, false); } /* device_run() - prepares and starts the device @@ -1202,7 +1202,7 @@ static void device_run(void *priv) enable_irqs(ctx); vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->desc_list.buf); - vpdma_submit_descs(ctx->dev->vpdma, &ctx->desc_list); + vpdma_submit_descs(ctx->dev->vpdma, &ctx->desc_list, 0); } static void dei_error(struct vpe_ctx *ctx) @@ -1257,7 +1257,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) if (irqst0) { if (irqst0 & VPE_INT0_LIST0_COMPLETE) - vpdma_clear_list_stat(ctx->dev->vpdma); + vpdma_clear_list_stat(ctx->dev->vpdma, 0); irqst0 &= ~(VPE_INT0_LIST0_COMPLETE); } -- cgit v1.2.3 From 3f43554c0a3c2a311f484b9131a7b9edf183f6e0 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:13 -0200 Subject: [media] media: ti-vpe: vpdma: Add helper to set a background color Add a helper to set the background color during vpdma transfer. This is needed when VPDMA is generating 32 bits RGB format to have the Alpha channel set to an appropriate value. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 10 ++++++++++ drivers/media/platform/ti-vpe/vpdma.h | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 2b094016b470..133154628543 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -867,6 +867,16 @@ void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num) } EXPORT_SYMBOL(vpdma_clear_list_stat); +void vpdma_set_bg_color(struct vpdma_data *vpdma, + struct vpdma_data_format *fmt, u32 color) +{ + if (fmt->type == VPDMA_DATA_FMT_TYPE_RGB) + write_reg(vpdma, VPDMA_BG_RGB, color); + else if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV) + write_reg(vpdma, VPDMA_BG_YUV, color); +} +EXPORT_SYMBOL(vpdma_set_bg_color); + /* * configures the output mode of the line buffer for the given client, the * line buffer content can either be mirrored(each line repeated twice) or diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 83325d887546..220dc7e793f6 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -221,7 +221,8 @@ void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, enum vpdma_channel chan); void vpdma_set_frame_start_event(struct vpdma_data *vpdma, enum vpdma_frame_start_event fs_event, enum vpdma_channel chan); - +void vpdma_set_bg_color(struct vpdma_data *vpdma, + struct vpdma_data_format *fmt, u32 color); void vpdma_dump_regs(struct vpdma_data *vpdma); /* initialize vpdma, passed with VPE's platform device pointer */ -- cgit v1.2.3 From 4f36178188e0b33ea594e3d4849f407e40f8149d Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:14 -0200 Subject: [media] media: ti-vpe: vpdma: Fix bus error when vpdma is writing a descriptor On DRA7 since l3_noc event are being reported it was found that when the write descriptor was being written it was consistently causing bus error events. The write address was improperly programmed. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma_priv.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index 65f0c067bed1..aeade5edc8ac 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h @@ -212,6 +212,7 @@ struct vpdma_dtd { #define DTD_V_START_MASK 0xffff #define DTD_V_START_SHFT 0 +#define DTD_DESC_START_MASK 0xffffffe0 #define DTD_DESC_START_SHIFT 5 #define DTD_WRITE_DESC_MASK 0x01 #define DTD_WRITE_DESC_SHIFT 2 @@ -294,7 +295,7 @@ static inline u32 dtd_frame_width_height(int width, int height) static inline u32 dtd_desc_write_addr(unsigned int addr, bool write_desc, bool drop_data, bool use_desc) { - return (addr << DTD_DESC_START_SHIFT) | + return (addr & DTD_DESC_START_MASK) | (write_desc << DTD_WRITE_DESC_SHIFT) | (drop_data << DTD_DROP_DATA_SHIFT) | use_desc; @@ -399,7 +400,7 @@ static inline int dtd_get_frame_height(struct vpdma_dtd *dtd) static inline int dtd_get_desc_write_addr(struct vpdma_dtd *dtd) { - return dtd->desc_write_addr >> DTD_DESC_START_SHIFT; + return dtd->desc_write_addr & DTD_DESC_START_MASK; } static inline bool dtd_get_write_desc(struct vpdma_dtd *dtd) -- cgit v1.2.3 From 15f632e665653da078a121f8478586f09dd56b4d Mon Sep 17 00:00:00 2001 From: Archit Taneja Date: Fri, 18 Nov 2016 21:20:15 -0200 Subject: [media] media: ti-vpe: Use line average de-interlacing for first 2 frames The motion detection block requires 3 fields to create the motion vector data. This means that using the default method the first progressive frame is only generated after 3rd field is consumed. Hence by default for N input field we would generate N - 2 progressive frames. In order to generate N progressive frames from N fields we use the line averaging mode of the de-interlacer for the first 2 fields and then revert back to the preferred Edge Directed Interpolation method (using the motion vector). Thus creating 2 line averaged frames + N - 2 motion based frames for a total of N frames. Signed-off-by: Archit Taneja Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index bd385c5bae2f..ad838b8a98c4 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -141,7 +141,7 @@ struct vpe_dei_regs { */ static const struct vpe_dei_regs dei_regs = { .mdt_spacial_freq_thr_reg = 0x020C0804u, - .edi_config_reg = 0x0118100Fu, + .edi_config_reg = 0x0118100Cu, .edi_lut_reg0 = 0x08040200u, .edi_lut_reg1 = 0x1010100Cu, .edi_lut_reg2 = 0x10101010u, @@ -798,6 +798,23 @@ static void set_dei_shadow_registers(struct vpe_ctx *ctx) ctx->load_mmrs = true; } +static void config_edi_input_mode(struct vpe_ctx *ctx, int mode) +{ + struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; + u32 *edi_config_reg = &mmr_adb->dei_regs[3]; + + if (mode & 0x2) + write_field(edi_config_reg, 1, 1, 2); /* EDI_ENABLE_3D */ + + if (mode & 0x3) + write_field(edi_config_reg, 1, 1, 3); /* EDI_CHROMA_3D */ + + write_field(edi_config_reg, mode, VPE_EDI_INP_MODE_MASK, + VPE_EDI_INP_MODE_SHIFT); + + ctx->load_mmrs = true; +} + /* * Set the shadow registers whose values are modified when either the * source or destination format is changed. @@ -1111,6 +1128,15 @@ static void device_run(void *priv) ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->dst_vb == NULL); + if (ctx->deinterlacing) { + /* + * we have output the first 2 frames through line average, we + * now switch to EDI de-interlacer + */ + if (ctx->sequence == 2) + config_edi_input_mode(ctx, 0x3); /* EDI (Y + UV) */ + } + /* config descriptors */ if (ctx->dev->loaded_mmrs != ctx->mmr_adb.dma_addr || ctx->load_mmrs) { vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->mmr_adb); @@ -1864,7 +1890,10 @@ static void vpe_buf_queue(struct vb2_buffer *vb) static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) { - /* currently we do nothing here */ + struct vpe_ctx *ctx = vb2_get_drv_priv(q); + + if (ctx->deinterlacing) + config_edi_input_mode(ctx, 0x0); return 0; } -- cgit v1.2.3 From 5dc07f20b67dc30ea2f7988eb76d2231a40a97bc Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:16 -0200 Subject: [media] media: ti-vpe: vpe: Do not perform job transaction atomically Current VPE driver does not start the job until all the buffers for a transaction are queued. When running in multiple context, this might increase the processing latency. Alternate solution would be to try to continue the same context as long as buffers for the transaction are ready; else switch the context. This may increase number of context switches but it reduces latency significantly. In this approach, the job_ready always succeeds as long as there are buffers on the CAPTURE and OUTPUT stream. Processing may start immediately as the first 2 iterations don't need extra source buffers. Shift all the source buffers after each iteration and remove the oldest buffer. Also, with this removes the constraint of pre buffering 3 buffers before call to STREAMON in case of de-interlacing. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index ad838b8a98c4..9b7b9be5641d 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -898,15 +898,14 @@ static struct vpe_ctx *file2ctx(struct file *file) static int job_ready(void *priv) { struct vpe_ctx *ctx = priv; - int needed = ctx->bufs_per_job; - if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) - needed += 2; /* need additional two most recent fields */ - - if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < needed) - return 0; - - if (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < needed) + /* + * This check is needed as this might be called directly from driver + * When called by m2m framework, this will always satisfy, but when + * called from vpe_irq, this might fail. (src stream with zero buffers) + */ + if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) <= 0 || + v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) <= 0) return 0; return 1; @@ -1116,19 +1115,20 @@ static void device_run(void *priv) struct sc_data *sc = ctx->dev->sc; struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; - if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) { - ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - WARN_ON(ctx->src_vbs[2] == NULL); - ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - WARN_ON(ctx->src_vbs[1] == NULL); - } - ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->src_vbs[0] == NULL); ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->dst_vb == NULL); if (ctx->deinterlacing) { + + if (ctx->src_vbs[2] == NULL) { + ctx->src_vbs[2] = ctx->src_vbs[0]; + WARN_ON(ctx->src_vbs[2] == NULL); + ctx->src_vbs[1] = ctx->src_vbs[0]; + WARN_ON(ctx->src_vbs[1] == NULL); + } + /* * we have output the first 2 frames through line average, we * now switch to EDI de-interlacer @@ -1348,7 +1348,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) } ctx->bufs_completed++; - if (ctx->bufs_completed < ctx->bufs_per_job) { + if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) { device_run(ctx); goto handled; } -- cgit v1.2.3 From 823f4208b2284dcc7137b17d036e71a16199572c Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:17 -0200 Subject: [media] media: ti-vpe: Add support for SEQ_TB buffers The video source can generate the data in the SEQ_TB buffer format. In the case of TI SoC, the IVA_HD can generate the interlaced content in the SEQ_TB buffer format. This is the format where the top and bottom field data can be contained in a single buffer. For example, for NV12, interlaced format, the data in Y buffer will be arranged as Y-top followed by Y-bottom. And likewise for UV plane. Also, queuing one buffer of SEQ_TB is equivalent to queuing two different buffers for top and bottom fields. Driver needs to take care of this when handling source buffer lists. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 125 +++++++++++++++++++++++++++++------- 1 file changed, 103 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 9b7b9be5641d..e5d55575350f 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -320,9 +320,13 @@ struct vpe_q_data { }; /* vpe_q_data flag bits */ -#define Q_DATA_FRAME_1D (1 << 0) -#define Q_DATA_MODE_TILED (1 << 1) -#define Q_DATA_INTERLACED (1 << 2) +#define Q_DATA_FRAME_1D BIT(0) +#define Q_DATA_MODE_TILED BIT(1) +#define Q_DATA_INTERLACED_ALTERNATE BIT(2) +#define Q_DATA_INTERLACED_SEQ_TB BIT(3) + +#define Q_IS_INTERLACED (Q_DATA_INTERLACED_ALTERNATE | \ + Q_DATA_INTERLACED_SEQ_TB) enum { Q_DATA_SRC = 0, @@ -638,7 +642,7 @@ static void set_us_coefficients(struct vpe_ctx *ctx) cp = &us_coeffs[0].anchor_fid0_c0; - if (s_q_data->flags & Q_DATA_INTERLACED) /* interlaced */ + if (s_q_data->flags & Q_IS_INTERLACED) /* interlaced */ cp += sizeof(us_coeffs[0]) / sizeof(*cp); end_cp = cp + sizeof(us_coeffs[0]) / sizeof(*cp); @@ -765,8 +769,7 @@ static void set_dei_regs(struct vpe_ctx *ctx) * for both progressive and interlace content in interlace bypass mode. * It has been recommended not to use progressive bypass mode. */ - if ((!ctx->deinterlacing && (s_q_data->flags & Q_DATA_INTERLACED)) || - !(s_q_data->flags & Q_DATA_INTERLACED)) { + if (!(s_q_data->flags & Q_IS_INTERLACED) || !ctx->deinterlacing) { deinterlace = false; val = VPE_DEI_INTERLACE_BYPASS; } @@ -834,8 +837,8 @@ static int set_srcdst_params(struct vpe_ctx *ctx) ctx->sequence = 0; ctx->field = V4L2_FIELD_TOP; - if ((s_q_data->flags & Q_DATA_INTERLACED) && - !(d_q_data->flags & Q_DATA_INTERLACED)) { + if ((s_q_data->flags & Q_IS_INTERLACED) && + !(d_q_data->flags & Q_IS_INTERLACED)) { int bytes_per_line; const struct vpdma_data_format *mv = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; @@ -1066,6 +1069,28 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) port); return; } + + if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) { + /* + * Use top or bottom field from same vb alternately + * f,f-1,f-2 = TBT when seq is even + * f,f-1,f-2 = BTB when seq is odd + */ + field = (p_data->vb_index + (ctx->sequence % 2)) % 2; + + if (field) { + /* + * bottom field of a SEQ_TB buffer + * Skip the top field data by + */ + int height = q_data->height / 2; + int bpp = fmt->fourcc == V4L2_PIX_FMT_NV12 ? + 1 : (vpdma_fmt->depth >> 3); + if (plane) + height /= 2; + dma_addr += q_data->width * height * bpp; + } + } } if (q_data->flags & Q_DATA_FRAME_1D) @@ -1114,9 +1139,22 @@ static void device_run(void *priv) struct vpe_ctx *ctx = priv; struct sc_data *sc = ctx->dev->sc; struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; + struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; + + if (ctx->deinterlacing && s_q_data->flags & Q_DATA_INTERLACED_SEQ_TB && + ctx->sequence % 2 == 0) { + /* When using SEQ_TB buffers, When using it first time, + * No need to remove the buffer as the next field is present + * in the same buffer. (so that job_ready won't fail) + * It will be removed when using bottom field + */ + ctx->src_vbs[0] = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); + WARN_ON(ctx->src_vbs[0] == NULL); + } else { + ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + WARN_ON(ctx->src_vbs[0] == NULL); + } - ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); - WARN_ON(ctx->src_vbs[0] == NULL); ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); WARN_ON(ctx->dst_vb == NULL); @@ -1320,7 +1358,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) d_vb->sequence = ctx->sequence; d_q_data = &ctx->q_data[Q_DATA_DST]; - if (d_q_data->flags & Q_DATA_INTERLACED) { + if (d_q_data->flags & Q_IS_INTERLACED) { d_vb->field = ctx->field; if (ctx->field == V4L2_FIELD_BOTTOM) { ctx->sequence++; @@ -1334,12 +1372,28 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) ctx->sequence++; } - if (ctx->deinterlacing) - s_vb = ctx->src_vbs[2]; + if (ctx->deinterlacing) { + /* + * Allow source buffer to be dequeued only if it won't be used + * in the next iteration. All vbs are initialized to first + * buffer and we are shifting buffers every iteration, for the + * first two iterations, no buffer will be dequeued. + * This ensures that driver will keep (n-2)th (n-1)th and (n)th + * field when deinterlacing is enabled + */ + if (ctx->src_vbs[2] != ctx->src_vbs[1]) + s_vb = ctx->src_vbs[2]; + else + s_vb = NULL; + } spin_lock_irqsave(&dev->lock, flags); - v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_DONE); + + if (s_vb) + v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_DONE); + v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_DONE); + spin_unlock_irqrestore(&dev->lock, flags); if (ctx->deinterlacing) { @@ -1455,7 +1509,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct v4l2_plane_pix_format *plane_fmt; unsigned int w_align; - int i, depth, depth_bytes; + int i, depth, depth_bytes, height; if (!fmt || !(fmt->types & type)) { vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n", @@ -1463,7 +1517,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, return -EINVAL; } - if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE) + if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE + && pix->field != V4L2_FIELD_SEQ_TB) pix->field = V4L2_FIELD_NONE; depth = fmt->vpdma_fmt[VPE_LUMA]->depth; @@ -1497,6 +1552,15 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, pix->num_planes = fmt->coplanar ? 2 : 1; pix->pixelformat = fmt->fourcc; + /* + * For the actual image parameters, we need to consider the field + * height of the image for SEQ_TB buffers. + */ + if (pix->field == V4L2_FIELD_SEQ_TB) + height = pix->height / 2; + else + height = pix->height; + if (!pix->colorspace) { if (fmt->fourcc == V4L2_PIX_FMT_RGB24 || fmt->fourcc == V4L2_PIX_FMT_BGR24 || @@ -1504,7 +1568,7 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, fmt->fourcc == V4L2_PIX_FMT_BGR32) { pix->colorspace = V4L2_COLORSPACE_SRGB; } else { - if (pix->height > 1280) /* HD */ + if (height > 1280) /* HD */ pix->colorspace = V4L2_COLORSPACE_REC709; else /* SD */ pix->colorspace = V4L2_COLORSPACE_SMPTE170M; @@ -1581,9 +1645,15 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) q_data->c_rect.height = q_data->height; if (q_data->field == V4L2_FIELD_ALTERNATE) - q_data->flags |= Q_DATA_INTERLACED; + q_data->flags |= Q_DATA_INTERLACED_ALTERNATE; + else if (q_data->field == V4L2_FIELD_SEQ_TB) + q_data->flags |= Q_DATA_INTERLACED_SEQ_TB; else - q_data->flags &= ~Q_DATA_INTERLACED; + q_data->flags &= ~Q_IS_INTERLACED; + + /* the crop height is halved for the case of SEQ_TB buffers */ + if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) + q_data->c_rect.height /= 2; vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d", f->type, q_data->width, q_data->height, q_data->fmt->fourcc, @@ -1619,6 +1689,7 @@ static int vpe_s_fmt(struct file *file, void *priv, struct v4l2_format *f) static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) { struct vpe_q_data *q_data; + int height; if ((s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)) @@ -1653,13 +1724,22 @@ static int __vpe_try_selection(struct vpe_ctx *ctx, struct v4l2_selection *s) return -EINVAL; } + /* + * For SEQ_TB buffers, crop height should be less than the height of + * the field height, not the buffer height + */ + if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) + height = q_data->height / 2; + else + height = q_data->height; + if (s->r.top < 0 || s->r.left < 0) { vpe_err(ctx->dev, "negative values for top and left\n"); s->r.top = s->r.left = 0; } v4l_bound_align_image(&s->r.width, MIN_W, q_data->width, 1, - &s->r.height, MIN_H, q_data->height, H_ALIGN, S_ALIGN); + &s->r.height, MIN_H, height, H_ALIGN, S_ALIGN); /* adjust left/top if cropping rectangle is out of bounds */ if (s->r.left + s->r.width > q_data->width) @@ -1855,11 +1935,12 @@ static int vpe_buf_prepare(struct vb2_buffer *vb) num_planes = q_data->fmt->coplanar ? 2 : 1; if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { - if (!(q_data->flags & Q_DATA_INTERLACED)) { + if (!(q_data->flags & Q_IS_INTERLACED)) { vbuf->field = V4L2_FIELD_NONE; } else { if (vbuf->field != V4L2_FIELD_TOP && - vbuf->field != V4L2_FIELD_BOTTOM) + vbuf->field != V4L2_FIELD_BOTTOM && + vbuf->field != V4L2_FIELD_SEQ_TB) return -EINVAL; } } -- cgit v1.2.3 From 8028bfed42dd2f5b612be3cc346699bdf327e16c Mon Sep 17 00:00:00 2001 From: Harinarayan Bhatta Date: Fri, 18 Nov 2016 21:20:18 -0200 Subject: [media] media: ti-vpe: Increasing max buffer height and width Increasing max buffer height and width to allow for padded buffers. Signed-off-by: Harinarayan Bhatta Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index e5d55575350f..c624f5db7f08 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -53,8 +53,8 @@ /* minimum and maximum frame sizes */ #define MIN_W 32 #define MIN_H 32 -#define MAX_W 1920 -#define MAX_H 1080 +#define MAX_W 2048 +#define MAX_H 1184 /* required alignments */ #define S_ALIGN 0 /* multiple of 1 */ -- cgit v1.2.3 From 072915b57a85e8d65e22be5595a639110afdcc90 Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:19 -0200 Subject: [media] media: ti-vpe: vpe: Return NULL for invalid buffer type get_q_data can be called with different values for type e.g. vpe_try_crop calls it with the buffer type which gets passed from user space Framework doesn't check wheather its correct type or not If user space passes wrong type, kernel should not crash. Return NULL when the passed type is invalid. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index c624f5db7f08..4b6e8839dd83 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -420,7 +420,7 @@ static struct vpe_q_data *get_q_data(struct vpe_ctx *ctx, case V4L2_BUF_TYPE_VIDEO_CAPTURE: return &ctx->q_data[Q_DATA_DST]; default: - BUG(); + return NULL; } return NULL; } -- cgit v1.2.3 From f43aa420a89a4a17117e21553283e2a50cf86df8 Mon Sep 17 00:00:00 2001 From: Harinarayan Bhatta Date: Fri, 18 Nov 2016 21:20:20 -0200 Subject: [media] media: ti-vpe: Free vpdma buffers in vpe_release Free vpdma buffers in vpe_release. Otherwise it was generating random backtrace. Signed-off-by: Harinarayan Bhatta Signed-off-by: Somnath Mukherjee Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 4b6e8839dd83..f2b90d42b408 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2182,6 +2182,9 @@ static int vpe_release(struct file *file) vpdma_free_desc_list(&ctx->desc_list); vpdma_free_desc_buf(&ctx->mmr_adb); + vpdma_free_desc_buf(&ctx->sc_coeff_v); + vpdma_free_desc_buf(&ctx->sc_coeff_h); + v4l2_fh_del(&ctx->fh); v4l2_fh_exit(&ctx->fh); v4l2_ctrl_handler_free(&ctx->hdl); -- cgit v1.2.3 From 634271f8f67532d48db6bf0fcacd5423e941bb5e Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:21 -0200 Subject: [media] media: ti-vpe: vpdma: Add support for setting max width height Add a helper function to be able to set the maximum VPDMA transfer size to limit potential buffer overrun. Added enums for max_width and max_height fields of the outbound data descriptor. Changed vpdma_add_out_dtd to accept two more arguments for max width and height. Make use of different max width & height sets for different of capture module (i.e. slices). Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 27 ++++++++++++++++---- drivers/media/platform/ti-vpe/vpdma.h | 32 ++++++++++++++++++++++-- drivers/media/platform/ti-vpe/vpdma_priv.h | 40 +++--------------------------- drivers/media/platform/ti-vpe/vpe.c | 7 +++++- 4 files changed, 62 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 133154628543..1a0152842a17 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -493,6 +493,22 @@ void vpdma_update_dma_addr(struct vpdma_data *vpdma, } EXPORT_SYMBOL(vpdma_update_dma_addr); +void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, + u32 width, u32 height) +{ + if (reg_addr != VPDMA_MAX_SIZE1 && reg_addr != VPDMA_MAX_SIZE2 && + reg_addr != VPDMA_MAX_SIZE3) + reg_addr = VPDMA_MAX_SIZE1; + + write_field_reg(vpdma, reg_addr, width - 1, + VPDMA_MAX_SIZE_WIDTH_MASK, VPDMA_MAX_SIZE_WIDTH_SHFT); + + write_field_reg(vpdma, reg_addr, height - 1, + VPDMA_MAX_SIZE_HEIGHT_MASK, VPDMA_MAX_SIZE_HEIGHT_SHFT); + +} +EXPORT_SYMBOL(vpdma_set_max_size); + static void dump_cfd(struct vpdma_cfd *cfd) { int class; @@ -667,23 +683,25 @@ static void dump_dtd(struct vpdma_dtd *dtd) * @c_rect: compose params of output image * @fmt: vpdma data format of the buffer * dma_addr: dma address as seen by VPDMA + * max_width: enum for maximum width of data transfer + * max_height: enum for maximum height of data transfer * chan: VPDMA channel * flags: VPDMA flags to configure some descriptor fileds */ void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - enum vpdma_channel chan, u32 flags) + int max_w, int max_h, enum vpdma_channel chan, u32 flags) { vpdma_rawchan_add_out_dtd(list, width, c_rect, fmt, dma_addr, - chan_info[chan].num, flags); + max_w, max_h, chan_info[chan].num, flags); } EXPORT_SYMBOL(vpdma_add_out_dtd); void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - int raw_vpdma_chan, u32 flags) + int max_w, int max_h, int raw_vpdma_chan, u32 flags) { int priority = 0; int field = 0; @@ -722,8 +740,7 @@ void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, dtd->pkt_ctl = dtd_pkt_ctl(!!(flags & VPDMA_DATA_MODE_TILED), DTD_DIR_OUT, channel, priority, next_chan); dtd->desc_write_addr = dtd_desc_write_addr(0, 0, 0, 0); - dtd->max_width_height = dtd_max_width_height(MAX_OUT_WIDTH_1920, - MAX_OUT_HEIGHT_1080); + dtd->max_width_height = dtd_max_width_height(max_w, max_h); dtd->client_attr0 = 0; dtd->client_attr1 = 0; diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 220dc7e793f6..32b9ed5191c5 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -117,6 +117,30 @@ enum vpdma_frame_start_event { VPDMA_FSEVENT_CHANNEL_ACTIVE, }; +/* max width configurations */ +enum vpdma_max_width { + MAX_OUT_WIDTH_UNLIMITED = 0, + MAX_OUT_WIDTH_REG1, + MAX_OUT_WIDTH_REG2, + MAX_OUT_WIDTH_REG3, + MAX_OUT_WIDTH_352, + MAX_OUT_WIDTH_768, + MAX_OUT_WIDTH_1280, + MAX_OUT_WIDTH_1920, +}; + +/* max height configurations */ +enum vpdma_max_height { + MAX_OUT_HEIGHT_UNLIMITED = 0, + MAX_OUT_HEIGHT_REG1, + MAX_OUT_HEIGHT_REG2, + MAX_OUT_HEIGHT_REG3, + MAX_OUT_HEIGHT_288, + MAX_OUT_HEIGHT_576, + MAX_OUT_HEIGHT_720, + MAX_OUT_HEIGHT_1080, +}; + /* * VPDMA channel numbers */ @@ -198,11 +222,12 @@ void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - enum vpdma_channel chan, u32 flags); + int max_w, int max_h, enum vpdma_channel chan, u32 flags); void vpdma_rawchan_add_out_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, - int raw_vpdma_chan, u32 flags); + int max_w, int max_h, int raw_vpdma_chan, u32 flags); + void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, @@ -221,6 +246,9 @@ void vpdma_set_line_mode(struct vpdma_data *vpdma, int line_mode, enum vpdma_channel chan); void vpdma_set_frame_start_event(struct vpdma_data *vpdma, enum vpdma_frame_start_event fs_event, enum vpdma_channel chan); +void vpdma_set_max_size(struct vpdma_data *vpdma, int reg_addr, + u32 width, u32 height); + void vpdma_set_bg_color(struct vpdma_data *vpdma, struct vpdma_data_format *fmt, u32 color); void vpdma_dump_regs(struct vpdma_data *vpdma); diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index aeade5edc8ac..54b6aa866c74 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h @@ -28,6 +28,10 @@ #define VPDMA_MAX_SIZE1 0x34 #define VPDMA_MAX_SIZE2 0x38 #define VPDMA_MAX_SIZE3 0x3c +#define VPDMA_MAX_SIZE_WIDTH_MASK 0xffff +#define VPDMA_MAX_SIZE_WIDTH_SHFT 16 +#define VPDMA_MAX_SIZE_HEIGHT_MASK 0xffff +#define VPDMA_MAX_SIZE_HEIGHT_SHFT 0 /* Interrupts */ #define VPDMA_INT_CHAN_STAT(grp) (0x40 + grp * 8) @@ -227,42 +231,6 @@ struct vpdma_dtd { #define DTD_MAX_HEIGHT_MASK 0x07 #define DTD_MAX_HEIGHT_SHFT 0 -/* max width configurations */ - /* unlimited width */ -#define MAX_OUT_WIDTH_UNLIMITED 0 -/* as specified in max_size1 reg */ -#define MAX_OUT_WIDTH_REG1 1 -/* as specified in max_size2 reg */ -#define MAX_OUT_WIDTH_REG2 2 -/* as specified in max_size3 reg */ -#define MAX_OUT_WIDTH_REG3 3 -/* maximum of 352 pixels as width */ -#define MAX_OUT_WIDTH_352 4 -/* maximum of 768 pixels as width */ -#define MAX_OUT_WIDTH_768 5 -/* maximum of 1280 pixels width */ -#define MAX_OUT_WIDTH_1280 6 -/* maximum of 1920 pixels as width */ -#define MAX_OUT_WIDTH_1920 7 - -/* max height configurations */ - /* unlimited height */ -#define MAX_OUT_HEIGHT_UNLIMITED 0 -/* as specified in max_size1 reg */ -#define MAX_OUT_HEIGHT_REG1 1 -/* as specified in max_size2 reg */ -#define MAX_OUT_HEIGHT_REG2 2 -/* as specified in max_size3 reg */ -#define MAX_OUT_HEIGHT_REG3 3 -/* maximum of 288 lines as height */ -#define MAX_OUT_HEIGHT_288 4 -/* maximum of 576 lines as height */ -#define MAX_OUT_HEIGHT_576 5 -/* maximum of 720 lines as height */ -#define MAX_OUT_HEIGHT_720 6 -/* maximum of 1080 lines as height */ -#define MAX_OUT_HEIGHT_1080 7 - static inline u32 dtd_type_ctl_stride(int type, bool notify, int field, bool one_d, bool even_line_skip, bool odd_line_skip, int line_stride) diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index f2b90d42b408..151a9280bb85 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -44,6 +44,7 @@ #include #include "vpdma.h" +#include "vpdma_priv.h" #include "vpe_regs.h" #include "sc.h" #include "csc.h" @@ -1035,8 +1036,12 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) if (q_data->flags & Q_DATA_MODE_TILED) flags |= VPDMA_DATA_MODE_TILED; + vpdma_set_max_size(ctx->dev->vpdma, VPDMA_MAX_SIZE1, + MAX_W, MAX_H); + vpdma_add_out_dtd(&ctx->desc_list, q_data->width, &q_data->c_rect, - vpdma_fmt, dma_addr, p_data->channel, flags); + vpdma_fmt, dma_addr, MAX_OUT_WIDTH_REG1, + MAX_OUT_HEIGHT_REG1, p_data->channel, flags); } static void add_in_dtd(struct vpe_ctx *ctx, int port) -- cgit v1.2.3 From dc12b124353b2b4d8d46b2d0826f4f7905d44612 Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:22 -0200 Subject: [media] media: ti-vpe: vpdma: Add abort channel desc and cleanup APIs Whenever VPDMA processes a data descriptor of a list, it processes it and sets up the channel for the DMA transaction. List manager holds the descriptor in the list until the DMA is complete. If sync_on_channel descriptor, or another descriptor for the same channel is present in the FIFO, list manager keeps them until the current channel is free. When the capture stream is closed suddenly while there are pending descriptors in the FIFO (streamON failed, application killed), it would keep the VPDMA in a busy state. Any further list post would fail with EBUSY. To avoid this, drivers need to stop the current processing list and cleanup all the resources VPDMA has taken and also clear the internal FSM of list manager. The state machine is cleared by issuing channel specific abort descriptor. Therefore, the vpdma_list_cleanup accepts an array of channels for which abort_channel descriptors should be posted. It is driver's responsibility to post for all the channels or the channels which were used in the last context. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 75 +++++++++++++++++++++++++++++++++++ drivers/media/platform/ti-vpe/vpdma.h | 6 +++ 2 files changed, 81 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 1a0152842a17..7808c9c1828b 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -384,6 +384,56 @@ void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) } EXPORT_SYMBOL(vpdma_unmap_desc_buf); +/* + * Cleanup all pending descriptors of a list + * First, stop the current list being processed. + * If the VPDMA was busy, this step makes vpdma to accept post lists. + * To cleanup the internal FSM, post abort list descriptor for all the + * channels from @channels array of size @size. + */ +int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, + int *channels, int size) +{ + struct vpdma_desc_list abort_list; + int i, ret, timeout = 500; + + write_reg(vpdma, VPDMA_LIST_ATTR, + (list_num << VPDMA_LIST_NUM_SHFT) | + (1 << VPDMA_LIST_STOP_SHFT)); + + if (size <= 0 || !channels) + return 0; + + ret = vpdma_create_desc_list(&abort_list, + size * sizeof(struct vpdma_dtd), VPDMA_LIST_TYPE_NORMAL); + if (ret) + return ret; + + for (i = 0; i < size; i++) + vpdma_add_abort_channel_ctd(&abort_list, channels[i]); + + ret = vpdma_map_desc_buf(vpdma, &abort_list.buf); + if (ret) + return ret; + ret = vpdma_submit_descs(vpdma, &abort_list, list_num); + if (ret) + return ret; + + while (vpdma_list_busy(vpdma, list_num) && timeout--) + ; + + if (timeout == 0) { + dev_err(&vpdma->pdev->dev, "Timed out cleaning up VPDMA list\n"); + return -EBUSY; + } + + vpdma_unmap_desc_buf(vpdma, &abort_list.buf); + vpdma_free_desc_buf(&abort_list.buf); + + return 0; +} +EXPORT_SYMBOL(vpdma_list_cleanup); + /* * create a descriptor list, the user of this list will append configuration, * control and data descriptors to this list, this list will be submitted to @@ -629,6 +679,31 @@ void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, } EXPORT_SYMBOL(vpdma_add_sync_on_channel_ctd); +/* + * append an 'abort_channel' type control descriptor to the given descriptor + * list, this descriptor aborts any DMA transaction happening using the + * specified channel + */ +void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, + int chan_num) +{ + struct vpdma_ctd *ctd; + + ctd = list->next; + WARN_ON((void *)(ctd + 1) > (list->buf.addr + list->buf.size)); + + ctd->w0 = 0; + ctd->w1 = 0; + ctd->w2 = 0; + ctd->type_source_ctl = ctd_type_source_ctl(chan_num, + CTD_TYPE_ABORT_CHANNEL); + + list->next = ctd + 1; + + dump_ctd(ctd); +} +EXPORT_SYMBOL(vpdma_add_abort_channel_ctd); + static void dump_dtd(struct vpdma_dtd *dtd) { int dir, chan; diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 32b9ed5191c5..4dafc1bcf116 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -163,6 +163,8 @@ enum vpdma_channel { #define VIP_CHAN_YUV_PORTB_OFFSET 2 #define VIP_CHAN_RGB_PORTB_OFFSET 1 +#define VPDMA_MAX_CHANNELS 256 + /* flags for VPDMA data descriptors */ #define VPDMA_DATA_ODD_LINE_SKIP (1 << 0) #define VPDMA_DATA_EVEN_LINE_SKIP (1 << 1) @@ -219,6 +221,8 @@ void vpdma_add_cfd_adb(struct vpdma_desc_list *list, int client, struct vpdma_buf *adb); void vpdma_add_sync_on_channel_ctd(struct vpdma_desc_list *list, enum vpdma_channel chan); +void vpdma_add_abort_channel_ctd(struct vpdma_desc_list *list, + int chan_num); void vpdma_add_out_dtd(struct vpdma_desc_list *list, int width, const struct v4l2_rect *c_rect, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, @@ -233,6 +237,8 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, const struct vpdma_data_format *fmt, dma_addr_t dma_addr, enum vpdma_channel chan, int field, u32 flags, int frame_width, int frame_height, int start_h, int start_v); +int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, + int *channels, int size); /* vpdma list interrupt management */ void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, -- cgit v1.2.3 From 4e4676d250efbc81c70e699fc1c805d3ab370e70 Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:23 -0200 Subject: [media] media: ti-vpe: vpdma: Make list post atomic operation Writing to the "VPDMA list attribute" register is considered as a list post. This informs the VPDMA firmware to load the list from the address which should be taken from the "VPDMA list address" register. As these two register writes are dependent, it is important that the two writes happen in atomic manner. This ensures multiple slices (which share same VPDMA) can post lists asynchronously and all of them point to the correct addresses. Slightly modified to implementation for the original patch to use spin_lock instead of mutex as the list post is also called from interrupt context. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 4 ++++ drivers/media/platform/ti-vpe/vpdma.h | 1 + 2 files changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 7808c9c1828b..ffc281d2b065 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -491,6 +491,7 @@ int vpdma_submit_descs(struct vpdma_data *vpdma, struct vpdma_desc_list *list, int list_num) { int list_size; + unsigned long flags; if (vpdma_list_busy(vpdma, list_num)) return -EBUSY; @@ -498,12 +499,14 @@ int vpdma_submit_descs(struct vpdma_data *vpdma, /* 16-byte granularity */ list_size = (list->next - list->buf.addr) >> 4; + spin_lock_irqsave(&vpdma->lock, flags); write_reg(vpdma, VPDMA_LIST_ADDR, (u32) list->buf.dma_addr); write_reg(vpdma, VPDMA_LIST_ATTR, (list_num << VPDMA_LIST_NUM_SHFT) | (list->type << VPDMA_LIST_TYPE_SHFT) | list_size); + spin_unlock_irqrestore(&vpdma->lock, flags); return 0; } @@ -1090,6 +1093,7 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev, vpdma->pdev = pdev; vpdma->cb = cb; + spin_lock_init(&vpdma->lock); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma"); if (res == NULL) { diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 4dafc1bcf116..f08f4370ce4a 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -35,6 +35,7 @@ struct vpdma_data { struct platform_device *pdev; + spinlock_t lock; /* callback to VPE driver when the firmware is loaded */ void (*cb)(struct platform_device *pdev); }; -- cgit v1.2.3 From afbc0ae9a42e3a447365edc47ba4a206183566ac Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:24 -0200 Subject: [media] media: ti-vpe: vpdma: Clear IRQs for individual lists VPDMA IRQs are registered for multiple lists When clearing an IRQ for a list interrupt, all the IRQs for the individual lists are to be cleared separately. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 6 +++--- drivers/media/platform/ti-vpe/vpdma.h | 3 ++- drivers/media/platform/ti-vpe/vpe.c | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index ffc281d2b065..c0a4e035bc2a 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -953,12 +953,12 @@ unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num) EXPORT_SYMBOL(vpdma_get_list_mask); /* clear previosuly occured list intterupts in the LIST_STAT register */ -void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num) +void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, + int list_num) { u32 reg_addr = VPDMA_INT_LIST0_STAT + VPDMA_INTX_OFFSET * irq_num; - write_reg(vpdma, reg_addr, - read_reg(vpdma, reg_addr)); + write_reg(vpdma, reg_addr, 3 << (list_num * 2)); } EXPORT_SYMBOL(vpdma_clear_list_stat); diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index f08f4370ce4a..65961147e8f7 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -244,7 +244,8 @@ int vpdma_list_cleanup(struct vpdma_data *vpdma, int list_num, /* vpdma list interrupt management */ void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, int list_num, bool enable); -void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num); +void vpdma_clear_list_stat(struct vpdma_data *vpdma, int irq_num, + int list_num); unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num); unsigned int vpdma_get_list_mask(struct vpdma_data *vpdma, int irq_num); diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 151a9280bb85..6fcdd0ea50e4 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1326,7 +1326,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) if (irqst0) { if (irqst0 & VPE_INT0_LIST0_COMPLETE) - vpdma_clear_list_stat(ctx->dev->vpdma, 0); + vpdma_clear_list_stat(ctx->dev->vpdma, 0, 0); irqst0 &= ~(VPE_INT0_LIST0_COMPLETE); } -- cgit v1.2.3 From 655e465671914b9d8c69d827f54d628b558dd58f Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:25 -0200 Subject: [media] media: ti-vpe: vpe: configure line mode separately Current driver configures the line mode of the DEI clients from the open function directly. Even if the newly created context is not yet scheduled, it updates some of the VPDMA registers. This causes a problem in multi instance use case where just opening the m2m device second time causes the running job to stall. This happens especially if the source buffers used are NV12. While all other configuration is being written to context specific shadow registers, only line mode configuration is happening directly. As there is no shadow register for line mode configuration, it's better to separate the config_mode setting and line_mode setting. Call the new "set_line_modes" functions only when actually loading the mmrs. This makes sure that no non-running job will write to the registers directly. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 6fcdd0ea50e4..c79137b404ea 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -660,14 +660,13 @@ static void set_us_coefficients(struct vpe_ctx *ctx) /* * Set the upsampler config mode and the VPDMA line mode in the shadow MMRs. */ -static void set_cfg_and_line_modes(struct vpe_ctx *ctx) +static void set_cfg_modes(struct vpe_ctx *ctx) { struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr; u32 *us1_reg0 = &mmr_adb->us1_regs[0]; u32 *us2_reg0 = &mmr_adb->us2_regs[0]; u32 *us3_reg0 = &mmr_adb->us3_regs[0]; - int line_mode = 1; int cfg_mode = 1; /* @@ -675,15 +674,24 @@ static void set_cfg_and_line_modes(struct vpe_ctx *ctx) * Cfg Mode 1: YUV422 source, disable upsampler, DEI is de-interlacing. */ - if (fmt->fourcc == V4L2_PIX_FMT_NV12) { + if (fmt->fourcc == V4L2_PIX_FMT_NV12) cfg_mode = 0; - line_mode = 0; /* double lines to line buffer */ - } write_field(us1_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); write_field(us2_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); write_field(us3_reg0, cfg_mode, VPE_US_MODE_MASK, VPE_US_MODE_SHIFT); + ctx->load_mmrs = true; +} + +static void set_line_modes(struct vpe_ctx *ctx) +{ + struct vpe_fmt *fmt = ctx->q_data[Q_DATA_SRC].fmt; + int line_mode = 1; + + if (fmt->fourcc == V4L2_PIX_FMT_NV12) + line_mode = 0; /* double lines to line buffer */ + /* regs for now */ vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA1_IN); vpdma_set_line_mode(ctx->dev->vpdma, line_mode, VPE_CHAN_CHROMA2_IN); @@ -708,8 +716,6 @@ static void set_cfg_and_line_modes(struct vpe_ctx *ctx) /* frame start for MV in client */ vpdma_set_frame_start_event(ctx->dev->vpdma, VPDMA_FSEVENT_CHANNEL_ACTIVE, VPE_CHAN_MV_IN); - - ctx->load_mmrs = true; } /* @@ -868,7 +874,7 @@ static int set_srcdst_params(struct vpe_ctx *ctx) if (ret) return ret; - set_cfg_and_line_modes(ctx); + set_cfg_modes(ctx); set_dei_regs(ctx); csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0], @@ -1184,6 +1190,9 @@ static void device_run(void *priv) if (ctx->dev->loaded_mmrs != ctx->mmr_adb.dma_addr || ctx->load_mmrs) { vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->mmr_adb); vpdma_add_cfd_adb(&ctx->desc_list, CFD_MMR_CLIENT, &ctx->mmr_adb); + + set_line_modes(ctx); + ctx->dev->loaded_mmrs = ctx->mmr_adb.dma_addr; ctx->load_mmrs = false; } -- cgit v1.2.3 From 0f469c1acf20b88bb8b9b91d652009dca9e9c561 Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:26 -0200 Subject: [media] media: ti-vpe: vpe: Setup srcdst parameters in start_streaming For deinterlacing operation, each operation needs 2 fields in the history. This is achieved by holding three buffers in ctx->src_vbs[0,1,2] (f,f-1,f-2) This is achieved by using the ctx->sequence which gets reset via the s_fmt ioctl. These buffers are dequeued in stream OFF by calling free_vbs() But the corresponding references aren't removed anywhere. When application tries to stream ON and OFF continuously, s_fmt ioctl won't be called and it won't setup the srcdst parameters. Setting source/destination parameters in stream ON ioctl would make sure that the context is re-initialized before it is being used by the driver. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index c79137b404ea..1ee7e611e41b 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -869,6 +869,7 @@ static int set_srcdst_params(struct vpe_ctx *ctx) } free_vbs(ctx); + ctx->src_vbs[2] = ctx->src_vbs[1] = ctx->src_vbs[0] = NULL; ret = realloc_mv_buffers(ctx, mv_buf_size); if (ret) @@ -1990,6 +1991,9 @@ static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) if (ctx->deinterlacing) config_edi_input_mode(ctx, 0x0); + if (ctx->sequence != 0) + set_srcdst_params(ctx); + return 0; } -- cgit v1.2.3 From 5b6179570fb3d89758c6bc93b322018edc2b2a8f Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:27 -0200 Subject: [media] media: ti-vpe: vpe: Post next descriptor only for list complete IRQ vpe_irq checks for the possible interrupt sources and prints the errors for the DEI_ERROR and DS_UV interrupts. But it also post the next descriptor list irrespective of whichever interrupt has occurred. Because of this, driver may release the buffers even before DMA is complete and also schedule next descriptor list. Fix this by _actually_ handling the IRQ only when ListComplete IRQ occurs. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1ee7e611e41b..0f652a049ede 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1304,6 +1304,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) struct vb2_v4l2_buffer *s_vb, *d_vb; unsigned long flags; u32 irqst0, irqst1; + bool list_complete = false; irqst0 = read_reg(dev, VPE_INT0_STATUS0); if (irqst0) { @@ -1339,6 +1340,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) vpdma_clear_list_stat(ctx->dev->vpdma, 0, 0); irqst0 &= ~(VPE_INT0_LIST0_COMPLETE); + list_complete = true; } if (irqst0 | irqst1) { @@ -1346,6 +1348,13 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) irqst0, irqst1); } + /* + * Setup next operation only when list complete IRQ occurs + * otherwise, skip the following code + */ + if (!list_complete) + goto handled; + disable_irqs(ctx); vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf); -- cgit v1.2.3 From b28b8f1d7fc73f283532cd33702b3e7a92c09fcf Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:28 -0200 Subject: [media] media: ti-vpe: vpe: Add RGB565 and RGB5551 support VPE hardware can generate output in RGB565 or in RGB5551 format. Add these formats in the supported format list for CAPTURE stream. Also, for RGB5551 format, the alpha component is not processed, so the alpha value is taken from the default color. Set the default color to make alpha component full when the dst format is of RGB color space. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 0f652a049ede..d3412accf564 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -302,6 +302,22 @@ static struct vpe_fmt vpe_formats[] = { .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ABGR32], }, }, + { + .name = "RGB565", + .fourcc = V4L2_PIX_FMT_RGB565, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB565], + }, + }, + { + .name = "RGB5551", + .fourcc = V4L2_PIX_FMT_RGB555, + .types = VPE_FMT_TYPE_CAPTURE, + .coplanar = 0, + .vpdma_fmt = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGBA16_5551], + }, + }, }; /* @@ -738,9 +754,11 @@ static void set_dst_registers(struct vpe_ctx *ctx) struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt; u32 val = 0; - if (clrspc == V4L2_COLORSPACE_SRGB) + if (clrspc == V4L2_COLORSPACE_SRGB) { val |= VPE_RGB_OUT_SELECT; - else if (fmt->fourcc == V4L2_PIX_FMT_NV16) + vpdma_set_bg_color(ctx->dev->vpdma, + (struct vpdma_data_format *)fmt->vpdma_fmt[0], 0xff); + } else if (fmt->fourcc == V4L2_PIX_FMT_NV16) val |= VPE_COLOR_SEPARATE_422; /* -- cgit v1.2.3 From c1cd15ea4283454f98ef22c5d1d02a59e4510b0e Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:29 -0200 Subject: [media] media: ti-vpe: vpdma: allocate and maintain hwlist VPDMA block used in ti-vip and ti-vpe modules have support for up to 8 hardware descriptor lists. A descriptor list can be submitted to any of the 8 lists (as long as it's not busy). When multiple clients want to transfer data in parallel, its easier to allocate one list per client and let it use it. This way, the list numbers need not be hard-coded into the driver. Add support for allocating hwlist and maintain them with a priv data. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 44 +++++++++++++++++++++++++++++++++++ drivers/media/platform/ti-vpe/vpdma.h | 9 +++++++ 2 files changed, 53 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index c0a4e035bc2a..f85727a0ac44 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -902,6 +902,50 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int width, } EXPORT_SYMBOL(vpdma_add_in_dtd); +int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv) +{ + int i, list_num = -1; + unsigned long flags; + + spin_lock_irqsave(&vpdma->lock, flags); + for (i = 0; i < VPDMA_MAX_NUM_LIST && + vpdma->hwlist_used[i] == true; i++) + ; + + if (i < VPDMA_MAX_NUM_LIST) { + list_num = i; + vpdma->hwlist_used[i] = true; + vpdma->hwlist_priv[i] = priv; + } + spin_unlock_irqrestore(&vpdma->lock, flags); + + return list_num; +} +EXPORT_SYMBOL(vpdma_hwlist_alloc); + +void *vpdma_hwlist_get_priv(struct vpdma_data *vpdma, int list_num) +{ + if (!vpdma || list_num >= VPDMA_MAX_NUM_LIST) + return NULL; + + return vpdma->hwlist_priv[list_num]; +} +EXPORT_SYMBOL(vpdma_hwlist_get_priv); + +void *vpdma_hwlist_release(struct vpdma_data *vpdma, int list_num) +{ + void *priv; + unsigned long flags; + + spin_lock_irqsave(&vpdma->lock, flags); + vpdma->hwlist_used[list_num] = false; + priv = vpdma->hwlist_priv; + spin_unlock_irqrestore(&vpdma->lock, flags); + + return priv; +} +EXPORT_SYMBOL(vpdma_hwlist_release); + /* set or clear the mask for list complete interrupt */ void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, int list_num, bool enable) diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 65961147e8f7..ccf871ad8800 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -13,6 +13,7 @@ #ifndef __TI_VPDMA_H_ #define __TI_VPDMA_H_ +#define VPDMA_MAX_NUM_LIST 8 /* * A vpdma_buf tracks the size, DMA address and mapping status of each * driver DMA area. @@ -36,6 +37,8 @@ struct vpdma_data { struct platform_device *pdev; spinlock_t lock; + bool hwlist_used[VPDMA_MAX_NUM_LIST]; + void *hwlist_priv[VPDMA_MAX_NUM_LIST]; /* callback to VPE driver when the firmware is loaded */ void (*cb)(struct platform_device *pdev); }; @@ -215,6 +218,12 @@ bool vpdma_list_busy(struct vpdma_data *vpdma, int list_num); void vpdma_update_dma_addr(struct vpdma_data *vpdma, struct vpdma_desc_list *list, dma_addr_t dma_addr, void *write_dtd, int drop, int idx); + +/* VPDMA hardware list funcs */ +int vpdma_hwlist_alloc(struct vpdma_data *vpdma, void *priv); +void *vpdma_hwlist_get_priv(struct vpdma_data *vpdma, int list_num); +void *vpdma_hwlist_release(struct vpdma_data *vpdma, int list_num); + /* helpers for creating vpdma descriptors */ void vpdma_add_cfd_block(struct vpdma_desc_list *list, int client, struct vpdma_buf *blk, u32 dest_offset); -- cgit v1.2.3 From e228467caa6eb18db05c0ca62e852bba47d08f58 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:30 -0200 Subject: [media] media: ti-vpe: vpe: Added MODULE_DEVICE_TABLE hint ti_vpe module currently does not get loaded automatically. Added MODULE_DEVICE_TABLE hint to the driver to assist. Signed-off-by: Benoit Parrot Reviewed-by: Javier Martinez Canillas Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index d3412accf564..05b793595ce9 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2447,6 +2447,7 @@ static const struct of_device_id vpe_of_match[] = { }, {}, }; +MODULE_DEVICE_TABLE(of, vpe_of_match); #endif static struct platform_driver vpe_pdrv = { -- cgit v1.2.3 From eaa6808d1d815d8d25c7a47649503da678e48e2e Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:31 -0200 Subject: [media] media: ti-vpe: vpdma: Corrected YUV422 data type label The YUV data type definition below are taken from both the TRM and i839 Errata information. Use the correct data type considering byte reordering of components. Added the 2 missing YUV422 variant. Also since the single use of "C" in the 422 case to mean "Cr" (i.e. V component). It was decided to explicitly label them CR to remove any confusion. Bear in mind that the type label refer to the memory packed order (LSB - MSB). Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 18 ++++++++++++++---- drivers/media/platform/ti-vpe/vpdma.h | 6 ++++-- drivers/media/platform/ti-vpe/vpdma_priv.h | 19 ++++++++++++++++--- drivers/media/platform/ti-vpe/vpe.c | 8 ++++---- 4 files changed, 38 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index f85727a0ac44..8f0d608c70f6 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -59,9 +59,9 @@ const struct vpdma_data_format vpdma_yuv_fmts[] = { .data_type = DATA_TYPE_C420, .depth = 4, }, - [VPDMA_DATA_FMT_YC422] = { + [VPDMA_DATA_FMT_YCR422] = { .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_YC422, + .data_type = DATA_TYPE_YCR422, .depth = 16, }, [VPDMA_DATA_FMT_YC444] = { @@ -69,9 +69,19 @@ const struct vpdma_data_format vpdma_yuv_fmts[] = { .data_type = DATA_TYPE_YC444, .depth = 24, }, - [VPDMA_DATA_FMT_CY422] = { + [VPDMA_DATA_FMT_CRY422] = { .type = VPDMA_DATA_FMT_TYPE_YUV, - .data_type = DATA_TYPE_CY422, + .data_type = DATA_TYPE_CRY422, + .depth = 16, + }, + [VPDMA_DATA_FMT_CBY422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CBY422, + .depth = 16, + }, + [VPDMA_DATA_FMT_YCB422] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_YCB422, .depth = 16, }, }; diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index ccf871ad8800..405a6febc254 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -74,9 +74,11 @@ enum vpdma_yuv_formats { VPDMA_DATA_FMT_C444, VPDMA_DATA_FMT_C422, VPDMA_DATA_FMT_C420, - VPDMA_DATA_FMT_YC422, + VPDMA_DATA_FMT_YCR422, VPDMA_DATA_FMT_YC444, - VPDMA_DATA_FMT_CY422, + VPDMA_DATA_FMT_CRY422, + VPDMA_DATA_FMT_CBY422, + VPDMA_DATA_FMT_YCB422, }; enum vpdma_rgb_formats { diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index 54b6aa866c74..f974a803fa27 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h @@ -77,16 +77,29 @@ #define VPDMA_LIST_TYPE_SHFT 16 #define VPDMA_LIST_SIZE_MASK 0xffff -/* VPDMA data type values for data formats */ +/* + * The YUV data type definition below are taken from + * both the TRM and i839 Errata information. + * Use the correct data type considering byte + * reordering of components. + * + * Also since the single use of "C" in the 422 case + * to mean "Cr" (i.e. V component). It was decided + * to explicitly label them CR to remove any confusion. + * Bear in mind that the type label refer to the memory + * packed order (LSB - MSB). + */ #define DATA_TYPE_Y444 0x0 #define DATA_TYPE_Y422 0x1 #define DATA_TYPE_Y420 0x2 #define DATA_TYPE_C444 0x4 #define DATA_TYPE_C422 0x5 #define DATA_TYPE_C420 0x6 -#define DATA_TYPE_YC422 0x7 #define DATA_TYPE_YC444 0x8 -#define DATA_TYPE_CY422 0x27 +#define DATA_TYPE_YCB422 0x7 +#define DATA_TYPE_YCR422 0x17 +#define DATA_TYPE_CBY422 0x27 +#define DATA_TYPE_CRY422 0x37 #define DATA_TYPE_RGB16_565 0x0 #define DATA_TYPE_ARGB_1555 0x1 diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 05b793595ce9..ef55fb45d0be 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -237,7 +237,7 @@ struct vpe_fmt { static struct vpe_fmt vpe_formats[] = { { - .name = "YUV 422 co-planar", + .name = "NV16 YUV 422 co-planar", .fourcc = V4L2_PIX_FMT_NV16, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 1, @@ -246,7 +246,7 @@ static struct vpe_fmt vpe_formats[] = { }, }, { - .name = "YUV 420 co-planar", + .name = "NV12 YUV 420 co-planar", .fourcc = V4L2_PIX_FMT_NV12, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 1, @@ -259,7 +259,7 @@ static struct vpe_fmt vpe_formats[] = { .fourcc = V4L2_PIX_FMT_YUYV, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 0, - .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YC422], + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCB422], }, }, { @@ -267,7 +267,7 @@ static struct vpe_fmt vpe_formats[] = { .fourcc = V4L2_PIX_FMT_UYVY, .types = VPE_FMT_TYPE_CAPTURE | VPE_FMT_TYPE_OUTPUT, .coplanar = 0, - .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CY422], + .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422], }, }, { -- cgit v1.2.3 From 3d7e61f6e25dd8000b46d6773b0a0249839c9554 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:32 -0200 Subject: [media] media: ti-vpe: vpdma: RGB data type yield inverted data The VPDMA RGB data type definition have been updated to match with Errata i839. But some of the ARGB definition appeared to be wrong in the document also. As they would yield RGBA instead. They have been corrected based on experimentation. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma_priv.h | 49 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma_priv.h b/drivers/media/platform/ti-vpe/vpdma_priv.h index f974a803fa27..72c7f13b4a9d 100644 --- a/drivers/media/platform/ti-vpe/vpdma_priv.h +++ b/drivers/media/platform/ti-vpe/vpdma_priv.h @@ -101,26 +101,35 @@ #define DATA_TYPE_CBY422 0x27 #define DATA_TYPE_CRY422 0x37 -#define DATA_TYPE_RGB16_565 0x0 -#define DATA_TYPE_ARGB_1555 0x1 -#define DATA_TYPE_ARGB_4444 0x2 -#define DATA_TYPE_RGBA_5551 0x3 -#define DATA_TYPE_RGBA_4444 0x4 -#define DATA_TYPE_ARGB24_6666 0x5 -#define DATA_TYPE_RGB24_888 0x6 -#define DATA_TYPE_ARGB32_8888 0x7 -#define DATA_TYPE_RGBA24_6666 0x8 -#define DATA_TYPE_RGBA32_8888 0x9 -#define DATA_TYPE_BGR16_565 0x10 -#define DATA_TYPE_ABGR_1555 0x11 -#define DATA_TYPE_ABGR_4444 0x12 -#define DATA_TYPE_BGRA_5551 0x13 -#define DATA_TYPE_BGRA_4444 0x14 -#define DATA_TYPE_ABGR24_6666 0x15 -#define DATA_TYPE_BGR24_888 0x16 -#define DATA_TYPE_ABGR32_8888 0x17 -#define DATA_TYPE_BGRA24_6666 0x18 -#define DATA_TYPE_BGRA32_8888 0x19 +/* + * The RGB data type definition below are defined + * to follow Errata i819. + * The initial values were taken from: + * VPDMA_data_type_mapping_v0.2vayu_c.pdf + * But some of the ARGB definition appeared to be wrong + * in the document also. As they would yield RGBA instead. + * They have been corrected based on experimentation. + */ +#define DATA_TYPE_RGB16_565 0x10 +#define DATA_TYPE_ARGB_1555 0x13 +#define DATA_TYPE_ARGB_4444 0x14 +#define DATA_TYPE_RGBA_5551 0x11 +#define DATA_TYPE_RGBA_4444 0x12 +#define DATA_TYPE_ARGB24_6666 0x18 +#define DATA_TYPE_RGB24_888 0x16 +#define DATA_TYPE_ARGB32_8888 0x17 +#define DATA_TYPE_RGBA24_6666 0x15 +#define DATA_TYPE_RGBA32_8888 0x19 +#define DATA_TYPE_BGR16_565 0x0 +#define DATA_TYPE_ABGR_1555 0x3 +#define DATA_TYPE_ABGR_4444 0x4 +#define DATA_TYPE_BGRA_5551 0x1 +#define DATA_TYPE_BGRA_4444 0x2 +#define DATA_TYPE_ABGR24_6666 0x8 +#define DATA_TYPE_BGR24_888 0x6 +#define DATA_TYPE_ABGR32_8888 0x7 +#define DATA_TYPE_BGRA24_6666 0x5 +#define DATA_TYPE_BGRA32_8888 0x9 #define DATA_TYPE_MV 0x3 -- cgit v1.2.3 From bc809bfc1796accdd0c15c3bccd4e8af33922018 Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:33 -0200 Subject: [media] media: ti-vpe: sc: Fix incorrect optimization Current scaler library implementation of sc_set_hs_coeffs and sc_set_vs_coeffs tries to return immediately if the calculated coefficient index is already being used. As the same scaler block is going to be used for all the VPE contexts, even if the calculated index is same, the parameters have to be reconfigured for each of the context. Because of this, when multiple contexts use the same coefficients, all other contexts would have zero scaling coefficients. Fix this and also remove the unnecessary hs_index and vs_index fields. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/sc.c | 9 --------- drivers/media/platform/ti-vpe/sc.h | 3 --- 2 files changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c index f82d1c7f667f..02f3dae8ae42 100644 --- a/drivers/media/platform/ti-vpe/sc.c +++ b/drivers/media/platform/ti-vpe/sc.c @@ -84,9 +84,6 @@ void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, } } - if (idx == sc->hs_index) - return; - cp = scaler_hs_coeffs[idx]; for (i = 0; i < SC_NUM_PHASES * 2; i++) { @@ -101,8 +98,6 @@ void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, coeff_h += SC_NUM_TAPS_MEM_ALIGN - SC_H_NUM_TAPS; } - sc->hs_index = idx; - sc->load_coeff_h = true; } @@ -130,9 +125,6 @@ void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, idx = VS_LT_9_16_SCALE + sixteenths - 8; } - if (idx == sc->vs_index) - return; - cp = scaler_vs_coeffs[idx]; for (i = 0; i < SC_NUM_PHASES * 2; i++) { @@ -146,7 +138,6 @@ void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, coeff_v += SC_NUM_TAPS_MEM_ALIGN - SC_V_NUM_TAPS; } - sc->vs_index = idx; sc->load_coeff_v = true; } diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h index 60e411e05c30..de947db98990 100644 --- a/drivers/media/platform/ti-vpe/sc.h +++ b/drivers/media/platform/ti-vpe/sc.h @@ -189,9 +189,6 @@ struct sc_data { bool load_coeff_h; /* have new h SC coeffs */ bool load_coeff_v; /* have new v SC coeffs */ - unsigned int hs_index; /* h SC coeffs selector */ - unsigned int vs_index; /* v SC coeffs selector */ - struct platform_device *pdev; }; -- cgit v1.2.3 From dfe1349dc805aa3113e6fba9db55761d24ce63fe Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:34 -0200 Subject: [media] media: ti-vpe: vpe: Fix vb2 buffer cleanup When stop_streaming is called we need to cleanup the queued vb2 buffers properly. This was not previously being done which caused kernel warning when the application using the resources was killed. Kernel warnings were also generated on successful completion of a de-interlacing case as well as upon aborting a conversion. Make sure every vb2 buffers is properly handled in all cases. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 62 +++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index ef55fb45d0be..f92ad7a473c1 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -605,7 +605,10 @@ static void free_vbs(struct vpe_ctx *ctx) spin_lock_irqsave(&dev->lock, flags); if (ctx->src_vbs[2]) { v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_DONE); - v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE); + if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2])) + v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_DONE); + ctx->src_vbs[2] = NULL; + ctx->src_vbs[1] = NULL; } spin_unlock_irqrestore(&dev->lock, flags); } @@ -1443,6 +1446,14 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data) ctx->src_vbs[1] = ctx->src_vbs[0]; } + /* + * Since the vb2_buf_done has already been called fir therse + * buffer we can now NULL them out so that we won't try + * to clean out stray pointer later on. + */ + ctx->src_vbs[0] = NULL; + ctx->dst_vb = NULL; + ctx->bufs_completed++; if (ctx->bufs_completed < ctx->bufs_per_job && job_ready(ctx)) { device_run(ctx); @@ -2027,9 +2038,57 @@ static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) static void vpe_stop_streaming(struct vb2_queue *q) { struct vpe_ctx *ctx = vb2_get_drv_priv(q); + struct vb2_v4l2_buffer *vb; + unsigned long flags; vpe_dump_regs(ctx->dev); vpdma_dump_regs(ctx->dev->vpdma); + + for (;;) { + if (V4L2_TYPE_IS_OUTPUT(q->type)) + vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); + else + vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); + if (!vb) + break; + spin_lock_irqsave(&ctx->dev->lock, flags); + v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + spin_unlock_irqrestore(&ctx->dev->lock, flags); + } + + /* + * Cleanup the in-transit vb2 buffers that have been + * removed from their respective queue already but for + * which procecessing has not been completed yet. + */ + if (V4L2_TYPE_IS_OUTPUT(q->type)) { + spin_lock_irqsave(&ctx->dev->lock, flags); + + if (ctx->src_vbs[2]) + v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_ERROR); + + if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2])) + v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_ERROR); + + if (ctx->src_vbs[0] && + (ctx->src_vbs[0] != ctx->src_vbs[1]) && + (ctx->src_vbs[0] != ctx->src_vbs[2])) + v4l2_m2m_buf_done(ctx->src_vbs[0], VB2_BUF_STATE_ERROR); + + ctx->src_vbs[2] = NULL; + ctx->src_vbs[1] = NULL; + ctx->src_vbs[0] = NULL; + + spin_unlock_irqrestore(&ctx->dev->lock, flags); + } else { + if (ctx->dst_vb) { + spin_lock_irqsave(&ctx->dev->lock, flags); + + v4l2_m2m_buf_done(ctx->dst_vb, VB2_BUF_STATE_ERROR); + ctx->dst_vb = NULL; + spin_unlock_irqrestore(&ctx->dev->lock, flags); + } + } } static const struct vb2_ops vpe_qops = { @@ -2222,7 +2281,6 @@ static int vpe_release(struct file *file) vpe_dbg(dev, "releasing instance %p\n", ctx); mutex_lock(&dev->dev_mutex); - free_vbs(ctx); free_mv_buffers(ctx); vpdma_free_desc_list(&ctx->desc_list); vpdma_free_desc_buf(&ctx->mmr_adb); -- cgit v1.2.3 From c786595beb89d74ff709b2ee382f34a1e0040d88 Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:35 -0200 Subject: [media] media: ti-vpe: vpdma: Fix race condition for firmware loading vpdma_create API is supposed to allocated the struct vpdma_data and return it to the driver. Also, it would call the callback function when the VPDMA firmware is loaded. Typically, VPE driver have following function call: dev->vpdma = vpdma_create(pdev, firmware_load_callback); And the callback implementation would continue the probe further. Also, the dev->vpdma is accessed from the callback implementation. This may lead to race condition between assignment of dev->vpdma and the callback function being triggered. This would lead to kernel crash because of NULL pointer access. Fix this by passing a driver wrapped &vpdma_data instead of allocating inside vpdma_create. Change the vpdma_create prototype accordingly and fix return paths. Also, update the VPE driver to use the updated API and initialize the dev->vpdma before hand so that the race condition is avoided. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 17 +++++------------ drivers/media/platform/ti-vpe/vpdma.h | 2 +- drivers/media/platform/ti-vpe/vpe.c | 8 ++++---- 3 files changed, 10 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 8f0d608c70f6..070937fe1af6 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -1130,21 +1130,14 @@ static int vpdma_load_firmware(struct vpdma_data *vpdma) return 0; } -struct vpdma_data *vpdma_create(struct platform_device *pdev, +int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma, void (*cb)(struct platform_device *pdev)) { struct resource *res; - struct vpdma_data *vpdma; int r; dev_dbg(&pdev->dev, "vpdma_create\n"); - vpdma = devm_kzalloc(&pdev->dev, sizeof(*vpdma), GFP_KERNEL); - if (!vpdma) { - dev_err(&pdev->dev, "couldn't alloc vpdma_dev\n"); - return ERR_PTR(-ENOMEM); - } - vpdma->pdev = pdev; vpdma->cb = cb; spin_lock_init(&vpdma->lock); @@ -1152,22 +1145,22 @@ struct vpdma_data *vpdma_create(struct platform_device *pdev, res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpdma"); if (res == NULL) { dev_err(&pdev->dev, "missing platform resources data\n"); - return ERR_PTR(-ENODEV); + return -ENODEV; } vpdma->base = devm_ioremap(&pdev->dev, res->start, resource_size(res)); if (!vpdma->base) { dev_err(&pdev->dev, "failed to ioremap\n"); - return ERR_PTR(-ENOMEM); + return -ENOMEM; } r = vpdma_load_firmware(vpdma); if (r) { pr_err("failed to load firmware %s\n", VPDMA_FIRMWARE); - return ERR_PTR(r); + return r; } - return vpdma; + return 0; } EXPORT_SYMBOL(vpdma_create); diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 405a6febc254..0df156b7c1cf 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -273,7 +273,7 @@ void vpdma_set_bg_color(struct vpdma_data *vpdma, void vpdma_dump_regs(struct vpdma_data *vpdma); /* initialize vpdma, passed with VPE's platform device pointer */ -struct vpdma_data *vpdma_create(struct platform_device *pdev, +int vpdma_create(struct platform_device *pdev, struct vpdma_data *vpdma, void (*cb)(struct platform_device *pdev)); #endif diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index f92ad7a473c1..15e846b95719 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -383,6 +383,7 @@ struct vpe_dev { void __iomem *base; struct resource *res; + struct vpdma_data vpdma_data; struct vpdma_data *vpdma; /* vpdma data handle */ struct sc_data *sc; /* scaler data handle */ struct csc_data *csc; /* csc data handle */ @@ -2462,11 +2463,10 @@ static int vpe_probe(struct platform_device *pdev) goto runtime_put; } - dev->vpdma = vpdma_create(pdev, vpe_fw_cb); - if (IS_ERR(dev->vpdma)) { - ret = PTR_ERR(dev->vpdma); + dev->vpdma = &dev->vpdma_data; + ret = vpdma_create(pdev, dev->vpdma, vpe_fw_cb); + if (ret) goto runtime_put; - } return 0; -- cgit v1.2.3 From 07e72eb0725ccd20b5cc26ee463def3f34606c7f Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:36 -0200 Subject: [media] media: ti-vpe: vpdma: Use bidirectional cached buffers VPDMA buffer will be used by CPU as well as by the VPDMA. CPU will write/update the VPDMA descriptors containing data about the video buffer DMA addresses. VPDMA will write the "write descriptor" containing the data about the DMA operation. When mapping/unmapping the buffer, driver has to take care of WriteBack and invalidation of the cache so that all the coherency is maintained from both directions. Use DMA_BIDIRECTIONAL to maintain coherency between CPU and VPDMA. Signed-off-by: Nikhil Devshatwar Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 070937fe1af6..2d13644a28a8 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -367,7 +367,7 @@ int vpdma_map_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) WARN_ON(buf->mapped); buf->dma_addr = dma_map_single(dev, buf->addr, buf->size, - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); if (dma_mapping_error(dev, buf->dma_addr)) { dev_err(dev, "failed to map buffer\n"); return -EINVAL; @@ -388,7 +388,8 @@ void vpdma_unmap_desc_buf(struct vpdma_data *vpdma, struct vpdma_buf *buf) struct device *dev = &vpdma->pdev->dev; if (buf->mapped) - dma_unmap_single(dev, buf->dma_addr, buf->size, DMA_TO_DEVICE); + dma_unmap_single(dev, buf->dma_addr, buf->size, + DMA_BIDIRECTIONAL); buf->mapped = false; } -- cgit v1.2.3 From 00db969964c8de88ccb33db08db330634e111778 Mon Sep 17 00:00:00 2001 From: Nikhil Devshatwar Date: Fri, 18 Nov 2016 21:20:37 -0200 Subject: [media] media: ti-vpe: vpe: Fix line stride for output motion vector For deinterlacing operation, VPE hardware uses motion vectors. MV calculated in the previous iteration are used for next interation. Therefore driver allocates two motion vectors in ping-pong fashion. For every transaction, one MV is DMAed in and one is DMAed out. All the outbound DMAs (DMA to memory) use output parameters, but as the motion vectors is generated purely out of input fields, it should use the input parameters for DMA. Fix the add_out_dtd to use source q_data for creating descriptor. If the output size is greater than input stride, without this change, MV DMA may overwrite the buffer causing memory corruption. This CRITICAL fix ensures that the motion vector DMA descriptor is created based on the attributes with which the buffer was allocated. Signed-off-by: Nikhil Devshatwar Signed-off-by: Ravikumar Kattekola Signed-off-by: Ravi Babu Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 15e846b95719..608d11344147 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1046,6 +1046,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) if (port == VPE_PORT_MV_OUT) { vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; dma_addr = ctx->mv_buf_dma[mv_buf_selector]; + q_data = &ctx->q_data[Q_DATA_SRC]; } else { /* to incorporate interleaved formats */ int plane = fmt->coplanar ? p_data->vb_part : 0; -- cgit v1.2.3 From b8b3ac44ddf156d0719eee1b0fb23a10a86c8163 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:38 -0200 Subject: [media] media: ti-vpe: vpe: Enable DMABUF export Allow VPE to be able to export DMA buffer. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 608d11344147..1d780ac7ff82 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1944,6 +1944,7 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = { .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, .vidioc_streamon = v4l2_m2m_ioctl_streamon, .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, -- cgit v1.2.3 From 1c6e81783cff1a54e05b08691f5ae034af82ba0a Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:39 -0200 Subject: [media] media: ti-vpe: Make scaler library into its own module In preparation to add scaler support into VIP we need to turn sc.c into its own kernel module. Add support for multiple SC memory block as VIP contains 2 scaler instances. This is done by passing the resource name to sc_create() and modify the vpe invocation accordingly. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 4 ++++ drivers/media/platform/ti-vpe/Makefile | 4 +++- drivers/media/platform/ti-vpe/sc.c | 17 ++++++++++++++--- drivers/media/platform/ti-vpe/sc.h | 2 +- drivers/media/platform/ti-vpe/vpe.c | 2 +- 5 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index b52b6771fc4d..5d7befad90e0 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -365,6 +365,7 @@ config VIDEO_TI_VPE select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV select VIDEO_TI_VPDMA + select VIDEO_TI_SC default n ---help--- Support for the TI VPE(Video Processing Engine) block @@ -383,6 +384,9 @@ endif # V4L_MEM2MEM_DRIVERS config VIDEO_TI_VPDMA tristate +config VIDEO_TI_SC + tristate + menuconfig V4L_TEST_DRIVERS bool "Media test drivers" depends on MEDIA_CAMERA_SUPPORT diff --git a/drivers/media/platform/ti-vpe/Makefile b/drivers/media/platform/ti-vpe/Makefile index faca5e115c1d..736558d309ad 100644 --- a/drivers/media/platform/ti-vpe/Makefile +++ b/drivers/media/platform/ti-vpe/Makefile @@ -1,8 +1,10 @@ obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o obj-$(CONFIG_VIDEO_TI_VPDMA) += ti-vpdma.o +obj-$(CONFIG_VIDEO_TI_SC) += ti-sc.o -ti-vpe-y := vpe.o sc.o csc.o +ti-vpe-y := vpe.o csc.o ti-vpdma-y := vpdma.o +ti-sc-y := sc.o ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c index 02f3dae8ae42..52ce1450362f 100644 --- a/drivers/media/platform/ti-vpe/sc.c +++ b/drivers/media/platform/ti-vpe/sc.c @@ -14,6 +14,7 @@ #include #include +#include #include #include @@ -52,6 +53,7 @@ void sc_dump_regs(struct sc_data *sc) #undef DUMPREG } +EXPORT_SYMBOL(sc_dump_regs); /* * set the horizontal scaler coefficients according to the ratio of output to @@ -100,6 +102,7 @@ void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w, sc->load_coeff_h = true; } +EXPORT_SYMBOL(sc_set_hs_coeffs); /* * set the vertical scaler coefficients according to the ratio of output to @@ -140,6 +143,7 @@ void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, sc->load_coeff_v = true; } +EXPORT_SYMBOL(sc_set_vs_coeffs); void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, u32 *sc_reg17, unsigned int src_w, unsigned int src_h, @@ -267,8 +271,9 @@ void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, *sc_reg24 = (src_w << CFG_ORG_W_SHIFT) | (src_h << CFG_ORG_H_SHIFT); } +EXPORT_SYMBOL(sc_config_scaler); -struct sc_data *sc_create(struct platform_device *pdev) +struct sc_data *sc_create(struct platform_device *pdev, const char *res_name) { struct sc_data *sc; @@ -282,9 +287,10 @@ struct sc_data *sc_create(struct platform_device *pdev) sc->pdev = pdev; - sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sc"); + sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name); if (!sc->res) { - dev_err(&pdev->dev, "missing platform resources data\n"); + dev_err(&pdev->dev, "missing '%s' platform resources data\n", + res_name); return ERR_PTR(-ENODEV); } @@ -296,3 +302,8 @@ struct sc_data *sc_create(struct platform_device *pdev) return sc; } +EXPORT_SYMBOL(sc_create); + +MODULE_DESCRIPTION("TI VIP/VPE Scaler"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h index de947db98990..d0aab5ef0eca 100644 --- a/drivers/media/platform/ti-vpe/sc.h +++ b/drivers/media/platform/ti-vpe/sc.h @@ -200,6 +200,6 @@ void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h, void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8, u32 *sc_reg17, unsigned int src_w, unsigned int src_h, unsigned int dst_w, unsigned int dst_h); -struct sc_data *sc_create(struct platform_device *pdev); +struct sc_data *sc_create(struct platform_device *pdev, const char *res_name); #endif diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1d780ac7ff82..ebde4f4586e6 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2453,7 +2453,7 @@ static int vpe_probe(struct platform_device *pdev) vpe_top_vpdma_reset(dev); - dev->sc = sc_create(pdev); + dev->sc = sc_create(pdev, "sc"); if (IS_ERR(dev->sc)) { ret = PTR_ERR(dev->sc); goto runtime_put; -- cgit v1.2.3 From d6a617877368c73c96d9f3adce9d9c8092bbff7d Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:40 -0200 Subject: [media] media: ti-vpe: scaler: Add debug support for multi-instance Since there might be more then one instance it is better to show the base address when dumping registers to help with debugging. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/sc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c index 52ce1450362f..e9273b713782 100644 --- a/drivers/media/platform/ti-vpe/sc.c +++ b/drivers/media/platform/ti-vpe/sc.c @@ -28,6 +28,8 @@ void sc_dump_regs(struct sc_data *sc) #define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \ ioread32(sc->base + CFG_##r)) + dev_dbg(dev, "SC Registers @ %pa:\n", &sc->res->start); + DUMPREG(SC0); DUMPREG(SC1); DUMPREG(SC2); -- cgit v1.2.3 From 35be6d865c2b6c0866164fef14832ecc5def9d2b Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:41 -0200 Subject: [media] media: ti-vpe: vpe: Make sure frame size dont exceed scaler capacity When scaler is to be used we need to make sure that the input and output frame size do not exceed the maximum frame sizes that the scaler h/w can handle otherwise streaming stall as the scaler cannot proceed. The scaler buffer is limited to 2047 pixels (i.e. 11 bits) when attempting anything larger (2048 for example) the scaler stalls. Realistically in an mem2mem device we can only check for this type of issue when start_streaming is called. We can't do it during the try_fmt/s_fmt because we do not have all of the info needed at that point. So instead when start_streaming is called we need to check that the input and output frames size do not exceed the scaler's capability. The only time larger frame size are allowed is when the input frame szie is the same as the output frame size. Now in the case where we need to fail, start_streaming must return all previously queued buffer back otherwise the vb2 framework will issue kernel WARN messages. In this case we also give an error message. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/sc.h | 6 ++++ drivers/media/platform/ti-vpe/vpe.c | 71 ++++++++++++++++++++++++++++--------- 2 files changed, 60 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h index d0aab5ef0eca..f1fe80b38c9f 100644 --- a/drivers/media/platform/ti-vpe/sc.h +++ b/drivers/media/platform/ti-vpe/sc.h @@ -173,6 +173,12 @@ /* number of taps expected by the scaler in it's coefficient memory */ #define SC_NUM_TAPS_MEM_ALIGN 8 +/* Maximum frame width the scaler can handle (in pixels) */ +#define SC_MAX_PIXEL_WIDTH 2047 + +/* Maximum frame height the scaler can handle (in lines) */ +#define SC_MAX_PIXEL_HEIGHT 2047 + /* * coefficient memory size in bytes: * num phases x num sets(luma and chroma) x num taps(aligned) x coeff size diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index ebde4f4586e6..32489d6369ca 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2025,28 +2025,33 @@ static void vpe_buf_queue(struct vb2_buffer *vb) v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); } -static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) +static int check_srcdst_sizes(struct vpe_ctx *ctx) { - struct vpe_ctx *ctx = vb2_get_drv_priv(q); + struct vpe_q_data *s_q_data = &ctx->q_data[Q_DATA_SRC]; + struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST]; + unsigned int src_w = s_q_data->c_rect.width; + unsigned int src_h = s_q_data->c_rect.height; + unsigned int dst_w = d_q_data->c_rect.width; + unsigned int dst_h = d_q_data->c_rect.height; - if (ctx->deinterlacing) - config_edi_input_mode(ctx, 0x0); + if (src_w == dst_w && src_h == dst_h) + return 0; - if (ctx->sequence != 0) - set_srcdst_params(ctx); + if (src_h <= SC_MAX_PIXEL_HEIGHT && + src_w <= SC_MAX_PIXEL_WIDTH && + dst_h <= SC_MAX_PIXEL_HEIGHT && + dst_w <= SC_MAX_PIXEL_WIDTH) + return 0; - return 0; + return -1; } -static void vpe_stop_streaming(struct vb2_queue *q) +static void vpe_return_all_buffers(struct vpe_ctx *ctx, struct vb2_queue *q, + enum vb2_buffer_state state) { - struct vpe_ctx *ctx = vb2_get_drv_priv(q); struct vb2_v4l2_buffer *vb; unsigned long flags; - vpe_dump_regs(ctx->dev); - vpdma_dump_regs(ctx->dev->vpdma); - for (;;) { if (V4L2_TYPE_IS_OUTPUT(q->type)) vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); @@ -2055,7 +2060,7 @@ static void vpe_stop_streaming(struct vb2_queue *q) if (!vb) break; spin_lock_irqsave(&ctx->dev->lock, flags); - v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(vb, state); spin_unlock_irqrestore(&ctx->dev->lock, flags); } @@ -2068,15 +2073,15 @@ static void vpe_stop_streaming(struct vb2_queue *q) spin_lock_irqsave(&ctx->dev->lock, flags); if (ctx->src_vbs[2]) - v4l2_m2m_buf_done(ctx->src_vbs[2], VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(ctx->src_vbs[2], state); if (ctx->src_vbs[1] && (ctx->src_vbs[1] != ctx->src_vbs[2])) - v4l2_m2m_buf_done(ctx->src_vbs[1], VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(ctx->src_vbs[1], state); if (ctx->src_vbs[0] && (ctx->src_vbs[0] != ctx->src_vbs[1]) && (ctx->src_vbs[0] != ctx->src_vbs[2])) - v4l2_m2m_buf_done(ctx->src_vbs[0], VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(ctx->src_vbs[0], state); ctx->src_vbs[2] = NULL; ctx->src_vbs[1] = NULL; @@ -2087,13 +2092,45 @@ static void vpe_stop_streaming(struct vb2_queue *q) if (ctx->dst_vb) { spin_lock_irqsave(&ctx->dev->lock, flags); - v4l2_m2m_buf_done(ctx->dst_vb, VB2_BUF_STATE_ERROR); + v4l2_m2m_buf_done(ctx->dst_vb, state); ctx->dst_vb = NULL; spin_unlock_irqrestore(&ctx->dev->lock, flags); } } } +static int vpe_start_streaming(struct vb2_queue *q, unsigned int count) +{ + struct vpe_ctx *ctx = vb2_get_drv_priv(q); + + /* Check any of the size exceed maximum scaling sizes */ + if (check_srcdst_sizes(ctx)) { + vpe_err(ctx->dev, + "Conversion setup failed, check source and destination parameters\n" + ); + vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_QUEUED); + return -EINVAL; + } + + if (ctx->deinterlacing) + config_edi_input_mode(ctx, 0x0); + + if (ctx->sequence != 0) + set_srcdst_params(ctx); + + return 0; +} + +static void vpe_stop_streaming(struct vb2_queue *q) +{ + struct vpe_ctx *ctx = vb2_get_drv_priv(q); + + vpe_dump_regs(ctx->dev); + vpdma_dump_regs(ctx->dev->vpdma); + + vpe_return_all_buffers(ctx, q, VB2_BUF_STATE_ERROR); +} + static const struct vb2_ops vpe_qops = { .queue_setup = vpe_queue_setup, .buf_prepare = vpe_buf_prepare, -- cgit v1.2.3 From ee1c02949d99be22485c790fe1c26aaa88e77837 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:42 -0200 Subject: [media] media: ti-vpe: vpdma: Add RAW8 and RAW16 data types Add RAW8 and RAW16 data type to VPDMA. To handle RAW format we are re-using the YUV CBY422 vpdma data type so that we use the vpdma to re-order the incoming bytes, as the VIP parser assumes that the first byte presented on the bus is the MSB of a 2 bytes value. RAW8 handles from 1 to 8 bits. RAW16 handles from 9 to 16 bits. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 23 +++++++++++++++++++++++ drivers/media/platform/ti-vpe/vpdma.h | 6 ++++++ 2 files changed, 29 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index 2d13644a28a8..c8f842fd7f75 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -191,6 +191,29 @@ const struct vpdma_data_format vpdma_rgb_fmts[] = { }; EXPORT_SYMBOL(vpdma_rgb_fmts); +/* + * To handle RAW format we are re-using the CBY422 + * vpdma data type so that we use the vpdma to re-order + * the incoming bytes, as the parser assumes that the + * first byte presented on the bus is the MSB of a 2 + * bytes value. + * RAW8 handles from 1 to 8 bits + * RAW16 handles from 9 to 16 bits + */ +const struct vpdma_data_format vpdma_raw_fmts[] = { + [VPDMA_DATA_FMT_RAW8] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CBY422, + .depth = 8, + }, + [VPDMA_DATA_FMT_RAW16] = { + .type = VPDMA_DATA_FMT_TYPE_YUV, + .data_type = DATA_TYPE_CBY422, + .depth = 16, + }, +}; +EXPORT_SYMBOL(vpdma_raw_fmts); + const struct vpdma_data_format vpdma_misc_fmts[] = { [VPDMA_DATA_FMT_MV] = { .type = VPDMA_DATA_FMT_TYPE_MISC, diff --git a/drivers/media/platform/ti-vpe/vpdma.h b/drivers/media/platform/ti-vpe/vpdma.h index 0df156b7c1cf..131700c112b2 100644 --- a/drivers/media/platform/ti-vpe/vpdma.h +++ b/drivers/media/platform/ti-vpe/vpdma.h @@ -104,12 +104,18 @@ enum vpdma_rgb_formats { VPDMA_DATA_FMT_BGRA32, }; +enum vpdma_raw_formats { + VPDMA_DATA_FMT_RAW8 = 0, + VPDMA_DATA_FMT_RAW16, +}; + enum vpdma_misc_formats { VPDMA_DATA_FMT_MV = 0, }; extern const struct vpdma_data_format vpdma_yuv_fmts[]; extern const struct vpdma_data_format vpdma_rgb_fmts[]; +extern const struct vpdma_data_format vpdma_raw_fmts[]; extern const struct vpdma_data_format vpdma_misc_fmts[]; enum vpdma_frame_start_event { -- cgit v1.2.3 From 51b56c3941410c046c28005fce7c72f02327b42d Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:43 -0200 Subject: [media] media: ti-vpe: Make colorspace converter library into its own module In preparation to add colorspace conversion support to VIP, we need to turn csc.c into its own kernel module. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 4 ++++ drivers/media/platform/ti-vpe/Makefile | 4 +++- drivers/media/platform/ti-vpe/csc.c | 16 +++++++++++++--- drivers/media/platform/ti-vpe/csc.h | 2 +- drivers/media/platform/ti-vpe/vpe.c | 2 +- 5 files changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 5d7befad90e0..60e20e5f4282 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -366,6 +366,7 @@ config VIDEO_TI_VPE select V4L2_MEM2MEM_DEV select VIDEO_TI_VPDMA select VIDEO_TI_SC + select VIDEO_TI_CSC default n ---help--- Support for the TI VPE(Video Processing Engine) block @@ -387,6 +388,9 @@ config VIDEO_TI_VPDMA config VIDEO_TI_SC tristate +config VIDEO_TI_CSC + tristate + menuconfig V4L_TEST_DRIVERS bool "Media test drivers" depends on MEDIA_CAMERA_SUPPORT diff --git a/drivers/media/platform/ti-vpe/Makefile b/drivers/media/platform/ti-vpe/Makefile index 736558d309ad..32504b724b5d 100644 --- a/drivers/media/platform/ti-vpe/Makefile +++ b/drivers/media/platform/ti-vpe/Makefile @@ -1,10 +1,12 @@ obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o obj-$(CONFIG_VIDEO_TI_VPDMA) += ti-vpdma.o obj-$(CONFIG_VIDEO_TI_SC) += ti-sc.o +obj-$(CONFIG_VIDEO_TI_CSC) += ti-csc.o -ti-vpe-y := vpe.o csc.o +ti-vpe-y := vpe.o ti-vpdma-y := vpdma.o ti-sc-y := sc.o +ti-csc-y := csc.o ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c index bec674994752..9fc6f70adeeb 100644 --- a/drivers/media/platform/ti-vpe/csc.c +++ b/drivers/media/platform/ti-vpe/csc.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -105,11 +106,13 @@ void csc_dump_regs(struct csc_data *csc) #undef DUMPREG } +EXPORT_SYMBOL(csc_dump_regs); void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5) { *csc_reg5 |= CSC_BYPASS; } +EXPORT_SYMBOL(csc_set_coeff_bypass); /* * set the color space converter coefficient shadow register values @@ -160,8 +163,9 @@ void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, for (; coeff < end_coeff; coeff += 2) *shadow_csc++ = (*(coeff + 1) << 16) | *coeff; } +EXPORT_SYMBOL(csc_set_coeff); -struct csc_data *csc_create(struct platform_device *pdev) +struct csc_data *csc_create(struct platform_device *pdev, const char *res_name) { struct csc_data *csc; @@ -176,9 +180,10 @@ struct csc_data *csc_create(struct platform_device *pdev) csc->pdev = pdev; csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "csc"); + res_name); if (csc->res == NULL) { - dev_err(&pdev->dev, "missing platform resources data\n"); + dev_err(&pdev->dev, "missing '%s' platform resources data\n", + res_name); return ERR_PTR(-ENODEV); } @@ -190,3 +195,8 @@ struct csc_data *csc_create(struct platform_device *pdev) return csc; } +EXPORT_SYMBOL(csc_create); + +MODULE_DESCRIPTION("TI VIP/VPE Color Space Converter"); +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h index 1ad2b6dad561..024700b15152 100644 --- a/drivers/media/platform/ti-vpe/csc.h +++ b/drivers/media/platform/ti-vpe/csc.h @@ -63,6 +63,6 @@ void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5); void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0, enum v4l2_colorspace src_colorspace, enum v4l2_colorspace dst_colorspace); -struct csc_data *csc_create(struct platform_device *pdev); +struct csc_data *csc_create(struct platform_device *pdev, const char *res_name); #endif diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 32489d6369ca..1e4d614bd3b6 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -2496,7 +2496,7 @@ static int vpe_probe(struct platform_device *pdev) goto runtime_put; } - dev->csc = csc_create(pdev); + dev->csc = csc_create(pdev, "csc"); if (IS_ERR(dev->csc)) { ret = PTR_ERR(dev->csc); goto runtime_put; -- cgit v1.2.3 From 3ce0f30f8eadbcabab22a41b5c8cb6af7fcdefca Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:44 -0200 Subject: [media] media: ti-vpe: csc: Add debug support for multi-instance Since there might be more then one instance it is better to show the base address when dumping registers to help with debugging. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/csc.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c index 9fc6f70adeeb..44b8465cf101 100644 --- a/drivers/media/platform/ti-vpe/csc.c +++ b/drivers/media/platform/ti-vpe/csc.c @@ -97,6 +97,8 @@ void csc_dump_regs(struct csc_data *csc) #define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \ ioread32(csc->base + CSC_##r)) + dev_dbg(dev, "CSC Registers @ %pa:\n", &csc->res->start); + DUMPREG(CSC00); DUMPREG(CSC01); DUMPREG(CSC02); -- cgit v1.2.3 From ed1f47cc69c3f230d394e001012336877d730ea2 Mon Sep 17 00:00:00 2001 From: Benoit Parrot Date: Fri, 18 Nov 2016 21:20:45 -0200 Subject: [media] media: ti-vpe: vpe: Add proper support single and multi-plane buffer The VPE was restricting the number of plane per buffer based on the fact that if a particular format had color separation it was meant to need 2 planes. However NV12/NV16 are color separate format which are meant to be presented in a single contiguous buffer/plane. It could also be presented in a multi-plane as well if need be. So we must support both modes for more flexibility. The number of plane requested by user space was previously ignored and was therefore always overwritten. The driver now use the requested num plane as hint to calculate needed offset when required. Signed-off-by: Benoit Parrot Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 58 ++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 1e4d614bd3b6..0626593a8b22 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -327,6 +327,7 @@ static struct vpe_fmt vpe_formats[] = { struct vpe_q_data { unsigned int width; /* frame width */ unsigned int height; /* frame height */ + unsigned int nplanes; /* Current number of planes */ unsigned int bytesperline[VPE_MAX_PLANES]; /* bytes per line in memory */ enum v4l2_colorspace colorspace; enum v4l2_field field; /* supported field value */ @@ -1042,6 +1043,7 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) int mv_buf_selector = !ctx->src_mv_buf_selector; dma_addr_t dma_addr; u32 flags = 0; + u32 offset = 0; if (port == VPE_PORT_MV_OUT) { vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; @@ -1052,13 +1054,27 @@ static void add_out_dtd(struct vpe_ctx *ctx, int port) int plane = fmt->coplanar ? p_data->vb_part : 0; vpdma_fmt = fmt->vpdma_fmt[plane]; - dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); + /* + * If we are using a single plane buffer and + * we need to set a separate vpdma chroma channel. + */ + if (q_data->nplanes == 1 && plane) { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + /* Compute required offset */ + offset = q_data->bytesperline[0] * q_data->height; + } else { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); + /* Use address as is, no offset */ + offset = 0; + } if (!dma_addr) { vpe_err(ctx->dev, "acquiring output buffer(%d) dma_addr failed\n", port); return; } + /* Apply the offset */ + dma_addr += offset; } if (q_data->flags & Q_DATA_FRAME_1D) @@ -1087,6 +1103,7 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) int frame_width, frame_height; dma_addr_t dma_addr; u32 flags = 0; + u32 offset = 0; if (port == VPE_PORT_MV_IN) { vpdma_fmt = &vpdma_misc_fmts[VPDMA_DATA_FMT_MV]; @@ -1096,14 +1113,27 @@ static void add_in_dtd(struct vpe_ctx *ctx, int port) int plane = fmt->coplanar ? p_data->vb_part : 0; vpdma_fmt = fmt->vpdma_fmt[plane]; - - dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); + /* + * If we are using a single plane buffer and + * we need to set a separate vpdma chroma channel. + */ + if (q_data->nplanes == 1 && plane) { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, 0); + /* Compute required offset */ + offset = q_data->bytesperline[0] * q_data->height; + } else { + dma_addr = vb2_dma_contig_plane_dma_addr(vb, plane); + /* Use address as is, no offset */ + offset = 0; + } if (!dma_addr) { vpe_err(ctx->dev, - "acquiring input buffer(%d) dma_addr failed\n", + "acquiring output buffer(%d) dma_addr failed\n", port); return; } + /* Apply the offset */ + dma_addr += offset; if (q_data->flags & Q_DATA_INTERLACED_SEQ_TB) { /* @@ -1548,7 +1578,7 @@ static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f) pix->colorspace = s_q_data->colorspace; } - pix->num_planes = q_data->fmt->coplanar ? 2 : 1; + pix->num_planes = q_data->nplanes; for (i = 0; i < pix->num_planes; i++) { pix->plane_fmt[i].bytesperline = q_data->bytesperline[i]; @@ -1604,7 +1634,11 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, &pix->height, MIN_H, MAX_H, H_ALIGN, S_ALIGN); - pix->num_planes = fmt->coplanar ? 2 : 1; + if (!pix->num_planes) + pix->num_planes = fmt->coplanar ? 2 : 1; + else if (pix->num_planes > 1 && !fmt->coplanar) + pix->num_planes = 1; + pix->pixelformat = fmt->fourcc; /* @@ -1640,6 +1674,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, else plane_fmt->bytesperline = pix->width; + if (pix->num_planes == 1 && fmt->coplanar) + depth += fmt->vpdma_fmt[VPE_CHROMA]->depth; plane_fmt->sizeimage = (pix->height * pix->width * depth) >> 3; @@ -1686,6 +1722,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) q_data->height = pix->height; q_data->colorspace = pix->colorspace; q_data->field = pix->field; + q_data->nplanes = pix->num_planes; for (i = 0; i < pix->num_planes; i++) { plane_fmt = &pix->plane_fmt[i]; @@ -1713,7 +1750,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f) vpe_dbg(ctx->dev, "Setting format for type %d, wxh: %dx%d, fmt: %d bpl_y %d", f->type, q_data->width, q_data->height, q_data->fmt->fourcc, q_data->bytesperline[VPE_LUMA]); - if (q_data->fmt->coplanar) + if (q_data->nplanes == 2) vpe_dbg(ctx->dev, " bpl_uv %d\n", q_data->bytesperline[VPE_CHROMA]); @@ -1965,14 +2002,14 @@ static int vpe_queue_setup(struct vb2_queue *vq, q_data = get_q_data(ctx, vq->type); - *nplanes = q_data->fmt->coplanar ? 2 : 1; + *nplanes = q_data->nplanes; for (i = 0; i < *nplanes; i++) sizes[i] = q_data->sizeimage[i]; vpe_dbg(ctx->dev, "get %d buffer(s) of size %d", *nbuffers, sizes[VPE_LUMA]); - if (q_data->fmt->coplanar) + if (q_data->nplanes == 2) vpe_dbg(ctx->dev, " and %d\n", sizes[VPE_CHROMA]); return 0; @@ -1988,7 +2025,7 @@ static int vpe_buf_prepare(struct vb2_buffer *vb) vpe_dbg(ctx->dev, "type: %d\n", vb->vb2_queue->type); q_data = get_q_data(ctx, vb->vb2_queue->type); - num_planes = q_data->fmt->coplanar ? 2 : 1; + num_planes = q_data->nplanes; if (vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { if (!(q_data->flags & Q_IS_INTERLACED)) { @@ -2248,6 +2285,7 @@ static int vpe_open(struct file *file) s_q_data->fmt = &vpe_formats[2]; s_q_data->width = 1920; s_q_data->height = 1080; + s_q_data->nplanes = 1; s_q_data->bytesperline[VPE_LUMA] = (s_q_data->width * s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3; s_q_data->sizeimage[VPE_LUMA] = (s_q_data->bytesperline[VPE_LUMA] * -- cgit v1.2.3 From 1827bdc7b141859a1eb9d2d45bb923ea7252774a Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Mon, 21 Nov 2016 11:59:20 -0200 Subject: [media] vpfe_capture: fix compiler warning davinci/vpfe_capture.c: In function 'vpfe_probe': davinci/vpfe_capture.c:1992:9: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized] return ret; ^~~ This is indeed correct, so if the kmalloc fails set ret to -ENOMEM. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index 6c41782b3ba0..bc2c62b95493 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1847,8 +1847,10 @@ static int vpfe_probe(struct platform_device *pdev) /* Allocate memory for ccdc configuration */ ccdc_cfg = kmalloc(sizeof(*ccdc_cfg), GFP_KERNEL); - if (!ccdc_cfg) + if (!ccdc_cfg) { + ret = -ENOMEM; goto probe_free_dev_mem; + } mutex_lock(&ccdc_lock); -- cgit v1.2.3 From 427da406bcaf4f51b561ed19de89f2401df85d05 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Nov 2016 08:15:15 -0200 Subject: [media] vpdma: remove vpdma_enable_list_notify_irq() Despite being exported, there's no prototype for it at the headers, as warned by sparse: Fixes this sparse warning: drivers/media/platform/ti-vpe/vpdma.c:1000:6: warning: no previous prototype for 'vpdma_enable_list_notify_irq' [-Wmissing-prototypes] void vpdma_enable_list_notify_irq(struct vpdma_data *vpdma, int irq_num, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ Worse than that, it is not even used, as making it static it would produce: drivers/media/platform/ti-vpe/vpdma.c:1000:13: warning: 'vpdma_enable_list_notify_irq' defined but not used [-Wunused-function] static void vpdma_enable_list_notify_irq(struct vpdma_data *vpdma, int irq_num, ^~~~~~~~~~~~~~~~~~~~~~~~~~~~ So, let's just get rid of the dead code. If needed in the future, someone could re-add it. Cc: Benoit Parrot Cc: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpdma.c | 16 ---------------- 1 file changed, 16 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpdma.c b/drivers/media/platform/ti-vpe/vpdma.c index c8f842fd7f75..13bfd7184160 100644 --- a/drivers/media/platform/ti-vpe/vpdma.c +++ b/drivers/media/platform/ti-vpe/vpdma.c @@ -996,22 +996,6 @@ void vpdma_enable_list_complete_irq(struct vpdma_data *vpdma, int irq_num, } EXPORT_SYMBOL(vpdma_enable_list_complete_irq); -/* set or clear the mask for list complete interrupt */ -void vpdma_enable_list_notify_irq(struct vpdma_data *vpdma, int irq_num, - int list_num, bool enable) -{ - u32 reg_addr = VPDMA_INT_LIST0_MASK + VPDMA_INTX_OFFSET * irq_num; - u32 val; - - val = read_reg(vpdma, reg_addr); - if (enable) - val |= (1 << ((list_num * 2) + 1)); - else - val &= ~(1 << ((list_num * 2) + 1)); - write_reg(vpdma, reg_addr, val); -} -EXPORT_SYMBOL(vpdma_enable_list_notify_irq); - /* get the LIST_STAT register */ unsigned int vpdma_get_list_stat(struct vpdma_data *vpdma, int irq_num) { -- cgit v1.2.3 From af93189d4ebc7851eb387145d0ea8db52698308e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 22 Nov 2016 09:05:59 -0200 Subject: [media] ti-vpe: get rid of some smatch warnings When compiled on i386, it produces several warnings: ./arch/x86/include/asm/bitops.h:457:22: warning: asm output is not an lvalue ./arch/x86/include/asm/bitops.h:457:22: warning: asm output is not an lvalue ./arch/x86/include/asm/bitops.h:457:22: warning: asm output is not an lvalue ./arch/x86/include/asm/bitops.h:457:22: warning: asm output is not an lvalue ./arch/x86/include/asm/bitops.h:457:22: warning: asm output is not an lvalue ./arch/x86/include/asm/bitops.h:457:22: warning: asm output is not an lvalue I suspect that some gcc optimization could be causing the asm code to be incorrectly generated. Splitting it into two macro calls fix the issues and gets us rid of 6 smatch warnings, with is a good thing. As it should not cause any troubles, as we're basically doing the same thing, let's apply such change to vpe.c. Cc: Benoit Parrot Cc: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/ti-vpe/vpe.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c index 0626593a8b22..f0156b7759e9 100644 --- a/drivers/media/platform/ti-vpe/vpe.c +++ b/drivers/media/platform/ti-vpe/vpe.c @@ -1615,20 +1615,32 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f, */ depth_bytes = depth >> 3; - if (depth_bytes == 3) + if (depth_bytes == 3) { /* * if bpp is 3(as in some RGB formats), the pixel width doesn't * really help in ensuring line stride is 16 byte aligned */ w_align = 4; - else + } else { /* * for the remainder bpp(4, 2 and 1), the pixel width alignment * can ensure a line stride alignment of 16 bytes. For example, * if bpp is 2, then the line stride can be 16 byte aligned if * the width is 8 byte aligned */ - w_align = order_base_2(VPDMA_DESC_ALIGN / depth_bytes); + + /* + * HACK: using order_base_2() here causes lots of asm output + * errors with smatch, on i386: + * ./arch/x86/include/asm/bitops.h:457:22: + * warning: asm output is not an lvalue + * Perhaps some gcc optimization is doing the wrong thing + * there. + * Let's get rid of them by doing the calculus on two steps + */ + w_align = roundup_pow_of_two(VPDMA_DESC_ALIGN / depth_bytes); + w_align = ilog2(w_align); + } v4l_bound_align_image(&pix->width, MIN_W, MAX_W, w_align, &pix->height, MIN_H, MAX_H, H_ALIGN, -- cgit v1.2.3 From 9388093db44356af911adf3d355b7544a13a63cd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 22 Nov 2016 12:33:11 +0100 Subject: ARM: 8631/1: clkdev: Detect errors in clk_hw_register_clkdev() for mass registration Unlike clk_register_clkdev(), clk_hw_register_clkdev() doesn't check for passed error objects from a previous registration call. Hence the caller of clk_hw_register_*() has to check for errors before calling clk_hw_register_clkdev*(). Make clk_hw_register_clkdev() more similar to clk_register_clkdev() by adding this error check, removing the burden from callers that do mass registration. Fixes: e4f1b49bda6d6aa2 ("clkdev: Add clk_hw based registration APIs") Fixes: 944b9a41e004534f ("clk: ls1x: Migrate to clk_hw based OF and registration APIs") Fixes: 44ce9a9ae977736f ("MIPS: TXx9: Convert to Common Clock Framework") Fixes: f48d947a162dfa9d ("clk: clps711x: Migrate to clk_hw based OF and registration APIs") Fixes: b4626a7f489238a5 ("CLK: Add Loongson1C clock support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Russell King --- drivers/clk/clkdev.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 97ae60fa1584..bb8a77a5985f 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -448,12 +448,20 @@ EXPORT_SYMBOL(clk_register_clkdev); * * con_id or dev_id may be NULL as a wildcard, just as in the rest of * clkdev. + * + * To make things easier for mass registration, we detect error clk_hws + * from a previous clk_hw_register_*() call, and return the error code for + * those. This is to permit this function to be called immediately + * after clk_hw_register_*(). */ int clk_hw_register_clkdev(struct clk_hw *hw, const char *con_id, const char *dev_id) { struct clk_lookup *cl; + if (IS_ERR(hw)) + return PTR_ERR(hw); + /* * Since dev_id can be NULL, and NULL is handled specially, we must * pass it as either a NULL format string, or with "%s". -- cgit v1.2.3 From a56bc171598c788fd43168b5c81df8ac3c7fbde4 Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Tue, 8 Nov 2016 14:06:44 -0200 Subject: [media] v4l: compat: Prevent allocating excessive amounts of memory get_v4l2_ext_controls32() is used to convert the 32-bit compat struct into native 64-bit representation. The function multiplies the array length by the entry length before validating size. Perform the size validation first. Also use unsigned values for size computation. Make similar changes to get_v4l2_buffer32() for multi-plane buffers. Signed-off-by: Sakari Ailus Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-compat-ioctl32.c | 30 +++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c index bacecbd68a6d..eac9565dc3d8 100644 --- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c +++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c @@ -409,7 +409,6 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user struct v4l2_plane32 __user *uplane32; struct v4l2_plane __user *uplane; compat_caddr_t p; - int num_planes; int ret; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) || @@ -429,12 +428,15 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user return -EFAULT; if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) { - num_planes = kp->length; - if (num_planes == 0) { + unsigned int num_planes; + + if (kp->length == 0) { kp->m.planes = NULL; /* num_planes == 0 is legal, e.g. when userspace doesn't * need planes array on DQBUF*/ return 0; + } else if (kp->length > VIDEO_MAX_PLANES) { + return -EINVAL; } if (get_user(p, &up->m.planes)) @@ -442,16 +444,16 @@ static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user uplane32 = compat_ptr(p); if (!access_ok(VERIFY_READ, uplane32, - num_planes * sizeof(struct v4l2_plane32))) + kp->length * sizeof(struct v4l2_plane32))) return -EFAULT; /* We don't really care if userspace decides to kill itself * by passing a very big num_planes value */ - uplane = compat_alloc_user_space(num_planes * - sizeof(struct v4l2_plane)); + uplane = compat_alloc_user_space(kp->length * + sizeof(struct v4l2_plane)); kp->m.planes = (__force struct v4l2_plane *)uplane; - while (--num_planes >= 0) { + for (num_planes = 0; num_planes < kp->length; num_planes++) { ret = get_v4l2_plane32(uplane, uplane32, kp->memory); if (ret) return ret; @@ -665,7 +667,7 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext { struct v4l2_ext_control32 __user *ucontrols; struct v4l2_ext_control __user *kcontrols; - int n; + unsigned int n; compat_caddr_t p; if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) || @@ -675,20 +677,22 @@ static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved))) return -EFAULT; - n = kp->count; - if (n == 0) { + if (kp->count == 0) { kp->controls = NULL; return 0; + } else if (kp->count > V4L2_CID_MAX_CTRLS) { + return -EINVAL; } if (get_user(p, &up->controls)) return -EFAULT; ucontrols = compat_ptr(p); if (!access_ok(VERIFY_READ, ucontrols, - n * sizeof(struct v4l2_ext_control32))) + kp->count * sizeof(struct v4l2_ext_control32))) return -EFAULT; - kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control)); + kcontrols = compat_alloc_user_space(kp->count * + sizeof(struct v4l2_ext_control)); kp->controls = (__force struct v4l2_ext_control *)kcontrols; - while (--n >= 0) { + for (n = 0; n < kp->count; n++) { u32 id; if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols))) -- cgit v1.2.3 From 2bfc04d64db66fa62021a988740e8028f018b9c3 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 9 Nov 2016 14:13:34 -0200 Subject: [media] sanyo decoder: address was being truncated The address is 13 bits but it was stuffed in an u8, so 5 bits are missing from the scancode. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/ir-sanyo-decoder.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c index 7331e5e7c497..b07d9caebeb1 100644 --- a/drivers/media/rc/ir-sanyo-decoder.c +++ b/drivers/media/rc/ir-sanyo-decoder.c @@ -56,7 +56,8 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev) { struct sanyo_dec *data = &dev->raw->sanyo; u32 scancode; - u8 address, command, not_command; + u16 address; + u8 command, not_command; if (!is_timing_event(ev)) { if (ev.reset) { -- cgit v1.2.3 From 30f88a42b65858d777b8dfb40bb222fa31d5f0d9 Mon Sep 17 00:00:00 2001 From: Shailendra Verma Date: Thu, 10 Nov 2016 07:52:38 -0200 Subject: [media] staging: lirc: Improvement in code readability There is no need to call kfree() if memdup_user() fails, as no memory was allocated and the error in the error-valued pointer should be returned. Signed-off-by: Shailendra Verma Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/lirc/lirc_imon.c | 5 ++--- drivers/staging/media/lirc/lirc_sasem.c | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c index 00e00b0be275..1e650fba4a92 100644 --- a/drivers/staging/media/lirc/lirc_imon.c +++ b/drivers/staging/media/lirc/lirc_imon.c @@ -408,9 +408,8 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, data_buf = memdup_user(buf, n_bytes); if (IS_ERR(data_buf)) { - retval = PTR_ERR(data_buf); - data_buf = NULL; - goto exit; + mutex_unlock(&context->ctx_lock); + return PTR_ERR(data_buf); } memcpy(context->tx.data_buf, data_buf, n_bytes); diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c index 4678ae10b030..4fd810bc46de 100644 --- a/drivers/staging/media/lirc/lirc_sasem.c +++ b/drivers/staging/media/lirc/lirc_sasem.c @@ -384,9 +384,8 @@ static ssize_t vfd_write(struct file *file, const char __user *buf, data_buf = memdup_user(buf, n_bytes); if (IS_ERR(data_buf)) { - retval = PTR_ERR(data_buf); - data_buf = NULL; - goto exit; + mutex_unlock(&context->ctx_lock); + return PTR_ERR(data_buf); } memcpy(context->tx.data_buf, data_buf, n_bytes); -- cgit v1.2.3 From 61393b0732fadc1efb2682c92062a54ff9f8fe0b Mon Sep 17 00:00:00 2001 From: Martin Blumenstingl Date: Sat, 24 Sep 2016 19:40:19 -0300 Subject: [media] mn88473: add DVBv5 statistics support Implement DVBv5 statistics support for DVB-T, DVB-T2 and DVB-C. All information was taken from the LinuxTV wiki, where Benjamin Larsson has documented all registers: https://www.linuxtv.org/wiki/index.php/Panasonic_MN88472 Signed-off-by: Martin Blumenstingl Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mn88473.c | 485 ++++++++++++++++++++++++++--- drivers/media/dvb-frontends/mn88473_priv.h | 1 + 2 files changed, 445 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index 451974a1d7ed..c8dc9d381201 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c @@ -234,13 +234,388 @@ err: return ret; } +static int mn88473_update_ber_stat_t_c(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct i2c_client *client = fe->demodulator_priv; + struct mn88473_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u64 total; + unsigned int uitmp, value, errors; + + if (*status & FE_HAS_LOCK) { + ret = regmap_read(dev->regmap[0], 0x5b, &value); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[0], 0xdf, &uitmp); + if (ret) + goto err; + + value &= uitmp; + ret = regmap_write(dev->regmap[0], 0x5b, value); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[0], 0x60, &value); + if (ret) + goto err; + + value &= 0xf0; + value |= 0x5; + ret = regmap_write(dev->regmap[0], 0x60, value); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[0], 0x92, &uitmp); + if (ret) + goto err; + + errors = uitmp << 16; + + ret = regmap_read(dev->regmap[0], 0x93, &uitmp); + if (ret) + goto err; + + errors |= uitmp << 8; + + ret = regmap_read(dev->regmap[0], 0x94, &uitmp); + if (ret) + goto err; + + errors |= uitmp; + + ret = regmap_read(dev->regmap[0], 0x95, &uitmp); + if (ret) + goto err; + + total = uitmp << 8; + + ret = regmap_read(dev->regmap[0], 0x96, &uitmp); + if (ret) + goto err; + + total |= uitmp; + + /* probably: (bytes -> bit) * (sizeof(TS packet) - 1) */ + total *= 8 * 203; + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += errors; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += total; + } else { + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + return 0; + +err: + dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); + return ret; +} + +static int mn88473_update_ber_stat_t2(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct i2c_client *client = fe->demodulator_priv; + struct mn88473_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + u64 total; + unsigned int uitmp, value, berlen, fec_type_m, errors; + static u16 fec_type_m_tbl0[] = { + 32400, 38880, 43200, 48600, 51840, 54000, 0 + }; + static u16 fec_type_m_tbl1[] = { + 28800, 38880, 43200, 47520, 50400, 53280, 0 + }; + + if (*status & FE_HAS_LOCK) { + ret = regmap_read(dev->regmap[2], 0x82, &value); + if (ret) + goto err; + + value |= 0x20; + value &= 0xef; + ret = regmap_write(dev->regmap[2], 0x82, value); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[2], 0xba, &uitmp); + if (ret) + goto err; + + errors = uitmp << 16; + + ret = regmap_read(dev->regmap[2], 0xbb, &uitmp); + if (ret) + goto err; + + errors |= uitmp << 8; + + ret = regmap_read(dev->regmap[2], 0xbc, &uitmp); + if (ret) + goto err; + + errors |= uitmp; + + ret = regmap_read(dev->regmap[2], 0x83, &berlen); + if (ret) + goto err; + + ret = regmap_write(dev->regmap[2], 0xc0, 0x3); + if (ret) + goto err; + + /* berlen[4:2] are the index in fec_type_m_tbl */ + uitmp = (berlen >> 2) & 0x7; + + if (BIT(0) & berlen) + fec_type_m = fec_type_m_tbl0[uitmp]; + else + fec_type_m = fec_type_m_tbl1[uitmp]; + + total = ((berlen & 0xff) << 1) * fec_type_m; + + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += errors; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += total; + } else { + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + return 0; + +err: + dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); + return ret; +} + +static inline u32 log10times1000(u32 value) +{ + return (1000L * intlog10(value)) >> 24; +} + +static int mn88473_read_status_t(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct i2c_client *client = fe->demodulator_priv; + struct mn88473_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + s32 cnr; + unsigned int uitmp, tmp_upper, tmp_lower; + + ret = regmap_read(dev->regmap[0], 0x62, &uitmp); + if (ret) + goto err; + + if (!(uitmp & 0xa0)) { + if ((uitmp & 0x0f) >= 0x09) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + else if ((uitmp & 0x0f) >= 0x03) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + } + + /* CNR */ + if (*status & FE_HAS_VITERBI) { + ret = regmap_read(dev->regmap[0], 0x8f, &tmp_upper); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[0], 0x90, &tmp_lower); + if (ret) + goto err; + + uitmp = (tmp_upper << 8) | tmp_lower; + if (uitmp) { + cnr = log10times1000(65536); + cnr -= log10times1000(uitmp); + cnr += 200; + } else + cnr = 0; + + if (cnr < 0) + cnr = 0; + + c->cnr.stat[0].svalue = cnr * 10; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + ret = mn88473_update_ber_stat_t_c(fe, status); + if (ret) + goto err; + + return 0; + +err: + dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); + return ret; +} + +static int mn88473_read_status_t2(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct i2c_client *client = fe->demodulator_priv; + struct mn88473_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + s32 cnr; + unsigned int uitmp, tmp_upper, tmp_lower, flag; + + ret = regmap_read(dev->regmap[2], 0x8b, &uitmp); + if (ret) + goto err; + + if (!(uitmp & 0x40)) { + if ((uitmp & 0x0f) >= 0x0d) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + else if ((uitmp & 0x0f) >= 0x0a) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + else if ((uitmp & 0x0f) >= 0x07) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + } + + /* CNR */ + if (*status & FE_HAS_VITERBI) { + ret = regmap_read(dev->regmap[2], 0xb7, &flag); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[2], 0xb8, &tmp_upper); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[2], 0xb9, &tmp_lower); + if (ret) + goto err; + + uitmp = (tmp_upper << 8) | tmp_lower; + if (uitmp) { + if (flag & BIT(2)) { + /* MISO */ + cnr = log10times1000(16384); + cnr -= log10times1000(uitmp); + cnr -= 600; + } else { + /* SISO */ + cnr = log10times1000(65536); + cnr -= log10times1000(uitmp); + cnr += 200; + } + } else + cnr = 0; + + if (cnr < 0) + cnr = 0; + + c->cnr.stat[0].svalue = cnr * 10; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + ret = mn88473_update_ber_stat_t2(fe, status); + if (ret) + goto err; + + return 0; + +err: + dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); + return ret; +} + +static int mn88473_read_status_c(struct dvb_frontend *fe, + enum fe_status *status) +{ + struct i2c_client *client = fe->demodulator_priv; + struct mn88473_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + int ret; + unsigned int uitmp, tmp_upper, tmp_lower, signal, noise; + + ret = regmap_read(dev->regmap[1], 0x85, &uitmp); + if (ret) + goto err; + + if (!(uitmp & 0x40)) { + ret = regmap_read(dev->regmap[1], 0x89, &uitmp); + if (ret) + goto err; + + if (uitmp & 0x01) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + } + + /* CNR */ + if (*status & FE_HAS_VITERBI) { + ret = regmap_read(dev->regmap[1], 0xa1, &tmp_upper); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[1], 0xa2, &tmp_lower); + if (ret) + goto err; + + signal = (tmp_upper << 8) | tmp_lower; + + ret = regmap_read(dev->regmap[1], 0xa3, &tmp_upper); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[1], 0xa4, &tmp_lower); + if (ret) + goto err; + + noise = (tmp_upper << 8) | tmp_lower; + if (noise) + uitmp = log10times1000(signal * 8 / noise); + else + uitmp = 0; + + c->cnr.stat[0].svalue = uitmp * 10; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + } else { + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* BER */ + ret = mn88473_update_ber_stat_t_c(fe, status); + if (ret) + goto err; + + return 0; + +err: + dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); + return ret; +} + static int mn88473_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct i2c_client *client = fe->demodulator_priv; struct mn88473_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret; - unsigned int uitmp; + u16 errors, per_len; + unsigned int upper, lower; if (!dev->active) { ret = -EAGAIN; @@ -251,60 +626,73 @@ static int mn88473_read_status(struct dvb_frontend *fe, enum fe_status *status) switch (c->delivery_system) { case SYS_DVBT: - ret = regmap_read(dev->regmap[0], 0x62, &uitmp); + ret = mn88473_read_status_t(fe, status); + break; + case SYS_DVBT2: + ret = mn88473_read_status_t2(fe, status); + break; + case SYS_DVBC_ANNEX_A: + ret = mn88473_read_status_c(fe, status); + break; + default: + ret = -EINVAL; + break; + } + + if (ret) + goto err; + + /* signal strength, derived from AGC */ + if (*status & FE_HAS_SIGNAL) { + ret = regmap_read(dev->regmap[2], 0x86, &upper); if (ret) goto err; - if (!(uitmp & 0xa0)) { - if ((uitmp & 0x0f) >= 0x09) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - else if ((uitmp & 0x0f) >= 0x03) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - } - break; - case SYS_DVBT2: - ret = regmap_read(dev->regmap[2], 0x8b, &uitmp); + ret = regmap_read(dev->regmap[2], 0x87, &lower); if (ret) goto err; - if (!(uitmp & 0x40)) { - if ((uitmp & 0x0f) >= 0x0d) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - else if ((uitmp & 0x0f) >= 0x0a) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI; - else if ((uitmp & 0x0f) >= 0x07) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; - } - break; - case SYS_DVBC_ANNEX_A: - ret = regmap_read(dev->regmap[1], 0x85, &uitmp); + /* AGCRD[15:6] gives us a 10bit value ([5:0] are always 0) */ + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = (upper << 8) | lower; + } else { + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + } + + /* PER */ + if (*status & FE_HAS_LOCK) { + ret = regmap_read(dev->regmap[0], 0xdd, &upper); if (ret) goto err; - if (!(uitmp & 0x40)) { - ret = regmap_read(dev->regmap[1], 0x89, &uitmp); - if (ret) - goto err; + ret = regmap_read(dev->regmap[0], 0xde, &lower); + if (ret) + goto err; - if (uitmp & 0x01) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - } - break; - default: - ret = -EINVAL; - goto err; + errors = (upper << 8) | lower; + + ret = regmap_read(dev->regmap[0], 0xdf, &upper); + if (ret) + goto err; + + ret = regmap_read(dev->regmap[0], 0xe0, &lower); + if (ret) + goto err; + + per_len = (upper << 8) | lower; + + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].uvalue += errors; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].uvalue += per_len; + } else { + c->block_error.stat[0].scale = FE_SCALE_COUNTER; + c->block_count.stat[0].scale = FE_SCALE_COUNTER; } return 0; err: - dev_dbg(&client->dev, "failed=%d\n", ret); + dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); return ret; } @@ -312,6 +700,7 @@ static int mn88473_init(struct dvb_frontend *fe) { struct i2c_client *client = fe->demodulator_priv; struct mn88473_dev *dev = i2c_get_clientdata(client); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; int ret, len, remain; unsigned int uitmp; const struct firmware *fw; @@ -378,6 +767,20 @@ warm: dev->active = true; + /* init stats here to indicate which stats are supported */ + c->strength.len = 1; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->cnr.len = 1; + c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.len = 1; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.len = 1; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_error.len = 1; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.len = 1; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + return 0; err_release_firmware: release_firmware(fw); diff --git a/drivers/media/dvb-frontends/mn88473_priv.h b/drivers/media/dvb-frontends/mn88473_priv.h index e6c65893e451..7cbef7b7fb39 100644 --- a/drivers/media/dvb-frontends/mn88473_priv.h +++ b/drivers/media/dvb-frontends/mn88473_priv.h @@ -18,6 +18,7 @@ #define MN88473_PRIV_H #include "dvb_frontend.h" +#include "dvb_math.h" #include "mn88473.h" #include #include -- cgit v1.2.3 From 69ace6ee3e3d088c6c8bd4aab42001fc6ba9d701 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Sun, 13 Nov 2016 05:25:54 -0200 Subject: [media] mn88473: refactor and fix statistics Remove DVB-T2 BER as it does not work at all and I didn't find how to fix. Fix DVB-T and DVB-C BER. It seems to return new some realistic looking values. Use (1 << 24) base for CNR calculations to keep it in line with dvb logarithm functions. Move all statistic logic to mn88473_read_status() function. Use regmap_bulk_read() for reading multiple registers as a one go. Many more and less minor changes. Cc: Martin Blumenstingl Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mn88473.c | 560 +++++++++-------------------- drivers/media/dvb-frontends/mn88473_priv.h | 1 + 2 files changed, 161 insertions(+), 400 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index c8dc9d381201..f3b59a5827d9 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c @@ -234,465 +234,225 @@ err: return ret; } -static int mn88473_update_ber_stat_t_c(struct dvb_frontend *fe, - enum fe_status *status) +static int mn88473_read_status(struct dvb_frontend *fe, enum fe_status *status) { struct i2c_client *client = fe->demodulator_priv; struct mn88473_dev *dev = i2c_get_clientdata(client); struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - u64 total; - unsigned int uitmp, value, errors; - - if (*status & FE_HAS_LOCK) { - ret = regmap_read(dev->regmap[0], 0x5b, &value); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[0], 0xdf, &uitmp); - if (ret) - goto err; - - value &= uitmp; - ret = regmap_write(dev->regmap[0], 0x5b, value); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[0], 0x60, &value); - if (ret) - goto err; - - value &= 0xf0; - value |= 0x5; - ret = regmap_write(dev->regmap[0], 0x60, value); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[0], 0x92, &uitmp); - if (ret) - goto err; - - errors = uitmp << 16; - - ret = regmap_read(dev->regmap[0], 0x93, &uitmp); - if (ret) - goto err; - - errors |= uitmp << 8; - - ret = regmap_read(dev->regmap[0], 0x94, &uitmp); - if (ret) - goto err; - - errors |= uitmp; - - ret = regmap_read(dev->regmap[0], 0x95, &uitmp); - if (ret) - goto err; - - total = uitmp << 8; + int ret, i, stmp; + unsigned int utmp, utmp1, utmp2; + u8 buf[5]; - ret = regmap_read(dev->regmap[0], 0x96, &uitmp); - if (ret) - goto err; - - total |= uitmp; - - /* probably: (bytes -> bit) * (sizeof(TS packet) - 1) */ - total *= 8 * 203; - - c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue += errors; - c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[0].uvalue += total; - } else { - c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + if (!dev->active) { + ret = -EAGAIN; + goto err; } - return 0; - -err: - dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); - return ret; -} - -static int mn88473_update_ber_stat_t2(struct dvb_frontend *fe, - enum fe_status *status) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88473_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - u64 total; - unsigned int uitmp, value, berlen, fec_type_m, errors; - static u16 fec_type_m_tbl0[] = { - 32400, 38880, 43200, 48600, 51840, 54000, 0 - }; - static u16 fec_type_m_tbl1[] = { - 28800, 38880, 43200, 47520, 50400, 53280, 0 - }; - - if (*status & FE_HAS_LOCK) { - ret = regmap_read(dev->regmap[2], 0x82, &value); - if (ret) - goto err; - - value |= 0x20; - value &= 0xef; - ret = regmap_write(dev->regmap[2], 0x82, value); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[2], 0xba, &uitmp); - if (ret) - goto err; - - errors = uitmp << 16; - - ret = regmap_read(dev->regmap[2], 0xbb, &uitmp); - if (ret) - goto err; - - errors |= uitmp << 8; - - ret = regmap_read(dev->regmap[2], 0xbc, &uitmp); - if (ret) - goto err; - - errors |= uitmp; - - ret = regmap_read(dev->regmap[2], 0x83, &berlen); + /* Lock detection */ + switch (c->delivery_system) { + case SYS_DVBT: + ret = regmap_read(dev->regmap[0], 0x62, &utmp); if (ret) goto err; - ret = regmap_write(dev->regmap[2], 0xc0, 0x3); + if (!(utmp & 0xa0)) { + if ((utmp & 0x0f) >= 0x09) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + else if ((utmp & 0x0f) >= 0x03) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + } else { + *status = 0; + } + break; + case SYS_DVBT2: + ret = regmap_read(dev->regmap[2], 0x8b, &utmp); + if (ret) + goto err; + + if (!(utmp & 0x40)) { + if ((utmp & 0x0f) >= 0x0d) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + else if ((utmp & 0x0f) >= 0x0a) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI; + else if ((utmp & 0x0f) >= 0x07) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + } else { + *status = 0; + } + break; + case SYS_DVBC_ANNEX_A: + ret = regmap_read(dev->regmap[1], 0x85, &utmp); if (ret) goto err; - /* berlen[4:2] are the index in fec_type_m_tbl */ - uitmp = (berlen >> 2) & 0x7; - - if (BIT(0) & berlen) - fec_type_m = fec_type_m_tbl0[uitmp]; - else - fec_type_m = fec_type_m_tbl1[uitmp]; - - total = ((berlen & 0xff) << 1) * fec_type_m; - - c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_error.stat[0].uvalue += errors; - c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; - c->post_bit_count.stat[0].uvalue += total; - } else { - c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - } - - return 0; - -err: - dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); - return ret; -} - -static inline u32 log10times1000(u32 value) -{ - return (1000L * intlog10(value)) >> 24; -} - -static int mn88473_read_status_t(struct dvb_frontend *fe, - enum fe_status *status) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88473_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - s32 cnr; - unsigned int uitmp, tmp_upper, tmp_lower; + if (!(utmp & 0x40)) { + ret = regmap_read(dev->regmap[1], 0x89, &utmp); + if (ret) + goto err; - ret = regmap_read(dev->regmap[0], 0x62, &uitmp); - if (ret) + if (utmp & 0x01) + *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | + FE_HAS_VITERBI | FE_HAS_SYNC | + FE_HAS_LOCK; + } else { + *status = 0; + } + break; + default: + ret = -EINVAL; goto err; - - if (!(uitmp & 0xa0)) { - if ((uitmp & 0x0f) >= 0x09) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - else if ((uitmp & 0x0f) >= 0x03) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; } - /* CNR */ - if (*status & FE_HAS_VITERBI) { - ret = regmap_read(dev->regmap[0], 0x8f, &tmp_upper); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[0], 0x90, &tmp_lower); - if (ret) - goto err; - - uitmp = (tmp_upper << 8) | tmp_lower; - if (uitmp) { - cnr = log10times1000(65536); - cnr -= log10times1000(uitmp); - cnr += 200; - } else - cnr = 0; + /* Signal strength */ + if (*status & FE_HAS_SIGNAL) { + for (i = 0; i < 2; i++) { + ret = regmap_bulk_read(dev->regmap[2], 0x86 + i, + &buf[i], 1); + if (ret) + goto err; + } - if (cnr < 0) - cnr = 0; + /* AGCRD[15:6] gives us a 10bit value ([5:0] are always 0) */ + utmp1 = buf[0] << 8 | buf[1] << 0 | buf[0] >> 2; + dev_dbg(&client->dev, "strength=%u\n", utmp1); - c->cnr.stat[0].svalue = cnr * 10; - c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + c->strength.stat[0].scale = FE_SCALE_RELATIVE; + c->strength.stat[0].uvalue = utmp1; } else { - c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - } - - /* BER */ - ret = mn88473_update_ber_stat_t_c(fe, status); - if (ret) - goto err; - - return 0; - -err: - dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); - return ret; -} - -static int mn88473_read_status_t2(struct dvb_frontend *fe, - enum fe_status *status) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88473_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - s32 cnr; - unsigned int uitmp, tmp_upper, tmp_lower, flag; - - ret = regmap_read(dev->regmap[2], 0x8b, &uitmp); - if (ret) - goto err; - - if (!(uitmp & 0x40)) { - if ((uitmp & 0x0f) >= 0x0d) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - else if ((uitmp & 0x0f) >= 0x0a) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI; - else if ((uitmp & 0x0f) >= 0x07) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; + c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } /* CNR */ - if (*status & FE_HAS_VITERBI) { - ret = regmap_read(dev->regmap[2], 0xb7, &flag); + if (*status & FE_HAS_VITERBI && c->delivery_system == SYS_DVBT) { + /* DVB-T CNR */ + ret = regmap_bulk_read(dev->regmap[0], 0x8f, buf, 2); if (ret) goto err; - ret = regmap_read(dev->regmap[2], 0xb8, &tmp_upper); - if (ret) - goto err; + utmp = buf[0] << 8 | buf[1] << 0; + if (utmp) { + /* CNR[dB]: 10 * (log10(65536 / value) + 0.2) */ + /* log10(65536) = 80807124, 0.2 = 3355443 */ + stmp = div_u64(((u64)80807124 - intlog10(utmp) + + 3355443) * 10000, 1 << 24); + dev_dbg(&client->dev, "cnr=%d value=%u\n", stmp, utmp); + } else { + stmp = 0; + } - ret = regmap_read(dev->regmap[2], 0xb9, &tmp_lower); - if (ret) - goto err; + c->cnr.stat[0].svalue = stmp; + c->cnr.stat[0].scale = FE_SCALE_DECIBEL; + } else if (*status & FE_HAS_VITERBI && + c->delivery_system == SYS_DVBT2) { + /* DVB-T2 CNR */ + for (i = 0; i < 3; i++) { + ret = regmap_bulk_read(dev->regmap[2], 0xb7 + i, + &buf[i], 1); + if (ret) + goto err; + } - uitmp = (tmp_upper << 8) | tmp_lower; - if (uitmp) { - if (flag & BIT(2)) { - /* MISO */ - cnr = log10times1000(16384); - cnr -= log10times1000(uitmp); - cnr -= 600; + utmp = buf[1] << 8 | buf[2] << 0; + utmp1 = (buf[0] >> 2) & 0x01; /* 0=SISO, 1=MISO */ + if (utmp) { + if (utmp1) { + /* CNR[dB]: 10 * (log10(16384 / value) - 0.6) */ + /* log10(16384) = 70706234, 0.6 = 10066330 */ + stmp = div_u64(((u64)70706234 - intlog10(utmp) + - 10066330) * 10000, 1 << 24); + dev_dbg(&client->dev, "cnr=%d value=%u MISO\n", + stmp, utmp); } else { - /* SISO */ - cnr = log10times1000(65536); - cnr -= log10times1000(uitmp); - cnr += 200; + /* CNR[dB]: 10 * (log10(65536 / value) + 0.2) */ + /* log10(65536) = 80807124, 0.2 = 3355443 */ + stmp = div_u64(((u64)80807124 - intlog10(utmp) + + 3355443) * 10000, 1 << 24); + dev_dbg(&client->dev, "cnr=%d value=%u SISO\n", + stmp, utmp); } - } else - cnr = 0; - - if (cnr < 0) - cnr = 0; + } else { + stmp = 0; + } - c->cnr.stat[0].svalue = cnr * 10; + c->cnr.stat[0].svalue = stmp; c->cnr.stat[0].scale = FE_SCALE_DECIBEL; - } else { - c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; - } - - /* BER */ - ret = mn88473_update_ber_stat_t2(fe, status); - if (ret) - goto err; - - return 0; - -err: - dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); - return ret; -} - -static int mn88473_read_status_c(struct dvb_frontend *fe, - enum fe_status *status) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88473_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - unsigned int uitmp, tmp_upper, tmp_lower, signal, noise; - - ret = regmap_read(dev->regmap[1], 0x85, &uitmp); - if (ret) - goto err; - - if (!(uitmp & 0x40)) { - ret = regmap_read(dev->regmap[1], 0x89, &uitmp); - if (ret) - goto err; - - if (uitmp & 0x01) - *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | - FE_HAS_VITERBI | FE_HAS_SYNC | - FE_HAS_LOCK; - } - - /* CNR */ - if (*status & FE_HAS_VITERBI) { - ret = regmap_read(dev->regmap[1], 0xa1, &tmp_upper); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[1], 0xa2, &tmp_lower); - if (ret) - goto err; - - signal = (tmp_upper << 8) | tmp_lower; - - ret = regmap_read(dev->regmap[1], 0xa3, &tmp_upper); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[1], 0xa4, &tmp_lower); - if (ret) - goto err; - - noise = (tmp_upper << 8) | tmp_lower; - if (noise) - uitmp = log10times1000(signal * 8 / noise); - else - uitmp = 0; + } else if (*status & FE_HAS_VITERBI && + c->delivery_system == SYS_DVBC_ANNEX_A) { + /* DVB-C CNR */ + ret = regmap_bulk_read(dev->regmap[1], 0xa1, buf, 4); + if (ret) + goto err; + + utmp1 = buf[0] << 8 | buf[1] << 0; /* signal */ + utmp2 = buf[2] << 8 | buf[3] << 0; /* noise */ + if (utmp1 && utmp2) { + /* CNR[dB]: 10 * log10(8 * (signal / noise)) */ + /* log10(8) = 15151336 */ + stmp = div_u64(((u64)15151336 + intlog10(utmp1) + - intlog10(utmp2)) * 10000, 1 << 24); + dev_dbg(&client->dev, "cnr=%d signal=%u noise=%u\n", + stmp, utmp1, utmp2); + } else { + stmp = 0; + } - c->cnr.stat[0].svalue = uitmp * 10; + c->cnr.stat[0].svalue = stmp; c->cnr.stat[0].scale = FE_SCALE_DECIBEL; } else { c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } /* BER */ - ret = mn88473_update_ber_stat_t_c(fe, status); - if (ret) - goto err; - - return 0; - -err: - dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); - return ret; -} - -static int mn88473_read_status(struct dvb_frontend *fe, enum fe_status *status) -{ - struct i2c_client *client = fe->demodulator_priv; - struct mn88473_dev *dev = i2c_get_clientdata(client); - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int ret; - u16 errors, per_len; - unsigned int upper, lower; - - if (!dev->active) { - ret = -EAGAIN; - goto err; - } - - *status = 0; - - switch (c->delivery_system) { - case SYS_DVBT: - ret = mn88473_read_status_t(fe, status); - break; - case SYS_DVBT2: - ret = mn88473_read_status_t2(fe, status); - break; - case SYS_DVBC_ANNEX_A: - ret = mn88473_read_status_c(fe, status); - break; - default: - ret = -EINVAL; - break; - } - - if (ret) - goto err; - - /* signal strength, derived from AGC */ - if (*status & FE_HAS_SIGNAL) { - ret = regmap_read(dev->regmap[2], 0x86, &upper); + if (*status & FE_HAS_LOCK && (c->delivery_system == SYS_DVBT || + c->delivery_system == SYS_DVBC_ANNEX_A)) { + /* DVB-T & DVB-C BER */ + ret = regmap_bulk_read(dev->regmap[0], 0x92, buf, 5); if (ret) goto err; - ret = regmap_read(dev->regmap[2], 0x87, &lower); - if (ret) - goto err; + utmp1 = buf[0] << 16 | buf[1] << 8 | buf[2] << 0; + utmp2 = buf[3] << 8 | buf[4] << 0; + utmp2 = utmp2 * 8 * 204; + dev_dbg(&client->dev, "post_bit_error=%u post_bit_count=%u\n", + utmp1, utmp2); - /* AGCRD[15:6] gives us a 10bit value ([5:0] are always 0) */ - c->strength.stat[0].scale = FE_SCALE_RELATIVE; - c->strength.stat[0].uvalue = (upper << 8) | lower; + c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_error.stat[0].uvalue += utmp1; + c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + c->post_bit_count.stat[0].uvalue += utmp2; } else { - c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } /* PER */ if (*status & FE_HAS_LOCK) { - ret = regmap_read(dev->regmap[0], 0xdd, &upper); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[0], 0xde, &lower); - if (ret) - goto err; - - errors = (upper << 8) | lower; - - ret = regmap_read(dev->regmap[0], 0xdf, &upper); - if (ret) - goto err; - - ret = regmap_read(dev->regmap[0], 0xe0, &lower); + ret = regmap_bulk_read(dev->regmap[0], 0xdd, buf, 4); if (ret) goto err; - per_len = (upper << 8) | lower; + utmp1 = buf[0] << 8 | buf[1] << 0; + utmp2 = buf[2] << 8 | buf[3] << 0; + dev_dbg(&client->dev, "block_error=%u block_count=%u\n", + utmp1, utmp2); c->block_error.stat[0].scale = FE_SCALE_COUNTER; - c->block_error.stat[0].uvalue += errors; + c->block_error.stat[0].uvalue += utmp1; c->block_count.stat[0].scale = FE_SCALE_COUNTER; - c->block_count.stat[0].uvalue += per_len; + c->block_count.stat[0].uvalue += utmp2; } else { - c->block_error.stat[0].scale = FE_SCALE_COUNTER; - c->block_count.stat[0].scale = FE_SCALE_COUNTER; + c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; + c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; } return 0; err: - dev_dbg(&client->dev, "%s failed=%d\n", __func__, ret); + dev_dbg(&client->dev, "failed=%d\n", ret); return ret; } diff --git a/drivers/media/dvb-frontends/mn88473_priv.h b/drivers/media/dvb-frontends/mn88473_priv.h index 7cbef7b7fb39..5fc463d147c8 100644 --- a/drivers/media/dvb-frontends/mn88473_priv.h +++ b/drivers/media/dvb-frontends/mn88473_priv.h @@ -20,6 +20,7 @@ #include "dvb_frontend.h" #include "dvb_math.h" #include "mn88473.h" +#include #include #include -- cgit v1.2.3 From 414e72c729534a89017bc19415edc4957ebcc6fa Mon Sep 17 00:00:00 2001 From: Ruqiang Ju Date: Tue, 15 Nov 2016 05:31:32 -0200 Subject: [media] ir-hix5hd2: make hisilicon,power-syscon property deprecated The clock of IR can be provided by the clock provider and controlled by common clock framework APIs. Signed-off-by: Ruqiang Ju Signed-off-by: Jiancheng Xue Acked-by: Rob Herring Signed-off-by: Mauro Carvalho Chehab --- .../devicetree/bindings/media/hix5hd2-ir.txt | 6 +++--- drivers/media/rc/ir-hix5hd2.c | 25 ++++++++++++++-------- 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/media/hix5hd2-ir.txt b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt index fb5e7606643a..54e1bede6244 100644 --- a/Documentation/devicetree/bindings/media/hix5hd2-ir.txt +++ b/Documentation/devicetree/bindings/media/hix5hd2-ir.txt @@ -8,10 +8,11 @@ Required properties: the device. The interrupt specifier format depends on the interrupt controller parent. - clocks: clock phandle and specifier pair. - - hisilicon,power-syscon: phandle of syscon used to control power. Optional properties: - linux,rc-map-name : Remote control map name. + - hisilicon,power-syscon: DEPRECATED. Don't use this in new dts files. + Provide correct clocks instead. Example node: @@ -19,7 +20,6 @@ Example node: compatible = "hisilicon,hix5hd2-ir"; reg = <0xf8001000 0x1000>; interrupts = <0 47 4>; - clocks = <&clock HIX5HD2_FIXED_24M>; - hisilicon,power-syscon = <&sysctrl>; + clocks = <&clock HIX5HD2_IR_CLOCK>; linux,rc-map-name = "rc-tivo"; }; diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c index d0549fba711c..d26907e684dc 100644 --- a/drivers/media/rc/ir-hix5hd2.c +++ b/drivers/media/rc/ir-hix5hd2.c @@ -75,15 +75,22 @@ static void hix5hd2_ir_enable(struct hix5hd2_ir_priv *dev, bool on) { u32 val; - regmap_read(dev->regmap, IR_CLK, &val); - if (on) { - val &= ~IR_CLK_RESET; - val |= IR_CLK_ENABLE; + if (dev->regmap) { + regmap_read(dev->regmap, IR_CLK, &val); + if (on) { + val &= ~IR_CLK_RESET; + val |= IR_CLK_ENABLE; + } else { + val &= ~IR_CLK_ENABLE; + val |= IR_CLK_RESET; + } + regmap_write(dev->regmap, IR_CLK, val); } else { - val &= ~IR_CLK_ENABLE; - val |= IR_CLK_RESET; + if (on) + clk_prepare_enable(dev->clock); + else + clk_disable_unprepare(dev->clock); } - regmap_write(dev->regmap, IR_CLK, val); } static int hix5hd2_ir_config(struct hix5hd2_ir_priv *priv) @@ -207,8 +214,8 @@ static int hix5hd2_ir_probe(struct platform_device *pdev) priv->regmap = syscon_regmap_lookup_by_phandle(node, "hisilicon,power-syscon"); if (IS_ERR(priv->regmap)) { - dev_err(dev, "no power-reg\n"); - return -EINVAL; + dev_info(dev, "no power-reg\n"); + priv->regmap = NULL; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -- cgit v1.2.3 From d08876f524a605d64c7ca32cb8e9f5be3839e82e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 16 Nov 2016 09:11:54 -0200 Subject: [media] stk-webcam: fix an endian bug in stk_camera_read_reg() We pass an int pointer to stk_camera_read_reg() but only write to the highest byte. It's a bug on big endian systems and generally a nasty thing to do and doesn't match the write function either. Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/stkwebcam/stk-sensor.c | 6 +++--- drivers/media/usb/stkwebcam/stk-webcam.c | 11 ++++++----- drivers/media/usb/stkwebcam/stk-webcam.h | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/stkwebcam/stk-sensor.c b/drivers/media/usb/stkwebcam/stk-sensor.c index 13ad8fdf05bb..fbccbb2eed9f 100644 --- a/drivers/media/usb/stkwebcam/stk-sensor.c +++ b/drivers/media/usb/stkwebcam/stk-sensor.c @@ -228,7 +228,7 @@ static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) { int i = 0; - int tmpval = 0; + u8 tmpval = 0; if (stk_camera_write_reg(dev, STK_IIC_TX_INDEX, reg)) return 1; @@ -253,7 +253,7 @@ static int stk_sensor_outb(struct stk_camera *dev, u8 reg, u8 val) static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) { int i = 0; - int tmpval = 0; + u8 tmpval = 0; if (stk_camera_write_reg(dev, STK_IIC_RX_INDEX, reg)) return 1; @@ -274,7 +274,7 @@ static int stk_sensor_inb(struct stk_camera *dev, u8 reg, u8 *val) if (stk_camera_read_reg(dev, STK_IIC_RX_VALUE, &tmpval)) return 1; - *val = (u8) tmpval; + *val = tmpval; return 0; } diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index e2e7d0f7a43c..a212248bc2a3 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -144,7 +144,7 @@ int stk_camera_write_reg(struct stk_camera *dev, u16 index, u8 value) return 0; } -int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) +int stk_camera_read_reg(struct stk_camera *dev, u16 index, u8 *value) { struct usb_device *udev = dev->udev; unsigned char *buf; @@ -163,7 +163,7 @@ int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) sizeof(u8), 500); if (ret >= 0) - memcpy(value, buf, sizeof(u8)); + *value = *buf; kfree(buf); return ret; @@ -171,9 +171,10 @@ int stk_camera_read_reg(struct stk_camera *dev, u16 index, int *value) static int stk_start_stream(struct stk_camera *dev) { - int value; + u8 value; int i, ret; - int value_116, value_117; + u8 value_116, value_117; + if (!is_present(dev)) return -ENODEV; @@ -213,7 +214,7 @@ static int stk_start_stream(struct stk_camera *dev) static int stk_stop_stream(struct stk_camera *dev) { - int value; + u8 value; int i; if (is_present(dev)) { stk_camera_read_reg(dev, 0x0100, &value); diff --git a/drivers/media/usb/stkwebcam/stk-webcam.h b/drivers/media/usb/stkwebcam/stk-webcam.h index 9bbfa3d9bfdd..92bb48e3c74e 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.h +++ b/drivers/media/usb/stkwebcam/stk-webcam.h @@ -129,7 +129,7 @@ struct stk_camera { #define vdev_to_camera(d) container_of(d, struct stk_camera, vdev) int stk_camera_write_reg(struct stk_camera *, u16, u8); -int stk_camera_read_reg(struct stk_camera *, u16, int *); +int stk_camera_read_reg(struct stk_camera *, u16, u8 *); int stk_sensor_init(struct stk_camera *); int stk_sensor_configure(struct stk_camera *); -- cgit v1.2.3 From 8ccd22db927995313a9ab3526c1765c7c157f3e9 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 16 Nov 2016 11:00:56 -0200 Subject: [media] netup_unidvb: use module_pci_driver Use module_pci_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/netup_unidvb/netup_unidvb_core.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c index b078ac2a682c..191bd8299dc3 100644 --- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c +++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c @@ -1030,15 +1030,4 @@ static struct pci_driver netup_unidvb_pci_driver = { .resume = NULL, }; -static int __init netup_unidvb_init(void) -{ - return pci_register_driver(&netup_unidvb_pci_driver); -} - -static void __exit netup_unidvb_fini(void) -{ - pci_unregister_driver(&netup_unidvb_pci_driver); -} - -module_init(netup_unidvb_init); -module_exit(netup_unidvb_fini); +module_pci_driver(netup_unidvb_pci_driver); -- cgit v1.2.3 From bd5d21310133921021d78995ad6346f908483124 Mon Sep 17 00:00:00 2001 From: Rafał Miłecki Date: Sun, 20 Nov 2016 16:09:30 +0100 Subject: mtd: bcm47xxpart: fix parsing first block after aligned TRX MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After parsing TRX we should skip to the first block placed behind it. Our code was working only with TRX with length not aligned to the blocksize. In other cases (length aligned) it was missing the block places right after TRX. This fixes calculation and simplifies the comment. Signed-off-by: Rafał Miłecki Signed-off-by: Brian Norris --- drivers/mtd/bcm47xxpart.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c index 377947580203..283ff7e17a0f 100644 --- a/drivers/mtd/bcm47xxpart.c +++ b/drivers/mtd/bcm47xxpart.c @@ -229,12 +229,10 @@ static int bcm47xxpart_parse(struct mtd_info *master, last_trx_part = curr_part - 1; - /* - * We have whole TRX scanned, skip to the next part. Use - * roundown (not roundup), as the loop will increase - * offset in next step. - */ - offset = rounddown(offset + trx->length, blocksize); + /* Jump to the end of TRX */ + offset = roundup(offset + trx->length, blocksize); + /* Next loop iteration will increase the offset */ + offset -= blocksize; continue; } -- cgit v1.2.3 From b2c4ba5cf712fede57dd3e15922ae647dde55a82 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 28 Oct 2016 19:25:59 +0100 Subject: mtd: mtdswap: fix spelling mistake "erassure" -> "erasure" Trivial fix to spelling mistake in dev_err message Signed-off-by: Colin Ian King [Brian: add EOL newline] Signed-off-by: Brian Norris --- drivers/mtd/mtdswap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdswap.c b/drivers/mtd/mtdswap.c index cb06bdd21a1b..c40e2c951758 100644 --- a/drivers/mtd/mtdswap.c +++ b/drivers/mtd/mtdswap.c @@ -587,7 +587,7 @@ retry: ret = wait_event_interruptible(wq, erase.state == MTD_ERASE_DONE || erase.state == MTD_ERASE_FAILED); if (ret) { - dev_err(d->dev, "Interrupted erase block %#llx erassure on %s", + dev_err(d->dev, "Interrupted erase block %#llx erasure on %s\n", erase.addr, mtd->name); return -EINTR; } -- cgit v1.2.3 From 262e1f6e39143c2a0f559e2fb4a835069a7693a9 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Mon, 21 Nov 2016 15:57:19 +0800 Subject: stm class: ftrace: Add ftrace-export-over-stm driver This patch adds a driver that models itself as an stm_source called stm_ftrace. Once the stm device and stm_ftrace have been linked via sysfs, the driver registers itself as a trace_export and everything passed to the interface from Ftrace subsystem will end up in the STM trace engine. Link: http://lkml.kernel.org/r/1479715043-6534-3-git-send-email-zhang.chunyan@linaro.org Signed-off-by: Chunyan Zhang Acked-by: Alexander Shishkin Signed-off-by: Steven Rostedt --- drivers/hwtracing/stm/Kconfig | 11 ++++++ drivers/hwtracing/stm/Makefile | 2 + drivers/hwtracing/stm/ftrace.c | 87 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 drivers/hwtracing/stm/ftrace.c (limited to 'drivers') diff --git a/drivers/hwtracing/stm/Kconfig b/drivers/hwtracing/stm/Kconfig index 847a39b35307..723e2d90083d 100644 --- a/drivers/hwtracing/stm/Kconfig +++ b/drivers/hwtracing/stm/Kconfig @@ -39,4 +39,15 @@ config STM_SOURCE_HEARTBEAT If you want to send heartbeat messages over STM devices, say Y. +config STM_SOURCE_FTRACE + tristate "Copy the output from kernel Ftrace to STM engine" + depends on FUNCTION_TRACER + help + This option can be used to copy the output from kernel Ftrace + to STM engine. Enabling this option will introduce a slight + timing effect. + + If you want to send kernel Ftrace messages over STM devices, + say Y. + endif diff --git a/drivers/hwtracing/stm/Makefile b/drivers/hwtracing/stm/Makefile index a9ce3d487e57..3abd84ce13d4 100644 --- a/drivers/hwtracing/stm/Makefile +++ b/drivers/hwtracing/stm/Makefile @@ -6,6 +6,8 @@ obj-$(CONFIG_STM_DUMMY) += dummy_stm.o obj-$(CONFIG_STM_SOURCE_CONSOLE) += stm_console.o obj-$(CONFIG_STM_SOURCE_HEARTBEAT) += stm_heartbeat.o +obj-$(CONFIG_STM_SOURCE_FTRACE) += stm_ftrace.o stm_console-y := console.o stm_heartbeat-y := heartbeat.o +stm_ftrace-y := ftrace.o diff --git a/drivers/hwtracing/stm/ftrace.c b/drivers/hwtracing/stm/ftrace.c new file mode 100644 index 000000000000..bd126a7c6da2 --- /dev/null +++ b/drivers/hwtracing/stm/ftrace.c @@ -0,0 +1,87 @@ +/* + * Simple kernel driver to link kernel Ftrace and an STM device + * Copyright (c) 2016, Linaro Ltd. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * STM Ftrace will be registered as a trace_export. + */ + +#include +#include +#include + +#define STM_FTRACE_NR_CHANNELS 1 +#define STM_FTRACE_CHAN 0 + +static int stm_ftrace_link(struct stm_source_data *data); +static void stm_ftrace_unlink(struct stm_source_data *data); + +static struct stm_ftrace { + struct stm_source_data data; + struct trace_export ftrace; +} stm_ftrace = { + .data = { + .name = "ftrace", + .nr_chans = STM_FTRACE_NR_CHANNELS, + .link = stm_ftrace_link, + .unlink = stm_ftrace_unlink, + }, +}; + +/** + * stm_ftrace_write() - write data to STM via 'stm_ftrace' source + * @buf: buffer containing the data packet + * @len: length of the data packet + */ +static void notrace +stm_ftrace_write(const void *buf, unsigned int len) +{ + stm_source_write(&stm_ftrace.data, STM_FTRACE_CHAN, buf, len); +} + +static int stm_ftrace_link(struct stm_source_data *data) +{ + struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data); + + sf->ftrace.write = stm_ftrace_write; + + return register_ftrace_export(&sf->ftrace); +} + +static void stm_ftrace_unlink(struct stm_source_data *data) +{ + struct stm_ftrace *sf = container_of(data, struct stm_ftrace, data); + + unregister_ftrace_export(&sf->ftrace); +} + +static int __init stm_ftrace_init(void) +{ + int ret; + + ret = stm_source_register_device(NULL, &stm_ftrace.data); + if (ret) + pr_err("Failed to register stm_source - ftrace.\n"); + + return ret; +} + +static void __exit stm_ftrace_exit(void) +{ + stm_source_unregister_device(&stm_ftrace.data); +} + +module_init(stm_ftrace_init); +module_exit(stm_ftrace_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("stm_ftrace driver"); +MODULE_AUTHOR("Chunyan Zhang "); -- cgit v1.2.3 From dea5d0e1fcac657ea0d699afb1595e52cb051d46 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Mon, 21 Nov 2016 15:57:20 +0800 Subject: coresight: Mark stm_generic_packet() with notrace If CONFIG_STM_SOURCE_FTRACE is selected, Function trace data can be writen to sink via STM, all functions that related to writing data packets to STM should be marked 'notrace' to avoid being traced by Ftrace, otherwise the program would stall into an endless loop. Link: http://lkml.kernel.org/r/1479715043-6534-4-git-send-email-zhang.chunyan@linaro.org Signed-off-by: Chunyan Zhang Acked-by: Alexander Shishkin Signed-off-by: Steven Rostedt --- drivers/hwtracing/coresight/coresight-stm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwtracing/coresight/coresight-stm.c b/drivers/hwtracing/coresight/coresight-stm.c index 49e0f1b925a5..b7543bd19c9e 100644 --- a/drivers/hwtracing/coresight/coresight-stm.c +++ b/drivers/hwtracing/coresight/coresight-stm.c @@ -406,7 +406,7 @@ static long stm_generic_set_options(struct stm_data *stm_data, return 0; } -static ssize_t stm_generic_packet(struct stm_data *stm_data, +static ssize_t notrace stm_generic_packet(struct stm_data *stm_data, unsigned int master, unsigned int channel, unsigned int packet, -- cgit v1.2.3 From 22975be20f40616420dc4b26e8c1fe84e9f68427 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Mon, 21 Nov 2016 15:57:21 +0800 Subject: intel_th: Mark sth_stm_packet() with notrace If CONFIG_STM_SOURCE_FTRACE is selected, Function trace data can be writen to sink via STM, all functions that related to writing data packets to STM should be marked 'notrace' to avoid being traced by Ftrace, otherwise the program would stall into an endless loop. Link: http://lkml.kernel.org/r/1479715043-6534-5-git-send-email-zhang.chunyan@linaro.org Signed-off-by: Chunyan Zhang Acked-by: Alexander Shishkin Signed-off-by: Steven Rostedt --- drivers/hwtracing/intel_th/sth.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/hwtracing/intel_th/sth.c b/drivers/hwtracing/intel_th/sth.c index e1aee61dd7b3..b03444624648 100644 --- a/drivers/hwtracing/intel_th/sth.c +++ b/drivers/hwtracing/intel_th/sth.c @@ -67,10 +67,13 @@ static void sth_iowrite(void __iomem *dest, const unsigned char *payload, } } -static ssize_t sth_stm_packet(struct stm_data *stm_data, unsigned int master, - unsigned int channel, unsigned int packet, - unsigned int flags, unsigned int size, - const unsigned char *payload) +static ssize_t notrace sth_stm_packet(struct stm_data *stm_data, + unsigned int master, + unsigned int channel, + unsigned int packet, + unsigned int flags, + unsigned int size, + const unsigned char *payload) { struct sth_device *sth = container_of(stm_data, struct sth_device, stm); struct intel_th_channel __iomem *out = -- cgit v1.2.3 From 9b5e3ff6b9baa77548c6cb832780162055733c67 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Mon, 21 Nov 2016 15:57:22 +0800 Subject: stm dummy: Mark dummy_stm_packet() with notrace If CONFIG_STM_SOURCE_FTRACE is selected, Function trace data can be writen to sink via STM, all functions that related to writing data packets to STM should be marked 'notrace' to avoid being traced by Ftrace, otherwise the program would stall into an endless loop. Link: http://lkml.kernel.org/r/1479715043-6534-6-git-send-email-zhang.chunyan@linaro.org Signed-off-by: Chunyan Zhang Acked-by: Alexander Shishkin Signed-off-by: Steven Rostedt --- drivers/hwtracing/stm/dummy_stm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/hwtracing/stm/dummy_stm.c b/drivers/hwtracing/stm/dummy_stm.c index a86612d989f9..c5f94ca31c4d 100644 --- a/drivers/hwtracing/stm/dummy_stm.c +++ b/drivers/hwtracing/stm/dummy_stm.c @@ -21,7 +21,7 @@ #include #include -static ssize_t +static ssize_t notrace dummy_stm_packet(struct stm_data *stm_data, unsigned int master, unsigned int channel, unsigned int packet, unsigned int flags, unsigned int size, const unsigned char *payload) -- cgit v1.2.3 From 9dfed80d87ca2c365cd1004a91ef4ed716c8e44e Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Mon, 21 Nov 2016 15:57:23 +0800 Subject: stm: Mark the functions of writing STM with notrace If CONFIG_STM_SOURCE_FTRACE is selected, Function trace data can be writen to sink via STM, all functions that related to writing data packets to STM should be marked 'notrace' to avoid being traced by Ftrace, otherwise the program would stall into an endless loop. Link: http://lkml.kernel.org/r/1479715043-6534-7-git-send-email-zhang.chunyan@linaro.org Signed-off-by: Chunyan Zhang Acked-by: Alexander Shishkin Signed-off-by: Steven Rostedt --- drivers/hwtracing/stm/core.c | 7 ++++--- include/linux/stm.h | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/hwtracing/stm/core.c b/drivers/hwtracing/stm/core.c index 51f81d64ca37..37d3bcbd2534 100644 --- a/drivers/hwtracing/stm/core.c +++ b/drivers/hwtracing/stm/core.c @@ -425,7 +425,7 @@ static int stm_file_assign(struct stm_file *stmf, char *id, unsigned int width) return ret; } -static ssize_t stm_write(struct stm_data *data, unsigned int master, +static ssize_t notrace stm_write(struct stm_data *data, unsigned int master, unsigned int channel, const char *buf, size_t count) { unsigned int flags = STP_PACKET_TIMESTAMPED; @@ -1121,8 +1121,9 @@ void stm_source_unregister_device(struct stm_source_data *data) } EXPORT_SYMBOL_GPL(stm_source_unregister_device); -int stm_source_write(struct stm_source_data *data, unsigned int chan, - const char *buf, size_t count) +int notrace stm_source_write(struct stm_source_data *data, + unsigned int chan, + const char *buf, size_t count) { struct stm_source_device *src = data->src; struct stm_device *stm; diff --git a/include/linux/stm.h b/include/linux/stm.h index 8369d8a8cabd..210ff2292361 100644 --- a/include/linux/stm.h +++ b/include/linux/stm.h @@ -133,7 +133,7 @@ int stm_source_register_device(struct device *parent, struct stm_source_data *data); void stm_source_unregister_device(struct stm_source_data *data); -int stm_source_write(struct stm_source_data *data, unsigned int chan, - const char *buf, size_t count); +int notrace stm_source_write(struct stm_source_data *data, unsigned int chan, + const char *buf, size_t count); #endif /* _STM_H_ */ -- cgit v1.2.3 From 29fd0ec2bdbef6734fd4c39c23f61d9f030a66a0 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Tue, 22 Nov 2016 17:44:12 -0800 Subject: Input: synaptics-rmi4 - add support for F34 device reflash Add support for updating firmware, triggered by a sysfs attribute. This patch has been tested on Synaptics S7300. Signed-off-by: Nick Dyer Tested-by: Chris Healy Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/Kconfig | 11 + drivers/input/rmi4/Makefile | 1 + drivers/input/rmi4/rmi_bus.c | 3 + drivers/input/rmi4/rmi_driver.c | 105 ++++++--- drivers/input/rmi4/rmi_driver.h | 24 ++ drivers/input/rmi4/rmi_f01.c | 6 + drivers/input/rmi4/rmi_f34.c | 481 ++++++++++++++++++++++++++++++++++++++++ drivers/input/rmi4/rmi_f34.h | 68 ++++++ include/linux/rmi.h | 2 + 9 files changed, 670 insertions(+), 31 deletions(-) create mode 100644 drivers/input/rmi4/rmi_f34.c create mode 100644 drivers/input/rmi4/rmi_f34.h (limited to 'drivers') diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index 8cbd362ae8a7..9a24867ae7a5 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -74,6 +74,17 @@ config RMI4_F30 Function 30 provides GPIO and LED support for RMI4 devices. This includes support for buttons on TouchPads and ClickPads. +config RMI4_F34 + bool "RMI4 Function 34 (Device reflash)" + depends on RMI4_CORE + select FW_LOADER + help + Say Y here if you want to add support for RMI4 function 34. + + Function 34 provides support for upgrading the firmware on the RMI4 + device via the firmware loader interface. This is triggered using a + sysfs attribute. + config RMI4_F54 bool "RMI4 Function 54 (Analog diagnostics)" depends on RMI4_CORE diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index a6e27527d514..0250abf38ad9 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -7,6 +7,7 @@ rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o +rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o # Transports diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 84b321262d74..ef7a66230d83 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -315,6 +315,9 @@ static struct rmi_function_handler *fn_handlers[] = { #ifdef CONFIG_RMI4_F30 &rmi_f30_handler, #endif +#ifdef CONFIG_RMI4_F34 + &rmi_f34_handler, +#endif #ifdef CONFIG_RMI4_F54 &rmi_f54_handler, #endif diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 4f8d19794b01..2b17d8cb3d10 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -35,14 +35,24 @@ #define RMI_DEVICE_RESET_CMD 0x01 #define DEFAULT_RESET_DELAY_MS 100 -static void rmi_free_function_list(struct rmi_device *rmi_dev) +void rmi_free_function_list(struct rmi_device *rmi_dev) { struct rmi_function *fn, *tmp; struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n"); + mutex_lock(&data->irq_mutex); + + devm_kfree(&rmi_dev->dev, data->irq_memory); + data->irq_memory = NULL; + data->irq_status = NULL; + data->fn_irq_bits = NULL; + data->current_irq_mask = NULL; + data->new_irq_mask = NULL; + data->f01_container = NULL; + data->f34_container = NULL; /* Doing it in the reverse order so F01 will be removed last */ list_for_each_entry_safe_reverse(fn, tmp, @@ -50,7 +60,10 @@ static void rmi_free_function_list(struct rmi_device *rmi_dev) list_del(&fn->node); rmi_unregister_function(fn); } + + mutex_unlock(&data->irq_mutex); } +EXPORT_SYMBOL_GPL(rmi_free_function_list); static int reset_one_function(struct rmi_function *fn) { @@ -147,24 +160,25 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) if (!data) return 0; + mutex_lock(&data->irq_mutex); + if (!data->irq_status || !data->f01_container) { + mutex_unlock(&data->irq_mutex); + return 0; + } + if (!rmi_dev->xport->attn_data) { error = rmi_read_block(rmi_dev, data->f01_container->fd.data_base_addr + 1, data->irq_status, data->num_of_irq_regs); if (error < 0) { dev_err(dev, "Failed to read irqs, code=%d\n", error); + mutex_unlock(&data->irq_mutex); return error; } } - mutex_lock(&data->irq_mutex); bitmap_and(data->irq_status, data->irq_status, data->current_irq_mask, data->irq_count); - /* - * At this point, irq_status has all bits that are set in the - * interrupt status register and are enabled. - */ - mutex_unlock(&data->irq_mutex); /* * It would be nice to be able to use irq_chip to handle these @@ -180,6 +194,8 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) if (data->input) input_sync(data->input); + mutex_unlock(&data->irq_mutex); + return 0; } @@ -244,12 +260,18 @@ static int rmi_suspend_functions(struct rmi_device *rmi_dev) struct rmi_function *entry; int retval; + mutex_lock(&data->irq_mutex); + list_for_each_entry(entry, &data->function_list, node) { retval = suspend_one_function(entry); - if (retval < 0) + if (retval < 0) { + mutex_unlock(&data->irq_mutex); return retval; + } } + mutex_unlock(&data->irq_mutex); + return 0; } @@ -278,16 +300,22 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev) struct rmi_function *entry; int retval; + mutex_lock(&data->irq_mutex); + list_for_each_entry(entry, &data->function_list, node) { retval = resume_one_function(entry); - if (retval < 0) + if (retval < 0) { + mutex_unlock(&data->irq_mutex); return retval; + } } + mutex_unlock(&data->irq_mutex); + return 0; } -static int enable_sensor(struct rmi_device *rmi_dev) +int rmi_enable_sensor(struct rmi_device *rmi_dev) { int retval = 0; @@ -297,6 +325,7 @@ static int enable_sensor(struct rmi_device *rmi_dev) return rmi_process_interrupt_requests(rmi_dev); } +EXPORT_SYMBOL_GPL(rmi_enable_sensor); /** * rmi_driver_set_input_params - set input device id and other data. @@ -502,10 +531,9 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev, RMI_SCAN_DONE : RMI_SCAN_CONTINUE; } -static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, - int (*callback)(struct rmi_device *rmi_dev, - void *ctx, - const struct pdt_entry *entry)) +int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, + int (*callback)(struct rmi_device *rmi_dev, + void *ctx, const struct pdt_entry *entry)) { int page; int empty_pages = 0; @@ -520,6 +548,7 @@ static int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, return retval < 0 ? retval : 0; } +EXPORT_SYMBOL_GPL(rmi_scan_pdt); int rmi_read_register_desc(struct rmi_device *d, u16 addr, struct rmi_register_descriptor *rdesc) @@ -740,19 +769,15 @@ static int rmi_count_irqs(struct rmi_device *rmi_dev, int *irq_count = ctx; *irq_count += pdt->interrupt_source_count; - if (pdt->function_number == 0x01) { + if (pdt->function_number == 0x01) data->f01_bootloader_mode = rmi_check_bootloader_mode(rmi_dev, pdt); - if (data->f01_bootloader_mode) - dev_warn(&rmi_dev->dev, - "WARNING: RMI4 device is in bootloader mode!\n"); - } return RMI_SCAN_CONTINUE; } -static int rmi_initial_reset(struct rmi_device *rmi_dev, - void *ctx, const struct pdt_entry *pdt) +int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx, + const struct pdt_entry *pdt) { int error; @@ -787,6 +812,7 @@ static int rmi_initial_reset(struct rmi_device *rmi_dev, /* F01 should always be on page 0. If we don't find it there, fail. */ return pdt->page_start == 0 ? RMI_SCAN_CONTINUE : -ENODEV; } +EXPORT_SYMBOL_GPL(rmi_initial_reset); static int rmi_create_function(struct rmi_device *rmi_dev, void *ctx, const struct pdt_entry *pdt) @@ -828,6 +854,8 @@ static int rmi_create_function(struct rmi_device *rmi_dev, if (pdt->function_number == 0x01) data->f01_container = fn; + else if (pdt->function_number == 0x34) + data->f34_container = fn; list_add_tail(&fn->node, &data->function_list); @@ -893,6 +921,7 @@ static int rmi_driver_remove(struct device *dev) disable_irq(irq); + rmi_f34_remove_sysfs(rmi_dev); rmi_free_function_list(rmi_dev); return 0; @@ -919,13 +948,12 @@ static inline int rmi_driver_of_probe(struct device *dev, } #endif -static int rmi_probe_interrupts(struct rmi_driver_data *data) +int rmi_probe_interrupts(struct rmi_driver_data *data) { struct rmi_device *rmi_dev = data->rmi_dev; struct device *dev = &rmi_dev->dev; int irq_count; size_t size; - void *irq_memory; int retval; /* @@ -941,31 +969,38 @@ static int rmi_probe_interrupts(struct rmi_driver_data *data) dev_err(dev, "IRQ counting failed with code %d.\n", retval); return retval; } + + if (data->f01_bootloader_mode) + dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n"); + data->irq_count = irq_count; data->num_of_irq_regs = (data->irq_count + 7) / 8; size = BITS_TO_LONGS(data->irq_count) * sizeof(unsigned long); - irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL); - if (!irq_memory) { + data->irq_memory = devm_kzalloc(dev, size * 4, GFP_KERNEL); + if (!data->irq_memory) { dev_err(dev, "Failed to allocate memory for irq masks.\n"); return retval; } - data->irq_status = irq_memory + size * 0; - data->fn_irq_bits = irq_memory + size * 1; - data->current_irq_mask = irq_memory + size * 2; - data->new_irq_mask = irq_memory + size * 3; + data->irq_status = data->irq_memory + size * 0; + data->fn_irq_bits = data->irq_memory + size * 1; + data->current_irq_mask = data->irq_memory + size * 2; + data->new_irq_mask = data->irq_memory + size * 3; return retval; } +EXPORT_SYMBOL_GPL(rmi_probe_interrupts); -static int rmi_init_functions(struct rmi_driver_data *data) +int rmi_init_functions(struct rmi_driver_data *data) { struct rmi_device *rmi_dev = data->rmi_dev; struct device *dev = &rmi_dev->dev; int irq_count; int retval; + mutex_lock(&data->irq_mutex); + irq_count = 0; rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__); retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function); @@ -990,12 +1025,16 @@ static int rmi_init_functions(struct rmi_driver_data *data) goto err_destroy_functions; } + mutex_unlock(&data->irq_mutex); + return 0; err_destroy_functions: rmi_free_function_list(rmi_dev); + mutex_unlock(&data->irq_mutex); return retval; } +EXPORT_SYMBOL_GPL(rmi_init_functions); static int rmi_driver_probe(struct device *dev) { @@ -1100,6 +1139,10 @@ static int rmi_driver_probe(struct device *dev) if (retval) goto err; + retval = rmi_f34_create_sysfs(rmi_dev); + if (retval) + goto err; + if (data->input) { rmi_driver_set_input_name(rmi_dev, data->input); if (!rmi_dev->xport->input) { @@ -1117,7 +1160,7 @@ static int rmi_driver_probe(struct device *dev) if (data->f01_container->dev.driver) /* Driver already bound, so enable ATTN now. */ - return enable_sensor(rmi_dev); + return rmi_enable_sensor(rmi_dev); return 0; diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index 8dfbebe9bf86..e627a3a8aced 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -95,12 +95,36 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, bool rmi_is_physical_driver(struct device_driver *); int rmi_register_physical_driver(void); void rmi_unregister_physical_driver(void); +void rmi_free_function_list(struct rmi_device *rmi_dev); +int rmi_enable_sensor(struct rmi_device *rmi_dev); +int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, + int (*callback)(struct rmi_device *rmi_dev, void *ctx, + const struct pdt_entry *entry)); +int rmi_probe_interrupts(struct rmi_driver_data *data); +int rmi_init_functions(struct rmi_driver_data *data); +int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx, + const struct pdt_entry *pdt); char *rmi_f01_get_product_ID(struct rmi_function *fn); +#ifdef CONFIG_RMI4_F34 +int rmi_f34_create_sysfs(struct rmi_device *rmi_dev); +void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev); +#else +static inline int rmi_f34_create_sysfs(struct rmi_device *rmi_dev) +{ + return 0; +} + +static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev) +{ +} +#endif /* CONFIG_RMI_F34 */ + extern struct rmi_function_handler rmi_f01_handler; extern struct rmi_function_handler rmi_f11_handler; extern struct rmi_function_handler rmi_f12_handler; extern struct rmi_function_handler rmi_f30_handler; +extern struct rmi_function_handler rmi_f34_handler; extern struct rmi_function_handler rmi_f54_handler; #endif diff --git a/drivers/input/rmi4/rmi_f01.c b/drivers/input/rmi4/rmi_f01.c index 2cfa9f64acfb..cae35c6cde31 100644 --- a/drivers/input/rmi4/rmi_f01.c +++ b/drivers/input/rmi4/rmi_f01.c @@ -63,6 +63,8 @@ struct f01_basic_properties { #define RMI_F01_STATUS_CODE(status) ((status) & 0x0f) /* The device has lost its configuration for some reason. */ #define RMI_F01_STATUS_UNCONFIGURED(status) (!!((status) & 0x80)) +/* The device is in bootloader mode */ +#define RMI_F01_STATUS_BOOTLOADER(status) ((status) & 0x40) /* Control register bits */ @@ -594,6 +596,10 @@ static int rmi_f01_attention(struct rmi_function *fn, return error; } + if (RMI_F01_STATUS_BOOTLOADER(device_status)) + dev_warn(&fn->dev, + "Device in bootloader mode, please update firmware\n"); + if (RMI_F01_STATUS_UNCONFIGURED(device_status)) { dev_warn(&fn->dev, "Device reset detected.\n"); error = rmi_dev->driver->reset_handler(rmi_dev); diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c new file mode 100644 index 000000000000..03df85ac91a5 --- /dev/null +++ b/drivers/input/rmi4/rmi_f34.c @@ -0,0 +1,481 @@ +/* + * Copyright (c) 2007-2016, Synaptics Incorporated + * Copyright (C) 2016 Zodiac Inflight Innovations + * + * 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 "rmi_driver.h" +#include "rmi_f34.h" + +static int rmi_f34_write_bootloader_id(struct f34_data *f34) +{ + struct rmi_function *fn = f34->fn; + struct rmi_device *rmi_dev = fn->rmi_dev; + u8 bootloader_id[F34_BOOTLOADER_ID_LEN]; + int ret; + + ret = rmi_read_block(rmi_dev, fn->fd.query_base_addr, + bootloader_id, sizeof(bootloader_id)); + if (ret) { + dev_err(&fn->dev, "%s: Reading bootloader ID failed: %d\n", + __func__, ret); + return ret; + } + + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: writing bootloader id '%c%c'\n", + __func__, bootloader_id[0], bootloader_id[1]); + + ret = rmi_write_block(rmi_dev, + fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET, + bootloader_id, sizeof(bootloader_id)); + if (ret) { + dev_err(&fn->dev, "Failed to write bootloader ID: %d\n", ret); + return ret; + } + + return 0; +} + +static int rmi_f34_command(struct f34_data *f34, u8 command, + unsigned int timeout, bool write_bl_id) +{ + struct rmi_function *fn = f34->fn; + struct rmi_device *rmi_dev = fn->rmi_dev; + int ret; + + if (write_bl_id) { + ret = rmi_f34_write_bootloader_id(f34); + if (ret) + return ret; + } + + init_completion(&f34->v5.cmd_done); + + ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status); + if (ret) { + dev_err(&f34->fn->dev, + "%s: Failed to read cmd register: %d (command %#02x)\n", + __func__, ret, command); + return ret; + } + + f34->v5.status |= command & 0x0f; + + ret = rmi_write(rmi_dev, f34->v5.ctrl_address, f34->v5.status); + if (ret < 0) { + dev_err(&f34->fn->dev, + "Failed to write F34 command %#02x: %d\n", + command, ret); + return ret; + } + + if (!wait_for_completion_timeout(&f34->v5.cmd_done, + msecs_to_jiffies(timeout))) { + + ret = rmi_read(rmi_dev, f34->v5.ctrl_address, &f34->v5.status); + if (ret) { + dev_err(&f34->fn->dev, + "%s: cmd %#02x timed out: %d\n", + __func__, command, ret); + return ret; + } + + if (f34->v5.status & 0x7f) { + dev_err(&f34->fn->dev, + "%s: cmd %#02x timed out, status: %#02x\n", + __func__, command, f34->v5.status); + return -ETIMEDOUT; + } + } + + return 0; +} + +static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits) +{ + struct f34_data *f34 = dev_get_drvdata(&fn->dev); + int ret; + + ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", + __func__, f34->v5.status, ret); + + if (!ret && !(f34->v5.status & 0x7f)) + complete(&f34->v5.cmd_done); + + return 0; +} + +static int rmi_f34_write_blocks(struct f34_data *f34, const void *data, + int block_count, u8 command) +{ + struct rmi_function *fn = f34->fn; + struct rmi_device *rmi_dev = fn->rmi_dev; + u16 address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET; + u8 start_address[] = { 0, 0 }; + int i; + int ret; + + ret = rmi_write_block(rmi_dev, fn->fd.data_base_addr, + start_address, sizeof(start_address)); + if (ret) { + dev_err(&fn->dev, "Failed to write initial zeros: %d\n", ret); + return ret; + } + + for (i = 0; i < block_count; i++) { + ret = rmi_write_block(rmi_dev, address, + data, f34->v5.block_size); + if (ret) { + dev_err(&fn->dev, + "failed to write block #%d: %d\n", i, ret); + return ret; + } + + ret = rmi_f34_command(f34, command, F34_IDLE_WAIT_MS, false); + if (ret) { + dev_err(&fn->dev, + "Failed to write command for block #%d: %d\n", + i, ret); + return ret; + } + + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "wrote block %d of %d\n", + i + 1, block_count); + + data += f34->v5.block_size; + } + + return 0; +} + +static int rmi_f34_write_firmware(struct f34_data *f34, const void *data) +{ + return rmi_f34_write_blocks(f34, data, f34->v5.fw_blocks, + F34_WRITE_FW_BLOCK); +} + +static int rmi_f34_write_config(struct f34_data *f34, const void *data) +{ + return rmi_f34_write_blocks(f34, data, f34->v5.config_blocks, + F34_WRITE_CONFIG_BLOCK); +} + +int rmi_f34_enable_flash(struct f34_data *f34) +{ + return rmi_f34_command(f34, F34_ENABLE_FLASH_PROG, + F34_ENABLE_WAIT_MS, true); +} + +static int rmi_f34_flash_firmware(struct f34_data *f34, + const struct rmi_f34_firmware *syn_fw) +{ + struct rmi_function *fn = f34->fn; + int ret; + + if (syn_fw->image_size) { + dev_info(&fn->dev, "Erasing firmware...\n"); + ret = rmi_f34_command(f34, F34_ERASE_ALL, + F34_ERASE_WAIT_MS, true); + if (ret) + return ret; + + dev_info(&fn->dev, "Writing firmware (%d bytes)...\n", + syn_fw->image_size); + ret = rmi_f34_write_firmware(f34, syn_fw->data); + if (ret) + return ret; + } + + if (syn_fw->config_size) { + /* + * We only need to erase config if we haven't updated + * firmware. + */ + if (!syn_fw->image_size) { + dev_info(&fn->dev, "Erasing config...\n"); + ret = rmi_f34_command(f34, F34_ERASE_CONFIG, + F34_ERASE_WAIT_MS, true); + if (ret) + return ret; + } + + dev_info(&fn->dev, "Writing config (%d bytes)...\n", + syn_fw->config_size); + ret = rmi_f34_write_config(f34, + &syn_fw->data[syn_fw->image_size]); + if (ret) + return ret; + } + + return 0; +} + +int rmi_f34_update_firmware(struct f34_data *f34, const struct firmware *fw) +{ + const struct rmi_f34_firmware *syn_fw; + int ret; + + syn_fw = (const struct rmi_f34_firmware *)fw->data; + BUILD_BUG_ON(offsetof(struct rmi_f34_firmware, data) != + F34_FW_IMAGE_OFFSET); + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "FW size:%d, checksum:%08x, image_size:%d, config_size:%d\n", + (int)fw->size, + le32_to_cpu(syn_fw->checksum), + le32_to_cpu(syn_fw->image_size), + le32_to_cpu(syn_fw->config_size)); + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "FW bootloader_id:%02x, product_id:%.*s, info: %02x%02x\n", + syn_fw->bootloader_version, + (int)sizeof(syn_fw->product_id), syn_fw->product_id, + syn_fw->product_info[0], syn_fw->product_info[1]); + + if (syn_fw->image_size && + syn_fw->image_size != f34->v5.fw_blocks * f34->v5.block_size) { + dev_err(&f34->fn->dev, + "Bad firmware image: fw size %d, expected %d\n", + syn_fw->image_size, + f34->v5.fw_blocks * f34->v5.block_size); + ret = -EILSEQ; + goto out; + } + + if (syn_fw->config_size && + syn_fw->config_size != f34->v5.config_blocks * f34->v5.block_size) { + dev_err(&f34->fn->dev, + "Bad firmware image: config size %d, expected %d\n", + syn_fw->config_size, + f34->v5.config_blocks * f34->v5.block_size); + ret = -EILSEQ; + goto out; + } + + if (syn_fw->image_size && !syn_fw->config_size) { + dev_err(&f34->fn->dev, "Bad firmware image: no config data\n"); + ret = -EILSEQ; + goto out; + } + + dev_info(&f34->fn->dev, "Firmware image OK\n"); + mutex_lock(&f34->v5.flash_mutex); + + ret = rmi_f34_flash_firmware(f34, syn_fw); + + mutex_unlock(&f34->v5.flash_mutex); + +out: + return ret; +} + +static int rmi_firmware_update(struct rmi_driver_data *data, + const struct firmware *fw) +{ + struct device *dev = &data->rmi_dev->dev; + struct f34_data *f34; + int ret; + + if (!data->f34_container) { + dev_warn(dev, "%s: No F34 present!\n", __func__); + return -EINVAL; + } + + /* Only version 0 currently supported */ + if (data->f34_container->fd.function_version != 0) { + dev_warn(dev, "F34 V%d not supported!\n", + data->f34_container->fd.function_version); + return -ENODEV; + } + + f34 = dev_get_drvdata(&data->f34_container->dev); + + /* Enter flash mode */ + ret = rmi_f34_enable_flash(f34); + if (ret) + return ret; + + /* Tear down functions and re-probe */ + rmi_free_function_list(data->rmi_dev); + + ret = rmi_probe_interrupts(data); + if (ret) + return ret; + + ret = rmi_init_functions(data); + if (ret) + return ret; + + if (!data->f01_bootloader_mode || !data->f34_container) { + dev_warn(dev, "%s: No F34 present or not in bootloader!\n", + __func__); + return -EINVAL; + } + + f34 = dev_get_drvdata(&data->f34_container->dev); + + /* Perform firmware update */ + ret = rmi_f34_update_firmware(f34, fw); + + dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret); + + /* Re-probe */ + rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n"); + rmi_free_function_list(data->rmi_dev); + + ret = rmi_scan_pdt(data->rmi_dev, NULL, rmi_initial_reset); + if (ret < 0) + dev_warn(dev, "RMI reset failed!\n"); + + ret = rmi_probe_interrupts(data); + if (ret) + return ret; + + ret = rmi_init_functions(data); + if (ret) + return ret; + + if (data->f01_container->dev.driver) + /* Driver already bound, so enable ATTN now. */ + return rmi_enable_sensor(data->rmi_dev); + + rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__); + + return ret; +} + +static ssize_t rmi_driver_update_fw_store(struct device *dev, + struct device_attribute *dattr, + const char *buf, size_t count) +{ + struct rmi_driver_data *data = dev_get_drvdata(dev); + char fw_name[NAME_MAX]; + const struct firmware *fw; + size_t copy_count = count; + int ret; + + if (count == 0 || count >= NAME_MAX) + return -EINVAL; + + if (buf[count - 1] == '\0' || buf[count - 1] == '\n') + copy_count -= 1; + + strncpy(fw_name, buf, copy_count); + fw_name[copy_count] = '\0'; + + ret = request_firmware(&fw, fw_name, dev); + if (ret) + return ret; + + dev_info(dev, "Flashing %s\n", fw_name); + + ret = rmi_firmware_update(data, fw); + + release_firmware(fw); + + return ret ?: count; +} + +static DEVICE_ATTR(update_fw, 0200, NULL, rmi_driver_update_fw_store); + +static struct attribute *rmi_firmware_attrs[] = { + &dev_attr_update_fw.attr, + NULL +}; + +static struct attribute_group rmi_firmware_attr_group = { + .attrs = rmi_firmware_attrs, +}; + +static int rmi_f34_probe(struct rmi_function *fn) +{ + struct f34_data *f34; + unsigned char f34_queries[9]; + bool has_config_id; + int ret; + + f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL); + if (!f34) + return -ENOMEM; + + f34->fn = fn; + dev_set_drvdata(&fn->dev, f34); + + ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, + f34_queries, sizeof(f34_queries)); + if (ret) { + dev_err(&fn->dev, "%s: Failed to query properties\n", + __func__); + return ret; + } + + snprintf(f34->bootloader_id, sizeof(f34->bootloader_id), + "%c%c", f34_queries[0], f34_queries[1]); + + mutex_init(&f34->v5.flash_mutex); + init_completion(&f34->v5.cmd_done); + + f34->v5.block_size = get_unaligned_le16(&f34_queries[3]); + f34->v5.fw_blocks = get_unaligned_le16(&f34_queries[5]); + f34->v5.config_blocks = get_unaligned_le16(&f34_queries[7]); + f34->v5.ctrl_address = fn->fd.data_base_addr + F34_BLOCK_DATA_OFFSET + + f34->v5.block_size; + has_config_id = f34_queries[2] & (1 << 2); + + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Bootloader ID: %s\n", + f34->bootloader_id); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Block size: %d\n", + f34->v5.block_size); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "FW blocks: %d\n", + f34->v5.fw_blocks); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "CFG blocks: %d\n", + f34->v5.config_blocks); + + if (has_config_id) { + ret = rmi_read_block(fn->rmi_dev, fn->fd.control_base_addr, + f34_queries, sizeof(f34_queries)); + if (ret) { + dev_err(&fn->dev, "Failed to read F34 config ID\n"); + return ret; + } + + snprintf(f34->configuration_id, sizeof(f34->configuration_id), + "%02x%02x%02x%02x", + f34_queries[0], f34_queries[1], + f34_queries[2], f34_queries[3]); + + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "Configuration ID: %s\n", + f34->configuration_id); + } + + return 0; +} + +int rmi_f34_create_sysfs(struct rmi_device *rmi_dev) +{ + return sysfs_create_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group); +} + +void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev) +{ + sysfs_remove_group(&rmi_dev->dev.kobj, &rmi_firmware_attr_group); +} + +struct rmi_function_handler rmi_f34_handler = { + .driver = { + .name = "rmi4_f34", + }, + .func = 0x34, + .probe = rmi_f34_probe, + .attention = rmi_f34_attention, +}; diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h new file mode 100644 index 000000000000..6cee5282fbb4 --- /dev/null +++ b/drivers/input/rmi4/rmi_f34.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2007-2016, Synaptics Incorporated + * Copyright (C) 2016 Zodiac Inflight Innovations + * + * 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 _RMI_F34_H +#define _RMI_F34_H + +/* F34 image file offsets. */ +#define F34_FW_IMAGE_OFFSET 0x100 + +/* F34 register offsets. */ +#define F34_BLOCK_DATA_OFFSET 2 + +/* F34 commands */ +#define F34_WRITE_FW_BLOCK 0x2 +#define F34_ERASE_ALL 0x3 +#define F34_READ_CONFIG_BLOCK 0x5 +#define F34_WRITE_CONFIG_BLOCK 0x6 +#define F34_ERASE_CONFIG 0x7 +#define F34_ENABLE_FLASH_PROG 0xf + +#define F34_STATUS_IN_PROGRESS 0xff +#define F34_STATUS_IDLE 0x80 + +#define F34_IDLE_WAIT_MS 500 +#define F34_ENABLE_WAIT_MS 300 +#define F34_ERASE_WAIT_MS 5000 + +#define F34_BOOTLOADER_ID_LEN 2 + +struct rmi_f34_firmware { + __le32 checksum; + u8 pad1[3]; + u8 bootloader_version; + __le32 image_size; + __le32 config_size; + u8 product_id[10]; + u8 product_info[2]; + u8 pad2[228]; + u8 data[]; +}; + +struct f34v5_data { + u16 block_size; + u16 fw_blocks; + u16 config_blocks; + u16 ctrl_address; + u8 status; + + struct completion cmd_done; + struct mutex flash_mutex; +}; + +struct f34_data { + struct rmi_function *fn; + + unsigned char bootloader_id[5]; + unsigned char configuration_id[9]; + + struct f34v5_data v5; +}; + +#endif /* _RMI_F34_H */ diff --git a/include/linux/rmi.h b/include/linux/rmi.h index ac904bb439a5..4096b0246c23 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -337,11 +337,13 @@ struct rmi_driver_data { struct rmi_device *rmi_dev; struct rmi_function *f01_container; + struct rmi_function *f34_container; bool f01_bootloader_mode; u32 attn_count; int num_of_irq_regs; int irq_count; + void *irq_memory; unsigned long *irq_status; unsigned long *fn_irq_bits; unsigned long *current_irq_mask; -- cgit v1.2.3 From 6adba43fd222ea362c36296d1a6897c2e28fdc8e Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 22 Nov 2016 17:53:26 -0800 Subject: Input: synaptics-rmi4 - add support for F55 sensor tuning Sensor tuning support is needed to determine the number of enabled tx and rx electrodes for use in F54 functions. The number of enabled electrodes is not identical to the total number of electrodes as reported with F55:Query0 and F55:Query1. It has to be calculated by analyzing F55:Ctrl1 (sensor receiver assignment) and F55:Ctrl2 (sensor transmitter assignment). Support for additional sensor tuning functions may be added later. Fixes: 3a762dbd5347 ("[media] Input: synaptics-rmi4 - add support for F54 ...") Signed-off-by: Guenter Roeck Tested-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/Kconfig | 9 +++ drivers/input/rmi4/Makefile | 1 + drivers/input/rmi4/rmi_bus.c | 3 + drivers/input/rmi4/rmi_driver.h | 1 + drivers/input/rmi4/rmi_f55.c | 124 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 138 insertions(+) create mode 100644 drivers/input/rmi4/rmi_f55.c (limited to 'drivers') diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index 9a24867ae7a5..f4460f3ebac5 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -95,3 +95,12 @@ config RMI4_F54 Function 54 provides access to various diagnostic features in certain RMI4 touch sensors. + +config RMI4_F55 + bool "RMI4 Function 55 (Sensor tuning)" + depends on RMI4_CORE + help + Say Y here if you want to add support for RMI4 function 55 + + Function 55 provides access to the RMI4 touch sensor tuning + mechanism. diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index 0250abf38ad9..e7f4ca6c0508 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -9,6 +9,7 @@ rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o +rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o # Transports obj-$(CONFIG_RMI4_I2C) += rmi_i2c.o diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index ef7a66230d83..2534331ad9dc 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -321,6 +321,9 @@ static struct rmi_function_handler *fn_handlers[] = { #ifdef CONFIG_RMI4_F54 &rmi_f54_handler, #endif +#ifdef CONFIG_RMI4_F55 + &rmi_f55_handler, +#endif }; static void __rmi_unregister_function_handlers(int start_idx) diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index e627a3a8aced..5b201f369505 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -127,4 +127,5 @@ extern struct rmi_function_handler rmi_f12_handler; extern struct rmi_function_handler rmi_f30_handler; extern struct rmi_function_handler rmi_f34_handler; extern struct rmi_function_handler rmi_f54_handler; +extern struct rmi_function_handler rmi_f55_handler; #endif diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c new file mode 100644 index 000000000000..2d221cc97391 --- /dev/null +++ b/drivers/input/rmi4/rmi_f55.c @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2012-2015 Synaptics Incorporated + * Copyright (C) 2016 Zodiac Inflight Innovations + * + * 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 "rmi_driver.h" + +#define F55_NAME "rmi4_f55" + +/* F55 data offsets */ +#define F55_NUM_RX_OFFSET 0 +#define F55_NUM_TX_OFFSET 1 +#define F55_PHYS_CHAR_OFFSET 2 + +/* Only read required query registers */ +#define F55_QUERY_LEN 3 + +/* F55 capabilities */ +#define F55_CAP_SENSOR_ASSIGN BIT(0) + +struct f55_data { + struct rmi_function *fn; + + u8 qry[F55_QUERY_LEN]; + u8 num_rx_electrodes; + u8 cfg_num_rx_electrodes; + u8 num_tx_electrodes; + u8 cfg_num_tx_electrodes; +}; + +static int rmi_f55_detect(struct rmi_function *fn) +{ + struct f55_data *f55; + int error; + + f55 = dev_get_drvdata(&fn->dev); + + error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, + &f55->qry, sizeof(f55->qry)); + if (error) { + dev_err(&fn->dev, "%s: Failed to query F55 properties\n", + __func__); + return error; + } + + f55->num_rx_electrodes = f55->qry[F55_NUM_RX_OFFSET]; + f55->num_tx_electrodes = f55->qry[F55_NUM_TX_OFFSET]; + + f55->cfg_num_rx_electrodes = f55->num_rx_electrodes; + f55->cfg_num_tx_electrodes = f55->num_rx_electrodes; + + if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) { + int i, total; + u8 buf[256]; + + /* + * Calculate the number of enabled receive and transmit + * electrodes by reading F55:Ctrl1 (sensor receiver assignment) + * and F55:Ctrl2 (sensor transmitter assignment). The number of + * enabled electrodes is the sum of all field entries with a + * value other than 0xff. + */ + error = rmi_read_block(fn->rmi_dev, + fn->fd.control_base_addr + 1, + buf, f55->num_rx_electrodes); + if (!error) { + total = 0; + for (i = 0; i < f55->num_rx_electrodes; i++) { + if (buf[i] != 0xff) + total++; + } + f55->cfg_num_rx_electrodes = total; + } + + error = rmi_read_block(fn->rmi_dev, + fn->fd.control_base_addr + 2, + buf, f55->num_tx_electrodes); + if (!error) { + total = 0; + for (i = 0; i < f55->num_tx_electrodes; i++) { + if (buf[i] != 0xff) + total++; + } + f55->cfg_num_tx_electrodes = total; + } + } + + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_rx_electrodes: %d (raw %d)\n", + f55->cfg_num_rx_electrodes, f55->num_rx_electrodes); + rmi_dbg(RMI_DEBUG_FN, &fn->dev, "F55 num_tx_electrodes: %d (raw %d)\n", + f55->cfg_num_tx_electrodes, f55->num_tx_electrodes); + + return 0; +} + +static int rmi_f55_probe(struct rmi_function *fn) +{ + struct f55_data *f55; + + f55 = devm_kzalloc(&fn->dev, sizeof(struct f55_data), GFP_KERNEL); + if (!f55) + return -ENOMEM; + + f55->fn = fn; + dev_set_drvdata(&fn->dev, f55); + + return rmi_f55_detect(fn); +} + +struct rmi_function_handler rmi_f55_handler = { + .driver = { + .name = F55_NAME, + }, + .func = 0x55, + .probe = rmi_f55_probe, +}; -- cgit v1.2.3 From c762cc68b6a12eedebefc156ea4838e54804e2eb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 22 Nov 2016 17:57:02 -0800 Subject: Input: synaptics-rmi4 - propagate correct number of rx and tx electrodes to F54 F54 diagnostics report functions provide data based on the number of enabled rx and tx electrodes, which is not identical to the number of electrodes reported with F54:Query0 and F54:Query1. Those values report the number of supported electrodes, not the number of enabled electrodes. The number of enabled electrodes can be determined by analyzing F55:Ctrl1 (sensor receiver assignment) and F55:Ctrl2 (sensor transmitter assignment). Propagate the number of enabled electrodes from F55 to F54 to avoid corrupted output if not all electrodes are enabled. Fixes: 3a762dbd5347 ("[media] Input: synaptics-rmi4 - add support for F54 ...") Signed-off-by: Guenter Roeck Tested-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/Kconfig | 1 + drivers/input/rmi4/rmi_f54.c | 14 ++++++++++---- drivers/input/rmi4/rmi_f55.c | 7 +++++++ include/linux/rmi.h | 3 +++ 4 files changed, 21 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index f4460f3ebac5..a9c36a5fe708 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -90,6 +90,7 @@ config RMI4_F54 depends on RMI4_CORE depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m) select VIDEOBUF2_VMALLOC + select RMI4_F55 help Say Y here if you want to add support for RMI4 function 54 diff --git a/drivers/input/rmi4/rmi_f54.c b/drivers/input/rmi4/rmi_f54.c index 2e934aef3d2a..dea63e2db3e6 100644 --- a/drivers/input/rmi4/rmi_f54.c +++ b/drivers/input/rmi4/rmi_f54.c @@ -217,8 +217,10 @@ unlock: static size_t rmi_f54_get_report_size(struct f54_data *f54) { - u8 rx = f54->num_rx_electrodes ? : f54->num_rx_electrodes; - u8 tx = f54->num_tx_electrodes ? : f54->num_tx_electrodes; + struct rmi_device *rmi_dev = f54->fn->rmi_dev; + struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); + u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes; + u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes; size_t size; switch (rmi_f54_get_reptype(f54, f54->input)) { @@ -402,6 +404,10 @@ static int rmi_f54_vidioc_enum_input(struct file *file, void *priv, static int rmi_f54_set_input(struct f54_data *f54, unsigned int i) { + struct rmi_device *rmi_dev = f54->fn->rmi_dev; + struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); + u8 rx = drv_data->num_rx_electrodes ? : f54->num_rx_electrodes; + u8 tx = drv_data->num_tx_electrodes ? : f54->num_tx_electrodes; struct v4l2_pix_format *f = &f54->format; enum rmi_f54_report_type reptype; int ret; @@ -416,8 +422,8 @@ static int rmi_f54_set_input(struct f54_data *f54, unsigned int i) f54->input = i; - f->width = f54->num_rx_electrodes; - f->height = f54->num_tx_electrodes; + f->width = rx; + f->height = tx; f->field = V4L2_FIELD_NONE; f->colorspace = V4L2_COLORSPACE_RAW; f->bytesperline = f->width * sizeof(u16); diff --git a/drivers/input/rmi4/rmi_f55.c b/drivers/input/rmi4/rmi_f55.c index 2d221cc97391..37390ca6a924 100644 --- a/drivers/input/rmi4/rmi_f55.c +++ b/drivers/input/rmi4/rmi_f55.c @@ -38,6 +38,8 @@ struct f55_data { static int rmi_f55_detect(struct rmi_function *fn) { + struct rmi_device *rmi_dev = fn->rmi_dev; + struct rmi_driver_data *drv_data = dev_get_drvdata(&rmi_dev->dev); struct f55_data *f55; int error; @@ -57,6 +59,9 @@ static int rmi_f55_detect(struct rmi_function *fn) f55->cfg_num_rx_electrodes = f55->num_rx_electrodes; f55->cfg_num_tx_electrodes = f55->num_rx_electrodes; + drv_data->num_rx_electrodes = f55->cfg_num_rx_electrodes; + drv_data->num_tx_electrodes = f55->cfg_num_rx_electrodes; + if (f55->qry[F55_PHYS_CHAR_OFFSET] & F55_CAP_SENSOR_ASSIGN) { int i, total; u8 buf[256]; @@ -78,6 +83,7 @@ static int rmi_f55_detect(struct rmi_function *fn) total++; } f55->cfg_num_rx_electrodes = total; + drv_data->num_rx_electrodes = total; } error = rmi_read_block(fn->rmi_dev, @@ -90,6 +96,7 @@ static int rmi_f55_detect(struct rmi_function *fn) total++; } f55->cfg_num_tx_electrodes = total; + drv_data->num_tx_electrodes = total; } } diff --git a/include/linux/rmi.h b/include/linux/rmi.h index 4096b0246c23..8499b6aa2221 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -354,6 +354,9 @@ struct rmi_driver_data { u8 pdt_props; u8 bsr; + u8 num_rx_electrodes; + u8 num_tx_electrodes; + bool enabled; void *data; -- cgit v1.2.3 From 0e2b4458e9180e0b0d65cadfa729faf84f9f0115 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Tue, 22 Nov 2016 18:03:35 -0800 Subject: Input: i8042 - fix typo from i8042_aux_close to i8042_port_close Signed-off-by: Marcos Paulo de Souza Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c index 89abfdb539ac..62685a768913 100644 --- a/drivers/input/serio/i8042.c +++ b/drivers/input/serio/i8042.c @@ -387,7 +387,7 @@ static int i8042_aux_write(struct serio *serio, unsigned char c) /* - * i8042_aux_close attempts to clear AUX or KBD port state by disabling + * i8042_port_close attempts to clear AUX or KBD port state by disabling * and then re-enabling it. */ -- cgit v1.2.3 From 75ff76687cfd9f62ea4a6d3a86679d5be1439a94 Mon Sep 17 00:00:00 2001 From: Sinan Kaya Date: Sat, 19 Nov 2016 14:28:37 -0500 Subject: dmaengine: qcom_hidma: autoload while probing ACPI MODULE_DEVICE_TABLE is used by the kernel to determine which device driver should be loaded for which platform device. MODULE_DEVICE_TABLE has been only defined for the device-tree based platforms in the current code. Defining it also for ACPI based platforms. Signed-off-by: Sinan Kaya Signed-off-by: Vinod Koul --- drivers/dma/qcom/hidma.c | 1 + drivers/dma/qcom/hidma_mgmt.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/qcom/hidma.c b/drivers/dma/qcom/hidma.c index 248e74bfd95a..3c982c96b4b7 100644 --- a/drivers/dma/qcom/hidma.c +++ b/drivers/dma/qcom/hidma.c @@ -895,6 +895,7 @@ static const struct acpi_device_id hidma_acpi_ids[] = { {"QCOM8062"}, {}, }; +MODULE_DEVICE_TABLE(acpi, hidma_acpi_ids); #endif static const struct of_device_id hidma_match[] = { diff --git a/drivers/dma/qcom/hidma_mgmt.c b/drivers/dma/qcom/hidma_mgmt.c index 985f5ac2695d..f847d32cc4b5 100644 --- a/drivers/dma/qcom/hidma_mgmt.c +++ b/drivers/dma/qcom/hidma_mgmt.c @@ -282,6 +282,7 @@ static const struct acpi_device_id hidma_mgmt_acpi_ids[] = { {"QCOM8060"}, {}, }; +MODULE_DEVICE_TABLE(acpi, hidma_mgmt_acpi_ids); #endif static const struct of_device_id hidma_mgmt_match[] = { -- cgit v1.2.3 From 02b7d2a833b007bae45be8d4adbae0f2a43d8dc4 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 16 Nov 2016 16:40:14 +0200 Subject: soc/qman: Check ioremap return value Signed-off-by: Madalin Bucur Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman_ccsr.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c index 0cace9e0077e..f4e6e70de259 100644 --- a/drivers/soc/fsl/qbman/qman_ccsr.c +++ b/drivers/soc/fsl/qbman/qman_ccsr.c @@ -444,6 +444,9 @@ static int zero_priv_mem(struct device *dev, struct device_node *node, /* map as cacheable, non-guarded */ void __iomem *tmpp = ioremap_prot(addr, sz, 0); + if (!tmpp) + return -ENOMEM; + memset_io(tmpp, 0, sz); flush_dcache_range((unsigned long)tmpp, (unsigned long)tmpp + sz); -- cgit v1.2.3 From 2f28d218d4b82e0eb5c437f25004a4d36e32ab35 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Wed, 16 Nov 2016 16:40:15 +0200 Subject: soc/qman: Replace of_get_property() with portable equivalent Use arch portable of_property_read_u32() instead, which takes care of endianness conversions. Signed-off-by: Madalin Bucur Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/dpaa_sys.h | 1 + drivers/soc/fsl/qbman/qman_portal.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/dpaa_sys.h b/drivers/soc/fsl/qbman/dpaa_sys.h index b63fd72295c6..2eaf3184f61d 100644 --- a/drivers/soc/fsl/qbman/dpaa_sys.h +++ b/drivers/soc/fsl/qbman/dpaa_sys.h @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index 148614388fca..0c3e8adae647 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -238,9 +238,9 @@ static int qman_portal_probe(struct platform_device *pdev) struct device_node *node = dev->of_node; struct qm_portal_config *pcfg; struct resource *addr_phys[2]; - const u32 *channel; void __iomem *va; - int irq, len, cpu; + int irq, cpu, err; + u32 val; pcfg = devm_kmalloc(dev, sizeof(*pcfg), GFP_KERNEL); if (!pcfg) @@ -264,13 +264,13 @@ static int qman_portal_probe(struct platform_device *pdev) return -ENXIO; } - channel = of_get_property(node, "cell-index", &len); - if (!channel || (len != 4)) { + err = of_property_read_u32(node, "cell-index", &val); + if (err) { dev_err(dev, "Can't get %s property 'cell-index'\n", node->full_name); - return -ENXIO; + return err; } - pcfg->channel = *channel; + pcfg->channel = val; pcfg->cpu = -1; irq = platform_get_irq(pdev, 0); if (irq <= 0) { -- cgit v1.2.3 From d95cb0d361d509bda3c351c5933904477b103af0 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:16 +0200 Subject: soc/qman: Fix h/w resource cleanup error path handling qman_query_fq*() may return other error codes apart from -ERANGE, in which cases the error handling done by the resource cleanup callers would be wrong. The patch fixes the handling of those cases, and cleans up related code inside the resource cleanup & release handlers (i.e. replace hardcoded fqid value with corresponding define). Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index deeacd5d123e..e350ed6450ae 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -2789,15 +2789,18 @@ static int qpool_cleanup(u32 qp) struct qm_mcr_queryfq_np np; err = qman_query_fq_np(&fq, &np); - if (err) + if (err == -ERANGE) /* FQID range exceeded, found no problems */ return 0; + else if (WARN_ON(err)) + return err; + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { struct qm_fqd fqd; err = qman_query_fq(&fq, &fqd); if (WARN_ON(err)) - return 0; + return err; if (qm_fqd_get_chan(&fqd) == qp) { /* The channel is the FQ's target, clean it */ err = qman_shutdown_fq(fq.fqid); @@ -2836,7 +2839,7 @@ static int cgr_cleanup(u32 cgrid) * error, looking for non-OOS FQDs whose CGR is the CGR being released */ struct qman_fq fq = { - .fqid = 1 + .fqid = QM_FQID_RANGE_START }; int err; @@ -2844,15 +2847,18 @@ static int cgr_cleanup(u32 cgrid) struct qm_mcr_queryfq_np np; err = qman_query_fq_np(&fq, &np); - if (err) + if (err == -ERANGE) /* FQID range exceeded, found no problems */ return 0; + else if (WARN_ON(err)) + return err; + if ((np.state & QM_MCR_NP_STATE_MASK) != QM_MCR_NP_STATE_OOS) { struct qm_fqd fqd; err = qman_query_fq(&fq, &fqd); if (WARN_ON(err)) - return 0; + return err; if ((fqd.fq_ctrl & QM_FQCTRL_CGE) && fqd.cgid == cgrid) { pr_err("CRGID 0x%x is being used by FQID 0x%x, CGR will be leaked\n", -- cgit v1.2.3 From 333e72cf475065a42b7bf33d76214eca45b9acbb Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:17 +0200 Subject: soc/qbman: Fix resource leak on portal probing error path In case init_pcfg() returns with error the CI region must be unmapped too. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/bman_portal.c | 17 ++++++++++++----- drivers/soc/fsl/qbman/qman_portal.c | 17 ++++++++++++----- 2 files changed, 24 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/bman_portal.c b/drivers/soc/fsl/qbman/bman_portal.c index 6579cc18811a..dd3f5d7617d2 100644 --- a/drivers/soc/fsl/qbman/bman_portal.c +++ b/drivers/soc/fsl/qbman/bman_portal.c @@ -146,15 +146,19 @@ static int bman_portal_probe(struct platform_device *pdev) pcfg->irq = irq; va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CE failed\n"); goto err_ioremap1; + } pcfg->addr_virt[DPAA_PORTAL_CE] = va; va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]), _PAGE_GUARDED | _PAGE_NO_CACHE); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CI failed\n"); goto err_ioremap2; + } pcfg->addr_virt[DPAA_PORTAL_CI] = va; @@ -170,8 +174,10 @@ static int bman_portal_probe(struct platform_device *pdev) spin_unlock(&bman_lock); pcfg->cpu = cpu; - if (!init_pcfg(pcfg)) - goto err_ioremap2; + if (!init_pcfg(pcfg)) { + dev_err(dev, "portal init failed\n"); + goto err_portal_init; + } /* clear irq affinity if assigned cpu is offline */ if (!cpu_online(cpu)) @@ -179,10 +185,11 @@ static int bman_portal_probe(struct platform_device *pdev) return 0; +err_portal_init: + iounmap(pcfg->addr_virt[DPAA_PORTAL_CI]); err_ioremap2: iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]); err_ioremap1: - dev_err(dev, "ioremap failed\n"); return -ENXIO; } diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index 0c3e8adae647..6651168333e1 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -280,15 +280,19 @@ static int qman_portal_probe(struct platform_device *pdev) pcfg->irq = irq; va = ioremap_prot(addr_phys[0]->start, resource_size(addr_phys[0]), 0); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CE failed\n"); goto err_ioremap1; + } pcfg->addr_virt[DPAA_PORTAL_CE] = va; va = ioremap_prot(addr_phys[1]->start, resource_size(addr_phys[1]), _PAGE_GUARDED | _PAGE_NO_CACHE); - if (!va) + if (!va) { + dev_err(dev, "ioremap::CI failed\n"); goto err_ioremap2; + } pcfg->addr_virt[DPAA_PORTAL_CI] = va; @@ -306,8 +310,10 @@ static int qman_portal_probe(struct platform_device *pdev) spin_unlock(&qman_lock); pcfg->cpu = cpu; - if (!init_pcfg(pcfg)) - goto err_ioremap2; + if (!init_pcfg(pcfg)) { + dev_err(dev, "portal init failed\n"); + goto err_portal_init; + } /* clear irq affinity if assigned cpu is offline */ if (!cpu_online(cpu)) @@ -315,10 +321,11 @@ static int qman_portal_probe(struct platform_device *pdev) return 0; +err_portal_init: + iounmap(pcfg->addr_virt[DPAA_PORTAL_CI]); err_ioremap2: iounmap(pcfg->addr_virt[DPAA_PORTAL_CE]); err_ioremap1: - dev_err(dev, "ioremap failed\n"); return -ENXIO; } -- cgit v1.2.3 From b6e969dbaec0fe6633a756468e74151ebb1e6c49 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:19 +0200 Subject: soc/qman: Fix direct access to fd's addr_lo, use proper accesor Use the proper accessor to get the FD address. Accessing the internal field "addr_lo" directly is not portable and error prone. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index e350ed6450ae..96b0f004e007 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -1239,8 +1239,8 @@ static int qman_create_portal(struct qman_portal *portal, /* special handling, drain just in case it's a few FQRNIs */ const union qm_mr_entry *e = qm_mr_current(p); - dev_err(c->dev, "MR dirty, VB 0x%x, rc 0x%x\n, addr 0x%x", - e->verb, e->ern.rc, e->ern.fd.addr_lo); + dev_err(c->dev, "MR dirty, VB 0x%x, rc 0x%x, addr 0x%llx\n", + e->verb, e->ern.rc, qm_fd_addr_get64(&e->ern.fd)); goto fail_dqrr_mr_empty; } /* Success */ -- cgit v1.2.3 From 57e68a5e23570ff3ab76772a974724c226fcee7d Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:20 +0200 Subject: soc/qman: test: Fix implementation of fd_cmp() This function must only return the truth value of whether two frame descriptors are different or not. It does NOT have to compute some obscure difference between fd fields and return it as an int, making sparse complain about type conversions in the process. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman_test_api.c | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman_test_api.c b/drivers/soc/fsl/qbman/qman_test_api.c index 6880ff17f45e..dba6a80622ed 100644 --- a/drivers/soc/fsl/qbman/qman_test_api.c +++ b/drivers/soc/fsl/qbman/qman_test_api.c @@ -90,22 +90,15 @@ static void fd_inc(struct qm_fd *fd) } /* The only part of the 'fd' we can't memcmp() is the ppid */ -static int fd_cmp(const struct qm_fd *a, const struct qm_fd *b) +static bool fd_neq(const struct qm_fd *a, const struct qm_fd *b) { - int r = (qm_fd_addr_get64(a) == qm_fd_addr_get64(b)) ? 0 : -1; + bool neq = qm_fd_addr_get64(a) != qm_fd_addr_get64(b); - if (!r) { - enum qm_fd_format fmt_a, fmt_b; + neq |= qm_fd_get_format(a) != qm_fd_get_format(b); + neq |= a->cfg != b->cfg; + neq |= a->cmd != b->cmd; - fmt_a = qm_fd_get_format(a); - fmt_b = qm_fd_get_format(b); - r = fmt_a - fmt_b; - } - if (!r) - r = a->cfg - b->cfg; - if (!r) - r = a->cmd - b->cmd; - return r; + return neq; } /* test */ @@ -217,12 +210,12 @@ static enum qman_cb_dqrr_result cb_dqrr(struct qman_portal *p, struct qman_fq *fq, const struct qm_dqrr_entry *dq) { - if (WARN_ON(fd_cmp(&fd_dq, &dq->fd))) { + if (WARN_ON(fd_neq(&fd_dq, &dq->fd))) { pr_err("BADNESS: dequeued frame doesn't match;\n"); return qman_cb_dqrr_consume; } fd_inc(&fd_dq); - if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_cmp(&fd_dq, &fd)) { + if (!(dq->stat & QM_DQRR_STAT_UNSCHEDULED) && !fd_neq(&fd_dq, &fd)) { sdqcr_complete = 1; wake_up(&waitqueue); } -- cgit v1.2.3 From 0fbeac3b0f67a50d45e8a7d72ee3e0301ac7e9a9 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:21 +0200 Subject: soc/qman: Don't add a new platform device for dma mapping The qman portals are platform devices themselves, so they should handle dma mappings. Creating a dummy platform device in order to support dma mapping operations is not justified (and not portable). Instead, do the mapping against the first portal that has been initialised. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 31 ++++++++++--------------------- drivers/soc/fsl/qbman/qman_portal.c | 11 +++++++++++ drivers/soc/fsl/qbman/qman_priv.h | 1 + 3 files changed, 22 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 96b0f004e007..4ceb9a1da7ee 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -962,8 +962,6 @@ struct qman_portal { u32 sdqcr; /* probing time config params for cpu-affine portals */ const struct qm_portal_config *config; - /* needed for providing a non-NULL device to dma_map_***() */ - struct platform_device *pdev; /* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */ struct qman_cgrs *cgrs; /* linked-list of CSCN handlers. */ @@ -1133,7 +1131,6 @@ static int qman_create_portal(struct qman_portal *portal, const struct qman_cgrs *cgrs) { struct qm_portal *p; - char buf[16]; int ret; u32 isdr; @@ -1196,15 +1193,6 @@ static int qman_create_portal(struct qman_portal *portal, portal->sdqcr = QM_SDQCR_SOURCE_CHANNELS | QM_SDQCR_COUNT_UPTO3 | QM_SDQCR_DEDICATED_PRECEDENCE | QM_SDQCR_TYPE_PRIO_QOS | QM_SDQCR_TOKEN_SET(0xab) | QM_SDQCR_CHANNELS_DEDICATED; - sprintf(buf, "qportal-%d", c->channel); - portal->pdev = platform_device_alloc(buf, -1); - if (!portal->pdev) - goto fail_devalloc; - if (dma_set_mask(&portal->pdev->dev, DMA_BIT_MASK(40))) - goto fail_devadd; - ret = platform_device_add(portal->pdev); - if (ret) - goto fail_devadd; isdr = 0xffffffff; qm_out(p, QM_REG_ISDR, isdr); portal->irq_sources = 0; @@ -1256,10 +1244,6 @@ fail_eqcr_empty: fail_affinity: free_irq(c->irq, portal); fail_irq: - platform_device_del(portal->pdev); -fail_devadd: - platform_device_put(portal->pdev); -fail_devalloc: kfree(portal->cgrs); fail_cgrs: qm_mc_finish(p); @@ -1321,9 +1305,6 @@ static void qman_destroy_portal(struct qman_portal *qm) qm_dqrr_finish(&qm->p); qm_eqcr_finish(&qm->p); - platform_device_del(qm->pdev); - platform_device_put(qm->pdev); - qm->config = NULL; } @@ -1817,8 +1798,16 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) memset(&mcc->initfq.fqd.context_a, 0, sizeof(mcc->initfq.fqd.context_a)); } else { - phys_fq = dma_map_single(&p->pdev->dev, fq, sizeof(*fq), - DMA_TO_DEVICE); + struct qman_portal *p = qman_dma_portal; + + phys_fq = dma_map_single(p->config->dev, fq, + sizeof(*fq), DMA_TO_DEVICE); + if (dma_mapping_error(p->config->dev, phys_fq)) { + dev_err(p->config->dev, "dma_mapping failed\n"); + ret = -EIO; + goto out; + } + qm_fqd_stashing_set64(&mcc->initfq.fqd, phys_fq); } } diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index 6651168333e1..e6da2ea78554 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -30,6 +30,8 @@ #include "qman_priv.h" +struct qman_portal *qman_dma_portal; + /* Enable portal interupts (as opposed to polling mode) */ #define CONFIG_FSL_DPA_PIRQ_SLOW 1 #define CONFIG_FSL_DPA_PIRQ_FAST 1 @@ -150,6 +152,10 @@ static struct qman_portal *init_pcfg(struct qm_portal_config *pcfg) /* all assigned portals are initialized now */ qman_init_cgr_all(); } + + if (!qman_dma_portal) + qman_dma_portal = p; + spin_unlock(&qman_lock); dev_info(pcfg->dev, "Portal initialised, cpu %d\n", pcfg->cpu); @@ -310,6 +316,11 @@ static int qman_portal_probe(struct platform_device *pdev) spin_unlock(&qman_lock); pcfg->cpu = cpu; + if (dma_set_mask(dev, DMA_BIT_MASK(40))) { + dev_err(dev, "dma_set_mask() failed\n"); + goto err_portal_init; + } + if (!init_pcfg(pcfg)) { dev_err(dev, "portal init failed\n"); goto err_portal_init; diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h index 5cf821e623a9..59b4b463d884 100644 --- a/drivers/soc/fsl/qbman/qman_priv.h +++ b/drivers/soc/fsl/qbman/qman_priv.h @@ -367,5 +367,6 @@ int qman_alloc_fq_table(u32 num_fqids); #define QM_PIRQ_VISIBLE (QM_PIRQ_SLOW | QM_PIRQ_DQRI) extern struct qman_portal *affine_portals[NR_CPUS]; +extern struct qman_portal *qman_dma_portal; const struct qm_portal_config *qman_get_qm_portal_config( struct qman_portal *portal); -- cgit v1.2.3 From 021ba010663146305b0ba51246a41223d38943af Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:22 +0200 Subject: soc/qman: test: Don't use dummy platform device for dma mapping Replace dummy platform device hack with a reference to a portal's platform device, in order to dma map the test frame for this small unit test. The 2 qman symbols need to be exported because this self test is a kernel module. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 1 + drivers/soc/fsl/qbman/qman_portal.c | 1 + drivers/soc/fsl/qbman/qman_test_stash.c | 31 ++++++++++++++++++++----------- 3 files changed, 22 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 4ceb9a1da7ee..307c818e14ab 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -2711,6 +2711,7 @@ const struct qm_portal_config *qman_get_qm_portal_config( { return portal->config; } +EXPORT_SYMBOL(qman_get_qm_portal_config); struct gen_pool *qm_fqalloc; /* FQID allocator */ struct gen_pool *qm_qpalloc; /* pool-channel allocator */ diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c index e6da2ea78554..c9a9bcb1aea2 100644 --- a/drivers/soc/fsl/qbman/qman_portal.c +++ b/drivers/soc/fsl/qbman/qman_portal.c @@ -31,6 +31,7 @@ #include "qman_priv.h" struct qman_portal *qman_dma_portal; +EXPORT_SYMBOL(qman_dma_portal); /* Enable portal interupts (as opposed to polling mode) */ #define CONFIG_FSL_DPA_PIRQ_SLOW 1 diff --git a/drivers/soc/fsl/qbman/qman_test_stash.c b/drivers/soc/fsl/qbman/qman_test_stash.c index 43cf66ba42f5..f8d25faf4d8a 100644 --- a/drivers/soc/fsl/qbman/qman_test_stash.c +++ b/drivers/soc/fsl/qbman/qman_test_stash.c @@ -191,6 +191,9 @@ static void *__frame_ptr; static u32 *frame_ptr; static dma_addr_t frame_dma; +/* needed for dma_map*() */ +static const struct qm_portal_config *pcfg; + /* the main function waits on this */ static DECLARE_WAIT_QUEUE_HEAD(queue); @@ -210,16 +213,14 @@ static int allocate_frame_data(void) { u32 lfsr = HP_FIRST_WORD; int loop; - struct platform_device *pdev = platform_device_alloc("foobar", -1); - if (!pdev) { - pr_crit("platform_device_alloc() failed"); - return -EIO; - } - if (platform_device_add(pdev)) { - pr_crit("platform_device_add() failed"); + if (!qman_dma_portal) { + pr_crit("portal not available\n"); return -EIO; } + + pcfg = qman_get_qm_portal_config(qman_dma_portal); + __frame_ptr = kmalloc(4 * HP_NUM_WORDS, GFP_KERNEL); if (!__frame_ptr) return -ENOMEM; @@ -229,15 +230,22 @@ static int allocate_frame_data(void) frame_ptr[loop] = lfsr; lfsr = do_lfsr(lfsr); } - frame_dma = dma_map_single(&pdev->dev, frame_ptr, 4 * HP_NUM_WORDS, + + frame_dma = dma_map_single(pcfg->dev, frame_ptr, 4 * HP_NUM_WORDS, DMA_BIDIRECTIONAL); - platform_device_del(pdev); - platform_device_put(pdev); + if (dma_mapping_error(pcfg->dev, frame_dma)) { + pr_crit("dma mapping failure\n"); + kfree(__frame_ptr); + return -EIO; + } + return 0; } static void deallocate_frame_data(void) { + dma_unmap_single(pcfg->dev, frame_dma, 4 * HP_NUM_WORDS, + DMA_BIDIRECTIONAL); kfree(__frame_ptr); } @@ -249,7 +257,8 @@ static inline int process_frame_data(struct hp_handler *handler, int loop; if (qm_fd_addr_get64(fd) != handler->addr) { - pr_crit("bad frame address"); + pr_crit("bad frame address, [%llX != %llX]\n", + qm_fd_addr_get64(fd), handler->addr); return -EIO; } for (loop = 0; loop < HP_NUM_WORDS; loop++, p++) { -- cgit v1.2.3 From e5caf693ac6ac498ef05c7c1947024d5b678626f Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:23 +0200 Subject: soc/qman: Remove redundant checks from qman_create_cgr() opts is checked redundantly. Move local_opts declaration inside its usage scope. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 307c818e14ab..4a1697eefcdf 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -2294,7 +2294,6 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags, struct qm_mcc_initcgr *opts) { struct qm_mcr_querycgr cgr_state; - struct qm_mcc_initcgr local_opts = {}; int ret; struct qman_portal *p; @@ -2316,11 +2315,12 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags, spin_lock(&p->cgr_lock); if (opts) { + struct qm_mcc_initcgr local_opts = *opts; + ret = qman_query_cgr(cgr, &cgr_state); if (ret) goto out; - if (opts) - local_opts = *opts; + if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) local_opts.cgr.cscn_targ_upd_ctrl = QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p); @@ -2331,7 +2331,7 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags, local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; /* send init if flags indicate so */ - if (opts && (flags & QMAN_CGR_FLAG_USE_INIT)) + if (flags & QMAN_CGR_FLAG_USE_INIT) ret = qm_modify_cgr(cgr, QMAN_CGR_FLAG_USE_INIT, &local_opts); else -- cgit v1.2.3 From 7ff07da015c290cd2b0627c53267fbc1336cf055 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:24 +0200 Subject: soc/qman: Remove unused struct qm_mcc* layouts 1. qm_mcc_querywq layout not used for now, so drop it; 2. queryfq, queryfq_np and alterfq are used only for accesses to the 'fqid' field, so replace these with a generic 'fq' layout. As a consequence, 'querycgr' turns into 'cgr' following the same reasoning above and for consistent naming. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 58 ++++++++++++--------------------------- drivers/soc/fsl/qbman/qman_priv.h | 6 ---- 2 files changed, 18 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 4a1697eefcdf..0d2e3bcaaf9e 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -183,41 +183,22 @@ struct qm_mr { }; /* MC (Management Command) command */ -/* "Query FQ" */ -struct qm_mcc_queryfq { +/* "FQ" command layout */ +struct qm_mcc_fq { u8 _ncw_verb; u8 __reserved1[3]; u32 fqid; /* 24-bit */ u8 __reserved2[56]; } __packed; -/* "Alter FQ State Commands " */ -struct qm_mcc_alterfq { - u8 _ncw_verb; - u8 __reserved1[3]; - u32 fqid; /* 24-bit */ - u8 __reserved2; - u8 count; /* number of consecutive FQID */ - u8 __reserved3[10]; - u32 context_b; /* frame queue context b */ - u8 __reserved4[40]; -} __packed; -/* "Query CGR" */ -struct qm_mcc_querycgr { +/* "CGR" command layout */ +struct qm_mcc_cgr { u8 _ncw_verb; u8 __reserved1[30]; u8 cgid; u8 __reserved2[32]; }; -struct qm_mcc_querywq { - u8 _ncw_verb; - u8 __reserved; - /* select channel if verb != QUERYWQ_DEDICATED */ - u16 channel_wq; /* ignores wq (3 lsbits): _res[0-2] */ - u8 __reserved2[60]; -} __packed; - #define QM_MCC_VERB_VBIT 0x80 #define QM_MCC_VERB_MASK 0x7f /* where the verb contains; */ #define QM_MCC_VERB_INITFQ_PARKED 0x40 @@ -243,12 +224,9 @@ union qm_mc_command { u8 __reserved[63]; }; struct qm_mcc_initfq initfq; - struct qm_mcc_queryfq queryfq; - struct qm_mcc_alterfq alterfq; struct qm_mcc_initcgr initcgr; - struct qm_mcc_querycgr querycgr; - struct qm_mcc_querywq querywq; - struct qm_mcc_queryfq_np queryfq_np; + struct qm_mcc_fq fq; + struct qm_mcc_cgr cgr; }; /* MC (Management Command) result */ @@ -1777,7 +1755,7 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) mcc = qm_mc_start(&p->p); if (opts) mcc->initfq = *opts; - mcc->initfq.fqid = fq->fqid; + mcc->fq.fqid = fq->fqid; mcc->initfq.count = 0; /* * If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a @@ -1873,7 +1851,7 @@ int qman_schedule_fq(struct qman_fq *fq) goto out; } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fq->fqid; + mcc->fq.fqid = fq->fqid; qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(p->config->dev, "ALTER_SCHED timeout\n"); @@ -1916,7 +1894,7 @@ int qman_retire_fq(struct qman_fq *fq, u32 *flags) goto out; } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fq->fqid; + mcc->fq.fqid = fq->fqid; qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_crit(p->config->dev, "ALTER_RETIRE timeout\n"); @@ -1995,7 +1973,7 @@ int qman_oos_fq(struct qman_fq *fq) goto out; } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fq->fqid; + mcc->fq.fqid = fq->fqid; qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2021,7 +1999,7 @@ int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd) int ret = 0; mcc = qm_mc_start(&p->p); - mcc->queryfq.fqid = fq->fqid; + mcc->fq.fqid = fq->fqid; qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2047,7 +2025,7 @@ static int qman_query_fq_np(struct qman_fq *fq, int ret = 0; mcc = qm_mc_start(&p->p); - mcc->queryfq.fqid = fq->fqid; + mcc->fq.fqid = fq->fqid; qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2075,7 +2053,7 @@ static int qman_query_cgr(struct qman_cgr *cgr, int ret = 0; mcc = qm_mc_start(&p->p); - mcc->querycgr.cgid = cgr->cgrid; + mcc->cgr.cgid = cgr->cgrid; qm_mc_commit(&p->p, QM_MCC_VERB_QUERYCGR); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2526,7 +2504,7 @@ static int qman_shutdown_fq(u32 fqid) dev = p->config->dev; /* Determine the state of the FQID */ mcc = qm_mc_start(&p->p); - mcc->queryfq_np.fqid = fqid; + mcc->fq.fqid = fqid; qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ_NP timeout\n"); @@ -2541,7 +2519,7 @@ static int qman_shutdown_fq(u32 fqid) /* Query which channel the FQ is using */ mcc = qm_mc_start(&p->p); - mcc->queryfq.fqid = fqid; + mcc->fq.fqid = fqid; qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ timeout\n"); @@ -2561,7 +2539,7 @@ static int qman_shutdown_fq(u32 fqid) case QM_MCR_NP_STATE_PARKED: orl_empty = 0; mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fqid; + mcc->fq.fqid = fqid; qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ_NP timeout\n"); @@ -2656,7 +2634,7 @@ static int qman_shutdown_fq(u32 fqid) cpu_relax(); } mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fqid; + mcc->fq.fqid = fqid; qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2676,7 +2654,7 @@ static int qman_shutdown_fq(u32 fqid) case QM_MCR_NP_STATE_RETIRED: /* Send OOS Command */ mcc = qm_mc_start(&p->p); - mcc->alterfq.fqid = fqid; + mcc->fq.fqid = fqid; qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h index 59b4b463d884..5606d74c21d4 100644 --- a/drivers/soc/fsl/qbman/qman_priv.h +++ b/drivers/soc/fsl/qbman/qman_priv.h @@ -90,12 +90,6 @@ static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q) } /* "Query FQ Non-Programmable Fields" */ -struct qm_mcc_queryfq_np { - u8 _ncw_verb; - u8 __reserved1[3]; - u32 fqid; /* 24-bit */ - u8 __reserved2[56]; -} __packed; struct qm_mcr_queryfq_np { u8 verb; -- cgit v1.2.3 From d6753c7e65e70e90ea991797059f4204b66cf523 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:25 +0200 Subject: soc/qman: Fix accesses to fqid, cleanup Preventively mask every access to the 'fqid' h/w field, since it is defined as a 24-bit field, for every h/w descriptor. Add generic accessors for this field to ensure correct access. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 32 ++++++++++++++++---------------- include/soc/fsl/qman.h | 5 +++++ 2 files changed, 21 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 0d2e3bcaaf9e..06626bee0e7e 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -471,7 +471,7 @@ static inline void eqcr_commit_checks(struct qm_eqcr *eqcr) { DPAA_ASSERT(eqcr->busy); DPAA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); - DPAA_ASSERT(eqcr->cursor->fqid == (eqcr->cursor->fqid & 0x00ffffff)); + DPAA_ASSERT(!(eqcr->cursor->fqid & ~QM_FQID_MASK)); DPAA_ASSERT(eqcr->available >= 1); } @@ -1387,7 +1387,7 @@ static void qm_mr_process_task(struct work_struct *work) case QM_MR_VERB_FQRN: case QM_MR_VERB_FQRL: /* Lookup in the retirement table */ - fq = fqid_to_fq(msg->fq.fqid); + fq = fqid_to_fq(qm_fqid_get(&msg->fq)); if (WARN_ON(!fq)) break; fq_state_change(p, fq, msg, verb); @@ -1755,7 +1755,7 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) mcc = qm_mc_start(&p->p); if (opts) mcc->initfq = *opts; - mcc->fq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); mcc->initfq.count = 0; /* * If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a @@ -1851,7 +1851,7 @@ int qman_schedule_fq(struct qman_fq *fq) goto out; } mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_SCHED); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(p->config->dev, "ALTER_SCHED timeout\n"); @@ -1894,7 +1894,7 @@ int qman_retire_fq(struct qman_fq *fq, u32 *flags) goto out; } mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_crit(p->config->dev, "ALTER_RETIRE timeout\n"); @@ -1937,7 +1937,7 @@ int qman_retire_fq(struct qman_fq *fq, u32 *flags) msg.verb = QM_MR_VERB_FQRNI; msg.fq.fqs = mcr->alterfq.fqs; - msg.fq.fqid = fq->fqid; + qm_fqid_set(&msg.fq, fq->fqid); msg.fq.contextB = fq_to_tag(fq); fq->cb.fqs(p, fq, &msg); } @@ -1973,7 +1973,7 @@ int qman_oos_fq(struct qman_fq *fq) goto out; } mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -1999,7 +1999,7 @@ int qman_query_fq(struct qman_fq *fq, struct qm_fqd *fqd) int ret = 0; mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2025,7 +2025,7 @@ static int qman_query_fq_np(struct qman_fq *fq, int ret = 0; mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fq->fqid; + qm_fqid_set(&mcc->fq, fq->fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2206,7 +2206,7 @@ int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd) if (unlikely(!eq)) goto out; - eq->fqid = fq->fqid; + qm_fqid_set(eq, fq->fqid); eq->tag = fq_to_tag(fq); eq->fd = *fd; @@ -2468,7 +2468,7 @@ static int _qm_dqrr_consume_and_match(struct qm_portal *p, u32 fqid, int s, } while (wait && !dqrr); while (dqrr) { - if (dqrr->fqid == fqid && (dqrr->stat & s)) + if (qm_fqid_get(dqrr) == fqid && (dqrr->stat & s)) found = 1; qm_dqrr_cdc_consume_1ptr(p, dqrr, 0); qm_dqrr_pvb_update(p); @@ -2504,7 +2504,7 @@ static int qman_shutdown_fq(u32 fqid) dev = p->config->dev; /* Determine the state of the FQID */ mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ_NP); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ_NP timeout\n"); @@ -2519,7 +2519,7 @@ static int qman_shutdown_fq(u32 fqid) /* Query which channel the FQ is using */ mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_QUERYFQ); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ timeout\n"); @@ -2539,7 +2539,7 @@ static int qman_shutdown_fq(u32 fqid) case QM_MCR_NP_STATE_PARKED: orl_empty = 0; mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); if (!qm_mc_result_timeout(&p->p, &mcr)) { dev_err(dev, "QUERYFQ_NP timeout\n"); @@ -2634,7 +2634,7 @@ static int qman_shutdown_fq(u32 fqid) cpu_relax(); } mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; @@ -2654,7 +2654,7 @@ static int qman_shutdown_fq(u32 fqid) case QM_MCR_NP_STATE_RETIRED: /* Send OOS Command */ mcc = qm_mc_start(&p->p); - mcc->fq.fqid = fqid; + qm_fqid_set(&mcc->fq, fqid); qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_OOS); if (!qm_mc_result_timeout(&p->p, &mcr)) { ret = -ETIMEDOUT; diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h index 1405810e4050..f3fa53fef421 100644 --- a/include/soc/fsl/qman.h +++ b/include/soc/fsl/qman.h @@ -262,6 +262,11 @@ struct qm_dqrr_entry { #define QM_DQRR_STAT_UNSCHEDULED 0x02 /* Unscheduled dequeue */ #define QM_DQRR_STAT_DQCR_EXPIRED 0x01 /* VDQCR or PDQCR expired*/ +/* 'fqid' is a 24-bit field in every h/w descriptor */ +#define QM_FQID_MASK GENMASK(23, 0) +#define qm_fqid_set(p, v) ((p)->fqid = ((v) & QM_FQID_MASK)) +#define qm_fqid_get(p) ((p)->fqid & QM_FQID_MASK) + /* "ERN Message Response" */ /* "FQ State Change Notification" */ union qm_mr_entry { -- cgit v1.2.3 From b539945286bdd2d7c4cb92ef1237873b1c00c778 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:26 +0200 Subject: soc/qman: Drop unused field from eqcr/dqrr descriptors ORP ("Order Restoration Point") mechanism not supported. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 3 +-- include/soc/fsl/qman.h | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 06626bee0e7e..c679e0285ccd 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -141,7 +141,7 @@ struct qm_eqcr_entry { u8 _ncw_verb; /* writes to this are non-coherent */ u8 dca; u16 seqnum; - u32 orp; /* 24-bit */ + u8 __reserved[4]; u32 fqid; /* 24-bit */ u32 tag; struct qm_fd fd; @@ -470,7 +470,6 @@ static inline struct qm_eqcr_entry *qm_eqcr_start_stash(struct qm_portal static inline void eqcr_commit_checks(struct qm_eqcr *eqcr) { DPAA_ASSERT(eqcr->busy); - DPAA_ASSERT(eqcr->cursor->orp == (eqcr->cursor->orp & 0x00ffffff)); DPAA_ASSERT(!(eqcr->cursor->fqid & ~QM_FQID_MASK)); DPAA_ASSERT(eqcr->available >= 1); } diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h index f3fa53fef421..20bbc716a6a8 100644 --- a/include/soc/fsl/qman.h +++ b/include/soc/fsl/qman.h @@ -279,8 +279,7 @@ union qm_mr_entry { u8 dca; u16 seqnum; u8 rc; /* Rej Code: 8-bit */ - u8 orp_hi; /* ORP: 24-bit */ - u16 orp_lo; + u8 __reserved[3]; u32 fqid; /* 24-bit */ u32 tag; struct qm_fd fd; -- cgit v1.2.3 From 5a42f1ecb304789f75a017b2a36bc6d1dac6dcf2 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:27 +0200 Subject: soc/qbman: Handle endianness of qm/bm_in/out() Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/bman.c | 6 +++--- drivers/soc/fsl/qbman/qman.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/bman.c b/drivers/soc/fsl/qbman/bman.c index 48b7eb698689..a3d6d7cfa929 100644 --- a/drivers/soc/fsl/qbman/bman.c +++ b/drivers/soc/fsl/qbman/bman.c @@ -167,12 +167,12 @@ struct bm_portal { /* Cache-inhibited register access. */ static inline u32 bm_in(struct bm_portal *p, u32 offset) { - return __raw_readl(p->addr.ci + offset); + return be32_to_cpu(__raw_readl(p->addr.ci + offset)); } static inline void bm_out(struct bm_portal *p, u32 offset, u32 val) { - __raw_writel(val, p->addr.ci + offset); + __raw_writel(cpu_to_be32(val), p->addr.ci + offset); } /* Cache Enabled Portal Access */ @@ -188,7 +188,7 @@ static inline void bm_cl_touch_ro(struct bm_portal *p, u32 offset) static inline u32 bm_ce_in(struct bm_portal *p, u32 offset) { - return __raw_readl(p->addr.ce + offset); + return be32_to_cpu(__raw_readl(p->addr.ce + offset)); } struct bman_portal { diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index c679e0285ccd..936aee19747d 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -321,12 +321,12 @@ struct qm_portal { /* Cache-inhibited register access. */ static inline u32 qm_in(struct qm_portal *p, u32 offset) { - return __raw_readl(p->addr.ci + offset); + return be32_to_cpu(__raw_readl(p->addr.ci + offset)); } static inline void qm_out(struct qm_portal *p, u32 offset, u32 val) { - __raw_writel(val, p->addr.ci + offset); + __raw_writel(cpu_to_be32(val), p->addr.ci + offset); } /* Cache Enabled Portal Access */ @@ -342,7 +342,7 @@ static inline void qm_cl_touch_ro(struct qm_portal *p, u32 offset) static inline u32 qm_ce_in(struct qm_portal *p, u32 offset) { - return __raw_readl(p->addr.ce + offset); + return be32_to_cpu(__raw_readl(p->addr.ce + offset)); } /* --- EQCR API --- */ -- cgit v1.2.3 From efe848cdb724be2d0cc61f6329997f9a7cd7948f Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:28 +0200 Subject: soc/qman: Change remaining contextB into context_b There are multiple occurences of both contextB and context_b in different h/w descriptors, referring to the same descriptor field known as "Context B". Stick with the "context_b" naming, for obvious reasons including consistency (see also context_a). Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 12 ++++++------ include/soc/fsl/qman.h | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 936aee19747d..8386acc1d37d 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -1395,7 +1395,7 @@ static void qm_mr_process_task(struct work_struct *work) break; case QM_MR_VERB_FQPN: /* Parked */ - fq = tag_to_fq(msg->fq.contextB); + fq = tag_to_fq(msg->fq.context_b); fq_state_change(p, fq, msg, verb); if (fq->cb.fqs) fq->cb.fqs(p, fq, msg); @@ -1494,7 +1494,7 @@ static inline unsigned int __poll_portal_fast(struct qman_portal *p, if (dq->stat & QM_DQRR_STAT_UNSCHEDULED) { /* - * VDQCR: don't trust contextB as the FQ may have + * VDQCR: don't trust context_b as the FQ may have * been configured for h/w consumption and we're * draining it post-retirement. */ @@ -1520,8 +1520,8 @@ static inline unsigned int __poll_portal_fast(struct qman_portal *p, if (dq->stat & QM_DQRR_STAT_DQCR_EXPIRED) clear_vdqcr(p, fq); } else { - /* SDQCR: contextB points to the FQ */ - fq = tag_to_fq(dq->contextB); + /* SDQCR: context_b points to the FQ */ + fq = tag_to_fq(dq->context_b); /* Now let the callback do its stuff */ res = fq->cb.dqrr(p, fq, dq); /* @@ -1757,7 +1757,7 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) qm_fqid_set(&mcc->fq, fq->fqid); mcc->initfq.count = 0; /* - * If the FQ does *not* have the TO_DCPORTAL flag, contextB is set as a + * If the FQ does *not* have the TO_DCPORTAL flag, context_b is set as a * demux pointer. Otherwise, the caller-provided value is allowed to * stand, don't overwrite it. */ @@ -1937,7 +1937,7 @@ int qman_retire_fq(struct qman_fq *fq, u32 *flags) msg.verb = QM_MR_VERB_FQRNI; msg.fq.fqs = mcr->alterfq.fqs; qm_fqid_set(&msg.fq, fq->fqid); - msg.fq.contextB = fq_to_tag(fq); + msg.fq.context_b = fq_to_tag(fq); fq->cb.fqs(p, fq, &msg); } } else if (res == QM_MCR_RESULT_PENDING) { diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h index 20bbc716a6a8..c80eccac64f6 100644 --- a/include/soc/fsl/qman.h +++ b/include/soc/fsl/qman.h @@ -248,7 +248,7 @@ struct qm_dqrr_entry { u8 tok; u8 __reserved2[3]; u32 fqid; /* 24-bit */ - u32 contextB; + u32 context_b; struct qm_fd fd; u8 __reserved4[32]; } __packed; @@ -290,7 +290,7 @@ union qm_mr_entry { u8 fqs; /* Frame Queue Status */ u8 __reserved1[6]; u32 fqid; /* 24-bit */ - u32 contextB; + u32 context_b; u8 __reserved2[48]; } __packed fq; /* FQRN/FQRNI/FQRL/FQPN */ }; @@ -658,7 +658,7 @@ struct qman_cgr; /* * This enum, and the callback type that returns it, are used when handling * dequeued frames via DQRR. Note that for "null" callbacks registered with the - * portal object (for handling dequeues that do not demux because contextB is + * portal object (for handling dequeues that do not demux because context_b is * NULL), the return value *MUST* be qman_cb_dqrr_consume. */ enum qman_cb_dqrr_result { @@ -863,11 +863,11 @@ void qman_p_static_dequeue_add(struct qman_portal *p, u32 pools); * qman_fq" for more info). NO_MODIFY is only intended for enqueuing to * pre-existing frame-queues that aren't to be otherwise interfered with, it * prevents all other modifications to the frame queue. The TO_DCPORTAL flag - * causes the driver to honour any contextB modifications requested in the + * causes the driver to honour any context_b modifications requested in the * qm_init_fq() API, as this indicates the frame queue will be consumed by a * direct-connect portal (PME, CAAM, or Fman). When frame queues are consumed by - * software portals, the contextB field is controlled by the driver and can't be - * modified by the caller. + * software portals, the context_b field is controlled by the driver and can't + * be modified by the caller. */ int qman_create_fq(u32 fqid, u32 flags, struct qman_fq *fq); -- cgit v1.2.3 From 496bfa11de2e6805b63168d45c2f92edbeae54e2 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:29 +0200 Subject: soc/qman: Clean up CGR CSCN target update operations Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 37 +++++++++++++++++++++++-------------- include/soc/fsl/qman.h | 4 ++-- 2 files changed, 25 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index 8386acc1d37d..acee99da71a7 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -2248,7 +2248,23 @@ out: } #define PORTAL_IDX(n) (n->config->channel - QM_CHANNEL_SWPORTAL0) -#define TARG_MASK(n) (BIT(31) >> PORTAL_IDX(n)) + +/* congestion state change notification target update control */ +static void qm_cgr_cscn_targ_set(struct __qm_mc_cgr *cgr, int pi, u32 val) +{ + if (qman_ip_rev >= QMAN_REV30) + cgr->cscn_targ_upd_ctrl = QM_CGR_TARG_UDP_CTRL_WRITE_BIT | pi; + else + cgr->cscn_targ = val | QM_CGR_TARG_PORTAL(pi); +} + +static void qm_cgr_cscn_targ_clear(struct __qm_mc_cgr *cgr, int pi, u32 val) +{ + if (qman_ip_rev >= QMAN_REV30) + cgr->cscn_targ_upd_ctrl = pi; + else + cgr->cscn_targ = val & ~QM_CGR_TARG_PORTAL(pi); +} static u8 qman_cgr_cpus[CGR_NUM]; @@ -2298,13 +2314,8 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags, if (ret) goto out; - if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) - local_opts.cgr.cscn_targ_upd_ctrl = - QM_CGR_TARG_UDP_CTRL_WRITE_BIT | PORTAL_IDX(p); - else - /* Overwrite TARG */ - local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ | - TARG_MASK(p); + qm_cgr_cscn_targ_set(&local_opts.cgr, PORTAL_IDX(p), + cgr_state.cgr.cscn_targ); local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; /* send init if flags indicate so */ @@ -2371,13 +2382,11 @@ int qman_delete_cgr(struct qman_cgr *cgr) list_add(&cgr->node, &p->cgr_cbs); goto release_lock; } - /* Overwrite TARG */ + local_opts.we_mask = QM_CGR_WE_CSCN_TARG; - if ((qman_ip_rev & 0xFF00) >= QMAN_REV30) - local_opts.cgr.cscn_targ_upd_ctrl = PORTAL_IDX(p); - else - local_opts.cgr.cscn_targ = cgr_state.cgr.cscn_targ & - ~(TARG_MASK(p)); + qm_cgr_cscn_targ_clear(&local_opts.cgr, PORTAL_IDX(p), + cgr_state.cgr.cscn_targ); + ret = qm_modify_cgr(cgr, 0, &local_opts); if (ret) /* add back to the list */ diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h index c80eccac64f6..d01d5a358945 100644 --- a/include/soc/fsl/qman.h +++ b/include/soc/fsl/qman.h @@ -553,8 +553,8 @@ struct __qm_mc_cgr { u8 cscn_en; /* boolean, use QM_CGR_EN */ union { struct { - u16 cscn_targ_upd_ctrl; /* use QM_CSCN_TARG_UDP_ */ - u16 cscn_targ_dcp_low; /* CSCN_TARG_DCP low-16bits */ + u16 cscn_targ_upd_ctrl; /* use QM_CGR_TARG_UDP_* */ + u16 cscn_targ_dcp_low; }; u32 cscn_targ; /* use QM_CGR_TARG_* */ }; -- cgit v1.2.3 From 3382a6220ff3bac886d9d90766f3fe18cf25b468 Mon Sep 17 00:00:00 2001 From: Andrew Donnellan Date: Tue, 22 Nov 2016 21:13:27 +1100 Subject: cxl: Fix coccinelle warnings Fix the following coccinelle warnings: drivers/misc/cxl/debugfs.c:46:0-23: WARNING: fops_io_x64 should be defined with DEFINE_DEBUGFS_ATTRIBUTE drivers/misc/cxl/guest.c:890:5-26: WARNING: Comparison to bool drivers/misc/cxl/irq.c:107:3-23: WARNING: Assignment of bool to 0/1 drivers/misc/cxl/native.c:57:2-3: Unneeded semicolon drivers/misc/cxl/native.c:170:2-3: Unneeded semicolon Signed-off-by: Andrew Donnellan Acked-by: Frederic Barrat Reviewed-by: Matthew R. Ochs Acked-by: Ian Munsie Signed-off-by: Michael Ellerman --- drivers/misc/cxl/debugfs.c | 6 ++++-- drivers/misc/cxl/guest.c | 2 +- drivers/misc/cxl/irq.c | 2 +- drivers/misc/cxl/native.c | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/debugfs.c b/drivers/misc/cxl/debugfs.c index ec7b8a017439..9c06ac8fa5ac 100644 --- a/drivers/misc/cxl/debugfs.c +++ b/drivers/misc/cxl/debugfs.c @@ -43,12 +43,14 @@ static int debugfs_io_u64_set(void *data, u64 val) out_be64((u64 __iomem *)data, val); return 0; } -DEFINE_SIMPLE_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set, "0x%016llx\n"); +DEFINE_DEBUGFS_ATTRIBUTE(fops_io_x64, debugfs_io_u64_get, debugfs_io_u64_set, + "0x%016llx\n"); static struct dentry *debugfs_create_io_x64(const char *name, umode_t mode, struct dentry *parent, u64 __iomem *value) { - return debugfs_create_file(name, mode, parent, (void __force *)value, &fops_io_x64); + return debugfs_create_file_unsafe(name, mode, parent, + (void __force *)value, &fops_io_x64); } void cxl_debugfs_add_adapter_psl_regs(struct cxl *adapter, struct dentry *dir) diff --git a/drivers/misc/cxl/guest.c b/drivers/misc/cxl/guest.c index 3e102cd6ed91..e04bc4ddfd74 100644 --- a/drivers/misc/cxl/guest.c +++ b/drivers/misc/cxl/guest.c @@ -887,7 +887,7 @@ static void afu_handle_errstate(struct work_struct *work) afu_guest->previous_state == H_STATE_PERM_UNAVAILABLE) return; - if (afu_guest->handle_err == true) + if (afu_guest->handle_err) schedule_delayed_work(&afu_guest->work_err, msecs_to_jiffies(3000)); } diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c index dec60f58a767..1a402bbed687 100644 --- a/drivers/misc/cxl/irq.c +++ b/drivers/misc/cxl/irq.c @@ -104,7 +104,7 @@ irqreturn_t cxl_irq(int irq, struct cxl_context *ctx, struct cxl_irq_info *irq_i } else { spin_lock(&ctx->lock); ctx->afu_err = irq_info->afu_err; - ctx->pending_afu_err = 1; + ctx->pending_afu_err = true; spin_unlock(&ctx->lock); wake_up_all(&ctx->wq); diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index c336350ede94..c1216d31796c 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -54,7 +54,7 @@ static int afu_control(struct cxl_afu *afu, u64 command, u64 clear, AFU_Cntl | command); cpu_relax(); AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An); - }; + } if (AFU_Cntl & CXL_AFU_Cntl_An_RA) { /* @@ -167,7 +167,7 @@ int cxl_psl_purge(struct cxl_afu *afu) cpu_relax(); } PSL_CNTL = cxl_p1n_read(afu, CXL_PSL_SCNTL_An); - }; + } end = local_clock(); pr_devel("PSL purged in %lld ns\n", end - start); -- cgit v1.2.3 From 141723e0cbdc1139410f77d8a572f17ce2de6bf5 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sat, 5 Nov 2016 00:46:13 +0300 Subject: soc: renesas: rcar-sysc: add R8A7745 support Add support for RZ/G1E (R8A7745) SoC power areas to the R-Car SYSC driver. Based on the original (and large) patch by Dmitry Shifrin . Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Acked-by: Rob Herring Signed-off-by: Simon Horman --- .../bindings/power/renesas,rcar-sysc.txt | 1 + drivers/soc/renesas/Makefile | 1 + drivers/soc/renesas/r8a7745-sysc.c | 32 ++++++++++++++++++++++ drivers/soc/renesas/rcar-sysc.c | 3 ++ drivers/soc/renesas/rcar-sysc.h | 1 + 5 files changed, 38 insertions(+) create mode 100644 drivers/soc/renesas/r8a7745-sysc.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt index 0725fb37a973..1375758307d2 100644 --- a/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt +++ b/Documentation/devicetree/bindings/power/renesas,rcar-sysc.txt @@ -7,6 +7,7 @@ various coprocessors. Required properties: - compatible: Must contain exactly one of the following: + - "renesas,r8a7745-sysc" (RZ/G1E) - "renesas,r8a7779-sysc" (R-Car H1) - "renesas,r8a7790-sysc" (R-Car H2) - "renesas,r8a7791-sysc" (R-Car M2-W) diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 623039c3514c..a25a628e90b5 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -1,3 +1,4 @@ +obj-$(CONFIG_ARCH_R8A7745) += rcar-sysc.o r8a7745-sysc.o obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o diff --git a/drivers/soc/renesas/r8a7745-sysc.c b/drivers/soc/renesas/r8a7745-sysc.c new file mode 100644 index 000000000000..d17887c08aa1 --- /dev/null +++ b/drivers/soc/renesas/r8a7745-sysc.c @@ -0,0 +1,32 @@ +/* + * Renesas RZ/G1E System Controller + * + * Copyright (C) 2016 Cogent Embedded Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation; of the License. + */ + +#include +#include + +#include + +#include "rcar-sysc.h" + +static const struct rcar_sysc_area r8a7745_areas[] __initconst = { + { "always-on", 0, 0, R8A7745_PD_ALWAYS_ON, -1, PD_ALWAYS_ON }, + { "ca7-scu", 0x100, 0, R8A7745_PD_CA7_SCU, R8A7745_PD_ALWAYS_ON, + PD_SCU }, + { "ca7-cpu0", 0x1c0, 0, R8A7745_PD_CA7_CPU0, R8A7745_PD_CA7_SCU, + PD_CPU_NOCR }, + { "ca7-cpu1", 0x1c0, 1, R8A7745_PD_CA7_CPU1, R8A7745_PD_CA7_SCU, + PD_CPU_NOCR }, + { "sgx", 0xc0, 0, R8A7745_PD_SGX, R8A7745_PD_ALWAYS_ON }, +}; + +const struct rcar_sysc_info r8a7745_sysc_info __initconst = { + .areas = r8a7745_areas, + .num_areas = ARRAY_SIZE(r8a7745_areas), +}; diff --git a/drivers/soc/renesas/rcar-sysc.c b/drivers/soc/renesas/rcar-sysc.c index 65c8e1eb90c0..a4e1bb046bc7 100644 --- a/drivers/soc/renesas/rcar-sysc.c +++ b/drivers/soc/renesas/rcar-sysc.c @@ -275,6 +275,9 @@ finalize: } static const struct of_device_id rcar_sysc_matches[] = { +#ifdef CONFIG_ARCH_R8A7745 + { .compatible = "renesas,r8a7745-sysc", .data = &r8a7745_sysc_info }, +#endif #ifdef CONFIG_ARCH_R8A7779 { .compatible = "renesas,r8a7779-sysc", .data = &r8a7779_sysc_info }, #endif diff --git a/drivers/soc/renesas/rcar-sysc.h b/drivers/soc/renesas/rcar-sysc.h index 77dbe861473f..3048dd31288a 100644 --- a/drivers/soc/renesas/rcar-sysc.h +++ b/drivers/soc/renesas/rcar-sysc.h @@ -50,6 +50,7 @@ struct rcar_sysc_info { unsigned int num_areas; }; +extern const struct rcar_sysc_info r8a7745_sysc_info; extern const struct rcar_sysc_info r8a7779_sysc_info; extern const struct rcar_sysc_info r8a7790_sysc_info; extern const struct rcar_sysc_info r8a7791_sysc_info; -- cgit v1.2.3 From 355445b86f0f61125409e1217be4f0a8ee362116 Mon Sep 17 00:00:00 2001 From: Ash Benz Date: Sat, 19 Nov 2016 07:51:49 +0800 Subject: mtd: spi-nor: add Macronix mx25u25635f to list of known devices. Signed-off-by: Ash Benz Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index d0fc165d7d66..4fd3ac8b5317 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -872,6 +872,7 @@ static const struct flash_info spi_nor_ids[] = { { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, + { "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K) }, { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) }, { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, SPI_NOR_QUAD_READ) }, { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, -- cgit v1.2.3 From 807c16253319ee6ccf8873ae64f070f7eb532cd5 Mon Sep 17 00:00:00 2001 From: Joël Esponde Date: Wed, 23 Nov 2016 12:47:40 +0100 Subject: mtd: spi-nor: fix spansion quad enable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With the S25FL127S nor flash part, each writing to the configuration register takes hundreds of ms. During that time, no more accesses to the flash should be done (even reads). This commit adds a wait loop after the register writing until the flash finishes its work. This issue could make rootfs mounting fail when the latter was done too much closely to this quad enable bit setting step. And in this case, a driver as UBIFS may try to recover the filesystem and may broke it completely. Signed-off-by: Joël Esponde Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 4fd3ac8b5317..cebd0cc8a5b1 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -1256,6 +1256,13 @@ static int spansion_quad_enable(struct spi_nor *nor) return -EINVAL; } + ret = spi_nor_wait_till_ready(nor); + if (ret) { + dev_err(nor->dev, + "timeout while writing configuration register\n"); + return ret; + } + /* read back and check it */ ret = read_cr(nor); if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) { -- cgit v1.2.3 From 386701892b4821c4d127710fa35b1309c4355bbf Mon Sep 17 00:00:00 2001 From: Joerg Riechardt Date: Sat, 29 Aug 2015 12:02:57 -0300 Subject: [media] stv090x: use lookup tables for carrier/noise ratio MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The stv090x driver uses the lookup table for signal strength already, with this patch we use the lookup tables for carrier/noise ratio as well. This has the advantage, that values for DVB-S and DVB-S2 are now corresponding, while before they were way off. The values are now proportional to real carrier/noise ratio, while before they were corresponding to register values. So now applications are able to give the user real carrier/noise ratio. Because the output has to be within 0x0000...0xFFFF the three negative values for DVB-S2 are omitted. This is no significant loss, because reception is lost at 7.5 dB already (TT S2-1600, Cine S2), so the negative values are not really important, and also for DVB-S they don´t exist. Signed-off-by: Joerg Riechardt Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/stv090x.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index b586d2a49737..7ef469c0c866 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -3692,9 +3692,12 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr) } val /= 16; last = ARRAY_SIZE(stv090x_s2cn_tab) - 1; - div = stv090x_s2cn_tab[0].read - - stv090x_s2cn_tab[last].read; - *cnr = 0xFFFF - ((val * 0xFFFF) / div); + div = stv090x_s2cn_tab[last].real - + stv090x_s2cn_tab[3].real; + val = stv090x_table_lookup(stv090x_s2cn_tab, last, val); + if (val < 0) + val = 0; + *cnr = val * 0xFFFF / div; } break; @@ -3714,9 +3717,10 @@ static int stv090x_read_cnr(struct dvb_frontend *fe, u16 *cnr) } val /= 16; last = ARRAY_SIZE(stv090x_s1cn_tab) - 1; - div = stv090x_s1cn_tab[0].read - - stv090x_s1cn_tab[last].read; - *cnr = 0xFFFF - ((val * 0xFFFF) / div); + div = stv090x_s1cn_tab[last].real - + stv090x_s1cn_tab[0].real; + val = stv090x_table_lookup(stv090x_s1cn_tab, last, val); + *cnr = val * 0xFFFF / div; } break; default: -- cgit v1.2.3 From 48c28337380ac499df5e370bc1ec1d6217ac35bc Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 23 Nov 2016 14:39:59 +0100 Subject: bus: da8xx-mstpri: drop the call to of_flat_dt_get_machine_name() In order to avoid a section mismatch drop the call to of_flat_dt_get_machine_name() when printing the error message. While we're at it: fix a typo. Signed-off-by: Bartosz Golaszewski Signed-off-by: Sekhar Nori --- drivers/bus/da8xx-mstpri.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/bus/da8xx-mstpri.c b/drivers/bus/da8xx-mstpri.c index 85f0b533f8e4..063397f2c0db 100644 --- a/drivers/bus/da8xx-mstpri.c +++ b/drivers/bus/da8xx-mstpri.c @@ -16,7 +16,6 @@ #include #include #include -#include /* * REVISIT: Linux doesn't have a good framework for the kind of performance @@ -226,8 +225,7 @@ static int da8xx_mstpri_probe(struct platform_device *pdev) prio_list = da8xx_mstpri_get_board_prio(); if (!prio_list) { - dev_err(dev, "no master priotities defined for board '%s'\n", - of_flat_dt_get_machine_name()); + dev_err(dev, "no master priorities defined for this board\n"); return -EINVAL; } -- cgit v1.2.3 From d0c7546f6257b4680a760e3fd0dff8a7cc4600ff Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Wed, 23 Nov 2016 14:40:00 +0100 Subject: memory: da8xx-ddrctl: drop the call to of_flat_dt_get_machine_name() In order to avoid a section mismatch drop the call to of_flat_dt_get_machine_name() when printing the error message. Signed-off-by: Bartosz Golaszewski Signed-off-by: Sekhar Nori --- drivers/memory/da8xx-ddrctl.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/memory/da8xx-ddrctl.c b/drivers/memory/da8xx-ddrctl.c index a20e7bbbcbe0..030afbe29d0c 100644 --- a/drivers/memory/da8xx-ddrctl.c +++ b/drivers/memory/da8xx-ddrctl.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -117,8 +116,7 @@ static int da8xx_ddrctl_probe(struct platform_device *pdev) setting = da8xx_ddrctl_get_board_settings(); if (!setting) { - dev_err(dev, "no settings for board '%s'\n", - of_flat_dt_get_machine_name()); + dev_err(dev, "no settings defined for this board\n"); return -EINVAL; } -- cgit v1.2.3 From a19e160d108a80953e4404be39e03b9bc8417376 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 17 Sep 2015 18:19:33 -0300 Subject: [media] dvb: remove unused systime() function The systime function uses struct timespec, which we want to stop using in the kernel because it overflows in 2038. Fortunately, this use in dibx000_common is in a function that is never called, so we can just remove it. Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/dibx000_common.c | 10 ---------- drivers/media/dvb-frontends/dibx000_common.h | 2 -- 2 files changed, 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/dibx000_common.c b/drivers/media/dvb-frontends/dibx000_common.c index 7db908ed87f6..bc28184c7fb0 100644 --- a/drivers/media/dvb-frontends/dibx000_common.c +++ b/drivers/media/dvb-frontends/dibx000_common.c @@ -502,16 +502,6 @@ void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst) } EXPORT_SYMBOL(dibx000_exit_i2c_master); - -u32 systime(void) -{ - struct timespec t; - - t = current_kernel_time(); - return (t.tv_sec * 10000) + (t.tv_nsec / 100000); -} -EXPORT_SYMBOL(systime); - MODULE_AUTHOR("Patrick Boettcher "); MODULE_DESCRIPTION("Common function the DiBcom demodulator family"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb-frontends/dibx000_common.h b/drivers/media/dvb-frontends/dibx000_common.h index b538e0555c95..61f4152f24ee 100644 --- a/drivers/media/dvb-frontends/dibx000_common.h +++ b/drivers/media/dvb-frontends/dibx000_common.h @@ -47,8 +47,6 @@ extern void dibx000_exit_i2c_master(struct dibx000_i2c_master *mst); extern void dibx000_reset_i2c_master(struct dibx000_i2c_master *mst); extern int dibx000_i2c_set_speed(struct i2c_adapter *i2c_adap, u16 speed); -extern u32 systime(void); - #define BAND_LBAND 0x01 #define BAND_UHF 0x02 #define BAND_VHF 0x04 -- cgit v1.2.3 From fa6317eedd6341f2144ed1097706d8c34f18b6e4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 26 Jan 2016 12:10:01 -0200 Subject: [media] go7007: add MEDIA_CAMERA_SUPPORT dependency If MEDIA_SUBDRV_AUTOSELECT and VIDEO_GO7007 are both set, we automatically select VIDEO_OV7640, but that depends on MEDIA_CAMERA_SUPPORT, so we get a Kconfig warning if that is disabled: warning: (VIDEO_GO7007) selects VIDEO_OV7640 which has unmet direct dependencies (MEDIA_SUPPORT && I2C && VIDEO_V4L2 && MEDIA_CAMERA_SUPPORT) This adds another dependency so we don't accidentally select it when it is unavailable. Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/go7007/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/go7007/Kconfig b/drivers/media/usb/go7007/Kconfig index 95a3af644a92..af1d02430931 100644 --- a/drivers/media/usb/go7007/Kconfig +++ b/drivers/media/usb/go7007/Kconfig @@ -11,7 +11,7 @@ config VIDEO_GO7007 select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT ---help--- This is a video4linux driver for the WIS GO7007 MPEG -- cgit v1.2.3 From 190b23b4eb997767afad186bd8c96badceabf39e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 26 Jan 2016 12:09:59 -0200 Subject: [media] em28xx: only use mt9v011 if camera support is enabled In randconfig builds that select VIDEO_EM28XX_V4L2 and MEDIA_SUBDRV_AUTOSELECT, but not MEDIA_CAMERA_SUPPORT, we get a Kconfig warning: warning: (VIDEO_EM28XX_V4L2) selects VIDEO_MT9V011 which has unmet direct dependencies (MEDIA_SUPPORT && I2C && VIDEO_V4L2 && MEDIA_CAMERA_SUPPORT) This avoids the warning by making that 'select' conditional on MEDIA_CAMERA_SUPPORT. Alternatively we could mark EM28XX as 'depends on MEDIA_CAMERA_SUPPORT', but it does not seem to have any real dependency on that itself. Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/Kconfig b/drivers/media/usb/em28xx/Kconfig index d917b0a2beb1..aa131cf9989b 100644 --- a/drivers/media/usb/em28xx/Kconfig +++ b/drivers/media/usb/em28xx/Kconfig @@ -11,7 +11,7 @@ config VIDEO_EM28XX_V4L2 select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_CAMERA_SUPPORT ---help--- This is a video4linux driver for Empia 28xx based TV cards. -- cgit v1.2.3 From 90866b3a8011703d87d9ea263ef29a194453a898 Mon Sep 17 00:00:00 2001 From: "Буди Романто, AreMa Inc" Date: Tue, 5 Apr 2016 13:14:10 -0300 Subject: [media] Raise adapter number limit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current limit is too low for latest cards with 8+ tuners on a single slot. IMHO, the most appropriate minimum default is 16. Signed-off-by: Буди Романто, AreMa Inc Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/Kconfig | 4 ++-- drivers/media/dvb-core/dvbdev.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig index 8964f1d3cf57..eeef94a0c84e 100644 --- a/drivers/media/dvb-core/Kconfig +++ b/drivers/media/dvb-core/Kconfig @@ -5,7 +5,7 @@ config DVB_MAX_ADAPTERS int "maximum number of DVB/ATSC adapters" depends on DVB_CORE - default 8 + default 16 range 1 255 help Maximum number of DVB/ATSC adapters. Increasing this number @@ -13,7 +13,7 @@ config DVB_MAX_ADAPTERS if a much lower number of DVB/ATSC adapters is present. Only values in the range 4-32 are tested. - If you are unsure about this, use the default value 8 + If you are unsure about this, use the default value 16 config DVB_DYNAMIC_MINORS bool "Dynamic DVB minor allocation" diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h index 576bbd4445b5..8c0a7b51555e 100644 --- a/drivers/media/dvb-core/dvbdev.h +++ b/drivers/media/dvb-core/dvbdev.h @@ -34,7 +34,7 @@ #if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0 #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS #else - #define DVB_MAX_ADAPTERS 8 + #define DVB_MAX_ADAPTERS 16 #endif #define DVB_UNSET (-1) -- cgit v1.2.3 From d26cec2268bcb5521b8b7a0edd44b8129bb978ec Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 14 Apr 2016 17:42:49 -0300 Subject: [media] mceusb: remove useless debug message Such debug message has a logic to track the IR status, but it doesn't provide much info. So, get rid of it. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index f813b77c595d..517d218a6179 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -153,12 +153,6 @@ #define MCE_COMMAND_IRDATA 0x80 #define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ -/* general constants */ -#define SEND_FLAG_IN_PROGRESS 1 -#define SEND_FLAG_COMPLETE 2 -#define RECV_FLAG_IN_PROGRESS 3 -#define RECV_FLAG_COMPLETE 4 - #define MCEUSB_RX 1 #define MCEUSB_TX 2 @@ -422,7 +416,6 @@ struct mceusb_dev { struct rc_dev *rc; /* optional features we can enable */ - bool carrier_report_enabled; bool learning_enabled; /* core device bits */ @@ -455,7 +448,6 @@ struct mceusb_dev { } flags; /* transmit support */ - int send_flags; u32 carrier; unsigned char tx_mask; @@ -778,8 +770,6 @@ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, } else if (urb_type == MCEUSB_RX) { /* standard request */ async_urb = ir->urb_in; - ir->send_flags = RECV_FLAG_IN_PROGRESS; - } else { dev_err(dev, "Error! Unknown urb type %d\n", urb_type); return; @@ -1060,7 +1050,6 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len) static void mceusb_dev_recv(struct urb *urb) { struct mceusb_dev *ir; - int buf_len; if (!urb) return; @@ -1071,18 +1060,10 @@ static void mceusb_dev_recv(struct urb *urb) return; } - buf_len = urb->actual_length; - - if (ir->send_flags == RECV_FLAG_IN_PROGRESS) { - ir->send_flags = SEND_FLAG_COMPLETE; - dev_dbg(ir->dev, "setup answer received %d bytes\n", - buf_len); - } - switch (urb->status) { /* success */ case 0: - mceusb_process_ir_data(ir, buf_len); + mceusb_process_ir_data(ir, urb->actual_length); break; case -ECONNRESET: -- cgit v1.2.3 From e1159cb35712bc708f444f167b6954a5afeebbdf Mon Sep 17 00:00:00 2001 From: Sean Young Date: Thu, 14 Apr 2016 17:42:50 -0300 Subject: [media] mceusb: remove pointless mce_flush_rx_buffer function This function just submits the urb much like mceusb_dev_resume; removing it simplifies mce_request_packet. Also add missing usb_kill_urb to mce_dev_probe. Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/mceusb.c | 77 +++++++++++++++++++---------------------------- 1 file changed, 31 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c index 517d218a6179..9bf69179eee0 100644 --- a/drivers/media/rc/mceusb.c +++ b/drivers/media/rc/mceusb.c @@ -153,9 +153,6 @@ #define MCE_COMMAND_IRDATA 0x80 #define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */ -#define MCEUSB_RX 1 -#define MCEUSB_TX 2 - #define VENDOR_PHILIPS 0x0471 #define VENDOR_SMK 0x0609 #define VENDOR_TATUNG 0x1460 @@ -730,50 +727,40 @@ static void mce_async_callback(struct urb *urb) /* request incoming or send outgoing usb packet - used to initialize remote */ static void mce_request_packet(struct mceusb_dev *ir, unsigned char *data, - int size, int urb_type) + int size) { int res, pipe; struct urb *async_urb; struct device *dev = ir->dev; unsigned char *async_buf; - if (urb_type == MCEUSB_TX) { - async_urb = usb_alloc_urb(0, GFP_KERNEL); - if (unlikely(!async_urb)) { - dev_err(dev, "Error, couldn't allocate urb!\n"); - return; - } - - async_buf = kzalloc(size, GFP_KERNEL); - if (!async_buf) { - dev_err(dev, "Error, couldn't allocate buf!\n"); - usb_free_urb(async_urb); - return; - } + async_urb = usb_alloc_urb(0, GFP_KERNEL); + if (unlikely(!async_urb)) { + dev_err(dev, "Error, couldn't allocate urb!\n"); + return; + } - /* outbound data */ - if (usb_endpoint_xfer_int(ir->usb_ep_out)) { - pipe = usb_sndintpipe(ir->usbdev, - ir->usb_ep_out->bEndpointAddress); - usb_fill_int_urb(async_urb, ir->usbdev, pipe, async_buf, - size, mce_async_callback, ir, - ir->usb_ep_out->bInterval); - } else { - pipe = usb_sndbulkpipe(ir->usbdev, - ir->usb_ep_out->bEndpointAddress); - usb_fill_bulk_urb(async_urb, ir->usbdev, pipe, - async_buf, size, mce_async_callback, - ir); - } - memcpy(async_buf, data, size); + async_buf = kmalloc(size, GFP_KERNEL); + if (!async_buf) { + usb_free_urb(async_urb); + return; + } - } else if (urb_type == MCEUSB_RX) { - /* standard request */ - async_urb = ir->urb_in; + /* outbound data */ + if (usb_endpoint_xfer_int(ir->usb_ep_out)) { + pipe = usb_sndintpipe(ir->usbdev, + ir->usb_ep_out->bEndpointAddress); + usb_fill_int_urb(async_urb, ir->usbdev, pipe, async_buf, + size, mce_async_callback, ir, + ir->usb_ep_out->bInterval); } else { - dev_err(dev, "Error! Unknown urb type %d\n", urb_type); - return; + pipe = usb_sndbulkpipe(ir->usbdev, + ir->usb_ep_out->bEndpointAddress); + usb_fill_bulk_urb(async_urb, ir->usbdev, pipe, + async_buf, size, mce_async_callback, + ir); } + memcpy(async_buf, data, size); dev_dbg(dev, "receive request called (size=%#x)", size); @@ -794,19 +781,14 @@ static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size) if (ir->need_reset) { ir->need_reset = false; - mce_request_packet(ir, DEVICE_RESUME, rsize, MCEUSB_TX); + mce_request_packet(ir, DEVICE_RESUME, rsize); msleep(10); } - mce_request_packet(ir, data, size, MCEUSB_TX); + mce_request_packet(ir, data, size); msleep(10); } -static void mce_flush_rx_buffer(struct mceusb_dev *ir, int size) -{ - mce_request_packet(ir, NULL, size, MCEUSB_RX); -} - /* Send data out the IR blaster port(s) */ static int mceusb_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count) { @@ -1264,7 +1246,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, struct usb_endpoint_descriptor *ep_in = NULL; struct usb_endpoint_descriptor *ep_out = NULL; struct mceusb_dev *ir = NULL; - int pipe, maxp, i; + int pipe, maxp, i, res; char buf[63], name[128] = ""; enum mceusb_model_type model = id->driver_info; bool is_gen3; @@ -1367,7 +1349,9 @@ static int mceusb_dev_probe(struct usb_interface *intf, /* flush buffers on the device */ dev_dbg(&intf->dev, "Flushing receive buffers\n"); - mce_flush_rx_buffer(ir, maxp); + res = usb_submit_urb(ir->urb_in, GFP_KERNEL); + if (res) + dev_err(&intf->dev, "failed to flush buffers: %d\n", res); /* figure out which firmware/emulator version this hardware has */ mceusb_get_emulator_version(ir); @@ -1402,6 +1386,7 @@ static int mceusb_dev_probe(struct usb_interface *intf, /* Error-handling path */ rc_dev_fail: usb_put_dev(ir->usbdev); + usb_kill_urb(ir->urb_in); usb_free_urb(ir->urb_in); urb_in_alloc_fail: usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in); -- cgit v1.2.3 From f1c002f262fb8f1a8064341a185ca9413a4b96d7 Mon Sep 17 00:00:00 2001 From: Saatvik Arya Date: Wed, 3 Feb 2016 00:26:42 -0200 Subject: [media] staging: media: davinci_vpfe: dm365_resizer: Fix some spelling mistakes Fix spelling mistakes which referred to OUTPUT as OUPUT. Signed-off-by: Saatvik Arya Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/davinci_vpfe/dm365_resizer.c | 22 +++++++++++----------- drivers/staging/media/davinci_vpfe/dm365_resizer.h | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c index 128662623ea8..544f13206b83 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c @@ -490,7 +490,7 @@ resizer_configure_in_continious_mode(struct vpfe_resizer_device *resizer) int line_len; int ret; - if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY) { + if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) { dev_err(dev, "enable resizer - Resizer-A\n"); return -EINVAL; } @@ -502,7 +502,7 @@ resizer_configure_in_continious_mode(struct vpfe_resizer_device *resizer) param->rsz_en[RSZ_B] = DISABLE; param->oper_mode = RESIZER_MODE_CONTINIOUS; - if (resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) { + if (resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) { struct v4l2_mbus_framefmt *outformat2; param->rsz_en[RSZ_B] = ENABLE; @@ -1043,13 +1043,13 @@ static void resizer_ss_isr(struct vpfe_resizer_device *resizer) if (ipipeif_sink != IPIPEIF_INPUT_MEMORY) return; - if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) { + if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { val = vpss_dma_complete_interrupt(); if (val != 0 && val != 2) return; } - if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) { + if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { spin_lock(&video_out->dma_queue_lock); vpfe_video_process_buffer_complete(video_out); video_out->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; @@ -1059,7 +1059,7 @@ static void resizer_ss_isr(struct vpfe_resizer_device *resizer) /* If resizer B is enabled */ if (pipe->output_num > 1 && resizer->resizer_b.output == - RESIZER_OUPUT_MEMORY) { + RESIZER_OUTPUT_MEMORY) { spin_lock(&video_out->dma_queue_lock); vpfe_video_process_buffer_complete(video_out2); video_out2->state = VPFE_VIDEO_BUFFER_NOT_QUEUED; @@ -1069,7 +1069,7 @@ static void resizer_ss_isr(struct vpfe_resizer_device *resizer) /* start HW if buffers are queued */ if (vpfe_video_is_pipe_ready(pipe) && - resizer->resizer_a.output == RESIZER_OUPUT_MEMORY) { + resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY) { resizer_enable(resizer, 1); vpfe_ipipe_enable(vpfe_dev, 1); vpfe_ipipeif_enable(vpfe_dev); @@ -1237,8 +1237,8 @@ static int resizer_do_hw_setup(struct vpfe_resizer_device *resizer) struct resizer_params *param = &resizer->config; int ret = 0; - if (resizer->resizer_a.output == RESIZER_OUPUT_MEMORY || - resizer->resizer_b.output == RESIZER_OUPUT_MEMORY) { + if (resizer->resizer_a.output == RESIZER_OUTPUT_MEMORY || + resizer->resizer_b.output == RESIZER_OUTPUT_MEMORY) { if (ipipeif_sink == IPIPEIF_INPUT_MEMORY && ipipeif_source == IPIPEIF_OUTPUT_RESIZER) ret = resizer_configure_in_single_shot_mode(resizer); @@ -1263,7 +1263,7 @@ static int resizer_set_stream(struct v4l2_subdev *sd, int enable) if (&resizer->crop_resizer.subdev != sd) return 0; - if (resizer->resizer_a.output != RESIZER_OUPUT_MEMORY) + if (resizer->resizer_a.output != RESIZER_OUTPUT_MEMORY) return 0; switch (enable) { @@ -1724,7 +1724,7 @@ static int resizer_link_setup(struct media_entity *entity, } if (resizer->resizer_a.output != RESIZER_OUTPUT_NONE) return -EBUSY; - resizer->resizer_a.output = RESIZER_OUPUT_MEMORY; + resizer->resizer_a.output = RESIZER_OUTPUT_MEMORY; break; default: @@ -1749,7 +1749,7 @@ static int resizer_link_setup(struct media_entity *entity, } if (resizer->resizer_b.output != RESIZER_OUTPUT_NONE) return -EBUSY; - resizer->resizer_b.output = RESIZER_OUPUT_MEMORY; + resizer->resizer_b.output = RESIZER_OUTPUT_MEMORY; break; default: diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.h b/drivers/staging/media/davinci_vpfe/dm365_resizer.h index 93b0f44030aa..00e64b0d0295 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.h +++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.h @@ -210,7 +210,7 @@ enum resizer_input_entity { enum resizer_output_entity { RESIZER_OUTPUT_NONE = 0, - RESIZER_OUPUT_MEMORY = 1, + RESIZER_OUTPUT_MEMORY = 1, }; struct dm365_resizer_device { -- cgit v1.2.3 From 7809c97622a257abf1c3ee3cd18141035e498af8 Mon Sep 17 00:00:00 2001 From: Manuel Rodriguez Date: Tue, 8 Mar 2016 04:16:06 -0300 Subject: [media] staging: media: davinci_vpfe: Fix spelling error on a comment Fix spelling error on a comment, change 'wether' to 'whether' Signed-off-by: Manuel Rodriguez Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/davinci_vpfe/vpfe_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 8be9f854510f..117b6be2f3c4 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -198,7 +198,7 @@ static int vpfe_update_pipe_state(struct vpfe_video_device *video) return 0; } -/* checks wether pipeline is ready for enabling */ +/* checks whether pipeline is ready for enabling */ int vpfe_video_is_pipe_ready(struct vpfe_pipeline *pipe) { int i; -- cgit v1.2.3 From 5f87406663d48ed54fe1767f35734e11b971da12 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 11 May 2016 10:29:44 -0300 Subject: [media] staging: media: davinci_vfpe: allow modular build It has never been possible to actually build this driver as a loadable module, only built-in because the Makefile attempts to build each file into its own module and fails: ERROR: "mbus_to_pix" [drivers/staging/media/davinci_vpfe/vpfe_video.ko] undefined! ERROR: "vpfe_resizer_register_entities" [drivers/staging/media/davinci_vpfe/vpfe_mc_capture.ko] undefined! ERROR: "rsz_enable" [drivers/staging/media/davinci_vpfe/dm365_resizer.ko] undefined! ERROR: "config_ipipe_hw" [drivers/staging/media/davinci_vpfe/dm365_ipipe.ko] undefined! ERROR: "ipipe_set_lutdpc_regs" [drivers/staging/media/davinci_vpfe/dm365_ipipe.ko] undefined! It took a long time to catch this bug with randconfig builds because at least 14 other Kconfig symbols have to be enabled in order to configure this one, and it was clearly only ever tested as built-in with mainline kernels, if at all. The solution is really easy: this patch changes the Makefile to link all files into one module. As discussed previously, the driver has never before used successfully as a loadable module, but there is no reason to prevent that configuration. Link: http://lkml.iu.edu/hypermail/linux/kernel/1512.1/02383.html Signed-off-by: Arnd Bergmann Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/davinci_vpfe/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/media/davinci_vpfe/Makefile b/drivers/staging/media/davinci_vpfe/Makefile index c64515c644cd..3019c9ecd548 100644 --- a/drivers/staging/media/davinci_vpfe/Makefile +++ b/drivers/staging/media/davinci_vpfe/Makefile @@ -1,3 +1,5 @@ -obj-$(CONFIG_VIDEO_DM365_VPFE) += \ +obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci-vfpe.o + +davinci-vfpe-objs := \ dm365_isif.o dm365_ipipe_hw.o dm365_ipipe.o \ dm365_resizer.o dm365_ipipeif.o vpfe_mc_capture.o vpfe_video.o -- cgit v1.2.3 From a3283fb2165fdfd71a894332284ed59239a27872 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 20 Jun 2016 12:47:56 -0300 Subject: [media] staging: media: davinci_vpfe: fix W=1 build warnings When building with "make W=1", we get multiple harmless build warnings for the vpfe driver: drivers/staging/media/davinci_vpfe/dm365_resizer.c:241:1: error: 'static' is not at beginning of declaration [-Werror=old-style-declaration] drivers/staging/media/davinci_vpfe/dm365_resizer.c: In function 'resizer_set_defualt_configuration': drivers/staging/media/davinci_vpfe/dm365_resizer.c:831:16: error: initialized field overwritten [-Werror=override-init] drivers/staging/media/davinci_vpfe/dm365_resizer.c:831:16: note: (near initialization for 'rsz_default_config.rsz_rsc_param[0].h_typ_c') drivers/staging/media/davinci_vpfe/dm365_resizer.c:849:16: error: initialized field overwritten [-Werror=override-init] drivers/staging/media/davinci_vpfe/dm365_resizer.c:849:16: note: (near initialization for 'rsz_default_config.rsz_rsc_param[1].h_typ_c') All of them are trivial to fix without changing the behavior of the driver, as "static const" is interpreted the same as "const static", and VPFE_RSZ_INTP_CUBIC is defined as zero, so the initializations are not really needed. Signed-off-by: Arnd Bergmann Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/davinci_vpfe/dm365_resizer.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c index 544f13206b83..5fbc2d447ff2 100644 --- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c +++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c @@ -237,9 +237,8 @@ resizer_calculate_resize_ratios(struct vpfe_resizer_device *resizer, int index) ((informat->width) * 256) / (outformat->width); } -void -static resizer_enable_422_420_conversion(struct resizer_params *param, - int index, bool en) +static void resizer_enable_422_420_conversion(struct resizer_params *param, + int index, bool en) { param->rsz_rsc_param[index].cen = en; param->rsz_rsc_param[index].yen = en; @@ -825,7 +824,7 @@ resizer_set_defualt_configuration(struct vpfe_resizer_device *resizer) .o_hsz = WIDTH_O - 1, .v_dif = 256, .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, + .v_typ_c = VPFE_RSZ_INTP_CUBIC, .h_dif = 256, .h_typ_y = VPFE_RSZ_INTP_CUBIC, .h_typ_c = VPFE_RSZ_INTP_CUBIC, @@ -843,7 +842,7 @@ resizer_set_defualt_configuration(struct vpfe_resizer_device *resizer) .o_hsz = WIDTH_O - 1, .v_dif = 256, .v_typ_y = VPFE_RSZ_INTP_CUBIC, - .h_typ_c = VPFE_RSZ_INTP_CUBIC, + .v_typ_c = VPFE_RSZ_INTP_CUBIC, .h_dif = 256, .h_typ_y = VPFE_RSZ_INTP_CUBIC, .h_typ_c = VPFE_RSZ_INTP_CUBIC, -- cgit v1.2.3 From eb02cadc5ca0d9753510cded8b9afc57c37be4e0 Mon Sep 17 00:00:00 2001 From: Leo Sperling Date: Sun, 23 Oct 2016 10:02:23 -0200 Subject: [media] staging: media: davinci_vpfe: Fix indentation issue in vpfe_video.c This is a patch to the vpfe_video.c file that fixes an indentation warning reported by checkpatch.pl Signed-off-by: Leo Sperling Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/davinci_vpfe/vpfe_video.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 117b6be2f3c4..8fd3f7cd40d6 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -1143,8 +1143,8 @@ static int vpfe_buffer_prepare(struct vb2_buffer *vb) /* Initialize buffer */ vb2_set_plane_payload(vb, 0, video->fmt.fmt.pix.sizeimage); if (vb2_plane_vaddr(vb, 0) && - vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) - return -EINVAL; + vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) + return -EINVAL; addr = vb2_dma_contig_plane_dma_addr(vb, 0); /* Make sure user addresses are aligned to 32 bytes */ -- cgit v1.2.3 From c4a407b91f4b644145492e28723f9f880efb1da0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 18 Nov 2016 09:30:24 -0200 Subject: [media] staging: media: davinci_vpfe: unlock on error in vpfe_reqbufs() We should unlock before returning this error code in vpfe_reqbufs(). Fixes: 622897da67b3 ("[media] davinci: vpfe: add v4l2 video driver support") Signed-off-by: Dan Carpenter Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/staging/media/davinci_vpfe/vpfe_video.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c index 8fd3f7cd40d6..c27d7e9a1bdb 100644 --- a/drivers/staging/media/davinci_vpfe/vpfe_video.c +++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c @@ -1362,7 +1362,7 @@ static int vpfe_reqbufs(struct file *file, void *priv, ret = vb2_queue_init(q); if (ret) { v4l2_err(&vpfe_dev->v4l2_dev, "vb2_queue_init() failed\n"); - return ret; + goto unlock_out; } fh->io_allowed = 1; -- cgit v1.2.3 From ab0822d57d8ccde7161aef56b97313fc24162d61 Mon Sep 17 00:00:00 2001 From: "spjoshi@codeaurora.org" Date: Tue, 15 Nov 2016 17:19:24 -0800 Subject: firmware: qcom: scm: Remove core, iface and bus clocks dependency Core, iface and bus clocks are not required to be voted from SCM driver for some of the Qualcomm chipsets. Remove dependency on these clocks from driver. Suggested-by: Bjorn Andersson Signed-off-by: Sarangdhar Joshi Acked-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/firmware/qcom_scm.c | 49 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 9bf66aefdbd0..7a104d31ef0f 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -28,6 +28,10 @@ #include "qcom_scm.h" +#define SCM_HAS_CORE_CLK BIT(0) +#define SCM_HAS_IFACE_CLK BIT(1) +#define SCM_HAS_BUS_CLK BIT(2) + struct qcom_scm { struct device *dev; struct clk *core_clk; @@ -323,32 +327,40 @@ EXPORT_SYMBOL(qcom_scm_is_available); static int qcom_scm_probe(struct platform_device *pdev) { struct qcom_scm *scm; + unsigned long clks; int ret; scm = devm_kzalloc(&pdev->dev, sizeof(*scm), GFP_KERNEL); if (!scm) return -ENOMEM; - scm->core_clk = devm_clk_get(&pdev->dev, "core"); - if (IS_ERR(scm->core_clk)) { - if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) - return PTR_ERR(scm->core_clk); + clks = (unsigned long)of_device_get_match_data(&pdev->dev); + if (clks & SCM_HAS_CORE_CLK) { + scm->core_clk = devm_clk_get(&pdev->dev, "core"); + if (IS_ERR(scm->core_clk)) { + if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) + return PTR_ERR(scm->core_clk); - scm->core_clk = NULL; + scm->core_clk = NULL; + } } - if (of_device_is_compatible(pdev->dev.of_node, "qcom,scm")) { + if (clks & SCM_HAS_IFACE_CLK) { scm->iface_clk = devm_clk_get(&pdev->dev, "iface"); if (IS_ERR(scm->iface_clk)) { if (PTR_ERR(scm->iface_clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to acquire iface clk\n"); + dev_err(&pdev->dev, + "failed to acquire iface clk\n"); return PTR_ERR(scm->iface_clk); } + } + if (clks & SCM_HAS_BUS_CLK) { scm->bus_clk = devm_clk_get(&pdev->dev, "bus"); if (IS_ERR(scm->bus_clk)) { if (PTR_ERR(scm->bus_clk) != -EPROBE_DEFER) - dev_err(&pdev->dev, "failed to acquire bus clk\n"); + dev_err(&pdev->dev, + "failed to acquire bus clk\n"); return PTR_ERR(scm->bus_clk); } } @@ -374,10 +386,23 @@ static int qcom_scm_probe(struct platform_device *pdev) } static const struct of_device_id qcom_scm_dt_match[] = { - { .compatible = "qcom,scm-apq8064",}, - { .compatible = "qcom,scm-msm8660",}, - { .compatible = "qcom,scm-msm8960",}, - { .compatible = "qcom,scm",}, + { .compatible = "qcom,scm-apq8064", + .data = (void *) SCM_HAS_CORE_CLK, + }, + { .compatible = "qcom,scm-msm8660", + .data = (void *) SCM_HAS_CORE_CLK, + }, + { .compatible = "qcom,scm-msm8960", + .data = (void *) SCM_HAS_CORE_CLK, + }, + { .compatible = "qcom,scm-msm8996", + .data = NULL, /* no clocks */ + }, + { .compatible = "qcom,scm", + .data = (void *)(SCM_HAS_CORE_CLK + | SCM_HAS_IFACE_CLK + | SCM_HAS_BUS_CLK), + }, {} }; -- cgit v1.2.3 From ed19b86e817c5f30d557042f2e8ab68dc93940d4 Mon Sep 17 00:00:00 2001 From: "spjoshi@codeaurora.org" Date: Tue, 15 Nov 2016 17:19:25 -0800 Subject: firmware: qcom: scm: Return PTR_ERR when devm_clk_get fails When devm_clk_get fails for core clock, the failure was ignored and the core_clk was explicitly set to NULL so that other remaining clocks can be queried. However, now that we have a cleaner way of expressing the clock dependency, return failure when devm_clk_get fails for core clock. Signed-off-by: Sarangdhar Joshi Reviewed-by: Stephen Boyd Acked-by: Bjorn Andersson Signed-off-by: Andy Gross --- drivers/firmware/qcom_scm.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c index 7a104d31ef0f..893f953eaccf 100644 --- a/drivers/firmware/qcom_scm.c +++ b/drivers/firmware/qcom_scm.c @@ -338,10 +338,10 @@ static int qcom_scm_probe(struct platform_device *pdev) if (clks & SCM_HAS_CORE_CLK) { scm->core_clk = devm_clk_get(&pdev->dev, "core"); if (IS_ERR(scm->core_clk)) { - if (PTR_ERR(scm->core_clk) == -EPROBE_DEFER) - return PTR_ERR(scm->core_clk); - - scm->core_clk = NULL; + if (PTR_ERR(scm->core_clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, + "failed to acquire core clk\n"); + return PTR_ERR(scm->core_clk); } } -- cgit v1.2.3 From b88214ce4d7064992452765028bd50702414f15f Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Tue, 15 Nov 2016 09:59:58 +0200 Subject: PCI: Convert broken INTx masking quirks from HEADER to FINAL Convert all quirk_broken_intx_masking() quirks from HEADER to FINAL. The quirk sets dev->broken_intx_masking, which is only used by pci_intx_mask_supported(), which is not needed until after FINAL quirks have been run. [bhelgaas: changelog] Signed-off-by: Noa Osherovich Signed-off-by: Bjorn Helgaas Reviewed-by: Gavin Shan --- drivers/pci/quirks.c | 72 ++++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c232729f5b1b..85048fdf2474 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3146,53 +3146,53 @@ static void quirk_broken_intx_masking(struct pci_dev *dev) { dev->broken_intx_masking = 1; } -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_CHELSIO, 0x0030, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */ - quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x0030, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */ + quirk_broken_intx_masking); /* * Realtek RTL8169 PCI Gigabit Ethernet Controller (rev 10) * Subsystem: Realtek RTL8169/8110 Family PCI Gigabit Ethernet NIC * * RTL8110SC - Fails under PCI device assignment using DisINTx masking. */ -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_REALTEK, 0x8169, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, - quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REALTEK, 0x8169, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, + quirk_broken_intx_masking); /* * Intel i40e (XL710/X710) 10/20/40GbE NICs all have broken INTx masking, * DisINTx can be set but the interrupt status bit is non-functional. */ -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1572, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1574, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1580, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1581, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1583, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1584, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1585, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1586, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1587, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1588, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x1589, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x37d0, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x37d1, - quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x37d2, - quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1572, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1574, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1580, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1581, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1583, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1584, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1585, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1586, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1587, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1588, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1589, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d0, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d1, + quirk_broken_intx_masking); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d2, + quirk_broken_intx_masking); static void quirk_no_bus_reset(struct pci_dev *dev) { -- cgit v1.2.3 From d76d2fe05fd93673d184af77255bbbc63780f4ea Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Tue, 15 Nov 2016 09:59:59 +0200 Subject: PCI: Convert Mellanox broken INTx quirks to be for listed devices only Change Mellanox's broken_intx_masking() quirk from an "all Mellanox devices" to a quirk for listed devices only. [bhelgaas: remove #defines, reorder to keep other quirks together] Signed-off-by: Noa Osherovich Signed-off-by: Bjorn Helgaas Reviewed-by: Or Gerlitz Reviewed-by: Gavin Shan --- drivers/pci/quirks.c | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 85048fdf2474..f0515b78a4a6 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3137,8 +3137,9 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b5, quirk_remove_d3_delay); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x22b7, quirk_remove_d3_delay); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x2298, quirk_remove_d3_delay); DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x229c, quirk_remove_d3_delay); + /* - * Some devices may pass our check in pci_intx_mask_supported if + * Some devices may pass our check in pci_intx_mask_supported() if * PCI_COMMAND_INTX_DISABLE works though they actually do not properly * support this feature. */ @@ -3150,6 +3151,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x0030, quirk_broken_intx_masking); DECLARE_PCI_FIXUP_FINAL(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */ quirk_broken_intx_masking); + /* * Realtek RTL8169 PCI Gigabit Ethernet Controller (rev 10) * Subsystem: Realtek RTL8169/8110 Family PCI Gigabit Ethernet NIC @@ -3158,8 +3160,6 @@ DECLARE_PCI_FIXUP_FINAL(0x1814, 0x0601, /* Ralink RT2800 802.11n PCI */ */ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_REALTEK, 0x8169, quirk_broken_intx_masking); -DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, - quirk_broken_intx_masking); /* * Intel i40e (XL710/X710) 10/20/40GbE NICs all have broken INTx masking, @@ -3194,6 +3194,40 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d1, DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x37d2, quirk_broken_intx_masking); +static u16 mellanox_broken_intx_devs[] = { + PCI_DEVICE_ID_MELLANOX_HERMON_SDR, + PCI_DEVICE_ID_MELLANOX_HERMON_DDR, + PCI_DEVICE_ID_MELLANOX_HERMON_QDR, + PCI_DEVICE_ID_MELLANOX_HERMON_DDR_GEN2, + PCI_DEVICE_ID_MELLANOX_HERMON_QDR_GEN2, + PCI_DEVICE_ID_MELLANOX_HERMON_EN, + PCI_DEVICE_ID_MELLANOX_HERMON_EN_GEN2, + PCI_DEVICE_ID_MELLANOX_CONNECTX_EN, + PCI_DEVICE_ID_MELLANOX_CONNECTX_EN_T_GEN2, + PCI_DEVICE_ID_MELLANOX_CONNECTX_EN_GEN2, + PCI_DEVICE_ID_MELLANOX_CONNECTX_EN_5_GEN2, + PCI_DEVICE_ID_MELLANOX_CONNECTX2, + PCI_DEVICE_ID_MELLANOX_CONNECTX3, + PCI_DEVICE_ID_MELLANOX_CONNECTX3_PRO, + PCI_DEVICE_ID_MELLANOX_CONNECTIB, + PCI_DEVICE_ID_MELLANOX_CONNECTX4, + PCI_DEVICE_ID_MELLANOX_CONNECTX4_LX, +}; + +static void mellanox_check_broken_intx_masking(struct pci_dev *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mellanox_broken_intx_devs); i++) { + if (pdev->device == mellanox_broken_intx_devs[i]) { + pdev->broken_intx_masking = 1; + return; + } + } +} +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, + mellanox_check_broken_intx_masking); + static void quirk_no_bus_reset(struct pci_dev *dev) { dev->dev_flags |= PCI_DEV_FLAGS_NO_BUS_RESET; -- cgit v1.2.3 From 1600f62534b7b3da7978b43b52231a54c24df287 Mon Sep 17 00:00:00 2001 From: Noa Osherovich Date: Tue, 15 Nov 2016 10:00:00 +0200 Subject: PCI: Support INTx masking on ConnectX-4 with firmware x.14.1100+ Mellanox devices were marked as having INTx masking ability broken. As a result, the VFIO driver fails to start when more than one device function is passed-through to a VM if both have the same INTx pin. Prior to Connect-IB, Mellanox devices exposed to the operating system one PCI function per all ports. Starting from Connect-IB, the devices are function-per-port. When passing the second function to a VM, VFIO will fail to start. Exclude ConnectX-4, ConnectX4-Lx and Connect-IB from the list of Mellanox devices marked as having broken INTx masking: - ConnectX-4 and ConnectX4-LX firmware version is checked. If INTx masking is supported, we unmark the broken INTx masking. - Connect-IB does not support INTx currently so will not cause any problem. [bhelgaas: call pci_disable_device() always, after iounmap()] Fixes: 11e42532ada3 ("PCI: Assume all Mellanox devices have broken INTx masking") Signed-off-by: Noa Osherovich Signed-off-by: Bjorn Helgaas Reviewed-by: Or Gerlitz Reviewed-by: Gavin Shan --- drivers/pci/quirks.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index f0515b78a4a6..93b03128bec0 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3209,13 +3209,25 @@ static u16 mellanox_broken_intx_devs[] = { PCI_DEVICE_ID_MELLANOX_CONNECTX2, PCI_DEVICE_ID_MELLANOX_CONNECTX3, PCI_DEVICE_ID_MELLANOX_CONNECTX3_PRO, - PCI_DEVICE_ID_MELLANOX_CONNECTIB, - PCI_DEVICE_ID_MELLANOX_CONNECTX4, - PCI_DEVICE_ID_MELLANOX_CONNECTX4_LX, }; +#define CONNECTX_4_CURR_MAX_MINOR 99 +#define CONNECTX_4_INTX_SUPPORT_MINOR 14 + +/* + * Check ConnectX-4/LX FW version to see if it supports legacy interrupts. + * If so, don't mark it as broken. + * FW minor > 99 means older FW version format and no INTx masking support. + * FW minor < 14 means new FW version format and no INTx masking support. + */ static void mellanox_check_broken_intx_masking(struct pci_dev *pdev) { + __be32 __iomem *fw_ver; + u16 fw_major; + u16 fw_minor; + u16 fw_subminor; + u32 fw_maj_min; + u32 fw_sub_min; int i; for (i = 0; i < ARRAY_SIZE(mellanox_broken_intx_devs); i++) { @@ -3224,6 +3236,47 @@ static void mellanox_check_broken_intx_masking(struct pci_dev *pdev) return; } } + + /* Getting here means Connect-IB cards and up. Connect-IB has no INTx + * support so shouldn't be checked further + */ + if (pdev->device == PCI_DEVICE_ID_MELLANOX_CONNECTIB) + return; + + if (pdev->device != PCI_DEVICE_ID_MELLANOX_CONNECTX4 && + pdev->device != PCI_DEVICE_ID_MELLANOX_CONNECTX4_LX) + return; + + /* For ConnectX-4 and ConnectX-4LX, need to check FW support */ + if (pci_enable_device_mem(pdev)) { + dev_warn(&pdev->dev, "Can't enable device memory\n"); + return; + } + + fw_ver = ioremap(pci_resource_start(pdev, 0), 4); + if (!fw_ver) { + dev_warn(&pdev->dev, "Can't map ConnectX-4 initialization segment\n"); + goto out; + } + + /* Reading from resource space should be 32b aligned */ + fw_maj_min = ioread32be(fw_ver); + fw_sub_min = ioread32be(fw_ver + 1); + fw_major = fw_maj_min & 0xffff; + fw_minor = fw_maj_min >> 16; + fw_subminor = fw_sub_min & 0xffff; + if (fw_minor > CONNECTX_4_CURR_MAX_MINOR || + fw_minor < CONNECTX_4_INTX_SUPPORT_MINOR) { + dev_warn(&pdev->dev, "ConnectX-4: FW %u.%u.%u doesn't support INTx masking, disabling. Please upgrade FW to %d.14.1100 and up for INTx support\n", + fw_major, fw_minor, fw_subminor, pdev->device == + PCI_DEVICE_ID_MELLANOX_CONNECTX4 ? 12 : 14); + pdev->broken_intx_masking = 1; + } + + iounmap(fw_ver); + +out: + pci_disable_device(pdev); } DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_MELLANOX, PCI_ANY_ID, mellanox_check_broken_intx_masking); -- cgit v1.2.3 From 8d6799a9ba23acd675f3243580ee6f1756fb4381 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 14 Nov 2016 19:37:08 +0100 Subject: soc: renesas: Identify SoC and register with the SoC bus Identify the SoC type and revision, and register this information with the SoC bus, so it is available under /sys/devices/soc0/, and can be checked where needed using soc_device_match(). Identification is done using the Product Register or Common Chip Code Register, as declared in DT (PRR only for now), or using a hardcoded fallback if missing. Example: Detected Renesas R-Car Gen2 r8a7791 ES1.0 ... # cat /sys/devices/soc0/{machine,family,soc_id,revision} Koelsch R-Car Gen2 r8a7791 ES1.0 Signed-off-by: Geert Uytterhoeven Signed-off-by: Simon Horman --- arch/arm/mach-shmobile/Kconfig | 1 + arch/arm64/Kconfig.platforms | 1 + drivers/soc/renesas/Makefile | 2 + drivers/soc/renesas/renesas-soc.c | 257 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 261 insertions(+) create mode 100644 drivers/soc/renesas/renesas-soc.c (limited to 'drivers') diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig index 09817bae4558..ebab13e8afa1 100644 --- a/arch/arm/mach-shmobile/Kconfig +++ b/arch/arm/mach-shmobile/Kconfig @@ -40,6 +40,7 @@ menuconfig ARCH_RENESAS select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE select NO_IOPORT_MAP select PINCTRL + select SOC_BUS select GPIOLIB select ZONE_DMA if ARM_LPAE diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms index cfbdf02ef566..72f4eac5cbbc 100644 --- a/arch/arm64/Kconfig.platforms +++ b/arch/arm64/Kconfig.platforms @@ -143,6 +143,7 @@ config ARCH_RENESAS select PM select PM_GENERIC_DOMAINS select RENESAS_IRQC + select SOC_BUS help This enables support for the ARMv8 based Renesas SoCs. diff --git a/drivers/soc/renesas/Makefile b/drivers/soc/renesas/Makefile index 623039c3514c..f2737a9f96ae 100644 --- a/drivers/soc/renesas/Makefile +++ b/drivers/soc/renesas/Makefile @@ -1,3 +1,5 @@ +obj-$(CONFIG_SOC_BUS) += renesas-soc.o + obj-$(CONFIG_ARCH_R8A7779) += rcar-sysc.o r8a7779-sysc.o obj-$(CONFIG_ARCH_R8A7790) += rcar-sysc.o r8a7790-sysc.o obj-$(CONFIG_ARCH_R8A7791) += rcar-sysc.o r8a7791-sysc.o diff --git a/drivers/soc/renesas/renesas-soc.c b/drivers/soc/renesas/renesas-soc.c new file mode 100644 index 000000000000..330960312296 --- /dev/null +++ b/drivers/soc/renesas/renesas-soc.c @@ -0,0 +1,257 @@ +/* + * Renesas SoC Identification + * + * Copyright (C) 2014-2016 Glider bvba + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include + + +struct renesas_family { + const char name[16]; + u32 reg; /* CCCR or PRR, if not in DT */ +}; + +static const struct renesas_family fam_rcar_gen1 __initconst __maybe_unused = { + .name = "R-Car Gen1", + .reg = 0xff000044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_rcar_gen2 __initconst __maybe_unused = { + .name = "R-Car Gen2", + .reg = 0xff000044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_rcar_gen3 __initconst __maybe_unused = { + .name = "R-Car Gen3", + .reg = 0xfff00044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_rmobile __initconst __maybe_unused = { + .name = "R-Mobile", + .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ +}; + +static const struct renesas_family fam_rza __initconst __maybe_unused = { + .name = "RZ/A", +}; + +static const struct renesas_family fam_rzg __initconst __maybe_unused = { + .name = "RZ/G", + .reg = 0xff000044, /* PRR (Product Register) */ +}; + +static const struct renesas_family fam_shmobile __initconst __maybe_unused = { + .name = "SH-Mobile", + .reg = 0xe600101c, /* CCCR (Common Chip Code Register) */ +}; + + +struct renesas_soc { + const struct renesas_family *family; + u8 id; +}; + +static const struct renesas_soc soc_rz_a1h __initconst __maybe_unused = { + .family = &fam_rza, +}; + +static const struct renesas_soc soc_rmobile_ape6 __initconst __maybe_unused = { + .family = &fam_rmobile, + .id = 0x3f, +}; + +static const struct renesas_soc soc_rmobile_a1 __initconst __maybe_unused = { + .family = &fam_rmobile, + .id = 0x40, +}; + +static const struct renesas_soc soc_rz_g1m __initconst __maybe_unused = { + .family = &fam_rzg, + .id = 0x47, +}; + +static const struct renesas_soc soc_rz_g1e __initconst __maybe_unused = { + .family = &fam_rzg, + .id = 0x4c, +}; + +static const struct renesas_soc soc_rcar_m1a __initconst __maybe_unused = { + .family = &fam_rcar_gen1, +}; + +static const struct renesas_soc soc_rcar_h1 __initconst __maybe_unused = { + .family = &fam_rcar_gen1, + .id = 0x3b, +}; + +static const struct renesas_soc soc_rcar_h2 __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x45, +}; + +static const struct renesas_soc soc_rcar_m2_w __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x47, +}; + +static const struct renesas_soc soc_rcar_v2h __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x4a, +}; + +static const struct renesas_soc soc_rcar_m2_n __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x4b, +}; + +static const struct renesas_soc soc_rcar_e2 __initconst __maybe_unused = { + .family = &fam_rcar_gen2, + .id = 0x4c, +}; + +static const struct renesas_soc soc_rcar_h3 __initconst __maybe_unused = { + .family = &fam_rcar_gen3, + .id = 0x4f, +}; + +static const struct renesas_soc soc_rcar_m3_w __initconst __maybe_unused = { + .family = &fam_rcar_gen3, + .id = 0x52, +}; + +static const struct renesas_soc soc_shmobile_ag5 __initconst __maybe_unused = { + .family = &fam_shmobile, + .id = 0x37, +}; + + +static const struct of_device_id renesas_socs[] __initconst = { +#ifdef CONFIG_ARCH_R7S72100 + { .compatible = "renesas,r7s72100", .data = &soc_rz_a1h }, +#endif +#ifdef CONFIG_ARCH_R8A73A4 + { .compatible = "renesas,r8a73a4", .data = &soc_rmobile_ape6 }, +#endif +#ifdef CONFIG_ARCH_R8A7740 + { .compatible = "renesas,r8a7740", .data = &soc_rmobile_a1 }, +#endif +#ifdef CONFIG_ARCH_R8A7743 + { .compatible = "renesas,r8a7743", .data = &soc_rz_g1m }, +#endif +#ifdef CONFIG_ARCH_R8A7745 + { .compatible = "renesas,r8a7745", .data = &soc_rz_g1e }, +#endif +#ifdef CONFIG_ARCH_R8A7778 + { .compatible = "renesas,r8a7778", .data = &soc_rcar_m1a }, +#endif +#ifdef CONFIG_ARCH_R8A7779 + { .compatible = "renesas,r8a7779", .data = &soc_rcar_h1 }, +#endif +#ifdef CONFIG_ARCH_R8A7790 + { .compatible = "renesas,r8a7790", .data = &soc_rcar_h2 }, +#endif +#ifdef CONFIG_ARCH_R8A7791 + { .compatible = "renesas,r8a7791", .data = &soc_rcar_m2_w }, +#endif +#ifdef CONFIG_ARCH_R8A7792 + { .compatible = "renesas,r8a7792", .data = &soc_rcar_v2h }, +#endif +#ifdef CONFIG_ARCH_R8A7793 + { .compatible = "renesas,r8a7793", .data = &soc_rcar_m2_n }, +#endif +#ifdef CONFIG_ARCH_R8A7794 + { .compatible = "renesas,r8a7794", .data = &soc_rcar_e2 }, +#endif +#ifdef CONFIG_ARCH_R8A7795 + { .compatible = "renesas,r8a7795", .data = &soc_rcar_h3 }, +#endif +#ifdef CONFIG_ARCH_R8A7796 + { .compatible = "renesas,r8a7796", .data = &soc_rcar_m3_w }, +#endif +#ifdef CONFIG_ARCH_SH73A0 + { .compatible = "renesas,sh73a0", .data = &soc_shmobile_ag5 }, +#endif + { /* sentinel */ } +}; + +static int __init renesas_soc_init(void) +{ + struct soc_device_attribute *soc_dev_attr; + const struct renesas_family *family; + const struct of_device_id *match; + const struct renesas_soc *soc; + void __iomem *chipid = NULL; + struct soc_device *soc_dev; + struct device_node *np; + unsigned int product; + + match = of_match_node(renesas_socs, of_root); + if (!match) + return -ENODEV; + + soc = match->data; + family = soc->family; + + /* Try PRR first, then hardcoded fallback */ + np = of_find_compatible_node(NULL, NULL, "renesas,prr"); + if (np) { + chipid = of_iomap(np, 0); + of_node_put(np); + } else if (soc->id) { + chipid = ioremap(family->reg, 4); + } + if (chipid) { + product = readl(chipid); + iounmap(chipid); + if (soc->id && ((product >> 8) & 0xff) != soc->id) { + pr_warn("SoC mismatch (product = 0x%x)\n", product); + return -ENODEV; + } + } + + soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL); + if (!soc_dev_attr) + return -ENOMEM; + + np = of_find_node_by_path("/"); + of_property_read_string(np, "model", &soc_dev_attr->machine); + of_node_put(np); + + soc_dev_attr->family = kstrdup_const(family->name, GFP_KERNEL); + soc_dev_attr->soc_id = kstrdup_const(strchr(match->compatible, ',') + 1, + GFP_KERNEL); + if (chipid) + soc_dev_attr->revision = kasprintf(GFP_KERNEL, "ES%u.%u", + ((product >> 4) & 0x0f) + 1, + product & 0xf); + + pr_info("Detected Renesas %s %s %s\n", soc_dev_attr->family, + soc_dev_attr->soc_id, soc_dev_attr->revision ?: ""); + + soc_dev = soc_device_register(soc_dev_attr); + if (IS_ERR(soc_dev)) { + kfree(soc_dev_attr->revision); + kfree_const(soc_dev_attr->soc_id); + kfree_const(soc_dev_attr->family); + kfree(soc_dev_attr); + return PTR_ERR(soc_dev); + } + + return 0; +} +core_initcall(renesas_soc_init); -- cgit v1.2.3 From 59eba2d1ec0272ea9cb472b5805e179242df226d Mon Sep 17 00:00:00 2001 From: Andrey Utkin Date: Mon, 17 Oct 2016 17:25:59 -0200 Subject: [media] saa7146: Fix for while releasing video buffers Fix this bug: "[BUG] process stuck when closing saa7146 [dvb_ttpci]" Release queued DMA buffers when ending streaming, so that videobuf_waiton() doesn't block forever. As reported, this fixes avoids occasional lockup of process reading from video device, which manifests in such log: INFO: task ffmpeg:9864 blocked for more than 120 seconds. Tainted: P O 4.6.7 #3 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. ffmpeg D ffff880177cc7b00 0 9864 1 0x00000000 ffff880177cc7b00 0000000000000202 0000000000000202 ffffffff8180b4c0 ffff88019d79e4c0 ffffffff81064050 ffff880177cc7ae0 ffff880177cc8000 ffff880177cc7b18 ffff8801fd41d648 ffff8802307acca0 ffff8802307acc70 Call Trace: [] ? preempt_count_add+0x89/0xab [] schedule+0x86/0x9e [] ? schedule+0x86/0x9e [] videobuf_waiton+0x131/0x15e [videobuf_core] [] ? wait_woken+0x6d/0x6d [] saa7146_dma_free+0x39/0x5b [saa7146_vv] [] buffer_release+0x2a/0x3e [saa7146_vv] [] videobuf_vm_close+0xd8/0x103 [videobuf_dma_sg] [] remove_vma+0x25/0x4d [] exit_mmap+0xce/0xf7 [] mmput+0x4e/0xe2 [] do_exit+0x372/0x920 [] do_group_exit+0x3c/0x98 [] get_signal+0x4e8/0x56e [] ? task_dead_fair+0xd/0xf [] do_signal+0x23/0x521 [] ? _raw_spin_unlock_irqrestore+0x13/0x25 [] ? hrtimer_try_to_cancel+0xd7/0x104 [] ? ktime_get+0x4c/0xa1 [] ? update_rmtp+0x46/0x5b [] ? hrtimer_nanosleep+0xe4/0x10e [] ? hrtimer_init+0xeb/0xeb [] exit_to_usermode_loop+0x4f/0x93 [] syscall_return_slowpath+0x3b/0x46 [] entry_SYSCALL_64_fastpath+0x8d/0x8f Reported-by: Philipp Matthias Hahn Tested-by: Philipp Matthias Hahn Signed-off-by: Andrey Utkin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/saa7146/saa7146_video.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c index ea2f3bf7368b..e034bcfcf757 100644 --- a/drivers/media/common/saa7146/saa7146_video.c +++ b/drivers/media/common/saa7146/saa7146_video.c @@ -390,6 +390,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file) { struct saa7146_dev *dev = fh->dev; struct saa7146_vv *vv = dev->vv_data; + struct saa7146_dmaqueue *q = &vv->video_dmaq; struct saa7146_format *fmt = NULL; unsigned long flags; unsigned int resource; @@ -428,6 +429,9 @@ static int video_end(struct saa7146_fh *fh, struct file *file) /* shut down all used video dma transfers */ saa7146_write(dev, MC1, dmas); + if (q->curr) + saa7146_buffer_finish(dev, q, VIDEOBUF_DONE); + spin_unlock_irqrestore(&dev->slock, flags); vv->video_fh = NULL; -- cgit v1.2.3 From b9a4b13c770a84599dc706b78cd70ad5761fc30b Mon Sep 17 00:00:00 2001 From: Sakari Ailus Date: Mon, 27 Jun 2016 10:46:16 -0300 Subject: [media] v4l: Add 16-bit raw bayer pixel formats The formats added by this patch are: V4L2_PIX_FMT_SBGGR16 V4L2_PIX_FMT_SGBRG16 V4L2_PIX_FMT_SGRBG16 V4L2_PIX_FMT_SRGGB16 already existed before the patch. Rework the documentation to match that of the other sample depths. Also align the description of V4L2_PIX_FMT_SRGGB16 to match with other similar formats. Signed-off-by: Sakari Ailus Acked-by: Lad, Prabhakar Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/uapi/v4l/pixfmt-rgb.rst | 2 +- Documentation/media/uapi/v4l/pixfmt-sbggr16.rst | 62 ---------------------- Documentation/media/uapi/v4l/pixfmt-srggb16.rst | 69 +++++++++++++++++++++++++ drivers/media/v4l2-core/v4l2-ioctl.c | 5 +- include/uapi/linux/videodev2.h | 3 ++ 5 files changed, 77 insertions(+), 64 deletions(-) delete mode 100644 Documentation/media/uapi/v4l/pixfmt-sbggr16.rst create mode 100644 Documentation/media/uapi/v4l/pixfmt-srggb16.rst (limited to 'drivers') diff --git a/Documentation/media/uapi/v4l/pixfmt-rgb.rst b/Documentation/media/uapi/v4l/pixfmt-rgb.rst index 9cc980882e80..b0f35136021e 100644 --- a/Documentation/media/uapi/v4l/pixfmt-rgb.rst +++ b/Documentation/media/uapi/v4l/pixfmt-rgb.rst @@ -12,9 +12,9 @@ RGB Formats pixfmt-packed-rgb pixfmt-srggb8 - pixfmt-sbggr16 pixfmt-srggb10 pixfmt-srggb10p pixfmt-srggb10alaw8 pixfmt-srggb10dpcm8 pixfmt-srggb12 + pixfmt-srggb16 diff --git a/Documentation/media/uapi/v4l/pixfmt-sbggr16.rst b/Documentation/media/uapi/v4l/pixfmt-sbggr16.rst deleted file mode 100644 index 6f7f327db85c..000000000000 --- a/Documentation/media/uapi/v4l/pixfmt-sbggr16.rst +++ /dev/null @@ -1,62 +0,0 @@ -.. -*- coding: utf-8; mode: rst -*- - -.. _V4L2-PIX-FMT-SBGGR16: - -***************************** -V4L2_PIX_FMT_SBGGR16 ('BYR2') -***************************** - -Bayer RGB format - - -Description -=========== - -This format is similar to -:ref:`V4L2_PIX_FMT_SBGGR8 `, except each pixel -has a depth of 16 bits. The least significant byte is stored at lower -memory addresses (little-endian). - -**Byte Order.** -Each cell is one byte. - -.. flat-table:: - :header-rows: 0 - :stub-columns: 0 - - * - start + 0: - - B\ :sub:`00low` - - B\ :sub:`00high` - - G\ :sub:`01low` - - G\ :sub:`01high` - - B\ :sub:`02low` - - B\ :sub:`02high` - - G\ :sub:`03low` - - G\ :sub:`03high` - * - start + 8: - - G\ :sub:`10low` - - G\ :sub:`10high` - - R\ :sub:`11low` - - R\ :sub:`11high` - - G\ :sub:`12low` - - G\ :sub:`12high` - - R\ :sub:`13low` - - R\ :sub:`13high` - * - start + 16: - - B\ :sub:`20low` - - B\ :sub:`20high` - - G\ :sub:`21low` - - G\ :sub:`21high` - - B\ :sub:`22low` - - B\ :sub:`22high` - - G\ :sub:`23low` - - G\ :sub:`23high` - * - start + 24: - - G\ :sub:`30low` - - G\ :sub:`30high` - - R\ :sub:`31low` - - R\ :sub:`31high` - - G\ :sub:`32low` - - G\ :sub:`32high` - - R\ :sub:`33low` - - R\ :sub:`33high` diff --git a/Documentation/media/uapi/v4l/pixfmt-srggb16.rst b/Documentation/media/uapi/v4l/pixfmt-srggb16.rst new file mode 100644 index 000000000000..06facc9cd539 --- /dev/null +++ b/Documentation/media/uapi/v4l/pixfmt-srggb16.rst @@ -0,0 +1,69 @@ +.. -*- coding: utf-8; mode: rst -*- + +.. _V4L2-PIX-FMT-SRGGB16: +.. _v4l2-pix-fmt-sbggr16: +.. _v4l2-pix-fmt-sgbrg16: +.. _v4l2-pix-fmt-sgrbg16: + + +*************************************************************************************************************************** +V4L2_PIX_FMT_SRGGB16 ('RG16'), V4L2_PIX_FMT_SGRBG16 ('GR16'), V4L2_PIX_FMT_SGBRG16 ('GB16'), V4L2_PIX_FMT_SBGGR16 ('BYR2'), +*************************************************************************************************************************** + + +16-bit Bayer formats + + +Description +=========== + +These four pixel formats are raw sRGB / Bayer formats with 16 bits per +sample. Each sample is stored in a 16-bit word. Each n-pixel row contains +n/2 green samples and n/2 blue or red samples, with alternating red and blue +rows. Bytes are stored in memory in little endian order. They are +conventionally described as GRGR... BGBG..., RGRG... GBGB..., etc. Below is +an example of one of these formats: + +**Byte Order.** +Each cell is one byte. + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - start + 0: + - B\ :sub:`00low` + - B\ :sub:`00high` + - G\ :sub:`01low` + - G\ :sub:`01high` + - B\ :sub:`02low` + - B\ :sub:`02high` + - G\ :sub:`03low` + - G\ :sub:`03high` + * - start + 8: + - G\ :sub:`10low` + - G\ :sub:`10high` + - R\ :sub:`11low` + - R\ :sub:`11high` + - G\ :sub:`12low` + - G\ :sub:`12high` + - R\ :sub:`13low` + - R\ :sub:`13high` + * - start + 16: + - B\ :sub:`20low` + - B\ :sub:`20high` + - G\ :sub:`21low` + - G\ :sub:`21high` + - B\ :sub:`22low` + - B\ :sub:`22high` + - G\ :sub:`23low` + - G\ :sub:`23high` + * - start + 24: + - G\ :sub:`30low` + - G\ :sub:`30high` + - R\ :sub:`31low` + - R\ :sub:`31high` + - G\ :sub:`32low` + - G\ :sub:`32high` + - R\ :sub:`33low` + - R\ :sub:`33high` diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 181381d1dc77..61d2d65318c5 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1191,7 +1191,10 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_SGBRG10DPCM8: descr = "8-bit Bayer GBGB/RGRG (DPCM)"; break; case V4L2_PIX_FMT_SGRBG10DPCM8: descr = "8-bit Bayer GRGR/BGBG (DPCM)"; break; case V4L2_PIX_FMT_SRGGB10DPCM8: descr = "8-bit Bayer RGRG/GBGB (DPCM)"; break; - case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR (Exp.)"; break; + case V4L2_PIX_FMT_SBGGR16: descr = "16-bit Bayer BGBG/GRGR"; break; + case V4L2_PIX_FMT_SGBRG16: descr = "16-bit Bayer GBGB/RGRG"; break; + case V4L2_PIX_FMT_SGRBG16: descr = "16-bit Bayer GRGR/BGBG"; break; + case V4L2_PIX_FMT_SRGGB16: descr = "16-bit Bayer RGRG/GBGB"; break; case V4L2_PIX_FMT_SN9C20X_I420: descr = "GSPCA SN9C20X I420"; break; case V4L2_PIX_FMT_SPCA501: descr = "GSPCA SPCA501"; break; case V4L2_PIX_FMT_SPCA505: descr = "GSPCA SPCA505"; break; diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h index d3f613e2c54a..46e8a2e369f9 100644 --- a/include/uapi/linux/videodev2.h +++ b/include/uapi/linux/videodev2.h @@ -605,6 +605,9 @@ struct v4l2_pix_format { #define V4L2_PIX_FMT_SGRBG12 v4l2_fourcc('B', 'A', '1', '2') /* 12 GRGR.. BGBG.. */ #define V4L2_PIX_FMT_SRGGB12 v4l2_fourcc('R', 'G', '1', '2') /* 12 RGRG.. GBGB.. */ #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16 BGBG.. GRGR.. */ +#define V4L2_PIX_FMT_SGBRG16 v4l2_fourcc('G', 'B', '1', '6') /* 16 GBGB.. RGRG.. */ +#define V4L2_PIX_FMT_SGRBG16 v4l2_fourcc('G', 'R', '1', '6') /* 16 GRGR.. BGBG.. */ +#define V4L2_PIX_FMT_SRGGB16 v4l2_fourcc('R', 'G', '1', '6') /* 16 RGRG.. GBGB.. */ /* HSV formats */ #define V4L2_PIX_FMT_HSV24 v4l2_fourcc('H', 'S', 'V', '3') -- cgit v1.2.3 From 5b382290ffe1561b6eba7b0e8d4b7abbf63f0c1a Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 15 Nov 2016 14:44:01 -0200 Subject: [media] v4l: Add description of the Y8I, Y12I and Z16 formats The formats have been added without a description, fix that. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/v4l2-core/v4l2-ioctl.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index 61d2d65318c5..0c3f238a2e76 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -1128,6 +1128,9 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt) case V4L2_PIX_FMT_Y16: descr = "16-bit Greyscale"; break; case V4L2_PIX_FMT_Y16_BE: descr = "16-bit Greyscale BE"; break; case V4L2_PIX_FMT_Y10BPACK: descr = "10-bit Greyscale (Packed)"; break; + case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break; + case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break; + case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break; case V4L2_PIX_FMT_PAL8: descr = "8-bit Palette"; break; case V4L2_PIX_FMT_UV8: descr = "8-bit Chrominance UV 4-4"; break; case V4L2_PIX_FMT_YVU410: descr = "Planar YVU 4:1:0"; break; -- cgit v1.2.3 From eb165a20dfbe8b82e82b671e9941c4ad9f34388d Mon Sep 17 00:00:00 2001 From: Edgar Thier Date: Tue, 15 Nov 2016 03:33:10 -0200 Subject: [media] uvcvideo: Add bayer 16-bit format patterns Those formats are implemented by The DFK 23UP1300, DFK 23UX249 and DFK 23UX250 USB 3.0 industrial cameras from The Imaging Source. Signed-off-by: Edgar Thier Acked-by: Sakari Ailus Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_driver.c | 20 ++++++++++++++++++++ drivers/media/usb/uvc/uvcvideo.h | 12 ++++++++++++ 2 files changed, 32 insertions(+) (limited to 'drivers') diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 11744f92097b..04bf35063c4c 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -168,6 +168,26 @@ static struct uvc_format_desc uvc_fmts[] = { .guid = UVC_GUID_FORMAT_RW10, .fcc = V4L2_PIX_FMT_SRGGB10P, }, + { + .name = "Bayer 16-bit (SBGGR16)", + .guid = UVC_GUID_FORMAT_BG16, + .fcc = V4L2_PIX_FMT_SBGGR16, + }, + { + .name = "Bayer 16-bit (SGBRG16)", + .guid = UVC_GUID_FORMAT_GB16, + .fcc = V4L2_PIX_FMT_SGBRG16, + }, + { + .name = "Bayer 16-bit (SRGGB16)", + .guid = UVC_GUID_FORMAT_RG16, + .fcc = V4L2_PIX_FMT_SRGGB16, + }, + { + .name = "Bayer 16-bit (SGRBG16)", + .guid = UVC_GUID_FORMAT_GR16, + .fcc = V4L2_PIX_FMT_SGRBG16, + }, }; /* ------------------------------------------------------------------------ diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 7e4d3eea371b..3d6cc62f3cd2 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -106,6 +106,18 @@ #define UVC_GUID_FORMAT_RGGB \ { 'R', 'G', 'G', 'B', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_BG16 \ + { 'B', 'G', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GB16 \ + { 'G', 'B', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_RG16 \ + { 'R', 'G', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} +#define UVC_GUID_FORMAT_GR16 \ + { 'G', 'R', '1', '6', 0x00, 0x00, 0x10, 0x00, \ + 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} #define UVC_GUID_FORMAT_RGBP \ { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71} -- cgit v1.2.3 From 4cc5bed1caeb6d40f2f41c4c5eb83368691fbffb Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Fri, 19 Aug 2016 05:50:05 -0300 Subject: [media] uvcvideo: Use memdup_user() rather than duplicating its implementation Reuse existing functionality from memdup_user() instead of keeping duplicate source code. This issue was detected by using the Coccinelle software. Signed-off-by: Markus Elfring Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index 05eed4be25df..a7e12fd20adc 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -70,14 +70,9 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, } size = xmap->menu_count * sizeof(*map->menu_info); - map->menu_info = kmalloc(size, GFP_KERNEL); - if (map->menu_info == NULL) { - ret = -ENOMEM; - goto done; - } - - if (copy_from_user(map->menu_info, xmap->menu_info, size)) { - ret = -EFAULT; + map->menu_info = memdup_user(xmap->menu_info, size); + if (IS_ERR(map->menu_info)) { + ret = PTR_ERR(map->menu_info); goto done; } -- cgit v1.2.3 From 075eb5719d53e8bb4a406ad87e1de99319aa50f0 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Mon, 14 Nov 2016 19:38:31 -0800 Subject: bq24190_charger: Fix PM runtime use for bq24190_battery_set_property There's a typo, it should do pm_runtime_get_sync, not put. Fixes: d7bf353fd0aa3 ("bq24190_charger: Add support for TI BQ24190 Battery Charger") Cc: Mark A. Greer Signed-off-by: Tony Lindgren Reviewed-by: Mark Greer Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq24190_charger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/supply/bq24190_charger.c b/drivers/power/supply/bq24190_charger.c index f5746b9f4e83..e9584330aeed 100644 --- a/drivers/power/supply/bq24190_charger.c +++ b/drivers/power/supply/bq24190_charger.c @@ -1141,7 +1141,7 @@ static int bq24190_battery_set_property(struct power_supply *psy, dev_dbg(bdi->dev, "prop: %d\n", psp); - pm_runtime_put_sync(bdi->dev); + pm_runtime_get_sync(bdi->dev); switch (psp) { case POWER_SUPPLY_PROP_ONLINE: -- cgit v1.2.3 From 3bee9ea1de687925d116670f036599cbed8b66b0 Mon Sep 17 00:00:00 2001 From: "Andrew F. Davis" Date: Fri, 4 Nov 2016 13:33:13 -0500 Subject: power: supply: bq27xxx_battery: Fix register map for BQ27510 and BQ27520 The BQ27510 and BQ27520 use a slightly different register map than the BQ27500, add a new type enum and add these gauges to it. Fixes: d74534c27775 ("power: bq27xxx_battery: Add support for additional bq27xxx family devices") Based-on-patch-by: Kenneth R. Crudup Signed-off-by: Andrew F. Davis Signed-off-by: Sebastian Reichel --- drivers/power/supply/bq27xxx_battery.c | 41 +++++++++++++++++++++++++++++- drivers/power/supply/bq27xxx_battery_i2c.c | 4 +-- include/linux/power/bq27xxx_battery.h | 3 ++- 3 files changed, 44 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/power/supply/bq27xxx_battery.c b/drivers/power/supply/bq27xxx_battery.c index 0c343a0c941e..08c36b8e04bd 100644 --- a/drivers/power/supply/bq27xxx_battery.c +++ b/drivers/power/supply/bq27xxx_battery.c @@ -164,6 +164,25 @@ static u8 bq27xxx_regs[][BQ27XXX_REG_MAX] = { [BQ27XXX_REG_DCAP] = 0x3c, [BQ27XXX_REG_AP] = INVALID_REG_ADDR, }, + [BQ27510] = { + [BQ27XXX_REG_CTRL] = 0x00, + [BQ27XXX_REG_TEMP] = 0x06, + [BQ27XXX_REG_INT_TEMP] = 0x28, + [BQ27XXX_REG_VOLT] = 0x08, + [BQ27XXX_REG_AI] = 0x14, + [BQ27XXX_REG_FLAGS] = 0x0a, + [BQ27XXX_REG_TTE] = 0x16, + [BQ27XXX_REG_TTF] = INVALID_REG_ADDR, + [BQ27XXX_REG_TTES] = 0x1a, + [BQ27XXX_REG_TTECP] = INVALID_REG_ADDR, + [BQ27XXX_REG_NAC] = 0x0c, + [BQ27XXX_REG_FCC] = 0x12, + [BQ27XXX_REG_CYCT] = 0x1e, + [BQ27XXX_REG_AE] = INVALID_REG_ADDR, + [BQ27XXX_REG_SOC] = 0x20, + [BQ27XXX_REG_DCAP] = 0x2e, + [BQ27XXX_REG_AP] = INVALID_REG_ADDR, + }, [BQ27530] = { [BQ27XXX_REG_CTRL] = 0x00, [BQ27XXX_REG_TEMP] = 0x06, @@ -302,6 +321,24 @@ static enum power_supply_property bq27500_battery_props[] = { POWER_SUPPLY_PROP_MANUFACTURER, }; +static enum power_supply_property bq27510_battery_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_CAPACITY, + POWER_SUPPLY_PROP_CAPACITY_LEVEL, + POWER_SUPPLY_PROP_TEMP, + POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_CHARGE_FULL, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CYCLE_COUNT, + POWER_SUPPLY_PROP_HEALTH, + POWER_SUPPLY_PROP_MANUFACTURER, +}; + static enum power_supply_property bq27530_battery_props[] = { POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_PRESENT, @@ -385,6 +422,7 @@ static struct { BQ27XXX_PROP(BQ27000, bq27000_battery_props), BQ27XXX_PROP(BQ27010, bq27010_battery_props), BQ27XXX_PROP(BQ27500, bq27500_battery_props), + BQ27XXX_PROP(BQ27510, bq27510_battery_props), BQ27XXX_PROP(BQ27530, bq27530_battery_props), BQ27XXX_PROP(BQ27541, bq27541_battery_props), BQ27XXX_PROP(BQ27545, bq27545_battery_props), @@ -636,7 +674,8 @@ static int bq27xxx_battery_read_pwr_avg(struct bq27xxx_device_info *di) */ static bool bq27xxx_battery_overtemp(struct bq27xxx_device_info *di, u16 flags) { - if (di->chip == BQ27500 || di->chip == BQ27541 || di->chip == BQ27545) + if (di->chip == BQ27500 || di->chip == BQ27510 || + di->chip == BQ27541 || di->chip == BQ27545) return flags & (BQ27XXX_FLAG_OTC | BQ27XXX_FLAG_OTD); if (di->chip == BQ27530 || di->chip == BQ27421) return flags & BQ27XXX_FLAG_OT; diff --git a/drivers/power/supply/bq27xxx_battery_i2c.c b/drivers/power/supply/bq27xxx_battery_i2c.c index 85d4ea2a9c20..5c5c3a6f9923 100644 --- a/drivers/power/supply/bq27xxx_battery_i2c.c +++ b/drivers/power/supply/bq27xxx_battery_i2c.c @@ -149,8 +149,8 @@ static const struct i2c_device_id bq27xxx_i2c_id_table[] = { { "bq27200", BQ27000 }, { "bq27210", BQ27010 }, { "bq27500", BQ27500 }, - { "bq27510", BQ27500 }, - { "bq27520", BQ27500 }, + { "bq27510", BQ27510 }, + { "bq27520", BQ27510 }, { "bq27530", BQ27530 }, { "bq27531", BQ27530 }, { "bq27541", BQ27541 }, diff --git a/include/linux/power/bq27xxx_battery.h b/include/linux/power/bq27xxx_battery.h index e30deb046156..bed9557b69e7 100644 --- a/include/linux/power/bq27xxx_battery.h +++ b/include/linux/power/bq27xxx_battery.h @@ -4,7 +4,8 @@ enum bq27xxx_chip { BQ27000 = 1, /* bq27000, bq27200 */ BQ27010, /* bq27010, bq27210 */ - BQ27500, /* bq27500, bq27510, bq27520 */ + BQ27500, /* bq27500 */ + BQ27510, /* bq27510, bq27520 */ BQ27530, /* bq27530, bq27531 */ BQ27541, /* bq27541, bq27542, bq27546, bq27742 */ BQ27545, /* bq27545 */ -- cgit v1.2.3 From 5ee1d39e1c2e88946ecdb204659ed34518f88ddc Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 1 Nov 2016 09:59:50 +0000 Subject: power: ipaq_micro_battery: fix alias The alias for the ipaq_micro_battery driver is incorrect, fix it so the module can be auto-loaded. Signed-off-by: Russell King Signed-off-by: Sebastian Reichel --- drivers/power/supply/ipaq_micro_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/supply/ipaq_micro_battery.c b/drivers/power/supply/ipaq_micro_battery.c index 4af7b770f293..2fa6edd6e8b1 100644 --- a/drivers/power/supply/ipaq_micro_battery.c +++ b/drivers/power/supply/ipaq_micro_battery.c @@ -313,4 +313,4 @@ module_platform_driver(micro_batt_device_driver); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("driver for iPAQ Atmel micro battery"); -MODULE_ALIAS("platform:battery-ipaq-micro"); +MODULE_ALIAS("platform:ipaq-micro-battery"); -- cgit v1.2.3 From 8d4124cb94c0613d79a2e3e5727b35a36497ffb7 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 29 Oct 2016 21:36:57 +0200 Subject: wm8350_power: use permission-specific DEVICE_ATTR variants Use DEVICE_ATTR_RO for read only attributes. This simplifies the source code, improves readbility, and reduces the chance of inconsistencies. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @ro@ declarer name DEVICE_ATTR; identifier x,x_show; @@ DEVICE_ATTR(x, \(0444\|S_IRUGO\), x_show, NULL); @script:ocaml@ x << ro.x; x_show << ro.x_show; @@ if not (x^"_show" = x_show) then Coccilib.include_match false @@ declarer name DEVICE_ATTR_RO; identifier ro.x,ro.x_show; @@ - DEVICE_ATTR(x, \(0444\|S_IRUGO\), x_show, NULL); + DEVICE_ATTR_RO(x); // Signed-off-by: Julia Lawall Acked-by: Charles Keepax Signed-off-by: Sebastian Reichel --- drivers/power/supply/wm8350_power.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/power/supply/wm8350_power.c b/drivers/power/supply/wm8350_power.c index 5c5880664e09..a2740cf57ad3 100644 --- a/drivers/power/supply/wm8350_power.c +++ b/drivers/power/supply/wm8350_power.c @@ -182,7 +182,7 @@ static ssize_t charger_state_show(struct device *dev, return sprintf(buf, "%s\n", charge); } -static DEVICE_ATTR(charger_state, 0444, charger_state_show, NULL); +static DEVICE_ATTR_RO(charger_state); static irqreturn_t wm8350_charger_handler(int irq, void *data) { -- cgit v1.2.3 From 6480af4915d6ffb66afc39eee4e9e66cbf59b938 Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Wed, 26 Oct 2016 21:41:44 +0200 Subject: power_supply: wm97xx_battery: use power_supply_get_drvdata As the power supply framework provides a way to store and retrieve private supply data, use it. In the process, change the platform data for wm97xx_battery from a container of a single struct wm97xx_batt_pdata to the direct point to wm97xx_batt_pdata. Signed-off-by: Robert Jarzmik Acked-by: Charles Keepax Signed-off-by: Sebastian Reichel --- drivers/input/touchscreen/wm97xx-core.c | 2 +- drivers/power/supply/wm97xx_battery.c | 25 ++++++++++--------------- 2 files changed, 11 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index 90d6be3c26cc..83cf11312fd9 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -682,7 +682,7 @@ static int wm97xx_probe(struct device *dev) } platform_set_drvdata(wm->battery_dev, wm); wm->battery_dev->dev.parent = dev; - wm->battery_dev->dev.platform_data = pdata; + wm->battery_dev->dev.platform_data = pdata->batt_pdata; ret = platform_device_add(wm->battery_dev); if (ret < 0) goto batt_reg_err; diff --git a/drivers/power/supply/wm97xx_battery.c b/drivers/power/supply/wm97xx_battery.c index 6285626d142a..e3edb31ac880 100644 --- a/drivers/power/supply/wm97xx_battery.c +++ b/drivers/power/supply/wm97xx_battery.c @@ -30,8 +30,7 @@ static enum power_supply_property *prop; static unsigned long wm97xx_read_bat(struct power_supply *bat_ps) { - struct wm97xx_pdata *wmdata = bat_ps->dev.parent->platform_data; - struct wm97xx_batt_pdata *pdata = wmdata->batt_pdata; + struct wm97xx_batt_pdata *pdata = power_supply_get_drvdata(bat_ps); return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev.parent), pdata->batt_aux) * pdata->batt_mult / @@ -40,8 +39,7 @@ static unsigned long wm97xx_read_bat(struct power_supply *bat_ps) static unsigned long wm97xx_read_temp(struct power_supply *bat_ps) { - struct wm97xx_pdata *wmdata = bat_ps->dev.parent->platform_data; - struct wm97xx_batt_pdata *pdata = wmdata->batt_pdata; + struct wm97xx_batt_pdata *pdata = power_supply_get_drvdata(bat_ps); return wm97xx_read_aux_adc(dev_get_drvdata(bat_ps->dev.parent), pdata->temp_aux) * pdata->temp_mult / @@ -52,8 +50,7 @@ static int wm97xx_bat_get_property(struct power_supply *bat_ps, enum power_supply_property psp, union power_supply_propval *val) { - struct wm97xx_pdata *wmdata = bat_ps->dev.parent->platform_data; - struct wm97xx_batt_pdata *pdata = wmdata->batt_pdata; + struct wm97xx_batt_pdata *pdata = power_supply_get_drvdata(bat_ps); switch (psp) { case POWER_SUPPLY_PROP_STATUS: @@ -103,8 +100,7 @@ static void wm97xx_bat_external_power_changed(struct power_supply *bat_ps) static void wm97xx_bat_update(struct power_supply *bat_ps) { int old_status = bat_status; - struct wm97xx_pdata *wmdata = bat_ps->dev.parent->platform_data; - struct wm97xx_batt_pdata *pdata = wmdata->batt_pdata; + struct wm97xx_batt_pdata *pdata = power_supply_get_drvdata(bat_ps); mutex_lock(&work_lock); @@ -166,15 +162,15 @@ static int wm97xx_bat_probe(struct platform_device *dev) int ret = 0; int props = 1; /* POWER_SUPPLY_PROP_PRESENT */ int i = 0; - struct wm97xx_pdata *wmdata = dev->dev.platform_data; - struct wm97xx_batt_pdata *pdata; + struct wm97xx_batt_pdata *pdata = dev->dev.platform_data; + struct power_supply_config cfg = {}; - if (!wmdata) { + if (!pdata) { dev_err(&dev->dev, "No platform data supplied\n"); return -EINVAL; } - pdata = wmdata->batt_pdata; + cfg.drv_data = pdata; if (dev->id != -1) return -EINVAL; @@ -243,7 +239,7 @@ static int wm97xx_bat_probe(struct platform_device *dev) bat_psy_desc.properties = prop; bat_psy_desc.num_properties = props; - bat_psy = power_supply_register(&dev->dev, &bat_psy_desc, NULL); + bat_psy = power_supply_register(&dev->dev, &bat_psy_desc, &cfg); if (!IS_ERR(bat_psy)) { schedule_work(&bat_work); } else { @@ -266,8 +262,7 @@ err: static int wm97xx_bat_remove(struct platform_device *dev) { - struct wm97xx_pdata *wmdata = dev->dev.platform_data; - struct wm97xx_batt_pdata *pdata = wmdata->batt_pdata; + struct wm97xx_batt_pdata *pdata = dev->dev.platform_data; if (pdata && gpio_is_valid(pdata->charge_gpio)) { free_irq(gpio_to_irq(pdata->charge_gpio), dev); -- cgit v1.2.3 From c7c44527b364bce2858bc1c8b630371fea153b56 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 31 Oct 2016 17:38:41 -0700 Subject: PCI: iproc: Add support for the next-gen PAXB controller Add support for the next generation of the iProc PAXB host controller, used in Stingray. Signed-off-by: Oza Oza Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas Reviewed-by: Scott Branden --- drivers/pci/host/pcie-iproc-platform.c | 3 + drivers/pci/host/pcie-iproc.c | 128 +++++++++++++++++++++++++++++++++ drivers/pci/host/pcie-iproc.h | 1 + 3 files changed, 132 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index 47329d34267c..fd3ed9bccaff 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -30,6 +30,9 @@ static const struct of_device_id iproc_pcie_of_match_table[] = { { .compatible = "brcm,iproc-pcie", .data = (int *)IPROC_PCIE_PAXB, + }, { + .compatible = "brcm,iproc-pcie-paxb-v2", + .data = (int *)IPROC_PCIE_PAXB_V2, }, { .compatible = "brcm,iproc-pcie-paxc", .data = (int *)IPROC_PCIE_PAXC, diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index cbbbeaa46dad..3d02ad261761 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -118,6 +118,29 @@ static const struct iproc_pcie_ob_map paxb_ob_map[] = { }, }; +static const struct iproc_pcie_ob_map paxb_v2_ob_map[] = { + { + /* OARR0/OMAP0 */ + .window_sizes = { 128, 256 }, + .nr_sizes = 2, + }, + { + /* OARR1/OMAP1 */ + .window_sizes = { 128, 256 }, + .nr_sizes = 2, + }, + { + /* OARR2/OMAP2 */ + .window_sizes = { 128, 256, 512, 1024 }, + .nr_sizes = 4, + }, + { + /* OARR3/OMAP3 */ + .window_sizes = { 128, 256, 512, 1024 }, + .nr_sizes = 4, + }, +}; + /** * iProc PCIe inbound mapping type */ @@ -156,6 +179,54 @@ struct iproc_pcie_ib_map { u16 imap_window_offset; }; +static const struct iproc_pcie_ib_map paxb_v2_ib_map[] = { + { + /* IARR0/IMAP0 */ + .type = IPROC_PCIE_IB_MAP_IO, + .size_unit = SZ_1K, + .region_sizes = { 32 }, + .nr_sizes = 1, + .nr_windows = 8, + .imap_addr_offset = 0x40, + .imap_window_offset = 0x4, + }, + { + /* IARR1/IMAP1 (currently unused) */ + .type = IPROC_PCIE_IB_MAP_INVALID, + }, + { + /* IARR2/IMAP2 */ + .type = IPROC_PCIE_IB_MAP_MEM, + .size_unit = SZ_1M, + .region_sizes = { 64, 128, 256, 512, 1024, 2048, 4096, 8192, + 16384 }, + .nr_sizes = 9, + .nr_windows = 1, + .imap_addr_offset = 0x4, + .imap_window_offset = 0x8, + }, + { + /* IARR3/IMAP3 */ + .type = IPROC_PCIE_IB_MAP_MEM, + .size_unit = SZ_1G, + .region_sizes = { 1, 2, 4, 8, 16, 32 }, + .nr_sizes = 6, + .nr_windows = 8, + .imap_addr_offset = 0x4, + .imap_window_offset = 0x8, + }, + { + /* IARR4/IMAP4 */ + .type = IPROC_PCIE_IB_MAP_MEM, + .size_unit = SZ_1G, + .region_sizes = { 32, 64, 128, 256, 512 }, + .nr_sizes = 5, + .nr_windows = 8, + .imap_addr_offset = 0x4, + .imap_window_offset = 0x8, + }, +}; + /* * iProc PCIe host registers */ @@ -258,6 +329,34 @@ static const u16 iproc_pcie_reg_paxb[] = { [IPROC_PCIE_APB_ERR_EN] = 0xf40, }; +/* iProc PCIe PAXB v2 registers */ +static const u16 iproc_pcie_reg_paxb_v2[] = { + [IPROC_PCIE_CLK_CTRL] = 0x000, + [IPROC_PCIE_CFG_IND_ADDR] = 0x120, + [IPROC_PCIE_CFG_IND_DATA] = 0x124, + [IPROC_PCIE_CFG_ADDR] = 0x1f8, + [IPROC_PCIE_CFG_DATA] = 0x1fc, + [IPROC_PCIE_INTX_EN] = 0x330, + [IPROC_PCIE_OARR0] = 0xd20, + [IPROC_PCIE_OMAP0] = 0xd40, + [IPROC_PCIE_OARR1] = 0xd28, + [IPROC_PCIE_OMAP1] = 0xd48, + [IPROC_PCIE_OARR2] = 0xd60, + [IPROC_PCIE_OMAP2] = 0xd68, + [IPROC_PCIE_OARR3] = 0xdf0, + [IPROC_PCIE_OMAP3] = 0xdf8, + [IPROC_PCIE_IARR0] = 0xd00, + [IPROC_PCIE_IMAP0] = 0xc00, + [IPROC_PCIE_IARR2] = 0xd10, + [IPROC_PCIE_IMAP2] = 0xcc0, + [IPROC_PCIE_IARR3] = 0xe00, + [IPROC_PCIE_IMAP3] = 0xe08, + [IPROC_PCIE_IARR4] = 0xe68, + [IPROC_PCIE_IMAP4] = 0xe70, + [IPROC_PCIE_LINK_STATUS] = 0xf0c, + [IPROC_PCIE_APB_ERR_EN] = 0xf40, +}; + /* iProc PCIe PAXC v1 registers */ static const u16 iproc_pcie_reg_paxc[] = { [IPROC_PCIE_CLK_CTRL] = 0x000, @@ -914,6 +1013,19 @@ static int iproce_pcie_get_msi(struct iproc_pcie *pcie, return 0; } +static int iproc_pcie_paxb_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) +{ + int ret; + struct of_pci_range range; + + memset(&range, 0, sizeof(range)); + range.size = SZ_32K; + range.pci_addr = range.cpu_addr = ALIGN(msi_addr, range.size); + + ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_IO); + return ret; +} + static void iproc_pcie_paxc_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) { u32 val; @@ -965,6 +1077,11 @@ static int iproc_pcie_msi_steer(struct iproc_pcie *pcie, } switch (pcie->type) { + case IPROC_PCIE_PAXB_V2: + ret = iproc_pcie_paxb_v2_msi_steer(pcie, msi_addr); + if (ret) + return ret; + break; case IPROC_PCIE_PAXC_V2: iproc_pcie_paxc_v2_msi_steer(pcie, msi_addr); break; @@ -1042,6 +1159,17 @@ static int iproc_pcie_rev_init(struct iproc_pcie *pcie) pcie->ob.nr_windows = ARRAY_SIZE(paxb_ob_map); } break; + case IPROC_PCIE_PAXB_V2: + regs = iproc_pcie_reg_paxb_v2; + pcie->has_apb_err_disable = true; + if (pcie->need_ob_cfg) { + pcie->ob_map = paxb_v2_ob_map; + pcie->ob.nr_windows = ARRAY_SIZE(paxb_v2_ob_map); + } + pcie->ib.nr_regions = ARRAY_SIZE(paxb_v2_ib_map); + pcie->ib_map = paxb_v2_ib_map; + pcie->need_msi_steer = true; + break; case IPROC_PCIE_PAXC: regs = iproc_pcie_reg_paxc; pcie->ep_is_internal = true; diff --git a/drivers/pci/host/pcie-iproc.h b/drivers/pci/host/pcie-iproc.h index 3f2709af1a50..04fed8e907f1 100644 --- a/drivers/pci/host/pcie-iproc.h +++ b/drivers/pci/host/pcie-iproc.h @@ -26,6 +26,7 @@ enum iproc_pcie_type { IPROC_PCIE_PAXB_BCMA = 0, IPROC_PCIE_PAXB, + IPROC_PCIE_PAXB_V2, IPROC_PCIE_PAXC, IPROC_PCIE_PAXC_V2, }; -- cgit v1.2.3 From b11d207fb229943d75c17cef4ae3fa980f0cee79 Mon Sep 17 00:00:00 2001 From: Quentin Lambert Date: Sat, 19 Nov 2016 18:41:48 +0100 Subject: PCI: cpqphp: Add missing call to pci_disable_device() Most error branches following the call to pci_enable_device() contain a call to pci_disable_device(). Add these calls where they are missing. This issue was found with Hector. Signed-off-by: Quentin Lambert Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/cpqphp_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index 74f3a0695b43..ec009a7dba20 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -867,7 +867,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) */ if ((pdev->revision <= 2) && (vendor_id != PCI_VENDOR_ID_INTEL)) { err(msg_HPC_not_supported); - return -ENODEV; + rc = -ENODEV; + goto err_disable_device; } /* TODO: This code can be made to support non-Compaq or Intel -- cgit v1.2.3 From d0491fc39bdd45575cd0094af18703d38665a309 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 22 Nov 2016 10:43:29 +0000 Subject: PCI: qcom: Add support for MSM8996 PCIe controller Add support for the MSM8996/APQ8096 PCIe controller. MSM8996 supports Gen 1/2, one lane, 3 PCIe root complexes with support for MSI and legacy interrupts, and it conforms to PCI Express Base 2.1 specification. Add a post_init callback to qcom_pcie_ops, as the PCIe pipe clocks are only setup after the phy is powered on. It also adds an ltssm_enable callback as it is very much different from other supported SoCs in the driver. Signed-off-by: Srinivas Kandagatla Signed-off-by: Bjorn Helgaas Acked-by: Stanimir Varbanov --- .../devicetree/bindings/pci/qcom,pcie.txt | 14 +- drivers/pci/host/pcie-qcom.c | 177 ++++++++++++++++++++- 2 files changed, 185 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pci/qcom,pcie.txt b/Documentation/devicetree/bindings/pci/qcom,pcie.txt index 4059a6f89bc1..e15f9b19901f 100644 --- a/Documentation/devicetree/bindings/pci/qcom,pcie.txt +++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt @@ -7,6 +7,7 @@ - "qcom,pcie-ipq8064" for ipq8064 - "qcom,pcie-apq8064" for apq8064 - "qcom,pcie-apq8084" for apq8084 + - "qcom,pcie-msm8996" for msm8996 or apq8096 - reg: Usage: required @@ -92,6 +93,17 @@ - "aux" Auxiliary (AUX) clock - "bus_master" Master AXI clock - "bus_slave" Slave AXI clock + +- clock-names: + Usage: required for msm8996/apq8096 + Value type: + Definition: Should contain the following entries + - "pipe" Pipe Clock driving internal logic + - "aux" Auxiliary (AUX) clock + - "cfg" Configuration clock + - "bus_master" Master AXI clock + - "bus_slave" Slave AXI clock + - resets: Usage: required Value type: @@ -115,7 +127,7 @@ - "core" Core reset - power-domains: - Usage: required for apq8084 + Usage: required for apq8084 and msm8996/apq8096 Value type: Definition: A phandle and power domain specifier pair to the power domain which is responsible for collapsing diff --git a/drivers/pci/host/pcie-qcom.c b/drivers/pci/host/pcie-qcom.c index ef0a84c7a588..8b02db2da6cc 100644 --- a/drivers/pci/host/pcie-qcom.c +++ b/drivers/pci/host/pcie-qcom.c @@ -36,11 +36,17 @@ #include "pcie-designware.h" +#define PCIE20_PARF_SYS_CTRL 0x00 #define PCIE20_PARF_PHY_CTRL 0x40 #define PCIE20_PARF_PHY_REFCLK 0x4C #define PCIE20_PARF_DBI_BASE_ADDR 0x168 -#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c +#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16C +#define PCIE20_PARF_MHI_CLOCK_RESET_CTRL 0x174 #define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178 +#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2 0x1A8 +#define PCIE20_PARF_LTSSM 0x1B0 +#define PCIE20_PARF_SID_OFFSET 0x234 +#define PCIE20_PARF_BDF_TRANSLATE_CFG 0x24C #define PCIE20_ELBI_SYS_CTRL 0x04 #define PCIE20_ELBI_SYS_CTRL_LT_ENABLE BIT(0) @@ -72,9 +78,18 @@ struct qcom_pcie_resources_v1 { struct regulator *vdda; }; +struct qcom_pcie_resources_v2 { + struct clk *aux_clk; + struct clk *master_clk; + struct clk *slave_clk; + struct clk *cfg_clk; + struct clk *pipe_clk; +}; + union qcom_pcie_resources { struct qcom_pcie_resources_v0 v0; struct qcom_pcie_resources_v1 v1; + struct qcom_pcie_resources_v2 v2; }; struct qcom_pcie; @@ -82,7 +97,9 @@ struct qcom_pcie; struct qcom_pcie_ops { int (*get_resources)(struct qcom_pcie *pcie); int (*init)(struct qcom_pcie *pcie); + int (*post_init)(struct qcom_pcie *pcie); void (*deinit)(struct qcom_pcie *pcie); + void (*ltssm_enable)(struct qcom_pcie *pcie); }; struct qcom_pcie { @@ -116,17 +133,35 @@ static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg) return dw_handle_msi_irq(pp); } -static int qcom_pcie_establish_link(struct qcom_pcie *pcie) +static void qcom_pcie_v0_v1_ltssm_enable(struct qcom_pcie *pcie) { u32 val; - if (dw_pcie_link_up(&pcie->pp)) - return 0; - /* enable link training */ val = readl(pcie->elbi + PCIE20_ELBI_SYS_CTRL); val |= PCIE20_ELBI_SYS_CTRL_LT_ENABLE; writel(val, pcie->elbi + PCIE20_ELBI_SYS_CTRL); +} + +static void qcom_pcie_v2_ltssm_enable(struct qcom_pcie *pcie) +{ + u32 val; + + /* enable link training */ + val = readl(pcie->parf + PCIE20_PARF_LTSSM); + val |= BIT(8); + writel(val, pcie->parf + PCIE20_PARF_LTSSM); +} + +static int qcom_pcie_establish_link(struct qcom_pcie *pcie) +{ + + if (dw_pcie_link_up(&pcie->pp)) + return 0; + + /* Enable Link Training state machine */ + if (pcie->ops->ltssm_enable) + pcie->ops->ltssm_enable(pcie); return dw_pcie_wait_for_link(&pcie->pp); } @@ -421,6 +456,113 @@ err_res: return ret; } +static int qcom_pcie_get_resources_v2(struct qcom_pcie *pcie) +{ + struct qcom_pcie_resources_v2 *res = &pcie->res.v2; + struct device *dev = pcie->pp.dev; + + res->aux_clk = devm_clk_get(dev, "aux"); + if (IS_ERR(res->aux_clk)) + return PTR_ERR(res->aux_clk); + + res->cfg_clk = devm_clk_get(dev, "cfg"); + if (IS_ERR(res->cfg_clk)) + return PTR_ERR(res->cfg_clk); + + res->master_clk = devm_clk_get(dev, "bus_master"); + if (IS_ERR(res->master_clk)) + return PTR_ERR(res->master_clk); + + res->slave_clk = devm_clk_get(dev, "bus_slave"); + if (IS_ERR(res->slave_clk)) + return PTR_ERR(res->slave_clk); + + res->pipe_clk = devm_clk_get(dev, "pipe"); + if (IS_ERR(res->pipe_clk)) + return PTR_ERR(res->pipe_clk); + + return 0; +} + +static int qcom_pcie_init_v2(struct qcom_pcie *pcie) +{ + struct qcom_pcie_resources_v2 *res = &pcie->res.v2; + struct device *dev = pcie->pp.dev; + u32 val; + int ret; + + ret = clk_prepare_enable(res->aux_clk); + if (ret) { + dev_err(dev, "cannot prepare/enable aux clock\n"); + return ret; + } + + ret = clk_prepare_enable(res->cfg_clk); + if (ret) { + dev_err(dev, "cannot prepare/enable cfg clock\n"); + goto err_cfg_clk; + } + + ret = clk_prepare_enable(res->master_clk); + if (ret) { + dev_err(dev, "cannot prepare/enable master clock\n"); + goto err_master_clk; + } + + ret = clk_prepare_enable(res->slave_clk); + if (ret) { + dev_err(dev, "cannot prepare/enable slave clock\n"); + goto err_slave_clk; + } + + /* enable PCIe clocks and resets */ + val = readl(pcie->parf + PCIE20_PARF_PHY_CTRL); + val &= ~BIT(0); + writel(val, pcie->parf + PCIE20_PARF_PHY_CTRL); + + /* change DBI base address */ + writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR); + + /* MAC PHY_POWERDOWN MUX DISABLE */ + val = readl(pcie->parf + PCIE20_PARF_SYS_CTRL); + val &= ~BIT(29); + writel(val, pcie->parf + PCIE20_PARF_SYS_CTRL); + + val = readl(pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL); + val |= BIT(4); + writel(val, pcie->parf + PCIE20_PARF_MHI_CLOCK_RESET_CTRL); + + val = readl(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2); + val |= BIT(31); + writel(val, pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT_V2); + + return 0; + +err_slave_clk: + clk_disable_unprepare(res->master_clk); +err_master_clk: + clk_disable_unprepare(res->cfg_clk); +err_cfg_clk: + clk_disable_unprepare(res->aux_clk); + + return ret; +} + +static int qcom_pcie_post_init_v2(struct qcom_pcie *pcie) +{ + struct qcom_pcie_resources_v2 *res = &pcie->res.v2; + struct device *dev = pcie->pp.dev; + int ret; + + ret = clk_prepare_enable(res->pipe_clk); + if (ret) { + dev_err(dev, "cannot prepare/enable pipe clock\n"); + return ret; + } + + return 0; +} + static int qcom_pcie_link_up(struct pcie_port *pp) { struct qcom_pcie *pcie = to_qcom_pcie(pp); @@ -429,6 +571,17 @@ static int qcom_pcie_link_up(struct pcie_port *pp) return !!(val & PCI_EXP_LNKSTA_DLLLA); } +static void qcom_pcie_deinit_v2(struct qcom_pcie *pcie) +{ + struct qcom_pcie_resources_v2 *res = &pcie->res.v2; + + clk_disable_unprepare(res->pipe_clk); + clk_disable_unprepare(res->slave_clk); + clk_disable_unprepare(res->master_clk); + clk_disable_unprepare(res->cfg_clk); + clk_disable_unprepare(res->aux_clk); +} + static void qcom_pcie_host_init(struct pcie_port *pp) { struct qcom_pcie *pcie = to_qcom_pcie(pp); @@ -444,6 +597,9 @@ static void qcom_pcie_host_init(struct pcie_port *pp) if (ret) goto err_deinit; + if (pcie->ops->post_init) + pcie->ops->post_init(pcie); + dw_pcie_setup_rc(pp); if (IS_ENABLED(CONFIG_PCI_MSI)) @@ -487,12 +643,22 @@ static const struct qcom_pcie_ops ops_v0 = { .get_resources = qcom_pcie_get_resources_v0, .init = qcom_pcie_init_v0, .deinit = qcom_pcie_deinit_v0, + .ltssm_enable = qcom_pcie_v0_v1_ltssm_enable, }; static const struct qcom_pcie_ops ops_v1 = { .get_resources = qcom_pcie_get_resources_v1, .init = qcom_pcie_init_v1, .deinit = qcom_pcie_deinit_v1, + .ltssm_enable = qcom_pcie_v0_v1_ltssm_enable, +}; + +static const struct qcom_pcie_ops ops_v2 = { + .get_resources = qcom_pcie_get_resources_v2, + .init = qcom_pcie_init_v2, + .post_init = qcom_pcie_post_init_v2, + .deinit = qcom_pcie_deinit_v2, + .ltssm_enable = qcom_pcie_v2_ltssm_enable, }; static int qcom_pcie_probe(struct platform_device *pdev) @@ -572,6 +738,7 @@ static const struct of_device_id qcom_pcie_match[] = { { .compatible = "qcom,pcie-ipq8064", .data = &ops_v0 }, { .compatible = "qcom,pcie-apq8064", .data = &ops_v0 }, { .compatible = "qcom,pcie-apq8084", .data = &ops_v1 }, + { .compatible = "qcom,pcie-msm8996", .data = &ops_v2 }, { } }; -- cgit v1.2.3 From feacdb4a35920235a0daf42d6f5701a74c4708b5 Mon Sep 17 00:00:00 2001 From: Ray Jui Date: Mon, 21 Nov 2016 17:48:30 -0800 Subject: PCI: iproc: Fix incorrect MSI address alignment In the code to handle PAXB v2 based MSI steering, the logic aligns the MSI register address to the size of supported inbound mapping range. This is incorrect since it rounds "up" the starting address to the next aligned address, but what we want is the starting address to be rounded "down" to the aligned address. This patch fixes the issue and allows MSI writes to be properly steered to the GIC. Fixes: 4b073155fbd3 ("PCI: iproc: Add support for the next-gen PAXB controller") Signed-off-by: Ray Jui Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-iproc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index 3d02ad261761..cd513342b913 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -1020,7 +1020,7 @@ static int iproc_pcie_paxb_v2_msi_steer(struct iproc_pcie *pcie, u64 msi_addr) memset(&range, 0, sizeof(range)); range.size = SZ_32K; - range.pci_addr = range.cpu_addr = ALIGN(msi_addr, range.size); + range.pci_addr = range.cpu_addr = msi_addr & ~(range.size - 1); ret = iproc_pcie_setup_ib(pcie, &range, IPROC_PCIE_IB_MAP_IO); return ret; -- cgit v1.2.3 From f40ec3c748c6912f6266c56a7f7992de61b255ed Mon Sep 17 00:00:00 2001 From: Gavin Shan Date: Wed, 26 Oct 2016 12:15:35 +1100 Subject: PCI: Do any VF BAR updates before enabling the BARs Previously we enabled VFs and enable their memory space before calling pcibios_sriov_enable(). But pcibios_sriov_enable() may update the VF BARs: for example, on PPC PowerNV we may change them to manage the association of VFs to PEs. Because 64-bit BARs cannot be updated atomically, it's unsafe to update them while they're enabled. The half-updated state may conflict with other devices in the system. Call pcibios_sriov_enable() before enabling the VFs so any BAR updates happen while the VF BARs are disabled. [bhelgaas: changelog] Tested-by: Carol Soto Signed-off-by: Gavin Shan Signed-off-by: Bjorn Helgaas --- drivers/pci/iov.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index e30f05c8517f..d41ec29be60b 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -306,13 +306,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) return rc; } - pci_iov_set_numvfs(dev, nr_virtfn); - iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; - pci_cfg_access_lock(dev); - pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); - msleep(100); - pci_cfg_access_unlock(dev); - iov->initial_VFs = initial; if (nr_virtfn < initial) initial = nr_virtfn; @@ -323,6 +316,13 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) goto err_pcibios; } + pci_iov_set_numvfs(dev, nr_virtfn); + iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; + pci_cfg_access_lock(dev); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); + msleep(100); + pci_cfg_access_unlock(dev); + for (i = 0; i < initial; i++) { rc = pci_iov_add_virtfn(dev, i, 0); if (rc) -- cgit v1.2.3 From 18058822768f4665e2132ddd1cb413a9033edf09 Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Wed, 16 Nov 2016 16:40:30 +0200 Subject: soc/qman: Handle endianness of h/w descriptors The hardware descriptors have big endian (BE) format. Provide proper endianness handling for the remaining descriptor fields, to ensure they are correctly accessed by non-BE CPUs too. Signed-off-by: Claudiu Manoil Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman.c | 65 ++++++++++++++++++--------------- drivers/soc/fsl/qbman/qman_priv.h | 10 ++--- drivers/soc/fsl/qbman/qman_test_api.c | 4 +- drivers/soc/fsl/qbman/qman_test_stash.c | 5 ++- include/soc/fsl/qman.h | 48 ++++++++++++------------ 5 files changed, 70 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c index acee99da71a7..6f509f68085e 100644 --- a/drivers/soc/fsl/qbman/qman.c +++ b/drivers/soc/fsl/qbman/qman.c @@ -140,10 +140,10 @@ enum qm_mr_cmode { /* matches QCSP_CFG::MM */ struct qm_eqcr_entry { u8 _ncw_verb; /* writes to this are non-coherent */ u8 dca; - u16 seqnum; + __be16 seqnum; u8 __reserved[4]; - u32 fqid; /* 24-bit */ - u32 tag; + __be32 fqid; /* 24-bit */ + __be32 tag; struct qm_fd fd; u8 __reserved3[32]; } __packed; @@ -187,7 +187,7 @@ struct qm_mr { struct qm_mcc_fq { u8 _ncw_verb; u8 __reserved1[3]; - u32 fqid; /* 24-bit */ + __be32 fqid; /* 24-bit */ u8 __reserved2[56]; } __packed; @@ -470,7 +470,7 @@ static inline struct qm_eqcr_entry *qm_eqcr_start_stash(struct qm_portal static inline void eqcr_commit_checks(struct qm_eqcr *eqcr) { DPAA_ASSERT(eqcr->busy); - DPAA_ASSERT(!(eqcr->cursor->fqid & ~QM_FQID_MASK)); + DPAA_ASSERT(!(be32_to_cpu(eqcr->cursor->fqid) & ~QM_FQID_MASK)); DPAA_ASSERT(eqcr->available >= 1); } @@ -1395,7 +1395,7 @@ static void qm_mr_process_task(struct work_struct *work) break; case QM_MR_VERB_FQPN: /* Parked */ - fq = tag_to_fq(msg->fq.context_b); + fq = tag_to_fq(be32_to_cpu(msg->fq.context_b)); fq_state_change(p, fq, msg, verb); if (fq->cb.fqs) fq->cb.fqs(p, fq, msg); @@ -1409,7 +1409,7 @@ static void qm_mr_process_task(struct work_struct *work) } } else { /* Its a software ERN */ - fq = tag_to_fq(msg->ern.tag); + fq = tag_to_fq(be32_to_cpu(msg->ern.tag)); fq->cb.ern(p, fq, msg); } num++; @@ -1521,7 +1521,7 @@ static inline unsigned int __poll_portal_fast(struct qman_portal *p, clear_vdqcr(p, fq); } else { /* SDQCR: context_b points to the FQ */ - fq = tag_to_fq(dq->context_b); + fq = tag_to_fq(be32_to_cpu(dq->context_b)); /* Now let the callback do its stuff */ res = fq->cb.dqrr(p, fq, dq); /* @@ -1738,9 +1738,9 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) if (fq_isset(fq, QMAN_FQ_FLAG_NO_MODIFY)) return -EINVAL; #endif - if (opts && (opts->we_mask & QM_INITFQ_WE_OAC)) { + if (opts && (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_OAC)) { /* And can't be set at the same time as TDTHRESH */ - if (opts->we_mask & QM_INITFQ_WE_TDTHRESH) + if (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_TDTHRESH) return -EINVAL; } /* Issue an INITFQ_[PARKED|SCHED] management command */ @@ -1764,14 +1764,16 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) if (fq_isclear(fq, QMAN_FQ_FLAG_TO_DCPORTAL)) { dma_addr_t phys_fq; - mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTB; - mcc->initfq.fqd.context_b = fq_to_tag(fq); + mcc->initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CONTEXTB); + mcc->initfq.fqd.context_b = cpu_to_be32(fq_to_tag(fq)); /* * and the physical address - NB, if the user wasn't trying to * set CONTEXTA, clear the stashing settings. */ - if (!(mcc->initfq.we_mask & QM_INITFQ_WE_CONTEXTA)) { - mcc->initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; + if (!(be16_to_cpu(mcc->initfq.we_mask) & + QM_INITFQ_WE_CONTEXTA)) { + mcc->initfq.we_mask |= + cpu_to_be16(QM_INITFQ_WE_CONTEXTA); memset(&mcc->initfq.fqd.context_a, 0, sizeof(mcc->initfq.fqd.context_a)); } else { @@ -1791,8 +1793,10 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) if (flags & QMAN_INITFQ_FLAG_LOCAL) { int wq = 0; - if (!(mcc->initfq.we_mask & QM_INITFQ_WE_DESTWQ)) { - mcc->initfq.we_mask |= QM_INITFQ_WE_DESTWQ; + if (!(be16_to_cpu(mcc->initfq.we_mask) & + QM_INITFQ_WE_DESTWQ)) { + mcc->initfq.we_mask |= + cpu_to_be16(QM_INITFQ_WE_DESTWQ); wq = 4; } qm_fqd_set_destwq(&mcc->initfq.fqd, p->config->channel, wq); @@ -1811,13 +1815,13 @@ int qman_init_fq(struct qman_fq *fq, u32 flags, struct qm_mcc_initfq *opts) goto out; } if (opts) { - if (opts->we_mask & QM_INITFQ_WE_FQCTRL) { - if (opts->fqd.fq_ctrl & QM_FQCTRL_CGE) + if (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_FQCTRL) { + if (be16_to_cpu(opts->fqd.fq_ctrl) & QM_FQCTRL_CGE) fq_set(fq, QMAN_FQ_STATE_CGR_EN); else fq_clear(fq, QMAN_FQ_STATE_CGR_EN); } - if (opts->we_mask & QM_INITFQ_WE_CGID) + if (be16_to_cpu(opts->we_mask) & QM_INITFQ_WE_CGID) fq->cgr_groupid = opts->fqd.cgid; } fq->state = (flags & QMAN_INITFQ_FLAG_SCHED) ? @@ -1937,7 +1941,7 @@ int qman_retire_fq(struct qman_fq *fq, u32 *flags) msg.verb = QM_MR_VERB_FQRNI; msg.fq.fqs = mcr->alterfq.fqs; qm_fqid_set(&msg.fq, fq->fqid); - msg.fq.context_b = fq_to_tag(fq); + msg.fq.context_b = cpu_to_be32(fq_to_tag(fq)); fq->cb.fqs(p, fq, &msg); } } else if (res == QM_MCR_RESULT_PENDING) { @@ -2206,7 +2210,7 @@ int qman_enqueue(struct qman_fq *fq, const struct qm_fd *fd) goto out; qm_fqid_set(eq, fq->fqid); - eq->tag = fq_to_tag(fq); + eq->tag = cpu_to_be32(fq_to_tag(fq)); eq->fd = *fd; qm_eqcr_pvb_commit(&p->p, QM_EQCR_VERB_CMD_ENQUEUE); @@ -2253,17 +2257,18 @@ out: static void qm_cgr_cscn_targ_set(struct __qm_mc_cgr *cgr, int pi, u32 val) { if (qman_ip_rev >= QMAN_REV30) - cgr->cscn_targ_upd_ctrl = QM_CGR_TARG_UDP_CTRL_WRITE_BIT | pi; + cgr->cscn_targ_upd_ctrl = cpu_to_be16(pi | + QM_CGR_TARG_UDP_CTRL_WRITE_BIT); else - cgr->cscn_targ = val | QM_CGR_TARG_PORTAL(pi); + cgr->cscn_targ = cpu_to_be32(val | QM_CGR_TARG_PORTAL(pi)); } static void qm_cgr_cscn_targ_clear(struct __qm_mc_cgr *cgr, int pi, u32 val) { if (qman_ip_rev >= QMAN_REV30) - cgr->cscn_targ_upd_ctrl = pi; + cgr->cscn_targ_upd_ctrl = cpu_to_be16(pi); else - cgr->cscn_targ = val & ~QM_CGR_TARG_PORTAL(pi); + cgr->cscn_targ = cpu_to_be32(val & ~QM_CGR_TARG_PORTAL(pi)); } static u8 qman_cgr_cpus[CGR_NUM]; @@ -2315,8 +2320,8 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags, goto out; qm_cgr_cscn_targ_set(&local_opts.cgr, PORTAL_IDX(p), - cgr_state.cgr.cscn_targ); - local_opts.we_mask |= QM_CGR_WE_CSCN_TARG; + be32_to_cpu(cgr_state.cgr.cscn_targ)); + local_opts.we_mask |= cpu_to_be16(QM_CGR_WE_CSCN_TARG); /* send init if flags indicate so */ if (flags & QMAN_CGR_FLAG_USE_INIT) @@ -2383,9 +2388,9 @@ int qman_delete_cgr(struct qman_cgr *cgr) goto release_lock; } - local_opts.we_mask = QM_CGR_WE_CSCN_TARG; + local_opts.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_TARG); qm_cgr_cscn_targ_clear(&local_opts.cgr, PORTAL_IDX(p), - cgr_state.cgr.cscn_targ); + be32_to_cpu(cgr_state.cgr.cscn_targ)); ret = qm_modify_cgr(cgr, 0, &local_opts); if (ret) @@ -2835,7 +2840,7 @@ static int cgr_cleanup(u32 cgrid) err = qman_query_fq(&fq, &fqd); if (WARN_ON(err)) return err; - if ((fqd.fq_ctrl & QM_FQCTRL_CGE) && + if (be16_to_cpu(fqd.fq_ctrl) & QM_FQCTRL_CGE && fqd.cgid == cgrid) { pr_err("CRGID 0x%x is being used by FQID 0x%x, CGR will be leaked\n", cgrid, fq.fqid); diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h index 5606d74c21d4..53685b59718e 100644 --- a/drivers/soc/fsl/qbman/qman_priv.h +++ b/drivers/soc/fsl/qbman/qman_priv.h @@ -73,20 +73,20 @@ struct qm_mcr_querycgr { struct __qm_mc_cgr cgr; /* CGR fields */ u8 __reserved2[6]; u8 i_bcnt_hi; /* high 8-bits of 40-bit "Instant" */ - u32 i_bcnt_lo; /* low 32-bits of 40-bit */ + __be32 i_bcnt_lo; /* low 32-bits of 40-bit */ u8 __reserved3[3]; u8 a_bcnt_hi; /* high 8-bits of 40-bit "Average" */ - u32 a_bcnt_lo; /* low 32-bits of 40-bit */ - u32 cscn_targ_swp[4]; + __be32 a_bcnt_lo; /* low 32-bits of 40-bit */ + __be32 cscn_targ_swp[4]; } __packed; static inline u64 qm_mcr_querycgr_i_get64(const struct qm_mcr_querycgr *q) { - return ((u64)q->i_bcnt_hi << 32) | (u64)q->i_bcnt_lo; + return ((u64)q->i_bcnt_hi << 32) | be32_to_cpu(q->i_bcnt_lo); } static inline u64 qm_mcr_querycgr_a_get64(const struct qm_mcr_querycgr *q) { - return ((u64)q->a_bcnt_hi << 32) | (u64)q->a_bcnt_lo; + return ((u64)q->a_bcnt_hi << 32) | be32_to_cpu(q->a_bcnt_lo); } /* "Query FQ Non-Programmable Fields" */ diff --git a/drivers/soc/fsl/qbman/qman_test_api.c b/drivers/soc/fsl/qbman/qman_test_api.c index dba6a80622ed..2895d062cf51 100644 --- a/drivers/soc/fsl/qbman/qman_test_api.c +++ b/drivers/soc/fsl/qbman/qman_test_api.c @@ -65,7 +65,7 @@ static void fd_init(struct qm_fd *fd) { qm_fd_addr_set64(fd, 0xabdeadbeefLLU); qm_fd_set_contig_big(fd, 0x0000ffff); - fd->cmd = 0xfeedf00d; + fd->cmd = cpu_to_be32(0xfeedf00d); } static void fd_inc(struct qm_fd *fd) @@ -86,7 +86,7 @@ static void fd_inc(struct qm_fd *fd) len--; qm_fd_set_param(fd, fmt, off, len); - fd->cmd++; + fd->cmd = cpu_to_be32(be32_to_cpu(fd->cmd) + 1); } /* The only part of the 'fd' we can't memcmp() is the ppid */ diff --git a/drivers/soc/fsl/qbman/qman_test_stash.c b/drivers/soc/fsl/qbman/qman_test_stash.c index f8d25faf4d8a..b9795f39bcc8 100644 --- a/drivers/soc/fsl/qbman/qman_test_stash.c +++ b/drivers/soc/fsl/qbman/qman_test_stash.c @@ -406,8 +406,9 @@ static int init_handler(void *h) goto failed; } memset(&opts, 0, sizeof(opts)); - opts.we_mask = QM_INITFQ_WE_FQCTRL | QM_INITFQ_WE_CONTEXTA; - opts.fqd.fq_ctrl = QM_FQCTRL_CTXASTASHING; + opts.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL | + QM_INITFQ_WE_CONTEXTA); + opts.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_CTXASTASHING); qm_fqd_set_stashing(&opts.fqd, 0, STASH_DATA_CL, STASH_CTX_CL); err = qman_init_fq(&handler->rx, QMAN_INITFQ_FLAG_SCHED | QMAN_INITFQ_FLAG_LOCAL, &opts); diff --git a/include/soc/fsl/qman.h b/include/soc/fsl/qman.h index d01d5a358945..3d4df74a96de 100644 --- a/include/soc/fsl/qman.h +++ b/include/soc/fsl/qman.h @@ -244,11 +244,11 @@ static inline int qm_sg_entry_get_off(const struct qm_sg_entry *sg) struct qm_dqrr_entry { u8 verb; u8 stat; - u16 seqnum; /* 15-bit */ + __be16 seqnum; /* 15-bit */ u8 tok; u8 __reserved2[3]; - u32 fqid; /* 24-bit */ - u32 context_b; + __be32 fqid; /* 24-bit */ + __be32 context_b; struct qm_fd fd; u8 __reserved4[32]; } __packed; @@ -264,8 +264,8 @@ struct qm_dqrr_entry { /* 'fqid' is a 24-bit field in every h/w descriptor */ #define QM_FQID_MASK GENMASK(23, 0) -#define qm_fqid_set(p, v) ((p)->fqid = ((v) & QM_FQID_MASK)) -#define qm_fqid_get(p) ((p)->fqid & QM_FQID_MASK) +#define qm_fqid_set(p, v) ((p)->fqid = cpu_to_be32((v) & QM_FQID_MASK)) +#define qm_fqid_get(p) (be32_to_cpu((p)->fqid) & QM_FQID_MASK) /* "ERN Message Response" */ /* "FQ State Change Notification" */ @@ -277,11 +277,11 @@ union qm_mr_entry { struct { u8 verb; u8 dca; - u16 seqnum; + __be16 seqnum; u8 rc; /* Rej Code: 8-bit */ u8 __reserved[3]; - u32 fqid; /* 24-bit */ - u32 tag; + __be32 fqid; /* 24-bit */ + __be32 tag; struct qm_fd fd; u8 __reserved1[32]; } __packed ern; @@ -289,8 +289,8 @@ union qm_mr_entry { u8 verb; u8 fqs; /* Frame Queue Status */ u8 __reserved1[6]; - u32 fqid; /* 24-bit */ - u32 context_b; + __be32 fqid; /* 24-bit */ + __be32 context_b; u8 __reserved2[48]; } __packed fq; /* FQRN/FQRNI/FQRL/FQPN */ }; @@ -409,8 +409,8 @@ static inline u64 qm_fqd_context_a_get64(const struct qm_fqd *fqd) static inline void qm_fqd_stashing_set64(struct qm_fqd *fqd, u64 addr) { - fqd->context_a.context_hi = upper_32_bits(addr); - fqd->context_a.context_lo = lower_32_bits(addr); + fqd->context_a.context_hi = cpu_to_be16(upper_32_bits(addr)); + fqd->context_a.context_lo = cpu_to_be32(lower_32_bits(addr)); } static inline void qm_fqd_context_a_set64(struct qm_fqd *fqd, u64 addr) @@ -525,7 +525,7 @@ static inline int qm_fqd_get_wq(const struct qm_fqd *fqd) */ struct qm_cgr_wr_parm { /* MA[24-31], Mn[19-23], SA[12-18], Sn[6-11], Pn[0-5] */ - u32 word; + __be32 word; }; /* * This struct represents the 13-bit "CS_THRES" CGR field. In the corresponding @@ -536,7 +536,7 @@ struct qm_cgr_wr_parm { */ struct qm_cgr_cs_thres { /* _res[13-15], TA[5-12], Tn[0-4] */ - u16 word; + __be16 word; }; /* * This identical structure of CGR fields is present in the "Init/Modify CGR" @@ -553,10 +553,10 @@ struct __qm_mc_cgr { u8 cscn_en; /* boolean, use QM_CGR_EN */ union { struct { - u16 cscn_targ_upd_ctrl; /* use QM_CGR_TARG_UDP_* */ - u16 cscn_targ_dcp_low; + __be16 cscn_targ_upd_ctrl; /* use QM_CGR_TARG_UDP_* */ + __be16 cscn_targ_dcp_low; }; - u32 cscn_targ; /* use QM_CGR_TARG_* */ + __be32 cscn_targ; /* use QM_CGR_TARG_* */ }; u8 cstd_en; /* boolean, use QM_CGR_EN */ u8 cs; /* boolean, only used in query response */ @@ -572,7 +572,9 @@ struct __qm_mc_cgr { /* Convert CGR thresholds to/from "cs_thres" format */ static inline u64 qm_cgr_cs_thres_get64(const struct qm_cgr_cs_thres *th) { - return ((th->word >> 5) & 0xff) << (th->word & 0x1f); + int thres = be16_to_cpu(th->word); + + return ((thres >> 5) & 0xff) << (thres & 0x1f); } static inline int qm_cgr_cs_thres_set64(struct qm_cgr_cs_thres *th, u64 val, @@ -588,23 +590,23 @@ static inline int qm_cgr_cs_thres_set64(struct qm_cgr_cs_thres *th, u64 val, if (roundup && oddbit) val++; } - th->word = ((val & 0xff) << 5) | (e & 0x1f); + th->word = cpu_to_be16(((val & 0xff) << 5) | (e & 0x1f)); return 0; } /* "Initialize FQ" */ struct qm_mcc_initfq { u8 __reserved1[2]; - u16 we_mask; /* Write Enable Mask */ - u32 fqid; /* 24-bit */ - u16 count; /* Initialises 'count+1' FQDs */ + __be16 we_mask; /* Write Enable Mask */ + __be32 fqid; /* 24-bit */ + __be16 count; /* Initialises 'count+1' FQDs */ struct qm_fqd fqd; /* the FQD fields go here */ u8 __reserved2[30]; } __packed; /* "Initialize/Modify CGR" */ struct qm_mcc_initcgr { u8 __reserve1[2]; - u16 we_mask; /* Write Enable Mask */ + __be16 we_mask; /* Write Enable Mask */ struct __qm_mc_cgr cgr; /* CGR fields */ u8 __reserved2[2]; u8 cgid; -- cgit v1.2.3 From 6bec23bff914915822f2c34d0555902fb2b9be1f Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Sun, 20 Nov 2016 16:56:14 +0000 Subject: i2c: mlxcpld: add master driver for mellanox systems Device driver for Mellanox I2C controller logic, implemented in Lattice CPLD device. Device supports: - Master mode - One physical bus - Polling mode The Kconfig currently controlling compilation of this code is: drivers/i2c/busses/Kconfig:config I2C_MLXCPLD Signed-off-by: Michael Shych Signed-off-by: Vadim Pasternak Reviewed-by: Jiri Pirko Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-mlxcpld | 47 ++++ MAINTAINERS | 4 +- drivers/i2c/busses/Kconfig | 11 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-mlxcpld.c | 504 +++++++++++++++++++++++++++++++++++ 5 files changed, 566 insertions(+), 1 deletion(-) create mode 100644 Documentation/i2c/busses/i2c-mlxcpld create mode 100644 drivers/i2c/busses/i2c-mlxcpld.c (limited to 'drivers') diff --git a/Documentation/i2c/busses/i2c-mlxcpld b/Documentation/i2c/busses/i2c-mlxcpld new file mode 100644 index 000000000000..4e46c440b38d --- /dev/null +++ b/Documentation/i2c/busses/i2c-mlxcpld @@ -0,0 +1,47 @@ +Driver i2c-mlxcpld + +Author: Michael Shych + +This is the Mellanox I2C controller logic, implemented in Lattice CPLD +device. +Device supports: + - Master mode. + - One physical bus. + - Polling mode. + +This controller is equipped within the next Mellanox systems: +"msx6710", "msx6720", "msb7700", "msn2700", "msx1410", "msn2410", "msb7800", +"msn2740", "msn2100". + +The next transaction types are supported: + - Receive Byte/Block. + - Send Byte/Block. + - Read Byte/Block. + - Write Byte/Block. + +Registers: +CTRL 0x1 - control reg. + Resets all the registers. +HALF_CYC 0x4 - cycle reg. + Configure the width of I2C SCL half clock cycle (in 4 LPC_CLK + units). +I2C_HOLD 0x5 - hold reg. + OE (output enable) is delayed by value set to this register + (in LPC_CLK units) +CMD 0x6 - command reg. + Bit 0, 0 = write, 1 = read. + Bits [7:1] - the 7bit Address of the I2C device. + It should be written last as it triggers an I2C transaction. +NUM_DATA 0x7 - data size reg. + Number of data bytes to write in read transaction +NUM_ADDR 0x8 - address reg. + Number of address bytes to write in read transaction. +STATUS 0x9 - status reg. + Bit 0 - transaction is completed. + Bit 4 - ACK/NACK. +DATAx 0xa - 0x54 - 68 bytes data buffer regs. + For write transaction address is specified in four first bytes + (DATA1 - DATA4), data starting from DATA4. + For read transactions address is sent in a separate transaction and + specified in the four first bytes (DATA0 - DATA3). Data is read + starting from DATA0. diff --git a/MAINTAINERS b/MAINTAINERS index 22ee29a8f403..8c710270cfde 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7881,12 +7881,14 @@ W: http://www.mellanox.com Q: http://patchwork.ozlabs.org/project/netdev/list/ F: drivers/net/ethernet/mellanox/mlxsw/ -MELLANOX MLXCPLD I2C MUX DRIVER +MELLANOX MLXCPLD I2C AND MUX DRIVER M: Vadim Pasternak M: Michael Shych L: linux-i2c@vger.kernel.org S: Supported +F: drivers/i2c/busses/i2c-mlxcpld.c F: drivers/i2c/muxes/i2c-mux-mlxcpld.c +F: Documentation/i2c/busses/i2c-mlxcpld MELLANOX MLXCPLD LED DRIVER M: Vadim Pasternak diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index d252276feadf..6399ceab402b 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -1150,6 +1150,17 @@ config I2C_ELEKTOR This support is also available as a module. If so, the module will be called i2c-elektor. +config I2C_MLXCPLD + tristate "Mellanox I2C driver" + depends on X86_64 + help + This exposes the Mellanox platform I2C busses to the linux I2C layer + for X86 based systems. + Controller is implemented as CPLD logic. + + This driver can also be built as a module. If so, the module will be + called as i2c-mlxcpld. + config I2C_PCA_ISA tristate "PCA9564/PCA9665 on an ISA bus" depends on ISA diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 29764cc20a44..645bf081bd6a 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -116,6 +116,7 @@ obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o +obj-$(CONFIG_I2C_MLXCPLD) += i2c-mlxcpld.o obj-$(CONFIG_I2C_OPAL) += i2c-opal.o obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c new file mode 100644 index 000000000000..d271e6a0954c --- /dev/null +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016 Michael Shych + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* General defines */ +#define MLXPLAT_CPLD_LPC_I2C_BASE_ADDR 0x2000 +#define MLXCPLD_I2C_DEVICE_NAME "i2c_mlxcpld" +#define MLXCPLD_I2C_VALID_FLAG (I2C_M_RECV_LEN | I2C_M_RD) +#define MLXCPLD_I2C_BUS_NUM 1 +#define MLXCPLD_I2C_DATA_REG_SZ 36 +#define MLXCPLD_I2C_MAX_ADDR_LEN 4 +#define MLXCPLD_I2C_RETR_NUM 2 +#define MLXCPLD_I2C_XFER_TO 500000 /* usec */ +#define MLXCPLD_I2C_POLL_TIME 2000 /* usec */ + +/* LPC I2C registers */ +#define MLXCPLD_LPCI2C_LPF_REG 0x0 +#define MLXCPLD_LPCI2C_CTRL_REG 0x1 +#define MLXCPLD_LPCI2C_HALF_CYC_REG 0x4 +#define MLXCPLD_LPCI2C_I2C_HOLD_REG 0x5 +#define MLXCPLD_LPCI2C_CMD_REG 0x6 +#define MLXCPLD_LPCI2C_NUM_DAT_REG 0x7 +#define MLXCPLD_LPCI2C_NUM_ADDR_REG 0x8 +#define MLXCPLD_LPCI2C_STATUS_REG 0x9 +#define MLXCPLD_LPCI2C_DATA_REG 0xa + +/* LPC I2C masks and parametres */ +#define MLXCPLD_LPCI2C_RST_SEL_MASK 0x1 +#define MLXCPLD_LPCI2C_TRANS_END 0x1 +#define MLXCPLD_LPCI2C_STATUS_NACK 0x10 +#define MLXCPLD_LPCI2C_NO_IND 0 +#define MLXCPLD_LPCI2C_ACK_IND 1 +#define MLXCPLD_LPCI2C_NACK_IND 2 + +struct mlxcpld_i2c_curr_xfer { + u8 cmd; + u8 addr_width; + u8 data_len; + u8 msg_num; + struct i2c_msg *msg; +}; + +struct mlxcpld_i2c_priv { + struct i2c_adapter adap; + u32 base_addr; + struct mutex lock; + struct mlxcpld_i2c_curr_xfer xfer; + struct device *dev; +}; + +static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) +{ + int i; + + for (i = 0; i < len - len % 4; i += 4) + outl(*(u32 *)(data + i), addr + i); + for (; i < len; ++i) + outb(*(data + i), addr + i); +} + +static void mlxcpld_i2c_lpc_read_buf(u8 *data, u8 len, u32 addr) +{ + int i; + + for (i = 0; i < len - len % 4; i += 4) + *(u32 *)(data + i) = inl(addr + i); + for (; i < len; ++i) + *(data + i) = inb(addr + i); +} + +static void mlxcpld_i2c_read_comm(struct mlxcpld_i2c_priv *priv, u8 offs, + u8 *data, u8 datalen) +{ + u32 addr = priv->base_addr + offs; + + switch (datalen) { + case 1: + *(data) = inb(addr); + break; + case 2: + *((u16 *)data) = inw(addr); + break; + case 3: + *((u16 *)data) = inw(addr); + *(data + 2) = inb(addr + 2); + break; + case 4: + *((u32 *)data) = inl(addr); + break; + default: + mlxcpld_i2c_lpc_read_buf(data, datalen, addr); + break; + } +} + +static void mlxcpld_i2c_write_comm(struct mlxcpld_i2c_priv *priv, u8 offs, + u8 *data, u8 datalen) +{ + u32 addr = priv->base_addr + offs; + + switch (datalen) { + case 1: + outb(*(data), addr); + break; + case 2: + outw(*((u16 *)data), addr); + break; + case 3: + outw(*((u16 *)data), addr); + outb(*(data + 2), addr + 2); + break; + case 4: + outl(*((u32 *)data), addr); + break; + default: + mlxcpld_i2c_lpc_write_buf(data, datalen, addr); + break; + } +} + +/* + * Check validity of received i2c messages parameters. + * Returns 0 if OK, other - in case of invalid parameters. + */ +static int mlxcpld_i2c_check_msg_params(struct mlxcpld_i2c_priv *priv, + struct i2c_msg *msgs, int num) +{ + int i; + + if (!num) { + dev_err(priv->dev, "Incorrect 0 num of messages\n"); + return -EINVAL; + } + + if (unlikely(msgs[0].addr > 0x7f)) { + dev_err(priv->dev, "Invalid address 0x%03x\n", + msgs[0].addr); + return -EINVAL; + } + + for (i = 0; i < num; ++i) { + if (unlikely(!msgs[i].buf)) { + dev_err(priv->dev, "Invalid buf in msg[%d]\n", + i); + return -EINVAL; + } + if (unlikely(msgs[0].addr != msgs[i].addr)) { + dev_err(priv->dev, "Invalid addr in msg[%d]\n", + i); + return -EINVAL; + } + } + + return 0; +} + +/* + * Check if transfer is completed and status of operation. + * Returns 0 - transfer completed (both ACK or NACK), + * negative - transfer isn't finished. + */ +static int mlxcpld_i2c_check_status(struct mlxcpld_i2c_priv *priv, int *status) +{ + u8 val; + + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1); + + if (val & MLXCPLD_LPCI2C_TRANS_END) { + if (val & MLXCPLD_LPCI2C_STATUS_NACK) + /* + * The slave is unable to accept the data. No such + * slave, command not understood, or unable to accept + * any more data. + */ + *status = MLXCPLD_LPCI2C_NACK_IND; + else + *status = MLXCPLD_LPCI2C_ACK_IND; + return 0; + } + *status = MLXCPLD_LPCI2C_NO_IND; + + return -EIO; +} + +static void mlxcpld_i2c_set_transf_data(struct mlxcpld_i2c_priv *priv, + struct i2c_msg *msgs, int num, + u8 comm_len) +{ + priv->xfer.msg = msgs; + priv->xfer.msg_num = num; + + /* + * All upper layers currently are never use transfer with more than + * 2 messages. Actually, it's also not so relevant in Mellanox systems + * because of HW limitation. Max size of transfer is not more than 32 + * bytes in the current x86 LPCI2C bridge. + */ + priv->xfer.cmd = msgs[num - 1].flags & I2C_M_RD; + + if (priv->xfer.cmd == I2C_M_RD && comm_len != msgs[0].len) { + priv->xfer.addr_width = msgs[0].len; + priv->xfer.data_len = comm_len - priv->xfer.addr_width; + } else { + priv->xfer.addr_width = 0; + priv->xfer.data_len = comm_len; + } +} + +/* Reset CPLD LPCI2C block */ +static void mlxcpld_i2c_reset(struct mlxcpld_i2c_priv *priv) +{ + u8 val; + + mutex_lock(&priv->lock); + + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1); + val &= ~MLXCPLD_LPCI2C_RST_SEL_MASK; + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CTRL_REG, &val, 1); + + mutex_unlock(&priv->lock); +} + +/* Make sure the CPLD is ready to start transmitting. */ +static int mlxcpld_i2c_check_busy(struct mlxcpld_i2c_priv *priv) +{ + u8 val; + + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_STATUS_REG, &val, 1); + + if (val & MLXCPLD_LPCI2C_TRANS_END) + return 0; + + return -EIO; +} + +static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) +{ + int timeout = 0; + + do { + if (!mlxcpld_i2c_check_busy(priv)) + break; + usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); + timeout += MLXCPLD_I2C_POLL_TIME; + } while (timeout <= MLXCPLD_I2C_XFER_TO); + + if (timeout > MLXCPLD_I2C_XFER_TO) + return -ETIMEDOUT; + + return 0; +} + +/* + * Wait for master transfer to complete. + * It puts current process to sleep until we get interrupt or timeout expires. + * Returns the number of transferred or read bytes or error (<0). + */ +static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) +{ + int status, i, timeout = 0; + u8 datalen; + + do { + usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); + if (!mlxcpld_i2c_check_status(priv, &status)) + break; + timeout += MLXCPLD_I2C_POLL_TIME; + } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO); + + switch (status) { + case MLXCPLD_LPCI2C_NO_IND: + return -ETIMEDOUT; + + case MLXCPLD_LPCI2C_ACK_IND: + if (priv->xfer.cmd != I2C_M_RD) + return (priv->xfer.addr_width + priv->xfer.data_len); + + if (priv->xfer.msg_num == 1) + i = 0; + else + i = 1; + + if (!priv->xfer.msg[i].buf) + return -EINVAL; + + /* + * Actual read data len will be always the same as + * requested len. 0xff (line pull-up) will be returned + * if slave has no data to return. Thus don't read + * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. + */ + datalen = priv->xfer.data_len; + + mlxcpld_i2c_read_comm(priv, MLXCPLD_LPCI2C_DATA_REG, + priv->xfer.msg[i].buf, datalen); + + return datalen; + + case MLXCPLD_LPCI2C_NACK_IND: + return -ENXIO; + + default: + return -EINVAL; + } +} + +static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) +{ + int i, len = 0; + u8 cmd; + + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_DAT_REG, + &priv->xfer.data_len, 1); + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_NUM_ADDR_REG, + &priv->xfer.addr_width, 1); + + for (i = 0; i < priv->xfer.msg_num; i++) { + if ((priv->xfer.msg[i].flags & I2C_M_RD) != I2C_M_RD) { + /* Don't write to CPLD buffer in read transaction */ + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_DATA_REG + + len, priv->xfer.msg[i].buf, + priv->xfer.msg[i].len); + len += priv->xfer.msg[i].len; + } + } + + /* + * Set target slave address with command for master transfer. + * It should be latest executed function before CPLD transaction. + */ + cmd = (priv->xfer.msg[0].addr << 1) | priv->xfer.cmd; + mlxcpld_i2c_write_comm(priv, MLXCPLD_LPCI2C_CMD_REG, &cmd, 1); +} + +/* + * Generic lpc-i2c transfer. + * Returns the number of processed messages or error (<0). + */ +static int mlxcpld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct mlxcpld_i2c_priv *priv = i2c_get_adapdata(adap); + u8 comm_len = 0; + int i, err; + + err = mlxcpld_i2c_check_msg_params(priv, msgs, num); + if (err) { + dev_err(priv->dev, "Incorrect message\n"); + return err; + } + + for (i = 0; i < num; ++i) + comm_len += msgs[i].len; + + /* Check bus state */ + if (mlxcpld_i2c_wait_for_free(priv)) { + dev_err(priv->dev, "LPCI2C bridge is busy\n"); + + /* + * Usually it means something serious has happened. + * We can not have unfinished previous transfer + * so it doesn't make any sense to try to stop it. + * Probably we were not able to recover from the + * previous error. + * The only reasonable thing - is soft reset. + */ + mlxcpld_i2c_reset(priv); + if (mlxcpld_i2c_check_busy(priv)) { + dev_err(priv->dev, "LPCI2C bridge is busy after reset\n"); + return -EIO; + } + } + + mlxcpld_i2c_set_transf_data(priv, msgs, num, comm_len); + + mutex_lock(&priv->lock); + + /* Do real transfer. Can't fail */ + mlxcpld_i2c_xfer_msg(priv); + + /* Wait for transaction complete */ + err = mlxcpld_i2c_wait_for_tc(priv); + + mutex_unlock(&priv->lock); + + return err < 0 ? err : num; +} + +static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm mlxcpld_i2c_algo = { + .master_xfer = mlxcpld_i2c_xfer, + .functionality = mlxcpld_i2c_func +}; + +static struct i2c_adapter_quirks mlxcpld_i2c_quirks = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_read_len = MLXCPLD_I2C_DATA_REG_SZ - MLXCPLD_I2C_MAX_ADDR_LEN, + .max_write_len = MLXCPLD_I2C_DATA_REG_SZ, + .max_comb_1st_msg_len = 4, +}; + +static struct i2c_adapter mlxcpld_i2c_adapter = { + .owner = THIS_MODULE, + .name = "i2c-mlxcpld", + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .algo = &mlxcpld_i2c_algo, + .quirks = &mlxcpld_i2c_quirks, + .retries = MLXCPLD_I2C_RETR_NUM, + .nr = MLXCPLD_I2C_BUS_NUM, +}; + +static int mlxcpld_i2c_probe(struct platform_device *pdev) +{ + struct mlxcpld_i2c_priv *priv; + int err; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->lock); + platform_set_drvdata(pdev, priv); + + priv->dev = &pdev->dev; + + /* Register with i2c layer */ + mlxcpld_i2c_adapter.timeout = usecs_to_jiffies(MLXCPLD_I2C_XFER_TO); + priv->adap = mlxcpld_i2c_adapter; + priv->adap.dev.parent = &pdev->dev; + priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; + i2c_set_adapdata(&priv->adap, priv); + + err = i2c_add_numbered_adapter(&priv->adap); + if (err) + mutex_destroy(&priv->lock); + + return err; +} + +static int mlxcpld_i2c_remove(struct platform_device *pdev) +{ + struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev); + + i2c_del_adapter(&priv->adap); + mutex_destroy(&priv->lock); + + return 0; +} + +static struct platform_driver mlxcpld_i2c_driver = { + .probe = mlxcpld_i2c_probe, + .remove = mlxcpld_i2c_remove, + .driver = { + .name = MLXCPLD_I2C_DEVICE_NAME, + }, +}; + +module_platform_driver(mlxcpld_i2c_driver); + +MODULE_AUTHOR("Michael Shych "); +MODULE_DESCRIPTION("Mellanox I2C-CPLD controller driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("platform:i2c-mlxcpld"); -- cgit v1.2.3 From 22e94bd6779e1140350c0792e85c79552ec43673 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 13 Oct 2016 14:10:35 +0200 Subject: i2c: i801: store and restore the SLVCMD register at load and unload Also do not override any other configuration in this register. Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index eb3627f35d12..750c4753e2bc 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -243,6 +243,7 @@ struct i801_priv { struct i2c_adapter adapter; unsigned long smba; unsigned char original_hstcfg; + unsigned char original_slvcmd; struct pci_dev *pci_dev; unsigned int features; @@ -962,13 +963,26 @@ static int i801_enable_host_notify(struct i2c_adapter *adapter) if (!priv->host_notify) return -ENOMEM; - outb_p(SMBSLVCMD_HST_NTFY_INTREN, SMBSLVCMD(priv)); + priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); + + if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) + outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, + SMBSLVCMD(priv)); + /* clear Host Notify bit to allow a new notification */ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); return 0; } +static void i801_disable_host_notify(struct i801_priv *priv) +{ + if (!(priv->features & FEATURE_HOST_NOTIFY)) + return; + + outb_p(priv->original_slvcmd, SMBSLVCMD(priv)); +} + static const struct i2c_algorithm smbus_algorithm = { .smbus_xfer = i801_access, .functionality = i801_func, @@ -1663,6 +1677,7 @@ static void i801_remove(struct pci_dev *dev) pm_runtime_forbid(&dev->dev); pm_runtime_get_noresume(&dev->dev); + i801_disable_host_notify(priv); i801_del_mux(priv); i2c_del_adapter(&priv->adapter); i801_acpi_remove(priv); -- cgit v1.2.3 From 9786b1f19ecff36909d3255d5a808012ca3568a6 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 13 Oct 2016 14:10:36 +0200 Subject: i2c: i801: minor formatting issues No functional changes, just typos and remove unused #define. Reviewed-by: Jean Delvare Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 750c4753e2bc..e6ea8f49acea 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -188,10 +188,10 @@ #define SMBHSTSTS_INTR 0x02 #define SMBHSTSTS_HOST_BUSY 0x01 -/* Host Notify Status registers bits */ +/* Host Notify Status register bits */ #define SMBSLVSTS_HST_NTFY_STS 1 -/* Host Notify Command registers bits */ +/* Host Notify Command register bits */ #define SMBSLVCMD_HST_NTFY_INTREN 0x01 #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ @@ -273,8 +273,6 @@ struct i801_priv { struct smbus_host_notify *host_notify; }; -#define SMBHSTNTFY_SIZE 8 - #define FEATURE_SMBUS_PEC (1 << 0) #define FEATURE_BLOCK_BUFFER (1 << 1) #define FEATURE_BLOCK_PROC (1 << 2) -- cgit v1.2.3 From fe9ba3ec1b6d472c4304728b8193900e7b160ea6 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 13 Oct 2016 14:10:37 +0200 Subject: i2c: i801: use BIT() macro for bits definition i801 mixes hexadecimal and decimal values for defining bits. However, we have a nice BIT() macro for this exact purpose. No functional changes, cleanup only. Reviewed-by: Jean Delvare Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 52 +++++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e6ea8f49acea..5ff5c30c2a13 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -137,27 +137,27 @@ #define SBREG_SMBCTRL 0xc6000c /* Host status bits for SMBPCISTS */ -#define SMBPCISTS_INTS 0x08 +#define SMBPCISTS_INTS BIT(3) /* Control bits for SMBPCICTL */ -#define SMBPCICTL_INTDIS 0x0400 +#define SMBPCICTL_INTDIS BIT(10) /* Host configuration bits for SMBHSTCFG */ -#define SMBHSTCFG_HST_EN 1 -#define SMBHSTCFG_SMB_SMI_EN 2 -#define SMBHSTCFG_I2C_EN 4 -#define SMBHSTCFG_SPD_WD 0x10 +#define SMBHSTCFG_HST_EN BIT(0) +#define SMBHSTCFG_SMB_SMI_EN BIT(1) +#define SMBHSTCFG_I2C_EN BIT(2) +#define SMBHSTCFG_SPD_WD BIT(4) /* TCO configuration bits for TCOCTL */ -#define TCOCTL_EN 0x0100 +#define TCOCTL_EN BIT(8) /* Auxiliary status register bits, ICH4+ only */ -#define SMBAUXSTS_CRCE 1 -#define SMBAUXSTS_STCO 2 +#define SMBAUXSTS_CRCE BIT(0) +#define SMBAUXSTS_STCO BIT(1) /* Auxiliary control register bits, ICH4+ only */ -#define SMBAUXCTL_CRC 1 -#define SMBAUXCTL_E32B 2 +#define SMBAUXCTL_CRC BIT(0) +#define SMBAUXCTL_E32B BIT(1) /* Other settings */ #define MAX_RETRIES 400 @@ -172,27 +172,27 @@ #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ /* I801 Host Control register bits */ -#define SMBHSTCNT_INTREN 0x01 -#define SMBHSTCNT_KILL 0x02 -#define SMBHSTCNT_LAST_BYTE 0x20 -#define SMBHSTCNT_START 0x40 -#define SMBHSTCNT_PEC_EN 0x80 /* ICH3 and later */ +#define SMBHSTCNT_INTREN BIT(0) +#define SMBHSTCNT_KILL BIT(1) +#define SMBHSTCNT_LAST_BYTE BIT(5) +#define SMBHSTCNT_START BIT(6) +#define SMBHSTCNT_PEC_EN BIT(7) /* ICH3 and later */ /* I801 Hosts Status register bits */ -#define SMBHSTSTS_BYTE_DONE 0x80 -#define SMBHSTSTS_INUSE_STS 0x40 -#define SMBHSTSTS_SMBALERT_STS 0x20 -#define SMBHSTSTS_FAILED 0x10 -#define SMBHSTSTS_BUS_ERR 0x08 -#define SMBHSTSTS_DEV_ERR 0x04 -#define SMBHSTSTS_INTR 0x02 -#define SMBHSTSTS_HOST_BUSY 0x01 +#define SMBHSTSTS_BYTE_DONE BIT(7) +#define SMBHSTSTS_INUSE_STS BIT(6) +#define SMBHSTSTS_SMBALERT_STS BIT(5) +#define SMBHSTSTS_FAILED BIT(4) +#define SMBHSTSTS_BUS_ERR BIT(3) +#define SMBHSTSTS_DEV_ERR BIT(2) +#define SMBHSTSTS_INTR BIT(1) +#define SMBHSTSTS_HOST_BUSY BIT(0) /* Host Notify Status register bits */ -#define SMBSLVSTS_HST_NTFY_STS 1 +#define SMBSLVSTS_HST_NTFY_STS BIT(0) /* Host Notify Command register bits */ -#define SMBSLVCMD_HST_NTFY_INTREN 0x01 +#define SMBSLVCMD_HST_NTFY_INTREN BIT(0) #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ SMBHSTSTS_DEV_ERR) -- cgit v1.2.3 From f91fba627caa20189185248b771625cf5994813e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 13 Oct 2016 14:10:38 +0200 Subject: i2c: i801: use the BIT() macro for FEATURES_* also no functional changes Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 5ff5c30c2a13..1d042af4374d 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -273,15 +273,15 @@ struct i801_priv { struct smbus_host_notify *host_notify; }; -#define FEATURE_SMBUS_PEC (1 << 0) -#define FEATURE_BLOCK_BUFFER (1 << 1) -#define FEATURE_BLOCK_PROC (1 << 2) -#define FEATURE_I2C_BLOCK_READ (1 << 3) -#define FEATURE_IRQ (1 << 4) -#define FEATURE_HOST_NOTIFY (1 << 5) +#define FEATURE_SMBUS_PEC BIT(0) +#define FEATURE_BLOCK_BUFFER BIT(1) +#define FEATURE_BLOCK_PROC BIT(2) +#define FEATURE_I2C_BLOCK_READ BIT(3) +#define FEATURE_IRQ BIT(4) +#define FEATURE_HOST_NOTIFY BIT(5) /* Not really a feature, but it's convenient to handle it as such */ -#define FEATURE_IDF (1 << 15) -#define FEATURE_TCO (1 << 16) +#define FEATURE_IDF BIT(15) +#define FEATURE_TCO BIT(16) static const char *i801_feature_names[] = { "SMBus PEC", -- cgit v1.2.3 From c912a25a5a12a497bb47068e3d42d7c9b67bde12 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 13 Oct 2016 14:10:39 +0200 Subject: i2c: i801: remove SMBNTFDDAT reads as they always seem to return 0 On the platform tested, reading SMBNTFDDAT always returns 0 (using 1 read of a word or 2 of 2 bytes). Given that we are not sure why and that we don't need to rely on the data parameter in the current users of Host Notify, remove this part of the code. If someone wants to re-enable it, just revert this commit and data should be available. Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-i801.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 1d042af4374d..c0c0cac9950c 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -118,7 +118,6 @@ #define SMBSLVSTS(p) (16 + (p)->smba) /* ICH3 and later */ #define SMBSLVCMD(p) (17 + (p)->smba) /* ICH3 and later */ #define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ -#define SMBNTFDDAT(p) (22 + (p)->smba) /* ICH3 and later */ /* PCI Address Constants */ #define SMBBAR 4 @@ -581,12 +580,15 @@ static void i801_isr_byte_done(struct i801_priv *priv) static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) { unsigned short addr; - unsigned int data; addr = inb_p(SMBNTFDADD(priv)) >> 1; - data = inw_p(SMBNTFDDAT(priv)); - i2c_handle_smbus_host_notify(priv->host_notify, addr, data); + /* + * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba) + * always returns 0 and is safe to read. + * We just use 0 given we have no use of the data right now. + */ + i2c_handle_smbus_host_notify(priv->host_notify, addr, 0); /* clear Host Notify bit and return */ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); -- cgit v1.2.3 From 4d5538f5882a6b67eefbab0f0a3a67ce811621aa Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Thu, 13 Oct 2016 14:10:40 +0200 Subject: i2c: use an IRQ to report Host Notify events, not alert The current SMBus Host Notify implementation relies on .alert() to relay its notifications. However, the use cases where SMBus Host Notify is needed currently is to signal data ready on touchpads. This is closer to an IRQ than a custom API through .alert(). Given that the 2 touchpad manufacturers (Synaptics and Elan) that use SMBus Host Notify don't put any data in the SMBus payload, the concept actually matches one to one. Benefits are multiple: - simpler code and API: the client will just have an IRQ, and nothing needs to be added in the adapter beside internally enabling it. - no more specific workqueue, the threading is handled by IRQ core directly (when required) - no more races when removing the device (the drivers are already required to disable irq on remove) - simpler handling for drivers: use plain regular IRQs - no more dependency on i2c-smbus for i2c-i801 (and any other adapter) - the IRQ domain is created automatically when the adapter exports the Host Notify capability - the IRQ are assign only if ACPI, OF and the caller did not assign one already - the domain is automatically destroyed on remove - fewer lines of code (minus 20, yeah!) Signed-off-by: Benjamin Tissoires Signed-off-by: Wolfram Sang --- Documentation/i2c/smbus-protocol | 12 +++-- drivers/i2c/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 32 +++-------- drivers/i2c/i2c-core.c | 113 +++++++++++++++++++++++++++++++++++++++ drivers/i2c/i2c-smbus.c | 102 ----------------------------------- include/linux/i2c-smbus.h | 27 ---------- include/linux/i2c.h | 4 ++ 7 files changed, 133 insertions(+), 158 deletions(-) (limited to 'drivers') diff --git a/Documentation/i2c/smbus-protocol b/Documentation/i2c/smbus-protocol index 14d4ec1be245..092d474f5843 100644 --- a/Documentation/i2c/smbus-protocol +++ b/Documentation/i2c/smbus-protocol @@ -200,10 +200,14 @@ alerting device's address. [S] [HostAddr] [Wr] A [DevAddr] A [DataLow] A [DataHigh] A [P] This is implemented in the following way in the Linux kernel: -* I2C bus drivers which support SMBus Host Notify should call - i2c_setup_smbus_host_notify() to setup SMBus Host Notify support. -* I2C drivers for devices which can trigger SMBus Host Notify should implement - the optional alert() callback. +* I2C bus drivers which support SMBus Host Notify should report + I2C_FUNC_SMBUS_HOST_NOTIFY. +* I2C bus drivers trigger SMBus Host Notify by a call to + i2c_handle_smbus_host_notify(). +* I2C drivers for devices which can trigger SMBus Host Notify will have + client->irq assigned to a Host Notify IRQ if noone else specified an other. + +There is currently no way to retrieve the data parameter from the client. Packet Error Checking (PEC) diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index d223650a97e4..de305f89a659 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -7,6 +7,7 @@ menu "I2C support" config I2C tristate "I2C support" select RT_MUTEXES + select IRQ_DOMAIN ---help--- I2C (pronounce: I-squared-C) is a slow serial bus protocol used in many micro controller applications and developed by Philips. SMBus, diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index c0c0cac9950c..e242db43774b 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -269,7 +269,6 @@ struct i801_priv { */ bool acpi_reserved; struct mutex acpi_lock; - struct smbus_host_notify *host_notify; }; #define FEATURE_SMBUS_PEC BIT(0) @@ -585,10 +584,10 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) /* * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba) - * always returns 0 and is safe to read. - * We just use 0 given we have no use of the data right now. + * always returns 0. Our current implementation doesn't provide + * data, so we just ignore it. */ - i2c_handle_smbus_host_notify(priv->host_notify, addr, 0); + i2c_handle_smbus_host_notify(&priv->adapter, addr); /* clear Host Notify bit and return */ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); @@ -951,17 +950,12 @@ static u32 i801_func(struct i2c_adapter *adapter) I2C_FUNC_SMBUS_HOST_NOTIFY : 0); } -static int i801_enable_host_notify(struct i2c_adapter *adapter) +static void i801_enable_host_notify(struct i2c_adapter *adapter) { struct i801_priv *priv = i2c_get_adapdata(adapter); if (!(priv->features & FEATURE_HOST_NOTIFY)) - return -ENOTSUPP; - - if (!priv->host_notify) - priv->host_notify = i2c_setup_smbus_host_notify(adapter); - if (!priv->host_notify) - return -ENOMEM; + return; priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); @@ -971,8 +965,6 @@ static int i801_enable_host_notify(struct i2c_adapter *adapter) /* clear Host Notify bit to allow a new notification */ outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); - - return 0; } static void i801_disable_host_notify(struct i801_priv *priv) @@ -1647,14 +1639,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) return err; } - /* - * Enable Host Notify for chips that supports it. - * It is done after i2c_add_adapter() so that we are sure the work queue - * is not used if i2c_add_adapter() fails. - */ - err = i801_enable_host_notify(&priv->adapter); - if (err && err != -ENOTSUPP) - dev_warn(&dev->dev, "Unable to enable SMBus Host Notify\n"); + i801_enable_host_notify(&priv->adapter); i801_probe_optional_slaves(priv); /* We ignore errors - multiplexing is optional */ @@ -1705,11 +1690,8 @@ static int i801_resume(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); struct i801_priv *priv = pci_get_drvdata(pci_dev); - int err; - err = i801_enable_host_notify(&priv->adapter); - if (err && err != -ENOTSUPP) - dev_warn(dev, "Unable to enable SMBus Host Notify\n"); + i801_enable_host_notify(&priv->adapter); return 0; } diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 8b93a262e237..3a1bc9c4efc7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -65,6 +65,9 @@ #define I2C_ADDR_OFFSET_TEN_BIT 0xa000 #define I2C_ADDR_OFFSET_SLAVE 0x1000 +#define I2C_ADDR_7BITS_MAX 0x77 +#define I2C_ADDR_7BITS_COUNT (I2C_ADDR_7BITS_MAX + 1) + /* core_lock protects i2c_adapter_idr, and guarantees that device detection, deletion of detected devices, and attach_adapter calls are serialized */ @@ -896,6 +899,25 @@ static void i2c_init_recovery(struct i2c_adapter *adap) adap->bus_recovery_info = NULL; } +static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client) +{ + struct i2c_adapter *adap = client->adapter; + unsigned int irq; + + if (!adap->host_notify_domain) + return -ENXIO; + + if (client->flags & I2C_CLIENT_TEN) + return -EINVAL; + + irq = irq_find_mapping(adap->host_notify_domain, client->addr); + if (!irq) + irq = irq_create_mapping(adap->host_notify_domain, + client->addr); + + return irq > 0 ? irq : -ENXIO; +} + static int i2c_device_probe(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); @@ -917,6 +939,14 @@ static int i2c_device_probe(struct device *dev) } if (irq == -EPROBE_DEFER) return irq; + /* + * ACPI and OF did not find any useful IRQ, try to see + * if Host Notify can be used. + */ + if (irq < 0) { + dev_dbg(dev, "Using Host Notify IRQ\n"); + irq = i2c_smbus_host_notify_to_irq(client); + } if (irq < 0) irq = 0; @@ -1866,6 +1896,79 @@ static const struct i2c_lock_operations i2c_adapter_lock_ops = { .unlock_bus = i2c_adapter_unlock_bus, }; +static void i2c_host_notify_irq_teardown(struct i2c_adapter *adap) +{ + struct irq_domain *domain = adap->host_notify_domain; + irq_hw_number_t hwirq; + + if (!domain) + return; + + for (hwirq = 0 ; hwirq < I2C_ADDR_7BITS_COUNT ; hwirq++) + irq_dispose_mapping(irq_find_mapping(domain, hwirq)); + + irq_domain_remove(domain); + adap->host_notify_domain = NULL; +} + +static int i2c_host_notify_irq_map(struct irq_domain *h, + unsigned int virq, + irq_hw_number_t hw_irq_num) +{ + irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); + + return 0; +} + +static const struct irq_domain_ops i2c_host_notify_irq_ops = { + .map = i2c_host_notify_irq_map, +}; + +static int i2c_setup_host_notify_irq_domain(struct i2c_adapter *adap) +{ + struct irq_domain *domain; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_HOST_NOTIFY)) + return 0; + + domain = irq_domain_create_linear(adap->dev.fwnode, + I2C_ADDR_7BITS_COUNT, + &i2c_host_notify_irq_ops, adap); + if (!domain) + return -ENOMEM; + + adap->host_notify_domain = domain; + + return 0; +} + +/** + * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct + * I2C client. + * @adap: the adapter + * @addr: the I2C address of the notifying device + * Context: can't sleep + * + * Helper function to be called from an I2C bus driver's interrupt + * handler. It will schedule the Host Notify IRQ. + */ +int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr) +{ + int irq; + + if (!adap) + return -EINVAL; + + irq = irq_find_mapping(adap->host_notify_domain, addr); + if (irq <= 0) + return -ENXIO; + + generic_handle_irq(irq); + + return 0; +} +EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify); + static int i2c_register_adapter(struct i2c_adapter *adap) { int res = -EINVAL; @@ -1897,6 +2000,14 @@ static int i2c_register_adapter(struct i2c_adapter *adap) if (adap->timeout == 0) adap->timeout = HZ; + /* register soft irqs for Host Notify */ + res = i2c_setup_host_notify_irq_domain(adap); + if (res) { + pr_err("adapter '%s': can't create Host Notify IRQs (%d)\n", + adap->name, res); + goto out_list; + } + dev_set_name(&adap->dev, "i2c-%d", adap->nr); adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; @@ -2134,6 +2245,8 @@ void i2c_del_adapter(struct i2c_adapter *adap) pm_runtime_disable(&adap->dev); + i2c_host_notify_irq_teardown(adap); + /* wait until all references to the device are gone * * FIXME: This is old code and should ideally be replaced by an diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index b0d2679c60d1..f9271c713d20 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -241,108 +241,6 @@ int i2c_handle_smbus_alert(struct i2c_client *ara) } EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert); -static void smbus_host_notify_work(struct work_struct *work) -{ - struct alert_data alert; - struct i2c_adapter *adapter; - unsigned long flags; - u16 payload; - u8 addr; - struct smbus_host_notify *data; - - data = container_of(work, struct smbus_host_notify, work); - - spin_lock_irqsave(&data->lock, flags); - payload = data->payload; - addr = data->addr; - adapter = data->adapter; - - /* clear the pending bit and release the spinlock */ - data->pending = false; - spin_unlock_irqrestore(&data->lock, flags); - - if (!adapter || !addr) - return; - - alert.type = I2C_PROTOCOL_SMBUS_HOST_NOTIFY; - alert.addr = addr; - alert.data = payload; - - device_for_each_child(&adapter->dev, &alert, smbus_do_alert); -} - -/** - * i2c_setup_smbus_host_notify - Allocate a new smbus_host_notify for the given - * I2C adapter. - * @adapter: the adapter we want to associate a Host Notify function - * - * Returns a struct smbus_host_notify pointer on success, and NULL on failure. - * The resulting smbus_host_notify must not be freed afterwards, it is a - * managed resource already. - */ -struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap) -{ - struct smbus_host_notify *host_notify; - - host_notify = devm_kzalloc(&adap->dev, sizeof(struct smbus_host_notify), - GFP_KERNEL); - if (!host_notify) - return NULL; - - host_notify->adapter = adap; - - spin_lock_init(&host_notify->lock); - INIT_WORK(&host_notify->work, smbus_host_notify_work); - - return host_notify; -} -EXPORT_SYMBOL_GPL(i2c_setup_smbus_host_notify); - -/** - * i2c_handle_smbus_host_notify - Forward a Host Notify event to the correct - * I2C client. - * @host_notify: the struct host_notify attached to the relevant adapter - * @addr: the I2C address of the notifying device - * @data: the payload of the notification - * Context: can't sleep - * - * Helper function to be called from an I2C bus driver's interrupt - * handler. It will schedule the Host Notify work, in turn calling the - * corresponding I2C device driver's alert function. - * - * host_notify should be a valid pointer previously returned by - * i2c_setup_smbus_host_notify(). - */ -int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, - unsigned short addr, unsigned int data) -{ - unsigned long flags; - struct i2c_adapter *adapter; - - if (!host_notify || !host_notify->adapter) - return -EINVAL; - - adapter = host_notify->adapter; - - spin_lock_irqsave(&host_notify->lock, flags); - - if (host_notify->pending) { - spin_unlock_irqrestore(&host_notify->lock, flags); - dev_warn(&adapter->dev, "Host Notify already scheduled.\n"); - return -EBUSY; - } - - host_notify->payload = data; - host_notify->addr = addr; - - /* Mark that there is a pending notification and release the lock */ - host_notify->pending = true; - spin_unlock_irqrestore(&host_notify->lock, flags); - - return schedule_work(&host_notify->work); -} -EXPORT_SYMBOL_GPL(i2c_handle_smbus_host_notify); - module_i2c_driver(smbalert_driver); MODULE_AUTHOR("Jean Delvare "); diff --git a/include/linux/i2c-smbus.h b/include/linux/i2c-smbus.h index c2e3324f9468..a1385023a29b 100644 --- a/include/linux/i2c-smbus.h +++ b/include/linux/i2c-smbus.h @@ -50,31 +50,4 @@ struct i2c_client *i2c_setup_smbus_alert(struct i2c_adapter *adapter, struct i2c_smbus_alert_setup *setup); int i2c_handle_smbus_alert(struct i2c_client *ara); -/** - * smbus_host_notify - internal structure used by the Host Notify mechanism. - * @adapter: the I2C adapter associated with this struct - * @work: worker used to schedule the IRQ in the slave device - * @lock: spinlock to check if a notification is already pending - * @pending: flag set when a notification is pending (any new notification will - * be rejected if pending is true) - * @payload: the actual payload of the Host Notify event - * @addr: the address of the slave device which raised the notification - * - * This struct needs to be allocated by i2c_setup_smbus_host_notify() and does - * not need to be freed. Internally, i2c_setup_smbus_host_notify() uses a - * managed resource to clean this up when the adapter get released. - */ -struct smbus_host_notify { - struct i2c_adapter *adapter; - struct work_struct work; - spinlock_t lock; - bool pending; - u16 payload; - u8 addr; -}; - -struct smbus_host_notify *i2c_setup_smbus_host_notify(struct i2c_adapter *adap); -int i2c_handle_smbus_host_notify(struct smbus_host_notify *host_notify, - unsigned short addr, unsigned int data); - #endif /* _LINUX_I2C_SMBUS_H */ diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 82cf90945bb8..b2109c522dec 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -30,6 +30,7 @@ #include /* for struct device */ #include /* for completion */ #include +#include /* for Host Notify IRQ */ #include /* for struct device_node */ #include /* for swab16 */ #include @@ -575,6 +576,8 @@ struct i2c_adapter { struct i2c_bus_recovery_info *bus_recovery_info; const struct i2c_adapter_quirks *quirks; + + struct irq_domain *host_notify_domain; }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) @@ -747,6 +750,7 @@ static inline u8 i2c_8bit_addr_from_msg(const struct i2c_msg *msg) return (msg->addr << 1) | (msg->flags & I2C_M_RD ? 1 : 0); } +int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr); /** * module_i2c_driver() - Helper macro for registering a modular I2C driver * @__i2c_driver: i2c_driver struct -- cgit v1.2.3 From 1abf71eef32c7f242fe30ea66a635e297b2c1c8d Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 7 Nov 2016 07:37:06 -0700 Subject: Move platform device creation earlier in the initialization Some logs are printed out early using smi->dev, but on a platform device that is not created until later. So move the creation of that device structure earlier in the sequence so it can be used for printing. Signed-off-by: Corey Minyard Tested-by: Corentin Labbe --- drivers/char/ipmi/ipmi_si_intf.c | 46 +++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index cb451088a4af..751c2815fc2a 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -3502,6 +3502,7 @@ static int try_smi_init(struct smi_info *new_smi) { int rv = 0; int i; + char *init_name = NULL; printk(KERN_INFO PFX "Trying %s-specified %s state" " machine at %s address 0x%lx, slave address 0x%x," @@ -3531,6 +3532,26 @@ static int try_smi_init(struct smi_info *new_smi) goto out_err; } + /* Do this early so it's available for logs. */ + if (!new_smi->dev) { + init_name = kasprintf(GFP_KERNEL, "ipmi_si.%d", 0); + + /* + * If we don't already have a device from something + * else (like PCI), then register a new one. + */ + new_smi->pdev = platform_device_alloc("ipmi_si", + new_smi->intf_num); + if (!new_smi->pdev) { + pr_err(PFX "Unable to allocate platform device\n"); + goto out_err; + } + new_smi->dev = &new_smi->pdev->dev; + new_smi->dev->driver = &ipmi_driver.driver; + /* Nulled by device_add() */ + new_smi->dev->init_name = init_name; + } + /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); if (!new_smi->si_sm) { @@ -3604,21 +3625,7 @@ static int try_smi_init(struct smi_info *new_smi) atomic_set(&new_smi->req_events, 1); } - if (!new_smi->dev) { - /* - * If we don't already have a device from something - * else (like PCI), then register a new one. - */ - new_smi->pdev = platform_device_alloc("ipmi_si", - new_smi->intf_num); - if (!new_smi->pdev) { - printk(KERN_ERR PFX - "Unable to allocate platform device\n"); - goto out_err; - } - new_smi->dev = &new_smi->pdev->dev; - new_smi->dev->driver = &ipmi_driver.driver; - + if (new_smi->pdev) { rv = platform_device_add(new_smi->pdev); if (rv) { printk(KERN_ERR PFX @@ -3668,6 +3675,9 @@ static int try_smi_init(struct smi_info *new_smi) dev_info(new_smi->dev, "IPMI %s interface initialized\n", si_to_str[new_smi->si_type]); + WARN_ON(new_smi->dev->init_name != NULL); + kfree(init_name); + return 0; out_err_stop_timer: @@ -3712,8 +3722,14 @@ out_err: if (new_smi->dev_registered) { platform_device_unregister(new_smi->pdev); new_smi->dev_registered = false; + new_smi->pdev = NULL; + } else if (new_smi->pdev) { + platform_device_put(new_smi->pdev); + new_smi->pdev = NULL; } + kfree(init_name); + return rv; } -- cgit v1.2.3 From bb2a08c01a66e77917bd2fdaf5cffd917ec03573 Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 7 Nov 2016 11:27:18 -0600 Subject: ipmi_si: Clean up printks Convert them to pr_xxx or dev_xxx. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 130 ++++++++++++++++----------------------- 1 file changed, 54 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 751c2815fc2a..017994900ad7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -1764,7 +1764,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name, s = strchr(*curr, ','); if (!s) { - printk(KERN_WARNING PFX "No hotmod %s given.\n", name); + pr_warn(PFX "No hotmod %s given.\n", name); return -EINVAL; } *s = '\0'; @@ -1777,7 +1777,7 @@ static int parse_str(const struct hotmod_vals *v, int *val, char *name, } } - printk(KERN_WARNING PFX "Invalid hotmod %s '%s'\n", name, *curr); + pr_warn(PFX "Invalid hotmod %s '%s'\n", name, *curr); return -EINVAL; } @@ -1788,16 +1788,12 @@ static int check_hotmod_int_op(const char *curr, const char *option, if (strcmp(curr, name) == 0) { if (!option) { - printk(KERN_WARNING PFX - "No option given for '%s'\n", - curr); + pr_warn(PFX "No option given for '%s'\n", curr); return -EINVAL; } *val = simple_strtoul(option, &n, 0); if ((*n != '\0') || (*option == '\0')) { - printk(KERN_WARNING PFX - "Bad option given for '%s'\n", - curr); + pr_warn(PFX "Bad option given for '%s'\n", curr); return -EINVAL; } return 1; @@ -1877,8 +1873,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) } addr = simple_strtoul(curr, &n, 0); if ((*n != '\0') || (*curr == '\0')) { - printk(KERN_WARNING PFX "Invalid hotmod address" - " '%s'\n", curr); + pr_warn(PFX "Invalid hotmod address '%s'\n", curr); break; } @@ -1921,9 +1916,7 @@ static int hotmod_handler(const char *val, struct kernel_param *kp) continue; rv = -EINVAL; - printk(KERN_WARNING PFX - "Invalid hotmod option '%s'\n", - curr); + pr_warn(PFX "Invalid hotmod option '%s'\n", curr); goto out; } @@ -2003,7 +1996,7 @@ static int hardcode_find_bmc(void) return -ENOMEM; info->addr_source = SI_HARDCODED; - printk(KERN_INFO PFX "probing via hardcoded address\n"); + pr_info(PFX "probing via hardcoded address\n"); if (!si_type[i] || strcmp(si_type[i], "kcs") == 0) { info->si_type = SI_KCS; @@ -2012,9 +2005,8 @@ static int hardcode_find_bmc(void) } else if (strcmp(si_type[i], "bt") == 0) { info->si_type = SI_BT; } else { - printk(KERN_WARNING PFX "Interface type specified " - "for interface %d, was invalid: %s\n", - i, si_type[i]); + pr_warn(PFX "Interface type specified for interface %d, was invalid: %s\n", + i, si_type[i]); kfree(info); continue; } @@ -2030,9 +2022,8 @@ static int hardcode_find_bmc(void) info->io.addr_data = addrs[i]; info->io.addr_type = IPMI_MEM_ADDR_SPACE; } else { - printk(KERN_WARNING PFX "Interface type specified " - "for interface %d, but port and address were " - "not set or set to zero.\n", i); + pr_warn(PFX "Interface type specified for interface %d, but port and address were not set or set to zero.\n", + i); kfree(info); continue; } @@ -2173,18 +2164,18 @@ static int try_init_spmi(struct SPMITable *spmi) int rv; if (spmi->IPMIlegacy != 1) { - printk(KERN_INFO PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); + pr_info(PFX "Bad SPMI legacy %d\n", spmi->IPMIlegacy); return -ENODEV; } info = smi_info_alloc(); if (!info) { - printk(KERN_ERR PFX "Could not allocate SI data (3)\n"); + pr_err(PFX "Could not allocate SI data (3)\n"); return -ENOMEM; } info->addr_source = SI_SPMI; - printk(KERN_INFO PFX "probing via SPMI\n"); + pr_info(PFX "probing via SPMI\n"); /* Figure out the interface type. */ switch (spmi->InterfaceType) { @@ -2201,8 +2192,8 @@ static int try_init_spmi(struct SPMITable *spmi) kfree(info); return -EIO; default: - printk(KERN_INFO PFX "Unknown ACPI/SPMI SI type %d\n", - spmi->InterfaceType); + pr_info(PFX "Unknown ACPI/SPMI SI type %d\n", + spmi->InterfaceType); kfree(info); return -EIO; } @@ -2238,15 +2229,15 @@ static int try_init_spmi(struct SPMITable *spmi) info->io.addr_type = IPMI_IO_ADDR_SPACE; } else { kfree(info); - printk(KERN_WARNING PFX "Unknown ACPI I/O Address type\n"); + pr_warn(PFX "Unknown ACPI I/O Address type\n"); return -EIO; } info->io.addr_data = spmi->addr.address; pr_info("ipmi_si: SPMI: %s %#lx regsize %d spacing %d irq %d\n", - (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", - info->io.addr_data, info->io.regsize, info->io.regspacing, - info->irq); + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); rv = add_smi(info); if (rv) @@ -2356,12 +2347,12 @@ static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) info = smi_info_alloc(); if (!info) { - printk(KERN_ERR PFX "Could not allocate SI data\n"); + pr_err(PFX "Could not allocate SI data\n"); return; } info->addr_source = SI_SMBIOS; - printk(KERN_INFO PFX "probing via SMBIOS\n"); + pr_info(PFX "probing via SMBIOS\n"); switch (ipmi_data->type) { case 0x01: /* KCS */ @@ -2391,8 +2382,8 @@ static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) default: kfree(info); - printk(KERN_WARNING PFX "Unknown SMBIOS I/O Address type: %d\n", - ipmi_data->addr_space); + pr_warn(PFX "Unknown SMBIOS I/O Address type: %d\n", + ipmi_data->addr_space); return; } info->io.addr_data = ipmi_data->base_addr; @@ -2410,9 +2401,9 @@ static void try_init_dmi(struct dmi_ipmi_data *ipmi_data) info->irq_setup = std_irq_setup; pr_info("ipmi_si: SMBIOS: %s %#lx regsize %d spacing %d irq %d\n", - (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", - info->io.addr_data, info->io.regsize, info->io.regspacing, - info->irq); + (info->io.addr_type == IPMI_IO_ADDR_SPACE) ? "io" : "mem", + info->io.addr_data, info->io.regsize, info->io.regspacing, + info->irq); if (add_smi(info)) kfree(info); @@ -3141,9 +3132,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) rv = wait_for_msg_done(smi_info); if (rv) { - printk(KERN_WARNING PFX "Error getting response from get" - " global enables command, the event buffer is not" - " enabled.\n"); + pr_warn(PFX "Error getting response from get global enables command, the event buffer is not enabled.\n"); goto out; } @@ -3154,8 +3143,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD || resp[2] != 0) { - printk(KERN_WARNING PFX "Invalid return from get global" - " enables command, cannot enable the event buffer.\n"); + pr_warn(PFX "Invalid return from get global enables command, cannot enable the event buffer.\n"); rv = -EINVAL; goto out; } @@ -3173,9 +3161,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) rv = wait_for_msg_done(smi_info); if (rv) { - printk(KERN_WARNING PFX "Error getting response from set" - " global, enables command, the event buffer is not" - " enabled.\n"); + pr_warn(PFX "Error getting response from set global, enables command, the event buffer is not enabled.\n"); goto out; } @@ -3185,8 +3171,7 @@ static int try_enable_event_buffer(struct smi_info *smi_info) if (resp_len < 3 || resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 || resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) { - printk(KERN_WARNING PFX "Invalid return from get global," - "enables command, not enable the event buffer.\n"); + pr_warn(PFX "Invalid return from get global, enables command, not enable the event buffer.\n"); rv = -EINVAL; goto out; } @@ -3474,17 +3459,18 @@ static int add_smi(struct smi_info *new_smi) { int rv = 0; - printk(KERN_INFO PFX "Adding %s-specified %s state machine", - ipmi_addr_src_to_str(new_smi->addr_source), - si_to_str[new_smi->si_type]); mutex_lock(&smi_infos_lock); if (!is_new_interface(new_smi)) { - printk(KERN_CONT " duplicate interface\n"); + pr_info(PFX "%s-specified %s state machine: duplicate\n", + ipmi_addr_src_to_str(new_smi->addr_source), + si_to_str[new_smi->si_type]); rv = -EBUSY; goto out_err; } - printk(KERN_CONT "\n"); + pr_info(PFX "Adding %s-specified %s state machine\n", + ipmi_addr_src_to_str(new_smi->addr_source), + si_to_str[new_smi->si_type]); /* So we know not to free it unless we have allocated one. */ new_smi->intf = NULL; @@ -3504,14 +3490,12 @@ static int try_smi_init(struct smi_info *new_smi) int i; char *init_name = NULL; - printk(KERN_INFO PFX "Trying %s-specified %s state" - " machine at %s address 0x%lx, slave address 0x%x," - " irq %d\n", - ipmi_addr_src_to_str(new_smi->addr_source), - si_to_str[new_smi->si_type], - addr_space_to_str[new_smi->io.addr_type], - new_smi->io.addr_data, - new_smi->slave_addr, new_smi->irq); + pr_info(PFX "Trying %s-specified %s state machine at %s address 0x%lx, slave address 0x%x, irq %d\n", + ipmi_addr_src_to_str(new_smi->addr_source), + si_to_str[new_smi->si_type], + addr_space_to_str[new_smi->io.addr_type], + new_smi->io.addr_data, + new_smi->slave_addr, new_smi->irq); switch (new_smi->si_type) { case SI_KCS: @@ -3555,8 +3539,7 @@ static int try_smi_init(struct smi_info *new_smi) /* Allocate the state machine's data and initialize it. */ new_smi->si_sm = kmalloc(new_smi->handlers->size(), GFP_KERNEL); if (!new_smi->si_sm) { - printk(KERN_ERR PFX - "Could not allocate state machine memory\n"); + pr_err(PFX "Could not allocate state machine memory\n"); rv = -ENOMEM; goto out_err; } @@ -3566,14 +3549,14 @@ static int try_smi_init(struct smi_info *new_smi) /* Now that we know the I/O size, we can set up the I/O. */ rv = new_smi->io_setup(new_smi); if (rv) { - printk(KERN_ERR PFX "Could not set up I/O space\n"); + dev_err(new_smi->dev, "Could not set up I/O space\n"); goto out_err; } /* Do low-level detection first. */ if (new_smi->handlers->detect(new_smi->si_sm)) { if (new_smi->addr_source) - printk(KERN_INFO PFX "Interface detection failed\n"); + dev_err(new_smi->dev, "Interface detection failed\n"); rv = -ENODEV; goto out_err; } @@ -3585,8 +3568,7 @@ static int try_smi_init(struct smi_info *new_smi) rv = try_get_dev_id(new_smi); if (rv) { if (new_smi->addr_source) - printk(KERN_INFO PFX "There appears to be no BMC" - " at this location\n"); + dev_err(new_smi->dev, "There appears to be no BMC at this location\n"); goto out_err; } @@ -3628,10 +3610,9 @@ static int try_smi_init(struct smi_info *new_smi) if (new_smi->pdev) { rv = platform_device_add(new_smi->pdev); if (rv) { - printk(KERN_ERR PFX - "Unable to register system interface device:" - " %d\n", - rv); + dev_err(new_smi->dev, + "Unable to register system interface device: %d\n", + rv); goto out_err; } new_smi->dev_registered = true; @@ -3748,8 +3729,7 @@ static int init_ipmi_si(void) if (si_tryplatform) { rv = platform_driver_register(&ipmi_driver); if (rv) { - printk(KERN_ERR PFX "Unable to register " - "driver: %d\n", rv); + pr_err(PFX "Unable to register driver: %d\n", rv); return rv; } } @@ -3769,7 +3749,7 @@ static int init_ipmi_si(void) } } - printk(KERN_INFO "IPMI System Interface driver.\n"); + pr_info("IPMI System Interface driver.\n"); /* If the user gave us a device, they presumably want us to use it */ if (!hardcode_find_bmc()) @@ -3779,8 +3759,7 @@ static int init_ipmi_si(void) if (si_trypci) { rv = pci_register_driver(&ipmi_pci_driver); if (rv) - printk(KERN_ERR PFX "Unable to register " - "PCI driver: %d\n", rv); + pr_err(PFX "Unable to register PCI driver: %d\n", rv); else pci_registered = true; } @@ -3842,8 +3821,7 @@ static int init_ipmi_si(void) if (unload_when_empty && list_empty(&smi_infos)) { mutex_unlock(&smi_infos_lock); cleanup_ipmi_si(); - printk(KERN_WARNING PFX - "Unable to find any System Interface(s)\n"); + pr_warn(PFX "Unable to find any System Interface(s)\n"); return -ENODEV; } else { mutex_unlock(&smi_infos_lock); -- cgit v1.2.3 From 94671710183c3f5eed7cf33f73600c836e4777fd Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 7 Nov 2016 12:07:09 -0600 Subject: ipmi: Pick up slave address from SMBIOS on an ACPI device When added by ACPI, the information does not contain the slave address of the BMC. However, that information is available from SMBIOS. So if we add a device that doesn't have a slave address, look at the other devices that are duplicate interfaces and see if they have a slave address. Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_si_intf.c | 10 +++++++++- drivers/char/ipmi/ipmi_ssif.c | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 40 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 017994900ad7..2a7c425ddfa7 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -3448,8 +3448,16 @@ static int is_new_interface(struct smi_info *info) list_for_each_entry(e, &smi_infos, link) { if (e->io.addr_type != info->io.addr_type) continue; - if (e->io.addr_data == info->io.addr_data) + if (e->io.addr_data == info->io.addr_data) { + /* + * This is a cheap hack, ACPI doesn't have a defined + * slave address but SMBIOS does. Pick it up from + * any source that has it available. + */ + if (info->slave_addr && !e->slave_addr) + e->slave_addr = info->slave_addr; return 0; + } } return 1; diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c index 04232431eaf7..cca6e5bc1cea 100644 --- a/drivers/char/ipmi/ipmi_ssif.c +++ b/drivers/char/ipmi/ipmi_ssif.c @@ -174,7 +174,6 @@ enum ssif_stat_indexes { }; struct ssif_addr_info { - unsigned short addr; struct i2c_board_info binfo; char *adapter_name; int debug; @@ -1401,6 +1400,34 @@ static bool check_acpi(struct ssif_info *ssif_info, struct device *dev) return false; } +static int find_slave_address(struct i2c_client *client, int slave_addr) +{ + struct ssif_addr_info *info; + + if (slave_addr) + return slave_addr; + + /* + * Came in without a slave address, search around to see if + * the other sources have a slave address. This lets us pick + * up an SMBIOS slave address when using ACPI. + */ + list_for_each_entry(info, &ssif_infos, link) { + if (info->binfo.addr != client->addr) + continue; + if (info->adapter_name && client->adapter->name && + strcmp_nospace(info->adapter_name, + client->adapter->name)) + continue; + if (info->slave_addr) { + slave_addr = info->slave_addr; + break; + } + } + + return slave_addr; +} + /* * Global enables we care about. */ @@ -1443,6 +1470,8 @@ static int ssif_probe(struct i2c_client *client, const struct i2c_device_id *id) } } + slave_addr = find_slave_address(client, slave_addr); + pr_info(PFX "Trying %s-specified SSIF interface at i2c address 0x%x, adapter %s, slave address 0x%x\n", ipmi_addr_src_to_str(ssif_info->addr_source), client->addr, client->adapter->name, slave_addr); @@ -1931,7 +1960,7 @@ static int decode_dmi(const struct dmi_device *dmi_dev) slave_addr = data[6]; } - return new_ssif_client(myaddr, NULL, 0, 0, SI_SMBIOS); + return new_ssif_client(myaddr, NULL, 0, slave_addr, SI_SMBIOS); } static void dmi_iterator(void) -- cgit v1.2.3 From a24b5dd5eda73b956da27031cefbe4374b6af2bc Mon Sep 17 00:00:00 2001 From: Corey Minyard Date: Mon, 14 Nov 2016 10:11:30 -0600 Subject: ipmi: Fix sequence number handling The IPMI message handler uses a message id that the lower-layer preserved to track the sequence number of the message. The macros that handled these sequence numbers were somewhat broken as they could result in sequence number truncation and they were not doing an "and" of the proper number of bits. I think this actually is not a problem, because the truncation should be harmless and the improper "and" didn't hurt anything because sequence number generation used the same improper "and" and wouldn't generate a sequence number that would get truncated wrong. However, it should be fixed. Reported-by: Dan Carpenter Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_msghandler.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index fcdd886819f5..be982d10d305 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -158,15 +158,16 @@ struct seq_table { * Store the information in a msgid (long) to allow us to find a * sequence table entry from the msgid. */ -#define STORE_SEQ_IN_MSGID(seq, seqid) (((seq&0xff)<<26) | (seqid&0x3ffffff)) +#define STORE_SEQ_IN_MSGID(seq, seqid) \ + ((((seq) & 0x3f) << 26) | ((seqid) & 0x3ffffff)) #define GET_SEQ_FROM_MSGID(msgid, seq, seqid) \ do { \ - seq = ((msgid >> 26) & 0x3f); \ - seqid = (msgid & 0x3fffff); \ + seq = (((msgid) >> 26) & 0x3f); \ + seqid = ((msgid) & 0x3ffffff); \ } while (0) -#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3fffff) +#define NEXT_SEQID(seqid) (((seqid) + 1) & 0x3ffffff) struct ipmi_channel { unsigned char medium; -- cgit v1.2.3 From 7184bc2ddb15d9539c701668d6a5be1574efa6a5 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Nov 2016 23:27:38 +0800 Subject: cxl: drop duplicate header sched.h Drop duplicate header sched.h from native.c. Signed-off-by: Geliang Tang Reviewed-by: Andrew Donnellan Signed-off-by: Michael Ellerman --- drivers/misc/cxl/native.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c index c1216d31796c..09505f432eda 100644 --- a/drivers/misc/cxl/native.c +++ b/drivers/misc/cxl/native.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 85f57752b33cf12f1d583f0c10b752292de00abe Mon Sep 17 00:00:00 2001 From: Nandor Han Date: Tue, 11 Oct 2016 14:13:41 +0300 Subject: dmaengine: imx-sdma - correct the dma transfer residue calculation The residue calculation was taking in consideration that dma transaction status will be always retrieved in the dma callback used to inform that dma transfer is complete. However this is not the case for all subsystems that use dma. Some subsystems use a timer to check the dma status periodically. Therefore the calculation was updated and residue is calculated accordingly by a) update the residue calculation taking in consideration the last used buffer index by using *buf_ptail* variable and b) chn_real_count (number of bytes transferred) is initialized to zero, when dma channel is created, to avoid using an uninitialized value in residue calculation when dma status is checked without waiting dma complete event. Signed-off-by: Nandor Han Acked-by: Peter Senna Tschudin Tested-by: Peter Senna Tschudin Tested-by: Marek Vasut Signed-off-by: Vinod Koul --- drivers/dma/imx-sdma.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c index b9629b2bfc05..d1651a50c349 100644 --- a/drivers/dma/imx-sdma.c +++ b/drivers/dma/imx-sdma.c @@ -298,6 +298,7 @@ struct sdma_engine; * @event_id1 for channels that use 2 events * @word_size peripheral access size * @buf_tail ID of the buffer that was processed + * @buf_ptail ID of the previous buffer that was processed * @num_bd max NUM_BD. number of descriptors currently handling */ struct sdma_channel { @@ -309,6 +310,7 @@ struct sdma_channel { unsigned int event_id1; enum dma_slave_buswidth word_size; unsigned int buf_tail; + unsigned int buf_ptail; unsigned int num_bd; unsigned int period_len; struct sdma_buffer_descriptor *bd; @@ -700,6 +702,8 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac) sdmac->chn_real_count = bd->mode.count; bd->mode.status |= BD_DONE; bd->mode.count = sdmac->period_len; + sdmac->buf_ptail = sdmac->buf_tail; + sdmac->buf_tail = (sdmac->buf_tail + 1) % sdmac->num_bd; /* * The callback is called from the interrupt context in order @@ -710,9 +714,6 @@ static void sdma_update_channel_loop(struct sdma_channel *sdmac) dmaengine_desc_get_callback_invoke(&sdmac->desc, NULL); - sdmac->buf_tail++; - sdmac->buf_tail %= sdmac->num_bd; - if (error) sdmac->status = old_status; } @@ -1186,6 +1187,8 @@ static struct dma_async_tx_descriptor *sdma_prep_slave_sg( sdmac->flags = 0; sdmac->buf_tail = 0; + sdmac->buf_ptail = 0; + sdmac->chn_real_count = 0; dev_dbg(sdma->dev, "setting up %d entries for channel %d.\n", sg_len, channel); @@ -1288,6 +1291,8 @@ static struct dma_async_tx_descriptor *sdma_prep_dma_cyclic( sdmac->status = DMA_IN_PROGRESS; sdmac->buf_tail = 0; + sdmac->buf_ptail = 0; + sdmac->chn_real_count = 0; sdmac->period_len = period_len; sdmac->flags |= IMX_DMA_SG_LOOP; @@ -1385,7 +1390,7 @@ static enum dma_status sdma_tx_status(struct dma_chan *chan, u32 residue; if (sdmac->flags & IMX_DMA_SG_LOOP) - residue = (sdmac->num_bd - sdmac->buf_tail) * + residue = (sdmac->num_bd - sdmac->buf_ptail) * sdmac->period_len - sdmac->chn_real_count; else residue = sdmac->chn_count - sdmac->chn_real_count; -- cgit v1.2.3 From e9bb8a9df316a2480d316af7b242f40cba3b69b6 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 26 Oct 2016 18:18:21 +0300 Subject: dmaengine: hsu: pci: switch to new API for IRQ allocation There is new API in place which provides allocation mechanism of interrupts for PCI devices. Use it in the HSU DMA driver. Signed-off-by: Andy Shevchenko Signed-off-by: Vinod Koul --- drivers/dma/hsu/pci.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/hsu/pci.c b/drivers/dma/hsu/pci.c index b51639f045ed..4875fa428e81 100644 --- a/drivers/dma/hsu/pci.c +++ b/drivers/dma/hsu/pci.c @@ -77,13 +77,15 @@ static int hsu_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) if (!chip) return -ENOMEM; + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + chip->dev = &pdev->dev; chip->regs = pcim_iomap_table(pdev)[0]; chip->length = pci_resource_len(pdev, 0); chip->offset = HSU_PCI_CHAN_OFFSET; - chip->irq = pdev->irq; - - pci_enable_msi(pdev); + chip->irq = pci_irq_vector(pdev, 0); ret = hsu_dma_probe(chip); if (ret) -- cgit v1.2.3 From c5db858bdfeff00c219c64a95338c1eb5460555c Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Wed, 26 Oct 2016 10:10:25 +0200 Subject: dmaengine: mv_xor: Add support for scatter-gather DMA mode This patch adds memory to memory scatter-gather support to the Marvell mv_or DMA driver. Signed-off-by: Stefan Roese Cc: Gregory CLEMENT Cc: Thomas Petazzoni Cc: Marcin Wojtas Cc: Arnd Bergmann Cc: Vinod Koul Signed-off-by: Vinod Koul --- drivers/dma/mv_xor.c | 183 +++++++++++++++++++++++++++++++++++++++++++++++++-- drivers/dma/mv_xor.h | 1 + 2 files changed, 180 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index 23f75285a4d9..b0d09d97535f 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -68,6 +68,36 @@ static void mv_desc_init(struct mv_xor_desc_slot *desc, hw_desc->byte_count = byte_count; } +/* Populate the descriptor */ +static void mv_xor_config_sg_ll_desc(struct mv_xor_desc_slot *desc, + dma_addr_t dma_src, dma_addr_t dma_dst, + u32 len, struct mv_xor_desc_slot *prev) +{ + struct mv_xor_desc *hw_desc = desc->hw_desc; + + hw_desc->status = XOR_DESC_DMA_OWNED; + hw_desc->phy_next_desc = 0; + /* Configure for XOR with only one src address -> MEMCPY */ + hw_desc->desc_command = XOR_DESC_OPERATION_XOR | (0x1 << 0); + hw_desc->phy_dest_addr = dma_dst; + hw_desc->phy_src_addr[0] = dma_src; + hw_desc->byte_count = len; + + if (prev) { + struct mv_xor_desc *hw_prev = prev->hw_desc; + + hw_prev->phy_next_desc = desc->async_tx.phys; + } +} + +static void mv_xor_desc_config_eod(struct mv_xor_desc_slot *desc) +{ + struct mv_xor_desc *hw_desc = desc->hw_desc; + + /* Enable end-of-descriptor interrupt */ + hw_desc->desc_command |= XOR_DESC_EOD_INT_EN; +} + static void mv_desc_set_mode(struct mv_xor_desc_slot *desc) { struct mv_xor_desc *hw_desc = desc->hw_desc; @@ -228,8 +258,13 @@ mv_chan_clean_completed_slots(struct mv_xor_chan *mv_chan) list_for_each_entry_safe(iter, _iter, &mv_chan->completed_slots, node) { - if (async_tx_test_ack(&iter->async_tx)) + if (async_tx_test_ack(&iter->async_tx)) { list_move_tail(&iter->node, &mv_chan->free_slots); + if (!list_empty(&iter->sg_tx_list)) { + list_splice_tail_init(&iter->sg_tx_list, + &mv_chan->free_slots); + } + } } return 0; } @@ -244,11 +279,20 @@ mv_desc_clean_slot(struct mv_xor_desc_slot *desc, /* the client is allowed to attach dependent operations * until 'ack' is set */ - if (!async_tx_test_ack(&desc->async_tx)) + if (!async_tx_test_ack(&desc->async_tx)) { /* move this slot to the completed_slots */ list_move_tail(&desc->node, &mv_chan->completed_slots); - else + if (!list_empty(&desc->sg_tx_list)) { + list_splice_tail_init(&desc->sg_tx_list, + &mv_chan->completed_slots); + } + } else { list_move_tail(&desc->node, &mv_chan->free_slots); + if (!list_empty(&desc->sg_tx_list)) { + list_splice_tail_init(&desc->sg_tx_list, + &mv_chan->free_slots); + } + } return 0; } @@ -450,6 +494,7 @@ static int mv_xor_alloc_chan_resources(struct dma_chan *chan) dma_async_tx_descriptor_init(&slot->async_tx, chan); slot->async_tx.tx_submit = mv_xor_tx_submit; INIT_LIST_HEAD(&slot->node); + INIT_LIST_HEAD(&slot->sg_tx_list); dma_desc = mv_chan->dma_desc_pool; slot->async_tx.phys = dma_desc + idx * MV_XOR_SLOT_SIZE; slot->idx = idx++; @@ -617,6 +662,132 @@ mv_xor_prep_dma_interrupt(struct dma_chan *chan, unsigned long flags) return mv_xor_prep_dma_xor(chan, dest, &src, 1, len, flags); } +/** + * mv_xor_prep_dma_sg - prepare descriptors for a memory sg transaction + * @chan: DMA channel + * @dst_sg: Destination scatter list + * @dst_sg_len: Number of entries in destination scatter list + * @src_sg: Source scatter list + * @src_sg_len: Number of entries in source scatter list + * @flags: transfer ack flags + * + * Return: Async transaction descriptor on success and NULL on failure + */ +static struct dma_async_tx_descriptor * +mv_xor_prep_dma_sg(struct dma_chan *chan, struct scatterlist *dst_sg, + unsigned int dst_sg_len, struct scatterlist *src_sg, + unsigned int src_sg_len, unsigned long flags) +{ + struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); + struct mv_xor_desc_slot *new; + struct mv_xor_desc_slot *first = NULL; + struct mv_xor_desc_slot *prev = NULL; + size_t len, dst_avail, src_avail; + dma_addr_t dma_dst, dma_src; + int desc_cnt = 0; + int ret; + + dev_dbg(mv_chan_to_devp(mv_chan), + "%s dst_sg_len: %d src_sg_len: %d flags: %ld\n", + __func__, dst_sg_len, src_sg_len, flags); + + dst_avail = sg_dma_len(dst_sg); + src_avail = sg_dma_len(src_sg); + + /* Run until we are out of scatterlist entries */ + while (true) { + /* Allocate and populate the descriptor */ + desc_cnt++; + new = mv_chan_alloc_slot(mv_chan); + if (!new) { + dev_err(mv_chan_to_devp(mv_chan), + "Out of descriptors (desc_cnt=%d)!\n", + desc_cnt); + goto err; + } + + len = min_t(size_t, src_avail, dst_avail); + len = min_t(size_t, len, MV_XOR_MAX_BYTE_COUNT); + if (len == 0) + goto fetch; + + if (len < MV_XOR_MIN_BYTE_COUNT) { + dev_err(mv_chan_to_devp(mv_chan), + "Transfer size of %zu too small!\n", len); + goto err; + } + + dma_dst = sg_dma_address(dst_sg) + sg_dma_len(dst_sg) - + dst_avail; + dma_src = sg_dma_address(src_sg) + sg_dma_len(src_sg) - + src_avail; + + /* Check if a new window needs to get added for 'dst' */ + ret = mv_xor_add_io_win(mv_chan, dma_dst); + if (ret) + goto err; + + /* Check if a new window needs to get added for 'src' */ + ret = mv_xor_add_io_win(mv_chan, dma_src); + if (ret) + goto err; + + /* Populate the descriptor */ + mv_xor_config_sg_ll_desc(new, dma_src, dma_dst, len, prev); + prev = new; + dst_avail -= len; + src_avail -= len; + + if (!first) + first = new; + else + list_move_tail(&new->node, &first->sg_tx_list); + +fetch: + /* Fetch the next dst scatterlist entry */ + if (dst_avail == 0) { + if (dst_sg_len == 0) + break; + + /* Fetch the next entry: if there are no more: done */ + dst_sg = sg_next(dst_sg); + if (dst_sg == NULL) + break; + + dst_sg_len--; + dst_avail = sg_dma_len(dst_sg); + } + + /* Fetch the next src scatterlist entry */ + if (src_avail == 0) { + if (src_sg_len == 0) + break; + + /* Fetch the next entry: if there are no more: done */ + src_sg = sg_next(src_sg); + if (src_sg == NULL) + break; + + src_sg_len--; + src_avail = sg_dma_len(src_sg); + } + } + + /* Set the EOD flag in the last descriptor */ + mv_xor_desc_config_eod(new); + first->async_tx.flags = flags; + + return &first->async_tx; + +err: + /* Cleanup: Move all descriptors back into the free list */ + spin_lock_bh(&mv_chan->lock); + mv_desc_clean_slot(first, mv_chan); + spin_unlock_bh(&mv_chan->lock); + + return NULL; +} + static void mv_xor_free_chan_resources(struct dma_chan *chan) { struct mv_xor_chan *mv_chan = to_mv_xor_chan(chan); @@ -1083,6 +1254,8 @@ mv_xor_channel_add(struct mv_xor_device *xordev, dma_dev->device_prep_dma_interrupt = mv_xor_prep_dma_interrupt; if (dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask)) dma_dev->device_prep_dma_memcpy = mv_xor_prep_dma_memcpy; + if (dma_has_cap(DMA_SG, dma_dev->cap_mask)) + dma_dev->device_prep_dma_sg = mv_xor_prep_dma_sg; if (dma_has_cap(DMA_XOR, dma_dev->cap_mask)) { dma_dev->max_xor = 8; dma_dev->device_prep_dma_xor = mv_xor_prep_dma_xor; @@ -1132,10 +1305,11 @@ mv_xor_channel_add(struct mv_xor_device *xordev, goto err_free_irq; } - dev_info(&pdev->dev, "Marvell XOR (%s): ( %s%s%s)\n", + dev_info(&pdev->dev, "Marvell XOR (%s): ( %s%s%s%s)\n", mv_chan->op_in_desc ? "Descriptor Mode" : "Registers Mode", dma_has_cap(DMA_XOR, dma_dev->cap_mask) ? "xor " : "", dma_has_cap(DMA_MEMCPY, dma_dev->cap_mask) ? "cpy " : "", + dma_has_cap(DMA_SG, dma_dev->cap_mask) ? "sg " : "", dma_has_cap(DMA_INTERRUPT, dma_dev->cap_mask) ? "intr " : ""); dma_async_device_register(dma_dev); @@ -1378,6 +1552,7 @@ static int mv_xor_probe(struct platform_device *pdev) dma_cap_zero(cap_mask); dma_cap_set(DMA_MEMCPY, cap_mask); + dma_cap_set(DMA_SG, cap_mask); dma_cap_set(DMA_XOR, cap_mask); dma_cap_set(DMA_INTERRUPT, cap_mask); diff --git a/drivers/dma/mv_xor.h b/drivers/dma/mv_xor.h index 88eeab222a23..cf921dd6af73 100644 --- a/drivers/dma/mv_xor.h +++ b/drivers/dma/mv_xor.h @@ -148,6 +148,7 @@ struct mv_xor_chan { */ struct mv_xor_desc_slot { struct list_head node; + struct list_head sg_tx_list; enum dma_transaction_type type; void *hw_desc; u16 idx; -- cgit v1.2.3 From 812608d1961c48916c758df60eef7abd8ff8b59e Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Fri, 18 Nov 2016 22:12:26 +0800 Subject: dmaengine: mv_xor: use builtin_platform_driver Use builtin_platform_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Vinod Koul --- drivers/dma/mv_xor.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c index b0d09d97535f..0cb951b743a6 100644 --- a/drivers/dma/mv_xor.c +++ b/drivers/dma/mv_xor.c @@ -1630,12 +1630,7 @@ static struct platform_driver mv_xor_driver = { }, }; - -static int __init mv_xor_init(void) -{ - return platform_driver_register(&mv_xor_driver); -} -device_initcall(mv_xor_init); +builtin_platform_driver(mv_xor_driver); /* MODULE_AUTHOR("Saeed Bishara "); -- cgit v1.2.3 From 644e906f923957557369d7f50ab72d5d9cc3cf28 Mon Sep 17 00:00:00 2001 From: Hao Zhang Date: Sun, 20 Nov 2016 00:43:56 +0800 Subject: dmaengine: sun6i: fix the uninitialized value for v_lli dma_pool_alloc does not initialize the value of the newly allocated block for the v_lli, and the uninitilize value make the tests failed which is on pine64 with dmatest. we can fix it just change the "|=" to "=" for the v_lli->cfg. Signed-off-by: Hao Zhang Signed-off-by: Vinod Koul --- drivers/dma/sun6i-dma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c index 83461994e418..a2358780ab2c 100644 --- a/drivers/dma/sun6i-dma.c +++ b/drivers/dma/sun6i-dma.c @@ -578,7 +578,7 @@ static struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( burst = convert_burst(8); width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES); - v_lli->cfg |= DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) | + v_lli->cfg = DMA_CHAN_CFG_SRC_DRQ(DRQ_SDRAM) | DMA_CHAN_CFG_DST_DRQ(DRQ_SDRAM) | DMA_CHAN_CFG_DST_LINEAR_MODE | DMA_CHAN_CFG_SRC_LINEAR_MODE | -- cgit v1.2.3 From efb9ab67255fc2333293827f8c45d2f51647faf9 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 19 Nov 2016 12:56:58 -0200 Subject: [media] dvb_net: prepare to split a very complex function The dvb_net code has a really complex function, meant to handle DVB network packages: it is long, has several loops and ifs inside, and even cause warnings with gcc5. Prepare it to be split into smaller functions by storing all arguments and internal vars inside a struct. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_net.c | 465 +++++++++++++++++++++------------------ 1 file changed, 245 insertions(+), 220 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index b9a46d5a1bb5..6fef0fc61cd2 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -311,323 +311,348 @@ static inline void reset_ule( struct dvb_net_priv *p ) * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of * TS cells of a single PID. */ -static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) -{ - struct dvb_net_priv *priv = netdev_priv(dev); - unsigned long skipped = 0L; - const u8 *ts, *ts_end, *from_where = NULL; - u8 ts_remain = 0, how_much = 0, new_ts = 1; - struct ethhdr *ethh = NULL; - bool error = false; +struct dvb_net_ule_handle { + struct net_device *dev; + struct dvb_net_priv *priv; + struct ethhdr *ethh; + const u8 *buf; + size_t buf_len; + unsigned long skipped; + const u8 *ts, *ts_end, *from_where; + u8 ts_remain, how_much, new_ts; + bool error; #ifdef ULE_DEBUG - /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */ + /* + * The code inside ULE_DEBUG keeps a history of the + * last 100 TS cells processed. + */ static unsigned char ule_hist[100*TS_SZ]; static unsigned char *ule_where = ule_hist, ule_dump; #endif +}; + +static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) +{ + struct dvb_net_ule_handle h = { + .dev = dev, + .buf = buf, + .buf_len = buf_len, + .skipped = 0L, + .ts = NULL, + .ts_end = NULL, + .from_where = NULL, + .ts_remain = 0, + .how_much = 0, + .new_ts = 1, + .ethh = NULL, + .error = false, +#ifdef ULE_DEBUG + .ule_where = ule_hist, +#endif + }; /* For all TS cells in current buffer. * Appearently, we are called for every single TS cell. */ - for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) { - - if (new_ts) { + for (h.ts = h.buf, h.ts_end = h.buf + h.buf_len; h.ts < h.ts_end; /* no incr. */ ) { + if (h.new_ts) { /* We are about to process a new TS cell. */ #ifdef ULE_DEBUG - if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist; - memcpy( ule_where, ts, TS_SZ ); - if (ule_dump) { - hexdump( ule_where, TS_SZ ); - ule_dump = 0; + if (h.ule_where >= &h.ule_hist[100*TS_SZ]) h.ule_where = h.ule_hist; + memcpy( h.ule_where, h.ts, TS_SZ ); + if (h.ule_dump) { + hexdump( h.ule_where, TS_SZ ); + h.ule_dump = 0; } - ule_where += TS_SZ; + h.ule_where += TS_SZ; #endif - /* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */ - if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) { + /* Check TS h.error conditions: sync_byte, transport_error_indicator, scrambling_control . */ + if ((h.ts[0] != TS_SYNC) || (h.ts[1] & TS_TEI) || ((h.ts[3] & TS_SC) != 0)) { pr_warn("%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", - priv->ts_count, ts[0], - (ts[1] & TS_TEI) >> 7, - (ts[3] & TS_SC) >> 6); + h.priv->ts_count, h.ts[0], + (h.ts[1] & TS_TEI) >> 7, + (h.ts[3] & TS_SC) >> 6); /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (priv->ule_skb) { - dev_kfree_skb( priv->ule_skb ); + if (h.priv->ule_skb) { + dev_kfree_skb( h.priv->ule_skb ); /* Prepare for next SNDU. */ - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; + h.dev->stats.rx_errors++; + h.dev->stats.rx_frame_errors++; } - reset_ule(priv); - priv->need_pusi = 1; + reset_ule(h.priv); + h.priv->need_pusi = 1; /* Continue with next TS cell. */ - ts += TS_SZ; - priv->ts_count++; + h.ts += TS_SZ; + h.priv->ts_count++; continue; } - ts_remain = 184; - from_where = ts + 4; + h.ts_remain = 184; + h.from_where = h.ts + 4; } /* Synchronize on PUSI, if required. */ - if (priv->need_pusi) { - if (ts[1] & TS_PUSI) { + if (h.priv->need_pusi) { + if (h.ts[1] & TS_PUSI) { /* Find beginning of first ULE SNDU in current TS cell. */ /* Synchronize continuity counter. */ - priv->tscc = ts[3] & 0x0F; + h.priv->tscc = h.ts[3] & 0x0F; /* There is a pointer field here. */ - if (ts[4] > ts_remain) { + if (h.ts[4] > h.ts_remain) { pr_err("%lu: Invalid ULE packet (pointer field %d)\n", - priv->ts_count, ts[4]); - ts += TS_SZ; - priv->ts_count++; + h.priv->ts_count, h.ts[4]); + h.ts += TS_SZ; + h.priv->ts_count++; continue; } /* Skip to destination of pointer field. */ - from_where = &ts[5] + ts[4]; - ts_remain -= 1 + ts[4]; - skipped = 0; + h.from_where = &h.ts[5] + h.ts[4]; + h.ts_remain -= 1 + h.ts[4]; + h.skipped = 0; } else { - skipped++; - ts += TS_SZ; - priv->ts_count++; + h.skipped++; + h.ts += TS_SZ; + h.priv->ts_count++; continue; } } - if (new_ts) { + if (h.new_ts) { /* Check continuity counter. */ - if ((ts[3] & 0x0F) == priv->tscc) - priv->tscc = (priv->tscc + 1) & 0x0F; + if ((h.ts[3] & 0x0F) == h.priv->tscc) + h.priv->tscc = (h.priv->tscc + 1) & 0x0F; else { /* TS discontinuity handling: */ pr_warn("%lu: TS discontinuity: got %#x, expected %#x.\n", - priv->ts_count, ts[3] & 0x0F, - priv->tscc); + h.priv->ts_count, h.ts[3] & 0x0F, + h.priv->tscc); /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (priv->ule_skb) { - dev_kfree_skb( priv->ule_skb ); + if (h.priv->ule_skb) { + dev_kfree_skb( h.priv->ule_skb ); /* Prepare for next SNDU. */ - // reset_ule(priv); moved to below. - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; + // reset_ule(h.priv); moved to below. + h.dev->stats.rx_errors++; + h.dev->stats.rx_frame_errors++; } - reset_ule(priv); + reset_ule(h.priv); /* skip to next PUSI. */ - priv->need_pusi = 1; + h.priv->need_pusi = 1; continue; } /* If we still have an incomplete payload, but PUSI is * set; some TS cells are missing. * This is only possible here, if we missed exactly 16 TS * cells (continuity counter wrap). */ - if (ts[1] & TS_PUSI) { - if (! priv->need_pusi) { - if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) { + if (h.ts[1] & TS_PUSI) { + if (! h.priv->need_pusi) { + if (!(*h.from_where < (h.ts_remain-1)) || *h.from_where != h.priv->ule_sndu_remain) { /* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */ pr_warn("%lu: Invalid pointer field: %u.\n", - priv->ts_count, - *from_where); + h.priv->ts_count, + *h.from_where); /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (priv->ule_skb) { - error = true; - dev_kfree_skb(priv->ule_skb); + if (h.priv->ule_skb) { + h.error = true; + dev_kfree_skb(h.priv->ule_skb); } - if (error || priv->ule_sndu_remain) { - dev->stats.rx_errors++; - dev->stats.rx_frame_errors++; - error = false; + if (h.error || h.priv->ule_sndu_remain) { + h.dev->stats.rx_errors++; + h.dev->stats.rx_frame_errors++; + h.error = false; } - reset_ule(priv); - priv->need_pusi = 1; + reset_ule(h.priv); + h.priv->need_pusi = 1; continue; } /* Skip pointer field (we're processing a * packed payload). */ - from_where += 1; - ts_remain -= 1; + h.from_where += 1; + h.ts_remain -= 1; } else - priv->need_pusi = 0; + h.priv->need_pusi = 0; - if (priv->ule_sndu_remain > 183) { + if (h.priv->ule_sndu_remain > 183) { /* Current SNDU lacks more data than there could be available in the * current TS cell. */ - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - pr_warn("%lu: Expected %d more SNDU bytes, but got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", - priv->ts_count, - priv->ule_sndu_remain, - ts[4], ts_remain); - dev_kfree_skb(priv->ule_skb); + h.dev->stats.rx_errors++; + h.dev->stats.rx_length_errors++; + pr_warn("%lu: Expected %d more SNDU bytes, but got PUSI (pf %d, h.ts_remain %d). Flushing incomplete payload.\n", + h.priv->ts_count, + h.priv->ule_sndu_remain, + h.ts[4], h.ts_remain); + dev_kfree_skb(h.priv->ule_skb); /* Prepare for next SNDU. */ - reset_ule(priv); + reset_ule(h.priv); /* Resync: go to where pointer field points to: start of next ULE SNDU. */ - from_where += ts[4]; - ts_remain -= ts[4]; + h.from_where += h.ts[4]; + h.ts_remain -= h.ts[4]; } } } /* Check if new payload needs to be started. */ - if (priv->ule_skb == NULL) { + if (h.priv->ule_skb == NULL) { /* Start a new payload with skb. * Find ULE header. It is only guaranteed that the * length field (2 bytes) is contained in the current * TS. - * Check ts_remain has to be >= 2 here. */ - if (ts_remain < 2) { + * Check h.ts_remain has to be >= 2 here. */ + if (h.ts_remain < 2) { pr_warn("Invalid payload packing: only %d bytes left in TS. Resyncing.\n", - ts_remain); - priv->ule_sndu_len = 0; - priv->need_pusi = 1; - ts += TS_SZ; + h.ts_remain); + h.priv->ule_sndu_len = 0; + h.priv->need_pusi = 1; + h.ts += TS_SZ; continue; } - if (! priv->ule_sndu_len) { + if (! h.priv->ule_sndu_len) { /* Got at least two bytes, thus extrace the SNDU length. */ - priv->ule_sndu_len = from_where[0] << 8 | from_where[1]; - if (priv->ule_sndu_len & 0x8000) { + h.priv->ule_sndu_len = h.from_where[0] << 8 | h.from_where[1]; + if (h.priv->ule_sndu_len & 0x8000) { /* D-Bit is set: no dest mac present. */ - priv->ule_sndu_len &= 0x7FFF; - priv->ule_dbit = 1; + h.priv->ule_sndu_len &= 0x7FFF; + h.priv->ule_dbit = 1; } else - priv->ule_dbit = 0; + h.priv->ule_dbit = 0; - if (priv->ule_sndu_len < 5) { + if (h.priv->ule_sndu_len < 5) { pr_warn("%lu: Invalid ULE SNDU length %u. Resyncing.\n", - priv->ts_count, - priv->ule_sndu_len); - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - priv->ule_sndu_len = 0; - priv->need_pusi = 1; - new_ts = 1; - ts += TS_SZ; - priv->ts_count++; + h.priv->ts_count, + h.priv->ule_sndu_len); + h.dev->stats.rx_errors++; + h.dev->stats.rx_length_errors++; + h.priv->ule_sndu_len = 0; + h.priv->need_pusi = 1; + h.new_ts = 1; + h.ts += TS_SZ; + h.priv->ts_count++; continue; } - ts_remain -= 2; /* consume the 2 bytes SNDU length. */ - from_where += 2; + h.ts_remain -= 2; /* consume the 2 bytes SNDU length. */ + h.from_where += 2; } - priv->ule_sndu_remain = priv->ule_sndu_len + 2; + h.priv->ule_sndu_remain = h.priv->ule_sndu_len + 2; /* * State of current TS: - * ts_remain (remaining bytes in the current TS cell) + * h.ts_remain (remaining bytes in the current TS cell) * 0 ule_type is not available now, we need the next TS cell * 1 the first byte of the ule_type is present * >=2 full ULE header present, maybe some payload data as well. */ - switch (ts_remain) { + switch (h.ts_remain) { case 1: - priv->ule_sndu_remain--; - priv->ule_sndu_type = from_where[0] << 8; - priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ - ts_remain -= 1; from_where += 1; + h.priv->ule_sndu_remain--; + h.priv->ule_sndu_type = h.from_where[0] << 8; + h.priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ + h.ts_remain -= 1; h.from_where += 1; /* Continue w/ next TS. */ case 0: - new_ts = 1; - ts += TS_SZ; - priv->ts_count++; + h.new_ts = 1; + h.ts += TS_SZ; + h.priv->ts_count++; continue; default: /* complete ULE header is present in current TS. */ /* Extract ULE type field. */ - if (priv->ule_sndu_type_1) { - priv->ule_sndu_type_1 = 0; - priv->ule_sndu_type |= from_where[0]; - from_where += 1; /* points to payload start. */ - ts_remain -= 1; + if (h.priv->ule_sndu_type_1) { + h.priv->ule_sndu_type_1 = 0; + h.priv->ule_sndu_type |= h.from_where[0]; + h.from_where += 1; /* points to payload start. */ + h.ts_remain -= 1; } else { /* Complete type is present in new TS. */ - priv->ule_sndu_type = from_where[0] << 8 | from_where[1]; - from_where += 2; /* points to payload start. */ - ts_remain -= 2; + h.priv->ule_sndu_type = h.from_where[0] << 8 | h.from_where[1]; + h.from_where += 2; /* points to payload start. */ + h.ts_remain -= 2; } break; } /* Allocate the skb (decoder target buffer) with the correct size, as follows: * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */ - priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN ); - if (priv->ule_skb == NULL) { + h.priv->ule_skb = dev_alloc_skb( h.priv->ule_sndu_len + ETH_HLEN + ETH_ALEN ); + if (h.priv->ule_skb == NULL) { pr_notice("%s: Memory squeeze, dropping packet.\n", - dev->name); - dev->stats.rx_dropped++; + h.dev->name); + h.dev->stats.rx_dropped++; return; } /* This includes the CRC32 _and_ dest mac, if !dbit. */ - priv->ule_sndu_remain = priv->ule_sndu_len; - priv->ule_skb->dev = dev; + h.priv->ule_sndu_remain = h.priv->ule_sndu_len; + h.priv->ule_skb->dev = h.dev; /* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */ - skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN ); + skb_reserve( h.priv->ule_skb, ETH_HLEN + ETH_ALEN ); } /* Copy data into our current skb. */ - how_much = min(priv->ule_sndu_remain, (int)ts_remain); - memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much); - priv->ule_sndu_remain -= how_much; - ts_remain -= how_much; - from_where += how_much; + h.how_much = min(h.priv->ule_sndu_remain, (int)h.ts_remain); + memcpy(skb_put(h.priv->ule_skb, h.how_much), h.from_where, h.how_much); + h.priv->ule_sndu_remain -= h.how_much; + h.ts_remain -= h.how_much; + h.from_where += h.how_much; /* Check for complete payload. */ - if (priv->ule_sndu_remain <= 0) { + if (h.priv->ule_sndu_remain <= 0) { /* Check CRC32, we've got it in our skb already. */ - __be16 ulen = htons(priv->ule_sndu_len); - __be16 utype = htons(priv->ule_sndu_type); + __be16 ulen = htons(h.priv->ule_sndu_len); + __be16 utype = htons(h.priv->ule_sndu_type); const u8 *tail; struct kvec iov[3] = { { &ulen, sizeof ulen }, { &utype, sizeof utype }, - { priv->ule_skb->data, priv->ule_skb->len - 4 } + { h.priv->ule_skb->data, h.priv->ule_skb->len - 4 } }; u32 ule_crc = ~0L, expected_crc; - if (priv->ule_dbit) { + if (h.priv->ule_dbit) { /* Set D-bit for CRC32 verification, * if it was set originally. */ ulen |= htons(0x8000); } ule_crc = iov_crc32(ule_crc, iov, 3); - tail = skb_tail_pointer(priv->ule_skb); + tail = skb_tail_pointer(h.priv->ule_skb); expected_crc = *(tail - 4) << 24 | *(tail - 3) << 16 | *(tail - 2) << 8 | *(tail - 1); if (ule_crc != expected_crc) { - pr_warn("%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", - priv->ts_count, ule_crc, expected_crc, - priv->ule_sndu_len, priv->ule_sndu_type, - ts_remain, - ts_remain > 2 ? *(unsigned short *)from_where : 0); + pr_warn("%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, h.ts_remain %d, next 2: %x.\n", + h.priv->ts_count, ule_crc, expected_crc, + h.priv->ule_sndu_len, h.priv->ule_sndu_type, + h.ts_remain, + h.ts_remain > 2 ? *(unsigned short *)h.from_where : 0); #ifdef ULE_DEBUG hexdump( iov[0].iov_base, iov[0].iov_len ); hexdump( iov[1].iov_base, iov[1].iov_len ); hexdump( iov[2].iov_base, iov[2].iov_len ); - if (ule_where == ule_hist) { - hexdump( &ule_hist[98*TS_SZ], TS_SZ ); - hexdump( &ule_hist[99*TS_SZ], TS_SZ ); - } else if (ule_where == &ule_hist[TS_SZ]) { - hexdump( &ule_hist[99*TS_SZ], TS_SZ ); - hexdump( ule_hist, TS_SZ ); + if (h.ule_where == h.ule_hist) { + hexdump( &h.ule_hist[98*TS_SZ], TS_SZ ); + hexdump( &h.ule_hist[99*TS_SZ], TS_SZ ); + } else if (h.ule_where == &h.ule_hist[TS_SZ]) { + hexdump( &h.ule_hist[99*TS_SZ], TS_SZ ); + hexdump( h.ule_hist, TS_SZ ); } else { - hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ ); - hexdump( ule_where - TS_SZ, TS_SZ ); + hexdump( h.ule_where - TS_SZ - TS_SZ, TS_SZ ); + hexdump( h.ule_where - TS_SZ, TS_SZ ); } - ule_dump = 1; + h.ule_dump = 1; #endif - dev->stats.rx_errors++; - dev->stats.rx_crc_errors++; - dev_kfree_skb(priv->ule_skb); + h.dev->stats.rx_errors++; + h.dev->stats.rx_crc_errors++; + dev_kfree_skb(h.priv->ule_skb); } else { /* CRC32 verified OK. */ u8 dest_addr[ETH_ALEN]; @@ -635,10 +660,10 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) { [ 0 ... ETH_ALEN-1] = 0xff }; /* CRC32 was OK. Remove it from skb. */ - priv->ule_skb->tail -= 4; - priv->ule_skb->len -= 4; + h.priv->ule_skb->tail -= 4; + h.priv->ule_skb->len -= 4; - if (!priv->ule_dbit) { + if (!h.priv->ule_dbit) { /* * The destination MAC address is the * next data in the skb. It comes @@ -648,26 +673,26 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * should be passed up the stack. */ register int drop = 0; - if (priv->rx_mode != RX_MODE_PROMISC) { - if (priv->ule_skb->data[0] & 0x01) { + if (h.priv->rx_mode != RX_MODE_PROMISC) { + if (h.priv->ule_skb->data[0] & 0x01) { /* multicast or broadcast */ - if (!ether_addr_equal(priv->ule_skb->data, bc_addr)) { + if (!ether_addr_equal(h.priv->ule_skb->data, bc_addr)) { /* multicast */ - if (priv->rx_mode == RX_MODE_MULTI) { + if (h.priv->rx_mode == RX_MODE_MULTI) { int i; - for(i = 0; i < priv->multi_num && - !ether_addr_equal(priv->ule_skb->data, - priv->multi_macs[i]); i++) + for(i = 0; i < h.priv->multi_num && + !ether_addr_equal(h.priv->ule_skb->data, + h.priv->multi_macs[i]); i++) ; - if (i == priv->multi_num) + if (i == h.priv->multi_num) drop = 1; - } else if (priv->rx_mode != RX_MODE_ALL_MULTI) + } else if (h.priv->rx_mode != RX_MODE_ALL_MULTI) drop = 1; /* no broadcast; */ /* else: all multicast mode: accept all multicast packets */ } /* else: broadcast */ } - else if (!ether_addr_equal(priv->ule_skb->data, dev->dev_addr)) + else if (!ether_addr_equal(h.priv->ule_skb->data, h.dev->dev_addr)) drop = 1; /* else: destination address matches the MAC address of our receiver device */ } @@ -675,94 +700,94 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (drop) { #ifdef ULE_DEBUG - netdev_dbg(dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, dev addr: %pM\n", - priv->ule_skb->data, dev->dev_addr); + netdev_dbg(h.dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, h.dev addr: %pM\n", + h.priv->ule_skb->data, h.dev->dev_addr); #endif - dev_kfree_skb(priv->ule_skb); + dev_kfree_skb(h.priv->ule_skb); goto sndu_done; } else { - skb_copy_from_linear_data(priv->ule_skb, + skb_copy_from_linear_data(h.priv->ule_skb, dest_addr, ETH_ALEN); - skb_pull(priv->ule_skb, ETH_ALEN); + skb_pull(h.priv->ule_skb, ETH_ALEN); } } /* Handle ULE Extension Headers. */ - if (priv->ule_sndu_type < ETH_P_802_3_MIN) { + if (h.priv->ule_sndu_type < ETH_P_802_3_MIN) { /* There is an extension header. Handle it accordingly. */ - int l = handle_ule_extensions(priv); + int l = handle_ule_extensions(h.priv); if (l < 0) { /* Mandatory extension header unknown or TEST SNDU. Drop it. */ // pr_warn("Dropping SNDU, extension headers.\n" ); - dev_kfree_skb(priv->ule_skb); + dev_kfree_skb(h.priv->ule_skb); goto sndu_done; } - skb_pull(priv->ule_skb, l); + skb_pull(h.priv->ule_skb, l); } /* * Construct/assure correct ethernet header. - * Note: in bridged mode (priv->ule_bridged != + * Note: in bridged mode (h.priv->ule_bridged != * 0) we already have the (original) ethernet * header at the start of the payload (after * optional dest. address and any extension * headers). */ - if (!priv->ule_bridged) { - skb_push(priv->ule_skb, ETH_HLEN); - ethh = (struct ethhdr *)priv->ule_skb->data; - if (!priv->ule_dbit) { - /* dest_addr buffer is only valid if priv->ule_dbit == 0 */ - memcpy(ethh->h_dest, dest_addr, ETH_ALEN); - eth_zero_addr(ethh->h_source); + if (!h.priv->ule_bridged) { + skb_push(h.priv->ule_skb, ETH_HLEN); + h.ethh = (struct ethhdr *)h.priv->ule_skb->data; + if (!h.priv->ule_dbit) { + /* dest_addr buffer is only valid if h.priv->ule_dbit == 0 */ + memcpy(h.ethh->h_dest, dest_addr, ETH_ALEN); + eth_zero_addr(h.ethh->h_source); } else /* zeroize source and dest */ - memset( ethh, 0, ETH_ALEN*2 ); + memset( h.ethh, 0, ETH_ALEN*2 ); - ethh->h_proto = htons(priv->ule_sndu_type); + h.ethh->h_proto = htons(h.priv->ule_sndu_type); } /* else: skb is in correct state; nothing to do. */ - priv->ule_bridged = 0; + h.priv->ule_bridged = 0; /* Stuff into kernel's protocol stack. */ - priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev); + h.priv->ule_skb->protocol = dvb_net_eth_type_trans(h.priv->ule_skb, h.dev); /* If D-bit is set (i.e. destination MAC address not present), * receive the packet anyhow. */ - /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) - priv->ule_skb->pkt_type = PACKET_HOST; */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += priv->ule_skb->len; - netif_rx(priv->ule_skb); + /* if (h.priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) + h.priv->ule_skb->pkt_type = PACKET_HOST; */ + h.dev->stats.rx_packets++; + h.dev->stats.rx_bytes += h.priv->ule_skb->len; + netif_rx(h.priv->ule_skb); } sndu_done: /* Prepare for next SNDU. */ - reset_ule(priv); + reset_ule(h.priv); } /* More data in current TS (look at the bytes following the CRC32)? */ - if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) { + if (h.ts_remain >= 2 && *((unsigned short *)h.from_where) != 0xFFFF) { /* Next ULE SNDU starts right there. */ - new_ts = 0; - priv->ule_skb = NULL; - priv->ule_sndu_type_1 = 0; - priv->ule_sndu_len = 0; + h.new_ts = 0; + h.priv->ule_skb = NULL; + h.priv->ule_sndu_type_1 = 0; + h.priv->ule_sndu_len = 0; // pr_warn("More data in current TS: [%#x %#x %#x %#x]\n", - // *(from_where + 0), *(from_where + 1), - // *(from_where + 2), *(from_where + 3)); - // pr_warn("ts @ %p, stopped @ %p:\n", ts, from_where + 0); - // hexdump(ts, 188); + // *(h.from_where + 0), *(h.from_where + 1), + // *(h.from_where + 2), *(h.from_where + 3)); + // pr_warn("h.ts @ %p, stopped @ %p:\n", h.ts, h.from_where + 0); + // hexdump(h.ts, 188); } else { - new_ts = 1; - ts += TS_SZ; - priv->ts_count++; - if (priv->ule_skb == NULL) { - priv->need_pusi = 1; - priv->ule_sndu_type_1 = 0; - priv->ule_sndu_len = 0; + h.new_ts = 1; + h.ts += TS_SZ; + h.priv->ts_count++; + if (h.priv->ule_skb == NULL) { + h.priv->need_pusi = 1; + h.priv->ule_sndu_type_1 = 0; + h.priv->ule_sndu_len = 0; } } } /* for all available TS cells */ -- cgit v1.2.3 From 8b0041db80ddea91d9be509f0a7817dd09fbdd1d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 19 Nov 2016 12:56:59 -0200 Subject: [media] dvb-net: split the logic at dvb_net_ule() into other functions This function is too big and too complex, making really hard to understand what's there. Split it into sub-routines, in order to make it easier to be understood, and to allow gcc to better parse it. As a bonus, it gets rid of a goto in the middle of a routine. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-core/dvb_net.c | 828 ++++++++++++++++++++++----------------- 1 file changed, 467 insertions(+), 361 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index 6fef0fc61cd2..bd833b0824c6 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -332,8 +332,458 @@ struct dvb_net_ule_handle { #endif }; +static int dvb_net_ule_new_ts_cell(struct dvb_net_ule_handle *h) +{ + /* We are about to process a new TS cell. */ + +#ifdef ULE_DEBUG + if (h->ule_where >= &h->ule_hist[100*TS_SZ]) + h->ule_where = h->ule_hist; + memcpy(h->ule_where, h->ts, TS_SZ); + if (h->ule_dump) { + hexdump(h->ule_where, TS_SZ); + h->ule_dump = 0; + } + h->ule_where += TS_SZ; +#endif + + /* + * Check TS h->error conditions: sync_byte, transport_error_indicator, + * scrambling_control . + */ + if ((h->ts[0] != TS_SYNC) || (h->ts[1] & TS_TEI) || + ((h->ts[3] & TS_SC) != 0)) { + pr_warn("%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", + h->priv->ts_count, h->ts[0], + (h->ts[1] & TS_TEI) >> 7, + (h->ts[3] & TS_SC) >> 6); + + /* Drop partly decoded SNDU, reset state, resync on PUSI. */ + if (h->priv->ule_skb) { + dev_kfree_skb(h->priv->ule_skb); + /* Prepare for next SNDU. */ + h->dev->stats.rx_errors++; + h->dev->stats.rx_frame_errors++; + } + reset_ule(h->priv); + h->priv->need_pusi = 1; + + /* Continue with next TS cell. */ + h->ts += TS_SZ; + h->priv->ts_count++; + return 1; + } + + h->ts_remain = 184; + h->from_where = h->ts + 4; + + return 0; +} + +static int dvb_net_ule_ts_pusi(struct dvb_net_ule_handle *h) +{ + if (h->ts[1] & TS_PUSI) { + /* Find beginning of first ULE SNDU in current TS cell. */ + /* Synchronize continuity counter. */ + h->priv->tscc = h->ts[3] & 0x0F; + /* There is a pointer field here. */ + if (h->ts[4] > h->ts_remain) { + pr_err("%lu: Invalid ULE packet (pointer field %d)\n", + h->priv->ts_count, h->ts[4]); + h->ts += TS_SZ; + h->priv->ts_count++; + return 1; + } + /* Skip to destination of pointer field. */ + h->from_where = &h->ts[5] + h->ts[4]; + h->ts_remain -= 1 + h->ts[4]; + h->skipped = 0; + } else { + h->skipped++; + h->ts += TS_SZ; + h->priv->ts_count++; + return 1; + } + + return 0; +} + +static int dvb_net_ule_new_ts(struct dvb_net_ule_handle *h) +{ + /* Check continuity counter. */ + if ((h->ts[3] & 0x0F) == h->priv->tscc) + h->priv->tscc = (h->priv->tscc + 1) & 0x0F; + else { + /* TS discontinuity handling: */ + pr_warn("%lu: TS discontinuity: got %#x, expected %#x.\n", + h->priv->ts_count, h->ts[3] & 0x0F, + h->priv->tscc); + /* Drop partly decoded SNDU, reset state, resync on PUSI. */ + if (h->priv->ule_skb) { + dev_kfree_skb(h->priv->ule_skb); + /* Prepare for next SNDU. */ + // reset_ule(h->priv); moved to below. + h->dev->stats.rx_errors++; + h->dev->stats.rx_frame_errors++; + } + reset_ule(h->priv); + /* skip to next PUSI. */ + h->priv->need_pusi = 1; + return 1; + } + /* + * If we still have an incomplete payload, but PUSI is + * set; some TS cells are missing. + * This is only possible here, if we missed exactly 16 TS + * cells (continuity counter wrap). + */ + if (h->ts[1] & TS_PUSI) { + if (!h->priv->need_pusi) { + if (!(*h->from_where < (h->ts_remain-1)) || + *h->from_where != h->priv->ule_sndu_remain) { + /* + * Pointer field is invalid. + * Drop this TS cell and any started ULE SNDU. + */ + pr_warn("%lu: Invalid pointer field: %u.\n", + h->priv->ts_count, + *h->from_where); + + /* + * Drop partly decoded SNDU, reset state, + * resync on PUSI. + */ + if (h->priv->ule_skb) { + h->error = true; + dev_kfree_skb(h->priv->ule_skb); + } + + if (h->error || h->priv->ule_sndu_remain) { + h->dev->stats.rx_errors++; + h->dev->stats.rx_frame_errors++; + h->error = false; + } + + reset_ule(h->priv); + h->priv->need_pusi = 1; + return 1; + } + /* + * Skip pointer field (we're processing a + * packed payload). + */ + h->from_where += 1; + h->ts_remain -= 1; + } else + h->priv->need_pusi = 0; + + if (h->priv->ule_sndu_remain > 183) { + /* + * Current SNDU lacks more data than there + * could be available in the current TS cell. + */ + h->dev->stats.rx_errors++; + h->dev->stats.rx_length_errors++; + pr_warn("%lu: Expected %d more SNDU bytes, but got PUSI (pf %d, h->ts_remain %d). Flushing incomplete payload.\n", + h->priv->ts_count, + h->priv->ule_sndu_remain, + h->ts[4], h->ts_remain); + dev_kfree_skb(h->priv->ule_skb); + /* Prepare for next SNDU. */ + reset_ule(h->priv); + /* + * Resync: go to where pointer field points to: + * start of next ULE SNDU. + */ + h->from_where += h->ts[4]; + h->ts_remain -= h->ts[4]; + } + } + return 0; +} + + +/* + * Start a new payload with skb. + * Find ULE header. It is only guaranteed that the + * length field (2 bytes) is contained in the current + * TS. + * Check h.ts_remain has to be >= 2 here. + */ +static int dvb_net_ule_new_payload(struct dvb_net_ule_handle *h) +{ + if (h->ts_remain < 2) { + pr_warn("Invalid payload packing: only %d bytes left in TS. Resyncing.\n", + h->ts_remain); + h->priv->ule_sndu_len = 0; + h->priv->need_pusi = 1; + h->ts += TS_SZ; + return 1; + } + + if (!h->priv->ule_sndu_len) { + /* Got at least two bytes, thus extrace the SNDU length. */ + h->priv->ule_sndu_len = h->from_where[0] << 8 | + h->from_where[1]; + if (h->priv->ule_sndu_len & 0x8000) { + /* D-Bit is set: no dest mac present. */ + h->priv->ule_sndu_len &= 0x7FFF; + h->priv->ule_dbit = 1; + } else + h->priv->ule_dbit = 0; + + if (h->priv->ule_sndu_len < 5) { + pr_warn("%lu: Invalid ULE SNDU length %u. Resyncing.\n", + h->priv->ts_count, + h->priv->ule_sndu_len); + h->dev->stats.rx_errors++; + h->dev->stats.rx_length_errors++; + h->priv->ule_sndu_len = 0; + h->priv->need_pusi = 1; + h->new_ts = 1; + h->ts += TS_SZ; + h->priv->ts_count++; + return 1; + } + h->ts_remain -= 2; /* consume the 2 bytes SNDU length. */ + h->from_where += 2; + } + + h->priv->ule_sndu_remain = h->priv->ule_sndu_len + 2; + /* + * State of current TS: + * h->ts_remain (remaining bytes in the current TS cell) + * 0 ule_type is not available now, we need the next TS cell + * 1 the first byte of the ule_type is present + * >=2 full ULE header present, maybe some payload data as well. + */ + switch (h->ts_remain) { + case 1: + h->priv->ule_sndu_remain--; + h->priv->ule_sndu_type = h->from_where[0] << 8; + + /* first byte of ule_type is set. */ + h->priv->ule_sndu_type_1 = 1; + h->ts_remain -= 1; + h->from_where += 1; + /* fallthrough */ + case 0: + h->new_ts = 1; + h->ts += TS_SZ; + h->priv->ts_count++; + return 1; + + default: /* complete ULE header is present in current TS. */ + /* Extract ULE type field. */ + if (h->priv->ule_sndu_type_1) { + h->priv->ule_sndu_type_1 = 0; + h->priv->ule_sndu_type |= h->from_where[0]; + h->from_where += 1; /* points to payload start. */ + h->ts_remain -= 1; + } else { + /* Complete type is present in new TS. */ + h->priv->ule_sndu_type = h->from_where[0] << 8 | + h->from_where[1]; + h->from_where += 2; /* points to payload start. */ + h->ts_remain -= 2; + } + break; + } + + /* + * Allocate the skb (decoder target buffer) with the correct size, + * as follows: + * + * prepare for the largest case: bridged SNDU with MAC address + * (dbit = 0). + */ + h->priv->ule_skb = dev_alloc_skb(h->priv->ule_sndu_len + + ETH_HLEN + ETH_ALEN); + if (!h->priv->ule_skb) { + pr_notice("%s: Memory squeeze, dropping packet.\n", + h->dev->name); + h->dev->stats.rx_dropped++; + return -1; + } + + /* This includes the CRC32 _and_ dest mac, if !dbit. */ + h->priv->ule_sndu_remain = h->priv->ule_sndu_len; + h->priv->ule_skb->dev = h->dev; + /* + * Leave space for Ethernet or bridged SNDU header + * (eth hdr plus one MAC addr). + */ + skb_reserve(h->priv->ule_skb, ETH_HLEN + ETH_ALEN); + + return 0; +} + + +static int dvb_net_ule_should_drop(struct dvb_net_ule_handle *h) +{ + static const u8 bc_addr[ETH_ALEN] = { [0 ... ETH_ALEN - 1] = 0xff }; + + /* + * The destination MAC address is the next data in the skb. It comes + * before any extension headers. + * + * Check if the payload of this SNDU should be passed up the stack. + */ + if (h->priv->rx_mode == RX_MODE_PROMISC) + return 0; + + if (h->priv->ule_skb->data[0] & 0x01) { + /* multicast or broadcast */ + if (!ether_addr_equal(h->priv->ule_skb->data, bc_addr)) { + /* multicast */ + if (h->priv->rx_mode == RX_MODE_MULTI) { + int i; + + for (i = 0; i < h->priv->multi_num && + !ether_addr_equal(h->priv->ule_skb->data, + h->priv->multi_macs[i]); + i++) + ; + if (i == h->priv->multi_num) + return 1; + } else if (h->priv->rx_mode != RX_MODE_ALL_MULTI) + return 1; /* no broadcast; */ + /* + * else: + * all multicast mode: accept all multicast packets + */ + } + /* else: broadcast */ + } else if (!ether_addr_equal(h->priv->ule_skb->data, h->dev->dev_addr)) + return 1; + + return 0; +} + + +static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, + u32 ule_crc, u32 expected_crc) +{ + u8 dest_addr[ETH_ALEN]; + + if (ule_crc != expected_crc) { + pr_warn("%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", + h->priv->ts_count, ule_crc, expected_crc, + h->priv->ule_sndu_len, h->priv->ule_sndu_type, + h->ts_remain, + h->ts_remain > 2 ? + *(unsigned short *)h->from_where : 0); + + #ifdef ULE_DEBUG + hexdump(iov[0].iov_base, iov[0].iov_len); + hexdump(iov[1].iov_base, iov[1].iov_len); + hexdump(iov[2].iov_base, iov[2].iov_len); + + if (h->ule_where == h->ule_hist) { + hexdump(&h->ule_hist[98*TS_SZ], TS_SZ); + hexdump(&h->ule_hist[99*TS_SZ], TS_SZ); + } else if (h->ule_where == &h->ule_hist[TS_SZ]) { + hexdump(&h->ule_hist[99*TS_SZ], TS_SZ); + hexdump(h->ule_hist, TS_SZ); + } else { + hexdump(h->ule_where - TS_SZ - TS_SZ, TS_SZ); + hexdump(h->ule_where - TS_SZ, TS_SZ); + } + h->ule_dump = 1; + #endif + + h->dev->stats.rx_errors++; + h->dev->stats.rx_crc_errors++; + dev_kfree_skb(h->priv->ule_skb); + + return; + } + + /* CRC32 verified OK. */ + + /* CRC32 was OK, so remove it from skb. */ + h->priv->ule_skb->tail -= 4; + h->priv->ule_skb->len -= 4; + + if (!h->priv->ule_dbit) { + if (dvb_net_ule_should_drop(h)) { +#ifdef ULE_DEBUG + netdev_dbg(h->dev, + "Dropping SNDU: MAC destination address does not match: dest addr: %pM, h->dev addr: %pM\n", + h->priv->ule_skb->data, h->dev->dev_addr); +#endif + dev_kfree_skb(h->priv->ule_skb); + return; + } + + skb_copy_from_linear_data(h->priv->ule_skb, dest_addr, + ETH_ALEN); + skb_pull(h->priv->ule_skb, ETH_ALEN); + } + + /* Handle ULE Extension Headers. */ + if (h->priv->ule_sndu_type < ETH_P_802_3_MIN) { + /* There is an extension header. Handle it accordingly. */ + int l = handle_ule_extensions(h->priv); + + if (l < 0) { + /* + * Mandatory extension header unknown or TEST SNDU. + * Drop it. + */ + + // pr_warn("Dropping SNDU, extension headers.\n" ); + dev_kfree_skb(h->priv->ule_skb); + return; + } + skb_pull(h->priv->ule_skb, l); + } + + /* + * Construct/assure correct ethernet header. + * Note: in bridged mode (h->priv->ule_bridged != 0) + * we already have the (original) ethernet + * header at the start of the payload (after + * optional dest. address and any extension + * headers). + */ + if (!h->priv->ule_bridged) { + skb_push(h->priv->ule_skb, ETH_HLEN); + h->ethh = (struct ethhdr *)h->priv->ule_skb->data; + if (!h->priv->ule_dbit) { + /* + * dest_addr buffer is only valid if + * h->priv->ule_dbit == 0 + */ + memcpy(h->ethh->h_dest, dest_addr, ETH_ALEN); + eth_zero_addr(h->ethh->h_source); + } else /* zeroize source and dest */ + memset(h->ethh, 0, ETH_ALEN * 2); + + h->ethh->h_proto = htons(h->priv->ule_sndu_type); + } + /* else: skb is in correct state; nothing to do. */ + h->priv->ule_bridged = 0; + + /* Stuff into kernel's protocol stack. */ + h->priv->ule_skb->protocol = dvb_net_eth_type_trans(h->priv->ule_skb, + h->dev); + /* + * If D-bit is set (i.e. destination MAC address not present), + * receive the packet anyhow. + */ +#if 0 + if (h->priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) + h->priv->ule_skb->pkt_type = PACKET_HOST; +#endif + h->dev->stats.rx_packets++; + h->dev->stats.rx_bytes += h->priv->ule_skb->len; + netif_rx(h->priv->ule_skb); +} + static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) { + int ret; struct dvb_net_ule_handle h = { .dev = dev, .buf = buf, @@ -352,251 +802,42 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) #endif }; - /* For all TS cells in current buffer. + /* + * For all TS cells in current buffer. * Appearently, we are called for every single TS cell. */ - for (h.ts = h.buf, h.ts_end = h.buf + h.buf_len; h.ts < h.ts_end; /* no incr. */ ) { + for (h.ts = h.buf, h.ts_end = h.buf + h.buf_len; + h.ts < h.ts_end; /* no incr. */) { if (h.new_ts) { /* We are about to process a new TS cell. */ - -#ifdef ULE_DEBUG - if (h.ule_where >= &h.ule_hist[100*TS_SZ]) h.ule_where = h.ule_hist; - memcpy( h.ule_where, h.ts, TS_SZ ); - if (h.ule_dump) { - hexdump( h.ule_where, TS_SZ ); - h.ule_dump = 0; - } - h.ule_where += TS_SZ; -#endif - - /* Check TS h.error conditions: sync_byte, transport_error_indicator, scrambling_control . */ - if ((h.ts[0] != TS_SYNC) || (h.ts[1] & TS_TEI) || ((h.ts[3] & TS_SC) != 0)) { - pr_warn("%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", - h.priv->ts_count, h.ts[0], - (h.ts[1] & TS_TEI) >> 7, - (h.ts[3] & TS_SC) >> 6); - - /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (h.priv->ule_skb) { - dev_kfree_skb( h.priv->ule_skb ); - /* Prepare for next SNDU. */ - h.dev->stats.rx_errors++; - h.dev->stats.rx_frame_errors++; - } - reset_ule(h.priv); - h.priv->need_pusi = 1; - - /* Continue with next TS cell. */ - h.ts += TS_SZ; - h.priv->ts_count++; + if (dvb_net_ule_new_ts_cell(&h)) continue; - } - - h.ts_remain = 184; - h.from_where = h.ts + 4; } + /* Synchronize on PUSI, if required. */ if (h.priv->need_pusi) { - if (h.ts[1] & TS_PUSI) { - /* Find beginning of first ULE SNDU in current TS cell. */ - /* Synchronize continuity counter. */ - h.priv->tscc = h.ts[3] & 0x0F; - /* There is a pointer field here. */ - if (h.ts[4] > h.ts_remain) { - pr_err("%lu: Invalid ULE packet (pointer field %d)\n", - h.priv->ts_count, h.ts[4]); - h.ts += TS_SZ; - h.priv->ts_count++; - continue; - } - /* Skip to destination of pointer field. */ - h.from_where = &h.ts[5] + h.ts[4]; - h.ts_remain -= 1 + h.ts[4]; - h.skipped = 0; - } else { - h.skipped++; - h.ts += TS_SZ; - h.priv->ts_count++; + if (dvb_net_ule_ts_pusi(&h)) continue; - } } if (h.new_ts) { - /* Check continuity counter. */ - if ((h.ts[3] & 0x0F) == h.priv->tscc) - h.priv->tscc = (h.priv->tscc + 1) & 0x0F; - else { - /* TS discontinuity handling: */ - pr_warn("%lu: TS discontinuity: got %#x, expected %#x.\n", - h.priv->ts_count, h.ts[3] & 0x0F, - h.priv->tscc); - /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (h.priv->ule_skb) { - dev_kfree_skb( h.priv->ule_skb ); - /* Prepare for next SNDU. */ - // reset_ule(h.priv); moved to below. - h.dev->stats.rx_errors++; - h.dev->stats.rx_frame_errors++; - } - reset_ule(h.priv); - /* skip to next PUSI. */ - h.priv->need_pusi = 1; + if (dvb_net_ule_new_ts(&h)) continue; - } - /* If we still have an incomplete payload, but PUSI is - * set; some TS cells are missing. - * This is only possible here, if we missed exactly 16 TS - * cells (continuity counter wrap). */ - if (h.ts[1] & TS_PUSI) { - if (! h.priv->need_pusi) { - if (!(*h.from_where < (h.ts_remain-1)) || *h.from_where != h.priv->ule_sndu_remain) { - /* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */ - pr_warn("%lu: Invalid pointer field: %u.\n", - h.priv->ts_count, - *h.from_where); - - /* Drop partly decoded SNDU, reset state, resync on PUSI. */ - if (h.priv->ule_skb) { - h.error = true; - dev_kfree_skb(h.priv->ule_skb); - } - - if (h.error || h.priv->ule_sndu_remain) { - h.dev->stats.rx_errors++; - h.dev->stats.rx_frame_errors++; - h.error = false; - } - - reset_ule(h.priv); - h.priv->need_pusi = 1; - continue; - } - /* Skip pointer field (we're processing a - * packed payload). */ - h.from_where += 1; - h.ts_remain -= 1; - } else - h.priv->need_pusi = 0; - - if (h.priv->ule_sndu_remain > 183) { - /* Current SNDU lacks more data than there could be available in the - * current TS cell. */ - h.dev->stats.rx_errors++; - h.dev->stats.rx_length_errors++; - pr_warn("%lu: Expected %d more SNDU bytes, but got PUSI (pf %d, h.ts_remain %d). Flushing incomplete payload.\n", - h.priv->ts_count, - h.priv->ule_sndu_remain, - h.ts[4], h.ts_remain); - dev_kfree_skb(h.priv->ule_skb); - /* Prepare for next SNDU. */ - reset_ule(h.priv); - /* Resync: go to where pointer field points to: start of next ULE SNDU. */ - h.from_where += h.ts[4]; - h.ts_remain -= h.ts[4]; - } - } } /* Check if new payload needs to be started. */ if (h.priv->ule_skb == NULL) { - /* Start a new payload with skb. - * Find ULE header. It is only guaranteed that the - * length field (2 bytes) is contained in the current - * TS. - * Check h.ts_remain has to be >= 2 here. */ - if (h.ts_remain < 2) { - pr_warn("Invalid payload packing: only %d bytes left in TS. Resyncing.\n", - h.ts_remain); - h.priv->ule_sndu_len = 0; - h.priv->need_pusi = 1; - h.ts += TS_SZ; - continue; - } - - if (! h.priv->ule_sndu_len) { - /* Got at least two bytes, thus extrace the SNDU length. */ - h.priv->ule_sndu_len = h.from_where[0] << 8 | h.from_where[1]; - if (h.priv->ule_sndu_len & 0x8000) { - /* D-Bit is set: no dest mac present. */ - h.priv->ule_sndu_len &= 0x7FFF; - h.priv->ule_dbit = 1; - } else - h.priv->ule_dbit = 0; - - if (h.priv->ule_sndu_len < 5) { - pr_warn("%lu: Invalid ULE SNDU length %u. Resyncing.\n", - h.priv->ts_count, - h.priv->ule_sndu_len); - h.dev->stats.rx_errors++; - h.dev->stats.rx_length_errors++; - h.priv->ule_sndu_len = 0; - h.priv->need_pusi = 1; - h.new_ts = 1; - h.ts += TS_SZ; - h.priv->ts_count++; - continue; - } - h.ts_remain -= 2; /* consume the 2 bytes SNDU length. */ - h.from_where += 2; - } - - h.priv->ule_sndu_remain = h.priv->ule_sndu_len + 2; - /* - * State of current TS: - * h.ts_remain (remaining bytes in the current TS cell) - * 0 ule_type is not available now, we need the next TS cell - * 1 the first byte of the ule_type is present - * >=2 full ULE header present, maybe some payload data as well. - */ - switch (h.ts_remain) { - case 1: - h.priv->ule_sndu_remain--; - h.priv->ule_sndu_type = h.from_where[0] << 8; - h.priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ - h.ts_remain -= 1; h.from_where += 1; - /* Continue w/ next TS. */ - case 0: - h.new_ts = 1; - h.ts += TS_SZ; - h.priv->ts_count++; - continue; - - default: /* complete ULE header is present in current TS. */ - /* Extract ULE type field. */ - if (h.priv->ule_sndu_type_1) { - h.priv->ule_sndu_type_1 = 0; - h.priv->ule_sndu_type |= h.from_where[0]; - h.from_where += 1; /* points to payload start. */ - h.ts_remain -= 1; - } else { - /* Complete type is present in new TS. */ - h.priv->ule_sndu_type = h.from_where[0] << 8 | h.from_where[1]; - h.from_where += 2; /* points to payload start. */ - h.ts_remain -= 2; - } - break; - } - - /* Allocate the skb (decoder target buffer) with the correct size, as follows: - * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */ - h.priv->ule_skb = dev_alloc_skb( h.priv->ule_sndu_len + ETH_HLEN + ETH_ALEN ); - if (h.priv->ule_skb == NULL) { - pr_notice("%s: Memory squeeze, dropping packet.\n", - h.dev->name); - h.dev->stats.rx_dropped++; + ret = dvb_net_ule_new_payload(&h); + if (ret < 0) return; - } - - /* This includes the CRC32 _and_ dest mac, if !dbit. */ - h.priv->ule_sndu_remain = h.priv->ule_sndu_len; - h.priv->ule_skb->dev = h.dev; - /* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */ - skb_reserve( h.priv->ule_skb, ETH_HLEN + ETH_ALEN ); + if (ret) + continue; } /* Copy data into our current skb. */ h.how_much = min(h.priv->ule_sndu_remain, (int)h.ts_remain); - memcpy(skb_put(h.priv->ule_skb, h.how_much), h.from_where, h.how_much); + memcpy(skb_put(h.priv->ule_skb, h.how_much), + h.from_where, h.how_much); h.priv->ule_sndu_remain -= h.how_much; h.ts_remain -= h.how_much; h.from_where += h.how_much; @@ -610,7 +851,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) struct kvec iov[3] = { { &ulen, sizeof ulen }, { &utype, sizeof utype }, - { h.priv->ule_skb->data, h.priv->ule_skb->len - 4 } + { h.priv->ule_skb->data, + h.priv->ule_skb->len - 4 } }; u32 ule_crc = ~0L, expected_crc; if (h.priv->ule_dbit) { @@ -625,145 +867,9 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) *(tail - 3) << 16 | *(tail - 2) << 8 | *(tail - 1); - if (ule_crc != expected_crc) { - pr_warn("%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, h.ts_remain %d, next 2: %x.\n", - h.priv->ts_count, ule_crc, expected_crc, - h.priv->ule_sndu_len, h.priv->ule_sndu_type, - h.ts_remain, - h.ts_remain > 2 ? *(unsigned short *)h.from_where : 0); -#ifdef ULE_DEBUG - hexdump( iov[0].iov_base, iov[0].iov_len ); - hexdump( iov[1].iov_base, iov[1].iov_len ); - hexdump( iov[2].iov_base, iov[2].iov_len ); - - if (h.ule_where == h.ule_hist) { - hexdump( &h.ule_hist[98*TS_SZ], TS_SZ ); - hexdump( &h.ule_hist[99*TS_SZ], TS_SZ ); - } else if (h.ule_where == &h.ule_hist[TS_SZ]) { - hexdump( &h.ule_hist[99*TS_SZ], TS_SZ ); - hexdump( h.ule_hist, TS_SZ ); - } else { - hexdump( h.ule_where - TS_SZ - TS_SZ, TS_SZ ); - hexdump( h.ule_where - TS_SZ, TS_SZ ); - } - h.ule_dump = 1; -#endif + dvb_net_ule_check_crc(&h, ule_crc, expected_crc); - h.dev->stats.rx_errors++; - h.dev->stats.rx_crc_errors++; - dev_kfree_skb(h.priv->ule_skb); - } else { - /* CRC32 verified OK. */ - u8 dest_addr[ETH_ALEN]; - static const u8 bc_addr[ETH_ALEN] = - { [ 0 ... ETH_ALEN-1] = 0xff }; - - /* CRC32 was OK. Remove it from skb. */ - h.priv->ule_skb->tail -= 4; - h.priv->ule_skb->len -= 4; - - if (!h.priv->ule_dbit) { - /* - * The destination MAC address is the - * next data in the skb. It comes - * before any extension headers. - * - * Check if the payload of this SNDU - * should be passed up the stack. - */ - register int drop = 0; - if (h.priv->rx_mode != RX_MODE_PROMISC) { - if (h.priv->ule_skb->data[0] & 0x01) { - /* multicast or broadcast */ - if (!ether_addr_equal(h.priv->ule_skb->data, bc_addr)) { - /* multicast */ - if (h.priv->rx_mode == RX_MODE_MULTI) { - int i; - for(i = 0; i < h.priv->multi_num && - !ether_addr_equal(h.priv->ule_skb->data, - h.priv->multi_macs[i]); i++) - ; - if (i == h.priv->multi_num) - drop = 1; - } else if (h.priv->rx_mode != RX_MODE_ALL_MULTI) - drop = 1; /* no broadcast; */ - /* else: all multicast mode: accept all multicast packets */ - } - /* else: broadcast */ - } - else if (!ether_addr_equal(h.priv->ule_skb->data, h.dev->dev_addr)) - drop = 1; - /* else: destination address matches the MAC address of our receiver device */ - } - /* else: promiscuous mode; pass everything up the stack */ - - if (drop) { -#ifdef ULE_DEBUG - netdev_dbg(h.dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, h.dev addr: %pM\n", - h.priv->ule_skb->data, h.dev->dev_addr); -#endif - dev_kfree_skb(h.priv->ule_skb); - goto sndu_done; - } - else - { - skb_copy_from_linear_data(h.priv->ule_skb, - dest_addr, - ETH_ALEN); - skb_pull(h.priv->ule_skb, ETH_ALEN); - } - } - - /* Handle ULE Extension Headers. */ - if (h.priv->ule_sndu_type < ETH_P_802_3_MIN) { - /* There is an extension header. Handle it accordingly. */ - int l = handle_ule_extensions(h.priv); - if (l < 0) { - /* Mandatory extension header unknown or TEST SNDU. Drop it. */ - // pr_warn("Dropping SNDU, extension headers.\n" ); - dev_kfree_skb(h.priv->ule_skb); - goto sndu_done; - } - skb_pull(h.priv->ule_skb, l); - } - - /* - * Construct/assure correct ethernet header. - * Note: in bridged mode (h.priv->ule_bridged != - * 0) we already have the (original) ethernet - * header at the start of the payload (after - * optional dest. address and any extension - * headers). - */ - - if (!h.priv->ule_bridged) { - skb_push(h.priv->ule_skb, ETH_HLEN); - h.ethh = (struct ethhdr *)h.priv->ule_skb->data; - if (!h.priv->ule_dbit) { - /* dest_addr buffer is only valid if h.priv->ule_dbit == 0 */ - memcpy(h.ethh->h_dest, dest_addr, ETH_ALEN); - eth_zero_addr(h.ethh->h_source); - } - else /* zeroize source and dest */ - memset( h.ethh, 0, ETH_ALEN*2 ); - - h.ethh->h_proto = htons(h.priv->ule_sndu_type); - } - /* else: skb is in correct state; nothing to do. */ - h.priv->ule_bridged = 0; - - /* Stuff into kernel's protocol stack. */ - h.priv->ule_skb->protocol = dvb_net_eth_type_trans(h.priv->ule_skb, h.dev); - /* If D-bit is set (i.e. destination MAC address not present), - * receive the packet anyhow. */ - /* if (h.priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) - h.priv->ule_skb->pkt_type = PACKET_HOST; */ - h.dev->stats.rx_packets++; - h.dev->stats.rx_bytes += h.priv->ule_skb->len; - netif_rx(h.priv->ule_skb); - } - sndu_done: /* Prepare for next SNDU. */ reset_ule(h.priv); } -- cgit v1.2.3 From 8c2ebcf103b106bd8b9c5517bf72885d126d3d27 Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Wed, 16 Nov 2016 18:49:50 -0200 Subject: [media] media: remove obsolete Media Device Managed resource interfaces Remove obsolete media_device_get_devres(), media_device_find_devres(), and media_device_release_devres() interfaces. These interfaces are now obsolete. Signed-off-by: Shuah Khan Signed-off-by: Mauro Carvalho Chehab --- drivers/media/media-device.c | 26 -------------------------- include/media/media-device.h | 32 -------------------------------- 2 files changed, 58 deletions(-) (limited to 'drivers') diff --git a/drivers/media/media-device.c b/drivers/media/media-device.c index 219ab5fc8b4c..8756275e9fc4 100644 --- a/drivers/media/media-device.c +++ b/drivers/media/media-device.c @@ -821,32 +821,6 @@ void media_device_unregister(struct media_device *mdev) } EXPORT_SYMBOL_GPL(media_device_unregister); -static void media_device_release_devres(struct device *dev, void *res) -{ -} - -struct media_device *media_device_get_devres(struct device *dev) -{ - struct media_device *mdev; - - mdev = devres_find(dev, media_device_release_devres, NULL, NULL); - if (mdev) - return mdev; - - mdev = devres_alloc(media_device_release_devres, - sizeof(struct media_device), GFP_KERNEL); - if (!mdev) - return NULL; - return devres_get(dev, mdev, NULL, NULL); -} -EXPORT_SYMBOL_GPL(media_device_get_devres); - -struct media_device *media_device_find_devres(struct device *dev) -{ - return devres_find(dev, media_device_release_devres, NULL, NULL); -} -EXPORT_SYMBOL_GPL(media_device_find_devres); - #if IS_ENABLED(CONFIG_PCI) void media_device_pci_init(struct media_device *mdev, struct pci_dev *pci_dev, diff --git a/include/media/media-device.h b/include/media/media-device.h index a267f9ceee8f..c21b4c5f5871 100644 --- a/include/media/media-device.h +++ b/include/media/media-device.h @@ -375,30 +375,6 @@ int __must_check media_device_register_entity_notify(struct media_device *mdev, void media_device_unregister_entity_notify(struct media_device *mdev, struct media_entity_notify *nptr); -/** - * media_device_get_devres() - get media device as device resource - * creates if one doesn't exist - * - * @dev: pointer to struct &device. - * - * Sometimes, the media controller &media_device needs to be shared by more - * than one driver. This function adds support for that, by dynamically - * allocating the &media_device and allowing it to be obtained from the - * struct &device associated with the common device where all sub-device - * components belong. So, for example, on an USB device with multiple - * interfaces, each interface may be handled by a separate per-interface - * drivers. While each interface have its own &device, they all share a - * common &device associated with the hole USB device. - */ -struct media_device *media_device_get_devres(struct device *dev); - -/** - * media_device_find_devres() - find media device as device resource - * - * @dev: pointer to struct &device. - */ -struct media_device *media_device_find_devres(struct device *dev); - /* Iterate over all entities. */ #define media_device_for_each_entity(entity, mdev) \ list_for_each_entry(entity, &(mdev)->entities, graph_obj.list) @@ -476,14 +452,6 @@ static inline void media_device_unregister_entity_notify( struct media_entity_notify *nptr) { } -static inline struct media_device *media_device_get_devres(struct device *dev) -{ - return NULL; -} -static inline struct media_device *media_device_find_devres(struct device *dev) -{ - return NULL; -} static inline void media_device_pci_init(struct media_device *mdev, struct pci_dev *pci_dev, -- cgit v1.2.3 From fa4a2fd17dc5d2d1fbad7ace78d39d7fea20d78e Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 18 Nov 2016 14:16:04 -0200 Subject: [media] v4l: rcar_fdp1: mark PM functions as __maybe_unused The new driver produces a warning when CONFIG_PM is disabled: platform/rcar_fdp1.c:2408:12: error: 'fdp1_pm_runtime_resume' defined but not used [-Werror=unused-function] platform/rcar_fdp1.c:2399:12: error: 'fdp1_pm_runtime_suspend' defined but not used [-Werror=unused-function] This marks the two functions as __maybe_unused. Fixes: 4710b752e029 ("[media] v4l: Add Renesas R-Car FDP1 Driver") Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/rcar_fdp1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/rcar_fdp1.c b/drivers/media/platform/rcar_fdp1.c index dd1a6ea17f22..674cc1309b43 100644 --- a/drivers/media/platform/rcar_fdp1.c +++ b/drivers/media/platform/rcar_fdp1.c @@ -2396,7 +2396,7 @@ static int fdp1_remove(struct platform_device *pdev) return 0; } -static int fdp1_pm_runtime_suspend(struct device *dev) +static int __maybe_unused fdp1_pm_runtime_suspend(struct device *dev) { struct fdp1_dev *fdp1 = dev_get_drvdata(dev); @@ -2405,7 +2405,7 @@ static int fdp1_pm_runtime_suspend(struct device *dev) return 0; } -static int fdp1_pm_runtime_resume(struct device *dev) +static int __maybe_unused fdp1_pm_runtime_resume(struct device *dev) { struct fdp1_dev *fdp1 = dev_get_drvdata(dev); -- cgit v1.2.3 From 1d38971438157dc57f0a4be89abf23b472458633 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 18 Nov 2016 14:16:05 -0200 Subject: [media] v4l: rcar_fdp1: add FCP dependency Commit 4710b752e029 ("[media] v4l: Add Renesas R-Car FDP1 Driver") in the v4l-dvb tree adds CONFIG_VIDEO_RENESAS_FDP1. It calls into the FCP driver, but when there is no dependency, FCP might be a module while FDP1 is built-in. We have the same logic in VIDEO_RENESAS_VSP1, which also depends on FCP not being a module when it is built-in itself. drivers/media/platform/rcar_fdp1.o: In function `fdp1_pm_runtime_resume': rcar_fdp1.c:(.text.fdp1_pm_runtime_resume+0x78): undefined reference to `rcar_fcp_enable' drivers/media/platform/rcar_fdp1.o: In function `fdp1_pm_runtime_suspend': rcar_fdp1.c:(.text.fdp1_pm_runtime_suspend+0x14): undefined reference to `rcar_fcp_disable' drivers/media/platform/rcar_fdp1.o: In function `fdp1_probe': rcar_fdp1.c:(.text.fdp1_probe+0x15c): undefined reference to `rcar_fcp_get' Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig index 60e20e5f4282..d944421e392d 100644 --- a/drivers/media/platform/Kconfig +++ b/drivers/media/platform/Kconfig @@ -311,6 +311,7 @@ config VIDEO_RENESAS_FDP1 tristate "Renesas Fine Display Processor" depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA depends on ARCH_SHMOBILE || COMPILE_TEST + depends on (!ARCH_RENESAS && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP select VIDEOBUF2_DMA_CONTIG select V4L2_MEM2MEM_DEV ---help--- -- cgit v1.2.3 From 399426cadf5b0539a5b2a4d805257ce8acc6aba2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 19 Nov 2016 19:27:30 -0200 Subject: [media] cx88: make checkpatch.pl happy Usually, I don't like fixing coding style issues on non-staging drivers, as it could be a mess pretty easy, and could become like a snow ball. That's the case of recent changes on two changesets: they disalign some statements. Yet, a care a lot with cx88 driver, as it was the first driver I touched at the Kernel, and I've been maintaining it since 2005. So, several of the coding style issues were due to my code. Per Andrey's suggestion, I ran checkpatch.pl in strict mode, with fixed several other issues, did some function alinments, but broke other alinments. So, I had to manually apply another round of manual fixes to make sure that everything is ok, and to make checkpatch happy with this patch. With this patch, checkpatch.pl is now happy when called with: ./scripts/checkpatch.pl -f --max-line-length=998 --ignore PREFER_PR_LEVEL Also, the 80-cols violations that made sense were fixed. Checkpatch would be happier if we convert it to use dev_foo(), but this is a more complex change. NOTE: there are some places with msleep(1). As this driver was written at the time that the default was to sleep at least 10ms on such calls (e. g. CONFIG_HZ=100), I replaced those calls by usleep_range(10000, 20000), with should be safe to avoid breakages. Fixes: 65bc2fe86e66 ("[media] cx88: convert it to use pr_foo() macros") Fixes: 7b61ba8ff838 ("[media] cx88: make checkpatch happier") Suggested-by: Andrey Utkin Signed-off-by: Mauro Carvalho Chehab Reviewed-by: Andrey Utkin Signed-off-by: Mauro Carvalho Chehab --- drivers/media/pci/cx88/cx88-alsa.c | 206 ++++++++++---------- drivers/media/pci/cx88/cx88-blackbird.c | 169 ++++++++++------- drivers/media/pci/cx88/cx88-cards.c | 313 +++++++++++++++++-------------- drivers/media/pci/cx88/cx88-core.c | 205 ++++++++++---------- drivers/media/pci/cx88/cx88-dsp.c | 50 +++-- drivers/media/pci/cx88/cx88-dvb.c | 154 +++++++-------- drivers/media/pci/cx88/cx88-i2c.c | 25 ++- drivers/media/pci/cx88/cx88-input.c | 45 +++-- drivers/media/pci/cx88/cx88-mpeg.c | 114 +++++------ drivers/media/pci/cx88/cx88-reg.h | 110 +++++------ drivers/media/pci/cx88/cx88-tvaudio.c | 63 ++++--- drivers/media/pci/cx88/cx88-vbi.c | 19 +- drivers/media/pci/cx88/cx88-video.c | 155 ++++++++------- drivers/media/pci/cx88/cx88-vp3054-i2c.c | 10 +- drivers/media/pci/cx88/cx88-vp3054-i2c.h | 38 ++-- drivers/media/pci/cx88/cx88.h | 171 ++++++++--------- 16 files changed, 975 insertions(+), 872 deletions(-) (limited to 'drivers') diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c index 56770e84b3d5..c81fe4681d14 100644 --- a/drivers/media/pci/cx88/cx88-alsa.c +++ b/drivers/media/pci/cx88/cx88-alsa.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -31,7 +32,6 @@ #include #include -#include #include #include #include @@ -46,9 +46,9 @@ chip->core->name, ##arg); \ } while (0) -/**************************************************************************** - Data type declarations - Can be moded to a header file later - ****************************************************************************/ +/* + * Data type declarations - Can be moded to a header file later + */ struct cx88_audio_buffer { unsigned int bpl; @@ -82,13 +82,10 @@ struct cx88_audio_dev { struct snd_pcm_substream *substream; }; -typedef struct cx88_audio_dev snd_cx88_card_t; - - -/**************************************************************************** - Module global static vars - ****************************************************************************/ +/* + * Module global static vars + */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ @@ -100,10 +97,9 @@ MODULE_PARM_DESC(enable, "Enable cx88x soundcard. default enabled."); module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for cx88x capture interface(s)."); - -/**************************************************************************** - Module macros - ****************************************************************************/ +/* + * Module macros + */ MODULE_DESCRIPTION("ALSA driver module for cx2388x based TV cards"); MODULE_AUTHOR("Ricardo Cerqueira"); @@ -116,15 +112,15 @@ static unsigned int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "enable debug messages"); -/**************************************************************************** - Module specific funtions - ****************************************************************************/ +/* + * Module specific functions + */ /* * BOARD Specific: Sets audio DMA */ -static int _cx88_start_audio_dma(snd_cx88_card_t *chip) +static int _cx88_start_audio_dma(struct cx88_audio_dev *chip) { struct cx88_audio_buffer *buf = chip->buf; struct cx88_core *core = chip->core; @@ -143,8 +139,9 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) cx_write(MO_AUDD_GPCNTRL, GP_COUNT_CONTROL_RESET); atomic_set(&chip->count, 0); - dprintk(1, "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d byte buffer\n", - buf->bpl, cx_read(audio_ch->cmds_start + 8)>>1, + dprintk(1, + "Start audio DMA, %d B/line, %d lines/FIFO, %d periods, %d byte buffer\n", + buf->bpl, cx_read(audio_ch->cmds_start + 8) >> 1, chip->num_periods, buf->bpl * chip->num_periods); /* Enables corresponding bits at AUD_INT_STAT */ @@ -158,8 +155,11 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) cx_set(MO_PCI_INTMSK, chip->core->pci_irqmask | PCI_INT_AUDINT); /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); /* Enables Risc Processor */ - cx_set(MO_AUD_DMACNTRL, 0x11); /* audio downstream FIFO and RISC enable */ + + /* Enables Risc Processor */ + cx_set(MO_DEV_CNTRL2, (1 << 5)); + /* audio downstream FIFO and RISC enable */ + cx_set(MO_AUD_DMACNTRL, 0x11); if (debug) cx88_sram_channel_dump(chip->core, audio_ch); @@ -170,7 +170,7 @@ static int _cx88_start_audio_dma(snd_cx88_card_t *chip) /* * BOARD Specific: Resets audio DMA */ -static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) +static int _cx88_stop_audio_dma(struct cx88_audio_dev *chip) { struct cx88_core *core = chip->core; @@ -185,7 +185,8 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip) AUD_INT_DN_RISCI2 | AUD_INT_DN_RISCI1); if (debug) - cx88_sram_channel_dump(chip->core, &cx88_sram_channels[SRAM_CH25]); + cx88_sram_channel_dump(chip->core, + &cx88_sram_channels[SRAM_CH25]); return 0; } @@ -211,7 +212,7 @@ static const char *cx88_aud_irqs[32] = { /* * BOARD Specific: Threats IRQ audio specific calls */ -static void cx8801_aud_irq(snd_cx88_card_t *chip) +static void cx8801_aud_irq(struct cx88_audio_dev *chip) { struct cx88_core *core = chip->core; u32 status, mask; @@ -249,7 +250,7 @@ static void cx8801_aud_irq(snd_cx88_card_t *chip) */ static irqreturn_t cx8801_irq(int irq, void *dev_id) { - snd_cx88_card_t *chip = dev_id; + struct cx88_audio_dev *chip = dev_id; struct cx88_core *core = chip->core; u32 status; int loop, handled = 0; @@ -286,26 +287,25 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages) int i; buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT); - if (buf->vaddr == NULL) { + if (!buf->vaddr) { dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages); return -ENOMEM; } dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n", - (unsigned long)buf->vaddr, - nr_pages << PAGE_SHIFT); + (unsigned long)buf->vaddr, nr_pages << PAGE_SHIFT); memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT); buf->nr_pages = nr_pages; buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist)); - if (buf->sglist == NULL) + if (!buf->sglist) goto vzalloc_err; sg_init_table(buf->sglist, buf->nr_pages); for (i = 0; i < buf->nr_pages; i++) { pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE); - if (pg == NULL) + if (!pg) goto vmalloc_to_page_err; sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0); } @@ -341,7 +341,8 @@ static int cx88_alsa_dma_unmap(struct cx88_audio_dev *dev) if (!buf->sglen) return 0; - dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE); + dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, + PCI_DMA_FROMDEVICE); buf->sglen = 0; return 0; } @@ -355,18 +356,18 @@ static int cx88_alsa_dma_free(struct cx88_audio_buffer *buf) return 0; } - -static int dsp_buffer_free(snd_cx88_card_t *chip) +static int dsp_buffer_free(struct cx88_audio_dev *chip) { struct cx88_riscmem *risc = &chip->buf->risc; - BUG_ON(!chip->dma_size); + WARN_ON(!chip->dma_size); dprintk(2, "Freeing buffer\n"); cx88_alsa_dma_unmap(chip); cx88_alsa_dma_free(chip->buf); if (risc->cpu) - pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma); + pci_free_consistent(chip->pci, risc->size, + risc->cpu, risc->dma); kfree(chip->buf); chip->buf = NULL; @@ -374,9 +375,9 @@ static int dsp_buffer_free(snd_cx88_card_t *chip) return 0; } -/**************************************************************************** - ALSA PCM Interface - ****************************************************************************/ +/* + * ALSA PCM Interface + */ /* * Digital hardware definition @@ -394,13 +395,15 @@ static const struct snd_pcm_hardware snd_cx88_digital_hw = { .rate_max = 48000, .channels_min = 2, .channels_max = 2, - /* Analog audio output will be full of clicks and pops if there - are not exactly four lines in the SRAM FIFO buffer. */ - .period_bytes_min = DEFAULT_FIFO_SIZE/4, - .period_bytes_max = DEFAULT_FIFO_SIZE/4, + /* + * Analog audio output will be full of clicks and pops if there + * are not exactly four lines in the SRAM FIFO buffer. + */ + .period_bytes_min = DEFAULT_FIFO_SIZE / 4, + .period_bytes_max = DEFAULT_FIFO_SIZE / 4, .periods_min = 1, .periods_max = 1024, - .buffer_bytes_max = (1024*1024), + .buffer_bytes_max = (1024 * 1024), }; /* @@ -408,7 +411,7 @@ static const struct snd_pcm_hardware snd_cx88_digital_hw = { */ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) { - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; @@ -417,7 +420,8 @@ static int snd_cx88_pcm_open(struct snd_pcm_substream *substream) return -ENODEV; } - err = snd_pcm_hw_constraint_pow2(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS); + err = snd_pcm_hw_constraint_pow2(runtime, 0, + SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) goto _error; @@ -453,7 +457,7 @@ static int snd_cx88_close(struct snd_pcm_substream *substream) static int snd_cx88_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream); struct cx88_audio_buffer *buf; int ret; @@ -467,18 +471,18 @@ static int snd_cx88_hw_params(struct snd_pcm_substream *substream, chip->num_periods = params_periods(hw_params); chip->dma_size = chip->period_size * params_periods(hw_params); - BUG_ON(!chip->dma_size); - BUG_ON(chip->num_periods & (chip->num_periods-1)); + WARN_ON(!chip->dma_size); + WARN_ON(chip->num_periods & (chip->num_periods - 1)); buf = kzalloc(sizeof(*buf), GFP_KERNEL); - if (buf == NULL) + if (!buf) return -ENOMEM; chip->buf = buf; buf->bpl = chip->period_size; ret = cx88_alsa_dma_init(chip, - (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); + (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT)); if (ret < 0) goto error; @@ -492,7 +496,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream *substream, goto error; /* Loop back to start of program */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC); + buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC); buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma); substream->runtime->dma_area = chip->buf->vaddr; @@ -510,8 +514,7 @@ error: */ static int snd_cx88_hw_free(struct snd_pcm_substream *substream) { - - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream); if (substream->runtime->dma_area) { dsp_buffer_free(chip); @@ -534,7 +537,7 @@ static int snd_cx88_prepare(struct snd_pcm_substream *substream) */ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) { - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream); int err; /* Local interrupts are already disabled by ALSA */ @@ -562,7 +565,7 @@ static int snd_cx88_card_trigger(struct snd_pcm_substream *substream, int cmd) */ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) { - snd_cx88_card_t *chip = snd_pcm_substream_chip(substream); + struct cx88_audio_dev *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; u16 count; @@ -571,14 +574,14 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream) // dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__, // count, new, count & (runtime->periods-1), // runtime->period_size * (count & (runtime->periods-1))); - return runtime->period_size * (count & (runtime->periods-1)); + return runtime->period_size * (count & (runtime->periods - 1)); } /* * page callback (needed for mmap) */ static struct page *snd_cx88_page(struct snd_pcm_substream *substream, - unsigned long offset) + unsigned long offset) { void *pageptr = substream->runtime->dma_area + offset; @@ -603,7 +606,8 @@ static const struct snd_pcm_ops snd_cx88_pcm_ops = { /* * create a PCM device */ -static int snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name) +static int snd_cx88_pcm(struct cx88_audio_dev *chip, int device, + const char *name) { int err; struct snd_pcm *pcm; @@ -618,9 +622,9 @@ static int snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name) return 0; } -/**************************************************************************** - CONTROL INTERFACE - ****************************************************************************/ +/* + * CONTROL INTERFACE + */ static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *info) { @@ -635,7 +639,7 @@ static int snd_cx88_volume_info(struct snd_kcontrol *kcontrol, static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; int vol = 0x3f - (cx_read(AUD_VOL_CTL) & 0x3f), bal = cx_read(AUD_BAL_CTL); @@ -648,9 +652,9 @@ static int snd_cx88_volume_get(struct snd_kcontrol *kcontrol, } static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) + struct snd_ctl_elem_value *value) { - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; int left = value->value.integer.value[0]; int right = value->value.integer.value[1]; @@ -672,7 +676,7 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; int left, right, v, b; int changed = 0; @@ -722,7 +726,7 @@ static const struct snd_kcontrol_new snd_cx88_volume = { static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *value) { - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; u32 bit = kcontrol->private_value; @@ -731,9 +735,9 @@ static int snd_cx88_switch_get(struct snd_kcontrol *kcontrol, } static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) + struct snd_ctl_elem_value *value) { - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; u32 bit = kcontrol->private_value; int ret = 0; @@ -745,8 +749,9 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, vol ^= bit; cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); /* Pass mute onto any WM8775 */ - if (core->sd_wm8775 && ((1<<6) == bit)) - wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit)); + if (core->sd_wm8775 && ((1 << 6) == bit)) + wm8775_s_ctrl(core, + V4L2_CID_AUDIO_MUTE, 0 != (vol & bit)); ret = 1; } spin_unlock_irq(&chip->reg_lock); @@ -759,7 +764,7 @@ static const struct snd_kcontrol_new snd_cx88_dac_switch = { .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, - .private_value = (1<<8), + .private_value = (1 << 8), }; static const struct snd_kcontrol_new snd_cx88_source_switch = { @@ -768,13 +773,13 @@ static const struct snd_kcontrol_new snd_cx88_source_switch = { .info = snd_ctl_boolean_mono_info, .get = snd_cx88_switch_get, .put = snd_cx88_switch_put, - .private_value = (1<<6), + .private_value = (1 << 6), }; static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) + struct snd_ctl_elem_value *value) { - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; s32 val; @@ -784,9 +789,9 @@ static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, } static int snd_cx88_alc_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *value) + struct snd_ctl_elem_value *value) { - snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); + struct cx88_audio_dev *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; wm8775_s_ctrl(core, V4L2_CID_AUDIO_LOUDNESS, @@ -802,9 +807,9 @@ static struct snd_kcontrol_new snd_cx88_alc_switch = { .put = snd_cx88_alc_put, }; -/**************************************************************************** - Basic Flow for Sound Devices - ****************************************************************************/ +/* + * Basic Flow for Sound Devices + */ /* * PCI ID Table - 14f1:8801 and 14f1:8811 means function 1: Audio @@ -822,9 +827,8 @@ MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl); * Chip-specific destructor */ -static int snd_cx88_free(snd_cx88_card_t *chip) +static int snd_cx88_free(struct cx88_audio_dev *chip) { - if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -839,25 +843,24 @@ static int snd_cx88_free(snd_cx88_card_t *chip) */ static void snd_cx88_dev_free(struct snd_card *card) { - snd_cx88_card_t *chip = card->private_data; + struct cx88_audio_dev *chip = card->private_data; snd_cx88_free(chip); } - /* * Alsa Constructor - Component probe */ static int devno; static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, - snd_cx88_card_t **rchip, + struct cx88_audio_dev **rchip, struct cx88_core **core_ptr) { - snd_cx88_card_t *chip; - struct cx88_core *core; - int err; - unsigned char pci_lat; + struct cx88_audio_dev *chip; + struct cx88_core *core; + int err; + unsigned char pci_lat; *rchip = NULL; @@ -870,7 +873,7 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, chip = card->private_data; core = cx88_core_get(pci); - if (core == NULL) { + if (!core) { err = -EINVAL; return err; } @@ -882,7 +885,6 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, return err; } - /* pci init */ chip->card = card; chip->pci = pci; @@ -896,17 +898,18 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, IRQF_SHARED, chip->core->name, chip); if (err < 0) { dprintk(0, "%s: can't get IRQ %d\n", - chip->core->name, chip->pci->irq); + chip->core->name, chip->pci->irq); return err; } /* print pci info */ pci_read_config_byte(pci, PCI_LATENCY_TIMER, &pci_lat); - dprintk(1, "ALSA %s/%i: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dprintk(1, + "ALSA %s/%i: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", core->name, devno, - pci_name(pci), pci->revision, pci->irq, - pci_lat, (unsigned long long)pci_resource_start(pci, 0)); + pci_name(pci), pci->revision, pci->irq, + pci_lat, (unsigned long long)pci_resource_start(pci, 0)); chip->irq = pci->irq; synchronize_irq(chip->irq); @@ -920,10 +923,10 @@ static int snd_cx88_create(struct snd_card *card, struct pci_dev *pci, static int cx88_audio_initdev(struct pci_dev *pci, const struct pci_device_id *pci_id) { - struct snd_card *card; - snd_cx88_card_t *chip; - struct cx88_core *core = NULL; - int err; + struct snd_card *card; + struct cx88_audio_dev *chip; + struct cx88_core *core = NULL; + int err; if (devno >= SNDRV_CARDS) return (-ENODEV); @@ -934,7 +937,7 @@ static int cx88_audio_initdev(struct pci_dev *pci, } err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE, - sizeof(snd_cx88_card_t), &card); + sizeof(struct cx88_audio_dev), &card); if (err < 0) return err; @@ -970,7 +973,7 @@ static int cx88_audio_initdev(struct pci_dev *pci, strcpy(card->mixername, "CX88"); dprintk(0, "%s/%i: ALSA support for cx2388x boards\n", - card->driver, devno); + card->driver, devno); err = snd_card_register(card); if (err < 0) @@ -984,6 +987,7 @@ error: snd_card_free(card); return err; } + /* * ALSA destructor */ diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c index bffd064daff5..aa49c9597d9c 100644 --- a/drivers/media/pci/cx88/cx88-blackbird.c +++ b/drivers/media/pci/cx88/cx88-blackbird.c @@ -66,6 +66,7 @@ enum blackbird_capture_type { BLACKBIRD_RAW_CAPTURE, BLACKBIRD_RAW_PASSTHRU_CAPTURE }; + enum blackbird_capture_bits { BLACKBIRD_RAW_BITS_NONE = 0x00, BLACKBIRD_RAW_BITS_YUV_CAPTURE = 0x01, @@ -74,33 +75,40 @@ enum blackbird_capture_bits { BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08, BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x10 }; + enum blackbird_capture_end { BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */ BLACKBIRD_END_NOW, /* stop immediately, no irq */ }; + enum blackbird_framerate { BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */ BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */ }; + enum blackbird_stream_port { BLACKBIRD_OUTPUT_PORT_MEMORY, BLACKBIRD_OUTPUT_PORT_STREAMING, BLACKBIRD_OUTPUT_PORT_SERIAL }; + enum blackbird_data_xfer_status { BLACKBIRD_MORE_BUFFERS_FOLLOW, BLACKBIRD_LAST_BUFFER, }; + enum blackbird_picture_mask { BLACKBIRD_PICTURE_MASK_NONE, BLACKBIRD_PICTURE_MASK_I_FRAMES, BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3, BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7, }; + enum blackbird_vbi_mode_bits { BLACKBIRD_VBI_BITS_SLICED, BLACKBIRD_VBI_BITS_RAW, }; + enum blackbird_vbi_insertion_bits { BLACKBIRD_VBI_BITS_INSERT_IN_XTENSION_USR_DATA, BLACKBIRD_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1, @@ -108,56 +116,69 @@ enum blackbird_vbi_insertion_bits { BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1, BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1, }; + enum blackbird_dma_unit { BLACKBIRD_DMA_BYTES, BLACKBIRD_DMA_FRAMES, }; + enum blackbird_dma_transfer_status_bits { BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01, BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04, BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10, }; + enum blackbird_pause { BLACKBIRD_PAUSE_ENCODING, BLACKBIRD_RESUME_ENCODING, }; + enum blackbird_copyright { BLACKBIRD_COPYRIGHT_OFF, BLACKBIRD_COPYRIGHT_ON, }; + enum blackbird_notification_type { BLACKBIRD_NOTIFICATION_REFRESH, }; + enum blackbird_notification_status { BLACKBIRD_NOTIFICATION_OFF, BLACKBIRD_NOTIFICATION_ON, }; + enum blackbird_notification_mailbox { BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1, }; + enum blackbird_field1_lines { BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */ BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */ BLACKBIRD_FIELD1_MICRONAS = 0x0105, /* 261 */ }; + enum blackbird_field2_lines { BLACKBIRD_FIELD2_SAA7114 = 0x00EF, /* 239 */ BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */ BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */ }; + enum blackbird_custom_data_type { BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, BLACKBIRD_CUSTOM_PRIVATE_PACKET, }; + enum blackbird_mute { BLACKBIRD_UNMUTE, BLACKBIRD_MUTE, }; + enum blackbird_mute_video_mask { BLACKBIRD_MUTE_VIDEO_V_MASK = 0x0000FF00, BLACKBIRD_MUTE_VIDEO_U_MASK = 0x00FF0000, BLACKBIRD_MUTE_VIDEO_Y_MASK = 0xFF000000, }; + enum blackbird_mute_video_shift { BLACKBIRD_MUTE_VIDEO_V_SHIFT = 8, BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16, @@ -281,7 +302,6 @@ static int register_write(struct cx88_core *core, u32 address, u32 value) return wait_ready_gpio0_bit1(core, 1); } - static int register_read(struct cx88_core *core, u32 address, u32 *value) { int retval; @@ -304,7 +324,8 @@ static int register_read(struct cx88_core *core, u32 address, u32 *value) /* ------------------------------------------------------------------ */ -static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]) +static int blackbird_mbox_func(void *priv, u32 command, int in, + int out, u32 data[CX2341X_MBOX_MAX_DATA]) { struct cx8802_dev *dev = priv; unsigned long timeout; @@ -313,11 +334,14 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat dprintk(1, "%s: 0x%X\n", __func__, command); - /* this may not be 100% safe if we can't read any memory location - without side effects */ + /* + * this may not be 100% safe if we can't read any memory location + * without side effects + */ memory_read(dev->core, dev->mailbox - 4, &value); if (value != 0x12345678) { - dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n"); + dprintk(0, + "Firmware and/or mailbox pointer not initialized or corrupted\n"); return -EIO; } @@ -332,7 +356,8 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat /* write command + args + fill remaining with zeros */ memory_write(dev->core, dev->mailbox + 1, command); /* command code */ - memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); /* timeout */ + /* timeout */ + memory_write(dev->core, dev->mailbox + 3, IVTV_API_STD_TIMEOUT); for (i = 0; i < in; i++) { memory_write(dev->core, dev->mailbox + 4 + i, data[i]); dprintk(1, "API Input %d = %d\n", i, data[i]); @@ -369,9 +394,13 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat memory_write(dev->core, dev->mailbox, flag); return retval; } + /* ------------------------------------------------------------------ */ -/* We don't need to call the API often, so using just one mailbox will probably suffice */ +/* + * We don't need to call the API often, so using just one mailbox + * will probably suffice + */ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command, u32 inputcnt, u32 outputcnt, ...) { @@ -381,9 +410,9 @@ static int blackbird_api_cmd(struct cx8802_dev *dev, u32 command, va_start(vargs, outputcnt); - for (i = 0; i < inputcnt; i++) { + for (i = 0; i < inputcnt; i++) data[i] = va_arg(vargs, int); - } + err = blackbird_mbox_func(dev, command, inputcnt, outputcnt, data); for (i = 0; i < outputcnt; i++) { int *vptr = va_arg(vargs, int *); @@ -408,7 +437,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev) signaturecnt = 0; if (signaturecnt == 4) { dprintk(1, "Mailbox signature found\n"); - return i+1; + return i + 1; } } dprintk(0, "Mailbox signature values not found!\n"); @@ -427,10 +456,13 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) __le32 *dataptr; retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED); - retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); - retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, 0x80000640); - retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A); - msleep(1); + retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, + IVTV_CMD_HW_BLOCKS_RST); + retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_REFRESH, + 0x80000640); + retval |= register_write(dev->core, IVTV_REG_ENC_SDRAM_PRECHARGE, + 0x1A); + usleep_range(10000, 20000); retval |= register_write(dev->core, IVTV_REG_APU, 0); if (retval < 0) @@ -439,7 +471,6 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) retval = request_firmware(&firmware, CX2341X_FIRM_ENC_FILENAME, &dev->pci->dev); - if (retval != 0) { pr_err("Hotplug firmware request failed (%s).\n", CX2341X_FIRM_ENC_FILENAME); @@ -482,10 +513,11 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) } dprintk(0, "Firmware upload successful.\n"); - retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST); + retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, + IVTV_CMD_HW_BLOCKS_RST); retval |= register_read(dev->core, IVTV_REG_SPU, &value); retval |= register_write(dev->core, IVTV_REG_SPU, value & 0xFFFFFFFE); - msleep(1); + usleep_range(10000, 20000); retval |= register_read(dev->core, IVTV_REG_VPU, &value); retval |= register_write(dev->core, IVTV_REG_VPU, value & 0xFFFFFFE8); @@ -495,19 +527,19 @@ static int blackbird_load_firmware(struct cx8802_dev *dev) return 0; } -/** - Settings used by the windows tv app for PVR2000: -================================================================================================================= -Profile | Codec | Resolution | CBR/VBR | Video Qlty | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode ------------------------------------------------------------------------------------------------------------------ -MPEG-1 | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 2000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -MPEG-2 | MPEG2 | 720x576PAL | VBR | 600 :Good | 4000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -VCD | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 1150 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -DVD | MPEG2 | 720x576PAL | VBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo -================================================================================================================= -*DB: "DirectBurn" -*/ +/* + * Settings used by the windows tv app for PVR2000: + * ================================================================================================================= + * Profile | Codec | Resolution | CBR/VBR | Video Qlty | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode + * ----------------------------------------------------------------------------------------------------------------- + * MPEG-1 | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 2000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo + * MPEG-2 | MPEG2 | 720x576PAL | VBR | 600 :Good | 4000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo + * VCD | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 1150 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo + * DVD | MPEG2 | 720x576PAL | VBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo + * DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo + * ================================================================================================================= + * [*] DB: "DirectBurn" + */ static void blackbird_codec_settings(struct cx8802_dev *dev) { @@ -515,11 +547,12 @@ static void blackbird_codec_settings(struct cx8802_dev *dev) /* assign frame size */ blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, - core->height, core->width); + core->height, core->width); dev->cxhdl.width = core->width; dev->cxhdl.height = core->height; - cx2341x_handler_set_50hz(&dev->cxhdl, dev->core->tvnorm & V4L2_STD_625_50); + cx2341x_handler_set_50hz(&dev->cxhdl, + dev->core->tvnorm & V4L2_STD_625_50); cx2341x_handler_setup(&dev->cxhdl); } @@ -545,15 +578,18 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) dev->mailbox = retval; - retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */ + /* ping */ + retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); if (retval < 0) { dprintk(0, "ERROR: Firmware ping failed!\n"); return -1; } - retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1, &version); + retval = blackbird_api_cmd(dev, CX2341X_ENC_GET_VERSION, + 0, 1, &version); if (retval < 0) { - dprintk(0, "ERROR: Firmware get encoder version failed!\n"); + dprintk(0, + "ERROR: Firmware get encoder version failed!\n"); return -1; } dprintk(0, "Firmware version is 0x%08x\n", version); @@ -567,13 +603,11 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev) blackbird_codec_settings(dev); blackbird_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0, - BLACKBIRD_FIELD1_SAA7115, - BLACKBIRD_FIELD2_SAA7115 - ); + BLACKBIRD_FIELD1_SAA7115, BLACKBIRD_FIELD2_SAA7115); blackbird_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0, - BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + BLACKBIRD_CUSTOM_EXTENSION_USR_DATA, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); return 0; } @@ -611,9 +645,7 @@ static int blackbird_start_codec(struct cx8802_dev *dev) /* start capturing to the host interface */ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE - ); + BLACKBIRD_MPEG_CAPTURE, BLACKBIRD_RAW_BITS_NONE); return 0; } @@ -621,10 +653,9 @@ static int blackbird_start_codec(struct cx8802_dev *dev) static int blackbird_stop_codec(struct cx8802_dev *dev) { blackbird_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE, 3, 0, - BLACKBIRD_END_NOW, - BLACKBIRD_MPEG_CAPTURE, - BLACKBIRD_RAW_BITS_NONE - ); + BLACKBIRD_END_NOW, + BLACKBIRD_MPEG_CAPTURE, + BLACKBIRD_RAW_BITS_NONE); cx2341x_handler_set_busy(&dev->cxhdl, 0); @@ -634,8 +665,8 @@ static int blackbird_stop_codec(struct cx8802_dev *dev) /* ------------------------------------------------------------------ */ static int queue_setup(struct vb2_queue *q, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], struct device *alloc_devs[]) + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8802_dev *dev = q->drv_priv; @@ -695,7 +726,8 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) err = drv->request_acquire(drv); if (err != 0) { - dprintk(1, "%s: Unable to acquire hardware, %d\n", __func__, err); + dprintk(1, "%s: Unable to acquire hardware, %d\n", __func__, + err); goto fail; } @@ -766,7 +798,7 @@ static const struct vb2_ops blackbird_qops = { /* ------------------------------------------------------------------ */ static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) + struct v4l2_capability *cap) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -778,7 +810,7 @@ static int vidioc_querycap(struct file *file, void *priv, } static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) + struct v4l2_fmtdesc *f) { if (f->index != 0) return -EINVAL; @@ -790,7 +822,7 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -806,7 +838,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -846,7 +878,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -860,14 +892,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, core->width = f->fmt.pix.width; core->height = f->fmt.pix.height; core->field = f->fmt.pix.field; - cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); + cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, + f->fmt.pix.field); blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, - f->fmt.pix.height, f->fmt.pix.width); + f->fmt.pix.height, f->fmt.pix.width); return 0; } static int vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -883,8 +916,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, cx88_set_freq(core, f); blackbird_initialize_codec(dev); - cx88_set_scale(core, core->width, core->height, - core->field); + cx88_set_scale(core, core->width, core->height, core->field); if (streaming) blackbird_start_codec(dev); return 0; @@ -903,7 +935,7 @@ static int vidioc_log_status(struct file *file, void *priv) } static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) + struct v4l2_input *i) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -912,7 +944,7 @@ static int vidioc_enum_input(struct file *file, void *priv, } static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -944,7 +976,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) if (i >= 4) return -EINVAL; - if (0 == INPUT(i).type) + if (!INPUT(i).type) return -EINVAL; cx88_newstation(core); @@ -953,7 +985,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) } static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + struct v4l2_tuner *t) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -971,12 +1003,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, cx88_get_stereo(core, t); reg = cx_read(MO_DEVICE_STATUS); - t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; + t->signal = (reg & (1 << 5)) ? 0xffff : 0x0000; return 0; } static int vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx8802_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -1008,7 +1040,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id) } static const struct v4l2_file_operations mpeg_fops = { - .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -1061,7 +1092,9 @@ static int cx8802_blackbird_advise_acquire(struct cx8802_driver *drv) switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: - /* By default, core setup will leave the cx22702 out of reset, on the bus. + /* + * By default, core setup will leave the cx22702 out of reset, + * on the bus. * We left the hardware on power up with the cx22702 active. * We're being given access to re-arrange the GPIOs. * Take the bus off the cx22702 and put the cx23416 on it. diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c index 269179142cd8..cdfbde277b8b 100644 --- a/drivers/media/pci/cx88/cx88-cards.c +++ b/drivers/media/pci/cx88/cx88-cards.c @@ -51,7 +51,6 @@ MODULE_PARM_DESC(disable_ir, "Disable IR support"); __func__, ##arg); \ } while (0) - /* ------------------------------------------------------------------ */ /* board config info */ @@ -278,7 +277,6 @@ static const struct cx88_board cx88_boards[] = { .gpio2 = 0x0035e700, .gpio3 = 0x02000000, }, { - .type = CX88_VMUX_COMPOSITE1, .vmux = 1, .gpio0 = 0x0035c700, @@ -492,22 +490,22 @@ static const struct cx88_board cx88_boards[] = { .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, /* - GPIO[0] resets DT3302 DTV receiver - 0 - reset asserted - 1 - normal operation - GPIO[1] mutes analog audio output connector - 0 - enable selected source - 1 - mute - GPIO[2] selects source for analog audio output connector - 0 - analog audio input connector on tab - 1 - analog DAC output from CX23881 chip - GPIO[3] selects RF input connector on tuner module - 0 - RF connector labeled CABLE - 1 - RF connector labeled ANT - GPIO[4] selects high RF for QAM256 mode - 0 - normal RF - 1 - high RF - */ + * GPIO[0] resets DT3302 DTV receiver + * 0 - reset asserted + * 1 - normal operation + * GPIO[1] mutes analog audio output connector + * 0 - enable selected source + * 1 - mute + * GPIO[2] selects source for analog audio output connector + * 0 - analog audio input connector on tab + * 1 - analog DAC output from CX23881 chip + * GPIO[3] selects RF input connector on tuner module + * 0 - RF connector labeled CABLE + * 1 - RF connector labeled ANT + * GPIO[4] selects high RF for QAM256 mode + * 0 - normal RF + * 1 - high RF + */ .input = { { .type = CX88_VMUX_TELEVISION, .vmux = 0, @@ -730,7 +728,10 @@ static const struct cx88_board cx88_boards[] = { .radio_type = UNSET, .tuner_addr = ADDR_UNSET, .radio_addr = ADDR_UNSET, - /* Some variants use a tda9874 and so need the tvaudio module. */ + /* + * Some variants use a tda9874 and so need the + * tvaudio module. + */ .audio_chip = CX88_AUDIO_TVAUDIO, .input = { { .type = CX88_VMUX_TELEVISION, @@ -1196,8 +1197,10 @@ static const struct cx88_board cx88_boards[] = { .mpeg = CX88_MPEG_DVB, }, [CX88_BOARD_KWORLD_MCE200_DELUXE] = { - /* FIXME: tested TV input only, disabled composite, - svideo and radio until they can be tested also. */ + /* + * FIXME: tested TV input only, disabled composite, + * svideo and radio until they can be tested also. + */ .name = "Kworld MCE 200 Deluxe", .tuner_type = TUNER_TENA_9533_DI, .radio_type = UNSET, @@ -1708,16 +1711,24 @@ static const struct cx88_board cx88_boards[] = { }, }, [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = { - .name = "PowerColor RA330", /* Long names may confuse LIRC. */ + /* Long names may confuse LIRC. */ + .name = "PowerColor RA330", .tuner_type = TUNER_XC2028, .tuner_addr = 0x61, .input = { { + /* + * Due to the way the cx88 driver is written, + * there is no way to deactivate audio pass- + * through without this entry. Furthermore, if + * the TV mux entry is first, you get audio + * from the tuner on boot for a little while. + */ .type = CX88_VMUX_DEBUG, - .vmux = 3, /* Due to the way the cx88 driver is written, */ - .gpio0 = 0x00ff, /* there is no way to deactivate audio pass- */ - .gpio1 = 0xf39d, /* through without this entry. Furthermore, if */ - .gpio3 = 0x0000, /* the TV mux entry is first, you get audio */ - }, { /* from the tuner on boot for a little while. */ + .vmux = 3, + .gpio0 = 0x00ff, + .gpio1 = 0xf39d, + .gpio3 = 0x0000, + }, { .type = CX88_VMUX_TELEVISION, .vmux = 0, .gpio0 = 0x00ff, @@ -1870,11 +1881,12 @@ static const struct cx88_board cx88_boards[] = { .gpio2 = 0x0cf7, }, }, - /* Both radio, analog and ATSC work with this board. - However, for analog to work, s5h1409 gate should be open, - otherwise, tuner-xc3028 won't be detected. - A proper fix require using the newer i2c methods to add - tuner-xc3028 without doing an i2c probe. + /* + * Both radio, analog and ATSC work with this board. + * However, for analog to work, s5h1409 gate should be open, + * otherwise, tuner-xc3028 won't be detected. + * A proper fix require using the newer i2c methods to add + * tuner-xc3028 without doing an i2c probe. */ [CX88_BOARD_KWORLD_ATSC_120] = { .name = "Kworld PlusTV HD PCI 120 (ATSC 120)", @@ -2808,9 +2820,9 @@ static const struct cx88_subid cx88_subids[] = { }, }; -/* ----------------------------------------------------------------------- */ -/* some leadtek specific stuff */ - +/* + * some leadtek specific stuff + */ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data) { if (eeprom_data[4] != 0x7d || @@ -2849,8 +2861,7 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) core->model = tv.model; /* Make sure we support the board model */ - switch (tv.model) - { + switch (tv.model) { case 14009: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in) */ case 14019: /* WinTV-HVR3000 (Retail, IR Blaster, b/panel video, 3.5mm audio in) */ case 14029: /* WinTV-HVR3000 (Retail, IR, b/panel video, 3.5mm audio in - 880 bridge) */ @@ -2898,8 +2909,9 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data) pr_info("hauppauge eeprom: model=%d\n", tv.model); } -/* ----------------------------------------------------------------------- */ -/* some GDI (was: Modular Technology) specific stuff */ +/* + * some GDI (was: Modular Technology) specific stuff + */ static const struct { int id; @@ -2907,33 +2919,33 @@ static const struct { const char *name; } gdi_tuner[] = { [0x01] = { .id = UNSET, - .name = "NTSC_M" }, + .name = "NTSC_M" }, [0x02] = { .id = UNSET, - .name = "PAL_B" }, + .name = "PAL_B" }, [0x03] = { .id = UNSET, - .name = "PAL_I" }, + .name = "PAL_I" }, [0x04] = { .id = UNSET, - .name = "PAL_D" }, + .name = "PAL_D" }, [0x05] = { .id = UNSET, - .name = "SECAM" }, + .name = "SECAM" }, [0x10] = { .id = UNSET, - .fm = 1, - .name = "TEMIC_4049" }, + .fm = 1, + .name = "TEMIC_4049" }, [0x11] = { .id = TUNER_TEMIC_4136FY5, - .name = "TEMIC_4136" }, + .name = "TEMIC_4136" }, [0x12] = { .id = UNSET, - .name = "TEMIC_4146" }, + .name = "TEMIC_4146" }, [0x20] = { .id = TUNER_PHILIPS_FQ1216ME, - .fm = 1, - .name = "PHILIPS_FQ1216_MK3" }, + .fm = 1, + .name = "PHILIPS_FQ1216_MK3" }, [0x21] = { .id = UNSET, .fm = 1, - .name = "PHILIPS_FQ1236_MK3" }, + .name = "PHILIPS_FQ1236_MK3" }, [0x22] = { .id = UNSET, - .name = "PHILIPS_FI1236_MK3" }, + .name = "PHILIPS_FI1236_MK3" }, [0x23] = { .id = UNSET, - .name = "PHILIPS_FI1216_MK3" }, + .name = "PHILIPS_FI1216_MK3" }, }; static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) @@ -2942,15 +2954,16 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data) ? gdi_tuner[eeprom_data[0x0d]].name : NULL; pr_info("GDI: tuner=%s\n", name ? name : "unknown"); - if (name == NULL) + if (!name) return; core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id; core->board.radio.type = gdi_tuner[eeprom_data[0x0d]].fm ? CX88_RADIO : 0; } -/* ------------------------------------------------------------------- */ -/* some Divco specific stuff */ +/* + * some Divco specific stuff + */ static int cx88_dvico_xc2028_callback(struct cx88_core *core, int command, int arg) { @@ -2979,9 +2992,9 @@ static int cx88_dvico_xc2028_callback(struct cx88_core *core, return 0; } - -/* ----------------------------------------------------------------------- */ -/* some Geniatech specific stuff */ +/* + * some Geniatech specific stuff + */ static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core, int command, int mode) @@ -3044,8 +3057,9 @@ static int cx88_xc4000_winfast2000h_plus_callback(struct cx88_core *core, return -EINVAL; } -/* ------------------------------------------------------------------- */ -/* some Divco specific stuff */ +/* + * some Divco specific stuff + */ static int cx88_pv_8000gt_callback(struct cx88_core *core, int command, int arg) { @@ -3064,8 +3078,9 @@ static int cx88_pv_8000gt_callback(struct cx88_core *core, return 0; } -/* ----------------------------------------------------------------------- */ -/* some DViCO specific stuff */ +/* + * some DViCO specific stuff + */ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core) { @@ -3161,11 +3176,11 @@ static int cx88_xc4000_tuner_callback(struct cx88_core *core, return -EINVAL; } -/* ----------------------------------------------------------------------- */ -/* Tuner callback function. Currently only needed for the Pinnacle * - * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both * - * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */ - +/* + * Tuner callback function. Currently only needed for the Pinnacle + * PCTV HD 800i with an xc5000 sillicon tuner. This is used for both + * analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) + */ static int cx88_xc5000_tuner_callback(struct cx88_core *core, int command, int arg) { @@ -3173,38 +3188,38 @@ static int cx88_xc5000_tuner_callback(struct cx88_core *core, case CX88_BOARD_PINNACLE_PCTV_HD_800i: if (command == 0) { /* This is the reset command from xc5000 */ - /* djh - According to the engineer at PCTV Systems, - the xc5000 reset pin is supposed to be on GPIO12. - However, despite three nights of effort, pulling - that GPIO low didn't reset the xc5000. While - pulling MO_SRST_IO low does reset the xc5000, this - also resets in the s5h1409 being reset as well. - This causes tuning to always fail since the internal - state of the s5h1409 does not match the driver's - state. Given that the only two conditions in which - the driver performs a reset is during firmware load - and powering down the chip, I am taking out the - reset. We know that the chip is being reset - when the cx88 comes online, and not being able to - do power management for this board is worse than - not having any tuning at all. */ + /* + * djh - According to the engineer at PCTV Systems, + * the xc5000 reset pin is supposed to be on GPIO12. + * However, despite three nights of effort, pulling + * that GPIO low didn't reset the xc5000. While + * pulling MO_SRST_IO low does reset the xc5000, this + * also resets in the s5h1409 being reset as well. + * This causes tuning to always fail since the internal + * state of the s5h1409 does not match the driver's + * state. Given that the only two conditions in which + * the driver performs a reset is during firmware load + * and powering down the chip, I am taking out the + * reset. We know that the chip is being reset + * when the cx88 comes online, and not being able to + * do power management for this board is worse than + * not having any tuning at all. + */ return 0; - } else { - dprintk(1, "xc5000: unknown tuner callback command.\n"); - return -EINVAL; } - break; + + dprintk(1, "xc5000: unknown tuner callback command.\n"); + return -EINVAL; case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: if (command == 0) { /* This is the reset command from xc5000 */ cx_clear(MO_GP0_IO, 0x00000010); - msleep(10); + usleep_range(10000, 20000); cx_set(MO_GP0_IO, 0x00000010); return 0; - } else { - dprintk(1, "xc5000: unknown tuner callback command.\n"); - return -EINVAL; } - break; + + dprintk(1, "xc5000: unknown tuner callback command.\n"); + return -EINVAL; } return 0; /* Should never be here */ } @@ -3230,15 +3245,15 @@ int cx88_tuner_callback(void *priv, int component, int command, int arg) return -EINVAL; switch (core->board.tuner_type) { - case TUNER_XC2028: - dprintk(1, "Calling XC2028/3028 callback\n"); - return cx88_xc2028_tuner_callback(core, command, arg); - case TUNER_XC4000: - dprintk(1, "Calling XC4000 callback\n"); - return cx88_xc4000_tuner_callback(core, command, arg); - case TUNER_XC5000: - dprintk(1, "Calling XC5000 callback\n"); - return cx88_xc5000_tuner_callback(core, command, arg); + case TUNER_XC2028: + dprintk(1, "Calling XC2028/3028 callback\n"); + return cx88_xc2028_tuner_callback(core, command, arg); + case TUNER_XC4000: + dprintk(1, "Calling XC4000 callback\n"); + return cx88_xc4000_tuner_callback(core, command, arg); + case TUNER_XC5000: + dprintk(1, "Calling XC5000 callback\n"); + return cx88_xc5000_tuner_callback(core, command, arg); } pr_err("Error: Calling callback for tuner %d\n", core->board.tuner_type); @@ -3252,8 +3267,7 @@ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci) { int i; - if (0 == pci->subsystem_vendor && - 0 == pci->subsystem_device) { + if (!pci->subsystem_vendor && !pci->subsystem_device) { pr_err("Your board has no valid PCI Subsystem ID and thus can't\n"); pr_err("be autodetected. Please pass card= insmod option to\n"); pr_err("workaround that. Redirect complaints to the vendor of\n"); @@ -3274,7 +3288,9 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE_HVR1300: /* - * Bring the 702 demod up before i2c scanning/attach or devices are hidden + * Bring the 702 demod up before i2c scanning/attach or + * devices are hidden. + * * We leave here with the 702 on the bus * * "reset the IR receiver on GPIO[3]" @@ -3295,7 +3311,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) cx_write(MO_GP2_IO, 0xef5); mdelay(50); cx_write(MO_GP2_IO, 0xcf7); - msleep(10); + usleep_range(10000, 20000); break; case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: @@ -3331,7 +3347,7 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core) case CX88_BOARD_TWINHAN_VP1027_DVBS: cx_write(MO_GP0_IO, 0x00003230); cx_write(MO_GP0_IO, 0x00003210); - msleep(1); + usleep_range(10000, 20000); cx_write(MO_GP0_IO, 0x00001230); break; } @@ -3362,11 +3378,13 @@ void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl) ctl->demod = XC3028_FE_OREN538; break; case CX88_BOARD_GENIATECH_X8000_MT: - /* FIXME: For this board, the xc3028 never recovers after being - powered down (the reset GPIO probably is not set properly). - We don't have access to the hardware so we cannot determine - which GPIO is used for xc3028, so just disable power xc3028 - power management for now */ + /* + * FIXME: For this board, the xc3028 never recovers after being + * powered down (the reset GPIO probably is not set properly). + * We don't have access to the hardware so we cannot determine + * which GPIO is used for xc3028, so just disable power xc3028 + * power management for now + */ ctl->disable_power_mgmt = 1; break; case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL: @@ -3396,7 +3414,7 @@ static void cx88_card_setup(struct cx88_core *core) memset(&tun_setup, 0, sizeof(tun_setup)); - if (core->i2c_rc == 0) { + if (!core->i2c_rc) { core->i2c_client.addr = 0xa0 >> 1; tveeprom_read(&core->i2c_client, eeprom, sizeof(eeprom)); } @@ -3404,17 +3422,17 @@ static void cx88_card_setup(struct cx88_core *core) switch (core->boardnr) { case CX88_BOARD_HAUPPAUGE: case CX88_BOARD_HAUPPAUGE_ROSLYN: - if (core->i2c_rc == 0) - hauppauge_eeprom(core, eeprom+8); + if (!core->i2c_rc) + hauppauge_eeprom(core, eeprom + 8); break; case CX88_BOARD_GDI: - if (core->i2c_rc == 0) + if (!core->i2c_rc) gdi_eeprom(core, eeprom); break; case CX88_BOARD_LEADTEK_PVR2000: case CX88_BOARD_WINFAST_DV2000: case CX88_BOARD_WINFAST2000XP_EXPERT: - if (core->i2c_rc == 0) + if (!core->i2c_rc) leadtek_eeprom(core, eeprom); break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: @@ -3427,7 +3445,7 @@ static void cx88_card_setup(struct cx88_core *core) case CX88_BOARD_HAUPPAUGE_HVR4000: case CX88_BOARD_HAUPPAUGE_HVR4000LITE: case CX88_BOARD_HAUPPAUGE_IRONLY: - if (core->i2c_rc == 0) + if (!core->i2c_rc) hauppauge_eeprom(core, eeprom); break; case CX88_BOARD_KWORLD_DVBS_100: @@ -3438,7 +3456,7 @@ static void cx88_card_setup(struct cx88_core *core) /* GPIO0:0 is hooked to demod reset */ /* GPIO0:4 is hooked to xc3028 reset */ cx_write(MO_GP0_IO, 0x00111100); - msleep(1); + usleep_range(10000, 20000); cx_write(MO_GP0_IO, 0x00111111); break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: @@ -3454,9 +3472,9 @@ static void cx88_card_setup(struct cx88_core *core) /* GPIO0:0 is hooked to mt352 reset pin */ cx_set(MO_GP0_IO, 0x00000101); cx_clear(MO_GP0_IO, 0x00000001); - msleep(1); + usleep_range(10000, 20000); cx_set(MO_GP0_IO, 0x00000101); - if (0 == core->i2c_rc && + if (!core->i2c_rc && core->boardnr == CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID) dvico_fusionhdtv_hybrid_init(core); break; @@ -3465,7 +3483,7 @@ static void cx88_card_setup(struct cx88_core *core) cx_set(MO_GP0_IO, 0x00000707); cx_set(MO_GP2_IO, 0x00000101); cx_clear(MO_GP2_IO, 0x00000001); - msleep(1); + usleep_range(10000, 20000); cx_clear(MO_GP0_IO, 0x00000007); cx_set(MO_GP2_IO, 0x00000101); break; @@ -3473,7 +3491,7 @@ static void cx88_card_setup(struct cx88_core *core) cx_write(MO_GP0_IO, 0x00080808); break; case CX88_BOARD_ATI_HDTVWONDER: - if (core->i2c_rc == 0) { + if (!core->i2c_rc) { /* enable tuner */ int i; static const u8 buffer[][2] = { @@ -3486,8 +3504,8 @@ static void cx88_card_setup(struct cx88_core *core) core->i2c_client.addr = 0x0a; for (i = 0; i < ARRAY_SIZE(buffer); i++) - if (2 != i2c_master_send(&core->i2c_client, - buffer[i], 2)) + if (i2c_master_send(&core->i2c_client, + buffer[i], 2) != 2) pr_warn("Unable to enable tuner(%i).\n", i); } @@ -3523,7 +3541,7 @@ static void cx88_card_setup(struct cx88_core *core) cx_write(MO_GP0_IO, 0x8000); msleep(100); cx_write(MO_SRST_IO, 0); - msleep(10); + usleep_range(10000, 20000); cx_write(MO_GP0_IO, 0x8080); msleep(100); cx_write(MO_SRST_IO, 1); @@ -3531,9 +3549,8 @@ static void cx88_card_setup(struct cx88_core *core) break; } /*end switch() */ - /* Setup tuners */ - if ((core->board.radio_type != UNSET)) { + if (core->board.radio_type != UNSET) { tun_setup.mode_mask = T_RADIO; tun_setup.type = core->board.radio_type; tun_setup.addr = core->board.radio_addr; @@ -3621,8 +3638,7 @@ static int cx88_pci_quirks(const char *name, struct pci_dev *pci) pci_write_config_byte(pci, CX88X_DEVCTRL, value); } if (lat != UNSET) { - pr_info("setting pci latency timer to %d\n", - latency); + pr_info("setting pci latency timer to %d\n", latency); pci_write_config_byte(pci, PCI_LATENCY_TIMER, latency); } return 0; @@ -3641,15 +3657,17 @@ int cx88_get_resources(const struct cx88_core *core, struct pci_dev *pci) return -EBUSY; } -/* Allocate and initialize the cx88 core struct. One should hold the - * devlist mutex before calling this. */ +/* + * Allocate and initialize the cx88 core struct. One should hold the + * devlist mutex before calling this. + */ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) { struct cx88_core *core; int i; core = kzalloc(sizeof(*core), GFP_KERNEL); - if (core == NULL) + if (!core) return NULL; atomic_inc(&core->refcount); @@ -3701,9 +3719,9 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) pci_resource_len(pci, 0)); core->bmmio = (u8 __iomem *)core->lmmio; - if (core->lmmio == NULL) { + if (!core->lmmio) { release_mem_region(pci_resource_start(pci, 0), - pci_resource_len(pci, 0)); + pci_resource_len(pci, 0)); v4l2_ctrl_handler_free(&core->video_hdl); v4l2_ctrl_handler_free(&core->audio_hdl); v4l2_device_unregister(&core->v4l2_dev); @@ -3715,7 +3733,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) core->boardnr = UNSET; if (card[core->nr] < ARRAY_SIZE(cx88_boards)) core->boardnr = card[core->nr]; - for (i = 0; UNSET == core->boardnr && i < ARRAY_SIZE(cx88_subids); i++) + for (i = 0; core->boardnr == UNSET && i < ARRAY_SIZE(cx88_subids); i++) if (pci->subsystem_vendor == cx88_subids[i].subvendor && pci->subsystem_device == cx88_subids[i].subdevice) core->boardnr = cx88_subids[i].card; @@ -3750,9 +3768,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) /* load tuner module, if needed */ if (core->board.tuner_type != UNSET) { - /* Ignore 0x6b and 0x6f on cx88 boards. + /* + * Ignore 0x6b and 0x6f on cx88 boards. * FusionHDTV5 RT Gold has an ir receiver at 0x6b - * and an RTC at 0x6f which can get corrupted if probed. */ + * and an RTC at 0x6f which can get corrupted if probed. + */ static const unsigned short tv_addrs[] = { 0x42, 0x43, 0x4a, 0x4b, /* tda8290 */ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, @@ -3761,24 +3781,27 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) }; int has_demod = (core->board.tda9887_conf & TDA9887_PRESENT); - /* I don't trust the radio_type as is stored in the card - definitions, so we just probe for it. - The radio_type is sometimes missing, or set to UNSET but - later code configures a tea5767. + /* + * I don't trust the radio_type as is stored in the card + * definitions, so we just probe for it. + * The radio_type is sometimes missing, or set to UNSET but + * later code configures a tea5767. */ v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO)); + "tuner", 0, + v4l2_i2c_tuner_addrs(ADDRS_RADIO)); if (has_demod) v4l2_i2c_new_subdev(&core->v4l2_dev, - &core->i2c_adap, "tuner", + &core->i2c_adap, "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD)); if (core->board.tuner_addr == ADDR_UNSET) { v4l2_i2c_new_subdev(&core->v4l2_dev, - &core->i2c_adap, "tuner", + &core->i2c_adap, "tuner", 0, has_demod ? tv_addrs + 4 : tv_addrs); } else { v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - "tuner", core->board.tuner_addr, NULL); + "tuner", core->board.tuner_addr, + NULL); } } diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c index 33719f0b06a5..973a9cd4c635 100644 --- a/drivers/media/pci/cx88/cx88-core.c +++ b/drivers/media/pci/cx88/cx88-core.c @@ -72,12 +72,14 @@ static DEFINE_MUTEX(devlist); #define NO_SYNC_LINE (-1U) -/* @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be - generated _after_ lpi lines are transferred. */ +/* + * @lpi: lines per IRQ, or 0 to not generate irqs. Note: IRQ to be + * generated _after_ lpi lines are transferred. + */ static __le32 *cx88_risc_field(__le32 *rp, struct scatterlist *sglist, - unsigned int offset, u32 sync_line, - unsigned int bpl, unsigned int padding, - unsigned int lines, unsigned int lpi, bool jump) + unsigned int offset, u32 sync_line, + unsigned int bpl, unsigned int padding, + unsigned int lines, unsigned int lpi, bool jump) { struct scatterlist *sg; unsigned int line, todo, sol; @@ -102,28 +104,29 @@ static __le32 *cx88_risc_field(__le32 *rp, struct scatterlist *sglist, sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC; else sol = RISC_SOL; - if (bpl <= sg_dma_len(sg)-offset) { + if (bpl <= sg_dma_len(sg) - offset) { /* fits into current chunk */ - *(rp++) = cpu_to_le32(RISC_WRITE|sol|RISC_EOL|bpl); - *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); + *(rp++) = cpu_to_le32(RISC_WRITE | sol | + RISC_EOL | bpl); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); offset += bpl; } else { /* scanline needs to be split */ todo = bpl; - *(rp++) = cpu_to_le32(RISC_WRITE|sol| - (sg_dma_len(sg)-offset)); - *(rp++) = cpu_to_le32(sg_dma_address(sg)+offset); - todo -= (sg_dma_len(sg)-offset); + *(rp++) = cpu_to_le32(RISC_WRITE | sol | + (sg_dma_len(sg) - offset)); + *(rp++) = cpu_to_le32(sg_dma_address(sg) + offset); + todo -= (sg_dma_len(sg) - offset); offset = 0; sg = sg_next(sg); while (todo > sg_dma_len(sg)) { - *(rp++) = cpu_to_le32(RISC_WRITE| - sg_dma_len(sg)); + *(rp++) = cpu_to_le32(RISC_WRITE | + sg_dma_len(sg)); *(rp++) = cpu_to_le32(sg_dma_address(sg)); todo -= sg_dma_len(sg); sg = sg_next(sg); } - *(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo); + *(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo); *(rp++) = cpu_to_le32(sg_dma_address(sg)); offset += todo; } @@ -147,16 +150,19 @@ int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc, if (bottom_offset != UNSET) fields++; - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Padding - can cause next bpl to start close to a page border. First DMA - region may be smaller than PAGE_SIZE */ - instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines); + /* + * estimate risc mem: worst case is one write per page border + + * one write per scan line + syncs + jump (all 2 dwords). Padding + * can cause next bpl to start close to a page border. First DMA + * region may be smaller than PAGE_SIZE + */ + instructions = fields * (1 + ((bpl + padding) * lines) / + PAGE_SIZE + lines); instructions += 4; risc->size = instructions * 8; risc->dma = 0; risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma); - if (risc->cpu == NULL) + if (!risc->cpu) return -ENOMEM; /* write risc instructions */ @@ -166,13 +172,15 @@ int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc, bpl, padding, lines, 0, true); if (bottom_offset != UNSET) rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200, - bpl, padding, lines, 0, top_offset == UNSET); + bpl, padding, lines, 0, + top_offset == UNSET); /* save pointer to jmp instruction address */ risc->jmp = rp; WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } +EXPORT_SYMBOL(cx88_risc_buffer); int cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, @@ -181,32 +189,38 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc, u32 instructions; __le32 *rp; - /* estimate risc mem: worst case is one write per page border + - one write per scan line + syncs + jump (all 2 dwords). Here - there is no padding and no sync. First DMA region may be smaller - than PAGE_SIZE */ + /* + * estimate risc mem: worst case is one write per page border + + * one write per scan line + syncs + jump (all 2 dwords). Here + * there is no padding and no sync. First DMA region may be smaller + * than PAGE_SIZE + */ instructions = 1 + (bpl * lines) / PAGE_SIZE + lines; instructions += 3; risc->size = instructions * 8; risc->dma = 0; risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma); - if (risc->cpu == NULL) + if (!risc->cpu) return -ENOMEM; /* write risc instructions */ rp = risc->cpu; - rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi, !lpi); + rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, + lines, lpi, !lpi); /* save pointer to jmp instruction address */ risc->jmp = rp; WARN_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size); return 0; } +EXPORT_SYMBOL(cx88_risc_databuffer); -/* ------------------------------------------------------------------ */ -/* our SRAM memory layout */ +/* + * our SRAM memory layout + */ -/* we are going to put all thr risc programs into host memory, so we +/* + * we are going to put all thr risc programs into host memory, so we * can use the whole SDRAM for the DMA fifos. To simplify things, we * use a static memory layout. That surely will waste memory in case * we don't use all DMA channels at the same time (which will be the @@ -330,6 +344,7 @@ const struct sram_channel cx88_sram_channels[] = { .cnt2_reg = MO_DMA27_CNT2, }, }; +EXPORT_SYMBOL(cx88_sram_channels); int cx88_sram_channel_setup(struct cx88_core *core, const struct sram_channel *ch, @@ -347,12 +362,12 @@ int cx88_sram_channel_setup(struct cx88_core *core, /* write CDT */ for (i = 0; i < lines; i++) - cx_write(cdt + 16*i, ch->fifo_start + bpl*i); + cx_write(cdt + 16 * i, ch->fifo_start + bpl * i); /* write CMDS */ cx_write(ch->cmds_start + 0, risc); cx_write(ch->cmds_start + 4, cdt); - cx_write(ch->cmds_start + 8, (lines*16) >> 3); + cx_write(ch->cmds_start + 8, (lines * 16) >> 3); cx_write(ch->cmds_start + 12, ch->ctrl_start); cx_write(ch->cmds_start + 16, 64 >> 2); for (i = 20; i < 64; i += 4) @@ -362,11 +377,12 @@ int cx88_sram_channel_setup(struct cx88_core *core, cx_write(ch->ptr1_reg, ch->fifo_start); cx_write(ch->ptr2_reg, cdt); cx_write(ch->cnt1_reg, (bpl >> 3) - 1); - cx_write(ch->cnt2_reg, (lines*16) >> 3); + cx_write(ch->cnt2_reg, (lines * 16) >> 3); dprintk(2, "sram setup %s: bpl=%d lines=%d\n", ch->name, bpl, lines); return 0; } +EXPORT_SYMBOL(cx88_sram_channel_setup); /* ------------------------------------------------------------------ */ /* debug helper code */ @@ -401,15 +417,14 @@ static int cx88_risc_decode(u32 risc) int i; dprintk0("0x%08x [ %s", risc, - instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); - for (i = ARRAY_SIZE(bits)-1; i >= 0; i--) + instr[risc >> 28] ? instr[risc >> 28] : "INVALID"); + for (i = ARRAY_SIZE(bits) - 1; i >= 0; i--) if (risc & (1 << (i + 12))) pr_cont(" %s", bits[i]); pr_cont(" count=%d ]\n", risc & 0xfff); return incr[risc >> 28] ? incr[risc >> 28] : 1; } - void cx88_sram_channel_dump(struct cx88_core *core, const struct sram_channel *ch) { @@ -429,14 +444,12 @@ void cx88_sram_channel_dump(struct cx88_core *core, u32 risc; unsigned int i, j, n; - dprintk0("%s - dma channel status dump\n", - ch->name); + dprintk0("%s - dma channel status dump\n", ch->name); for (i = 0; i < ARRAY_SIZE(name); i++) dprintk0(" cmds: %-12s: 0x%08x\n", - name[i], - cx_read(ch->cmds_start + 4*i)); + name[i], cx_read(ch->cmds_start + 4 * i)); for (n = 1, i = 0; i < 4; i++) { - risc = cx_read(ch->cmds_start + 4 * (i+11)); + risc = cx_read(ch->cmds_start + 4 * (i + 11)); pr_cont(" risc%d: ", i); if (--n) pr_cont("0x%08x [ arg #%d ]\n", risc, n); @@ -448,21 +461,22 @@ void cx88_sram_channel_dump(struct cx88_core *core, dprintk0(" iq %x: ", i); n = cx88_risc_decode(risc); for (j = 1; j < n; j++) { - risc = cx_read(ch->ctrl_start + 4 * (i+j)); + risc = cx_read(ch->ctrl_start + 4 * (i + j)); pr_cont(" iq %x: 0x%08x [ arg #%d ]\n", i + j, risc, j); } } dprintk0("fifo: 0x%08x -> 0x%x\n", - ch->fifo_start, ch->fifo_start+ch->fifo_size); + ch->fifo_start, ch->fifo_start + ch->fifo_size); dprintk0("ctrl: 0x%08x -> 0x%x\n", - ch->ctrl_start, ch->ctrl_start + 6 * 16); + ch->ctrl_start, ch->ctrl_start + 6 * 16); dprintk0(" ptr1_reg: 0x%08x\n", cx_read(ch->ptr1_reg)); dprintk0(" ptr2_reg: 0x%08x\n", cx_read(ch->ptr2_reg)); dprintk0(" cnt1_reg: 0x%08x\n", cx_read(ch->cnt1_reg)); dprintk0(" cnt2_reg: 0x%08x\n", cx_read(ch->cnt2_reg)); } +EXPORT_SYMBOL(cx88_sram_channel_dump); static const char *cx88_pci_irqs[32] = { "vid", "aud", "ts", "vip", "hst", "5", "6", "tm1", @@ -490,6 +504,7 @@ void cx88_print_irqbits(const char *tag, const char *strings[], } pr_cont("\n"); } +EXPORT_SYMBOL(cx88_print_irqbits); /* ------------------------------------------------------------------ */ @@ -507,6 +522,7 @@ int cx88_core_irq(struct cx88_core *core, u32 status) status, core->pci_irqmask); return handled; } +EXPORT_SYMBOL(cx88_core_irq); void cx88_wakeup(struct cx88_core *core, struct cx88_dmaqueue *q, u32 count) @@ -521,6 +537,7 @@ void cx88_wakeup(struct cx88_core *core, list_del(&buf->list); vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE); } +EXPORT_SYMBOL(cx88_wakeup); void cx88_shutdown(struct cx88_core *core) { @@ -545,6 +562,7 @@ void cx88_shutdown(struct cx88_core *core) /* stop capturing */ cx_write(VID_CAPTURE_CONTROL, 0); } +EXPORT_SYMBOL(cx88_shutdown); int cx88_reset(struct cx88_core *core) { @@ -560,13 +578,15 @@ int cx88_reset(struct cx88_core *core) msleep(100); /* init sram */ - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], 720*4, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21], + 720 * 4, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH22], 128, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH23], 128, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH24], 128, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); - cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0); + cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], + 188 * 4, 0); cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0); /* misc init ... */ @@ -594,11 +614,12 @@ int cx88_reset(struct cx88_core *core) /* Reset on-board parts */ cx_write(MO_SRST_IO, 0); - msleep(10); + usleep_range(10000, 20000); cx_write(MO_SRST_IO, 1); return 0; } +EXPORT_SYMBOL(cx88_reset); /* ------------------------------------------------------------------ */ @@ -628,10 +649,11 @@ static inline unsigned int norm_fsc8(v4l2_std_id norm) if (norm & V4L2_STD_NTSC) // All NTSC/M and variants return 28636360; // 3.57954545 MHz +/- 10 Hz - /* SECAM have also different sub carrier for chroma, - but step_db and step_dr, at cx88_set_tvnorm already handles that. - - The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N + /* + * SECAM have also different sub carrier for chroma, + * but step_db and step_dr, at cx88_set_tvnorm already handles that. + * + * The same FSC applies to PAL/BGDKIH, PAL/60, NTSC/4.43 and PAL/N */ return 35468950; // 4.43361875 MHz +/- 5 Hz @@ -639,13 +661,12 @@ static inline unsigned int norm_fsc8(v4l2_std_id norm) static inline unsigned int norm_htotal(v4l2_std_id norm) { - - unsigned int fsc4 = norm_fsc8(norm)/2; + unsigned int fsc4 = norm_fsc8(norm) / 2; /* returns 4*FSC / vtotal / frames per seconds */ return (norm & V4L2_STD_625_50) ? - ((fsc4+312)/625+12)/25 : - ((fsc4+262)/525*1001+15000)/30000; + ((fsc4 + 312) / 625 + 12) / 25 : + ((fsc4 + 262) / 525 * 1001 + 15000) / 30000; } static inline unsigned int norm_vbipack(v4l2_std_id norm) @@ -653,8 +674,8 @@ static inline unsigned int norm_vbipack(v4l2_std_id norm) return (norm & V4L2_STD_625_50) ? 511 : 400; } -int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int height, - enum v4l2_field field) +int cx88_set_scale(struct cx88_core *core, unsigned int width, + unsigned int height, enum v4l2_field field) { unsigned int swidth = norm_swidth(core->tvnorm); unsigned int sheight = norm_maxh(core->tvnorm); @@ -721,6 +742,7 @@ int cx88_set_scale(struct cx88_core *core, unsigned int width, unsigned int heig return 0; } +EXPORT_SYMBOL(cx88_set_scale); static const u32 xtal = 28636363; @@ -749,13 +771,13 @@ static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) cx_write(MO_PLL_REG, reg); for (i = 0; i < 100; i++) { reg = cx_read(MO_DEVICE_STATUS); - if (reg & (1<<2)) { + if (reg & (1 << 2)) { dprintk(1, "pll locked [pre=%d,ofreq=%d]\n", prescale, ofreq); return 0; } dprintk(1, "pll not locked yet, waiting ...\n"); - msleep(10); + usleep_range(10000, 20000); } dprintk(1, "pll NOT locked [pre=%d,ofreq=%d]\n", prescale, ofreq); return -1; @@ -764,9 +786,9 @@ static int set_pll(struct cx88_core *core, int prescale, u32 ofreq) int cx88_start_audio_dma(struct cx88_core *core) { /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */ - int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4; + int bpl = cx88_sram_channels[SRAM_CH25].fifo_size / 4; - int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES; + int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size / AUD_RDS_LINES; /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ if (cx_read(MO_AUD_DMACNTRL) & 0x10) @@ -803,8 +825,8 @@ static int set_tvaudio(struct cx88_core *core) { v4l2_std_id norm = core->tvnorm; - if (CX88_VMUX_TELEVISION != INPUT(core->input).type && - CX88_VMUX_CABLE != INPUT(core->input).type) + if (INPUT(core->input).type != CX88_VMUX_TELEVISION && + INPUT(core->input).type != CX88_VMUX_CABLE) return 0; if (V4L2_STD_PAL_BG & norm) { @@ -819,7 +841,8 @@ static int set_tvaudio(struct cx88_core *core) } else if (V4L2_STD_SECAM_L & norm) { core->tvaudio = WW_L; - } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & norm) { + } else if ((V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H) & + norm) { core->tvaudio = WW_BG; } else if (V4L2_STD_SECAM_DK & norm) { @@ -844,15 +867,13 @@ static int set_tvaudio(struct cx88_core *core) /* cx88_set_stereo(dev,V4L2_TUNER_MODE_STEREO); */ /* - This should be needed only on cx88-alsa. It seems that some cx88 chips have - bugs and does require DMA enabled for it to work. + * This should be needed only on cx88-alsa. It seems that some cx88 chips have + * bugs and does require DMA enabled for it to work. */ cx88_start_audio_dma(core); return 0; } - - int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) { u32 fsc8; @@ -916,8 +937,10 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) dprintk(1, "set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n", cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f); - /* Chroma AGC must be disabled if SECAM is used, we enable it - by default on PAL and NTSC */ + /* + * Chroma AGC must be disabled if SECAM is used, we enable it + * by default on PAL and NTSC + */ cx_andor(MO_INPUT_FORMAT, 0x40f, norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400); @@ -952,7 +975,8 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) agcdelay = vdec_clock * 68 / 20000000 + 15; dprintk(1, "set_tvnorm: MO_AGC_BURST 0x%08x [old=0x%08x,bdelay=%d,agcdelay=%d]\n", - (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), bdelay, agcdelay); + (bdelay << 8) | agcdelay, cx_read(MO_AGC_BURST), + bdelay, agcdelay); cx_write(MO_AGC_BURST, (bdelay << 8) | agcdelay); // htotal @@ -966,7 +990,7 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) // vbi stuff, set vbi offset to 10 (for 20 Clk*2 pixels), this makes // the effective vbi offset ~244 samples, the same as the Bt8x8 - cx_write(MO_VBI_PACKET, (10<<11) | norm_vbipack(norm)); + cx_write(MO_VBI_PACKET, (10 << 11) | norm_vbipack(norm)); // this is needed as well to set all tvnorm parameter cx88_set_scale(core, 320, 240, V4L2_FIELD_INTERLACED); @@ -977,12 +1001,16 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) // tell i2c chips call_all(core, video, s_std, norm); - /* The chroma_agc control should be inaccessible if the video format is SECAM */ + /* + * The chroma_agc control should be inaccessible + * if the video format is SECAM + */ v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM); // done return 0; } +EXPORT_SYMBOL(cx88_set_tvnorm); /* ------------------------------------------------------------------ */ @@ -1007,6 +1035,7 @@ void cx88_vdev_init(struct cx88_core *core, snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", core->name, type, core->board.name); } +EXPORT_SYMBOL(cx88_vdev_init); struct cx88_core *cx88_core_get(struct pci_dev *pci) { @@ -1029,7 +1058,7 @@ struct cx88_core *cx88_core_get(struct pci_dev *pci) } core = cx88_core_create(pci, cx88_devcount); - if (core != NULL) { + if (core) { cx88_devcount++; list_add_tail(&core->devlist, &cx88_devlist); } @@ -1037,6 +1066,7 @@ struct cx88_core *cx88_core_get(struct pci_dev *pci) mutex_unlock(&devlist); return core; } +EXPORT_SYMBOL(cx88_core_get); void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) { @@ -1062,29 +1092,4 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) v4l2_device_unregister(&core->v4l2_dev); kfree(core); } - -/* ------------------------------------------------------------------ */ - -EXPORT_SYMBOL(cx88_print_irqbits); - -EXPORT_SYMBOL(cx88_core_irq); -EXPORT_SYMBOL(cx88_wakeup); -EXPORT_SYMBOL(cx88_reset); -EXPORT_SYMBOL(cx88_shutdown); - -EXPORT_SYMBOL(cx88_risc_buffer); -EXPORT_SYMBOL(cx88_risc_databuffer); - -EXPORT_SYMBOL(cx88_sram_channels); -EXPORT_SYMBOL(cx88_sram_channel_setup); -EXPORT_SYMBOL(cx88_sram_channel_dump); - -EXPORT_SYMBOL(cx88_set_tvnorm); -EXPORT_SYMBOL(cx88_set_scale); - -EXPORT_SYMBOL(cx88_vdev_init); -EXPORT_SYMBOL(cx88_core_get); EXPORT_SYMBOL(cx88_core_put); - -EXPORT_SYMBOL(cx88_ir_start); -EXPORT_SYMBOL(cx88_ir_stop); diff --git a/drivers/media/pci/cx88/cx88-dsp.c b/drivers/media/pci/cx88/cx88-dsp.c index 235124e2a763..105029088120 100644 --- a/drivers/media/pci/cx88/cx88-dsp.c +++ b/drivers/media/pci/cx88/cx88-dsp.c @@ -31,18 +31,22 @@ #define baseband_freq(carrier, srate, tone) ((s32)( \ (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI)) -/* We calculate the baseband frequencies of the carrier and the pilot tones - * based on the the sampling rate of the audio rds fifo. */ +/* + * We calculate the baseband frequencies of the carrier and the pilot tones + * based on the the sampling rate of the audio rds fifo. + */ #define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) #define FREQ_A2_DUAL baseband_freq(54687.5, 2689.36, 274.1) #define FREQ_A2_STEREO baseband_freq(54687.5, 2689.36, 117.5) -/* The frequencies below are from the reference driver. They probably need +/* + * The frequencies below are from the reference driver. They probably need * further adjustments, because they are not tested at all. You may even need * to play a bit with the registers of the chip to select the proper signal * for the input of the audio rds fifo, and measure it's sampling rate to - * calculate the proper baseband frequencies... */ + * calculate the proper baseband frequencies... + */ #define FREQ_A2M_CARRIER ((s32)(2.114516 * 32768.0)) #define FREQ_A2M_DUAL ((s32)(2.754916 * 32768.0)) @@ -83,8 +87,10 @@ static s32 int_cos(u32 x) x = x % INT_PI; if (x > INT_PI / 2) return -int_cos(INT_PI / 2 - (x % (INT_PI / 2))); - /* Now x is between 0 and INT_PI/2. - * To calculate cos(x) we use it's Taylor polinom. */ + /* + * Now x is between 0 and INT_PI/2. + * To calculate cos(x) we use it's Taylor polinom. + */ t2 = x * x / 32768 / 2; t4 = t2 * x / 32768 * x / 32768 / 3 / 4; t6 = t4 * x / 32768 * x / 32768 / 5 / 6; @@ -95,8 +101,10 @@ static s32 int_cos(u32 x) static u32 int_goertzel(s16 x[], u32 N, u32 freq) { - /* We use the Goertzel algorithm to determine the power of the - * given frequency in the signal */ + /* + * We use the Goertzel algorithm to determine the power of the + * given frequency in the signal + */ s32 s_prev = 0; s32 s_prev2 = 0; s32 coeff = 2 * int_cos(freq); @@ -115,12 +123,14 @@ static u32 int_goertzel(s16 x[], u32 N, u32 freq) tmp = (s64)s_prev2 * s_prev2 + (s64)s_prev * s_prev - (s64)coeff * s_prev2 * s_prev / 32768; - /* XXX: N must be low enough so that N*N fits in s32. - * Else we need two divisions. */ + /* + * XXX: N must be low enough so that N*N fits in s32. + * Else we need two divisions. + */ divisor = N * N; do_div(tmp, divisor); - return (u32) tmp; + return (u32)tmp; } static u32 freq_magnitude(s16 x[], u32 N, u32 freq) @@ -187,7 +197,8 @@ static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) dual = freq_magnitude(x, N, dual_freq); noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END); - dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, noise=%d\n", + dprintk(1, + "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, noise=%d\n", carrier, stereo, dual, noise); if (stereo > dual) @@ -201,8 +212,10 @@ static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) (carrier < max(stereo, dual) * 6) && (carrier > 20 && carrier < 200) && (max(stereo, dual) > min(stereo, dual))) { - /* For EIAJ the carrier is always present, - so we probably don't need noise detection */ + /* + * For EIAJ the carrier is always present, + * so we probably don't need noise detection + */ return ret; } } else { @@ -243,7 +256,8 @@ static s16 *read_rds_samples(struct cx88_core *core, u32 *N) u32 current_address = cx_read(srch->ptr1_reg); u32 offset = (current_address - srch->fifo_start + bpl); - dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), sample_count=%d, aud_intstat=%08x\n", + dprintk(1, + "read RDS samples: current_address=%08x (offset=%08x), sample_count=%d, aud_intstat=%08x\n", current_address, current_address - srch->fifo_start, sample_count, cx_read(MO_AUD_INTSTAT)); @@ -308,9 +322,9 @@ s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core) if (ret != UNSET) dprintk(1, "stereo/sap detection result:%s%s%s\n", - (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", - (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", - (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : ""); + (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", + (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", + (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : ""); return ret; } diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c index 5188f8f2d6dd..ddf90678df34 100644 --- a/drivers/media/pci/cx88/cx88-dvb.c +++ b/drivers/media/pci/cx88/cx88-dvb.c @@ -82,8 +82,8 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /* ------------------------------------------------------------------ */ static int queue_setup(struct vb2_queue *q, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], struct device *alloc_devs[]) + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8802_dev *dev = q->drv_priv; @@ -445,7 +445,7 @@ static const struct nxt200x_config ati_hdtvwonder = { }; static int cx24123_set_ts_param(struct dvb_frontend *fe, - int is_punctured) + int is_punctured) { struct cx8802_dev *dev = fe->dvb->priv; @@ -684,7 +684,7 @@ static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg) } static int cx24116_set_ts_param(struct dvb_frontend *fe, - int is_punctured) + int is_punctured) { struct cx8802_dev *dev = fe->dvb->priv; @@ -694,7 +694,7 @@ static int cx24116_set_ts_param(struct dvb_frontend *fe, } static int stv0900_set_ts_param(struct dvb_frontend *fe, - int is_punctured) + int is_punctured) { struct cx8802_dev *dev = fe->dvb->priv; @@ -711,10 +711,10 @@ static int cx24116_reset_device(struct dvb_frontend *fe) /* Reset the part */ /* Put the cx24116 into reset */ cx_write(MO_SRST_IO, 0); - msleep(10); + usleep_range(10000, 20000); /* Take the cx24116 out of reset */ cx_write(MO_SRST_IO, 1); - msleep(10); + usleep_range(10000, 20000); return 0; } @@ -732,7 +732,7 @@ static const struct cx24116_config tevii_s460_config = { }; static int ds3000_set_ts_param(struct dvb_frontend *fe, - int is_punctured) + int is_punctured) { struct cx8802_dev *dev = fe->dvb->priv; @@ -812,8 +812,6 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev) return 0; } - - static const u8 samsung_smt_7020_inittab[] = { 0x01, 0x15, 0x02, 0x00, @@ -865,7 +863,6 @@ static const u8 samsung_smt_7020_inittab[] = { 0xff, 0xff, }; - static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe) { struct dtv_frontend_properties *c = &fe->dtv_property_cache; @@ -898,7 +895,7 @@ static int samsung_smt_7020_tuner_set_params(struct dvb_frontend *fe) } static int samsung_smt_7020_set_tone(struct dvb_frontend *fe, - enum fe_sec_tone_mode tone) + enum fe_sec_tone_mode tone) { struct cx8802_dev *dev = fe->dvb->priv; struct cx88_core *core = dev->core; @@ -953,7 +950,7 @@ static int samsung_smt_7020_set_voltage(struct dvb_frontend *fe, } static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe, - u32 srate, u32 ratio) + u32 srate, u32 ratio) { u8 aclk = 0; u8 bclk = 0; @@ -987,7 +984,6 @@ static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe, return 0; } - static const struct stv0299_config samsung_stv0299_config = { .demod_address = 0x68, .inittab = samsung_smt_7020_inittab, @@ -1029,7 +1025,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, &core->i2c_adap, DVB_PLL_THOMSON_DTT759X)) @@ -1043,7 +1039,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx22702_attach, &connexant_refboard_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, &core->i2c_adap, DVB_PLL_THOMSON_DTT7579)) @@ -1057,10 +1053,10 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx22702_attach, &hauppauge_hvr_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216ME_MK3)) + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216ME_MK3)) goto frontend_detach; } break; @@ -1068,10 +1064,10 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx22702_attach, &hauppauge_hvr_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_PHILIPS_FMD1216MEX_MK3)) + &core->i2c_adap, 0x61, + TUNER_PHILIPS_FMD1216MEX_MK3)) goto frontend_detach; } break; @@ -1081,8 +1077,8 @@ static int dvb_register(struct cx8802_dev *dev) dev->frontends.gate = 2; /* DVB-S init */ fe0->dvb.frontend = dvb_attach(cx24123_attach, - &hauppauge_novas_config, - &dev->core->i2c_adap); + &hauppauge_novas_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, @@ -1096,8 +1092,8 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; /* DVB-T init */ fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); + &hauppauge_hvr_config, + &dev->core->i2c_adap); if (fe1->dvb.frontend) { fe1->dvb.frontend->id = 1; if (!dvb_attach(simple_tuner_attach, @@ -1111,7 +1107,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) goto frontend_detach; @@ -1121,19 +1117,21 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_plus_v1_1, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, NULL, DVB_PLL_THOMSON_DTT7579)) goto frontend_detach; } break; case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL: - /* The tin box says DEE1601, but it seems to be DTT7579 - * compatible, with a slightly different MT352 AGC gain. */ + /* + * The tin box says DEE1601, but it seems to be DTT7579 + * compatible, with a slightly different MT352 AGC gain. + */ fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv_dual, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) goto frontend_detach; @@ -1143,7 +1141,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_plus_v1_1, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, NULL, DVB_PLL_THOMSON_DTT7579)) goto frontend_detach; @@ -1153,7 +1151,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, NULL, DVB_PLL_LG_Z201)) goto frontend_detach; @@ -1165,7 +1163,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x61, NULL, DVB_PLL_UNKNOWN_1)) goto frontend_detach; @@ -1174,9 +1172,10 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_DNTV_LIVE_DVB_T_PRO: #if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054) /* MT352 is on a secondary I2C bus made from some GPIO lines */ - fe0->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config, + fe0->dvb.frontend = dvb_attach(mt352_attach, + &dntv_live_dvbt_pro_config, &dev->vp3054->adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_PHILIPS_FMD1216ME_MK3)) @@ -1190,10 +1189,10 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_hybrid, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x61, - TUNER_THOMSON_FE6600)) + &core->i2c_adap, 0x61, + TUNER_THOMSON_FE6600)) goto frontend_detach; } break; @@ -1201,7 +1200,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(zl10353_attach, &dvico_fusionhdtv_xc3028, &core->i2c_adap); - if (fe0->dvb.frontend == NULL) + if (!fe0->dvb.frontend) fe0->dvb.frontend = dvb_attach(mt352_attach, &dvico_fusionhdtv_mt352_xc3028, &core->i2c_adap); @@ -1218,7 +1217,7 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_PCHDTV_HD3000: fe0->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) @@ -1239,7 +1238,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_MICROTUNE_4042FI5)) @@ -1257,7 +1256,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_3_gold, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_THOMSON_DTT761X)) @@ -1275,13 +1274,13 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &fusionhdtv_5_gold, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF)) goto frontend_detach; if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x43)) + &core->i2c_adap, 0x43)) goto frontend_detach; } break; @@ -1296,13 +1295,13 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(lgdt330x_attach, &pchdtv_hd5500, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF)) goto frontend_detach; if (!dvb_attach(tda9887_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x43)) + &core->i2c_adap, 0x43)) goto frontend_detach; } break; @@ -1310,7 +1309,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(nxt200x_attach, &ati_hdtvwonder, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(simple_tuner_attach, fe0->dvb.frontend, &core->i2c_adap, 0x61, TUNER_PHILIPS_TUV1236D)) @@ -1331,8 +1330,8 @@ static int dvb_register(struct cx8802_dev *dev) override_tone = false; if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, - &core->i2c_adap, 0x08, ISL6421_DCL, 0x00, - override_tone)) + &core->i2c_adap, 0x08, ISL6421_DCL, + 0x00, override_tone)) goto frontend_detach; } break; @@ -1358,7 +1357,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(s5h1409_attach, &pinnacle_pctv_hd_800i_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(xc5000_attach, fe0->dvb.frontend, &core->i2c_adap, &pinnacle_pctv_hd_800i_tuner_config)) @@ -1367,9 +1366,9 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO: fe0->dvb.frontend = dvb_attach(s5h1409_attach, - &dvico_hdtv5_pci_nano_config, - &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + &dvico_hdtv5_pci_nano_config, + &core->i2c_adap); + if (fe0->dvb.frontend) { struct dvb_frontend *fe; struct xc2028_config cfg = { .i2c_adap = &core->i2c_adap, @@ -1383,7 +1382,7 @@ static int dvb_register(struct cx8802_dev *dev) fe = dvb_attach(xc2028_attach, fe0->dvb.frontend, &cfg); - if (fe != NULL && fe->ops.tuner_ops.set_config != NULL) + if (fe && fe->ops.tuner_ops.set_config) fe->ops.tuner_ops.set_config(fe, &ctl); } break; @@ -1436,7 +1435,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(s5h1411_attach, &dvico_fusionhdtv7_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(xc5000_attach, fe0->dvb.frontend, &core->i2c_adap, &dvico_fusionhdtv7_tuner_config)) @@ -1449,8 +1448,8 @@ static int dvb_register(struct cx8802_dev *dev) dev->frontends.gate = 2; /* DVB-S/S2 Init */ fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, @@ -1464,8 +1463,8 @@ static int dvb_register(struct cx8802_dev *dev) goto frontend_detach; /* DVB-T Init */ fe1->dvb.frontend = dvb_attach(cx22702_attach, - &hauppauge_hvr_config, - &dev->core->i2c_adap); + &hauppauge_hvr_config, + &dev->core->i2c_adap); if (fe1->dvb.frontend) { fe1->dvb.frontend->id = 1; if (!dvb_attach(simple_tuner_attach, @@ -1477,8 +1476,8 @@ static int dvb_register(struct cx8802_dev *dev) break; case CX88_BOARD_HAUPPAUGE_HVR4000LITE: fe0->dvb.frontend = dvb_attach(cx24116_attach, - &hauppauge_hvr4000_config, - &dev->core->i2c_adap); + &hauppauge_hvr4000_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { if (!dvb_attach(isl6421_attach, fe0->dvb.frontend, @@ -1493,7 +1492,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(stv0299_attach, &tevii_tuner_sharp_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { if (!dvb_attach(dvb_pll_attach, fe0->dvb.frontend, 0x60, &core->i2c_adap, DVB_PLL_OPERA1)) goto frontend_detach; @@ -1504,8 +1503,9 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(stv0288_attach, &tevii_tuner_earda_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { - if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61, + if (fe0->dvb.frontend) { + if (!dvb_attach(stb6000_attach, + fe0->dvb.frontend, 0x61, &core->i2c_adap)) goto frontend_detach; core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; @@ -1517,16 +1517,16 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx24116_attach, &tevii_s460_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) + if (fe0->dvb.frontend) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; break; case CX88_BOARD_TEVII_S464: fe0->dvb.frontend = dvb_attach(ds3000_attach, &tevii_ds3000_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) { + if (fe0->dvb.frontend) { dvb_attach(ts2020_attach, fe0->dvb.frontend, - &tevii_ts2020_config, &core->i2c_adap); + &tevii_ts2020_config, &core->i2c_adap); fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; } @@ -1538,7 +1538,7 @@ static int dvb_register(struct cx8802_dev *dev) fe0->dvb.frontend = dvb_attach(cx24116_attach, &hauppauge_hvr4000_config, &core->i2c_adap); - if (fe0->dvb.frontend != NULL) + if (fe0->dvb.frontend) fe0->dvb.frontend->ops.set_voltage = tevii_dvbs_set_voltage; break; case CX88_BOARD_TERRATEC_CINERGY_HT_PCI_MKII: @@ -1555,9 +1555,9 @@ static int dvb_register(struct cx8802_dev *dev) struct dvb_tuner_ops *tuner_ops = NULL; fe0->dvb.frontend = dvb_attach(stv0900_attach, - &prof_7301_stv0900_config, - &core->i2c_adap, 0); - if (fe0->dvb.frontend != NULL) { + &prof_7301_stv0900_config, + &core->i2c_adap, 0); + if (fe0->dvb.frontend) { if (!dvb_attach(stb6100_attach, fe0->dvb.frontend, &prof_7301_stb6100_config, &core->i2c_adap)) @@ -1587,8 +1587,8 @@ static int dvb_register(struct cx8802_dev *dev) mdelay(200); fe0->dvb.frontend = dvb_attach(stv0299_attach, - &samsung_stv0299_config, - &dev->core->i2c_adap); + &samsung_stv0299_config, + &dev->core->i2c_adap); if (fe0->dvb.frontend) { fe0->dvb.frontend->ops.tuner_ops.set_params = samsung_smt_7020_tuner_set_params; @@ -1604,8 +1604,8 @@ static int dvb_register(struct cx8802_dev *dev) case CX88_BOARD_TWINHAN_VP1027_DVBS: dev->ts_gen_cntrl = 0x00; fe0->dvb.frontend = dvb_attach(mb86a16_attach, - &twinhan_vp1027, - &core->i2c_adap); + &twinhan_vp1027, + &core->i2c_adap); if (fe0->dvb.frontend) { core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage; @@ -1772,7 +1772,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv) struct vb2_queue *q; fe = vb2_dvb_get_frontend(&core->dvbdev->frontends, i); - if (fe == NULL) { + if (!fe) { pr_err("%s() failed to get frontend(%d)\n", __func__, i); err = -ENODEV; diff --git a/drivers/media/pci/cx88/cx88-i2c.c b/drivers/media/pci/cx88/cx88-i2c.c index 99596fe56cd2..f7692775fb5a 100644 --- a/drivers/media/pci/cx88/cx88-i2c.c +++ b/drivers/media/pci/cx88/cx88-i2c.c @@ -24,10 +24,9 @@ #include "cx88.h" -#include #include - -#include +#include +#include #include @@ -41,7 +40,8 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time"); static unsigned int i2c_udelay = 5; module_param(i2c_udelay, int, 0644); -MODULE_PARM_DESC(i2c_udelay, "i2c delay at insmod time, in usecs (should be 5 or higher). Lower value means higher bus speed."); +MODULE_PARM_DESC(i2c_udelay, + "i2c delay at insmod time, in usecs (should be 5 or higher). Lower value means higher bus speed."); #define dprintk(level, fmt, arg...) do { \ if (i2c_debug >= level) \ @@ -139,7 +139,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) core->i2c_algo = cx8800_i2c_algo_template; - core->i2c_adap.dev.parent = &pci->dev; strlcpy(core->i2c_adap.name, core->name, sizeof(core->i2c_adap.name)); core->i2c_adap.owner = THIS_MODULE; @@ -166,14 +165,14 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci) dprintk(1, "i2c register ok\n"); switch (core->boardnr) { - case CX88_BOARD_HAUPPAUGE_HVR1300: - case CX88_BOARD_HAUPPAUGE_HVR3000: - case CX88_BOARD_HAUPPAUGE_HVR4000: - pr_info("i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n"); - i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1); - break; - default: - break; + case CX88_BOARD_HAUPPAUGE_HVR1300: + case CX88_BOARD_HAUPPAUGE_HVR3000: + case CX88_BOARD_HAUPPAUGE_HVR4000: + pr_info("i2c init: enabling analog demod on HVR1300/3000/4000 tuner\n"); + i2c_transfer(core->i2c_client.adapter, &tuner_msg, 1); + break; + default: + break; } if (i2c_scan) do_i2c_scan(core->name, &core->i2c_client); diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c index c072b7ecc8d6..dcfea3502e42 100644 --- a/drivers/media/pci/cx88/cx88-input.c +++ b/drivers/media/pci/cx88/cx88-input.c @@ -62,11 +62,15 @@ static int ir_debug; module_param(ir_debug, int, 0644); /* debug level [IR] */ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); -#define ir_dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "%s IR: " fmt, ir->core->name, ##arg) +#define ir_dprintk(fmt, arg...) do { \ + if (ir_debug) \ + printk(KERN_DEBUG "%s IR: " fmt, ir->core->name, ##arg);\ +} while (0) -#define dprintk(fmt, arg...) if (ir_debug) \ - printk(KERN_DEBUG "cx88 IR: " fmt, ##arg) +#define dprintk(fmt, arg...) do { \ + if (ir_debug) \ + printk(KERN_DEBUG "cx88 IR: " fmt, ##arg); \ +} while (0) /* ---------------------------------------------------------------------- */ @@ -79,16 +83,17 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) gpio = cx_read(ir->gpio_addr); switch (core->boardnr) { case CX88_BOARD_NPGTECH_REALTV_TOP10FM: - /* This board apparently uses a combination of 2 GPIO - to represent the keys. Additionally, the second GPIO - can be used for parity. - - Example: - - for key "5" - gpio = 0x758, auxgpio = 0xe5 or 0xf5 - for key "Power" - gpio = 0x758, auxgpio = 0xed or 0xfd + /* + * This board apparently uses a combination of 2 GPIO + * to represent the keys. Additionally, the second GPIO + * can be used for parity. + * + * Example: + * + * for key "5" + * gpio = 0x758, auxgpio = 0xe5 or 0xf5 + * for key "Power" + * gpio = 0x758, auxgpio = 0xed or 0xfd */ auxgpio = cx_read(MO_GP1_IO); @@ -142,7 +147,7 @@ static void cx88_ir_handle_key(struct cx88_IR *ir) if (0 == (gpio & ir->mask_keyup)) rc_keydown_notimeout(ir->dev, RC_TYPE_NECX, scancode, - 0); + 0); else rc_keyup(ir->dev); @@ -231,12 +236,14 @@ int cx88_ir_start(struct cx88_core *core) return 0; } +EXPORT_SYMBOL(cx88_ir_start); void cx88_ir_stop(struct cx88_core *core) { if (core->ir->users) __cx88_ir_stop(core); } +EXPORT_SYMBOL(cx88_ir_stop); static int cx88_ir_open(struct rc_dev *rc) { @@ -508,7 +515,7 @@ int cx88_ir_fini(struct cx88_core *core) struct cx88_IR *ir = core->ir; /* skip detach on non attached boards */ - if (ir == NULL) + if (!ir) return 0; cx88_ir_stop(core); @@ -576,7 +583,7 @@ static int get_key_pvr2000(struct IR_i2c *ir, enum rc_type *protocol, } dprintk("IR Key/Flags: (0x%02x/0x%02x)\n", - code & 0xff, flags & 0xff); + code & 0xff, flags & 0xff); *protocol = RC_TYPE_UNKNOWN; *scancode = code & 0xff; @@ -636,8 +643,8 @@ void cx88_i2c_init_ir(struct cx88_core *core) info.platform_data = &core->init_data; } if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0, - I2C_SMBUS_READ, 0, - I2C_SMBUS_QUICK, NULL) >= 0) { + I2C_SMBUS_READ, 0, + I2C_SMBUS_QUICK, NULL) >= 0) { info.addr = *addrp; i2c_new_device(&core->i2c_adap, &info); break; diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c index 4533e2c6cb9f..52ff00ebd4bd 100644 --- a/drivers/media/pci/cx88/cx88-mpeg.c +++ b/drivers/media/pci/cx88/cx88-mpeg.c @@ -16,10 +16,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 "cx88.h" @@ -30,7 +26,7 @@ #include #include #include -#include +#include /* ------------------------------------------------------------------ */ @@ -54,7 +50,8 @@ MODULE_PARM_DESC(debug, "enable debug messages [mpeg]"); #if defined(CONFIG_MODULES) && defined(MODULE) static void request_module_async(struct work_struct *work) { - struct cx8802_dev *dev = container_of(work, struct cx8802_dev, request_module_wk); + struct cx8802_dev *dev = container_of(work, struct cx8802_dev, + request_module_wk); if (dev->core->board.mpeg & CX88_MPEG_DVB) request_module("cx88-dvb"); @@ -77,14 +74,13 @@ static void flush_request_modules(struct cx8802_dev *dev) #define flush_request_modules(dev) #endif /* CONFIG_MODULES */ - static LIST_HEAD(cx8802_devlist); static DEFINE_MUTEX(cx8802_mutex); /* ------------------------------------------------------------------ */ int cx8802_start_dma(struct cx8802_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf) + struct cx88_dmaqueue *q, + struct cx88_buffer *buf) { struct cx88_core *core = dev->core; @@ -98,33 +94,35 @@ int cx8802_start_dma(struct cx8802_dev *dev, /* write TS length to chip */ cx_write(MO_TS_LNGTH, dev->ts_packet_size); - /* FIXME: this needs a review. - * also: move to cx88-blackbird + cx88-dvb source files? */ + /* + * FIXME: this needs a review. + * also: move to cx88-blackbird + cx88-dvb source files? + */ dprintk(1, "core->active_type_id = 0x%08x\n", core->active_type_id); if ((core->active_type_id == CX88_MPEG_DVB) && - (core->board.mpeg & CX88_MPEG_DVB)) { - + (core->board.mpeg & CX88_MPEG_DVB)) { dprintk(1, "cx8802_start_dma doing .dvb\n"); /* negedge driven & software reset */ cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl); udelay(100); cx_write(MO_PINMUX_IO, 0x00); - cx_write(TS_HW_SOP_CNTRL, 0x47<<16|188<<4|0x01); + cx_write(TS_HW_SOP_CNTRL, 0x47 << 16 | 188 << 4 | 0x01); switch (core->boardnr) { case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q: case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T: case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD: case CX88_BOARD_PCHDTV_HD5500: - cx_write(TS_SOP_STAT, 1<<13); + cx_write(TS_SOP_STAT, 1 << 13); break; case CX88_BOARD_SAMSUNG_SMT_7020: cx_write(TS_SOP_STAT, 0x00); break; case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1: case CX88_BOARD_HAUPPAUGE_NOVASE2_S1: - cx_write(MO_PINMUX_IO, 0x88); /* Enable MPEG parallel IO and video signal pins */ + /* Enable MPEG parallel IO and video signal pins */ + cx_write(MO_PINMUX_IO, 0x88); udelay(100); break; case CX88_BOARD_HAUPPAUGE_HVR1300: @@ -153,13 +151,15 @@ int cx8802_start_dma(struct cx8802_dev *dev, dprintk(1, "cx8802_start_dma doing .blackbird\n"); cx_write(MO_PINMUX_IO, 0x88); /* enable MPEG parallel IO */ - cx_write(TS_GEN_CNTRL, 0x46); /* punctured clock TS & posedge driven & software reset */ + /* punctured clock TS & posedge driven & software reset */ + cx_write(TS_GEN_CNTRL, 0x46); udelay(100); cx_write(TS_HW_SOP_CNTRL, 0x408); /* mpeg start byte */ cx_write(TS_VALERR_CNTRL, 0x2000); - cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */ + /* punctured clock TS & posedge driven */ + cx_write(TS_GEN_CNTRL, 0x06); udelay(100); } else { pr_err("%s() Failed. Unsupported value in .mpeg (0x%08x)\n", @@ -177,10 +177,11 @@ int cx8802_start_dma(struct cx8802_dev *dev, cx_set(MO_TS_INTMSK, 0x1f0011); /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); + cx_set(MO_DEV_CNTRL2, (1 << 5)); cx_set(MO_TS_DMACNTRL, 0x11); return 0; } +EXPORT_SYMBOL(cx8802_start_dma); static int cx8802_stop_dma(struct cx8802_dev *dev) { @@ -219,7 +220,7 @@ static int cx8802_restart_queue(struct cx8802_dev *dev, /* ------------------------------------------------------------------ */ int cx8802_buf_prepare(struct vb2_queue *q, struct cx8802_dev *dev, - struct cx88_buffer *buf) + struct cx88_buffer *buf) { int size = dev->ts_packet_size * dev->ts_packet_count; struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb.vb2_buf, 0); @@ -231,15 +232,17 @@ int cx8802_buf_prepare(struct vb2_queue *q, struct cx8802_dev *dev, vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size); rc = cx88_risc_databuffer(dev->pci, risc, sgt->sgl, - dev->ts_packet_size, dev->ts_packet_count, 0); + dev->ts_packet_size, dev->ts_packet_count, 0); if (rc) { if (risc->cpu) - pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma); + pci_free_consistent(dev->pci, risc->size, + risc->cpu, risc->dma); memset(risc, 0, sizeof(*risc)); return rc; } return 0; } +EXPORT_SYMBOL(cx8802_buf_prepare); void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) { @@ -268,6 +271,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf) buf, buf->vb.vb2_buf.index, __func__); } } +EXPORT_SYMBOL(cx8802_buf_queue); /* ----------------------------------------------------------- */ @@ -292,6 +296,7 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev) cx8802_stop_dma(dev); do_cancel_buffers(dev); } +EXPORT_SYMBOL(cx8802_cancel_buffers); static const char *cx88_mpeg_irqs[32] = { "ts_risci1", NULL, NULL, NULL, @@ -324,7 +329,8 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev) if (status & (1 << 16)) { pr_warn("mpeg risc op code error\n"); cx_clear(MO_TS_DMACNTRL, 0x11); - cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]); + cx88_sram_channel_dump(dev->core, + &cx88_sram_channels[SRAM_CH28]); } /* risc1 y */ @@ -452,7 +458,8 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state) cx88_shutdown(dev->core); pci_save_state(pci_dev); - if (pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)) != 0) { + if (pci_set_power_state(pci_dev, + pci_choose_state(pci_dev, state)) != 0) { pci_disable_device(pci_dev); dev->state.disabled = 1; } @@ -497,7 +504,8 @@ static int cx8802_resume_common(struct pci_dev *pci_dev) return 0; } -struct cx8802_driver *cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype) +struct cx8802_driver *cx8802_get_driver(struct cx8802_dev *dev, + enum cx88_board_type btype) { struct cx8802_driver *d; @@ -507,6 +515,7 @@ struct cx8802_driver *cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_ return NULL; } +EXPORT_SYMBOL(cx8802_get_driver); /* Driver asked for hardware access. */ static int cx8802_request_acquire(struct cx8802_driver *drv) @@ -524,7 +533,8 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) core->last_analog_input = core->input; core->input = 0; for (i = 0; - i < (sizeof(core->board.input) / sizeof(struct cx88_input)); + i < (sizeof(core->board.input) / + sizeof(struct cx88_input)); i++) { if (core->board.input[i].type == CX88_VMUX_DVB) { core->input = i; @@ -533,8 +543,7 @@ static int cx8802_request_acquire(struct cx8802_driver *drv) } } - if (drv->advise_acquire) - { + if (drv->advise_acquire) { core->active_ref++; if (core->active_type_id == CX88_BOARD_NONE) { core->active_type_id = drv->type_id; @@ -552,11 +561,12 @@ static int cx8802_request_release(struct cx8802_driver *drv) { struct cx88_core *core = drv->core; - if (drv->advise_release && --core->active_ref == 0) - { + if (drv->advise_release && --core->active_ref == 0) { if (drv->type_id == CX88_MPEG_DVB) { - /* If the DVB driver is releasing, reset the input - state to the last configured analog input */ + /* + * If the DVB driver is releasing, reset the input + * state to the last configured analog input + */ core->input = core->last_analog_input; } @@ -570,21 +580,21 @@ static int cx8802_request_release(struct cx8802_driver *drv) static int cx8802_check_driver(struct cx8802_driver *drv) { - if (drv == NULL) + if (!drv) return -ENODEV; if ((drv->type_id != CX88_MPEG_DVB) && - (drv->type_id != CX88_MPEG_BLACKBIRD)) + (drv->type_id != CX88_MPEG_BLACKBIRD)) return -EINVAL; if ((drv->hw_access != CX8802_DRVCTL_SHARED) && - (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE)) + (drv->hw_access != CX8802_DRVCTL_EXCLUSIVE)) return -EINVAL; - if ((drv->probe == NULL) || - (drv->remove == NULL) || - (drv->advise_acquire == NULL) || - (drv->advise_release == NULL)) + if ((!drv->probe) || + (!drv->remove) || + (!drv->advise_acquire) || + (!drv->advise_release)) return -EINVAL; return 0; @@ -598,9 +608,11 @@ int cx8802_register_driver(struct cx8802_driver *drv) pr_info("registering cx8802 driver, type: %s access: %s\n", drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + drv->hw_access == CX8802_DRVCTL_SHARED ? + "shared" : "exclusive"); - if ((err = cx8802_check_driver(drv)) != 0) { + err = cx8802_check_driver(drv); + if (err) { pr_err("cx8802_driver is invalid\n"); return err; } @@ -615,7 +627,7 @@ int cx8802_register_driver(struct cx8802_driver *drv) /* Bring up a new struct for each driver instance */ driver = kzalloc(sizeof(*drv), GFP_KERNEL); - if (driver == NULL) { + if (!driver) { err = -ENOMEM; goto out; } @@ -644,6 +656,7 @@ out: mutex_unlock(&cx8802_mutex); return err; } +EXPORT_SYMBOL(cx8802_register_driver); int cx8802_unregister_driver(struct cx8802_driver *drv) { @@ -653,7 +666,8 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) pr_info("unregistering cx8802 driver, type: %s access: %s\n", drv->type_id == CX88_MPEG_DVB ? "dvb" : "blackbird", - drv->hw_access == CX8802_DRVCTL_SHARED ? "shared" : "exclusive"); + drv->hw_access == CX8802_DRVCTL_SHARED ? + "shared" : "exclusive"); mutex_lock(&cx8802_mutex); @@ -686,6 +700,7 @@ int cx8802_unregister_driver(struct cx8802_driver *drv) return err; } +EXPORT_SYMBOL(cx8802_unregister_driver); /* ----------------------------------------------------------- */ static int cx8802_probe(struct pci_dev *pci_dev, @@ -697,7 +712,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, /* general setup */ core = cx88_core_get(pci_dev); - if (core == NULL) + if (!core) return -EINVAL; pr_info("cx2388x 8802 Driver Manager\n"); @@ -708,7 +723,7 @@ static int cx8802_probe(struct pci_dev *pci_dev, err = -ENOMEM; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) + if (!dev) goto fail_core; dev->pci = pci_dev; dev->core = core; @@ -797,12 +812,3 @@ static struct pci_driver cx8802_pci_driver = { }; module_pci_driver(cx8802_pci_driver); - -EXPORT_SYMBOL(cx8802_buf_prepare); -EXPORT_SYMBOL(cx8802_buf_queue); -EXPORT_SYMBOL(cx8802_cancel_buffers); -EXPORT_SYMBOL(cx8802_start_dma); - -EXPORT_SYMBOL(cx8802_register_driver); -EXPORT_SYMBOL(cx8802_unregister_driver); -EXPORT_SYMBOL(cx8802_get_driver); diff --git a/drivers/media/pci/cx88/cx88-reg.h b/drivers/media/pci/cx88/cx88-reg.h index 88ed8a2e4ee1..f1e1dd634a72 100644 --- a/drivers/media/pci/cx88/cx88-reg.h +++ b/drivers/media/pci/cx88/cx88-reg.h @@ -1,32 +1,28 @@ /* - - cx88x-hw.h - CX2388x register offsets - - Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) - 2001 Michael Eskin - 2002 Yurij Sysoev - 2003 Gerd Knorr - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ + * cx88x-hw.h - CX2388x register offsets + * + * Copyright (C) 1996,97,98 Ralph Metzler (rjkm@thp.uni-koeln.de) + * 2001 Michael Eskin + * 2002 Yurij Sysoev + * 2003 Gerd Knorr + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ #ifndef _CX88_REG_H_ #define _CX88_REG_H_ -/* ---------------------------------------------------------------------- */ -/* PCI IDs and config space */ +/* + * PCI IDs and config space + */ #ifndef PCI_VENDOR_ID_CONEXANT # define PCI_VENDOR_ID_CONEXANT 0x14F1 @@ -39,8 +35,9 @@ #define CX88X_EN_TBFX 0x02 #define CX88X_EN_VSFX 0x04 -/* ---------------------------------------------------------------------- */ -/* PCI controller registers */ +/* + * PCI controller registers + */ /* Command and Status Register */ #define F0_CMD_STAT_MM 0x2f0004 @@ -63,8 +60,9 @@ #define F3_BAR0_MM 0x2f0310 #define F4_BAR0_MM 0x2f0410 -/* ---------------------------------------------------------------------- */ -/* DMA Controller registers */ +/* + * DMA Controller registers + */ #define MO_PDMA_STHRSH 0x200000 // Source threshold #define MO_PDMA_STADRS 0x200004 // Source target address @@ -157,9 +155,9 @@ #define MO_DMA31_CNT2 0x300168 // {11}RW* DMA Table Size : Ch#31 #define MO_DMA32_CNT2 0x30016C // {11}RW* DMA Table Size : Ch#32 - -/* ---------------------------------------------------------------------- */ -/* Video registers */ +/* + * Video registers + */ #define MO_VIDY_DMA 0x310000 // {64}RWp Video Y #define MO_VIDU_DMA 0x310008 // {64}RWp Video U @@ -217,9 +215,9 @@ #define MO_VID_DMACNTRL 0x31C040 // {8}RW Video DMA control #define MO_VID_XFR_STAT 0x31C044 // {1}RO Video transfer status - -/* ---------------------------------------------------------------------- */ -/* audio registers */ +/* + * audio registers + */ #define MO_AUDD_DMA 0x320000 // {64}RWp Audio downstream #define MO_AUDU_DMA 0x320008 // {64}RWp Audio upstream @@ -437,9 +435,9 @@ #define AUD_PHACC_FREQ_8LSB 0x320d2b #define AUD_QAM_MODE 0x320d04 - -/* ---------------------------------------------------------------------- */ -/* transport stream registers */ +/* + * transport stream registers + */ #define MO_TS_DMA 0x330000 // {64}RWp Transport stream downstream #define MO_TS_GPCNT 0x33C020 // {16}RO TS general purpose counter @@ -455,9 +453,9 @@ #define TS_FIFO_OVFL_STAT 0x33C05C #define TS_VALERR_CNTRL 0x33C060 - -/* ---------------------------------------------------------------------- */ -/* VIP registers */ +/* + * VIP registers + */ #define MO_VIPD_DMA 0x340000 // {64}RWp VIP downstream #define MO_VIPU_DMA 0x340008 // {64}RWp VIP upstream @@ -475,9 +473,9 @@ #define MO_VIP_INTCNTRL 0x34C05C // VIP Interrupt Control #define MO_VIP_XFTERM 0x340060 // VIP transfer terminate - -/* ---------------------------------------------------------------------- */ -/* misc registers */ +/* + * misc registers + */ #define MO_M2M_DMA 0x350000 // {64}RWp Mem2Mem DMA Bfr #define MO_GP0_IO 0x350010 // {32}RW* GPIOoutput enablesdata I/O @@ -509,9 +507,9 @@ #define MO_INT1_STAT 0x35C064 // DMA RISC interrupt status #define MO_INT1_MSTAT 0x35C068 // DMA RISC interrupt masked status - -/* ---------------------------------------------------------------------- */ -/* i2c bus registers */ +/* + * i2c bus registers + */ #define MO_I2C 0x368000 // I2C data/control #define MO_I2C_DIV (0xf<<4) @@ -521,9 +519,11 @@ #define MO_I2C_SDA (1<<0) -/* ---------------------------------------------------------------------- */ -/* general purpose host registers */ -/* FIXME: tyops? s/0x35/0x38/ ?? */ +/* + * general purpose host registers + * + * FIXME: tyops? s/0x35/0x38/ ?? + */ #define MO_GPHSTD_DMA 0x350000 // {64}RWp Host downstream #define MO_GPHSTU_DMA 0x350008 // {64}RWp Host upstream @@ -545,9 +545,9 @@ #define MO_GPHST_XFR_STAT 0x38C044 // Host transfer status #define MO_GPHST_SOFT_RST 0x38C06C // Host software reset - -/* ---------------------------------------------------------------------- */ -/* RISC instructions */ +/* + * RISC instructions + */ #define RISC_SYNC 0x80000000 #define RISC_SYNC_ODD 0x80000000 @@ -578,9 +578,9 @@ #define RISC_CNT_RESET 0x00030000 #define RISC_JMP_SRP 0x01 - -/* ---------------------------------------------------------------------- */ -/* various constants */ +/* + * various constants + */ // DMA /* Interrupt mask/status */ diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c index 20f6924abe35..545ad4c4d1c7 100644 --- a/drivers/media/pci/cx88/cx88-tvaudio.c +++ b/drivers/media/pci/cx88/cx88-tvaudio.c @@ -57,7 +57,8 @@ MODULE_PARM_DESC(always_analog, "force analog audio out"); static unsigned int radio_deemphasis; module_param(radio_deemphasis, int, 0644); -MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, 0=None, 1=50us (elsewhere), 2=75us (USA)"); +MODULE_PARM_DESC(radio_deemphasis, + "Radio deemphasis time constant, 0=None, 1=50us (elsewhere), 2=75us (USA)"); #define dprintk(fmt, arg...) do { \ if (audio_debug) \ @@ -141,7 +142,10 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) if (core->board.mpeg & CX88_MPEG_BLACKBIRD) { cx_write(AUD_I2SINPUTCNTL, 4); cx_write(AUD_BAUDRATE, 1); - /* 'pass-thru mode': this enables the i2s output to the mpeg encoder */ + /* + * 'pass-thru mode': this enables the i2s + * output to the mpeg encoder + */ cx_set(AUD_CTL, EN_I2SOUT_ENABLE); cx_write(AUD_I2SOUTPUTCNTL, 1); cx_write(AUD_I2SCNTL, 0); @@ -634,7 +638,6 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode) case WW_M: dprintk("%s Warning: wrong value\n", __func__); return; - break; } mode |= EN_FMRADIO_EN_RDS | EN_DMTRX_SUMDIFF; @@ -691,13 +694,15 @@ static void set_audio_standard_FM(struct cx88_core *core, { /* end of list */ }, }; - /* It is enough to leave default values? */ - /* No, it's not! The deemphasis registers are reset to the 75us + /* + * It is enough to leave default values? + * + * No, it's not! The deemphasis registers are reset to the 75us * values by default. Analyzing the spectrum of the decoded audio * reveals that "no deemphasis" is the same as 75 us, while the 50 us - * setting results in less deemphasis. */ + * setting results in less deemphasis. + */ static const struct rlist fm_no_deemph[] = { - {AUD_POLYPH80SCALEFAC, 0x0003}, { /* end of list */ }, }; @@ -741,7 +746,7 @@ static int cx88_detect_nicam(struct cx88_core *core) } /* wait a little bit for next reading status */ - msleep(10); + usleep_range(10000, 20000); } dprintk("nicam is not detected.\n"); @@ -762,8 +767,10 @@ void cx88_set_tvaudio(struct cx88_core *core) /* prepare all dsp registers */ set_audio_standard_A2(core, EN_A2_FORCE_MONO1); - /* set nicam mode - otherwise - AUD_NICAM_STATUS2 contains wrong values */ + /* + * set nicam mode - otherwise + * AUD_NICAM_STATUS2 contains wrong values + */ set_audio_standard_NICAM(core, EN_NICAM_AUTO_STEREO); if (cx88_detect_nicam(core) == 0) { /* fall back to fm / am mono */ @@ -797,19 +804,22 @@ void cx88_set_tvaudio(struct cx88_core *core) pr_info("unknown tv audio mode [%d]\n", core->tvaudio); break; } - return; } +EXPORT_SYMBOL(cx88_set_tvaudio); void cx88_newstation(struct cx88_core *core) { core->audiomode_manual = UNSET; core->last_change = jiffies; } +EXPORT_SYMBOL(cx88_newstation); void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) { - static const char * const m[] = { "stereo", "dual mono", "mono", "sap" }; - static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" }; + static const char * const m[] = { "stereo", "dual mono", + "mono", "sap" }; + static const char * const p[] = { "no pilot", "pilot c1", + "pilot c2", "?" }; u32 reg, mode, pilot; reg = cx_read(AUD_STATUS); @@ -866,13 +876,16 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) /* If software stereo detection is not supported... */ if (t->rxsubchans == UNSET) { t->rxsubchans = V4L2_TUNER_SUB_MONO; - /* If the hardware itself detected stereo, also return - stereo as an available subchannel */ + /* + * If the hardware itself detected stereo, also return + * stereo as an available subchannel + */ if (t->audmode == V4L2_TUNER_MODE_STEREO) t->rxsubchans |= V4L2_TUNER_SUB_STEREO; } - return; } +EXPORT_SYMBOL(cx88_get_stereo); + void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) { @@ -928,7 +941,8 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) break; } } else { - if ((core->tvaudio == WW_I) || (core->tvaudio == WW_L)) { + if ((core->tvaudio == WW_I) || + (core->tvaudio == WW_L)) { /* fall back to fm / am mono */ set_audio_standard_A2(core, EN_A2_FORCE_MONO1); } else { @@ -976,8 +990,8 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) cx_read(AUD_CTL), cx_sread(SHADOW_AUD_VOL_CTL)); cx_andor(AUD_CTL, mask, ctl); } - return; } +EXPORT_SYMBOL(cx88_set_stereo); int cx88_audio_thread(void *data) { @@ -1027,8 +1041,10 @@ int cx88_audio_thread(void *data) case WW_FM: case WW_I2SADC: hw_autodetect: - /* stereo autodetection is supported by hardware so - we don't need to do it manually. Do nothing. */ + /* + * stereo autodetection is supported by hardware so + * we don't need to do it manually. Do nothing. + */ break; } } @@ -1036,11 +1052,4 @@ hw_autodetect: dprintk("cx88: tvaudio thread exiting\n"); return 0; } - -/* ----------------------------------------------------------- */ - -EXPORT_SYMBOL(cx88_set_tvaudio); -EXPORT_SYMBOL(cx88_newstation); -EXPORT_SYMBOL(cx88_set_stereo); -EXPORT_SYMBOL(cx88_get_stereo); EXPORT_SYMBOL(cx88_audio_thread); diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c index 9028822f507e..2d0ef19e6d65 100644 --- a/drivers/media/pci/cx88/cx88-vbi.c +++ b/drivers/media/pci/cx88/cx88-vbi.c @@ -20,7 +20,7 @@ MODULE_PARM_DESC(vbi_debug, "enable debug messages [vbi]"); /* ------------------------------------------------------------------ */ int cx8800_vbi_fmt(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct cx8800_dev *dev = video_drvdata(file); @@ -48,8 +48,8 @@ int cx8800_vbi_fmt(struct file *file, void *priv, } static int cx8800_start_vbi_dma(struct cx8800_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf) + struct cx88_dmaqueue *q, + struct cx88_buffer *buf) { struct cx88_core *core = dev->core; @@ -57,9 +57,9 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24], VBI_LINE_LENGTH, buf->risc.dma); - cx_write(MO_VBOS_CONTROL, ((1 << 18) | // comb filter delay fixup - (1 << 15) | // enable vbi capture - (1 << 11))); + cx_write(MO_VBOS_CONTROL, (1 << 18) | /* comb filter delay fixup */ + (1 << 15) | /* enable vbi capture */ + (1 << 11)); /* reset counter */ cx_write(MO_VBI_GPCNTRL, GP_COUNT_CONTROL_RESET); @@ -73,7 +73,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev, cx_set(VID_CAPTURE_CONTROL, 0x18); /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); + cx_set(MO_DEV_CNTRL2, (1 << 5)); cx_set(MO_VID_DMACNTRL, 0x88); return 0; @@ -112,8 +112,8 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev, /* ------------------------------------------------------------------ */ static int queue_setup(struct vb2_queue *q, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], struct device *alloc_devs[]) + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8800_dev *dev = q->drv_priv; @@ -125,7 +125,6 @@ static int queue_setup(struct vb2_queue *q, return 0; } - static int buffer_prepare(struct vb2_buffer *vb) { struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c index 797d5d0a4060..c7d4e87ccb64 100644 --- a/drivers/media/pci/cx88/cx88-video.c +++ b/drivers/media/pci/cx88/cx88-video.c @@ -73,7 +73,6 @@ MODULE_PARM_DESC(irq_debug, "enable debug messages [IRQ handler]"); __func__, ##arg); \ } while (0) - /* ------------------------------------------------------------------- */ /* static data */ @@ -123,7 +122,8 @@ static const struct cx8800_fmt formats[] = { }, { .name = "32 bpp RGB, be", .fourcc = V4L2_PIX_FMT_RGB32, - .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | ColorFormatWSWAP, + .cxformat = ColorFormatRGB32 | ColorFormatBSWAP | + ColorFormatWSWAP, .depth = 32, .flags = FORMAT_FLAGS_PACKED, }, { @@ -147,7 +147,7 @@ static const struct cx8800_fmt *format_by_fourcc(unsigned int fourcc) for (i = 0; i < ARRAY_SIZE(formats); i++) if (formats[i].fourcc == fourcc) - return formats+i; + return formats + i; return NULL; } @@ -221,8 +221,10 @@ static const struct cx88_ctrl cx8800_vid_ctls[] = { .step = 1, .default_value = 0x0, .off = 0, - /* NOTE: the value is converted and written to both even - and odd registers in the code */ + /* + * NOTE: the value is converted and written to both even + * and odd registers in the code + */ .reg = MO_FILTER_ODD, .mask = 7 << 7, .shift = 7, @@ -326,19 +328,25 @@ int cx88_video_mux(struct cx88_core *core, unsigned int input) break; } - /* if there are audioroutes defined, we have an external - ADC to deal with audio */ + /* + * if there are audioroutes defined, we have an external + * ADC to deal with audio + */ if (INPUT(input).audioroute) { - /* The wm8775 module has the "2" route hardwired into - the initialization. Some boards may use different - routes for different inputs. HVR-1300 surely does */ + /* + * The wm8775 module has the "2" route hardwired into + * the initialization. Some boards may use different + * routes for different inputs. HVR-1300 surely does + */ if (core->sd_wm8775) { call_all(core, audio, s_routing, INPUT(input).audioroute, 0, 0); } - /* cx2388's C-ADC is connected to the tuner only. - When used with S-Video, that ADC is busy dealing with - chroma, so an external must be used for baseband audio */ + /* + * cx2388's C-ADC is connected to the tuner only. + * When used with S-Video, that ADC is busy dealing with + * chroma, so an external must be used for baseband audio + */ if (INPUT(input).type != CX88_VMUX_TELEVISION && INPUT(input).type != CX88_VMUX_CABLE) { /* "I2S ADC mode" */ @@ -376,12 +384,13 @@ static int start_video_dma(struct cx8800_dev *dev, /* enable irqs */ cx_set(MO_PCI_INTMSK, core->pci_irqmask | PCI_INT_VIDINT); - /* Enables corresponding bits at PCI_INT_STAT: - bits 0 to 4: video, audio, transport stream, VIP, Host - bit 7: timer - bits 8 and 9: DMA complete for: SRC, DST - bits 10 and 11: BERR signal asserted for RISC: RD, WR - bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB + /* + * Enables corresponding bits at PCI_INT_STAT: + * bits 0 to 4: video, audio, transport stream, VIP, Host + * bit 7: timer + * bits 8 and 9: DMA complete for: SRC, DST + * bits 10 and 11: BERR signal asserted for RISC: RD, WR + * bits 12 to 15: BERR signal asserted for: BRDG, SRC, DST, IPB */ cx_set(MO_VID_INTMSK, 0x0f0011); @@ -389,7 +398,7 @@ static int start_video_dma(struct cx8800_dev *dev, cx_set(VID_CAPTURE_CONTROL, 0x06); /* start dma */ - cx_set(MO_DEV_CNTRL2, (1<<5)); + cx_set(MO_DEV_CNTRL2, (1 << 5)); cx_set(MO_VID_DMACNTRL, 0x11); /* Planar Y and packed FIFO and RISC enable */ return 0; @@ -430,8 +439,8 @@ static int restart_video_queue(struct cx8800_dev *dev, /* ------------------------------------------------------------------ */ static int queue_setup(struct vb2_queue *q, - unsigned int *num_buffers, unsigned int *num_planes, - unsigned int sizes[], struct device *alloc_devs[]) + unsigned int *num_buffers, unsigned int *num_planes, + unsigned int sizes[], struct device *alloc_devs[]) { struct cx8800_dev *dev = q->drv_priv; struct cx88_core *core = dev->core; @@ -488,7 +497,8 @@ static int buffer_prepare(struct vb2_buffer *vb) core->height >> 1); break; } - dprintk(2, "[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", + dprintk(2, + "[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", buf, buf->vb.vb2_buf.index, core->width, core->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); @@ -595,7 +605,7 @@ static int radio_open(struct file *file) if (core->board.radio.audioroute) { if (core->sd_wm8775) { call_all(core, audio, s_routing, - core->board.radio.audioroute, 0, 0); + core->board.radio.audioroute, 0, 0); } /* "I2S ADC mode" */ core->tvaudio = WW_I2SADC; @@ -649,9 +659,10 @@ static int cx8800_s_vid_ctrl(struct v4l2_ctrl *ctrl) value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; } - dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctrl->id, ctrl->name, ctrl->val, cc->reg, value, - mask, cc->sreg ? " [shadowed]" : ""); + dprintk(1, + "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctrl->id, ctrl->name, ctrl->val, cc->reg, value, + mask, cc->sreg ? " [shadowed]" : ""); if (cc->sreg) cx_sandor(cc->sreg, cc->reg, mask, value); else @@ -687,7 +698,8 @@ static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) mask = cc->mask; switch (ctrl->id) { case V4L2_CID_AUDIO_BALANCE: - value = (ctrl->val < 0x40) ? (0x7f - ctrl->val) : (ctrl->val - 0x40); + value = (ctrl->val < 0x40) ? + (0x7f - ctrl->val) : (ctrl->val - 0x40); break; case V4L2_CID_AUDIO_VOLUME: value = 0x3f - (ctrl->val & 0x3f); @@ -696,9 +708,10 @@ static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; } - dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctrl->id, ctrl->name, ctrl->val, cc->reg, value, - mask, cc->sreg ? " [shadowed]" : ""); + dprintk(1, + "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctrl->id, ctrl->name, ctrl->val, cc->reg, value, + mask, cc->sreg ? " [shadowed]" : ""); if (cc->sreg) cx_sandor(cc->sreg, cc->reg, mask, value); else @@ -710,7 +723,7 @@ static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) /* VIDEO IOCTLS */ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -728,7 +741,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -737,7 +750,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, unsigned int maxw, maxh; fmt = format_by_fourcc(f->fmt.pix.pixelformat); - if (fmt == NULL) + if (!fmt) return -EINVAL; maxw = norm_maxw(core->tvnorm); @@ -774,7 +787,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, } static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_format *f) + struct v4l2_format *f) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -794,7 +807,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, } void cx88_querycap(struct file *file, struct cx88_core *core, - struct v4l2_capability *cap) + struct v4l2_capability *cap) { struct video_device *vdev = video_devdata(file); @@ -821,7 +834,7 @@ void cx88_querycap(struct file *file, struct cx88_core *core, EXPORT_SYMBOL(cx88_querycap); static int vidioc_querycap(struct file *file, void *priv, - struct v4l2_capability *cap) + struct v4l2_capability *cap) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -833,7 +846,7 @@ static int vidioc_querycap(struct file *file, void *priv, } static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, - struct v4l2_fmtdesc *f) + struct v4l2_fmtdesc *f) { if (unlikely(f->index >= ARRAY_SIZE(formats))) return -EINVAL; @@ -879,21 +892,21 @@ int cx88_enum_input(struct cx88_core *core, struct v4l2_input *i) if (n >= 4) return -EINVAL; - if (0 == INPUT(n).type) + if (!INPUT(n).type) return -EINVAL; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name, iname[INPUT(n).type]); - if ((CX88_VMUX_TELEVISION == INPUT(n).type) || - (CX88_VMUX_CABLE == INPUT(n).type)) { + if ((INPUT(n).type == CX88_VMUX_TELEVISION) || + (INPUT(n).type == CX88_VMUX_CABLE)) i->type = V4L2_INPUT_TYPE_TUNER; - } + i->std = CX88_NORMS; return 0; } EXPORT_SYMBOL(cx88_enum_input); static int vidioc_enum_input(struct file *file, void *priv, - struct v4l2_input *i) + struct v4l2_input *i) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -917,7 +930,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) if (i >= 4) return -EINVAL; - if (0 == INPUT(i).type) + if (!INPUT(i).type) return -EINVAL; cx88_newstation(core); @@ -926,7 +939,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i) } static int vidioc_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -944,12 +957,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, cx88_get_stereo(core, t); reg = cx_read(MO_DEVICE_STATUS); - t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; + t->signal = (reg & (1 << 5)) ? 0xffff : 0x0000; return 0; } static int vidioc_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -964,7 +977,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, } static int vidioc_g_frequency(struct file *file, void *priv, - struct v4l2_frequency *f) + struct v4l2_frequency *f) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -982,7 +995,7 @@ static int vidioc_g_frequency(struct file *file, void *priv, } int cx88_set_freq(struct cx88_core *core, - const struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct v4l2_frequency new_freq = *f; @@ -1005,7 +1018,7 @@ int cx88_set_freq(struct cx88_core *core, EXPORT_SYMBOL(cx88_set_freq); static int vidioc_s_frequency(struct file *file, void *priv, - const struct v4l2_frequency *f) + const struct v4l2_frequency *f) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -1015,7 +1028,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, #ifdef CONFIG_VIDEO_ADV_DEBUG static int vidioc_g_register(struct file *file, void *fh, - struct v4l2_dbg_register *reg) + struct v4l2_dbg_register *reg) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -1027,7 +1040,7 @@ static int vidioc_g_register(struct file *file, void *fh, } static int vidioc_s_register(struct file *file, void *fh, - const struct v4l2_dbg_register *reg) + const struct v4l2_dbg_register *reg) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -1042,7 +1055,7 @@ static int vidioc_s_register(struct file *file, void *fh, /* ----------------------------------------------------------- */ static int radio_g_tuner(struct file *file, void *priv, - struct v4l2_tuner *t) + struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -1057,7 +1070,7 @@ static int radio_g_tuner(struct file *file, void *priv, } static int radio_s_tuner(struct file *file, void *priv, - const struct v4l2_tuner *t) + const struct v4l2_tuner *t) { struct cx8800_dev *dev = video_drvdata(file); struct cx88_core *core = dev->core; @@ -1152,7 +1165,6 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id) /* exported stuff */ static const struct v4l2_file_operations video_fops = { - .owner = THIS_MODULE, .open = v4l2_fh_open, .release = vb2_fop_release, @@ -1232,7 +1244,6 @@ static const struct video_device cx8800_vbi_template = { }; static const struct v4l2_file_operations radio_fops = { - .owner = THIS_MODULE, .open = radio_open, .poll = v4l2_ctrl_poll, @@ -1287,7 +1298,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, int i; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) + if (!dev) return -ENOMEM; /* pci init */ @@ -1297,7 +1308,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev, goto fail_free; } core = cx88_core_get(dev->pci); - if (core == NULL) { + if (!core) { err = -EINVAL; goto fail_free; } @@ -1341,8 +1352,9 @@ static int cx8800_initdev(struct pci_dev *pci_dev, struct v4l2_ctrl *vc; vc = v4l2_ctrl_new_std(&core->audio_hdl, &cx8800_ctrl_aud_ops, - cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); - if (vc == NULL) { + cc->id, cc->minimum, cc->maximum, + cc->step, cc->default_value); + if (!vc) { err = core->audio_hdl.error; goto fail_core; } @@ -1354,8 +1366,9 @@ static int cx8800_initdev(struct pci_dev *pci_dev, struct v4l2_ctrl *vc; vc = v4l2_ctrl_new_std(&core->video_hdl, &cx8800_ctrl_vid_ops, - cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); - if (vc == NULL) { + cc->id, cc->minimum, cc->maximum, + cc->step, cc->default_value); + if (!vc) { err = core->video_hdl.error; goto fail_core; } @@ -1381,18 +1394,20 @@ static int cx8800_initdev(struct pci_dev *pci_dev, core->wm8775_data.is_nova_s = false; sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap, - &wm8775_info, NULL); - if (sd != NULL) { + &wm8775_info, NULL); + if (sd) { core->sd_wm8775 = sd; sd->grp_id = WM8775_GID; } } if (core->board.audio_chip == CX88_AUDIO_TVAUDIO) { - /* This probes for a tda9874 as is used on some - Pixelview Ultra boards. */ + /* + * This probes for a tda9874 as is used on some + * Pixelview Ultra boards. + */ v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap, - "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); + "tvaudio", 0, I2C_ADDRS(0xb0 >> 1)); } switch (core->boardnr) { @@ -1504,7 +1519,8 @@ static int cx8800_initdev(struct pci_dev *pci_dev, /* start tvaudio thread */ if (core->board.tuner_type != UNSET) { - core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio"); + core->kthread = kthread_run(cx88_audio_thread, + core, "cx88 tvaudio"); if (IS_ERR(core->kthread)) { err = PTR_ERR(core->kthread); pr_err("failed to create cx88 audio thread, err=%d\n", @@ -1581,7 +1597,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state) cx88_shutdown(core); pci_save_state(pci_dev); - if (pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)) != 0) { + if (pci_set_power_state(pci_dev, + pci_choose_state(pci_dev, state)) != 0) { pci_disable_device(pci_dev); dev->state.disabled = 1; } diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.c b/drivers/media/pci/cx88/cx88-vp3054-i2c.c index eea56ae9071e..92876de3841c 100644 --- a/drivers/media/pci/cx88/cx88-vp3054-i2c.c +++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.c @@ -22,8 +22,7 @@ #include #include #include - -#include +#include MODULE_DESCRIPTION("driver for cx2388x VP3054 design"); MODULE_AUTHOR("Chris Pascoe "); @@ -108,7 +107,7 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) return 0; vp3054_i2c = kzalloc(sizeof(*vp3054_i2c), GFP_KERNEL); - if (vp3054_i2c == NULL) + if (!vp3054_i2c) return -ENOMEM; dev->vp3054 = vp3054_i2c; @@ -135,18 +134,17 @@ int vp3054_i2c_probe(struct cx8802_dev *dev) return rc; } +EXPORT_SYMBOL(vp3054_i2c_probe); void vp3054_i2c_remove(struct cx8802_dev *dev) { struct vp3054_i2c_state *vp3054_i2c = dev->vp3054; - if (vp3054_i2c == NULL || + if (!vp3054_i2c || dev->core->boardnr != CX88_BOARD_DNTV_LIVE_DVB_T_PRO) return; i2c_del_adapter(&vp3054_i2c->adap); kfree(vp3054_i2c); } - -EXPORT_SYMBOL(vp3054_i2c_probe); EXPORT_SYMBOL(vp3054_i2c_remove); diff --git a/drivers/media/pci/cx88/cx88-vp3054-i2c.h b/drivers/media/pci/cx88/cx88-vp3054-i2c.h index 95d0c60a35e1..ec19bea8f1e2 100644 --- a/drivers/media/pci/cx88/cx88-vp3054-i2c.h +++ b/drivers/media/pci/cx88/cx88-vp3054-i2c.h @@ -1,26 +1,20 @@ /* - - cx88-vp3054-i2c.h -- support for the secondary I2C bus of the - DNTV Live! DVB-T Pro (VP-3054), wired as: - GPIO[0] -> SCL, GPIO[1] -> SDA - - (c) 2005 Chris Pascoe - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ + * cx88-vp3054-i2c.h -- support for the secondary I2C bus of the + * DNTV Live! DVB-T Pro (VP-3054), wired as: + * GPIO[0] -> SCL, GPIO[1] -> SDA + * + * (c) 2005 Chris Pascoe + * + * 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. + */ /* ----------------------------------------------------------------------- */ struct vp3054_i2c_state { diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h index ac1fb9fb340e..115414cf520f 100644 --- a/drivers/media/pci/cx88/cx88.h +++ b/drivers/media/pci/cx88/cx88.h @@ -1,5 +1,4 @@ /* - * * v4l2 device driver for cx2388x based TV cards * * (c) 2003,04 Gerd Knorr [SUSE Labs] @@ -99,7 +98,6 @@ static inline unsigned int norm_maxw(v4l2_std_id norm) return 720; } - static inline unsigned int norm_maxh(v4l2_std_id norm) { return (norm & V4L2_STD_525_60) ? 480 : 576; @@ -141,6 +139,7 @@ struct sram_channel { u32 cnt1_reg; u32 cnt2_reg; }; + extern const struct sram_channel cx88_sram_channels[]; /* ----------------------------------------------------------- */ @@ -384,8 +383,8 @@ struct cx88_core { /* state info */ struct task_struct *kthread; v4l2_std_id tvnorm; - unsigned int width, height; - unsigned int field; + unsigned int width, height; + unsigned int field; enum cx88_tvaudio tvaudio; u32 audiomode_manual; u32 audiomode_current; @@ -428,7 +427,8 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) if (!core->i2c_rc) { \ if (core->gate_ctrl) \ core->gate_ctrl(core, 1); \ - v4l2_device_call_all(&core->v4l2_dev, grpid, o, f, ##args); \ + v4l2_device_call_all(&core->v4l2_dev, \ + grpid, o, f, ##args); \ if (core->gate_ctrl) \ core->gate_ctrl(core, 0); \ } \ @@ -439,31 +439,31 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) #define WM8775_GID (1 << 0) #define wm8775_s_ctrl(core, id, val) \ - do { \ - struct v4l2_ctrl *ctrl_ = \ - v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \ - if (ctrl_ && !core->i2c_rc) { \ - if (core->gate_ctrl) \ - core->gate_ctrl(core, 1); \ - v4l2_ctrl_s_ctrl(ctrl_, val); \ - if (core->gate_ctrl) \ - core->gate_ctrl(core, 0); \ - } \ + do { \ + struct v4l2_ctrl *ctrl_ = \ + v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id);\ + if (ctrl_ && !core->i2c_rc) { \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 1); \ + v4l2_ctrl_s_ctrl(ctrl_, val); \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 0); \ + } \ } while (0) #define wm8775_g_ctrl(core, id) \ - ({ \ - struct v4l2_ctrl *ctrl_ = \ - v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \ - s32 val = 0; \ - if (ctrl_ && !core->i2c_rc) { \ - if (core->gate_ctrl) \ - core->gate_ctrl(core, 1); \ - val = v4l2_ctrl_g_ctrl(ctrl_); \ - if (core->gate_ctrl) \ - core->gate_ctrl(core, 0); \ - } \ - val; \ + ({ \ + struct v4l2_ctrl *ctrl_ = \ + v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id);\ + s32 val = 0; \ + if (ctrl_ && !core->i2c_rc) { \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 1); \ + val = v4l2_ctrl_g_ctrl(ctrl_); \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 0); \ + } \ + val; \ }) /* ----------------------------------------------------------- */ @@ -505,7 +505,6 @@ struct cx8800_dev { /* function 1: audio/alsa stuff */ /* =============> moved to cx88-alsa.c <====================== */ - /* ----------------------------------------------------------- */ /* function 2: mpeg stuff */ @@ -567,6 +566,7 @@ struct cx8802_dev { /* mpeg params */ struct cx2341x_handler cxhdl; + #endif #if IS_ENABLED(CONFIG_VIDEO_CX88_DVB) @@ -589,40 +589,42 @@ struct cx8802_dev { /* ----------------------------------------------------------- */ -#define cx_read(reg) readl(core->lmmio + ((reg)>>2)) -#define cx_write(reg, value) writel((value), core->lmmio + ((reg)>>2)) -#define cx_writeb(reg, value) writeb((value), core->bmmio + (reg)) +#define cx_read(reg) readl(core->lmmio + ((reg) >> 2)) +#define cx_write(reg, value) writel((value), core->lmmio + ((reg) >> 2)) +#define cx_writeb(reg, value) writeb((value), core->bmmio + (reg)) #define cx_andor(reg, mask, value) \ - writel((readl(core->lmmio+((reg)>>2)) & ~(mask)) |\ - ((value) & (mask)), core->lmmio+((reg)>>2)) -#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) -#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) + writel((readl(core->lmmio + ((reg) >> 2)) & ~(mask)) |\ + ((value) & (mask)), core->lmmio + ((reg) >> 2)) +#define cx_set(reg, bit) cx_andor((reg), (bit), (bit)) +#define cx_clear(reg, bit) cx_andor((reg), (bit), 0) #define cx_wait(d) { if (need_resched()) schedule(); else udelay(d); } /* shadow registers */ #define cx_sread(sreg) (core->shadow[sreg]) #define cx_swrite(sreg, reg, value) \ - (core->shadow[sreg] = value, \ - writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) + (core->shadow[sreg] = value, \ + writel(core->shadow[sreg], core->lmmio + ((reg) >> 2))) #define cx_sandor(sreg, reg, mask, value) \ - (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | ((value) & (mask)), \ - writel(core->shadow[sreg], core->lmmio + ((reg)>>2))) + (core->shadow[sreg] = (core->shadow[sreg] & ~(mask)) | \ + ((value) & (mask)), \ + writel(core->shadow[sreg], \ + core->lmmio + ((reg) >> 2))) /* ----------------------------------------------------------- */ /* cx88-core.c */ extern unsigned int cx88_core_debug; -extern void cx88_print_irqbits(const char *tag, const char *strings[], - int len, u32 bits, u32 mask); +void cx88_print_irqbits(const char *tag, const char *strings[], + int len, u32 bits, u32 mask); -extern int cx88_core_irq(struct cx88_core *core, u32 status); -extern void cx88_wakeup(struct cx88_core *core, - struct cx88_dmaqueue *q, u32 count); -extern void cx88_shutdown(struct cx88_core *core); -extern int cx88_reset(struct cx88_core *core); +int cx88_core_irq(struct cx88_core *core, u32 status); +void cx88_wakeup(struct cx88_core *core, + struct cx88_dmaqueue *q, u32 count); +void cx88_shutdown(struct cx88_core *core); +int cx88_reset(struct cx88_core *core); extern int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc, @@ -634,43 +636,37 @@ cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc, struct scatterlist *sglist, unsigned int bpl, unsigned int lines, unsigned int lpi); -extern void cx88_risc_disasm(struct cx88_core *core, - struct cx88_riscmem *risc); -extern int cx88_sram_channel_setup(struct cx88_core *core, - const struct sram_channel *ch, - unsigned int bpl, u32 risc); -extern void cx88_sram_channel_dump(struct cx88_core *core, - const struct sram_channel *ch); - -extern int cx88_set_scale(struct cx88_core *core, unsigned int width, - unsigned int height, enum v4l2_field field); -extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm); - -extern void cx88_vdev_init(struct cx88_core *core, - struct pci_dev *pci, - struct video_device *vfd, - const struct video_device *template_, - const char *type); -extern struct cx88_core *cx88_core_get(struct pci_dev *pci); -extern void cx88_core_put(struct cx88_core *core, - struct pci_dev *pci); - -extern int cx88_start_audio_dma(struct cx88_core *core); -extern int cx88_stop_audio_dma(struct cx88_core *core); - +void cx88_risc_disasm(struct cx88_core *core, + struct cx88_riscmem *risc); +int cx88_sram_channel_setup(struct cx88_core *core, + const struct sram_channel *ch, + unsigned int bpl, u32 risc); +void cx88_sram_channel_dump(struct cx88_core *core, + const struct sram_channel *ch); + +int cx88_set_scale(struct cx88_core *core, unsigned int width, + unsigned int height, enum v4l2_field field); +int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm); + +void cx88_vdev_init(struct cx88_core *core, + struct pci_dev *pci, + struct video_device *vfd, + const struct video_device *template_, + const char *type); +struct cx88_core *cx88_core_get(struct pci_dev *pci); +void cx88_core_put(struct cx88_core *core, + struct pci_dev *pci); + +int cx88_start_audio_dma(struct cx88_core *core); +int cx88_stop_audio_dma(struct cx88_core *core); /* ----------------------------------------------------------- */ /* cx88-vbi.c */ /* Can be used as g_vbi_fmt, try_vbi_fmt and s_vbi_fmt */ int cx8800_vbi_fmt(struct file *file, void *priv, - struct v4l2_format *f); + struct v4l2_format *f); -/* -int cx8800_start_vbi_dma(struct cx8800_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf); -*/ void cx8800_stop_vbi_dma(struct cx8800_dev *dev); int cx8800_restart_vbi_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q); @@ -679,17 +675,16 @@ extern const struct vb2_ops cx8800_vbi_qops; /* ----------------------------------------------------------- */ /* cx88-i2c.c */ -extern int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); - +int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci); /* ----------------------------------------------------------- */ /* cx88-cards.c */ -extern int cx88_tuner_callback(void *dev, int component, int command, int arg); -extern int cx88_get_resources(const struct cx88_core *core, - struct pci_dev *pci); -extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); -extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl); +int cx88_tuner_callback(void *dev, int component, int command, int arg); +int cx88_get_resources(const struct cx88_core *core, + struct pci_dev *pci); +struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr); +void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl); /* ----------------------------------------------------------- */ /* cx88-tvaudio.c */ @@ -720,18 +715,18 @@ int cx88_ir_fini(struct cx88_core *core); void cx88_ir_irq(struct cx88_core *core); int cx88_ir_start(struct cx88_core *core); void cx88_ir_stop(struct cx88_core *core); -extern void cx88_i2c_init_ir(struct cx88_core *core); +void cx88_i2c_init_ir(struct cx88_core *core); /* ----------------------------------------------------------- */ /* cx88-mpeg.c */ int cx8802_buf_prepare(struct vb2_queue *q, struct cx8802_dev *dev, - struct cx88_buffer *buf); + struct cx88_buffer *buf); void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf); void cx8802_cancel_buffers(struct cx8802_dev *dev); int cx8802_start_dma(struct cx8802_dev *dev, - struct cx88_dmaqueue *q, - struct cx88_buffer *buf); + struct cx88_dmaqueue *q, + struct cx88_buffer *buf); /* ----------------------------------------------------------- */ /* cx88-video.c*/ @@ -739,6 +734,6 @@ int cx88_enum_input(struct cx88_core *core, struct v4l2_input *i); int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f); int cx88_video_mux(struct cx88_core *core, unsigned int input); void cx88_querycap(struct file *file, struct cx88_core *core, - struct v4l2_capability *cap); + struct v4l2_capability *cap); #endif -- cgit v1.2.3 From d3d83ee20afda16ad0133ba00f63c11a8d842a35 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 22 Nov 2016 18:52:17 -0200 Subject: [media] DaVinci-VPFE-Capture: fix error handling A recent cleanup had the right idea to remove the initialization of the error variable, but missed the actual benefit of that, which is that we get warnings if there is a bug in it. Now we get a warning about a bug that was introduced by this cleanup: drivers/media/platform/davinci/vpfe_capture.c: In function 'vpfe_probe': drivers/media/platform/davinci/vpfe_capture.c:1992:9: error: 'ret' may be used uninitialized in this function [-Werror=maybe-uninitialized] This adds the missing initialization that the warning is about, and another one that was preexisting and that we did not get a warning for. That second bug has existed since the driver was first added. Fixes: efb74461f5a6 ("[media] DaVinci-VPFE-Capture: Delete an unnecessary variable initialisation in vpfe_probe()") Fixes: 7da8a6cb3e5b ("V4L/DVB (12248): v4l: vpfe capture bridge driver for DM355 and DM6446") [mchehab@s-opensource.com: fix a merge conflict] Signed-off-by: Arnd Bergmann Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/davinci/vpfe_capture.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c index bc2c62b95493..ee1cd79739c8 100644 --- a/drivers/media/platform/davinci/vpfe_capture.c +++ b/drivers/media/platform/davinci/vpfe_capture.c @@ -1966,6 +1966,7 @@ static int vpfe_probe(struct platform_device *pdev) v4l2_info(&vpfe_dev->v4l2_dev, "v4l2 sub device %s register fails\n", sdinfo->name); + ret = -ENXIO; goto probe_sd_out; } } -- cgit v1.2.3 From be8e7a7ec876d509bc61af64b41b314a142aa262 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 25 Nov 2016 11:20:43 -0800 Subject: Input: soc_button_array - use gpio_is_valid() gpio_keys will later use gpio_is_valid(). To match the actual behavior, we should use it here too. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index c14b82709b0f..bbd433c4a5aa 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* @@ -92,7 +93,7 @@ soc_button_device_create(struct platform_device *pdev, continue; gpio = soc_button_lookup_gpio(&pdev->dev, info->acpi_index); - if (gpio < 0) + if (!gpio_is_valid(gpio)) continue; gpio_keys[n_buttons].type = info->event_type; -- cgit v1.2.3 From 3d5a9437a68a184fbbd0dcf09bf4daf40250505e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 25 Nov 2016 11:36:01 -0800 Subject: Input: soc_button_array - bail out earlier if gpiod_count is zero The PNP0C40 device of the Surface 3 doesn't have any GPIO attached to it. Instead of trying to access the GPIO, request the count beforehand and bail out if it is null or if an error is returned. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/misc/soc_button_array.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers') diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c index bbd433c4a5aa..908b51089dee 100644 --- a/drivers/input/misc/soc_button_array.c +++ b/drivers/input/misc/soc_button_array.c @@ -167,6 +167,11 @@ static int soc_button_probe(struct platform_device *pdev) button_info = (struct soc_button_info *)id->driver_data; + if (gpiod_count(&pdev->dev, KBUILD_MODNAME) <= 0) { + dev_dbg(&pdev->dev, "no GPIO attached, ignoring...\n"); + return -ENODEV; + } + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; -- cgit v1.2.3 From ea8b1c4a6019fb96ca8301f0b3ffcb13fb1cd0ae Mon Sep 17 00:00:00 2001 From: Kevin Brodsky Date: Tue, 8 Nov 2016 17:55:46 +0000 Subject: drivers: psci: PSCI checker module On arm and arm64, PSCI is one of the possible firmware interfaces used for power management. This includes both turning CPUs on and off, and suspending them (entering idle states). This patch adds a PSCI checker module that enables basic testing of PSCI operations during startup. There are two main tests: CPU hotplugging and suspending. In the hotplug tests, the hotplug API is used to turn off and on again all CPUs in the system, and then all CPUs in each cluster, checking the consistency of the return codes. In the suspend tests, a high-priority thread is created on each core and uses low-level cpuidle functionalities to enter suspend, in all the possible states and multiple times. This should allow a maximum number of CPUs to enter the same sleep state at the same or slightly different time. In essence, the suspend tests use a principle similar to that of the intel_powerclamp driver (drivers/thermal/intel_powerclamp.c), but the threads are only kept for the duration of the test (they are already gone when userspace is started) and it does not require to stop/start the tick. While in theory power management PSCI functions (CPU_{ON,OFF,SUSPEND}) could be directly called, this proved too difficult as it would imply the duplication of all the logic used by the kernel to allow for a clean shutdown/bringup/suspend of the CPU (the deepest sleep states implying potentially the shutdown of the CPU). Note that this file cannot be compiled as a loadable module, since it uses a number of non-exported identifiers (essentially for PSCI-specific checks and direct use of cpuidle) and relies on the absence of userspace to avoid races when calling hotplug and cpuidle functions. For now at least, CONFIG_PSCI_CHECKER is mutually exclusive with CONFIG_TORTURE_TEST, because torture tests may also use hotplug and cause false positives in the hotplug tests. Cc: Thomas Gleixner Cc: Kevin Hilman Cc: "Rafael J. Wysocki" Cc: Peter Zijlstra Cc: "Paul E. McKenney" Cc: James Morse Cc: Sudeep Holla Cc: Lorenzo Pieralisi Cc: Mark Rutland Acked-by: "Paul E. McKenney" [torture test config] Signed-off-by: Kevin Brodsky [lpieralisi: added cpuidle locking, reworded commit log/kconfig entry] Signed-off-by: Lorenzo Pieralisi Signed-off-by: Arnd Bergmann --- drivers/firmware/Kconfig | 11 + drivers/firmware/Makefile | 1 + drivers/firmware/psci_checker.c | 490 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 502 insertions(+) create mode 100644 drivers/firmware/psci_checker.c (limited to 'drivers') diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 9968de04d1d5..6a42a098fe59 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig @@ -8,6 +8,17 @@ menu "Firmware Drivers" config ARM_PSCI_FW bool +config ARM_PSCI_CHECKER + bool "ARM PSCI checker" + depends on ARM_PSCI_FW && HOTPLUG_CPU && !TORTURE_TEST + help + Run the PSCI checker during startup. This checks that hotplug and + suspend operations work correctly when using PSCI. + + The torture tests may interfere with the PSCI checker by turning CPUs + on and off through hotplug, so for now torture tests and PSCI checker + are mutually exclusive. + config ARM_SCPI_PROTOCOL tristate "ARM System Control and Power Interface (SCPI) Message Protocol" depends on MAILBOX diff --git a/drivers/firmware/Makefile b/drivers/firmware/Makefile index 2afe75c52ac2..e9e178b38f7e 100644 --- a/drivers/firmware/Makefile +++ b/drivers/firmware/Makefile @@ -2,6 +2,7 @@ # Makefile for the linux kernel. # obj-$(CONFIG_ARM_PSCI_FW) += psci.o +obj-$(CONFIG_ARM_PSCI_CHECKER) += psci_checker.o obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o obj-$(CONFIG_DMI) += dmi_scan.o diff --git a/drivers/firmware/psci_checker.c b/drivers/firmware/psci_checker.c new file mode 100644 index 000000000000..44bdb78f837b --- /dev/null +++ b/drivers/firmware/psci_checker.c @@ -0,0 +1,490 @@ +/* + * 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. + * + * Copyright (C) 2016 ARM Limited + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define NUM_SUSPEND_CYCLE (10) + +static unsigned int nb_available_cpus; +static int tos_resident_cpu = -1; + +static atomic_t nb_active_threads; +static struct completion suspend_threads_started = + COMPLETION_INITIALIZER(suspend_threads_started); +static struct completion suspend_threads_done = + COMPLETION_INITIALIZER(suspend_threads_done); + +/* + * We assume that PSCI operations are used if they are available. This is not + * necessarily true on arm64, since the decision is based on the + * "enable-method" property of each CPU in the DT, but given that there is no + * arch-specific way to check this, we assume that the DT is sensible. + */ +static int psci_ops_check(void) +{ + int migrate_type = -1; + int cpu; + + if (!(psci_ops.cpu_off && psci_ops.cpu_on && psci_ops.cpu_suspend)) { + pr_warn("Missing PSCI operations, aborting tests\n"); + return -EOPNOTSUPP; + } + + if (psci_ops.migrate_info_type) + migrate_type = psci_ops.migrate_info_type(); + + if (migrate_type == PSCI_0_2_TOS_UP_MIGRATE || + migrate_type == PSCI_0_2_TOS_UP_NO_MIGRATE) { + /* There is a UP Trusted OS, find on which core it resides. */ + for_each_online_cpu(cpu) + if (psci_tos_resident_on(cpu)) { + tos_resident_cpu = cpu; + break; + } + if (tos_resident_cpu == -1) + pr_warn("UP Trusted OS resides on no online CPU\n"); + } + + return 0; +} + +static int find_clusters(const struct cpumask *cpus, + const struct cpumask **clusters) +{ + unsigned int nb = 0; + cpumask_var_t tmp; + + if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) + return -ENOMEM; + cpumask_copy(tmp, cpus); + + while (!cpumask_empty(tmp)) { + const struct cpumask *cluster = + topology_core_cpumask(cpumask_any(tmp)); + + clusters[nb++] = cluster; + cpumask_andnot(tmp, tmp, cluster); + } + + free_cpumask_var(tmp); + return nb; +} + +/* + * offlined_cpus is a temporary array but passing it as an argument avoids + * multiple allocations. + */ +static unsigned int down_and_up_cpus(const struct cpumask *cpus, + struct cpumask *offlined_cpus) +{ + int cpu; + int err = 0; + + cpumask_clear(offlined_cpus); + + /* Try to power down all CPUs in the mask. */ + for_each_cpu(cpu, cpus) { + int ret = cpu_down(cpu); + + /* + * cpu_down() checks the number of online CPUs before the TOS + * resident CPU. + */ + if (cpumask_weight(offlined_cpus) + 1 == nb_available_cpus) { + if (ret != -EBUSY) { + pr_err("Unexpected return code %d while trying " + "to power down last online CPU %d\n", + ret, cpu); + ++err; + } + } else if (cpu == tos_resident_cpu) { + if (ret != -EPERM) { + pr_err("Unexpected return code %d while trying " + "to power down TOS resident CPU %d\n", + ret, cpu); + ++err; + } + } else if (ret != 0) { + pr_err("Error occurred (%d) while trying " + "to power down CPU %d\n", ret, cpu); + ++err; + } + + if (ret == 0) + cpumask_set_cpu(cpu, offlined_cpus); + } + + /* Try to power up all the CPUs that have been offlined. */ + for_each_cpu(cpu, offlined_cpus) { + int ret = cpu_up(cpu); + + if (ret != 0) { + pr_err("Error occurred (%d) while trying " + "to power up CPU %d\n", ret, cpu); + ++err; + } else { + cpumask_clear_cpu(cpu, offlined_cpus); + } + } + + /* + * Something went bad at some point and some CPUs could not be turned + * back on. + */ + WARN_ON(!cpumask_empty(offlined_cpus) || + num_online_cpus() != nb_available_cpus); + + return err; +} + +static int hotplug_tests(void) +{ + int err; + cpumask_var_t offlined_cpus; + int i, nb_cluster; + const struct cpumask **clusters; + char *page_buf; + + err = -ENOMEM; + if (!alloc_cpumask_var(&offlined_cpus, GFP_KERNEL)) + return err; + /* We may have up to nb_available_cpus clusters. */ + clusters = kmalloc_array(nb_available_cpus, sizeof(*clusters), + GFP_KERNEL); + if (!clusters) + goto out_free_cpus; + page_buf = (char *)__get_free_page(GFP_KERNEL); + if (!page_buf) + goto out_free_clusters; + + err = 0; + nb_cluster = find_clusters(cpu_online_mask, clusters); + + /* + * Of course the last CPU cannot be powered down and cpu_down() should + * refuse doing that. + */ + pr_info("Trying to turn off and on again all CPUs\n"); + err += down_and_up_cpus(cpu_online_mask, offlined_cpus); + + /* + * Take down CPUs by cluster this time. When the last CPU is turned + * off, the cluster itself should shut down. + */ + for (i = 0; i < nb_cluster; ++i) { + int cluster_id = + topology_physical_package_id(cpumask_any(clusters[i])); + ssize_t len = cpumap_print_to_pagebuf(true, page_buf, + clusters[i]); + /* Remove trailing newline. */ + page_buf[len - 1] = '\0'; + pr_info("Trying to turn off and on again cluster %d " + "(CPUs %s)\n", cluster_id, page_buf); + err += down_and_up_cpus(clusters[i], offlined_cpus); + } + + free_page((unsigned long)page_buf); +out_free_clusters: + kfree(clusters); +out_free_cpus: + free_cpumask_var(offlined_cpus); + return err; +} + +static void dummy_callback(unsigned long ignored) {} + +static int suspend_cpu(int index, bool broadcast) +{ + int ret; + + arch_cpu_idle_enter(); + + if (broadcast) { + /* + * The local timer will be shut down, we need to enter tick + * broadcast. + */ + ret = tick_broadcast_enter(); + if (ret) { + /* + * In the absence of hardware broadcast mechanism, + * this CPU might be used to broadcast wakeups, which + * may be why entering tick broadcast has failed. + * There is little the kernel can do to work around + * that, so enter WFI instead (idle state 0). + */ + cpu_do_idle(); + ret = 0; + goto out_arch_exit; + } + } + + /* + * Replicate the common ARM cpuidle enter function + * (arm_enter_idle_state). + */ + ret = CPU_PM_CPU_IDLE_ENTER(arm_cpuidle_suspend, index); + + if (broadcast) + tick_broadcast_exit(); + +out_arch_exit: + arch_cpu_idle_exit(); + + return ret; +} + +static int suspend_test_thread(void *arg) +{ + int cpu = (long)arg; + int i, nb_suspend = 0, nb_shallow_sleep = 0, nb_err = 0; + struct sched_param sched_priority = { .sched_priority = MAX_RT_PRIO-1 }; + struct cpuidle_device *dev; + struct cpuidle_driver *drv; + /* No need for an actual callback, we just want to wake up the CPU. */ + struct timer_list wakeup_timer = + TIMER_INITIALIZER(dummy_callback, 0, 0); + + /* Wait for the main thread to give the start signal. */ + wait_for_completion(&suspend_threads_started); + + /* Set maximum priority to preempt all other threads on this CPU. */ + if (sched_setscheduler_nocheck(current, SCHED_FIFO, &sched_priority)) + pr_warn("Failed to set suspend thread scheduler on CPU %d\n", + cpu); + + dev = this_cpu_read(cpuidle_devices); + drv = cpuidle_get_cpu_driver(dev); + + pr_info("CPU %d entering suspend cycles, states 1 through %d\n", + cpu, drv->state_count - 1); + + for (i = 0; i < NUM_SUSPEND_CYCLE; ++i) { + int index; + /* + * Test all possible states, except 0 (which is usually WFI and + * doesn't use PSCI). + */ + for (index = 1; index < drv->state_count; ++index) { + struct cpuidle_state *state = &drv->states[index]; + bool broadcast = state->flags & CPUIDLE_FLAG_TIMER_STOP; + int ret; + + /* + * Set the timer to wake this CPU up in some time (which + * should be largely sufficient for entering suspend). + * If the local tick is disabled when entering suspend, + * suspend_cpu() takes care of switching to a broadcast + * tick, so the timer will still wake us up. + */ + mod_timer(&wakeup_timer, jiffies + + usecs_to_jiffies(state->target_residency)); + + /* IRQs must be disabled during suspend operations. */ + local_irq_disable(); + + ret = suspend_cpu(index, broadcast); + + /* + * We have woken up. Re-enable IRQs to handle any + * pending interrupt, do not wait until the end of the + * loop. + */ + local_irq_enable(); + + if (ret == index) { + ++nb_suspend; + } else if (ret >= 0) { + /* We did not enter the expected state. */ + ++nb_shallow_sleep; + } else { + pr_err("Failed to suspend CPU %d: error %d " + "(requested state %d, cycle %d)\n", + cpu, ret, index, i); + ++nb_err; + } + } + } + + /* + * Disable the timer to make sure that the timer will not trigger + * later. + */ + del_timer(&wakeup_timer); + + if (atomic_dec_return_relaxed(&nb_active_threads) == 0) + complete(&suspend_threads_done); + + /* Give up on RT scheduling and wait for termination. */ + sched_priority.sched_priority = 0; + if (sched_setscheduler_nocheck(current, SCHED_NORMAL, &sched_priority)) + pr_warn("Failed to set suspend thread scheduler on CPU %d\n", + cpu); + for (;;) { + /* Needs to be set first to avoid missing a wakeup. */ + set_current_state(TASK_INTERRUPTIBLE); + if (kthread_should_stop()) { + __set_current_state(TASK_RUNNING); + break; + } + schedule(); + } + + pr_info("CPU %d suspend test results: success %d, shallow states %d, errors %d\n", + cpu, nb_suspend, nb_shallow_sleep, nb_err); + + return nb_err; +} + +static int suspend_tests(void) +{ + int i, cpu, err = 0; + struct task_struct **threads; + int nb_threads = 0; + + threads = kmalloc_array(nb_available_cpus, sizeof(*threads), + GFP_KERNEL); + if (!threads) + return -ENOMEM; + + /* + * Stop cpuidle to prevent the idle tasks from entering a deep sleep + * mode, as it might interfere with the suspend threads on other CPUs. + * This does not prevent the suspend threads from using cpuidle (only + * the idle tasks check this status). Take the idle lock so that + * the cpuidle driver and device look-up can be carried out safely. + */ + cpuidle_pause_and_lock(); + + for_each_online_cpu(cpu) { + struct task_struct *thread; + /* Check that cpuidle is available on that CPU. */ + struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu); + struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); + + if (!dev || !drv) { + pr_warn("cpuidle not available on CPU %d, ignoring\n", + cpu); + continue; + } + + thread = kthread_create_on_cpu(suspend_test_thread, + (void *)(long)cpu, cpu, + "psci_suspend_test"); + if (IS_ERR(thread)) + pr_err("Failed to create kthread on CPU %d\n", cpu); + else + threads[nb_threads++] = thread; + } + + if (nb_threads < 1) { + err = -ENODEV; + goto out; + } + + atomic_set(&nb_active_threads, nb_threads); + + /* + * Wake up the suspend threads. To avoid the main thread being preempted + * before all the threads have been unparked, the suspend threads will + * wait for the completion of suspend_threads_started. + */ + for (i = 0; i < nb_threads; ++i) + wake_up_process(threads[i]); + complete_all(&suspend_threads_started); + + wait_for_completion(&suspend_threads_done); + + + /* Stop and destroy all threads, get return status. */ + for (i = 0; i < nb_threads; ++i) + err += kthread_stop(threads[i]); + out: + cpuidle_resume_and_unlock(); + kfree(threads); + return err; +} + +static int __init psci_checker(void) +{ + int ret; + + /* + * Since we're in an initcall, we assume that all the CPUs that all + * CPUs that can be onlined have been onlined. + * + * The tests assume that hotplug is enabled but nobody else is using it, + * otherwise the results will be unpredictable. However, since there + * is no userspace yet in initcalls, that should be fine, as long as + * no torture test is running at the same time (see Kconfig). + */ + nb_available_cpus = num_online_cpus(); + + /* Check PSCI operations are set up and working. */ + ret = psci_ops_check(); + if (ret) + return ret; + + pr_info("PSCI checker started using %u CPUs\n", nb_available_cpus); + + pr_info("Starting hotplug tests\n"); + ret = hotplug_tests(); + if (ret == 0) + pr_info("Hotplug tests passed OK\n"); + else if (ret > 0) + pr_err("%d error(s) encountered in hotplug tests\n", ret); + else { + pr_err("Out of memory\n"); + return ret; + } + + pr_info("Starting suspend tests (%d cycles per state)\n", + NUM_SUSPEND_CYCLE); + ret = suspend_tests(); + if (ret == 0) + pr_info("Suspend tests passed OK\n"); + else if (ret > 0) + pr_err("%d error(s) encountered in suspend tests\n", ret); + else { + switch (ret) { + case -ENOMEM: + pr_err("Out of memory\n"); + break; + case -ENODEV: + pr_warn("Could not start suspend tests on any CPU\n"); + break; + } + } + + pr_info("PSCI checker completed\n"); + return ret < 0 ? ret : 0; +} +late_initcall(psci_checker); -- cgit v1.2.3 From d09a0011ec0d511b51d6378a071fd8d75eb27622 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Tue, 8 Nov 2016 17:55:47 +0000 Subject: drivers: psci: Allow PSCI node to be disabled Allow disabling PSCI support (mostly for testing purposes) by setting the status property to "disabled". This makes the node behave in much the same way as proper device nodes. Signed-off-by: Thierry Reding Signed-off-by: Lorenzo Pieralisi Acked-by: Mark Rutland Signed-off-by: Arnd Bergmann --- drivers/firmware/psci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/firmware/psci.c b/drivers/firmware/psci.c index 8263429e21b8..6c60a5087caf 100644 --- a/drivers/firmware/psci.c +++ b/drivers/firmware/psci.c @@ -630,7 +630,7 @@ int __init psci_dt_init(void) np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np); - if (!np) + if (!np || !of_device_is_available(np)) return -ENODEV; init_fn = (psci_initcall_t)matched_np->data; -- cgit v1.2.3 From 4287916d7bab2806305d3296b4cf261fa49d959b Mon Sep 17 00:00:00 2001 From: Heiner Kallweit Date: Thu, 27 Oct 2016 23:13:26 +0200 Subject: mtd: spi-nor: fix flags for s25fl128s The Spansion S25FL128S also supports dual read mode. In addition remove flag SECT_4K. 4K erases are supported, but not uniformly. Signed-off-by: Heiner Kallweit Reviewed-by: Jagan Teki Acked-by: Marek Vasut Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index cebd0cc8a5b1..96e202b1b446 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -906,7 +906,7 @@ static const struct flash_info spi_nor_ids[] = { { "s70fl01gs", INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) }, { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024, 64, 0) }, { "s25sl12801", INFO(0x012018, 0x0301, 64 * 1024, 256, 0) }, - { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SECT_4K | SPI_NOR_QUAD_READ) }, + { "s25fl128s", INFO6(0x012018, 0x4d0180, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024, 64, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25fl129p1", INFO(0x012018, 0x4d01, 64 * 1024, 256, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) }, { "s25sl004a", INFO(0x010212, 0, 64 * 1024, 8, 0) }, -- cgit v1.2.3 From 022a400f90ceeb26405edd5e077d56e2f38c8123 Mon Sep 17 00:00:00 2001 From: Sean Nyekjaer Date: Wed, 5 Oct 2016 10:59:49 +0200 Subject: mtd: spi-nor: add support for s25fl208k Signed-off-by: Sean Nyekjaer Reviewed-by: Jagan Teki Acked-by: Marek Vasut Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 96e202b1b446..a350de9753bd 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -922,6 +922,7 @@ static const struct flash_info spi_nor_ids[] = { { "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, SECT_4K) }, { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) }, { "s25fl204k", INFO(0x014013, 0, 64 * 1024, 8, SECT_4K | SPI_NOR_DUAL_READ) }, + { "s25fl208k", INFO(0x014014, 0, 64 * 1024, 16, SECT_4K | SPI_NOR_DUAL_READ) }, /* SST -- large erase sizes are "overlays", "sectors" are 4K */ { "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) }, -- cgit v1.2.3 From 193e87143c290ec16838f5368adc0e0bc94eb931 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Oct 2016 11:06:47 +0300 Subject: mtd: spi-nor: Off by one in cqspi_setup_flash() There are CQSPI_MAX_CHIPSELECT elements in the ->f_pdata array so the > should be >=. Fixes: 140623410536 ('mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller') Signed-off-by: Dan Carpenter Reviewed-by: Marek Vasut Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/cadence-quadspi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index d403ba7b8f43..944863be0320 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -1082,7 +1082,7 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np) goto err; } - if (cs > CQSPI_MAX_CHIPSELECT) { + if (cs >= CQSPI_MAX_CHIPSELECT) { dev_err(dev, "Chip select %d out of range.\n", cs); goto err; } -- cgit v1.2.3 From 10ad1d754a434c024ce7eeb1cec9f69fd3ecc863 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 13 Oct 2016 11:30:39 +0300 Subject: mtd: spi-nor: Fix some error codes in cqspi_setup_flash() We return success or possibly uninitialized values on these error paths instead of proper error codes. Fixes: 140623410536 ("mtd: spi-nor: Add driver for Cadence Quad SPI Flash Controller") Signed-off-by: Dan Carpenter Reviewed-by: Marek Vasut Reviewed-by: Moritz Fischer Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/cadence-quadspi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/cadence-quadspi.c b/drivers/mtd/spi-nor/cadence-quadspi.c index 944863be0320..d489fbd07c12 100644 --- a/drivers/mtd/spi-nor/cadence-quadspi.c +++ b/drivers/mtd/spi-nor/cadence-quadspi.c @@ -1077,12 +1077,14 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi, struct device_node *np) /* Get flash device data */ for_each_available_child_of_node(dev->of_node, np) { - if (of_property_read_u32(np, "reg", &cs)) { + ret = of_property_read_u32(np, "reg", &cs); + if (ret) { dev_err(dev, "Couldn't determine chip select.\n"); goto err; } if (cs >= CQSPI_MAX_CHIPSELECT) { + ret = -EINVAL; dev_err(dev, "Chip select %d out of range.\n", cs); goto err; } -- cgit v1.2.3 From b08618c929b289699a496b8d45a4e1a014187e56 Mon Sep 17 00:00:00 2001 From: Jagan Teki Date: Tue, 26 Jul 2016 14:07:54 +0530 Subject: mtd: spi-nor: Add at25df321 spi-nor flash support Add Atmel at25df321 spi-nor flash to the list of spi_nor_ids. Cc: Brian Norris Cc: Wenyou Yang Signed-off-by: Jagan Teki Acked-by: Wenyou Yang Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index a350de9753bd..59d1d52b23aa 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -799,6 +799,7 @@ static const struct flash_info spi_nor_ids[] = { { "at25fs040", INFO(0x1f6604, 0, 64 * 1024, 8, SECT_4K) }, { "at25df041a", INFO(0x1f4401, 0, 64 * 1024, 8, SECT_4K) }, + { "at25df321", INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) }, { "at25df321a", INFO(0x1f4701, 0, 64 * 1024, 64, SECT_4K) }, { "at25df641", INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) }, -- cgit v1.2.3 From 61e4611864b396c7e9040b7335f25d3921bc87cd Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Fri, 15 Jul 2016 10:03:48 -0700 Subject: mtd: spi-nor: Add support for N25Q016A This commit adds support in the spi-nor driver for the N25Q016A, a 16Mbit SPI NOR flash from Micron. Cc: David Woodhouse Cc: Brian Norris Cc: Jagan Teki Signed-off-by: Moritz Fischer Reviewed-by: Jagan Teki Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 59d1d52b23aa..72f59a7de173 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -879,6 +879,7 @@ static const struct flash_info spi_nor_ids[] = { { "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) }, /* Micron */ + { "n25q016a", INFO(0x20bb15, 0, 64 * 1024, 32, SECT_4K | SPI_NOR_QUAD_READ) }, { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, { "n25q032a", INFO(0x20bb16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) }, { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SECT_4K | SPI_NOR_QUAD_READ) }, -- cgit v1.2.3 From edd0c8f4932dbf3e21036cb443ba5bdf7449d02b Mon Sep 17 00:00:00 2001 From: IWAMOTO Masahiko Date: Wed, 5 Oct 2016 08:22:52 +0000 Subject: mtd: spi-nor: Add support for mr25h40 Add Everspin mr25h40 512KB MRAM to the list of supported chips. Signed-off-by: Masahiko Iwamoto Reviewed-by: Jagan Teki Acked-by: Marek Vasut Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 72f59a7de173..da7cd69d4857 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -826,6 +826,7 @@ static const struct flash_info spi_nor_ids[] = { /* Everspin */ { "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, { "mr25h10", CAT25_INFO(128 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, + { "mr25h40", CAT25_INFO(512 * 1024, 1, 256, 3, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) }, /* Fujitsu */ { "mb85rs1mt", INFO(0x047f27, 0, 128 * 1024, 1, SPI_NOR_NO_ERASE) }, -- cgit v1.2.3 From dfce0cd943fe0554f5f79d5b29624064dafb18cd Mon Sep 17 00:00:00 2001 From: LABBE Corentin Date: Tue, 16 Aug 2016 14:56:38 +0200 Subject: mtd: spi-nor: constify fsl_qspi_devtype_data All fsl_qspi_devtype_data structures are never modified. This patch constify them. Signed-off-by: LABBE Corentin Acked-by: Han Xu Signed-off-by: Cyrille Pitchen --- drivers/mtd/spi-nor/fsl-quadspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 5c82e4ef1904..b4d8953fb30a 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -224,7 +224,7 @@ struct fsl_qspi_devtype_data { int driver_data; }; -static struct fsl_qspi_devtype_data vybrid_data = { +static const struct fsl_qspi_devtype_data vybrid_data = { .devtype = FSL_QUADSPI_VYBRID, .rxfifo = 128, .txfifo = 64, @@ -232,7 +232,7 @@ static struct fsl_qspi_devtype_data vybrid_data = { .driver_data = QUADSPI_QUIRK_SWAP_ENDIAN, }; -static struct fsl_qspi_devtype_data imx6sx_data = { +static const struct fsl_qspi_devtype_data imx6sx_data = { .devtype = FSL_QUADSPI_IMX6SX, .rxfifo = 128, .txfifo = 512, @@ -241,7 +241,7 @@ static struct fsl_qspi_devtype_data imx6sx_data = { | QUADSPI_QUIRK_TKT245618, }; -static struct fsl_qspi_devtype_data imx7d_data = { +static const struct fsl_qspi_devtype_data imx7d_data = { .devtype = FSL_QUADSPI_IMX7D, .rxfifo = 512, .txfifo = 512, @@ -250,7 +250,7 @@ static struct fsl_qspi_devtype_data imx7d_data = { | QUADSPI_QUIRK_4X_INT_CLK, }; -static struct fsl_qspi_devtype_data imx6ul_data = { +static const struct fsl_qspi_devtype_data imx6ul_data = { .devtype = FSL_QUADSPI_IMX6UL, .rxfifo = 128, .txfifo = 512, -- cgit v1.2.3 From ba5287b6ef6a2ee91dc6cc0829649cecf7b70253 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Thu, 15 Sep 2016 10:27:38 +0300 Subject: tpm/tpm_crb: implement tpm crb idle state The register TPM_CRB_CTRL_REQ_x contains bits goIdle and cmdReady for SW to indicate that the device can enter or should exit the idle state. The legacy ACPI-start (SMI + DMA) based devices do not support these bits and the idle state management is not exposed to the host SW. Thus, this functionality only is enabled only for a CRB start (MMIO) based devices. Based on Jarkko Sakkinen original patch: 'tpm_crb: implement power tpm crb power management' To keep the implementation local to the hw we don't use wait_for_tpm_stat for polling the TPM_CRB_CTRL_REQ. [jarkko.sakkinen@linux.intel.com: removed cmdReady debug trace on a success case due the heavy amount of log traffic it causes.] Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index a7c870af916c..8dd0f20a839c 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -83,6 +83,72 @@ struct crb_priv { u32 cmd_size; }; +/** + * crb_go_idle - request tpm crb device to go the idle state + * + * @dev: crb device + * @priv: crb private data + * + * Write CRB_CTRL_REQ_GO_IDLE to TPM_CRB_CTRL_REQ + * The device should respond within TIMEOUT_C by clearing the bit. + * Anyhow, we do not wait here as a consequent CMD_READY request + * will be handled correctly even if idle was not completed. + * + * The function does nothing for devices with ACPI-start method. + * + * Return: 0 always + */ +static int __maybe_unused crb_go_idle(struct device *dev, struct crb_priv *priv) +{ + if (priv->flags & CRB_FL_ACPI_START) + return 0; + + iowrite32(CRB_CTRL_REQ_GO_IDLE, &priv->cca->req); + /* we don't really care when this settles */ + + return 0; +} + +/** + * crb_cmd_ready - request tpm crb device to enter ready state + * + * @dev: crb device + * @priv: crb private data + * + * Write CRB_CTRL_REQ_CMD_READY to TPM_CRB_CTRL_REQ + * and poll till the device acknowledge it by clearing the bit. + * The device should respond within TIMEOUT_C. + * + * The function does nothing for devices with ACPI-start method + * + * Return: 0 on success -ETIME on timeout; + */ +static int __maybe_unused crb_cmd_ready(struct device *dev, + struct crb_priv *priv) +{ + ktime_t stop, start; + + if (priv->flags & CRB_FL_ACPI_START) + return 0; + + iowrite32(CRB_CTRL_REQ_CMD_READY, &priv->cca->req); + + start = ktime_get(); + stop = ktime_add(start, ms_to_ktime(TPM2_TIMEOUT_C)); + do { + if (!(ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY)) + return 0; + usleep_range(50, 100); + } while (ktime_before(ktime_get(), stop)); + + if (ioread32(&priv->cca->req) & CRB_CTRL_REQ_CMD_READY) { + dev_warn(dev, "cmdReady timed out\n"); + return -ETIME; + } + + return 0; +} + static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); static u8 crb_status(struct tpm_chip *chip) -- cgit v1.2.3 From bc33c5df710c0aae6db396146194108634ef6f60 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Mon, 12 Sep 2016 16:04:19 +0300 Subject: tmp/tpm_crb: fix Intel PTT hw bug during idle state There is a HW bug in Skylake, and Broxton PCH Intel PTT device, where most of the registers in the control area except START, REQUEST, CANCEL, and LOC_CTRL lost retention when the device is in the idle state. Hence we need to bring the device to ready state before accessing the other registers. The fix brings device to ready state before trying to read command and response buffer addresses in order to remap the for access. Signed-off-by: Tomas Winkler Tested-by: Jarkko Sakkinen Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 47 ++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 39 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index 8dd0f20a839c..ff0d505ecffd 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -315,6 +315,7 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, struct list_head resources; struct resource io_res; struct device *dev = &device->dev; + u32 pa_high, pa_low; u64 cmd_pa; u32 cmd_size; u64 rsp_pa; @@ -342,12 +343,27 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, if (IS_ERR(priv->cca)) return PTR_ERR(priv->cca); - cmd_pa = ((u64) ioread32(&priv->cca->cmd_pa_high) << 32) | - (u64) ioread32(&priv->cca->cmd_pa_low); + /* + * PTT HW bug w/a: wake up the device to access + * possibly not retained registers. + */ + ret = crb_cmd_ready(dev, priv); + if (ret) + return ret; + + pa_high = ioread32(&priv->cca->cmd_pa_high); + pa_low = ioread32(&priv->cca->cmd_pa_low); + cmd_pa = ((u64)pa_high << 32) | pa_low; cmd_size = ioread32(&priv->cca->cmd_size); + + dev_dbg(dev, "cmd_hi = %X cmd_low = %X cmd_size %X\n", + pa_high, pa_low, cmd_size); + priv->cmd = crb_map_res(dev, priv, &io_res, cmd_pa, cmd_size); - if (IS_ERR(priv->cmd)) - return PTR_ERR(priv->cmd); + if (IS_ERR(priv->cmd)) { + ret = PTR_ERR(priv->cmd); + goto out; + } memcpy_fromio(&rsp_pa, &priv->cca->rsp_pa, 8); rsp_pa = le64_to_cpu(rsp_pa); @@ -355,7 +371,8 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, if (cmd_pa != rsp_pa) { priv->rsp = crb_map_res(dev, priv, &io_res, rsp_pa, rsp_size); - return PTR_ERR_OR_ZERO(priv->rsp); + ret = PTR_ERR_OR_ZERO(priv->rsp); + goto out; } /* According to the PTP specification, overlapping command and response @@ -363,12 +380,18 @@ static int crb_map_io(struct acpi_device *device, struct crb_priv *priv, */ if (cmd_size != rsp_size) { dev_err(dev, FW_BUG "overlapping command and response buffer sizes are not identical"); - return -EINVAL; + ret = -EINVAL; + goto out; } + priv->cmd_size = cmd_size; priv->rsp = priv->cmd; - return 0; + +out: + crb_go_idle(dev, priv); + + return ret; } static int crb_acpi_add(struct acpi_device *device) @@ -412,7 +435,15 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; - return crb_init(device, priv); + rc = crb_cmd_ready(dev, priv); + if (rc) + return rc; + + rc = crb_init(device, priv); + if (rc) + crb_go_idle(dev, priv); + + return rc; } static int crb_acpi_remove(struct acpi_device *device) -- cgit v1.2.3 From c58bd34cec4c05f8e3362a79ae94de9f405c39b5 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Mon, 12 Sep 2016 16:04:20 +0300 Subject: tpm/tpm_crb: open code the crb_init into acpi_add This is preparation step for implementing tpm crb runtime pm. We need to have tpm chip allocated and populated before we access the runtime handlers. Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_crb.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index ff0d505ecffd..f579f1ac4688 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -262,21 +262,6 @@ static const struct tpm_class_ops tpm_crb = { .req_complete_val = CRB_DRV_STS_COMPLETE, }; -static int crb_init(struct acpi_device *device, struct crb_priv *priv) -{ - struct tpm_chip *chip; - - chip = tpmm_chip_alloc(&device->dev, &tpm_crb); - if (IS_ERR(chip)) - return PTR_ERR(chip); - - dev_set_drvdata(&chip->dev, priv); - chip->acpi_dev_handle = device->handle; - chip->flags = TPM_CHIP_FLAG_TPM2; - - return tpm_chip_register(chip); -} - static int crb_check_resource(struct acpi_resource *ares, void *data) { struct resource *io_res = data; @@ -398,6 +383,7 @@ static int crb_acpi_add(struct acpi_device *device) { struct acpi_table_tpm2 *buf; struct crb_priv *priv; + struct tpm_chip *chip; struct device *dev = &device->dev; acpi_status status; u32 sm; @@ -435,11 +421,19 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; + chip = tpmm_chip_alloc(dev, &tpm_crb); + if (IS_ERR(chip)) + return PTR_ERR(chip); + + dev_set_drvdata(&chip->dev, priv); + chip->acpi_dev_handle = device->handle; + chip->flags = TPM_CHIP_FLAG_TPM2; + rc = crb_cmd_ready(dev, priv); if (rc) return rc; - rc = crb_init(device, priv); + rc = tpm_chip_register(chip); if (rc) crb_go_idle(dev, priv); -- cgit v1.2.3 From e74f2f76c13770bb8e004475a933923e9c92723d Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Sat, 8 Oct 2016 14:59:39 +0300 Subject: tmp/tpm_crb: implement runtime pm for tpm_crb Utilize runtime_pm for driving tpm crb idle states. The framework calls cmd_ready from the pm_runtime_resume handler and go idle from the pm_runtime_suspend handler. The TPM framework should wake the device before transmit and receive. In case the runtime_pm framework is not compiled in or enabled, the device will be in the permanent ready state. Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 5 +++++ drivers/char/tpm/tpm_crb.c | 42 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 43 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index 3a9149cf0110..cb0e57ee053d 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "tpm.h" #include "tpm_eventlog.h" @@ -356,6 +357,8 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); + pm_runtime_get_sync(chip->dev.parent); + rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { dev_err(&chip->dev, @@ -397,6 +400,8 @@ out_recv: dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: + pm_runtime_put_sync(chip->dev.parent); + if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); return rc; diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c index f579f1ac4688..717b6b47c042 100644 --- a/drivers/char/tpm/tpm_crb.c +++ b/drivers/char/tpm/tpm_crb.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "tpm.h" #define ACPI_SIG_TPM2 "TPM2" @@ -149,8 +150,6 @@ static int __maybe_unused crb_cmd_ready(struct device *dev, return 0; } -static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume); - static u8 crb_status(struct tpm_chip *chip) { struct crb_priv *priv = dev_get_drvdata(&chip->dev); @@ -433,11 +432,21 @@ static int crb_acpi_add(struct acpi_device *device) if (rc) return rc; + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + rc = tpm_chip_register(chip); - if (rc) + if (rc) { crb_go_idle(dev, priv); + pm_runtime_put_noidle(dev); + pm_runtime_disable(dev); + return rc; + } - return rc; + pm_runtime_put(dev); + + return 0; } static int crb_acpi_remove(struct acpi_device *device) @@ -447,9 +456,34 @@ static int crb_acpi_remove(struct acpi_device *device) tpm_chip_unregister(chip); + pm_runtime_disable(dev); + return 0; } +#ifdef CONFIG_PM +static int crb_pm_runtime_suspend(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return crb_go_idle(dev, priv); +} + +static int crb_pm_runtime_resume(struct device *dev) +{ + struct tpm_chip *chip = dev_get_drvdata(dev); + struct crb_priv *priv = dev_get_drvdata(&chip->dev); + + return crb_cmd_ready(dev, priv); +} +#endif /* CONFIG_PM */ + +static const struct dev_pm_ops crb_pm = { + SET_SYSTEM_SLEEP_PM_OPS(tpm_pm_suspend, tpm_pm_resume) + SET_RUNTIME_PM_OPS(crb_pm_runtime_suspend, crb_pm_runtime_resume, NULL) +}; + static struct acpi_device_id crb_device_ids[] = { {"MSFT0101", 0}, {"", 0}, -- cgit v1.2.3 From 2c97f6f20cb193264360067259029892c70ce63f Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 11 Oct 2016 15:01:01 +0300 Subject: char/tpm: Check return code of wait_for_tpm_stat In some weird cases it might be possible that the TPM does not set STS.VALID within the given timeout time (or ever) but sets STS.EXPECT (STS=0x0C) In this case the driver gets stuck in the while loop of tpm_tis_send_data and loops endlessly. Checking the return value of wait_for_tpm_stat fixes this and the driver bails out correctly. While at it fixing all other users since if the TPM does not manage to set STS.VALID within the reasonable timeframe something is definitely wrong and the driver should react correctly. Signed-off-by: Peter Huewe Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_core.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index e3bf31b37138..73f4c4bbc4df 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -180,11 +180,13 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) struct tpm_tis_data *priv = dev_get_drvdata(&chip->dev); int size = 0, burstcnt, rc; - while (size < count && - wait_for_tpm_stat(chip, + while (size < count) { + rc = wait_for_tpm_stat(chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, chip->timeout_c, - &priv->read_queue, true) == 0) { + &priv->read_queue, true); + if (rc < 0) + return rc; burstcnt = min_t(int, get_burstcount(chip), count - size); rc = tpm_tis_read_bytes(priv, TPM_DATA_FIFO(priv->locality), @@ -229,8 +231,11 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count) goto out; } - wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, - &priv->int_queue, false); + if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, + &priv->int_queue, false) < 0) { + size = -ETIME; + goto out; + } status = tpm_tis_status(chip); if (status & TPM_STS_DATA_AVAIL) { /* retry? */ dev_err(&chip->dev, "Error left over data\n"); @@ -279,8 +284,11 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) count += burstcnt; - wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, - &priv->int_queue, false); + if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, + &priv->int_queue, false) < 0) { + rc = -ETIME; + goto out_err; + } status = tpm_tis_status(chip); if (!itpm && (status & TPM_STS_DATA_EXPECT) == 0) { rc = -EIO; @@ -293,8 +301,11 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) if (rc < 0) goto out_err; - wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, - &priv->int_queue, false); + if (wait_for_tpm_stat(chip, TPM_STS_VALID, chip->timeout_c, + &priv->int_queue, false) < 0) { + rc = -ETIME; + goto out_err; + } status = tpm_tis_status(chip); if (!itpm && (status & TPM_STS_DATA_EXPECT) != 0) { rc = -EIO; -- cgit v1.2.3 From aaa6f7f6c8bf1a056c1bb337578cbb2f0c50c12a Mon Sep 17 00:00:00 2001 From: Ed Swierk Date: Mon, 19 Sep 2016 23:22:08 +0300 Subject: tpm: Clean up reading of timeout and duration capabilities Call tpm_getcap() from tpm_get_timeouts() to eliminate redundant code. Return all errors to the caller rather than swallowing them (e.g. when tpm_transmit_cmd() returns nonzero). Signed-off-by: Ed Swierk Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 65 +++++++++++----------------------------- 1 file changed, 17 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index cb0e57ee053d..acf89e8d838e 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -493,10 +493,9 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type) int tpm_get_timeouts(struct tpm_chip *chip) { - struct tpm_cmd_t tpm_cmd; + cap_t cap; unsigned long new_timeout[4]; unsigned long old_timeout[4]; - struct duration_t *duration_cap; ssize_t rc; if (chip->flags & TPM_CHIP_FLAG_TPM2) { @@ -514,43 +513,25 @@ int tpm_get_timeouts(struct tpm_chip *chip) return 0; } - tpm_cmd.header.in = tpm_getcap_header; - tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; - tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); - tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, - NULL); - + rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, + "attempting to determine the timeouts"); if (rc == TPM_ERR_INVALID_POSTINIT) { /* The TPM is not started, we are the first to talk to it. Execute a startup command. */ - dev_info(&chip->dev, "Issuing TPM_STARTUP"); + dev_info(&chip->dev, "Issuing TPM_STARTUP\n"); if (tpm_startup(chip, TPM_ST_CLEAR)) return rc; - tpm_cmd.header.in = tpm_getcap_header; - tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; - tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); - tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT; - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, - 0, NULL); + rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_TIMEOUT, &cap, + "attempting to determine the timeouts"); } - if (rc) { - dev_err(&chip->dev, - "A TPM error (%zd) occurred attempting to determine the timeouts\n", - rc); - goto duration; - } - - if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || - be32_to_cpu(tpm_cmd.header.out.length) - != sizeof(tpm_cmd.header.out) + sizeof(u32) + 4 * sizeof(u32)) - return -EINVAL; + if (rc) + return rc; - old_timeout[0] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.a); - old_timeout[1] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.b); - old_timeout[2] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.c); - old_timeout[3] = be32_to_cpu(tpm_cmd.params.getcap_out.cap.timeout.d); + old_timeout[0] = be32_to_cpu(cap.timeout.a); + old_timeout[1] = be32_to_cpu(cap.timeout.b); + old_timeout[2] = be32_to_cpu(cap.timeout.c); + old_timeout[3] = be32_to_cpu(cap.timeout.d); memcpy(new_timeout, old_timeout, sizeof(new_timeout)); /* @@ -588,29 +569,17 @@ int tpm_get_timeouts(struct tpm_chip *chip) chip->timeout_c = usecs_to_jiffies(new_timeout[2]); chip->timeout_d = usecs_to_jiffies(new_timeout[3]); -duration: - tpm_cmd.header.in = tpm_getcap_header; - tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; - tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); - tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION; - - rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, - "attempting to determine the durations"); + rc = tpm_getcap(chip, TPM_CAP_PROP_TIS_DURATION, &cap, + "attempting to determine the durations"); if (rc) return rc; - if (be32_to_cpu(tpm_cmd.header.out.return_code) != 0 || - be32_to_cpu(tpm_cmd.header.out.length) - != sizeof(tpm_cmd.header.out) + sizeof(u32) + 3 * sizeof(u32)) - return -EINVAL; - - duration_cap = &tpm_cmd.params.getcap_out.cap.duration; chip->duration[TPM_SHORT] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_short)); + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_short)); chip->duration[TPM_MEDIUM] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_medium)); + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_medium)); chip->duration[TPM_LONG] = - usecs_to_jiffies(be32_to_cpu(duration_cap->tpm_long)); + usecs_to_jiffies(be32_to_cpu(cap.duration.tpm_long)); /* The Broadcom BCM0102 chipset in a Dell Latitude D820 gets the above * value wrong and apparently reports msecs rather than usecs. So we -- cgit v1.2.3 From 84fda15286d1bcf15e1c5cfb8320c5fab770165f Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 19 Sep 2016 23:22:09 +0300 Subject: tpm: sanitize constant expressions Use cpu_to_b32 at the time it is needed in enum tpm_capabilities and enum tpm_sub_capabilities in order to be consistent with the other enums in drivats/char/tpm/tpm.h. Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 15 +++++++++------ drivers/char/tpm/tpm-sysfs.c | 4 ++-- drivers/char/tpm/tpm.h | 25 ++++++++++++------------- 3 files changed, 23 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index acf89e8d838e..fa9752087181 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -442,26 +442,29 @@ static const struct tpm_input_header tpm_getcap_header = { .ordinal = TPM_ORD_GET_CAP }; -ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, +ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, const char *desc) { struct tpm_cmd_t tpm_cmd; int rc; tpm_cmd.header.in = tpm_getcap_header; - if (subcap_id == CAP_VERSION_1_1 || subcap_id == CAP_VERSION_1_2) { - tpm_cmd.params.getcap_in.cap = subcap_id; + if (subcap_id == TPM_CAP_VERSION_1_1 || + subcap_id == TPM_CAP_VERSION_1_2) { + tpm_cmd.params.getcap_in.cap = cpu_to_be32(subcap_id); /*subcap field not necessary */ tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(0); tpm_cmd.header.in.length -= cpu_to_be32(sizeof(__be32)); } else { if (subcap_id == TPM_CAP_FLAG_PERM || subcap_id == TPM_CAP_FLAG_VOL) - tpm_cmd.params.getcap_in.cap = TPM_CAP_FLAG; + tpm_cmd.params.getcap_in.cap = + cpu_to_be32(TPM_CAP_FLAG); else - tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP; + tpm_cmd.params.getcap_in.cap = + cpu_to_be32(TPM_CAP_PROP); tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4); - tpm_cmd.params.getcap_in.subcap = subcap_id; + tpm_cmd.params.getcap_in.subcap = cpu_to_be32(subcap_id); } rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, 0, desc); diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index a76ab4af9fb2..59a1ead4d141 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -193,7 +193,7 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, be32_to_cpu(cap.manufacturer_id)); /* Try to get a TPM version 1.2 TPM_CAP_VERSION_INFO */ - rc = tpm_getcap(chip, CAP_VERSION_1_2, &cap, + rc = tpm_getcap(chip, TPM_CAP_VERSION_1_2, &cap, "attempting to determine the 1.2 version"); if (!rc) { str += sprintf(str, @@ -204,7 +204,7 @@ static ssize_t caps_show(struct device *dev, struct device_attribute *attr, cap.tpm_version_1_2.revMinor); } else { /* Otherwise just use TPM_STRUCT_VER */ - rc = tpm_getcap(chip, CAP_VERSION_1_1, &cap, + rc = tpm_getcap(chip, TPM_CAP_VERSION_1_1, &cap, "attempting to determine the 1.1 version"); if (rc) return 0; diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 4d183c97f6a6..186493234c52 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -282,21 +282,20 @@ typedef union { } cap_t; enum tpm_capabilities { - TPM_CAP_FLAG = cpu_to_be32(4), - TPM_CAP_PROP = cpu_to_be32(5), - CAP_VERSION_1_1 = cpu_to_be32(0x06), - CAP_VERSION_1_2 = cpu_to_be32(0x1A) + TPM_CAP_FLAG = 4, + TPM_CAP_PROP = 5, + TPM_CAP_VERSION_1_1 = 0x06, + TPM_CAP_VERSION_1_2 = 0x1A, }; enum tpm_sub_capabilities { - TPM_CAP_PROP_PCR = cpu_to_be32(0x101), - TPM_CAP_PROP_MANUFACTURER = cpu_to_be32(0x103), - TPM_CAP_FLAG_PERM = cpu_to_be32(0x108), - TPM_CAP_FLAG_VOL = cpu_to_be32(0x109), - TPM_CAP_PROP_OWNER = cpu_to_be32(0x111), - TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), - TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), - + TPM_CAP_PROP_PCR = 0x101, + TPM_CAP_PROP_MANUFACTURER = 0x103, + TPM_CAP_FLAG_PERM = 0x108, + TPM_CAP_FLAG_VOL = 0x109, + TPM_CAP_PROP_OWNER = 0x111, + TPM_CAP_PROP_TIS_TIMEOUT = 0x115, + TPM_CAP_PROP_TIS_DURATION = 0x120, }; struct tpm_getcap_params_in { @@ -484,7 +483,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, unsigned int flags); ssize_t tpm_transmit_cmd(struct tpm_chip *chip, const void *cmd, int len, unsigned int flags, const char *desc); -ssize_t tpm_getcap(struct tpm_chip *chip, __be32 subcap_id, cap_t *cap, +ssize_t tpm_getcap(struct tpm_chip *chip, u32 subcap_id, cap_t *cap, const char *desc); int tpm_get_timeouts(struct tpm_chip *); int tpm1_auto_startup(struct tpm_chip *chip); -- cgit v1.2.3 From ca6d45802201c2680af040579af7697049149e38 Mon Sep 17 00:00:00 2001 From: "Winkler, Tomas" Date: Tue, 1 Nov 2016 03:05:13 +0200 Subject: tpm: place kdoc just above tpm_pcr_extend Place kdoc just above tpm_pcr_extend so it can be parsed correctly. Signed-off-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index fa9752087181..ffdae1daa138 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -703,6 +703,14 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf) } EXPORT_SYMBOL_GPL(tpm_pcr_read); +#define TPM_ORD_PCR_EXTEND cpu_to_be32(20) +#define EXTEND_PCR_RESULT_SIZE 34 +static const struct tpm_input_header pcrextend_header = { + .tag = TPM_TAG_RQU_COMMAND, + .length = cpu_to_be32(34), + .ordinal = TPM_ORD_PCR_EXTEND +}; + /** * tpm_pcr_extend - extend pcr value with hash * @chip_num: tpm idx # or AN& @@ -713,14 +721,6 @@ EXPORT_SYMBOL_GPL(tpm_pcr_read); * isn't, protect against the chip disappearing, by incrementing * the module usage count. */ -#define TPM_ORD_PCR_EXTEND cpu_to_be32(20) -#define EXTEND_PCR_RESULT_SIZE 34 -static const struct tpm_input_header pcrextend_header = { - .tag = TPM_TAG_RQU_COMMAND, - .length = cpu_to_be32(34), - .ordinal = TPM_ORD_PCR_EXTEND -}; - int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash) { struct tpm_cmd_t cmd; -- cgit v1.2.3 From 26a137e31ffe6fbfdb008554a8d9b3d55bd5c86e Mon Sep 17 00:00:00 2001 From: Josh Zimmerman Date: Thu, 27 Oct 2016 14:50:09 -0700 Subject: tpm_tis: Check return values from get_burstcount. If the TPM we're connecting to uses a static burst count, it will report a burst count of zero throughout the response read. However, get_burstcount assumes that a response of zero indicates that the TPM is not ready to receive more data. In this case, it returns a negative error code, which is passed on to tpm_tis_{write,read}_bytes as a u16, causing them to read/write far too many bytes. This patch checks for negative return codes and bails out from recv_data and tpm_tis_send_data. Cc: stable@vger.kernel.org Fixes: 1107d065fdf1 (tpm_tis: Introduce intermediate layer for TPM access) Signed-off-by: Josh Zimmerman Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_tis_core.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 73f4c4bbc4df..2d1e451fb1b3 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -187,7 +187,12 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count) &priv->read_queue, true); if (rc < 0) return rc; - burstcnt = min_t(int, get_burstcount(chip), count - size); + burstcnt = get_burstcount(chip); + if (burstcnt < 0) { + dev_err(&chip->dev, "Unable to read burstcount\n"); + return burstcnt; + } + burstcnt = min_t(int, burstcnt, count - size); rc = tpm_tis_read_bytes(priv, TPM_DATA_FIFO(priv->locality), burstcnt, buf + size); @@ -276,7 +281,13 @@ static int tpm_tis_send_data(struct tpm_chip *chip, u8 *buf, size_t len) } while (count < len - 1) { - burstcnt = min_t(int, get_burstcount(chip), len - count - 1); + burstcnt = get_burstcount(chip); + if (burstcnt < 0) { + dev_err(&chip->dev, "Unable to read burstcount\n"); + rc = burstcnt; + goto out_err; + } + burstcnt = min_t(int, burstcnt, len - count - 1); rc = tpm_tis_write_bytes(priv, TPM_DATA_FIFO(priv->locality), burstcnt, buf + count); if (rc < 0) -- cgit v1.2.3 From d1d253cff74fb866bce69c5052764ed571383ea8 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 26 Oct 2016 16:28:44 -0600 Subject: tpm tis: Do not print timeout messages twice The tis driver does a tpm_get_timeouts out side of tpm_chip_register, and tpm_get_timeouts can print a message, resulting in two prints, eg: tpm tpm0: [Hardware Error]: Adjusting reported timeouts: A 10000->750000us B 10000->2000000us C 10000->750000us D 10000->750000us Keep track and prevent tpm_get_timeouts from running a second time, and clarify the purpose of the call in tpm_tis_core to only be connected to irq testing. Signed-off-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 7 +++++++ drivers/char/tpm/tpm.h | 1 + drivers/char/tpm/tpm_tis_core.c | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index ffdae1daa138..ef0fcdb40cc3 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -501,6 +501,9 @@ int tpm_get_timeouts(struct tpm_chip *chip) unsigned long old_timeout[4]; ssize_t rc; + if (chip->flags & TPM_CHIP_FLAG_HAVE_TIMEOUTS) + return 0; + if (chip->flags & TPM_CHIP_FLAG_TPM2) { /* Fixed timeouts for TPM2 */ chip->timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A); @@ -513,6 +516,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) msecs_to_jiffies(TPM2_DURATION_MEDIUM); chip->duration[TPM_LONG] = msecs_to_jiffies(TPM2_DURATION_LONG); + + chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS; return 0; } @@ -596,6 +601,8 @@ int tpm_get_timeouts(struct tpm_chip *chip) chip->duration_adjusted = true; dev_info(&chip->dev, "Adjusting TPM timeout parameters."); } + + chip->flags |= TPM_CHIP_FLAG_HAVE_TIMEOUTS; return 0; } EXPORT_SYMBOL_GPL(tpm_get_timeouts); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 186493234c52..21c3dbe8c89c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -143,6 +143,7 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_TPM2 = BIT(1), TPM_CHIP_FLAG_IRQ = BIT(2), TPM_CHIP_FLAG_VIRTUAL = BIT(3), + TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), }; struct tpm_chip { diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c index 2d1e451fb1b3..7993678954a2 100644 --- a/drivers/char/tpm/tpm_tis_core.c +++ b/drivers/char/tpm/tpm_tis_core.c @@ -777,20 +777,20 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq, if (intfcaps & TPM_INTF_DATA_AVAIL_INT) dev_dbg(dev, "\tData Avail Int Support\n"); - /* Very early on issue a command to the TPM in polling mode to make - * sure it works. May as well use that command to set the proper - * timeouts for the driver. - */ - if (tpm_get_timeouts(chip)) { - dev_err(dev, "Could not get TPM timeouts and durations\n"); - rc = -ENODEV; - goto out_err; - } - /* INTERRUPT Setup */ init_waitqueue_head(&priv->read_queue); init_waitqueue_head(&priv->int_queue); if (irq != -1) { + /* Before doing irq testing issue a command to the TPM in polling mode + * to make sure it works. May as well use that command to set the + * proper timeouts for the driver. + */ + if (tpm_get_timeouts(chip)) { + dev_err(dev, "Could not get TPM timeouts and durations\n"); + rc = -ENODEV; + goto out_err; + } + if (irq) { tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED, irq); -- cgit v1.2.3 From 1f0f30e404b3d8f4597a2d9b77fba55452f8fd0e Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 26 Oct 2016 16:28:45 -0600 Subject: tpm xen: Remove bogus tpm_chip_unregister tpm_chip_unregister can only be called after tpm_chip_register. devm manages the allocation so no unwind is needed here. Cc: stable@vger.kernel.org Fixes: afb5abc262e96 ("tpm: two-phase chip management functions") Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/xen-tpmfront.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c index 62028f483bba..a2ab00831df1 100644 --- a/drivers/char/tpm/xen-tpmfront.c +++ b/drivers/char/tpm/xen-tpmfront.c @@ -307,7 +307,6 @@ static int tpmfront_probe(struct xenbus_device *dev, rv = setup_ring(dev, priv); if (rv) { chip = dev_get_drvdata(&dev->dev); - tpm_chip_unregister(chip); ring_free(priv); return rv; } -- cgit v1.2.3 From 1a277e674bc2cf5300c77e1901ae2357726afe07 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Wed, 26 Oct 2016 16:28:46 -0600 Subject: tpm: Get rid of TPM_CHIP_FLAG_REGISTERED This is no longer necessary, all calls to tpm_chip_unregister happen in remove() callbacks. Signed-off-by: Jason Gunthorpe Reviewed-by: Tomas Winkler Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 5 ----- drivers/char/tpm/tpm.h | 1 - 2 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e5950131bd90..836f056f7d27 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -375,8 +375,6 @@ int tpm_chip_register(struct tpm_chip *chip) return rc; } - chip->flags |= TPM_CHIP_FLAG_REGISTERED; - rc = tpm_add_legacy_sysfs(chip); if (rc) { tpm_chip_unregister(chip); @@ -402,9 +400,6 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); */ void tpm_chip_unregister(struct tpm_chip *chip) { - if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED)) - return; - tpm_del_legacy_sysfs(chip); tpm1_chip_unregister(chip); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 21c3dbe8c89c..f9401ca0454c 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -139,7 +139,6 @@ enum tpm2_startup_types { #define TPM_PPI_VERSION_LEN 3 enum tpm_chip_flags { - TPM_CHIP_FLAG_REGISTERED = BIT(0), TPM_CHIP_FLAG_TPM2 = BIT(1), TPM_CHIP_FLAG_IRQ = BIT(2), TPM_CHIP_FLAG_VIRTUAL = BIT(3), -- cgit v1.2.3 From 2528a64664f8a463d85b6e6876b4025042687553 Mon Sep 17 00:00:00 2001 From: Nayna Jain Date: Tue, 18 Oct 2016 20:49:39 -0400 Subject: tpm: define a generic open() method for ascii & bios measurements open() method for event log ascii and binary bios measurements file operations are very similar. This patch refactors the code into a single open() call by passing seq_operations as i_node->private data. Suggested-by: Jason Gunthorpe Signed-off-by: Nayna Jain Reviewed-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_eventlog.c | 63 ++++++++++------------------------------- 1 file changed, 15 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index e7228863290e..42b49c4dff01 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -7,6 +7,7 @@ * Stefan Berger * Reiner Sailer * Kylene Hall + * Nayna Jain * * Maintained by: * @@ -304,26 +305,28 @@ static int tpm_ascii_bios_measurements_show(struct seq_file *m, void *v) return 0; } -static const struct seq_operations tpm_ascii_b_measurments_seqops = { +static const struct seq_operations tpm_ascii_b_measurements_seqops = { .start = tpm_bios_measurements_start, .next = tpm_bios_measurements_next, .stop = tpm_bios_measurements_stop, .show = tpm_ascii_bios_measurements_show, }; -static const struct seq_operations tpm_binary_b_measurments_seqops = { +static const struct seq_operations tpm_binary_b_measurements_seqops = { .start = tpm_bios_measurements_start, .next = tpm_bios_measurements_next, .stop = tpm_bios_measurements_stop, .show = tpm_binary_bios_measurements_show, }; -static int tpm_ascii_bios_measurements_open(struct inode *inode, +static int tpm_bios_measurements_open(struct inode *inode, struct file *file) { int err; struct tpm_bios_log *log; struct seq_file *seq; + const struct seq_operations *seqops = + (const struct seq_operations *)inode->i_private; log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); if (!log) @@ -333,7 +336,7 @@ static int tpm_ascii_bios_measurements_open(struct inode *inode, goto out_free; /* now register seq file */ - err = seq_open(file, &tpm_ascii_b_measurments_seqops); + err = seq_open(file, seqops); if (!err) { seq = file->private_data; seq->private = log; @@ -349,46 +352,8 @@ out_free: goto out; } -static const struct file_operations tpm_ascii_bios_measurements_ops = { - .open = tpm_ascii_bios_measurements_open, - .read = seq_read, - .llseek = seq_lseek, - .release = tpm_bios_measurements_release, -}; - -static int tpm_binary_bios_measurements_open(struct inode *inode, - struct file *file) -{ - int err; - struct tpm_bios_log *log; - struct seq_file *seq; - - log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); - if (!log) - return -ENOMEM; - - if ((err = read_log(log))) - goto out_free; - - /* now register seq file */ - err = seq_open(file, &tpm_binary_b_measurments_seqops); - if (!err) { - seq = file->private_data; - seq->private = log; - } else { - goto out_free; - } - -out: - return err; -out_free: - kfree(log->bios_event_log); - kfree(log); - goto out; -} - -static const struct file_operations tpm_binary_bios_measurements_ops = { - .open = tpm_binary_bios_measurements_open, +static const struct file_operations tpm_bios_measurements_ops = { + .open = tpm_bios_measurements_open, .read = seq_read, .llseek = seq_lseek, .release = tpm_bios_measurements_release, @@ -413,15 +378,17 @@ struct dentry **tpm_bios_log_setup(const char *name) bin_file = securityfs_create_file("binary_bios_measurements", - S_IRUSR | S_IRGRP, tpm_dir, NULL, - &tpm_binary_bios_measurements_ops); + S_IRUSR | S_IRGRP, tpm_dir, + (void *)&tpm_binary_b_measurements_seqops, + &tpm_bios_measurements_ops); if (is_bad(bin_file)) goto out_tpm; ascii_file = securityfs_create_file("ascii_bios_measurements", - S_IRUSR | S_IRGRP, tpm_dir, NULL, - &tpm_ascii_bios_measurements_ops); + S_IRUSR | S_IRGRP, tpm_dir, + (void *)&tpm_ascii_b_measurements_seqops, + &tpm_bios_measurements_ops); if (is_bad(ascii_file)) goto out_bin; -- cgit v1.2.3 From 6804f6bba09997393904a112f2043963a8e08abf Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Mon, 7 Nov 2016 07:14:33 -0500 Subject: tpm: Only call pm_runtime_get_sync if device has a parent Only call pm_runtime_get_sync if the device has a parent. This change fixes a crash in the tpm_vtpm_proxy driver since that driver does not have a parent device. Signed-off-by: Stefan Berger Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-interface.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c index ef0fcdb40cc3..a2688ac2b48f 100644 --- a/drivers/char/tpm/tpm-interface.c +++ b/drivers/char/tpm/tpm-interface.c @@ -357,7 +357,8 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const u8 *buf, size_t bufsiz, if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_lock(&chip->tpm_mutex); - pm_runtime_get_sync(chip->dev.parent); + if (chip->dev.parent) + pm_runtime_get_sync(chip->dev.parent); rc = chip->ops->send(chip, (u8 *) buf, count); if (rc < 0) { @@ -400,7 +401,8 @@ out_recv: dev_err(&chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); out: - pm_runtime_put_sync(chip->dev.parent); + if (chip->dev.parent) + pm_runtime_put_sync(chip->dev.parent); if (!(flags & TPM_TRANSMIT_UNLOCKED)) mutex_unlock(&chip->tpm_mutex); -- cgit v1.2.3 From 7ea7861c8c2462af932410c54542cb279683eaf8 Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Thu, 3 Nov 2016 17:57:50 -0600 Subject: tpm, tpm_vtpm_proxy: add kdoc comments for VTPM_PROXY_IOC_NEW_DEV Added kdoc comments for VTPM_PROXY_IOC_NEW_DEV so that these can be imported to the kernel documentation written with rst markup and generated with Sphinx. Signed-off-by: Jarkko Sakkinen Reviewed-by: Stefan Berger --- drivers/char/tpm/tpm_vtpm_proxy.c | 72 +++++++++++++++++++++++++-------------- include/uapi/linux/vtpm_proxy.h | 23 ++++++++++--- 2 files changed, 65 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 9a940332c157..3d6f6ca81def 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2015, 2016 IBM Corporation + * Copyright (C) 2016 Intel Corporation * * Author: Stefan Berger * @@ -524,6 +525,50 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev) * Code related to the control device /dev/vtpmx */ +/** + * vtpmx_ioc_new_dev - handler for the %VTPM_PROXY_IOC_NEW_DEV ioctl + * @file: /dev/vtpmx + * @ioctl: the ioctl number + * @arg: pointer to the struct vtpmx_proxy_new_dev + * + * Creates an anonymous file that is used by the process acting as a TPM to + * communicate with the client processes. The function will also add a new TPM + * device through which data is proxied to this TPM acting process. The caller + * will be provided with a file descriptor to communicate with the clients and + * major and minor numbers for the TPM device. + */ +static long vtpmx_ioc_new_dev(struct file *file, unsigned int ioctl, + unsigned long arg) +{ + void __user *argp = (void __user *)arg; + struct vtpm_proxy_new_dev __user *vtpm_new_dev_p; + struct vtpm_proxy_new_dev vtpm_new_dev; + struct file *vtpm_file; + + if (!capable(CAP_SYS_ADMIN)) + return -EPERM; + + vtpm_new_dev_p = argp; + + if (copy_from_user(&vtpm_new_dev, vtpm_new_dev_p, + sizeof(vtpm_new_dev))) + return -EFAULT; + + vtpm_file = vtpm_proxy_create_device(&vtpm_new_dev); + if (IS_ERR(vtpm_file)) + return PTR_ERR(vtpm_file); + + if (copy_to_user(vtpm_new_dev_p, &vtpm_new_dev, + sizeof(vtpm_new_dev))) { + put_unused_fd(vtpm_new_dev.fd); + fput(vtpm_file); + return -EFAULT; + } + + fd_install(vtpm_new_dev.fd, vtpm_file); + return 0; +} + /* * vtpmx_fops_ioctl: ioctl on /dev/vtpmx * @@ -531,34 +576,11 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev) * Returns 0 on success, a negative error code otherwise. */ static long vtpmx_fops_ioctl(struct file *f, unsigned int ioctl, - unsigned long arg) + unsigned long arg) { - void __user *argp = (void __user *)arg; - struct vtpm_proxy_new_dev __user *vtpm_new_dev_p; - struct vtpm_proxy_new_dev vtpm_new_dev; - struct file *file; - switch (ioctl) { case VTPM_PROXY_IOC_NEW_DEV: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - vtpm_new_dev_p = argp; - if (copy_from_user(&vtpm_new_dev, vtpm_new_dev_p, - sizeof(vtpm_new_dev))) - return -EFAULT; - file = vtpm_proxy_create_device(&vtpm_new_dev); - if (IS_ERR(file)) - return PTR_ERR(file); - if (copy_to_user(vtpm_new_dev_p, &vtpm_new_dev, - sizeof(vtpm_new_dev))) { - put_unused_fd(vtpm_new_dev.fd); - fput(file); - return -EFAULT; - } - - fd_install(vtpm_new_dev.fd, file); - return 0; - + return vtpmx_ioc_new_dev(f, ioctl, arg); default: return -ENOIOCTLCMD; } diff --git a/include/uapi/linux/vtpm_proxy.h b/include/uapi/linux/vtpm_proxy.h index 41e8e2252a30..a69e991eb080 100644 --- a/include/uapi/linux/vtpm_proxy.h +++ b/include/uapi/linux/vtpm_proxy.h @@ -1,6 +1,7 @@ /* * Definitions for the VTPM proxy driver * Copyright (c) 2015, 2016, IBM Corporation + * Copyright (C) 2016 Intel Corporation * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -18,8 +19,23 @@ #include #include -/* ioctls */ +/** + * enum vtpm_proxy_flags - flags for the proxy TPM + * @VTPM_PROXY_FLAG_TPM2: the proxy TPM uses TPM 2.0 protocol + */ +enum vtpm_proxy_flags { + VTPM_PROXY_FLAG_TPM2 = 1, +}; +/** + * struct vtpm_proxy_new_dev - parameter structure for the + * %VTPM_PROXY_IOC_NEW_DEV ioctl + * @flags: flags for the proxy TPM + * @tpm_num: index of the TPM device + * @fd: the file descriptor used by the proxy TPM + * @major: the major number of the TPM device + * @minor: the minor number of the TPM device + */ struct vtpm_proxy_new_dev { __u32 flags; /* input */ __u32 tpm_num; /* output */ @@ -28,9 +44,6 @@ struct vtpm_proxy_new_dev { __u32 minor; /* output */ }; -/* above flags */ -#define VTPM_PROXY_FLAG_TPM2 1 /* emulator is TPM 2 */ - -#define VTPM_PROXY_IOC_NEW_DEV _IOWR(0xa1, 0x00, struct vtpm_proxy_new_dev) +#define VTPM_PROXY_IOC_NEW_DEV _IOWR(0xa1, 0x00, struct vtpm_proxy_new_dev) #endif /* _UAPI_LINUX_VTPM_PROXY_H */ -- cgit v1.2.3 From 420d439849cabaa0587c424b09b9507108a4e058 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Mon, 7 Nov 2016 15:44:31 -0700 Subject: tpm_tis: Allow tpm_tis to be bound using DT This provides an open firwmare driver binding for tpm_tis. OF is useful on arches where ACPI/PNP is not used. The tcg,tpm-tis-mmio register map interface is specified by the TCG. Reviewed-by: Rob Herring Signed-off-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- .../bindings/security/tpm/tpm_tis_mmio.txt | 25 ++++++++++++++++++++++ drivers/char/tpm/Kconfig | 2 +- drivers/char/tpm/tpm_tis.c | 11 ++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt b/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt new file mode 100644 index 000000000000..41d740545189 --- /dev/null +++ b/Documentation/devicetree/bindings/security/tpm/tpm_tis_mmio.txt @@ -0,0 +1,25 @@ +Trusted Computing Group MMIO Trusted Platform Module + +The TCG defines multi vendor standard for accessing a TPM chip, this +is the standard protocol defined to access the TPM via MMIO. Typically +this interface will be implemented over Intel's LPC bus. + +Refer to the 'TCG PC Client Specific TPM Interface Specification (TIS)' TCG +publication for the specification. + +Required properties: + +- compatible: should contain a string below for the chip, followed by + "tcg,tpm-tis-mmio". Valid chip strings are: + * "atmel,at97sc3204" +- reg: The location of the MMIO registers, should be at least 0x5000 bytes +- interrupt-parent/interrupts: An optional interrupt indicating command completion. + +Example: + + tpm_tis@90000 { + compatible = "atmel,at97sc3204", "tcg,tpm-tis-mmio"; + reg = <0x90000 0x5000>; + interrupt-parent = <&EIC0>; + interrupts = <1 2>; + }; diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index 9faa0b1e7766..277186d3b668 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -32,7 +32,7 @@ config TCG_TIS_CORE config TCG_TIS tristate "TPM Interface Specification 1.2 Interface / TPM 2.0 FIFO Interface" - depends on X86 + depends on X86 || OF select TCG_TIS_CORE ---help--- If you have a TPM security chip that is compliant with the diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c index eaf5730d79eb..0127af130cb1 100644 --- a/drivers/char/tpm/tpm_tis.c +++ b/drivers/char/tpm/tpm_tis.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include "tpm.h" #include "tpm_tis_core.h" @@ -354,12 +356,21 @@ static int tpm_tis_plat_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_OF +static const struct of_device_id tis_of_platform_match[] = { + {.compatible = "tcg,tpm-tis-mmio"}, + {}, +}; +MODULE_DEVICE_TABLE(of, tis_of_platform_match); +#endif + static struct platform_driver tis_drv = { .probe = tpm_tis_plat_probe, .remove = tpm_tis_plat_remove, .driver = { .name = "tpm_tis", .pm = &tpm_tis_pm, + .of_match_table = of_match_ptr(tis_of_platform_match), }, }; -- cgit v1.2.3 From cbef69a9e190aeaae65e8ba52ebff1f4884ca0dc Mon Sep 17 00:00:00 2001 From: Baruch Siach Date: Sun, 6 Nov 2016 11:02:45 +0200 Subject: char: tpm: fix kerneldoc tpm2_unseal_trusted name typo Signed-off-by: Baruch Siach Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm2-cmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c index 7df55d58c939..da5b782a9731 100644 --- a/drivers/char/tpm/tpm2-cmd.c +++ b/drivers/char/tpm/tpm2-cmd.c @@ -680,7 +680,7 @@ static int tpm2_unseal_cmd(struct tpm_chip *chip, } /** - * tpm_unseal_trusted() - unseal the payload of a trusted key + * tpm2_unseal_trusted() - unseal the payload of a trusted key * @chip_num: TPM chip to use * @payload: the key data in clear and encrypted form * @options: authentication values and other options -- cgit v1.2.3 From b1a9b7b602c5320ab3827a3f6a6a5211826308c4 Mon Sep 17 00:00:00 2001 From: Nayna Jain Date: Mon, 14 Nov 2016 05:00:49 -0500 Subject: tpm: replace symbolic permission with octal for securityfs files checkpatch.pl flags warning for symbolic permissions and suggests to replace with octal value. This patch changes securityfs pseudo files permission to octal values in tpm_bios_log_setup(). Signed-off-by: Nayna Jain Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_eventlog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 42b49c4dff01..9467e316324a 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -378,7 +378,7 @@ struct dentry **tpm_bios_log_setup(const char *name) bin_file = securityfs_create_file("binary_bios_measurements", - S_IRUSR | S_IRGRP, tpm_dir, + 0440, tpm_dir, (void *)&tpm_binary_b_measurements_seqops, &tpm_bios_measurements_ops); if (is_bad(bin_file)) @@ -386,7 +386,7 @@ struct dentry **tpm_bios_log_setup(const char *name) ascii_file = securityfs_create_file("ascii_bios_measurements", - S_IRUSR | S_IRGRP, tpm_dir, + 0440, tpm_dir, (void *)&tpm_ascii_b_measurements_seqops, &tpm_bios_measurements_ops); if (is_bad(ascii_file)) -- cgit v1.2.3 From cd9b7631a888f6615dac148c10d72a253b98c64b Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 14 Nov 2016 05:00:50 -0500 Subject: tpm: replace dynamically allocated bios_dir with a static array This commit is based on a commit by Nayna Jain. Replaced dynamically allocated bios_dir with a static array as the size is always constant. Suggested-by: Jason Gunthorpe Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 9 ++--- drivers/char/tpm/tpm.h | 3 +- drivers/char/tpm/tpm_eventlog.c | 75 +++++++++++++++++------------------------ drivers/char/tpm/tpm_eventlog.h | 10 +++--- 4 files changed, 43 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 836f056f7d27..d0c187269ef4 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -278,14 +278,16 @@ static void tpm_del_char_device(struct tpm_chip *chip) static int tpm1_chip_register(struct tpm_chip *chip) { + int rc; + if (chip->flags & TPM_CHIP_FLAG_TPM2) return 0; tpm_sysfs_add_device(chip); - chip->bios_dir = tpm_bios_log_setup(dev_name(&chip->dev)); + rc = tpm_bios_log_setup(chip); - return 0; + return rc; } static void tpm1_chip_unregister(struct tpm_chip *chip) @@ -293,8 +295,7 @@ static void tpm1_chip_unregister(struct tpm_chip *chip) if (chip->flags & TPM_CHIP_FLAG_TPM2) return; - if (chip->bios_dir) - tpm_bios_log_teardown(chip->bios_dir); + tpm_bios_log_teardown(chip); } static void tpm_del_legacy_sysfs(struct tpm_chip *chip) diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index f9401ca0454c..9d69580a9743 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -40,6 +40,7 @@ enum tpm_const { TPM_BUFSIZE = 4096, TPM_NUM_DEVICES = 65536, TPM_RETRY = 50, /* 5 seconds */ + TPM_NUM_EVENT_LOG_FILES = 3, }; enum tpm_timeout { @@ -171,7 +172,7 @@ struct tpm_chip { unsigned long duration[3]; /* jiffies */ bool duration_adjusted; - struct dentry **bios_dir; + struct dentry *bios_dir[TPM_NUM_EVENT_LOG_FILES]; const struct attribute_group *groups[3]; unsigned int groups_cnt; diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 9467e316324a..9c6447642144 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -359,63 +359,50 @@ static const struct file_operations tpm_bios_measurements_ops = { .release = tpm_bios_measurements_release, }; -static int is_bad(void *p) +int tpm_bios_log_setup(struct tpm_chip *chip) { - if (!p) - return 1; - if (IS_ERR(p) && (PTR_ERR(p) != -ENODEV)) - return 1; - return 0; -} - -struct dentry **tpm_bios_log_setup(const char *name) -{ - struct dentry **ret = NULL, *tpm_dir, *bin_file, *ascii_file; - - tpm_dir = securityfs_create_dir(name, NULL); - if (is_bad(tpm_dir)) - goto out; - - bin_file = + const char *name = dev_name(&chip->dev); + unsigned int cnt; + + cnt = 0; + chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); + /* NOTE: securityfs_create_dir can return ENODEV if securityfs is + * compiled out. The caller should ignore the ENODEV return code. + */ + if (IS_ERR(chip->bios_dir[cnt])) + goto err; + cnt++; + + chip->bios_dir[cnt] = securityfs_create_file("binary_bios_measurements", - 0440, tpm_dir, + 0440, chip->bios_dir[0], (void *)&tpm_binary_b_measurements_seqops, &tpm_bios_measurements_ops); - if (is_bad(bin_file)) - goto out_tpm; + if (IS_ERR(chip->bios_dir[cnt])) + goto err; + cnt++; - ascii_file = + chip->bios_dir[cnt] = securityfs_create_file("ascii_bios_measurements", - 0440, tpm_dir, + 0440, chip->bios_dir[0], (void *)&tpm_ascii_b_measurements_seqops, &tpm_bios_measurements_ops); - if (is_bad(ascii_file)) - goto out_bin; - - ret = kmalloc(3 * sizeof(struct dentry *), GFP_KERNEL); - if (!ret) - goto out_ascii; - - ret[0] = ascii_file; - ret[1] = bin_file; - ret[2] = tpm_dir; + if (IS_ERR(chip->bios_dir[cnt])) + goto err; + cnt++; - return ret; + return 0; -out_ascii: - securityfs_remove(ascii_file); -out_bin: - securityfs_remove(bin_file); -out_tpm: - securityfs_remove(tpm_dir); -out: - return NULL; +err: + chip->bios_dir[cnt] = NULL; + tpm_bios_log_teardown(chip); + return -EIO; } -void tpm_bios_log_teardown(struct dentry **lst) +void tpm_bios_log_teardown(struct tpm_chip *chip) { int i; - for (i = 0; i < 3; i++) - securityfs_remove(lst[i]); + for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) + securityfs_remove(chip->bios_dir[i]); } diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h index 8de62b09be51..fd3357e3a322 100644 --- a/drivers/char/tpm/tpm_eventlog.h +++ b/drivers/char/tpm/tpm_eventlog.h @@ -77,14 +77,14 @@ int read_log(struct tpm_bios_log *log); #if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ defined(CONFIG_ACPI) -extern struct dentry **tpm_bios_log_setup(const char *); -extern void tpm_bios_log_teardown(struct dentry **); +extern int tpm_bios_log_setup(struct tpm_chip *chip); +extern void tpm_bios_log_teardown(struct tpm_chip *chip); #else -static inline struct dentry **tpm_bios_log_setup(const char *name) +static inline int tpm_bios_log_setup(struct tpm_chip *chip) { - return NULL; + return 0; } -static inline void tpm_bios_log_teardown(struct dentry **dir) +static inline void tpm_bios_log_teardown(struct tpm_chip *chip) { } #endif -- cgit v1.2.3 From 7518a21a9da39dc605ae08714ad046bfeca26f9b Mon Sep 17 00:00:00 2001 From: Jarkko Sakkinen Date: Mon, 14 Nov 2016 05:00:51 -0500 Subject: tpm: drop tpm1_chip_register(/unregister) Check for TPM2 chip in tpm_sysfs_add_device, tpm_bios_log_setup and tpm_bios_log_teardown in order to make code flow cleaner and to enable to implement TPM 2.0 support later on. This is partially derived from the commit by Nayna Jain with the extension that also tpm1_chip_register is dropped. Signed-off-by: Jarkko Sakkinen Reviewed-by: Jason Gunthorpe Reviewed-by: Nayna Jain Tested-by: Jason Gunthorpe Tested-by: Nayna Jain --- drivers/char/tpm/tpm-chip.c | 31 +++++-------------------------- drivers/char/tpm/tpm-sysfs.c | 3 +++ drivers/char/tpm/tpm_eventlog.c | 3 +++ 3 files changed, 11 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index d0c187269ef4..250a651ebd95 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -276,28 +276,6 @@ static void tpm_del_char_device(struct tpm_chip *chip) up_write(&chip->ops_sem); } -static int tpm1_chip_register(struct tpm_chip *chip) -{ - int rc; - - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return 0; - - tpm_sysfs_add_device(chip); - - rc = tpm_bios_log_setup(chip); - - return rc; -} - -static void tpm1_chip_unregister(struct tpm_chip *chip) -{ - if (chip->flags & TPM_CHIP_FLAG_TPM2) - return; - - tpm_bios_log_teardown(chip); -} - static void tpm_del_legacy_sysfs(struct tpm_chip *chip) { struct attribute **i; @@ -364,7 +342,9 @@ int tpm_chip_register(struct tpm_chip *chip) return rc; } - rc = tpm1_chip_register(chip); + tpm_sysfs_add_device(chip); + + rc = tpm_bios_log_setup(chip); if (rc) return rc; @@ -372,7 +352,7 @@ int tpm_chip_register(struct tpm_chip *chip) rc = tpm_add_char_device(chip); if (rc) { - tpm1_chip_unregister(chip); + tpm_bios_log_teardown(chip); return rc; } @@ -402,8 +382,7 @@ EXPORT_SYMBOL_GPL(tpm_chip_register); void tpm_chip_unregister(struct tpm_chip *chip) { tpm_del_legacy_sysfs(chip); - - tpm1_chip_unregister(chip); + tpm_bios_log_teardown(chip); tpm_del_char_device(chip); } EXPORT_SYMBOL_GPL(tpm_chip_unregister); diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c index 59a1ead4d141..848ad6580b46 100644 --- a/drivers/char/tpm/tpm-sysfs.c +++ b/drivers/char/tpm/tpm-sysfs.c @@ -284,6 +284,9 @@ static const struct attribute_group tpm_dev_group = { void tpm_sysfs_add_device(struct tpm_chip *chip) { + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return; + /* The sysfs routines rely on an implicit tpm_try_get_ops, device_del * is called before ops is null'd and the sysfs core synchronizes this * removal so that no callbacks are running or can run again diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 9c6447642144..0afb0f4e81f0 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -364,6 +364,9 @@ int tpm_bios_log_setup(struct tpm_chip *chip) const char *name = dev_name(&chip->dev); unsigned int cnt; + if (chip->flags & TPM_CHIP_FLAG_TPM2) + return 0; + cnt = 0; chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); /* NOTE: securityfs_create_dir can return ENODEV if securityfs is -- cgit v1.2.3 From 748935eeb72c34368ab514a2bfdf75161768cec0 Mon Sep 17 00:00:00 2001 From: Nayna Jain Date: Mon, 14 Nov 2016 05:00:52 -0500 Subject: tpm: have event log use the tpm_chip Move the backing memory for the event log into tpm_chip and push the tpm_chip into read_log. This optimizes read_log processing by only doing it once and prepares things for the next patches in the series which require the tpm_chip to locate the event log via ACPI and OF handles instead of searching. This is straightfoward except for the issue of passing a kref through i_private with securityfs. Since securityfs_remove does not have any removal fencing like sysfs we use the inode lock to safely get a kref on the tpm_chip. Suggested-by: Jason Gunthorpe Signed-off-by: Nayna Jain Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 3 +- drivers/char/tpm/tpm.h | 11 ++++++ drivers/char/tpm/tpm_acpi.c | 15 +++++-- drivers/char/tpm/tpm_eventlog.c | 86 +++++++++++++++++++++++++++-------------- drivers/char/tpm/tpm_eventlog.h | 2 +- drivers/char/tpm/tpm_of.c | 4 +- 6 files changed, 84 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 250a651ebd95..3f27753d96aa 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -127,6 +127,7 @@ static void tpm_dev_release(struct device *dev) idr_remove(&dev_nums_idr, chip->dev_num); mutex_unlock(&idr_lock); + kfree(chip->log.bios_event_log); kfree(chip); } @@ -345,7 +346,7 @@ int tpm_chip_register(struct tpm_chip *chip) tpm_sysfs_add_device(chip); rc = tpm_bios_log_setup(chip); - if (rc) + if (rc == -ENODEV) return rc; tpm_add_ppi(chip); diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h index 9d69580a9743..1ae976894257 100644 --- a/drivers/char/tpm/tpm.h +++ b/drivers/char/tpm/tpm.h @@ -35,6 +35,8 @@ #include #include +#include "tpm_eventlog.h" + enum tpm_const { TPM_MINOR = 224, /* officially assigned */ TPM_BUFSIZE = 4096, @@ -146,6 +148,11 @@ enum tpm_chip_flags { TPM_CHIP_FLAG_HAVE_TIMEOUTS = BIT(4), }; +struct tpm_chip_seqops { + struct tpm_chip *chip; + const struct seq_operations *seqops; +}; + struct tpm_chip { struct device dev; struct cdev cdev; @@ -157,6 +164,10 @@ struct tpm_chip { struct rw_semaphore ops_sem; const struct tpm_class_ops *ops; + struct tpm_bios_log log; + struct tpm_chip_seqops bin_log_seqops; + struct tpm_chip_seqops ascii_log_seqops; + unsigned int flags; int dev_num; /* /dev/tpm# */ diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 565a9478cb94..01dfb35a30e4 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -9,7 +9,7 @@ * * Maintained by: * - * Access to the eventlog extended by the TCG BIOS of PC platform + * Access to the event log extended by the TCG BIOS of PC platform * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -45,13 +45,15 @@ struct acpi_tcpa { }; /* read binary bios log */ -int read_log(struct tpm_bios_log *log) +int read_log(struct tpm_chip *chip) { struct acpi_tcpa *buff; acpi_status status; void __iomem *virt; u64 len, start; + struct tpm_bios_log *log; + log = &chip->log; if (log->bios_event_log != NULL) { printk(KERN_ERR "%s: ERROR - Eventlog already initialized\n", @@ -97,13 +99,18 @@ int read_log(struct tpm_bios_log *log) virt = acpi_os_map_iomem(start, len); if (!virt) { - kfree(log->bios_event_log); printk("%s: ERROR - Unable to map memory\n", __func__); - return -EIO; + goto err; } memcpy_fromio(log->bios_event_log, virt, len); acpi_os_unmap_iomem(virt, len); return 0; + +err: + kfree(log->bios_event_log); + log->bios_event_log = NULL; + return -EIO; + } diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 0afb0f4e81f0..2c4bc99729e5 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -11,7 +11,7 @@ * * Maintained by: * - * Access to the eventlog created by a system's firmware / BIOS + * Access to the event log created by a system's firmware / BIOS * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -73,7 +73,8 @@ static const char* tcpa_pc_event_id_strings[] = { static void *tpm_bios_measurements_start(struct seq_file *m, loff_t *pos) { loff_t i; - struct tpm_bios_log *log = m->private; + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; void *addr = log->bios_event_log; void *limit = log->bios_event_log_end; struct tcpa_event *event; @@ -120,7 +121,8 @@ static void *tpm_bios_measurements_next(struct seq_file *m, void *v, loff_t *pos) { struct tcpa_event *event = v; - struct tpm_bios_log *log = m->private; + struct tpm_chip *chip = m->private; + struct tpm_bios_log *log = &chip->log; void *limit = log->bios_event_log_end; u32 converted_event_size; u32 converted_event_type; @@ -261,13 +263,10 @@ static int tpm_binary_bios_measurements_show(struct seq_file *m, void *v) static int tpm_bios_measurements_release(struct inode *inode, struct file *file) { - struct seq_file *seq = file->private_data; - struct tpm_bios_log *log = seq->private; + struct seq_file *seq = (struct seq_file *)file->private_data; + struct tpm_chip *chip = (struct tpm_chip *)seq->private; - if (log) { - kfree(log->bios_event_log); - kfree(log); - } + put_device(&chip->dev); return seq_release(inode, file); } @@ -323,33 +322,30 @@ static int tpm_bios_measurements_open(struct inode *inode, struct file *file) { int err; - struct tpm_bios_log *log; struct seq_file *seq; - const struct seq_operations *seqops = - (const struct seq_operations *)inode->i_private; - - log = kzalloc(sizeof(struct tpm_bios_log), GFP_KERNEL); - if (!log) - return -ENOMEM; - - if ((err = read_log(log))) - goto out_free; + struct tpm_chip_seqops *chip_seqops; + const struct seq_operations *seqops; + struct tpm_chip *chip; + + inode_lock(inode); + if (!inode->i_private) { + inode_unlock(inode); + return -ENODEV; + } + chip_seqops = (struct tpm_chip_seqops *)inode->i_private; + seqops = chip_seqops->seqops; + chip = chip_seqops->chip; + get_device(&chip->dev); + inode_unlock(inode); /* now register seq file */ err = seq_open(file, seqops); if (!err) { seq = file->private_data; - seq->private = log; - } else { - goto out_free; + seq->private = chip; } -out: return err; -out_free: - kfree(log->bios_event_log); - kfree(log); - goto out; } static const struct file_operations tpm_bios_measurements_ops = { @@ -363,10 +359,22 @@ int tpm_bios_log_setup(struct tpm_chip *chip) { const char *name = dev_name(&chip->dev); unsigned int cnt; + int rc = 0; if (chip->flags & TPM_CHIP_FLAG_TPM2) return 0; + rc = read_log(chip); + /* + * read_log failure means event log is not supported except for ENOMEM. + */ + if (rc < 0) { + if (rc == -ENOMEM) + return -ENODEV; + else + return rc; + } + cnt = 0; chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); /* NOTE: securityfs_create_dir can return ENODEV if securityfs is @@ -376,19 +384,25 @@ int tpm_bios_log_setup(struct tpm_chip *chip) goto err; cnt++; + chip->bin_log_seqops.chip = chip; + chip->bin_log_seqops.seqops = &tpm_binary_b_measurements_seqops; + chip->bios_dir[cnt] = securityfs_create_file("binary_bios_measurements", 0440, chip->bios_dir[0], - (void *)&tpm_binary_b_measurements_seqops, + (void *)&chip->bin_log_seqops, &tpm_bios_measurements_ops); if (IS_ERR(chip->bios_dir[cnt])) goto err; cnt++; + chip->ascii_log_seqops.chip = chip; + chip->ascii_log_seqops.seqops = &tpm_ascii_b_measurements_seqops; + chip->bios_dir[cnt] = securityfs_create_file("ascii_bios_measurements", 0440, chip->bios_dir[0], - (void *)&tpm_ascii_b_measurements_seqops, + (void *)&chip->ascii_log_seqops, &tpm_bios_measurements_ops); if (IS_ERR(chip->bios_dir[cnt])) goto err; @@ -405,7 +419,19 @@ err: void tpm_bios_log_teardown(struct tpm_chip *chip) { int i; + struct inode *inode; - for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) + /* securityfs_remove currently doesn't take care of handling sync + * between removal and opening of pseudo files. To handle this, a + * workaround is added by making i_private = NULL here during removal + * and to check it during open(), both within inode_lock()/unlock(). + * This design ensures that open() either safely gets kref or fails. + */ + for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) { + inode = d_inode(chip->bios_dir[i]); + inode_lock(inode); + inode->i_private = NULL; + inode_unlock(inode); securityfs_remove(chip->bios_dir[i]); + } } diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h index fd3357e3a322..6df2f8e79a8e 100644 --- a/drivers/char/tpm/tpm_eventlog.h +++ b/drivers/char/tpm/tpm_eventlog.h @@ -73,7 +73,7 @@ enum tcpa_pc_event_ids { HOST_TABLE_OF_DEVICES, }; -int read_log(struct tpm_bios_log *log); +int read_log(struct tpm_chip *chip); #if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ defined(CONFIG_ACPI) diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 570f30c5c5f4..68d891ab55db 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -20,12 +20,14 @@ #include "tpm.h" #include "tpm_eventlog.h" -int read_log(struct tpm_bios_log *log) +int read_log(struct tpm_chip *chip) { struct device_node *np; const u32 *sizep; const u64 *basep; + struct tpm_bios_log *log; + log = &chip->log; if (log->bios_event_log != NULL) { pr_err("%s: ERROR - Eventlog already initialized\n", __func__); return -EFAULT; -- cgit v1.2.3 From f40e68ef4a111d194a801abd1695f1ec8ef119ff Mon Sep 17 00:00:00 2001 From: Nayna Jain Date: Mon, 14 Nov 2016 05:00:53 -0500 Subject: tpm: fix the missing .owner in tpm_bios_measurements_ops This patch fixes the missing .owner field in tpm_bios_measurements_ops definition. Suggested-by: Jason Gunthorpe Signed-off-by: Nayna Jain Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_eventlog.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 2c4bc99729e5..c6c80f0f25a2 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -349,6 +349,7 @@ static int tpm_bios_measurements_open(struct inode *inode, } static const struct file_operations tpm_bios_measurements_ops = { + .owner = THIS_MODULE, .open = tpm_bios_measurements_open, .read = seq_read, .llseek = seq_lseek, -- cgit v1.2.3 From 02ae1382882f08c5804b996ca9c8d79b399dbe36 Mon Sep 17 00:00:00 2001 From: Nayna Jain Date: Mon, 14 Nov 2016 05:00:54 -0500 Subject: tpm: redefine read_log() to handle ACPI/OF at runtime Currently, read_log() has two implementations: one for ACPI platforms and the other for device tree(OF) based platforms. The proper one is selected at compile time using Kconfig and #ifdef in the Makefile, which is not the recommended approach. This patch removes the #ifdef in the Makefile by defining a single read_log() method, which checks for ACPI/OF event log properties at runtime. [jarkko.sakkinen@linux.intel.com: added tpm_ prefix to read_log*] Suggested-by: Jason Gunthorpe Signed-off-by: Nayna Jain Reviewed-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/Makefile | 14 ++++---------- drivers/char/tpm/tpm_acpi.c | 9 ++------- drivers/char/tpm/tpm_eventlog.c | 22 +++++++++++++++++++++- drivers/char/tpm/tpm_eventlog.h | 22 +++++++++++++--------- drivers/char/tpm/tpm_of.c | 8 ++------ 5 files changed, 42 insertions(+), 33 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile index a385fb8c17de..a05b1ebd0b26 100644 --- a/drivers/char/tpm/Makefile +++ b/drivers/char/tpm/Makefile @@ -2,16 +2,10 @@ # Makefile for the kernel tpm device drivers. # obj-$(CONFIG_TCG_TPM) += tpm.o -tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o -tpm-$(CONFIG_ACPI) += tpm_ppi.o - -ifdef CONFIG_ACPI - tpm-y += tpm_eventlog.o tpm_acpi.o -else -ifdef CONFIG_TCG_IBMVTPM - tpm-y += tpm_eventlog.o tpm_of.o -endif -endif +tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o \ + tpm_eventlog.o +tpm-$(CONFIG_ACPI) += tpm_ppi.o tpm_acpi.o +tpm-$(CONFIG_OF) += tpm_of.o obj-$(CONFIG_TCG_TIS_CORE) += tpm_tis_core.o obj-$(CONFIG_TCG_TIS) += tpm_tis.o obj-$(CONFIG_TCG_TIS_SPI) += tpm_tis_spi.o diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 01dfb35a30e4..04663cba3a0b 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -6,6 +6,7 @@ * Stefan Berger * Reiner Sailer * Kylene Hall + * Nayna Jain * * Maintained by: * @@ -45,7 +46,7 @@ struct acpi_tcpa { }; /* read binary bios log */ -int read_log(struct tpm_chip *chip) +int tpm_read_log_acpi(struct tpm_chip *chip) { struct acpi_tcpa *buff; acpi_status status; @@ -54,12 +55,6 @@ int read_log(struct tpm_chip *chip) struct tpm_bios_log *log; log = &chip->log; - if (log->bios_event_log != NULL) { - printk(KERN_ERR - "%s: ERROR - Eventlog already initialized\n", - __func__); - return -EFAULT; - } /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ status = acpi_get_table(ACPI_SIG_TCPA, 1, diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index c6c80f0f25a2..8ee4ea10714b 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -356,6 +356,26 @@ static const struct file_operations tpm_bios_measurements_ops = { .release = tpm_bios_measurements_release, }; +static int tpm_read_log(struct tpm_chip *chip) +{ + int rc; + + if (chip->log.bios_event_log != NULL) { + dev_dbg(&chip->dev, + "%s: ERROR - event log already initialized\n", + __func__); + return -EFAULT; + } + + rc = tpm_read_log_acpi(chip); + if ((rc == 0) || (rc == -ENOMEM)) + return rc; + + rc = tpm_read_log_of(chip); + + return rc; +} + int tpm_bios_log_setup(struct tpm_chip *chip) { const char *name = dev_name(&chip->dev); @@ -365,7 +385,7 @@ int tpm_bios_log_setup(struct tpm_chip *chip) if (chip->flags & TPM_CHIP_FLAG_TPM2) return 0; - rc = read_log(chip); + rc = tpm_read_log(chip); /* * read_log failure means event log is not supported except for ENOMEM. */ diff --git a/drivers/char/tpm/tpm_eventlog.h b/drivers/char/tpm/tpm_eventlog.h index 6df2f8e79a8e..1660d74ea79a 100644 --- a/drivers/char/tpm/tpm_eventlog.h +++ b/drivers/char/tpm/tpm_eventlog.h @@ -73,20 +73,24 @@ enum tcpa_pc_event_ids { HOST_TABLE_OF_DEVICES, }; -int read_log(struct tpm_chip *chip); - -#if defined(CONFIG_TCG_IBMVTPM) || defined(CONFIG_TCG_IBMVTPM_MODULE) || \ - defined(CONFIG_ACPI) -extern int tpm_bios_log_setup(struct tpm_chip *chip); -extern void tpm_bios_log_teardown(struct tpm_chip *chip); +#if defined(CONFIG_ACPI) +int tpm_read_log_acpi(struct tpm_chip *chip); #else -static inline int tpm_bios_log_setup(struct tpm_chip *chip) +static inline int tpm_read_log_acpi(struct tpm_chip *chip) { - return 0; + return -ENODEV; } -static inline void tpm_bios_log_teardown(struct tpm_chip *chip) +#endif +#if defined(CONFIG_OF) +int tpm_read_log_of(struct tpm_chip *chip); +#else +static inline int tpm_read_log_of(struct tpm_chip *chip) { + return -ENODEV; } #endif +int tpm_bios_log_setup(struct tpm_chip *chip); +void tpm_bios_log_teardown(struct tpm_chip *chip); + #endif diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 68d891ab55db..83c26bffb150 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -2,6 +2,7 @@ * Copyright 2012 IBM Corporation * * Author: Ashley Lai + * Nayna Jain * * Maintained by: * @@ -20,7 +21,7 @@ #include "tpm.h" #include "tpm_eventlog.h" -int read_log(struct tpm_chip *chip) +int tpm_read_log_of(struct tpm_chip *chip) { struct device_node *np; const u32 *sizep; @@ -28,11 +29,6 @@ int read_log(struct tpm_chip *chip) struct tpm_bios_log *log; log = &chip->log; - if (log->bios_event_log != NULL) { - pr_err("%s: ERROR - Eventlog already initialized\n", __func__); - return -EFAULT; - } - np = of_find_node_by_name(NULL, "vtpm"); if (!np) { pr_err("%s: ERROR - IBMVTPM not supported\n", __func__); -- cgit v1.2.3 From ed4fdb4f5dc758e9d5bfb5582c701b08a87115a6 Mon Sep 17 00:00:00 2001 From: Nayna Jain Date: Mon, 14 Nov 2016 05:00:55 -0500 Subject: tpm: replace of_find_node_by_name() with dev of_node property Using the device of_node property is a better way to refer to the device tree node rather than of_find_node_by_name(). Suggested-by: Jason Gunthorpe Signed-off-by: Nayna Jain Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_of.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 83c26bffb150..12a86dda3b69 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -29,7 +29,8 @@ int tpm_read_log_of(struct tpm_chip *chip) struct tpm_bios_log *log; log = &chip->log; - np = of_find_node_by_name(NULL, "vtpm"); + if (chip->dev.parent->of_node) + np = chip->dev.parent->of_node; if (!np) { pr_err("%s: ERROR - IBMVTPM not supported\n", __func__); return -ENODEV; @@ -55,18 +56,15 @@ int tpm_read_log_of(struct tpm_chip *chip) if (!log->bios_event_log) { pr_err("%s: ERROR - Not enough memory for BIOS measurements\n", __func__); - of_node_put(np); return -ENOMEM; } log->bios_event_log_end = log->bios_event_log + *sizep; memcpy(log->bios_event_log, __va(*basep), *sizep); - of_node_put(np); return 0; cleanup_eio: - of_node_put(np); return -EIO; } -- cgit v1.2.3 From 5efae7d6b07f37939f8f99d0983d5346f0c3e4e6 Mon Sep 17 00:00:00 2001 From: Nayna Jain Date: Mon, 14 Nov 2016 05:00:56 -0500 Subject: tpm: cleanup of printk error messages This patch removes the unnecessary error messages on failing to allocate memory and replaces pr_err/printk with dev_dbg/dev_info as applicable. Suggested-by: Jason Gunthorpe Signed-off-by: Nayna Jain Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_acpi.c | 16 ++++------------ drivers/char/tpm/tpm_of.c | 29 +++++++++-------------------- 2 files changed, 13 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 04663cba3a0b..0cb43ef5f79a 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -60,11 +60,8 @@ int tpm_read_log_acpi(struct tpm_chip *chip) status = acpi_get_table(ACPI_SIG_TCPA, 1, (struct acpi_table_header **)&buff); - if (ACPI_FAILURE(status)) { - printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n", - __func__); + if (ACPI_FAILURE(status)) return -EIO; - } switch(buff->platform_class) { case BIOS_SERVER: @@ -78,25 +75,20 @@ int tpm_read_log_acpi(struct tpm_chip *chip) break; } if (!len) { - printk(KERN_ERR "%s: ERROR - TCPA log area empty\n", __func__); + dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__); return -EIO; } /* malloc EventLog space */ log->bios_event_log = kmalloc(len, GFP_KERNEL); - if (!log->bios_event_log) { - printk("%s: ERROR - Not enough Memory for BIOS measurements\n", - __func__); + if (!log->bios_event_log) return -ENOMEM; - } log->bios_event_log_end = log->bios_event_log + len; virt = acpi_os_map_iomem(start, len); - if (!virt) { - printk("%s: ERROR - Unable to map memory\n", __func__); + if (!virt) goto err; - } memcpy_fromio(log->bios_event_log, virt, len); diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 12a86dda3b69..643cc8ccb35b 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -31,40 +31,29 @@ int tpm_read_log_of(struct tpm_chip *chip) log = &chip->log; if (chip->dev.parent->of_node) np = chip->dev.parent->of_node; - if (!np) { - pr_err("%s: ERROR - IBMVTPM not supported\n", __func__); + if (!np) return -ENODEV; - } sizep = of_get_property(np, "linux,sml-size", NULL); - if (sizep == NULL) { - pr_err("%s: ERROR - SML size not found\n", __func__); - goto cleanup_eio; - } + if (sizep == NULL) + return -EIO; + if (*sizep == 0) { - pr_err("%s: ERROR - event log area empty\n", __func__); - goto cleanup_eio; + dev_warn(&chip->dev, "%s: Event log area empty\n", __func__); + return -EIO; } basep = of_get_property(np, "linux,sml-base", NULL); - if (basep == NULL) { - pr_err("%s: ERROR - SML not found\n", __func__); - goto cleanup_eio; - } + if (basep == NULL) + return -EIO; log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); - if (!log->bios_event_log) { - pr_err("%s: ERROR - Not enough memory for BIOS measurements\n", - __func__); + if (!log->bios_event_log) return -ENOMEM; - } log->bios_event_log_end = log->bios_event_log + *sizep; memcpy(log->bios_event_log, __va(*basep), *sizep); return 0; - -cleanup_eio: - return -EIO; } -- cgit v1.2.3 From 79eec5b940cffff14c7bd1b9eb856ccb36274cc2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 15 Nov 2016 13:27:22 +0000 Subject: tpm: return -ENODEV if np is not set device_node np contains a garbage value from the stack and it is only set if chip->dev.parent->of_node is not null. Thus the check for a null np won't spot a garbage value of np from the stack if chip->dev.parent->of_node is null and if np contains an garbage non-null value. I believe the correct fix is to return -ENODEV if and only if chip->dev.parent->of_node is null. Found with static analysis by CoverityScan, CID 1377755 Signed-off-by: Colin Ian King Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_of.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 643cc8ccb35b..36df9df4c472 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -31,7 +31,7 @@ int tpm_read_log_of(struct tpm_chip *chip) log = &chip->log; if (chip->dev.parent->of_node) np = chip->dev.parent->of_node; - if (!np) + else return -ENODEV; sizep = of_get_property(np, "linux,sml-size", NULL); -- cgit v1.2.3 From 005451d44ad46623aac8349df15d7c0d1d8914c1 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Wed, 16 Nov 2016 08:56:13 -0500 Subject: tpm: Check the bios_dir entry for NULL before accessing it Check the bios_dir entry for NULL before accessing it. Currently this crashes the driver when a TPM 2 is attached and the entries are NULL. Signed-off-by: Stefan Berger Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_eventlog.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 8ee4ea10714b..34f0921f0203 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -449,10 +449,12 @@ void tpm_bios_log_teardown(struct tpm_chip *chip) * This design ensures that open() either safely gets kref or fails. */ for (i = (TPM_NUM_EVENT_LOG_FILES - 1); i >= 0; i--) { - inode = d_inode(chip->bios_dir[i]); - inode_lock(inode); - inode->i_private = NULL; - inode_unlock(inode); - securityfs_remove(chip->bios_dir[i]); + if (chip->bios_dir[i]) { + inode = d_inode(chip->bios_dir[i]); + inode_lock(inode); + inode->i_private = NULL; + inode_unlock(inode); + securityfs_remove(chip->bios_dir[i]); + } } } -- cgit v1.2.3 From 0cf577a03f21a988f6dbe8133d07410967b8489a Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sat, 19 Nov 2016 11:18:28 -0700 Subject: tpm: Fix handling of missing event log The event log is an optional firmware feature, if the firmware does not support it then the securityfs files should not be created and no other notification given. - Uniformly return -ENODEV from the tpm_bios_log_setup cone if no event log is detected. - Check in ACPI if this node was discovered via ACPI. - Improve the check in OF to make sure there is a parent and to fail detection if the two log properties are not declared - Pass through all other error codes instead of filtering just some Signed-off-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm-chip.c | 2 +- drivers/char/tpm/tpm_acpi.c | 8 +++++++- drivers/char/tpm/tpm_eventlog.c | 26 +++++++++++++------------- drivers/char/tpm/tpm_of.c | 11 +++++------ 4 files changed, 26 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index 3f27753d96aa..7a4869151d3b 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -346,7 +346,7 @@ int tpm_chip_register(struct tpm_chip *chip) tpm_sysfs_add_device(chip); rc = tpm_bios_log_setup(chip); - if (rc == -ENODEV) + if (rc != 0 && rc != -ENODEV) return rc; tpm_add_ppi(chip); diff --git a/drivers/char/tpm/tpm_acpi.c b/drivers/char/tpm/tpm_acpi.c index 0cb43ef5f79a..b7718c95fd0b 100644 --- a/drivers/char/tpm/tpm_acpi.c +++ b/drivers/char/tpm/tpm_acpi.c @@ -56,12 +56,18 @@ int tpm_read_log_acpi(struct tpm_chip *chip) log = &chip->log; + /* Unfortuntely ACPI does not associate the event log with a specific + * TPM, like PPI. Thus all ACPI TPMs will read the same log. + */ + if (!chip->acpi_dev_handle) + return -ENODEV; + /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ status = acpi_get_table(ACPI_SIG_TCPA, 1, (struct acpi_table_header **)&buff); if (ACPI_FAILURE(status)) - return -EIO; + return -ENODEV; switch(buff->platform_class) { case BIOS_SERVER: diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index 34f0921f0203..c73f88cdeadf 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -368,14 +368,21 @@ static int tpm_read_log(struct tpm_chip *chip) } rc = tpm_read_log_acpi(chip); - if ((rc == 0) || (rc == -ENOMEM)) + if (rc != -ENODEV) return rc; - rc = tpm_read_log_of(chip); - - return rc; + return tpm_read_log_of(chip); } +/* + * tpm_bios_log_setup() - Read the event log from the firmware + * @chip: TPM chip to use. + * + * If an event log is found then the securityfs files are setup to + * export it to userspace, otherwise nothing is done. + * + * Returns -ENODEV if the firmware has no event log. + */ int tpm_bios_log_setup(struct tpm_chip *chip) { const char *name = dev_name(&chip->dev); @@ -386,15 +393,8 @@ int tpm_bios_log_setup(struct tpm_chip *chip) return 0; rc = tpm_read_log(chip); - /* - * read_log failure means event log is not supported except for ENOMEM. - */ - if (rc < 0) { - if (rc == -ENOMEM) - return -ENODEV; - else - return rc; - } + if (rc) + return rc; cnt = 0; chip->bios_dir[cnt] = securityfs_create_dir(name, NULL); diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c index 36df9df4c472..7dee42d7b5e0 100644 --- a/drivers/char/tpm/tpm_of.c +++ b/drivers/char/tpm/tpm_of.c @@ -29,13 +29,16 @@ int tpm_read_log_of(struct tpm_chip *chip) struct tpm_bios_log *log; log = &chip->log; - if (chip->dev.parent->of_node) + if (chip->dev.parent && chip->dev.parent->of_node) np = chip->dev.parent->of_node; else return -ENODEV; sizep = of_get_property(np, "linux,sml-size", NULL); - if (sizep == NULL) + basep = of_get_property(np, "linux,sml-base", NULL); + if (sizep == NULL && basep == NULL) + return -ENODEV; + if (sizep == NULL || basep == NULL) return -EIO; if (*sizep == 0) { @@ -43,10 +46,6 @@ int tpm_read_log_of(struct tpm_chip *chip) return -EIO; } - basep = of_get_property(np, "linux,sml-base", NULL); - if (basep == NULL) - return -EIO; - log->bios_event_log = kmalloc(*sizep, GFP_KERNEL); if (!log->bios_event_log) return -ENOMEM; -- cgit v1.2.3 From c4484f791c9434445db7fc1d6791af4388756479 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Sat, 19 Nov 2016 11:32:55 -0700 Subject: tpm: vtpm_proxy: conditionally call tpm_chip_unregister If tpm_chip_register fails vtpm must not call tpm_chip_unregister: > [ 58.271017] [] dpm_sysfs_remove+0x22/0x60 > [ 58.271017] [] device_del+0x58/0x280 > [ 58.271017] [] tpm_chip_unregister+0x40/0xb0 [tpm] > [ 58.271017] [] vtpm_proxy_fops_release+0x40/0x60 [tpm_vtpm_proxy] [jarkko.sakkinen@linux.intel.com: cleaned up unneeded goto away] Signed-off-by: Jason Gunthorpe Tested-by: Stefan Berger Reviewed-by: Jarkko Sakkinen Tested-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_vtpm_proxy.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_vtpm_proxy.c b/drivers/char/tpm/tpm_vtpm_proxy.c index 3d6f6ca81def..5463b58af26e 100644 --- a/drivers/char/tpm/tpm_vtpm_proxy.c +++ b/drivers/char/tpm/tpm_vtpm_proxy.c @@ -42,6 +42,7 @@ struct proxy_dev { long state; /* internal state */ #define STATE_OPENED_FLAG BIT(0) #define STATE_WAIT_RESPONSE_FLAG BIT(1) /* waiting for emulator response */ +#define STATE_REGISTERED_FLAG BIT(2) size_t req_len; /* length of queued TPM request */ size_t resp_len; /* length of queued TPM response */ @@ -370,12 +371,9 @@ static void vtpm_proxy_work(struct work_struct *work) rc = tpm_chip_register(proxy_dev->chip); if (rc) - goto err; - - return; - -err: - vtpm_proxy_fops_undo_open(proxy_dev); + vtpm_proxy_fops_undo_open(proxy_dev); + else + proxy_dev->state |= STATE_REGISTERED_FLAG; } /* @@ -516,7 +514,8 @@ static void vtpm_proxy_delete_device(struct proxy_dev *proxy_dev) */ vtpm_proxy_fops_undo_open(proxy_dev); - tpm_chip_unregister(proxy_dev->chip); + if (proxy_dev->state & STATE_REGISTERED_FLAG) + tpm_chip_unregister(proxy_dev->chip); vtpm_proxy_delete_proxy_dev(proxy_dev); } -- cgit v1.2.3 From 9430066a15d6f55a3d008a6f99bb462480870207 Mon Sep 17 00:00:00 2001 From: Jason Gunthorpe Date: Tue, 22 Nov 2016 09:58:56 -0700 Subject: tpm: adjust return value of tpm_read_log Signed-off-by: Jason Gunthorpe Reviewed-by: Jarkko Sakkinen Signed-off-by: Jarkko Sakkinen --- drivers/char/tpm/tpm_eventlog.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm_eventlog.c b/drivers/char/tpm/tpm_eventlog.c index c73f88cdeadf..11bb1138a828 100644 --- a/drivers/char/tpm/tpm_eventlog.c +++ b/drivers/char/tpm/tpm_eventlog.c @@ -381,7 +381,8 @@ static int tpm_read_log(struct tpm_chip *chip) * If an event log is found then the securityfs files are setup to * export it to userspace, otherwise nothing is done. * - * Returns -ENODEV if the firmware has no event log. + * Returns -ENODEV if the firmware has no event log or securityfs is not + * supported. */ int tpm_bios_log_setup(struct tpm_chip *chip) { @@ -432,9 +433,10 @@ int tpm_bios_log_setup(struct tpm_chip *chip) return 0; err: + rc = PTR_ERR(chip->bios_dir[cnt]); chip->bios_dir[cnt] = NULL; tpm_bios_log_teardown(chip); - return -EIO; + return rc; } void tpm_bios_log_teardown(struct tpm_chip *chip) -- cgit v1.2.3 From 599b8c09d974d6e4d85a8f7bc8ed7442977866a8 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 27 Nov 2016 20:37:31 -0800 Subject: Input: xpad - add product ID for Xbox One S pad This is the new gamepad that ships with the Xbox One S which includes Bluetooth functionality. Signed-off-by: Cameron Gutman Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 83af17ad0f1f..19886dbfe18d 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -134,6 +134,7 @@ static const struct xpad_device { { 0x045e, 0x02d1, "Microsoft X-Box One pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x02dd, "Microsoft X-Box One pad (Firmware 2015)", 0, XTYPE_XBOXONE }, { 0x045e, 0x02e3, "Microsoft X-Box One Elite pad", 0, XTYPE_XBOXONE }, + { 0x045e, 0x02ea, "Microsoft X-Box One S pad", 0, XTYPE_XBOXONE }, { 0x045e, 0x0291, "Xbox 360 Wireless Receiver (XBOX)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x045e, 0x0719, "Xbox 360 Wireless Receiver", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360W }, { 0x044f, 0x0f07, "Thrustmaster, Inc. Controller", 0, XTYPE_XBOX }, -- cgit v1.2.3 From ae3b4469dbcd3b842a9fd20940946e4d092d8731 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Sun, 27 Nov 2016 20:37:56 -0800 Subject: Input: xpad - fix Xbox One rumble stopping after 2.5 secs Unlike previous Xbox pads, the Xbox One pad doesn't have "sticky" rumble packets. The duration is encoded into the command and expiration is handled by the pad firmware. ff-memless needs pseudo-sticky behavior for rumble effects to behave properly for long duration effects. We already specify the maximum rumble on duration in the command packets, but it's still only good for about 2.5 seconds of rumble. This is easily reproducible running fftest's sine vibration test. It turns out there's a repeat count encoded in the rumble command. We can abuse that to get the pseudo-sticky behavior needed for rumble to behave as expected for effects with long duration. By my math, this change should allow a single ff_effect to rumble for 10 minutes straight, which should be more than enough for most needs. Signed-off-by: Cameron Gutman Signed-off-by: Dmitry Torokhov --- drivers/input/joystick/xpad.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c index 19886dbfe18d..6d9499658671 100644 --- a/drivers/input/joystick/xpad.c +++ b/drivers/input/joystick/xpad.c @@ -1045,9 +1045,9 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect packet->data[7] = 0x00; packet->data[8] = strong / 512; /* left actuator */ packet->data[9] = weak / 512; /* right actuator */ - packet->data[10] = 0xFF; - packet->data[11] = 0x00; - packet->data[12] = 0x00; + packet->data[10] = 0xFF; /* on period */ + packet->data[11] = 0x00; /* off period */ + packet->data[12] = 0xFF; /* repeat count */ packet->len = 13; packet->pending = true; break; -- cgit v1.2.3 From 031bfed2aba8a727fe5a6c2169d5e4e0751a1bf0 Mon Sep 17 00:00:00 2001 From: Guy Shapiro Date: Sun, 27 Nov 2016 20:40:39 -0800 Subject: Input: imx6ul_tsc - add support for sample averaging The i.MX6UL internal touchscreen controller contains an option to average upon samples. This feature reduces noise from the produced touch locations. This patch adds sample averaging support to the imx6ul_tsc device driver. Signed-off-by: Guy Shapiro Reviewed-by: Fabio Estevam Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/imx6ul_tsc.txt | 8 ++++++++ drivers/input/touchscreen/imx6ul_tsc.c | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt index 853dff96dd9f..a66069f6db66 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt @@ -17,6 +17,13 @@ Optional properties: This value depends on the touch screen. - pre-charge-time: the touch screen need some time to precharge. This value depends on the touch screen. +- average-samples: Number of data samples which are averaged for each read. + Valid values 0-4 + 0 = 1 sample + 1 = 4 samples + 2 = 8 samples + 3 = 16 samples + 4 = 32 samples Example: tsc: tsc@02040000 { @@ -32,5 +39,6 @@ Example: xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; measure-delay-time = <0xfff>; pre-charge-time = <0xffff>; + average-samples = <4>; status = "okay"; }; diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 8275267eac25..00b336f37fb3 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -25,6 +25,7 @@ /* ADC configuration registers field define */ #define ADC_AIEN (0x1 << 7) #define ADC_CONV_DISABLE 0x1F +#define ADC_AVGE (0x1 << 5) #define ADC_CAL (0x1 << 7) #define ADC_CALF 0x2 #define ADC_12BIT_MODE (0x2 << 2) @@ -32,6 +33,7 @@ #define ADC_CLK_DIV_8 (0x03 << 5) #define ADC_SHORT_SAMPLE_MODE (0x0 << 4) #define ADC_HARDWARE_TRIGGER (0x1 << 13) +#define ADC_AVGS_SHIFT 14 #define SELECT_CHANNEL_4 0x04 #define SELECT_CHANNEL_1 0x01 #define DISABLE_CONVERSION_INT (0x0 << 7) @@ -86,6 +88,7 @@ struct imx6ul_tsc { int measure_delay_time; int pre_charge_time; + int average_samples; struct completion completion; }; @@ -107,6 +110,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK; adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE; + if (tsc->average_samples) + adc_cfg |= (tsc->average_samples - 1) << ADC_AVGS_SHIFT; adc_cfg &= ~ADC_HARDWARE_TRIGGER; writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); @@ -118,6 +123,8 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) /* start ADC calibration */ adc_gc = readl(tsc->adc_regs + REG_ADC_GC); adc_gc |= ADC_CAL; + if (tsc->average_samples) + adc_gc |= ADC_AVGE; writel(adc_gc, tsc->adc_regs + REG_ADC_GC); timeout = wait_for_completion_timeout @@ -450,6 +457,17 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) if (err) tsc->pre_charge_time = 0xfff; + err = of_property_read_u32(np, "average-samples", + &tsc->average_samples); + if (err) + tsc->average_samples = 0; + + if (tsc->average_samples > 4) { + dev_err(&pdev->dev, "average-samples (%u) must be [0-4]\n", + tsc->average_samples); + return -EINVAL; + } + err = input_register_device(tsc->input); if (err) { dev_err(&pdev->dev, -- cgit v1.2.3 From 64c9295b2320efea5aec1d0511577e9cee06eddb Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:03 +0200 Subject: crypto: caam - move append_key_aead() into init_sh_desc_key_aead() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit append_key_aead() is used in only one place, thus inline it. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 8db54b090d39..567e234fb49b 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -228,12 +228,19 @@ struct caam_ctx { unsigned int authsize; }; -static void append_key_aead(u32 *desc, struct caam_ctx *ctx, - int keys_fit_inline, bool is_rfc3686) +static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, + int keys_fit_inline, bool is_rfc3686) { - u32 *nonce; + u32 *key_jump_cmd; unsigned int enckeylen = ctx->enckeylen; + /* Note: Context registers are saved. */ + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + /* * RFC3686 specific: * | ctx->key = {AUTH_KEY, ENC_KEY, NONCE} @@ -258,6 +265,8 @@ static void append_key_aead(u32 *desc, struct caam_ctx *ctx, /* Load Counter into CONTEXT1 reg */ if (is_rfc3686) { + u32 *nonce; + nonce = (u32 *)((void *)ctx->key + ctx->split_key_pad_len + enckeylen); append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, @@ -269,21 +278,6 @@ static void append_key_aead(u32 *desc, struct caam_ctx *ctx, (16 << MOVE_OFFSET_SHIFT) | (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); } -} - -static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, - int keys_fit_inline, bool is_rfc3686) -{ - u32 *key_jump_cmd; - - /* Note: Context registers are saved. */ - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - append_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); set_jump_tgt_here(desc, key_jump_cmd); } -- cgit v1.2.3 From db57656b0072415488a08332ba46494a5e334b37 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:04 +0200 Subject: crypto: caam - group algorithm related params MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In preparation of factoring out the shared descriptors, struct alginfo is introduced to group the algorithm related parameters. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 394 +++++++++++++++++++++----------------- drivers/crypto/caam/caamhash.c | 48 +++-- drivers/crypto/caam/desc_constr.h | 19 ++ drivers/crypto/caam/key_gen.c | 12 +- drivers/crypto/caam/key_gen.h | 6 +- 5 files changed, 274 insertions(+), 205 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 567e234fb49b..4141143cce7d 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -217,14 +217,11 @@ struct caam_ctx { dma_addr_t sh_desc_enc_dma; dma_addr_t sh_desc_dec_dma; dma_addr_t sh_desc_givenc_dma; - u32 class1_alg_type; - u32 class2_alg_type; u32 alg_op; u8 key[CAAM_MAX_KEY_SIZE]; dma_addr_t key_dma; - unsigned int enckeylen; - unsigned int split_key_len; - unsigned int split_key_pad_len; + struct alginfo adata; + struct alginfo cdata; unsigned int authsize; }; @@ -232,7 +229,7 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, int keys_fit_inline, bool is_rfc3686) { u32 *key_jump_cmd; - unsigned int enckeylen = ctx->enckeylen; + unsigned int enckeylen = ctx->cdata.keylen; /* Note: Context registers are saved. */ init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); @@ -250,24 +247,23 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, enckeylen -= CTR_RFC3686_NONCE_SIZE; if (keys_fit_inline) { - append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - append_key_as_imm(desc, (void *)ctx->key + - ctx->split_key_pad_len, enckeylen, + append_key_as_imm(desc, (void *)ctx->adata.key, + ctx->adata.keylen_pad, ctx->adata.keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + append_key_as_imm(desc, (void *)ctx->cdata.key, enckeylen, enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); } else { - append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | + append_key(desc, ctx->adata.key, ctx->adata.keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); - append_key(desc, ctx->key_dma + ctx->split_key_pad_len, - enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + append_key(desc, ctx->cdata.key, enckeylen, CLASS_1 | + KEY_DEST_CLASS_REG); } /* Load Counter into CONTEXT1 reg */ if (is_rfc3686) { u32 *nonce; - nonce = (u32 *)((void *)ctx->key + ctx->split_key_pad_len + + nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad + enckeylen); append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, LDST_CLASS_IND_CCB | @@ -286,7 +282,6 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; u32 *key_jump_cmd, *jump_cmd, *read_move_cmd, *write_move_cmd; u32 *desc; @@ -295,8 +290,13 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) * must all fit into the 64-word Descriptor h/w Buffer */ if (DESC_AEAD_NULL_ENC_LEN + AEAD_DESC_JOB_IO_LEN + - ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->adata.keylen_pad <= CAAM_DESC_BYTES_MAX) { + ctx->adata.key_inline = true; + ctx->adata.key = (uintptr_t)ctx->key; + } else { + ctx->adata.key_inline = false; + ctx->adata.key = ctx->key_dma; + } /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; @@ -306,12 +306,12 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); + if (ctx->adata.key_inline) + append_key_as_imm(desc, (void *)ctx->adata.key, + ctx->adata.keylen_pad, ctx->adata.keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); else - append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | + append_key(desc, ctx->adata.key, ctx->adata.keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); set_jump_tgt_here(desc, key_jump_cmd); @@ -336,8 +336,8 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) (0x8 << MOVE_LEN_SHIFT)); /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* Read and write cryptlen bytes */ aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); @@ -370,10 +370,14 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_AEAD_NULL_DEC_LEN + DESC_JOB_IO_LEN + - ctx->split_key_pad_len <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->adata.keylen_pad <= CAAM_DESC_BYTES_MAX) { + ctx->adata.key_inline = true; + ctx->adata.key = (uintptr_t)ctx->key; + } else { + ctx->adata.key_inline = false; + ctx->adata.key = ctx->key_dma; + } desc = ctx->sh_desc_dec; @@ -383,18 +387,18 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); + if (ctx->adata.key_inline) + append_key_as_imm(desc, (void *)ctx->adata.key, + ctx->adata.keylen_pad, ctx->adata.keylen, + CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); else - append_key(desc, ctx->key_dma, ctx->split_key_len, CLASS_2 | + append_key(desc, ctx->adata.key, ctx->adata.keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); set_jump_tgt_here(desc, key_jump_cmd); /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); + append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); /* assoclen + cryptlen = seqoutlen */ append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); @@ -465,7 +469,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) u32 geniv, moveiv; u32 ctx1_iv_off = 0; u32 *desc; - const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == + const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; @@ -473,7 +477,7 @@ static int aead_set_sh_desc(struct crypto_aead *aead) return 0; /* NULL encryption / decryption */ - if (!ctx->enckeylen) + if (!ctx->cdata.keylen) return aead_null_set_sh_desc(aead); /* @@ -498,12 +502,18 @@ static int aead_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_AEAD_ENC_LEN + AUTHENC_DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen + + ctx->adata.keylen_pad + ctx->cdata.keylen + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= - CAAM_DESC_BYTES_MAX) + CAAM_DESC_BYTES_MAX) { keys_fit_inline = true; + ctx->adata.key = (uintptr_t)ctx->key; + ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + } else { + keys_fit_inline = false; + ctx->adata.key = ctx->key_dma; + ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; + } /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; @@ -512,8 +522,8 @@ static int aead_set_sh_desc(struct crypto_aead *aead) init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* Read and write assoclen bytes */ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); @@ -534,8 +544,8 @@ static int aead_set_sh_desc(struct crypto_aead *aead) LDST_OFFSET_SHIFT)); /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* Read and write cryptlen bytes */ append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); @@ -564,12 +574,18 @@ skip_enc: * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_AEAD_DEC_LEN + AUTHENC_DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen + + ctx->adata.keylen_pad + ctx->cdata.keylen + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= - CAAM_DESC_BYTES_MAX) + CAAM_DESC_BYTES_MAX) { keys_fit_inline = true; + ctx->adata.key = (uintptr_t)ctx->key; + ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + } else { + keys_fit_inline = false; + ctx->adata.key = ctx->key_dma; + ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; + } /* aead_decrypt shared descriptor */ desc = ctx->sh_desc_dec; @@ -578,8 +594,8 @@ skip_enc: init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); /* Class 2 operation */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); + append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); /* Read and write assoclen bytes */ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); @@ -612,10 +628,10 @@ skip_enc: /* Choose operation */ if (ctr_mode) - append_operation(desc, ctx->class1_alg_type | + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); else - append_dec_op1(desc, ctx->class1_alg_type); + append_dec_op1(desc, ctx->cdata.algtype); /* Read and write cryptlen bytes */ append_math_add(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); @@ -646,12 +662,18 @@ skip_enc: * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_AEAD_GIVENC_LEN + AUTHENC_DESC_JOB_IO_LEN + - ctx->split_key_pad_len + ctx->enckeylen + + ctx->adata.keylen_pad + ctx->cdata.keylen + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= - CAAM_DESC_BYTES_MAX) + CAAM_DESC_BYTES_MAX) { keys_fit_inline = true; + ctx->adata.key = (uintptr_t)ctx->key; + ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + } else { + keys_fit_inline = false; + ctx->adata.key = ctx->key_dma; + ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; + } /* aead_givencrypt shared descriptor */ desc = ctx->sh_desc_enc; @@ -682,8 +704,8 @@ copy_iv: (ivsize << MOVE_LEN_SHIFT)); /* Return to encryption */ - append_operation(desc, ctx->class2_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* Read and write assoclen bytes */ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); @@ -712,8 +734,8 @@ copy_iv: LDST_OFFSET_SHIFT)); /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* Will write ivsize + cryptlen */ append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); @@ -764,12 +786,11 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1, *zero_assoc_jump_cmd2; u32 *desc; - if (!ctx->enckeylen || !ctx->authsize) + if (!ctx->cdata.keylen || !ctx->authsize) return 0; /* @@ -778,8 +799,13 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) * must fit into the 64-word Descriptor h/w Buffer */ if (DESC_GCM_ENC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + ctx->cdata.key_inline = true; + ctx->cdata.key = (uintptr_t)ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key = ctx->key_dma; + } desc = ctx->sh_desc_enc; @@ -788,17 +814,18 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) /* skip key loading if they are loaded due to sharing */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD | JUMP_COND_SELF); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + if (ctx->cdata.key_inline) + append_key_as_imm(desc, (void *)ctx->cdata.key, + ctx->cdata.keylen, ctx->cdata.keylen, + CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); + append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | + KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); /* class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* if assoclen + cryptlen is ZERO, skip to ICV write */ append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); @@ -870,10 +897,14 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_GCM_DEC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + ctx->cdata.key_inline = true; + ctx->cdata.key = (uintptr_t)ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key = ctx->key_dma; + } desc = ctx->sh_desc_dec; @@ -883,17 +914,18 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD | JUMP_COND_SELF); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + if (ctx->cdata.key_inline) + append_key_as_imm(desc, (void *)ctx->cdata.key, + ctx->cdata.keylen, ctx->cdata.keylen, + CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); + append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | + KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); /* class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); /* if assoclen is ZERO, skip reading the assoc data */ append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); @@ -964,11 +996,10 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; u32 *key_jump_cmd; u32 *desc; - if (!ctx->enckeylen || !ctx->authsize) + if (!ctx->cdata.keylen || !ctx->authsize) return 0; /* @@ -977,8 +1008,13 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) * must fit into the 64-word Descriptor h/w Buffer */ if (DESC_RFC4106_ENC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + ctx->cdata.key_inline = true; + ctx->cdata.key = (uintptr_t)ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key = ctx->key_dma; + } desc = ctx->sh_desc_enc; @@ -987,17 +1023,18 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) /* Skip key loading if it is loaded due to sharing */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + if (ctx->cdata.key_inline) + append_key_as_imm(desc, (void *)ctx->cdata.key, + ctx->cdata.keylen, ctx->cdata.keylen, + CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); + append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | + KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); @@ -1049,10 +1086,14 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_RFC4106_DEC_LEN + DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + ctx->cdata.key_inline = true; + ctx->cdata.key = (uintptr_t)ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key = ctx->key_dma; + } desc = ctx->sh_desc_dec; @@ -1061,17 +1102,18 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) /* Skip key loading if it is loaded due to sharing */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + if (ctx->cdata.key_inline) + append_key_as_imm(desc, (void *)ctx->cdata.key, + ctx->cdata.keylen, ctx->cdata.keylen, + CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); + append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | + KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); @@ -1137,12 +1179,11 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline = false; u32 *key_jump_cmd; u32 *read_move_cmd, *write_move_cmd; u32 *desc; - if (!ctx->enckeylen || !ctx->authsize) + if (!ctx->cdata.keylen || !ctx->authsize) return 0; /* @@ -1151,8 +1192,13 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) * must fit into the 64-word Descriptor h/w Buffer */ if (DESC_RFC4543_ENC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + ctx->cdata.key_inline = true; + ctx->cdata.key = (uintptr_t)ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key = ctx->key_dma; + } desc = ctx->sh_desc_enc; @@ -1161,17 +1207,18 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) /* Skip key loading if it is loaded due to sharing */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + if (ctx->cdata.key_inline) + append_key_as_imm(desc, (void *)ctx->cdata.key, + ctx->cdata.keylen, ctx->cdata.keylen, + CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); + append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | + KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* assoclen + cryptlen = seqinlen */ append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); @@ -1222,10 +1269,14 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - keys_fit_inline = false; if (DESC_RFC4543_DEC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->enckeylen <= CAAM_DESC_BYTES_MAX) - keys_fit_inline = true; + ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + ctx->cdata.key_inline = true; + ctx->cdata.key = (uintptr_t)ctx->key; + } else { + ctx->cdata.key_inline = false; + ctx->cdata.key = ctx->key_dma; + } desc = ctx->sh_desc_dec; @@ -1234,17 +1285,18 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) /* Skip key loading if it is loaded due to sharing */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); - if (keys_fit_inline) - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + if (ctx->cdata.key_inline) + append_key_as_imm(desc, (void *)ctx->cdata.key, + ctx->cdata.keylen, ctx->cdata.keylen, + CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, ctx->key_dma, ctx->enckeylen, - CLASS_1 | KEY_DEST_CLASS_REG); + append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | + KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); /* Class 1 operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT | OP_ALG_ICV_ON); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); /* assoclen + cryptlen = seqoutlen */ append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ); @@ -1313,9 +1365,8 @@ static int rfc4543_setauthsize(struct crypto_aead *authenc, static u32 gen_split_aead_key(struct caam_ctx *ctx, const u8 *key_in, u32 authkeylen) { - return gen_split_key(ctx->jrdev, ctx->key, ctx->split_key_len, - ctx->split_key_pad_len, key_in, authkeylen, - ctx->alg_op); + return gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key_in, + authkeylen, ctx->alg_op); } static int aead_setkey(struct crypto_aead *aead, @@ -1332,11 +1383,11 @@ static int aead_setkey(struct crypto_aead *aead, goto badkey; /* Pick class 2 key length from algorithm submask */ - ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> - OP_ALG_ALGSEL_SHIFT] * 2; - ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); + ctx->adata.keylen = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT] * 2; + ctx->adata.keylen_pad = ALIGN(ctx->adata.keylen, 16); - if (ctx->split_key_pad_len + keys.enckeylen > CAAM_MAX_KEY_SIZE) + if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE) goto badkey; #ifdef DEBUG @@ -1344,7 +1395,7 @@ static int aead_setkey(struct crypto_aead *aead, keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", - ctx->split_key_len, ctx->split_key_pad_len); + ctx->adata.keylen, ctx->adata.keylen_pad); print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif @@ -1355,9 +1406,9 @@ static int aead_setkey(struct crypto_aead *aead, } /* postpend encryption key to auth split key */ - memcpy(ctx->key + ctx->split_key_pad_len, keys.enckey, keys.enckeylen); + memcpy(ctx->key + ctx->adata.keylen_pad, keys.enckey, keys.enckeylen); - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len + + ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->adata.keylen_pad + keys.enckeylen, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->key_dma)) { dev_err(jrdev, "unable to map key i/o memory\n"); @@ -1366,14 +1417,14 @@ static int aead_setkey(struct crypto_aead *aead, #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, - ctx->split_key_pad_len + keys.enckeylen, 1); + ctx->adata.keylen_pad + keys.enckeylen, 1); #endif - ctx->enckeylen = keys.enckeylen; + ctx->cdata.keylen = keys.enckeylen; ret = aead_set_sh_desc(aead); if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->split_key_pad_len + + dma_unmap_single(jrdev, ctx->key_dma, ctx->adata.keylen_pad + keys.enckeylen, DMA_TO_DEVICE); } @@ -1402,11 +1453,11 @@ static int gcm_setkey(struct crypto_aead *aead, dev_err(jrdev, "unable to map key i/o memory\n"); return -ENOMEM; } - ctx->enckeylen = keylen; + ctx->cdata.keylen = keylen; ret = gcm_set_sh_desc(aead); if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, + dma_unmap_single(jrdev, ctx->key_dma, ctx->cdata.keylen, DMA_TO_DEVICE); } @@ -1434,9 +1485,9 @@ static int rfc4106_setkey(struct crypto_aead *aead, * The last four bytes of the key material are used as the salt value * in the nonce. Update the AES key length. */ - ctx->enckeylen = keylen - 4; + ctx->cdata.keylen = keylen - 4; - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->enckeylen, + ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->cdata.keylen, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->key_dma)) { dev_err(jrdev, "unable to map key i/o memory\n"); @@ -1445,7 +1496,7 @@ static int rfc4106_setkey(struct crypto_aead *aead, ret = rfc4106_set_sh_desc(aead); if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, + dma_unmap_single(jrdev, ctx->key_dma, ctx->cdata.keylen, DMA_TO_DEVICE); } @@ -1473,9 +1524,9 @@ static int rfc4543_setkey(struct crypto_aead *aead, * The last four bytes of the key material are used as the salt value * in the nonce. Update the AES key length. */ - ctx->enckeylen = keylen - 4; + ctx->cdata.keylen = keylen - 4; - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->enckeylen, + ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->cdata.keylen, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->key_dma)) { dev_err(jrdev, "unable to map key i/o memory\n"); @@ -1484,7 +1535,7 @@ static int rfc4543_setkey(struct crypto_aead *aead, ret = rfc4543_set_sh_desc(aead); if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->enckeylen, + dma_unmap_single(jrdev, ctx->key_dma, ctx->cdata.keylen, DMA_TO_DEVICE); } @@ -1505,7 +1556,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, u8 *nonce; u32 geniv; u32 ctx1_iv_off = 0; - const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == + const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = (ctr_mode && (strstr(alg_name, "rfc3686") != NULL)); @@ -1539,7 +1590,9 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, dev_err(jrdev, "unable to map key i/o memory\n"); return -ENOMEM; } - ctx->enckeylen = keylen; + ctx->cdata.keylen = keylen; + ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_inline = true; /* ablkcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; @@ -1549,9 +1602,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | - KEY_DEST_CLASS_REG); + append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, + ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load nonce into CONTEXT1 reg */ if (is_rfc3686) { @@ -1580,8 +1632,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, LDST_OFFSET_SHIFT)); /* Load operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* Perform operation */ ablkcipher_append_src_dst(desc); @@ -1608,9 +1660,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | - KEY_DEST_CLASS_REG); + append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, + ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load nonce into CONTEXT1 reg */ if (is_rfc3686) { @@ -1640,10 +1691,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* Choose operation */ if (ctr_mode) - append_operation(desc, ctx->class1_alg_type | + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); else - append_dec_op1(desc, ctx->class1_alg_type); + append_dec_op1(desc, ctx->cdata.algtype); /* Perform operation */ ablkcipher_append_src_dst(desc); @@ -1671,9 +1722,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | - KEY_DEST_CLASS_REG); + append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, + ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load Nonce into CONTEXT1 reg */ if (is_rfc3686) { @@ -1720,8 +1770,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, (1 << JUMP_OFFSET_SHIFT)); /* Load operation */ - append_operation(desc, ctx->class1_alg_type | - OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); /* Perform operation */ ablkcipher_append_src_dst(desc); @@ -1764,7 +1814,9 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, dev_err(jrdev, "unable to map key i/o memory\n"); return -ENOMEM; } - ctx->enckeylen = keylen; + ctx->cdata.keylen = keylen; + ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_inline = true; /* xts_ablkcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; @@ -1774,8 +1826,8 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, JUMP_COND_SHRD); /* Load class1 keys only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, + ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load sector size with index 40 bytes (0x28) */ append_cmd(desc, CMD_LOAD | IMMEDIATE | LDST_SRCDST_BYTE_CONTEXT | @@ -1794,7 +1846,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); /* Load operation */ - append_operation(desc, ctx->class1_alg_type | OP_ALG_AS_INITFINAL | + append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | OP_ALG_ENCRYPT); /* Perform operation */ @@ -1821,8 +1873,8 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->key, ctx->enckeylen, - ctx->enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, + ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load sector size with index 40 bytes (0x28) */ append_cmd(desc, CMD_LOAD | IMMEDIATE | LDST_SRCDST_BYTE_CONTEXT | @@ -1841,7 +1893,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); /* Load operation */ - append_dec_op1(desc, ctx->class1_alg_type); + append_dec_op1(desc, ctx->cdata.algtype); /* Perform operation */ ablkcipher_append_src_dst(desc); @@ -2141,7 +2193,7 @@ static void init_gcm_job(struct aead_request *req, FIFOLD_TYPE_IV | FIFOLD_TYPE_FLUSH1 | 12 | last); /* Append Salt */ if (!generic_gcm) - append_data(desc, ctx->key + ctx->enckeylen, 4); + append_data(desc, ctx->key + ctx->cdata.keylen, 4); /* Append IV */ append_data(desc, req->iv, ivsize); /* End of blank commands */ @@ -2156,7 +2208,7 @@ static void init_authenc_job(struct aead_request *req, struct caam_aead_alg, aead); unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); - const bool ctr_mode = ((ctx->class1_alg_type & OP_ALG_AAI_MASK) == + const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; u32 *desc = edesc->hw_desc; @@ -4395,8 +4447,8 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) } /* copy descriptor header template value */ - ctx->class1_alg_type = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; - ctx->class2_alg_type = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; + ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; + ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; ctx->alg_op = OP_TYPE_CLASS2_ALG | caam->alg_op; return 0; @@ -4440,7 +4492,7 @@ static void caam_exit_common(struct caam_ctx *ctx) if (ctx->key_dma && !dma_mapping_error(ctx->jrdev, ctx->key_dma)) dma_unmap_single(ctx->jrdev, ctx->key_dma, - ctx->enckeylen + ctx->split_key_pad_len, + ctx->cdata.keylen + ctx->adata.keylen_pad, DMA_TO_DEVICE); caam_jr_free(ctx->jrdev); diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 86f360853502..5e569ff06b4b 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -108,13 +108,11 @@ struct caam_hash_ctx { dma_addr_t sh_desc_fin_dma; dma_addr_t sh_desc_digest_dma; struct device *jrdev; - u32 alg_type; u32 alg_op; u8 key[CAAM_MAX_HASH_KEY_SIZE]; dma_addr_t key_dma; int ctx_len; - unsigned int split_key_len; - unsigned int split_key_pad_len; + struct alginfo adata; }; /* ahash state */ @@ -223,9 +221,9 @@ static inline int ctx_map_to_sec4_sg(u32 *desc, struct device *jrdev, /* Common shared descriptor commands */ static inline void append_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) { - append_key_as_imm(desc, ctx->key, ctx->split_key_pad_len, - ctx->split_key_len, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); + append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad, + ctx->adata.keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | + KEY_ENC); } /* Append key if it has been set */ @@ -235,7 +233,7 @@ static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) init_sh_desc(desc, HDR_SHARE_SERIAL); - if (ctx->split_key_len) { + if (ctx->adata.keylen) { /* Skip if already shared */ key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); @@ -310,7 +308,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) u32 have_key = 0; u32 *desc; - if (ctx->split_key_len) + if (ctx->adata.keylen) have_key = OP_ALG_AAI_HMAC_PRECOMP; /* ahash_update shared descriptor */ @@ -323,7 +321,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) LDST_CLASS_2_CCB | ctx->ctx_len); /* Class 2 operation */ - append_operation(desc, ctx->alg_type | OP_ALG_AS_UPDATE | + append_operation(desc, ctx->adata.algtype | OP_ALG_AS_UPDATE | OP_ALG_ENCRYPT); /* Load data and write to result or context */ @@ -344,7 +342,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_update_first shared descriptor */ desc = ctx->sh_desc_update_first; - ahash_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INIT, + ahash_data_to_out(desc, have_key | ctx->adata.algtype, OP_ALG_AS_INIT, ctx->ctx_len, ctx); ctx->sh_desc_update_first_dma = dma_map_single(jrdev, desc, @@ -363,7 +361,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_final shared descriptor */ desc = ctx->sh_desc_fin; - ahash_ctx_data_to_out(desc, have_key | ctx->alg_type, + ahash_ctx_data_to_out(desc, have_key | ctx->adata.algtype, OP_ALG_AS_FINALIZE, digestsize, ctx); ctx->sh_desc_fin_dma = dma_map_single(jrdev, desc, desc_bytes(desc), @@ -381,8 +379,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_digest shared descriptor */ desc = ctx->sh_desc_digest; - ahash_data_to_out(desc, have_key | ctx->alg_type, OP_ALG_AS_INITFINAL, - digestsize, ctx); + ahash_data_to_out(desc, have_key | ctx->adata.algtype, + OP_ALG_AS_INITFINAL, digestsize, ctx); ctx->sh_desc_digest_dma = dma_map_single(jrdev, desc, desc_bytes(desc), @@ -404,9 +402,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in, u32 keylen) { - return gen_split_key(ctx->jrdev, ctx->key, ctx->split_key_len, - ctx->split_key_pad_len, key_in, keylen, - ctx->alg_op); + return gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key_in, keylen, + ctx->alg_op); } /* Digest hash size if it is too large */ @@ -444,7 +441,7 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, } /* Job descriptor to perform unkeyed hash on key_in */ - append_operation(desc, ctx->alg_type | OP_ALG_ENCRYPT | + append_operation(desc, ctx->adata.algtype | OP_ALG_ENCRYPT | OP_ALG_AS_INITFINAL); append_seq_in_ptr(desc, src_dma, *keylen, 0); append_seq_fifo_load(desc, *keylen, FIFOLD_CLASS_CLASS2 | @@ -515,13 +512,13 @@ static int ahash_setkey(struct crypto_ahash *ahash, } /* Pick class 2 key length from algorithm submask */ - ctx->split_key_len = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> - OP_ALG_ALGSEL_SHIFT] * 2; - ctx->split_key_pad_len = ALIGN(ctx->split_key_len, 16); + ctx->adata.keylen = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + OP_ALG_ALGSEL_SHIFT] * 2; + ctx->adata.keylen_pad = ALIGN(ctx->adata.keylen, 16); #ifdef DEBUG printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", - ctx->split_key_len, ctx->split_key_pad_len); + ctx->adata.keylen, ctx->adata.keylen_pad); print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif @@ -530,7 +527,7 @@ static int ahash_setkey(struct crypto_ahash *ahash, if (ret) goto bad_free_key; - ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->split_key_pad_len, + ctx->key_dma = dma_map_single(jrdev, ctx->key, ctx->adata.keylen_pad, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->key_dma)) { dev_err(jrdev, "unable to map key i/o memory\n"); @@ -540,14 +537,15 @@ static int ahash_setkey(struct crypto_ahash *ahash, #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, ctx->key, - ctx->split_key_pad_len, 1); + ctx->adata.keylen_pad, 1); #endif ret = ahash_set_sh_desc(ahash); if (ret) { - dma_unmap_single(jrdev, ctx->key_dma, ctx->split_key_pad_len, + dma_unmap_single(jrdev, ctx->key_dma, ctx->adata.keylen_pad, DMA_TO_DEVICE); } + error_free_key: kfree(hashed_key); return ret; @@ -1832,7 +1830,7 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) return PTR_ERR(ctx->jrdev); } /* copy descriptor header template value */ - ctx->alg_type = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; + ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_hash->alg_op; ctx->ctx_len = runninglen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index 354da735af62..bfef7952dfb7 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -430,3 +430,22 @@ do { \ APPEND_MATH_IMM_u64(LSHIFT, desc, dest, src0, src1, data) #define append_math_rshift_imm_u64(desc, dest, src0, src1, data) \ APPEND_MATH_IMM_u64(RSHIFT, desc, dest, src0, src1, data) + +/** + * struct alginfo - Container for algorithm details + * @algtype: algorithm selector; for valid values, see documentation of the + * functions where it is used. + * @keylen: length of the provided algorithm key, in bytes + * @keylen_pad: padded length of the provided algorithm key, in bytes + * @key: address where algorithm key resides; virtual address if key_inline + * is true, dma (bus) address if key_inline is false. + * @key_inline: true - key can be inlined in the descriptor; false - key is + * referenced by the descriptor + */ +struct alginfo { + u32 algtype; + unsigned int keylen; + unsigned int keylen_pad; + u64 key; + bool key_inline; +}; diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index e1eaf4ff9762..df287e751df1 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -41,8 +41,8 @@ Split key generation----------------------------------------------- [06] 0x64260028 fifostr: class2 mdsplit-jdk len=40 @0xffe04000 */ -int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, - int split_key_pad_len, const u8 *key_in, u32 keylen, +int gen_split_key(struct device *jrdev, u8 *key_out, + struct alginfo * const adata, const u8 *key_in, u32 keylen, u32 alg_op) { u32 *desc; @@ -63,7 +63,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, goto out_free; } - dma_addr_out = dma_map_single(jrdev, key_out, split_key_pad_len, + dma_addr_out = dma_map_single(jrdev, key_out, adata->keylen_pad, DMA_FROM_DEVICE); if (dma_mapping_error(jrdev, dma_addr_out)) { dev_err(jrdev, "unable to map key output memory\n"); @@ -87,7 +87,7 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, * FIFO_STORE with the explicit split-key content store * (0x26 output type) */ - append_fifo_store(desc, dma_addr_out, split_key_len, + append_fifo_store(desc, dma_addr_out, adata->keylen, LDST_CLASS_2_CCB | FIFOST_TYPE_SPLIT_KEK); #ifdef DEBUG @@ -108,11 +108,11 @@ int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, #ifdef DEBUG print_hex_dump(KERN_ERR, "ctx.key@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key_out, - split_key_pad_len, 1); + adata->keylen_pad, 1); #endif } - dma_unmap_single(jrdev, dma_addr_out, split_key_pad_len, + dma_unmap_single(jrdev, dma_addr_out, adata->keylen_pad, DMA_FROM_DEVICE); out_unmap_in: dma_unmap_single(jrdev, dma_addr_in, keylen, DMA_TO_DEVICE); diff --git a/drivers/crypto/caam/key_gen.h b/drivers/crypto/caam/key_gen.h index c5588f6d8109..511882af0596 100644 --- a/drivers/crypto/caam/key_gen.h +++ b/drivers/crypto/caam/key_gen.h @@ -12,6 +12,6 @@ struct split_key_result { void split_key_done(struct device *dev, u32 *desc, u32 err, void *context); -int gen_split_key(struct device *jrdev, u8 *key_out, int split_key_len, - int split_key_pad_len, const u8 *key_in, u32 keylen, - u32 alg_op); +int gen_split_key(struct device *jrdev, u8 *key_out, + struct alginfo * const adata, const u8 *key_in, u32 keylen, + u32 alg_op); -- cgit v1.2.3 From 488ebc3a41260d62b24c18271356abc1f3ffdb63 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:05 +0200 Subject: crypto: caam - remove superfluous alg_op algorithm param MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Information carried by alg_op can be deduced from adata->algtype plus some fixed flags. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 64 ++---------------------------------------- drivers/crypto/caam/caamhash.c | 20 ++++--------- drivers/crypto/caam/key_gen.c | 7 +++-- drivers/crypto/caam/key_gen.h | 3 +- 4 files changed, 13 insertions(+), 81 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 4141143cce7d..48fc000d86bf 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -149,7 +149,6 @@ static struct list_head alg_list; struct caam_alg_entry { int class1_alg_type; int class2_alg_type; - int alg_op; bool rfc3686; bool geniv; }; @@ -217,7 +216,6 @@ struct caam_ctx { dma_addr_t sh_desc_enc_dma; dma_addr_t sh_desc_dec_dma; dma_addr_t sh_desc_givenc_dma; - u32 alg_op; u8 key[CAAM_MAX_KEY_SIZE]; dma_addr_t key_dma; struct alginfo adata; @@ -1366,7 +1364,7 @@ static u32 gen_split_aead_key(struct caam_ctx *ctx, const u8 *key_in, u32 authkeylen) { return gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key_in, - authkeylen, ctx->alg_op); + authkeylen); } static int aead_setkey(struct crypto_aead *aead, @@ -1383,7 +1381,8 @@ static int aead_setkey(struct crypto_aead *aead, goto badkey; /* Pick class 2 key length from algorithm submask */ - ctx->adata.keylen = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + ctx->adata.keylen = mdpadlen[(ctx->adata.algtype & + OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT] * 2; ctx->adata.keylen_pad = ALIGN(ctx->adata.keylen, 16); @@ -2988,7 +2987,6 @@ struct caam_alg_template { } template_u; u32 class1_alg_type; u32 class2_alg_type; - u32 alg_op; }; static struct caam_alg_template driver_algs[] = { @@ -3173,7 +3171,6 @@ static struct caam_aead_alg driver_aeads[] = { .caam = { .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, }, }, { @@ -3195,7 +3192,6 @@ static struct caam_aead_alg driver_aeads[] = { .caam = { .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, }, { @@ -3217,7 +3213,6 @@ static struct caam_aead_alg driver_aeads[] = { .caam = { .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, }, }, { @@ -3239,7 +3234,6 @@ static struct caam_aead_alg driver_aeads[] = { .caam = { .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, }, { @@ -3261,7 +3255,6 @@ static struct caam_aead_alg driver_aeads[] = { .caam = { .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, }, }, { @@ -3283,7 +3276,6 @@ static struct caam_aead_alg driver_aeads[] = { .caam = { .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, }, }, { @@ -3305,7 +3297,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, }, }, { @@ -3328,7 +3319,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3351,7 +3341,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, }, { @@ -3374,7 +3363,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3397,7 +3385,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, }, }, { @@ -3420,7 +3407,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3443,7 +3429,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, }, { @@ -3466,7 +3451,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3489,7 +3473,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, }, }, { @@ -3512,7 +3495,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3535,7 +3517,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, }, }, { @@ -3558,7 +3539,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_AES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3581,7 +3561,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, } }, { @@ -3604,7 +3583,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, .geniv = true, } }, @@ -3628,7 +3606,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, }, { @@ -3652,7 +3629,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3676,7 +3652,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, }, }, { @@ -3700,7 +3675,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3724,7 +3698,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, }, { @@ -3748,7 +3721,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3772,7 +3744,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, }, }, { @@ -3796,7 +3767,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3820,7 +3790,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, }, }, { @@ -3844,7 +3813,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_3DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3867,7 +3835,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, }, }, { @@ -3890,7 +3857,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3913,7 +3879,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, }, { @@ -3936,7 +3901,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -3959,7 +3923,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, }, }, { @@ -3982,7 +3945,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -4005,7 +3967,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, }, { @@ -4028,7 +3989,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -4051,7 +4011,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, }, }, { @@ -4074,7 +4033,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -4097,7 +4055,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, }, }, { @@ -4120,7 +4077,6 @@ static struct caam_aead_alg driver_aeads[] = { .class1_alg_type = OP_ALG_ALGSEL_DES | OP_ALG_AAI_CBC, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, .geniv = true, }, }, @@ -4145,7 +4101,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, .rfc3686 = true, }, }, @@ -4170,7 +4125,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, .rfc3686 = true, .geniv = true, }, @@ -4196,7 +4150,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, .rfc3686 = true, }, }, @@ -4221,7 +4174,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, .rfc3686 = true, .geniv = true, }, @@ -4247,7 +4199,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, .rfc3686 = true, }, }, @@ -4272,7 +4223,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, .rfc3686 = true, .geniv = true, }, @@ -4298,7 +4248,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, .rfc3686 = true, }, }, @@ -4323,7 +4272,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, .rfc3686 = true, .geniv = true, }, @@ -4349,7 +4297,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, .rfc3686 = true, }, }, @@ -4374,7 +4321,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, .rfc3686 = true, .geniv = true, }, @@ -4400,7 +4346,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, .rfc3686 = true, }, }, @@ -4425,7 +4370,6 @@ static struct caam_aead_alg driver_aeads[] = { OP_ALG_AAI_CTR_MOD128, .class2_alg_type = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC_PRECOMP, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, .rfc3686 = true, .geniv = true, }, @@ -4449,7 +4393,6 @@ static int caam_init_common(struct caam_ctx *ctx, struct caam_alg_entry *caam) /* copy descriptor header template value */ ctx->cdata.algtype = OP_TYPE_CLASS1_ALG | caam->class1_alg_type; ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam->class2_alg_type; - ctx->alg_op = OP_TYPE_CLASS2_ALG | caam->alg_op; return 0; } @@ -4570,7 +4513,6 @@ static struct caam_crypto_alg *caam_alg_alloc(struct caam_alg_template t_alg->caam.class1_alg_type = template->class1_alg_type; t_alg->caam.class2_alg_type = template->class2_alg_type; - t_alg->caam.alg_op = template->alg_op; return t_alg; } diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 5e569ff06b4b..8e4530d68208 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -108,7 +108,6 @@ struct caam_hash_ctx { dma_addr_t sh_desc_fin_dma; dma_addr_t sh_desc_digest_dma; struct device *jrdev; - u32 alg_op; u8 key[CAAM_MAX_HASH_KEY_SIZE]; dma_addr_t key_dma; int ctx_len; @@ -402,8 +401,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in, u32 keylen) { - return gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key_in, keylen, - ctx->alg_op); + return gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key_in, keylen); } /* Digest hash size if it is too large */ @@ -512,7 +510,8 @@ static int ahash_setkey(struct crypto_ahash *ahash, } /* Pick class 2 key length from algorithm submask */ - ctx->adata.keylen = mdpadlen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + ctx->adata.keylen = mdpadlen[(ctx->adata.algtype & + OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT] * 2; ctx->adata.keylen_pad = ALIGN(ctx->adata.keylen, 16); @@ -1654,7 +1653,6 @@ struct caam_hash_template { unsigned int blocksize; struct ahash_alg template_ahash; u32 alg_type; - u32 alg_op; }; /* ahash descriptors */ @@ -1680,7 +1678,6 @@ static struct caam_hash_template driver_hash[] = { }, }, .alg_type = OP_ALG_ALGSEL_SHA1, - .alg_op = OP_ALG_ALGSEL_SHA1 | OP_ALG_AAI_HMAC, }, { .name = "sha224", .driver_name = "sha224-caam", @@ -1702,7 +1699,6 @@ static struct caam_hash_template driver_hash[] = { }, }, .alg_type = OP_ALG_ALGSEL_SHA224, - .alg_op = OP_ALG_ALGSEL_SHA224 | OP_ALG_AAI_HMAC, }, { .name = "sha256", .driver_name = "sha256-caam", @@ -1724,7 +1720,6 @@ static struct caam_hash_template driver_hash[] = { }, }, .alg_type = OP_ALG_ALGSEL_SHA256, - .alg_op = OP_ALG_ALGSEL_SHA256 | OP_ALG_AAI_HMAC, }, { .name = "sha384", .driver_name = "sha384-caam", @@ -1746,7 +1741,6 @@ static struct caam_hash_template driver_hash[] = { }, }, .alg_type = OP_ALG_ALGSEL_SHA384, - .alg_op = OP_ALG_ALGSEL_SHA384 | OP_ALG_AAI_HMAC, }, { .name = "sha512", .driver_name = "sha512-caam", @@ -1768,7 +1762,6 @@ static struct caam_hash_template driver_hash[] = { }, }, .alg_type = OP_ALG_ALGSEL_SHA512, - .alg_op = OP_ALG_ALGSEL_SHA512 | OP_ALG_AAI_HMAC, }, { .name = "md5", .driver_name = "md5-caam", @@ -1790,14 +1783,12 @@ static struct caam_hash_template driver_hash[] = { }, }, .alg_type = OP_ALG_ALGSEL_MD5, - .alg_op = OP_ALG_ALGSEL_MD5 | OP_ALG_AAI_HMAC, }, }; struct caam_hash_alg { struct list_head entry; int alg_type; - int alg_op; struct ahash_alg ahash_alg; }; @@ -1831,9 +1822,9 @@ static int caam_hash_cra_init(struct crypto_tfm *tfm) } /* copy descriptor header template value */ ctx->adata.algtype = OP_TYPE_CLASS2_ALG | caam_hash->alg_type; - ctx->alg_op = OP_TYPE_CLASS2_ALG | caam_hash->alg_op; - ctx->ctx_len = runninglen[(ctx->alg_op & OP_ALG_ALGSEL_SUBMASK) >> + ctx->ctx_len = runninglen[(ctx->adata.algtype & + OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT]; crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), @@ -1923,7 +1914,6 @@ caam_hash_alloc(struct caam_hash_template *template, alg->cra_type = &crypto_ahash_type; t_alg->alg_type = template->alg_type; - t_alg->alg_op = template->alg_op; return t_alg; } diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index df287e751df1..621199a02f2e 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -42,8 +42,7 @@ Split key generation----------------------------------------------- @0xffe04000 */ int gen_split_key(struct device *jrdev, u8 *key_out, - struct alginfo * const adata, const u8 *key_in, u32 keylen, - u32 alg_op) + struct alginfo * const adata, const u8 *key_in, u32 keylen) { u32 *desc; struct split_key_result result; @@ -74,7 +73,9 @@ int gen_split_key(struct device *jrdev, u8 *key_out, append_key(desc, dma_addr_in, keylen, CLASS_2 | KEY_DEST_CLASS_REG); /* Sets MDHA up into an HMAC-INIT */ - append_operation(desc, alg_op | OP_ALG_DECRYPT | OP_ALG_AS_INIT); + append_operation(desc, (adata->algtype & OP_ALG_ALGSEL_MASK) | + OP_ALG_AAI_HMAC | OP_TYPE_CLASS2_ALG | OP_ALG_DECRYPT | + OP_ALG_AS_INIT); /* * do a FIFO_LOAD of zero, this will trigger the internal key expansion diff --git a/drivers/crypto/caam/key_gen.h b/drivers/crypto/caam/key_gen.h index 511882af0596..e87483c6057b 100644 --- a/drivers/crypto/caam/key_gen.h +++ b/drivers/crypto/caam/key_gen.h @@ -13,5 +13,4 @@ struct split_key_result { void split_key_done(struct device *dev, u32 *desc, u32 err, void *context); int gen_split_key(struct device *jrdev, u8 *key_out, - struct alginfo * const adata, const u8 *key_in, u32 keylen, - u32 alg_op); + struct alginfo * const adata, const u8 *key_in, u32 keylen); -- cgit v1.2.3 From 4cbe79ccb5233c52b291d53200e75f8db19c6a14 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:06 +0200 Subject: crypto: caam - improve key inlining MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For authenc / stitched AEAD algorithms, check independently each of the two (authentication, encryption) keys whether inlining is possible. Prioritize the inlining of the authentication key, since the length of the (split) key is bigger than that of the encryption key. For the other algorithms, compute only once per tfm the remaining available bytes and decide whether key inlining is possible based on this. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 130 ++++++++++++++++++++++---------------- drivers/crypto/caam/desc_constr.h | 39 ++++++++++++ 2 files changed, 116 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 48fc000d86bf..5f332df1a8e6 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -224,7 +224,7 @@ struct caam_ctx { }; static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, - int keys_fit_inline, bool is_rfc3686) + bool is_rfc3686) { u32 *key_jump_cmd; unsigned int enckeylen = ctx->cdata.keylen; @@ -244,18 +244,20 @@ static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, if (is_rfc3686) enckeylen -= CTR_RFC3686_NONCE_SIZE; - if (keys_fit_inline) { + if (ctx->adata.key_inline) append_key_as_imm(desc, (void *)ctx->adata.key, ctx->adata.keylen_pad, ctx->adata.keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); - append_key_as_imm(desc, (void *)ctx->cdata.key, enckeylen, - enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - } else { + else append_key(desc, ctx->adata.key, ctx->adata.keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); + + if (ctx->cdata.key_inline) + append_key_as_imm(desc, (void *)ctx->cdata.key, enckeylen, + enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + else append_key(desc, ctx->cdata.key, enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - } /* Load Counter into CONTEXT1 reg */ if (is_rfc3686) { @@ -282,13 +284,14 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) struct device *jrdev = ctx->jrdev; u32 *key_jump_cmd, *jump_cmd, *read_move_cmd, *write_move_cmd; u32 *desc; + int rem_bytes = CAAM_DESC_BYTES_MAX - AEAD_DESC_JOB_IO_LEN - + ctx->adata.keylen_pad; /* * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_AEAD_NULL_ENC_LEN + AEAD_DESC_JOB_IO_LEN + - ctx->adata.keylen_pad <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_AEAD_NULL_ENC_LEN) { ctx->adata.key_inline = true; ctx->adata.key = (uintptr_t)ctx->key; } else { @@ -368,8 +371,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_AEAD_NULL_DEC_LEN + DESC_JOB_IO_LEN + - ctx->adata.keylen_pad <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_AEAD_NULL_DEC_LEN) { ctx->adata.key_inline = true; ctx->adata.key = (uintptr_t)ctx->key; } else { @@ -463,10 +465,11 @@ static int aead_set_sh_desc(struct crypto_aead *aead) unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - bool keys_fit_inline; u32 geniv, moveiv; u32 ctx1_iv_off = 0; u32 *desc; + u32 inl_mask; + unsigned int data_len[2]; const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = alg->caam.rfc3686; @@ -493,6 +496,9 @@ static int aead_set_sh_desc(struct crypto_aead *aead) if (is_rfc3686) ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + data_len[0] = ctx->adata.keylen_pad; + data_len[1] = ctx->cdata.keylen; + if (alg->caam.geniv) goto skip_enc; @@ -500,24 +506,30 @@ static int aead_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_AEAD_ENC_LEN + AUTHENC_DESC_JOB_IO_LEN + - ctx->adata.keylen_pad + ctx->cdata.keylen + - (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= - CAAM_DESC_BYTES_MAX) { - keys_fit_inline = true; + if (desc_inline_query(DESC_AEAD_ENC_LEN + + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), + AUTHENC_DESC_JOB_IO_LEN, data_len, &inl_mask, + ARRAY_SIZE(data_len)) < 0) + return -EINVAL; + + if (inl_mask & 1) ctx->adata.key = (uintptr_t)ctx->key; - ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); - } else { - keys_fit_inline = false; + else ctx->adata.key = ctx->key_dma; + + if (inl_mask & 2) + ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + else ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; - } + + ctx->adata.key_inline = !!(inl_mask & 1); + ctx->cdata.key_inline = !!(inl_mask & 2); /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); + init_sh_desc_key_aead(desc, ctx, is_rfc3686); /* Class 2 operation */ append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | @@ -572,24 +584,30 @@ skip_enc: * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_AEAD_DEC_LEN + AUTHENC_DESC_JOB_IO_LEN + - ctx->adata.keylen_pad + ctx->cdata.keylen + - (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= - CAAM_DESC_BYTES_MAX) { - keys_fit_inline = true; + if (desc_inline_query(DESC_AEAD_DEC_LEN + + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), + AUTHENC_DESC_JOB_IO_LEN, data_len, &inl_mask, + ARRAY_SIZE(data_len)) < 0) + return -EINVAL; + + if (inl_mask & 1) ctx->adata.key = (uintptr_t)ctx->key; - ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); - } else { - keys_fit_inline = false; + else ctx->adata.key = ctx->key_dma; + + if (inl_mask & 2) + ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + else ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; - } + + ctx->adata.key_inline = !!(inl_mask & 1); + ctx->cdata.key_inline = !!(inl_mask & 2); /* aead_decrypt shared descriptor */ desc = ctx->sh_desc_dec; /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); + init_sh_desc_key_aead(desc, ctx, is_rfc3686); /* Class 2 operation */ append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | @@ -660,24 +678,30 @@ skip_enc: * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_AEAD_GIVENC_LEN + AUTHENC_DESC_JOB_IO_LEN + - ctx->adata.keylen_pad + ctx->cdata.keylen + - (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0) <= - CAAM_DESC_BYTES_MAX) { - keys_fit_inline = true; + if (desc_inline_query(DESC_AEAD_GIVENC_LEN + + (is_rfc3686 ? DESC_AEAD_CTR_RFC3686_LEN : 0), + AUTHENC_DESC_JOB_IO_LEN, data_len, &inl_mask, + ARRAY_SIZE(data_len)) < 0) + return -EINVAL; + + if (inl_mask & 1) ctx->adata.key = (uintptr_t)ctx->key; - ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); - } else { - keys_fit_inline = false; + else ctx->adata.key = ctx->key_dma; + + if (inl_mask & 2) + ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + else ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; - } + + ctx->adata.key_inline = !!(inl_mask & 1); + ctx->cdata.key_inline = !!(inl_mask & 2); /* aead_givencrypt shared descriptor */ desc = ctx->sh_desc_enc; /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, keys_fit_inline, is_rfc3686); + init_sh_desc_key_aead(desc, ctx, is_rfc3686); if (is_rfc3686) goto copy_iv; @@ -787,6 +811,8 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1, *zero_assoc_jump_cmd2; u32 *desc; + int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - + ctx->cdata.keylen; if (!ctx->cdata.keylen || !ctx->authsize) return 0; @@ -796,8 +822,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptor * must fit into the 64-word Descriptor h/w Buffer */ - if (DESC_GCM_ENC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_GCM_ENC_LEN) { ctx->cdata.key_inline = true; ctx->cdata.key = (uintptr_t)ctx->key; } else { @@ -895,8 +920,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_GCM_DEC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_GCM_DEC_LEN) { ctx->cdata.key_inline = true; ctx->cdata.key = (uintptr_t)ctx->key; } else { @@ -996,6 +1020,8 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) struct device *jrdev = ctx->jrdev; u32 *key_jump_cmd; u32 *desc; + int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - + ctx->cdata.keylen; if (!ctx->cdata.keylen || !ctx->authsize) return 0; @@ -1005,8 +1031,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptor * must fit into the 64-word Descriptor h/w Buffer */ - if (DESC_RFC4106_ENC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_RFC4106_ENC_LEN) { ctx->cdata.key_inline = true; ctx->cdata.key = (uintptr_t)ctx->key; } else { @@ -1084,8 +1109,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_RFC4106_DEC_LEN + DESC_JOB_IO_LEN + - ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_RFC4106_DEC_LEN) { ctx->cdata.key_inline = true; ctx->cdata.key = (uintptr_t)ctx->key; } else { @@ -1180,6 +1204,8 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) u32 *key_jump_cmd; u32 *read_move_cmd, *write_move_cmd; u32 *desc; + int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - + ctx->cdata.keylen; if (!ctx->cdata.keylen || !ctx->authsize) return 0; @@ -1189,8 +1215,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptor * must fit into the 64-word Descriptor h/w Buffer */ - if (DESC_RFC4543_ENC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_RFC4543_ENC_LEN) { ctx->cdata.key_inline = true; ctx->cdata.key = (uintptr_t)ctx->key; } else { @@ -1267,8 +1292,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) * Job Descriptor and Shared Descriptors * must all fit into the 64-word Descriptor h/w Buffer */ - if (DESC_RFC4543_DEC_LEN + GCM_DESC_JOB_IO_LEN + - ctx->cdata.keylen <= CAAM_DESC_BYTES_MAX) { + if (rem_bytes >= DESC_RFC4543_DEC_LEN) { ctx->cdata.key_inline = true; ctx->cdata.key = (uintptr_t)ctx->key; } else { diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index bfef7952dfb7..fa70c0d79c40 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -449,3 +449,42 @@ struct alginfo { u64 key; bool key_inline; }; + +/** + * desc_inline_query() - Provide indications on which data items can be inlined + * and which shall be referenced in a shared descriptor. + * @sd_base_len: Shared descriptor base length - bytes consumed by the commands, + * excluding the data items to be inlined (or corresponding + * pointer if an item is not inlined). Each cnstr_* function that + * generates descriptors should have a define mentioning + * corresponding length. + * @jd_len: Maximum length of the job descriptor(s) that will be used + * together with the shared descriptor. + * @data_len: Array of lengths of the data items trying to be inlined + * @inl_mask: 32bit mask with bit x = 1 if data item x can be inlined, 0 + * otherwise. + * @count: Number of data items (size of @data_len array); must be <= 32 + * + * Return: 0 if data can be inlined / referenced, negative value if not. If 0, + * check @inl_mask for details. + */ +static inline int desc_inline_query(unsigned int sd_base_len, + unsigned int jd_len, unsigned int *data_len, + u32 *inl_mask, unsigned int count) +{ + int rem_bytes = (int)(CAAM_DESC_BYTES_MAX - sd_base_len - jd_len); + unsigned int i; + + *inl_mask = 0; + for (i = 0; (i < count) && (rem_bytes > 0); i++) { + if (rem_bytes - (int)(data_len[i] + + (count - i - 1) * CAAM_PTR_SZ) >= 0) { + rem_bytes -= data_len[i]; + *inl_mask |= (1 << i); + } else { + rem_bytes -= CAAM_PTR_SZ; + } + } + + return (rem_bytes >= 0) ? 0 : -1; +} -- cgit v1.2.3 From 281669dfbabedb8b44466c4e788df71ff43bd8b5 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:07 +0200 Subject: crypto: caam - rewrite some generic inline append cmds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A few descriptor commands are generated using generic inline append "append_cmd" function. Rewrite them using specific inline append functions. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 20 ++++++++++---------- drivers/crypto/caam/caamhash.c | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 5f332df1a8e6..9cb95f5b2eb3 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -1853,9 +1853,9 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load sector size with index 40 bytes (0x28) */ - append_cmd(desc, CMD_LOAD | IMMEDIATE | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (0x28 << LDST_OFFSET_SHIFT) | 8); - append_data(desc, (void *)§or_size, 8); + append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + (0x28 << LDST_OFFSET_SHIFT)); set_jump_tgt_here(desc, key_jump_cmd); @@ -1864,8 +1864,8 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, * Upper 8B of IV - will be used as sector index * Lower 8B of IV - will be discarded */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (0x20 << LDST_OFFSET_SHIFT) | 8); + append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | + (0x20 << LDST_OFFSET_SHIFT)); append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); /* Load operation */ @@ -1900,9 +1900,9 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load sector size with index 40 bytes (0x28) */ - append_cmd(desc, CMD_LOAD | IMMEDIATE | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (0x28 << LDST_OFFSET_SHIFT) | 8); - append_data(desc, (void *)§or_size, 8); + append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + (0x28 << LDST_OFFSET_SHIFT)); set_jump_tgt_here(desc, key_jump_cmd); @@ -1911,8 +1911,8 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, * Upper 8B of IV - will be used as sector index * Lower 8B of IV - will be discarded */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (0x20 << LDST_OFFSET_SHIFT) | 8); + append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | + (0x20 << LDST_OFFSET_SHIFT)); append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); /* Load operation */ diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 8e4530d68208..d3f0ae16a73b 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -272,8 +272,8 @@ static inline void ahash_ctx_data_to_out(u32 *desc, u32 op, u32 state, init_sh_desc_key_ahash(desc, ctx); /* Import context from software */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_2_CCB | ctx->ctx_len); + append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); /* Class 2 operation */ append_operation(desc, op | state | OP_ALG_ENCRYPT); @@ -316,8 +316,8 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) init_sh_desc(desc, HDR_SHARE_SERIAL); /* Import context from software */ - append_cmd(desc, CMD_SEQ_LOAD | LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_2_CCB | ctx->ctx_len); + append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); /* Class 2 operation */ append_operation(desc, ctx->adata.algtype | OP_ALG_AS_UPDATE | -- cgit v1.2.3 From 746f069038961e8a72780c0625acc8accafd28fe Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:08 +0200 Subject: crypto: caam - remove unneded dependencies on CRYPTO_DEV_FSL_CAAM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove dependency on CRYPTO_DEV_FSL_CAAM where superfluous: depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR is equivalent to depends on CRYPTO_DEV_FSL_CAAM_JR since CRYPTO_DEV_FSL_CAAM_JR depends on CRYPTO_DEV_FSL_CAAM. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index 64bf3024b680..ebeada75ab2d 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -74,7 +74,7 @@ config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD config CRYPTO_DEV_FSL_CAAM_CRYPTO_API tristate "Register algorithm implementations with the Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_AEAD select CRYPTO_AUTHENC @@ -89,7 +89,7 @@ config CRYPTO_DEV_FSL_CAAM_CRYPTO_API config CRYPTO_DEV_FSL_CAAM_AHASH_API tristate "Register hash algorithm implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_HASH help @@ -101,7 +101,7 @@ config CRYPTO_DEV_FSL_CAAM_AHASH_API config CRYPTO_DEV_FSL_CAAM_PKC_API tristate "Register public key cryptography implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_RSA help @@ -113,7 +113,7 @@ config CRYPTO_DEV_FSL_CAAM_PKC_API config CRYPTO_DEV_FSL_CAAM_RNG_API tristate "Register caam device for hwrng API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR + depends on CRYPTO_DEV_FSL_CAAM_JR default y select CRYPTO_RNG select HW_RANDOM -- cgit v1.2.3 From 8cea7b66b821fd914aa26a2af156604f9ef5f709 Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:09 +0200 Subject: crypto: caam - refactor encryption descriptors generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactor the generation of the authenc, ablkcipher shared descriptors and exports the functionality, such that they could be shared with the upcoming caam/qi (Queue Interface) driver. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 3 + drivers/crypto/caam/Makefile | 1 + drivers/crypto/caam/caamalg.c | 1109 +----------------------------- drivers/crypto/caam/caamalg_desc.c | 1302 ++++++++++++++++++++++++++++++++++++ drivers/crypto/caam/caamalg_desc.h | 97 +++ 5 files changed, 1440 insertions(+), 1072 deletions(-) create mode 100644 drivers/crypto/caam/caamalg_desc.c create mode 100644 drivers/crypto/caam/caamalg_desc.h (limited to 'drivers') diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index ebeada75ab2d..da24c5752c06 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -134,3 +134,6 @@ config CRYPTO_DEV_FSL_CAAM_DEBUG help Selecting this will enable printing of various debug information in the CAAM driver. + +config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC + def_bool CRYPTO_DEV_FSL_CAAM_CRYPTO_API diff --git a/drivers/crypto/caam/Makefile b/drivers/crypto/caam/Makefile index 08bf5515ae8a..6554742f357e 100644 --- a/drivers/crypto/caam/Makefile +++ b/drivers/crypto/caam/Makefile @@ -8,6 +8,7 @@ endif obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_JR) += caam_jr.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API) += caamalg.o +obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC) += caamalg_desc.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_AHASH_API) += caamhash.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_RNG_API) += caamrng.o obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM_PKC_API) += caam_pkc.o diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 9cb95f5b2eb3..78b0b7c17205 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -2,6 +2,7 @@ * caam - Freescale FSL CAAM support for crypto API * * Copyright 2008-2011 Freescale Semiconductor, Inc. + * Copyright 2016 NXP * * Based on talitos crypto API driver. * @@ -53,6 +54,7 @@ #include "error.h" #include "sg_sw_sec4.h" #include "key_gen.h" +#include "caamalg_desc.h" /* * crypto alg @@ -69,37 +71,6 @@ #define AUTHENC_DESC_JOB_IO_LEN (AEAD_DESC_JOB_IO_LEN + \ CAAM_CMD_SZ * 5) -/* length of descriptors text */ -#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) -#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) -#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) -#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) - -/* Note: Nonce is counted in enckeylen */ -#define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ) - -#define DESC_AEAD_NULL_BASE (3 * CAAM_CMD_SZ) -#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 11 * CAAM_CMD_SZ) -#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 13 * CAAM_CMD_SZ) - -#define DESC_GCM_BASE (3 * CAAM_CMD_SZ) -#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ) -#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ) - -#define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) -#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) -#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) - -#define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ) -#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ) -#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ) - -#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ) -#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \ - 20 * CAAM_CMD_SZ) -#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \ - 15 * CAAM_CMD_SZ) - #define DESC_MAX_USED_BYTES (CAAM_DESC_BYTES_MAX - DESC_JOB_IO_LEN) #define DESC_MAX_USED_LEN (DESC_MAX_USED_BYTES / CAAM_CMD_SZ) @@ -159,52 +130,6 @@ struct caam_aead_alg { bool registered; }; -/* Set DK bit in class 1 operation if shared */ -static inline void append_dec_op1(u32 *desc, u32 type) -{ - u32 *jump_cmd, *uncond_jump_cmd; - - /* DK bit is valid only for AES */ - if ((type & OP_ALG_ALGSEL_MASK) != OP_ALG_ALGSEL_AES) { - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT); - return; - } - - jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT); - uncond_jump_cmd = append_jump(desc, JUMP_TEST_ALL); - set_jump_tgt_here(desc, jump_cmd); - append_operation(desc, type | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_AAI_DK); - set_jump_tgt_here(desc, uncond_jump_cmd); -} - -/* - * For aead functions, read payload and write payload, - * both of which are specified in req->src and req->dst - */ -static inline void aead_append_src_dst(u32 *desc, u32 msg_type) -{ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | - KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH); -} - -/* - * For ablkcipher encrypt and decrypt, read from req->src and - * write to req->dst - */ -static inline void ablkcipher_append_src_dst(u32 *desc) -{ - append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | - KEY_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); -} - /* * per-session context */ @@ -223,66 +148,10 @@ struct caam_ctx { unsigned int authsize; }; -static void init_sh_desc_key_aead(u32 *desc, struct caam_ctx *ctx, - bool is_rfc3686) -{ - u32 *key_jump_cmd; - unsigned int enckeylen = ctx->cdata.keylen; - - /* Note: Context registers are saved. */ - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* - * RFC3686 specific: - * | ctx->key = {AUTH_KEY, ENC_KEY, NONCE} - * | enckeylen = encryption key size + nonce size - */ - if (is_rfc3686) - enckeylen -= CTR_RFC3686_NONCE_SIZE; - - if (ctx->adata.key_inline) - append_key_as_imm(desc, (void *)ctx->adata.key, - ctx->adata.keylen_pad, ctx->adata.keylen, - CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_key(desc, ctx->adata.key, ctx->adata.keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - - if (ctx->cdata.key_inline) - append_key_as_imm(desc, (void *)ctx->cdata.key, enckeylen, - enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->cdata.key, enckeylen, CLASS_1 | - KEY_DEST_CLASS_REG); - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) { - u32 *nonce; - - nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad + - enckeylen); - append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, - LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - - set_jump_tgt_here(desc, key_jump_cmd); -} - static int aead_null_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - u32 *key_jump_cmd, *jump_cmd, *read_move_cmd, *write_move_cmd; u32 *desc; int rem_bytes = CAAM_DESC_BYTES_MAX - AEAD_DESC_JOB_IO_LEN - ctx->adata.keylen_pad; @@ -301,58 +170,7 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (ctx->adata.key_inline) - append_key_as_imm(desc, (void *)ctx->adata.key, - ctx->adata.keylen_pad, ctx->adata.keylen, - CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_key(desc, ctx->adata.key, ctx->adata.keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - set_jump_tgt_here(desc, key_jump_cmd); - - /* assoclen + cryptlen = seqinlen */ - append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Prepare to read and write cryptlen + assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | - MOVE_DEST_MATH3 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | - MOVE_DEST_DESCBUF | - MOVE_WAITCOMP | - (0x8 << MOVE_LEN_SHIFT)); - - /* Class 2 operation */ - append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Read and write cryptlen bytes */ - aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | - MOVE_AUX_LS); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - + cnstr_shdsc_aead_null_encap(desc, &ctx->adata, ctx->authsize); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -360,12 +178,6 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "aead null enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif /* * Job Descriptor and Shared Descriptors @@ -379,68 +191,9 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) ctx->adata.key = ctx->key_dma; } - desc = ctx->sh_desc_dec; - /* aead_decrypt shared descriptor */ - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (ctx->adata.key_inline) - append_key_as_imm(desc, (void *)ctx->adata.key, - ctx->adata.keylen_pad, ctx->adata.keylen, - CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); - else - append_key(desc, ctx->adata.key, ctx->adata.keylen, CLASS_2 | - KEY_DEST_MDHA_SPLIT | KEY_ENC); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 2 operation */ - append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* assoclen + cryptlen = seqoutlen */ - append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* Prepare to read and write cryptlen + assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | - MOVE_DEST_MATH2 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH2 | - MOVE_DEST_DESCBUF | - MOVE_WAITCOMP | - (0x8 << MOVE_LEN_SHIFT)); - - /* Read and write cryptlen bytes */ - aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - /* - * Insert a NOP here, since we need at least 4 instructions between - * code patching the descriptor buffer and the location being patched. - */ - jump_cmd = append_jump(desc, JUMP_TEST_ALL); - set_jump_tgt_here(desc, jump_cmd); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | - MOVE_AUX_LS); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Load ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 | - FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); - + desc = ctx->sh_desc_dec; + cnstr_shdsc_aead_null_decap(desc, &ctx->adata, ctx->authsize); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -448,12 +201,6 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "aead null dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif return 0; } @@ -465,9 +212,8 @@ static int aead_set_sh_desc(struct crypto_aead *aead) unsigned int ivsize = crypto_aead_ivsize(aead); struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - u32 geniv, moveiv; u32 ctx1_iv_off = 0; - u32 *desc; + u32 *desc, *nonce = NULL; u32 inl_mask; unsigned int data_len[2]; const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == @@ -493,8 +239,11 @@ static int aead_set_sh_desc(struct crypto_aead *aead) * RFC3686 specific: * CONTEXT1[255:128] = {NONCE, IV, COUNTER} */ - if (is_rfc3686) + if (is_rfc3686) { ctx1_iv_off = 16 + CTR_RFC3686_NONCE_SIZE; + nonce = (u32 *)((void *)ctx->key + ctx->adata.keylen_pad + + ctx->cdata.keylen - CTR_RFC3686_NONCE_SIZE); + } data_len[0] = ctx->adata.keylen_pad; data_len[1] = ctx->cdata.keylen; @@ -527,45 +276,8 @@ static int aead_set_sh_desc(struct crypto_aead *aead) /* aead_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - - /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, is_rfc3686); - - /* Class 2 operation */ - append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Read and write assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - FIFOLDST_VLF); - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - /* Class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - + cnstr_shdsc_aead_encap(desc, &ctx->cdata, &ctx->adata, ctx->authsize, + is_rfc3686, nonce, ctx1_iv_off); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -573,11 +285,6 @@ static int aead_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif skip_enc: /* @@ -605,59 +312,9 @@ skip_enc: /* aead_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - - /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, is_rfc3686); - - /* Class 2 operation */ - append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* Read and write assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - if (alg->caam.geniv) - append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize); - else - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - - if (alg->caam.geniv) { - append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - (ctx1_iv_off << LDST_OFFSET_SHIFT)); - append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | - (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ivsize); - } - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - /* Choose operation */ - if (ctr_mode) - append_operation(desc, ctx->cdata.algtype | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); - else - append_dec_op1(desc, ctx->cdata.algtype); - - /* Read and write cryptlen bytes */ - append_math_add(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - aead_append_src_dst(desc, FIFOLD_TYPE_MSG); - - /* Load ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS2 | - FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); - + cnstr_shdsc_aead_decap(desc, &ctx->cdata, &ctx->adata, ivsize, + ctx->authsize, alg->caam.geniv, is_rfc3686, + nonce, ctx1_iv_off); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -665,11 +322,6 @@ skip_enc: dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif if (!alg->caam.geniv) goto skip_givenc; @@ -699,83 +351,9 @@ skip_enc: /* aead_givencrypt shared descriptor */ desc = ctx->sh_desc_enc; - - /* Note: Context registers are saved. */ - init_sh_desc_key_aead(desc, ctx, is_rfc3686); - - if (is_rfc3686) - goto copy_iv; - - /* Generate IV */ - geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | - NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | - NFIFOENTRY_PTYPE_RND | (ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | - (ctx1_iv_off << MOVE_OFFSET_SHIFT) | - (ivsize << MOVE_LEN_SHIFT)); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - -copy_iv: - /* Copy IV to class 1 context */ - append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | - (ctx1_iv_off << MOVE_OFFSET_SHIFT) | - (ivsize << MOVE_LEN_SHIFT)); - - /* Return to encryption */ - append_operation(desc, ctx->adata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Read and write assoclen bytes */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - - /* read assoc before reading payload */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | - KEY_VLF); - - /* Copy iv from outfifo to class 2 fifo */ - moveiv = NFIFOENTRY_STYPE_OFIFO | NFIFOENTRY_DEST_CLASS2 | - NFIFOENTRY_DTYPE_MSG | (ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, moveiv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_load_imm_u32(desc, ivsize, LDST_CLASS_2_CCB | - LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM); - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - /* Class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Will write ivsize + cryptlen */ - append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Not need to reload iv */ - append_seq_fifo_load(desc, ivsize, - FIFOLD_CLASS_SKIP); - - /* Will read cryptlen */ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | - FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH); - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - + cnstr_shdsc_aead_givencap(desc, &ctx->cdata, &ctx->adata, ivsize, + ctx->authsize, is_rfc3686, nonce, + ctx1_iv_off); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -783,11 +361,6 @@ copy_iv: dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "aead givenc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif skip_givenc: return 0; @@ -808,8 +381,6 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - u32 *key_jump_cmd, *zero_payload_jump_cmd, - *zero_assoc_jump_cmd1, *zero_assoc_jump_cmd2; u32 *desc; int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - ctx->cdata.keylen; @@ -831,78 +402,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) } desc = ctx->sh_desc_enc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* skip key loading if they are loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD | JUMP_COND_SELF); - if (ctx->cdata.key_inline) - append_key_as_imm(desc, (void *)ctx->cdata.key, - ctx->cdata.keylen, ctx->cdata.keylen, - CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | - KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* if assoclen + cryptlen is ZERO, skip to ICV write */ - append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - - /* if assoclen is ZERO, skip reading the assoc data */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - - /* cryptlen = seqinlen - assoclen */ - append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG3, CAAM_CMD_SZ); - - /* if cryptlen is ZERO jump to zero-payload commands */ - zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - - /* read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - set_jump_tgt_here(desc, zero_assoc_jump_cmd1); - - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* write encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); - - /* jump the zero-payload commands */ - append_jump(desc, JUMP_TEST_ALL | 2); - - /* zero-payload commands */ - set_jump_tgt_here(desc, zero_payload_jump_cmd); - - /* read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1); - - /* There is no input data */ - set_jump_tgt_here(desc, zero_assoc_jump_cmd2); - - /* write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - + cnstr_shdsc_gcm_encap(desc, &ctx->cdata, ctx->authsize); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -910,11 +410,6 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "gcm enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif /* * Job Descriptor and Shared Descriptors @@ -929,65 +424,7 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) } desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* skip key loading if they are loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | - JUMP_TEST_ALL | JUMP_COND_SHRD | - JUMP_COND_SELF); - if (ctx->cdata.key_inline) - append_key_as_imm(desc, (void *)ctx->cdata.key, - ctx->cdata.keylen, ctx->cdata.keylen, - CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | - KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* if assoclen is ZERO, skip reading the assoc data */ - append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); - zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - - /* read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - - set_jump_tgt_here(desc, zero_assoc_jump_cmd1); - - /* cryptlen = seqoutlen - assoclen */ - append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* jump to zero-payload command if cryptlen is zero */ - zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | - JUMP_COND_MATH_Z); - - append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* store encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - /* zero-payload command */ - set_jump_tgt_here(desc, zero_payload_jump_cmd); - - /* read ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); - + cnstr_shdsc_gcm_decap(desc, &ctx->cdata, ctx->authsize); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -995,11 +432,6 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "gcm dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif return 0; } @@ -1018,7 +450,6 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - u32 *key_jump_cmd; u32 *desc; int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - ctx->cdata.keylen; @@ -1040,58 +471,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) } desc = ctx->sh_desc_enc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (ctx->cdata.key_inline) - append_key_as_imm(desc, (void *)ctx->cdata.key, - ctx->cdata.keylen, ctx->cdata.keylen, - CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | - KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - - /* Skip IV */ - append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); - - /* Will read cryptlen bytes */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); - - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - - /* cryptlen = seqoutlen - assoclen */ - append_math_sub(desc, VARSEQOUTLEN, VARSEQINLEN, REG0, CAAM_CMD_SZ); - - /* Write encrypted data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* Read payload data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - + cnstr_shdsc_rfc4106_encap(desc, &ctx->cdata, ctx->authsize); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -1099,11 +479,6 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4106 enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif /* * Job Descriptor and Shared Descriptors @@ -1118,58 +493,7 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) } desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | - JUMP_TEST_ALL | JUMP_COND_SHRD); - if (ctx->cdata.key_inline) - append_key_as_imm(desc, (void *)ctx->cdata.key, - ctx->cdata.keylen, ctx->cdata.keylen, - CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | - KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); - append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); - - /* Read assoc data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); - - /* Skip IV */ - append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); - - /* Will read cryptlen bytes */ - append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ); - - /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); - - /* Skip assoc data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); - - /* Will write cryptlen bytes */ - append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* Store payload data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* Read encrypted data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | - FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); - - /* Read ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); - + cnstr_shdsc_rfc4106_decap(desc, &ctx->cdata, ctx->authsize); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -1177,11 +501,6 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4106 dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif return 0; } @@ -1201,8 +520,6 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) { struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; - u32 *key_jump_cmd; - u32 *read_move_cmd, *write_move_cmd; u32 *desc; int rem_bytes = CAAM_DESC_BYTES_MAX - GCM_DESC_JOB_IO_LEN - ctx->cdata.keylen; @@ -1224,57 +541,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) } desc = ctx->sh_desc_enc; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - if (ctx->cdata.key_inline) - append_key_as_imm(desc, (void *)ctx->cdata.key, - ctx->cdata.keylen, ctx->cdata.keylen, - CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | - KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* assoclen + cryptlen = seqinlen */ - append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | - (0x8 << MOVE_LEN_SHIFT)); - - /* Will read assoclen + cryptlen bytes */ - append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Will write assoclen + cryptlen bytes */ - append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); - - /* Read and write assoclen + cryptlen bytes */ - aead_append_src_dst(desc, FIFOLD_TYPE_AAD); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - /* Move payload data to OFIFO */ - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); - - /* Write ICV */ - append_seq_store(desc, ctx->authsize, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT); - + cnstr_shdsc_rfc4543_encap(desc, &ctx->cdata, ctx->authsize); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -1282,11 +549,6 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4543 enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif /* * Job Descriptor and Shared Descriptors @@ -1301,62 +563,7 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) } desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Skip key loading if it is loaded due to sharing */ - key_jump_cmd = append_jump(desc, JUMP_JSL | - JUMP_TEST_ALL | JUMP_COND_SHRD); - if (ctx->cdata.key_inline) - append_key_as_imm(desc, (void *)ctx->cdata.key, - ctx->cdata.keylen, ctx->cdata.keylen, - CLASS_1 | KEY_DEST_CLASS_REG); - else - append_key(desc, ctx->cdata.key, ctx->cdata.keylen, CLASS_1 | - KEY_DEST_CLASS_REG); - set_jump_tgt_here(desc, key_jump_cmd); - - /* Class 1 operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_DECRYPT | OP_ALG_ICV_ON); - - /* assoclen + cryptlen = seqoutlen */ - append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* - * MOVE_LEN opcode is not available in all SEC HW revisions, - * thus need to do some magic, i.e. self-patch the descriptor - * buffer. - */ - read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | - (0x6 << MOVE_LEN_SHIFT)); - write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | - (0x8 << MOVE_LEN_SHIFT)); - - /* Will read assoclen + cryptlen bytes */ - append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* Will write assoclen + cryptlen bytes */ - append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); - - /* Store payload data */ - append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); - - /* In-snoop assoclen + cryptlen data */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLDST_VLF | - FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST2FLUSH1); - - set_move_tgt_here(desc, read_move_cmd); - set_move_tgt_here(desc, write_move_cmd); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - /* Move payload data to OFIFO */ - append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Read ICV */ - append_seq_fifo_load(desc, ctx->authsize, FIFOLD_CLASS_CLASS1 | - FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); - + cnstr_shdsc_rfc4543_decap(desc, &ctx->cdata, ctx->authsize); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -1364,11 +571,6 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, "rfc4543 dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif return 0; } @@ -1569,21 +771,18 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, const u8 *key, unsigned int keylen) { struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); - struct ablkcipher_tfm *crt = &ablkcipher->base.crt_ablkcipher; struct crypto_tfm *tfm = crypto_ablkcipher_tfm(ablkcipher); const char *alg_name = crypto_tfm_alg_name(tfm); struct device *jrdev = ctx->jrdev; - int ret = 0; - u32 *key_jump_cmd; + unsigned int ivsize = crypto_ablkcipher_ivsize(ablkcipher); u32 *desc; - u8 *nonce; - u32 geniv; u32 ctx1_iv_off = 0; const bool ctr_mode = ((ctx->cdata.algtype & OP_ALG_AAI_MASK) == OP_ALG_AAI_CTR_MOD128); const bool is_rfc3686 = (ctr_mode && (strstr(alg_name, "rfc3686") != NULL)); + memcpy(ctx->key, key, keylen); #ifdef DEBUG print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); @@ -1606,7 +805,6 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, keylen -= CTR_RFC3686_NONCE_SIZE; } - memcpy(ctx->key, key, keylen); ctx->key_dma = dma_map_single(jrdev, ctx->key, keylen, DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->key_dma)) { @@ -1619,48 +817,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* ablkcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, - ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); - - /* Load nonce into CONTEXT1 reg */ - if (is_rfc3686) { - nonce = (u8 *)key + keylen; - append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, - LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - - set_jump_tgt_here(desc, key_jump_cmd); - - /* Load iv */ - append_seq_load(desc, crt->ivsize, LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); - - /* Load counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - /* Load operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - + cnstr_shdsc_ablkcipher_encap(desc, &ctx->cdata, ivsize, is_rfc3686, + ctx1_iv_off); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -1668,60 +826,11 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher enc shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif + /* ablkcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, - ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); - - /* Load nonce into CONTEXT1 reg */ - if (is_rfc3686) { - nonce = (u8 *)key + keylen; - append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, - LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - - set_jump_tgt_here(desc, key_jump_cmd); - - /* load IV */ - append_seq_load(desc, crt->ivsize, LDST_SRCDST_BYTE_CONTEXT | - LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); - - /* Load counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - /* Choose operation */ - if (ctr_mode) - append_operation(desc, ctx->cdata.algtype | - OP_ALG_AS_INITFINAL | OP_ALG_DECRYPT); - else - append_dec_op1(desc, ctx->cdata.algtype); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - + cnstr_shdsc_ablkcipher_decap(desc, &ctx->cdata, ivsize, is_rfc3686, + ctx1_iv_off); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -1730,75 +839,10 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher dec shdesc@"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif /* ablkcipher_givencrypt shared descriptor */ desc = ctx->sh_desc_givenc; - - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, - ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); - - /* Load Nonce into CONTEXT1 reg */ - if (is_rfc3686) { - nonce = (u8 *)key + keylen; - append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, - LDST_CLASS_IND_CCB | - LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_OUTFIFO | - MOVE_DEST_CLASS1CTX | - (16 << MOVE_OFFSET_SHIFT) | - (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); - } - set_jump_tgt_here(desc, key_jump_cmd); - - /* Generate IV */ - geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | - NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | - NFIFOENTRY_PTYPE_RND | (crt->ivsize << NFIFOENTRY_DLEN_SHIFT); - append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | - LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); - append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); - append_move(desc, MOVE_WAITCOMP | - MOVE_SRC_INFIFO | - MOVE_DEST_CLASS1CTX | - (crt->ivsize << MOVE_LEN_SHIFT) | - (ctx1_iv_off << MOVE_OFFSET_SHIFT)); - append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); - - /* Copy generated IV to memory */ - append_seq_store(desc, crt->ivsize, - LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | - (ctx1_iv_off << LDST_OFFSET_SHIFT)); - - /* Load Counter into CONTEXT1 reg */ - if (is_rfc3686) - append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << - LDST_OFFSET_SHIFT)); - - if (ctx1_iv_off) - append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP | - (1 << JUMP_OFFSET_SHIFT)); - - /* Load operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - + cnstr_shdsc_ablkcipher_givencap(desc, &ctx->cdata, ivsize, is_rfc3686, + ctx1_iv_off); ctx->sh_desc_givenc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -1806,14 +850,8 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "ablkcipher givenc shdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, - desc_bytes(desc), 1); -#endif - return ret; + return 0; } static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, @@ -1821,8 +859,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, { struct caam_ctx *ctx = crypto_ablkcipher_ctx(ablkcipher); struct device *jrdev = ctx->jrdev; - u32 *key_jump_cmd, *desc; - __be64 sector_size = cpu_to_be64(512); + u32 *desc; if (keylen != 2 * AES_MIN_KEY_SIZE && keylen != 2 * AES_MAX_KEY_SIZE) { crypto_ablkcipher_set_flags(ablkcipher, @@ -1843,84 +880,17 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, /* xts_ablkcipher_encrypt shared descriptor */ desc = ctx->sh_desc_enc; - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 keys only */ - append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, - ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); - - /* Load sector size with index 40 bytes (0x28) */ - append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - (0x28 << LDST_OFFSET_SHIFT)); - - set_jump_tgt_here(desc, key_jump_cmd); - - /* - * create sequence for loading the sector index - * Upper 8B of IV - will be used as sector index - * Lower 8B of IV - will be discarded - */ - append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | - (0x20 << LDST_OFFSET_SHIFT)); - append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); - - /* Load operation */ - append_operation(desc, ctx->cdata.algtype | OP_ALG_AS_INITFINAL | - OP_ALG_ENCRYPT); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - + cnstr_shdsc_xts_ablkcipher_encap(desc, &ctx->cdata); ctx->sh_desc_enc_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->sh_desc_enc_dma)) { dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "xts ablkcipher enc shdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif /* xts_ablkcipher_decrypt shared descriptor */ desc = ctx->sh_desc_dec; - - init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - /* Load class1 key only */ - append_key_as_imm(desc, (void *)ctx->cdata.key, ctx->cdata.keylen, - ctx->cdata.keylen, CLASS_1 | KEY_DEST_CLASS_REG); - - /* Load sector size with index 40 bytes (0x28) */ - append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | - LDST_SRCDST_BYTE_CONTEXT | - (0x28 << LDST_OFFSET_SHIFT)); - - set_jump_tgt_here(desc, key_jump_cmd); - - /* - * create sequence for loading the sector index - * Upper 8B of IV - will be used as sector index - * Lower 8B of IV - will be discarded - */ - append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | - (0x20 << LDST_OFFSET_SHIFT)); - append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); - - /* Load operation */ - append_dec_op1(desc, ctx->cdata.algtype); - - /* Perform operation */ - ablkcipher_append_src_dst(desc); - + cnstr_shdsc_xts_ablkcipher_decap(desc, &ctx->cdata); ctx->sh_desc_dec_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->sh_desc_dec_dma)) { @@ -1929,11 +899,6 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, dev_err(jrdev, "unable to map shared descriptor\n"); return -ENOMEM; } -#ifdef DEBUG - print_hex_dump(KERN_ERR, - "xts ablkcipher dec shdesc@" __stringify(__LINE__) ": ", - DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); -#endif return 0; } diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c new file mode 100644 index 000000000000..fa2479d9da24 --- /dev/null +++ b/drivers/crypto/caam/caamalg_desc.c @@ -0,0 +1,1302 @@ +/* + * Shared descriptors for aead, ablkcipher algorithms + * + * Copyright 2016 NXP + */ + +#include "compat.h" +#include "desc_constr.h" +#include "caamalg_desc.h" + +/* + * For aead functions, read payload and write payload, + * both of which are specified in req->src and req->dst + */ +static inline void aead_append_src_dst(u32 *desc, u32 msg_type) +{ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | + KEY_VLF | msg_type | FIFOLD_TYPE_LASTBOTH); +} + +/* Set DK bit in class 1 operation if shared */ +static inline void append_dec_op1(u32 *desc, u32 type) +{ + u32 *jump_cmd, *uncond_jump_cmd; + + /* DK bit is valid only for AES */ + if ((type & OP_ALG_ALGSEL_MASK) != OP_ALG_ALGSEL_AES) { + append_operation(desc, type | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT); + return; + } + + jump_cmd = append_jump(desc, JUMP_TEST_ALL | JUMP_COND_SHRD); + append_operation(desc, type | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT); + uncond_jump_cmd = append_jump(desc, JUMP_TEST_ALL); + set_jump_tgt_here(desc, jump_cmd); + append_operation(desc, type | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_AAI_DK); + set_jump_tgt_here(desc, uncond_jump_cmd); +} + +/** + * cnstr_shdsc_aead_null_encap - IPSec ESP encapsulation shared descriptor + * (non-protocol) with no (null) encryption. + * @desc: pointer to buffer used for descriptor construction + * @adata: pointer to authentication transform definitions. Note that since a + * split key is to be used, the size of the split key itself is + * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, + * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @icvsize: integrity check value (ICV) size (truncated or full) + * + * Note: Requires an MDHA split key. + */ +void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, + unsigned int icvsize) +{ + u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + if (adata->key_inline) + append_key_as_imm(desc, (void *)adata->key, adata->keylen_pad, + adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | + KEY_ENC); + else + append_key(desc, adata->key, adata->keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + set_jump_tgt_here(desc, key_jump_cmd); + + /* assoclen + cryptlen = seqinlen */ + append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Prepare to read and write cryptlen + assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* + * MOVE_LEN opcode is not available in all SEC HW revisions, + * thus need to do some magic, i.e. self-patch the descriptor + * buffer. + */ + read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | + MOVE_DEST_MATH3 | + (0x6 << MOVE_LEN_SHIFT)); + write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | + MOVE_DEST_DESCBUF | + MOVE_WAITCOMP | + (0x8 << MOVE_LEN_SHIFT)); + + /* Class 2 operation */ + append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Read and write cryptlen bytes */ + aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); + + set_move_tgt_here(desc, read_move_cmd); + set_move_tgt_here(desc, write_move_cmd); + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | + MOVE_AUX_LS); + + /* Write ICV */ + append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "aead null enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_aead_null_encap); + +/** + * cnstr_shdsc_aead_null_decap - IPSec ESP decapsulation shared descriptor + * (non-protocol) with no (null) decryption. + * @desc: pointer to buffer used for descriptor construction + * @adata: pointer to authentication transform definitions. Note that since a + * split key is to be used, the size of the split key itself is + * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, + * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @icvsize: integrity check value (ICV) size (truncated or full) + * + * Note: Requires an MDHA split key. + */ +void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, + unsigned int icvsize) +{ + u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd, *jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + if (adata->key_inline) + append_key_as_imm(desc, (void *)adata->key, adata->keylen_pad, + adata->keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + else + append_key(desc, adata->key, adata->keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + set_jump_tgt_here(desc, key_jump_cmd); + + /* Class 2 operation */ + append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); + + /* assoclen + cryptlen = seqoutlen */ + append_math_sub(desc, REG2, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* Prepare to read and write cryptlen + assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG2, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG2, CAAM_CMD_SZ); + + /* + * MOVE_LEN opcode is not available in all SEC HW revisions, + * thus need to do some magic, i.e. self-patch the descriptor + * buffer. + */ + read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | + MOVE_DEST_MATH2 | + (0x6 << MOVE_LEN_SHIFT)); + write_move_cmd = append_move(desc, MOVE_SRC_MATH2 | + MOVE_DEST_DESCBUF | + MOVE_WAITCOMP | + (0x8 << MOVE_LEN_SHIFT)); + + /* Read and write cryptlen bytes */ + aead_append_src_dst(desc, FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); + + /* + * Insert a NOP here, since we need at least 4 instructions between + * code patching the descriptor buffer and the location being patched. + */ + jump_cmd = append_jump(desc, JUMP_TEST_ALL); + set_jump_tgt_here(desc, jump_cmd); + + set_move_tgt_here(desc, read_move_cmd); + set_move_tgt_here(desc, write_move_cmd); + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO | + MOVE_AUX_LS); + append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); + + /* Load ICV */ + append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 | + FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "aead null dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_aead_null_decap); + +static void init_sh_desc_key_aead(u32 * const desc, + struct alginfo * const cdata, + struct alginfo * const adata, + const bool is_rfc3686, u32 *nonce) +{ + u32 *key_jump_cmd; + unsigned int enckeylen = cdata->keylen; + + /* Note: Context registers are saved. */ + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + /* + * RFC3686 specific: + * | key = {AUTH_KEY, ENC_KEY, NONCE} + * | enckeylen = encryption key size + nonce size + */ + if (is_rfc3686) + enckeylen -= CTR_RFC3686_NONCE_SIZE; + + if (adata->key_inline) + append_key_as_imm(desc, (void *)adata->key, adata->keylen_pad, + adata->keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + else + append_key(desc, adata->key, adata->keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); + + if (cdata->key_inline) + append_key_as_imm(desc, (void *)cdata->key, enckeylen, + enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); + else + append_key(desc, cdata->key, enckeylen, CLASS_1 | + KEY_DEST_CLASS_REG); + + /* Load Counter into CONTEXT1 reg */ + if (is_rfc3686) { + append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, + LDST_CLASS_IND_CCB | + LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); + append_move(desc, + MOVE_SRC_OUTFIFO | + MOVE_DEST_CLASS1CTX | + (16 << MOVE_OFFSET_SHIFT) | + (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); + } + + set_jump_tgt_here(desc, key_jump_cmd); +} + +/** + * cnstr_shdsc_aead_encap - IPSec ESP encapsulation shared descriptor + * (non-protocol). + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed + * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. + * @adata: pointer to authentication transform definitions. Note that since a + * split key is to be used, the size of the split key itself is + * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, + * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @icvsize: integrity check value (ICV) size (truncated or full) + * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template + * @nonce: pointer to rfc3686 nonce + * @ctx1_iv_off: IV offset in CONTEXT1 register + * + * Note: Requires an MDHA split key. + */ +void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, + struct alginfo *adata, unsigned int icvsize, + const bool is_rfc3686, u32 *nonce, + const u32 ctx1_iv_off) +{ + /* Note: Context registers are saved. */ + init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); + + /* Class 2 operation */ + append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Read and write assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* read assoc before reading payload */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | + FIFOLDST_VLF); + + /* Load Counter into CONTEXT1 reg */ + if (is_rfc3686) + append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << + LDST_OFFSET_SHIFT)); + + /* Class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Read and write cryptlen bytes */ + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + aead_append_src_dst(desc, FIFOLD_TYPE_MSG1OUT2); + + /* Write ICV */ + append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "aead enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_aead_encap); + +/** + * cnstr_shdsc_aead_decap - IPSec ESP decapsulation shared descriptor + * (non-protocol). + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed + * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. + * @adata: pointer to authentication transform definitions. Note that since a + * split key is to be used, the size of the split key itself is + * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, + * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @ivsize: initialization vector size + * @icvsize: integrity check value (ICV) size (truncated or full) + * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template + * @nonce: pointer to rfc3686 nonce + * @ctx1_iv_off: IV offset in CONTEXT1 register + * + * Note: Requires an MDHA split key. + */ +void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, + struct alginfo *adata, unsigned int ivsize, + unsigned int icvsize, const bool geniv, + const bool is_rfc3686, u32 *nonce, + const u32 ctx1_iv_off) +{ + /* Note: Context registers are saved. */ + init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); + + /* Class 2 operation */ + append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); + + /* Read and write assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + if (geniv) + append_math_add_imm_u32(desc, VARSEQOUTLEN, REG3, IMM, ivsize); + else + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* read assoc before reading payload */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | + KEY_VLF); + + if (geniv) { + append_seq_load(desc, ivsize, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + (ctx1_iv_off << LDST_OFFSET_SHIFT)); + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_CLASS2INFIFO | + (ctx1_iv_off << MOVE_OFFSET_SHIFT) | ivsize); + } + + /* Load Counter into CONTEXT1 reg */ + if (is_rfc3686) + append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << + LDST_OFFSET_SHIFT)); + + /* Choose operation */ + if (ctx1_iv_off) + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT); + else + append_dec_op1(desc, cdata->algtype); + + /* Read and write cryptlen bytes */ + append_math_add(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + aead_append_src_dst(desc, FIFOLD_TYPE_MSG); + + /* Load ICV */ + append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS2 | + FIFOLD_TYPE_LAST2 | FIFOLD_TYPE_ICV); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "aead dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_aead_decap); + +/** + * cnstr_shdsc_aead_givencap - IPSec ESP encapsulation shared descriptor + * (non-protocol) with HW-generated initialization + * vector. + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed + * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. + * @adata: pointer to authentication transform definitions. Note that since a + * split key is to be used, the size of the split key itself is + * specified. Valid algorithm values - one of OP_ALG_ALGSEL_{MD5, SHA1, + * SHA224, SHA256, SHA384, SHA512} ANDed with OP_ALG_AAI_HMAC_PRECOMP. + * @ivsize: initialization vector size + * @icvsize: integrity check value (ICV) size (truncated or full) + * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template + * @nonce: pointer to rfc3686 nonce + * @ctx1_iv_off: IV offset in CONTEXT1 register + * + * Note: Requires an MDHA split key. + */ +void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, + struct alginfo *adata, unsigned int ivsize, + unsigned int icvsize, const bool is_rfc3686, + u32 *nonce, const u32 ctx1_iv_off) +{ + u32 geniv, moveiv; + + /* Note: Context registers are saved. */ + init_sh_desc_key_aead(desc, cdata, adata, is_rfc3686, nonce); + + if (is_rfc3686) + goto copy_iv; + + /* Generate IV */ + geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | + NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | + NFIFOENTRY_PTYPE_RND | (ivsize << NFIFOENTRY_DLEN_SHIFT); + append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | + LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + append_move(desc, MOVE_WAITCOMP | + MOVE_SRC_INFIFO | MOVE_DEST_CLASS1CTX | + (ctx1_iv_off << MOVE_OFFSET_SHIFT) | + (ivsize << MOVE_LEN_SHIFT)); + append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); + +copy_iv: + /* Copy IV to class 1 context */ + append_move(desc, MOVE_SRC_CLASS1CTX | MOVE_DEST_OUTFIFO | + (ctx1_iv_off << MOVE_OFFSET_SHIFT) | + (ivsize << MOVE_LEN_SHIFT)); + + /* Return to encryption */ + append_operation(desc, adata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Read and write assoclen bytes */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* read assoc before reading payload */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_MSG | + KEY_VLF); + + /* Copy iv from outfifo to class 2 fifo */ + moveiv = NFIFOENTRY_STYPE_OFIFO | NFIFOENTRY_DEST_CLASS2 | + NFIFOENTRY_DTYPE_MSG | (ivsize << NFIFOENTRY_DLEN_SHIFT); + append_load_imm_u32(desc, moveiv, LDST_CLASS_IND_CCB | + LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); + append_load_imm_u32(desc, ivsize, LDST_CLASS_2_CCB | + LDST_SRCDST_WORD_DATASZ_REG | LDST_IMM); + + /* Load Counter into CONTEXT1 reg */ + if (is_rfc3686) + append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << + LDST_OFFSET_SHIFT)); + + /* Class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Will write ivsize + cryptlen */ + append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Not need to reload iv */ + append_seq_fifo_load(desc, ivsize, + FIFOLD_CLASS_SKIP); + + /* Will read cryptlen */ + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | KEY_VLF | + FIFOLD_TYPE_MSG1OUT2 | FIFOLD_TYPE_LASTBOTH); + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); + + /* Write ICV */ + append_seq_store(desc, icvsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "aead givenc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_aead_givencap); + +/** + * cnstr_shdsc_gcm_encap - gcm encapsulation shared descriptor + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. + * @icvsize: integrity check value (ICV) size (truncated or full) + */ +void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize) +{ + u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1, + *zero_assoc_jump_cmd2; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* skip key loading if they are loaded due to sharing */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD | JUMP_COND_SELF); + if (cdata->key_inline) + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + else + append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + KEY_DEST_CLASS_REG); + set_jump_tgt_here(desc, key_jump_cmd); + + /* class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* if assoclen + cryptlen is ZERO, skip to ICV write */ + append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + zero_assoc_jump_cmd2 = append_jump(desc, JUMP_TEST_ALL | + JUMP_COND_MATH_Z); + + /* if assoclen is ZERO, skip reading the assoc data */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | + JUMP_COND_MATH_Z); + + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* cryptlen = seqinlen - assoclen */ + append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG3, CAAM_CMD_SZ); + + /* if cryptlen is ZERO jump to zero-payload commands */ + zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | + JUMP_COND_MATH_Z); + + /* read assoc data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); + set_jump_tgt_here(desc, zero_assoc_jump_cmd1); + + append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* write encrypted data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + + /* read payload data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); + + /* jump the zero-payload commands */ + append_jump(desc, JUMP_TEST_ALL | 2); + + /* zero-payload commands */ + set_jump_tgt_here(desc, zero_payload_jump_cmd); + + /* read assoc data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST1); + + /* There is no input data */ + set_jump_tgt_here(desc, zero_assoc_jump_cmd2); + + /* write ICV */ + append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "gcm enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_gcm_encap); + +/** + * cnstr_shdsc_gcm_decap - gcm decapsulation shared descriptor + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. + * @icvsize: integrity check value (ICV) size (truncated or full) + */ +void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize) +{ + u32 *key_jump_cmd, *zero_payload_jump_cmd, *zero_assoc_jump_cmd1; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* skip key loading if they are loaded due to sharing */ + key_jump_cmd = append_jump(desc, JUMP_JSL | + JUMP_TEST_ALL | JUMP_COND_SHRD | + JUMP_COND_SELF); + if (cdata->key_inline) + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + else + append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + KEY_DEST_CLASS_REG); + set_jump_tgt_here(desc, key_jump_cmd); + + /* class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); + + /* if assoclen is ZERO, skip reading the assoc data */ + append_math_add(desc, VARSEQINLEN, ZERO, REG3, CAAM_CMD_SZ); + zero_assoc_jump_cmd1 = append_jump(desc, JUMP_TEST_ALL | + JUMP_COND_MATH_Z); + + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* read assoc data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); + + set_jump_tgt_here(desc, zero_assoc_jump_cmd1); + + /* cryptlen = seqoutlen - assoclen */ + append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* jump to zero-payload command if cryptlen is zero */ + zero_payload_jump_cmd = append_jump(desc, JUMP_TEST_ALL | + JUMP_COND_MATH_Z); + + append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* store encrypted data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + + /* read payload data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); + + /* zero-payload command */ + set_jump_tgt_here(desc, zero_payload_jump_cmd); + + /* read ICV */ + append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | + FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, "gcm dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_gcm_decap); + +/** + * cnstr_shdsc_rfc4106_encap - IPSec ESP gcm encapsulation shared descriptor + * (non-protocol). + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. + * @icvsize: integrity check value (ICV) size (truncated or full) + */ +void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize) +{ + u32 *key_jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Skip key loading if it is loaded due to sharing */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + if (cdata->key_inline) + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + else + append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + KEY_DEST_CLASS_REG); + set_jump_tgt_here(desc, key_jump_cmd); + + /* Class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* Read assoc data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); + + /* Skip IV */ + append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); + + /* Will read cryptlen bytes */ + append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); + + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* cryptlen = seqoutlen - assoclen */ + append_math_sub(desc, VARSEQOUTLEN, VARSEQINLEN, REG0, CAAM_CMD_SZ); + + /* Write encrypted data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + + /* Read payload data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); + + /* Write ICV */ + append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "rfc4106 enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_rfc4106_encap); + +/** + * cnstr_shdsc_rfc4106_decap - IPSec ESP gcm decapsulation shared descriptor + * (non-protocol). + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. + * @icvsize: integrity check value (ICV) size (truncated or full) + */ +void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize) +{ + u32 *key_jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Skip key loading if it is loaded due to sharing */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + if (cdata->key_inline) + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | + KEY_DEST_CLASS_REG); + else + append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + KEY_DEST_CLASS_REG); + set_jump_tgt_here(desc, key_jump_cmd); + + /* Class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); + + append_math_sub_imm_u32(desc, VARSEQINLEN, REG3, IMM, 8); + append_math_add(desc, VARSEQOUTLEN, ZERO, REG3, CAAM_CMD_SZ); + + /* Read assoc data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_FLUSH1); + + /* Skip IV */ + append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); + + /* Will read cryptlen bytes */ + append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG3, CAAM_CMD_SZ); + + /* Workaround for erratum A-005473 (simultaneous SEQ FIFO skips) */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLD_TYPE_MSG); + + /* Skip assoc data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_SKIP | FIFOLDST_VLF); + + /* Will write cryptlen bytes */ + append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* Store payload data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + + /* Read encrypted data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | FIFOLDST_VLF | + FIFOLD_TYPE_MSG | FIFOLD_TYPE_FLUSH1); + + /* Read ICV */ + append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | + FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "rfc4106 dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_rfc4106_decap); + +/** + * cnstr_shdsc_rfc4543_encap - IPSec ESP gmac encapsulation shared descriptor + * (non-protocol). + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. + * @icvsize: integrity check value (ICV) size (truncated or full) + */ +void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize) +{ + u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Skip key loading if it is loaded due to sharing */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + if (cdata->key_inline) + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + else + append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + KEY_DEST_CLASS_REG); + set_jump_tgt_here(desc, key_jump_cmd); + + /* Class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* assoclen + cryptlen = seqinlen */ + append_math_sub(desc, REG3, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* + * MOVE_LEN opcode is not available in all SEC HW revisions, + * thus need to do some magic, i.e. self-patch the descriptor + * buffer. + */ + read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | + (0x6 << MOVE_LEN_SHIFT)); + write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | + (0x8 << MOVE_LEN_SHIFT)); + + /* Will read assoclen + cryptlen bytes */ + append_math_sub(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Will write assoclen + cryptlen bytes */ + append_math_sub(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + + /* Read and write assoclen + cryptlen bytes */ + aead_append_src_dst(desc, FIFOLD_TYPE_AAD); + + set_move_tgt_here(desc, read_move_cmd); + set_move_tgt_here(desc, write_move_cmd); + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + /* Move payload data to OFIFO */ + append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); + + /* Write ICV */ + append_seq_store(desc, icvsize, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "rfc4543 enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_rfc4543_encap); + +/** + * cnstr_shdsc_rfc4543_decap - IPSec ESP gmac decapsulation shared descriptor + * (non-protocol). + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_GCM. + * @icvsize: integrity check value (ICV) size (truncated or full) + */ +void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize) +{ + u32 *key_jump_cmd, *read_move_cmd, *write_move_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL); + + /* Skip key loading if it is loaded due to sharing */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + if (cdata->key_inline) + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + else + append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + KEY_DEST_CLASS_REG); + set_jump_tgt_here(desc, key_jump_cmd); + + /* Class 1 operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT | OP_ALG_ICV_ON); + + /* assoclen + cryptlen = seqoutlen */ + append_math_sub(desc, REG3, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* + * MOVE_LEN opcode is not available in all SEC HW revisions, + * thus need to do some magic, i.e. self-patch the descriptor + * buffer. + */ + read_move_cmd = append_move(desc, MOVE_SRC_DESCBUF | MOVE_DEST_MATH3 | + (0x6 << MOVE_LEN_SHIFT)); + write_move_cmd = append_move(desc, MOVE_SRC_MATH3 | MOVE_DEST_DESCBUF | + (0x8 << MOVE_LEN_SHIFT)); + + /* Will read assoclen + cryptlen bytes */ + append_math_sub(desc, VARSEQINLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* Will write assoclen + cryptlen bytes */ + append_math_sub(desc, VARSEQOUTLEN, SEQOUTLEN, REG0, CAAM_CMD_SZ); + + /* Store payload data */ + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | FIFOLDST_VLF); + + /* In-snoop assoclen + cryptlen data */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_BOTH | FIFOLDST_VLF | + FIFOLD_TYPE_AAD | FIFOLD_TYPE_LAST2FLUSH1); + + set_move_tgt_here(desc, read_move_cmd); + set_move_tgt_here(desc, write_move_cmd); + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + /* Move payload data to OFIFO */ + append_move(desc, MOVE_SRC_INFIFO_CL | MOVE_DEST_OUTFIFO); + append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); + + /* Read ICV */ + append_seq_fifo_load(desc, icvsize, FIFOLD_CLASS_CLASS1 | + FIFOLD_TYPE_ICV | FIFOLD_TYPE_LAST1); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "rfc4543 dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_rfc4543_decap); + +/* + * For ablkcipher encrypt and decrypt, read from req->src and + * write to req->dst + */ +static inline void ablkcipher_append_src_dst(u32 *desc) +{ + append_math_add(desc, VARSEQOUTLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS1 | + KEY_VLF | FIFOLD_TYPE_MSG | FIFOLD_TYPE_LAST1); + append_seq_fifo_store(desc, 0, FIFOST_TYPE_MESSAGE_DATA | KEY_VLF); +} + +/** + * cnstr_shdsc_ablkcipher_encap - ablkcipher encapsulation shared descriptor + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed + * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. + * @ivsize: initialization vector size + * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template + * @ctx1_iv_off: IV offset in CONTEXT1 register + */ +void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off) +{ + u32 *key_jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + /* Load class1 key only */ + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + + /* Load nonce into CONTEXT1 reg */ + if (is_rfc3686) { + u8 *nonce = (u8 *)cdata->key + cdata->keylen; + + append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, + LDST_CLASS_IND_CCB | + LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); + append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | + MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) | + (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); + } + + set_jump_tgt_here(desc, key_jump_cmd); + + /* Load iv */ + append_seq_load(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); + + /* Load counter into CONTEXT1 reg */ + if (is_rfc3686) + append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << + LDST_OFFSET_SHIFT)); + + /* Load operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Perform operation */ + ablkcipher_append_src_dst(desc); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "ablkcipher enc shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_encap); + +/** + * cnstr_shdsc_ablkcipher_decap - ablkcipher decapsulation shared descriptor + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed + * with OP_ALG_AAI_CBC or OP_ALG_AAI_CTR_MOD128. + * @ivsize: initialization vector size + * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template + * @ctx1_iv_off: IV offset in CONTEXT1 register + */ +void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off) +{ + u32 *key_jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + /* Load class1 key only */ + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + + /* Load nonce into CONTEXT1 reg */ + if (is_rfc3686) { + u8 *nonce = (u8 *)cdata->key + cdata->keylen; + + append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, + LDST_CLASS_IND_CCB | + LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); + append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | + MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) | + (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); + } + + set_jump_tgt_here(desc, key_jump_cmd); + + /* load IV */ + append_seq_load(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); + + /* Load counter into CONTEXT1 reg */ + if (is_rfc3686) + append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << + LDST_OFFSET_SHIFT)); + + /* Choose operation */ + if (ctx1_iv_off) + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_DECRYPT); + else + append_dec_op1(desc, cdata->algtype); + + /* Perform operation */ + ablkcipher_append_src_dst(desc); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "ablkcipher dec shdesc@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_decap); + +/** + * cnstr_shdsc_ablkcipher_givencap - ablkcipher encapsulation shared descriptor + * with HW-generated initialization vector. + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - one of OP_ALG_ALGSEL_{AES, DES, 3DES} ANDed + * with OP_ALG_AAI_CBC. + * @ivsize: initialization vector size + * @is_rfc3686: true when ctr(aes) is wrapped by rfc3686 template + * @ctx1_iv_off: IV offset in CONTEXT1 register + */ +void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off) +{ + u32 *key_jump_cmd, geniv; + + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + /* Load class1 key only */ + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + + /* Load Nonce into CONTEXT1 reg */ + if (is_rfc3686) { + u8 *nonce = (u8 *)cdata->key + cdata->keylen; + + append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, + LDST_CLASS_IND_CCB | + LDST_SRCDST_BYTE_OUTFIFO | LDST_IMM); + append_move(desc, MOVE_WAITCOMP | MOVE_SRC_OUTFIFO | + MOVE_DEST_CLASS1CTX | (16 << MOVE_OFFSET_SHIFT) | + (CTR_RFC3686_NONCE_SIZE << MOVE_LEN_SHIFT)); + } + set_jump_tgt_here(desc, key_jump_cmd); + + /* Generate IV */ + geniv = NFIFOENTRY_STYPE_PAD | NFIFOENTRY_DEST_DECO | + NFIFOENTRY_DTYPE_MSG | NFIFOENTRY_LC1 | NFIFOENTRY_PTYPE_RND | + (ivsize << NFIFOENTRY_DLEN_SHIFT); + append_load_imm_u32(desc, geniv, LDST_CLASS_IND_CCB | + LDST_SRCDST_WORD_INFO_FIFO | LDST_IMM); + append_cmd(desc, CMD_LOAD | DISABLE_AUTO_INFO_FIFO); + append_move(desc, MOVE_WAITCOMP | MOVE_SRC_INFIFO | + MOVE_DEST_CLASS1CTX | (ivsize << MOVE_LEN_SHIFT) | + (ctx1_iv_off << MOVE_OFFSET_SHIFT)); + append_cmd(desc, CMD_LOAD | ENABLE_AUTO_INFO_FIFO); + + /* Copy generated IV to memory */ + append_seq_store(desc, ivsize, LDST_SRCDST_BYTE_CONTEXT | + LDST_CLASS_1_CCB | (ctx1_iv_off << LDST_OFFSET_SHIFT)); + + /* Load Counter into CONTEXT1 reg */ + if (is_rfc3686) + append_load_imm_be32(desc, 1, LDST_IMM | LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + ((ctx1_iv_off + CTR_RFC3686_IV_SIZE) << + LDST_OFFSET_SHIFT)); + + if (ctx1_iv_off) + append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_NCP | + (1 << JUMP_OFFSET_SHIFT)); + + /* Load operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Perform operation */ + ablkcipher_append_src_dst(desc); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "ablkcipher givenc shdesc@" __stringify(__LINE__) ": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_ablkcipher_givencap); + +/** + * cnstr_shdsc_xts_ablkcipher_encap - xts ablkcipher encapsulation shared + * descriptor + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS. + */ +void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata) +{ + __be64 sector_size = cpu_to_be64(512); + u32 *key_jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + /* Load class1 keys only */ + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + + /* Load sector size with index 40 bytes (0x28) */ + append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + (0x28 << LDST_OFFSET_SHIFT)); + + set_jump_tgt_here(desc, key_jump_cmd); + + /* + * create sequence for loading the sector index + * Upper 8B of IV - will be used as sector index + * Lower 8B of IV - will be discarded + */ + append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | + (0x20 << LDST_OFFSET_SHIFT)); + append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); + + /* Load operation */ + append_operation(desc, cdata->algtype | OP_ALG_AS_INITFINAL | + OP_ALG_ENCRYPT); + + /* Perform operation */ + ablkcipher_append_src_dst(desc); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "xts ablkcipher enc shdesc@" __stringify(__LINE__) ": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_encap); + +/** + * cnstr_shdsc_xts_ablkcipher_decap - xts ablkcipher decapsulation shared + * descriptor + * @desc: pointer to buffer used for descriptor construction + * @cdata: pointer to block cipher transform definitions + * Valid algorithm values - OP_ALG_ALGSEL_AES ANDed with OP_ALG_AAI_XTS. + */ +void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata) +{ + __be64 sector_size = cpu_to_be64(512); + u32 *key_jump_cmd; + + init_sh_desc(desc, HDR_SHARE_SERIAL | HDR_SAVECTX); + /* Skip if already shared */ + key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); + + /* Load class1 key only */ + append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); + + /* Load sector size with index 40 bytes (0x28) */ + append_load_as_imm(desc, (void *)§or_size, 8, LDST_CLASS_1_CCB | + LDST_SRCDST_BYTE_CONTEXT | + (0x28 << LDST_OFFSET_SHIFT)); + + set_jump_tgt_here(desc, key_jump_cmd); + + /* + * create sequence for loading the sector index + * Upper 8B of IV - will be used as sector index + * Lower 8B of IV - will be discarded + */ + append_seq_load(desc, 8, LDST_SRCDST_BYTE_CONTEXT | LDST_CLASS_1_CCB | + (0x20 << LDST_OFFSET_SHIFT)); + append_seq_fifo_load(desc, 8, FIFOLD_CLASS_SKIP); + + /* Load operation */ + append_dec_op1(desc, cdata->algtype); + + /* Perform operation */ + ablkcipher_append_src_dst(desc); + +#ifdef DEBUG + print_hex_dump(KERN_ERR, + "xts ablkcipher dec shdesc@" __stringify(__LINE__) ": ", + DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc), 1); +#endif +} +EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_decap); diff --git a/drivers/crypto/caam/caamalg_desc.h b/drivers/crypto/caam/caamalg_desc.h new file mode 100644 index 000000000000..95551737333a --- /dev/null +++ b/drivers/crypto/caam/caamalg_desc.h @@ -0,0 +1,97 @@ +/* + * Shared descriptors for aead, ablkcipher algorithms + * + * Copyright 2016 NXP + */ + +#ifndef _CAAMALG_DESC_H_ +#define _CAAMALG_DESC_H_ + +/* length of descriptors text */ +#define DESC_AEAD_BASE (4 * CAAM_CMD_SZ) +#define DESC_AEAD_ENC_LEN (DESC_AEAD_BASE + 11 * CAAM_CMD_SZ) +#define DESC_AEAD_DEC_LEN (DESC_AEAD_BASE + 15 * CAAM_CMD_SZ) +#define DESC_AEAD_GIVENC_LEN (DESC_AEAD_ENC_LEN + 7 * CAAM_CMD_SZ) + +/* Note: Nonce is counted in cdata.keylen */ +#define DESC_AEAD_CTR_RFC3686_LEN (4 * CAAM_CMD_SZ) + +#define DESC_AEAD_NULL_BASE (3 * CAAM_CMD_SZ) +#define DESC_AEAD_NULL_ENC_LEN (DESC_AEAD_NULL_BASE + 11 * CAAM_CMD_SZ) +#define DESC_AEAD_NULL_DEC_LEN (DESC_AEAD_NULL_BASE + 13 * CAAM_CMD_SZ) + +#define DESC_GCM_BASE (3 * CAAM_CMD_SZ) +#define DESC_GCM_ENC_LEN (DESC_GCM_BASE + 16 * CAAM_CMD_SZ) +#define DESC_GCM_DEC_LEN (DESC_GCM_BASE + 12 * CAAM_CMD_SZ) + +#define DESC_RFC4106_BASE (3 * CAAM_CMD_SZ) +#define DESC_RFC4106_ENC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) +#define DESC_RFC4106_DEC_LEN (DESC_RFC4106_BASE + 13 * CAAM_CMD_SZ) + +#define DESC_RFC4543_BASE (3 * CAAM_CMD_SZ) +#define DESC_RFC4543_ENC_LEN (DESC_RFC4543_BASE + 11 * CAAM_CMD_SZ) +#define DESC_RFC4543_DEC_LEN (DESC_RFC4543_BASE + 12 * CAAM_CMD_SZ) + +#define DESC_ABLKCIPHER_BASE (3 * CAAM_CMD_SZ) +#define DESC_ABLKCIPHER_ENC_LEN (DESC_ABLKCIPHER_BASE + \ + 20 * CAAM_CMD_SZ) +#define DESC_ABLKCIPHER_DEC_LEN (DESC_ABLKCIPHER_BASE + \ + 15 * CAAM_CMD_SZ) + +void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, + unsigned int icvsize); + +void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, + unsigned int icvsize); + +void cnstr_shdsc_aead_encap(u32 * const desc, struct alginfo *cdata, + struct alginfo *adata, unsigned int icvsize, + const bool is_rfc3686, u32 *nonce, + const u32 ctx1_iv_off); + +void cnstr_shdsc_aead_decap(u32 * const desc, struct alginfo *cdata, + struct alginfo *adata, unsigned int ivsize, + unsigned int icvsize, const bool geniv, + const bool is_rfc3686, u32 *nonce, + const u32 ctx1_iv_off); + +void cnstr_shdsc_aead_givencap(u32 * const desc, struct alginfo *cdata, + struct alginfo *adata, unsigned int ivsize, + unsigned int icvsize, const bool is_rfc3686, + u32 *nonce, const u32 ctx1_iv_off); + +void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize); + +void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize); + +void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize); + +void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize); + +void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize); + +void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, + unsigned int icvsize); + +void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off); + +void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off); + +void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, + unsigned int ivsize, const bool is_rfc3686, + const u32 ctx1_iv_off); + +void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata); + +void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata); + +#endif /* _CAAMALG_DESC_H_ */ -- cgit v1.2.3 From 6655cb8e56691fab3291c83d2afd6f1fd0776ecf Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:10 +0200 Subject: crypto: caam - consolidate split key length computation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move split key length and padded length computation from caamalg.c and caamhash.c to key_gen.c. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 24 +++------------------ drivers/crypto/caam/caamhash.c | 24 ++------------------- drivers/crypto/caam/key_gen.c | 47 +++++++++++++++++++++++++++++++++++++++++- drivers/crypto/caam/key_gen.h | 3 ++- 4 files changed, 53 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 78b0b7c17205..767ffaea9649 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -586,18 +586,9 @@ static int rfc4543_setauthsize(struct crypto_aead *authenc, return 0; } -static u32 gen_split_aead_key(struct caam_ctx *ctx, const u8 *key_in, - u32 authkeylen) -{ - return gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key_in, - authkeylen); -} - static int aead_setkey(struct crypto_aead *aead, const u8 *key, unsigned int keylen) { - /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ - static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; struct caam_ctx *ctx = crypto_aead_ctx(aead); struct device *jrdev = ctx->jrdev; struct crypto_authenc_keys keys; @@ -606,26 +597,17 @@ static int aead_setkey(struct crypto_aead *aead, if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) goto badkey; - /* Pick class 2 key length from algorithm submask */ - ctx->adata.keylen = mdpadlen[(ctx->adata.algtype & - OP_ALG_ALGSEL_SUBMASK) >> - OP_ALG_ALGSEL_SHIFT] * 2; - ctx->adata.keylen_pad = ALIGN(ctx->adata.keylen, 16); - - if (ctx->adata.keylen_pad + keys.enckeylen > CAAM_MAX_KEY_SIZE) - goto badkey; - #ifdef DEBUG printk(KERN_ERR "keylen %d enckeylen %d authkeylen %d\n", keys.authkeylen + keys.enckeylen, keys.enckeylen, keys.authkeylen); - printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", - ctx->adata.keylen, ctx->adata.keylen_pad); print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); #endif - ret = gen_split_aead_key(ctx, keys.authkey, keys.authkeylen); + ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, keys.authkey, + keys.authkeylen, CAAM_MAX_KEY_SIZE - + keys.enckeylen); if (ret) { goto badkey; } diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index d3f0ae16a73b..505007d0277c 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -398,12 +398,6 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) return 0; } -static int gen_split_hash_key(struct caam_hash_ctx *ctx, const u8 *key_in, - u32 keylen) -{ - return gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key_in, keylen); -} - /* Digest hash size if it is too large */ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, u32 *keylen, u8 *key_out, u32 digestsize) @@ -483,8 +477,6 @@ static int hash_digest_key(struct caam_hash_ctx *ctx, const u8 *key_in, static int ahash_setkey(struct crypto_ahash *ahash, const u8 *key, unsigned int keylen) { - /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ - static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); struct device *jrdev = ctx->jrdev; int blocksize = crypto_tfm_alg_blocksize(&ahash->base); @@ -509,20 +501,8 @@ static int ahash_setkey(struct crypto_ahash *ahash, key = hashed_key; } - /* Pick class 2 key length from algorithm submask */ - ctx->adata.keylen = mdpadlen[(ctx->adata.algtype & - OP_ALG_ALGSEL_SUBMASK) >> - OP_ALG_ALGSEL_SHIFT] * 2; - ctx->adata.keylen_pad = ALIGN(ctx->adata.keylen, 16); - -#ifdef DEBUG - printk(KERN_ERR "split_key_len %d split_key_pad_len %d\n", - ctx->adata.keylen, ctx->adata.keylen_pad); - print_hex_dump(KERN_ERR, "key in @"__stringify(__LINE__)": ", - DUMP_PREFIX_ADDRESS, 16, 4, key, keylen, 1); -#endif - - ret = gen_split_hash_key(ctx, key, keylen); + ret = gen_split_key(ctx->jrdev, ctx->key, &ctx->adata, key, keylen, + CAAM_MAX_HASH_KEY_SIZE); if (ret) goto bad_free_key; diff --git a/drivers/crypto/caam/key_gen.c b/drivers/crypto/caam/key_gen.c index 621199a02f2e..1bb2816a9b4d 100644 --- a/drivers/crypto/caam/key_gen.c +++ b/drivers/crypto/caam/key_gen.c @@ -10,6 +10,36 @@ #include "desc_constr.h" #include "key_gen.h" +/** + * split_key_len - Compute MDHA split key length for a given algorithm + * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, + * SHA224, SHA384, SHA512. + * + * Return: MDHA split key length + */ +static inline u32 split_key_len(u32 hash) +{ + /* Sizes for MDHA pads (*not* keys): MD5, SHA1, 224, 256, 384, 512 */ + static const u8 mdpadlen[] = { 16, 20, 32, 32, 64, 64 }; + u32 idx; + + idx = (hash & OP_ALG_ALGSEL_SUBMASK) >> OP_ALG_ALGSEL_SHIFT; + + return (u32)(mdpadlen[idx] * 2); +} + +/** + * split_key_pad_len - Compute MDHA split key pad length for a given algorithm + * @hash: Hashing algorithm selection, one of OP_ALG_ALGSEL_* - MD5, SHA1, + * SHA224, SHA384, SHA512. + * + * Return: MDHA split key pad length + */ +static inline u32 split_key_pad_len(u32 hash) +{ + return ALIGN(split_key_len(hash), 16); +} + void split_key_done(struct device *dev, u32 *desc, u32 err, void *context) { @@ -42,13 +72,28 @@ Split key generation----------------------------------------------- @0xffe04000 */ int gen_split_key(struct device *jrdev, u8 *key_out, - struct alginfo * const adata, const u8 *key_in, u32 keylen) + struct alginfo * const adata, const u8 *key_in, u32 keylen, + int max_keylen) { u32 *desc; struct split_key_result result; dma_addr_t dma_addr_in, dma_addr_out; int ret = -ENOMEM; + adata->keylen = split_key_len(adata->algtype & OP_ALG_ALGSEL_MASK); + adata->keylen_pad = split_key_pad_len(adata->algtype & + OP_ALG_ALGSEL_MASK); + +#ifdef DEBUG + dev_err(jrdev, "split keylen %d split keylen padded %d\n", + adata->keylen, adata->keylen_pad); + print_hex_dump(KERN_ERR, "ctx.key@" __stringify(__LINE__)": ", + DUMP_PREFIX_ADDRESS, 16, 4, key_in, keylen, 1); +#endif + + if (adata->keylen_pad > max_keylen) + return -EINVAL; + desc = kmalloc(CAAM_CMD_SZ * 6 + CAAM_PTR_SZ * 2, GFP_KERNEL | GFP_DMA); if (!desc) { dev_err(jrdev, "unable to allocate key input memory\n"); diff --git a/drivers/crypto/caam/key_gen.h b/drivers/crypto/caam/key_gen.h index e87483c6057b..4628f389eb64 100644 --- a/drivers/crypto/caam/key_gen.h +++ b/drivers/crypto/caam/key_gen.h @@ -13,4 +13,5 @@ struct split_key_result { void split_key_done(struct device *dev, u32 *desc, u32 err, void *context); int gen_split_key(struct device *jrdev, u8 *key_out, - struct alginfo * const adata, const u8 *key_in, u32 keylen); + struct alginfo * const adata, const u8 *key_in, u32 keylen, + int max_keylen); -- cgit v1.2.3 From 1a0166f19974d8eb262ff03e621d19eb5894230d Mon Sep 17 00:00:00 2001 From: Horia Geantă Date: Tue, 22 Nov 2016 15:44:11 +0200 Subject: crypto: caam - refactor ahash shared descriptor generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move ahash shared descriptor generation into a single function. Currently there is no plan to support ahash on any other interface besides the Job Ring, thus for now the functionality is not exported. Signed-off-by: Horia Geantă Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamhash.c | 130 ++++++++++++----------------------------- 1 file changed, 36 insertions(+), 94 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamhash.c b/drivers/crypto/caam/caamhash.c index 505007d0277c..e58639ea53b1 100644 --- a/drivers/crypto/caam/caamhash.c +++ b/drivers/crypto/caam/caamhash.c @@ -217,86 +217,54 @@ static inline int ctx_map_to_sec4_sg(u32 *desc, struct device *jrdev, return 0; } -/* Common shared descriptor commands */ -static inline void append_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) -{ - append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad, - ctx->adata.keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | - KEY_ENC); -} - -/* Append key if it has been set */ -static inline void init_sh_desc_key_ahash(u32 *desc, struct caam_hash_ctx *ctx) -{ - u32 *key_jump_cmd; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - if (ctx->adata.keylen) { - /* Skip if already shared */ - key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | - JUMP_COND_SHRD); - - append_key_ahash(desc, ctx); - - set_jump_tgt_here(desc, key_jump_cmd); - } -} - /* - * For ahash read data from seqin following state->caam_ctx, - * and write resulting class2 context to seqout, which may be state->caam_ctx - * or req->result + * For ahash update, final and finup (import_ctx = true) + * import context, read and write to seqout + * For ahash firsts and digest (import_ctx = false) + * read and write to seqout */ -static inline void ahash_append_load_str(u32 *desc, int digestsize) +static inline void ahash_gen_sh_desc(u32 *desc, u32 state, int digestsize, + struct caam_hash_ctx *ctx, bool import_ctx) { - /* Calculate remaining bytes to read */ - append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + u32 op = ctx->adata.algtype; + u32 *skip_key_load; - /* Read remaining bytes */ - append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | - FIFOLD_TYPE_MSG | KEY_VLF); - - /* Store class2 context bytes */ - append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); -} + init_sh_desc(desc, HDR_SHARE_SERIAL); -/* - * For ahash update, final and finup, import context, read and write to seqout - */ -static inline void ahash_ctx_data_to_out(u32 *desc, u32 op, u32 state, - int digestsize, - struct caam_hash_ctx *ctx) -{ - init_sh_desc_key_ahash(desc, ctx); + /* Append key if it has been set; ahash update excluded */ + if ((state != OP_ALG_AS_UPDATE) && (ctx->adata.keylen)) { + /* Skip key loading if already shared */ + skip_key_load = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | + JUMP_COND_SHRD); - /* Import context from software */ - append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); + append_key_as_imm(desc, ctx->key, ctx->adata.keylen_pad, + ctx->adata.keylen, CLASS_2 | + KEY_DEST_MDHA_SPLIT | KEY_ENC); - /* Class 2 operation */ - append_operation(desc, op | state | OP_ALG_ENCRYPT); + set_jump_tgt_here(desc, skip_key_load); - /* - * Load from buf and/or src and write to req->result or state->context - */ - ahash_append_load_str(desc, digestsize); -} + op |= OP_ALG_AAI_HMAC_PRECOMP; + } -/* For ahash firsts and digest, read and write to seqout */ -static inline void ahash_data_to_out(u32 *desc, u32 op, u32 state, - int digestsize, struct caam_hash_ctx *ctx) -{ - init_sh_desc_key_ahash(desc, ctx); + /* If needed, import context from software */ + if (import_ctx) + append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); /* Class 2 operation */ append_operation(desc, op | state | OP_ALG_ENCRYPT); /* * Load from buf and/or src and write to req->result or state->context + * Calculate remaining bytes to read */ - ahash_append_load_str(desc, digestsize); + append_math_add(desc, VARSEQINLEN, SEQINLEN, REG0, CAAM_CMD_SZ); + /* Read remaining bytes */ + append_seq_fifo_load(desc, 0, FIFOLD_CLASS_CLASS2 | FIFOLD_TYPE_LAST2 | + FIFOLD_TYPE_MSG | KEY_VLF); + /* Store class2 context bytes */ + append_seq_store(desc, digestsize, LDST_CLASS_2_CCB | + LDST_SRCDST_BYTE_CONTEXT); } static int ahash_set_sh_desc(struct crypto_ahash *ahash) @@ -304,28 +272,11 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) struct caam_hash_ctx *ctx = crypto_ahash_ctx(ahash); int digestsize = crypto_ahash_digestsize(ahash); struct device *jrdev = ctx->jrdev; - u32 have_key = 0; u32 *desc; - if (ctx->adata.keylen) - have_key = OP_ALG_AAI_HMAC_PRECOMP; - /* ahash_update shared descriptor */ desc = ctx->sh_desc_update; - - init_sh_desc(desc, HDR_SHARE_SERIAL); - - /* Import context from software */ - append_seq_load(desc, ctx->ctx_len, LDST_CLASS_2_CCB | - LDST_SRCDST_BYTE_CONTEXT); - - /* Class 2 operation */ - append_operation(desc, ctx->adata.algtype | OP_ALG_AS_UPDATE | - OP_ALG_ENCRYPT); - - /* Load data and write to result or context */ - ahash_append_load_str(desc, ctx->ctx_len); - + ahash_gen_sh_desc(desc, OP_ALG_AS_UPDATE, ctx->ctx_len, ctx, true); ctx->sh_desc_update_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->sh_desc_update_dma)) { @@ -340,10 +291,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_update_first shared descriptor */ desc = ctx->sh_desc_update_first; - - ahash_data_to_out(desc, have_key | ctx->adata.algtype, OP_ALG_AS_INIT, - ctx->ctx_len, ctx); - + ahash_gen_sh_desc(desc, OP_ALG_AS_INIT, ctx->ctx_len, ctx, false); ctx->sh_desc_update_first_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); @@ -359,10 +307,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_final shared descriptor */ desc = ctx->sh_desc_fin; - - ahash_ctx_data_to_out(desc, have_key | ctx->adata.algtype, - OP_ALG_AS_FINALIZE, digestsize, ctx); - + ahash_gen_sh_desc(desc, OP_ALG_AS_FINALIZE, digestsize, ctx, true); ctx->sh_desc_fin_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); if (dma_mapping_error(jrdev, ctx->sh_desc_fin_dma)) { @@ -377,10 +322,7 @@ static int ahash_set_sh_desc(struct crypto_ahash *ahash) /* ahash_digest shared descriptor */ desc = ctx->sh_desc_digest; - - ahash_data_to_out(desc, have_key | ctx->adata.algtype, - OP_ALG_AS_INITFINAL, digestsize, ctx); - + ahash_gen_sh_desc(desc, OP_ALG_AS_INITFINAL, digestsize, ctx, false); ctx->sh_desc_digest_dma = dma_map_single(jrdev, desc, desc_bytes(desc), DMA_TO_DEVICE); -- cgit v1.2.3 From 63880b230a4af502c56dde3d4588634c70c66006 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 28 Nov 2016 11:19:27 -0600 Subject: PCI: Ignore BAR updates on virtual functions VF BARs are read-only zero, so updating VF BARs will not have any effect. See the SR-IOV spec r1.1, sec 3.4.1.11. We already ignore these updates because of 70675e0b6a1a ("PCI: Don't try to restore VF BARs"); this merely restructures it slightly to make it easier to split updates for standard and SR-IOV BARs. Signed-off-by: Bjorn Helgaas Reviewed-by: Gavin Shan --- drivers/pci/pci.c | 4 ---- drivers/pci/setup-res.c | 5 ++--- 2 files changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index ba34907538f6..631eac2bed78 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -564,10 +564,6 @@ static void pci_restore_bars(struct pci_dev *dev) { int i; - /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */ - if (dev->is_virtfn) - return; - for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) pci_update_resource(dev, i); } diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 66c4d8f42233..d2a32d88d2ae 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -36,10 +36,9 @@ void pci_update_resource(struct pci_dev *dev, int resno) enum pci_bar_type type; struct resource *res = dev->resource + resno; - if (dev->is_virtfn) { - dev_warn(&dev->dev, "can't update VF BAR%d\n", resno); + /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */ + if (dev->is_virtfn) return; - } /* * Ignore resources for unimplemented BARs and unused resource slots -- cgit v1.2.3 From 450c6633e874c4d38112b39647831f67b41a8067 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 28 Nov 2016 11:15:18 -0800 Subject: libnvdimm: use consistent naming for request_mem_region() Here is an example /proc/iomem listing for a system with 2 namespaces, one in "sector" mode and one in "memory" mode: 1fc000000-2fbffffff : Persistent Memory (legacy) 1fc000000-2fbffffff : namespace1.0 340000000-34fffffff : Persistent Memory 340000000-34fffffff : btt0.1 Here is the corresponding ndctl listing: # ndctl list [ { "dev":"namespace1.0", "mode":"memory", "size":4294967296, "blockdev":"pmem1" }, { "dev":"namespace0.0", "mode":"sector", "size":267091968, "uuid":"f7594f86-badb-4592-875f-ded577da2eaf", "sector_size":4096, "blockdev":"pmem0s" } ] Notice that the ndctl listing is purely in terms of namespace devices, while the iomem listing leaks the internal "btt0.1" implementation detail. Given that ndctl requires the namespace device name to change the mode, for example: # ndctl create-namespace --reconfig=namespace0.0 --mode=raw --force ...use the namespace name in the iomem listing to keep the claiming device name consistent across different mode settings. Cc: Vishal Verma Signed-off-by: Dan Williams --- drivers/dax/pmem.c | 3 ++- drivers/nvdimm/claim.c | 2 +- drivers/nvdimm/pmem.c | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dax/pmem.c b/drivers/dax/pmem.c index 9630d8837ba9..3ff84784249a 100644 --- a/drivers/dax/pmem.c +++ b/drivers/dax/pmem.c @@ -87,7 +87,8 @@ static int dax_pmem_probe(struct device *dev) pfn_sb = nd_pfn->pfn_sb; if (!devm_request_mem_region(dev, nsio->res.start, - resource_size(&nsio->res), dev_name(dev))) { + resource_size(&nsio->res), + dev_name(&ndns->dev))) { dev_warn(dev, "could not reserve region %pR\n", &nsio->res); return -EBUSY; } diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 8d66fbb779ed..4638b9ea5229 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -275,7 +275,7 @@ int devm_nsio_enable(struct device *dev, struct nd_namespace_io *nsio) nsio->size = resource_size(res); if (!devm_request_mem_region(dev, res->start, resource_size(res), - dev_name(dev))) { + dev_name(&ndns->dev))) { dev_warn(dev, "could not reserve region %pR\n", res); return -EBUSY; } diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 42b3a8217073..34f16a17c07b 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -266,7 +266,7 @@ static int pmem_attach_disk(struct device *dev, dev_warn(dev, "unable to guarantee persistence of writes\n"); if (!devm_request_mem_region(dev, res->start, resource_size(res), - dev_name(dev))) { + dev_name(&ndns->dev))) { dev_warn(dev, "could not reserve region %pR\n", res); return -EBUSY; } -- cgit v1.2.3 From 238b323a681dd4a5ea0c651fdf4e6ee91a09a9ba Mon Sep 17 00:00:00 2001 From: Nicolas Iooss Date: Sat, 26 Nov 2016 20:18:04 +0100 Subject: libnvdimm, namespace: fix the type of name variable In create_namespace_blk(), the local variable "name" is defined as an array of NSLABEL_NAME_LEN pointers: char *name[NSLABEL_NAME_LEN]; This variable is then used in calls to memcpy() and kmemdup() as if it were char[NSLABEL_NAME_LEN]. Remove the star in the variable definition to makes it look right. Signed-off-by: Nicolas Iooss Reviewed-by: Ross Zwisler Signed-off-by: Dan Williams --- drivers/nvdimm/namespace_devs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 3509cff68ef9..61636d135105 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1997,7 +1997,7 @@ struct device *create_namespace_blk(struct nd_region *nd_region, struct nd_mapping *nd_mapping = &nd_region->mapping[0]; struct nvdimm_drvdata *ndd = to_ndd(nd_mapping); struct nd_namespace_blk *nsblk; - char *name[NSLABEL_NAME_LEN]; + char name[NSLABEL_NAME_LEN]; struct device *dev = NULL; struct resource *res; -- cgit v1.2.3 From 5c279b1003f9070b29d9e1e4da7b61126c5a46bb Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Mon, 28 Nov 2016 15:41:44 +0530 Subject: dmaengine: pch_dma: Replace pci_pool_alloc by pci_pool_zalloc Inside pdc_alloc_desc(), pci_pool_alloc() followed by memset will be replaced by pci_pool_zalloc() Signed-off-by: Souptick joarder Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index df95727dc2fb..b8d858c7a7a5 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -439,9 +439,8 @@ static struct pch_dma_desc *pdc_alloc_desc(struct dma_chan *chan, gfp_t flags) struct pch_dma *pd = to_pd(chan->device); dma_addr_t addr; - desc = pci_pool_alloc(pd->pool, flags, &addr); + desc = pci_pool_zalloc(pd->pool, flags, &addr); if (desc) { - memset(desc, 0, sizeof(struct pch_dma_desc)); INIT_LIST_HEAD(&desc->tx_list); dma_async_tx_descriptor_init(&desc->txd, chan); desc->txd.tx_submit = pd_tx_submit; -- cgit v1.2.3 From 864db9295b06837d11a260e5dacf99a3fdf6bce2 Mon Sep 17 00:00:00 2001 From: Paul Donohue Date: Mon, 28 Nov 2016 20:11:25 -0800 Subject: Input: ALPS - fix TrackStick support for SS5 hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The current Alps SS5 (SS4 v2) code generates bogus TouchPad events when TrackStick packets are processed. This causes the xorg synaptics driver to print "unable to find touch point 0" and "BUG: triggered 'if (priv->num_active_touches > priv->num_slots)'" messages. It also causes unexpected TouchPad button release and re-click event sequences if the TrackStick is moved while holding a TouchPad button. This commit corrects the problem by adjusting alps_process_packet_ss4_v2() so that it only sends TrackStick reports when processing TrackStick packets. Reviewed-by: Pali Rohár Signed-off-by: Paul Donohue Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 6d7de9bfed9a..b93fe83a0b63 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1346,6 +1346,18 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) priv->multi_packet = 0; + /* Report trackstick */ + if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) { + if (priv->flags & ALPS_DUALPOINT) { + input_report_key(dev2, BTN_LEFT, f->ts_left); + input_report_key(dev2, BTN_RIGHT, f->ts_right); + input_report_key(dev2, BTN_MIDDLE, f->ts_middle); + input_sync(dev2); + } + return; + } + + /* Report touchpad */ alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4); input_mt_report_finger_count(dev, f->fingers); @@ -1356,13 +1368,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) input_report_abs(dev, ABS_PRESSURE, f->pressure); input_sync(dev); - - if (priv->flags & ALPS_DUALPOINT) { - input_report_key(dev2, BTN_LEFT, f->ts_left); - input_report_key(dev2, BTN_RIGHT, f->ts_right); - input_report_key(dev2, BTN_MIDDLE, f->ts_middle); - input_sync(dev2); - } } static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) -- cgit v1.2.3 From 7229c58c096ca08576cbcbf6669bfbdcae0b5d22 Mon Sep 17 00:00:00 2001 From: Paul Donohue Date: Mon, 28 Nov 2016 20:13:47 -0800 Subject: Input: ALPS - clean up TrackStick handling for SS5 hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For consistency and clarity, the input_report_*() functions should be called by alps_process_packet_ss4_v2() instead of by alps_decode_ss4_v2(). Reviewed-by: Pali Rohár Signed-off-by: Paul Donohue Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index b93fe83a0b63..61d61cc24fd2 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1267,18 +1267,12 @@ static int alps_decode_ss4_v2(struct alps_fields *f, break; case SS4_PACKET_ID_STICK: - if (!(priv->flags & ALPS_DUALPOINT)) { - psmouse_warn(psmouse, - "Rejected trackstick packet from non DualPoint device"); - } else { - int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f)); - int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f)); - int pressure = (s8)(p[4] & 0x7f); - - input_report_rel(priv->dev2, REL_X, x); - input_report_rel(priv->dev2, REL_Y, -y); - input_report_abs(priv->dev2, ABS_PRESSURE, pressure); - } + /* + * x, y, and pressure are decoded in + * alps_process_packet_ss4_v2() + */ + f->first_mp = 0; + f->is_mp = 0; break; case SS4_PACKET_ID_IDLE: @@ -1312,6 +1306,7 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; struct input_dev *dev2 = priv->dev2; struct alps_fields *f = &priv->f; + int x, y, pressure; memset(f, 0, sizeof(struct alps_fields)); priv->decode_fields(f, packet, psmouse); @@ -1348,12 +1343,25 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) /* Report trackstick */ if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) { - if (priv->flags & ALPS_DUALPOINT) { - input_report_key(dev2, BTN_LEFT, f->ts_left); - input_report_key(dev2, BTN_RIGHT, f->ts_right); - input_report_key(dev2, BTN_MIDDLE, f->ts_middle); - input_sync(dev2); + if (!(priv->flags & ALPS_DUALPOINT)) { + psmouse_warn(psmouse, + "Rejected trackstick packet from non DualPoint device"); + return; } + + x = (s8)(((packet[0] & 1) << 7) | (packet[1] & 0x7f)); + y = (s8)(((packet[3] & 1) << 7) | (packet[2] & 0x7f)); + pressure = (s8)(packet[4] & 0x7f); + + input_report_rel(dev2, REL_X, x); + input_report_rel(dev2, REL_Y, -y); + input_report_abs(dev2, ABS_PRESSURE, pressure); + + input_report_key(dev2, BTN_LEFT, f->ts_left); + input_report_key(dev2, BTN_RIGHT, f->ts_right); + input_report_key(dev2, BTN_MIDDLE, f->ts_middle); + + input_sync(dev2); return; } -- cgit v1.2.3 From 23fce365c6a26e40d459ca97289dd18543fb6845 Mon Sep 17 00:00:00 2001 From: Paul Donohue Date: Mon, 28 Nov 2016 20:16:21 -0800 Subject: Input: ALPS - clean up code for SS5 hardware MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The return value of alps_get_pkt_id_ss4_v2() should really be "enum SS4_PACKET_ID", not "unsigned char". Correct this. Also, most of the Alps SS5 (SS4 v2) packet byte parsing code is implemented using macros, but there are a few places where bytes are directly manipulated in alps.c. For consistency, migrate the rest of these to macros. Reviewed-by: Pali Rohár Signed-off-by: Paul Donohue Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.c | 21 +++++++-------------- drivers/input/mouse/alps.h | 22 +++++++++++++++++++++- 2 files changed, 28 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 61d61cc24fd2..328edc8c8786 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -1153,15 +1153,13 @@ static void alps_process_packet_v7(struct psmouse *psmouse) alps_process_touchpad_packet_v7(psmouse); } -static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte) +static enum SS4_PACKET_ID alps_get_pkt_id_ss4_v2(unsigned char *byte) { - unsigned char pkt_id = SS4_PACKET_ID_IDLE; + enum SS4_PACKET_ID pkt_id = SS4_PACKET_ID_IDLE; switch (byte[3] & 0x30) { case 0x00: - if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && - (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && - byte[5] == 0x00) { + if (SS4_IS_IDLE_V2(byte)) { pkt_id = SS4_PACKET_ID_IDLE; } else { pkt_id = SS4_PACKET_ID_ONE; @@ -1188,7 +1186,7 @@ static int alps_decode_ss4_v2(struct alps_fields *f, unsigned char *p, struct psmouse *psmouse) { struct alps_data *priv = psmouse->private; - unsigned char pkt_id; + enum SS4_PACKET_ID pkt_id; unsigned int no_data_x, no_data_y; pkt_id = alps_get_pkt_id_ss4_v2(p); @@ -1306,7 +1304,6 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) struct input_dev *dev = psmouse->dev; struct input_dev *dev2 = priv->dev2; struct alps_fields *f = &priv->f; - int x, y, pressure; memset(f, 0, sizeof(struct alps_fields)); priv->decode_fields(f, packet, psmouse); @@ -1349,13 +1346,9 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse) return; } - x = (s8)(((packet[0] & 1) << 7) | (packet[1] & 0x7f)); - y = (s8)(((packet[3] & 1) << 7) | (packet[2] & 0x7f)); - pressure = (s8)(packet[4] & 0x7f); - - input_report_rel(dev2, REL_X, x); - input_report_rel(dev2, REL_Y, -y); - input_report_abs(dev2, ABS_PRESSURE, pressure); + input_report_rel(dev2, REL_X, SS4_TS_X_V2(packet)); + input_report_rel(dev2, REL_Y, SS4_TS_Y_V2(packet)); + input_report_abs(dev2, ABS_PRESSURE, SS4_TS_Z_V2(packet)); input_report_key(dev2, BTN_LEFT, f->ts_left); input_report_key(dev2, BTN_RIGHT, f->ts_right); diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index b9417e2d7ad3..72b9efc5217b 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -54,7 +54,15 @@ enum SS4_PACKET_ID { #define SS4_MASK_NORMAL_BUTTONS 0x07 -#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \ +#define SS4_IS_IDLE_V2(_b) (((_b[0]) == 0x18) && \ + ((_b[1]) == 0x10) && \ + ((_b[2]) == 0x00) && \ + ((_b[3] & 0x88) == 0x08) && \ + ((_b[4]) == 0x10) && \ + ((_b[5]) == 0x00) \ + ) + +#define SS4_1F_X_V2(_b) (((_b[0]) & 0x0007) | \ ((_b[1] << 3) & 0x0078) | \ ((_b[1] << 2) & 0x0380) | \ ((_b[2] << 5) & 0x1C00) \ @@ -101,6 +109,18 @@ enum SS4_PACKET_ID { #define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10) #define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10) +#define SS4_TS_X_V2(_b) (s8)( \ + ((_b[0] & 0x01) << 7) | \ + (_b[1] & 0x7F) \ + ) + +#define SS4_TS_Y_V2(_b) (s8)( \ + ((_b[3] & 0x01) << 7) | \ + (_b[2] & 0x7F) \ + ) + +#define SS4_TS_Z_V2(_b) (s8)(_b[4] & 0x7F) + #define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */ #define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */ -- cgit v1.2.3 From 937d3a0af521ece133a8716c1bf2d8044e15faa0 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Thu, 15 Sep 2016 14:44:03 +0200 Subject: mfd: Add support for Allwinner SoCs ADC The Allwinner SoCs all have an ADC that can also act as a touchscreen controller and a thermal sensor. For now, only the ADC and the thermal sensor drivers are probed by the MFD, the touchscreen controller support will be added later. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Acked-by: Jonathan Cameron Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 15 ++++ drivers/mfd/Makefile | 1 + drivers/mfd/sun4i-gpadc.c | 181 ++++++++++++++++++++++++++++++++++++++++ include/linux/mfd/sun4i-gpadc.h | 94 +++++++++++++++++++++ 4 files changed, 291 insertions(+) create mode 100644 drivers/mfd/sun4i-gpadc.c create mode 100644 include/linux/mfd/sun4i-gpadc.h (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 1ed0584f494e..94db77307f62 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -40,6 +40,21 @@ config MFD_ACT8945A linear regulators, along with a complete ActivePath battery charger. +config MFD_SUN4I_GPADC + tristate "Allwinner sunxi platforms' GPADC MFD driver" + select MFD_CORE + select REGMAP_MMIO + depends on ARCH_SUNXI || COMPILE_TEST + help + Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC. + This driver will only map the hardware interrupt and registers, you + have to select individual drivers based on this MFD to be able to use + the ADC or the thermal sensor. This will try to probe the ADC driver + sun4i-gpadc-iio and the hwmon driver iio_hwmon. + + To compile this driver as a module, choose M here: the module will be + called sun4i-gpadc. + config MFD_AS3711 bool "AMS AS3711" select MFD_CORE diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 7bb5a50127cb..dda4d4f73ad7 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -211,3 +211,4 @@ obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o obj-$(CONFIG_MFD_MT6397) += mt6397-core.o obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o +obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c new file mode 100644 index 000000000000..8a7ee5b6beb1 --- /dev/null +++ b/drivers/mfd/sun4i-gpadc.c @@ -0,0 +1,181 @@ +/* ADC MFD core driver for sunxi platforms + * + * Copyright (c) 2016 Quentin Schulz + * + * 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 + +#define ARCH_SUN4I_A10 0 +#define ARCH_SUN5I_A13 1 +#define ARCH_SUN6I_A31 2 + +static struct resource adc_resources[] = { + DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_FIFO_DATA, "FIFO_DATA_PENDING"), + DEFINE_RES_IRQ_NAMED(SUN4I_GPADC_IRQ_TEMP_DATA, "TEMP_DATA_PENDING"), +}; + +static const struct regmap_irq sun4i_gpadc_regmap_irq[] = { + REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_FIFO_DATA, 0, + SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN), + REGMAP_IRQ_REG(SUN4I_GPADC_IRQ_TEMP_DATA, 0, + SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN), +}; + +static const struct regmap_irq_chip sun4i_gpadc_regmap_irq_chip = { + .name = "sun4i_gpadc_irq_chip", + .status_base = SUN4I_GPADC_INT_FIFOS, + .ack_base = SUN4I_GPADC_INT_FIFOS, + .mask_base = SUN4I_GPADC_INT_FIFOC, + .init_ack_masked = true, + .mask_invert = true, + .irqs = sun4i_gpadc_regmap_irq, + .num_irqs = ARRAY_SIZE(sun4i_gpadc_regmap_irq), + .num_regs = 1, +}; + +static struct mfd_cell sun4i_gpadc_cells[] = { + { + .name = "sun4i-a10-gpadc-iio", + .resources = adc_resources, + .num_resources = ARRAY_SIZE(adc_resources), + }, + { .name = "iio_hwmon" } +}; + +static struct mfd_cell sun5i_gpadc_cells[] = { + { + .name = "sun5i-a13-gpadc-iio", + .resources = adc_resources, + .num_resources = ARRAY_SIZE(adc_resources), + }, + { .name = "iio_hwmon" }, +}; + +static struct mfd_cell sun6i_gpadc_cells[] = { + { + .name = "sun6i-a31-gpadc-iio", + .resources = adc_resources, + .num_resources = ARRAY_SIZE(adc_resources), + }, + { .name = "iio_hwmon" }, +}; + +static const struct regmap_config sun4i_gpadc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .fast_io = true, +}; + +static const struct of_device_id sun4i_gpadc_of_match[] = { + { + .compatible = "allwinner,sun4i-a10-ts", + .data = (void *)ARCH_SUN4I_A10, + }, { + .compatible = "allwinner,sun5i-a13-ts", + .data = (void *)ARCH_SUN5I_A13, + }, { + .compatible = "allwinner,sun6i-a31-ts", + .data = (void *)ARCH_SUN6I_A31, + }, { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, sun4i_gpadc_of_match); + +static int sun4i_gpadc_probe(struct platform_device *pdev) +{ + struct sun4i_gpadc_dev *dev; + struct resource *mem; + const struct of_device_id *of_id; + const struct mfd_cell *cells; + unsigned int irq, size; + int ret; + + of_id = of_match_node(sun4i_gpadc_of_match, pdev->dev.of_node); + if (!of_id) + return -EINVAL; + + switch ((int)of_id->data) { + case ARCH_SUN4I_A10: + cells = sun4i_gpadc_cells; + size = ARRAY_SIZE(sun4i_gpadc_cells); + break; + case ARCH_SUN5I_A13: + cells = sun5i_gpadc_cells; + size = ARRAY_SIZE(sun5i_gpadc_cells); + break; + case ARCH_SUN6I_A31: + cells = sun6i_gpadc_cells; + size = ARRAY_SIZE(sun6i_gpadc_cells); + break; + default: + return -EINVAL; + } + + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + dev->base = devm_ioremap_resource(&pdev->dev, mem); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); + + dev->dev = &pdev->dev; + dev_set_drvdata(dev->dev, dev); + + dev->regmap = devm_regmap_init_mmio(dev->dev, dev->base, + &sun4i_gpadc_regmap_config); + if (IS_ERR(dev->regmap)) { + ret = PTR_ERR(dev->regmap); + dev_err(&pdev->dev, "failed to init regmap: %d\n", ret); + return ret; + } + + /* Disable all interrupts */ + regmap_write(dev->regmap, SUN4I_GPADC_INT_FIFOC, 0); + + irq = platform_get_irq(pdev, 0); + ret = devm_regmap_add_irq_chip(&pdev->dev, dev->regmap, irq, + IRQF_ONESHOT, 0, + &sun4i_gpadc_regmap_irq_chip, + &dev->regmap_irqc); + if (ret) { + dev_err(&pdev->dev, "failed to add irq chip: %d\n", ret); + return ret; + } + + ret = devm_mfd_add_devices(dev->dev, 0, cells, size, NULL, 0, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to add MFD devices: %d\n", ret); + return ret; + } + + return 0; +} + +static struct platform_driver sun4i_gpadc_driver = { + .driver = { + .name = "sun4i-gpadc", + .of_match_table = of_match_ptr(sun4i_gpadc_of_match), + }, + .probe = sun4i_gpadc_probe, +}; + +module_platform_driver(sun4i_gpadc_driver); + +MODULE_DESCRIPTION("Allwinner sunxi platforms' GPADC MFD core driver"); +MODULE_AUTHOR("Quentin Schulz "); +MODULE_LICENSE("GPL v2"); diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h new file mode 100644 index 000000000000..d7a29f246d64 --- /dev/null +++ b/include/linux/mfd/sun4i-gpadc.h @@ -0,0 +1,94 @@ +/* Header of ADC MFD core driver for sunxi platforms + * + * Copyright (c) 2016 Quentin Schulz + * + * 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 __SUN4I_GPADC__H__ +#define __SUN4I_GPADC__H__ + +#define SUN4I_GPADC_CTRL0 0x00 + +#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY(x) ((GENMASK(7, 0) & (x)) << 24) +#define SUN4I_GPADC_CTRL0_ADC_FIRST_DLY_MODE BIT(23) +#define SUN4I_GPADC_CTRL0_ADC_CLK_SELECT BIT(22) +#define SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(x) ((GENMASK(1, 0) & (x)) << 20) +#define SUN4I_GPADC_CTRL0_FS_DIV(x) ((GENMASK(3, 0) & (x)) << 16) +#define SUN4I_GPADC_CTRL0_T_ACQ(x) (GENMASK(15, 0) & (x)) + +#define SUN4I_GPADC_CTRL1 0x04 + +#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE(x) ((GENMASK(7, 0) & (x)) << 12) +#define SUN4I_GPADC_CTRL1_STYLUS_UP_DEBOUNCE_EN BIT(9) +#define SUN4I_GPADC_CTRL1_TOUCH_PAN_CALI_EN BIT(6) +#define SUN4I_GPADC_CTRL1_TP_DUAL_EN BIT(5) +#define SUN4I_GPADC_CTRL1_TP_MODE_EN BIT(4) +#define SUN4I_GPADC_CTRL1_TP_ADC_SELECT BIT(3) +#define SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(2, 0) & (x)) + +/* TP_CTRL1 bits for sun6i SOCs */ +#define SUN6I_GPADC_CTRL1_TOUCH_PAN_CALI_EN BIT(7) +#define SUN6I_GPADC_CTRL1_TP_DUAL_EN BIT(6) +#define SUN6I_GPADC_CTRL1_TP_MODE_EN BIT(5) +#define SUN6I_GPADC_CTRL1_TP_ADC_SELECT BIT(4) +#define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x) (GENMASK(3, 0) & BIT(x)) + +#define SUN4I_GPADC_CTRL2 0x08 + +#define SUN4I_GPADC_CTRL2_TP_SENSITIVE_ADJUST(x) ((GENMASK(3, 0) & (x)) << 28) +#define SUN4I_GPADC_CTRL2_TP_MODE_SELECT(x) ((GENMASK(1, 0) & (x)) << 26) +#define SUN4I_GPADC_CTRL2_PRE_MEA_EN BIT(24) +#define SUN4I_GPADC_CTRL2_PRE_MEA_THRE_CNT(x) (GENMASK(23, 0) & (x)) + +#define SUN4I_GPADC_CTRL3 0x0c + +#define SUN4I_GPADC_CTRL3_FILTER_EN BIT(2) +#define SUN4I_GPADC_CTRL3_FILTER_TYPE(x) (GENMASK(1, 0) & (x)) + +#define SUN4I_GPADC_TPR 0x18 + +#define SUN4I_GPADC_TPR_TEMP_ENABLE BIT(16) +#define SUN4I_GPADC_TPR_TEMP_PERIOD(x) (GENMASK(15, 0) & (x)) + +#define SUN4I_GPADC_INT_FIFOC 0x10 + +#define SUN4I_GPADC_INT_FIFOC_TEMP_IRQ_EN BIT(18) +#define SUN4I_GPADC_INT_FIFOC_TP_OVERRUN_IRQ_EN BIT(17) +#define SUN4I_GPADC_INT_FIFOC_TP_DATA_IRQ_EN BIT(16) +#define SUN4I_GPADC_INT_FIFOC_TP_DATA_XY_CHANGE BIT(13) +#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(x) ((GENMASK(4, 0) & (x)) << 8) +#define SUN4I_GPADC_INT_FIFOC_TP_DATA_DRQ_EN BIT(7) +#define SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH BIT(4) +#define SUN4I_GPADC_INT_FIFOC_TP_UP_IRQ_EN BIT(1) +#define SUN4I_GPADC_INT_FIFOC_TP_DOWN_IRQ_EN BIT(0) + +#define SUN4I_GPADC_INT_FIFOS 0x14 + +#define SUN4I_GPADC_INT_FIFOS_TEMP_DATA_PENDING BIT(18) +#define SUN4I_GPADC_INT_FIFOS_FIFO_OVERRUN_PENDING BIT(17) +#define SUN4I_GPADC_INT_FIFOS_FIFO_DATA_PENDING BIT(16) +#define SUN4I_GPADC_INT_FIFOS_TP_IDLE_FLG BIT(2) +#define SUN4I_GPADC_INT_FIFOS_TP_UP_PENDING BIT(1) +#define SUN4I_GPADC_INT_FIFOS_TP_DOWN_PENDING BIT(0) + +#define SUN4I_GPADC_CDAT 0x1c +#define SUN4I_GPADC_TEMP_DATA 0x20 +#define SUN4I_GPADC_DATA 0x24 + +#define SUN4I_GPADC_IRQ_FIFO_DATA 0 +#define SUN4I_GPADC_IRQ_TEMP_DATA 1 + +/* 10s delay before suspending the IP */ +#define SUN4I_GPADC_AUTOSUSPEND_DELAY 10000 + +struct sun4i_gpadc_dev { + struct device *dev; + struct regmap *regmap; + struct regmap_irq_chip_data *regmap_irqc; + void __iomem *base; +}; + +#endif -- cgit v1.2.3 From d87814a3e846aa23a1ae3519413841954d27fb40 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 1 Oct 2016 21:46:23 +0200 Subject: mfd: tc3589x: Improve function-level documentation Use the correct function name in one case and adjust a variable name to that of the corresponding function parameter in another case. Issue detected using Coccinelle (http://coccinelle.lip6.fr/) Signed-off-by: Julia Lawall Signed-off-by: Lee Jones --- drivers/mfd/tc3589x.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 274bf39968aa..cc9e563f23aa 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -53,7 +53,7 @@ int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg) EXPORT_SYMBOL_GPL(tc3589x_reg_read); /** - * tc3589x_reg_read() - write a single TC3589x register + * tc3589x_reg_write() - write a single TC3589x register * @tc3589x: Device to write to * @reg: Register to read * @data: Value to write @@ -118,7 +118,7 @@ EXPORT_SYMBOL_GPL(tc3589x_block_write); * @tc3589x: Device to write to * @reg: Register to write * @mask: Mask of bits to set - * @values: Value to set + * @val: Value to set */ int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val) { -- cgit v1.2.3 From 28e9e55ed30d1a0f46c541a1f3976be9b9141a4e Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 2 Oct 2016 22:58:17 +0200 Subject: mfd: Enable compile testing for max77620 and max77686 The OF is not a strict build-time dependency so max77620 and max77686 can be compile tested to increase build coverage. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 94db77307f62..0d9590358273 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -578,7 +578,7 @@ config MFD_MAX14577 config MFD_MAX77620 bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support" depends on I2C=y - depends on OF + depends on OF || COMPILE_TEST select MFD_CORE select REGMAP_I2C select REGMAP_IRQ @@ -593,7 +593,7 @@ config MFD_MAX77620 config MFD_MAX77686 tristate "Maxim Semiconductor MAX77686/802 PMIC Support" depends on I2C - depends on OF + depends on OF || COMPILE_TEST select MFD_CORE select REGMAP_I2C select REGMAP_IRQ -- cgit v1.2.3 From 3e56c4688e6b0c648da0e6e2b8e096f5f2aabc60 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 16 Sep 2016 08:56:58 +0530 Subject: mfd: wm8994-core: Don't split lines unnecessarily These can fit in a single line (80 columns), don't split lines unnecessarily. Signed-off-by: Viresh Kumar Signed-off-by: Lee Jones --- drivers/mfd/wm8994-core.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 7eec619a6023..1990b2c90732 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -401,8 +401,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) goto err; } - ret = regulator_bulk_enable(wm8994->num_supplies, - wm8994->supplies); + ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); goto err; @@ -606,8 +605,7 @@ static void wm8994_device_exit(struct wm8994 *wm8994) pm_runtime_disable(wm8994->dev); mfd_remove_devices(wm8994->dev); wm8994_irq_exit(wm8994); - regulator_bulk_disable(wm8994->num_supplies, - wm8994->supplies); + regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); } static const struct of_device_id wm8994_of_match[] = { -- cgit v1.2.3 From bb63f7d33d35b17faac72ea63e03c57396766eee Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Fri, 16 Sep 2016 08:56:59 +0530 Subject: mfd: wm8994-core: Disable regulators before removing them The order in which resources were freed in wm8994_device_exit() isn't correct. The regulators are removed before they are disabled. Fix it by reordering code a bit, which makes it exact opposite of wm8994_device_init() as well. Signed-off-by: Viresh Kumar Acked-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm8994-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 1990b2c90732..95e6bc55adbb 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -603,9 +603,9 @@ err: static void wm8994_device_exit(struct wm8994 *wm8994) { pm_runtime_disable(wm8994->dev); - mfd_remove_devices(wm8994->dev); wm8994_irq_exit(wm8994); regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); + mfd_remove_devices(wm8994->dev); } static const struct of_device_id wm8994_of_match[] = { -- cgit v1.2.3 From 054814b863b32a19a5094edb78a14c3c441f57dd Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Thu, 15 Sep 2016 13:35:30 +0200 Subject: mfd: tps65912: Move regmap config into core driver When building with extra warnings enabled, most files including linux/mfd/tps65912.h warn about a static variable defined in the header: include/linux/mfd/tps65912.h:331:35: warning: 'tps65912_regmap_config' defined but not used [-Wunused-const-variable=] We also duplicate the data structure between the i2c and spi front-end drivers. Moving it into the driver code avoids the warning and the duplication. Signed-off-by: Arnd Bergmann Signed-off-by: Lee Jones --- drivers/mfd/tps65912-core.c | 17 +++++++++++++++++ include/linux/mfd/tps65912.h | 16 +--------------- 2 files changed, 18 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65912-core.c b/drivers/mfd/tps65912-core.c index a88cfa80dbc4..f33567bc428d 100644 --- a/drivers/mfd/tps65912-core.c +++ b/drivers/mfd/tps65912-core.c @@ -77,6 +77,23 @@ static struct regmap_irq_chip tps65912_irq_chip = { .init_ack_masked = true, }; +static const struct regmap_range tps65912_yes_ranges[] = { + regmap_reg_range(TPS65912_INT_STS, TPS65912_GPIO5), +}; + +static const struct regmap_access_table tps65912_volatile_table = { + .yes_ranges = tps65912_yes_ranges, + .n_yes_ranges = ARRAY_SIZE(tps65912_yes_ranges), +}; + +const struct regmap_config tps65912_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .cache_type = REGCACHE_RBTREE, + .volatile_table = &tps65912_volatile_table, +}; +EXPORT_SYMBOL_GPL(tps65912_regmap_config); + int tps65912_device_init(struct tps65912 *tps) { int ret; diff --git a/include/linux/mfd/tps65912.h b/include/linux/mfd/tps65912.h index 1a603701550e..b25d0297ba88 100644 --- a/include/linux/mfd/tps65912.h +++ b/include/linux/mfd/tps65912.h @@ -319,21 +319,7 @@ struct tps65912 { struct regmap_irq_chip_data *irq_data; }; -static const struct regmap_range tps65912_yes_ranges[] = { - regmap_reg_range(TPS65912_INT_STS, TPS65912_GPIO5), -}; - -static const struct regmap_access_table tps65912_volatile_table = { - .yes_ranges = tps65912_yes_ranges, - .n_yes_ranges = ARRAY_SIZE(tps65912_yes_ranges), -}; - -static const struct regmap_config tps65912_regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .cache_type = REGCACHE_RBTREE, - .volatile_table = &tps65912_volatile_table, -}; +extern const struct regmap_config tps65912_regmap_config; int tps65912_device_init(struct tps65912 *tps); int tps65912_device_exit(struct tps65912 *tps); -- cgit v1.2.3 From 23feb7c6e1245ea76b89c9b22d9cc4a4dfb37626 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Fri, 14 Oct 2016 14:35:44 +0200 Subject: mfd: exynos-lpass: Add hardware dependency This driver is meant for Exynos systems so do not offer the option elsewhere unless build-testing. Cc: Inha Song Cc: Beomho Seo Signed-off-by: Jean Delvare Reviewed-by: Sylwester Nawrocki Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0d9590358273..01ef4fed9e3c 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -308,6 +308,7 @@ config MFD_DLN2 config MFD_EXYNOS_LPASS tristate "Samsung Exynos SoC Low Power Audio Subsystem" + depends on ARCH_EXYNOS || COMPILE_TEST select MFD_CORE select REGMAP_MMIO help -- cgit v1.2.3 From 108fbd619869e44f7b70c97e30b5a5d0114791af Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 14 Oct 2016 09:57:32 -0300 Subject: mfd: abx500-core: Allow driver to built if COMPILE_TEST is enabled The driver only has runtime but no build time dependency with ARCH_U300 || ARCH_U8500 So it can be built for testing purposes if COMPILE_TEST option is enabled. This is useful to have more build coverage and make sure that the driver is not affected by changes that could cause build regressions. Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 01ef4fed9e3c..c7dd32870558 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -967,7 +967,7 @@ config MFD_SMSC config ABX500_CORE bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" - default y if ARCH_U300 || ARCH_U8500 + default y if ARCH_U300 || ARCH_U8500 || COMPILE_TEST help Say yes here if you have the ABX500 Mixed Signal IC family chips. This core driver expose register access functions. -- cgit v1.2.3 From e45b6c80b8bc1572788ed3d38bc2605eda20cd2b Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 14 Oct 2016 12:40:51 -0300 Subject: mfd: hi655x-pmic: Fix module autoload when registered via OF If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/mfd/hi655x-pmic.ko | grep alias After this patch: $ modinfo drivers/mfd/hi655x-pmic.ko | grep alias alias: of:N*T*Chisilicon,hi655x-pmicC* alias: of:N*T*Chisilicon,hi655x-pmic Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/hi655x-pmic.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/hi655x-pmic.c b/drivers/mfd/hi655x-pmic.c index 0fc62995695b..ba706adee38b 100644 --- a/drivers/mfd/hi655x-pmic.c +++ b/drivers/mfd/hi655x-pmic.c @@ -169,6 +169,7 @@ static const struct of_device_id hi655x_pmic_match[] = { { .compatible = "hisilicon,hi655x-pmic", }, {}, }; +MODULE_DEVICE_TABLE(of, hi655x_pmic_match); static struct platform_driver hi655x_pmic_driver = { .driver = { -- cgit v1.2.3 From a893764ca8693429ae130c3ff01f2cf3bcfb0d05 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 14 Oct 2016 12:40:50 -0300 Subject: mfd: fsl-imx25-tsadc: Fix module autoload when registered via OF If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/mfd/fsl-imx25-tsadc.ko | grep alias alias: platform:mx25-tsadc After this patch: $ modinfo drivers/mfd/fsl-imx25-tsadc.ko | grep alias alias: platform:mx25-tsadc alias: of:N*T*Cfsl,imx25-tsadcC* alias: of:N*T*Cfsl,imx25-tsadc Signed-off-by: Javier Martinez Canillas Signed-off-by: Lee Jones --- drivers/mfd/fsl-imx25-tsadc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/fsl-imx25-tsadc.c b/drivers/mfd/fsl-imx25-tsadc.c index 77b2675cf8f5..ac430a396a89 100644 --- a/drivers/mfd/fsl-imx25-tsadc.c +++ b/drivers/mfd/fsl-imx25-tsadc.c @@ -187,6 +187,7 @@ static const struct of_device_id mx25_tsadc_ids[] = { { .compatible = "fsl,imx25-tsadc" }, { /* Sentinel */ } }; +MODULE_DEVICE_TABLE(of, mx25_tsadc_ids); static struct platform_driver mx25_tsadc_driver = { .driver = { -- cgit v1.2.3 From b2e2c85091710159b305735d557f4ef4695f5dff Mon Sep 17 00:00:00 2001 From: Jianhong Chen Date: Mon, 17 Oct 2016 17:03:10 +0800 Subject: mfd: rk808: RK818 uses DEV_OFF to power off supplies DEV_OFF and DEV_OFF_RST functions for RK808 are designed error that only DEV_OFF_RST can power off supplies. RK818 has been fixed this issue, so that DEV_OFF is used to power off supplies. Signed-off-by: Jianhong Chen Signed-off-by: Lee Jones --- drivers/mfd/rk808.c | 23 ++++++++++++++++++++++- include/linux/mfd/rk808.h | 1 + 2 files changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c index 0f8acc5882a4..2c9acdba7c2d 100644 --- a/drivers/mfd/rk808.c +++ b/drivers/mfd/rk808.c @@ -290,6 +290,24 @@ static void rk808_device_shutdown(void) dev_err(&rk808_i2c_client->dev, "power off error!\n"); } +static void rk818_device_shutdown(void) +{ + int ret; + struct rk808 *rk808 = i2c_get_clientdata(rk808_i2c_client); + + if (!rk808) { + dev_warn(&rk808_i2c_client->dev, + "have no rk818, so do nothing here\n"); + return; + } + + ret = regmap_update_bits(rk808->regmap, + RK818_DEVCTRL_REG, + DEV_OFF, DEV_OFF); + if (ret) + dev_err(&rk808_i2c_client->dev, "power off error!\n"); +} + static const struct of_device_id rk808_of_match[] = { { .compatible = "rockchip,rk808" }, { .compatible = "rockchip,rk818" }, @@ -304,6 +322,7 @@ static int rk808_probe(struct i2c_client *client, struct rk808 *rk808; const struct rk808_reg_data *pre_init_reg; const struct mfd_cell *cells; + void (*pm_pwroff_fn)(void); int nr_pre_init_regs; int nr_cells; int pm_off = 0; @@ -331,6 +350,7 @@ static int rk808_probe(struct i2c_client *client, nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg); cells = rk808s; nr_cells = ARRAY_SIZE(rk808s); + pm_pwroff_fn = rk808_device_shutdown; break; case RK818_ID: rk808->regmap_cfg = &rk818_regmap_config; @@ -339,6 +359,7 @@ static int rk808_probe(struct i2c_client *client, nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg); cells = rk818s; nr_cells = ARRAY_SIZE(rk818s); + pm_pwroff_fn = rk818_device_shutdown; break; default: dev_err(&client->dev, "Unsupported RK8XX ID %lu\n", @@ -393,7 +414,7 @@ static int rk808_probe(struct i2c_client *client, "rockchip,system-power-controller"); if (pm_off && !pm_power_off) { rk808_i2c_client = client; - pm_power_off = rk808_device_shutdown; + pm_power_off = pm_pwroff_fn; } return 0; diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h index 6d435a3c06bc..83701ef7d3c7 100644 --- a/include/linux/mfd/rk808.h +++ b/include/linux/mfd/rk808.h @@ -290,6 +290,7 @@ enum rk818_reg { #define SWITCH2_EN BIT(6) #define SWITCH1_EN BIT(5) #define DEV_OFF_RST BIT(3) +#define DEV_OFF BIT(0) #define VB_LO_ACT BIT(4) #define VB_LO_SEL_3500MV (7 << 0) -- cgit v1.2.3 From 8e52b61cc8ead97ebe9de63a7ab1e70039a48129 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 14 Oct 2016 10:17:31 +0100 Subject: mfd: syscon: Support native-endian regmaps The regmap devicetree binding documentation states that a native-endian property should be supported as well as big-endian & little-endian, however syscon in its duplication of the parsing of these properties omits support for native-endian. Fix this by setting REGMAP_ENDIAN_NATIVE when a native-endian property is found. Cc: linux-mips@linux-mips.org Cc: Arnd Bergmann Cc: Ralf Baechle Signed-off-by: Paul Burton Tested-by: Maciej W. Rozycki Tested-by: Guenter Roeck Signed-off-by: Lee Jones --- drivers/mfd/syscon.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 2f2225e845ef..b93fe4c4957a 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -73,8 +73,10 @@ static struct syscon *of_syscon_register(struct device_node *np) /* Parse the device's DT node for an endianness specification */ if (of_property_read_bool(np, "big-endian")) syscon_config.val_format_endian = REGMAP_ENDIAN_BIG; - else if (of_property_read_bool(np, "little-endian")) + else if (of_property_read_bool(np, "little-endian")) syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE; + else if (of_property_read_bool(np, "native-endian")) + syscon_config.val_format_endian = REGMAP_ENDIAN_NATIVE; /* * search for reg-io-width property in DT. If it is not provided, -- cgit v1.2.3 From 41751b033aaa9eb996f43496d1e8295cfd7dbcb0 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 5 Oct 2016 17:51:12 +0200 Subject: mfd: axp20x-i2c: Add i2c-ids to fix module auto-loading The i2c subsys does not load modules by compatible, only by i2c-id, with e.g. a modalias of: "i2c:axp209". Populate the axp20x_i2c_id[] table with supported ids, so that module auto-loading will work. Reported-by: Dennis Gilmore Signed-off-by: Hans de Goede Acked-by: Chen-Yu Tsai Signed-off-by: Lee Jones --- drivers/mfd/axp20x-i2c.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/axp20x-i2c.c b/drivers/mfd/axp20x-i2c.c index b1b865822c07..d35a5fe6c950 100644 --- a/drivers/mfd/axp20x-i2c.c +++ b/drivers/mfd/axp20x-i2c.c @@ -69,10 +69,11 @@ static const struct of_device_id axp20x_i2c_of_match[] = { }; MODULE_DEVICE_TABLE(of, axp20x_i2c_of_match); -/* - * This is useless for OF-enabled devices, but it is needed by I2C subsystem - */ static const struct i2c_device_id axp20x_i2c_id[] = { + { "axp152", 0 }, + { "axp202", 0 }, + { "axp209", 0 }, + { "axp221", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id); -- cgit v1.2.3 From e8ae79d6746649cf1d007831d47c042003a46951 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Wed, 26 Oct 2016 17:07:35 +0100 Subject: mfd: sun4i-gpadc: Fix 'cast from pointer to integer of different size' warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When building for X86 using COMPILE_TEST we get this warning: ../drivers/mfd/sun4i-gpadc.c: In function ‘sun4i_gpadc_probe’: ../drivers/mfd/sun4i-gpadc.c:110:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast] Since an integer and a pointer are difference sizes on 64bit architectures. Convert to case to a long instead. Signed-off-by: Lee Jones --- drivers/mfd/sun4i-gpadc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/sun4i-gpadc.c b/drivers/mfd/sun4i-gpadc.c index 8a7ee5b6beb1..9cfc88134d03 100644 --- a/drivers/mfd/sun4i-gpadc.c +++ b/drivers/mfd/sun4i-gpadc.c @@ -107,7 +107,7 @@ static int sun4i_gpadc_probe(struct platform_device *pdev) if (!of_id) return -EINVAL; - switch ((int)of_id->data) { + switch ((long)of_id->data) { case ARCH_SUN4I_A10: cells = sun4i_gpadc_cells; size = ARRAY_SIZE(sun4i_gpadc_cells); -- cgit v1.2.3 From ba28f546754bd73199828b5c8f81a1bad4785610 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Wed, 2 Nov 2016 10:37:29 +0000 Subject: mfd: wm5102: Remove spurious trailing spaces Remove the trailing spaces on the register default lines to stop checkpatch complaining. Signed-off-by: Richard Fitzgerald Signed-off-by: Lee Jones --- drivers/mfd/wm5102-tables.c | 1412 +++++++++++++++++++++---------------------- 1 file changed, 706 insertions(+), 706 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c index ab8b23b5bd22..853113d97c1e 100644 --- a/drivers/mfd/wm5102-tables.c +++ b/drivers/mfd/wm5102-tables.c @@ -244,752 +244,752 @@ const struct regmap_irq_chip wm5102_irq = { }; static const struct reg_default wm5102_reg_default[] = { - { 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */ - { 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */ - { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */ - { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */ - { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */ - { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */ - { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */ - { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */ - { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */ - { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */ - { 0x00000040, 0x0000 }, /* R64 - Wake control */ - { 0x00000041, 0x0000 }, /* R65 - Sequence control */ - { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */ - { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ - { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ - { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ + { 0x00000008, 0x0019 }, /* R8 - Ctrl IF SPI CFG 1 */ + { 0x00000009, 0x0001 }, /* R9 - Ctrl IF I2C1 CFG 1 */ + { 0x00000020, 0x0000 }, /* R32 - Tone Generator 1 */ + { 0x00000021, 0x1000 }, /* R33 - Tone Generator 2 */ + { 0x00000022, 0x0000 }, /* R34 - Tone Generator 3 */ + { 0x00000023, 0x1000 }, /* R35 - Tone Generator 4 */ + { 0x00000024, 0x0000 }, /* R36 - Tone Generator 5 */ + { 0x00000030, 0x0000 }, /* R48 - PWM Drive 1 */ + { 0x00000031, 0x0100 }, /* R49 - PWM Drive 2 */ + { 0x00000032, 0x0100 }, /* R50 - PWM Drive 3 */ + { 0x00000040, 0x0000 }, /* R64 - Wake control */ + { 0x00000041, 0x0000 }, /* R65 - Sequence control */ + { 0x00000061, 0x01FF }, /* R97 - Sample Rate Sequence Select 1 */ + { 0x00000062, 0x01FF }, /* R98 - Sample Rate Sequence Select 2 */ + { 0x00000063, 0x01FF }, /* R99 - Sample Rate Sequence Select 3 */ + { 0x00000064, 0x01FF }, /* R100 - Sample Rate Sequence Select 4 */ { 0x00000066, 0x01FF }, /* R102 - Always On Triggers Sequence Select 1 */ { 0x00000067, 0x01FF }, /* R103 - Always On Triggers Sequence Select 2 */ { 0x00000068, 0x01FF }, /* R104 - Always On Triggers Sequence Select 3 */ { 0x00000069, 0x01FF }, /* R105 - Always On Triggers Sequence Select 4 */ { 0x0000006A, 0x01FF }, /* R106 - Always On Triggers Sequence Select 5 */ { 0x0000006B, 0x01FF }, /* R107 - Always On Triggers Sequence Select 6 */ - { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */ - { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ - { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ - { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */ - { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */ - { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */ - { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */ - { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */ - { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */ + { 0x00000070, 0x0000 }, /* R112 - Comfort Noise Generator */ + { 0x00000090, 0x0000 }, /* R144 - Haptics Control 1 */ + { 0x00000091, 0x7FFF }, /* R145 - Haptics Control 2 */ + { 0x00000092, 0x0000 }, /* R146 - Haptics phase 1 intensity */ + { 0x00000093, 0x0000 }, /* R147 - Haptics phase 1 duration */ + { 0x00000094, 0x0000 }, /* R148 - Haptics phase 2 intensity */ + { 0x00000095, 0x0000 }, /* R149 - Haptics phase 2 duration */ + { 0x00000096, 0x0000 }, /* R150 - Haptics phase 3 intensity */ + { 0x00000097, 0x0000 }, /* R151 - Haptics phase 3 duration */ { 0x00000100, 0x0002 }, /* R256 - Clock 32k 1 */ - { 0x00000101, 0x0304 }, /* R257 - System Clock 1 */ - { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */ - { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */ - { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */ - { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */ - { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */ + { 0x00000101, 0x0304 }, /* R257 - System Clock 1 */ + { 0x00000102, 0x0011 }, /* R258 - Sample rate 1 */ + { 0x00000103, 0x0011 }, /* R259 - Sample rate 2 */ + { 0x00000104, 0x0011 }, /* R260 - Sample rate 3 */ + { 0x00000112, 0x0305 }, /* R274 - Async clock 1 */ + { 0x00000113, 0x0011 }, /* R275 - Async sample rate 1 */ { 0x00000114, 0x0011 }, /* R276 - Async sample rate 2 */ - { 0x00000149, 0x0000 }, /* R329 - Output system clock */ - { 0x0000014A, 0x0000 }, /* R330 - Output async clock */ - { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */ - { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */ - { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */ - { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ - { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ - { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ + { 0x00000149, 0x0000 }, /* R329 - Output system clock */ + { 0x0000014A, 0x0000 }, /* R330 - Output async clock */ + { 0x00000152, 0x0000 }, /* R338 - Rate Estimator 1 */ + { 0x00000153, 0x0000 }, /* R339 - Rate Estimator 2 */ + { 0x00000154, 0x0000 }, /* R340 - Rate Estimator 3 */ + { 0x00000155, 0x0000 }, /* R341 - Rate Estimator 4 */ + { 0x00000156, 0x0000 }, /* R342 - Rate Estimator 5 */ + { 0x00000161, 0x0000 }, /* R353 - Dynamic Frequency Scaling 1 */ { 0x00000171, 0x0000 }, /* R369 - FLL1 Control 1 */ - { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ - { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ - { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ - { 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */ - { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ + { 0x00000172, 0x0008 }, /* R370 - FLL1 Control 2 */ + { 0x00000173, 0x0018 }, /* R371 - FLL1 Control 3 */ + { 0x00000174, 0x007D }, /* R372 - FLL1 Control 4 */ + { 0x00000175, 0x0004 }, /* R373 - FLL1 Control 5 */ + { 0x00000176, 0x0000 }, /* R374 - FLL1 Control 6 */ { 0x00000179, 0x0000 }, /* R377 - FLL1 Control 7 */ - { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ - { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ - { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ - { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ - { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ - { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ + { 0x00000181, 0x0000 }, /* R385 - FLL1 Synchroniser 1 */ + { 0x00000182, 0x0000 }, /* R386 - FLL1 Synchroniser 2 */ + { 0x00000183, 0x0000 }, /* R387 - FLL1 Synchroniser 3 */ + { 0x00000184, 0x0000 }, /* R388 - FLL1 Synchroniser 4 */ + { 0x00000185, 0x0000 }, /* R389 - FLL1 Synchroniser 5 */ + { 0x00000186, 0x0000 }, /* R390 - FLL1 Synchroniser 6 */ { 0x00000187, 0x0001 }, /* R391 - FLL1 Synchroniser 7 */ - { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ - { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */ - { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */ - { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */ - { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */ - { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */ - { 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */ - { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ + { 0x00000189, 0x0000 }, /* R393 - FLL1 Spread Spectrum */ + { 0x0000018A, 0x0004 }, /* R394 - FLL1 GPIO Clock */ + { 0x00000191, 0x0000 }, /* R401 - FLL2 Control 1 */ + { 0x00000192, 0x0008 }, /* R402 - FLL2 Control 2 */ + { 0x00000193, 0x0018 }, /* R403 - FLL2 Control 3 */ + { 0x00000194, 0x007D }, /* R404 - FLL2 Control 4 */ + { 0x00000195, 0x0004 }, /* R405 - FLL2 Control 5 */ + { 0x00000196, 0x0000 }, /* R406 - FLL2 Control 6 */ { 0x00000199, 0x0000 }, /* R409 - FLL2 Control 7 */ - { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ - { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ - { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ - { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ - { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ - { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ + { 0x000001A1, 0x0000 }, /* R417 - FLL2 Synchroniser 1 */ + { 0x000001A2, 0x0000 }, /* R418 - FLL2 Synchroniser 2 */ + { 0x000001A3, 0x0000 }, /* R419 - FLL2 Synchroniser 3 */ + { 0x000001A4, 0x0000 }, /* R420 - FLL2 Synchroniser 4 */ + { 0x000001A5, 0x0000 }, /* R421 - FLL2 Synchroniser 5 */ + { 0x000001A6, 0x0000 }, /* R422 - FLL2 Synchroniser 6 */ { 0x000001A7, 0x0001 }, /* R423 - FLL2 Synchroniser 7 */ - { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ - { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ - { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ - { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */ + { 0x000001A9, 0x0000 }, /* R425 - FLL2 Spread Spectrum */ + { 0x000001AA, 0x0004 }, /* R426 - FLL2 GPIO Clock */ + { 0x00000200, 0x0006 }, /* R512 - Mic Charge Pump 1 */ + { 0x00000210, 0x00D4 }, /* R528 - LDO1 Control 1 */ { 0x00000212, 0x0000 }, /* R530 - LDO1 Control 2 */ - { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */ - { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */ - { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */ - { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */ - { 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */ - { 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */ + { 0x00000213, 0x0344 }, /* R531 - LDO2 Control 1 */ + { 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */ + { 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */ + { 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */ + { 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */ + { 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */ { 0x000002A2, 0x0000 }, /* R674 - Micd clamp control */ - { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ - { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ + { 0x000002A3, 0x1102 }, /* R675 - Mic Detect 1 */ + { 0x000002A4, 0x009F }, /* R676 - Mic Detect 2 */ { 0x000002A6, 0x3737 }, /* R678 - Mic Detect Level 1 */ { 0x000002A7, 0x2C37 }, /* R679 - Mic Detect Level 2 */ { 0x000002A8, 0x1422 }, /* R680 - Mic Detect Level 3 */ { 0x000002A9, 0x030A }, /* R681 - Mic Detect Level 4 */ - { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */ - { 0x000002CB, 0x0000 }, /* R715 - Isolation control */ - { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ - { 0x00000300, 0x0000 }, /* R768 - Input Enables */ - { 0x00000308, 0x0000 }, /* R776 - Input Rate */ - { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */ - { 0x00000310, 0x2080 }, /* R784 - IN1L Control */ - { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */ - { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */ - { 0x00000314, 0x0080 }, /* R788 - IN1R Control */ - { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */ - { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */ - { 0x00000318, 0x2080 }, /* R792 - IN2L Control */ - { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */ - { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */ - { 0x0000031C, 0x0080 }, /* R796 - IN2R Control */ - { 0x0000031D, 0x0180 }, /* R797 - ADC Digital Volume 2R */ - { 0x0000031E, 0x0000 }, /* R798 - DMIC2R Control */ - { 0x00000320, 0x2080 }, /* R800 - IN3L Control */ - { 0x00000321, 0x0180 }, /* R801 - ADC Digital Volume 3L */ - { 0x00000322, 0x0000 }, /* R802 - DMIC3L Control */ - { 0x00000324, 0x0080 }, /* R804 - IN3R Control */ - { 0x00000325, 0x0180 }, /* R805 - ADC Digital Volume 3R */ - { 0x00000326, 0x0000 }, /* R806 - DMIC3R Control */ - { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ - { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ - { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ + { 0x000002C3, 0x0000 }, /* R707 - Mic noise mix control 1 */ + { 0x000002CB, 0x0000 }, /* R715 - Isolation control */ + { 0x000002D3, 0x0000 }, /* R723 - Jack detect analogue */ + { 0x00000300, 0x0000 }, /* R768 - Input Enables */ + { 0x00000308, 0x0000 }, /* R776 - Input Rate */ + { 0x00000309, 0x0022 }, /* R777 - Input Volume Ramp */ + { 0x00000310, 0x2080 }, /* R784 - IN1L Control */ + { 0x00000311, 0x0180 }, /* R785 - ADC Digital Volume 1L */ + { 0x00000312, 0x0000 }, /* R786 - DMIC1L Control */ + { 0x00000314, 0x0080 }, /* R788 - IN1R Control */ + { 0x00000315, 0x0180 }, /* R789 - ADC Digital Volume 1R */ + { 0x00000316, 0x0000 }, /* R790 - DMIC1R Control */ + { 0x00000318, 0x2080 }, /* R792 - IN2L Control */ + { 0x00000319, 0x0180 }, /* R793 - ADC Digital Volume 2L */ + { 0x0000031A, 0x0000 }, /* R794 - DMIC2L Control */ + { 0x0000031C, 0x0080 }, /* R796 - IN2R Control */ + { 0x0000031D, 0x0180 }, /* R797 - ADC Digital Volume 2R */ + { 0x0000031E, 0x0000 }, /* R798 - DMIC2R Control */ + { 0x00000320, 0x2080 }, /* R800 - IN3L Control */ + { 0x00000321, 0x0180 }, /* R801 - ADC Digital Volume 3L */ + { 0x00000322, 0x0000 }, /* R802 - DMIC3L Control */ + { 0x00000324, 0x0080 }, /* R804 - IN3R Control */ + { 0x00000325, 0x0180 }, /* R805 - ADC Digital Volume 3R */ + { 0x00000326, 0x0000 }, /* R806 - DMIC3R Control */ + { 0x00000400, 0x0000 }, /* R1024 - Output Enables 1 */ + { 0x00000408, 0x0000 }, /* R1032 - Output Rate 1 */ + { 0x00000409, 0x0022 }, /* R1033 - Output Volume Ramp */ { 0x00000410, 0x6080 }, /* R1040 - Output Path Config 1L */ - { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ + { 0x00000411, 0x0180 }, /* R1041 - DAC Digital Volume 1L */ { 0x00000412, 0x0081 }, /* R1042 - DAC Volume Limit 1L */ - { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ - { 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */ - { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ + { 0x00000413, 0x0001 }, /* R1043 - Noise Gate Select 1L */ + { 0x00000414, 0x0080 }, /* R1044 - Output Path Config 1R */ + { 0x00000415, 0x0180 }, /* R1045 - DAC Digital Volume 1R */ { 0x00000416, 0x0081 }, /* R1046 - DAC Volume Limit 1R */ - { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ + { 0x00000417, 0x0002 }, /* R1047 - Noise Gate Select 1R */ { 0x00000418, 0xA080 }, /* R1048 - Output Path Config 2L */ - { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ + { 0x00000419, 0x0180 }, /* R1049 - DAC Digital Volume 2L */ { 0x0000041A, 0x0081 }, /* R1050 - DAC Volume Limit 2L */ - { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ - { 0x0000041C, 0x0080 }, /* R1052 - Output Path Config 2R */ - { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ + { 0x0000041B, 0x0004 }, /* R1051 - Noise Gate Select 2L */ + { 0x0000041C, 0x0080 }, /* R1052 - Output Path Config 2R */ + { 0x0000041D, 0x0180 }, /* R1053 - DAC Digital Volume 2R */ { 0x0000041E, 0x0081 }, /* R1054 - DAC Volume Limit 2R */ - { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ + { 0x0000041F, 0x0008 }, /* R1055 - Noise Gate Select 2R */ { 0x00000420, 0xA080 }, /* R1056 - Output Path Config 3L */ - { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ + { 0x00000421, 0x0180 }, /* R1057 - DAC Digital Volume 3L */ { 0x00000422, 0x0081 }, /* R1058 - DAC Volume Limit 3L */ - { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ + { 0x00000423, 0x0010 }, /* R1059 - Noise Gate Select 3L */ { 0x00000428, 0xE000 }, /* R1064 - Output Path Config 4L */ - { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ + { 0x00000429, 0x0180 }, /* R1065 - DAC Digital Volume 4L */ { 0x0000042A, 0x0081 }, /* R1066 - Out Volume 4L */ - { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ - { 0x0000042D, 0x0180 }, /* R1069 - DAC Digital Volume 4R */ + { 0x0000042B, 0x0040 }, /* R1067 - Noise Gate Select 4L */ + { 0x0000042D, 0x0180 }, /* R1069 - DAC Digital Volume 4R */ { 0x0000042E, 0x0081 }, /* R1070 - Out Volume 4R */ - { 0x0000042F, 0x0080 }, /* R1071 - Noise Gate Select 4R */ - { 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */ - { 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */ + { 0x0000042F, 0x0080 }, /* R1071 - Noise Gate Select 4R */ + { 0x00000430, 0x0000 }, /* R1072 - Output Path Config 5L */ + { 0x00000431, 0x0180 }, /* R1073 - DAC Digital Volume 5L */ { 0x00000432, 0x0081 }, /* R1074 - DAC Volume Limit 5L */ - { 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */ - { 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */ + { 0x00000433, 0x0100 }, /* R1075 - Noise Gate Select 5L */ + { 0x00000435, 0x0180 }, /* R1077 - DAC Digital Volume 5R */ { 0x00000436, 0x0081 }, /* R1078 - DAC Volume Limit 5R */ { 0x00000437, 0x0200 }, /* R1079 - Noise Gate Select 5R */ { 0x00000440, 0x0FFF }, /* R1088 - DRE Enable */ { 0x00000442, 0x3F0A }, /* R1090 - DRE Control 2 */ { 0x00000443, 0xDC1F }, /* R1090 - DRE Control 3 */ - { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ + { 0x00000450, 0x0000 }, /* R1104 - DAC AEC Control 1 */ { 0x00000458, 0x000B }, /* R1112 - Noise Gate Control */ - { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ - { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ - { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ - { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */ - { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */ - { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */ - { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */ - { 0x00000505, 0x0040 }, /* R1285 - AIF1 Tx BCLK Rate */ - { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */ - { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */ - { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */ - { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */ - { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */ - { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */ - { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */ - { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */ - { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */ - { 0x0000050F, 0x0006 }, /* R1295 - AIF1 Frame Ctrl 9 */ - { 0x00000510, 0x0007 }, /* R1296 - AIF1 Frame Ctrl 10 */ - { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */ - { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */ - { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */ - { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */ - { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */ - { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */ - { 0x00000517, 0x0006 }, /* R1303 - AIF1 Frame Ctrl 17 */ - { 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */ - { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */ - { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */ - { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */ - { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */ - { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */ - { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */ - { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */ - { 0x00000545, 0x0040 }, /* R1349 - AIF2 Tx BCLK Rate */ - { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */ - { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */ - { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */ - { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */ - { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */ - { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */ - { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */ - { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */ - { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */ - { 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */ - { 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */ - { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */ - { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */ - { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */ - { 0x00000585, 0x0040 }, /* R1413 - AIF3 Tx BCLK Rate */ - { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */ - { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */ - { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */ - { 0x00000589, 0x0000 }, /* R1417 - AIF3 Frame Ctrl 3 */ - { 0x0000058A, 0x0001 }, /* R1418 - AIF3 Frame Ctrl 4 */ - { 0x00000591, 0x0000 }, /* R1425 - AIF3 Frame Ctrl 11 */ - { 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */ - { 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */ - { 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */ - { 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */ - { 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */ - { 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */ - { 0x000005E7, 0x0000 }, /* R1511 - SLIMbus Rates 3 */ - { 0x000005E8, 0x0000 }, /* R1512 - SLIMbus Rates 4 */ - { 0x000005E9, 0x0000 }, /* R1513 - SLIMbus Rates 5 */ - { 0x000005EA, 0x0000 }, /* R1514 - SLIMbus Rates 6 */ - { 0x000005EB, 0x0000 }, /* R1515 - SLIMbus Rates 7 */ - { 0x000005EC, 0x0000 }, /* R1516 - SLIMbus Rates 8 */ - { 0x000005F5, 0x0000 }, /* R1525 - SLIMbus RX Channel Enable */ - { 0x000005F6, 0x0000 }, /* R1526 - SLIMbus TX Channel Enable */ - { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */ - { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */ - { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */ - { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */ - { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */ - { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */ - { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */ - { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */ - { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */ - { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */ - { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */ - { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */ - { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */ - { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */ - { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */ - { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */ - { 0x00000660, 0x0000 }, /* R1632 - MICMIX Input 1 Source */ - { 0x00000661, 0x0080 }, /* R1633 - MICMIX Input 1 Volume */ - { 0x00000662, 0x0000 }, /* R1634 - MICMIX Input 2 Source */ - { 0x00000663, 0x0080 }, /* R1635 - MICMIX Input 2 Volume */ - { 0x00000664, 0x0000 }, /* R1636 - MICMIX Input 3 Source */ - { 0x00000665, 0x0080 }, /* R1637 - MICMIX Input 3 Volume */ - { 0x00000666, 0x0000 }, /* R1638 - MICMIX Input 4 Source */ - { 0x00000667, 0x0080 }, /* R1639 - MICMIX Input 4 Volume */ - { 0x00000668, 0x0000 }, /* R1640 - NOISEMIX Input 1 Source */ - { 0x00000669, 0x0080 }, /* R1641 - NOISEMIX Input 1 Volume */ - { 0x0000066A, 0x0000 }, /* R1642 - NOISEMIX Input 2 Source */ - { 0x0000066B, 0x0080 }, /* R1643 - NOISEMIX Input 2 Volume */ - { 0x0000066C, 0x0000 }, /* R1644 - NOISEMIX Input 3 Source */ - { 0x0000066D, 0x0080 }, /* R1645 - NOISEMIX Input 3 Volume */ - { 0x0000066E, 0x0000 }, /* R1646 - NOISEMIX Input 4 Source */ - { 0x0000066F, 0x0080 }, /* R1647 - NOISEMIX Input 4 Volume */ - { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */ - { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */ - { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */ - { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */ - { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */ - { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */ - { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */ - { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */ - { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */ - { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */ - { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */ - { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */ - { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */ - { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */ - { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */ - { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */ - { 0x00000690, 0x0000 }, /* R1680 - OUT2LMIX Input 1 Source */ - { 0x00000691, 0x0080 }, /* R1681 - OUT2LMIX Input 1 Volume */ - { 0x00000692, 0x0000 }, /* R1682 - OUT2LMIX Input 2 Source */ - { 0x00000693, 0x0080 }, /* R1683 - OUT2LMIX Input 2 Volume */ - { 0x00000694, 0x0000 }, /* R1684 - OUT2LMIX Input 3 Source */ - { 0x00000695, 0x0080 }, /* R1685 - OUT2LMIX Input 3 Volume */ - { 0x00000696, 0x0000 }, /* R1686 - OUT2LMIX Input 4 Source */ - { 0x00000697, 0x0080 }, /* R1687 - OUT2LMIX Input 4 Volume */ - { 0x00000698, 0x0000 }, /* R1688 - OUT2RMIX Input 1 Source */ - { 0x00000699, 0x0080 }, /* R1689 - OUT2RMIX Input 1 Volume */ - { 0x0000069A, 0x0000 }, /* R1690 - OUT2RMIX Input 2 Source */ - { 0x0000069B, 0x0080 }, /* R1691 - OUT2RMIX Input 2 Volume */ - { 0x0000069C, 0x0000 }, /* R1692 - OUT2RMIX Input 3 Source */ - { 0x0000069D, 0x0080 }, /* R1693 - OUT2RMIX Input 3 Volume */ - { 0x0000069E, 0x0000 }, /* R1694 - OUT2RMIX Input 4 Source */ - { 0x0000069F, 0x0080 }, /* R1695 - OUT2RMIX Input 4 Volume */ - { 0x000006A0, 0x0000 }, /* R1696 - OUT3LMIX Input 1 Source */ - { 0x000006A1, 0x0080 }, /* R1697 - OUT3LMIX Input 1 Volume */ - { 0x000006A2, 0x0000 }, /* R1698 - OUT3LMIX Input 2 Source */ - { 0x000006A3, 0x0080 }, /* R1699 - OUT3LMIX Input 2 Volume */ - { 0x000006A4, 0x0000 }, /* R1700 - OUT3LMIX Input 3 Source */ - { 0x000006A5, 0x0080 }, /* R1701 - OUT3LMIX Input 3 Volume */ - { 0x000006A6, 0x0000 }, /* R1702 - OUT3LMIX Input 4 Source */ - { 0x000006A7, 0x0080 }, /* R1703 - OUT3LMIX Input 4 Volume */ - { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */ - { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */ - { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */ - { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */ - { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */ - { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */ - { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */ - { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */ - { 0x000006B8, 0x0000 }, /* R1720 - OUT4RMIX Input 1 Source */ - { 0x000006B9, 0x0080 }, /* R1721 - OUT4RMIX Input 1 Volume */ - { 0x000006BA, 0x0000 }, /* R1722 - OUT4RMIX Input 2 Source */ - { 0x000006BB, 0x0080 }, /* R1723 - OUT4RMIX Input 2 Volume */ - { 0x000006BC, 0x0000 }, /* R1724 - OUT4RMIX Input 3 Source */ - { 0x000006BD, 0x0080 }, /* R1725 - OUT4RMIX Input 3 Volume */ - { 0x000006BE, 0x0000 }, /* R1726 - OUT4RMIX Input 4 Source */ - { 0x000006BF, 0x0080 }, /* R1727 - OUT4RMIX Input 4 Volume */ - { 0x000006C0, 0x0000 }, /* R1728 - OUT5LMIX Input 1 Source */ - { 0x000006C1, 0x0080 }, /* R1729 - OUT5LMIX Input 1 Volume */ - { 0x000006C2, 0x0000 }, /* R1730 - OUT5LMIX Input 2 Source */ - { 0x000006C3, 0x0080 }, /* R1731 - OUT5LMIX Input 2 Volume */ - { 0x000006C4, 0x0000 }, /* R1732 - OUT5LMIX Input 3 Source */ - { 0x000006C5, 0x0080 }, /* R1733 - OUT5LMIX Input 3 Volume */ - { 0x000006C6, 0x0000 }, /* R1734 - OUT5LMIX Input 4 Source */ - { 0x000006C7, 0x0080 }, /* R1735 - OUT5LMIX Input 4 Volume */ - { 0x000006C8, 0x0000 }, /* R1736 - OUT5RMIX Input 1 Source */ - { 0x000006C9, 0x0080 }, /* R1737 - OUT5RMIX Input 1 Volume */ - { 0x000006CA, 0x0000 }, /* R1738 - OUT5RMIX Input 2 Source */ - { 0x000006CB, 0x0080 }, /* R1739 - OUT5RMIX Input 2 Volume */ - { 0x000006CC, 0x0000 }, /* R1740 - OUT5RMIX Input 3 Source */ - { 0x000006CD, 0x0080 }, /* R1741 - OUT5RMIX Input 3 Volume */ - { 0x000006CE, 0x0000 }, /* R1742 - OUT5RMIX Input 4 Source */ - { 0x000006CF, 0x0080 }, /* R1743 - OUT5RMIX Input 4 Volume */ - { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */ - { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */ - { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */ - { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */ - { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */ - { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */ - { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */ - { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */ - { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */ - { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */ - { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */ - { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */ - { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */ - { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */ - { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */ - { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */ - { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */ - { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */ - { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */ - { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */ - { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */ - { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */ - { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */ - { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */ - { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */ - { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */ - { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */ - { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */ - { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */ - { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */ - { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */ - { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */ - { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */ - { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */ - { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */ - { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */ - { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */ - { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */ - { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */ - { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */ - { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */ - { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */ - { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */ - { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */ - { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */ - { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */ - { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */ - { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */ - { 0x00000730, 0x0000 }, /* R1840 - AIF1TX7MIX Input 1 Source */ - { 0x00000731, 0x0080 }, /* R1841 - AIF1TX7MIX Input 1 Volume */ - { 0x00000732, 0x0000 }, /* R1842 - AIF1TX7MIX Input 2 Source */ - { 0x00000733, 0x0080 }, /* R1843 - AIF1TX7MIX Input 2 Volume */ - { 0x00000734, 0x0000 }, /* R1844 - AIF1TX7MIX Input 3 Source */ - { 0x00000735, 0x0080 }, /* R1845 - AIF1TX7MIX Input 3 Volume */ - { 0x00000736, 0x0000 }, /* R1846 - AIF1TX7MIX Input 4 Source */ - { 0x00000737, 0x0080 }, /* R1847 - AIF1TX7MIX Input 4 Volume */ - { 0x00000738, 0x0000 }, /* R1848 - AIF1TX8MIX Input 1 Source */ - { 0x00000739, 0x0080 }, /* R1849 - AIF1TX8MIX Input 1 Volume */ - { 0x0000073A, 0x0000 }, /* R1850 - AIF1TX8MIX Input 2 Source */ - { 0x0000073B, 0x0080 }, /* R1851 - AIF1TX8MIX Input 2 Volume */ - { 0x0000073C, 0x0000 }, /* R1852 - AIF1TX8MIX Input 3 Source */ - { 0x0000073D, 0x0080 }, /* R1853 - AIF1TX8MIX Input 3 Volume */ - { 0x0000073E, 0x0000 }, /* R1854 - AIF1TX8MIX Input 4 Source */ - { 0x0000073F, 0x0080 }, /* R1855 - AIF1TX8MIX Input 4 Volume */ - { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */ - { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */ - { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */ - { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */ - { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */ - { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */ - { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */ - { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */ - { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */ - { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */ - { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */ - { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */ - { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */ - { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */ - { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */ - { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */ - { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */ - { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */ - { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */ - { 0x00000783, 0x0080 }, /* R1923 - AIF3TX1MIX Input 2 Volume */ - { 0x00000784, 0x0000 }, /* R1924 - AIF3TX1MIX Input 3 Source */ - { 0x00000785, 0x0080 }, /* R1925 - AIF3TX1MIX Input 3 Volume */ - { 0x00000786, 0x0000 }, /* R1926 - AIF3TX1MIX Input 4 Source */ - { 0x00000787, 0x0080 }, /* R1927 - AIF3TX1MIX Input 4 Volume */ - { 0x00000788, 0x0000 }, /* R1928 - AIF3TX2MIX Input 1 Source */ - { 0x00000789, 0x0080 }, /* R1929 - AIF3TX2MIX Input 1 Volume */ - { 0x0000078A, 0x0000 }, /* R1930 - AIF3TX2MIX Input 2 Source */ - { 0x0000078B, 0x0080 }, /* R1931 - AIF3TX2MIX Input 2 Volume */ - { 0x0000078C, 0x0000 }, /* R1932 - AIF3TX2MIX Input 3 Source */ - { 0x0000078D, 0x0080 }, /* R1933 - AIF3TX2MIX Input 3 Volume */ - { 0x0000078E, 0x0000 }, /* R1934 - AIF3TX2MIX Input 4 Source */ - { 0x0000078F, 0x0080 }, /* R1935 - AIF3TX2MIX Input 4 Volume */ - { 0x000007C0, 0x0000 }, /* R1984 - SLIMTX1MIX Input 1 Source */ - { 0x000007C1, 0x0080 }, /* R1985 - SLIMTX1MIX Input 1 Volume */ - { 0x000007C2, 0x0000 }, /* R1986 - SLIMTX1MIX Input 2 Source */ - { 0x000007C3, 0x0080 }, /* R1987 - SLIMTX1MIX Input 2 Volume */ - { 0x000007C4, 0x0000 }, /* R1988 - SLIMTX1MIX Input 3 Source */ - { 0x000007C5, 0x0080 }, /* R1989 - SLIMTX1MIX Input 3 Volume */ - { 0x000007C6, 0x0000 }, /* R1990 - SLIMTX1MIX Input 4 Source */ - { 0x000007C7, 0x0080 }, /* R1991 - SLIMTX1MIX Input 4 Volume */ - { 0x000007C8, 0x0000 }, /* R1992 - SLIMTX2MIX Input 1 Source */ - { 0x000007C9, 0x0080 }, /* R1993 - SLIMTX2MIX Input 1 Volume */ - { 0x000007CA, 0x0000 }, /* R1994 - SLIMTX2MIX Input 2 Source */ - { 0x000007CB, 0x0080 }, /* R1995 - SLIMTX2MIX Input 2 Volume */ - { 0x000007CC, 0x0000 }, /* R1996 - SLIMTX2MIX Input 3 Source */ - { 0x000007CD, 0x0080 }, /* R1997 - SLIMTX2MIX Input 3 Volume */ - { 0x000007CE, 0x0000 }, /* R1998 - SLIMTX2MIX Input 4 Source */ - { 0x000007CF, 0x0080 }, /* R1999 - SLIMTX2MIX Input 4 Volume */ - { 0x000007D0, 0x0000 }, /* R2000 - SLIMTX3MIX Input 1 Source */ - { 0x000007D1, 0x0080 }, /* R2001 - SLIMTX3MIX Input 1 Volume */ - { 0x000007D2, 0x0000 }, /* R2002 - SLIMTX3MIX Input 2 Source */ - { 0x000007D3, 0x0080 }, /* R2003 - SLIMTX3MIX Input 2 Volume */ - { 0x000007D4, 0x0000 }, /* R2004 - SLIMTX3MIX Input 3 Source */ - { 0x000007D5, 0x0080 }, /* R2005 - SLIMTX3MIX Input 3 Volume */ - { 0x000007D6, 0x0000 }, /* R2006 - SLIMTX3MIX Input 4 Source */ - { 0x000007D7, 0x0080 }, /* R2007 - SLIMTX3MIX Input 4 Volume */ - { 0x000007D8, 0x0000 }, /* R2008 - SLIMTX4MIX Input 1 Source */ - { 0x000007D9, 0x0080 }, /* R2009 - SLIMTX4MIX Input 1 Volume */ - { 0x000007DA, 0x0000 }, /* R2010 - SLIMTX4MIX Input 2 Source */ - { 0x000007DB, 0x0080 }, /* R2011 - SLIMTX4MIX Input 2 Volume */ - { 0x000007DC, 0x0000 }, /* R2012 - SLIMTX4MIX Input 3 Source */ - { 0x000007DD, 0x0080 }, /* R2013 - SLIMTX4MIX Input 3 Volume */ - { 0x000007DE, 0x0000 }, /* R2014 - SLIMTX4MIX Input 4 Source */ - { 0x000007DF, 0x0080 }, /* R2015 - SLIMTX4MIX Input 4 Volume */ - { 0x000007E0, 0x0000 }, /* R2016 - SLIMTX5MIX Input 1 Source */ - { 0x000007E1, 0x0080 }, /* R2017 - SLIMTX5MIX Input 1 Volume */ - { 0x000007E2, 0x0000 }, /* R2018 - SLIMTX5MIX Input 2 Source */ - { 0x000007E3, 0x0080 }, /* R2019 - SLIMTX5MIX Input 2 Volume */ - { 0x000007E4, 0x0000 }, /* R2020 - SLIMTX5MIX Input 3 Source */ - { 0x000007E5, 0x0080 }, /* R2021 - SLIMTX5MIX Input 3 Volume */ - { 0x000007E6, 0x0000 }, /* R2022 - SLIMTX5MIX Input 4 Source */ - { 0x000007E7, 0x0080 }, /* R2023 - SLIMTX5MIX Input 4 Volume */ - { 0x000007E8, 0x0000 }, /* R2024 - SLIMTX6MIX Input 1 Source */ - { 0x000007E9, 0x0080 }, /* R2025 - SLIMTX6MIX Input 1 Volume */ - { 0x000007EA, 0x0000 }, /* R2026 - SLIMTX6MIX Input 2 Source */ - { 0x000007EB, 0x0080 }, /* R2027 - SLIMTX6MIX Input 2 Volume */ - { 0x000007EC, 0x0000 }, /* R2028 - SLIMTX6MIX Input 3 Source */ - { 0x000007ED, 0x0080 }, /* R2029 - SLIMTX6MIX Input 3 Volume */ - { 0x000007EE, 0x0000 }, /* R2030 - SLIMTX6MIX Input 4 Source */ - { 0x000007EF, 0x0080 }, /* R2031 - SLIMTX6MIX Input 4 Volume */ - { 0x000007F0, 0x0000 }, /* R2032 - SLIMTX7MIX Input 1 Source */ - { 0x000007F1, 0x0080 }, /* R2033 - SLIMTX7MIX Input 1 Volume */ - { 0x000007F2, 0x0000 }, /* R2034 - SLIMTX7MIX Input 2 Source */ - { 0x000007F3, 0x0080 }, /* R2035 - SLIMTX7MIX Input 2 Volume */ - { 0x000007F4, 0x0000 }, /* R2036 - SLIMTX7MIX Input 3 Source */ - { 0x000007F5, 0x0080 }, /* R2037 - SLIMTX7MIX Input 3 Volume */ - { 0x000007F6, 0x0000 }, /* R2038 - SLIMTX7MIX Input 4 Source */ - { 0x000007F7, 0x0080 }, /* R2039 - SLIMTX7MIX Input 4 Volume */ - { 0x000007F8, 0x0000 }, /* R2040 - SLIMTX8MIX Input 1 Source */ - { 0x000007F9, 0x0080 }, /* R2041 - SLIMTX8MIX Input 1 Volume */ - { 0x000007FA, 0x0000 }, /* R2042 - SLIMTX8MIX Input 2 Source */ - { 0x000007FB, 0x0080 }, /* R2043 - SLIMTX8MIX Input 2 Volume */ - { 0x000007FC, 0x0000 }, /* R2044 - SLIMTX8MIX Input 3 Source */ - { 0x000007FD, 0x0080 }, /* R2045 - SLIMTX8MIX Input 3 Volume */ - { 0x000007FE, 0x0000 }, /* R2046 - SLIMTX8MIX Input 4 Source */ - { 0x000007FF, 0x0080 }, /* R2047 - SLIMTX8MIX Input 4 Volume */ - { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */ - { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */ - { 0x00000882, 0x0000 }, /* R2178 - EQ1MIX Input 2 Source */ - { 0x00000883, 0x0080 }, /* R2179 - EQ1MIX Input 2 Volume */ - { 0x00000884, 0x0000 }, /* R2180 - EQ1MIX Input 3 Source */ - { 0x00000885, 0x0080 }, /* R2181 - EQ1MIX Input 3 Volume */ - { 0x00000886, 0x0000 }, /* R2182 - EQ1MIX Input 4 Source */ - { 0x00000887, 0x0080 }, /* R2183 - EQ1MIX Input 4 Volume */ - { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */ - { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */ - { 0x0000088A, 0x0000 }, /* R2186 - EQ2MIX Input 2 Source */ - { 0x0000088B, 0x0080 }, /* R2187 - EQ2MIX Input 2 Volume */ - { 0x0000088C, 0x0000 }, /* R2188 - EQ2MIX Input 3 Source */ - { 0x0000088D, 0x0080 }, /* R2189 - EQ2MIX Input 3 Volume */ - { 0x0000088E, 0x0000 }, /* R2190 - EQ2MIX Input 4 Source */ - { 0x0000088F, 0x0080 }, /* R2191 - EQ2MIX Input 4 Volume */ - { 0x00000890, 0x0000 }, /* R2192 - EQ3MIX Input 1 Source */ - { 0x00000891, 0x0080 }, /* R2193 - EQ3MIX Input 1 Volume */ - { 0x00000892, 0x0000 }, /* R2194 - EQ3MIX Input 2 Source */ - { 0x00000893, 0x0080 }, /* R2195 - EQ3MIX Input 2 Volume */ - { 0x00000894, 0x0000 }, /* R2196 - EQ3MIX Input 3 Source */ - { 0x00000895, 0x0080 }, /* R2197 - EQ3MIX Input 3 Volume */ - { 0x00000896, 0x0000 }, /* R2198 - EQ3MIX Input 4 Source */ - { 0x00000897, 0x0080 }, /* R2199 - EQ3MIX Input 4 Volume */ - { 0x00000898, 0x0000 }, /* R2200 - EQ4MIX Input 1 Source */ - { 0x00000899, 0x0080 }, /* R2201 - EQ4MIX Input 1 Volume */ - { 0x0000089A, 0x0000 }, /* R2202 - EQ4MIX Input 2 Source */ - { 0x0000089B, 0x0080 }, /* R2203 - EQ4MIX Input 2 Volume */ - { 0x0000089C, 0x0000 }, /* R2204 - EQ4MIX Input 3 Source */ - { 0x0000089D, 0x0080 }, /* R2205 - EQ4MIX Input 3 Volume */ - { 0x0000089E, 0x0000 }, /* R2206 - EQ4MIX Input 4 Source */ - { 0x0000089F, 0x0080 }, /* R2207 - EQ4MIX Input 4 Volume */ - { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */ - { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */ - { 0x000008C2, 0x0000 }, /* R2242 - DRC1LMIX Input 2 Source */ - { 0x000008C3, 0x0080 }, /* R2243 - DRC1LMIX Input 2 Volume */ - { 0x000008C4, 0x0000 }, /* R2244 - DRC1LMIX Input 3 Source */ - { 0x000008C5, 0x0080 }, /* R2245 - DRC1LMIX Input 3 Volume */ - { 0x000008C6, 0x0000 }, /* R2246 - DRC1LMIX Input 4 Source */ - { 0x000008C7, 0x0080 }, /* R2247 - DRC1LMIX Input 4 Volume */ - { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */ - { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */ - { 0x000008CA, 0x0000 }, /* R2250 - DRC1RMIX Input 2 Source */ - { 0x000008CB, 0x0080 }, /* R2251 - DRC1RMIX Input 2 Volume */ - { 0x000008CC, 0x0000 }, /* R2252 - DRC1RMIX Input 3 Source */ - { 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */ - { 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */ - { 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */ - { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */ - { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */ - { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */ - { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */ - { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */ - { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */ - { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */ - { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */ - { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */ - { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */ - { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */ - { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */ - { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */ - { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */ - { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */ - { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */ - { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */ - { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */ - { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */ - { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */ - { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */ - { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */ - { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */ - { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */ - { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */ - { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */ - { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */ - { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */ - { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */ - { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */ - { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */ - { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */ - { 0x00000940, 0x0000 }, /* R2368 - DSP1LMIX Input 1 Source */ - { 0x00000941, 0x0080 }, /* R2369 - DSP1LMIX Input 1 Volume */ - { 0x00000942, 0x0000 }, /* R2370 - DSP1LMIX Input 2 Source */ - { 0x00000943, 0x0080 }, /* R2371 - DSP1LMIX Input 2 Volume */ - { 0x00000944, 0x0000 }, /* R2372 - DSP1LMIX Input 3 Source */ - { 0x00000945, 0x0080 }, /* R2373 - DSP1LMIX Input 3 Volume */ - { 0x00000946, 0x0000 }, /* R2374 - DSP1LMIX Input 4 Source */ - { 0x00000947, 0x0080 }, /* R2375 - DSP1LMIX Input 4 Volume */ - { 0x00000948, 0x0000 }, /* R2376 - DSP1RMIX Input 1 Source */ - { 0x00000949, 0x0080 }, /* R2377 - DSP1RMIX Input 1 Volume */ - { 0x0000094A, 0x0000 }, /* R2378 - DSP1RMIX Input 2 Source */ - { 0x0000094B, 0x0080 }, /* R2379 - DSP1RMIX Input 2 Volume */ - { 0x0000094C, 0x0000 }, /* R2380 - DSP1RMIX Input 3 Source */ - { 0x0000094D, 0x0080 }, /* R2381 - DSP1RMIX Input 3 Volume */ - { 0x0000094E, 0x0000 }, /* R2382 - DSP1RMIX Input 4 Source */ - { 0x0000094F, 0x0080 }, /* R2383 - DSP1RMIX Input 4 Volume */ - { 0x00000950, 0x0000 }, /* R2384 - DSP1AUX1MIX Input 1 Source */ - { 0x00000958, 0x0000 }, /* R2392 - DSP1AUX2MIX Input 1 Source */ - { 0x00000960, 0x0000 }, /* R2400 - DSP1AUX3MIX Input 1 Source */ - { 0x00000968, 0x0000 }, /* R2408 - DSP1AUX4MIX Input 1 Source */ - { 0x00000970, 0x0000 }, /* R2416 - DSP1AUX5MIX Input 1 Source */ - { 0x00000978, 0x0000 }, /* R2424 - DSP1AUX6MIX Input 1 Source */ - { 0x00000A80, 0x0000 }, /* R2688 - ASRC1LMIX Input 1 Source */ - { 0x00000A88, 0x0000 }, /* R2696 - ASRC1RMIX Input 1 Source */ - { 0x00000A90, 0x0000 }, /* R2704 - ASRC2LMIX Input 1 Source */ - { 0x00000A98, 0x0000 }, /* R2712 - ASRC2RMIX Input 1 Source */ - { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */ - { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */ - { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */ - { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */ - { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */ - { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */ - { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */ - { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */ - { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */ - { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */ - { 0x00000C02, 0xA101 }, /* R3074 - GPIO3 CTRL */ - { 0x00000C03, 0xA101 }, /* R3075 - GPIO4 CTRL */ - { 0x00000C04, 0xA101 }, /* R3076 - GPIO5 CTRL */ - { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */ - { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */ - { 0x00000C20, 0x8002 }, /* R3104 - Misc Pad Ctrl 1 */ + { 0x00000490, 0x0069 }, /* R1168 - PDM SPK1 CTRL 1 */ + { 0x00000491, 0x0000 }, /* R1169 - PDM SPK1 CTRL 2 */ + { 0x00000500, 0x000C }, /* R1280 - AIF1 BCLK Ctrl */ + { 0x00000501, 0x0008 }, /* R1281 - AIF1 Tx Pin Ctrl */ + { 0x00000502, 0x0000 }, /* R1282 - AIF1 Rx Pin Ctrl */ + { 0x00000503, 0x0000 }, /* R1283 - AIF1 Rate Ctrl */ + { 0x00000504, 0x0000 }, /* R1284 - AIF1 Format */ + { 0x00000505, 0x0040 }, /* R1285 - AIF1 Tx BCLK Rate */ + { 0x00000506, 0x0040 }, /* R1286 - AIF1 Rx BCLK Rate */ + { 0x00000507, 0x1818 }, /* R1287 - AIF1 Frame Ctrl 1 */ + { 0x00000508, 0x1818 }, /* R1288 - AIF1 Frame Ctrl 2 */ + { 0x00000509, 0x0000 }, /* R1289 - AIF1 Frame Ctrl 3 */ + { 0x0000050A, 0x0001 }, /* R1290 - AIF1 Frame Ctrl 4 */ + { 0x0000050B, 0x0002 }, /* R1291 - AIF1 Frame Ctrl 5 */ + { 0x0000050C, 0x0003 }, /* R1292 - AIF1 Frame Ctrl 6 */ + { 0x0000050D, 0x0004 }, /* R1293 - AIF1 Frame Ctrl 7 */ + { 0x0000050E, 0x0005 }, /* R1294 - AIF1 Frame Ctrl 8 */ + { 0x0000050F, 0x0006 }, /* R1295 - AIF1 Frame Ctrl 9 */ + { 0x00000510, 0x0007 }, /* R1296 - AIF1 Frame Ctrl 10 */ + { 0x00000511, 0x0000 }, /* R1297 - AIF1 Frame Ctrl 11 */ + { 0x00000512, 0x0001 }, /* R1298 - AIF1 Frame Ctrl 12 */ + { 0x00000513, 0x0002 }, /* R1299 - AIF1 Frame Ctrl 13 */ + { 0x00000514, 0x0003 }, /* R1300 - AIF1 Frame Ctrl 14 */ + { 0x00000515, 0x0004 }, /* R1301 - AIF1 Frame Ctrl 15 */ + { 0x00000516, 0x0005 }, /* R1302 - AIF1 Frame Ctrl 16 */ + { 0x00000517, 0x0006 }, /* R1303 - AIF1 Frame Ctrl 17 */ + { 0x00000518, 0x0007 }, /* R1304 - AIF1 Frame Ctrl 18 */ + { 0x00000519, 0x0000 }, /* R1305 - AIF1 Tx Enables */ + { 0x0000051A, 0x0000 }, /* R1306 - AIF1 Rx Enables */ + { 0x00000540, 0x000C }, /* R1344 - AIF2 BCLK Ctrl */ + { 0x00000541, 0x0008 }, /* R1345 - AIF2 Tx Pin Ctrl */ + { 0x00000542, 0x0000 }, /* R1346 - AIF2 Rx Pin Ctrl */ + { 0x00000543, 0x0000 }, /* R1347 - AIF2 Rate Ctrl */ + { 0x00000544, 0x0000 }, /* R1348 - AIF2 Format */ + { 0x00000545, 0x0040 }, /* R1349 - AIF2 Tx BCLK Rate */ + { 0x00000546, 0x0040 }, /* R1350 - AIF2 Rx BCLK Rate */ + { 0x00000547, 0x1818 }, /* R1351 - AIF2 Frame Ctrl 1 */ + { 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */ + { 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */ + { 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */ + { 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */ + { 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */ + { 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */ + { 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */ + { 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */ + { 0x00000581, 0x0008 }, /* R1409 - AIF3 Tx Pin Ctrl */ + { 0x00000582, 0x0000 }, /* R1410 - AIF3 Rx Pin Ctrl */ + { 0x00000583, 0x0000 }, /* R1411 - AIF3 Rate Ctrl */ + { 0x00000584, 0x0000 }, /* R1412 - AIF3 Format */ + { 0x00000585, 0x0040 }, /* R1413 - AIF3 Tx BCLK Rate */ + { 0x00000586, 0x0040 }, /* R1414 - AIF3 Rx BCLK Rate */ + { 0x00000587, 0x1818 }, /* R1415 - AIF3 Frame Ctrl 1 */ + { 0x00000588, 0x1818 }, /* R1416 - AIF3 Frame Ctrl 2 */ + { 0x00000589, 0x0000 }, /* R1417 - AIF3 Frame Ctrl 3 */ + { 0x0000058A, 0x0001 }, /* R1418 - AIF3 Frame Ctrl 4 */ + { 0x00000591, 0x0000 }, /* R1425 - AIF3 Frame Ctrl 11 */ + { 0x00000592, 0x0001 }, /* R1426 - AIF3 Frame Ctrl 12 */ + { 0x00000599, 0x0000 }, /* R1433 - AIF3 Tx Enables */ + { 0x0000059A, 0x0000 }, /* R1434 - AIF3 Rx Enables */ + { 0x000005E3, 0x0004 }, /* R1507 - SLIMbus Framer Ref Gear */ + { 0x000005E5, 0x0000 }, /* R1509 - SLIMbus Rates 1 */ + { 0x000005E6, 0x0000 }, /* R1510 - SLIMbus Rates 2 */ + { 0x000005E7, 0x0000 }, /* R1511 - SLIMbus Rates 3 */ + { 0x000005E8, 0x0000 }, /* R1512 - SLIMbus Rates 4 */ + { 0x000005E9, 0x0000 }, /* R1513 - SLIMbus Rates 5 */ + { 0x000005EA, 0x0000 }, /* R1514 - SLIMbus Rates 6 */ + { 0x000005EB, 0x0000 }, /* R1515 - SLIMbus Rates 7 */ + { 0x000005EC, 0x0000 }, /* R1516 - SLIMbus Rates 8 */ + { 0x000005F5, 0x0000 }, /* R1525 - SLIMbus RX Channel Enable */ + { 0x000005F6, 0x0000 }, /* R1526 - SLIMbus TX Channel Enable */ + { 0x00000640, 0x0000 }, /* R1600 - PWM1MIX Input 1 Source */ + { 0x00000641, 0x0080 }, /* R1601 - PWM1MIX Input 1 Volume */ + { 0x00000642, 0x0000 }, /* R1602 - PWM1MIX Input 2 Source */ + { 0x00000643, 0x0080 }, /* R1603 - PWM1MIX Input 2 Volume */ + { 0x00000644, 0x0000 }, /* R1604 - PWM1MIX Input 3 Source */ + { 0x00000645, 0x0080 }, /* R1605 - PWM1MIX Input 3 Volume */ + { 0x00000646, 0x0000 }, /* R1606 - PWM1MIX Input 4 Source */ + { 0x00000647, 0x0080 }, /* R1607 - PWM1MIX Input 4 Volume */ + { 0x00000648, 0x0000 }, /* R1608 - PWM2MIX Input 1 Source */ + { 0x00000649, 0x0080 }, /* R1609 - PWM2MIX Input 1 Volume */ + { 0x0000064A, 0x0000 }, /* R1610 - PWM2MIX Input 2 Source */ + { 0x0000064B, 0x0080 }, /* R1611 - PWM2MIX Input 2 Volume */ + { 0x0000064C, 0x0000 }, /* R1612 - PWM2MIX Input 3 Source */ + { 0x0000064D, 0x0080 }, /* R1613 - PWM2MIX Input 3 Volume */ + { 0x0000064E, 0x0000 }, /* R1614 - PWM2MIX Input 4 Source */ + { 0x0000064F, 0x0080 }, /* R1615 - PWM2MIX Input 4 Volume */ + { 0x00000660, 0x0000 }, /* R1632 - MICMIX Input 1 Source */ + { 0x00000661, 0x0080 }, /* R1633 - MICMIX Input 1 Volume */ + { 0x00000662, 0x0000 }, /* R1634 - MICMIX Input 2 Source */ + { 0x00000663, 0x0080 }, /* R1635 - MICMIX Input 2 Volume */ + { 0x00000664, 0x0000 }, /* R1636 - MICMIX Input 3 Source */ + { 0x00000665, 0x0080 }, /* R1637 - MICMIX Input 3 Volume */ + { 0x00000666, 0x0000 }, /* R1638 - MICMIX Input 4 Source */ + { 0x00000667, 0x0080 }, /* R1639 - MICMIX Input 4 Volume */ + { 0x00000668, 0x0000 }, /* R1640 - NOISEMIX Input 1 Source */ + { 0x00000669, 0x0080 }, /* R1641 - NOISEMIX Input 1 Volume */ + { 0x0000066A, 0x0000 }, /* R1642 - NOISEMIX Input 2 Source */ + { 0x0000066B, 0x0080 }, /* R1643 - NOISEMIX Input 2 Volume */ + { 0x0000066C, 0x0000 }, /* R1644 - NOISEMIX Input 3 Source */ + { 0x0000066D, 0x0080 }, /* R1645 - NOISEMIX Input 3 Volume */ + { 0x0000066E, 0x0000 }, /* R1646 - NOISEMIX Input 4 Source */ + { 0x0000066F, 0x0080 }, /* R1647 - NOISEMIX Input 4 Volume */ + { 0x00000680, 0x0000 }, /* R1664 - OUT1LMIX Input 1 Source */ + { 0x00000681, 0x0080 }, /* R1665 - OUT1LMIX Input 1 Volume */ + { 0x00000682, 0x0000 }, /* R1666 - OUT1LMIX Input 2 Source */ + { 0x00000683, 0x0080 }, /* R1667 - OUT1LMIX Input 2 Volume */ + { 0x00000684, 0x0000 }, /* R1668 - OUT1LMIX Input 3 Source */ + { 0x00000685, 0x0080 }, /* R1669 - OUT1LMIX Input 3 Volume */ + { 0x00000686, 0x0000 }, /* R1670 - OUT1LMIX Input 4 Source */ + { 0x00000687, 0x0080 }, /* R1671 - OUT1LMIX Input 4 Volume */ + { 0x00000688, 0x0000 }, /* R1672 - OUT1RMIX Input 1 Source */ + { 0x00000689, 0x0080 }, /* R1673 - OUT1RMIX Input 1 Volume */ + { 0x0000068A, 0x0000 }, /* R1674 - OUT1RMIX Input 2 Source */ + { 0x0000068B, 0x0080 }, /* R1675 - OUT1RMIX Input 2 Volume */ + { 0x0000068C, 0x0000 }, /* R1676 - OUT1RMIX Input 3 Source */ + { 0x0000068D, 0x0080 }, /* R1677 - OUT1RMIX Input 3 Volume */ + { 0x0000068E, 0x0000 }, /* R1678 - OUT1RMIX Input 4 Source */ + { 0x0000068F, 0x0080 }, /* R1679 - OUT1RMIX Input 4 Volume */ + { 0x00000690, 0x0000 }, /* R1680 - OUT2LMIX Input 1 Source */ + { 0x00000691, 0x0080 }, /* R1681 - OUT2LMIX Input 1 Volume */ + { 0x00000692, 0x0000 }, /* R1682 - OUT2LMIX Input 2 Source */ + { 0x00000693, 0x0080 }, /* R1683 - OUT2LMIX Input 2 Volume */ + { 0x00000694, 0x0000 }, /* R1684 - OUT2LMIX Input 3 Source */ + { 0x00000695, 0x0080 }, /* R1685 - OUT2LMIX Input 3 Volume */ + { 0x00000696, 0x0000 }, /* R1686 - OUT2LMIX Input 4 Source */ + { 0x00000697, 0x0080 }, /* R1687 - OUT2LMIX Input 4 Volume */ + { 0x00000698, 0x0000 }, /* R1688 - OUT2RMIX Input 1 Source */ + { 0x00000699, 0x0080 }, /* R1689 - OUT2RMIX Input 1 Volume */ + { 0x0000069A, 0x0000 }, /* R1690 - OUT2RMIX Input 2 Source */ + { 0x0000069B, 0x0080 }, /* R1691 - OUT2RMIX Input 2 Volume */ + { 0x0000069C, 0x0000 }, /* R1692 - OUT2RMIX Input 3 Source */ + { 0x0000069D, 0x0080 }, /* R1693 - OUT2RMIX Input 3 Volume */ + { 0x0000069E, 0x0000 }, /* R1694 - OUT2RMIX Input 4 Source */ + { 0x0000069F, 0x0080 }, /* R1695 - OUT2RMIX Input 4 Volume */ + { 0x000006A0, 0x0000 }, /* R1696 - OUT3LMIX Input 1 Source */ + { 0x000006A1, 0x0080 }, /* R1697 - OUT3LMIX Input 1 Volume */ + { 0x000006A2, 0x0000 }, /* R1698 - OUT3LMIX Input 2 Source */ + { 0x000006A3, 0x0080 }, /* R1699 - OUT3LMIX Input 2 Volume */ + { 0x000006A4, 0x0000 }, /* R1700 - OUT3LMIX Input 3 Source */ + { 0x000006A5, 0x0080 }, /* R1701 - OUT3LMIX Input 3 Volume */ + { 0x000006A6, 0x0000 }, /* R1702 - OUT3LMIX Input 4 Source */ + { 0x000006A7, 0x0080 }, /* R1703 - OUT3LMIX Input 4 Volume */ + { 0x000006B0, 0x0000 }, /* R1712 - OUT4LMIX Input 1 Source */ + { 0x000006B1, 0x0080 }, /* R1713 - OUT4LMIX Input 1 Volume */ + { 0x000006B2, 0x0000 }, /* R1714 - OUT4LMIX Input 2 Source */ + { 0x000006B3, 0x0080 }, /* R1715 - OUT4LMIX Input 2 Volume */ + { 0x000006B4, 0x0000 }, /* R1716 - OUT4LMIX Input 3 Source */ + { 0x000006B5, 0x0080 }, /* R1717 - OUT4LMIX Input 3 Volume */ + { 0x000006B6, 0x0000 }, /* R1718 - OUT4LMIX Input 4 Source */ + { 0x000006B7, 0x0080 }, /* R1719 - OUT4LMIX Input 4 Volume */ + { 0x000006B8, 0x0000 }, /* R1720 - OUT4RMIX Input 1 Source */ + { 0x000006B9, 0x0080 }, /* R1721 - OUT4RMIX Input 1 Volume */ + { 0x000006BA, 0x0000 }, /* R1722 - OUT4RMIX Input 2 Source */ + { 0x000006BB, 0x0080 }, /* R1723 - OUT4RMIX Input 2 Volume */ + { 0x000006BC, 0x0000 }, /* R1724 - OUT4RMIX Input 3 Source */ + { 0x000006BD, 0x0080 }, /* R1725 - OUT4RMIX Input 3 Volume */ + { 0x000006BE, 0x0000 }, /* R1726 - OUT4RMIX Input 4 Source */ + { 0x000006BF, 0x0080 }, /* R1727 - OUT4RMIX Input 4 Volume */ + { 0x000006C0, 0x0000 }, /* R1728 - OUT5LMIX Input 1 Source */ + { 0x000006C1, 0x0080 }, /* R1729 - OUT5LMIX Input 1 Volume */ + { 0x000006C2, 0x0000 }, /* R1730 - OUT5LMIX Input 2 Source */ + { 0x000006C3, 0x0080 }, /* R1731 - OUT5LMIX Input 2 Volume */ + { 0x000006C4, 0x0000 }, /* R1732 - OUT5LMIX Input 3 Source */ + { 0x000006C5, 0x0080 }, /* R1733 - OUT5LMIX Input 3 Volume */ + { 0x000006C6, 0x0000 }, /* R1734 - OUT5LMIX Input 4 Source */ + { 0x000006C7, 0x0080 }, /* R1735 - OUT5LMIX Input 4 Volume */ + { 0x000006C8, 0x0000 }, /* R1736 - OUT5RMIX Input 1 Source */ + { 0x000006C9, 0x0080 }, /* R1737 - OUT5RMIX Input 1 Volume */ + { 0x000006CA, 0x0000 }, /* R1738 - OUT5RMIX Input 2 Source */ + { 0x000006CB, 0x0080 }, /* R1739 - OUT5RMIX Input 2 Volume */ + { 0x000006CC, 0x0000 }, /* R1740 - OUT5RMIX Input 3 Source */ + { 0x000006CD, 0x0080 }, /* R1741 - OUT5RMIX Input 3 Volume */ + { 0x000006CE, 0x0000 }, /* R1742 - OUT5RMIX Input 4 Source */ + { 0x000006CF, 0x0080 }, /* R1743 - OUT5RMIX Input 4 Volume */ + { 0x00000700, 0x0000 }, /* R1792 - AIF1TX1MIX Input 1 Source */ + { 0x00000701, 0x0080 }, /* R1793 - AIF1TX1MIX Input 1 Volume */ + { 0x00000702, 0x0000 }, /* R1794 - AIF1TX1MIX Input 2 Source */ + { 0x00000703, 0x0080 }, /* R1795 - AIF1TX1MIX Input 2 Volume */ + { 0x00000704, 0x0000 }, /* R1796 - AIF1TX1MIX Input 3 Source */ + { 0x00000705, 0x0080 }, /* R1797 - AIF1TX1MIX Input 3 Volume */ + { 0x00000706, 0x0000 }, /* R1798 - AIF1TX1MIX Input 4 Source */ + { 0x00000707, 0x0080 }, /* R1799 - AIF1TX1MIX Input 4 Volume */ + { 0x00000708, 0x0000 }, /* R1800 - AIF1TX2MIX Input 1 Source */ + { 0x00000709, 0x0080 }, /* R1801 - AIF1TX2MIX Input 1 Volume */ + { 0x0000070A, 0x0000 }, /* R1802 - AIF1TX2MIX Input 2 Source */ + { 0x0000070B, 0x0080 }, /* R1803 - AIF1TX2MIX Input 2 Volume */ + { 0x0000070C, 0x0000 }, /* R1804 - AIF1TX2MIX Input 3 Source */ + { 0x0000070D, 0x0080 }, /* R1805 - AIF1TX2MIX Input 3 Volume */ + { 0x0000070E, 0x0000 }, /* R1806 - AIF1TX2MIX Input 4 Source */ + { 0x0000070F, 0x0080 }, /* R1807 - AIF1TX2MIX Input 4 Volume */ + { 0x00000710, 0x0000 }, /* R1808 - AIF1TX3MIX Input 1 Source */ + { 0x00000711, 0x0080 }, /* R1809 - AIF1TX3MIX Input 1 Volume */ + { 0x00000712, 0x0000 }, /* R1810 - AIF1TX3MIX Input 2 Source */ + { 0x00000713, 0x0080 }, /* R1811 - AIF1TX3MIX Input 2 Volume */ + { 0x00000714, 0x0000 }, /* R1812 - AIF1TX3MIX Input 3 Source */ + { 0x00000715, 0x0080 }, /* R1813 - AIF1TX3MIX Input 3 Volume */ + { 0x00000716, 0x0000 }, /* R1814 - AIF1TX3MIX Input 4 Source */ + { 0x00000717, 0x0080 }, /* R1815 - AIF1TX3MIX Input 4 Volume */ + { 0x00000718, 0x0000 }, /* R1816 - AIF1TX4MIX Input 1 Source */ + { 0x00000719, 0x0080 }, /* R1817 - AIF1TX4MIX Input 1 Volume */ + { 0x0000071A, 0x0000 }, /* R1818 - AIF1TX4MIX Input 2 Source */ + { 0x0000071B, 0x0080 }, /* R1819 - AIF1TX4MIX Input 2 Volume */ + { 0x0000071C, 0x0000 }, /* R1820 - AIF1TX4MIX Input 3 Source */ + { 0x0000071D, 0x0080 }, /* R1821 - AIF1TX4MIX Input 3 Volume */ + { 0x0000071E, 0x0000 }, /* R1822 - AIF1TX4MIX Input 4 Source */ + { 0x0000071F, 0x0080 }, /* R1823 - AIF1TX4MIX Input 4 Volume */ + { 0x00000720, 0x0000 }, /* R1824 - AIF1TX5MIX Input 1 Source */ + { 0x00000721, 0x0080 }, /* R1825 - AIF1TX5MIX Input 1 Volume */ + { 0x00000722, 0x0000 }, /* R1826 - AIF1TX5MIX Input 2 Source */ + { 0x00000723, 0x0080 }, /* R1827 - AIF1TX5MIX Input 2 Volume */ + { 0x00000724, 0x0000 }, /* R1828 - AIF1TX5MIX Input 3 Source */ + { 0x00000725, 0x0080 }, /* R1829 - AIF1TX5MIX Input 3 Volume */ + { 0x00000726, 0x0000 }, /* R1830 - AIF1TX5MIX Input 4 Source */ + { 0x00000727, 0x0080 }, /* R1831 - AIF1TX5MIX Input 4 Volume */ + { 0x00000728, 0x0000 }, /* R1832 - AIF1TX6MIX Input 1 Source */ + { 0x00000729, 0x0080 }, /* R1833 - AIF1TX6MIX Input 1 Volume */ + { 0x0000072A, 0x0000 }, /* R1834 - AIF1TX6MIX Input 2 Source */ + { 0x0000072B, 0x0080 }, /* R1835 - AIF1TX6MIX Input 2 Volume */ + { 0x0000072C, 0x0000 }, /* R1836 - AIF1TX6MIX Input 3 Source */ + { 0x0000072D, 0x0080 }, /* R1837 - AIF1TX6MIX Input 3 Volume */ + { 0x0000072E, 0x0000 }, /* R1838 - AIF1TX6MIX Input 4 Source */ + { 0x0000072F, 0x0080 }, /* R1839 - AIF1TX6MIX Input 4 Volume */ + { 0x00000730, 0x0000 }, /* R1840 - AIF1TX7MIX Input 1 Source */ + { 0x00000731, 0x0080 }, /* R1841 - AIF1TX7MIX Input 1 Volume */ + { 0x00000732, 0x0000 }, /* R1842 - AIF1TX7MIX Input 2 Source */ + { 0x00000733, 0x0080 }, /* R1843 - AIF1TX7MIX Input 2 Volume */ + { 0x00000734, 0x0000 }, /* R1844 - AIF1TX7MIX Input 3 Source */ + { 0x00000735, 0x0080 }, /* R1845 - AIF1TX7MIX Input 3 Volume */ + { 0x00000736, 0x0000 }, /* R1846 - AIF1TX7MIX Input 4 Source */ + { 0x00000737, 0x0080 }, /* R1847 - AIF1TX7MIX Input 4 Volume */ + { 0x00000738, 0x0000 }, /* R1848 - AIF1TX8MIX Input 1 Source */ + { 0x00000739, 0x0080 }, /* R1849 - AIF1TX8MIX Input 1 Volume */ + { 0x0000073A, 0x0000 }, /* R1850 - AIF1TX8MIX Input 2 Source */ + { 0x0000073B, 0x0080 }, /* R1851 - AIF1TX8MIX Input 2 Volume */ + { 0x0000073C, 0x0000 }, /* R1852 - AIF1TX8MIX Input 3 Source */ + { 0x0000073D, 0x0080 }, /* R1853 - AIF1TX8MIX Input 3 Volume */ + { 0x0000073E, 0x0000 }, /* R1854 - AIF1TX8MIX Input 4 Source */ + { 0x0000073F, 0x0080 }, /* R1855 - AIF1TX8MIX Input 4 Volume */ + { 0x00000740, 0x0000 }, /* R1856 - AIF2TX1MIX Input 1 Source */ + { 0x00000741, 0x0080 }, /* R1857 - AIF2TX1MIX Input 1 Volume */ + { 0x00000742, 0x0000 }, /* R1858 - AIF2TX1MIX Input 2 Source */ + { 0x00000743, 0x0080 }, /* R1859 - AIF2TX1MIX Input 2 Volume */ + { 0x00000744, 0x0000 }, /* R1860 - AIF2TX1MIX Input 3 Source */ + { 0x00000745, 0x0080 }, /* R1861 - AIF2TX1MIX Input 3 Volume */ + { 0x00000746, 0x0000 }, /* R1862 - AIF2TX1MIX Input 4 Source */ + { 0x00000747, 0x0080 }, /* R1863 - AIF2TX1MIX Input 4 Volume */ + { 0x00000748, 0x0000 }, /* R1864 - AIF2TX2MIX Input 1 Source */ + { 0x00000749, 0x0080 }, /* R1865 - AIF2TX2MIX Input 1 Volume */ + { 0x0000074A, 0x0000 }, /* R1866 - AIF2TX2MIX Input 2 Source */ + { 0x0000074B, 0x0080 }, /* R1867 - AIF2TX2MIX Input 2 Volume */ + { 0x0000074C, 0x0000 }, /* R1868 - AIF2TX2MIX Input 3 Source */ + { 0x0000074D, 0x0080 }, /* R1869 - AIF2TX2MIX Input 3 Volume */ + { 0x0000074E, 0x0000 }, /* R1870 - AIF2TX2MIX Input 4 Source */ + { 0x0000074F, 0x0080 }, /* R1871 - AIF2TX2MIX Input 4 Volume */ + { 0x00000780, 0x0000 }, /* R1920 - AIF3TX1MIX Input 1 Source */ + { 0x00000781, 0x0080 }, /* R1921 - AIF3TX1MIX Input 1 Volume */ + { 0x00000782, 0x0000 }, /* R1922 - AIF3TX1MIX Input 2 Source */ + { 0x00000783, 0x0080 }, /* R1923 - AIF3TX1MIX Input 2 Volume */ + { 0x00000784, 0x0000 }, /* R1924 - AIF3TX1MIX Input 3 Source */ + { 0x00000785, 0x0080 }, /* R1925 - AIF3TX1MIX Input 3 Volume */ + { 0x00000786, 0x0000 }, /* R1926 - AIF3TX1MIX Input 4 Source */ + { 0x00000787, 0x0080 }, /* R1927 - AIF3TX1MIX Input 4 Volume */ + { 0x00000788, 0x0000 }, /* R1928 - AIF3TX2MIX Input 1 Source */ + { 0x00000789, 0x0080 }, /* R1929 - AIF3TX2MIX Input 1 Volume */ + { 0x0000078A, 0x0000 }, /* R1930 - AIF3TX2MIX Input 2 Source */ + { 0x0000078B, 0x0080 }, /* R1931 - AIF3TX2MIX Input 2 Volume */ + { 0x0000078C, 0x0000 }, /* R1932 - AIF3TX2MIX Input 3 Source */ + { 0x0000078D, 0x0080 }, /* R1933 - AIF3TX2MIX Input 3 Volume */ + { 0x0000078E, 0x0000 }, /* R1934 - AIF3TX2MIX Input 4 Source */ + { 0x0000078F, 0x0080 }, /* R1935 - AIF3TX2MIX Input 4 Volume */ + { 0x000007C0, 0x0000 }, /* R1984 - SLIMTX1MIX Input 1 Source */ + { 0x000007C1, 0x0080 }, /* R1985 - SLIMTX1MIX Input 1 Volume */ + { 0x000007C2, 0x0000 }, /* R1986 - SLIMTX1MIX Input 2 Source */ + { 0x000007C3, 0x0080 }, /* R1987 - SLIMTX1MIX Input 2 Volume */ + { 0x000007C4, 0x0000 }, /* R1988 - SLIMTX1MIX Input 3 Source */ + { 0x000007C5, 0x0080 }, /* R1989 - SLIMTX1MIX Input 3 Volume */ + { 0x000007C6, 0x0000 }, /* R1990 - SLIMTX1MIX Input 4 Source */ + { 0x000007C7, 0x0080 }, /* R1991 - SLIMTX1MIX Input 4 Volume */ + { 0x000007C8, 0x0000 }, /* R1992 - SLIMTX2MIX Input 1 Source */ + { 0x000007C9, 0x0080 }, /* R1993 - SLIMTX2MIX Input 1 Volume */ + { 0x000007CA, 0x0000 }, /* R1994 - SLIMTX2MIX Input 2 Source */ + { 0x000007CB, 0x0080 }, /* R1995 - SLIMTX2MIX Input 2 Volume */ + { 0x000007CC, 0x0000 }, /* R1996 - SLIMTX2MIX Input 3 Source */ + { 0x000007CD, 0x0080 }, /* R1997 - SLIMTX2MIX Input 3 Volume */ + { 0x000007CE, 0x0000 }, /* R1998 - SLIMTX2MIX Input 4 Source */ + { 0x000007CF, 0x0080 }, /* R1999 - SLIMTX2MIX Input 4 Volume */ + { 0x000007D0, 0x0000 }, /* R2000 - SLIMTX3MIX Input 1 Source */ + { 0x000007D1, 0x0080 }, /* R2001 - SLIMTX3MIX Input 1 Volume */ + { 0x000007D2, 0x0000 }, /* R2002 - SLIMTX3MIX Input 2 Source */ + { 0x000007D3, 0x0080 }, /* R2003 - SLIMTX3MIX Input 2 Volume */ + { 0x000007D4, 0x0000 }, /* R2004 - SLIMTX3MIX Input 3 Source */ + { 0x000007D5, 0x0080 }, /* R2005 - SLIMTX3MIX Input 3 Volume */ + { 0x000007D6, 0x0000 }, /* R2006 - SLIMTX3MIX Input 4 Source */ + { 0x000007D7, 0x0080 }, /* R2007 - SLIMTX3MIX Input 4 Volume */ + { 0x000007D8, 0x0000 }, /* R2008 - SLIMTX4MIX Input 1 Source */ + { 0x000007D9, 0x0080 }, /* R2009 - SLIMTX4MIX Input 1 Volume */ + { 0x000007DA, 0x0000 }, /* R2010 - SLIMTX4MIX Input 2 Source */ + { 0x000007DB, 0x0080 }, /* R2011 - SLIMTX4MIX Input 2 Volume */ + { 0x000007DC, 0x0000 }, /* R2012 - SLIMTX4MIX Input 3 Source */ + { 0x000007DD, 0x0080 }, /* R2013 - SLIMTX4MIX Input 3 Volume */ + { 0x000007DE, 0x0000 }, /* R2014 - SLIMTX4MIX Input 4 Source */ + { 0x000007DF, 0x0080 }, /* R2015 - SLIMTX4MIX Input 4 Volume */ + { 0x000007E0, 0x0000 }, /* R2016 - SLIMTX5MIX Input 1 Source */ + { 0x000007E1, 0x0080 }, /* R2017 - SLIMTX5MIX Input 1 Volume */ + { 0x000007E2, 0x0000 }, /* R2018 - SLIMTX5MIX Input 2 Source */ + { 0x000007E3, 0x0080 }, /* R2019 - SLIMTX5MIX Input 2 Volume */ + { 0x000007E4, 0x0000 }, /* R2020 - SLIMTX5MIX Input 3 Source */ + { 0x000007E5, 0x0080 }, /* R2021 - SLIMTX5MIX Input 3 Volume */ + { 0x000007E6, 0x0000 }, /* R2022 - SLIMTX5MIX Input 4 Source */ + { 0x000007E7, 0x0080 }, /* R2023 - SLIMTX5MIX Input 4 Volume */ + { 0x000007E8, 0x0000 }, /* R2024 - SLIMTX6MIX Input 1 Source */ + { 0x000007E9, 0x0080 }, /* R2025 - SLIMTX6MIX Input 1 Volume */ + { 0x000007EA, 0x0000 }, /* R2026 - SLIMTX6MIX Input 2 Source */ + { 0x000007EB, 0x0080 }, /* R2027 - SLIMTX6MIX Input 2 Volume */ + { 0x000007EC, 0x0000 }, /* R2028 - SLIMTX6MIX Input 3 Source */ + { 0x000007ED, 0x0080 }, /* R2029 - SLIMTX6MIX Input 3 Volume */ + { 0x000007EE, 0x0000 }, /* R2030 - SLIMTX6MIX Input 4 Source */ + { 0x000007EF, 0x0080 }, /* R2031 - SLIMTX6MIX Input 4 Volume */ + { 0x000007F0, 0x0000 }, /* R2032 - SLIMTX7MIX Input 1 Source */ + { 0x000007F1, 0x0080 }, /* R2033 - SLIMTX7MIX Input 1 Volume */ + { 0x000007F2, 0x0000 }, /* R2034 - SLIMTX7MIX Input 2 Source */ + { 0x000007F3, 0x0080 }, /* R2035 - SLIMTX7MIX Input 2 Volume */ + { 0x000007F4, 0x0000 }, /* R2036 - SLIMTX7MIX Input 3 Source */ + { 0x000007F5, 0x0080 }, /* R2037 - SLIMTX7MIX Input 3 Volume */ + { 0x000007F6, 0x0000 }, /* R2038 - SLIMTX7MIX Input 4 Source */ + { 0x000007F7, 0x0080 }, /* R2039 - SLIMTX7MIX Input 4 Volume */ + { 0x000007F8, 0x0000 }, /* R2040 - SLIMTX8MIX Input 1 Source */ + { 0x000007F9, 0x0080 }, /* R2041 - SLIMTX8MIX Input 1 Volume */ + { 0x000007FA, 0x0000 }, /* R2042 - SLIMTX8MIX Input 2 Source */ + { 0x000007FB, 0x0080 }, /* R2043 - SLIMTX8MIX Input 2 Volume */ + { 0x000007FC, 0x0000 }, /* R2044 - SLIMTX8MIX Input 3 Source */ + { 0x000007FD, 0x0080 }, /* R2045 - SLIMTX8MIX Input 3 Volume */ + { 0x000007FE, 0x0000 }, /* R2046 - SLIMTX8MIX Input 4 Source */ + { 0x000007FF, 0x0080 }, /* R2047 - SLIMTX8MIX Input 4 Volume */ + { 0x00000880, 0x0000 }, /* R2176 - EQ1MIX Input 1 Source */ + { 0x00000881, 0x0080 }, /* R2177 - EQ1MIX Input 1 Volume */ + { 0x00000882, 0x0000 }, /* R2178 - EQ1MIX Input 2 Source */ + { 0x00000883, 0x0080 }, /* R2179 - EQ1MIX Input 2 Volume */ + { 0x00000884, 0x0000 }, /* R2180 - EQ1MIX Input 3 Source */ + { 0x00000885, 0x0080 }, /* R2181 - EQ1MIX Input 3 Volume */ + { 0x00000886, 0x0000 }, /* R2182 - EQ1MIX Input 4 Source */ + { 0x00000887, 0x0080 }, /* R2183 - EQ1MIX Input 4 Volume */ + { 0x00000888, 0x0000 }, /* R2184 - EQ2MIX Input 1 Source */ + { 0x00000889, 0x0080 }, /* R2185 - EQ2MIX Input 1 Volume */ + { 0x0000088A, 0x0000 }, /* R2186 - EQ2MIX Input 2 Source */ + { 0x0000088B, 0x0080 }, /* R2187 - EQ2MIX Input 2 Volume */ + { 0x0000088C, 0x0000 }, /* R2188 - EQ2MIX Input 3 Source */ + { 0x0000088D, 0x0080 }, /* R2189 - EQ2MIX Input 3 Volume */ + { 0x0000088E, 0x0000 }, /* R2190 - EQ2MIX Input 4 Source */ + { 0x0000088F, 0x0080 }, /* R2191 - EQ2MIX Input 4 Volume */ + { 0x00000890, 0x0000 }, /* R2192 - EQ3MIX Input 1 Source */ + { 0x00000891, 0x0080 }, /* R2193 - EQ3MIX Input 1 Volume */ + { 0x00000892, 0x0000 }, /* R2194 - EQ3MIX Input 2 Source */ + { 0x00000893, 0x0080 }, /* R2195 - EQ3MIX Input 2 Volume */ + { 0x00000894, 0x0000 }, /* R2196 - EQ3MIX Input 3 Source */ + { 0x00000895, 0x0080 }, /* R2197 - EQ3MIX Input 3 Volume */ + { 0x00000896, 0x0000 }, /* R2198 - EQ3MIX Input 4 Source */ + { 0x00000897, 0x0080 }, /* R2199 - EQ3MIX Input 4 Volume */ + { 0x00000898, 0x0000 }, /* R2200 - EQ4MIX Input 1 Source */ + { 0x00000899, 0x0080 }, /* R2201 - EQ4MIX Input 1 Volume */ + { 0x0000089A, 0x0000 }, /* R2202 - EQ4MIX Input 2 Source */ + { 0x0000089B, 0x0080 }, /* R2203 - EQ4MIX Input 2 Volume */ + { 0x0000089C, 0x0000 }, /* R2204 - EQ4MIX Input 3 Source */ + { 0x0000089D, 0x0080 }, /* R2205 - EQ4MIX Input 3 Volume */ + { 0x0000089E, 0x0000 }, /* R2206 - EQ4MIX Input 4 Source */ + { 0x0000089F, 0x0080 }, /* R2207 - EQ4MIX Input 4 Volume */ + { 0x000008C0, 0x0000 }, /* R2240 - DRC1LMIX Input 1 Source */ + { 0x000008C1, 0x0080 }, /* R2241 - DRC1LMIX Input 1 Volume */ + { 0x000008C2, 0x0000 }, /* R2242 - DRC1LMIX Input 2 Source */ + { 0x000008C3, 0x0080 }, /* R2243 - DRC1LMIX Input 2 Volume */ + { 0x000008C4, 0x0000 }, /* R2244 - DRC1LMIX Input 3 Source */ + { 0x000008C5, 0x0080 }, /* R2245 - DRC1LMIX Input 3 Volume */ + { 0x000008C6, 0x0000 }, /* R2246 - DRC1LMIX Input 4 Source */ + { 0x000008C7, 0x0080 }, /* R2247 - DRC1LMIX Input 4 Volume */ + { 0x000008C8, 0x0000 }, /* R2248 - DRC1RMIX Input 1 Source */ + { 0x000008C9, 0x0080 }, /* R2249 - DRC1RMIX Input 1 Volume */ + { 0x000008CA, 0x0000 }, /* R2250 - DRC1RMIX Input 2 Source */ + { 0x000008CB, 0x0080 }, /* R2251 - DRC1RMIX Input 2 Volume */ + { 0x000008CC, 0x0000 }, /* R2252 - DRC1RMIX Input 3 Source */ + { 0x000008CD, 0x0080 }, /* R2253 - DRC1RMIX Input 3 Volume */ + { 0x000008CE, 0x0000 }, /* R2254 - DRC1RMIX Input 4 Source */ + { 0x000008CF, 0x0080 }, /* R2255 - DRC1RMIX Input 4 Volume */ + { 0x00000900, 0x0000 }, /* R2304 - HPLP1MIX Input 1 Source */ + { 0x00000901, 0x0080 }, /* R2305 - HPLP1MIX Input 1 Volume */ + { 0x00000902, 0x0000 }, /* R2306 - HPLP1MIX Input 2 Source */ + { 0x00000903, 0x0080 }, /* R2307 - HPLP1MIX Input 2 Volume */ + { 0x00000904, 0x0000 }, /* R2308 - HPLP1MIX Input 3 Source */ + { 0x00000905, 0x0080 }, /* R2309 - HPLP1MIX Input 3 Volume */ + { 0x00000906, 0x0000 }, /* R2310 - HPLP1MIX Input 4 Source */ + { 0x00000907, 0x0080 }, /* R2311 - HPLP1MIX Input 4 Volume */ + { 0x00000908, 0x0000 }, /* R2312 - HPLP2MIX Input 1 Source */ + { 0x00000909, 0x0080 }, /* R2313 - HPLP2MIX Input 1 Volume */ + { 0x0000090A, 0x0000 }, /* R2314 - HPLP2MIX Input 2 Source */ + { 0x0000090B, 0x0080 }, /* R2315 - HPLP2MIX Input 2 Volume */ + { 0x0000090C, 0x0000 }, /* R2316 - HPLP2MIX Input 3 Source */ + { 0x0000090D, 0x0080 }, /* R2317 - HPLP2MIX Input 3 Volume */ + { 0x0000090E, 0x0000 }, /* R2318 - HPLP2MIX Input 4 Source */ + { 0x0000090F, 0x0080 }, /* R2319 - HPLP2MIX Input 4 Volume */ + { 0x00000910, 0x0000 }, /* R2320 - HPLP3MIX Input 1 Source */ + { 0x00000911, 0x0080 }, /* R2321 - HPLP3MIX Input 1 Volume */ + { 0x00000912, 0x0000 }, /* R2322 - HPLP3MIX Input 2 Source */ + { 0x00000913, 0x0080 }, /* R2323 - HPLP3MIX Input 2 Volume */ + { 0x00000914, 0x0000 }, /* R2324 - HPLP3MIX Input 3 Source */ + { 0x00000915, 0x0080 }, /* R2325 - HPLP3MIX Input 3 Volume */ + { 0x00000916, 0x0000 }, /* R2326 - HPLP3MIX Input 4 Source */ + { 0x00000917, 0x0080 }, /* R2327 - HPLP3MIX Input 4 Volume */ + { 0x00000918, 0x0000 }, /* R2328 - HPLP4MIX Input 1 Source */ + { 0x00000919, 0x0080 }, /* R2329 - HPLP4MIX Input 1 Volume */ + { 0x0000091A, 0x0000 }, /* R2330 - HPLP4MIX Input 2 Source */ + { 0x0000091B, 0x0080 }, /* R2331 - HPLP4MIX Input 2 Volume */ + { 0x0000091C, 0x0000 }, /* R2332 - HPLP4MIX Input 3 Source */ + { 0x0000091D, 0x0080 }, /* R2333 - HPLP4MIX Input 3 Volume */ + { 0x0000091E, 0x0000 }, /* R2334 - HPLP4MIX Input 4 Source */ + { 0x0000091F, 0x0080 }, /* R2335 - HPLP4MIX Input 4 Volume */ + { 0x00000940, 0x0000 }, /* R2368 - DSP1LMIX Input 1 Source */ + { 0x00000941, 0x0080 }, /* R2369 - DSP1LMIX Input 1 Volume */ + { 0x00000942, 0x0000 }, /* R2370 - DSP1LMIX Input 2 Source */ + { 0x00000943, 0x0080 }, /* R2371 - DSP1LMIX Input 2 Volume */ + { 0x00000944, 0x0000 }, /* R2372 - DSP1LMIX Input 3 Source */ + { 0x00000945, 0x0080 }, /* R2373 - DSP1LMIX Input 3 Volume */ + { 0x00000946, 0x0000 }, /* R2374 - DSP1LMIX Input 4 Source */ + { 0x00000947, 0x0080 }, /* R2375 - DSP1LMIX Input 4 Volume */ + { 0x00000948, 0x0000 }, /* R2376 - DSP1RMIX Input 1 Source */ + { 0x00000949, 0x0080 }, /* R2377 - DSP1RMIX Input 1 Volume */ + { 0x0000094A, 0x0000 }, /* R2378 - DSP1RMIX Input 2 Source */ + { 0x0000094B, 0x0080 }, /* R2379 - DSP1RMIX Input 2 Volume */ + { 0x0000094C, 0x0000 }, /* R2380 - DSP1RMIX Input 3 Source */ + { 0x0000094D, 0x0080 }, /* R2381 - DSP1RMIX Input 3 Volume */ + { 0x0000094E, 0x0000 }, /* R2382 - DSP1RMIX Input 4 Source */ + { 0x0000094F, 0x0080 }, /* R2383 - DSP1RMIX Input 4 Volume */ + { 0x00000950, 0x0000 }, /* R2384 - DSP1AUX1MIX Input 1 Source */ + { 0x00000958, 0x0000 }, /* R2392 - DSP1AUX2MIX Input 1 Source */ + { 0x00000960, 0x0000 }, /* R2400 - DSP1AUX3MIX Input 1 Source */ + { 0x00000968, 0x0000 }, /* R2408 - DSP1AUX4MIX Input 1 Source */ + { 0x00000970, 0x0000 }, /* R2416 - DSP1AUX5MIX Input 1 Source */ + { 0x00000978, 0x0000 }, /* R2424 - DSP1AUX6MIX Input 1 Source */ + { 0x00000A80, 0x0000 }, /* R2688 - ASRC1LMIX Input 1 Source */ + { 0x00000A88, 0x0000 }, /* R2696 - ASRC1RMIX Input 1 Source */ + { 0x00000A90, 0x0000 }, /* R2704 - ASRC2LMIX Input 1 Source */ + { 0x00000A98, 0x0000 }, /* R2712 - ASRC2RMIX Input 1 Source */ + { 0x00000B00, 0x0000 }, /* R2816 - ISRC1DEC1MIX Input 1 Source */ + { 0x00000B08, 0x0000 }, /* R2824 - ISRC1DEC2MIX Input 1 Source */ + { 0x00000B20, 0x0000 }, /* R2848 - ISRC1INT1MIX Input 1 Source */ + { 0x00000B28, 0x0000 }, /* R2856 - ISRC1INT2MIX Input 1 Source */ + { 0x00000B40, 0x0000 }, /* R2880 - ISRC2DEC1MIX Input 1 Source */ + { 0x00000B48, 0x0000 }, /* R2888 - ISRC2DEC2MIX Input 1 Source */ + { 0x00000B60, 0x0000 }, /* R2912 - ISRC2INT1MIX Input 1 Source */ + { 0x00000B68, 0x0000 }, /* R2920 - ISRC2INT2MIX Input 1 Source */ + { 0x00000C00, 0xA101 }, /* R3072 - GPIO1 CTRL */ + { 0x00000C01, 0xA101 }, /* R3073 - GPIO2 CTRL */ + { 0x00000C02, 0xA101 }, /* R3074 - GPIO3 CTRL */ + { 0x00000C03, 0xA101 }, /* R3075 - GPIO4 CTRL */ + { 0x00000C04, 0xA101 }, /* R3076 - GPIO5 CTRL */ + { 0x00000C0F, 0x0400 }, /* R3087 - IRQ CTRL 1 */ + { 0x00000C10, 0x1000 }, /* R3088 - GPIO Debounce Config */ + { 0x00000C20, 0x8002 }, /* R3104 - Misc Pad Ctrl 1 */ { 0x00000C21, 0x0001 }, /* R3105 - Misc Pad Ctrl 2 */ - { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */ - { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */ - { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */ - { 0x00000C25, 0x0000 }, /* R3109 - Misc Pad Ctrl 6 */ - { 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */ - { 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */ - { 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */ - { 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */ - { 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */ - { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */ - { 0x00000D18, 0xFFFF }, /* R3352 - IRQ2 Status 1 Mask */ - { 0x00000D19, 0xFFFF }, /* R3353 - IRQ2 Status 2 Mask */ - { 0x00000D1A, 0xFFFF }, /* R3354 - IRQ2 Status 3 Mask */ - { 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */ - { 0x00000D1C, 0xFFFF }, /* R3356 - IRQ2 Status 5 Mask */ - { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */ + { 0x00000C22, 0x0000 }, /* R3106 - Misc Pad Ctrl 3 */ + { 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */ + { 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */ + { 0x00000C25, 0x0000 }, /* R3109 - Misc Pad Ctrl 6 */ + { 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */ + { 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */ + { 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */ + { 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */ + { 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */ + { 0x00000D0F, 0x0000 }, /* R3343 - Interrupt Control */ + { 0x00000D18, 0xFFFF }, /* R3352 - IRQ2 Status 1 Mask */ + { 0x00000D19, 0xFFFF }, /* R3353 - IRQ2 Status 2 Mask */ + { 0x00000D1A, 0xFFFF }, /* R3354 - IRQ2 Status 3 Mask */ + { 0x00000D1B, 0xFFFF }, /* R3355 - IRQ2 Status 4 Mask */ + { 0x00000D1C, 0xFFFF }, /* R3356 - IRQ2 Status 5 Mask */ + { 0x00000D1F, 0x0000 }, /* R3359 - IRQ2 Control */ { 0x00000D41, 0x0000 }, /* R3393 - ADSP2 IRQ0 */ - { 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */ - { 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */ - { 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */ - { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */ - { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */ - { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */ - { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */ - { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */ - { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */ - { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */ - { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */ - { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */ - { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */ - { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */ - { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */ - { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */ - { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */ - { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */ - { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */ - { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */ - { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */ - { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */ - { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */ - { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */ - { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */ - { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */ - { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */ - { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */ - { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */ - { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */ - { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */ - { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */ - { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */ - { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */ - { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */ - { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */ - { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */ - { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */ - { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */ - { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */ - { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */ - { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */ - { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */ - { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */ - { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */ - { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */ - { 0x00000E3C, 0x6318 }, /* R3644 - EQ3_1 */ - { 0x00000E3D, 0x6300 }, /* R3645 - EQ3_2 */ - { 0x00000E3E, 0x0FC8 }, /* R3646 - EQ3_3 */ - { 0x00000E3F, 0x03FE }, /* R3647 - EQ3_4 */ - { 0x00000E40, 0x00E0 }, /* R3648 - EQ3_5 */ - { 0x00000E41, 0x1EC4 }, /* R3649 - EQ3_6 */ - { 0x00000E42, 0xF136 }, /* R3650 - EQ3_7 */ - { 0x00000E43, 0x0409 }, /* R3651 - EQ3_8 */ - { 0x00000E44, 0x04CC }, /* R3652 - EQ3_9 */ - { 0x00000E45, 0x1C9B }, /* R3653 - EQ3_10 */ - { 0x00000E46, 0xF337 }, /* R3654 - EQ3_11 */ - { 0x00000E47, 0x040B }, /* R3655 - EQ3_12 */ - { 0x00000E48, 0x0CBB }, /* R3656 - EQ3_13 */ - { 0x00000E49, 0x16F8 }, /* R3657 - EQ3_14 */ - { 0x00000E4A, 0xF7D9 }, /* R3658 - EQ3_15 */ - { 0x00000E4B, 0x040A }, /* R3659 - EQ3_16 */ - { 0x00000E4C, 0x1F14 }, /* R3660 - EQ3_17 */ - { 0x00000E4D, 0x058C }, /* R3661 - EQ3_18 */ - { 0x00000E4E, 0x0563 }, /* R3662 - EQ3_19 */ - { 0x00000E4F, 0x4000 }, /* R3663 - EQ3_20 */ - { 0x00000E50, 0x0B75 }, /* R3664 - EQ3_21 */ - { 0x00000E52, 0x6318 }, /* R3666 - EQ4_1 */ - { 0x00000E53, 0x6300 }, /* R3667 - EQ4_2 */ - { 0x00000E54, 0x0FC8 }, /* R3668 - EQ4_3 */ - { 0x00000E55, 0x03FE }, /* R3669 - EQ4_4 */ - { 0x00000E56, 0x00E0 }, /* R3670 - EQ4_5 */ - { 0x00000E57, 0x1EC4 }, /* R3671 - EQ4_6 */ - { 0x00000E58, 0xF136 }, /* R3672 - EQ4_7 */ - { 0x00000E59, 0x0409 }, /* R3673 - EQ4_8 */ - { 0x00000E5A, 0x04CC }, /* R3674 - EQ4_9 */ - { 0x00000E5B, 0x1C9B }, /* R3675 - EQ4_10 */ - { 0x00000E5C, 0xF337 }, /* R3676 - EQ4_11 */ - { 0x00000E5D, 0x040B }, /* R3677 - EQ4_12 */ - { 0x00000E5E, 0x0CBB }, /* R3678 - EQ4_13 */ - { 0x00000E5F, 0x16F8 }, /* R3679 - EQ4_14 */ - { 0x00000E60, 0xF7D9 }, /* R3680 - EQ4_15 */ - { 0x00000E61, 0x040A }, /* R3681 - EQ4_16 */ - { 0x00000E62, 0x1F14 }, /* R3682 - EQ4_17 */ - { 0x00000E63, 0x058C }, /* R3683 - EQ4_18 */ - { 0x00000E64, 0x0563 }, /* R3684 - EQ4_19 */ - { 0x00000E65, 0x4000 }, /* R3685 - EQ4_20 */ - { 0x00000E66, 0x0B75 }, /* R3686 - EQ4_21 */ - { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */ - { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */ - { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */ - { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */ - { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */ - { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */ - { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */ - { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */ - { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */ - { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */ - { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */ - { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */ - { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */ - { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */ - { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */ + { 0x00000D53, 0xFFFF }, /* R3411 - AOD IRQ Mask IRQ1 */ + { 0x00000D54, 0xFFFF }, /* R3412 - AOD IRQ Mask IRQ2 */ + { 0x00000D56, 0x0000 }, /* R3414 - Jack detect debounce */ + { 0x00000E00, 0x0000 }, /* R3584 - FX_Ctrl1 */ + { 0x00000E10, 0x6318 }, /* R3600 - EQ1_1 */ + { 0x00000E11, 0x6300 }, /* R3601 - EQ1_2 */ + { 0x00000E12, 0x0FC8 }, /* R3602 - EQ1_3 */ + { 0x00000E13, 0x03FE }, /* R3603 - EQ1_4 */ + { 0x00000E14, 0x00E0 }, /* R3604 - EQ1_5 */ + { 0x00000E15, 0x1EC4 }, /* R3605 - EQ1_6 */ + { 0x00000E16, 0xF136 }, /* R3606 - EQ1_7 */ + { 0x00000E17, 0x0409 }, /* R3607 - EQ1_8 */ + { 0x00000E18, 0x04CC }, /* R3608 - EQ1_9 */ + { 0x00000E19, 0x1C9B }, /* R3609 - EQ1_10 */ + { 0x00000E1A, 0xF337 }, /* R3610 - EQ1_11 */ + { 0x00000E1B, 0x040B }, /* R3611 - EQ1_12 */ + { 0x00000E1C, 0x0CBB }, /* R3612 - EQ1_13 */ + { 0x00000E1D, 0x16F8 }, /* R3613 - EQ1_14 */ + { 0x00000E1E, 0xF7D9 }, /* R3614 - EQ1_15 */ + { 0x00000E1F, 0x040A }, /* R3615 - EQ1_16 */ + { 0x00000E20, 0x1F14 }, /* R3616 - EQ1_17 */ + { 0x00000E21, 0x058C }, /* R3617 - EQ1_18 */ + { 0x00000E22, 0x0563 }, /* R3618 - EQ1_19 */ + { 0x00000E23, 0x4000 }, /* R3619 - EQ1_20 */ + { 0x00000E24, 0x0B75 }, /* R3620 - EQ1_21 */ + { 0x00000E26, 0x6318 }, /* R3622 - EQ2_1 */ + { 0x00000E27, 0x6300 }, /* R3623 - EQ2_2 */ + { 0x00000E28, 0x0FC8 }, /* R3624 - EQ2_3 */ + { 0x00000E29, 0x03FE }, /* R3625 - EQ2_4 */ + { 0x00000E2A, 0x00E0 }, /* R3626 - EQ2_5 */ + { 0x00000E2B, 0x1EC4 }, /* R3627 - EQ2_6 */ + { 0x00000E2C, 0xF136 }, /* R3628 - EQ2_7 */ + { 0x00000E2D, 0x0409 }, /* R3629 - EQ2_8 */ + { 0x00000E2E, 0x04CC }, /* R3630 - EQ2_9 */ + { 0x00000E2F, 0x1C9B }, /* R3631 - EQ2_10 */ + { 0x00000E30, 0xF337 }, /* R3632 - EQ2_11 */ + { 0x00000E31, 0x040B }, /* R3633 - EQ2_12 */ + { 0x00000E32, 0x0CBB }, /* R3634 - EQ2_13 */ + { 0x00000E33, 0x16F8 }, /* R3635 - EQ2_14 */ + { 0x00000E34, 0xF7D9 }, /* R3636 - EQ2_15 */ + { 0x00000E35, 0x040A }, /* R3637 - EQ2_16 */ + { 0x00000E36, 0x1F14 }, /* R3638 - EQ2_17 */ + { 0x00000E37, 0x058C }, /* R3639 - EQ2_18 */ + { 0x00000E38, 0x0563 }, /* R3640 - EQ2_19 */ + { 0x00000E39, 0x4000 }, /* R3641 - EQ2_20 */ + { 0x00000E3A, 0x0B75 }, /* R3642 - EQ2_21 */ + { 0x00000E3C, 0x6318 }, /* R3644 - EQ3_1 */ + { 0x00000E3D, 0x6300 }, /* R3645 - EQ3_2 */ + { 0x00000E3E, 0x0FC8 }, /* R3646 - EQ3_3 */ + { 0x00000E3F, 0x03FE }, /* R3647 - EQ3_4 */ + { 0x00000E40, 0x00E0 }, /* R3648 - EQ3_5 */ + { 0x00000E41, 0x1EC4 }, /* R3649 - EQ3_6 */ + { 0x00000E42, 0xF136 }, /* R3650 - EQ3_7 */ + { 0x00000E43, 0x0409 }, /* R3651 - EQ3_8 */ + { 0x00000E44, 0x04CC }, /* R3652 - EQ3_9 */ + { 0x00000E45, 0x1C9B }, /* R3653 - EQ3_10 */ + { 0x00000E46, 0xF337 }, /* R3654 - EQ3_11 */ + { 0x00000E47, 0x040B }, /* R3655 - EQ3_12 */ + { 0x00000E48, 0x0CBB }, /* R3656 - EQ3_13 */ + { 0x00000E49, 0x16F8 }, /* R3657 - EQ3_14 */ + { 0x00000E4A, 0xF7D9 }, /* R3658 - EQ3_15 */ + { 0x00000E4B, 0x040A }, /* R3659 - EQ3_16 */ + { 0x00000E4C, 0x1F14 }, /* R3660 - EQ3_17 */ + { 0x00000E4D, 0x058C }, /* R3661 - EQ3_18 */ + { 0x00000E4E, 0x0563 }, /* R3662 - EQ3_19 */ + { 0x00000E4F, 0x4000 }, /* R3663 - EQ3_20 */ + { 0x00000E50, 0x0B75 }, /* R3664 - EQ3_21 */ + { 0x00000E52, 0x6318 }, /* R3666 - EQ4_1 */ + { 0x00000E53, 0x6300 }, /* R3667 - EQ4_2 */ + { 0x00000E54, 0x0FC8 }, /* R3668 - EQ4_3 */ + { 0x00000E55, 0x03FE }, /* R3669 - EQ4_4 */ + { 0x00000E56, 0x00E0 }, /* R3670 - EQ4_5 */ + { 0x00000E57, 0x1EC4 }, /* R3671 - EQ4_6 */ + { 0x00000E58, 0xF136 }, /* R3672 - EQ4_7 */ + { 0x00000E59, 0x0409 }, /* R3673 - EQ4_8 */ + { 0x00000E5A, 0x04CC }, /* R3674 - EQ4_9 */ + { 0x00000E5B, 0x1C9B }, /* R3675 - EQ4_10 */ + { 0x00000E5C, 0xF337 }, /* R3676 - EQ4_11 */ + { 0x00000E5D, 0x040B }, /* R3677 - EQ4_12 */ + { 0x00000E5E, 0x0CBB }, /* R3678 - EQ4_13 */ + { 0x00000E5F, 0x16F8 }, /* R3679 - EQ4_14 */ + { 0x00000E60, 0xF7D9 }, /* R3680 - EQ4_15 */ + { 0x00000E61, 0x040A }, /* R3681 - EQ4_16 */ + { 0x00000E62, 0x1F14 }, /* R3682 - EQ4_17 */ + { 0x00000E63, 0x058C }, /* R3683 - EQ4_18 */ + { 0x00000E64, 0x0563 }, /* R3684 - EQ4_19 */ + { 0x00000E65, 0x4000 }, /* R3685 - EQ4_20 */ + { 0x00000E66, 0x0B75 }, /* R3686 - EQ4_21 */ + { 0x00000E80, 0x0018 }, /* R3712 - DRC1 ctrl1 */ + { 0x00000E81, 0x0933 }, /* R3713 - DRC1 ctrl2 */ + { 0x00000E82, 0x0018 }, /* R3714 - DRC1 ctrl3 */ + { 0x00000E83, 0x0000 }, /* R3715 - DRC1 ctrl4 */ + { 0x00000E84, 0x0000 }, /* R3716 - DRC1 ctrl5 */ + { 0x00000EC0, 0x0000 }, /* R3776 - HPLPF1_1 */ + { 0x00000EC1, 0x0000 }, /* R3777 - HPLPF1_2 */ + { 0x00000EC4, 0x0000 }, /* R3780 - HPLPF2_1 */ + { 0x00000EC5, 0x0000 }, /* R3781 - HPLPF2_2 */ + { 0x00000EC8, 0x0000 }, /* R3784 - HPLPF3_1 */ + { 0x00000EC9, 0x0000 }, /* R3785 - HPLPF3_2 */ + { 0x00000ECC, 0x0000 }, /* R3788 - HPLPF4_1 */ + { 0x00000ECD, 0x0000 }, /* R3789 - HPLPF4_2 */ + { 0x00000EE0, 0x0000 }, /* R3808 - ASRC_ENABLE */ + { 0x00000EE2, 0x0000 }, /* R3810 - ASRC_RATE1 */ { 0x00000EE3, 0x4000 }, /* R3811 - ASRC_RATE2 */ - { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */ - { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */ - { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */ - { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */ - { 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */ - { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */ - { 0x00001100, 0x0010 }, /* R4352 - DSP1 Control 1 */ + { 0x00000EF0, 0x0000 }, /* R3824 - ISRC 1 CTRL 1 */ + { 0x00000EF1, 0x0000 }, /* R3825 - ISRC 1 CTRL 2 */ + { 0x00000EF2, 0x0000 }, /* R3826 - ISRC 1 CTRL 3 */ + { 0x00000EF3, 0x0000 }, /* R3827 - ISRC 2 CTRL 1 */ + { 0x00000EF4, 0x0000 }, /* R3828 - ISRC 2 CTRL 2 */ + { 0x00000EF5, 0x0000 }, /* R3829 - ISRC 2 CTRL 3 */ + { 0x00001100, 0x0010 }, /* R4352 - DSP1 Control 1 */ }; static bool wm5102_readable_register(struct device *dev, unsigned int reg) -- cgit v1.2.3 From 8ca9edc837932469b81b8b47ea43a074b6add970 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Thu, 27 Oct 2016 08:38:08 +0000 Subject: mfd: davinci_voicecodec: Tidyup header difinitions mach/hardware.h is needed on C source code side, not header. And struct davinci_vc is duplicated definition. Signed-off-by: Kuninori Morimoto Signed-off-by: Lee Jones --- drivers/mfd/davinci_voicecodec.c | 1 + include/linux/mfd/davinci_voicecodec.h | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c index dff2f19296b8..4d0a5f38038a 100644 --- a/drivers/mfd/davinci_voicecodec.c +++ b/drivers/mfd/davinci_voicecodec.c @@ -32,6 +32,7 @@ #include #include +#include static const struct regmap_config davinci_vc_regmap = { .reg_bits = 32, diff --git a/include/linux/mfd/davinci_voicecodec.h b/include/linux/mfd/davinci_voicecodec.h index 8e1cdbef3dad..2c0127cb06c5 100644 --- a/include/linux/mfd/davinci_voicecodec.h +++ b/include/linux/mfd/davinci_voicecodec.h @@ -28,8 +28,6 @@ #include #include -#include - struct regmap; /* @@ -99,8 +97,6 @@ struct davinci_vcif { dma_addr_t dma_rx_addr; }; -struct davinci_vc; - struct davinci_vc { /* Device data */ struct device *dev; -- cgit v1.2.3 From 202b56890aead063f90b6995554d4602dbd7752e Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Thu, 27 Oct 2016 15:50:18 +0530 Subject: mfd: wm8994-core: Don't use managed regulator bulk get API The kernel WARNs and then crashes today if wm8994_device_init() fails after calling devm_regulator_bulk_get(). That happens because there are multiple devices involved here and the order in which managed resources are freed isn't correct. The regulators are added as children of wm8994->dev. Whereas, devm_regulator_bulk_get() receives wm8994->dev as the device, though it gets the same regulators which were added as children of wm8994->dev earlier. During failures, the children are removed first and the core eventually calls regulator_unregister() for them. As regulator_put() was never done for them (opposite of devm_regulator_bulk_get()), the kernel WARNs at WARN_ON(rdev->open_count); And eventually it crashes from debugfs_remove_recursive(). Fix the kernel warnings and crashes by using regulator_bulk_get() instead of devm_regulator_bulk_get() and explicitly freeing the supplies in exit paths. Tested on Exynos 5250, dual core ARM A15 machine. Signed-off-by: Viresh Kumar Acked-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/wm8994-core.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c index 95e6bc55adbb..953d0790ffd5 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -393,8 +393,13 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) BUG(); goto err; } - - ret = devm_regulator_bulk_get(wm8994->dev, wm8994->num_supplies, + + /* + * Can't use devres helper here as some of the supplies are provided by + * wm8994->dev's children (regulators) and those regulators are + * unregistered by the devres core before the supplies are freed. + */ + ret = regulator_bulk_get(wm8994->dev, wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to get supplies: %d\n", ret); @@ -404,7 +409,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq) ret = regulator_bulk_enable(wm8994->num_supplies, wm8994->supplies); if (ret != 0) { dev_err(wm8994->dev, "Failed to enable supplies: %d\n", ret); - goto err; + goto err_regulator_free; } ret = wm8994_reg_read(wm8994, WM8994_SOFTWARE_RESET); @@ -595,6 +600,8 @@ err_irq: err_enable: regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); +err_regulator_free: + regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); err: mfd_remove_devices(wm8994->dev); return ret; @@ -605,6 +612,7 @@ static void wm8994_device_exit(struct wm8994 *wm8994) pm_runtime_disable(wm8994->dev); wm8994_irq_exit(wm8994); regulator_bulk_disable(wm8994->num_supplies, wm8994->supplies); + regulator_bulk_free(wm8994->num_supplies, wm8994->supplies); mfd_remove_devices(wm8994->dev); } -- cgit v1.2.3 From d34bffb5c5b4c370890f78c882136fe4711e9730 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Fri, 28 Oct 2016 11:32:53 +0100 Subject: mfd: arizona: Use irq_find_mapping when appropriate No need to use irq_create_mapping (although there is no issue with doing so) when we are only looking up an existing mapping. Just to streamline things a little and make the code a little more clear change some calls from irq_create_mapping to irq_find_mapping. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-irq.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/arizona-irq.c b/drivers/mfd/arizona-irq.c index 5e18d3c77582..2e01975f042d 100644 --- a/drivers/mfd/arizona-irq.c +++ b/drivers/mfd/arizona-irq.c @@ -398,10 +398,10 @@ err_ctrlif: err_boot_done: free_irq(arizona->irq, arizona); err_main_irq: - regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1), + regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1), arizona->irq_chip); err_aod: - regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0), + regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0), arizona->aod_irq_chip); err: return ret; @@ -413,9 +413,9 @@ int arizona_irq_exit(struct arizona *arizona) free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR), arizona); free_irq(arizona_map_irq(arizona, ARIZONA_IRQ_BOOT_DONE), arizona); - regmap_del_irq_chip(irq_create_mapping(arizona->virq, 1), + regmap_del_irq_chip(irq_find_mapping(arizona->virq, 1), arizona->irq_chip); - regmap_del_irq_chip(irq_create_mapping(arizona->virq, 0), + regmap_del_irq_chip(irq_find_mapping(arizona->virq, 0), arizona->aod_irq_chip); free_irq(arizona->irq, arizona); -- cgit v1.2.3 From d4c55da236e660b9f8786c3a2979e0c8eaf93026 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 28 Oct 2016 19:35:48 +0100 Subject: mfd: si476x-i2c: Fix spelling mistakes "Failet" and "gett" Trivial spelling mistake fixes in dev_err message. Signed-off-by: Colin Ian King Signed-off-by: Lee Jones --- drivers/mfd/si476x-i2c.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/si476x-i2c.c b/drivers/mfd/si476x-i2c.c index c180b7533bba..e6a3d999a376 100644 --- a/drivers/mfd/si476x-i2c.c +++ b/drivers/mfd/si476x-i2c.c @@ -753,7 +753,7 @@ static int si476x_core_probe(struct i2c_client *client, ARRAY_SIZE(core->supplies), core->supplies); if (rval) { - dev_err(&client->dev, "Failet to gett all of the regulators\n"); + dev_err(&client->dev, "Failed to get all of the regulators\n"); goto free_gpio; } -- cgit v1.2.3 From 4be85fc4f8eabd0b265e1f891fe0e733bf01407a Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sat, 29 Oct 2016 21:24:35 -0400 Subject: mfd: ab3100-core: Make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/mfd/Kconfig:config AB3100_CORE drivers/mfd/Kconfig: bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. In doing so, the debugfs unregister fcn becomes unused so we remove it too. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init was not in use by this code, the init ordering remains unchanged with this commit. Also note that MODULE_DEVICE_TABLE is a no-op for non-modular code. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Signed-off-by: Paul Gortmaker Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab3100-core.c | 39 +++------------------------------------ 1 file changed, 3 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab3100-core.c b/drivers/mfd/ab3100-core.c index 6a5a98806cb8..099635bed188 100644 --- a/drivers/mfd/ab3100-core.c +++ b/drivers/mfd/ab3100-core.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include @@ -628,20 +628,10 @@ static void ab3100_setup_debugfs(struct ab3100 *ab3100) exit_no_debugfs: return; } -static inline void ab3100_remove_debugfs(void) -{ - debugfs_remove(ab3100_set_reg_file); - debugfs_remove(ab3100_get_reg_file); - debugfs_remove(ab3100_reg_file); - debugfs_remove(ab3100_dir); -} #else static inline void ab3100_setup_debugfs(struct ab3100 *ab3100) { } -static inline void ab3100_remove_debugfs(void) -{ -} #endif /* @@ -949,45 +939,22 @@ static int ab3100_probe(struct i2c_client *client, return err; } -static int ab3100_remove(struct i2c_client *client) -{ - struct ab3100 *ab3100 = i2c_get_clientdata(client); - - /* Unregister subdevices */ - mfd_remove_devices(&client->dev); - ab3100_remove_debugfs(); - i2c_unregister_device(ab3100->testreg_client); - return 0; -} - static const struct i2c_device_id ab3100_id[] = { { "ab3100", 0 }, { } }; -MODULE_DEVICE_TABLE(i2c, ab3100_id); static struct i2c_driver ab3100_driver = { .driver = { - .name = "ab3100", + .name = "ab3100", + .suppress_bind_attrs = true, }, .id_table = ab3100_id, .probe = ab3100_probe, - .remove = ab3100_remove, }; static int __init ab3100_i2c_init(void) { return i2c_add_driver(&ab3100_driver); } - -static void __exit ab3100_i2c_exit(void) -{ - i2c_del_driver(&ab3100_driver); -} - subsys_initcall(ab3100_i2c_init); -module_exit(ab3100_i2c_exit); - -MODULE_AUTHOR("Linus Walleij "); -MODULE_DESCRIPTION("AB3100 core driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 31cbae2224c189b54a198ba4c9e93fea30ed61f1 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sat, 29 Oct 2016 21:24:36 -0400 Subject: mfd: ab8500-core: Make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/mfd/Kconfig:config AB8500_CORE drivers/mfd/Kconfig: bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init was not in use by this code, the init ordering remains unchanged with this commit. We replace module.h with moduleparam.h ; the latter since this file was implicitly relying on getting it. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Signed-off-by: Paul Gortmaker Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-core.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 589eebfc13df..6e00124cef01 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -123,6 +123,10 @@ static DEFINE_SPINLOCK(on_stat_lock); static u8 turn_on_stat_mask = 0xFF; static u8 turn_on_stat_set; static bool no_bm; /* No battery management */ +/* + * not really modular, but the easiest way to keep compat with existing + * bootargs behaviour is to continue using module_param here. + */ module_param(no_bm, bool, S_IRUGO); #define AB9540_MODEM_CTRL2_REG 0x23 @@ -1324,25 +1328,6 @@ static int ab8500_probe(struct platform_device *pdev) return ret; } -static int ab8500_remove(struct platform_device *pdev) -{ - struct ab8500 *ab8500 = platform_get_drvdata(pdev); - - if (((is_ab8505(ab8500) || is_ab9540(ab8500)) && - ab8500->chip_id >= AB8500_CUT2P0) || is_ab8540(ab8500)) - sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); - else - sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); - - if ((is_ab8505(ab8500) || is_ab9540(ab8500)) && - ab8500->chip_id >= AB8500_CUT2P0) - sysfs_remove_group(&ab8500->dev->kobj, &ab8505_attr_group); - - mfd_remove_devices(ab8500->dev); - - return 0; -} - static const struct platform_device_id ab8500_id[] = { { "ab8500-core", AB8500_VERSION_AB8500 }, { "ab8505-i2c", AB8500_VERSION_AB8505 }, @@ -1354,9 +1339,9 @@ static const struct platform_device_id ab8500_id[] = { static struct platform_driver ab8500_core_driver = { .driver = { .name = "ab8500-core", + .suppress_bind_attrs = true, }, .probe = ab8500_probe, - .remove = ab8500_remove, .id_table = ab8500_id, }; @@ -1364,14 +1349,4 @@ static int __init ab8500_core_init(void) { return platform_driver_register(&ab8500_core_driver); } - -static void __exit ab8500_core_exit(void) -{ - platform_driver_unregister(&ab8500_core_driver); -} core_initcall(ab8500_core_init); -module_exit(ab8500_core_exit); - -MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent"); -MODULE_DESCRIPTION("AB8500 MFD core"); -MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 4b3f2b60b53c65d42374c4aafcda3f3a836d436e Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sat, 29 Oct 2016 21:24:37 -0400 Subject: mfd: ab8500-debugfs: Make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/mfd/Kconfig:config AB8500_DEBUG drivers/mfd/Kconfig: bool "Enable debug info via debugfs" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. We explicitly disallow a driver unbind, since that doesn't have a sensible use case anyway, and it allows us to drop the ".remove" code for non-modular drivers. Since module_init was not in use by this code, the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. Signed-off-by: Paul Gortmaker Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-debugfs.c | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-debugfs.c b/drivers/mfd/ab8500-debugfs.c index acf6c00b14b9..c1c815241e02 100644 --- a/drivers/mfd/ab8500-debugfs.c +++ b/drivers/mfd/ab8500-debugfs.c @@ -74,7 +74,7 @@ #include #include #include -#include +#include #include #include #include @@ -3234,33 +3234,16 @@ err: return -ENOMEM; } -static int ab8500_debug_remove(struct platform_device *plf) -{ - debugfs_remove_recursive(ab8500_dir); - - return 0; -} - static struct platform_driver ab8500_debug_driver = { .driver = { .name = "ab8500-debug", + .suppress_bind_attrs = true, }, .probe = ab8500_debug_probe, - .remove = ab8500_debug_remove }; static int __init ab8500_debug_init(void) { return platform_driver_register(&ab8500_debug_driver); } - -static void __exit ab8500_debug_exit(void) -{ - platform_driver_unregister(&ab8500_debug_driver); -} subsys_initcall(ab8500_debug_init); -module_exit(ab8500_debug_exit); - -MODULE_AUTHOR("Mattias WALLIN Date: Sat, 29 Oct 2016 21:24:38 -0400 Subject: mfd: ab8500-gpadc: Make it explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/mfd/Kconfig:config AB8500_GPADC drivers/mfd/Kconfig: bool "ST-Ericsson AB8500 GPADC driver" ...meaning that it currently is not being built as a module by anyone. Lets remove the modular code that is essentially orphaned, so that when reading the driver there is no doubt it is builtin-only. Since module_init was not in use by this code, the init ordering remains unchanged with this commit. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. Signed-off-by: Paul Gortmaker Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-gpadc.c | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c index 97dcadc8fa8b..f4e94869d612 100644 --- a/drivers/mfd/ab8500-gpadc.c +++ b/drivers/mfd/ab8500-gpadc.c @@ -5,9 +5,9 @@ * Author: Arun R Murthy * Author: Daniel Willerud * Author: Johan Palsson + * Author: M'boumba Cedric Madianga */ #include -#include #include #include #include @@ -1054,11 +1054,7 @@ static int __init ab8500_gpadc_init(void) { return platform_driver_register(&ab8500_gpadc_driver); } - -static void __exit ab8500_gpadc_exit(void) -{ - platform_driver_unregister(&ab8500_gpadc_driver); -} +subsys_initcall_sync(ab8500_gpadc_init); /** * ab8540_gpadc_get_otp() - returns OTP values @@ -1077,14 +1073,3 @@ void ab8540_gpadc_get_otp(struct ab8500_gpadc *gpadc, *ibat_l = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_lo; *ibat_h = gpadc->cal_data[ADC_INPUT_IBAT].otp_calib_hi; } - -subsys_initcall_sync(ab8500_gpadc_init); -module_exit(ab8500_gpadc_exit); - -MODULE_LICENSE("GPL v2"); -MODULE_AUTHOR("Arun R Murthy"); -MODULE_AUTHOR("Daniel Willerud"); -MODULE_AUTHOR("Johan Palsson"); -MODULE_AUTHOR("M'boumba Cedric Madianga"); -MODULE_ALIAS("platform:ab8500_gpadc"); -MODULE_DESCRIPTION("AB8500 GPADC driver"); -- cgit v1.2.3 From dac94efad230764d876a9795611cbd79e465d936 Mon Sep 17 00:00:00 2001 From: Paul Gortmaker Date: Sat, 29 Oct 2016 21:24:39 -0400 Subject: mfd: ab8500: make sysctrl explicitly non-modular The Kconfig currently controlling compilation of this code is: drivers/mfd/Kconfig:config AB8500_CORE drivers/mfd/Kconfig: bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. We also delete the MODULE_LICENSE tag etc. since all that information was (or is now) contained at the top of the file in the comments. We replace module.h with init.h and export.h -- the latter since the file does make use of EXPORT_SYMBOL. Signed-off-by: Paul Gortmaker Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/ab8500-sysctrl.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c index 207cc497958a..80c0efa66ac1 100644 --- a/drivers/mfd/ab8500-sysctrl.c +++ b/drivers/mfd/ab8500-sysctrl.c @@ -1,11 +1,14 @@ /* + * AB8500 system control driver + * * Copyright (C) ST-Ericsson SA 2010 * Author: Mattias Nilsson for ST Ericsson. * License terms: GNU General Public License (GPL) version 2 */ #include -#include +#include +#include #include #include #include @@ -158,7 +161,3 @@ static int __init ab8500_sysctrl_init(void) return platform_driver_register(&ab8500_sysctrl_driver); } arch_initcall(ab8500_sysctrl_init); - -MODULE_AUTHOR("Mattias Nilsson Date: Sat, 29 Oct 2016 21:24:40 -0400 Subject: mfd: abx500-core: drop unused MODULE_ tags from non-modular code The Kconfig currently controlling compilation of this code is: drivers/mfd/Kconfig:config ABX500_CORE drivers/mfd/Kconfig: bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" ...meaning that it currently is not being built as a module by anyone. Lets remove the couple traces of modular infrastructure use, so that when reading the driver there is no doubt it is builtin-only. We delete the MODULE_LICENSE tag etc. since all that information is already contained at the top of the file in the comments. We replace module.h with init.h and export.h ; the latter since the file does export some symbols. Signed-off-by: Paul Gortmaker Acked-by: Linus Walleij Signed-off-by: Lee Jones --- drivers/mfd/abx500-core.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/abx500-core.c b/drivers/mfd/abx500-core.c index fe418995108c..0d3846a4767c 100644 --- a/drivers/mfd/abx500-core.c +++ b/drivers/mfd/abx500-core.c @@ -8,7 +8,8 @@ #include #include #include -#include +#include +#include #include static LIST_HEAD(abx500_list); @@ -150,7 +151,3 @@ int abx500_startup_irq_enabled(struct device *dev, unsigned int irq) return -ENOTSUPP; } EXPORT_SYMBOL(abx500_startup_irq_enabled); - -MODULE_AUTHOR("Mattias Wallin "); -MODULE_DESCRIPTION("ABX500 core driver"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 51a6c60b2f4d96e6954b620e84d5d9dc7ddc4103 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 31 Oct 2016 16:31:45 +0100 Subject: mfd: sun4i-gpadc: Select regmap-irq The new sun4i mfd driver is lacking a dependency, triggering very rarely int randconfig kernel builds: drivers/mfd/sun4i-gpadc.o: In function `sun4i_gpadc_probe': sun4i-gpadc.c:(.text.sun4i_gpadc_probe+0x110): undefined reference to `devm_regmap_add_irq_chip' This adds a 'select REGMAP_IRQ', as the other drivers with this problem do. Signed-off-by: Arnd Bergmann Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index c7dd32870558..0fde51ee633d 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -44,6 +44,7 @@ config MFD_SUN4I_GPADC tristate "Allwinner sunxi platforms' GPADC MFD driver" select MFD_CORE select REGMAP_MMIO + select REGMAP_IRQ depends on ARCH_SUNXI || COMPILE_TEST help Select this to get support for Allwinner SoCs (A10, A13 and A31) ADC. -- cgit v1.2.3 From 794550ffbf9134f8357b3035b8784f4ead6001d6 Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Tue, 1 Nov 2016 07:49:05 +0100 Subject: mfd: bcm590xx: Simplify a test 'i2c_new_dummy()' does not return an error pointer, so the test can be simplified to be more consistent. Signed-off-by: Christophe JAILLET Signed-off-by: Lee Jones --- drivers/mfd/bcm590xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c index 0d76d690176b..c572a35a9341 100644 --- a/drivers/mfd/bcm590xx.c +++ b/drivers/mfd/bcm590xx.c @@ -67,7 +67,7 @@ static int bcm590xx_i2c_probe(struct i2c_client *i2c_pri, /* Secondary I2C slave address is the base address with A(2) asserted */ bcm590xx->i2c_sec = i2c_new_dummy(i2c_pri->adapter, i2c_pri->addr | BIT(2)); - if (IS_ERR_OR_NULL(bcm590xx->i2c_sec)) { + if (!bcm590xx->i2c_sec) { dev_err(&i2c_pri->dev, "failed to add secondary I2C device\n"); return -ENODEV; } -- cgit v1.2.3 From dd5a8f20c28732d7eeaa5a9768676e9045c97ce1 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 1 Nov 2016 11:38:18 +0100 Subject: mfd: core: Fix device reference leak in mfd_clone_cell Make sure to drop the reference taken by bus_find_device_by_name() before returning from mfd_clone_cell(). Fixes: a9bbba996302 ("mfd: add platform_device sharing support for mfd") Signed-off-by: Johan Hovold Signed-off-by: Lee Jones --- drivers/mfd/mfd-core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 3ac486a597f3..c57e407020f1 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -399,6 +399,8 @@ int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) clones[i]); } + put_device(dev); + return 0; } EXPORT_SYMBOL(mfd_clone_cell); -- cgit v1.2.3 From f57576e73cc4808af3b097b1fdedfa7d0f6378a4 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Tue, 1 Nov 2016 15:59:50 +0000 Subject: mfd: intel_soc_pmic_bxtwc: Fix a typo in MODULE_DEVICE_TABLE() Fix a typo in MODULE_DEVICE_TABLE(). 'pmic_acpi_ids' should be 'bxtwc_acpi_ids'. Signed-off-by: Wei Yongjun Signed-off-by: Lee Jones --- drivers/mfd/intel_soc_pmic_bxtwc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 43e54b7e908f..9f9c04364254 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -479,7 +479,7 @@ static const struct acpi_device_id bxtwc_acpi_ids[] = { { "INT34D3", }, { } }; -MODULE_DEVICE_TABLE(acpi, pmic_acpi_ids); +MODULE_DEVICE_TABLE(acpi, bxtwc_acpi_ids); static struct platform_driver bxtwc_driver = { .probe = bxtwc_probe, -- cgit v1.2.3 From 34d9030b5d06ec0072796b3ab6a3fa24e53ece3d Mon Sep 17 00:00:00 2001 From: Chen-Yu Tsai Date: Fri, 11 Nov 2016 11:29:52 +0800 Subject: mfd: axp20x: Add address extension registers for AXP806 regmap The AXP806 supports either master/standalone or slave mode. Slave mode allows sharing the serial bus, even with multiple AXP806 which all have the same hardware address. This is done with extra "serial interface address extension", or AXP806_BUS_ADDR_EXT, and "register address extension", or AXP806_REG_ADDR_EXT, registers. The former is read-only, with 1 bit customizable at the factory, and 1 bit depending on the state of an external pin. The latter is writable. Only when the these device addressing bits (in the upper 4 bits of the registers) match, will the device respond to operations on its other registers. Add these 2 registers to the regmap so we can access them. Signed-off-by: Chen-Yu Tsai Signed-off-by: Lee Jones --- drivers/mfd/axp20x.c | 3 ++- include/linux/mfd/axp20x.h | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c index 98377d29b783..ed918de84238 100644 --- a/drivers/mfd/axp20x.c +++ b/drivers/mfd/axp20x.c @@ -136,6 +136,7 @@ static const struct regmap_range axp806_writeable_ranges[] = { regmap_reg_range(AXP806_PWR_OUT_CTRL1, AXP806_CLDO3_V_CTRL), regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IRQ2_EN), regmap_reg_range(AXP20X_IRQ1_STATE, AXP20X_IRQ2_STATE), + regmap_reg_range(AXP806_REG_ADDR_EXT, AXP806_REG_ADDR_EXT), }; static const struct regmap_range axp806_volatile_ranges[] = { @@ -306,7 +307,7 @@ static const struct regmap_config axp806_regmap_config = { .val_bits = 8, .wr_table = &axp806_writeable_table, .volatile_table = &axp806_volatile_table, - .max_register = AXP806_VREF_TEMP_WARN_L, + .max_register = AXP806_REG_ADDR_EXT, .cache_type = REGCACHE_RBTREE, }; diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h index 6349496f09fc..a4860bc9b73d 100644 --- a/include/linux/mfd/axp20x.h +++ b/include/linux/mfd/axp20x.h @@ -115,6 +115,8 @@ enum { #define AXP806_CLDO2_V_CTRL 0x25 #define AXP806_CLDO3_V_CTRL 0x26 #define AXP806_VREF_TEMP_WARN_L 0xf3 +#define AXP806_BUS_ADDR_EXT 0xfe +#define AXP806_REG_ADDR_EXT 0xff /* Interrupt */ #define AXP152_IRQ1_EN 0x40 -- cgit v1.2.3 From c5e589a171728c9f5c587f9254ec6b343153c2ce Mon Sep 17 00:00:00 2001 From: Pierre-Hugues Husson Date: Sat, 5 Nov 2016 17:19:24 +0100 Subject: mfd: rn5t618: Add Ricoh RC5T619 PMIC support The Ricoh RN5T567 is from the same family as the Ricoh RN5T618 is, the differences are: + DCDC4/DCDC5 + LDO7-10 + Slightly different output voltage/currents + 32kHz Output + RTC + USB Charger detection Signed-off-by: Pierre-Hugues Husson Acked-by: Rob Herring Signed-off-by: Lee Jones --- Documentation/devicetree/bindings/mfd/rn5t618.txt | 16 ++++++++++------ drivers/mfd/Kconfig | 3 ++- drivers/mfd/rn5t618.c | 1 + include/linux/mfd/rn5t618.h | 9 +++++++++ 4 files changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mfd/rn5t618.txt b/Documentation/devicetree/bindings/mfd/rn5t618.txt index 9e6770b105c9..65c23263cc54 100644 --- a/Documentation/devicetree/bindings/mfd/rn5t618.txt +++ b/Documentation/devicetree/bindings/mfd/rn5t618.txt @@ -1,21 +1,25 @@ * Ricoh RN5T567/RN5T618 PMIC -Ricoh RN5T567/RN5T618 is a power management IC family which integrates -3 to 4 step-down DCDC converters, 7 low-dropout regulators, GPIOs and -a watchdog timer. The RN5T618 provides additionally a Li-ion battery -charger, fuel gauge and an ADC. It can be controlled through an I2C -interface. +Ricoh RN5T567/RN5T618/RC5T619 is a power management IC family which +integrates 3 to 5 step-down DCDC converters, 7 to 10 low-dropout regulators, +GPIOs, and a watchdog timer. It can be controlled through an I2C interface. +The RN5T618/RC5T619 provides additionally a Li-ion battery charger, +fuel gauge, and an ADC. +The RC5T619 additionnally includes USB charger detection and an RTC. Required properties: - compatible: must be one of "ricoh,rn5t567" "ricoh,rn5t618" + "ricoh,rc5t619" - reg: the I2C slave address of the device Sub-nodes: - regulators: the node is required if the regulator functionality is needed. The valid regulator names are: DCDC1, DCDC2, DCDC3, DCDC4 - (RN5T567), LDO1, LDO2, LDO3, LDO4, LDO5, LDORTC1 and LDORTC2. + (RN5T567/RC5T619), LDO1, LDO2, LDO3, LDO4, LDO5, LDO6, LDO7, LDO8, + LDO9, LDO10, LDORTC1 and LDORTC2. + LDO7-10 are specific to RC5T619. The common bindings for each individual regulator can be found in: Documentation/devicetree/bindings/regulator/regulator.txt diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 0fde51ee633d..4ce3b6f11830 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -894,7 +894,8 @@ config MFD_RN5T618 select MFD_CORE select REGMAP_I2C help - Say yes here to add support for the Ricoh RN5T567 or R5T618 PMIC. + Say yes here to add support for the Ricoh RN5T567, + RN5T618, RC5T619 PMIC. This driver provides common support for accessing the device, additional drivers must be enabled in order to use the functionality of the device. diff --git a/drivers/mfd/rn5t618.c b/drivers/mfd/rn5t618.c index ee94080e1cbb..8131d1975745 100644 --- a/drivers/mfd/rn5t618.c +++ b/drivers/mfd/rn5t618.c @@ -87,6 +87,7 @@ static int rn5t618_restart(struct notifier_block *this, static const struct of_device_id rn5t618_of_match[] = { { .compatible = "ricoh,rn5t567", .data = (void *)RN5T567 }, { .compatible = "ricoh,rn5t618", .data = (void *)RN5T618 }, + { .compatible = "ricoh,rc5t619", .data = (void *)RC5T619 }, { } }; MODULE_DEVICE_TABLE(of, rn5t618_of_match); diff --git a/include/linux/mfd/rn5t618.h b/include/linux/mfd/rn5t618.h index cadc6543909d..e5a6cdeb77db 100644 --- a/include/linux/mfd/rn5t618.h +++ b/include/linux/mfd/rn5t618.h @@ -58,10 +58,13 @@ #define RN5T618_DC3CTL2 0x31 #define RN5T618_DC4CTL 0x32 #define RN5T618_DC4CTL2 0x33 +#define RN5T618_DC5CTL 0x34 +#define RN5T618_DC5CTL2 0x35 #define RN5T618_DC1DAC 0x36 #define RN5T618_DC2DAC 0x37 #define RN5T618_DC3DAC 0x38 #define RN5T618_DC4DAC 0x39 +#define RN5T618_DC5DAC 0x3a #define RN5T618_DC1DAC_SLP 0x3b #define RN5T618_DC2DAC_SLP 0x3c #define RN5T618_DC3DAC_SLP 0x3d @@ -77,6 +80,11 @@ #define RN5T618_LDO3DAC 0x4e #define RN5T618_LDO4DAC 0x4f #define RN5T618_LDO5DAC 0x50 +#define RN5T618_LDO6DAC 0x51 +#define RN5T618_LDO7DAC 0x52 +#define RN5T618_LDO8DAC 0x53 +#define RN5T618_LDO9DAC 0x54 +#define RN5T618_LDO10DAC 0x55 #define RN5T618_LDORTCDAC 0x56 #define RN5T618_LDORTC2DAC 0x57 #define RN5T618_LDO1DAC_SLP 0x58 @@ -231,6 +239,7 @@ enum { enum { RN5T567 = 0, RN5T618, + RC5T619, }; struct rn5t618 { -- cgit v1.2.3 From 85a9419a254e234c997a2bf56b71264009ebc117 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 15 Nov 2016 12:37:04 +0200 Subject: mfd: intel-lpss: Try to enable Memory-Write-Invalidate Enable MWI mechanism if PCI bus master supports it. It might be potential benefit in some cases. Documentation [1] says that standard Memory Write might supply more current data than in the CPU modified cache line and "trashing a line in the cache may trash some data that is more current that in the memory line". This allows to avoid potential retries and other performance degradation issues on the bus. [1] PCI System Architecture, 4th edition, ISBN: 0-201-30974-2, pp.117-119. Signed-off-by: Andy Shevchenko Acked-by: Mika Westerberg Signed-off-by: Lee Jones --- drivers/mfd/intel-lpss-pci.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/intel-lpss-pci.c b/drivers/mfd/intel-lpss-pci.c index 3228fd182a99..4f561869b966 100644 --- a/drivers/mfd/intel-lpss-pci.c +++ b/drivers/mfd/intel-lpss-pci.c @@ -41,6 +41,7 @@ static int intel_lpss_pci_probe(struct pci_dev *pdev, /* Probably it is enough to set this for iDMA capable devices only */ pci_set_master(pdev); + pci_try_set_mwi(pdev); ret = intel_lpss_probe(&pdev->dev, info); if (ret) -- cgit v1.2.3 From 953f432b3d0a171276455e40fdeac7225d36d678 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 15 Nov 2016 12:01:51 +0000 Subject: mfd: pm8xxx: add support to pm8821 This patch adds support to PM8821 PMIC and interrupt support. PM8821 is companion device that supplements primary PMIC PM8921 IC. Signed-off-by: Srinivas Kandagatla Acked-by: Rob Herring Signed-off-by: Lee Jones --- .../devicetree/bindings/mfd/qcom-pm8xxx.txt | 1 + drivers/mfd/qcom-pm8xxx.c | 231 ++++++++++++++++++++- 2 files changed, 222 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt index 37a088f9a648..9e5eba4a4f0d 100644 --- a/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt +++ b/Documentation/devicetree/bindings/mfd/qcom-pm8xxx.txt @@ -10,6 +10,7 @@ voltages and other various functionality to Qualcomm SoCs. Value type: Definition: must be one of: "qcom,pm8058" + "qcom,pm8821" "qcom,pm8921" - #address-cells: diff --git a/drivers/mfd/qcom-pm8xxx.c b/drivers/mfd/qcom-pm8xxx.c index 7f9620ec61e8..f08758f6b418 100644 --- a/drivers/mfd/qcom-pm8xxx.c +++ b/drivers/mfd/qcom-pm8xxx.c @@ -39,6 +39,20 @@ #define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7) #define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8) +#define PM8821_SSBI_REG_ADDR_IRQ_BASE 0x100 +#define PM8821_SSBI_REG_ADDR_IRQ_MASTER0 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0x30) +#define PM8821_SSBI_REG_ADDR_IRQ_MASTER1 (PM8821_SSBI_REG_ADDR_IRQ_BASE + 0xb0) +#define PM8821_SSBI_REG(m, b, offset) \ + ((m == 0) ? \ + (PM8821_SSBI_REG_ADDR_IRQ_MASTER0 + b + offset) : \ + (PM8821_SSBI_REG_ADDR_IRQ_MASTER1 + b + offset)) +#define PM8821_SSBI_ADDR_IRQ_ROOT(m, b) PM8821_SSBI_REG(m, b, 0x0) +#define PM8821_SSBI_ADDR_IRQ_CLEAR(m, b) PM8821_SSBI_REG(m, b, 0x01) +#define PM8821_SSBI_ADDR_IRQ_MASK(m, b) PM8821_SSBI_REG(m, b, 0x08) +#define PM8821_SSBI_ADDR_IRQ_RT_STATUS(m, b) PM8821_SSBI_REG(m, b, 0x0f) + +#define PM8821_BLOCKS_PER_MASTER 7 + #define PM_IRQF_LVL_SEL 0x01 /* level select */ #define PM_IRQF_MASK_FE 0x02 /* mask falling edge */ #define PM_IRQF_MASK_RE 0x04 /* mask rising edge */ @@ -54,6 +68,7 @@ #define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */ #define PM8XXX_NR_IRQS 256 +#define PM8821_NR_IRQS 112 struct pm_irq_chip { struct regmap *regmap; @@ -65,6 +80,12 @@ struct pm_irq_chip { u8 config[0]; }; +struct pm_irq_data { + int num_irqs; + const struct irq_domain_ops *irq_domain_ops; + void (*irq_handler)(struct irq_desc *desc); +}; + static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp, unsigned int *ip) { @@ -182,6 +203,78 @@ static void pm8xxx_irq_handler(struct irq_desc *desc) chained_irq_exit(irq_chip, desc); } +static void pm8821_irq_block_handler(struct pm_irq_chip *chip, + int master, int block) +{ + int pmirq, irq, i, ret; + unsigned int bits; + + ret = regmap_read(chip->regmap, + PM8821_SSBI_ADDR_IRQ_ROOT(master, block), &bits); + if (ret) { + pr_err("Reading block %d failed ret=%d", block, ret); + return; + } + + /* Convert block offset to global block number */ + block += (master * PM8821_BLOCKS_PER_MASTER) - 1; + + /* Check IRQ bits */ + for (i = 0; i < 8; i++) { + if (bits & BIT(i)) { + pmirq = block * 8 + i; + irq = irq_find_mapping(chip->irqdomain, pmirq); + generic_handle_irq(irq); + } + } +} + +static inline void pm8821_irq_master_handler(struct pm_irq_chip *chip, + int master, u8 master_val) +{ + int block; + + for (block = 1; block < 8; block++) + if (master_val & BIT(block)) + pm8821_irq_block_handler(chip, master, block); +} + +static void pm8821_irq_handler(struct irq_desc *desc) +{ + struct pm_irq_chip *chip = irq_desc_get_handler_data(desc); + struct irq_chip *irq_chip = irq_desc_get_chip(desc); + unsigned int master; + int ret; + + chained_irq_enter(irq_chip, desc); + ret = regmap_read(chip->regmap, + PM8821_SSBI_REG_ADDR_IRQ_MASTER0, &master); + if (ret) { + pr_err("Failed to read master 0 ret=%d\n", ret); + goto done; + } + + /* bits 1 through 7 marks the first 7 blocks in master 0 */ + if (master & GENMASK(7, 1)) + pm8821_irq_master_handler(chip, 0, master); + + /* bit 0 marks if master 1 contains any bits */ + if (!(master & BIT(0))) + goto done; + + ret = regmap_read(chip->regmap, + PM8821_SSBI_REG_ADDR_IRQ_MASTER1, &master); + if (ret) { + pr_err("Failed to read master 1 ret=%d\n", ret); + goto done; + } + + pm8821_irq_master_handler(chip, 1, master); + +done: + chained_irq_exit(irq_chip, desc); +} + static void pm8xxx_irq_mask_ack(struct irq_data *d) { struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); @@ -299,6 +392,104 @@ static const struct irq_domain_ops pm8xxx_irq_domain_ops = { .map = pm8xxx_irq_domain_map, }; +static void pm8821_irq_mask_ack(struct irq_data *d) +{ + struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); + unsigned int pmirq = irqd_to_hwirq(d); + u8 block, master; + int irq_bit, rc; + + block = pmirq / 8; + master = block / PM8821_BLOCKS_PER_MASTER; + irq_bit = pmirq % 8; + block %= PM8821_BLOCKS_PER_MASTER; + + rc = regmap_update_bits(chip->regmap, + PM8821_SSBI_ADDR_IRQ_MASK(master, block), + BIT(irq_bit), BIT(irq_bit)); + if (rc) { + pr_err("Failed to mask IRQ:%d rc=%d\n", pmirq, rc); + return; + } + + rc = regmap_update_bits(chip->regmap, + PM8821_SSBI_ADDR_IRQ_CLEAR(master, block), + BIT(irq_bit), BIT(irq_bit)); + if (rc) + pr_err("Failed to CLEAR IRQ:%d rc=%d\n", pmirq, rc); +} + +static void pm8821_irq_unmask(struct irq_data *d) +{ + struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); + unsigned int pmirq = irqd_to_hwirq(d); + int irq_bit, rc; + u8 block, master; + + block = pmirq / 8; + master = block / PM8821_BLOCKS_PER_MASTER; + irq_bit = pmirq % 8; + block %= PM8821_BLOCKS_PER_MASTER; + + rc = regmap_update_bits(chip->regmap, + PM8821_SSBI_ADDR_IRQ_MASK(master, block), + BIT(irq_bit), ~BIT(irq_bit)); + if (rc) + pr_err("Failed to read/write unmask IRQ:%d rc=%d\n", pmirq, rc); + +} + +static int pm8821_irq_get_irqchip_state(struct irq_data *d, + enum irqchip_irq_state which, + bool *state) +{ + struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); + int rc, pmirq = irqd_to_hwirq(d); + u8 block, irq_bit, master; + unsigned int bits; + + block = pmirq / 8; + master = block / PM8821_BLOCKS_PER_MASTER; + irq_bit = pmirq % 8; + block %= PM8821_BLOCKS_PER_MASTER; + + rc = regmap_read(chip->regmap, + PM8821_SSBI_ADDR_IRQ_RT_STATUS(master, block), &bits); + if (rc) { + pr_err("Reading Status of IRQ %d failed rc=%d\n", pmirq, rc); + return rc; + } + + *state = !!(bits & BIT(irq_bit)); + + return rc; +} + +static struct irq_chip pm8821_irq_chip = { + .name = "pm8821", + .irq_mask_ack = pm8821_irq_mask_ack, + .irq_unmask = pm8821_irq_unmask, + .irq_get_irqchip_state = pm8821_irq_get_irqchip_state, + .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE, +}; + +static int pm8821_irq_domain_map(struct irq_domain *d, unsigned int irq, + irq_hw_number_t hwirq) +{ + struct pm_irq_chip *chip = d->host_data; + + irq_set_chip_and_handler(irq, &pm8821_irq_chip, handle_level_irq); + irq_set_chip_data(irq, chip); + irq_set_noprobe(irq); + + return 0; +} + +static const struct irq_domain_ops pm8821_irq_domain_ops = { + .xlate = irq_domain_xlate_twocell, + .map = pm8821_irq_domain_map, +}; + static const struct regmap_config ssbi_regmap_config = { .reg_bits = 16, .val_bits = 8, @@ -308,22 +499,41 @@ static const struct regmap_config ssbi_regmap_config = { .reg_write = ssbi_reg_write }; +static const struct pm_irq_data pm8xxx_data = { + .num_irqs = PM8XXX_NR_IRQS, + .irq_domain_ops = &pm8xxx_irq_domain_ops, + .irq_handler = pm8xxx_irq_handler, +}; + +static const struct pm_irq_data pm8821_data = { + .num_irqs = PM8821_NR_IRQS, + .irq_domain_ops = &pm8821_irq_domain_ops, + .irq_handler = pm8821_irq_handler, +}; + static const struct of_device_id pm8xxx_id_table[] = { - { .compatible = "qcom,pm8018", }, - { .compatible = "qcom,pm8058", }, - { .compatible = "qcom,pm8921", }, + { .compatible = "qcom,pm8018", .data = &pm8xxx_data}, + { .compatible = "qcom,pm8058", .data = &pm8xxx_data}, + { .compatible = "qcom,pm8821", .data = &pm8821_data}, + { .compatible = "qcom,pm8921", .data = &pm8xxx_data}, { } }; MODULE_DEVICE_TABLE(of, pm8xxx_id_table); static int pm8xxx_probe(struct platform_device *pdev) { + const struct pm_irq_data *data; struct regmap *regmap; int irq, rc; unsigned int val; u32 rev; struct pm_irq_chip *chip; - unsigned int nirqs = PM8XXX_NR_IRQS; + + data = of_device_get_match_data(&pdev->dev); + if (!data) { + dev_err(&pdev->dev, "No matching driver data found\n"); + return -EINVAL; + } irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -354,25 +564,26 @@ static int pm8xxx_probe(struct platform_device *pdev) rev |= val << BITS_PER_BYTE; chip = devm_kzalloc(&pdev->dev, sizeof(*chip) + - sizeof(chip->config[0]) * nirqs, - GFP_KERNEL); + sizeof(chip->config[0]) * data->num_irqs, + GFP_KERNEL); if (!chip) return -ENOMEM; platform_set_drvdata(pdev, chip); chip->regmap = regmap; - chip->num_irqs = nirqs; + chip->num_irqs = data->num_irqs; chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8); chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8); spin_lock_init(&chip->pm_irq_lock); - chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, nirqs, - &pm8xxx_irq_domain_ops, + chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, + data->num_irqs, + data->irq_domain_ops, chip); if (!chip->irqdomain) return -ENODEV; - irq_set_chained_handler_and_data(irq, pm8xxx_irq_handler, chip); + irq_set_chained_handler_and_data(irq, data->irq_handler, chip); irq_set_irq_wake(irq, 1); rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev); -- cgit v1.2.3 From fb36f77efec7c4371a8be0c73424fa2bf841e3b2 Mon Sep 17 00:00:00 2001 From: Charles Keepax Date: Mon, 14 Nov 2016 17:15:56 +0000 Subject: mfd: arizona: Disable IRQs during driver remove As DCVDD will often be supplied by a child node of the MFD, we can't call mfd_remove_devices as the first step in arizona_dev_exit as might be expected (tidy up the children before we tidy up the MFD). We need to disable and put the DCVDD regulator before we call mfd_remove_devices, to prevent PM runtime from turning this back on we also need to disable the PM runtime before we do this. Finally we can not clean up the IRQs until all the MFD children have been removed, as they may have registered IRQs themselves. This creates a window of time where the interrupts are enabled but the PM runtime, on which the IRQ handler depends, is not available, any interrupts in this window will go unhandled and fill the log with failed to resume device messages. To avoid this we simply disable the main IRQ at the start of arizona_dev_exit, we don't need to actually handle any IRQs in this window as we are removing the driver. Signed-off-by: Charles Keepax Signed-off-by: Lee Jones --- drivers/mfd/arizona-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c index 41767f7239bb..b6d4bc63c426 100644 --- a/drivers/mfd/arizona-core.c +++ b/drivers/mfd/arizona-core.c @@ -1553,6 +1553,7 @@ EXPORT_SYMBOL_GPL(arizona_dev_init); int arizona_dev_exit(struct arizona *arizona) { + disable_irq(arizona->irq); pm_runtime_disable(arizona->dev); regulator_disable(arizona->dcvdd); -- cgit v1.2.3 From 445c93093d7f28a0a07fd10f0d7a8aada4e1932e Mon Sep 17 00:00:00 2001 From: Keerthy Date: Thu, 10 Nov 2016 10:39:17 +0530 Subject: mfd: palmas: Remove redundant check in palmas_power_off palmas_dev and palmas_power_off are always assigned together. So the check for palmas_dev inside palmas_power_off function is redundant. Removing the same. Signed-off-by: Keerthy Signed-off-by: Lee Jones --- drivers/mfd/palmas.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/palmas.c b/drivers/mfd/palmas.c index 8f8bacb67a15..ee9e9ea10444 100644 --- a/drivers/mfd/palmas.c +++ b/drivers/mfd/palmas.c @@ -431,9 +431,6 @@ static void palmas_power_off(void) unsigned int addr; int ret, slave; - if (!palmas_dev) - return; - slave = PALMAS_BASE_TO_SLAVE(PALMAS_PMU_CONTROL_BASE); addr = PALMAS_BASE_TO_REG(PALMAS_PMU_CONTROL_BASE, PALMAS_DEV_CTRL); -- cgit v1.2.3 From 40a50f8b307de8d08f3fa37c312fc16a7dd233e5 Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Tue, 15 Nov 2016 22:02:11 +0900 Subject: mfd: tps65217: Fix page fault on unloading modules TPS65217 IRQ domain should be removed and initialised as NULL when the module is unloaded for the next use. When tps65217.ko is loaded again, it causes the page fault. This patch fixes the error below. root@arm:~# lsmod | grep "tps" tps65217_charger 3538 0 tps65218_pwrbutton 2974 0 tps65217 6710 1 tps65217_charger root@arm:~# modprobe -r tps65217_charger root@arm:~# modprobe tps65217.ko [ 71.990277] Unable to handle kernel paging request at virtual address bf055944 [ 71.998063] pgd = dd3a4000 [ 72.000904] [bf055944] *pgd=9e6f7811, *pte=00000000, *ppte=00000000 [ 72.007567] Internal error: Oops: 7 [#1] SMP ARM [ 72.012404] Modules linked in: tps65217(+) evdev musb_dsps musb_hdrc udc_core tps65218_pwrbutton usbcore phy_am335] [ 72.055700] CPU: 0 PID: 243 Comm: modprobe Not tainted 4.9.0-rc5-next-20161114 #3 [ 72.063531] Hardware name: Generic AM33XX (Flattened Device Tree) [ 72.069899] task: de714380 task.stack: de7e6000 [ 72.074655] PC is at irq_find_matching_fwspec+0x88/0x100 [ 72.080211] LR is at 0xde7e79d8 [ 72.083496] pc : [] lr : [] psr: 200e0013 [ 72.083496] sp : de7e7a78 ip : 00000000 fp : dd138a68 [ 72.095506] r10: c0ca04f8 r9 : 00000018 r8 : de7e7ab8 [ 72.100973] r7 : 00000001 r6 : c0c4517c r5 : df963f68 r4 : de321980 [ 72.107797] r3 : bf055940 r2 : de714380 r1 : 00000000 r0 : 00000000 [ 72.114633] Flags: nzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none [ 72.122084] Control: 10c5387d Table: 9d3a4019 DAC: 00000051 [ 72.128097] Process modprobe (pid: 243, stack limit = 0xde7e6218) [ 72.134489] Stack: (0xde7e7a78 to 0xde7e8000) [ 72.139060] 7a60: df963f68 de7e7ab8 [ 72.147643] 7a80: 00000000 dd0e1000 dd491e20 c01a6ea0 600e0013 c01a5dc0 dd138a68 c0c45138 [ 72.156216] 7aa0: df963f68 00000000 df963f68 dd0e1010 00000000 c01a71a4 df963f68 00000001 [ 72.164800] 7ac0: 00000002 de7e7ac0 c80048b8 dd0adf00 df963f68 c0c4517c 00000000 de7e7b50 [ 72.173369] 7ae0: 00000018 c0ca04f8 dd138a68 c01a5dc0 df963f68 dd0e1010 00000000 dd0e1000 [ 72.181942] 7b00: dd491e20 c0653a70 df963f58 00000001 00000002 00000000 00000000 00000000 [ 72.190522] 7b20: 600e0093 c0cbf8f0 c0c0512c c0193674 00000001 00000080 00000000 c0554984 [ 72.199096] 7b40: 00000000 00000000 800e0013 c0553858 df963f68 00000000 00000000 00000000 [ 72.207674] 7b60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 72.216239] 7b80: 00000000 00000000 00000000 00000000 00000000 00000000 dd0e1000 c0544d24 [ 72.224816] 7ba0: dd491e10 dd0e1010 dd16e800 bf1d517c bf1d5620 dd0e1010 c1497ed4 bf1d5620 [ 72.233398] 7bc0: dd0e1010 fffffdfb bf1d5620 bf1d5620 00000000 c054537c c0545330 dd0e1010 [ 72.241967] 7be0: c1497ed4 00000000 bf1d5620 c05433ac 00000000 00000000 de7e7c28 c0543570 [ 72.250537] 7c00: 00000001 c1497e90 00000000 c0541884 de080cd4 dd44b7d4 dd0e1010 dd0e1010 [ 72.259109] 7c20: dd0e1044 c05430c8 dd0e1010 00000001 dd0e1010 dd0e1018 dd0e1010 c0c9e328 [ 72.267676] 7c40: de5d4020 c0542760 dd0e1018 dd0e1010 00000000 c0540ba8 dd138a40 c048dec4 [ 72.276253] 7c60: 00000000 dd0e1000 00000001 dd0e1000 dd0e1010 dd0e1000 bf233de0 dd138a40 [ 72.284829] 7c80: dd0e1010 c05450a0 000000bf 00000000 dd138a60 00000001 dd0e1000 c0571240 [ 72.293398] 7ca0: 00000000 dd1ce9c0 00000040 dd1ce9cc bf233de0 00000003 de5d4020 ffffffff [ 72.301969] 7cc0: 00000004 dd0adf00 00000000 c0571408 00000000 00000000 dd0adf00 de5d4020 [ 72.310543] 7ce0: c057146c dd1ce9c0 bf233d14 de5d4020 de7fb3d0 00000004 bf233d14 ffffffff [ 72.319120] 7d00: 00000018 dd49bf30 c01cedc0 c05714d0 00000000 00000000 dd0adf00 de322810 [ 72.327692] 7d20: de322810 00000000 dd033000 000000f0 00000001 bf2333fc 00000000 00000000 [ 72.336269] 7d40: dd0adf00 de5d4020 000000b6 bf233e40 de5d4020 bf233968 de5d4004 de5d4000 [ 72.344848] 7d60: bf233314 c06148ac de5d4020 c1497ed4 00000000 bf233e40 00000000 c05433ac [ 72.353422] 7d80: 00000000 de5d4020 bf233e40 de5d4054 00000000 bf236000 00000000 c0543538 [ 72.362002] 7da0: 00000000 bf233e40 c0543484 c05417e4 de1442a4 de5d04d0 bf233e40 de321300 [ 72.370582] 7dc0: c0caa5a4 c05429fc bf233be0 bf233e40 c0cbfa44 bf233e40 c0cbfa44 dd2f7740 [ 72.379148] 7de0: bf233f00 c05442f0 bf233e8c bf233e24 c0cbfa44 c0615ae0 00000000 bf233f00 [ 72.387718] 7e00: c0cbfa44 c010186c 200f0013 c0191650 de714380 00000000 600f0013 00000040 [ 72.396286] 7e20: dd2f7740 c018f1ac 00000001 c0c8356c 024000c0 c01a8854 c0c56e0e c028225c [ 72.404863] 7e40: dd2f7740 c0191984 de714380 dd2f7740 00000001 bf233f00 bf233f00 c0cbfa44 [ 72.413440] 7e60: dd2f7740 bf233f00 00000001 dd49bf08 dd49bf30 c0230998 00000001 c0c8356c [ 72.421997] 7e80: c0c4c536 c0cbfa44 c0c0512c c01d2070 bf233f0c 00007fff bf233f00 c01cf5b8 [ 72.430570] 7ea0: 00000000 c1475134 c01cee34 bf23411c bf233f48 bf234054 bf234150 00000000 [ 72.439144] 7ec0: 024002c2 de7fbf40 0009bc20 c02776ac ff800000 00000000 00000000 bf233670 [ 72.447723] 7ee0: 00000004 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 72.456298] 7f00: 00000000 00000000 00000000 00000000 c01d2590 0000aa41 00000000 00000000 [ 72.464862] 7f20: 000b2549 e12c3a41 00000051 de7e6000 0009bc20 c01d2630 00000530 e12b9000 [ 72.473438] 7f40: 0000aa41 e12c1434 e12c1211 e12c336c 00001150 00001620 00000000 00000000 [ 72.482003] 7f60: 00000000 000010fc 00000035 00000036 0000001d 0000001a 00000017 00000000 [ 72.490564] 7f80: de7e6000 3ba39a00 0009b008 0009b718 00000080 c0107704 de7e6000 00000000 [ 72.499141] 7fa0: 0009f609 c0107560 3ba39a00 0009b008 000a7b08 0000aa41 0009bc20 0000aa41 [ 72.507717] 7fc0: 3ba39a00 0009b008 0009b718 00000080 00000001 00000008 0009ab14 0009f609 [ 72.516290] 7fe0: bea31ab8 bea31aa8 0001e5eb b6e83b42 800f0030 000a7b08 0000ffff 0840ffff [ 72.524883] [] (irq_find_matching_fwspec) from [] (irq_create_fwspec_mapping+0x28/0x2e0) [ 72.535174] [] (irq_create_fwspec_mapping) from [] (irq_create_of_mapping+0x4c/0x54) [ 72.545115] [] (irq_create_of_mapping) from [] (of_irq_get+0x58/0x68) [ 72.553699] [] (of_irq_get) from [] (platform_get_irq+0x1c/0xec) [ 72.561828] [] (platform_get_irq) from [] (tps6521x_pb_probe+0xd0/0x1a8 [tps65218_pwrbutton]) [ 72.572581] [] (tps6521x_pb_probe [tps65218_pwrbutton]) from [] (platform_drv_probe+0x4c/0xac) [ 72.583426] [] (platform_drv_probe) from [] (driver_probe_device+0x204/0x2dc) [ 72.592729] [] (driver_probe_device) from [] (bus_for_each_drv+0x58/0x8c) [ 72.601657] [] (bus_for_each_drv) from [] (__device_attach+0xb0/0x114) [ 72.610324] [] (__device_attach) from [] (bus_probe_device+0x88/0x90) [ 72.618898] [] (bus_probe_device) from [] (device_add+0x3b8/0x560) [ 72.627203] [] (device_add) from [] (platform_device_add+0xa8/0x208) [ 72.635693] [] (platform_device_add) from [] (mfd_add_device+0x240/0x338) [ 72.644634] [] (mfd_add_device) from [] (mfd_add_devices+0xa0/0x104) [ 72.653120] [] (mfd_add_devices) from [] (devm_mfd_add_devices+0x60/0xa8) [ 72.662077] [] (devm_mfd_add_devices) from [] (tps65217_probe+0xe8/0x2ec [tps65217]) [ 72.672026] [] (tps65217_probe [tps65217]) from [] (i2c_device_probe+0x168/0x1f4) [ 72.681695] [] (i2c_device_probe) from [] (driver_probe_device+0x204/0x2dc) [ 72.690816] [] (driver_probe_device) from [] (__driver_attach+0xb4/0xb8) [ 72.699657] [] (__driver_attach) from [] (bus_for_each_dev+0x60/0x94) [ 72.708224] [] (bus_for_each_dev) from [] (bus_add_driver+0x18c/0x214) [ 72.716892] [] (bus_add_driver) from [] (driver_register+0x78/0xf8) [ 72.725280] [] (driver_register) from [] (i2c_register_driver+0x38/0x80) [ 72.734120] [] (i2c_register_driver) from [] (do_one_initcall+0x3c/0x178) [ 72.743055] [] (do_one_initcall) from [] (do_init_module+0x5c/0x1d0) [ 72.751537] [] (do_init_module) from [] (load_module+0x1d10/0x21c0) [ 72.759933] [] (load_module) from [] (SyS_init_module+0x110/0x154) [ 72.768242] [] (SyS_init_module) from [] (ret_fast_syscall+0x0/0x1c) [ 72.776725] Code: e5944000 e1540006 0a00001b e594300c (e593c004) [ 72.783181] ---[ end trace 0278ec325f4689b8 ]--- Fixes: 6556bdacf646 ("mfd: tps65217: Add support for IRQs") Signed-off-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/tps65217.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 9a4d8684dd32..df2e7756927f 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -424,6 +424,24 @@ static int tps65217_probe(struct i2c_client *client, return 0; } +static int tps65217_remove(struct i2c_client *client) +{ + struct tps65217 *tps = i2c_get_clientdata(client); + unsigned int virq; + int i; + + for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) { + virq = irq_find_mapping(tps->irq_domain, i); + if (virq) + irq_dispose_mapping(virq); + } + + irq_domain_remove(tps->irq_domain); + tps->irq_domain = NULL; + + return 0; +} + static const struct i2c_device_id tps65217_id_table[] = { {"tps65217", TPS65217}, { /* sentinel */ } @@ -437,6 +455,7 @@ static struct i2c_driver tps65217_driver = { }, .id_table = tps65217_id_table, .probe = tps65217_probe, + .remove = tps65217_remove, }; static int __init tps65217_init(void) -- cgit v1.2.3 From f66020640367affd8efa788dc3f904acac435244 Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Tue, 15 Nov 2016 22:02:12 +0900 Subject: mfd: tps65217: Specify the IRQ name TPS65217 MFD is an interrupt controller and MFD slave devices like tps65217-charger and tps65217-pwrbutton request an interrupt to handle each HW event. Currently, TPS65217 IRQ name is not defined, so the result is as below. root@arm:~# cat /proc/interrupts ... 182: 0 INTC 7 Level tps65217-irq 183: 0 - 1 Edge tps65217-charger 185: 0 - 2 Edge tps65217_pwrbutton This patch specifies the name of the interrupt controller. 182: 0 INTC 7 Level tps65217-irq 183: 0 tps65217 1 Edge tps65217-charger 185: 0 tps65217 2 Edge tps65217_pwrbutton Signed-off-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/tps65217.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index df2e7756927f..77fb8122abd8 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -105,6 +105,7 @@ static void tps65217_irq_disable(struct irq_data *data) } static struct irq_chip tps65217_irq_chip = { + .name = "tps65217", .irq_bus_lock = tps65217_irq_lock, .irq_bus_sync_unlock = tps65217_irq_sync_unlock, .irq_enable = tps65217_irq_enable, -- cgit v1.2.3 From 6d2c2b9f806a4ec81833af533d57395db856d5a3 Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Tue, 15 Nov 2016 22:02:13 +0900 Subject: mfd: tps65217: Update register interrupt mask bits instead of writing operation TPS65217 interrupt register includes read/writeable mask bits with read-only status bits. (bit 4, 5, 6 are R/W, bit 0, 1, 2 are RO) And reserved bit is not required. Register update operation is preferred for disabling all interrupts during the device initialisation. Signed-off-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/tps65217.c | 7 +++---- include/linux/mfd/tps65217.h | 3 ++- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 77fb8122abd8..9d76de99b2e3 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -189,10 +189,9 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq) tps->irq = irq; /* Mask all interrupt sources */ - tps->irq_mask = (TPS65217_INT_RESERVEDM | TPS65217_INT_PBM - | TPS65217_INT_ACM | TPS65217_INT_USBM); - tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask, - TPS65217_PROTECT_NONE); + tps->irq_mask = TPS65217_INT_MASK; + tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK, + TPS65217_INT_MASK, TPS65217_PROTECT_NONE); tps->irq_domain = irq_domain_add_linear(tps->dev->of_node, TPS65217_NUM_IRQ, &tps65217_irq_domain_ops, tps); diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index 4ccda8969639..dfa9f0d0ae2b 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -73,13 +73,14 @@ #define TPS65217_PPATH_AC_CURRENT_MASK 0x0C #define TPS65217_PPATH_USB_CURRENT_MASK 0x03 -#define TPS65217_INT_RESERVEDM BIT(7) #define TPS65217_INT_PBM BIT(6) #define TPS65217_INT_ACM BIT(5) #define TPS65217_INT_USBM BIT(4) #define TPS65217_INT_PBI BIT(2) #define TPS65217_INT_ACI BIT(1) #define TPS65217_INT_USBI BIT(0) +#define TPS65217_INT_MASK (TPS65217_INT_PBM | TPS65217_INT_ACM | \ + TPS65217_INT_USBM) #define TPS65217_CHGCONFIG0_TREG BIT(7) #define TPS65217_CHGCONFIG0_DPPM BIT(6) -- cgit v1.2.3 From fa9170522b362aefb4fef58b5cbff45dbefec258 Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Tue, 15 Nov 2016 22:02:14 +0900 Subject: mfd: tps65217: Make an interrupt handler simpler Rework the IRQ handler by using HW IRQ number and status bit. Each HW IRQ number is matched with TPS65217 register layout[*]. (USB IRQ number is 0, AC is 1, Push button is 2) When an interrupt is enabled, mask bit should be cleared (unmasked). If an interrupt is disabled, then mask bit should be set (masked). This mask value is updated into the TPS65217 register in irq_sync_unlock(). Mask bit and interrupt status bit can be handled with HW IRQ number. Eventually, additional IRQ data, 'tps65217_irqs[]' and the function, 'irq_to_tps65217_irq()' are not necessary. [*] TPS65217 interrupt register layout Bit7 6 5 4 3 2 1 0 ---------------------------------------------- | x | PBM | ACM | USBM | x | PBI | ACI | USBI PBM: Push button status change interrupt mask ACM: AC interrupt mask USBM: USB power status change interrupt mask PBI: Push button status change interrupt ACI: AC power status change interrupt USBI: USB power status change interrupt x: Not used Signed-off-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/tps65217.c | 44 +++++++++----------------------------------- include/linux/mfd/tps65217.h | 1 + 2 files changed, 10 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 9d76de99b2e3..73760906681c 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -42,26 +42,6 @@ static struct resource pb_resources[] = { DEFINE_RES_IRQ_NAMED(TPS65217_IRQ_PB, "PB"), }; -struct tps65217_irq { - int mask; - int interrupt; -}; - -static const struct tps65217_irq tps65217_irqs[] = { - [TPS65217_IRQ_PB] = { - .mask = TPS65217_INT_PBM, - .interrupt = TPS65217_INT_PBI, - }, - [TPS65217_IRQ_AC] = { - .mask = TPS65217_INT_ACM, - .interrupt = TPS65217_INT_ACI, - }, - [TPS65217_IRQ_USB] = { - .mask = TPS65217_INT_USBM, - .interrupt = TPS65217_INT_USBI, - }, -}; - static void tps65217_irq_lock(struct irq_data *data) { struct tps65217 *tps = irq_data_get_irq_chip_data(data); @@ -74,34 +54,28 @@ static void tps65217_irq_sync_unlock(struct irq_data *data) struct tps65217 *tps = irq_data_get_irq_chip_data(data); int ret; - ret = tps65217_reg_write(tps, TPS65217_REG_INT, tps->irq_mask, - TPS65217_PROTECT_NONE); + ret = tps65217_set_bits(tps, TPS65217_REG_INT, TPS65217_INT_MASK, + tps->irq_mask, TPS65217_PROTECT_NONE); if (ret != 0) dev_err(tps->dev, "Failed to sync IRQ masks\n"); mutex_unlock(&tps->irq_lock); } -static inline const struct tps65217_irq * -irq_to_tps65217_irq(struct tps65217 *tps, struct irq_data *data) -{ - return &tps65217_irqs[data->hwirq]; -} - static void tps65217_irq_enable(struct irq_data *data) { struct tps65217 *tps = irq_data_get_irq_chip_data(data); - const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data); + u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT; - tps->irq_mask &= ~irq_data->mask; + tps->irq_mask &= ~mask; } static void tps65217_irq_disable(struct irq_data *data) { struct tps65217 *tps = irq_data_get_irq_chip_data(data); - const struct tps65217_irq *irq_data = irq_to_tps65217_irq(tps, data); + u8 mask = BIT(data->hwirq) << TPS65217_INT_SHIFT; - tps->irq_mask |= irq_data->mask; + tps->irq_mask |= mask; } static struct irq_chip tps65217_irq_chip = { @@ -150,8 +124,8 @@ static irqreturn_t tps65217_irq_thread(int irq, void *data) return IRQ_NONE; } - for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) { - if (status & tps65217_irqs[i].interrupt) { + for (i = 0; i < TPS65217_NUM_IRQ; i++) { + if (status & BIT(i)) { handle_nested_irq(irq_find_mapping(tps->irq_domain, i)); handled = true; } @@ -430,7 +404,7 @@ static int tps65217_remove(struct i2c_client *client) unsigned int virq; int i; - for (i = 0; i < ARRAY_SIZE(tps65217_irqs); i++) { + for (i = 0; i < TPS65217_NUM_IRQ; i++) { virq = irq_find_mapping(tps->irq_domain, i); if (virq) irq_dispose_mapping(virq); diff --git a/include/linux/mfd/tps65217.h b/include/linux/mfd/tps65217.h index dfa9f0d0ae2b..20d9dd3d74f1 100644 --- a/include/linux/mfd/tps65217.h +++ b/include/linux/mfd/tps65217.h @@ -79,6 +79,7 @@ #define TPS65217_INT_PBI BIT(2) #define TPS65217_INT_ACI BIT(1) #define TPS65217_INT_USBI BIT(0) +#define TPS65217_INT_SHIFT 4 #define TPS65217_INT_MASK (TPS65217_INT_PBM | TPS65217_INT_ACM | \ TPS65217_INT_USBM) -- cgit v1.2.3 From 93559191e71bc0f862638b0a9644d4592452a5db Mon Sep 17 00:00:00 2001 From: Milo Kim Date: Tue, 15 Nov 2016 22:02:15 +0900 Subject: mfd: tps65217: Support an interrupt pin as the system wakeup TPS65217 INT pin is used for the system wakeup from suspend mode. This patch enables push button or charger input event as a wakeup source. Signed-off-by: Milo Kim Signed-off-by: Lee Jones --- drivers/mfd/tps65217.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c index 73760906681c..f769c7d4e335 100644 --- a/drivers/mfd/tps65217.c +++ b/drivers/mfd/tps65217.c @@ -183,6 +183,8 @@ static int tps65217_irq_init(struct tps65217 *tps, int irq) return ret; } + enable_irq_wake(irq); + return 0; } -- cgit v1.2.3 From cf2113ca563191a9ee5943561827e50ad8cda4e0 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 25 Nov 2016 08:28:35 -0200 Subject: [media] uvcvideo: freeing an error pointer A recent cleanup introduced a potential dereference of -EFAULT when we call kfree(map->menu_info). Fixes: 4cc5bed1caeb ("[media] uvcvideo: Use memdup_user() rather than duplicating its implementation") Signed-off-by: Dan Carpenter Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/uvc/uvc_v4l2.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c index a7e12fd20adc..3e7e283a44a8 100644 --- a/drivers/media/usb/uvc/uvc_v4l2.c +++ b/drivers/media/usb/uvc/uvc_v4l2.c @@ -66,14 +66,14 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, if (xmap->menu_count == 0 || xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) { ret = -EINVAL; - goto done; + goto free_map; } size = xmap->menu_count * sizeof(*map->menu_info); map->menu_info = memdup_user(xmap->menu_info, size); if (IS_ERR(map->menu_info)) { ret = PTR_ERR(map->menu_info); - goto done; + goto free_map; } map->menu_count = xmap->menu_count; @@ -83,13 +83,13 @@ static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain, uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type " "%u.\n", xmap->v4l2_type); ret = -ENOTTY; - goto done; + goto free_map; } ret = uvc_ctrl_add_mapping(chain, map); -done: kfree(map->menu_info); +free_map: kfree(map); return ret; -- cgit v1.2.3 From f51e80804f084de269954d875c0892b081b7df3c Mon Sep 17 00:00:00 2001 From: Hans Verkuil Date: Fri, 25 Nov 2016 06:23:34 -0200 Subject: [media] cec: pass parent device in register(), not allocate() The cec_allocate_adapter function doesn't need the parent device, only the cec_register_adapter function needs it. Drop the cec_devnode parent field, since devnode.dev.parent can be used instead. This change makes the framework consistent with other frameworks where the parent device is not used until the device is registered. Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- Documentation/media/kapi/cec-core.rst | 14 ++++++-------- drivers/media/cec/cec-api.c | 2 +- drivers/media/cec/cec-core.c | 18 ++++++++++-------- drivers/media/i2c/adv7511.c | 5 +++-- drivers/media/i2c/adv7604.c | 6 +++--- drivers/media/i2c/adv7842.c | 6 +++--- drivers/media/platform/vivid/vivid-cec.c | 3 +-- drivers/media/platform/vivid/vivid-cec.h | 1 - drivers/media/platform/vivid/vivid-core.c | 9 ++++----- drivers/media/usb/pulse8-cec/pulse8-cec.c | 4 ++-- drivers/staging/media/s5p-cec/s5p_cec.c | 5 ++--- drivers/staging/media/st-cec/stih-cec.c | 5 ++--- include/media/cec.h | 10 ++++------ 13 files changed, 41 insertions(+), 47 deletions(-) (limited to 'drivers') diff --git a/Documentation/media/kapi/cec-core.rst b/Documentation/media/kapi/cec-core.rst index 8a88dd4ce3d4..81c6d8e93774 100644 --- a/Documentation/media/kapi/cec-core.rst +++ b/Documentation/media/kapi/cec-core.rst @@ -37,9 +37,8 @@ The struct cec_adapter represents the CEC adapter hardware. It is created by calling cec_allocate_adapter() and deleted by calling cec_delete_adapter(): .. c:function:: - struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, - void *priv, const char *name, u32 caps, u8 available_las, - struct device *parent); + struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, void *priv, + const char *name, u32 caps, u8 available_las); .. c:function:: void cec_delete_adapter(struct cec_adapter *adap); @@ -66,20 +65,19 @@ available_las: the number of simultaneous logical addresses that this adapter can handle. Must be 1 <= available_las <= CEC_MAX_LOG_ADDRS. -parent: - the parent device. - To register the /dev/cecX device node and the remote control device (if CEC_CAP_RC is set) you call: .. c:function:: - int cec_register_adapter(struct cec_adapter \*adap); + int cec_register_adapter(struct cec_adapter *adap, struct device *parent); + +where parent is the parent device. To unregister the devices call: .. c:function:: - void cec_unregister_adapter(struct cec_adapter \*adap); + void cec_unregister_adapter(struct cec_adapter *adap); Note: if cec_register_adapter() fails, then call cec_delete_adapter() to clean up. But if cec_register_adapter() succeeded, then only call diff --git a/drivers/media/cec/cec-api.c b/drivers/media/cec/cec-api.c index 597fbb62d829..8950b6c9d6a9 100644 --- a/drivers/media/cec/cec-api.c +++ b/drivers/media/cec/cec-api.c @@ -88,7 +88,7 @@ static long cec_adap_g_caps(struct cec_adapter *adap, { struct cec_caps caps = {}; - strlcpy(caps.driver, adap->devnode.parent->driver->name, + strlcpy(caps.driver, adap->devnode.dev.parent->driver->name, sizeof(caps.driver)); strlcpy(caps.name, adap->name, sizeof(caps.name)); caps.available_log_addrs = adap->available_log_addrs; diff --git a/drivers/media/cec/cec-core.c b/drivers/media/cec/cec-core.c index b0137e247dc9..aca3ab83a8a1 100644 --- a/drivers/media/cec/cec-core.c +++ b/drivers/media/cec/cec-core.c @@ -132,7 +132,6 @@ static int __must_check cec_devnode_register(struct cec_devnode *devnode, devnode->dev.bus = &cec_bus_type; devnode->dev.devt = MKDEV(MAJOR(cec_dev_t), minor); devnode->dev.release = cec_devnode_release; - devnode->dev.parent = devnode->parent; dev_set_name(&devnode->dev, "cec%d", devnode->minor); device_initialize(&devnode->dev); @@ -198,13 +197,11 @@ static void cec_devnode_unregister(struct cec_devnode *devnode) struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, void *priv, const char *name, u32 caps, - u8 available_las, struct device *parent) + u8 available_las) { struct cec_adapter *adap; int res; - if (WARN_ON(!parent)) - return ERR_PTR(-EINVAL); if (WARN_ON(!caps)) return ERR_PTR(-EINVAL); if (WARN_ON(!ops)) @@ -214,8 +211,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap = kzalloc(sizeof(*adap), GFP_KERNEL); if (!adap) return ERR_PTR(-ENOMEM); - adap->owner = parent->driver->owner; - adap->devnode.parent = parent; strlcpy(adap->name, name, sizeof(adap->name)); adap->phys_addr = CEC_PHYS_ADDR_INVALID; adap->log_addrs.cec_version = CEC_OP_CEC_VERSION_2_0; @@ -264,7 +259,6 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, adap->rc->input_id.vendor = 0; adap->rc->input_id.product = 0; adap->rc->input_id.version = 1; - adap->rc->dev.parent = parent; adap->rc->driver_type = RC_DRIVER_SCANCODE; adap->rc->driver_name = CEC_NAME; adap->rc->allowed_protocols = RC_BIT_CEC; @@ -278,14 +272,22 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, } EXPORT_SYMBOL_GPL(cec_allocate_adapter); -int cec_register_adapter(struct cec_adapter *adap) +int cec_register_adapter(struct cec_adapter *adap, + struct device *parent) { int res; if (IS_ERR_OR_NULL(adap)) return 0; + if (WARN_ON(!parent)) + return -EINVAL; + + adap->owner = parent->driver->owner; + adap->devnode.dev.parent = parent; + #if IS_REACHABLE(CONFIG_RC_CORE) + adap->rc->dev.parent = parent; if (adap->capabilities & CEC_CAP_RC) { res = rc_register_device(adap->rc); diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c index 5ba0f21bcfe4..8c9e28949ab1 100644 --- a/drivers/media/i2c/adv7511.c +++ b/drivers/media/i2c/adv7511.c @@ -1732,9 +1732,10 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd) static int adv7511_registered(struct v4l2_subdev *sd) { struct adv7511_state *state = get_adv7511_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); int err; - err = cec_register_adapter(state->cec_adap); + err = cec_register_adapter(state->cec_adap, &client->dev); if (err) cec_delete_adapter(state->cec_adap); return err; @@ -1928,7 +1929,7 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id * state->cec_adap = cec_allocate_adapter(&adv7511_cec_adap_ops, state, dev_name(&client->dev), CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | CEC_CAP_RC, - ADV7511_MAX_ADDRS, &client->dev); + ADV7511_MAX_ADDRS); err = PTR_ERR_OR_ZERO(state->cec_adap); if (err) { destroy_workqueue(state->work_queue); diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c index 5630eb22daaa..d0375cac6a05 100644 --- a/drivers/media/i2c/adv7604.c +++ b/drivers/media/i2c/adv7604.c @@ -2631,9 +2631,10 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd, static int adv76xx_registered(struct v4l2_subdev *sd) { struct adv76xx_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); int err; - err = cec_register_adapter(state->cec_adap); + err = cec_register_adapter(state->cec_adap, &client->dev); if (err) cec_delete_adapter(state->cec_adap); return err; @@ -3511,8 +3512,7 @@ static int adv76xx_probe(struct i2c_client *client, state->cec_adap = cec_allocate_adapter(&adv76xx_cec_adap_ops, state, dev_name(&client->dev), CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV76XX_MAX_ADDRS, - &client->dev); + CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV76XX_MAX_ADDRS); err = PTR_ERR_OR_ZERO(state->cec_adap); if (err) goto err_entity; diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c index 8c2a52e280af..2d61f0cc2b5b 100644 --- a/drivers/media/i2c/adv7842.c +++ b/drivers/media/i2c/adv7842.c @@ -3250,9 +3250,10 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd, static int adv7842_registered(struct v4l2_subdev *sd) { struct adv7842_state *state = to_state(sd); + struct i2c_client *client = v4l2_get_subdevdata(sd); int err; - err = cec_register_adapter(state->cec_adap); + err = cec_register_adapter(state->cec_adap, &client->dev); if (err) cec_delete_adapter(state->cec_adap); return err; @@ -3568,8 +3569,7 @@ static int adv7842_probe(struct i2c_client *client, state->cec_adap = cec_allocate_adapter(&adv7842_cec_adap_ops, state, dev_name(&client->dev), CEC_CAP_TRANSMIT | CEC_CAP_LOG_ADDRS | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV7842_MAX_ADDRS, - &client->dev); + CEC_CAP_PASSTHROUGH | CEC_CAP_RC, ADV7842_MAX_ADDRS); err = PTR_ERR_OR_ZERO(state->cec_adap); if (err) goto err_entity; diff --git a/drivers/media/platform/vivid/vivid-cec.c b/drivers/media/platform/vivid/vivid-cec.c index f9f878b8e0a7..cb4933592a3c 100644 --- a/drivers/media/platform/vivid/vivid-cec.c +++ b/drivers/media/platform/vivid/vivid-cec.c @@ -216,7 +216,6 @@ static const struct cec_adap_ops vivid_cec_adap_ops = { struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, unsigned int idx, - struct device *parent, bool is_source) { char name[sizeof(dev->vid_out_dev.name) + 2]; @@ -227,5 +226,5 @@ struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, is_source ? dev->vid_out_dev.name : dev->vid_cap_dev.name, idx); return cec_allocate_adapter(&vivid_cec_adap_ops, dev, - name, caps, 1, parent); + name, caps, 1); } diff --git a/drivers/media/platform/vivid/vivid-cec.h b/drivers/media/platform/vivid/vivid-cec.h index 97892afa6b3b..3926b1422777 100644 --- a/drivers/media/platform/vivid/vivid-cec.h +++ b/drivers/media/platform/vivid/vivid-cec.h @@ -20,7 +20,6 @@ #ifdef CONFIG_VIDEO_VIVID_CEC struct cec_adapter *vivid_cec_alloc_adap(struct vivid_dev *dev, unsigned int idx, - struct device *parent, bool is_source); void vivid_cec_bus_free_work(struct vivid_dev *dev); diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c index b8ef836766df..51e37812ec98 100644 --- a/drivers/media/platform/vivid/vivid-core.c +++ b/drivers/media/platform/vivid/vivid-core.c @@ -1167,12 +1167,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (in_type_counter[HDMI]) { struct cec_adapter *adap; - adap = vivid_cec_alloc_adap(dev, 0, &pdev->dev, false); + adap = vivid_cec_alloc_adap(dev, 0, false); ret = PTR_ERR_OR_ZERO(adap); if (ret < 0) goto unreg_dev; dev->cec_rx_adap = adap; - ret = cec_register_adapter(adap); + ret = cec_register_adapter(adap, &pdev->dev); if (ret < 0) { cec_delete_adapter(adap); dev->cec_rx_adap = NULL; @@ -1222,13 +1222,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst) if (dev->output_type[i] != HDMI) continue; dev->cec_output2bus_map[i] = bus_cnt; - adap = vivid_cec_alloc_adap(dev, bus_cnt, - &pdev->dev, true); + adap = vivid_cec_alloc_adap(dev, bus_cnt, true); ret = PTR_ERR_OR_ZERO(adap); if (ret < 0) goto unreg_dev; dev->cec_tx_adap[bus_cnt] = adap; - ret = cec_register_adapter(adap); + ret = cec_register_adapter(adap, &pdev->dev); if (ret < 0) { cec_delete_adapter(adap); dev->cec_tx_adap[bus_cnt] = NULL; diff --git a/drivers/media/usb/pulse8-cec/pulse8-cec.c b/drivers/media/usb/pulse8-cec/pulse8-cec.c index 9092494bb43c..7c18daeb0ade 100644 --- a/drivers/media/usb/pulse8-cec/pulse8-cec.c +++ b/drivers/media/usb/pulse8-cec/pulse8-cec.c @@ -659,7 +659,7 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv) pulse8->serio = serio; pulse8->adap = cec_allocate_adapter(&pulse8_cec_adap_ops, pulse8, - "HDMI CEC", caps, 1, &serio->dev); + "HDMI CEC", caps, 1); err = PTR_ERR_OR_ZERO(pulse8->adap); if (err < 0) goto free_device; @@ -679,7 +679,7 @@ static int pulse8_connect(struct serio *serio, struct serio_driver *drv) if (err) goto close_serio; - err = cec_register_adapter(pulse8->adap); + err = cec_register_adapter(pulse8->adap, &serio->dev); if (err < 0) goto close_serio; diff --git a/drivers/staging/media/s5p-cec/s5p_cec.c b/drivers/staging/media/s5p-cec/s5p_cec.c index 33e435855d66..2a07968b5ac6 100644 --- a/drivers/staging/media/s5p-cec/s5p_cec.c +++ b/drivers/staging/media/s5p-cec/s5p_cec.c @@ -203,12 +203,11 @@ static int s5p_cec_probe(struct platform_device *pdev) cec->adap = cec_allocate_adapter(&s5p_cec_adap_ops, cec, CEC_NAME, CEC_CAP_PHYS_ADDR | CEC_CAP_LOG_ADDRS | CEC_CAP_TRANSMIT | - CEC_CAP_PASSTHROUGH | CEC_CAP_RC, - 1, &pdev->dev); + CEC_CAP_PASSTHROUGH | CEC_CAP_RC, 1); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; - ret = cec_register_adapter(cec->adap); + ret = cec_register_adapter(cec->adap, &pdev->dev); if (ret) { cec_delete_adapter(cec->adap); return ret; diff --git a/drivers/staging/media/st-cec/stih-cec.c b/drivers/staging/media/st-cec/stih-cec.c index eed1fd6bbefa..3c25638a9610 100644 --- a/drivers/staging/media/st-cec/stih-cec.c +++ b/drivers/staging/media/st-cec/stih-cec.c @@ -335,13 +335,12 @@ static int stih_cec_probe(struct platform_device *pdev) cec->adap = cec_allocate_adapter(&sti_cec_adap_ops, cec, CEC_NAME, CEC_CAP_LOG_ADDRS | CEC_CAP_PASSTHROUGH | - CEC_CAP_PHYS_ADDR | CEC_CAP_TRANSMIT, - 1, &pdev->dev); + CEC_CAP_PHYS_ADDR | CEC_CAP_TRANSMIT, 1); ret = PTR_ERR_OR_ZERO(cec->adap); if (ret) return ret; - ret = cec_register_adapter(cec->adap); + ret = cec_register_adapter(cec->adap, &pdev->dev); if (ret) { cec_delete_adapter(cec->adap); return ret; diff --git a/include/media/cec.h b/include/media/cec.h index 717eaf552f3d..96a0aa770d61 100644 --- a/include/media/cec.h +++ b/include/media/cec.h @@ -35,7 +35,6 @@ * struct cec_devnode - cec device node * @dev: cec device * @cdev: cec character device - * @parent: parent device * @minor: device node minor number * @registered: the device was correctly registered * @unregistered: the device was unregistered @@ -51,7 +50,6 @@ struct cec_devnode { /* sysfs */ struct device dev; struct cdev cdev; - struct device *parent; /* device info */ int minor; @@ -198,9 +196,8 @@ static inline bool cec_is_sink(const struct cec_adapter *adap) #if IS_ENABLED(CONFIG_MEDIA_CEC_SUPPORT) struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops, - void *priv, const char *name, u32 caps, u8 available_las, - struct device *parent); -int cec_register_adapter(struct cec_adapter *adap); + void *priv, const char *name, u32 caps, u8 available_las); +int cec_register_adapter(struct cec_adapter *adap, struct device *parent); void cec_unregister_adapter(struct cec_adapter *adap); void cec_delete_adapter(struct cec_adapter *adap); @@ -218,7 +215,8 @@ void cec_received_msg(struct cec_adapter *adap, struct cec_msg *msg); #else -static inline int cec_register_adapter(struct cec_adapter *adap) +static inline int cec_register_adapter(struct cec_adapter *adap, + struct device *parent) { return 0; } -- cgit v1.2.3 From 94868d612fd917487a6c9a4b08b578031db3e717 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Tue, 15 Nov 2016 10:06:24 -0200 Subject: [media] v4l2-tpg: Init hv_enc field with a valid value Zero is not a valid value for hsv_enc. Set the field to a valid initial value. This is not a problem for vivid, because it sets the field to 180 via tpg_s_hsv_enc() on the control initialization, but it might be a source of errors for other drivers that use this code. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/common/v4l2-tpg/v4l2-tpg-core.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c index 28d7b072d867..e47b46e2d26c 100644 --- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c +++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c @@ -117,6 +117,7 @@ void tpg_init(struct tpg_data *tpg, unsigned w, unsigned h) tpg_s_fourcc(tpg, V4L2_PIX_FMT_RGB24); tpg->colorspace = V4L2_COLORSPACE_SRGB; tpg->perc_fill = 100; + tpg->hsv_enc = V4L2_HSV_ENC_180; } EXPORT_SYMBOL_GPL(tpg_init); -- cgit v1.2.3 From a000f0d3995f622410d433a01e94fbfb45969e27 Mon Sep 17 00:00:00 2001 From: Ricardo Ribalda Date: Tue, 15 Nov 2016 10:06:25 -0200 Subject: [media] vivid: Set color_enc on HSV formats HSV formats were missing the color encoding, which leads to an invalid ycbcr_enc value during get_fmt and try_fmt. Signed-off-by: Ricardo Ribalda Delgado Signed-off-by: Hans Verkuil Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/vivid/vivid-vid-common.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c index 3d003fb913ed..5fc010f6ce67 100644 --- a/drivers/media/platform/vivid/vivid-vid-common.c +++ b/drivers/media/platform/vivid/vivid-vid-common.c @@ -447,6 +447,7 @@ struct vivid_fmt vivid_formats[] = { }, { .fourcc = V4L2_PIX_FMT_HSV24, /* HSV 24bits */ + .color_enc = TGP_COLOR_ENC_HSV, .vdownsampling = { 1 }, .bit_depth = { 24 }, .planes = 1, @@ -454,6 +455,7 @@ struct vivid_fmt vivid_formats[] = { }, { .fourcc = V4L2_PIX_FMT_HSV32, /* HSV 32bits */ + .color_enc = TGP_COLOR_ENC_HSV, .vdownsampling = { 1 }, .bit_depth = { 32 }, .planes = 1, -- cgit v1.2.3 From 45d004f4afefdd8d79916ee6d97a9ecd94bb1ffe Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 29 Nov 2016 08:14:47 -0600 Subject: PCI: Update BARs using property bits appropriate for type The BAR property bits (0-3 for memory BARs, 0-1 for I/O BARs) are supposed to be read-only, but we do save them in res->flags and include them when updating the BAR. Mask the I/O property bits with ~PCI_BASE_ADDRESS_IO_MASK (0x3) instead of PCI_REGION_FLAG_MASK (0xf) to make it obvious that we can't corrupt bits 2-3 of I/O addresses. Use PCI_ROM_ADDRESS_MASK for ROM BARs. This means we'll only check the top 21 bits (instead of the 28 bits we used to check) of a ROM BAR to see if the update was successful. Signed-off-by: Bjorn Helgaas --- drivers/pci/setup-res.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index d2a32d88d2ae..53bc0638cac6 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -59,12 +59,17 @@ void pci_update_resource(struct pci_dev *dev, int resno) return; pcibios_resource_to_bus(dev->bus, ®ion, res); + new = region.start; - new = region.start | (res->flags & PCI_REGION_FLAG_MASK); - if (res->flags & IORESOURCE_IO) + if (res->flags & IORESOURCE_IO) { mask = (u32)PCI_BASE_ADDRESS_IO_MASK; - else + new |= res->flags & ~PCI_BASE_ADDRESS_IO_MASK; + } else if (resno == PCI_ROM_RESOURCE) { + mask = (u32)PCI_ROM_ADDRESS_MASK; + } else { mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; + new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; + } reg = pci_resource_bar(dev, resno, &type); if (!reg) -- cgit v1.2.3 From d09f00810850dd6e6eac8895b62bc3fc35435431 Mon Sep 17 00:00:00 2001 From: yuanjian Date: Mon, 28 Nov 2016 17:42:46 +0800 Subject: pwm: Add PWM driver for HiSilicon BVT SOCs Add PWM driver for the PWM controller found on HiSilicon BVT SoCs such as Hi3519V100, Hi3516CV300, etc. The PWM controller is primarily in charge of controlling the P-Iris lens. Reviewed-by: Jiancheng Xue Signed-off-by: Jian Yuan Acked-by: Rob Herring Signed-off-by: Thierry Reding --- .../devicetree/bindings/pwm/pwm-hibvt.txt | 21 ++ drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-hibvt.c | 271 +++++++++++++++++++++ 4 files changed, 302 insertions(+) create mode 100644 Documentation/devicetree/bindings/pwm/pwm-hibvt.txt create mode 100644 drivers/pwm/pwm-hibvt.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pwm/pwm-hibvt.txt b/Documentation/devicetree/bindings/pwm/pwm-hibvt.txt new file mode 100644 index 000000000000..fa7849d67836 --- /dev/null +++ b/Documentation/devicetree/bindings/pwm/pwm-hibvt.txt @@ -0,0 +1,21 @@ +Hisilicon PWM controller + +Required properties: +-compatible: should contain one SoC specific compatible string + The SoC specific strings supported including: + "hisilicon,hi3516cv300-pwm" + "hisilicon,hi3519v100-pwm" +- reg: physical base address and length of the controller's registers. +- clocks: phandle and clock specifier of the PWM reference clock. +- resets: phandle and reset specifier for the PWM controller reset. +- #pwm-cells: Should be 3. See pwm.txt in this directory for a description of + the cells format. + +Example: + pwm: pwm@12130000 { + compatible = "hisilicon,hi3516cv300-pwm"; + reg = <0x12130000 0x10000>; + clocks = <&crg_ctrl HI3516CV300_PWM_CLK>; + resets = <&crg_ctrl 0x38 0>; + #pwm-cells = <3>; + }; diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index bf0128899c09..f92dd41b0395 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -175,6 +175,15 @@ config PWM_FSL_FTM To compile this driver as a module, choose M here: the module will be called pwm-fsl-ftm. +config PWM_HIBVT + tristate "HiSilicon BVT PWM support" + depends on ARCH_HISI || COMPILE_TEST + help + Generic PWM framework driver for HiSilicon BVT SoCs. + + To compile this driver as a module, choose M here: the module + will be called pwm-hibvt. + config PWM_IMG tristate "Imagination Technologies PWM driver" depends on HAS_IOMEM diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 1194c54efcc2..a48bdb517792 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC) += pwm-crc.o obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o +obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o obj-$(CONFIG_PWM_IMG) += pwm-img.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o diff --git a/drivers/pwm/pwm-hibvt.c b/drivers/pwm/pwm-hibvt.c new file mode 100644 index 000000000000..d0e8f8542626 --- /dev/null +++ b/drivers/pwm/pwm-hibvt.c @@ -0,0 +1,271 @@ +/* + * PWM Controller Driver for HiSilicon BVT SoCs + * + * Copyright (c) 2016 HiSilicon Technologies Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 PWM_CFG0_ADDR(x) (((x) * 0x20) + 0x0) +#define PWM_CFG1_ADDR(x) (((x) * 0x20) + 0x4) +#define PWM_CFG2_ADDR(x) (((x) * 0x20) + 0x8) +#define PWM_CTRL_ADDR(x) (((x) * 0x20) + 0xC) + +#define PWM_ENABLE_SHIFT 0 +#define PWM_ENABLE_MASK BIT(0) + +#define PWM_POLARITY_SHIFT 1 +#define PWM_POLARITY_MASK BIT(1) + +#define PWM_KEEP_SHIFT 2 +#define PWM_KEEP_MASK BIT(2) + +#define PWM_PERIOD_MASK GENMASK(31, 0) +#define PWM_DUTY_MASK GENMASK(31, 0) + +struct hibvt_pwm_chip { + struct pwm_chip chip; + struct clk *clk; + void __iomem *base; + struct reset_control *rstc; +}; + +struct hibvt_pwm_soc { + u32 num_pwms; +}; + +static const struct hibvt_pwm_soc pwm_soc[2] = { + { .num_pwms = 4 }, + { .num_pwms = 8 }, +}; + +static inline struct hibvt_pwm_chip *to_hibvt_pwm_chip(struct pwm_chip *chip) +{ + return container_of(chip, struct hibvt_pwm_chip, chip); +} + +static void hibvt_pwm_set_bits(void __iomem *base, u32 offset, + u32 mask, u32 data) +{ + void __iomem *address = base + offset; + u32 value; + + value = readl(address); + value &= ~mask; + value |= (data & mask); + writel(value, address); +} + +static void hibvt_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); + + hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm), + PWM_ENABLE_MASK, 0x1); +} + +static void hibvt_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); + + hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm), + PWM_ENABLE_MASK, 0x0); +} + +static void hibvt_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_cycle_ns, int period_ns) +{ + struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); + u32 freq, period, duty; + + freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000); + + period = div_u64(freq * period_ns, 1000); + duty = div_u64(period * duty_cycle_ns, period_ns); + + hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG0_ADDR(pwm->hwpwm), + PWM_PERIOD_MASK, period); + + hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CFG1_ADDR(pwm->hwpwm), + PWM_DUTY_MASK, duty); +} + +static void hibvt_pwm_set_polarity(struct pwm_chip *chip, + struct pwm_device *pwm, + enum pwm_polarity polarity) +{ + struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); + + if (polarity == PWM_POLARITY_INVERSED) + hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm), + PWM_POLARITY_MASK, (0x1 << PWM_POLARITY_SHIFT)); + else + hibvt_pwm_set_bits(hi_pwm_chip->base, PWM_CTRL_ADDR(pwm->hwpwm), + PWM_POLARITY_MASK, (0x0 << PWM_POLARITY_SHIFT)); +} + +static void hibvt_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + struct hibvt_pwm_chip *hi_pwm_chip = to_hibvt_pwm_chip(chip); + void __iomem *base; + u32 freq, value; + + freq = div_u64(clk_get_rate(hi_pwm_chip->clk), 1000000); + base = hi_pwm_chip->base; + + value = readl(base + PWM_CFG0_ADDR(pwm->hwpwm)); + state->period = div_u64(value * 1000, freq); + + value = readl(base + PWM_CFG1_ADDR(pwm->hwpwm)); + state->duty_cycle = div_u64(value * 1000, freq); + + value = readl(base + PWM_CTRL_ADDR(pwm->hwpwm)); + state->enabled = (PWM_ENABLE_MASK & value); +} + +static int hibvt_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, + struct pwm_state *state) +{ + if (state->polarity != pwm->state.polarity) + hibvt_pwm_set_polarity(chip, pwm, state->polarity); + + if (state->period != pwm->state.period || + state->duty_cycle != pwm->state.duty_cycle) + hibvt_pwm_config(chip, pwm, state->duty_cycle, state->period); + + if (state->enabled != pwm->state.enabled) { + if (state->enabled) + hibvt_pwm_enable(chip, pwm); + else + hibvt_pwm_disable(chip, pwm); + } + + return 0; +} + +static struct pwm_ops hibvt_pwm_ops = { + .get_state = hibvt_pwm_get_state, + .apply = hibvt_pwm_apply, + + .owner = THIS_MODULE, +}; + +static int hibvt_pwm_probe(struct platform_device *pdev) +{ + const struct hibvt_pwm_soc *soc = + of_device_get_match_data(&pdev->dev); + struct hibvt_pwm_chip *pwm_chip; + struct resource *res; + int ret; + int i; + + pwm_chip = devm_kzalloc(&pdev->dev, sizeof(*pwm_chip), GFP_KERNEL); + if (pwm_chip == NULL) + return -ENOMEM; + + pwm_chip->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(pwm_chip->clk)) { + dev_err(&pdev->dev, "getting clock failed with %ld\n", + PTR_ERR(pwm_chip->clk)); + return PTR_ERR(pwm_chip->clk); + } + + pwm_chip->chip.ops = &hibvt_pwm_ops; + pwm_chip->chip.dev = &pdev->dev; + pwm_chip->chip.base = -1; + pwm_chip->chip.npwm = soc->num_pwms; + pwm_chip->chip.of_xlate = of_pwm_xlate_with_flags; + pwm_chip->chip.of_pwm_n_cells = 3; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + pwm_chip->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(pwm_chip->base)) + return PTR_ERR(pwm_chip->base); + + ret = clk_prepare_enable(pwm_chip->clk); + if (ret < 0) + return ret; + + pwm_chip->rstc = devm_reset_control_get(&pdev->dev, NULL); + if (IS_ERR(pwm_chip->rstc)) { + clk_disable_unprepare(pwm_chip->clk); + return PTR_ERR(pwm_chip->rstc); + } + + reset_control_assert(pwm_chip->rstc); + msleep(30); + reset_control_deassert(pwm_chip->rstc); + + ret = pwmchip_add(&pwm_chip->chip); + if (ret < 0) { + clk_disable_unprepare(pwm_chip->clk); + return ret; + } + + for (i = 0; i < pwm_chip->chip.npwm; i++) { + hibvt_pwm_set_bits(pwm_chip->base, PWM_CTRL_ADDR(i), + PWM_KEEP_MASK, (0x1 << PWM_KEEP_SHIFT)); + } + + platform_set_drvdata(pdev, pwm_chip); + + return 0; +} + +static int hibvt_pwm_remove(struct platform_device *pdev) +{ + struct hibvt_pwm_chip *pwm_chip; + + pwm_chip = platform_get_drvdata(pdev); + + reset_control_assert(pwm_chip->rstc); + msleep(30); + reset_control_deassert(pwm_chip->rstc); + + clk_disable_unprepare(pwm_chip->clk); + + return pwmchip_remove(&pwm_chip->chip); +} + +static const struct of_device_id hibvt_pwm_of_match[] = { + { .compatible = "hisilicon,hi3516cv300-pwm", .data = &pwm_soc[0] }, + { .compatible = "hisilicon,hi3519v100-pwm", .data = &pwm_soc[1] }, + { } +}; +MODULE_DEVICE_TABLE(of, hibvt_pwm_of_match); + +static struct platform_driver hibvt_pwm_driver = { + .driver = { + .name = "hibvt-pwm", + .of_match_table = hibvt_pwm_of_match, + }, + .probe = hibvt_pwm_probe, + .remove = hibvt_pwm_remove, +}; +module_platform_driver(hibvt_pwm_driver); + +MODULE_AUTHOR("Jian Yuan"); +MODULE_DESCRIPTION("HiSilicon BVT SoCs PWM driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 4ae8a5c528c0b1ed20f0a06bed15e2fddf3f3838 Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Wed, 21 Sep 2016 13:41:31 +0800 Subject: iommu/io-pgtable-arm: Use for_each_set_bit to simplify the code We can use for_each_set_bit() to simplify the code slightly in the ARM io-pgtable self tests. Reviewed-by: Robin Murphy Signed-off-by: Kefeng Wang Signed-off-by: Will Deacon --- drivers/iommu/io-pgtable-arm-v7s.c | 5 +---- drivers/iommu/io-pgtable-arm.c | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/io-pgtable-arm-v7s.c b/drivers/iommu/io-pgtable-arm-v7s.c index f50e51c1a9c8..0769276c0537 100644 --- a/drivers/iommu/io-pgtable-arm-v7s.c +++ b/drivers/iommu/io-pgtable-arm-v7s.c @@ -793,8 +793,7 @@ static int __init arm_v7s_do_selftests(void) * Distinct mappings of different granule sizes. */ iova = 0; - i = find_first_bit(&cfg.pgsize_bitmap, BITS_PER_LONG); - while (i != BITS_PER_LONG) { + for_each_set_bit(i, &cfg.pgsize_bitmap, BITS_PER_LONG) { size = 1UL << i; if (ops->map(ops, iova, iova, size, IOMMU_READ | IOMMU_WRITE | @@ -811,8 +810,6 @@ static int __init arm_v7s_do_selftests(void) return __FAIL(ops); iova += SZ_16M; - i++; - i = find_next_bit(&cfg.pgsize_bitmap, BITS_PER_LONG, i); loopnr++; } diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index f5c90e1366ce..8c3dfb7497c1 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -980,8 +980,7 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) * Distinct mappings of different granule sizes. */ iova = 0; - j = find_first_bit(&cfg->pgsize_bitmap, BITS_PER_LONG); - while (j != BITS_PER_LONG) { + for_each_set_bit(j, &cfg->pgsize_bitmap, BITS_PER_LONG) { size = 1UL << j; if (ops->map(ops, iova, iova, size, IOMMU_READ | @@ -999,8 +998,6 @@ static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg) return __FAIL(ops, i); iova += SZ_1G; - j++; - j = find_next_bit(&cfg->pgsize_bitmap, BITS_PER_LONG, j); } /* Partial unmap */ -- cgit v1.2.3 From 5896f3a3a1a898b08fd564136da3cb303a2668f6 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 25 Oct 2016 23:36:10 +0530 Subject: iommu/arm-smmu: Constify iommu_gather_ops structures Check for iommu_gather_ops structures that are only stored in the tlb field of an io_pgtable_cfg structure. The tlb field is of type const struct iommu_gather_ops *, so iommu_gather_ops structures having this property can be declared as const. Acked-by: Julia Lawall Signed-off-by: Bhumika Goyal Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 8f7281444551..2f15ffb6cb0c 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -642,7 +642,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, } } -static struct iommu_gather_ops arm_smmu_gather_ops = { +static const struct iommu_gather_ops arm_smmu_gather_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context, .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, .tlb_sync = arm_smmu_tlb_sync, -- cgit v1.2.3 From ca297aad17e1dfbce1d7e9e162fcaf74f7c87eb5 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 25 Oct 2016 23:36:11 +0530 Subject: iommu/arm-smmu: Constify iommu_gather_ops structures Check for iommu_gather_ops structures that are only stored in the tlb field of an io_pgtable_cfg structure. The tlb field is of type const struct iommu_gather_ops *, so iommu_gather_ops structures having this property can be declared as const. Acked-by: Julia Lawall Signed-off-by: Bhumika Goyal Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index e6f9b2d745ca..13ac9d896e3e 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1358,7 +1358,7 @@ static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size, } while (size -= granule); } -static struct iommu_gather_ops arm_smmu_gather_ops = { +static const struct iommu_gather_ops arm_smmu_gather_ops = { .tlb_flush_all = arm_smmu_tlb_inv_context, .tlb_add_flush = arm_smmu_tlb_inv_range_nosync, .tlb_sync = arm_smmu_tlb_sync, -- cgit v1.2.3 From dfed5f01e2461af2e5f05b87868c22fe8dff6762 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 25 Oct 2016 23:36:12 +0530 Subject: iommu/io-pgtable-arm: Use const and __initconst for iommu_gather_ops structures Check for iommu_gather_ops structures that are only stored in the tlb field of an io_pgtable_cfg structure. The tlb field is of type const struct iommu_gather_ops *, so iommu_gather_ops structures having this property can be declared as const. Also, replace __initdata with __initconst. Acked-by: Julia Lawall Signed-off-by: Bhumika Goyal Signed-off-by: Will Deacon --- drivers/iommu/io-pgtable-arm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 8c3dfb7497c1..a40ce3406fef 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -916,7 +916,7 @@ static void dummy_tlb_sync(void *cookie) WARN_ON(cookie != cfg_cookie); } -static struct iommu_gather_ops dummy_tlb_ops __initdata = { +static const struct iommu_gather_ops dummy_tlb_ops __initconst = { .tlb_flush_all = dummy_tlb_flush_all, .tlb_add_flush = dummy_tlb_add_flush, .tlb_sync = dummy_tlb_sync, -- cgit v1.2.3 From 6eb18d4a2b860ad259763c5e6d632839dcf974a1 Mon Sep 17 00:00:00 2001 From: Nipun Gupta Date: Fri, 4 Nov 2016 15:25:23 +0530 Subject: iommu/arm-smmu: Set SMTNMB_TLBEN in ACR to enable caching of bypass entries The SMTNMB_TLBEN in the Auxiliary Configuration Register (ACR) provides an option to enable the updation of TLB in case of bypass transactions due to no stream match in the stream match table. This reduces the latencies of the subsequent transactions with the same stream-id which bypasses the SMMU. This provides a significant performance benefit for certain networking workloads. With this change substantial performance improvement of ~9% is observed with DPDK l3fwd application (http://dpdk.org/doc/guides/sample_app_ug/l3_forward.html) on NXP's LS2088a platform. Reviewed-by: Robin Murphy Signed-off-by: Nipun Gupta Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 2f15ffb6cb0c..79d54a6f7f9a 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -247,6 +247,7 @@ enum arm_smmu_s2cr_privcfg { #define ARM_MMU500_ACTLR_CPRE (1 << 1) #define ARM_MMU500_ACR_CACHE_LOCK (1 << 26) +#define ARM_MMU500_ACR_SMTNMB_TLBEN (1 << 8) #define CB_PAR_F (1 << 0) @@ -1581,16 +1582,22 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu) for (i = 0; i < smmu->num_mapping_groups; ++i) arm_smmu_write_sme(smmu, i); - /* - * Before clearing ARM_MMU500_ACTLR_CPRE, need to - * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK - * bit is only present in MMU-500r2 onwards. - */ - reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7); - major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK; - if ((smmu->model == ARM_MMU500) && (major >= 2)) { + if (smmu->model == ARM_MMU500) { + /* + * Before clearing ARM_MMU500_ACTLR_CPRE, need to + * clear CACHE_LOCK bit of ACR first. And, CACHE_LOCK + * bit is only present in MMU-500r2 onwards. + */ + reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID7); + major = (reg >> ID7_MAJOR_SHIFT) & ID7_MAJOR_MASK; reg = readl_relaxed(gr0_base + ARM_SMMU_GR0_sACR); - reg &= ~ARM_MMU500_ACR_CACHE_LOCK; + if (major >= 2) + reg &= ~ARM_MMU500_ACR_CACHE_LOCK; + /* + * Allow unmatched Stream IDs to allocate bypass + * TLB entries for reduced latency. + */ + reg |= ARM_MMU500_ACR_SMTNMB_TLBEN; writel_relaxed(reg, gr0_base + ARM_SMMU_GR0_sACR); } -- cgit v1.2.3 From 34ceea275f626ae624b55f2b388a07f806988a55 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:34 +0000 Subject: ACPI/IORT: Introduce linker section for IORT entries probing Since commit e647b532275b ("ACPI: Add early device probing infrastructure") the kernel has gained the infrastructure that allows adding linker script section entries to execute ACPI driver callbacks (ie probe routines) for all subsystems that register a table entry in the respective kernel section (eg clocksource, irqchip). Since ARM IOMMU devices data is described through IORT tables when booting with ACPI, the ARM IOMMU drivers must be made able to hook ACPI callback routines that are called to probe IORT entries and initialize the respective IOMMU devices. To avoid adding driver specific hooks into IORT table initialization code (breaking therefore code modularity - ie ACPI IORT code must be made aware of ARM SMMU drivers ACPI init callbacks), this patch adds code that allows ARM SMMU drivers to take advantage of the ACPI early probing infrastructure, so that they can add linker script section entries containing drivers callback to be executed on IORT tables detection. Since IORT nodes are differentiated by a type, the callback routines can easily parse the IORT table entries, check the IORT nodes and carry out some actions whenever the IORT node type associated with the driver specific callback is matched. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Hanjun Guo Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Tomasz Nowicki Cc: "Rafael J. Wysocki" Cc: Marc Zyngier Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 13 ++++++++++--- include/asm-generic/vmlinux.lds.h | 1 + include/linux/acpi_iort.h | 3 +++ 3 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 6b81746cd13c..2c46ebca01af 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -361,8 +361,15 @@ void __init acpi_iort_init(void) acpi_status status; status = acpi_get_table(ACPI_SIG_IORT, 0, &iort_table); - if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) { - const char *msg = acpi_format_exception(status); - pr_err("Failed to get table, %s\n", msg); + if (ACPI_FAILURE(status)) { + if (status != AE_NOT_FOUND) { + const char *msg = acpi_format_exception(status); + + pr_err("Failed to get table, %s\n", msg); + } + + return; } + + acpi_probe_device_table(iort); } diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h index 31e1d639abed..9e3aa34341f4 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -566,6 +566,7 @@ IRQCHIP_OF_MATCH_TABLE() \ ACPI_PROBE_TABLE(irqchip) \ ACPI_PROBE_TABLE(clksrc) \ + ACPI_PROBE_TABLE(iort) \ EARLYCON_TABLE() #define INIT_TEXT \ diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 0e32dac8fd03..d16fddaf230e 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -39,4 +39,7 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev, { return NULL; } #endif +#define IORT_ACPI_DECLARE(name, table_id, fn) \ + ACPI_DECLARE_PROBE_ENTRY(iort, name, table_id, 0, NULL, 0, fn) + #endif /* __ACPI_IORT_H__ */ -- cgit v1.2.3 From 7936df92b9dbf568ab04717c142acaf08449dbfc Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:35 +0000 Subject: ACPI/IORT: Add support for IOMMU fwnode registration The ACPI IORT table provide entries for IOMMU (aka SMMU in ARM world) components that allow creating the kernel data structures required to probe and initialize the IOMMU devices. This patch provides support in the IORT kernel code to register IOMMU components and their respective fwnode. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Hanjun Guo Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Hanjun Guo Cc: Tomasz Nowicki Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 2c46ebca01af..1ac2720da96d 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -20,7 +20,9 @@ #include #include +#include #include +#include struct iort_its_msi_chip { struct list_head list; @@ -28,6 +30,90 @@ struct iort_its_msi_chip { u32 translation_id; }; +struct iort_fwnode { + struct list_head list; + struct acpi_iort_node *iort_node; + struct fwnode_handle *fwnode; +}; +static LIST_HEAD(iort_fwnode_list); +static DEFINE_SPINLOCK(iort_fwnode_lock); + +/** + * iort_set_fwnode() - Create iort_fwnode and use it to register + * iommu data in the iort_fwnode_list + * + * @node: IORT table node associated with the IOMMU + * @fwnode: fwnode associated with the IORT node + * + * Returns: 0 on success + * <0 on failure + */ +static inline int iort_set_fwnode(struct acpi_iort_node *iort_node, + struct fwnode_handle *fwnode) +{ + struct iort_fwnode *np; + + np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC); + + if (WARN_ON(!np)) + return -ENOMEM; + + INIT_LIST_HEAD(&np->list); + np->iort_node = iort_node; + np->fwnode = fwnode; + + spin_lock(&iort_fwnode_lock); + list_add_tail(&np->list, &iort_fwnode_list); + spin_unlock(&iort_fwnode_lock); + + return 0; +} + +/** + * iort_get_fwnode() - Retrieve fwnode associated with an IORT node + * + * @node: IORT table node to be looked-up + * + * Returns: fwnode_handle pointer on success, NULL on failure + */ +static inline +struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node) +{ + struct iort_fwnode *curr; + struct fwnode_handle *fwnode = NULL; + + spin_lock(&iort_fwnode_lock); + list_for_each_entry(curr, &iort_fwnode_list, list) { + if (curr->iort_node == node) { + fwnode = curr->fwnode; + break; + } + } + spin_unlock(&iort_fwnode_lock); + + return fwnode; +} + +/** + * iort_delete_fwnode() - Delete fwnode associated with an IORT node + * + * @node: IORT table node associated with fwnode to delete + */ +static inline void iort_delete_fwnode(struct acpi_iort_node *node) +{ + struct iort_fwnode *curr, *tmp; + + spin_lock(&iort_fwnode_lock); + list_for_each_entry_safe(curr, tmp, &iort_fwnode_list, list) { + if (curr->iort_node == node) { + list_del(&curr->list); + kfree(curr); + break; + } + } + spin_unlock(&iort_fwnode_lock); +} + typedef acpi_status (*iort_find_node_callback) (struct acpi_iort_node *node, void *context); -- cgit v1.2.3 From e4f10ffe4c9b500e545b874b816ffea5e8659b05 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:36 +0000 Subject: iommu: Make of_iommu_set/get_ops() DT agnostic The of_iommu_{set/get}_ops() API is used to associate a device tree node with a specific set of IOMMU operations. The same kernel interface is required on systems booting with ACPI, where devices are not associated with a device tree node, therefore the interface requires generalization. The struct device fwnode member represents the fwnode token associated with the device and the struct it points at is firmware specific; regardless, it is initialized on both ACPI and DT systems and makes an ideal candidate to use it to associate a set of IOMMU operations to a given device, through its struct device.fwnode member pointer, paving the way for representing per-device iommu_ops (ie an iommu instance associated with a device). Convert the DT specific of_iommu_{set/get}_ops() interface to use struct device.fwnode as a look-up token, making the interface usable on ACPI systems and rename the data structures and the registration API so that they are made to represent their usage more clearly. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Reviewed-by: Robin Murphy Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Will Deacon Cc: Hanjun Guo Cc: Robin Murphy Cc: Joerg Roedel Signed-off-by: Will Deacon --- drivers/iommu/iommu.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/iommu/of_iommu.c | 39 --------------------------------------- include/linux/iommu.h | 14 ++++++++++++++ include/linux/of_iommu.h | 12 ++++++++++-- 4 files changed, 64 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9a2f1960873b..8d3e847d4845 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -1615,6 +1615,46 @@ out: return ret; } +struct iommu_instance { + struct list_head list; + struct fwnode_handle *fwnode; + const struct iommu_ops *ops; +}; +static LIST_HEAD(iommu_instance_list); +static DEFINE_SPINLOCK(iommu_instance_lock); + +void iommu_register_instance(struct fwnode_handle *fwnode, + const struct iommu_ops *ops) +{ + struct iommu_instance *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); + + if (WARN_ON(!iommu)) + return; + + of_node_get(to_of_node(fwnode)); + INIT_LIST_HEAD(&iommu->list); + iommu->fwnode = fwnode; + iommu->ops = ops; + spin_lock(&iommu_instance_lock); + list_add_tail(&iommu->list, &iommu_instance_list); + spin_unlock(&iommu_instance_lock); +} + +const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode) +{ + struct iommu_instance *instance; + const struct iommu_ops *ops = NULL; + + spin_lock(&iommu_instance_lock); + list_for_each_entry(instance, &iommu_instance_list, list) + if (instance->fwnode == fwnode) { + ops = instance->ops; + break; + } + spin_unlock(&iommu_instance_lock); + return ops; +} + int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode, const struct iommu_ops *ops) { diff --git a/drivers/iommu/of_iommu.c b/drivers/iommu/of_iommu.c index 5b82862f571f..0f57ddc4ecc2 100644 --- a/drivers/iommu/of_iommu.c +++ b/drivers/iommu/of_iommu.c @@ -96,45 +96,6 @@ int of_get_dma_window(struct device_node *dn, const char *prefix, int index, } EXPORT_SYMBOL_GPL(of_get_dma_window); -struct of_iommu_node { - struct list_head list; - struct device_node *np; - const struct iommu_ops *ops; -}; -static LIST_HEAD(of_iommu_list); -static DEFINE_SPINLOCK(of_iommu_lock); - -void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops) -{ - struct of_iommu_node *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL); - - if (WARN_ON(!iommu)) - return; - - of_node_get(np); - INIT_LIST_HEAD(&iommu->list); - iommu->np = np; - iommu->ops = ops; - spin_lock(&of_iommu_lock); - list_add_tail(&iommu->list, &of_iommu_list); - spin_unlock(&of_iommu_lock); -} - -const struct iommu_ops *of_iommu_get_ops(struct device_node *np) -{ - struct of_iommu_node *node; - const struct iommu_ops *ops = NULL; - - spin_lock(&of_iommu_lock); - list_for_each_entry(node, &of_iommu_list, list) - if (node->np == np) { - ops = node->ops; - break; - } - spin_unlock(&of_iommu_lock); - return ops; -} - static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) { struct of_phandle_args *iommu_spec = data; diff --git a/include/linux/iommu.h b/include/linux/iommu.h index 436dc21318af..f2960e4de344 100644 --- a/include/linux/iommu.h +++ b/include/linux/iommu.h @@ -351,6 +351,9 @@ int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode, const struct iommu_ops *ops); void iommu_fwspec_free(struct device *dev); int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids); +void iommu_register_instance(struct fwnode_handle *fwnode, + const struct iommu_ops *ops); +const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode); #else /* CONFIG_IOMMU_API */ @@ -580,6 +583,17 @@ static inline int iommu_fwspec_add_ids(struct device *dev, u32 *ids, return -ENODEV; } +static inline void iommu_register_instance(struct fwnode_handle *fwnode, + const struct iommu_ops *ops) +{ +} + +static inline +const struct iommu_ops *iommu_get_instance(struct fwnode_handle *fwnode) +{ + return NULL; +} + #endif /* CONFIG_IOMMU_API */ #endif /* __LINUX_IOMMU_H */ diff --git a/include/linux/of_iommu.h b/include/linux/of_iommu.h index e80b9c762a03..6a7fc5051099 100644 --- a/include/linux/of_iommu.h +++ b/include/linux/of_iommu.h @@ -31,8 +31,16 @@ static inline const struct iommu_ops *of_iommu_configure(struct device *dev, #endif /* CONFIG_OF_IOMMU */ -void of_iommu_set_ops(struct device_node *np, const struct iommu_ops *ops); -const struct iommu_ops *of_iommu_get_ops(struct device_node *np); +static inline void of_iommu_set_ops(struct device_node *np, + const struct iommu_ops *ops) +{ + iommu_register_instance(&np->fwnode, ops); +} + +static inline const struct iommu_ops *of_iommu_get_ops(struct device_node *np) +{ + return iommu_get_instance(&np->fwnode); +} extern struct of_device_id __iommu_of_table; -- cgit v1.2.3 From ce9babe5f66df2c486a5faf9cb76c9a38c78d401 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:37 +0000 Subject: iommu/arm-smmu: Convert struct device of_node to fwnode usage Current ARM SMMU driver rely on the struct device.of_node pointer for device look-up and iommu_ops retrieval. In preparation for ACPI probing enablement, convert the driver to use the struct device.fwnode member for device and iommu_ops look-up so that the driver infrastructure can be used also on systems that do not associate an of_node pointer to a struct device (eg ACPI), making the device look-up and iommu_ops retrieval firmware agnostic. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Reviewed-by: Robin Murphy Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Will Deacon Cc: Hanjun Guo Cc: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 79d54a6f7f9a..7eed55484ad6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1380,13 +1380,14 @@ static bool arm_smmu_capable(enum iommu_cap cap) static int arm_smmu_match_node(struct device *dev, void *data) { - return dev->of_node == data; + return dev->fwnode == data; } -static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np) +static +struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode) { struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL, - np, arm_smmu_match_node); + fwnode, arm_smmu_match_node); put_device(dev); return dev ? dev_get_drvdata(dev) : NULL; } @@ -1404,7 +1405,7 @@ static int arm_smmu_add_device(struct device *dev) if (ret) goto out_free; } else if (fwspec && fwspec->ops == &arm_smmu_ops) { - smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode)); + smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode); } else { return -ENODEV; } @@ -2014,7 +2015,7 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) } } - of_iommu_set_ops(dev->of_node, &arm_smmu_ops); + iommu_register_instance(dev->fwnode, &arm_smmu_ops); platform_set_drvdata(pdev, smmu); arm_smmu_device_reset(smmu); -- cgit v1.2.3 From 778de074537582f86637f2240a8e369833372341 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:38 +0000 Subject: iommu/arm-smmu-v3: Convert struct device of_node to fwnode usage Current ARM SMMU v3 driver rely on the struct device.of_node pointer for device look-up and iommu_ops retrieval. In preparation for ACPI probing enablement, convert the driver to use the struct device.fwnode member for device and iommu_ops look-up so that the driver infrastructure can be used also on systems that do not associate an of_node pointer to a struct device (eg ACPI), making the device look-up and iommu_ops retrieval firmware agnostic. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Reviewed-by: Robin Murphy Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Will Deacon Cc: Hanjun Guo Cc: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 13ac9d896e3e..1406e1fd3847 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -1723,13 +1723,14 @@ static struct platform_driver arm_smmu_driver; static int arm_smmu_match_node(struct device *dev, void *data) { - return dev->of_node == data; + return dev->fwnode == data; } -static struct arm_smmu_device *arm_smmu_get_by_node(struct device_node *np) +static +struct arm_smmu_device *arm_smmu_get_by_fwnode(struct fwnode_handle *fwnode) { struct device *dev = driver_find_device(&arm_smmu_driver.driver, NULL, - np, arm_smmu_match_node); + fwnode, arm_smmu_match_node); put_device(dev); return dev ? dev_get_drvdata(dev) : NULL; } @@ -1765,7 +1766,7 @@ static int arm_smmu_add_device(struct device *dev) master = fwspec->iommu_priv; smmu = master->smmu; } else { - smmu = arm_smmu_get_by_node(to_of_node(fwspec->iommu_fwnode)); + smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode); if (!smmu) return -ENODEV; master = kzalloc(sizeof(*master), GFP_KERNEL); @@ -2634,7 +2635,8 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) return ret; /* And we're up. Go go go! */ - of_iommu_set_ops(dev->of_node, &arm_smmu_ops); + iommu_register_instance(dev->fwnode, &arm_smmu_ops); + #ifdef CONFIG_PCI if (pci_bus_type.iommu_ops != &arm_smmu_ops) { pci_request_acs(); -- cgit v1.2.3 From d760a1baf20e067d3a063aa134834ddd3d183e2f Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:39 +0000 Subject: ACPI: Implement acpi_dma_configure On DT based systems, the of_dma_configure() API implements DMA configuration for a given device. On ACPI systems an API equivalent to of_dma_configure() is missing which implies that it is currently not possible to set-up DMA operations for devices through the ACPI generic kernel layer. This patch fills the gap by introducing acpi_dma_configure/deconfigure() calls that for now are just wrappers around arch_setup_dma_ops() and arch_teardown_dma_ops() and also updates ACPI and PCI core code to use the newly introduced acpi_dma_configure/acpi_dma_deconfigure functions. Since acpi_dma_configure() is used to configure DMA operations, the function initializes the dma/coherent_dma masks to sane default values if the current masks are uninitialized (also to keep the default values consistent with DT systems) to make sure the device has a complete default DMA set-up. The DMA range size passed to arch_setup_dma_ops() is sized according to the device coherent_dma_mask (starting at address 0x0), mirroring the DT probing path behaviour when a dma-ranges property is not provided for the device being probed; this changes the current arch_setup_dma_ops() call parameters in the ACPI probing case, but since arch_setup_dma_ops() is a NOP on all architectures but ARM/ARM64 this patch does not change the current kernel behaviour on them. Signed-off-by: Lorenzo Pieralisi Acked-by: Bjorn Helgaas [pci] Acked-by: Rafael J. Wysocki Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Bjorn Helgaas Cc: Robin Murphy Cc: Tomasz Nowicki Cc: Joerg Roedel Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/glue.c | 4 ++-- drivers/acpi/scan.c | 40 ++++++++++++++++++++++++++++++++++++++++ drivers/pci/probe.c | 3 +-- include/acpi/acpi_bus.h | 2 ++ include/linux/acpi.h | 5 +++++ 5 files changed, 50 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 5ea5dc219f56..f8d65647ea79 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -227,8 +227,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) attr = acpi_get_dma_attr(acpi_dev); if (attr != DEV_DMA_NOT_SUPPORTED) - arch_setup_dma_ops(dev, 0, 0, NULL, - attr == DEV_DMA_COHERENT); + acpi_dma_configure(dev, attr); acpi_physnode_link_name(physical_node_name, node_id); retval = sysfs_create_link(&acpi_dev->dev.kobj, &dev->kobj, @@ -251,6 +250,7 @@ int acpi_bind_one(struct device *dev, struct acpi_device *acpi_dev) return 0; err: + acpi_dma_deconfigure(dev); ACPI_COMPANION_SET(dev, NULL); put_device(dev); put_device(&acpi_dev->dev); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3d1856f1f4d0..45b5710a0404 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1370,6 +1370,46 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NON_COHERENT; } +/** + * acpi_dma_configure - Set-up DMA configuration for the device. + * @dev: The pointer to the device + * @attr: device dma attributes + */ +void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) +{ + /* + * Set default coherent_dma_mask to 32 bit. Drivers are expected to + * setup the correct supported mask. + */ + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); + + /* + * Set it to coherent_dma_mask by default if the architecture + * code has not set it. + */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; + + /* + * Assume dma valid range starts at 0 and covers the whole + * coherent_dma_mask. + */ + arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL, + attr == DEV_DMA_COHERENT); +} +EXPORT_SYMBOL_GPL(acpi_dma_configure); + +/** + * acpi_dma_deconfigure - Tear-down DMA configuration for the device. + * @dev: The pointer to the device + */ +void acpi_dma_deconfigure(struct device *dev) +{ + arch_teardown_dma_ops(dev); +} +EXPORT_SYMBOL_GPL(acpi_dma_deconfigure); + static void acpi_init_coherency(struct acpi_device *adev) { unsigned long long cca = 0; diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ab002671fa60..c29e07ad5a7f 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -1738,8 +1738,7 @@ static void pci_dma_configure(struct pci_dev *dev) if (attr == DEV_DMA_NOT_SUPPORTED) dev_warn(&dev->dev, "DMA not supported.\n"); else - arch_setup_dma_ops(&dev->dev, 0, 0, NULL, - attr == DEV_DMA_COHERENT); + acpi_dma_configure(&dev->dev, attr); } pci_put_host_bridge_device(bridge); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c1a524de67c5..4242c31ffaee 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -573,6 +573,8 @@ struct acpi_pci_root { bool acpi_dma_supported(struct acpi_device *adev); enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev); +void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr); +void acpi_dma_deconfigure(struct device *dev); struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 996a29cdaccd..8d15fc59719f 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -765,6 +765,11 @@ static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) return DEV_DMA_NOT_SUPPORTED; } +static inline void acpi_dma_configure(struct device *dev, + enum dev_dma_attr attr) { } + +static inline void acpi_dma_deconfigure(struct device *dev) { } + #define ACPI_PTR(_ptr) (NULL) static inline void acpi_device_set_enumerated(struct acpi_device *adev) -- cgit v1.2.3 From bdca0c077fc5c2a7bb405281263270070c67f917 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:40 +0000 Subject: ACPI/IORT: Add node match function Device drivers (eg ARM SMMU) need to know if a specific component is part of the IORT table, so that kernel data structures are not initialized at initcalls time if the respective component is not part of the IORT table. To this end, this patch adds a trivial function that allows detecting if a given IORT node type is present or not in the ACPI table, providing an ACPI IORT equivalent for of_find_matching_node(). Signed-off-by: Lorenzo Pieralisi Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Acked-by: Hanjun Guo Cc: Hanjun Guo Cc: Tomasz Nowicki Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 15 +++++++++++++++ include/linux/acpi_iort.h | 2 ++ 2 files changed, 17 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 1ac2720da96d..4bb6acbf881f 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -227,6 +227,21 @@ static struct acpi_iort_node *iort_scan_node(enum acpi_iort_node_type type, return NULL; } +static acpi_status +iort_match_type_callback(struct acpi_iort_node *node, void *context) +{ + return AE_OK; +} + +bool iort_node_match(u8 type) +{ + struct acpi_iort_node *node; + + node = iort_scan_node(type, iort_match_type_callback, NULL); + + return node != NULL; +} + static acpi_status iort_match_node_callback(struct acpi_iort_node *node, void *context) { diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index d16fddaf230e..17bb078073de 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -28,10 +28,12 @@ void iort_deregister_domain_token(int trans_id); struct fwnode_handle *iort_find_domain_token(int trans_id); #ifdef CONFIG_ACPI_IORT void acpi_iort_init(void); +bool iort_node_match(u8 type); u32 iort_msi_map_rid(struct device *dev, u32 req_id); struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id); #else static inline void acpi_iort_init(void) { } +static inline bool iort_node_match(u8 type) { return false; } static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id) { return req_id; } static inline struct irq_domain *iort_get_device_domain(struct device *dev, -- cgit v1.2.3 From 846f0e9e74a034750123860804e247c13c5ee2ec Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:41 +0000 Subject: ACPI/IORT: Add support for ARM SMMU platform devices creation In ARM ACPI systems, IOMMU components are specified through static IORT table entries. In order to create platform devices for the corresponding ARM SMMU components, IORT kernel code should be made able to parse IORT table entries and create platform devices dynamically. This patch adds the generic IORT infrastructure required to create platform devices for ARM SMMUs. ARM SMMU versions have different resources requirement therefore this patch also introduces an IORT specific structure (ie iort_iommu_config) that contains hooks (to be defined when the corresponding ARM SMMU driver support is added to the kernel) to be used to define the platform devices names, init the IOMMUs, count their resources and finally initialize them. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Acked-by: Hanjun Guo Cc: Hanjun Guo Cc: Tomasz Nowicki Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 4bb6acbf881f..ddf83b59791d 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -19,9 +19,11 @@ #define pr_fmt(fmt) "ACPI: IORT: " fmt #include +#include #include #include #include +#include #include struct iort_its_msi_chip { @@ -457,6 +459,153 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI); } +struct iort_iommu_config { + const char *name; + int (*iommu_init)(struct acpi_iort_node *node); + bool (*iommu_is_coherent)(struct acpi_iort_node *node); + int (*iommu_count_resources)(struct acpi_iort_node *node); + void (*iommu_init_resources)(struct resource *res, + struct acpi_iort_node *node); +}; + +static __init +const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node) +{ + return NULL; +} + +/** + * iort_add_smmu_platform_device() - Allocate a platform device for SMMU + * @node: Pointer to SMMU ACPI IORT node + * + * Returns: 0 on success, <0 failure + */ +static int __init iort_add_smmu_platform_device(struct acpi_iort_node *node) +{ + struct fwnode_handle *fwnode; + struct platform_device *pdev; + struct resource *r; + enum dev_dma_attr attr; + int ret, count; + const struct iort_iommu_config *ops = iort_get_iommu_cfg(node); + + if (!ops) + return -ENODEV; + + pdev = platform_device_alloc(ops->name, PLATFORM_DEVID_AUTO); + if (!pdev) + return PTR_ERR(pdev); + + count = ops->iommu_count_resources(node); + + r = kcalloc(count, sizeof(*r), GFP_KERNEL); + if (!r) { + ret = -ENOMEM; + goto dev_put; + } + + ops->iommu_init_resources(r, node); + + ret = platform_device_add_resources(pdev, r, count); + /* + * Resources are duplicated in platform_device_add_resources, + * free their allocated memory + */ + kfree(r); + + if (ret) + goto dev_put; + + /* + * Add a copy of IORT node pointer to platform_data to + * be used to retrieve IORT data information. + */ + ret = platform_device_add_data(pdev, &node, sizeof(node)); + if (ret) + goto dev_put; + + /* + * We expect the dma masks to be equivalent for + * all SMMUs set-ups + */ + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + + fwnode = iort_get_fwnode(node); + + if (!fwnode) { + ret = -ENODEV; + goto dev_put; + } + + pdev->dev.fwnode = fwnode; + + attr = ops->iommu_is_coherent(node) ? + DEV_DMA_COHERENT : DEV_DMA_NON_COHERENT; + + /* Configure DMA for the page table walker */ + acpi_dma_configure(&pdev->dev, attr); + + ret = platform_device_add(pdev); + if (ret) + goto dma_deconfigure; + + return 0; + +dma_deconfigure: + acpi_dma_deconfigure(&pdev->dev); +dev_put: + platform_device_put(pdev); + + return ret; +} + +static void __init iort_init_platform_devices(void) +{ + struct acpi_iort_node *iort_node, *iort_end; + struct acpi_table_iort *iort; + struct fwnode_handle *fwnode; + int i, ret; + + /* + * iort_table and iort both point to the start of IORT table, but + * have different struct types + */ + iort = (struct acpi_table_iort *)iort_table; + + /* Get the first IORT node */ + iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort, + iort->node_offset); + iort_end = ACPI_ADD_PTR(struct acpi_iort_node, iort, + iort_table->length); + + for (i = 0; i < iort->node_count; i++) { + if (iort_node >= iort_end) { + pr_err("iort node pointer overflows, bad table\n"); + return; + } + + if ((iort_node->type == ACPI_IORT_NODE_SMMU) || + (iort_node->type == ACPI_IORT_NODE_SMMU_V3)) { + + fwnode = acpi_alloc_fwnode_static(); + if (!fwnode) + return; + + iort_set_fwnode(iort_node, fwnode); + + ret = iort_add_smmu_platform_device(iort_node); + if (ret) { + iort_delete_fwnode(iort_node); + acpi_free_fwnode_static(fwnode); + return; + } + } + + iort_node = ACPI_ADD_PTR(struct acpi_iort_node, iort_node, + iort_node->length); + } +} + void __init acpi_iort_init(void) { acpi_status status; @@ -472,5 +621,7 @@ void __init acpi_iort_init(void) return; } + iort_init_platform_devices(); + acpi_probe_device_table(iort); } -- cgit v1.2.3 From 2985b5210f4deb014bb976705d1c023eb973d1ed Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:42 +0000 Subject: iommu/arm-smmu-v3: Split probe functions into DT/generic portions Current ARM SMMUv3 probe functions intermingle HW and DT probing in the initialization functions to detect and programme the ARM SMMU v3 driver features. In order to allow probing the ARM SMMUv3 with other firmwares than DT, this patch splits the ARM SMMUv3 init functions into DT and HW specific portions so that other FW interfaces (ie ACPI) can reuse the HW probing functions and skip the DT portion accordingly. This patch implements no functional change, only code reshuffling. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Will Deacon Cc: Hanjun Guo Cc: Robin Murphy Cc: Joerg Roedel Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu-v3.c | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index 1406e1fd3847..d777d7e367bf 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -2381,10 +2381,10 @@ static int arm_smmu_device_reset(struct arm_smmu_device *smmu, bool bypass) return 0; } -static int arm_smmu_device_probe(struct arm_smmu_device *smmu) +static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) { u32 reg; - bool coherent; + bool coherent = smmu->features & ARM_SMMU_FEAT_COHERENCY; /* IDR0 */ reg = readl_relaxed(smmu->base + ARM_SMMU_IDR0); @@ -2436,13 +2436,9 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu) smmu->features |= ARM_SMMU_FEAT_HYP; /* - * The dma-coherent property is used in preference to the ID + * The coherency feature as set by FW is used in preference to the ID * register, but warn on mismatch. */ - coherent = of_dma_is_coherent(smmu->dev->of_node); - if (coherent) - smmu->features |= ARM_SMMU_FEAT_COHERENCY; - if (!!(reg & IDR0_COHACC) != coherent) dev_warn(smmu->dev, "IDR0.COHACC overridden by dma-coherent property (%s)\n", coherent ? "true" : "false"); @@ -2563,21 +2559,35 @@ static int arm_smmu_device_probe(struct arm_smmu_device *smmu) return 0; } -static int arm_smmu_device_dt_probe(struct platform_device *pdev) +static int arm_smmu_device_dt_probe(struct platform_device *pdev, + struct arm_smmu_device *smmu) { - int irq, ret; - struct resource *res; - struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; - bool bypass = true; u32 cells; + int ret = -EINVAL; if (of_property_read_u32(dev->of_node, "#iommu-cells", &cells)) dev_err(dev, "missing #iommu-cells property\n"); else if (cells != 1) dev_err(dev, "invalid #iommu-cells value (%d)\n", cells); else - bypass = false; + ret = 0; + + parse_driver_options(smmu); + + if (of_dma_is_coherent(dev->of_node)) + smmu->features |= ARM_SMMU_FEAT_COHERENCY; + + return ret; +} + +static int arm_smmu_device_probe(struct platform_device *pdev) +{ + int irq, ret; + struct resource *res; + struct arm_smmu_device *smmu; + struct device *dev = &pdev->dev; + bool bypass; smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); if (!smmu) { @@ -2614,10 +2624,11 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) if (irq > 0) smmu->gerr_irq = irq; - parse_driver_options(smmu); + /* Set bypass mode according to firmware probing result */ + bypass = !!arm_smmu_device_dt_probe(pdev, smmu); /* Probe the h/w */ - ret = arm_smmu_device_probe(smmu); + ret = arm_smmu_device_hw_probe(smmu); if (ret) return ret; @@ -2679,7 +2690,7 @@ static struct platform_driver arm_smmu_driver = { .name = "arm-smmu-v3", .of_match_table = of_match_ptr(arm_smmu_of_match), }, - .probe = arm_smmu_device_dt_probe, + .probe = arm_smmu_device_probe, .remove = arm_smmu_device_remove, }; -- cgit v1.2.3 From e4dadfa8122d72a464ac3ca368b98bc11f101de9 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:43 +0000 Subject: iommu/arm-smmu-v3: Add IORT configuration In ACPI bases systems, in order to be able to create platform devices and initialize them for ARM SMMU v3 components, the IORT kernel implementation requires a set of static functions to be used by the IORT kernel layer to configure platform devices for ARM SMMU v3 components. Add static configuration functions to the IORT kernel layer for the ARM SMMU v3 components, so that the ARM SMMU v3 driver can initialize its respective platform device by relying on the IORT kernel infrastructure and by adding a corresponding ACPI device early probe section entry. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Will Deacon Cc: Robin Murphy Cc: Joerg Roedel Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 103 +++++++++++++++++++++++++++++++++++++++++++- drivers/iommu/arm-smmu-v3.c | 49 ++++++++++++++++++++- 2 files changed, 150 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index ddf83b59791d..fd52e4c05a26 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -459,6 +459,95 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI); } +static void __init acpi_iort_register_irq(int hwirq, const char *name, + int trigger, + struct resource *res) +{ + int irq = acpi_register_gsi(NULL, hwirq, trigger, + ACPI_ACTIVE_HIGH); + + if (irq <= 0) { + pr_err("could not register gsi hwirq %d name [%s]\n", hwirq, + name); + return; + } + + res->start = irq; + res->end = irq; + res->flags = IORESOURCE_IRQ; + res->name = name; +} + +static int __init arm_smmu_v3_count_resources(struct acpi_iort_node *node) +{ + struct acpi_iort_smmu_v3 *smmu; + /* Always present mem resource */ + int num_res = 1; + + /* Retrieve SMMUv3 specific data */ + smmu = (struct acpi_iort_smmu_v3 *)node->node_data; + + if (smmu->event_gsiv) + num_res++; + + if (smmu->pri_gsiv) + num_res++; + + if (smmu->gerr_gsiv) + num_res++; + + if (smmu->sync_gsiv) + num_res++; + + return num_res; +} + +static void __init arm_smmu_v3_init_resources(struct resource *res, + struct acpi_iort_node *node) +{ + struct acpi_iort_smmu_v3 *smmu; + int num_res = 0; + + /* Retrieve SMMUv3 specific data */ + smmu = (struct acpi_iort_smmu_v3 *)node->node_data; + + res[num_res].start = smmu->base_address; + res[num_res].end = smmu->base_address + SZ_128K - 1; + res[num_res].flags = IORESOURCE_MEM; + + num_res++; + + if (smmu->event_gsiv) + acpi_iort_register_irq(smmu->event_gsiv, "eventq", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->pri_gsiv) + acpi_iort_register_irq(smmu->pri_gsiv, "priq", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->gerr_gsiv) + acpi_iort_register_irq(smmu->gerr_gsiv, "gerror", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); + + if (smmu->sync_gsiv) + acpi_iort_register_irq(smmu->sync_gsiv, "cmdq-sync", + ACPI_EDGE_SENSITIVE, + &res[num_res++]); +} + +static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node) +{ + struct acpi_iort_smmu_v3 *smmu; + + /* Retrieve SMMUv3 specific data */ + smmu = (struct acpi_iort_smmu_v3 *)node->node_data; + + return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE; +} + struct iort_iommu_config { const char *name; int (*iommu_init)(struct acpi_iort_node *node); @@ -468,10 +557,22 @@ struct iort_iommu_config { struct acpi_iort_node *node); }; +static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = { + .name = "arm-smmu-v3", + .iommu_is_coherent = arm_smmu_v3_is_coherent, + .iommu_count_resources = arm_smmu_v3_count_resources, + .iommu_init_resources = arm_smmu_v3_init_resources +}; + static __init const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node) { - return NULL; + switch (node->type) { + case ACPI_IORT_NODE_SMMU_V3: + return &iort_arm_smmu_v3_cfg; + default: + return NULL; + } } /** diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c index d777d7e367bf..4d6ec444a9d6 100644 --- a/drivers/iommu/arm-smmu-v3.c +++ b/drivers/iommu/arm-smmu-v3.c @@ -20,6 +20,8 @@ * This driver is powered by bad coffee and bombay mix. */ +#include +#include #include #include #include @@ -2559,6 +2561,32 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) return 0; } +#ifdef CONFIG_ACPI +static int arm_smmu_device_acpi_probe(struct platform_device *pdev, + struct arm_smmu_device *smmu) +{ + struct acpi_iort_smmu_v3 *iort_smmu; + struct device *dev = smmu->dev; + struct acpi_iort_node *node; + + node = *(struct acpi_iort_node **)dev_get_platdata(dev); + + /* Retrieve SMMUv3 specific data */ + iort_smmu = (struct acpi_iort_smmu_v3 *)node->node_data; + + if (iort_smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE) + smmu->features |= ARM_SMMU_FEAT_COHERENCY; + + return 0; +} +#else +static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev, + struct arm_smmu_device *smmu) +{ + return -ENODEV; +} +#endif + static int arm_smmu_device_dt_probe(struct platform_device *pdev, struct arm_smmu_device *smmu) { @@ -2624,8 +2652,16 @@ static int arm_smmu_device_probe(struct platform_device *pdev) if (irq > 0) smmu->gerr_irq = irq; + if (dev->of_node) { + ret = arm_smmu_device_dt_probe(pdev, smmu); + } else { + ret = arm_smmu_device_acpi_probe(pdev, smmu); + if (ret == -ENODEV) + return ret; + } + /* Set bypass mode according to firmware probing result */ - bypass = !!arm_smmu_device_dt_probe(pdev, smmu); + bypass = !!ret; /* Probe the h/w */ ret = arm_smmu_device_hw_probe(smmu); @@ -2728,6 +2764,17 @@ static int __init arm_smmu_of_init(struct device_node *np) } IOMMU_OF_DECLARE(arm_smmuv3, "arm,smmu-v3", arm_smmu_of_init); +#ifdef CONFIG_ACPI +static int __init acpi_smmu_v3_init(struct acpi_table_header *table) +{ + if (iort_node_match(ACPI_IORT_NODE_SMMU_V3)) + return arm_smmu_init(); + + return 0; +} +IORT_ACPI_DECLARE(arm_smmu_v3, ACPI_SIG_IORT, acpi_smmu_v3_init); +#endif + MODULE_DESCRIPTION("IOMMU API for ARM architected SMMUv3 implementations"); MODULE_AUTHOR("Will Deacon "); MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From bbb8a1848f351a4e4962280df586f1e88757a7df Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:44 +0000 Subject: iommu/arm-smmu: Split probe functions into DT/generic portions Current ARM SMMU probe functions intermingle HW and DT probing in the initialization functions to detect and programme the ARM SMMU driver features. In order to allow probing the ARM SMMU with other firmwares than DT, this patch splits the ARM SMMU init functions into DT and HW specific portions so that other FW interfaces (ie ACPI) can reuse the HW probing functions and skip the DT portion accordingly. This patch implements no functional change, only code reshuffling. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Will Deacon Reviewed-by: Robin Murphy Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Will Deacon Cc: Hanjun Guo Cc: Robin Murphy Signed-off-by: Will Deacon --- drivers/iommu/arm-smmu.c | 62 +++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index 7eed55484ad6..e068c6f4d1d6 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -1675,7 +1675,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) unsigned long size; void __iomem *gr0_base = ARM_SMMU_GR0(smmu); u32 id; - bool cttw_dt, cttw_reg; + bool cttw_reg, cttw_fw = smmu->features & ARM_SMMU_FEAT_COHERENT_WALK; int i; dev_notice(smmu->dev, "probing hardware configuration...\n"); @@ -1720,20 +1720,17 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu) /* * In order for DMA API calls to work properly, we must defer to what - * the DT says about coherency, regardless of what the hardware claims. + * the FW says about coherency, regardless of what the hardware claims. * Fortunately, this also opens up a workaround for systems where the * ID register value has ended up configured incorrectly. */ - cttw_dt = of_dma_is_coherent(smmu->dev->of_node); cttw_reg = !!(id & ID0_CTTW); - if (cttw_dt) - smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK; - if (cttw_dt || cttw_reg) + if (cttw_fw || cttw_reg) dev_notice(smmu->dev, "\t%scoherent table walk\n", - cttw_dt ? "" : "non-"); - if (cttw_dt != cttw_reg) + cttw_fw ? "" : "non-"); + if (cttw_fw != cttw_reg) dev_notice(smmu->dev, - "\t(IDR0.CTTW overridden by dma-coherent property)\n"); + "\t(IDR0.CTTW overridden by FW configuration)\n"); /* Max. number of entries we have for stream matching/indexing */ size = 1 << ((id >> ID0_NUMSIDB_SHIFT) & ID0_NUMSIDB_MASK); @@ -1914,15 +1911,25 @@ static const struct of_device_id arm_smmu_of_match[] = { }; MODULE_DEVICE_TABLE(of, arm_smmu_of_match); -static int arm_smmu_device_dt_probe(struct platform_device *pdev) +static int arm_smmu_device_dt_probe(struct platform_device *pdev, + struct arm_smmu_device *smmu) { const struct arm_smmu_match_data *data; - struct resource *res; - struct arm_smmu_device *smmu; struct device *dev = &pdev->dev; - int num_irqs, i, err; bool legacy_binding; + if (of_property_read_u32(dev->of_node, "#global-interrupts", + &smmu->num_global_irqs)) { + dev_err(dev, "missing #global-interrupts property\n"); + return -ENODEV; + } + + data = of_device_get_match_data(dev); + smmu->version = data->version; + smmu->model = data->model; + + parse_driver_options(smmu); + legacy_binding = of_find_property(dev->of_node, "mmu-masters", NULL); if (legacy_binding && !using_generic_binding) { if (!using_legacy_binding) @@ -1935,6 +1942,19 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) return -ENODEV; } + if (of_dma_is_coherent(dev->of_node)) + smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK; + + return 0; +} + +static int arm_smmu_device_probe(struct platform_device *pdev) +{ + struct resource *res; + struct arm_smmu_device *smmu; + struct device *dev = &pdev->dev; + int num_irqs, i, err; + smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL); if (!smmu) { dev_err(dev, "failed to allocate arm_smmu_device\n"); @@ -1942,9 +1962,9 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) } smmu->dev = dev; - data = of_device_get_match_data(dev); - smmu->version = data->version; - smmu->model = data->model; + err = arm_smmu_device_dt_probe(pdev, smmu); + if (err) + return err; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); smmu->base = devm_ioremap_resource(dev, res); @@ -1952,12 +1972,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) return PTR_ERR(smmu->base); smmu->size = resource_size(res); - if (of_property_read_u32(dev->of_node, "#global-interrupts", - &smmu->num_global_irqs)) { - dev_err(dev, "missing #global-interrupts property\n"); - return -ENODEV; - } - num_irqs = 0; while ((res = platform_get_resource(pdev, IORESOURCE_IRQ, num_irqs))) { num_irqs++; @@ -1992,8 +2006,6 @@ static int arm_smmu_device_dt_probe(struct platform_device *pdev) if (err) return err; - parse_driver_options(smmu); - if (smmu->version == ARM_SMMU_V2 && smmu->num_context_banks != smmu->num_context_irqs) { dev_err(dev, @@ -2055,7 +2067,7 @@ static struct platform_driver arm_smmu_driver = { .name = "arm-smmu", .of_match_table = of_match_ptr(arm_smmu_of_match), }, - .probe = arm_smmu_device_dt_probe, + .probe = arm_smmu_device_probe, .remove = arm_smmu_device_remove, }; -- cgit v1.2.3 From d6fcd3b149f3eab3b94cc107ca846bea8461cc2f Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:45 +0000 Subject: iommu/arm-smmu: Add IORT configuration In ACPI based systems, in order to be able to create platform devices and initialize them for ARM SMMU components, the IORT kernel implementation requires a set of static functions to be used by the IORT kernel layer to configure platform devices for ARM SMMU components. Add static configuration functions to the IORT kernel layer for the ARM SMMU components, so that the ARM SMMU driver can initialize its respective platform device by relying on the IORT kernel infrastructure and by adding a corresponding ACPI device early probe section entry. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Will Deacon Cc: Robin Murphy Cc: Joerg Roedel Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 71 +++++++++++++++++++++++++++++++++++++++++++ drivers/iommu/arm-smmu.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++- include/linux/acpi_iort.h | 3 ++ 3 files changed, 150 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index fd52e4c05a26..8a8ae5ed05d5 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -548,6 +548,68 @@ static bool __init arm_smmu_v3_is_coherent(struct acpi_iort_node *node) return smmu->flags & ACPI_IORT_SMMU_V3_COHACC_OVERRIDE; } +static int __init arm_smmu_count_resources(struct acpi_iort_node *node) +{ + struct acpi_iort_smmu *smmu; + + /* Retrieve SMMU specific data */ + smmu = (struct acpi_iort_smmu *)node->node_data; + + /* + * Only consider the global fault interrupt and ignore the + * configuration access interrupt. + * + * MMIO address and global fault interrupt resources are always + * present so add them to the context interrupt count as a static + * value. + */ + return smmu->context_interrupt_count + 2; +} + +static void __init arm_smmu_init_resources(struct resource *res, + struct acpi_iort_node *node) +{ + struct acpi_iort_smmu *smmu; + int i, hw_irq, trigger, num_res = 0; + u64 *ctx_irq, *glb_irq; + + /* Retrieve SMMU specific data */ + smmu = (struct acpi_iort_smmu *)node->node_data; + + res[num_res].start = smmu->base_address; + res[num_res].end = smmu->base_address + smmu->span - 1; + res[num_res].flags = IORESOURCE_MEM; + num_res++; + + glb_irq = ACPI_ADD_PTR(u64, node, smmu->global_interrupt_offset); + /* Global IRQs */ + hw_irq = IORT_IRQ_MASK(glb_irq[0]); + trigger = IORT_IRQ_TRIGGER_MASK(glb_irq[0]); + + acpi_iort_register_irq(hw_irq, "arm-smmu-global", trigger, + &res[num_res++]); + + /* Context IRQs */ + ctx_irq = ACPI_ADD_PTR(u64, node, smmu->context_interrupt_offset); + for (i = 0; i < smmu->context_interrupt_count; i++) { + hw_irq = IORT_IRQ_MASK(ctx_irq[i]); + trigger = IORT_IRQ_TRIGGER_MASK(ctx_irq[i]); + + acpi_iort_register_irq(hw_irq, "arm-smmu-context", trigger, + &res[num_res++]); + } +} + +static bool __init arm_smmu_is_coherent(struct acpi_iort_node *node) +{ + struct acpi_iort_smmu *smmu; + + /* Retrieve SMMU specific data */ + smmu = (struct acpi_iort_smmu *)node->node_data; + + return smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK; +} + struct iort_iommu_config { const char *name; int (*iommu_init)(struct acpi_iort_node *node); @@ -564,12 +626,21 @@ static const struct iort_iommu_config iort_arm_smmu_v3_cfg __initconst = { .iommu_init_resources = arm_smmu_v3_init_resources }; +static const struct iort_iommu_config iort_arm_smmu_cfg __initconst = { + .name = "arm-smmu", + .iommu_is_coherent = arm_smmu_is_coherent, + .iommu_count_resources = arm_smmu_count_resources, + .iommu_init_resources = arm_smmu_init_resources +}; + static __init const struct iort_iommu_config *iort_get_iommu_cfg(struct acpi_iort_node *node) { switch (node->type) { case ACPI_IORT_NODE_SMMU_V3: return &iort_arm_smmu_v3_cfg; + case ACPI_IORT_NODE_SMMU: + return &iort_arm_smmu_cfg; default: return NULL; } diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c index e068c6f4d1d6..41b67ce999bf 100644 --- a/drivers/iommu/arm-smmu.c +++ b/drivers/iommu/arm-smmu.c @@ -28,6 +28,8 @@ #define pr_fmt(fmt) "arm-smmu: " fmt +#include +#include #include #include #include @@ -1911,6 +1913,64 @@ static const struct of_device_id arm_smmu_of_match[] = { }; MODULE_DEVICE_TABLE(of, arm_smmu_of_match); +#ifdef CONFIG_ACPI +static int acpi_smmu_get_data(u32 model, struct arm_smmu_device *smmu) +{ + int ret = 0; + + switch (model) { + case ACPI_IORT_SMMU_V1: + case ACPI_IORT_SMMU_CORELINK_MMU400: + smmu->version = ARM_SMMU_V1; + smmu->model = GENERIC_SMMU; + break; + case ACPI_IORT_SMMU_V2: + smmu->version = ARM_SMMU_V2; + smmu->model = GENERIC_SMMU; + break; + case ACPI_IORT_SMMU_CORELINK_MMU500: + smmu->version = ARM_SMMU_V2; + smmu->model = ARM_MMU500; + break; + default: + ret = -ENODEV; + } + + return ret; +} + +static int arm_smmu_device_acpi_probe(struct platform_device *pdev, + struct arm_smmu_device *smmu) +{ + struct device *dev = smmu->dev; + struct acpi_iort_node *node = + *(struct acpi_iort_node **)dev_get_platdata(dev); + struct acpi_iort_smmu *iort_smmu; + int ret; + + /* Retrieve SMMU1/2 specific data */ + iort_smmu = (struct acpi_iort_smmu *)node->node_data; + + ret = acpi_smmu_get_data(iort_smmu->model, smmu); + if (ret < 0) + return ret; + + /* Ignore the configuration access interrupt */ + smmu->num_global_irqs = 1; + + if (iort_smmu->flags & ACPI_IORT_SMMU_COHERENT_WALK) + smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK; + + return 0; +} +#else +static inline int arm_smmu_device_acpi_probe(struct platform_device *pdev, + struct arm_smmu_device *smmu) +{ + return -ENODEV; +} +#endif + static int arm_smmu_device_dt_probe(struct platform_device *pdev, struct arm_smmu_device *smmu) { @@ -1962,7 +2022,11 @@ static int arm_smmu_device_probe(struct platform_device *pdev) } smmu->dev = dev; - err = arm_smmu_device_dt_probe(pdev, smmu); + if (dev->of_node) + err = arm_smmu_device_dt_probe(pdev, smmu); + else + err = arm_smmu_device_acpi_probe(pdev, smmu); + if (err) return err; @@ -2110,6 +2174,17 @@ IOMMU_OF_DECLARE(arm_mmu401, "arm,mmu-401", arm_smmu_of_init); IOMMU_OF_DECLARE(arm_mmu500, "arm,mmu-500", arm_smmu_of_init); IOMMU_OF_DECLARE(cavium_smmuv2, "cavium,smmu-v2", arm_smmu_of_init); +#ifdef CONFIG_ACPI +static int __init arm_smmu_acpi_init(struct acpi_table_header *table) +{ + if (iort_node_match(ACPI_IORT_NODE_SMMU)) + return arm_smmu_init(); + + return 0; +} +IORT_ACPI_DECLARE(arm_smmu, ACPI_SIG_IORT, arm_smmu_acpi_init); +#endif + MODULE_DESCRIPTION("IOMMU API for ARM architected SMMU implementations"); MODULE_AUTHOR("Will Deacon "); MODULE_LICENSE("GPL v2"); diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 17bb078073de..79ba1bb50950 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -23,6 +23,9 @@ #include #include +#define IORT_IRQ_MASK(irq) (irq & 0xffffffffULL) +#define IORT_IRQ_TRIGGER_MASK(irq) ((irq >> 32) & 0xffffffffULL) + int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node); void iort_deregister_domain_token(int trans_id); struct fwnode_handle *iort_find_domain_token(int trans_id); -- cgit v1.2.3 From ea50b5245ba8a5862c98556690a6c680e3ba08ca Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:46 +0000 Subject: ACPI/IORT: Replace rid map type with type mask IORT tables provide data that allow the kernel to carry out device ID mappings between endpoints and system components (eg interrupt controllers, IOMMUs). When the mapping for a given device ID is carried out, the translation mechanism is done on a per-subsystem basis rather than a component subtype (ie the IOMMU kernel layer will look for mappings from a device to all IORT node types corresponding to IOMMU components), therefore the corresponding mapping API should work on a range (ie mask) of IORT node types corresponding to a common set of components (eg IOMMUs) rather than a specific node type. Upgrade the IORT iort_node_map_rid() API to work with a type mask instead of a single node type so that it can be used for mappings that span multiple components types (ie IOMMUs). Signed-off-by: Lorenzo Pieralisi Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Acked-by: Hanjun Guo Cc: Hanjun Guo Cc: Tomasz Nowicki Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 8a8ae5ed05d5..f3bbef8bb15a 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -26,6 +26,9 @@ #include #include +#define IORT_TYPE_MASK(type) (1 << (type)) +#define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP) + struct iort_its_msi_chip { struct list_head list; struct fwnode_handle *fw_node; @@ -317,7 +320,7 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, u32 rid_in, u32 *rid_out, - u8 type) + u8 type_mask) { u32 rid = rid_in; @@ -326,7 +329,7 @@ static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, struct acpi_iort_id_mapping *map; int i; - if (node->type == type) { + if (IORT_TYPE_MASK(node->type) & type_mask) { if (rid_out) *rid_out = rid; return node; @@ -399,7 +402,7 @@ u32 iort_msi_map_rid(struct device *dev, u32 req_id) if (!node) return req_id; - iort_node_map_rid(node, req_id, &dev_id, ACPI_IORT_NODE_ITS_GROUP); + iort_node_map_rid(node, req_id, &dev_id, IORT_MSI_TYPE); return dev_id; } @@ -421,7 +424,7 @@ static int iort_dev_find_its_id(struct device *dev, u32 req_id, if (!node) return -ENXIO; - node = iort_node_map_rid(node, req_id, NULL, ACPI_IORT_NODE_ITS_GROUP); + node = iort_node_map_rid(node, req_id, NULL, IORT_MSI_TYPE); if (!node) return -ENXIO; -- cgit v1.2.3 From 618f535a60623c9e7c596b208a57bf094766b9f6 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:47 +0000 Subject: ACPI/IORT: Add single mapping function The current IORT id mapping API requires components to provide an input requester ID (a Bus-Device-Function (BDF) identifier for PCI devices) to translate an input identifier to an output identifier through an IORT range mapping. Named components do not have an identifiable source ID therefore their respective input/output mapping can only be defined in IORT tables through single mappings, that provide a translation that does not require any input identifier. Current IORT interface for requester id mappings (iort_node_map_rid()) is not suitable for components that do not provide a requester id, so it cannot be used for IORT named components. Add an interface to the IORT API to enable retrieval of id by allowing an indexed walk of the single mappings array for a given component, therefore completing the IORT mapping API. Signed-off-by: Lorenzo Pieralisi Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Hanjun Guo Cc: Tomasz Nowicki Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index f3bbef8bb15a..6aae49c35a95 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -318,6 +318,45 @@ static int iort_id_map(struct acpi_iort_id_mapping *map, u8 type, u32 rid_in, return 0; } +static +struct acpi_iort_node *iort_node_get_id(struct acpi_iort_node *node, + u32 *id_out, u8 type_mask, + int index) +{ + struct acpi_iort_node *parent; + struct acpi_iort_id_mapping *map; + + if (!node->mapping_offset || !node->mapping_count || + index >= node->mapping_count) + return NULL; + + map = ACPI_ADD_PTR(struct acpi_iort_id_mapping, node, + node->mapping_offset); + + /* Firmware bug! */ + if (!map->output_reference) { + pr_err(FW_BUG "[node %p type %d] ID map has NULL parent reference\n", + node, node->type); + return NULL; + } + + parent = ACPI_ADD_PTR(struct acpi_iort_node, iort_table, + map->output_reference); + + if (!(IORT_TYPE_MASK(parent->type) & type_mask)) + return NULL; + + if (map[index].flags & ACPI_IORT_ID_SINGLE_MAPPING) { + if (node->type == ACPI_IORT_NODE_NAMED_COMPONENT || + node->type == ACPI_IORT_NODE_PCI_ROOT_COMPLEX) { + *id_out = map[index].output_base; + return parent; + } + } + + return NULL; +} + static struct acpi_iort_node *iort_node_map_rid(struct acpi_iort_node *node, u32 rid_in, u32 *rid_out, u8 type_mask) -- cgit v1.2.3 From 643b8e4d86f8b1a62cf5cd9ea221e9bc0d531d18 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Mon, 21 Nov 2016 10:01:48 +0000 Subject: ACPI/IORT: Introduce iort_iommu_configure DT based systems have a generic kernel API to configure IOMMUs for devices (ie of_iommu_configure()). On ARM based ACPI systems, the of_iommu_configure() equivalent can be implemented atop ACPI IORT kernel API, with the corresponding functions to map device identifiers to IOMMUs and retrieve the corresponding IOMMU operations necessary for DMA operations set-up. By relying on the iommu_fwspec generic kernel infrastructure, implement the IORT based IOMMU configuration for ARM ACPI systems and hook it up in the ACPI kernel layer that implements DMA configuration for a device. Signed-off-by: Lorenzo Pieralisi Acked-by: Rafael J. Wysocki [ACPI core] Reviewed-by: Tomasz Nowicki Tested-by: Hanjun Guo Tested-by: Tomasz Nowicki Cc: Hanjun Guo Cc: Tomasz Nowicki Cc: "Rafael J. Wysocki" Signed-off-by: Will Deacon --- drivers/acpi/arm64/iort.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++ drivers/acpi/scan.c | 7 +++- include/linux/acpi_iort.h | 6 +++ 3 files changed, 110 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 6aae49c35a95..47bace8eafb6 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -28,6 +28,8 @@ #define IORT_TYPE_MASK(type) (1 << (type)) #define IORT_MSI_TYPE (1 << ACPI_IORT_NODE_ITS_GROUP) +#define IORT_IOMMU_TYPE ((1 << ACPI_IORT_NODE_SMMU) | \ + (1 << ACPI_IORT_NODE_SMMU_V3)) struct iort_its_msi_chip { struct list_head list; @@ -501,6 +503,102 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) return irq_find_matching_fwnode(handle, DOMAIN_BUS_PCI_MSI); } +static int __get_pci_rid(struct pci_dev *pdev, u16 alias, void *data) +{ + u32 *rid = data; + + *rid = alias; + return 0; +} + +static int arm_smmu_iort_xlate(struct device *dev, u32 streamid, + struct fwnode_handle *fwnode, + const struct iommu_ops *ops) +{ + int ret = iommu_fwspec_init(dev, fwnode, ops); + + if (!ret) + ret = iommu_fwspec_add_ids(dev, &streamid, 1); + + return ret; +} + +static const struct iommu_ops *iort_iommu_xlate(struct device *dev, + struct acpi_iort_node *node, + u32 streamid) +{ + const struct iommu_ops *ops = NULL; + int ret = -ENODEV; + struct fwnode_handle *iort_fwnode; + + if (node) { + iort_fwnode = iort_get_fwnode(node); + if (!iort_fwnode) + return NULL; + + ops = iommu_get_instance(iort_fwnode); + if (!ops) + return NULL; + + ret = arm_smmu_iort_xlate(dev, streamid, iort_fwnode, ops); + } + + return ret ? NULL : ops; +} + +/** + * iort_iommu_configure - Set-up IOMMU configuration for a device. + * + * @dev: device to configure + * + * Returns: iommu_ops pointer on configuration success + * NULL on configuration failure + */ +const struct iommu_ops *iort_iommu_configure(struct device *dev) +{ + struct acpi_iort_node *node, *parent; + const struct iommu_ops *ops = NULL; + u32 streamid = 0; + + if (dev_is_pci(dev)) { + struct pci_bus *bus = to_pci_dev(dev)->bus; + u32 rid; + + pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid, + &rid); + + node = iort_scan_node(ACPI_IORT_NODE_PCI_ROOT_COMPLEX, + iort_match_node_callback, &bus->dev); + if (!node) + return NULL; + + parent = iort_node_map_rid(node, rid, &streamid, + IORT_IOMMU_TYPE); + + ops = iort_iommu_xlate(dev, parent, streamid); + + } else { + int i = 0; + + node = iort_scan_node(ACPI_IORT_NODE_NAMED_COMPONENT, + iort_match_node_callback, dev); + if (!node) + return NULL; + + parent = iort_node_get_id(node, &streamid, + IORT_IOMMU_TYPE, i++); + + while (parent) { + ops = iort_iommu_xlate(dev, parent, streamid); + + parent = iort_node_get_id(node, &streamid, + IORT_IOMMU_TYPE, i++); + } + } + + return ops; +} + static void __init acpi_iort_register_irq(int hwirq, const char *name, int trigger, struct resource *res) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 45b5710a0404..80698d3c5feb 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -1377,6 +1378,8 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) */ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { + const struct iommu_ops *iommu; + /* * Set default coherent_dma_mask to 32 bit. Drivers are expected to * setup the correct supported mask. @@ -1391,11 +1394,13 @@ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) if (!dev->dma_mask) dev->dma_mask = &dev->coherent_dma_mask; + iommu = iort_iommu_configure(dev); + /* * Assume dma valid range starts at 0 and covers the whole * coherent_dma_mask. */ - arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, NULL, + arch_setup_dma_ops(dev, 0, dev->coherent_dma_mask + 1, iommu, attr == DEV_DMA_COHERENT); } EXPORT_SYMBOL_GPL(acpi_dma_configure); diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index 79ba1bb50950..dcb2b601e152 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -34,6 +34,8 @@ void acpi_iort_init(void); bool iort_node_match(u8 type); u32 iort_msi_map_rid(struct device *dev, u32 req_id); struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id); +/* IOMMU interface */ +const struct iommu_ops *iort_iommu_configure(struct device *dev); #else static inline void acpi_iort_init(void) { } static inline bool iort_node_match(u8 type) { return false; } @@ -42,6 +44,10 @@ static inline u32 iort_msi_map_rid(struct device *dev, u32 req_id) static inline struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) { return NULL; } +/* IOMMU interface */ +static inline +const struct iommu_ops *iort_iommu_configure(struct device *dev) +{ return NULL; } #endif #define IORT_ACPI_DECLARE(name, table_id, fn) \ -- cgit v1.2.3 From 37bad55b784cad590e13d9d4b3ad2f9202e254e4 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Nov 2016 23:23:19 +0800 Subject: iommu/s390: Drop duplicate header pci.h Drop duplicate header pci.h from s390-iommu.c. Signed-off-by: Geliang Tang Signed-off-by: Joerg Roedel --- drivers/iommu/s390-iommu.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c index 3b44b1d82f3b..179e636a4d91 100644 --- a/drivers/iommu/s390-iommu.c +++ b/drivers/iommu/s390-iommu.c @@ -8,7 +8,6 @@ #include #include #include -#include #include #include -- cgit v1.2.3 From 24c790fbf5d8f54c8c82979db11edea8855b74bf Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 24 Nov 2016 14:05:44 +0300 Subject: iommu/amd: Missing error code in amd_iommu_init_device() We should set "ret" to -EINVAL if iommu_group_get() fails. Fixes: 55c99a4dc50f ("iommu/amd: Use iommu_attach_group()") Signed-off-by: Dan Carpenter Signed-off-by: Joerg Roedel --- drivers/iommu/amd_iommu_v2.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c index 594849a3a9be..f8ed8c95b685 100644 --- a/drivers/iommu/amd_iommu_v2.c +++ b/drivers/iommu/amd_iommu_v2.c @@ -805,8 +805,10 @@ int amd_iommu_init_device(struct pci_dev *pdev, int pasids) goto out_free_domain; group = iommu_group_get(&pdev->dev); - if (!group) + if (!group) { + ret = -EINVAL; goto out_free_domain; + } ret = iommu_attach_group(dev_state->domain, group); if (ret != 0) -- cgit v1.2.3 From bbf9d262a147aeaeee0bf4e1c121166d69e556d4 Mon Sep 17 00:00:00 2001 From: "tnhuynh@apm.com" Date: Tue, 29 Nov 2016 17:12:43 +0700 Subject: i2c: mux: pca954x: Add ACPI support for pca954x This patch enables ACPI support for mux-pca954x driver. Signed-off-by: Tin Huynh Acked-by: Peter Rosin [wsa: removed a trailing whitespace] Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 1091346f2480..b3a538664fe0 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -35,6 +35,7 @@ * warranty of any kind, whether express or implied. */ +#include #include #include #include @@ -120,6 +121,21 @@ static const struct i2c_device_id pca954x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca954x_id); +#ifdef CONFIG_ACPI +static const struct acpi_device_id pca954x_acpi_ids[] = { + { .id = "PCA9540", .driver_data = pca_9540 }, + { .id = "PCA9542", .driver_data = pca_9540 }, + { .id = "PCA9543", .driver_data = pca_9543 }, + { .id = "PCA9544", .driver_data = pca_9544 }, + { .id = "PCA9545", .driver_data = pca_9545 }, + { .id = "PCA9546", .driver_data = pca_9545 }, + { .id = "PCA9547", .driver_data = pca_9547 }, + { .id = "PCA9548", .driver_data = pca_9548 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, pca954x_acpi_ids); +#endif + #ifdef CONFIG_OF static const struct of_device_id pca954x_of_match[] = { { .compatible = "nxp,pca9540", .data = &chips[pca_9540] }, @@ -245,8 +261,17 @@ static int pca954x_probe(struct i2c_client *client, match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); if (match) data->chip = of_device_get_match_data(&client->dev); - else + else if (id) data->chip = &chips[id->driver_data]; + else { + const struct acpi_device_id *acpi_id; + + acpi_id = acpi_match_device(ACPI_PTR(pca954x_acpi_ids), + &client->dev); + if (!acpi_id) + return -ENODEV; + data->chip = &chips[acpi_id->driver_data]; + } data->last_chan = 0; /* force the first selection */ @@ -321,6 +346,7 @@ static struct i2c_driver pca954x_driver = { .name = "pca954x", .pm = &pca954x_pm, .of_match_table = of_match_ptr(pca954x_of_match), + .acpi_match_table = ACPI_PTR(pca954x_acpi_ids), }, .probe = pca954x_probe, .remove = pca954x_remove, -- cgit v1.2.3 From feff5c0a274eef885881946057b2ddbbfd22c55f Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Thu, 24 Nov 2016 19:19:28 +0100 Subject: i2c: i2c-mux-gpio: update mux with gpiod_set_array_value_cansleep If the gpio controller supports it and the gpio lines are concentrated to one gpio chip, the mux controller pins will get updated simultaneously. Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-gpio.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index e5cf26eefa97..655684d621a4 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -21,6 +21,8 @@ struct gpiomux { struct i2c_mux_gpio_platform_data data; unsigned gpio_base; + struct gpio_desc **gpios; + int *values; }; static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) @@ -28,8 +30,10 @@ static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) int i; for (i = 0; i < mux->data.n_gpios; i++) - gpio_set_value_cansleep(mux->gpio_base + mux->data.gpios[i], - val & (1 << i)); + mux->values[i] = (val >> i) & 1; + + gpiod_set_array_value_cansleep(mux->data.n_gpios, + mux->gpios, mux->values); } static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan) @@ -176,12 +180,16 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) if (!parent) return -EPROBE_DEFER; - muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, 0, 0, + muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, + mux->data.n_gpios * sizeof(*mux->gpios) + + mux->data.n_gpios * sizeof(*mux->values), 0, i2c_mux_gpio_select, NULL); if (!muxc) { ret = -ENOMEM; goto alloc_failed; } + mux->gpios = muxc->priv; + mux->values = (int *)(mux->gpios + mux->data.n_gpios); muxc->priv = mux; platform_set_drvdata(pdev, muxc); @@ -219,10 +227,12 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) goto err_request_gpio; } + gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]); + mux->gpios[i] = gpio_desc; + if (!muxc->mux_locked) continue; - gpio_desc = gpio_to_desc(gpio_base + mux->data.gpios[i]); gpio_dev = &gpio_desc->gdev->dev; muxc->mux_locked = i2c_root_adapter(gpio_dev) == root; } -- cgit v1.2.3 From f06122f0bdd0d3c851c452f7c11a3a2198221fdd Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Mon, 21 Nov 2016 11:43:20 +0100 Subject: i2c: designware: Consolidate default functionality bits Use a common place for default functionality bits for both platform and pci driver. Signed-off-by: Alexander Stein Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.h | 8 ++++++++ drivers/i2c/busses/i2c-designware-pcidrv.c | 9 +-------- drivers/i2c/busses/i2c-designware-platdrv.c | 9 +-------- 3 files changed, 10 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 0d44d2ae7d4c..26250b425e2f 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -22,6 +22,14 @@ * */ +#include + +#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ + I2C_FUNC_SMBUS_BYTE | \ + I2C_FUNC_SMBUS_BYTE_DATA | \ + I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_BLOCK_DATA | \ + I2C_FUNC_SMBUS_I2C_BLOCK) #define DW_IC_CON_MASTER 0x1 #define DW_IC_CON_SPEED_STD 0x2 diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 8ffe2da6ca2f..300802e75d2e 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -71,13 +71,6 @@ struct dw_pci_controller { DW_IC_CON_SLAVE_DISABLE | \ DW_IC_CON_RESTART_EN) -#define DW_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ - I2C_FUNC_SMBUS_BYTE | \ - I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA | \ - I2C_FUNC_SMBUS_BLOCK_DATA | \ - I2C_FUNC_SMBUS_I2C_BLOCK) - /* Merrifield HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg mrfld_config = { .ss_hcnt = 0x2f8, @@ -250,7 +243,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, } dev->functionality = controller->functionality | - DW_DEFAULT_FUNCTIONALITY; + DW_IC_DEFAULT_FUNCTIONALITY; dev->master_cfg = controller->bus_cfg; if (controller->scl_sda_cfg) { diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 7429dfa39440..08153ea4d848 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -219,14 +219,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (r) return r; - dev->functionality = - I2C_FUNC_I2C | - I2C_FUNC_10BIT_ADDR | - I2C_FUNC_SMBUS_BYTE | - I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | - I2C_FUNC_SMBUS_BLOCK_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK; + dev->functionality = I2C_FUNC_10BIT_ADDR | DW_IC_DEFAULT_FUNCTIONALITY; dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | DW_IC_CON_RESTART_EN; -- cgit v1.2.3 From 515da746983bc6382e380ba8b1ce9345a9550ffe Mon Sep 17 00:00:00 2001 From: Naveen Kaje Date: Tue, 11 Oct 2016 10:27:56 -0600 Subject: i2c: qup: add ACPI support Add support to get the device parameters from ACPI. Assume that the clocks are managed by firmware. Signed-off-by: Naveen Kaje Signed-off-by: Austin Christ Reviewed-by: Sricharan R Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 58 ++++++++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index a8497cfdae6f..cef553fe270b 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -14,6 +14,7 @@ * */ +#include #include #include #include @@ -132,6 +133,10 @@ /* Max timeout in ms for 32k bytes */ #define TOUT_MAX 300 +/* Default values. Use these if FW query fails */ +#define DEFAULT_CLK_FREQ 100000 +#define DEFAULT_SRC_CLK 20000000 + struct qup_i2c_block { int count; int pos; @@ -1358,14 +1363,13 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) static int qup_i2c_probe(struct platform_device *pdev) { static const int blk_sizes[] = {4, 16, 32}; - struct device_node *node = pdev->dev.of_node; struct qup_i2c_dev *qup; unsigned long one_bit_t; struct resource *res; u32 io_mode, hw_ver, size; int ret, fs_div, hs_div; - int src_clk_freq; - u32 clk_freq = 100000; + u32 src_clk_freq = DEFAULT_SRC_CLK; + u32 clk_freq = DEFAULT_CLK_FREQ; int blocks; qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL); @@ -1376,7 +1380,11 @@ static int qup_i2c_probe(struct platform_device *pdev) init_completion(&qup->xfer); platform_set_drvdata(pdev, qup); - of_property_read_u32(node, "clock-frequency", &clk_freq); + ret = device_property_read_u32(qup->dev, "clock-frequency", &clk_freq); + if (ret) { + dev_notice(qup->dev, "using default clock-frequency %d", + DEFAULT_CLK_FREQ); + } if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { qup->adap.algo = &qup_i2c_algo; @@ -1452,20 +1460,30 @@ nodma: return qup->irq; } - qup->clk = devm_clk_get(qup->dev, "core"); - if (IS_ERR(qup->clk)) { - dev_err(qup->dev, "Could not get core clock\n"); - return PTR_ERR(qup->clk); - } + if (has_acpi_companion(qup->dev)) { + ret = device_property_read_u32(qup->dev, + "src-clock-hz", &src_clk_freq); + if (ret) { + dev_notice(qup->dev, "using default src-clock-hz %d", + DEFAULT_SRC_CLK); + } + ACPI_COMPANION_SET(&qup->adap.dev, ACPI_COMPANION(qup->dev)); + } else { + qup->clk = devm_clk_get(qup->dev, "core"); + if (IS_ERR(qup->clk)) { + dev_err(qup->dev, "Could not get core clock\n"); + return PTR_ERR(qup->clk); + } - qup->pclk = devm_clk_get(qup->dev, "iface"); - if (IS_ERR(qup->pclk)) { - dev_err(qup->dev, "Could not get iface clock\n"); - return PTR_ERR(qup->pclk); + qup->pclk = devm_clk_get(qup->dev, "iface"); + if (IS_ERR(qup->pclk)) { + dev_err(qup->dev, "Could not get iface clock\n"); + return PTR_ERR(qup->pclk); + } + qup_i2c_enable_clocks(qup); + src_clk_freq = clk_get_rate(qup->clk); } - qup_i2c_enable_clocks(qup); - /* * Bootloaders might leave a pending interrupt on certain QUP's, * so we reset the core before registering for interrupts. @@ -1512,7 +1530,6 @@ nodma: size = QUP_INPUT_FIFO_SIZE(io_mode); qup->in_fifo_sz = qup->in_blk_sz * (2 << size); - src_clk_freq = clk_get_rate(qup->clk); fs_div = ((src_clk_freq / clk_freq) / 2) - 3; hs_div = 3; qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff); @@ -1631,6 +1648,14 @@ static const struct of_device_id qup_i2c_dt_match[] = { }; MODULE_DEVICE_TABLE(of, qup_i2c_dt_match); +#if IS_ENABLED(CONFIG_ACPI) +static const struct acpi_device_id qup_i2c_acpi_match[] = { + { "QCOM8010"}, + { }, +}; +MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match); +#endif + static struct platform_driver qup_i2c_driver = { .probe = qup_i2c_probe, .remove = qup_i2c_remove, @@ -1638,6 +1663,7 @@ static struct platform_driver qup_i2c_driver = { .name = "i2c_qup", .pm = &qup_i2c_qup_pm_ops, .of_match_table = qup_i2c_dt_match, + .acpi_match_table = ACPI_PTR(qup_i2c_acpi_match), }, }; -- cgit v1.2.3 From cc9086e772b54a2399408af0bfb00bccb50a968b Mon Sep 17 00:00:00 2001 From: Naveen Kaje Date: Tue, 11 Oct 2016 10:27:57 -0600 Subject: i2c: qup: support SMBus block read I2C QUP driver relies on SMBus emulation support from the framework. To handle SMBus block reads, the driver should check I2C_M_RECV_LEN flag and should read the first byte received as the message length. The driver configures the QUP hardware to read one byte. Once the message length is known from this byte, the QUP hardware is configured to read the rest. Signed-off-by: Naveen Kaje Signed-off-by: Austin Christ Reviewed-by: Sricharan R Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-qup.c | 64 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index cef553fe270b..1902d8ac9753 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -530,6 +530,33 @@ static int qup_i2c_get_data_len(struct qup_i2c_dev *qup) return data_len; } +static bool qup_i2c_check_msg_len(struct i2c_msg *msg) +{ + return ((msg->flags & I2C_M_RD) && (msg->flags & I2C_M_RECV_LEN)); +} + +static int qup_i2c_set_tags_smb(u16 addr, u8 *tags, struct qup_i2c_dev *qup, + struct i2c_msg *msg) +{ + int len = 0; + + if (msg->len > 1) { + tags[len++] = QUP_TAG_V2_DATARD_STOP; + tags[len++] = qup_i2c_get_data_len(qup) - 1; + } else { + tags[len++] = QUP_TAG_V2_START; + tags[len++] = addr & 0xff; + + if (msg->flags & I2C_M_TEN) + tags[len++] = addr >> 8; + + tags[len++] = QUP_TAG_V2_DATARD; + /* Read 1 byte indicating the length of the SMBus message */ + tags[len++] = 1; + } + return len; +} + static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, struct i2c_msg *msg, int is_dma) { @@ -539,6 +566,10 @@ static int qup_i2c_set_tags(u8 *tags, struct qup_i2c_dev *qup, int last = (qup->blk.pos == (qup->blk.count - 1)) && (qup->is_last); + /* Handle tags for SMBus block read */ + if (qup_i2c_check_msg_len(msg)) + return qup_i2c_set_tags_smb(addr, tags, qup, msg); + if (qup->blk.pos == 0) { tags[len++] = QUP_TAG_V2_START; tags[len++] = addr & 0xff; @@ -1061,9 +1092,17 @@ static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg) { u32 val; - int idx, pos = 0, ret = 0, total; + int idx, pos = 0, ret = 0, total, msg_offset = 0; + /* + * If the message length is already read in + * the first byte of the buffer, account for + * that by setting the offset + */ + if (qup_i2c_check_msg_len(msg) && (msg->len > 1)) + msg_offset = 1; total = qup_i2c_get_data_len(qup); + total -= msg_offset; /* 2 extra bytes for read tags */ while (pos < (total + 2)) { @@ -1083,8 +1122,8 @@ static int qup_i2c_read_fifo_v2(struct qup_i2c_dev *qup, if (pos >= (total + 2)) goto out; - - msg->buf[qup->pos++] = val & 0xff; + msg->buf[qup->pos + msg_offset] = val & 0xff; + qup->pos++; } } @@ -1124,6 +1163,20 @@ static int qup_i2c_read_one_v2(struct qup_i2c_dev *qup, struct i2c_msg *msg) goto err; qup->blk.pos++; + + /* Handle SMBus block read length */ + if (qup_i2c_check_msg_len(msg) && (msg->len == 1)) { + if (msg->buf[0] > I2C_SMBUS_BLOCK_MAX) { + ret = -EPROTO; + goto err; + } + msg->len += msg->buf[0]; + qup->pos = 0; + qup_i2c_set_blk_data(qup, msg); + /* set tag length for block read */ + qup->blk.tx_tag_len = 2; + qup_i2c_set_read_mode_v2(qup, msg->buf[0]); + } } while (qup->blk.pos < qup->blk.count); err: @@ -1209,6 +1262,11 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, goto out; } + if (qup_i2c_check_msg_len(&msgs[idx])) { + ret = -EINVAL; + goto out; + } + if (msgs[idx].flags & I2C_M_RD) ret = qup_i2c_read_one(qup, &msgs[idx]); else -- cgit v1.2.3 From 7020bcb82838006e23d058ff07b063b393ed3f10 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 29 Nov 2016 23:19:46 +0100 Subject: ACPI: do not warn if _BQC does not exist Starting from ACPI spec 3.0, it's only clarified that _BCM control method is required if _BCL is implemented. There is no word saying _BQC is required. And in ACPI spec 6.1 B.5.4, for _BQC, it is explicitly stated that "This optional method returns the current brightness level of a built-in display output device. If present, it must be set by the platform for initial brightness." Thus remove the obsolete warning message. Signed-off-by: Zhang Rui Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3d1856f1f4d0..07aa2e649eb1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1119,9 +1119,6 @@ acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context, ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found generic backlight " "support\n")); *cap |= ACPI_VIDEO_BACKLIGHT; - if (!acpi_has_method(handle, "_BQC")) - printk(KERN_WARNING FW_BUG PREFIX "No _BQC method, " - "cannot determine initial brightness\n"); /* We have backlight support, no need to scan further */ return AE_CTRL_TERMINATE; } -- cgit v1.2.3 From 0de8ce3ee8e38cc66683438f715c79a2cc69539e Mon Sep 17 00:00:00 2001 From: Long Li Date: Tue, 8 Nov 2016 14:04:38 -0800 Subject: PCI: hv: Allocate physically contiguous hypercall params buffer hv_do_hypercall() assumes that we pass a segment from a physically contiguous buffer. A buffer allocated on the stack may not work if CONFIG_VMAP_STACK=y is set. Use kmalloc() to allocate this buffer. Reported-by: Haiyang Zhang Signed-off-by: Long Li Signed-off-by: Bjorn Helgaas Acked-by: K. Y. Srinivasan --- drivers/pci/host/pci-hyperv.c | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-hyperv.c b/drivers/pci/host/pci-hyperv.c index a63c3a4f6c7c..3efcc7bdc5fb 100644 --- a/drivers/pci/host/pci-hyperv.c +++ b/drivers/pci/host/pci-hyperv.c @@ -378,6 +378,8 @@ struct hv_pcibus_device { struct msi_domain_info msi_info; struct msi_controller msi_chip; struct irq_domain *irq_domain; + struct retarget_msi_interrupt retarget_msi_interrupt_params; + spinlock_t retarget_msi_interrupt_lock; }; /* @@ -774,34 +776,40 @@ static void hv_irq_unmask(struct irq_data *data) { struct msi_desc *msi_desc = irq_data_get_msi_desc(data); struct irq_cfg *cfg = irqd_cfg(data); - struct retarget_msi_interrupt params; + struct retarget_msi_interrupt *params; struct hv_pcibus_device *hbus; struct cpumask *dest; struct pci_bus *pbus; struct pci_dev *pdev; int cpu; + unsigned long flags; dest = irq_data_get_affinity_mask(data); pdev = msi_desc_to_pci_dev(msi_desc); pbus = pdev->bus; hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata); - memset(¶ms, 0, sizeof(params)); - params.partition_id = HV_PARTITION_ID_SELF; - params.source = 1; /* MSI(-X) */ - params.address = msi_desc->msg.address_lo; - params.data = msi_desc->msg.data; - params.device_id = (hbus->hdev->dev_instance.b[5] << 24) | + spin_lock_irqsave(&hbus->retarget_msi_interrupt_lock, flags); + + params = &hbus->retarget_msi_interrupt_params; + memset(params, 0, sizeof(*params)); + params->partition_id = HV_PARTITION_ID_SELF; + params->source = 1; /* MSI(-X) */ + params->address = msi_desc->msg.address_lo; + params->data = msi_desc->msg.data; + params->device_id = (hbus->hdev->dev_instance.b[5] << 24) | (hbus->hdev->dev_instance.b[4] << 16) | (hbus->hdev->dev_instance.b[7] << 8) | (hbus->hdev->dev_instance.b[6] & 0xf8) | PCI_FUNC(pdev->devfn); - params.vector = cfg->vector; + params->vector = cfg->vector; for_each_cpu_and(cpu, dest, cpu_online_mask) - params.vp_mask |= (1ULL << vmbus_cpu_number_to_vp_number(cpu)); + params->vp_mask |= (1ULL << vmbus_cpu_number_to_vp_number(cpu)); + + hv_do_hypercall(HVCALL_RETARGET_INTERRUPT, params, NULL); - hv_do_hypercall(HVCALL_RETARGET_INTERRUPT, ¶ms, NULL); + spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags); pci_msi_unmask_irq(data); } @@ -2186,6 +2194,7 @@ static int hv_pci_probe(struct hv_device *hdev, INIT_LIST_HEAD(&hbus->resources_for_children); spin_lock_init(&hbus->config_lock); spin_lock_init(&hbus->device_list_lock); + spin_lock_init(&hbus->retarget_msi_interrupt_lock); sema_init(&hbus->enum_sem, 1); init_completion(&hbus->remove_event); -- cgit v1.2.3 From 6ffa2489c51da77564a0881a73765ea2169f955d Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 28 Nov 2016 09:15:52 -0600 Subject: PCI: Separate VF BAR updates from standard BAR updates Previously pci_update_resource() used the same code path for updating standard BARs and VF BARs in SR-IOV capabilities. Split the VF BAR update into a new pci_iov_update_resource() internal interface, which makes it simpler to compute the BAR address (we can get rid of pci_resource_bar() and pci_iov_resource_bar()). This patch: - Renames pci_update_resource() to pci_std_update_resource(), - Adds pci_iov_update_resource(), - Makes pci_update_resource() a wrapper that calls the appropriate one, No functional change intended. Signed-off-by: Bjorn Helgaas Reviewed-by: Gavin Shan --- drivers/pci/iov.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 1 + drivers/pci/setup-res.c | 13 +++++++++++-- 3 files changed, 62 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index d41ec29be60b..aa499543473f 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -571,6 +571,56 @@ int pci_iov_resource_bar(struct pci_dev *dev, int resno) 4 * (resno - PCI_IOV_RESOURCES); } +/** + * pci_iov_update_resource - update a VF BAR + * @dev: the PCI device + * @resno: the resource number + * + * Update a VF BAR in the SR-IOV capability of a PF. + */ +void pci_iov_update_resource(struct pci_dev *dev, int resno) +{ + struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL; + struct resource *res = dev->resource + resno; + int vf_bar = resno - PCI_IOV_RESOURCES; + struct pci_bus_region region; + u32 new; + int reg; + + /* + * The generic pci_restore_bars() path calls this for all devices, + * including VFs and non-SR-IOV devices. If this is not a PF, we + * have nothing to do. + */ + if (!iov) + return; + + /* + * Ignore unimplemented BARs, unused resource slots for 64-bit + * BARs, and non-movable resources, e.g., those described via + * Enhanced Allocation. + */ + if (!res->flags) + return; + + if (res->flags & IORESOURCE_UNSET) + return; + + if (res->flags & IORESOURCE_PCI_FIXED) + return; + + pcibios_resource_to_bus(dev->bus, ®ion, res); + new = region.start; + new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; + + reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar; + pci_write_config_dword(dev, reg, new); + if (res->flags & IORESOURCE_MEM_64) { + new = region.start >> 16 >> 16; + pci_write_config_dword(dev, reg + 4, new); + } +} + resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev, int resno) { diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 451856210e18..5bfcb922f7f7 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -290,6 +290,7 @@ static inline void pci_restore_ats_state(struct pci_dev *dev) int pci_iov_init(struct pci_dev *dev); void pci_iov_release(struct pci_dev *dev); int pci_iov_resource_bar(struct pci_dev *dev, int resno); +void pci_iov_update_resource(struct pci_dev *dev, int resno); resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno); void pci_restore_iov_state(struct pci_dev *dev); int pci_iov_bus_range(struct pci_bus *bus); diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 53bc0638cac6..5ddeb6737f99 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -25,8 +25,7 @@ #include #include "pci.h" - -void pci_update_resource(struct pci_dev *dev, int resno) +static void pci_std_update_resource(struct pci_dev *dev, int resno) { struct pci_bus_region region; bool disable; @@ -114,6 +113,16 @@ void pci_update_resource(struct pci_dev *dev, int resno) pci_write_config_word(dev, PCI_COMMAND, cmd); } +void pci_update_resource(struct pci_dev *dev, int resno) +{ + if (resno <= PCI_ROM_RESOURCE) + pci_std_update_resource(dev, resno); +#ifdef CONFIG_PCI_IOV + else if (resno >= PCI_IOV_RESOURCES && resno <= PCI_IOV_RESOURCE_END) + pci_iov_update_resource(dev, resno); +#endif +} + int pci_claim_resource(struct pci_dev *dev, int resource) { struct resource *res = &dev->resource[resource]; -- cgit v1.2.3 From 546ba9f8f22f71b0202b6ba8967be5cc6dae4e21 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 28 Nov 2016 16:43:06 -0600 Subject: PCI: Don't update VF BARs while VF memory space is enabled If we update a VF BAR while it's enabled, there are two potential problems: 1) Any driver that's using the VF has a cached BAR value that is stale after the update, and 2) We can't update 64-bit BARs atomically, so the intermediate state (new lower dword with old upper dword) may conflict with another device, and an access by a driver unrelated to the VF may cause a bus error. Warn about attempts to update VF BARs while they are enabled. This is a programming error, so use dev_WARN() to get a backtrace. Signed-off-by: Bjorn Helgaas Reviewed-by: Gavin Shan --- drivers/pci/iov.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index aa499543473f..2480b3879182 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -584,6 +584,7 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno) struct resource *res = dev->resource + resno; int vf_bar = resno - PCI_IOV_RESOURCES; struct pci_bus_region region; + u16 cmd; u32 new; int reg; @@ -595,6 +596,13 @@ void pci_iov_update_resource(struct pci_dev *dev, int resno) if (!iov) return; + pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd); + if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) { + dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n", + vf_bar, res); + return; + } + /* * Ignore unimplemented BARs, unused resource slots for 64-bit * BARs, and non-movable resources, e.g., those described via -- cgit v1.2.3 From 286c2378aaccc7343ebf17ec6cd86567659caf70 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 28 Nov 2016 16:51:19 -0600 Subject: PCI: Remove pci_resource_bar() and pci_iov_resource_bar() pci_std_update_resource() only deals with standard BARs, so we don't have to worry about the complications of VF BARs in an SR-IOV capability. Compute the BAR address inline and remove pci_resource_bar(). That makes pci_iov_resource_bar() unused, so remove that as well. Signed-off-by: Bjorn Helgaas Reviewed-by: Gavin Shan --- drivers/pci/iov.c | 18 ------------------ drivers/pci/pci.c | 30 ------------------------------ drivers/pci/pci.h | 6 ------ drivers/pci/setup-res.c | 13 +++++++------ 4 files changed, 7 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 2480b3879182..47227820406d 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -553,24 +553,6 @@ void pci_iov_release(struct pci_dev *dev) sriov_release(dev); } -/** - * pci_iov_resource_bar - get position of the SR-IOV BAR - * @dev: the PCI device - * @resno: the resource number - * - * Returns position of the BAR encapsulated in the SR-IOV capability. - */ -int pci_iov_resource_bar(struct pci_dev *dev, int resno) -{ - if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END) - return 0; - - BUG_ON(!dev->is_physfn); - - return dev->sriov->pos + PCI_SRIOV_BAR + - 4 * (resno - PCI_IOV_RESOURCES); -} - /** * pci_iov_update_resource - update a VF BAR * @dev: the PCI device diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 631eac2bed78..ec3f16d13307 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -4827,36 +4827,6 @@ int pci_select_bars(struct pci_dev *dev, unsigned long flags) } EXPORT_SYMBOL(pci_select_bars); -/** - * pci_resource_bar - get position of the BAR associated with a resource - * @dev: the PCI device - * @resno: the resource number - * @type: the BAR type to be filled in - * - * Returns BAR position in config space, or 0 if the BAR is invalid. - */ -int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type) -{ - int reg; - - if (resno < PCI_ROM_RESOURCE) { - *type = pci_bar_unknown; - return PCI_BASE_ADDRESS_0 + 4 * resno; - } else if (resno == PCI_ROM_RESOURCE) { - *type = pci_bar_mem32; - return dev->rom_base_reg; - } else if (resno < PCI_BRIDGE_RESOURCES) { - /* device specific resource */ - *type = pci_bar_unknown; - reg = pci_iov_resource_bar(dev, resno); - if (reg) - return reg; - } - - dev_err(&dev->dev, "BAR %d: invalid resource\n", resno); - return 0; -} - /* Some architectures require additional programming to enable VGA */ static arch_set_vga_state_t arch_set_vga_state; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 5bfcb922f7f7..a5d37f6a9fb5 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -245,7 +245,6 @@ bool pci_bus_read_dev_vendor_id(struct pci_bus *bus, int devfn, u32 *pl, int pci_setup_device(struct pci_dev *dev); int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, struct resource *res, unsigned int reg); -int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type); void pci_configure_ari(struct pci_dev *dev); void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head); @@ -289,7 +288,6 @@ static inline void pci_restore_ats_state(struct pci_dev *dev) #ifdef CONFIG_PCI_IOV int pci_iov_init(struct pci_dev *dev); void pci_iov_release(struct pci_dev *dev); -int pci_iov_resource_bar(struct pci_dev *dev, int resno); void pci_iov_update_resource(struct pci_dev *dev, int resno); resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno); void pci_restore_iov_state(struct pci_dev *dev); @@ -304,10 +302,6 @@ static inline void pci_iov_release(struct pci_dev *dev) { } -static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno) -{ - return 0; -} static inline void pci_restore_iov_state(struct pci_dev *dev) { } diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 5ddeb6737f99..99c9e32775ee 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -32,7 +32,6 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno) u16 cmd; u32 new, check, mask; int reg; - enum pci_bar_type type; struct resource *res = dev->resource + resno; /* Per SR-IOV spec 3.4.1.11, VF BARs are RO zero */ @@ -70,14 +69,16 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno) new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; } - reg = pci_resource_bar(dev, resno, &type); - if (!reg) - return; - if (type != pci_bar_unknown) { + if (resno < PCI_ROM_RESOURCE) { + reg = PCI_BASE_ADDRESS_0 + 4 * resno; + } else if (resno == PCI_ROM_RESOURCE) { if (!(res->flags & IORESOURCE_ROM_ENABLE)) return; + + reg = dev->rom_base_reg; new |= PCI_ROM_ADDRESS_ENABLE; - } + } else + return; /* * We can't update a 64-bit BAR atomically, so when possible, -- cgit v1.2.3 From 7a6d312b50e63f598f5b5914c4fd21878ac2b595 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 28 Nov 2016 17:21:02 -0600 Subject: PCI: Decouple IORESOURCE_ROM_ENABLE and PCI_ROM_ADDRESS_ENABLE Remove the assumption that IORESOURCE_ROM_ENABLE == PCI_ROM_ADDRESS_ENABLE. PCI_ROM_ADDRESS_ENABLE is the ROM enable bit defined by the PCI spec, so if we're reading or writing a BAR register value, that's what we should use. IORESOURCE_ROM_ENABLE is a corresponding bit in struct resource flags. Signed-off-by: Bjorn Helgaas Reviewed-by: Gavin Shan --- drivers/pci/probe.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ab002671fa60..cf7670e81979 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -227,7 +227,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK; } } else { - res->flags |= (l & IORESOURCE_ROM_ENABLE); + if (l & PCI_ROM_ADDRESS_ENABLE) + res->flags |= IORESOURCE_ROM_ENABLE; l64 = l & PCI_ROM_ADDRESS_MASK; sz64 = sz & PCI_ROM_ADDRESS_MASK; mask64 = (u32)PCI_ROM_ADDRESS_MASK; -- cgit v1.2.3 From 0b457dde3cf8b7c76a60f8e960f21bbd4abdc416 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 28 Nov 2016 16:17:41 -0600 Subject: PCI: Add comments about ROM BAR updating pci_update_resource() updates a hardware BAR so its address matches the kernel's struct resource UNLESS it's a disabled ROM BAR. We only update those when we enable the ROM. It's not obvious from the code why ROM BARs should be handled specially. Apparently there are Matrox devices with defective ROM BARs that read as zero when disabled. That means that if pci_enable_rom() reads the disabled BAR, sets PCI_ROM_ADDRESS_ENABLE (without re-inserting the address), and writes it back, it would enable the ROM at address zero. Add comments and references to explain why we can't make the code look more rational. The code changes are from 755528c860b0 ("Ignore disabled ROM resources at setup") and 8085ce084c0f ("[PATCH] Fix PCI ROM mapping"). Link: https://lkml.org/lkml/2005/8/30/138 Signed-off-by: Bjorn Helgaas Reviewed-by: Gavin Shan --- drivers/pci/rom.c | 5 +++++ drivers/pci/setup-res.c | 6 ++++++ 2 files changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c index 06663d391b39..b6edb187d160 100644 --- a/drivers/pci/rom.c +++ b/drivers/pci/rom.c @@ -35,6 +35,11 @@ int pci_enable_rom(struct pci_dev *pdev) if (res->flags & IORESOURCE_ROM_SHADOW) return 0; + /* + * Ideally pci_update_resource() would update the ROM BAR address, + * and we would only set the enable bit here. But apparently some + * devices have buggy ROM BARs that read as zero when disabled. + */ pcibios_resource_to_bus(pdev->bus, ®ion, res); pci_read_config_dword(pdev, pdev->rom_base_reg, &rom_addr); rom_addr &= ~PCI_ROM_ADDRESS_MASK; diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c index 99c9e32775ee..045427336e11 100644 --- a/drivers/pci/setup-res.c +++ b/drivers/pci/setup-res.c @@ -72,6 +72,12 @@ static void pci_std_update_resource(struct pci_dev *dev, int resno) if (resno < PCI_ROM_RESOURCE) { reg = PCI_BASE_ADDRESS_0 + 4 * resno; } else if (resno == PCI_ROM_RESOURCE) { + + /* + * Apparently some Matrox devices have ROM BARs that read + * as zero when disabled, so don't update ROM BARs unless + * they're enabled. See https://lkml.org/lkml/2005/8/30/138. + */ if (!(res->flags & IORESOURCE_ROM_ENABLE)) return; -- cgit v1.2.3 From 31d182574a0ed2f2a540e2df51b245f3cec955e9 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 29 Nov 2016 13:22:01 -0700 Subject: dmaengine: fix spacing issues for dmatest Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/dmatest.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index cf76fc6149e5..3b358c46aec9 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -454,7 +454,7 @@ static int dmatest_func(void *data) src_cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0)); dst_cnt = 2; - pq_coefs = kmalloc(params->pq_sources+1, GFP_KERNEL); + pq_coefs = kmalloc(params->pq_sources + 1, GFP_KERNEL); if (!pq_coefs) goto err_thread_type; @@ -463,7 +463,7 @@ static int dmatest_func(void *data) } else goto err_thread_type; - thread->srcs = kcalloc(src_cnt+1, sizeof(u8 *), GFP_KERNEL); + thread->srcs = kcalloc(src_cnt + 1, sizeof(u8 *), GFP_KERNEL); if (!thread->srcs) goto err_srcs; for (i = 0; i < src_cnt; i++) { @@ -473,7 +473,7 @@ static int dmatest_func(void *data) } thread->srcs[i] = NULL; - thread->dsts = kcalloc(dst_cnt+1, sizeof(u8 *), GFP_KERNEL); + thread->dsts = kcalloc(dst_cnt + 1, sizeof(u8 *), GFP_KERNEL); if (!thread->dsts) goto err_dsts; for (i = 0; i < dst_cnt; i++) { @@ -549,7 +549,7 @@ static int dmatest_func(void *data) filltime = ktime_add(filltime, diff); } - um = dmaengine_get_unmap_data(dev->dev, src_cnt+dst_cnt, + um = dmaengine_get_unmap_data(dev->dev, src_cnt + dst_cnt, GFP_KERNEL); if (!um) { failed_tests++; -- cgit v1.2.3 From d6481608638946d8eeb91d7a19ad9ccd9e58a5c4 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 29 Nov 2016 13:22:20 -0700 Subject: dmaengine: dmatest: honor alignment restriction for buffers Existing implementation does not honor the alignment restrictions imposed by the DMA engines. Allocate buffers with built in slack for honoring alignment restrictions. Creating new arrays to hold the aligned pointers and use those pointers for operations. Signed-off-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/dmatest.c | 66 +++++++++++++++++++++++++++++++++++---------------- 1 file changed, 46 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c index 3b358c46aec9..451f899f74e4 100644 --- a/drivers/dma/dmatest.c +++ b/drivers/dma/dmatest.c @@ -164,7 +164,9 @@ struct dmatest_thread { struct task_struct *task; struct dma_chan *chan; u8 **srcs; + u8 **usrcs; u8 **dsts; + u8 **udsts; enum dma_transaction_type type; bool done; }; @@ -431,6 +433,7 @@ static int dmatest_func(void *data) ktime_t comparetime = ktime_set(0, 0); s64 runtime = 0; unsigned long long total_len = 0; + u8 align = 0; set_freezable(); @@ -441,18 +444,22 @@ static int dmatest_func(void *data) params = &info->params; chan = thread->chan; dev = chan->device; - if (thread->type == DMA_MEMCPY) + if (thread->type == DMA_MEMCPY) { + align = dev->copy_align; src_cnt = dst_cnt = 1; - else if (thread->type == DMA_SG) + } else if (thread->type == DMA_SG) { + align = dev->copy_align; src_cnt = dst_cnt = sg_buffers; - else if (thread->type == DMA_XOR) { + } else if (thread->type == DMA_XOR) { /* force odd to ensure dst = src */ src_cnt = min_odd(params->xor_sources | 1, dev->max_xor); dst_cnt = 1; + align = dev->xor_align; } else if (thread->type == DMA_PQ) { /* force odd to ensure dst = src */ src_cnt = min_odd(params->pq_sources | 1, dma_maxpq(dev, 0)); dst_cnt = 2; + align = dev->pq_align; pq_coefs = kmalloc(params->pq_sources + 1, GFP_KERNEL); if (!pq_coefs) @@ -466,20 +473,44 @@ static int dmatest_func(void *data) thread->srcs = kcalloc(src_cnt + 1, sizeof(u8 *), GFP_KERNEL); if (!thread->srcs) goto err_srcs; + + thread->usrcs = kcalloc(src_cnt + 1, sizeof(u8 *), GFP_KERNEL); + if (!thread->usrcs) + goto err_usrcs; + for (i = 0; i < src_cnt; i++) { - thread->srcs[i] = kmalloc(params->buf_size, GFP_KERNEL); - if (!thread->srcs[i]) + thread->usrcs[i] = kmalloc(params->buf_size + align, + GFP_KERNEL); + if (!thread->usrcs[i]) goto err_srcbuf; + + /* align srcs to alignment restriction */ + if (align) + thread->srcs[i] = PTR_ALIGN(thread->usrcs[i], align); + else + thread->srcs[i] = thread->usrcs[i]; } thread->srcs[i] = NULL; thread->dsts = kcalloc(dst_cnt + 1, sizeof(u8 *), GFP_KERNEL); if (!thread->dsts) goto err_dsts; + + thread->udsts = kcalloc(dst_cnt + 1, sizeof(u8 *), GFP_KERNEL); + if (!thread->udsts) + goto err_udsts; + for (i = 0; i < dst_cnt; i++) { - thread->dsts[i] = kmalloc(params->buf_size, GFP_KERNEL); - if (!thread->dsts[i]) + thread->udsts[i] = kmalloc(params->buf_size + align, + GFP_KERNEL); + if (!thread->udsts[i]) goto err_dstbuf; + + /* align dsts to alignment restriction */ + if (align) + thread->dsts[i] = PTR_ALIGN(thread->udsts[i], align); + else + thread->dsts[i] = thread->udsts[i]; } thread->dsts[i] = NULL; @@ -498,20 +529,11 @@ static int dmatest_func(void *data) dma_addr_t srcs[src_cnt]; dma_addr_t *dsts; unsigned int src_off, dst_off, len; - u8 align = 0; struct scatterlist tx_sg[src_cnt]; struct scatterlist rx_sg[src_cnt]; total_tests++; - /* honor alignment restrictions */ - if (thread->type == DMA_MEMCPY || thread->type == DMA_SG) - align = dev->copy_align; - else if (thread->type == DMA_XOR) - align = dev->xor_align; - else if (thread->type == DMA_PQ) - align = dev->pq_align; - if (1 << align > params->buf_size) { pr_err("%u-byte buffer too small for %d-byte alignment\n", params->buf_size, 1 << align); @@ -729,13 +751,17 @@ static int dmatest_func(void *data) ret = 0; err_dstbuf: - for (i = 0; thread->dsts[i]; i++) - kfree(thread->dsts[i]); + for (i = 0; thread->udsts[i]; i++) + kfree(thread->udsts[i]); + kfree(thread->udsts); +err_udsts: kfree(thread->dsts); err_dsts: err_srcbuf: - for (i = 0; thread->srcs[i]; i++) - kfree(thread->srcs[i]); + for (i = 0; thread->usrcs[i]; i++) + kfree(thread->usrcs[i]); + kfree(thread->usrcs); +err_usrcs: kfree(thread->srcs); err_srcs: kfree(pq_coefs); -- cgit v1.2.3 From c2e60fc702db68029e32c1fe00a9683dcb29316b Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Wed, 30 Nov 2016 02:28:58 +0530 Subject: dmaengine: zx296702_dma: Use dma_pool_zalloc We should use dma_pool_zalloc instead of dma_pool_alloc/memset. Signed-off-by: Souptick joarder Signed-off-by: Vinod Koul --- drivers/dma/zx296702_dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/zx296702_dma.c b/drivers/dma/zx296702_dma.c index 245d759d5ffc..380276d078b2 100644 --- a/drivers/dma/zx296702_dma.c +++ b/drivers/dma/zx296702_dma.c @@ -435,13 +435,12 @@ static struct zx_dma_desc_sw *zx_alloc_desc_resource(int num, if (!ds) return NULL; - ds->desc_hw = dma_pool_alloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli); + ds->desc_hw = dma_pool_zalloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli); if (!ds->desc_hw) { dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc); kfree(ds); return NULL; } - memset(ds->desc_hw, 0, sizeof(struct zx_desc_hw) * num); ds->desc_num = num; return ds; } -- cgit v1.2.3 From 9dcd74089a1ecf73ea4a355ee097b5b218ccf3dc Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Wed, 30 Nov 2016 02:30:37 +0530 Subject: dmaengine: at_xdmac: Use dma_pool_zalloc We should use dma_pool_zalloc instead of dma_pool_alloc/memset. Signed-off-by: Souptick joarder Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index b7d7f2d443a1..40287ff92768 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -444,9 +444,8 @@ static struct at_xdmac_desc *at_xdmac_alloc_desc(struct dma_chan *chan, struct at_xdmac *atxdmac = to_at_xdmac(chan->device); dma_addr_t phys; - desc = dma_pool_alloc(atxdmac->at_xdmac_desc_pool, gfp_flags, &phys); + desc = dma_pool_zalloc(atxdmac->at_xdmac_desc_pool, gfp_flags, &phys); if (desc) { - memset(desc, 0, sizeof(*desc)); INIT_LIST_HEAD(&desc->descs_list); dma_async_tx_descriptor_init(&desc->tx_dma_desc, chan); desc->tx_dma_desc.tx_submit = at_xdmac_tx_submit; -- cgit v1.2.3 From 201ac4861c1944ec3794364d6898b4ddfeb0faf8 Mon Sep 17 00:00:00 2001 From: Peter Ujfalusi Date: Tue, 29 Nov 2016 16:23:42 +0200 Subject: dmaengine: omap-dma: Support for slave devices with data port window Based on the src/dst_port_window_size - if it is set - configure the DMA channel to use double indexing in order to be able to loop within the address window. Signed-off-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/omap-dma.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c index 15eb8024666b..ac68666cd3f4 100644 --- a/drivers/dma/omap-dma.c +++ b/drivers/dma/omap-dma.c @@ -166,6 +166,9 @@ enum { CSDP_DST_BURST_16 = 1 << 14, CSDP_DST_BURST_32 = 2 << 14, CSDP_DST_BURST_64 = 3 << 14, + CSDP_WRITE_NON_POSTED = 0 << 16, + CSDP_WRITE_POSTED = 1 << 16, + CSDP_WRITE_LAST_NON_POSTED = 2 << 16, CICR_TOUT_IE = BIT(0), /* OMAP1 only */ CICR_DROP_IE = BIT(1), @@ -881,15 +884,18 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( unsigned i, es, en, frame_bytes; bool ll_failed = false; u32 burst; + u32 port_window, port_window_bytes; if (dir == DMA_DEV_TO_MEM) { dev_addr = c->cfg.src_addr; dev_width = c->cfg.src_addr_width; burst = c->cfg.src_maxburst; + port_window = c->cfg.src_port_window_size; } else if (dir == DMA_MEM_TO_DEV) { dev_addr = c->cfg.dst_addr; dev_width = c->cfg.dst_addr_width; burst = c->cfg.dst_maxburst; + port_window = c->cfg.dst_port_window_size; } else { dev_err(chan->device->dev, "%s: bad direction?\n", __func__); return NULL; @@ -910,6 +916,12 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( return NULL; } + /* When the port_window is used, one frame must cover the window */ + if (port_window) { + burst = port_window; + port_window_bytes = port_window * es_bytes[es]; + } + /* Now allocate and setup the descriptor. */ d = kzalloc(sizeof(*d) + sglen * sizeof(d->sg[0]), GFP_ATOMIC); if (!d) @@ -921,11 +933,45 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr = c->ccr | CCR_SYNC_FRAME; if (dir == DMA_DEV_TO_MEM) { - d->ccr |= CCR_DST_AMODE_POSTINC | CCR_SRC_AMODE_CONSTANT; d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED; + + d->ccr |= CCR_DST_AMODE_POSTINC; + if (port_window) { + d->ccr |= CCR_SRC_AMODE_DBLIDX; + d->ei = 1; + /* + * One frame covers the port_window and by configure + * the source frame index to be -1 * (port_window - 1) + * we instruct the sDMA that after a frame is processed + * it should move back to the start of the window. + */ + d->fi = -(port_window_bytes - 1); + + if (port_window_bytes >= 64) + d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED; + else if (port_window_bytes >= 32) + d->csdp = CSDP_SRC_BURST_32 | CSDP_SRC_PACKED; + else if (port_window_bytes >= 16) + d->csdp = CSDP_SRC_BURST_16 | CSDP_SRC_PACKED; + } else { + d->ccr |= CCR_SRC_AMODE_CONSTANT; + } } else { - d->ccr |= CCR_DST_AMODE_CONSTANT | CCR_SRC_AMODE_POSTINC; d->csdp = CSDP_SRC_BURST_64 | CSDP_SRC_PACKED; + + d->ccr |= CCR_SRC_AMODE_POSTINC; + if (port_window) { + d->ccr |= CCR_DST_AMODE_DBLIDX; + + if (port_window_bytes >= 64) + d->csdp = CSDP_DST_BURST_64 | CSDP_DST_PACKED; + else if (port_window_bytes >= 32) + d->csdp = CSDP_DST_BURST_32 | CSDP_DST_PACKED; + else if (port_window_bytes >= 16) + d->csdp = CSDP_DST_BURST_16 | CSDP_DST_PACKED; + } else { + d->ccr |= CCR_DST_AMODE_CONSTANT; + } } d->cicr = CICR_DROP_IE | CICR_BLOCK_IE; @@ -943,6 +989,9 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( d->ccr |= CCR_TRIGGER_SRC; d->cicr |= CICR_MISALIGNED_ERR_IE | CICR_TRANS_ERR_IE; + + if (port_window) + d->csdp |= CSDP_WRITE_LAST_NON_POSTED; } if (od->plat->errata & DMA_ERRATA_PARALLEL_CHANNELS) d->clnk_ctrl = c->dma_ch; @@ -968,6 +1017,16 @@ static struct dma_async_tx_descriptor *omap_dma_prep_slave_sg( osg->addr = sg_dma_address(sgent); osg->en = en; osg->fn = sg_dma_len(sgent) / frame_bytes; + if (port_window && dir == DMA_MEM_TO_DEV) { + osg->ei = 1; + /* + * One frame covers the port_window and by configure + * the source frame index to be -1 * (port_window - 1) + * we instruct the sDMA that after a frame is processed + * it should move back to the start of the window. + */ + osg->fi = -(port_window_bytes - 1); + } if (d->using_ll) { osg->t2_desc = dma_pool_alloc(od->desc_pool, GFP_ATOMIC, -- cgit v1.2.3 From 08c824e87ea05f989a9768a365f0fc70bcd25298 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Wed, 23 Nov 2016 14:57:55 +0530 Subject: dmaengine: edma: re-initialize dummy slot during system resume The last param set in a transfer should always be pointing to dummy param set in non-cyclic mode. When system wakes from low power state EDMA PARAM slots may be reset to random values. Hence, re-initialize dummy slot to dummy param set on system resume. Signed-off-by: Vignesh R Acked-by: Peter Ujfalusi Signed-off-by: Vinod Koul --- drivers/dma/edma.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c index e18a58068bca..1d2be18fec15 100644 --- a/drivers/dma/edma.c +++ b/drivers/dma/edma.c @@ -2450,6 +2450,9 @@ static int edma_pm_resume(struct device *dev) int i; s8 (*queue_priority_mapping)[2]; + /* re initialize dummy slot to dummy param set */ + edma_write_slot(ecc, ecc->dummy_slot, &dummy_paramset); + queue_priority_mapping = ecc->info->queue_priority_mapping; /* Event queue priority mapping */ -- cgit v1.2.3 From 258f2277a93fe0e3cdac275264d275c526170db6 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Fri, 25 Nov 2016 17:59:06 +0300 Subject: dmaengine: DW DMAC: enable memory-to-memory transfers support All known devices, which use DT for configuration, support memory-to-memory transfers. So enable it by default, if we read configuration from DT. Acked-by: Andy Shevchenko Signed-off-by: Eugeniy Paltsev Signed-off-by: Vinod Koul --- drivers/dma/dw/platform.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index 5bda0eb9f393..aa7a5c1b9bf8 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -129,6 +129,12 @@ dw_dma_parse_dt(struct platform_device *pdev) if (of_property_read_bool(np, "is_private")) pdata->is_private = true; + /* + * All known devices, which use DT for configuration, support + * memory-to-memory transfers. So enable it by default. + */ + pdata->is_memcpy = true; + if (!of_property_read_u32(np, "chan_allocation_order", &tmp)) pdata->chan_allocation_order = (unsigned char)tmp; -- cgit v1.2.3 From bd2c6636cc59c4626a04d9918953a107f88eaff9 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Fri, 25 Nov 2016 17:59:07 +0300 Subject: dmaengine: DW DMAC: add multi-block property to device tree Several versions of DW DMAC have multi block transfers hardware support. Hardware support of multi block transfers is disabled by default if we use DT to configure DMAC and software emulation of multi block transfers used instead. Add multi-block property, so it is possible to enable hardware multi block transfers (if present) via DT. Switch from per device is_nollp variable to multi_block array to be able enable/disable multi block transfers separately per channel. Acked-by: Andy Shevchenko Signed-off-by: Eugeniy Paltsev Signed-off-by: Vinod Koul --- Documentation/devicetree/bindings/dma/snps-dma.txt | 2 ++ arch/arc/boot/dts/abilis_tb10x.dtsi | 1 + arch/arm/boot/dts/spear13xx.dtsi | 2 ++ drivers/dma/dw/core.c | 2 +- drivers/dma/dw/platform.c | 12 +++++++++++- drivers/dma/dw/regs.h | 3 ++- drivers/tty/serial/8250/8250_lpss.c | 2 +- include/linux/platform_data/dma-dw.h | 5 +++-- 8 files changed, 23 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/dma/snps-dma.txt b/Documentation/devicetree/bindings/dma/snps-dma.txt index 0f5583293c9c..4775c66f4508 100644 --- a/Documentation/devicetree/bindings/dma/snps-dma.txt +++ b/Documentation/devicetree/bindings/dma/snps-dma.txt @@ -27,6 +27,8 @@ Optional properties: that services interrupts for this device - is_private: The device channels should be marked as private and not for by the general purpose DMA channel allocator. False if not passed. +- multi-block: Multi block transfers supported by hardware. Array property with + one cell per channel. 0: not supported, 1 (default): supported. Example: diff --git a/arch/arc/boot/dts/abilis_tb10x.dtsi b/arch/arc/boot/dts/abilis_tb10x.dtsi index de53f5c3251c..3121536b25a3 100644 --- a/arch/arc/boot/dts/abilis_tb10x.dtsi +++ b/arch/arc/boot/dts/abilis_tb10x.dtsi @@ -129,6 +129,7 @@ data-width = <4>; clocks = <&ahb_clk>; clock-names = "hclk"; + multi-block = <1 1 1 1 1 1>; }; i2c0: i2c@FF120000 { diff --git a/arch/arm/boot/dts/spear13xx.dtsi b/arch/arm/boot/dts/spear13xx.dtsi index 449acf0d8272..17ea0abcdbd7 100644 --- a/arch/arm/boot/dts/spear13xx.dtsi +++ b/arch/arm/boot/dts/spear13xx.dtsi @@ -118,6 +118,7 @@ block_size = <0xfff>; dma-masters = <2>; data-width = <8 8>; + multi-block = <1 1 1 1 1 1 1 1>; }; dma@eb000000 { @@ -134,6 +135,7 @@ chan_priority = <1>; block_size = <0xfff>; data-width = <8 8>; + multi-block = <1 1 1 1 1 1 1 1>; }; fsmc: flash@b0000000 { diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index c2c0a613cb7a..e5adf5d1c34f 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -1569,7 +1569,7 @@ int dw_dma_probe(struct dw_dma_chip *chip) (dwc_params >> DWC_PARAMS_MBLK_EN & 0x1) == 0; } else { dwc->block_size = pdata->block_size; - dwc->nollp = pdata->is_nollp; + dwc->nollp = !pdata->multi_block[i]; } } diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c index aa7a5c1b9bf8..b1655e40cfa2 100644 --- a/drivers/dma/dw/platform.c +++ b/drivers/dma/dw/platform.c @@ -102,7 +102,7 @@ dw_dma_parse_dt(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; struct dw_dma_platform_data *pdata; - u32 tmp, arr[DW_DMA_MAX_NR_MASTERS]; + u32 tmp, arr[DW_DMA_MAX_NR_MASTERS], mb[DW_DMA_MAX_NR_CHANNELS]; u32 nr_masters; u32 nr_channels; @@ -118,6 +118,8 @@ dw_dma_parse_dt(struct platform_device *pdev) if (of_property_read_u32(np, "dma-channels", &nr_channels)) return NULL; + if (nr_channels > DW_DMA_MAX_NR_CHANNELS) + return NULL; pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) @@ -152,6 +154,14 @@ dw_dma_parse_dt(struct platform_device *pdev) pdata->data_width[tmp] = BIT(arr[tmp] & 0x07); } + if (!of_property_read_u32_array(np, "multi-block", mb, nr_channels)) { + for (tmp = 0; tmp < nr_channels; tmp++) + pdata->multi_block[tmp] = mb[tmp]; + } else { + for (tmp = 0; tmp < nr_channels; tmp++) + pdata->multi_block[tmp] = 1; + } + return pdata; } #else diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h index f65dd104479f..4e0128c62704 100644 --- a/drivers/dma/dw/regs.h +++ b/drivers/dma/dw/regs.h @@ -12,7 +12,8 @@ #include #include -#define DW_DMA_MAX_NR_CHANNELS 8 +#include "internal.h" + #define DW_DMA_MAX_NR_REQUESTS 16 /* flow controller */ diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 886fcf37f291..c4593ec68ff7 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -157,12 +157,12 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) static const struct dw_dma_platform_data qrk_serial_dma_pdata = { .nr_channels = 2, .is_private = true, - .is_nollp = true, .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, .chan_priority = CHAN_PRIORITY_ASCENDING, .block_size = 4095, .nr_masters = 1, .data_width = {4}, + .multi_block = {0}, }; static void qrk_serial_setup_dma(struct lpss8250 *lpss, struct uart_port *port) diff --git a/include/linux/platform_data/dma-dw.h b/include/linux/platform_data/dma-dw.h index 5f0e11e7354c..e69e415d0d98 100644 --- a/include/linux/platform_data/dma-dw.h +++ b/include/linux/platform_data/dma-dw.h @@ -14,6 +14,7 @@ #include #define DW_DMA_MAX_NR_MASTERS 4 +#define DW_DMA_MAX_NR_CHANNELS 8 /** * struct dw_dma_slave - Controller-specific information about a slave @@ -40,19 +41,18 @@ struct dw_dma_slave { * @is_private: The device channels should be marked as private and not for * by the general purpose DMA channel allocator. * @is_memcpy: The device channels do support memory-to-memory transfers. - * @is_nollp: The device channels does not support multi block transfers. * @chan_allocation_order: Allocate channels starting from 0 or 7 * @chan_priority: Set channel priority increasing from 0 to 7 or 7 to 0. * @block_size: Maximum block size supported by the controller * @nr_masters: Number of AHB masters supported by the controller * @data_width: Maximum data width supported by hardware per AHB master * (in bytes, power of 2) + * @multi_block: Multi block transfers supported by hardware per channel. */ struct dw_dma_platform_data { unsigned int nr_channels; bool is_private; bool is_memcpy; - bool is_nollp; #define CHAN_ALLOCATION_ASCENDING 0 /* zero to seven */ #define CHAN_ALLOCATION_DESCENDING 1 /* seven to zero */ unsigned char chan_allocation_order; @@ -62,6 +62,7 @@ struct dw_dma_platform_data { unsigned int block_size; unsigned char nr_masters; unsigned char data_width[DW_DMA_MAX_NR_MASTERS]; + unsigned char multi_block[DW_DMA_MAX_NR_CHANNELS]; }; #endif /* _PLATFORM_DATA_DMA_DW_H */ -- cgit v1.2.3 From 3605163d98dbcd37e5d6f51c4982d7da77bdcba9 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 16 Nov 2016 07:04:50 -0200 Subject: [media] s5p-mfc: Set DMA_ATTR_ALLOC_SINGLE_PAGES We do video allocation all the time and we need it to be fast. Plus TLB efficiency isn't terribly important for video. That means we want to set DMA_ATTR_ALLOC_SINGLE_PAGES. See also the previous change (commit 14d3ae2efeed "ARM: dma-mapping: Use DMA_ATTR_ALLOC_SINGLE_PAGES hint to optimize allocation"). [m.szyprowski: rebased patch onto v4.9-rc1 and adapted changes to latest videbuf2 changes, this simplifies code changes to only set proper dma attribute flag and comment the reason for it, added commit id of arch/arm/mm patch] Signed-off-by: Douglas Anderson Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 320124352e82..da735cda2882 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -851,6 +851,11 @@ static int s5p_mfc_open(struct file *file) ret = -ENOENT; goto err_queue_init; } + /* + * We'll do mostly sequential access, so sacrifice TLB efficiency for + * faster allocation. + */ + q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); @@ -881,6 +886,12 @@ static int s5p_mfc_open(struct file *file) * will keep the value of bytesused intact. */ q->allow_zero_bytesused = 1; + + /* + * We'll do mostly sequential access, so sacrifice TLB efficiency for + * faster allocation. + */ + q->dma_attrs = DMA_ATTR_ALLOC_SINGLE_PAGES; q->mem_ops = &vb2_dma_contig_memops; q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; ret = vb2_queue_init(q); -- cgit v1.2.3 From 0a79ef333dfa7f25abc2eab10f3a11bbdf9a9f17 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:51 -0200 Subject: [media] s5p-mfc: Use printk_ratelimited for reporting ioctl errors Some applications don't check error codes from QBUF/DQBUF ioctls, so don't spam kernel log with errors if they fall into endless loop trying to queue next buffer after a failure. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_debug.h | 6 ++++++ drivers/media/platform/s5p-mfc/s5p_mfc_dec.c | 2 +- drivers/media/platform/s5p-mfc/s5p_mfc_enc.c | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h index 5936923c631c..1936a5b868f5 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_debug.h @@ -39,6 +39,12 @@ extern int mfc_debug_level; __func__, __LINE__, ##args); \ } while (0) +#define mfc_err_limited(fmt, args...) \ + do { \ + printk_ratelimited(KERN_ERR "%s:%d: " fmt, \ + __func__, __LINE__, ##args); \ + } while (0) + #define mfc_info(fmt, args...) \ do { \ printk(KERN_INFO "%s:%d: " fmt, \ diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c index cf787eae11b7..367ef8e8dbf0 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c @@ -642,7 +642,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) int ret; if (ctx->state == MFCINST_ERROR) { - mfc_err("Call on DQBUF after unrecoverable error\n"); + mfc_err_limited("Call on DQBUF after unrecoverable error\n"); return -EIO; } diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c index fcc2e054c61f..e39d9e06e299 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c @@ -1268,7 +1268,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf) int ret; if (ctx->state == MFCINST_ERROR) { - mfc_err("Call on DQBUF after unrecoverable error\n"); + mfc_err_limited("Call on DQBUF after unrecoverable error\n"); return -EIO; } if (buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { -- cgit v1.2.3 From 2e4e084465dd21f8a76c9fc5da496009d5803ada Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:52 -0200 Subject: [media] s5p-mfc: Remove special clock rate management The maximum rate of special clock depends on SoC variant and should be set in device tree via assigned-clock-rates property, so remove the code which forces special clock to 200MHz. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index b5806ab7ac31..818c04646061 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -20,7 +20,6 @@ #define MFC_GATE_CLK_NAME "mfc" #define MFC_SCLK_NAME "sclk_mfc" -#define MFC_SCLK_RATE (200 * 1000000) #define CLK_DEBUG @@ -57,7 +56,6 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) mfc_info("Failed to get MFC special clock control\n"); pm->clock = NULL; } else { - clk_set_rate(pm->clock, MFC_SCLK_RATE); ret = clk_prepare_enable(pm->clock); if (ret) { mfc_err("Failed to enable MFC special clock\n"); -- cgit v1.2.3 From 8accb8fdf6ea6e1e4eb513e88e06d629ed01103b Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:53 -0200 Subject: [media] s5p-mfc: Ensure that clock is disabled before turning power off Move clock disabling before turning power off. This will enable later to add calls to clk_prepare/unprepare in the s5p_mfc_power_off() function to avoid keeping clocks prepared all the time when driver is bound. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index da735cda2882..991649111e77 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -963,11 +963,13 @@ static int s5p_mfc_release(struct file *file) mfc_debug(2, "Last instance\n"); s5p_mfc_deinit_hw(dev); del_timer_sync(&dev->watchdog_timer); + s5p_mfc_clock_off(); if (s5p_mfc_power_off() < 0) mfc_err("Power off failed\n"); + } else { + mfc_debug(2, "Shutting down clock\n"); + s5p_mfc_clock_off(); } - mfc_debug(2, "Shutting down clock\n"); - s5p_mfc_clock_off(); } if (dev) dev->ctx[ctx->num] = NULL; -- cgit v1.2.3 From 7e55a016fac080118a634179405c821c31d8bd2e Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:54 -0200 Subject: [media] s5p-mfc: Remove dead conditional code CONFIG_PM is always enabled on Exynos platforms, so remove dead code related to early development of MFC driver on platform without PM support. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 22 ------------------ drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 1 - drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 30 +++++-------------------- 3 files changed, 5 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 991649111e77..b34ccbefbb02 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1405,31 +1405,9 @@ static int s5p_mfc_resume(struct device *dev) } #endif -#ifdef CONFIG_PM -static int s5p_mfc_runtime_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct s5p_mfc_dev *m_dev = platform_get_drvdata(pdev); - - atomic_set(&m_dev->pm.power, 0); - return 0; -} - -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); - - atomic_set(&m_dev->pm.power, 1); - return 0; -} -#endif - /* Power management */ static const struct dev_pm_ops s5p_mfc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) - SET_RUNTIME_PM_OPS(s5p_mfc_runtime_suspend, s5p_mfc_runtime_resume, - NULL) }; static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index c068ee3ece6e..58b15c212dd2 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -200,7 +200,6 @@ struct s5p_mfc_pm { struct clk *clock; struct clk *clock_gate; bool use_clock_gating; - atomic_t power; struct device *device; }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 818c04646061..11a918eb7564 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -21,14 +21,9 @@ #define MFC_GATE_CLK_NAME "mfc" #define MFC_SCLK_NAME "sclk_mfc" -#define CLK_DEBUG - static struct s5p_mfc_pm *pm; static struct s5p_mfc_dev *p_dev; - -#ifdef CLK_DEBUG static atomic_t clk_ref; -#endif int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) { @@ -64,14 +59,10 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) } } - atomic_set(&pm->power, 0); -#ifdef CONFIG_PM pm->device = &dev->plat_dev->dev; pm_runtime_enable(pm->device); -#endif -#ifdef CLK_DEBUG atomic_set(&clk_ref, 0); -#endif + return 0; err_s_clk: @@ -95,18 +86,16 @@ void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) clk_unprepare(pm->clock_gate); clk_put(pm->clock_gate); pm->clock_gate = NULL; -#ifdef CONFIG_PM pm_runtime_disable(pm->device); -#endif } int s5p_mfc_clock_on(void) { int ret = 0; -#ifdef CLK_DEBUG + atomic_inc(&clk_ref); mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); -#endif + if (!pm->use_clock_gating) return 0; if (!IS_ERR_OR_NULL(pm->clock_gate)) @@ -116,10 +105,9 @@ int s5p_mfc_clock_on(void) void s5p_mfc_clock_off(void) { -#ifdef CLK_DEBUG atomic_dec(&clk_ref); mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); -#endif + if (!pm->use_clock_gating) return; if (!IS_ERR_OR_NULL(pm->clock_gate)) @@ -130,13 +118,10 @@ int s5p_mfc_power_on(void) { int ret = 0; -#ifdef CONFIG_PM ret = pm_runtime_get_sync(pm->device); if (ret) return ret; -#else - atomic_set(&pm->power, 1); -#endif + if (!pm->use_clock_gating && !IS_ERR_OR_NULL(pm->clock_gate)) ret = clk_enable(pm->clock_gate); return ret; @@ -146,12 +131,7 @@ int s5p_mfc_power_off(void) { if (!pm->use_clock_gating && !IS_ERR_OR_NULL(pm->clock_gate)) clk_disable(pm->clock_gate); -#ifdef CONFIG_PM return pm_runtime_put_sync(pm->device); -#else - atomic_set(&pm->power, 0); - return 0; -#endif } -- cgit v1.2.3 From 387e08e2021022e764a235df6c1f0ed3d861f711 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:55 -0200 Subject: [media] s5p-mfc: Kill all IS_ERR_OR_NULL in clocks management code After commit "s5p-mfc: Fix clock management in s5p_mfc_release function" all clocks related functions are called only when MFC device is really available, so there is no additional check needed for NULL gate clocks. This patch simplifies the code and kills IS_ERR_OR_NULL macro usage. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 11a918eb7564..b514584cf00d 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -91,16 +91,12 @@ void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) int s5p_mfc_clock_on(void) { - int ret = 0; - atomic_inc(&clk_ref); mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); if (!pm->use_clock_gating) return 0; - if (!IS_ERR_OR_NULL(pm->clock_gate)) - ret = clk_enable(pm->clock_gate); - return ret; + return clk_enable(pm->clock_gate); } void s5p_mfc_clock_off(void) @@ -110,8 +106,7 @@ void s5p_mfc_clock_off(void) if (!pm->use_clock_gating) return; - if (!IS_ERR_OR_NULL(pm->clock_gate)) - clk_disable(pm->clock_gate); + clk_disable(pm->clock_gate); } int s5p_mfc_power_on(void) @@ -122,14 +117,14 @@ int s5p_mfc_power_on(void) if (ret) return ret; - if (!pm->use_clock_gating && !IS_ERR_OR_NULL(pm->clock_gate)) + if (!pm->use_clock_gating) ret = clk_enable(pm->clock_gate); return ret; } int s5p_mfc_power_off(void) { - if (!pm->use_clock_gating && !IS_ERR_OR_NULL(pm->clock_gate)) + if (!pm->use_clock_gating) clk_disable(pm->clock_gate); return pm_runtime_put_sync(pm->device); } -- cgit v1.2.3 From 741f4331d07fd670b9ebb5eeda18208b6eb2ba28 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:56 -0200 Subject: [media] s5p-mfc: Don't keep clock prepared all the time This patch moves preparation of clocks from s5p_mfc_init_pm() (driver probe) to s5p_mfc_power_on() (start of device operation). This change will allow to use runtime power usage optimization on newer Samsung Exynos platforms (for example Exynos 5433). Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 52 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index b514584cf00d..796dac85746a 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -39,23 +39,11 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) goto err_g_ip_clk; } - ret = clk_prepare(pm->clock_gate); - if (ret) { - mfc_err("Failed to prepare clock-gating control\n"); - goto err_p_ip_clk; - } - if (dev->variant->version != MFC_VERSION_V6) { pm->clock = clk_get(&dev->plat_dev->dev, MFC_SCLK_NAME); if (IS_ERR(pm->clock)) { mfc_info("Failed to get MFC special clock control\n"); pm->clock = NULL; - } else { - ret = clk_prepare_enable(pm->clock); - if (ret) { - mfc_err("Failed to enable MFC special clock\n"); - goto err_s_clk; - } } } @@ -65,10 +53,6 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) return 0; -err_s_clk: - clk_put(pm->clock); - pm->clock = NULL; -err_p_ip_clk: clk_put(pm->clock_gate); pm->clock_gate = NULL; err_g_ip_clk: @@ -79,11 +63,9 @@ void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) { if (dev->variant->version != MFC_VERSION_V6 && pm->clock) { - clk_disable_unprepare(pm->clock); clk_put(pm->clock); pm->clock = NULL; } - clk_unprepare(pm->clock_gate); clk_put(pm->clock_gate); pm->clock_gate = NULL; pm_runtime_disable(pm->device); @@ -111,22 +93,44 @@ void s5p_mfc_clock_off(void) int s5p_mfc_power_on(void) { - int ret = 0; + int ret; ret = pm_runtime_get_sync(pm->device); if (ret) return ret; - if (!pm->use_clock_gating) - ret = clk_enable(pm->clock_gate); + ret = clk_prepare_enable(pm->clock_gate); + if (ret) + goto err_pm; + + if (pm->clock) { + ret = clk_prepare_enable(pm->clock); + if (ret) + goto err_gate; + } + + if (pm->use_clock_gating) + clk_disable(pm->clock_gate); + return 0; + +err_gate: + clk_disable_unprepare(pm->clock_gate); +err_pm: + pm_runtime_put_sync(pm->device); return ret; + } int s5p_mfc_power_off(void) { - if (!pm->use_clock_gating) - clk_disable(pm->clock_gate); + if (pm->clock) + clk_disable_unprepare(pm->clock); + + if (pm->use_clock_gating) + clk_unprepare(pm->clock_gate); + else + clk_disable_unprepare(pm->clock_gate); + return pm_runtime_put_sync(pm->device); } - -- cgit v1.2.3 From 1bce6fb3edf17a0444226fbbd0f568559512f941 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:57 -0200 Subject: [media] s5p-mfc: Rework clock handling This patch changes the code for handling clocks. Now clocks are defined per each device variant, what is a preparation for adding support for Exynos 5433 MFC V8, which has more clocks than all previous versions. Also use devm_clk_get() to simplify cleanup path. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- drivers/media/platform/s5p-mfc/s5p_mfc.c | 8 ++ drivers/media/platform/s5p-mfc/s5p_mfc_common.h | 9 ++- drivers/media/platform/s5p-mfc/s5p_mfc_pm.c | 98 ++++++++++--------------- 3 files changed, 56 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index b34ccbefbb02..5fcf17008ded 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1434,6 +1434,8 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .buf_size = &buf_size_v5, .buf_align = &mfc_buf_align_v5, .fw_name[0] = "s5p-mfc.fw", + .clk_names = {"mfc", "sclk_mfc"}, + .num_clocks = 2, .use_clock_gating = true, }; @@ -1467,6 +1469,8 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = { * for init buffer command */ .fw_name[1] = "s5p-mfc-v6-v2.fw", + .clk_names = {"mfc"}, + .num_clocks = 1, }; static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { @@ -1494,6 +1498,8 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = { .buf_size = &buf_size_v7, .buf_align = &mfc_buf_align_v7, .fw_name[0] = "s5p-mfc-v7.fw", + .clk_names = {"mfc", "sclk_mfc"}, + .num_clocks = 2, }; static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { @@ -1521,6 +1527,8 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = { .buf_size = &buf_size_v8, .buf_align = &mfc_buf_align_v8, .fw_name[0] = "s5p-mfc-v8.fw", + .clk_names = {"mfc"}, + .num_clocks = 1, }; static const struct of_device_id exynos_mfc_match[] = { diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h index 58b15c212dd2..ab23236aa942 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h @@ -104,6 +104,8 @@ static inline dma_addr_t s5p_mfc_mem_cookie(void *a, void *b) #define S5P_MFC_R2H_CMD_ENC_BUFFER_FUL_RET 16 #define S5P_MFC_R2H_CMD_ERR_RET 32 +#define MFC_MAX_CLOCKS 4 + #define mfc_read(dev, offset) readl(dev->regs_base + (offset)) #define mfc_write(dev, data, offset) writel((data), dev->regs_base + \ (offset)) @@ -197,9 +199,12 @@ struct s5p_mfc_buf { * struct s5p_mfc_pm - power management data structure */ struct s5p_mfc_pm { - struct clk *clock; struct clk *clock_gate; + const char **clk_names; + struct clk *clocks[MFC_MAX_CLOCKS]; + int num_clocks; bool use_clock_gating; + struct device *device; }; @@ -235,6 +240,8 @@ struct s5p_mfc_variant { struct s5p_mfc_buf_size *buf_size; struct s5p_mfc_buf_align *buf_align; char *fw_name[MFC_FW_MAX_VERSIONS]; + const char *clk_names[MFC_MAX_CLOCKS]; + int num_clocks; bool use_clock_gating; }; diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c index 796dac85746a..eb85cedc5ef3 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c @@ -18,56 +18,42 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_pm.h" -#define MFC_GATE_CLK_NAME "mfc" -#define MFC_SCLK_NAME "sclk_mfc" - static struct s5p_mfc_pm *pm; static struct s5p_mfc_dev *p_dev; static atomic_t clk_ref; int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) { - int ret = 0; + int i; pm = &dev->pm; p_dev = dev; - pm->use_clock_gating = dev->variant->use_clock_gating; - pm->clock_gate = clk_get(&dev->plat_dev->dev, MFC_GATE_CLK_NAME); - if (IS_ERR(pm->clock_gate)) { - mfc_err("Failed to get clock-gating control\n"); - ret = PTR_ERR(pm->clock_gate); - goto err_g_ip_clk; - } - if (dev->variant->version != MFC_VERSION_V6) { - pm->clock = clk_get(&dev->plat_dev->dev, MFC_SCLK_NAME); - if (IS_ERR(pm->clock)) { - mfc_info("Failed to get MFC special clock control\n"); - pm->clock = NULL; + pm->num_clocks = dev->variant->num_clocks; + pm->clk_names = dev->variant->clk_names; + pm->device = &dev->plat_dev->dev; + pm->clock_gate = NULL; + + /* clock control */ + for (i = 0; i < pm->num_clocks; i++) { + pm->clocks[i] = devm_clk_get(pm->device, pm->clk_names[i]); + if (IS_ERR(pm->clocks[i])) { + mfc_err("Failed to get clock: %s\n", + pm->clk_names[i]); + return PTR_ERR(pm->clocks[i]); } } - pm->device = &dev->plat_dev->dev; + if (dev->variant->use_clock_gating) + pm->clock_gate = pm->clocks[0]; + pm_runtime_enable(pm->device); atomic_set(&clk_ref, 0); - return 0; - - clk_put(pm->clock_gate); - pm->clock_gate = NULL; -err_g_ip_clk: - return ret; } void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) { - if (dev->variant->version != MFC_VERSION_V6 && - pm->clock) { - clk_put(pm->clock); - pm->clock = NULL; - } - clk_put(pm->clock_gate); - pm->clock_gate = NULL; pm_runtime_disable(pm->device); } @@ -76,8 +62,6 @@ int s5p_mfc_clock_on(void) atomic_inc(&clk_ref); mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); - if (!pm->use_clock_gating) - return 0; return clk_enable(pm->clock_gate); } @@ -86,50 +70,48 @@ void s5p_mfc_clock_off(void) atomic_dec(&clk_ref); mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); - if (!pm->use_clock_gating) - return; clk_disable(pm->clock_gate); } int s5p_mfc_power_on(void) { - int ret; + int i, ret = 0; ret = pm_runtime_get_sync(pm->device); - if (ret) + if (ret < 0) return ret; - ret = clk_prepare_enable(pm->clock_gate); - if (ret) - goto err_pm; - - if (pm->clock) { - ret = clk_prepare_enable(pm->clock); - if (ret) - goto err_gate; + /* clock control */ + for (i = 0; i < pm->num_clocks; i++) { + ret = clk_prepare_enable(pm->clocks[i]); + if (ret < 0) { + mfc_err("clock prepare failed for clock: %s\n", + pm->clk_names[i]); + i++; + goto err; + } } - if (pm->use_clock_gating) - clk_disable(pm->clock_gate); - return 0; + /* prepare for software clock gating */ + clk_disable(pm->clock_gate); -err_gate: - clk_disable_unprepare(pm->clock_gate); -err_pm: - pm_runtime_put_sync(pm->device); + return 0; +err: + while (--i > 0) + clk_disable_unprepare(pm->clocks[i]); + pm_runtime_put(pm->device); return ret; - } int s5p_mfc_power_off(void) { - if (pm->clock) - clk_disable_unprepare(pm->clock); + int i; + + /* finish software clock gating */ + clk_enable(pm->clock_gate); - if (pm->use_clock_gating) - clk_unprepare(pm->clock_gate); - else - clk_disable_unprepare(pm->clock_gate); + for (i = 0; i < pm->num_clocks; i++) + clk_disable_unprepare(pm->clocks[i]); return pm_runtime_put_sync(pm->device); } -- cgit v1.2.3 From 003611334d5592984e319e08c6b66825aca00290 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 16 Nov 2016 07:04:58 -0200 Subject: [media] s5p-mfc: Add support for MFC v8 available in Exynos 5433 SoCs Exynos5433 SoC has MFC v8 hardware module, but it has more complex clock hierarchy, so a new compatible is added. Signed-off-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Signed-off-by: Mauro Carvalho Chehab --- Documentation/devicetree/bindings/media/s5p-mfc.txt | 1 + drivers/media/platform/s5p-mfc/s5p_mfc.c | 14 ++++++++++++++ 2 files changed, 15 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/media/s5p-mfc.txt b/Documentation/devicetree/bindings/media/s5p-mfc.txt index 92c94f5ecbf1..2c901286d818 100644 --- a/Documentation/devicetree/bindings/media/s5p-mfc.txt +++ b/Documentation/devicetree/bindings/media/s5p-mfc.txt @@ -12,6 +12,7 @@ Required properties: (b) "samsung,mfc-v6" for MFC v6 present in Exynos5 SoCs (c) "samsung,mfc-v7" for MFC v7 present in Exynos5420 SoC (d) "samsung,mfc-v8" for MFC v8 present in Exynos5800 SoC + (e) "samsung,exynos5433-mfc" for MFC v8 present in Exynos5433 SoC - reg : Physical base address of the IP registers and length of memory mapped region. diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c index 5fcf17008ded..bb0a5887c9a9 100644 --- a/drivers/media/platform/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c @@ -1531,6 +1531,17 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = { .num_clocks = 1, }; +static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { + .version = MFC_VERSION_V8, + .version_bit = MFC_V8_BIT, + .port_num = MFC_NUM_PORTS_V8, + .buf_size = &buf_size_v8, + .buf_align = &mfc_buf_align_v8, + .fw_name[0] = "s5p-mfc-v8.fw", + .clk_names = {"pclk", "aclk", "aclk_xiu"}, + .num_clocks = 3, +}; + static const struct of_device_id exynos_mfc_match[] = { { .compatible = "samsung,mfc-v5", @@ -1544,6 +1555,9 @@ static const struct of_device_id exynos_mfc_match[] = { }, { .compatible = "samsung,mfc-v8", .data = &mfc_drvdata_v8, + }, { + .compatible = "samsung,exynos5433-mfc", + .data = &mfc_drvdata_v8_5433, }, {}, }; -- cgit v1.2.3 From 39f91a34f3215ee730f9c6e3e1b5374b6b6cb62d Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:35 +0530 Subject: crypto: chcr - Cosmetic change Moves get_aes_decrypt_key function to .c file and declare inline for "aes_ks_subword" Signed-off-by: Jitendra Lulla Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 52 +++++++++++++++++++++++++++++++++ drivers/crypto/chelsio/chcr_algo.h | 59 +------------------------------------- 2 files changed, 53 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index e4ddb921d7b3..daad2bf2cb65 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -178,6 +178,58 @@ static inline unsigned int calc_tx_flits_ofld(const struct sk_buff *skb) return flits + sgl_len(cnt); } +static inline void get_aes_decrypt_key(unsigned char *dec_key, + const unsigned char *key, + unsigned int keylength) +{ + u32 temp; + u32 w_ring[MAX_NK]; + int i, j, k; + u8 nr, nk; + + switch (keylength) { + case AES_KEYLENGTH_128BIT: + nk = KEYLENGTH_4BYTES; + nr = NUMBER_OF_ROUNDS_10; + break; + case AES_KEYLENGTH_192BIT: + nk = KEYLENGTH_6BYTES; + nr = NUMBER_OF_ROUNDS_12; + break; + case AES_KEYLENGTH_256BIT: + nk = KEYLENGTH_8BYTES; + nr = NUMBER_OF_ROUNDS_14; + break; + default: + return; + } + for (i = 0; i < nk; i++) + w_ring[i] = be32_to_cpu(*(u32 *)&key[4 * i]); + + i = 0; + temp = w_ring[nk - 1]; + while (i + nk < (nr + 1) * 4) { + if (!(i % nk)) { + /* RotWord(temp) */ + temp = (temp << 8) | (temp >> 24); + temp = aes_ks_subword(temp); + temp ^= round_constant[i / nk]; + } else if (nk == 8 && (i % 4 == 0)) { + temp = aes_ks_subword(temp); + } + w_ring[i % nk] ^= temp; + temp = w_ring[i % nk]; + i++; + } + i--; + for (k = 0, j = i % nk; k < nk; k++) { + *((u32 *)dec_key + k) = htonl(w_ring[j]); + j--; + if (j < 0) + j += nk; + } +} + static struct shash_desc *chcr_alloc_shash(unsigned int ds) { struct crypto_shash *base_hash = NULL; diff --git a/drivers/crypto/chelsio/chcr_algo.h b/drivers/crypto/chelsio/chcr_algo.h index 199b0bb69b89..f34bc915783a 100644 --- a/drivers/crypto/chelsio/chcr_algo.h +++ b/drivers/crypto/chelsio/chcr_algo.h @@ -394,7 +394,7 @@ static const u8 aes_sbox[256] = { 187, 22 }; -static u32 aes_ks_subword(const u32 w) +static inline u32 aes_ks_subword(const u32 w) { u8 bytes[4]; @@ -412,61 +412,4 @@ static u32 round_constant[11] = { 0x1B000000, 0x36000000, 0x6C000000 }; -/* dec_key - OUTPUT - Reverse round key - * key - INPUT - key - * keylength - INPUT - length of the key in number of bits - */ -static inline void get_aes_decrypt_key(unsigned char *dec_key, - const unsigned char *key, - unsigned int keylength) -{ - u32 temp; - u32 w_ring[MAX_NK]; - int i, j, k; - u8 nr, nk; - - switch (keylength) { - case AES_KEYLENGTH_128BIT: - nk = KEYLENGTH_4BYTES; - nr = NUMBER_OF_ROUNDS_10; - break; - - case AES_KEYLENGTH_192BIT: - nk = KEYLENGTH_6BYTES; - nr = NUMBER_OF_ROUNDS_12; - break; - case AES_KEYLENGTH_256BIT: - nk = KEYLENGTH_8BYTES; - nr = NUMBER_OF_ROUNDS_14; - break; - default: - return; - } - for (i = 0; i < nk; i++ ) - w_ring[i] = be32_to_cpu(*(u32 *)&key[4 * i]); - - i = 0; - temp = w_ring[nk - 1]; - while(i + nk < (nr + 1) * 4) { - if(!(i % nk)) { - /* RotWord(temp) */ - temp = (temp << 8) | (temp >> 24); - temp = aes_ks_subword(temp); - temp ^= round_constant[i / nk]; - } - else if (nk == 8 && (i % 4 == 0)) - temp = aes_ks_subword(temp); - w_ring[i % nk] ^= temp; - temp = w_ring[i % nk]; - i++; - } - i--; - for (k = 0, j = i % nk; k < nk; k++) { - *((u32 *)dec_key + k) = htonl(w_ring[j]); - j--; - if(j < 0) - j += nk; - } -} - #endif /* __CHCR_ALGO_H__ */ -- cgit v1.2.3 From 358961d1cd1ee78bf2d7d573d21eafce53ba4280 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:36 +0530 Subject: crypto: chcr - Added new structure chcr_wr Added new structure chcr_wr to populate Work Request Header. Signed-off-by: Jitendra Lulla Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 239 +++++++++++++++++------------------ drivers/crypto/chelsio/chcr_algo.h | 28 ++-- drivers/crypto/chelsio/chcr_core.h | 16 +++ drivers/crypto/chelsio/chcr_crypto.h | 6 - 4 files changed, 140 insertions(+), 149 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index daad2bf2cb65..d24b7ce79142 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -414,8 +414,23 @@ static inline int get_cryptoalg_subtype(struct crypto_tfm *tfm) return chcr_crypto_alg->type & CRYPTO_ALG_SUB_TYPE_MASK; } +static inline void write_buffer_to_skb(struct sk_buff *skb, + unsigned int *frags, + char *bfr, + u8 bfr_len) +{ + skb->len += bfr_len; + skb->data_len += bfr_len; + skb->truesize += bfr_len; + get_page(virt_to_page(bfr)); + skb_fill_page_desc(skb, *frags, virt_to_page(bfr), + offset_in_page(bfr), bfr_len); + (*frags)++; +} + + static inline void -write_sg_data_page_desc(struct sk_buff *skb, unsigned int *frags, +write_sg_to_skb(struct sk_buff *skb, unsigned int *frags, struct scatterlist *sg, unsigned int count) { struct page *spage; @@ -456,14 +471,12 @@ static int generate_copy_rrkey(struct ablk_ctx *ablkctx, } static inline void create_wreq(struct chcr_context *ctx, - struct fw_crypto_lookaside_wr *wreq, + struct chcr_wr *chcr_req, void *req, struct sk_buff *skb, int kctx_len, int hash_sz, unsigned int phys_dsgl) { struct uld_ctx *u_ctx = ULD_CTX(ctx); - struct ulp_txpkt *ulptx = (struct ulp_txpkt *)(wreq + 1); - struct ulptx_idata *sc_imm = (struct ulptx_idata *)(ulptx + 1); int iv_loc = IV_DSGL; int qid = u_ctx->lldi.rxq_ids[ctx->tx_channel_id]; unsigned int immdatalen = 0, nr_frags = 0; @@ -475,24 +488,27 @@ static inline void create_wreq(struct chcr_context *ctx, nr_frags = skb_shinfo(skb)->nr_frags; } - wreq->op_to_cctx_size = FILL_WR_OP_CCTX_SIZE(immdatalen, - (kctx_len >> 4)); - wreq->pld_size_hash_size = + chcr_req->wreq.op_to_cctx_size = FILL_WR_OP_CCTX_SIZE(immdatalen, + ((sizeof(chcr_req->key_ctx) + kctx_len) >> 4)); + chcr_req->wreq.pld_size_hash_size = htonl(FW_CRYPTO_LOOKASIDE_WR_PLD_SIZE_V(sgl_lengths[nr_frags]) | FW_CRYPTO_LOOKASIDE_WR_HASH_SIZE_V(hash_sz)); - wreq->len16_pkd = htonl(FW_CRYPTO_LOOKASIDE_WR_LEN16_V(DIV_ROUND_UP( + chcr_req->wreq.len16_pkd = + htonl(FW_CRYPTO_LOOKASIDE_WR_LEN16_V(DIV_ROUND_UP( (calc_tx_flits_ofld(skb) * 8), 16))); - wreq->cookie = cpu_to_be64((uintptr_t)req); - wreq->rx_chid_to_rx_q_id = + chcr_req->wreq.cookie = cpu_to_be64((uintptr_t)req); + chcr_req->wreq.rx_chid_to_rx_q_id = FILL_WR_RX_Q_ID(ctx->dev->tx_channel_id, qid, (hash_sz) ? IV_NOP : iv_loc); - ulptx->cmd_dest = FILL_ULPTX_CMD_DEST(ctx->dev->tx_channel_id); - ulptx->len = htonl((DIV_ROUND_UP((calc_tx_flits_ofld(skb) * 8), - 16) - ((sizeof(*wreq)) >> 4))); + chcr_req->ulptx.cmd_dest = FILL_ULPTX_CMD_DEST(ctx->dev->tx_channel_id); + chcr_req->ulptx.len = htonl((DIV_ROUND_UP((calc_tx_flits_ofld(skb) * 8), + 16) - ((sizeof(chcr_req->wreq)) >> 4))); - sc_imm->cmd_more = FILL_CMD_MORE(immdatalen); - sc_imm->len = cpu_to_be32(sizeof(struct cpl_tx_sec_pdu) + kctx_len + + chcr_req->sc_imm.cmd_more = FILL_CMD_MORE(immdatalen); + chcr_req->sc_imm.len = cpu_to_be32(sizeof(struct cpl_tx_sec_pdu) + + sizeof(chcr_req->key_ctx) + + kctx_len + ((hash_sz) ? DUMMY_BYTES : (sizeof(struct cpl_rx_phys_dsgl) + phys_dsgl)) + immdatalen); @@ -506,23 +522,23 @@ static inline void create_wreq(struct chcr_context *ctx, * @op_type: encryption or decryption */ static struct sk_buff -*create_cipher_wr(struct crypto_async_request *req_base, - struct chcr_context *ctx, unsigned short qid, +*create_cipher_wr(struct ablkcipher_request *req, + unsigned short qid, unsigned short op_type) { - struct ablkcipher_request *req = (struct ablkcipher_request *)req_base; struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + struct chcr_context *ctx = crypto_ablkcipher_ctx(tfm); struct uld_ctx *u_ctx = ULD_CTX(ctx); struct ablk_ctx *ablkctx = ABLK_CTX(ctx); struct sk_buff *skb = NULL; - struct _key_ctx *key_ctx; - struct fw_crypto_lookaside_wr *wreq; - struct cpl_tx_sec_pdu *sec_cpl; + struct chcr_wr *chcr_req; struct cpl_rx_phys_dsgl *phys_cpl; struct chcr_blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); struct phys_sge_parm sg_param; unsigned int frags = 0, transhdr_len, phys_dsgl, dst_bufsize = 0; unsigned int ivsize = crypto_ablkcipher_ivsize(tfm), kctx_len; + gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; if (!req->info) return ERR_PTR(-EINVAL); @@ -530,62 +546,57 @@ static struct sk_buff ablkctx->enc = op_type; if ((ablkctx->enckey_len == 0) || (ivsize > AES_BLOCK_SIZE) || - (req->nbytes <= 0) || (req->nbytes % AES_BLOCK_SIZE)) + (req->nbytes <= 0) || (req->nbytes % AES_BLOCK_SIZE)) { + pr_err("AES: Invalid value of Key Len %d nbytes %d IV Len %d\n", + ablkctx->enckey_len, req->nbytes, ivsize); return ERR_PTR(-EINVAL); + } phys_dsgl = get_space_for_phys_dsgl(ablkctx->dst_nents); - kctx_len = sizeof(*key_ctx) + - (DIV_ROUND_UP(ablkctx->enckey_len, 16) * 16); + kctx_len = (DIV_ROUND_UP(ablkctx->enckey_len, 16) * 16); transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, phys_dsgl); - skb = alloc_skb((transhdr_len + sizeof(struct sge_opaque_hdr)), - GFP_ATOMIC); + skb = alloc_skb((transhdr_len + sizeof(struct sge_opaque_hdr)), flags); if (!skb) return ERR_PTR(-ENOMEM); skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - wreq = (struct fw_crypto_lookaside_wr *)__skb_put(skb, transhdr_len); - - sec_cpl = (struct cpl_tx_sec_pdu *)((u8 *)wreq + SEC_CPL_OFFSET); - sec_cpl->op_ivinsrtofst = - FILL_SEC_CPL_OP_IVINSR(ctx->dev->tx_channel_id, 2, 1, 1); - - sec_cpl->pldlen = htonl(ivsize + req->nbytes); - sec_cpl->aadstart_cipherstop_hi = FILL_SEC_CPL_CIPHERSTOP_HI(0, 0, - ivsize + 1, 0); - - sec_cpl->cipherstop_lo_authinsert = FILL_SEC_CPL_AUTHINSERT(0, 0, - 0, 0); - sec_cpl->seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(op_type, 0, + chcr_req = (struct chcr_wr *)__skb_put(skb, transhdr_len); + memset(chcr_req, 0, transhdr_len); + chcr_req->sec_cpl.op_ivinsrtofst = + FILL_SEC_CPL_OP_IVINSR(ctx->dev->tx_channel_id, 2, 1); + + chcr_req->sec_cpl.pldlen = htonl(ivsize + req->nbytes); + chcr_req->sec_cpl.aadstart_cipherstop_hi = + FILL_SEC_CPL_CIPHERSTOP_HI(0, 0, ivsize + 1, 0); + + chcr_req->sec_cpl.cipherstop_lo_authinsert = + FILL_SEC_CPL_AUTHINSERT(0, 0, 0, 0); + chcr_req->sec_cpl.seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(op_type, 0, ablkctx->ciph_mode, - 0, 0, ivsize >> 1, 1); - sec_cpl->ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 0, + 0, 0, ivsize >> 1); + chcr_req->sec_cpl.ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 0, 0, 1, phys_dsgl); - key_ctx = (struct _key_ctx *)((u8 *)sec_cpl + sizeof(*sec_cpl)); - key_ctx->ctx_hdr = ablkctx->key_ctx_hdr; + chcr_req->key_ctx.ctx_hdr = ablkctx->key_ctx_hdr; if (op_type == CHCR_DECRYPT_OP) { - if (generate_copy_rrkey(ablkctx, key_ctx)) - goto map_fail1; + generate_copy_rrkey(ablkctx, &chcr_req->key_ctx); } else { if (ablkctx->ciph_mode == CHCR_SCMD_CIPHER_MODE_AES_CBC) { - memcpy(key_ctx->key, ablkctx->key, ablkctx->enckey_len); + memcpy(chcr_req->key_ctx.key, ablkctx->key, + ablkctx->enckey_len); } else { - memcpy(key_ctx->key, ablkctx->key + + memcpy(chcr_req->key_ctx.key, ablkctx->key + (ablkctx->enckey_len >> 1), ablkctx->enckey_len >> 1); - memcpy(key_ctx->key + + memcpy(chcr_req->key_ctx.key + (ablkctx->enckey_len >> 1), ablkctx->key, ablkctx->enckey_len >> 1); } } - phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)key_ctx + kctx_len); - - memcpy(ablkctx->iv, req->info, ivsize); - sg_init_table(&ablkctx->iv_sg, 1); - sg_set_buf(&ablkctx->iv_sg, ablkctx->iv, ivsize); + phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); sg_param.nents = ablkctx->dst_nents; - sg_param.obsize = dst_bufsize; + sg_param.obsize = req->nbytes; sg_param.qid = qid; sg_param.align = 1; if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, req->dst, @@ -593,9 +604,10 @@ static struct sk_buff goto map_fail1; skb_set_transport_header(skb, transhdr_len); - write_sg_data_page_desc(skb, &frags, &ablkctx->iv_sg, ivsize); - write_sg_data_page_desc(skb, &frags, req->src, req->nbytes); - create_wreq(ctx, wreq, req, skb, kctx_len, 0, phys_dsgl); + memcpy(ablkctx->iv, req->info, ivsize); + write_buffer_to_skb(skb, &frags, ablkctx->iv, ivsize); + write_sg_to_skb(skb, &frags, req->src, req->nbytes); + create_wreq(ctx, chcr_req, req, skb, kctx_len, 0, phys_dsgl); req_ctx->skb = skb; skb_get(skb); return skb; @@ -662,7 +674,6 @@ static int chcr_aes_encrypt(struct ablkcipher_request *req) { struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct chcr_context *ctx = crypto_ablkcipher_ctx(tfm); - struct crypto_async_request *req_base = &req->base; struct uld_ctx *u_ctx = ULD_CTX(ctx); struct sk_buff *skb; @@ -672,8 +683,7 @@ static int chcr_aes_encrypt(struct ablkcipher_request *req) return -EBUSY; } - skb = create_cipher_wr(req_base, ctx, - u_ctx->lldi.rxq_ids[ctx->tx_channel_id], + skb = create_cipher_wr(req, u_ctx->lldi.rxq_ids[ctx->tx_channel_id], CHCR_ENCRYPT_OP); if (IS_ERR(skb)) { pr_err("chcr : %s : Failed to form WR. No memory\n", __func__); @@ -689,7 +699,6 @@ static int chcr_aes_decrypt(struct ablkcipher_request *req) { struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); struct chcr_context *ctx = crypto_ablkcipher_ctx(tfm); - struct crypto_async_request *req_base = &req->base; struct uld_ctx *u_ctx = ULD_CTX(ctx); struct sk_buff *skb; @@ -699,7 +708,7 @@ static int chcr_aes_decrypt(struct ablkcipher_request *req) return -EBUSY; } - skb = create_cipher_wr(req_base, ctx, u_ctx->lldi.rxq_ids[0], + skb = create_cipher_wr(req, u_ctx->lldi.rxq_ids[0], CHCR_DECRYPT_OP); if (IS_ERR(skb)) { pr_err("chcr : %s : Failed to form WR. No memory\n", __func__); @@ -779,33 +788,11 @@ static int get_alg_config(struct algo_param *params, return 0; } -static inline int -write_buffer_data_page_desc(struct chcr_ahash_req_ctx *req_ctx, - struct sk_buff *skb, unsigned int *frags, char *bfr, - u8 bfr_len) -{ - void *page_ptr = NULL; - - skb->len += bfr_len; - skb->data_len += bfr_len; - skb->truesize += bfr_len; - page_ptr = kmalloc(CHCR_HASH_MAX_BLOCK_SIZE_128, GFP_ATOMIC | GFP_DMA); - if (!page_ptr) - return -ENOMEM; - get_page(virt_to_page(page_ptr)); - req_ctx->dummy_payload_ptr = page_ptr; - memcpy(page_ptr, bfr, bfr_len); - skb_fill_page_desc(skb, *frags, virt_to_page(page_ptr), - offset_in_page(page_ptr), bfr_len); - (*frags)++; - return 0; -} - /** - * create_final_hash_wr - Create hash work request + * create_hash_wr - Create hash work request * @req - Cipher req base */ -static struct sk_buff *create_final_hash_wr(struct ahash_request *req, +static struct sk_buff *create_hash_wr(struct ahash_request *req, struct hash_wr_param *param) { struct chcr_ahash_req_ctx *req_ctx = ahash_request_ctx(req); @@ -813,16 +800,16 @@ static struct sk_buff *create_final_hash_wr(struct ahash_request *req, struct chcr_context *ctx = crypto_tfm_ctx(crypto_ahash_tfm(tfm)); struct hmac_ctx *hmacctx = HMAC_CTX(ctx); struct sk_buff *skb = NULL; - struct _key_ctx *key_ctx; - struct fw_crypto_lookaside_wr *wreq; - struct cpl_tx_sec_pdu *sec_cpl; + struct chcr_wr *chcr_req; unsigned int frags = 0, transhdr_len, iopad_alignment = 0; unsigned int digestsize = crypto_ahash_digestsize(tfm); - unsigned int kctx_len = sizeof(*key_ctx); + unsigned int kctx_len = 0; u8 hash_size_in_response = 0; + gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; iopad_alignment = KEYCTX_ALIGN_PAD(digestsize); - kctx_len += param->alg_prm.result_size + iopad_alignment; + kctx_len = param->alg_prm.result_size + iopad_alignment; if (param->opad_needed) kctx_len += param->alg_prm.result_size + iopad_alignment; @@ -831,53 +818,53 @@ static struct sk_buff *create_final_hash_wr(struct ahash_request *req, else hash_size_in_response = param->alg_prm.result_size; transhdr_len = HASH_TRANSHDR_SIZE(kctx_len); - skb = alloc_skb((transhdr_len + sizeof(struct sge_opaque_hdr)), - GFP_ATOMIC); + skb = alloc_skb((transhdr_len + sizeof(struct sge_opaque_hdr)), flags); if (!skb) return skb; skb_reserve(skb, sizeof(struct sge_opaque_hdr)); - wreq = (struct fw_crypto_lookaside_wr *)__skb_put(skb, transhdr_len); - memset(wreq, 0, transhdr_len); + chcr_req = (struct chcr_wr *)__skb_put(skb, transhdr_len); + memset(chcr_req, 0, transhdr_len); - sec_cpl = (struct cpl_tx_sec_pdu *)((u8 *)wreq + SEC_CPL_OFFSET); - sec_cpl->op_ivinsrtofst = - FILL_SEC_CPL_OP_IVINSR(ctx->dev->tx_channel_id, 2, 0, 0); - sec_cpl->pldlen = htonl(param->bfr_len + param->sg_len); + chcr_req->sec_cpl.op_ivinsrtofst = + FILL_SEC_CPL_OP_IVINSR(ctx->dev->tx_channel_id, 2, 0); + chcr_req->sec_cpl.pldlen = htonl(param->bfr_len + param->sg_len); - sec_cpl->aadstart_cipherstop_hi = + chcr_req->sec_cpl.aadstart_cipherstop_hi = FILL_SEC_CPL_CIPHERSTOP_HI(0, 0, 0, 0); - sec_cpl->cipherstop_lo_authinsert = + chcr_req->sec_cpl.cipherstop_lo_authinsert = FILL_SEC_CPL_AUTHINSERT(0, 1, 0, 0); - sec_cpl->seqno_numivs = + chcr_req->sec_cpl.seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(0, 0, 0, param->alg_prm.auth_mode, - param->opad_needed, 0, 0); + param->opad_needed, 0); - sec_cpl->ivgen_hdrlen = + chcr_req->sec_cpl.ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(param->last, param->more, 0, 1, 0, 0); - key_ctx = (struct _key_ctx *)((u8 *)sec_cpl + sizeof(*sec_cpl)); - memcpy(key_ctx->key, req_ctx->partial_hash, param->alg_prm.result_size); + memcpy(chcr_req->key_ctx.key, req_ctx->partial_hash, + param->alg_prm.result_size); if (param->opad_needed) - memcpy(key_ctx->key + ((param->alg_prm.result_size <= 32) ? 32 : - CHCR_HASH_MAX_DIGEST_SIZE), + memcpy(chcr_req->key_ctx.key + + ((param->alg_prm.result_size <= 32) ? 32 : + CHCR_HASH_MAX_DIGEST_SIZE), hmacctx->opad, param->alg_prm.result_size); - key_ctx->ctx_hdr = FILL_KEY_CTX_HDR(CHCR_KEYCTX_NO_KEY, + chcr_req->key_ctx.ctx_hdr = FILL_KEY_CTX_HDR(CHCR_KEYCTX_NO_KEY, param->alg_prm.mk_size, 0, param->opad_needed, - (kctx_len >> 4)); - sec_cpl->scmd1 = cpu_to_be64((u64)param->scmd1); + ((kctx_len + + sizeof(chcr_req->key_ctx)) >> 4)); + chcr_req->sec_cpl.scmd1 = cpu_to_be64((u64)param->scmd1); skb_set_transport_header(skb, transhdr_len); if (param->bfr_len != 0) - write_buffer_data_page_desc(req_ctx, skb, &frags, req_ctx->bfr, + write_buffer_to_skb(skb, &frags, req_ctx->bfr, param->bfr_len); if (param->sg_len != 0) - write_sg_data_page_desc(skb, &frags, req->src, param->sg_len); + write_sg_to_skb(skb, &frags, req->src, param->sg_len); - create_wreq(ctx, wreq, req, skb, kctx_len, hash_size_in_response, + create_wreq(ctx, chcr_req, req, skb, kctx_len, hash_size_in_response, 0); req_ctx->skb = skb; skb_get(skb); @@ -917,15 +904,11 @@ static int chcr_ahash_update(struct ahash_request *req) params.opad_needed = 0; params.more = 1; params.last = 0; - params.sg_len = nbytes - req_ctx->bfr_len; - params.bfr_len = req_ctx->bfr_len; params.scmd1 = 0; get_alg_config(¶ms.alg_prm, crypto_ahash_digestsize(rtfm)); req_ctx->result = 0; req_ctx->data_len += params.sg_len + params.bfr_len; - skb = create_final_hash_wr(req, ¶ms); - if (!skb) - return -ENOMEM; + skb = create_hash_wr(req, ¶ms); req_ctx->bfr_len = remainder; if (remainder) @@ -981,7 +964,10 @@ static int chcr_ahash_final(struct ahash_request *req) params.last = 1; params.more = 0; } - skb = create_final_hash_wr(req, ¶ms); + skb = create_hash_wr(req, ¶ms); + if (IS_ERR(skb)) + return PTR_ERR(skb); + skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); chcr_send_wr(skb); @@ -1029,9 +1015,10 @@ static int chcr_ahash_finup(struct ahash_request *req) params.more = 0; } - skb = create_final_hash_wr(req, ¶ms); - if (!skb) - return -ENOMEM; + skb = create_hash_wr(req, ¶ms); + if (IS_ERR(skb)) + return PTR_ERR(skb); + skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); chcr_send_wr(skb); @@ -1079,9 +1066,9 @@ static int chcr_ahash_digest(struct ahash_request *req) params.bfr_len = bs; } - skb = create_final_hash_wr(req, ¶ms); - if (!skb) - return -ENOMEM; + skb = create_hash_wr(req, ¶ms); + if (IS_ERR(skb)) + return PTR_ERR(skb); skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); diff --git a/drivers/crypto/chelsio/chcr_algo.h b/drivers/crypto/chelsio/chcr_algo.h index f34bc915783a..f2a59058b204 100644 --- a/drivers/crypto/chelsio/chcr_algo.h +++ b/drivers/crypto/chelsio/chcr_algo.h @@ -108,30 +108,24 @@ #define IPAD_DATA 0x36363636 #define OPAD_DATA 0x5c5c5c5c -#define TRANSHDR_SIZE(alignedkctx_len)\ - (sizeof(struct ulptx_idata) +\ - sizeof(struct ulp_txpkt) +\ - sizeof(struct fw_crypto_lookaside_wr) +\ - sizeof(struct cpl_tx_sec_pdu) +\ - (alignedkctx_len)) -#define CIPHER_TRANSHDR_SIZE(alignedkctx_len, sge_pairs) \ - (TRANSHDR_SIZE(alignedkctx_len) + sge_pairs +\ +#define TRANSHDR_SIZE(kctx_len)\ + (sizeof(struct chcr_wr) +\ + kctx_len) +#define CIPHER_TRANSHDR_SIZE(kctx_len, sge_pairs) \ + (TRANSHDR_SIZE((kctx_len)) + (sge_pairs) +\ sizeof(struct cpl_rx_phys_dsgl)) -#define HASH_TRANSHDR_SIZE(alignedkctx_len)\ - (TRANSHDR_SIZE(alignedkctx_len) + DUMMY_BYTES) +#define HASH_TRANSHDR_SIZE(kctx_len)\ + (TRANSHDR_SIZE(kctx_len) + DUMMY_BYTES) -#define SEC_CPL_OFFSET (sizeof(struct fw_crypto_lookaside_wr) + \ - sizeof(struct ulp_txpkt) + \ - sizeof(struct ulptx_idata)) -#define FILL_SEC_CPL_OP_IVINSR(id, len, hldr, ofst) \ +#define FILL_SEC_CPL_OP_IVINSR(id, len, ofst) \ htonl( \ CPL_TX_SEC_PDU_OPCODE_V(CPL_TX_SEC_PDU) | \ CPL_TX_SEC_PDU_RXCHID_V((id)) | \ CPL_TX_SEC_PDU_ACKFOLLOWS_V(0) | \ CPL_TX_SEC_PDU_ULPTXLPBK_V(1) | \ CPL_TX_SEC_PDU_CPLLEN_V((len)) | \ - CPL_TX_SEC_PDU_PLACEHOLDER_V((hldr)) | \ + CPL_TX_SEC_PDU_PLACEHOLDER_V(0) | \ CPL_TX_SEC_PDU_IVINSRTOFST_V((ofst))) #define FILL_SEC_CPL_CIPHERSTOP_HI(a_start, a_stop, c_start, c_stop_hi) \ @@ -148,7 +142,7 @@ CPL_TX_SEC_PDU_AUTHSTOP_V((a_stop)) | \ CPL_TX_SEC_PDU_AUTHINSERT_V((a_inst))) -#define FILL_SEC_CPL_SCMD0_SEQNO(ctrl, seq, cmode, amode, opad, size, nivs) \ +#define FILL_SEC_CPL_SCMD0_SEQNO(ctrl, seq, cmode, amode, opad, size) \ htonl( \ SCMD_SEQ_NO_CTRL_V(0) | \ SCMD_STATUS_PRESENT_V(0) | \ @@ -159,7 +153,7 @@ SCMD_AUTH_MODE_V((amode)) | \ SCMD_HMAC_CTRL_V((opad)) | \ SCMD_IV_SIZE_V((size)) | \ - SCMD_NUM_IVS_V((nivs))) + SCMD_NUM_IVS_V(0)) #define FILL_SEC_CPL_IVGEN_HDRLEN(last, more, ctx_in, mac, ivdrop, len) htonl( \ SCMD_ENB_DBGID_V(0) | \ diff --git a/drivers/crypto/chelsio/chcr_core.h b/drivers/crypto/chelsio/chcr_core.h index 2a5c671a4232..fc3cd77ad6d1 100644 --- a/drivers/crypto/chelsio/chcr_core.h +++ b/drivers/crypto/chelsio/chcr_core.h @@ -52,9 +52,25 @@ #define MAC_ERROR_BIT 0 #define CHK_MAC_ERR_BIT(x) (((x) >> MAC_ERROR_BIT) & 1) +#define MAX_SALT 4 struct uld_ctx; +struct _key_ctx { + __be32 ctx_hdr; + u8 salt[MAX_SALT]; + __be64 reserverd; + unsigned char key[0]; +}; + +struct chcr_wr { + struct fw_crypto_lookaside_wr wreq; + struct ulp_txpkt ulptx; + struct ulptx_idata sc_imm; + struct cpl_tx_sec_pdu sec_cpl; + struct _key_ctx key_ctx; +}; + struct chcr_dev { /* Request submited to h/w and waiting for response. */ spinlock_t lock_chcr_dev; diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index d7d75605da8b..acce36702e1f 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -118,12 +118,6 @@ #define CHCR_HASH_MAX_BLOCK_SIZE_128 128 /* Aligned to 128 bit boundary */ -struct _key_ctx { - __be32 ctx_hdr; - u8 salt[MAX_SALT]; - __be64 reserverd; - unsigned char key[0]; -}; struct ablk_ctx { u8 enc; -- cgit v1.2.3 From 18f0aa06a3c90b249e8b3a423e67dbfb0c784688 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:37 +0530 Subject: crypto: chcr - Fixes Unchecked dereference inside function Fixes 324429d74127, Unchecked dereference inside function. Reported-by: Dan Carpenter Signed-off-by: Jitendra Lulla Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index d24b7ce79142..0ae1b09c58ef 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -439,8 +439,9 @@ write_sg_to_skb(struct sk_buff *skb, unsigned int *frags, skb->len += count; skb->data_len += count; skb->truesize += count; + while (count > 0) { - if (sg && (!(sg->length))) + if (!sg || (!(sg->length))) break; spage = sg_page(sg); get_page(spage); -- cgit v1.2.3 From 44fce12a3464c35b5c6a36b6db379745ff502b82 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:38 +0530 Subject: crypto: chcr - Remove dynamic allocation Remove malloc/free in hash operation and allocate memory in chcr_ahash_req_ctx structure. Signed-off-by: Jitendra Lulla Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 69 +++++++++++++++++++++--------------- drivers/crypto/chelsio/chcr_crypto.h | 8 +++-- 2 files changed, 45 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 0ae1b09c58ef..13aaca2b6e95 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -150,8 +150,6 @@ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, sizeof(struct cpl_fw6_pld), updated_digestsize); } - kfree(ctx_req.ctx.ahash_ctx->dummy_payload_ptr); - ctx_req.ctx.ahash_ctx->dummy_payload_ptr = NULL; break; } return 0; @@ -860,8 +858,8 @@ static struct sk_buff *create_hash_wr(struct ahash_request *req, skb_set_transport_header(skb, transhdr_len); if (param->bfr_len != 0) - write_buffer_to_skb(skb, &frags, req_ctx->bfr, - param->bfr_len); + write_buffer_to_skb(skb, &frags, req_ctx->reqbfr, + param->bfr_len); if (param->sg_len != 0) write_sg_to_skb(skb, &frags, req->src, param->sg_len); @@ -892,30 +890,41 @@ static int chcr_ahash_update(struct ahash_request *req) return -EBUSY; } - if (nbytes + req_ctx->bfr_len >= bs) { - remainder = (nbytes + req_ctx->bfr_len) % bs; - nbytes = nbytes + req_ctx->bfr_len - remainder; + if (nbytes + req_ctx->reqlen >= bs) { + remainder = (nbytes + req_ctx->reqlen) % bs; + nbytes = nbytes + req_ctx->reqlen - remainder; } else { - sg_pcopy_to_buffer(req->src, sg_nents(req->src), req_ctx->bfr + - req_ctx->bfr_len, nbytes, 0); - req_ctx->bfr_len += nbytes; + sg_pcopy_to_buffer(req->src, sg_nents(req->src), req_ctx->reqbfr + + req_ctx->reqlen, nbytes, 0); + req_ctx->reqlen += nbytes; return 0; } params.opad_needed = 0; params.more = 1; params.last = 0; + params.sg_len = nbytes - req_ctx->reqlen; + params.bfr_len = req_ctx->reqlen; params.scmd1 = 0; get_alg_config(¶ms.alg_prm, crypto_ahash_digestsize(rtfm)); req_ctx->result = 0; req_ctx->data_len += params.sg_len + params.bfr_len; skb = create_hash_wr(req, ¶ms); - req_ctx->bfr_len = remainder; - if (remainder) + if (IS_ERR(skb)) + return PTR_ERR(skb); + + if (remainder) { + u8 *temp; + /* Swap buffers */ + temp = req_ctx->reqbfr; + req_ctx->reqbfr = req_ctx->skbfr; + req_ctx->skbfr = temp; sg_pcopy_to_buffer(req->src, sg_nents(req->src), - req_ctx->bfr, remainder, req->nbytes - + req_ctx->reqbfr, remainder, req->nbytes - remainder); + } + req_ctx->reqlen = remainder; skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); chcr_send_wr(skb); @@ -951,10 +960,10 @@ static int chcr_ahash_final(struct ahash_request *req) params.sg_len = 0; get_alg_config(¶ms.alg_prm, crypto_ahash_digestsize(rtfm)); req_ctx->result = 1; - params.bfr_len = req_ctx->bfr_len; + params.bfr_len = req_ctx->reqlen; req_ctx->data_len += params.bfr_len + params.sg_len; - if (req_ctx->bfr && (req_ctx->bfr_len == 0)) { - create_last_hash_block(req_ctx->bfr, bs, req_ctx->data_len); + if (req_ctx->reqlen == 0) { + create_last_hash_block(req_ctx->reqbfr, bs, req_ctx->data_len); params.last = 0; params.more = 1; params.scmd1 = 0; @@ -1000,12 +1009,12 @@ static int chcr_ahash_finup(struct ahash_request *req) params.opad_needed = 0; params.sg_len = req->nbytes; - params.bfr_len = req_ctx->bfr_len; + params.bfr_len = req_ctx->reqlen; get_alg_config(¶ms.alg_prm, crypto_ahash_digestsize(rtfm)); req_ctx->data_len += params.bfr_len + params.sg_len; req_ctx->result = 1; - if (req_ctx->bfr && (req_ctx->bfr_len + req->nbytes) == 0) { - create_last_hash_block(req_ctx->bfr, bs, req_ctx->data_len); + if ((req_ctx->reqlen + req->nbytes) == 0) { + create_last_hash_block(req_ctx->reqbfr, bs, req_ctx->data_len); params.last = 0; params.more = 1; params.scmd1 = 0; @@ -1061,8 +1070,8 @@ static int chcr_ahash_digest(struct ahash_request *req) req_ctx->result = 1; req_ctx->data_len += params.bfr_len + params.sg_len; - if (req_ctx->bfr && req->nbytes == 0) { - create_last_hash_block(req_ctx->bfr, bs, 0); + if (req->nbytes == 0) { + create_last_hash_block(req_ctx->reqbfr, bs, 0); params.more = 1; params.bfr_len = bs; } @@ -1082,12 +1091,12 @@ static int chcr_ahash_export(struct ahash_request *areq, void *out) struct chcr_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); struct chcr_ahash_req_ctx *state = out; - state->bfr_len = req_ctx->bfr_len; + state->reqlen = req_ctx->reqlen; state->data_len = req_ctx->data_len; - memcpy(state->bfr, req_ctx->bfr, CHCR_HASH_MAX_BLOCK_SIZE_128); + memcpy(state->bfr1, req_ctx->reqbfr, req_ctx->reqlen); memcpy(state->partial_hash, req_ctx->partial_hash, CHCR_HASH_MAX_DIGEST_SIZE); - return 0; + return 0; } static int chcr_ahash_import(struct ahash_request *areq, const void *in) @@ -1095,10 +1104,11 @@ static int chcr_ahash_import(struct ahash_request *areq, const void *in) struct chcr_ahash_req_ctx *req_ctx = ahash_request_ctx(areq); struct chcr_ahash_req_ctx *state = (struct chcr_ahash_req_ctx *)in; - req_ctx->bfr_len = state->bfr_len; + req_ctx->reqlen = state->reqlen; req_ctx->data_len = state->data_len; - req_ctx->dummy_payload_ptr = NULL; - memcpy(req_ctx->bfr, state->bfr, CHCR_HASH_MAX_BLOCK_SIZE_128); + req_ctx->reqbfr = req_ctx->bfr1; + req_ctx->skbfr = req_ctx->bfr2; + memcpy(req_ctx->bfr1, state->bfr1, CHCR_HASH_MAX_BLOCK_SIZE_128); memcpy(req_ctx->partial_hash, state->partial_hash, CHCR_HASH_MAX_DIGEST_SIZE); return 0; @@ -1193,8 +1203,9 @@ static int chcr_sha_init(struct ahash_request *areq) int digestsize = crypto_ahash_digestsize(tfm); req_ctx->data_len = 0; - req_ctx->dummy_payload_ptr = NULL; - req_ctx->bfr_len = 0; + req_ctx->reqlen = 0; + req_ctx->reqbfr = req_ctx->bfr1; + req_ctx->skbfr = req_ctx->bfr2; req_ctx->skb = NULL; req_ctx->result = 0; copy_hash_init_values(req_ctx->partial_hash, digestsize); diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index acce36702e1f..8934ea2fe56b 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -150,12 +150,14 @@ struct chcr_context { struct chcr_ahash_req_ctx { u32 result; - char bfr[CHCR_HASH_MAX_BLOCK_SIZE_128]; - u8 bfr_len; + u8 bfr1[CHCR_HASH_MAX_BLOCK_SIZE_128]; + u8 bfr2[CHCR_HASH_MAX_BLOCK_SIZE_128]; + u8 *reqbfr; + u8 *skbfr; + u8 reqlen; /* DMA the partial hash in it */ u8 partial_hash[CHCR_HASH_MAX_DIGEST_SIZE]; u64 data_len; /* Data len till time */ - void *dummy_payload_ptr; /* SKB which is being sent to the hardware for processing */ struct sk_buff *skb; }; -- cgit v1.2.3 From cc1b156df510f43d890d78cb3a92b3a616ecf691 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:39 +0530 Subject: crypto: chcr - Calculate Reverse round key in setkey callback. Move reverse round key calculation logic in setkey operation. Signed-off-by: Harsh Jain Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 52 ++++++++++++++++-------------------- drivers/crypto/chelsio/chcr_crypto.h | 2 +- 2 files changed, 24 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 13aaca2b6e95..3cf009315dbf 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -455,16 +455,13 @@ static int generate_copy_rrkey(struct ablk_ctx *ablkctx, struct _key_ctx *key_ctx) { if (ablkctx->ciph_mode == CHCR_SCMD_CIPHER_MODE_AES_CBC) { - get_aes_decrypt_key(key_ctx->key, ablkctx->key, - ablkctx->enckey_len << 3); - memset(key_ctx->key + ablkctx->enckey_len, 0, - CHCR_AES_MAX_KEY_LEN - ablkctx->enckey_len); + memcpy(key_ctx->key, ablkctx->rrkey, ablkctx->enckey_len); } else { memcpy(key_ctx->key, ablkctx->key + (ablkctx->enckey_len >> 1), ablkctx->enckey_len >> 1); - get_aes_decrypt_key(key_ctx->key + (ablkctx->enckey_len >> 1), - ablkctx->key, ablkctx->enckey_len << 2); + memcpy(key_ctx->key + (ablkctx->enckey_len >> 1), + ablkctx->rrkey, ablkctx->enckey_len >> 1); } return 0; } @@ -620,15 +617,9 @@ static int chcr_aes_cbc_setkey(struct crypto_ablkcipher *tfm, const u8 *key, { struct chcr_context *ctx = crypto_ablkcipher_ctx(tfm); struct ablk_ctx *ablkctx = ABLK_CTX(ctx); - struct ablkcipher_alg *alg = crypto_ablkcipher_alg(tfm); unsigned int ck_size, context_size; u16 alignment = 0; - if ((keylen < alg->min_keysize) || (keylen > alg->max_keysize)) - goto badkey_err; - - memcpy(ablkctx->key, key, keylen); - ablkctx->enckey_len = keylen; if (keylen == AES_KEYSIZE_128) { ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; } else if (keylen == AES_KEYSIZE_192) { @@ -639,7 +630,9 @@ static int chcr_aes_cbc_setkey(struct crypto_ablkcipher *tfm, const u8 *key, } else { goto badkey_err; } - + memcpy(ablkctx->key, key, keylen); + ablkctx->enckey_len = keylen; + get_aes_decrypt_key(ablkctx->rrkey, ablkctx->key, keylen << 3); context_size = (KEY_CONTEXT_HDR_SALT_AND_PAD + keylen + alignment) >> 4; @@ -1172,28 +1165,29 @@ static int chcr_aes_xts_setkey(struct crypto_ablkcipher *tfm, const u8 *key, { struct chcr_context *ctx = crypto_ablkcipher_ctx(tfm); struct ablk_ctx *ablkctx = ABLK_CTX(ctx); - int status = 0; unsigned short context_size = 0; - if ((key_len == (AES_KEYSIZE_128 << 1)) || - (key_len == (AES_KEYSIZE_256 << 1))) { - memcpy(ablkctx->key, key, key_len); - ablkctx->enckey_len = key_len; - context_size = (KEY_CONTEXT_HDR_SALT_AND_PAD + key_len) >> 4; - ablkctx->key_ctx_hdr = - FILL_KEY_CTX_HDR((key_len == AES_KEYSIZE_256) ? - CHCR_KEYCTX_CIPHER_KEY_SIZE_128 : - CHCR_KEYCTX_CIPHER_KEY_SIZE_256, - CHCR_KEYCTX_NO_KEY, 1, - 0, context_size); - ablkctx->ciph_mode = CHCR_SCMD_CIPHER_MODE_AES_XTS; - } else { + if ((key_len != (AES_KEYSIZE_128 << 1)) && + (key_len != (AES_KEYSIZE_256 << 1))) { crypto_tfm_set_flags((struct crypto_tfm *)tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); ablkctx->enckey_len = 0; - status = -EINVAL; + return -EINVAL; + } - return status; + + memcpy(ablkctx->key, key, key_len); + ablkctx->enckey_len = key_len; + get_aes_decrypt_key(ablkctx->rrkey, ablkctx->key, key_len << 2); + context_size = (KEY_CONTEXT_HDR_SALT_AND_PAD + key_len) >> 4; + ablkctx->key_ctx_hdr = + FILL_KEY_CTX_HDR((key_len == AES_KEYSIZE_256) ? + CHCR_KEYCTX_CIPHER_KEY_SIZE_128 : + CHCR_KEYCTX_CIPHER_KEY_SIZE_256, + CHCR_KEYCTX_NO_KEY, 1, + 0, context_size); + ablkctx->ciph_mode = CHCR_SCMD_CIPHER_MODE_AES_XTS; + return 0; } static int chcr_sha_init(struct ahash_request *areq) diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 8934ea2fe56b..7ed6d2b72320 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -125,8 +125,8 @@ struct ablk_ctx { __be32 key_ctx_hdr; unsigned int enckey_len; unsigned int dst_nents; - struct scatterlist iv_sg; u8 key[CHCR_AES_MAX_KEY_LEN]; + u8 rrkey[AES_MAX_KEY_SIZE]; u8 iv[CHCR_MAX_CRYPTO_IV_LEN]; unsigned char ciph_mode; }; -- cgit v1.2.3 From adf1ca6182a642866b4dc3019ef539ddcda3bad4 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:40 +0530 Subject: crypto: chcr - Adjust Dest. buffer size Destination buffer size passed to hardware should not be greater than crypto operation output. Signed-off-by: Harsh Jain Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 50 +++++++++++++++----------------------- 1 file changed, 20 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 3cf009315dbf..64cab64dfab2 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -335,25 +335,13 @@ static inline int is_hmac(struct crypto_tfm *tfm) return 0; } -static inline unsigned int ch_nents(struct scatterlist *sg, - unsigned int *total_size) -{ - unsigned int nents; - - for (nents = 0, *total_size = 0; sg; sg = sg_next(sg)) { - nents++; - *total_size += sg->length; - } - return nents; -} - static void write_phys_cpl(struct cpl_rx_phys_dsgl *phys_cpl, struct scatterlist *sg, struct phys_sge_parm *sg_param) { struct phys_sge_pairs *to; - unsigned int out_buf_size = sg_param->obsize; - unsigned int nents = sg_param->nents, i, j, tot_len = 0; + int out_buf_size = sg_param->obsize; + unsigned int nents = sg_param->nents, i, j = 0; phys_cpl->op_to_tid = htonl(CPL_RX_PHYS_DSGL_OPCODE_V(CPL_RX_PHYS_DSGL) | CPL_RX_PHYS_DSGL_ISRDMA_V(0)); @@ -371,25 +359,24 @@ static void write_phys_cpl(struct cpl_rx_phys_dsgl *phys_cpl, sizeof(struct cpl_rx_phys_dsgl)); for (i = 0; nents; to++) { - for (j = i; (nents && (j < (8 + i))); j++, nents--) { - to->len[j] = htons(sg->length); + for (j = 0; j < 8 && nents; j++, nents--) { + out_buf_size -= sg_dma_len(sg); + to->len[j] = htons(sg_dma_len(sg)); to->addr[j] = cpu_to_be64(sg_dma_address(sg)); - if (out_buf_size) { - if (tot_len + sg_dma_len(sg) >= out_buf_size) { - to->len[j] = htons(out_buf_size - - tot_len); - return; - } - tot_len += sg_dma_len(sg); - } sg = sg_next(sg); } } + if (out_buf_size) { + j--; + to--; + to->len[j] = htons(ntohs(to->len[j]) + (out_buf_size)); + } } -static inline unsigned -int map_writesg_phys_cpl(struct device *dev, struct cpl_rx_phys_dsgl *phys_cpl, - struct scatterlist *sg, struct phys_sge_parm *sg_param) +static inline int map_writesg_phys_cpl(struct device *dev, + struct cpl_rx_phys_dsgl *phys_cpl, + struct scatterlist *sg, + struct phys_sge_parm *sg_param) { if (!sg || !sg_param->nents) return 0; @@ -531,16 +518,19 @@ static struct sk_buff struct cpl_rx_phys_dsgl *phys_cpl; struct chcr_blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); struct phys_sge_parm sg_param; - unsigned int frags = 0, transhdr_len, phys_dsgl, dst_bufsize = 0; + unsigned int frags = 0, transhdr_len, phys_dsgl; unsigned int ivsize = crypto_ablkcipher_ivsize(tfm), kctx_len; gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : GFP_ATOMIC; if (!req->info) return ERR_PTR(-EINVAL); - ablkctx->dst_nents = ch_nents(req->dst, &dst_bufsize); + ablkctx->dst_nents = sg_nents_for_len(req->dst, req->nbytes); + if (ablkctx->dst_nents <= 0) { + pr_err("AES:Invalid Destination sg lists\n"); + return ERR_PTR(-EINVAL); + } ablkctx->enc = op_type; - if ((ablkctx->enckey_len == 0) || (ivsize > AES_BLOCK_SIZE) || (req->nbytes <= 0) || (req->nbytes % AES_BLOCK_SIZE)) { pr_err("AES: Invalid value of Key Len %d nbytes %d IV Len %d\n", -- cgit v1.2.3 From e7922729bef4474c5817fa2184154a1698757d48 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:41 +0530 Subject: crypto: chcr - Use SHASH_DESC_ON_STACK Use SHASH_DESC_ON_STACK macro to allocate memory for ipad/opad calculation. Signed-off-by: Harsh Jain Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 63 +++++++++++++++--------------------- drivers/crypto/chelsio/chcr_crypto.h | 2 +- 2 files changed, 27 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 64cab64dfab2..e19f7f40bd75 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -228,40 +228,29 @@ static inline void get_aes_decrypt_key(unsigned char *dec_key, } } -static struct shash_desc *chcr_alloc_shash(unsigned int ds) +static struct crypto_shash *chcr_alloc_shash(unsigned int ds) { struct crypto_shash *base_hash = NULL; - struct shash_desc *desc; switch (ds) { case SHA1_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha1-generic", 0, 0); + base_hash = crypto_alloc_shash("sha1", 0, 0); break; case SHA224_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha224-generic", 0, 0); + base_hash = crypto_alloc_shash("sha224", 0, 0); break; case SHA256_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha256-generic", 0, 0); + base_hash = crypto_alloc_shash("sha256", 0, 0); break; case SHA384_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha384-generic", 0, 0); + base_hash = crypto_alloc_shash("sha384", 0, 0); break; case SHA512_DIGEST_SIZE: - base_hash = crypto_alloc_shash("sha512-generic", 0, 0); + base_hash = crypto_alloc_shash("sha512", 0, 0); break; } - if (IS_ERR(base_hash)) { - pr_err("Can not allocate sha-generic algo.\n"); - return (void *)base_hash; - } - desc = kmalloc(sizeof(*desc) + crypto_shash_descsize(base_hash), - GFP_KERNEL); - if (!desc) - return ERR_PTR(-ENOMEM); - desc->tfm = base_hash; - desc->flags = crypto_shash_get_flags(base_hash); - return desc; + return base_hash; } static int chcr_compute_partial_hash(struct shash_desc *desc, @@ -770,6 +759,11 @@ static int get_alg_config(struct algo_param *params, return 0; } +static inline void chcr_free_shash(struct crypto_shash *base_hash) +{ + crypto_free_shash(base_hash); +} + /** * create_hash_wr - Create hash work request * @req - Cipher req base @@ -1106,15 +1100,16 @@ static int chcr_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, unsigned int bs = crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); unsigned int i, err = 0, updated_digestsize; - /* - * use the key to calculate the ipad and opad. ipad will sent with the + SHASH_DESC_ON_STACK(shash, hmacctx->base_hash); + + /* use the key to calculate the ipad and opad. ipad will sent with the * first request's data. opad will be sent with the final hash result * ipad in hmacctx->ipad and opad in hmacctx->opad location */ - if (!hmacctx->desc) - return -EINVAL; + shash->tfm = hmacctx->base_hash; + shash->flags = crypto_shash_get_flags(hmacctx->base_hash); if (keylen > bs) { - err = crypto_shash_digest(hmacctx->desc, key, keylen, + err = crypto_shash_digest(shash, key, keylen, hmacctx->ipad); if (err) goto out; @@ -1135,13 +1130,13 @@ static int chcr_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, updated_digestsize = SHA256_DIGEST_SIZE; else if (digestsize == SHA384_DIGEST_SIZE) updated_digestsize = SHA512_DIGEST_SIZE; - err = chcr_compute_partial_hash(hmacctx->desc, hmacctx->ipad, + err = chcr_compute_partial_hash(shash, hmacctx->ipad, hmacctx->ipad, digestsize); if (err) goto out; chcr_change_order(hmacctx->ipad, updated_digestsize); - err = chcr_compute_partial_hash(hmacctx->desc, hmacctx->opad, + err = chcr_compute_partial_hash(shash, hmacctx->opad, hmacctx->opad, digestsize); if (err) goto out; @@ -1237,26 +1232,20 @@ static int chcr_hmac_cra_init(struct crypto_tfm *tfm) crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm), sizeof(struct chcr_ahash_req_ctx)); - hmacctx->desc = chcr_alloc_shash(digestsize); - if (IS_ERR(hmacctx->desc)) - return PTR_ERR(hmacctx->desc); + hmacctx->base_hash = chcr_alloc_shash(digestsize); + if (IS_ERR(hmacctx->base_hash)) + return PTR_ERR(hmacctx->base_hash); return chcr_device_init(crypto_tfm_ctx(tfm)); } -static void chcr_free_shash(struct shash_desc *desc) -{ - crypto_free_shash(desc->tfm); - kfree(desc); -} - static void chcr_hmac_cra_exit(struct crypto_tfm *tfm) { struct chcr_context *ctx = crypto_tfm_ctx(tfm); struct hmac_ctx *hmacctx = HMAC_CTX(ctx); - if (hmacctx->desc) { - chcr_free_shash(hmacctx->desc); - hmacctx->desc = NULL; + if (hmacctx->base_hash) { + chcr_free_shash(hmacctx->base_hash); + hmacctx->base_hash = NULL; } } diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 7ed6d2b72320..977d20520f53 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -132,7 +132,7 @@ struct ablk_ctx { }; struct hmac_ctx { - struct shash_desc *desc; + struct crypto_shash *base_hash; u8 ipad[CHCR_HASH_MAX_BLOCK_SIZE_128]; u8 opad[CHCR_HASH_MAX_BLOCK_SIZE_128]; }; -- cgit v1.2.3 From 5c86a8ff2e0deba95324cc59e6b90c28da8af535 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:42 +0530 Subject: crypto: chcr - Move tfm ctx variable to request context Move request specific data in request context. Signed-off-by: Harsh Jain Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 26 +++++++++++++------------- drivers/crypto/chelsio/chcr_crypto.h | 9 ++++----- 2 files changed, 17 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index e19f7f40bd75..8d677c7e3d61 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -119,7 +119,7 @@ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, AES_BLOCK_SIZE); } dma_unmap_sg(&u_ctx->lldi.pdev->dev, ctx_req.req.ablk_req->dst, - ABLK_CTX(ctx)->dst_nents, DMA_FROM_DEVICE); + ctx_req.ctx.ablk_ctx->dst_nents, DMA_FROM_DEVICE); if (ctx_req.ctx.ablk_ctx->skb) { kfree_skb(ctx_req.ctx.ablk_ctx->skb); ctx_req.ctx.ablk_ctx->skb = NULL; @@ -138,8 +138,10 @@ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, updated_digestsize = SHA256_DIGEST_SIZE; else if (digestsize == SHA384_DIGEST_SIZE) updated_digestsize = SHA512_DIGEST_SIZE; - if (ctx_req.ctx.ahash_ctx->skb) + if (ctx_req.ctx.ahash_ctx->skb) { + kfree_skb(ctx_req.ctx.ahash_ctx->skb); ctx_req.ctx.ahash_ctx->skb = NULL; + } if (ctx_req.ctx.ahash_ctx->result == 1) { ctx_req.ctx.ahash_ctx->result = 0; memcpy(ctx_req.req.ahash_req->result, input + @@ -318,8 +320,7 @@ static inline int is_hmac(struct crypto_tfm *tfm) struct chcr_alg_template *chcr_crypto_alg = container_of(__crypto_ahash_alg(alg), struct chcr_alg_template, alg.hash); - if ((chcr_crypto_alg->type & CRYPTO_ALG_SUB_TYPE_MASK) == - CRYPTO_ALG_SUB_TYPE_HASH_HMAC) + if (chcr_crypto_alg->type == CRYPTO_ALG_TYPE_HMAC) return 1; return 0; } @@ -505,7 +506,7 @@ static struct sk_buff struct sk_buff *skb = NULL; struct chcr_wr *chcr_req; struct cpl_rx_phys_dsgl *phys_cpl; - struct chcr_blkcipher_req_ctx *req_ctx = ablkcipher_request_ctx(req); + struct chcr_blkcipher_req_ctx *reqctx = ablkcipher_request_ctx(req); struct phys_sge_parm sg_param; unsigned int frags = 0, transhdr_len, phys_dsgl; unsigned int ivsize = crypto_ablkcipher_ivsize(tfm), kctx_len; @@ -514,12 +515,11 @@ static struct sk_buff if (!req->info) return ERR_PTR(-EINVAL); - ablkctx->dst_nents = sg_nents_for_len(req->dst, req->nbytes); - if (ablkctx->dst_nents <= 0) { + reqctx->dst_nents = sg_nents_for_len(req->dst, req->nbytes); + if (reqctx->dst_nents <= 0) { pr_err("AES:Invalid Destination sg lists\n"); return ERR_PTR(-EINVAL); } - ablkctx->enc = op_type; if ((ablkctx->enckey_len == 0) || (ivsize > AES_BLOCK_SIZE) || (req->nbytes <= 0) || (req->nbytes % AES_BLOCK_SIZE)) { pr_err("AES: Invalid value of Key Len %d nbytes %d IV Len %d\n", @@ -527,7 +527,7 @@ static struct sk_buff return ERR_PTR(-EINVAL); } - phys_dsgl = get_space_for_phys_dsgl(ablkctx->dst_nents); + phys_dsgl = get_space_for_phys_dsgl(reqctx->dst_nents); kctx_len = (DIV_ROUND_UP(ablkctx->enckey_len, 16) * 16); transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, phys_dsgl); @@ -570,7 +570,7 @@ static struct sk_buff } } phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); - sg_param.nents = ablkctx->dst_nents; + sg_param.nents = reqctx->dst_nents; sg_param.obsize = req->nbytes; sg_param.qid = qid; sg_param.align = 1; @@ -579,11 +579,11 @@ static struct sk_buff goto map_fail1; skb_set_transport_header(skb, transhdr_len); - memcpy(ablkctx->iv, req->info, ivsize); - write_buffer_to_skb(skb, &frags, ablkctx->iv, ivsize); + memcpy(reqctx->iv, req->info, ivsize); + write_buffer_to_skb(skb, &frags, reqctx->iv, ivsize); write_sg_to_skb(skb, &frags, req->src, req->nbytes); create_wreq(ctx, chcr_req, req, skb, kctx_len, 0, phys_dsgl); - req_ctx->skb = skb; + reqctx->skb = skb; skb_get(skb); return skb; map_fail1: diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 977d20520f53..40a5182fac90 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -120,17 +120,14 @@ /* Aligned to 128 bit boundary */ struct ablk_ctx { - u8 enc; - unsigned int processed_len; __be32 key_ctx_hdr; unsigned int enckey_len; - unsigned int dst_nents; u8 key[CHCR_AES_MAX_KEY_LEN]; - u8 rrkey[AES_MAX_KEY_SIZE]; - u8 iv[CHCR_MAX_CRYPTO_IV_LEN]; unsigned char ciph_mode; + u8 rrkey[AES_MAX_KEY_SIZE]; }; + struct hmac_ctx { struct crypto_shash *base_hash; u8 ipad[CHCR_HASH_MAX_BLOCK_SIZE_128]; @@ -164,6 +161,8 @@ struct chcr_ahash_req_ctx { struct chcr_blkcipher_req_ctx { struct sk_buff *skb; + unsigned int dst_nents; + u8 iv[CHCR_MAX_CRYPTO_IV_LEN]; }; struct chcr_alg_template { -- cgit v1.2.3 From 2debd3325e55d448cae83b7f262e645db1697d25 Mon Sep 17 00:00:00 2001 From: Harsh Jain Date: Tue, 29 Nov 2016 19:00:43 +0530 Subject: crypto: chcr - Add AEAD algos. Add support for following AEAD algos. GCM,CCM,RFC4106,RFC4309,authenc(hmac(shaXXX),cbc(aes)). Reviewed-by: Stephan Mueller Signed-off-by: Harsh Jain Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/Kconfig | 1 + drivers/crypto/chelsio/chcr_algo.c | 1482 +++++++++++++++++++++++++++++++++- drivers/crypto/chelsio/chcr_algo.h | 16 +- drivers/crypto/chelsio/chcr_core.c | 8 +- drivers/crypto/chelsio/chcr_core.h | 2 - drivers/crypto/chelsio/chcr_crypto.h | 90 ++- 6 files changed, 1558 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/Kconfig b/drivers/crypto/chelsio/Kconfig index 4ce67fb9a880..3e104f5aa0c2 100644 --- a/drivers/crypto/chelsio/Kconfig +++ b/drivers/crypto/chelsio/Kconfig @@ -4,6 +4,7 @@ config CRYPTO_DEV_CHELSIO select CRYPTO_SHA1 select CRYPTO_SHA256 select CRYPTO_SHA512 + select CRYPTO_AUTHENC ---help--- The Chelsio Crypto Co-processor driver for T6 adapters. diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index 8d677c7e3d61..e73b9809591d 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -54,6 +54,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include "t4fw_api.h" @@ -62,6 +68,11 @@ #include "chcr_algo.h" #include "chcr_crypto.h" +static inline struct chcr_aead_ctx *AEAD_CTX(struct chcr_context *ctx) +{ + return ctx->crypto_ctx->aeadctx; +} + static inline struct ablk_ctx *ABLK_CTX(struct chcr_context *ctx) { return ctx->crypto_ctx->ablkctx; @@ -72,6 +83,16 @@ static inline struct hmac_ctx *HMAC_CTX(struct chcr_context *ctx) return ctx->crypto_ctx->hmacctx; } +static inline struct chcr_gcm_ctx *GCM_CTX(struct chcr_aead_ctx *gctx) +{ + return gctx->ctx->gcm; +} + +static inline struct chcr_authenc_ctx *AUTHENC_CTX(struct chcr_aead_ctx *gctx) +{ + return gctx->ctx->authenc; +} + static inline struct uld_ctx *ULD_CTX(struct chcr_context *ctx) { return ctx->dev->u_ctx; @@ -94,12 +115,37 @@ static inline unsigned int sgl_len(unsigned int n) return (3 * n) / 2 + (n & 1) + 2; } +static void chcr_verify_tag(struct aead_request *req, u8 *input, int *err) +{ + u8 temp[SHA512_DIGEST_SIZE]; + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + int authsize = crypto_aead_authsize(tfm); + struct cpl_fw6_pld *fw6_pld; + int cmp = 0; + + fw6_pld = (struct cpl_fw6_pld *)input; + if ((get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) || + (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_GCM)) { + cmp = memcmp(&fw6_pld->data[2], (fw6_pld + 1), authsize); + } else { + + sg_pcopy_to_buffer(req->src, sg_nents(req->src), temp, + authsize, req->assoclen + + req->cryptlen - authsize); + cmp = memcmp(temp, (fw6_pld + 1), authsize); + } + if (cmp) + *err = -EBADMSG; + else + *err = 0; +} + /* * chcr_handle_resp - Unmap the DMA buffers associated with the request * @req: crypto request */ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, - int error_status) + int err) { struct crypto_tfm *tfm = req->tfm; struct chcr_context *ctx = crypto_tfm_ctx(tfm); @@ -109,11 +155,27 @@ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, unsigned int digestsize, updated_digestsize; switch (tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { + case CRYPTO_ALG_TYPE_AEAD: + ctx_req.req.aead_req = (struct aead_request *)req; + ctx_req.ctx.reqctx = aead_request_ctx(ctx_req.req.aead_req); + dma_unmap_sg(&u_ctx->lldi.pdev->dev, ctx_req.req.aead_req->dst, + ctx_req.ctx.reqctx->dst_nents, DMA_FROM_DEVICE); + if (ctx_req.ctx.reqctx->skb) { + kfree_skb(ctx_req.ctx.reqctx->skb); + ctx_req.ctx.reqctx->skb = NULL; + } + if (ctx_req.ctx.reqctx->verify == VERIFY_SW) { + chcr_verify_tag(ctx_req.req.aead_req, input, + &err); + ctx_req.ctx.reqctx->verify = VERIFY_HW; + } + break; + case CRYPTO_ALG_TYPE_BLKCIPHER: ctx_req.req.ablk_req = (struct ablkcipher_request *)req; ctx_req.ctx.ablk_ctx = ablkcipher_request_ctx(ctx_req.req.ablk_req); - if (!error_status) { + if (!err) { fw6_pld = (struct cpl_fw6_pld *)input; memcpy(ctx_req.req.ablk_req->info, &fw6_pld->data[2], AES_BLOCK_SIZE); @@ -154,7 +216,7 @@ int chcr_handle_resp(struct crypto_async_request *req, unsigned char *input, } break; } - return 0; + return err; } /* @@ -380,6 +442,14 @@ static inline int map_writesg_phys_cpl(struct device *dev, return 0; } +static inline int get_aead_subtype(struct crypto_aead *aead) +{ + struct aead_alg *alg = crypto_aead_alg(aead); + struct chcr_alg_template *chcr_crypto_alg = + container_of(alg, struct chcr_alg_template, alg.aead); + return chcr_crypto_alg->type & CRYPTO_ALG_SUB_TYPE_MASK; +} + static inline int get_cryptoalg_subtype(struct crypto_tfm *tfm) { struct crypto_alg *alg = tfm->__crt_alg; @@ -447,7 +517,8 @@ static inline void create_wreq(struct chcr_context *ctx, struct chcr_wr *chcr_req, void *req, struct sk_buff *skb, int kctx_len, int hash_sz, - unsigned int phys_dsgl) + int is_iv, + unsigned int sc_len) { struct uld_ctx *u_ctx = ULD_CTX(ctx); int iv_loc = IV_DSGL; @@ -472,7 +543,7 @@ static inline void create_wreq(struct chcr_context *ctx, chcr_req->wreq.cookie = cpu_to_be64((uintptr_t)req); chcr_req->wreq.rx_chid_to_rx_q_id = FILL_WR_RX_Q_ID(ctx->dev->tx_channel_id, qid, - (hash_sz) ? IV_NOP : iv_loc); + is_iv ? iv_loc : IV_NOP); chcr_req->ulptx.cmd_dest = FILL_ULPTX_CMD_DEST(ctx->dev->tx_channel_id); chcr_req->ulptx.len = htonl((DIV_ROUND_UP((calc_tx_flits_ofld(skb) * 8), @@ -481,10 +552,7 @@ static inline void create_wreq(struct chcr_context *ctx, chcr_req->sc_imm.cmd_more = FILL_CMD_MORE(immdatalen); chcr_req->sc_imm.len = cpu_to_be32(sizeof(struct cpl_tx_sec_pdu) + sizeof(chcr_req->key_ctx) + - kctx_len + - ((hash_sz) ? DUMMY_BYTES : - (sizeof(struct cpl_rx_phys_dsgl) + - phys_dsgl)) + immdatalen); + kctx_len + sc_len + immdatalen); } /** @@ -582,7 +650,8 @@ static struct sk_buff memcpy(reqctx->iv, req->info, ivsize); write_buffer_to_skb(skb, &frags, reqctx->iv, ivsize); write_sg_to_skb(skb, &frags, req->src, req->nbytes); - create_wreq(ctx, chcr_req, req, skb, kctx_len, 0, phys_dsgl); + create_wreq(ctx, chcr_req, req, skb, kctx_len, 0, 1, + sizeof(struct cpl_rx_phys_dsgl) + phys_dsgl); reqctx->skb = skb; skb_get(skb); return skb; @@ -769,7 +838,7 @@ static inline void chcr_free_shash(struct crypto_shash *base_hash) * @req - Cipher req base */ static struct sk_buff *create_hash_wr(struct ahash_request *req, - struct hash_wr_param *param) + struct hash_wr_param *param) { struct chcr_ahash_req_ctx *req_ctx = ahash_request_ctx(req); struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); @@ -840,8 +909,8 @@ static struct sk_buff *create_hash_wr(struct ahash_request *req, if (param->sg_len != 0) write_sg_to_skb(skb, &frags, req->src, param->sg_len); - create_wreq(ctx, chcr_req, req, skb, kctx_len, hash_size_in_response, - 0); + create_wreq(ctx, chcr_req, req, skb, kctx_len, hash_size_in_response, 0, + DUMMY_BYTES); req_ctx->skb = skb; skb_get(skb); return skb; @@ -1249,6 +1318,1167 @@ static void chcr_hmac_cra_exit(struct crypto_tfm *tfm) } } +static int chcr_copy_assoc(struct aead_request *req, + struct chcr_aead_ctx *ctx) +{ + SKCIPHER_REQUEST_ON_STACK(skreq, ctx->null); + + skcipher_request_set_tfm(skreq, ctx->null); + skcipher_request_set_callback(skreq, aead_request_flags(req), + NULL, NULL); + skcipher_request_set_crypt(skreq, req->src, req->dst, req->assoclen, + NULL); + + return crypto_skcipher_encrypt(skreq); +} + +static unsigned char get_hmac(unsigned int authsize) +{ + switch (authsize) { + case ICV_8: + return CHCR_SCMD_HMAC_CTRL_PL1; + case ICV_10: + return CHCR_SCMD_HMAC_CTRL_TRUNC_RFC4366; + case ICV_12: + return CHCR_SCMD_HMAC_CTRL_IPSEC_96BIT; + } + return CHCR_SCMD_HMAC_CTRL_NO_TRUNC; +} + + +static struct sk_buff *create_authenc_wr(struct aead_request *req, + unsigned short qid, + int size, + unsigned short op_type) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_context *ctx = crypto_aead_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + struct chcr_authenc_ctx *actx = AUTHENC_CTX(aeadctx); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + struct sk_buff *skb = NULL; + struct chcr_wr *chcr_req; + struct cpl_rx_phys_dsgl *phys_cpl; + struct phys_sge_parm sg_param; + struct scatterlist *src, *dst; + struct scatterlist src_sg[2], dst_sg[2]; + unsigned int frags = 0, transhdr_len; + unsigned int ivsize = crypto_aead_ivsize(tfm), dst_size = 0; + unsigned int kctx_len = 0; + unsigned short stop_offset = 0; + unsigned int assoclen = req->assoclen; + unsigned int authsize = crypto_aead_authsize(tfm); + int err = 0; + int null = 0; + gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; + + if (aeadctx->enckey_len == 0 || (req->cryptlen == 0)) + goto err; + + if (op_type && req->cryptlen < crypto_aead_authsize(tfm)) + goto err; + + if (sg_nents_for_len(req->src, req->assoclen + req->cryptlen) < 0) + goto err; + src = scatterwalk_ffwd(src_sg, req->src, req->assoclen); + dst = src; + if (req->src != req->dst) { + err = chcr_copy_assoc(req, aeadctx); + if (err) + return ERR_PTR(err); + dst = scatterwalk_ffwd(dst_sg, req->dst, req->assoclen); + } + if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_NULL) { + null = 1; + assoclen = 0; + } + reqctx->dst_nents = sg_nents_for_len(dst, req->cryptlen + + (op_type ? -authsize : authsize)); + if (reqctx->dst_nents <= 0) { + pr_err("AUTHENC:Invalid Destination sg entries\n"); + goto err; + } + dst_size = get_space_for_phys_dsgl(reqctx->dst_nents); + kctx_len = (ntohl(KEY_CONTEXT_CTX_LEN_V(aeadctx->key_ctx_hdr)) << 4) + - sizeof(chcr_req->key_ctx); + transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size); + skb = alloc_skb((transhdr_len + sizeof(struct sge_opaque_hdr)), flags); + if (!skb) + goto err; + + /* LLD is going to write the sge hdr. */ + skb_reserve(skb, sizeof(struct sge_opaque_hdr)); + + /* Write WR */ + chcr_req = (struct chcr_wr *) __skb_put(skb, transhdr_len); + memset(chcr_req, 0, transhdr_len); + + stop_offset = (op_type == CHCR_ENCRYPT_OP) ? 0 : authsize; + + /* + * Input order is AAD,IV and Payload. where IV should be included as + * the part of authdata. All other fields should be filled according + * to the hardware spec + */ + chcr_req->sec_cpl.op_ivinsrtofst = + FILL_SEC_CPL_OP_IVINSR(ctx->dev->tx_channel_id, 2, + (ivsize ? (assoclen + 1) : 0)); + chcr_req->sec_cpl.pldlen = htonl(assoclen + ivsize + req->cryptlen); + chcr_req->sec_cpl.aadstart_cipherstop_hi = FILL_SEC_CPL_CIPHERSTOP_HI( + assoclen ? 1 : 0, assoclen, + assoclen + ivsize + 1, + (stop_offset & 0x1F0) >> 4); + chcr_req->sec_cpl.cipherstop_lo_authinsert = FILL_SEC_CPL_AUTHINSERT( + stop_offset & 0xF, + null ? 0 : assoclen + ivsize + 1, + stop_offset, stop_offset); + chcr_req->sec_cpl.seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(op_type, + (op_type == CHCR_ENCRYPT_OP) ? 1 : 0, + CHCR_SCMD_CIPHER_MODE_AES_CBC, + actx->auth_mode, aeadctx->hmac_ctrl, + ivsize >> 1); + chcr_req->sec_cpl.ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 1, + 0, 1, dst_size); + + chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr; + if (op_type == CHCR_ENCRYPT_OP) + memcpy(chcr_req->key_ctx.key, aeadctx->key, + aeadctx->enckey_len); + else + memcpy(chcr_req->key_ctx.key, actx->dec_rrkey, + aeadctx->enckey_len); + + memcpy(chcr_req->key_ctx.key + (DIV_ROUND_UP(aeadctx->enckey_len, 16) << + 4), actx->h_iopad, kctx_len - + (DIV_ROUND_UP(aeadctx->enckey_len, 16) << 4)); + + phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); + sg_param.nents = reqctx->dst_nents; + sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); + sg_param.qid = qid; + sg_param.align = 0; + if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, dst, + &sg_param)) + goto dstmap_fail; + + skb_set_transport_header(skb, transhdr_len); + + if (assoclen) { + /* AAD buffer in */ + write_sg_to_skb(skb, &frags, req->src, assoclen); + + } + write_buffer_to_skb(skb, &frags, req->iv, ivsize); + write_sg_to_skb(skb, &frags, src, req->cryptlen); + create_wreq(ctx, chcr_req, req, skb, kctx_len, size, 1, + sizeof(struct cpl_rx_phys_dsgl) + dst_size); + reqctx->skb = skb; + skb_get(skb); + + return skb; +dstmap_fail: + /* ivmap_fail: */ + kfree_skb(skb); +err: + return ERR_PTR(-EINVAL); +} + +static void aes_gcm_empty_pld_pad(struct scatterlist *sg, + unsigned short offset) +{ + struct page *spage; + unsigned char *addr; + + spage = sg_page(sg); + get_page(spage); /* so that it is not freed by NIC */ +#ifdef KMAP_ATOMIC_ARGS + addr = kmap_atomic(spage, KM_SOFTIRQ0); +#else + addr = kmap_atomic(spage); +#endif + memset(addr + sg->offset, 0, offset + 1); + + kunmap_atomic(addr); +} + +static int set_msg_len(u8 *block, unsigned int msglen, int csize) +{ + __be32 data; + + memset(block, 0, csize); + block += csize; + + if (csize >= 4) + csize = 4; + else if (msglen > (unsigned int)(1 << (8 * csize))) + return -EOVERFLOW; + + data = cpu_to_be32(msglen); + memcpy(block - csize, (u8 *)&data + 4 - csize, csize); + + return 0; +} + +static void generate_b0(struct aead_request *req, + struct chcr_aead_ctx *aeadctx, + unsigned short op_type) +{ + unsigned int l, lp, m; + int rc; + struct crypto_aead *aead = crypto_aead_reqtfm(req); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + u8 *b0 = reqctx->scratch_pad; + + m = crypto_aead_authsize(aead); + + memcpy(b0, reqctx->iv, 16); + + lp = b0[0]; + l = lp + 1; + + /* set m, bits 3-5 */ + *b0 |= (8 * ((m - 2) / 2)); + + /* set adata, bit 6, if associated data is used */ + if (req->assoclen) + *b0 |= 64; + rc = set_msg_len(b0 + 16 - l, + (op_type == CHCR_DECRYPT_OP) ? + req->cryptlen - m : req->cryptlen, l); +} + +static inline int crypto_ccm_check_iv(const u8 *iv) +{ + /* 2 <= L <= 8, so 1 <= L' <= 7. */ + if (iv[0] < 1 || iv[0] > 7) + return -EINVAL; + + return 0; +} + +static int ccm_format_packet(struct aead_request *req, + struct chcr_aead_ctx *aeadctx, + unsigned int sub_type, + unsigned short op_type) +{ + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + int rc = 0; + + if (req->assoclen > T5_MAX_AAD_SIZE) { + pr_err("CCM: Unsupported AAD data. It should be < %d\n", + T5_MAX_AAD_SIZE); + return -EINVAL; + } + if (sub_type == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) { + reqctx->iv[0] = 3; + memcpy(reqctx->iv + 1, &aeadctx->salt[0], 3); + memcpy(reqctx->iv + 4, req->iv, 8); + memset(reqctx->iv + 12, 0, 4); + *((unsigned short *)(reqctx->scratch_pad + 16)) = + htons(req->assoclen - 8); + } else { + memcpy(reqctx->iv, req->iv, 16); + *((unsigned short *)(reqctx->scratch_pad + 16)) = + htons(req->assoclen); + } + generate_b0(req, aeadctx, op_type); + /* zero the ctr value */ + memset(reqctx->iv + 15 - reqctx->iv[0], 0, reqctx->iv[0] + 1); + return rc; +} + +static void fill_sec_cpl_for_aead(struct cpl_tx_sec_pdu *sec_cpl, + unsigned int dst_size, + struct aead_request *req, + unsigned short op_type, + struct chcr_context *chcrctx) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + unsigned int ivsize = AES_BLOCK_SIZE; + unsigned int cipher_mode = CHCR_SCMD_CIPHER_MODE_AES_CCM; + unsigned int mac_mode = CHCR_SCMD_AUTH_MODE_CBCMAC; + unsigned int c_id = chcrctx->dev->tx_channel_id; + unsigned int ccm_xtra; + unsigned char tag_offset = 0, auth_offset = 0; + unsigned char hmac_ctrl = get_hmac(crypto_aead_authsize(tfm)); + unsigned int assoclen; + + if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) + assoclen = req->assoclen - 8; + else + assoclen = req->assoclen; + ccm_xtra = CCM_B0_SIZE + + ((assoclen) ? CCM_AAD_FIELD_SIZE : 0); + + auth_offset = req->cryptlen ? + (assoclen + ivsize + 1 + ccm_xtra) : 0; + if (op_type == CHCR_DECRYPT_OP) { + if (crypto_aead_authsize(tfm) != req->cryptlen) + tag_offset = crypto_aead_authsize(tfm); + else + auth_offset = 0; + } + + + sec_cpl->op_ivinsrtofst = FILL_SEC_CPL_OP_IVINSR(c_id, + 2, (ivsize ? (assoclen + 1) : 0) + + ccm_xtra); + sec_cpl->pldlen = + htonl(assoclen + ivsize + req->cryptlen + ccm_xtra); + /* For CCM there wil be b0 always. So AAD start will be 1 always */ + sec_cpl->aadstart_cipherstop_hi = FILL_SEC_CPL_CIPHERSTOP_HI( + 1, assoclen + ccm_xtra, assoclen + + ivsize + 1 + ccm_xtra, 0); + + sec_cpl->cipherstop_lo_authinsert = FILL_SEC_CPL_AUTHINSERT(0, + auth_offset, tag_offset, + (op_type == CHCR_ENCRYPT_OP) ? 0 : + crypto_aead_authsize(tfm)); + sec_cpl->seqno_numivs = FILL_SEC_CPL_SCMD0_SEQNO(op_type, + (op_type == CHCR_ENCRYPT_OP) ? 0 : 1, + cipher_mode, mac_mode, hmac_ctrl, + ivsize >> 1); + + sec_cpl->ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 1, 0, + 1, dst_size); +} + +int aead_ccm_validate_input(unsigned short op_type, + struct aead_request *req, + struct chcr_aead_ctx *aeadctx, + unsigned int sub_type) +{ + if (sub_type != CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) { + if (crypto_ccm_check_iv(req->iv)) { + pr_err("CCM: IV check fails\n"); + return -EINVAL; + } + } else { + if (req->assoclen != 16 && req->assoclen != 20) { + pr_err("RFC4309: Invalid AAD length %d\n", + req->assoclen); + return -EINVAL; + } + } + if (aeadctx->enckey_len == 0) { + pr_err("CCM: Encryption key not set\n"); + return -EINVAL; + } + return 0; +} + +unsigned int fill_aead_req_fields(struct sk_buff *skb, + struct aead_request *req, + struct scatterlist *src, + unsigned int ivsize, + struct chcr_aead_ctx *aeadctx) +{ + unsigned int frags = 0; + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + /* b0 and aad length(if available) */ + + write_buffer_to_skb(skb, &frags, reqctx->scratch_pad, CCM_B0_SIZE + + (req->assoclen ? CCM_AAD_FIELD_SIZE : 0)); + if (req->assoclen) { + if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309) + write_sg_to_skb(skb, &frags, req->src, + req->assoclen - 8); + else + write_sg_to_skb(skb, &frags, req->src, req->assoclen); + } + write_buffer_to_skb(skb, &frags, reqctx->iv, ivsize); + if (req->cryptlen) + write_sg_to_skb(skb, &frags, src, req->cryptlen); + + return frags; +} + +static struct sk_buff *create_aead_ccm_wr(struct aead_request *req, + unsigned short qid, + int size, + unsigned short op_type) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_context *ctx = crypto_aead_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + struct sk_buff *skb = NULL; + struct chcr_wr *chcr_req; + struct cpl_rx_phys_dsgl *phys_cpl; + struct phys_sge_parm sg_param; + struct scatterlist *src, *dst; + struct scatterlist src_sg[2], dst_sg[2]; + unsigned int frags = 0, transhdr_len, ivsize = AES_BLOCK_SIZE; + unsigned int dst_size = 0, kctx_len; + unsigned int sub_type; + unsigned int authsize = crypto_aead_authsize(tfm); + int err = 0; + gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; + + + if (op_type && req->cryptlen < crypto_aead_authsize(tfm)) + goto err; + + if (sg_nents_for_len(req->src, req->assoclen + req->cryptlen) < 0) + goto err; + sub_type = get_aead_subtype(tfm); + src = scatterwalk_ffwd(src_sg, req->src, req->assoclen); + dst = src; + if (req->src != req->dst) { + err = chcr_copy_assoc(req, aeadctx); + if (err) { + pr_err("AAD copy to destination buffer fails\n"); + return ERR_PTR(err); + } + dst = scatterwalk_ffwd(dst_sg, req->dst, req->assoclen); + } + reqctx->dst_nents = sg_nents_for_len(dst, req->cryptlen + + (op_type ? -authsize : authsize)); + if (reqctx->dst_nents <= 0) { + pr_err("CCM:Invalid Destination sg entries\n"); + goto err; + } + + + if (aead_ccm_validate_input(op_type, req, aeadctx, sub_type)) + goto err; + + dst_size = get_space_for_phys_dsgl(reqctx->dst_nents); + kctx_len = ((DIV_ROUND_UP(aeadctx->enckey_len, 16)) << 4) * 2; + transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size); + skb = alloc_skb((transhdr_len + sizeof(struct sge_opaque_hdr)), flags); + + if (!skb) + goto err; + + skb_reserve(skb, sizeof(struct sge_opaque_hdr)); + + chcr_req = (struct chcr_wr *) __skb_put(skb, transhdr_len); + memset(chcr_req, 0, transhdr_len); + + fill_sec_cpl_for_aead(&chcr_req->sec_cpl, dst_size, req, op_type, ctx); + + chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr; + memcpy(chcr_req->key_ctx.key, aeadctx->key, aeadctx->enckey_len); + memcpy(chcr_req->key_ctx.key + (DIV_ROUND_UP(aeadctx->enckey_len, 16) * + 16), aeadctx->key, aeadctx->enckey_len); + + phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); + if (ccm_format_packet(req, aeadctx, sub_type, op_type)) + goto dstmap_fail; + + sg_param.nents = reqctx->dst_nents; + sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); + sg_param.qid = qid; + sg_param.align = 0; + if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, dst, + &sg_param)) + goto dstmap_fail; + + skb_set_transport_header(skb, transhdr_len); + frags = fill_aead_req_fields(skb, req, src, ivsize, aeadctx); + create_wreq(ctx, chcr_req, req, skb, kctx_len, 0, 1, + sizeof(struct cpl_rx_phys_dsgl) + dst_size); + reqctx->skb = skb; + skb_get(skb); + return skb; +dstmap_fail: + kfree_skb(skb); + skb = NULL; +err: + return ERR_PTR(-EINVAL); +} + +static struct sk_buff *create_gcm_wr(struct aead_request *req, + unsigned short qid, + int size, + unsigned short op_type) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_context *ctx = crypto_aead_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + struct sk_buff *skb = NULL; + struct chcr_wr *chcr_req; + struct cpl_rx_phys_dsgl *phys_cpl; + struct phys_sge_parm sg_param; + struct scatterlist *src, *dst; + struct scatterlist src_sg[2], dst_sg[2]; + unsigned int frags = 0, transhdr_len; + unsigned int ivsize = AES_BLOCK_SIZE; + unsigned int dst_size = 0, kctx_len; + unsigned char tag_offset = 0; + unsigned int crypt_len = 0; + unsigned int authsize = crypto_aead_authsize(tfm); + unsigned char hmac_ctrl = get_hmac(authsize); + int err = 0; + gfp_t flags = req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP ? GFP_KERNEL : + GFP_ATOMIC; + + /* validate key size */ + if (aeadctx->enckey_len == 0) + goto err; + + if (op_type && req->cryptlen < crypto_aead_authsize(tfm)) + goto err; + + if (sg_nents_for_len(req->src, req->assoclen + req->cryptlen) < 0) + goto err; + + src = scatterwalk_ffwd(src_sg, req->src, req->assoclen); + dst = src; + if (req->src != req->dst) { + err = chcr_copy_assoc(req, aeadctx); + if (err) + return ERR_PTR(err); + dst = scatterwalk_ffwd(dst_sg, req->dst, req->assoclen); + } + + if (!req->cryptlen) + /* null-payload is not supported in the hardware. + * software is sending block size + */ + crypt_len = AES_BLOCK_SIZE; + else + crypt_len = req->cryptlen; + reqctx->dst_nents = sg_nents_for_len(dst, req->cryptlen + + (op_type ? -authsize : authsize)); + if (reqctx->dst_nents <= 0) { + pr_err("GCM:Invalid Destination sg entries\n"); + goto err; + } + + + dst_size = get_space_for_phys_dsgl(reqctx->dst_nents); + kctx_len = ((DIV_ROUND_UP(aeadctx->enckey_len, 16)) << 4) + + AEAD_H_SIZE; + transhdr_len = CIPHER_TRANSHDR_SIZE(kctx_len, dst_size); + skb = alloc_skb((transhdr_len + sizeof(struct sge_opaque_hdr)), flags); + if (!skb) + goto err; + + /* NIC driver is going to write the sge hdr. */ + skb_reserve(skb, sizeof(struct sge_opaque_hdr)); + + chcr_req = (struct chcr_wr *)__skb_put(skb, transhdr_len); + memset(chcr_req, 0, transhdr_len); + + if (get_aead_subtype(tfm) == CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) + req->assoclen -= 8; + + tag_offset = (op_type == CHCR_ENCRYPT_OP) ? 0 : authsize; + chcr_req->sec_cpl.op_ivinsrtofst = FILL_SEC_CPL_OP_IVINSR( + ctx->dev->tx_channel_id, 2, (ivsize ? + (req->assoclen + 1) : 0)); + chcr_req->sec_cpl.pldlen = htonl(req->assoclen + ivsize + crypt_len); + chcr_req->sec_cpl.aadstart_cipherstop_hi = FILL_SEC_CPL_CIPHERSTOP_HI( + req->assoclen ? 1 : 0, req->assoclen, + req->assoclen + ivsize + 1, 0); + if (req->cryptlen) { + chcr_req->sec_cpl.cipherstop_lo_authinsert = + FILL_SEC_CPL_AUTHINSERT(0, req->assoclen + ivsize + 1, + tag_offset, tag_offset); + chcr_req->sec_cpl.seqno_numivs = + FILL_SEC_CPL_SCMD0_SEQNO(op_type, (op_type == + CHCR_ENCRYPT_OP) ? 1 : 0, + CHCR_SCMD_CIPHER_MODE_AES_GCM, + CHCR_SCMD_AUTH_MODE_GHASH, hmac_ctrl, + ivsize >> 1); + } else { + chcr_req->sec_cpl.cipherstop_lo_authinsert = + FILL_SEC_CPL_AUTHINSERT(0, 0, 0, 0); + chcr_req->sec_cpl.seqno_numivs = + FILL_SEC_CPL_SCMD0_SEQNO(op_type, + (op_type == CHCR_ENCRYPT_OP) ? + 1 : 0, CHCR_SCMD_CIPHER_MODE_AES_CBC, + 0, 0, ivsize >> 1); + } + chcr_req->sec_cpl.ivgen_hdrlen = FILL_SEC_CPL_IVGEN_HDRLEN(0, 0, 1, + 0, 1, dst_size); + chcr_req->key_ctx.ctx_hdr = aeadctx->key_ctx_hdr; + memcpy(chcr_req->key_ctx.key, aeadctx->key, aeadctx->enckey_len); + memcpy(chcr_req->key_ctx.key + (DIV_ROUND_UP(aeadctx->enckey_len, 16) * + 16), GCM_CTX(aeadctx)->ghash_h, AEAD_H_SIZE); + + /* prepare a 16 byte iv */ + /* S A L T | IV | 0x00000001 */ + if (get_aead_subtype(tfm) == + CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) { + memcpy(reqctx->iv, aeadctx->salt, 4); + memcpy(reqctx->iv + 4, req->iv, 8); + } else { + memcpy(reqctx->iv, req->iv, 12); + } + *((unsigned int *)(reqctx->iv + 12)) = htonl(0x01); + + phys_cpl = (struct cpl_rx_phys_dsgl *)((u8 *)(chcr_req + 1) + kctx_len); + sg_param.nents = reqctx->dst_nents; + sg_param.obsize = req->cryptlen + (op_type ? -authsize : authsize); + sg_param.qid = qid; + sg_param.align = 0; + if (map_writesg_phys_cpl(&u_ctx->lldi.pdev->dev, phys_cpl, dst, + &sg_param)) + goto dstmap_fail; + + skb_set_transport_header(skb, transhdr_len); + + write_sg_to_skb(skb, &frags, req->src, req->assoclen); + + write_buffer_to_skb(skb, &frags, reqctx->iv, ivsize); + + if (req->cryptlen) { + write_sg_to_skb(skb, &frags, src, req->cryptlen); + } else { + aes_gcm_empty_pld_pad(req->dst, authsize - 1); + write_sg_to_skb(skb, &frags, dst, crypt_len); + } + + create_wreq(ctx, chcr_req, req, skb, kctx_len, size, 1, + sizeof(struct cpl_rx_phys_dsgl) + dst_size); + reqctx->skb = skb; + skb_get(skb); + return skb; + +dstmap_fail: + /* ivmap_fail: */ + kfree_skb(skb); + skb = NULL; +err: + return skb; +} + + + +static int chcr_aead_cra_init(struct crypto_aead *tfm) +{ + struct chcr_context *ctx = crypto_aead_ctx(tfm); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + + crypto_aead_set_reqsize(tfm, sizeof(struct chcr_aead_reqctx)); + aeadctx->null = crypto_get_default_null_skcipher(); + if (IS_ERR(aeadctx->null)) + return PTR_ERR(aeadctx->null); + return chcr_device_init(ctx); +} + +static void chcr_aead_cra_exit(struct crypto_aead *tfm) +{ + crypto_put_default_null_skcipher(); +} + +static int chcr_authenc_null_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + struct chcr_aead_ctx *aeadctx = AEAD_CTX(crypto_aead_ctx(tfm)); + + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NOP; + aeadctx->mayverify = VERIFY_HW; + return 0; +} +static int chcr_authenc_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + struct chcr_aead_ctx *aeadctx = AEAD_CTX(crypto_aead_ctx(tfm)); + u32 maxauth = crypto_aead_maxauthsize(tfm); + + /*SHA1 authsize in ipsec is 12 instead of 10 i.e maxauthsize / 2 is not + * true for sha1. authsize == 12 condition should be before + * authsize == (maxauth >> 1) + */ + if (authsize == ICV_4) { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL1; + aeadctx->mayverify = VERIFY_HW; + } else if (authsize == ICV_6) { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL2; + aeadctx->mayverify = VERIFY_HW; + } else if (authsize == ICV_10) { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_TRUNC_RFC4366; + aeadctx->mayverify = VERIFY_HW; + } else if (authsize == ICV_12) { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_IPSEC_96BIT; + aeadctx->mayverify = VERIFY_HW; + } else if (authsize == ICV_14) { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL3; + aeadctx->mayverify = VERIFY_HW; + } else if (authsize == (maxauth >> 1)) { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_DIV2; + aeadctx->mayverify = VERIFY_HW; + } else if (authsize == maxauth) { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NO_TRUNC; + aeadctx->mayverify = VERIFY_HW; + } else { + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NO_TRUNC; + aeadctx->mayverify = VERIFY_SW; + } + return 0; +} + + +static int chcr_gcm_setauthsize(struct crypto_aead *tfm, unsigned int authsize) +{ + struct chcr_aead_ctx *aeadctx = AEAD_CTX(crypto_aead_ctx(tfm)); + + switch (authsize) { + case ICV_4: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL1; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_8: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_DIV2; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_12: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_IPSEC_96BIT; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_14: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL3; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_16: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NO_TRUNC; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_13: + case ICV_15: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NO_TRUNC; + aeadctx->mayverify = VERIFY_SW; + break; + default: + + crypto_tfm_set_flags((struct crypto_tfm *) tfm, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + return 0; +} + +static int chcr_4106_4309_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + struct chcr_aead_ctx *aeadctx = AEAD_CTX(crypto_aead_ctx(tfm)); + + switch (authsize) { + case ICV_8: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_DIV2; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_12: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_IPSEC_96BIT; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_16: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NO_TRUNC; + aeadctx->mayverify = VERIFY_HW; + break; + default: + crypto_tfm_set_flags((struct crypto_tfm *)tfm, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + return 0; +} + +static int chcr_ccm_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) +{ + struct chcr_aead_ctx *aeadctx = AEAD_CTX(crypto_aead_ctx(tfm)); + + switch (authsize) { + case ICV_4: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL1; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_6: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL2; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_8: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_DIV2; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_10: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_TRUNC_RFC4366; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_12: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_IPSEC_96BIT; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_14: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_PL3; + aeadctx->mayverify = VERIFY_HW; + break; + case ICV_16: + aeadctx->hmac_ctrl = CHCR_SCMD_HMAC_CTRL_NO_TRUNC; + aeadctx->mayverify = VERIFY_HW; + break; + default: + crypto_tfm_set_flags((struct crypto_tfm *)tfm, + CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; + } + return 0; +} + +static int chcr_aead_ccm_setkey(struct crypto_aead *aead, + const u8 *key, + unsigned int keylen) +{ + struct chcr_context *ctx = crypto_aead_ctx(aead); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + unsigned char ck_size, mk_size; + int key_ctx_size = 0; + + memcpy(aeadctx->key, key, keylen); + aeadctx->enckey_len = keylen; + key_ctx_size = sizeof(struct _key_ctx) + + ((DIV_ROUND_UP(keylen, 16)) << 4) * 2; + if (keylen == AES_KEYSIZE_128) { + mk_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; + } else if (keylen == AES_KEYSIZE_192) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_192; + mk_size = CHCR_KEYCTX_MAC_KEY_SIZE_192; + } else if (keylen == AES_KEYSIZE_256) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; + mk_size = CHCR_KEYCTX_MAC_KEY_SIZE_256; + } else { + crypto_tfm_set_flags((struct crypto_tfm *)aead, + CRYPTO_TFM_RES_BAD_KEY_LEN); + aeadctx->enckey_len = 0; + return -EINVAL; + } + aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, mk_size, 0, 0, + key_ctx_size >> 4); + return 0; +} + +static int chcr_aead_rfc4309_setkey(struct crypto_aead *aead, const u8 *key, + unsigned int keylen) +{ + struct chcr_context *ctx = crypto_aead_ctx(aead); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + + if (keylen < 3) { + crypto_tfm_set_flags((struct crypto_tfm *)aead, + CRYPTO_TFM_RES_BAD_KEY_LEN); + aeadctx->enckey_len = 0; + return -EINVAL; + } + keylen -= 3; + memcpy(aeadctx->salt, key + keylen, 3); + return chcr_aead_ccm_setkey(aead, key, keylen); +} + +static int chcr_gcm_setkey(struct crypto_aead *aead, const u8 *key, + unsigned int keylen) +{ + struct chcr_context *ctx = crypto_aead_ctx(aead); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + struct chcr_gcm_ctx *gctx = GCM_CTX(aeadctx); + struct blkcipher_desc h_desc; + struct scatterlist src[1]; + unsigned int ck_size; + int ret = 0, key_ctx_size = 0; + + if (get_aead_subtype(aead) == + CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106) { + keylen -= 4; /* nonce/salt is present in the last 4 bytes */ + memcpy(aeadctx->salt, key + keylen, 4); + } + if (keylen == AES_KEYSIZE_128) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; + } else if (keylen == AES_KEYSIZE_192) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_192; + } else if (keylen == AES_KEYSIZE_256) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; + } else { + crypto_tfm_set_flags((struct crypto_tfm *)aead, + CRYPTO_TFM_RES_BAD_KEY_LEN); + aeadctx->enckey_len = 0; + pr_err("GCM: Invalid key length %d", keylen); + ret = -EINVAL; + goto out; + } + + memcpy(aeadctx->key, key, keylen); + aeadctx->enckey_len = keylen; + key_ctx_size = sizeof(struct _key_ctx) + + ((DIV_ROUND_UP(keylen, 16)) << 4) + + AEAD_H_SIZE; + aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, + CHCR_KEYCTX_MAC_KEY_SIZE_128, + 0, 0, + key_ctx_size >> 4); + /* Calculate the H = CIPH(K, 0 repeated 16 times) using sync aes + * blkcipher It will go on key context + */ + h_desc.tfm = crypto_alloc_blkcipher("cbc(aes-generic)", 0, 0); + if (IS_ERR(h_desc.tfm)) { + aeadctx->enckey_len = 0; + ret = -ENOMEM; + goto out; + } + h_desc.flags = 0; + ret = crypto_blkcipher_setkey(h_desc.tfm, key, keylen); + if (ret) { + aeadctx->enckey_len = 0; + goto out1; + } + memset(gctx->ghash_h, 0, AEAD_H_SIZE); + sg_init_one(&src[0], gctx->ghash_h, AEAD_H_SIZE); + ret = crypto_blkcipher_encrypt(&h_desc, &src[0], &src[0], AEAD_H_SIZE); + +out1: + crypto_free_blkcipher(h_desc.tfm); +out: + return ret; +} + +static int chcr_authenc_setkey(struct crypto_aead *authenc, const u8 *key, + unsigned int keylen) +{ + struct chcr_context *ctx = crypto_aead_ctx(authenc); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + struct chcr_authenc_ctx *actx = AUTHENC_CTX(aeadctx); + /* it contains auth and cipher key both*/ + struct crypto_authenc_keys keys; + unsigned int bs; + unsigned int max_authsize = crypto_aead_alg(authenc)->maxauthsize; + int err = 0, i, key_ctx_len = 0; + unsigned char ck_size = 0; + unsigned char pad[CHCR_HASH_MAX_BLOCK_SIZE_128] = { 0 }; + struct crypto_shash *base_hash = NULL; + struct algo_param param; + int align; + u8 *o_ptr = NULL; + + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) { + crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN); + goto out; + } + + if (get_alg_config(¶m, max_authsize)) { + pr_err("chcr : Unsupported digest size\n"); + goto out; + } + if (keys.enckeylen == AES_KEYSIZE_128) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; + } else if (keys.enckeylen == AES_KEYSIZE_192) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_192; + } else if (keys.enckeylen == AES_KEYSIZE_256) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; + } else { + pr_err("chcr : Unsupported cipher key\n"); + goto out; + } + + /* Copy only encryption key. We use authkey to generate h(ipad) and + * h(opad) so authkey is not needed again. authkeylen size have the + * size of the hash digest size. + */ + memcpy(aeadctx->key, keys.enckey, keys.enckeylen); + aeadctx->enckey_len = keys.enckeylen; + get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key, + aeadctx->enckey_len << 3); + + base_hash = chcr_alloc_shash(max_authsize); + if (IS_ERR(base_hash)) { + pr_err("chcr : Base driver cannot be loaded\n"); + goto out; + } + { + SHASH_DESC_ON_STACK(shash, base_hash); + shash->tfm = base_hash; + shash->flags = crypto_shash_get_flags(base_hash); + bs = crypto_shash_blocksize(base_hash); + align = KEYCTX_ALIGN_PAD(max_authsize); + o_ptr = actx->h_iopad + param.result_size + align; + + if (keys.authkeylen > bs) { + err = crypto_shash_digest(shash, keys.authkey, + keys.authkeylen, + o_ptr); + if (err) { + pr_err("chcr : Base driver cannot be loaded\n"); + goto out; + } + keys.authkeylen = max_authsize; + } else + memcpy(o_ptr, keys.authkey, keys.authkeylen); + + /* Compute the ipad-digest*/ + memset(pad + keys.authkeylen, 0, bs - keys.authkeylen); + memcpy(pad, o_ptr, keys.authkeylen); + for (i = 0; i < bs >> 2; i++) + *((unsigned int *)pad + i) ^= IPAD_DATA; + + if (chcr_compute_partial_hash(shash, pad, actx->h_iopad, + max_authsize)) + goto out; + /* Compute the opad-digest */ + memset(pad + keys.authkeylen, 0, bs - keys.authkeylen); + memcpy(pad, o_ptr, keys.authkeylen); + for (i = 0; i < bs >> 2; i++) + *((unsigned int *)pad + i) ^= OPAD_DATA; + + if (chcr_compute_partial_hash(shash, pad, o_ptr, max_authsize)) + goto out; + + /* convert the ipad and opad digest to network order */ + chcr_change_order(actx->h_iopad, param.result_size); + chcr_change_order(o_ptr, param.result_size); + key_ctx_len = sizeof(struct _key_ctx) + + ((DIV_ROUND_UP(keys.enckeylen, 16)) << 4) + + (param.result_size + align) * 2; + aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, param.mk_size, + 0, 1, key_ctx_len >> 4); + actx->auth_mode = param.auth_mode; + chcr_free_shash(base_hash); + + return 0; + } +out: + aeadctx->enckey_len = 0; + if (base_hash) + chcr_free_shash(base_hash); + return -EINVAL; +} + +static int chcr_aead_digest_null_setkey(struct crypto_aead *authenc, + const u8 *key, unsigned int keylen) +{ + struct chcr_context *ctx = crypto_aead_ctx(authenc); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(ctx); + struct chcr_authenc_ctx *actx = AUTHENC_CTX(aeadctx); + struct crypto_authenc_keys keys; + + /* it contains auth and cipher key both*/ + int key_ctx_len = 0; + unsigned char ck_size = 0; + + if (crypto_authenc_extractkeys(&keys, key, keylen) != 0) { + crypto_aead_set_flags(authenc, CRYPTO_TFM_RES_BAD_KEY_LEN); + goto out; + } + if (keys.enckeylen == AES_KEYSIZE_128) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_128; + } else if (keys.enckeylen == AES_KEYSIZE_192) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_192; + } else if (keys.enckeylen == AES_KEYSIZE_256) { + ck_size = CHCR_KEYCTX_CIPHER_KEY_SIZE_256; + } else { + pr_err("chcr : Unsupported cipher key\n"); + goto out; + } + memcpy(aeadctx->key, keys.enckey, keys.enckeylen); + aeadctx->enckey_len = keys.enckeylen; + get_aes_decrypt_key(actx->dec_rrkey, aeadctx->key, + aeadctx->enckey_len << 3); + key_ctx_len = sizeof(struct _key_ctx) + + ((DIV_ROUND_UP(keys.enckeylen, 16)) << 4); + + aeadctx->key_ctx_hdr = FILL_KEY_CTX_HDR(ck_size, CHCR_KEYCTX_NO_KEY, 0, + 0, key_ctx_len >> 4); + actx->auth_mode = CHCR_SCMD_AUTH_MODE_NOP; + return 0; +out: + aeadctx->enckey_len = 0; + return -EINVAL; +} +static int chcr_aead_encrypt(struct aead_request *req) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + + reqctx->verify = VERIFY_HW; + + switch (get_aead_subtype(tfm)) { + case CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC: + case CRYPTO_ALG_SUB_TYPE_AEAD_NULL: + return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, + create_authenc_wr); + case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: + case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: + return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, + create_aead_ccm_wr); + default: + return chcr_aead_op(req, CHCR_ENCRYPT_OP, 0, + create_gcm_wr); + } +} + +static int chcr_aead_decrypt(struct aead_request *req) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_aead_ctx *aeadctx = AEAD_CTX(crypto_aead_ctx(tfm)); + struct chcr_aead_reqctx *reqctx = aead_request_ctx(req); + int size; + + if (aeadctx->mayverify == VERIFY_SW) { + size = crypto_aead_maxauthsize(tfm); + reqctx->verify = VERIFY_SW; + } else { + size = 0; + reqctx->verify = VERIFY_HW; + } + + switch (get_aead_subtype(tfm)) { + case CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC: + case CRYPTO_ALG_SUB_TYPE_AEAD_NULL: + return chcr_aead_op(req, CHCR_DECRYPT_OP, size, + create_authenc_wr); + case CRYPTO_ALG_SUB_TYPE_AEAD_CCM: + case CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309: + return chcr_aead_op(req, CHCR_DECRYPT_OP, size, + create_aead_ccm_wr); + default: + return chcr_aead_op(req, CHCR_DECRYPT_OP, size, + create_gcm_wr); + } +} + +static int chcr_aead_op(struct aead_request *req, + unsigned short op_type, + int size, + create_wr_t create_wr_fn) +{ + struct crypto_aead *tfm = crypto_aead_reqtfm(req); + struct chcr_context *ctx = crypto_aead_ctx(tfm); + struct uld_ctx *u_ctx = ULD_CTX(ctx); + struct sk_buff *skb; + + if (ctx && !ctx->dev) { + pr_err("chcr : %s : No crypto device.\n", __func__); + return -ENXIO; + } + if (cxgb4_is_crypto_q_full(u_ctx->lldi.ports[0], + ctx->tx_channel_id)) { + if (!(req->base.flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) + return -EBUSY; + } + + /* Form a WR from req */ + skb = create_wr_fn(req, u_ctx->lldi.rxq_ids[ctx->tx_channel_id], size, + op_type); + + if (IS_ERR(skb) || skb == NULL) { + pr_err("chcr : %s : failed to form WR. No memory\n", __func__); + return PTR_ERR(skb); + } + + skb->dev = u_ctx->lldi.ports[0]; + set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); + chcr_send_wr(skb); + return -EINPROGRESS; +} static struct chcr_alg_template driver_algs[] = { /* AES-CBC */ { @@ -1256,7 +2486,7 @@ static struct chcr_alg_template driver_algs[] = { .is_registered = 0, .alg.crypto = { .cra_name = "cbc(aes)", - .cra_driver_name = "cbc(aes-chcr)", + .cra_driver_name = "cbc-aes-chcr", .cra_priority = CHCR_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC, @@ -1283,7 +2513,7 @@ static struct chcr_alg_template driver_algs[] = { .is_registered = 0, .alg.crypto = { .cra_name = "xts(aes)", - .cra_driver_name = "xts(aes-chcr)", + .cra_driver_name = "xts-aes-chcr", .cra_priority = CHCR_CRA_PRIORITY, .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER | CRYPTO_ALG_ASYNC, @@ -1376,7 +2606,7 @@ static struct chcr_alg_template driver_algs[] = { .halg.digestsize = SHA1_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha1)", - .cra_driver_name = "hmac(sha1-chcr)", + .cra_driver_name = "hmac-sha1-chcr", .cra_blocksize = SHA1_BLOCK_SIZE, } } @@ -1388,7 +2618,7 @@ static struct chcr_alg_template driver_algs[] = { .halg.digestsize = SHA224_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha224)", - .cra_driver_name = "hmac(sha224-chcr)", + .cra_driver_name = "hmac-sha224-chcr", .cra_blocksize = SHA224_BLOCK_SIZE, } } @@ -1400,7 +2630,7 @@ static struct chcr_alg_template driver_algs[] = { .halg.digestsize = SHA256_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha256)", - .cra_driver_name = "hmac(sha256-chcr)", + .cra_driver_name = "hmac-sha256-chcr", .cra_blocksize = SHA256_BLOCK_SIZE, } } @@ -1412,7 +2642,7 @@ static struct chcr_alg_template driver_algs[] = { .halg.digestsize = SHA384_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha384)", - .cra_driver_name = "hmac(sha384-chcr)", + .cra_driver_name = "hmac-sha384-chcr", .cra_blocksize = SHA384_BLOCK_SIZE, } } @@ -1424,11 +2654,205 @@ static struct chcr_alg_template driver_algs[] = { .halg.digestsize = SHA512_DIGEST_SIZE, .halg.base = { .cra_name = "hmac(sha512)", - .cra_driver_name = "hmac(sha512-chcr)", + .cra_driver_name = "hmac-sha512-chcr", .cra_blocksize = SHA512_BLOCK_SIZE, } } }, + /* Add AEAD Algorithms */ + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_GCM, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "gcm(aes)", + .cra_driver_name = "gcm-aes-chcr", + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_gcm_ctx), + }, + .ivsize = 12, + .maxauthsize = GHASH_DIGEST_SIZE, + .setkey = chcr_gcm_setkey, + .setauthsize = chcr_gcm_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "rfc4106(gcm(aes))", + .cra_driver_name = "rfc4106-gcm-aes-chcr", + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_gcm_ctx), + + }, + .ivsize = 8, + .maxauthsize = GHASH_DIGEST_SIZE, + .setkey = chcr_gcm_setkey, + .setauthsize = chcr_4106_4309_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_CCM, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "ccm(aes)", + .cra_driver_name = "ccm-aes-chcr", + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx), + + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = GHASH_DIGEST_SIZE, + .setkey = chcr_aead_ccm_setkey, + .setauthsize = chcr_ccm_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "rfc4309(ccm(aes))", + .cra_driver_name = "rfc4309-ccm-aes-chcr", + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx), + + }, + .ivsize = 8, + .maxauthsize = GHASH_DIGEST_SIZE, + .setkey = chcr_aead_rfc4309_setkey, + .setauthsize = chcr_4106_4309_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha1),cbc(aes))", + .cra_driver_name = + "authenc-hmac-sha1-cbc-aes-chcr", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA1_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .is_registered = 0, + .alg.aead = { + .base = { + + .cra_name = "authenc(hmac(sha256),cbc(aes))", + .cra_driver_name = + "authenc-hmac-sha256-cbc-aes-chcr", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA256_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha224),cbc(aes))", + .cra_driver_name = + "authenc-hmac-sha224-cbc-aes-chcr", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA224_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha384),cbc(aes))", + .cra_driver_name = + "authenc-hmac-sha384-cbc-aes-chcr", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA384_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(hmac(sha512),cbc(aes))", + .cra_driver_name = + "authenc-hmac-sha512-cbc-aes-chcr", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = SHA512_DIGEST_SIZE, + .setkey = chcr_authenc_setkey, + .setauthsize = chcr_authenc_setauthsize, + } + }, + { + .type = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_SUB_TYPE_AEAD_NULL, + .is_registered = 0, + .alg.aead = { + .base = { + .cra_name = "authenc(digest_null,cbc(aes))", + .cra_driver_name = + "authenc-digest_null-cbc-aes-chcr", + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct chcr_context) + + sizeof(struct chcr_aead_ctx) + + sizeof(struct chcr_authenc_ctx), + + }, + .ivsize = AES_BLOCK_SIZE, + .maxauthsize = 0, + .setkey = chcr_aead_digest_null_setkey, + .setauthsize = chcr_authenc_null_setauthsize, + } + }, }; /* @@ -1446,6 +2870,11 @@ static int chcr_unregister_alg(void) crypto_unregister_alg( &driver_algs[i].alg.crypto); break; + case CRYPTO_ALG_TYPE_AEAD: + if (driver_algs[i].is_registered) + crypto_unregister_aead( + &driver_algs[i].alg.aead); + break; case CRYPTO_ALG_TYPE_AHASH: if (driver_algs[i].is_registered) crypto_unregister_ahash( @@ -1480,6 +2909,19 @@ static int chcr_register_alg(void) err = crypto_register_alg(&driver_algs[i].alg.crypto); name = driver_algs[i].alg.crypto.cra_driver_name; break; + case CRYPTO_ALG_TYPE_AEAD: + driver_algs[i].alg.aead.base.cra_priority = + CHCR_CRA_PRIORITY; + driver_algs[i].alg.aead.base.cra_flags = + CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC; + driver_algs[i].alg.aead.encrypt = chcr_aead_encrypt; + driver_algs[i].alg.aead.decrypt = chcr_aead_decrypt; + driver_algs[i].alg.aead.init = chcr_aead_cra_init; + driver_algs[i].alg.aead.exit = chcr_aead_cra_exit; + driver_algs[i].alg.aead.base.cra_module = THIS_MODULE; + err = crypto_register_aead(&driver_algs[i].alg.aead); + name = driver_algs[i].alg.aead.base.cra_driver_name; + break; case CRYPTO_ALG_TYPE_AHASH: a_hash = &driver_algs[i].alg.hash; a_hash->update = chcr_ahash_update; diff --git a/drivers/crypto/chelsio/chcr_algo.h b/drivers/crypto/chelsio/chcr_algo.h index f2a59058b204..3c7c51f7bedf 100644 --- a/drivers/crypto/chelsio/chcr_algo.h +++ b/drivers/crypto/chelsio/chcr_algo.h @@ -258,13 +258,15 @@ enum { * where they indicate the size of the integrity check value (ICV) */ enum { - AES_CCM_ICV_4 = 4, - AES_CCM_ICV_6 = 6, - AES_CCM_ICV_8 = 8, - AES_CCM_ICV_10 = 10, - AES_CCM_ICV_12 = 12, - AES_CCM_ICV_14 = 14, - AES_CCM_ICV_16 = 16 + ICV_4 = 4, + ICV_6 = 6, + ICV_8 = 8, + ICV_10 = 10, + ICV_12 = 12, + ICV_13 = 13, + ICV_14 = 14, + ICV_15 = 15, + ICV_16 = 16 }; struct hash_op_params { diff --git a/drivers/crypto/chelsio/chcr_core.c b/drivers/crypto/chelsio/chcr_core.c index fb5f9bbfa09c..acde2de2c1e1 100644 --- a/drivers/crypto/chelsio/chcr_core.c +++ b/drivers/crypto/chelsio/chcr_core.c @@ -109,14 +109,12 @@ static int cpl_fw6_pld_handler(struct chcr_dev *dev, if (ack_err_status) { if (CHK_MAC_ERR_BIT(ack_err_status) || CHK_PAD_ERR_BIT(ack_err_status)) - error_status = -EINVAL; + error_status = -EBADMSG; } /* call completion callback with failure status */ if (req) { - if (!chcr_handle_resp(req, input, error_status)) - req->complete(req, error_status); - else - return -EINVAL; + error_status = chcr_handle_resp(req, input, error_status); + req->complete(req, error_status); } else { pr_err("Incorrect request address from the firmware\n"); return -EFAULT; diff --git a/drivers/crypto/chelsio/chcr_core.h b/drivers/crypto/chelsio/chcr_core.h index fc3cd77ad6d1..c7088a4e0a49 100644 --- a/drivers/crypto/chelsio/chcr_core.h +++ b/drivers/crypto/chelsio/chcr_core.h @@ -72,9 +72,7 @@ struct chcr_wr { }; struct chcr_dev { - /* Request submited to h/w and waiting for response. */ spinlock_t lock_chcr_dev; - struct crypto_queue pending_queue; struct uld_ctx *u_ctx; unsigned char tx_channel_id; }; diff --git a/drivers/crypto/chelsio/chcr_crypto.h b/drivers/crypto/chelsio/chcr_crypto.h index 40a5182fac90..d5af7d64a763 100644 --- a/drivers/crypto/chelsio/chcr_crypto.h +++ b/drivers/crypto/chelsio/chcr_crypto.h @@ -36,6 +36,14 @@ #ifndef __CHCR_CRYPTO_H__ #define __CHCR_CRYPTO_H__ +#define GHASH_BLOCK_SIZE 16 +#define GHASH_DIGEST_SIZE 16 + +#define CCM_B0_SIZE 16 +#define CCM_AAD_FIELD_SIZE 2 +#define T5_MAX_AAD_SIZE 512 + + /* Define following if h/w is not dropping the AAD and IV data before * giving the processed data */ @@ -63,22 +71,36 @@ #define CHCR_SCMD_AUTH_CTRL_AUTH_CIPHER 0 #define CHCR_SCMD_AUTH_CTRL_CIPHER_AUTH 1 -#define CHCR_SCMD_CIPHER_MODE_NOP 0 -#define CHCR_SCMD_CIPHER_MODE_AES_CBC 1 -#define CHCR_SCMD_CIPHER_MODE_GENERIC_AES 4 -#define CHCR_SCMD_CIPHER_MODE_AES_XTS 6 +#define CHCR_SCMD_CIPHER_MODE_NOP 0 +#define CHCR_SCMD_CIPHER_MODE_AES_CBC 1 +#define CHCR_SCMD_CIPHER_MODE_AES_GCM 2 +#define CHCR_SCMD_CIPHER_MODE_AES_CTR 3 +#define CHCR_SCMD_CIPHER_MODE_GENERIC_AES 4 +#define CHCR_SCMD_CIPHER_MODE_AES_XTS 6 +#define CHCR_SCMD_CIPHER_MODE_AES_CCM 7 #define CHCR_SCMD_AUTH_MODE_NOP 0 #define CHCR_SCMD_AUTH_MODE_SHA1 1 #define CHCR_SCMD_AUTH_MODE_SHA224 2 #define CHCR_SCMD_AUTH_MODE_SHA256 3 +#define CHCR_SCMD_AUTH_MODE_GHASH 4 #define CHCR_SCMD_AUTH_MODE_SHA512_224 5 #define CHCR_SCMD_AUTH_MODE_SHA512_256 6 #define CHCR_SCMD_AUTH_MODE_SHA512_384 7 #define CHCR_SCMD_AUTH_MODE_SHA512_512 8 +#define CHCR_SCMD_AUTH_MODE_CBCMAC 9 +#define CHCR_SCMD_AUTH_MODE_CMAC 10 #define CHCR_SCMD_HMAC_CTRL_NOP 0 #define CHCR_SCMD_HMAC_CTRL_NO_TRUNC 1 +#define CHCR_SCMD_HMAC_CTRL_TRUNC_RFC4366 2 +#define CHCR_SCMD_HMAC_CTRL_IPSEC_96BIT 3 +#define CHCR_SCMD_HMAC_CTRL_PL1 4 +#define CHCR_SCMD_HMAC_CTRL_PL2 5 +#define CHCR_SCMD_HMAC_CTRL_PL3 6 +#define CHCR_SCMD_HMAC_CTRL_DIV2 7 +#define VERIFY_HW 0 +#define VERIFY_SW 1 #define CHCR_SCMD_IVGEN_CTRL_HW 0 #define CHCR_SCMD_IVGEN_CTRL_SW 1 @@ -106,12 +128,20 @@ #define IV_IMMEDIATE 1 #define IV_DSGL 2 +#define AEAD_H_SIZE 16 + #define CRYPTO_ALG_SUB_TYPE_MASK 0x0f000000 #define CRYPTO_ALG_SUB_TYPE_HASH_HMAC 0x01000000 +#define CRYPTO_ALG_SUB_TYPE_AEAD_RFC4106 0x02000000 +#define CRYPTO_ALG_SUB_TYPE_AEAD_GCM 0x03000000 +#define CRYPTO_ALG_SUB_TYPE_AEAD_AUTHENC 0x04000000 +#define CRYPTO_ALG_SUB_TYPE_AEAD_CCM 0x05000000 +#define CRYPTO_ALG_SUB_TYPE_AEAD_RFC4309 0x06000000 +#define CRYPTO_ALG_SUB_TYPE_AEAD_NULL 0x07000000 +#define CRYPTO_ALG_SUB_TYPE_CTR 0x08000000 #define CRYPTO_ALG_TYPE_HMAC (CRYPTO_ALG_TYPE_AHASH |\ CRYPTO_ALG_SUB_TYPE_HASH_HMAC) -#define MAX_SALT 4 #define MAX_SCRATCH_PAD_SIZE 32 #define CHCR_HASH_MAX_BLOCK_SIZE_64 64 @@ -126,6 +156,42 @@ struct ablk_ctx { unsigned char ciph_mode; u8 rrkey[AES_MAX_KEY_SIZE]; }; +struct chcr_aead_reqctx { + struct sk_buff *skb; + short int dst_nents; + u16 verify; + u8 iv[CHCR_MAX_CRYPTO_IV_LEN]; + unsigned char scratch_pad[MAX_SCRATCH_PAD_SIZE]; +}; + +struct chcr_gcm_ctx { + u8 ghash_h[AEAD_H_SIZE]; +}; + +struct chcr_authenc_ctx { + u8 dec_rrkey[AES_MAX_KEY_SIZE]; + u8 h_iopad[2 * CHCR_HASH_MAX_DIGEST_SIZE]; + unsigned char auth_mode; +}; + +struct __aead_ctx { + struct chcr_gcm_ctx gcm[0]; + struct chcr_authenc_ctx authenc[0]; +}; + + + +struct chcr_aead_ctx { + __be32 key_ctx_hdr; + unsigned int enckey_len; + struct crypto_skcipher *null; + u8 salt[MAX_SALT]; + u8 key[CHCR_AES_MAX_KEY_LEN]; + u16 hmac_ctrl; + u16 mayverify; + struct __aead_ctx ctx[0]; +}; + struct hmac_ctx { @@ -137,6 +203,7 @@ struct hmac_ctx { struct __crypto_ctx { struct hmac_ctx hmacctx[0]; struct ablk_ctx ablkctx[0]; + struct chcr_aead_ctx aeadctx[0]; }; struct chcr_context { @@ -171,16 +238,19 @@ struct chcr_alg_template { union { struct crypto_alg crypto; struct ahash_alg hash; + struct aead_alg aead; } alg; }; struct chcr_req_ctx { union { struct ahash_request *ahash_req; + struct aead_request *aead_req; struct ablkcipher_request *ablk_req; } req; union { struct chcr_ahash_req_ctx *ahash_ctx; + struct chcr_aead_reqctx *reqctx; struct chcr_blkcipher_req_ctx *ablk_ctx; } ctx; }; @@ -190,9 +260,15 @@ struct sge_opaque_hdr { dma_addr_t addr[MAX_SKB_FRAGS + 1]; }; -typedef struct sk_buff *(*create_wr_t)(struct crypto_async_request *req, - struct chcr_context *ctx, +typedef struct sk_buff *(*create_wr_t)(struct aead_request *req, unsigned short qid, + int size, unsigned short op_type); +static int chcr_aead_op(struct aead_request *req_base, + unsigned short op_type, + int size, + create_wr_t create_wr_fn); +static inline int get_aead_subtype(struct crypto_aead *aead); + #endif /* __CHCR_CRYPTO_H__ */ -- cgit v1.2.3 From 2aa488a6bc6a13d7aed6dbcfa5aab31ec09eaeba Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 22 Nov 2016 15:30:54 +0100 Subject: misc: sram: remove useless #ifdef A recent patch added a new function that is now unused whenever CONFIG_OF is disabled: drivers/misc/sram.c:342:12: error: 'atmel_securam_wait' defined but not used [-Werror=unused-function] There is actually no reason for the #ifdef, because the driver currently cannot be used in a meaningful way without CONFIG_OF, and there is no compile-time dependency. Removing that #ifdef and the respective of_match_ptr() avoids the warning and simplifies the driver slightly. Fixes: 2ae2e28852f2 ("misc: sram: add Atmel securam support") Reviewed-by: Vladimir Zapolskiy Signed-off-by: Arnd Bergmann --- drivers/misc/sram.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/misc/sram.c b/drivers/misc/sram.c index b0d4dd9b0586..b33ab8ce47ab 100644 --- a/drivers/misc/sram.c +++ b/drivers/misc/sram.c @@ -353,13 +353,11 @@ static int atmel_securam_wait(void) 10000, 500000); } -#ifdef CONFIG_OF static const struct of_device_id sram_dt_ids[] = { { .compatible = "mmio-sram" }, { .compatible = "atmel,sama5d2-securam", .data = atmel_securam_wait }, {} }; -#endif static int sram_probe(struct platform_device *pdev) { @@ -443,7 +441,7 @@ static int sram_remove(struct platform_device *pdev) static struct platform_driver sram_driver = { .driver = { .name = "sram", - .of_match_table = of_match_ptr(sram_dt_ids), + .of_match_table = sram_dt_ids, }, .probe = sram_probe, .remove = sram_remove, -- cgit v1.2.3 From a64ea311f1e4bc090c89960650637423e86c35c0 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 29 Nov 2016 17:42:13 -0800 Subject: Input: synaptics-rmi4 - add rmi_enable/disable_irq Set the .enabled boolean and trigger an event processing when enabling for edge-triggered systems. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 83 +++++++++++++++++++++++++++++++---------- drivers/input/rmi4/rmi_driver.h | 2 + include/linux/rmi.h | 1 + 3 files changed, 67 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 2b17d8cb3d10..f04fc4152c1f 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -215,6 +215,7 @@ static irqreturn_t rmi_irq_fn(int irq, void *dev_id) static int rmi_irq_init(struct rmi_device *rmi_dev) { struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); + struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); int irq_flags = irq_get_trigger_type(pdata->irq); int ret; @@ -232,6 +233,8 @@ static int rmi_irq_init(struct rmi_device *rmi_dev) return ret; } + data->enabled = true; + return 0; } @@ -866,17 +869,54 @@ err_put_fn: return error; } -int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake) +void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake) { struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); + struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); int irq = pdata->irq; - int retval = 0; + int irq_flags; + int retval; - retval = rmi_suspend_functions(rmi_dev); - if (retval) - dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", - retval); + mutex_lock(&data->enabled_mutex); + + if (data->enabled) + goto out; + + enable_irq(irq); + data->enabled = true; + if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) { + retval = disable_irq_wake(irq); + if (!retval) + dev_warn(&rmi_dev->dev, + "Failed to disable irq for wake: %d\n", + retval); + } + + /* + * Call rmi_process_interrupt_requests() after enabling irq, + * otherwise we may lose interrupt on edge-triggered systems. + */ + irq_flags = irq_get_trigger_type(pdata->irq); + if (irq_flags & IRQ_TYPE_EDGE_BOTH) + rmi_process_interrupt_requests(rmi_dev); + +out: + mutex_unlock(&data->enabled_mutex); +} + +void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake) +{ + struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); + struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); + int irq = pdata->irq; + int retval; + + mutex_lock(&data->enabled_mutex); + + if (!data->enabled) + goto out; + data->enabled = false; disable_irq(irq); if (enable_wake && device_may_wakeup(rmi_dev->xport->dev)) { retval = enable_irq_wake(irq); @@ -885,24 +925,30 @@ int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake) "Failed to enable irq for wake: %d\n", retval); } + +out: + mutex_unlock(&data->enabled_mutex); +} + +int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake) +{ + int retval; + + retval = rmi_suspend_functions(rmi_dev); + if (retval) + dev_warn(&rmi_dev->dev, "Failed to suspend functions: %d\n", + retval); + + rmi_disable_irq(rmi_dev, enable_wake); return retval; } EXPORT_SYMBOL_GPL(rmi_driver_suspend); int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake) { - struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); - int irq = pdata->irq; int retval; - enable_irq(irq); - if (clear_wake && device_may_wakeup(rmi_dev->xport->dev)) { - retval = disable_irq_wake(irq); - if (!retval) - dev_warn(&rmi_dev->dev, - "Failed to disable irq for wake: %d\n", - retval); - } + rmi_enable_irq(rmi_dev, clear_wake); retval = rmi_resume_functions(rmi_dev); if (retval) @@ -916,10 +962,8 @@ EXPORT_SYMBOL_GPL(rmi_driver_resume); static int rmi_driver_remove(struct device *dev) { struct rmi_device *rmi_dev = to_rmi_device(dev); - struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); - int irq = pdata->irq; - disable_irq(irq); + rmi_disable_irq(rmi_dev, false); rmi_f34_remove_sysfs(rmi_dev); rmi_free_function_list(rmi_dev); @@ -1108,6 +1152,7 @@ static int rmi_driver_probe(struct device *dev) } mutex_init(&data->irq_mutex); + mutex_init(&data->enabled_mutex); retval = rmi_probe_interrupts(data); if (retval) diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index 5b201f369505..c9fe3d3deef3 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -101,6 +101,8 @@ int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, int (*callback)(struct rmi_device *rmi_dev, void *ctx, const struct pdt_entry *entry)); int rmi_probe_interrupts(struct rmi_driver_data *data); +void rmi_enable_irq(struct rmi_device *rmi_dev, bool clear_wake); +void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake); int rmi_init_functions(struct rmi_driver_data *data); int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx, const struct pdt_entry *pdt); diff --git a/include/linux/rmi.h b/include/linux/rmi.h index 0b118ab47b8d..621f098f1243 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -356,6 +356,7 @@ struct rmi_driver_data { u8 num_tx_electrodes; bool enabled; + struct mutex enabled_mutex; }; int rmi_register_transport_device(struct rmi_transport_dev *xport); -- cgit v1.2.3 From 037b3af6bf84a404a8c6dbe0a7dd551f1b95b530 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 29 Nov 2016 17:38:58 -0800 Subject: Input: drv2665 - fix misuse of regmap_update_bits Using regmap_update_bits(..., mask, 1) with 'mask' following (1 << k) and k greater than 0 is wrong. Indeed, _regmap_update_bits will perform (mask & 1), which results in 0 if LSB of mask is 0. Thus the call regmap_update_bits(..., mask, 1) is in reality equivalent to regmap_update_bits(..., mask, 0). In such a case, the correct use is regmap_update_bits(..., mask, mask). This driver is performing such a mistake with the DRV2665_STANDBY mask, which equals BIT(6). Fix the driver to make it consistent with the API, and fix the alignment problem at the same time. Please note that this change is untested, as I do not have this piece of hardware. Testers are welcome! Signed-off-by: Florian Vaussard Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv2665.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/drv2665.c b/drivers/input/misc/drv2665.c index ef9bc12b3be3..dcb6d8e94b11 100644 --- a/drivers/input/misc/drv2665.c +++ b/drivers/input/misc/drv2665.c @@ -125,8 +125,8 @@ static void drv2665_close(struct input_dev *input) cancel_work_sync(&haptics->work); - error = regmap_update_bits(haptics->regmap, - DRV2665_CTRL_2, DRV2665_STANDBY, 1); + error = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, + DRV2665_STANDBY, DRV2665_STANDBY); if (error) dev_err(&haptics->client->dev, "Failed to enter standby mode: %d\n", error); @@ -240,7 +240,7 @@ static int __maybe_unused drv2665_suspend(struct device *dev) if (haptics->input_dev->users) { ret = regmap_update_bits(haptics->regmap, DRV2665_CTRL_2, - DRV2665_STANDBY, 1); + DRV2665_STANDBY, DRV2665_STANDBY); if (ret) { dev_err(dev, "Failed to set standby mode\n"); regulator_disable(haptics->regulator); -- cgit v1.2.3 From 6473bbfd7e85a9f834ed668b4daa31638c73ff53 Mon Sep 17 00:00:00 2001 From: Florian Vaussard Date: Tue, 29 Nov 2016 17:39:25 -0800 Subject: Input: drv2667 - fix misuse of regmap_update_bits Using regmap_update_bits(..., mask, 1) with 'mask' following (1 << k) and k greater than 0 is wrong. Indeed, _regmap_update_bits will perform (mask & 1), which results in 0 if LSB of mask is 0. Thus the call regmap_update_bits(..., mask, 1) is in reality equivalent to regmap_update_bits(..., mask, 0). In such a case, the correct use is regmap_update_bits(..., mask, mask). This driver is performing such a mistake with the DRV2667_STANDBY mask, which equals (1 << 6). Fix the driver to make it consistent with the API, and fix the alignment problem at the same time. Please note that this change is untested, as I do not have this piece of hardware. Testers are welcome! Signed-off-by: Florian Vaussard Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv2667.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c index d5ba7481328c..2849bb6906a8 100644 --- a/drivers/input/misc/drv2667.c +++ b/drivers/input/misc/drv2667.c @@ -256,7 +256,7 @@ static void drv2667_close(struct input_dev *input) cancel_work_sync(&haptics->work); error = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, - DRV2667_STANDBY, 1); + DRV2667_STANDBY, DRV2667_STANDBY); if (error) dev_err(&haptics->client->dev, "Failed to enter standby mode: %d\n", error); @@ -415,7 +415,7 @@ static int __maybe_unused drv2667_suspend(struct device *dev) if (haptics->input_dev->users) { ret = regmap_update_bits(haptics->regmap, DRV2667_CTRL_2, - DRV2667_STANDBY, 1); + DRV2667_STANDBY, DRV2667_STANDBY); if (ret) { dev_err(dev, "Failed to set standby mode\n"); regulator_disable(haptics->regulator); -- cgit v1.2.3 From c4c9a040ecb7297e011e579f5a9cc280e42d725f Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Mon, 31 Oct 2016 13:46:38 -0700 Subject: clocksource: import ARC timer driver This adds support for - CONFIG_ARC_TIMERS : legacy 32-bit TIMER0 and TIMER1 which count UP from @CNT to @LIMIT, before optionally triggering an interrupt. These are programmed using ARC auxiliary register interface. These are present in all ARC cores (ARC700 and ARC HS38) TIMER0 serves as clockevent for all ARC linux builds. TIMER1 is used for clocksource in arc700 builds. - CONFIG_ARC_TIMERS_64BIT: 64-bit counters, RTC and GFRC found in ARC HS38 cores. These are independnet IP blocks with different programming model respectively. Link: http://lkml.kernel.org/r/20161111231132.GA4186@mai Acked-by: Daniel Lezcano Signed-off-by: Vineet Gupta --- MAINTAINERS | 1 + arch/arc/Kconfig | 7 +- arch/arc/kernel/Makefile | 2 +- arch/arc/kernel/time.c | 351 ---------------------------------------- drivers/clocksource/Kconfig | 20 +++ drivers/clocksource/Makefile | 1 + drivers/clocksource/arc_timer.c | 336 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 361 insertions(+), 357 deletions(-) delete mode 100644 arch/arc/kernel/time.c create mode 100644 drivers/clocksource/arc_timer.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 8d4148406923..34160a2dd131 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11662,6 +11662,7 @@ S: Supported F: arch/arc/ F: Documentation/devicetree/bindings/arc/* F: Documentation/devicetree/bindings/interrupt-controller/snps,arc* +F: drivers/clocksource/arc_timer.c F: drivers/tty/serial/arc_uart.c T: git git://git.kernel.org/pub/scm/linux/kernel/git/vgupta/arc.git diff --git a/arch/arc/Kconfig b/arch/arc/Kconfig index bde3e558d8bc..ab12723d39a0 100644 --- a/arch/arc/Kconfig +++ b/arch/arc/Kconfig @@ -8,9 +8,9 @@ config ARC def_bool y + select ARC_TIMERS select ARCH_SUPPORTS_ATOMIC_RMW if ARC_HAS_LLSC select BUILDTIME_EXTABLE_SORT - select CLKSRC_OF select CLONE_BACKWARDS select COMMON_CLK select GENERIC_ATOMIC64 if !ISA_ARCV2 || !(ARC_HAS_LL64 && ARC_HAS_LLSC) @@ -115,6 +115,7 @@ config ISA_ARCOMPACT config ISA_ARCV2 bool "ARC ISA v2" + select ARC_TIMERS_64BIT help ISA for the Next Generation ARC-HS cores @@ -410,10 +411,6 @@ config ARC_HAS_DIV_REM bool "Insn: div, divu, rem, remu" default y -config ARC_TIMERS_64BIT - bool "64-bit r/o cycle counters RTC (up) and GFRC (smp)" - default y - config ARC_NUMBER_OF_INTERRUPTS int "Number of interrupts" range 8 240 diff --git a/arch/arc/kernel/Makefile b/arch/arc/kernel/Makefile index cfcdedf52ff8..8942c5c3b4c5 100644 --- a/arch/arc/kernel/Makefile +++ b/arch/arc/kernel/Makefile @@ -8,7 +8,7 @@ # Pass UTS_MACHINE for user_regset definition CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"' -obj-y := arcksyms.o setup.o irq.o time.o reset.o ptrace.o process.o devtree.o +obj-y := arcksyms.o setup.o irq.o reset.o ptrace.o process.o devtree.o obj-y += signal.o traps.o sys.o troubleshoot.o stacktrace.o disasm.o obj-$(CONFIG_ISA_ARCOMPACT) += entry-compact.o intc-compact.o obj-$(CONFIG_ISA_ARCV2) += entry-arcv2.o intc-arcv2.o diff --git a/arch/arc/kernel/time.c b/arch/arc/kernel/time.c deleted file mode 100644 index 94b9cd169374..000000000000 --- a/arch/arc/kernel/time.c +++ /dev/null @@ -1,351 +0,0 @@ -/* - * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) - * - * 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. - * - * vineetg: Jan 1011 - * -sched_clock( ) no longer jiffies based. Uses the same clocksource - * as gtod - * - * Rajeshwarr/Vineetg: Mar 2008 - * -Implemented CONFIG_GENERIC_TIME (rather deleted arch specific code) - * for arch independent gettimeofday() - * -Implemented CONFIG_GENERIC_CLOCKEVENTS as base for hrtimers - * - * Vineetg: Mar 2008: Forked off from time.c which now is time-jiff.c - */ - -/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1 - * Each can programmed to go from @count to @limit and optionally - * interrupt when that happens. - * A write to Control Register clears the Interrupt - * - * We've designated TIMER0 for events (clockevents) - * while TIMER1 for free running (clocksource) - * - * Newer ARC700 cores have 64bit clk fetching RTSC insn, preferred over TIMER1 - * which however is currently broken - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -static unsigned long arc_timer_freq; - -static int noinline arc_get_timer_clk(struct device_node *node) -{ - struct clk *clk; - int ret; - - clk = of_clk_get(node, 0); - if (IS_ERR(clk)) { - pr_err("timer missing clk"); - return PTR_ERR(clk); - } - - ret = clk_prepare_enable(clk); - if (ret) { - pr_err("Couldn't enable parent clk\n"); - return ret; - } - - arc_timer_freq = clk_get_rate(clk); - - return 0; -} - -/********** Clock Source Device *********/ - -#ifdef CONFIG_ARC_TIMERS_64BIT - -static cycle_t arc_read_gfrc(struct clocksource *cs) -{ - unsigned long flags; - u32 l, h; - - local_irq_save(flags); - - __mcip_cmd(CMD_GFRC_READ_LO, 0); - l = read_aux_reg(ARC_REG_MCIP_READBACK); - - __mcip_cmd(CMD_GFRC_READ_HI, 0); - h = read_aux_reg(ARC_REG_MCIP_READBACK); - - local_irq_restore(flags); - - return (((cycle_t)h) << 32) | l; -} - -static struct clocksource arc_counter_gfrc = { - .name = "ARConnect GFRC", - .rating = 400, - .read = arc_read_gfrc, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init arc_cs_setup_gfrc(struct device_node *node) -{ - struct mcip_bcr mp; - int ret; - - READ_BCR(ARC_REG_MCIP_BCR, mp); - if (!mp.gfrc) { - pr_warn("Global-64-bit-Ctr clocksource not detected"); - return -ENXIO; - } - - ret = arc_get_timer_clk(node); - if (ret) - return ret; - - return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); -} -CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); - -#define AUX_RTC_CTRL 0x103 -#define AUX_RTC_LOW 0x104 -#define AUX_RTC_HIGH 0x105 - -static cycle_t arc_read_rtc(struct clocksource *cs) -{ - unsigned long status; - u32 l, h; - - /* - * hardware has an internal state machine which tracks readout of - * low/high and updates the CTRL.status if - * - interrupt/exception taken between the two reads - * - high increments after low has been read - */ - do { - l = read_aux_reg(AUX_RTC_LOW); - h = read_aux_reg(AUX_RTC_HIGH); - status = read_aux_reg(AUX_RTC_CTRL); - } while (!(status & _BITUL(31))); - - return (((cycle_t)h) << 32) | l; -} - -static struct clocksource arc_counter_rtc = { - .name = "ARCv2 RTC", - .rating = 350, - .read = arc_read_rtc, - .mask = CLOCKSOURCE_MASK(64), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init arc_cs_setup_rtc(struct device_node *node) -{ - struct bcr_timer timer; - int ret; - - READ_BCR(ARC_REG_TIMERS_BCR, timer); - if (!timer.rtc) { - pr_warn("Local-64-bit-Ctr clocksource not detected"); - return -ENXIO; - } - - /* Local to CPU hence not usable in SMP */ - if (IS_ENABLED(CONFIG_SMP)) { - pr_warn("Local-64-bit-Ctr not usable in SMP"); - return -EINVAL; - } - - ret = arc_get_timer_clk(node); - if (ret) - return ret; - - write_aux_reg(AUX_RTC_CTRL, 1); - - return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); -} -CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); - -#endif - -/* - * 32bit TIMER1 to keep counting monotonically and wraparound - */ - -static cycle_t arc_read_timer1(struct clocksource *cs) -{ - return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT); -} - -static struct clocksource arc_counter_timer1 = { - .name = "ARC Timer1", - .rating = 300, - .read = arc_read_timer1, - .mask = CLOCKSOURCE_MASK(32), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; - -static int __init arc_cs_setup_timer1(struct device_node *node) -{ - int ret; - - /* Local to CPU hence not usable in SMP */ - if (IS_ENABLED(CONFIG_SMP)) - return -EINVAL; - - ret = arc_get_timer_clk(node); - if (ret) - return ret; - - write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMERN_MAX); - write_aux_reg(ARC_REG_TIMER1_CNT, 0); - write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); - - return clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); -} - -/********** Clock Event Device *********/ - -static int arc_timer_irq; - -/* - * Arm the timer to interrupt after @cycles - * The distinction for oneshot/periodic is done in arc_event_timer_ack() below - */ -static void arc_timer_event_setup(unsigned int cycles) -{ - write_aux_reg(ARC_REG_TIMER0_LIMIT, cycles); - write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ - - write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); -} - - -static int arc_clkevent_set_next_event(unsigned long delta, - struct clock_event_device *dev) -{ - arc_timer_event_setup(delta); - return 0; -} - -static int arc_clkevent_set_periodic(struct clock_event_device *dev) -{ - /* - * At X Hz, 1 sec = 1000ms -> X cycles; - * 10ms -> X / 100 cycles - */ - arc_timer_event_setup(arc_timer_freq / HZ); - return 0; -} - -static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { - .name = "ARC Timer0", - .features = CLOCK_EVT_FEAT_ONESHOT | - CLOCK_EVT_FEAT_PERIODIC, - .rating = 300, - .set_next_event = arc_clkevent_set_next_event, - .set_state_periodic = arc_clkevent_set_periodic, -}; - -static irqreturn_t timer_irq_handler(int irq, void *dev_id) -{ - /* - * Note that generic IRQ core could have passed @evt for @dev_id if - * irq_set_chip_and_handler() asked for handle_percpu_devid_irq() - */ - struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - int irq_reenable = clockevent_state_periodic(evt); - - /* - * Any write to CTRL reg ACks the interrupt, we rewrite the - * Count when [N]ot [H]alted bit. - * And re-arm it if perioid by [I]nterrupt [E]nable bit - */ - write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH); - - evt->event_handler(evt); - - return IRQ_HANDLED; -} - - -static int arc_timer_starting_cpu(unsigned int cpu) -{ - struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - - evt->cpumask = cpumask_of(smp_processor_id()); - - clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMERN_MAX); - enable_percpu_irq(arc_timer_irq, 0); - return 0; -} - -static int arc_timer_dying_cpu(unsigned int cpu) -{ - disable_percpu_irq(arc_timer_irq); - return 0; -} - -/* - * clockevent setup for boot CPU - */ -static int __init arc_clockevent_setup(struct device_node *node) -{ - struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); - int ret; - - arc_timer_irq = irq_of_parse_and_map(node, 0); - if (arc_timer_irq <= 0) { - pr_err("clockevent: missing irq"); - return -EINVAL; - } - - ret = arc_get_timer_clk(node); - if (ret) { - pr_err("clockevent: missing clk"); - return ret; - } - - /* Needs apriori irq_set_percpu_devid() done in intc map function */ - ret = request_percpu_irq(arc_timer_irq, timer_irq_handler, - "Timer0 (per-cpu-tick)", evt); - if (ret) { - pr_err("clockevent: unable to request irq\n"); - return ret; - } - - ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING, - "AP_ARC_TIMER_STARTING", - arc_timer_starting_cpu, - arc_timer_dying_cpu); - if (ret) { - pr_err("Failed to setup hotplug state"); - return ret; - } - return 0; -} - -static int __init arc_of_timer_init(struct device_node *np) -{ - static int init_count = 0; - int ret; - - if (!init_count) { - init_count = 1; - ret = arc_clockevent_setup(np); - } else { - ret = arc_cs_setup_timer1(np); - } - - return ret; -} -CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index e2c6e43cf8ca..4866f7aa32e6 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig @@ -282,6 +282,26 @@ config CLKSRC_MPS2 select CLKSRC_MMIO select CLKSRC_OF +config ARC_TIMERS + bool "Support for 32-bit TIMERn counters in ARC Cores" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + select CLKSRC_OF + help + These are legacy 32-bit TIMER0 and TIMER1 counters found on all ARC cores + (ARC700 as well as ARC HS38). + TIMER0 serves as clockevent while TIMER1 provides clocksource + +config ARC_TIMERS_64BIT + bool "Support for 64-bit counters in ARC HS38 cores" if COMPILE_TEST + depends on GENERIC_CLOCKEVENTS + depends on ARC_TIMERS + select CLKSRC_OF + help + This enables 2 different 64-bit timers: RTC (for UP) and GFRC (for SMP) + RTC is implemented inside the core, while GFRC sits outside the core in + ARConnect IP block. Driver automatically picks one of them for clocksource + as appropriate. + config ARM_ARCH_TIMER bool select CLKSRC_OF if OF diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile index cf87f407f1ad..a14111e1f087 100644 --- a/drivers/clocksource/Makefile +++ b/drivers/clocksource/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o +obj-$(CONFIG_ARC_TIMERS) += arc_timer.o obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o diff --git a/drivers/clocksource/arc_timer.c b/drivers/clocksource/arc_timer.c new file mode 100644 index 000000000000..a49748d826c0 --- /dev/null +++ b/drivers/clocksource/arc_timer.c @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2016-17 Synopsys, Inc. (www.synopsys.com) + * Copyright (C) 2004, 2007-2010, 2011-2012 Synopsys, Inc. (www.synopsys.com) + * + * 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. + */ + +/* ARC700 has two 32bit independent prog Timers: TIMER0 and TIMER1, Each can be + * programmed to go from @count to @limit and optionally interrupt. + * We've designated TIMER0 for clockevents and TIMER1 for clocksource + * + * ARCv2 based HS38 cores have RTC (in-core) and GFRC (inside ARConnect/MCIP) + * which are suitable for UP and SMP based clocksources respectively + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static unsigned long arc_timer_freq; + +static int noinline arc_get_timer_clk(struct device_node *node) +{ + struct clk *clk; + int ret; + + clk = of_clk_get(node, 0); + if (IS_ERR(clk)) { + pr_err("timer missing clk"); + return PTR_ERR(clk); + } + + ret = clk_prepare_enable(clk); + if (ret) { + pr_err("Couldn't enable parent clk\n"); + return ret; + } + + arc_timer_freq = clk_get_rate(clk); + + return 0; +} + +/********** Clock Source Device *********/ + +#ifdef CONFIG_ARC_TIMERS_64BIT + +static cycle_t arc_read_gfrc(struct clocksource *cs) +{ + unsigned long flags; + u32 l, h; + + local_irq_save(flags); + + __mcip_cmd(CMD_GFRC_READ_LO, 0); + l = read_aux_reg(ARC_REG_MCIP_READBACK); + + __mcip_cmd(CMD_GFRC_READ_HI, 0); + h = read_aux_reg(ARC_REG_MCIP_READBACK); + + local_irq_restore(flags); + + return (((cycle_t)h) << 32) | l; +} + +static struct clocksource arc_counter_gfrc = { + .name = "ARConnect GFRC", + .rating = 400, + .read = arc_read_gfrc, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int __init arc_cs_setup_gfrc(struct device_node *node) +{ + struct mcip_bcr mp; + int ret; + + READ_BCR(ARC_REG_MCIP_BCR, mp); + if (!mp.gfrc) { + pr_warn("Global-64-bit-Ctr clocksource not detected"); + return -ENXIO; + } + + ret = arc_get_timer_clk(node); + if (ret) + return ret; + + return clocksource_register_hz(&arc_counter_gfrc, arc_timer_freq); +} +CLOCKSOURCE_OF_DECLARE(arc_gfrc, "snps,archs-timer-gfrc", arc_cs_setup_gfrc); + +#define AUX_RTC_CTRL 0x103 +#define AUX_RTC_LOW 0x104 +#define AUX_RTC_HIGH 0x105 + +static cycle_t arc_read_rtc(struct clocksource *cs) +{ + unsigned long status; + u32 l, h; + + /* + * hardware has an internal state machine which tracks readout of + * low/high and updates the CTRL.status if + * - interrupt/exception taken between the two reads + * - high increments after low has been read + */ + do { + l = read_aux_reg(AUX_RTC_LOW); + h = read_aux_reg(AUX_RTC_HIGH); + status = read_aux_reg(AUX_RTC_CTRL); + } while (!(status & _BITUL(31))); + + return (((cycle_t)h) << 32) | l; +} + +static struct clocksource arc_counter_rtc = { + .name = "ARCv2 RTC", + .rating = 350, + .read = arc_read_rtc, + .mask = CLOCKSOURCE_MASK(64), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int __init arc_cs_setup_rtc(struct device_node *node) +{ + struct bcr_timer timer; + int ret; + + READ_BCR(ARC_REG_TIMERS_BCR, timer); + if (!timer.rtc) { + pr_warn("Local-64-bit-Ctr clocksource not detected"); + return -ENXIO; + } + + /* Local to CPU hence not usable in SMP */ + if (IS_ENABLED(CONFIG_SMP)) { + pr_warn("Local-64-bit-Ctr not usable in SMP"); + return -EINVAL; + } + + ret = arc_get_timer_clk(node); + if (ret) + return ret; + + write_aux_reg(AUX_RTC_CTRL, 1); + + return clocksource_register_hz(&arc_counter_rtc, arc_timer_freq); +} +CLOCKSOURCE_OF_DECLARE(arc_rtc, "snps,archs-timer-rtc", arc_cs_setup_rtc); + +#endif + +/* + * 32bit TIMER1 to keep counting monotonically and wraparound + */ + +static cycle_t arc_read_timer1(struct clocksource *cs) +{ + return (cycle_t) read_aux_reg(ARC_REG_TIMER1_CNT); +} + +static struct clocksource arc_counter_timer1 = { + .name = "ARC Timer1", + .rating = 300, + .read = arc_read_timer1, + .mask = CLOCKSOURCE_MASK(32), + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static int __init arc_cs_setup_timer1(struct device_node *node) +{ + int ret; + + /* Local to CPU hence not usable in SMP */ + if (IS_ENABLED(CONFIG_SMP)) + return -EINVAL; + + ret = arc_get_timer_clk(node); + if (ret) + return ret; + + write_aux_reg(ARC_REG_TIMER1_LIMIT, ARC_TIMERN_MAX); + write_aux_reg(ARC_REG_TIMER1_CNT, 0); + write_aux_reg(ARC_REG_TIMER1_CTRL, TIMER_CTRL_NH); + + return clocksource_register_hz(&arc_counter_timer1, arc_timer_freq); +} + +/********** Clock Event Device *********/ + +static int arc_timer_irq; + +/* + * Arm the timer to interrupt after @cycles + * The distinction for oneshot/periodic is done in arc_event_timer_ack() below + */ +static void arc_timer_event_setup(unsigned int cycles) +{ + write_aux_reg(ARC_REG_TIMER0_LIMIT, cycles); + write_aux_reg(ARC_REG_TIMER0_CNT, 0); /* start from 0 */ + + write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH); +} + + +static int arc_clkevent_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + arc_timer_event_setup(delta); + return 0; +} + +static int arc_clkevent_set_periodic(struct clock_event_device *dev) +{ + /* + * At X Hz, 1 sec = 1000ms -> X cycles; + * 10ms -> X / 100 cycles + */ + arc_timer_event_setup(arc_timer_freq / HZ); + return 0; +} + +static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = { + .name = "ARC Timer0", + .features = CLOCK_EVT_FEAT_ONESHOT | + CLOCK_EVT_FEAT_PERIODIC, + .rating = 300, + .set_next_event = arc_clkevent_set_next_event, + .set_state_periodic = arc_clkevent_set_periodic, +}; + +static irqreturn_t timer_irq_handler(int irq, void *dev_id) +{ + /* + * Note that generic IRQ core could have passed @evt for @dev_id if + * irq_set_chip_and_handler() asked for handle_percpu_devid_irq() + */ + struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); + int irq_reenable = clockevent_state_periodic(evt); + + /* + * Any write to CTRL reg ACks the interrupt, we rewrite the + * Count when [N]ot [H]alted bit. + * And re-arm it if perioid by [I]nterrupt [E]nable bit + */ + write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH); + + evt->event_handler(evt); + + return IRQ_HANDLED; +} + + +static int arc_timer_starting_cpu(unsigned int cpu) +{ + struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); + + evt->cpumask = cpumask_of(smp_processor_id()); + + clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMERN_MAX); + enable_percpu_irq(arc_timer_irq, 0); + return 0; +} + +static int arc_timer_dying_cpu(unsigned int cpu) +{ + disable_percpu_irq(arc_timer_irq); + return 0; +} + +/* + * clockevent setup for boot CPU + */ +static int __init arc_clockevent_setup(struct device_node *node) +{ + struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device); + int ret; + + arc_timer_irq = irq_of_parse_and_map(node, 0); + if (arc_timer_irq <= 0) { + pr_err("clockevent: missing irq"); + return -EINVAL; + } + + ret = arc_get_timer_clk(node); + if (ret) { + pr_err("clockevent: missing clk"); + return ret; + } + + /* Needs apriori irq_set_percpu_devid() done in intc map function */ + ret = request_percpu_irq(arc_timer_irq, timer_irq_handler, + "Timer0 (per-cpu-tick)", evt); + if (ret) { + pr_err("clockevent: unable to request irq\n"); + return ret; + } + + ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING, + "AP_ARC_TIMER_STARTING", + arc_timer_starting_cpu, + arc_timer_dying_cpu); + if (ret) { + pr_err("Failed to setup hotplug state"); + return ret; + } + return 0; +} + +static int __init arc_of_timer_init(struct device_node *np) +{ + static int init_count = 0; + int ret; + + if (!init_count) { + init_count = 1; + ret = arc_clockevent_setup(np); + } else { + ret = arc_cs_setup_timer1(np); + } + + return ret; +} +CLOCKSOURCE_OF_DECLARE(arc_clkevt, "snps,arc-timer", arc_of_timer_init); -- cgit v1.2.3 From 0465fb495f9c9698de08ff103905008e5f38e8f1 Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Wed, 16 Nov 2016 08:31:12 +0200 Subject: clocksource: update "fn" at CLOCKSOURCE_OF_DECLARE() of nps400 timer nps_setup_clocksource() should take node as only argument as defined by typedef int (*of_init_fn_1_ret)(struct device_node *) Therefore need to replace: int __init nps_setup_clocksource(struct device_node *node, struct clk *clk) with int __init nps_setup_clocksource(struct device_node *node) This patch also serve as preparation for next patch which add support for clockevents to nps400. Specifically we add new function nps_get_timer_clk() to serve clocksource and later clockevent registration. Signed-off-by: Noam Camus Acked-by: Daniel Lezcano --- drivers/clocksource/timer-nps.c | 65 ++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index 70c149af8ee0..0c8e21f905d7 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -46,7 +46,35 @@ /* This array is per cluster of CPUs (Each NPS400 cluster got 256 CPUs) */ static void *nps_msu_reg_low_addr[NPS_CLUSTER_NUM] __read_mostly; -static unsigned long nps_timer_rate; +static int __init nps_get_timer_clk(struct device_node *node, + unsigned long *timer_freq, + struct clk **clk) +{ + int ret; + + *clk = of_clk_get(node, 0); + if (IS_ERR(*clk)) { + pr_err("timer missing clk"); + return PTR_ERR(*clk); + } + + ret = clk_prepare_enable(*clk); + if (ret) { + pr_err("Couldn't enable parent clk\n"); + clk_put(*clk); + return ret; + } + + *timer_freq = clk_get_rate(*clk); + if (!(*timer_freq)) { + pr_err("Couldn't get clk rate\n"); + clk_disable_unprepare(*clk); + clk_put(*clk); + return -EINVAL; + } + + return 0; +} static cycle_t nps_clksrc_read(struct clocksource *clksrc) { @@ -55,26 +83,24 @@ static cycle_t nps_clksrc_read(struct clocksource *clksrc) return (cycle_t)ioread32be(nps_msu_reg_low_addr[cluster]); } -static int __init nps_setup_clocksource(struct device_node *node, - struct clk *clk) +static int __init nps_setup_clocksource(struct device_node *node) { int ret, cluster; + struct clk *clk; + unsigned long nps_timer1_freq; + for (cluster = 0; cluster < NPS_CLUSTER_NUM; cluster++) nps_msu_reg_low_addr[cluster] = nps_host_reg((cluster << NPS_CLUSTER_OFFSET), - NPS_MSU_BLKID, NPS_MSU_TICK_LOW); + NPS_MSU_BLKID, NPS_MSU_TICK_LOW); - ret = clk_prepare_enable(clk); - if (ret) { - pr_err("Couldn't enable parent clock\n"); + ret = nps_get_timer_clk(node, &nps_timer1_freq, &clk); + if (ret) return ret; - } - nps_timer_rate = clk_get_rate(clk); - - ret = clocksource_mmio_init(nps_msu_reg_low_addr, "EZnps-tick", - nps_timer_rate, 301, 32, nps_clksrc_read); + ret = clocksource_mmio_init(nps_msu_reg_low_addr, "nps-tick", + nps_timer1_freq, 300, 32, nps_clksrc_read); if (ret) { pr_err("Couldn't register clock source.\n"); clk_disable_unprepare(clk); @@ -83,18 +109,5 @@ static int __init nps_setup_clocksource(struct device_node *node, return ret; } -static int __init nps_timer_init(struct device_node *node) -{ - struct clk *clk; - - clk = of_clk_get(node, 0); - if (IS_ERR(clk)) { - pr_err("Can't get timer clock.\n"); - return PTR_ERR(clk); - } - - return nps_setup_clocksource(node, clk); -} - CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", - nps_timer_init); + nps_setup_clocksource); -- cgit v1.2.3 From 60263dcd821b9558ea08b112d9d31ffbe3ac643f Mon Sep 17 00:00:00 2001 From: Noam Camus Date: Thu, 17 Nov 2016 09:12:43 +0200 Subject: clocksource: Add clockevent support to NPS400 driver Till now we used clockevent from generic ARC driver. This was enough as long as we worked with simple multicore SoC. When we are working with multithread SoC each HW thread can be scheduled to receive timer interrupt using timer mask register. This patch will provide a way to control clock events per HW thread. The design idea is that for each core there is dedicated register (TSI) serving all 16 HW threads. The register is a bitmask with one bit for each HW thread. When HW thread wants that next expiration of timer interrupt will hit it then the proper bit should be set in this dedicated register. When timer expires all HW threads within this core which their bit is set at the TSI register will be interrupted. Driver can be used from device tree by: compatible = "ezchip,nps400-timer0" <-- for clocksource compatible = "ezchip,nps400-timer1" <-- for clockevent Note that name convention for timer0/timer1 was taken from legacy ARC design. This design is our base before adding HW threads. For backward compatibility we keep "ezchip,nps400-timer" for clocksource Signed-off-by: Noam Camus Acked-by: Daniel Lezcano Acked-by: Rob Herring --- .../bindings/timer/ezchip,nps400-timer.txt | 15 -- .../bindings/timer/ezchip,nps400-timer0.txt | 17 +++ .../bindings/timer/ezchip,nps400-timer1.txt | 15 ++ drivers/clocksource/timer-nps.c | 170 +++++++++++++++++++++ 4 files changed, 202 insertions(+), 15 deletions(-) delete mode 100644 Documentation/devicetree/bindings/timer/ezchip,nps400-timer.txt create mode 100644 Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt create mode 100644 Documentation/devicetree/bindings/timer/ezchip,nps400-timer1.txt (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/timer/ezchip,nps400-timer.txt b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer.txt deleted file mode 100644 index c8c03d700382..000000000000 --- a/Documentation/devicetree/bindings/timer/ezchip,nps400-timer.txt +++ /dev/null @@ -1,15 +0,0 @@ -NPS Network Processor - -Required properties: - -- compatible : should be "ezchip,nps400-timer" - -Clocks required for compatible = "ezchip,nps400-timer": -- clocks : Must contain a single entry describing the clock input - -Example: - -timer { - compatible = "ezchip,nps400-timer"; - clocks = <&sysclk>; -}; diff --git a/Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt new file mode 100644 index 000000000000..e3cfce8fecc5 --- /dev/null +++ b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer0.txt @@ -0,0 +1,17 @@ +NPS Network Processor + +Required properties: + +- compatible : should be "ezchip,nps400-timer0" + +Clocks required for compatible = "ezchip,nps400-timer0": +- interrupts : The interrupt of the first timer +- clocks : Must contain a single entry describing the clock input + +Example: + +timer { + compatible = "ezchip,nps400-timer0"; + interrupts = <3>; + clocks = <&sysclk>; +}; diff --git a/Documentation/devicetree/bindings/timer/ezchip,nps400-timer1.txt b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer1.txt new file mode 100644 index 000000000000..c0ab4190b8fb --- /dev/null +++ b/Documentation/devicetree/bindings/timer/ezchip,nps400-timer1.txt @@ -0,0 +1,15 @@ +NPS Network Processor + +Required properties: + +- compatible : should be "ezchip,nps400-timer1" + +Clocks required for compatible = "ezchip,nps400-timer1": +- clocks : Must contain a single entry describing the clock input + +Example: + +timer { + compatible = "ezchip,nps400-timer1"; + clocks = <&sysclk>; +}; diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index 0c8e21f905d7..b4c8a023a2d4 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -111,3 +111,173 @@ static int __init nps_setup_clocksource(struct device_node *node) CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clksrc, "ezchip,nps400-timer", nps_setup_clocksource); +CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_src, "ezchip,nps400-timer1", + nps_setup_clocksource); + +#ifdef CONFIG_EZNPS_MTM_EXT +#include + +/* Timer related Aux registers */ +#define NPS_REG_TIMER0_TSI 0xFFFFF850 +#define NPS_REG_TIMER0_LIMIT 0x23 +#define NPS_REG_TIMER0_CTRL 0x22 +#define NPS_REG_TIMER0_CNT 0x21 + +/* + * Interrupt Enabled (IE) - re-arm the timer + * Not Halted (NH) - is cleared when working with JTAG (for debug) + */ +#define TIMER0_CTRL_IE BIT(0) +#define TIMER0_CTRL_NH BIT(1) + +static unsigned long nps_timer0_freq; +static unsigned long nps_timer0_irq; + +static void nps_clkevent_rm_thread(void) +{ + int thread; + unsigned int cflags, enabled_threads; + + hw_schd_save(&cflags); + + enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI); + + /* remove thread from TSI1 */ + thread = read_aux_reg(CTOP_AUX_THREAD_ID); + enabled_threads &= ~(1 << thread); + write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads); + + /* Acknowledge and if needed re-arm the timer */ + if (!enabled_threads) + write_aux_reg(NPS_REG_TIMER0_CTRL, TIMER0_CTRL_NH); + else + write_aux_reg(NPS_REG_TIMER0_CTRL, + TIMER0_CTRL_IE | TIMER0_CTRL_NH); + + hw_schd_restore(cflags); +} + +static void nps_clkevent_add_thread(unsigned long delta) +{ + int thread; + unsigned int cflags, enabled_threads; + + hw_schd_save(&cflags); + + /* add thread to TSI1 */ + thread = read_aux_reg(CTOP_AUX_THREAD_ID); + enabled_threads = read_aux_reg(NPS_REG_TIMER0_TSI); + enabled_threads |= (1 << thread); + write_aux_reg(NPS_REG_TIMER0_TSI, enabled_threads); + + /* set next timer event */ + write_aux_reg(NPS_REG_TIMER0_LIMIT, delta); + write_aux_reg(NPS_REG_TIMER0_CNT, 0); + write_aux_reg(NPS_REG_TIMER0_CTRL, + TIMER0_CTRL_IE | TIMER0_CTRL_NH); + + hw_schd_restore(cflags); +} + +/* + * Whenever anyone tries to change modes, we just mask interrupts + * and wait for the next event to get set. + */ +static int nps_clkevent_set_state(struct clock_event_device *dev) +{ + nps_clkevent_rm_thread(); + disable_percpu_irq(nps_timer0_irq); + + return 0; +} + +static int nps_clkevent_set_next_event(unsigned long delta, + struct clock_event_device *dev) +{ + nps_clkevent_add_thread(delta); + enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE); + + return 0; +} + +static DEFINE_PER_CPU(struct clock_event_device, nps_clockevent_device) = { + .name = "NPS Timer0", + .features = CLOCK_EVT_FEAT_ONESHOT, + .rating = 300, + .set_next_event = nps_clkevent_set_next_event, + .set_state_oneshot = nps_clkevent_set_state, + .set_state_oneshot_stopped = nps_clkevent_set_state, + .set_state_shutdown = nps_clkevent_set_state, + .tick_resume = nps_clkevent_set_state, +}; + +static irqreturn_t timer_irq_handler(int irq, void *dev_id) +{ + struct clock_event_device *evt = dev_id; + + nps_clkevent_rm_thread(); + evt->event_handler(evt); + + return IRQ_HANDLED; +} + +static int nps_timer_starting_cpu(unsigned int cpu) +{ + struct clock_event_device *evt = this_cpu_ptr(&nps_clockevent_device); + + evt->cpumask = cpumask_of(smp_processor_id()); + + clockevents_config_and_register(evt, nps_timer0_freq, 0, ULONG_MAX); + enable_percpu_irq(nps_timer0_irq, IRQ_TYPE_NONE); + + return 0; +} + +static int nps_timer_dying_cpu(unsigned int cpu) +{ + disable_percpu_irq(nps_timer0_irq); + return 0; +} + +static int __init nps_setup_clockevent(struct device_node *node) +{ + struct clk *clk; + int ret; + + nps_timer0_irq = irq_of_parse_and_map(node, 0); + if (nps_timer0_irq <= 0) { + pr_err("clockevent: missing irq"); + return -EINVAL; + } + + ret = nps_get_timer_clk(node, &nps_timer0_freq, &clk); + if (ret) + return ret; + + /* Needs apriori irq_set_percpu_devid() done in intc map function */ + ret = request_percpu_irq(nps_timer0_irq, timer_irq_handler, + "Timer0 (per-cpu-tick)", + &nps_clockevent_device); + if (ret) { + pr_err("Couldn't request irq\n"); + clk_disable_unprepare(clk); + return ret; + } + + ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING, + "clockevents/nps:starting", + nps_timer_starting_cpu, + nps_timer_dying_cpu); + if (ret) { + pr_err("Failed to setup hotplug state"); + clk_disable_unprepare(clk); + free_percpu_irq(nps_timer0_irq, &nps_clockevent_device); + return ret; + } + + return 0; +} + +CLOCKSOURCE_OF_DECLARE(ezchip_nps400_clk_evt, "ezchip,nps400-timer0", + nps_setup_clockevent); +#endif /* CONFIG_EZNPS_MTM_EXT */ -- cgit v1.2.3 From a26b0d4962c7daf91d942a917c71c20e164b687a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 22 Nov 2016 15:33:44 +0100 Subject: clocksource: nps: avoid maybe-uninitialized warning We get a harmless false-positive warning with the newly added nps clocksource driver: drivers/clocksource/timer-nps.c: In function 'nps_setup_clocksource': drivers/clocksource/timer-nps.c:102:6: error: 'nps_timer1_freq' may be used uninitialized in this function [-Werror=maybe-uninitialized] Gcc here fails to identify that IS_ERR() is only true if PTR_ERR() has a nonzero value. Using PTR_ERR_OR_ZERO() to convert the result first makes this obvious and shuts up the warning. Fixes: 0ee4d9922df5 ("clocksource: Add clockevent support to NPS400 driver") Signed-off-by: Arnd Bergmann Signed-off-by: Vineet Gupta --- drivers/clocksource/timer-nps.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/timer-nps.c b/drivers/clocksource/timer-nps.c index b4c8a023a2d4..8da5e93b6810 100644 --- a/drivers/clocksource/timer-nps.c +++ b/drivers/clocksource/timer-nps.c @@ -53,9 +53,10 @@ static int __init nps_get_timer_clk(struct device_node *node, int ret; *clk = of_clk_get(node, 0); - if (IS_ERR(*clk)) { + ret = PTR_ERR_OR_ZERO(*clk); + if (ret) { pr_err("timer missing clk"); - return PTR_ERR(*clk); + return ret; } ret = clk_prepare_enable(*clk); -- cgit v1.2.3 From e3e7f95bca95c7d0172e6481066668a176dc4696 Mon Sep 17 00:00:00 2001 From: Nicolae Rosia Date: Wed, 23 Nov 2016 10:55:56 +0200 Subject: rtc: twl: kill static variables The current code uses static variables which prevent the use of multiple rtc twl instances. We also make it clear that this driver supports only TWL4030 and TWL6030 classes. Signed-off-by: Nicolae Rosia Tested-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-twl.c | 190 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 114 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 176720b7b9e5..1e415268770e 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -33,6 +33,10 @@ #include +enum twl_class { + TWL_4030 = 0, + TWL_6030, +}; /* * RTC block register offsets (use TWL_MODULE_RTC) @@ -136,16 +140,30 @@ static const u8 twl6030_rtc_reg_map[] = { #define ALL_TIME_REGS 6 /*----------------------------------------------------------------------*/ -static u8 *rtc_reg_map; +struct twl_rtc { + struct device *dev; + struct rtc_device *rtc; + u8 *reg_map; + /* + * Cache the value for timer/alarm interrupts register; this is + * only changed by callers holding rtc ops lock (or resume). + */ + unsigned char rtc_irq_bits; + bool wake_enabled; +#ifdef CONFIG_PM_SLEEP + unsigned char irqstat; +#endif + enum twl_class class; +}; /* * Supports 1 byte read from TWL RTC register. */ -static int twl_rtc_read_u8(u8 *data, u8 reg) +static int twl_rtc_read_u8(struct twl_rtc *twl_rtc, u8 *data, u8 reg) { int ret; - ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); + ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg])); if (ret < 0) pr_err("Could not read TWL register %X - error %d\n", reg, ret); return ret; @@ -154,40 +172,34 @@ static int twl_rtc_read_u8(u8 *data, u8 reg) /* * Supports 1 byte write to TWL RTC registers. */ -static int twl_rtc_write_u8(u8 data, u8 reg) +static int twl_rtc_write_u8(struct twl_rtc *twl_rtc, u8 data, u8 reg) { int ret; - ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg])); + ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg])); if (ret < 0) pr_err("Could not write TWL register %X - error %d\n", reg, ret); return ret; } -/* - * Cache the value for timer/alarm interrupts register; this is - * only changed by callers holding rtc ops lock (or resume). - */ -static unsigned char rtc_irq_bits; - /* * Enable 1/second update and/or alarm interrupts. */ -static int set_rtc_irq_bit(unsigned char bit) +static int set_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit) { unsigned char val; int ret; /* if the bit is set, return from here */ - if (rtc_irq_bits & bit) + if (twl_rtc->rtc_irq_bits & bit) return 0; - val = rtc_irq_bits | bit; + val = twl_rtc->rtc_irq_bits | bit; val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; - ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); + ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG); if (ret == 0) - rtc_irq_bits = val; + twl_rtc->rtc_irq_bits = val; return ret; } @@ -195,19 +207,19 @@ static int set_rtc_irq_bit(unsigned char bit) /* * Disable update and/or alarm interrupts. */ -static int mask_rtc_irq_bit(unsigned char bit) +static int mask_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit) { unsigned char val; int ret; /* if the bit is clear, return from here */ - if (!(rtc_irq_bits & bit)) + if (!(twl_rtc->rtc_irq_bits & bit)) return 0; - val = rtc_irq_bits & ~bit; - ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); + val = twl_rtc->rtc_irq_bits & ~bit; + ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG); if (ret == 0) - rtc_irq_bits = val; + twl_rtc->rtc_irq_bits = val; return ret; } @@ -215,21 +227,23 @@ static int mask_rtc_irq_bit(unsigned char bit) static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) { struct platform_device *pdev = to_platform_device(dev); + struct twl_rtc *twl_rtc = dev_get_drvdata(dev); int irq = platform_get_irq(pdev, 0); - static bool twl_rtc_wake_enabled; int ret; if (enabled) { - ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - if (device_can_wakeup(dev) && !twl_rtc_wake_enabled) { + ret = set_rtc_irq_bit(twl_rtc, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + if (device_can_wakeup(dev) && !twl_rtc->wake_enabled) { enable_irq_wake(irq); - twl_rtc_wake_enabled = true; + twl_rtc->wake_enabled = true; } } else { - ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - if (twl_rtc_wake_enabled) { + ret = mask_rtc_irq_bit(twl_rtc, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + if (twl_rtc->wake_enabled) { disable_irq_wake(irq); - twl_rtc_wake_enabled = false; + twl_rtc->wake_enabled = false; } } @@ -247,21 +261,23 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) */ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) { + struct twl_rtc *twl_rtc = dev_get_drvdata(dev); unsigned char rtc_data[ALL_TIME_REGS]; int ret; u8 save_control; u8 rtc_control; - ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); + ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG); if (ret < 0) { dev_err(dev, "%s: reading CTRL_REG, error %d\n", __func__, ret); return ret; } /* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */ - if (twl_class_is_6030()) { + if (twl_rtc->class == TWL_6030) { if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) { save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M; - ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + ret = twl_rtc_write_u8(twl_rtc, save_control, + REG_RTC_CTRL_REG); if (ret < 0) { dev_err(dev, "%s clr GET_TIME, error %d\n", __func__, ret); @@ -274,17 +290,17 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M; /* for twl6030/32 enable read access to static shadowed registers */ - if (twl_class_is_6030()) + if (twl_rtc->class == TWL_6030) rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT; - ret = twl_rtc_write_u8(rtc_control, REG_RTC_CTRL_REG); + ret = twl_rtc_write_u8(twl_rtc, rtc_control, REG_RTC_CTRL_REG); if (ret < 0) { dev_err(dev, "%s: writing CTRL_REG, error %d\n", __func__, ret); return ret; } ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, - (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); + (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); if (ret < 0) { dev_err(dev, "%s: reading data, error %d\n", __func__, ret); @@ -292,8 +308,8 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) } /* for twl6030 restore original state of rtc control register */ - if (twl_class_is_6030()) { - ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + if (twl_rtc->class == TWL_6030) { + ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG); if (ret < 0) { dev_err(dev, "%s: restore CTRL_REG, error %d\n", __func__, ret); @@ -313,6 +329,7 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm) static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) { + struct twl_rtc *twl_rtc = dev_get_drvdata(dev); unsigned char save_control; unsigned char rtc_data[ALL_TIME_REGS]; int ret; @@ -325,18 +342,18 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc_data[5] = bin2bcd(tm->tm_year - 100); /* Stop RTC while updating the TC registers */ - ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); + ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG); if (ret < 0) goto out; save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG); if (ret < 0) goto out; /* update all the time registers in one shot */ ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data, - (rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); + (twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS); if (ret < 0) { dev_err(dev, "rtc_set_time error %d\n", ret); goto out; @@ -344,7 +361,7 @@ static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm) /* Start back RTC */ save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG); + ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG); out: return ret; @@ -355,11 +372,12 @@ out: */ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { + struct twl_rtc *twl_rtc = dev_get_drvdata(dev); unsigned char rtc_data[ALL_TIME_REGS]; int ret; ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, - (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); + twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS); if (ret < 0) { dev_err(dev, "rtc_read_alarm error %d\n", ret); return ret; @@ -374,7 +392,7 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) alm->time.tm_year = bcd2bin(rtc_data[5]) + 100; /* report cached alarm enable state */ - if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) + if (twl_rtc->rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) alm->enabled = 1; return ret; @@ -382,6 +400,8 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { + struct twl_rtc *twl_rtc = dev_get_drvdata(dev); + unsigned char alarm_data[ALL_TIME_REGS]; int ret; @@ -398,7 +418,7 @@ static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) /* update all the alarm registers in one shot */ ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, - (rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS); + twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS); if (ret) { dev_err(dev, "rtc_set_alarm error %d\n", ret); goto out; @@ -410,14 +430,15 @@ out: return ret; } -static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) +static irqreturn_t twl_rtc_interrupt(int irq, void *data) { + struct twl_rtc *twl_rtc = data; unsigned long events; int ret = IRQ_NONE; int res; u8 rd_reg; - res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); + res = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG); if (res) goto out; /* @@ -431,12 +452,12 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) else events = RTC_IRQF | RTC_PF; - res = twl_rtc_write_u8(BIT_RTC_STATUS_REG_ALARM_M, - REG_RTC_STATUS_REG); + res = twl_rtc_write_u8(twl_rtc, BIT_RTC_STATUS_REG_ALARM_M, + REG_RTC_STATUS_REG); if (res) goto out; - if (twl_class_is_4030()) { + if (twl_rtc->class == TWL_4030) { /* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 * needs 2 reads to clear the interrupt. One read is done in * do_twl_pwrirq(). Doing the second read, to clear @@ -455,7 +476,7 @@ static irqreturn_t twl_rtc_interrupt(int irq, void *rtc) } /* Notify RTC core on event */ - rtc_update_irq(rtc, 1, events); + rtc_update_irq(twl_rtc->rtc, 1, events); ret = IRQ_HANDLED; out: @@ -474,7 +495,7 @@ static const struct rtc_class_ops twl_rtc_ops = { static int twl_rtc_probe(struct platform_device *pdev) { - struct rtc_device *rtc; + struct twl_rtc *twl_rtc; int ret = -EINVAL; int irq = platform_get_irq(pdev, 0); u8 rd_reg; @@ -482,13 +503,22 @@ static int twl_rtc_probe(struct platform_device *pdev) if (irq <= 0) return ret; - /* Initialize the register map */ - if (twl_class_is_4030()) - rtc_reg_map = (u8 *)twl4030_rtc_reg_map; - else - rtc_reg_map = (u8 *)twl6030_rtc_reg_map; + twl_rtc = devm_kzalloc(&pdev->dev, sizeof(*twl_rtc), GFP_KERNEL); + if (!twl_rtc) + return -ENOMEM; + + if (twl_class_is_4030()) { + twl_rtc->class = TWL_4030; + twl_rtc->reg_map = (u8 *)twl4030_rtc_reg_map; + } else if (twl_class_is_6030()) { + twl_rtc->class = TWL_6030; + twl_rtc->reg_map = (u8 *)twl6030_rtc_reg_map; + } else { + dev_err(&pdev->dev, "TWL Class not supported.\n"); + return -EINVAL; + } - ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); + ret = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG); if (ret < 0) return ret; @@ -499,11 +529,11 @@ static int twl_rtc_probe(struct platform_device *pdev) dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); /* Clear RTC Power up reset and pending alarm interrupts */ - ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); + ret = twl_rtc_write_u8(twl_rtc, rd_reg, REG_RTC_STATUS_REG); if (ret < 0) return ret; - if (twl_class_is_6030()) { + if (twl_rtc->class == TWL_6030) { twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, REG_INT_MSK_LINE_A); twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, @@ -511,40 +541,42 @@ static int twl_rtc_probe(struct platform_device *pdev) } dev_info(&pdev->dev, "Enabling TWL-RTC\n"); - ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG); + ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M, + REG_RTC_CTRL_REG); if (ret < 0) return ret; /* ensure interrupts are disabled, bootloaders can be strange */ - ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); + ret = twl_rtc_write_u8(twl_rtc, 0, REG_RTC_INTERRUPTS_REG); if (ret < 0) dev_warn(&pdev->dev, "unable to disable interrupt\n"); /* init cached IRQ enable bits */ - ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); + ret = twl_rtc_read_u8(twl_rtc, &twl_rtc->rtc_irq_bits, + REG_RTC_INTERRUPTS_REG); if (ret < 0) return ret; + platform_set_drvdata(pdev, twl_rtc); device_init_wakeup(&pdev->dev, 1); - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &twl_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { + if (IS_ERR(twl_rtc->rtc)) { dev_err(&pdev->dev, "can't register RTC device, err %ld\n", - PTR_ERR(rtc)); - return PTR_ERR(rtc); + PTR_ERR(twl_rtc->rtc)); + return PTR_ERR(twl_rtc->rtc); } ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, twl_rtc_interrupt, IRQF_TRIGGER_RISING | IRQF_ONESHOT, - dev_name(&rtc->dev), rtc); + dev_name(&twl_rtc->rtc->dev), twl_rtc); if (ret < 0) { dev_err(&pdev->dev, "IRQ is not free.\n"); return ret; } - platform_set_drvdata(pdev, rtc); return 0; } @@ -554,10 +586,12 @@ static int twl_rtc_probe(struct platform_device *pdev) */ static int twl_rtc_remove(struct platform_device *pdev) { + struct twl_rtc *twl_rtc = platform_get_drvdata(pdev); + /* leave rtc running, but disable irqs */ - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - if (twl_class_is_6030()) { + mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); + mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + if (twl_rtc->class == TWL_6030) { twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, REG_INT_MSK_LINE_A); twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, @@ -569,25 +603,29 @@ static int twl_rtc_remove(struct platform_device *pdev) static void twl_rtc_shutdown(struct platform_device *pdev) { + struct twl_rtc *twl_rtc = platform_get_drvdata(pdev); + /* mask timer interrupts, but leave alarm interrupts on to enable power-on when alarm is triggered */ - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); } #ifdef CONFIG_PM_SLEEP -static unsigned char irqstat; - static int twl_rtc_suspend(struct device *dev) { - irqstat = rtc_irq_bits; + struct twl_rtc *twl_rtc = dev_get_drvdata(dev); - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + twl_rtc->irqstat = twl_rtc->rtc_irq_bits; + + mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); return 0; } static int twl_rtc_resume(struct device *dev) { - set_rtc_irq_bit(irqstat); + struct twl_rtc *twl_rtc = dev_get_drvdata(dev); + + set_rtc_irq_bit(twl_rtc, twl_rtc->irqstat); return 0; } #endif -- cgit v1.2.3 From 1c02cbfec5c7754cb16456fcb26592a20781cdff Mon Sep 17 00:00:00 2001 From: Nicolae Rosia Date: Wed, 23 Nov 2016 10:55:57 +0200 Subject: rtc: twl: make driver DT only Since there are no platform based users and all users of this code are TI OMAP-based which is DT only, it makes sense to remove unused code. Signed-off-by: Nicolae Rosia Tested-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 1 + drivers/rtc/rtc-twl.c | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index ab55f35019fc..a44f1f27ecfa 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -481,6 +481,7 @@ config RTC_DRV_TWL92330 config RTC_DRV_TWL4030 tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0" depends on TWL4030_CORE + depends on OF help If you say yes here you get support for the RTC on the TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms. diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 1e415268770e..c18c39212ce6 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -496,10 +496,16 @@ static const struct rtc_class_ops twl_rtc_ops = { static int twl_rtc_probe(struct platform_device *pdev) { struct twl_rtc *twl_rtc; + struct device_node *np = pdev->dev.of_node; int ret = -EINVAL; int irq = platform_get_irq(pdev, 0); u8 rd_reg; + if (!np) { + dev_err(&pdev->dev, "no DT info\n"); + return -EINVAL; + } + if (irq <= 0) return ret; @@ -632,15 +638,11 @@ static int twl_rtc_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume); -#ifdef CONFIG_OF static const struct of_device_id twl_rtc_of_match[] = { {.compatible = "ti,twl4030-rtc", }, { }, }; MODULE_DEVICE_TABLE(of, twl_rtc_of_match); -#endif - -MODULE_ALIAS("platform:twl_rtc"); static struct platform_driver twl4030rtc_driver = { .probe = twl_rtc_probe, @@ -649,7 +651,7 @@ static struct platform_driver twl4030rtc_driver = { .driver = { .name = "twl_rtc", .pm = &twl_rtc_pm_ops, - .of_match_table = of_match_ptr(twl_rtc_of_match), + .of_match_table = twl_rtc_of_match, }, }; -- cgit v1.2.3 From 920f8bf7f366ed20935669f782ffcb5a36d5df8f Mon Sep 17 00:00:00 2001 From: Grygorii Strashko Date: Wed, 30 Nov 2016 10:53:51 -0600 Subject: soc: ti: qmss: fix the case when !SMP The irq_set_affinity_hint() will always fail when !SMP and Networking will fail on Keystone 2 devices in this case. Hence, fix by ignoring IRQ affinity settings when !SMP. Signed-off-by: Grygorii Strashko Acked-by: Santosh Shilimkar Signed-off-by: Arnd Bergmann --- drivers/soc/ti/knav_qmss_queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index b73e3534f67b..eacad57f2977 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -1228,7 +1228,7 @@ static int knav_setup_queue_range(struct knav_device *kdev, range->num_irqs++; - if (oirq.args_count == 3) + if (IS_ENABLED(CONFIG_SMP) && oirq.args_count == 3) range->irqs[i].cpu_map = (oirq.args[2] & 0x0000ff00) >> 8; } -- cgit v1.2.3 From c090959b9dd8c87703e275079aa4b4a824ba3f8e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Wed, 16 Nov 2016 17:31:30 +0000 Subject: bus: vexpress-config: fix device reference leak Make sure to drop the reference to the parent device taken by class_find_device() after populating the bus. Fixes: 3b9334ac835b ("mfd: vexpress: Convert custom func API to regmap") Acked-by: Sudeep Holla Signed-off-by: Johan Hovold Signed-off-by: Arnd Bergmann --- drivers/bus/vexpress-config.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/bus/vexpress-config.c b/drivers/bus/vexpress-config.c index 9efdf1de4035..493e7b9fc813 100644 --- a/drivers/bus/vexpress-config.c +++ b/drivers/bus/vexpress-config.c @@ -171,6 +171,7 @@ static int vexpress_config_populate(struct device_node *node) { struct device_node *bridge; struct device *parent; + int ret; bridge = of_parse_phandle(node, "arm,vexpress,config-bridge", 0); if (!bridge) @@ -182,7 +183,11 @@ static int vexpress_config_populate(struct device_node *node) if (WARN_ON(!parent)) return -ENODEV; - return of_platform_populate(node, NULL, NULL, parent); + ret = of_platform_populate(node, NULL, NULL, parent); + + put_device(parent); + + return ret; } static int __init vexpress_config_init(void) -- cgit v1.2.3 From e155d4ee0b878c857f91deb14d6d7dba55c38648 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 30 Nov 2016 16:59:30 -0800 Subject: Input: synaptics-rmi4 - remove mutex calls while updating the firmware This partially reverts commit 29fd0ec2bdbe ("Input: synaptics-rmi4 - add support for F34 device reflash") irq_mutex should be used only to protect data->current_irq_mask, not preventing incoming input to be processed while the upgrade of the firmware is happening. We can simply disable the irqs when we don't want them to interfere with the upgrade process. Tested on S7300 and S7800 (with F34 v7 patch added) Signed-off-by: Benjamin Tissoires Signed-off-by: Nick Dyer Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 40 ++++++++-------------------------------- drivers/input/rmi4/rmi_f34.c | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index f04fc4152c1f..27c731ab71b8 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -42,8 +42,6 @@ void rmi_free_function_list(struct rmi_device *rmi_dev) rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Freeing function list\n"); - mutex_lock(&data->irq_mutex); - devm_kfree(&rmi_dev->dev, data->irq_memory); data->irq_memory = NULL; data->irq_status = NULL; @@ -60,8 +58,6 @@ void rmi_free_function_list(struct rmi_device *rmi_dev) list_del(&fn->node); rmi_unregister_function(fn); } - - mutex_unlock(&data->irq_mutex); } EXPORT_SYMBOL_GPL(rmi_free_function_list); @@ -160,25 +156,24 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) if (!data) return 0; - mutex_lock(&data->irq_mutex); - if (!data->irq_status || !data->f01_container) { - mutex_unlock(&data->irq_mutex); - return 0; - } - if (!rmi_dev->xport->attn_data) { error = rmi_read_block(rmi_dev, data->f01_container->fd.data_base_addr + 1, data->irq_status, data->num_of_irq_regs); if (error < 0) { dev_err(dev, "Failed to read irqs, code=%d\n", error); - mutex_unlock(&data->irq_mutex); return error; } } + mutex_lock(&data->irq_mutex); bitmap_and(data->irq_status, data->irq_status, data->current_irq_mask, data->irq_count); + /* + * At this point, irq_status has all bits that are set in the + * interrupt status register and are enabled. + */ + mutex_unlock(&data->irq_mutex); /* * It would be nice to be able to use irq_chip to handle these @@ -194,8 +189,6 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) if (data->input) input_sync(data->input); - mutex_unlock(&data->irq_mutex); - return 0; } @@ -263,18 +256,12 @@ static int rmi_suspend_functions(struct rmi_device *rmi_dev) struct rmi_function *entry; int retval; - mutex_lock(&data->irq_mutex); - list_for_each_entry(entry, &data->function_list, node) { retval = suspend_one_function(entry); - if (retval < 0) { - mutex_unlock(&data->irq_mutex); + if (retval < 0) return retval; - } } - mutex_unlock(&data->irq_mutex); - return 0; } @@ -303,18 +290,12 @@ static int rmi_resume_functions(struct rmi_device *rmi_dev) struct rmi_function *entry; int retval; - mutex_lock(&data->irq_mutex); - list_for_each_entry(entry, &data->function_list, node) { retval = resume_one_function(entry); - if (retval < 0) { - mutex_unlock(&data->irq_mutex); + if (retval < 0) return retval; - } } - mutex_unlock(&data->irq_mutex); - return 0; } @@ -1043,8 +1024,6 @@ int rmi_init_functions(struct rmi_driver_data *data) int irq_count; int retval; - mutex_lock(&data->irq_mutex); - irq_count = 0; rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Creating functions.\n", __func__); retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_create_function); @@ -1069,13 +1048,10 @@ int rmi_init_functions(struct rmi_driver_data *data) goto err_destroy_functions; } - mutex_unlock(&data->irq_mutex); - return 0; err_destroy_functions: rmi_free_function_list(rmi_dev); - mutex_unlock(&data->irq_mutex); return retval; } EXPORT_SYMBOL_GPL(rmi_init_functions); diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index 03df85ac91a5..01936a4a9a6c 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -282,7 +282,8 @@ out: static int rmi_firmware_update(struct rmi_driver_data *data, const struct firmware *fw) { - struct device *dev = &data->rmi_dev->dev; + struct rmi_device *rmi_dev = data->rmi_dev; + struct device *dev = &rmi_dev->dev; struct f34_data *f34; int ret; @@ -305,8 +306,10 @@ static int rmi_firmware_update(struct rmi_driver_data *data, if (ret) return ret; + rmi_disable_irq(rmi_dev, false); + /* Tear down functions and re-probe */ - rmi_free_function_list(data->rmi_dev); + rmi_free_function_list(rmi_dev); ret = rmi_probe_interrupts(data); if (ret) @@ -322,6 +325,8 @@ static int rmi_firmware_update(struct rmi_driver_data *data, return -EINVAL; } + rmi_enable_irq(rmi_dev, false); + f34 = dev_get_drvdata(&data->f34_container->dev); /* Perform firmware update */ @@ -329,11 +334,13 @@ static int rmi_firmware_update(struct rmi_driver_data *data, dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret); + rmi_disable_irq(rmi_dev, false); + /* Re-probe */ rmi_dbg(RMI_DEBUG_FN, dev, "Re-probing device\n"); - rmi_free_function_list(data->rmi_dev); + rmi_free_function_list(rmi_dev); - ret = rmi_scan_pdt(data->rmi_dev, NULL, rmi_initial_reset); + ret = rmi_scan_pdt(rmi_dev, NULL, rmi_initial_reset); if (ret < 0) dev_warn(dev, "RMI reset failed!\n"); @@ -345,9 +352,11 @@ static int rmi_firmware_update(struct rmi_driver_data *data, if (ret) return ret; + rmi_enable_irq(rmi_dev, false); + if (data->f01_container->dev.driver) /* Driver already bound, so enable ATTN now. */ - return rmi_enable_sensor(data->rmi_dev); + return rmi_enable_sensor(rmi_dev); rmi_dbg(RMI_DEBUG_FN, dev, "%s complete\n", __func__); -- cgit v1.2.3 From e9dade4106e1c1ff4ae91386b9812ee8f51c3775 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 30 Nov 2016 17:00:28 -0800 Subject: Input: synaptics-rmi4 - remove EXPORT_SYMBOL_GPL for internal functions those functions should not be used outside of rmi_core.ko. There is no point in exporting them to the world. It looks like rmi_read_pdt_entry() should be static too. Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 15 ++------------- drivers/input/rmi4/rmi_driver.h | 3 --- 2 files changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 27c731ab71b8..a718e51afb0b 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -59,7 +59,6 @@ void rmi_free_function_list(struct rmi_device *rmi_dev) rmi_unregister_function(fn); } } -EXPORT_SYMBOL_GPL(rmi_free_function_list); static int reset_one_function(struct rmi_function *fn) { @@ -309,7 +308,6 @@ int rmi_enable_sensor(struct rmi_device *rmi_dev) return rmi_process_interrupt_requests(rmi_dev); } -EXPORT_SYMBOL_GPL(rmi_enable_sensor); /** * rmi_driver_set_input_params - set input device id and other data. @@ -431,8 +429,8 @@ static int rmi_driver_reset_handler(struct rmi_device *rmi_dev) return 0; } -int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry, - u16 pdt_address) +static int rmi_read_pdt_entry(struct rmi_device *rmi_dev, + struct pdt_entry *entry, u16 pdt_address) { u8 buf[RMI_PDT_ENTRY_SIZE]; int error; @@ -455,7 +453,6 @@ int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry, return 0; } -EXPORT_SYMBOL_GPL(rmi_read_pdt_entry); static void rmi_driver_copy_pdt_to_fd(const struct pdt_entry *pdt, struct rmi_function_descriptor *fd) @@ -532,7 +529,6 @@ int rmi_scan_pdt(struct rmi_device *rmi_dev, void *ctx, return retval < 0 ? retval : 0; } -EXPORT_SYMBOL_GPL(rmi_scan_pdt); int rmi_read_register_desc(struct rmi_device *d, u16 addr, struct rmi_register_descriptor *rdesc) @@ -664,7 +660,6 @@ free_struct_buff: kfree(struct_buf); return ret; } -EXPORT_SYMBOL_GPL(rmi_read_register_desc); const struct rmi_register_desc_item *rmi_get_register_desc_item( struct rmi_register_descriptor *rdesc, u16 reg) @@ -680,7 +675,6 @@ const struct rmi_register_desc_item *rmi_get_register_desc_item( return NULL; } -EXPORT_SYMBOL_GPL(rmi_get_register_desc_item); size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc) { @@ -694,7 +688,6 @@ size_t rmi_register_desc_calc_size(struct rmi_register_descriptor *rdesc) } return size; } -EXPORT_SYMBOL_GPL(rmi_register_desc_calc_size); /* Compute the register offset relative to the base address */ int rmi_register_desc_calc_reg_offset( @@ -712,7 +705,6 @@ int rmi_register_desc_calc_reg_offset( } return -1; } -EXPORT_SYMBOL_GPL(rmi_register_desc_calc_reg_offset); bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, u8 subpacket) @@ -796,7 +788,6 @@ int rmi_initial_reset(struct rmi_device *rmi_dev, void *ctx, /* F01 should always be on page 0. If we don't find it there, fail. */ return pdt->page_start == 0 ? RMI_SCAN_CONTINUE : -ENODEV; } -EXPORT_SYMBOL_GPL(rmi_initial_reset); static int rmi_create_function(struct rmi_device *rmi_dev, void *ctx, const struct pdt_entry *pdt) @@ -1015,7 +1006,6 @@ int rmi_probe_interrupts(struct rmi_driver_data *data) return retval; } -EXPORT_SYMBOL_GPL(rmi_probe_interrupts); int rmi_init_functions(struct rmi_driver_data *data) { @@ -1054,7 +1044,6 @@ err_destroy_functions: rmi_free_function_list(rmi_dev); return retval; } -EXPORT_SYMBOL_GPL(rmi_init_functions); static int rmi_driver_probe(struct device *dev) { diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index c9fe3d3deef3..cc9458522279 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -51,9 +51,6 @@ struct pdt_entry { u8 function_number; }; -int rmi_read_pdt_entry(struct rmi_device *rmi_dev, struct pdt_entry *entry, - u16 pdt_address); - #define RMI_REG_DESC_PRESENSE_BITS (32 * BITS_PER_BYTE) #define RMI_REG_DESC_SUBPACKET_BITS (37 * BITS_PER_BYTE) -- cgit v1.2.3 From 0a135b88bceac40d0036e401c19cdbda65b38a8f Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Wed, 30 Nov 2016 17:01:50 -0800 Subject: Input: synaptics-rmi4 - have only one struct platform data If struct rmi_device_platform_data contains pointers to other struct, it gets difficult to allocate a fixed size struct and copy it over between drivers. Change the pointers into a struct and change the code in rmi4 accordingly. Reviewed-by: Andrew Duggan Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f11.c | 4 ++-- drivers/input/rmi4/rmi_f12.c | 4 ++-- drivers/input/rmi4/rmi_f30.c | 9 ++++----- include/linux/rmi.h | 4 ++-- 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index c252d405df4c..ffcbbc1745de 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -1080,8 +1080,8 @@ static int rmi_f11_initialize(struct rmi_function *fn) rc = rmi_2d_sensor_of_probe(&fn->dev, &f11->sensor_pdata); if (rc) return rc; - } else if (pdata->sensor_pdata) { - f11->sensor_pdata = *pdata->sensor_pdata; + } else { + f11->sensor_pdata = pdata->sensor_pdata; } f11->rezero_wait_ms = f11->sensor_pdata.rezero_wait; diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index d7255f18306d..82a4964e5eb9 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -352,8 +352,8 @@ static int rmi_f12_probe(struct rmi_function *fn) ret = rmi_2d_sensor_of_probe(&fn->dev, &f12->sensor_pdata); if (ret) return ret; - } else if (pdata->sensor_pdata) { - f12->sensor_pdata = *pdata->sensor_pdata; + } else { + f12->sensor_pdata = pdata->sensor_pdata; } ret = rmi_read_register_desc(rmi_dev, query_addr, diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c index 485907ff10f4..f696137a56f5 100644 --- a/drivers/input/rmi4/rmi_f30.c +++ b/drivers/input/rmi4/rmi_f30.c @@ -196,7 +196,7 @@ static int rmi_f30_config(struct rmi_function *fn) rmi_get_platform_data(fn->rmi_dev); int error; - if (pdata->f30_data && pdata->f30_data->disable) { + if (pdata->f30_data.disable) { drv->clear_irq_bits(fn->rmi_dev, fn->irq_mask); } else { /* Write Control Register values back to device */ @@ -355,7 +355,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn) f30->gpioled_key_map = (u16 *)map_memory; pdata = rmi_get_platform_data(rmi_dev); - if (pdata && f30->has_gpio) { + if (f30->has_gpio) { button = BTN_LEFT; for (i = 0; i < f30->gpioled_count; i++) { if (rmi_f30_is_valid_button(i, f30->ctrl)) { @@ -366,8 +366,7 @@ static inline int rmi_f30_initialize(struct rmi_function *fn) * f30->has_mech_mouse_btns, but I am * not sure, so use only the pdata info */ - if (pdata->f30_data && - pdata->f30_data->buttonpad) + if (pdata->f30_data.buttonpad) break; } } @@ -382,7 +381,7 @@ static int rmi_f30_probe(struct rmi_function *fn) const struct rmi_device_platform_data *pdata = rmi_get_platform_data(fn->rmi_dev); - if (pdata->f30_data && pdata->f30_data->disable) + if (pdata->f30_data.disable) return 0; rc = rmi_f30_initialize(fn); diff --git a/include/linux/rmi.h b/include/linux/rmi.h index 621f098f1243..7780e40a2573 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -218,9 +218,9 @@ struct rmi_device_platform_data { struct rmi_device_platform_data_spi spi_data; /* function handler pdata */ - struct rmi_2d_sensor_platform_data *sensor_pdata; + struct rmi_2d_sensor_platform_data sensor_pdata; struct rmi_f01_power_management power_management; - struct rmi_f30_data *f30_data; + struct rmi_f30_data f30_data; }; /** -- cgit v1.2.3 From 70f5a294ad2eec3f896dafb83075cb8f04d65e92 Mon Sep 17 00:00:00 2001 From: Haibo Chen Date: Wed, 30 Nov 2016 09:02:06 -0800 Subject: Input: imx6ul_tsc - add mask when set REG_ADC_CFG Add mask of each function bits of REG_ADC_CFG, and clear these function bits first, otherwise use '|=' operation may get the wrong setting which depends on the original value of REG_ADC_CFG. Signed-off-by: Haibo Chen Reviewed-by: Guy Shapiro Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 00b336f37fb3..5babefef99a1 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -29,11 +29,16 @@ #define ADC_CAL (0x1 << 7) #define ADC_CALF 0x2 #define ADC_12BIT_MODE (0x2 << 2) +#define ADC_CONV_MODE_MASK (0x3 << 2) #define ADC_IPG_CLK 0x00 +#define ADC_INPUT_CLK_MASK 0x3 #define ADC_CLK_DIV_8 (0x03 << 5) +#define ADC_CLK_DIV_MASK (0x3 << 5) #define ADC_SHORT_SAMPLE_MODE (0x0 << 4) +#define ADC_SAMPLE_MODE_MASK (0x1 << 4) #define ADC_HARDWARE_TRIGGER (0x1 << 13) #define ADC_AVGS_SHIFT 14 +#define ADC_AVGS_MASK (0x3 << 14) #define SELECT_CHANNEL_4 0x04 #define SELECT_CHANNEL_1 0x01 #define DISABLE_CONVERSION_INT (0x0 << 7) @@ -108,10 +113,14 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) reinit_completion(&tsc->completion); adc_cfg = readl(tsc->adc_regs + REG_ADC_CFG); + adc_cfg &= ~(ADC_CONV_MODE_MASK | ADC_INPUT_CLK_MASK); adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK; + adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK); adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE; - if (tsc->average_samples) + if (tsc->average_samples) { + adc_cfg &= ~ADC_AVGS_MASK; adc_cfg |= (tsc->average_samples - 1) << ADC_AVGS_SHIFT; + } adc_cfg &= ~ADC_HARDWARE_TRIGGER; writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); -- cgit v1.2.3 From accbcea3465b2038fa8aa66cfa8f40db7ab1c83c Mon Sep 17 00:00:00 2001 From: Guy Shapiro Date: Wed, 30 Nov 2016 10:25:11 -0800 Subject: Input: imx6ul_tsc - convert int to u32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The code uses of_property_read_u32 and expects positive values. However, the values are stored in signed int variables. Additionally, the registers values are also stored in signed variables without a good reason (readl/writel expect u32). The only time this caused a real bug was in the new average-samples property, in which the property is numerically compared and implicitly expected to be positive. I believe it's better to change all the properties and registers to u32, for consistency and warnings reduction. Signed-off-by: Guy Shapiro Reported-by: Bjørn Forsman Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/imx6ul_tsc.c | 42 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index 5babefef99a1..d2a39120f37f 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -91,9 +91,9 @@ struct imx6ul_tsc { struct clk *adc_clk; struct gpio_desc *xnur_gpio; - int measure_delay_time; - int pre_charge_time; - int average_samples; + u32 measure_delay_time; + u32 pre_charge_time; + u32 average_samples; struct completion completion; }; @@ -104,11 +104,11 @@ struct imx6ul_tsc { */ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) { - int adc_hc = 0; - int adc_gc; - int adc_gs; - int adc_cfg; - int timeout; + u32 adc_hc = 0; + u32 adc_gc; + u32 adc_gs; + u32 adc_cfg; + unsigned long timeout; reinit_completion(&tsc->completion); @@ -164,7 +164,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) */ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) { - int adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4; + u32 adc_hc0, adc_hc1, adc_hc2, adc_hc3, adc_hc4; adc_hc0 = DISABLE_CONVERSION_INT; writel(adc_hc0, tsc->adc_regs + REG_ADC_HC0); @@ -189,8 +189,8 @@ static void imx6ul_tsc_channel_config(struct imx6ul_tsc *tsc) */ static void imx6ul_tsc_set(struct imx6ul_tsc *tsc) { - int basic_setting = 0; - int start; + u32 basic_setting = 0; + u32 start; basic_setting |= tsc->measure_delay_time << 8; basic_setting |= DETECT_4_WIRE_MODE | AUTO_MEASURE; @@ -225,8 +225,8 @@ static int imx6ul_tsc_init(struct imx6ul_tsc *tsc) static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc) { - int tsc_flow; - int adc_cfg; + u32 tsc_flow; + u32 adc_cfg; /* TSC controller enters to idle status */ tsc_flow = readl(tsc->tsc_regs + REG_TSC_FLOW_CONTROL); @@ -243,8 +243,8 @@ static void imx6ul_tsc_disable(struct imx6ul_tsc *tsc) static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) { unsigned long timeout = jiffies + msecs_to_jiffies(2); - int state_machine; - int debug_mode2; + u32 state_machine; + u32 debug_mode2; do { if (time_after(jiffies, timeout)) @@ -262,10 +262,10 @@ static bool tsc_wait_detect_mode(struct imx6ul_tsc *tsc) static irqreturn_t tsc_irq_fn(int irq, void *dev_id) { struct imx6ul_tsc *tsc = dev_id; - int status; - int value; - int x, y; - int start; + u32 status; + u32 value; + u32 x, y; + u32 start; status = readl(tsc->tsc_regs + REG_TSC_INT_STATUS); @@ -305,8 +305,8 @@ static irqreturn_t tsc_irq_fn(int irq, void *dev_id) static irqreturn_t adc_irq_fn(int irq, void *dev_id) { struct imx6ul_tsc *tsc = dev_id; - int coco; - int value; + u32 coco; + u32 value; coco = readl(tsc->adc_regs + REG_ADC_HS); if (coco & 0x01) { -- cgit v1.2.3 From 3502fbcc25eb67db96fea35abe721c82aa1f4ff3 Mon Sep 17 00:00:00 2001 From: Luis Henriques Date: Wed, 23 Nov 2016 23:40:36 +0000 Subject: mtd: maps: add missing iounmap() in error path This patch was triggered by the following Coccinelle error: ./drivers/mtd/maps/sc520cdp.c:246:3-9: \ ERROR: missing iounmap; ioremap on line 242 \ and execution via conditional on line 244 Since do_map_probe() is also invoked in this loop, it is also necessary to map_destroy() any initialised struct mtd_info. Signed-off-by: Luis Henriques Reviewed-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/maps/sc520cdp.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c index 093edd51bdc7..9b1c13aa9f20 100644 --- a/drivers/mtd/maps/sc520cdp.c +++ b/drivers/mtd/maps/sc520cdp.c @@ -227,7 +227,7 @@ static void sc520cdp_setup_par(void) static int __init init_sc520cdp(void) { - int i, devices_found = 0; + int i, j, devices_found = 0; #ifdef REPROGRAM_PAR /* reprogram PAR registers so flash appears at the desired addresses */ @@ -243,6 +243,12 @@ static int __init init_sc520cdp(void) if (!sc520cdp_map[i].virt) { printk("Failed to ioremap_nocache\n"); + for (j = 0; j < i; j++) { + if (mymtd[j]) { + map_destroy(mymtd[j]); + iounmap(sc520cdp_map[j].virt); + } + } return -EIO; } -- cgit v1.2.3 From 9c0bc511e93cc7693f0147274edfb719f221b8c1 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 30 Nov 2016 22:01:59 +0100 Subject: crypto: caam - pass key buffers with typesafe pointers The 'key' field is defined as a 'u64' and used for two different pieces of information: either to store a pointer or a dma_addr_t. The former leads to a build error on 32-bit machines: drivers/crypto/caam/caamalg_desc.c: In function 'cnstr_shdsc_aead_null_encap': drivers/crypto/caam/caamalg_desc.c:67:27: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] drivers/crypto/caam/caamalg_desc.c: In function 'cnstr_shdsc_aead_null_decap': drivers/crypto/caam/caamalg_desc.c:143:27: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] Using a union to provide correct types gets rid of the warnings and as well as a couple of redundant casts. Fixes: db57656b0072 ("crypto: caam - group algorithm related params") Signed-off-by: Arnd Bergmann Signed-off-by: Herbert Xu --- drivers/crypto/caam/caamalg.c | 60 +++++++++++++++++++------------------- drivers/crypto/caam/caamalg_desc.c | 56 +++++++++++++++++------------------ drivers/crypto/caam/desc_constr.h | 5 +++- 3 files changed, 62 insertions(+), 59 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c index 37f0540d4694..662fe94cb2f8 100644 --- a/drivers/crypto/caam/caamalg.c +++ b/drivers/crypto/caam/caamalg.c @@ -162,10 +162,10 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_AEAD_NULL_ENC_LEN) { ctx->adata.key_inline = true; - ctx->adata.key = (uintptr_t)ctx->key; + ctx->adata.key_virt = ctx->key; } else { ctx->adata.key_inline = false; - ctx->adata.key = ctx->key_dma; + ctx->adata.key_dma = ctx->key_dma; } /* aead_encrypt shared descriptor */ @@ -185,10 +185,10 @@ static int aead_null_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_AEAD_NULL_DEC_LEN) { ctx->adata.key_inline = true; - ctx->adata.key = (uintptr_t)ctx->key; + ctx->adata.key_virt = ctx->key; } else { ctx->adata.key_inline = false; - ctx->adata.key = ctx->key_dma; + ctx->adata.key_dma = ctx->key_dma; } /* aead_decrypt shared descriptor */ @@ -262,14 +262,14 @@ static int aead_set_sh_desc(struct crypto_aead *aead) return -EINVAL; if (inl_mask & 1) - ctx->adata.key = (uintptr_t)ctx->key; + ctx->adata.key_virt = ctx->key; else - ctx->adata.key = ctx->key_dma; + ctx->adata.key_dma = ctx->key_dma; if (inl_mask & 2) - ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; else - ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -298,14 +298,14 @@ skip_enc: return -EINVAL; if (inl_mask & 1) - ctx->adata.key = (uintptr_t)ctx->key; + ctx->adata.key_virt = ctx->key; else - ctx->adata.key = ctx->key_dma; + ctx->adata.key_dma = ctx->key_dma; if (inl_mask & 2) - ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; else - ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -337,14 +337,14 @@ skip_enc: return -EINVAL; if (inl_mask & 1) - ctx->adata.key = (uintptr_t)ctx->key; + ctx->adata.key_virt = ctx->key; else - ctx->adata.key = ctx->key_dma; + ctx->adata.key_dma = ctx->key_dma; if (inl_mask & 2) - ctx->cdata.key = (uintptr_t)(ctx->key + ctx->adata.keylen_pad); + ctx->cdata.key_virt = ctx->key + ctx->adata.keylen_pad; else - ctx->cdata.key = ctx->key_dma + ctx->adata.keylen_pad; + ctx->cdata.key_dma = ctx->key_dma + ctx->adata.keylen_pad; ctx->adata.key_inline = !!(inl_mask & 1); ctx->cdata.key_inline = !!(inl_mask & 2); @@ -395,10 +395,10 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_GCM_ENC_LEN) { ctx->cdata.key_inline = true; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; } else { ctx->cdata.key_inline = false; - ctx->cdata.key = ctx->key_dma; + ctx->cdata.key_dma = ctx->key_dma; } desc = ctx->sh_desc_enc; @@ -417,10 +417,10 @@ static int gcm_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_GCM_DEC_LEN) { ctx->cdata.key_inline = true; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; } else { ctx->cdata.key_inline = false; - ctx->cdata.key = ctx->key_dma; + ctx->cdata.key_dma = ctx->key_dma; } desc = ctx->sh_desc_dec; @@ -464,10 +464,10 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_RFC4106_ENC_LEN) { ctx->cdata.key_inline = true; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; } else { ctx->cdata.key_inline = false; - ctx->cdata.key = ctx->key_dma; + ctx->cdata.key_dma = ctx->key_dma; } desc = ctx->sh_desc_enc; @@ -486,10 +486,10 @@ static int rfc4106_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_RFC4106_DEC_LEN) { ctx->cdata.key_inline = true; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; } else { ctx->cdata.key_inline = false; - ctx->cdata.key = ctx->key_dma; + ctx->cdata.key_dma = ctx->key_dma; } desc = ctx->sh_desc_dec; @@ -534,10 +534,10 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_RFC4543_ENC_LEN) { ctx->cdata.key_inline = true; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; } else { ctx->cdata.key_inline = false; - ctx->cdata.key = ctx->key_dma; + ctx->cdata.key_dma = ctx->key_dma; } desc = ctx->sh_desc_enc; @@ -556,10 +556,10 @@ static int rfc4543_set_sh_desc(struct crypto_aead *aead) */ if (rem_bytes >= DESC_RFC4543_DEC_LEN) { ctx->cdata.key_inline = true; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; } else { ctx->cdata.key_inline = false; - ctx->cdata.key = ctx->key_dma; + ctx->cdata.key_dma = ctx->key_dma; } desc = ctx->sh_desc_dec; @@ -794,7 +794,7 @@ static int ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return -ENOMEM; } ctx->cdata.keylen = keylen; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; ctx->cdata.key_inline = true; /* ablkcipher_encrypt shared descriptor */ @@ -857,7 +857,7 @@ static int xts_ablkcipher_setkey(struct crypto_ablkcipher *ablkcipher, return -ENOMEM; } ctx->cdata.keylen = keylen; - ctx->cdata.key = (uintptr_t)ctx->key; + ctx->cdata.key_virt = ctx->key; ctx->cdata.key_inline = true; /* xts_ablkcipher_encrypt shared descriptor */ diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index fa2479d9da24..7dee952ef432 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -64,11 +64,11 @@ void cnstr_shdsc_aead_null_encap(u32 * const desc, struct alginfo *adata, key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); if (adata->key_inline) - append_key_as_imm(desc, (void *)adata->key, adata->keylen_pad, + append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); else - append_key(desc, adata->key, adata->keylen, CLASS_2 | + append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); set_jump_tgt_here(desc, key_jump_cmd); @@ -140,11 +140,11 @@ void cnstr_shdsc_aead_null_decap(u32 * const desc, struct alginfo *adata, key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); if (adata->key_inline) - append_key_as_imm(desc, (void *)adata->key, adata->keylen_pad, + append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); else - append_key(desc, adata->key, adata->keylen, CLASS_2 | + append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); set_jump_tgt_here(desc, key_jump_cmd); @@ -225,18 +225,18 @@ static void init_sh_desc_key_aead(u32 * const desc, enckeylen -= CTR_RFC3686_NONCE_SIZE; if (adata->key_inline) - append_key_as_imm(desc, (void *)adata->key, adata->keylen_pad, + append_key_as_imm(desc, adata->key_virt, adata->keylen_pad, adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); else - append_key(desc, adata->key, adata->keylen, CLASS_2 | + append_key(desc, adata->key_dma, adata->keylen, CLASS_2 | KEY_DEST_MDHA_SPLIT | KEY_ENC); if (cdata->key_inline) - append_key_as_imm(desc, (void *)cdata->key, enckeylen, + append_key_as_imm(desc, cdata->key_virt, enckeylen, enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, cdata->key, enckeylen, CLASS_1 | + append_key(desc, cdata->key_dma, enckeylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load Counter into CONTEXT1 reg */ @@ -536,10 +536,10 @@ void cnstr_shdsc_gcm_encap(u32 * const desc, struct alginfo *cdata, key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD | JUMP_COND_SELF); if (cdata->key_inline) - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); @@ -626,10 +626,10 @@ void cnstr_shdsc_gcm_decap(u32 * const desc, struct alginfo *cdata, JUMP_TEST_ALL | JUMP_COND_SHRD | JUMP_COND_SELF); if (cdata->key_inline) - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); @@ -702,10 +702,10 @@ void cnstr_shdsc_rfc4106_encap(u32 * const desc, struct alginfo *cdata, key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); if (cdata->key_inline) - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); @@ -773,11 +773,11 @@ void cnstr_shdsc_rfc4106_decap(u32 * const desc, struct alginfo *cdata, key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); if (cdata->key_inline) - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); @@ -845,10 +845,10 @@ void cnstr_shdsc_rfc4543_encap(u32 * const desc, struct alginfo *cdata, key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); if (cdata->key_inline) - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); @@ -915,10 +915,10 @@ void cnstr_shdsc_rfc4543_decap(u32 * const desc, struct alginfo *cdata, key_jump_cmd = append_jump(desc, JUMP_JSL | JUMP_TEST_ALL | JUMP_COND_SHRD); if (cdata->key_inline) - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); else - append_key(desc, cdata->key, cdata->keylen, CLASS_1 | + append_key(desc, cdata->key_dma, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); set_jump_tgt_here(desc, key_jump_cmd); @@ -1006,12 +1006,12 @@ void cnstr_shdsc_ablkcipher_encap(u32 * const desc, struct alginfo *cdata, JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load nonce into CONTEXT1 reg */ if (is_rfc3686) { - u8 *nonce = (u8 *)cdata->key + cdata->keylen; + u8 *nonce = cdata->key_virt + cdata->keylen; append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, LDST_CLASS_IND_CCB | @@ -1071,12 +1071,12 @@ void cnstr_shdsc_ablkcipher_decap(u32 * const desc, struct alginfo *cdata, JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load nonce into CONTEXT1 reg */ if (is_rfc3686) { - u8 *nonce = (u8 *)cdata->key + cdata->keylen; + u8 *nonce = cdata->key_virt + cdata->keylen; append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, LDST_CLASS_IND_CCB | @@ -1140,12 +1140,12 @@ void cnstr_shdsc_ablkcipher_givencap(u32 * const desc, struct alginfo *cdata, JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load Nonce into CONTEXT1 reg */ if (is_rfc3686) { - u8 *nonce = (u8 *)cdata->key + cdata->keylen; + u8 *nonce = cdata->key_virt + cdata->keylen; append_load_as_imm(desc, nonce, CTR_RFC3686_NONCE_SIZE, LDST_CLASS_IND_CCB | @@ -1216,7 +1216,7 @@ void cnstr_shdsc_xts_ablkcipher_encap(u32 * const desc, struct alginfo *cdata) JUMP_COND_SHRD); /* Load class1 keys only */ - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load sector size with index 40 bytes (0x28) */ @@ -1268,7 +1268,7 @@ void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata) JUMP_COND_SHRD); /* Load class1 key only */ - append_key_as_imm(desc, (void *)cdata->key, cdata->keylen, + append_key_as_imm(desc, cdata->key_virt, cdata->keylen, cdata->keylen, CLASS_1 | KEY_DEST_CLASS_REG); /* Load sector size with index 40 bytes (0x28) */ diff --git a/drivers/crypto/caam/desc_constr.h b/drivers/crypto/caam/desc_constr.h index fa70c0d79c40..b9c8d98ef826 100644 --- a/drivers/crypto/caam/desc_constr.h +++ b/drivers/crypto/caam/desc_constr.h @@ -446,7 +446,10 @@ struct alginfo { u32 algtype; unsigned int keylen; unsigned int keylen_pad; - u64 key; + union { + dma_addr_t key_dma; + void *key_virt; + }; bool key_inline; }; -- cgit v1.2.3 From 37d8468108efb19b80aa8484534f8850ed60dbfb Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 30 Nov 2016 22:02:00 +0100 Subject: crypto: caam - make aamalg_desc a proper module The drivers/crypto/caam/ directory is entered during build only for building modules when CONFIG_CRYPTO_DEV_FSL_CAAM=m, but CONFIG_CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC is defined as a 'bool' symbol, meaning that caamalg_desc.c is always compiled into built-in code, or not at all, leading to a link failure: ERROR: "cnstr_shdsc_xts_ablkcipher_decap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_xts_ablkcipher_encap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_aead_givencap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_aead_decap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_aead_encap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_aead_null_decap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_aead_null_encap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_rfc4106_decap" [drivers/crypto/caam/caamalg.ko] undefined! ERROR: "cnstr_shdsc_rfc4106_encap" [drivers/crypto/caam/caamalg.ko] undefined! ... Making caamalg_desc itself a loadable module fixes this configuration by ensuring the driver gets built. Aside from making the symbol 'tristate', I'm adding appropriate module metadata here. Fixes: 8cea7b66b821 ("crypto: caam - refactor encryption descriptors generation") Signed-off-by: Arnd Bergmann Signed-off-by: Herbert Xu --- drivers/crypto/caam/Kconfig | 2 +- drivers/crypto/caam/caamalg_desc.c | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/Kconfig b/drivers/crypto/caam/Kconfig index da24c5752c06..bc0d3569f8d9 100644 --- a/drivers/crypto/caam/Kconfig +++ b/drivers/crypto/caam/Kconfig @@ -136,4 +136,4 @@ config CRYPTO_DEV_FSL_CAAM_DEBUG information in the CAAM driver. config CRYPTO_DEV_FSL_CAAM_CRYPTO_API_DESC - def_bool CRYPTO_DEV_FSL_CAAM_CRYPTO_API + def_tristate CRYPTO_DEV_FSL_CAAM_CRYPTO_API diff --git a/drivers/crypto/caam/caamalg_desc.c b/drivers/crypto/caam/caamalg_desc.c index 7dee952ef432..f3f48c10b9d6 100644 --- a/drivers/crypto/caam/caamalg_desc.c +++ b/drivers/crypto/caam/caamalg_desc.c @@ -1300,3 +1300,7 @@ void cnstr_shdsc_xts_ablkcipher_decap(u32 * const desc, struct alginfo *cdata) #endif } EXPORT_SYMBOL(cnstr_shdsc_xts_ablkcipher_decap); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("FSL CAAM descriptor support"); +MODULE_AUTHOR("Freescale Semiconductor - NMG/STC"); -- cgit v1.2.3 From b40769ee2ed09ed6c6da33b0cbdf423ff94f685b Mon Sep 17 00:00:00 2001 From: Sean Young Date: Sat, 26 Nov 2016 19:31:24 -0200 Subject: [media] lirc: fix error paths in lirc_cdev_add() "c77d17c0 [media] lirc: use-after free" introduces two problems: cdev_del() can be called with a NULL argument, and the kobject_put() path will cause a double free. Reported-by: Dan Carpenter Signed-off-by: Sean Young Signed-off-by: Mauro Carvalho Chehab --- drivers/media/rc/lirc_dev.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c index d3039efb4e7c..3854809e8531 100644 --- a/drivers/media/rc/lirc_dev.c +++ b/drivers/media/rc/lirc_dev.c @@ -157,13 +157,13 @@ static const struct file_operations lirc_dev_fops = { static int lirc_cdev_add(struct irctl *ir) { - int retval = -ENOMEM; struct lirc_driver *d = &ir->d; struct cdev *cdev; + int retval; cdev = cdev_alloc(); if (!cdev) - goto err_out; + return -ENOMEM; if (d->fops) { cdev->ops = d->fops; @@ -177,10 +177,8 @@ static int lirc_cdev_add(struct irctl *ir) goto err_out; retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1); - if (retval) { - kobject_put(&cdev->kobj); + if (retval) goto err_out; - } ir->cdev = cdev; -- cgit v1.2.3 From d930b5b5bf122a61952cfebabb1e618682a2631a Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 30 Nov 2016 19:36:14 -0200 Subject: [media] mn88473: fix chip id check on probe A register used to identify chip during probe was overwritten during firmware download and due to that later probe's for warm chip were failing. Detect chip from the another register, which is located on different register bank 2. Fixes: 7908fad99a6c ("[media] mn88473: finalize driver") Cc: # v4.8+ Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mn88473.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/mn88473.c b/drivers/media/dvb-frontends/mn88473.c index f3b59a5827d9..c221c7d2ac3e 100644 --- a/drivers/media/dvb-frontends/mn88473.c +++ b/drivers/media/dvb-frontends/mn88473.c @@ -648,18 +648,6 @@ static int mn88473_probe(struct i2c_client *client, goto err_kfree; } - /* Check demod answers with correct chip id */ - ret = regmap_read(dev->regmap[0], 0xff, &uitmp); - if (ret) - goto err_regmap_0_regmap_exit; - - dev_dbg(&client->dev, "chip id=%02x\n", uitmp); - - if (uitmp != 0x03) { - ret = -ENODEV; - goto err_regmap_0_regmap_exit; - } - /* * Chip has three I2C addresses for different register banks. Used * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, @@ -696,6 +684,18 @@ static int mn88473_probe(struct i2c_client *client, } i2c_set_clientdata(dev->client[2], dev); + /* Check demod answers with correct chip id */ + ret = regmap_read(dev->regmap[2], 0xff, &uitmp); + if (ret) + goto err_regmap_2_regmap_exit; + + dev_dbg(&client->dev, "chip id=%02x\n", uitmp); + + if (uitmp != 0x03) { + ret = -ENODEV; + goto err_regmap_2_regmap_exit; + } + /* Sleep because chip is active by default */ ret = regmap_write(dev->regmap[2], 0x05, 0x3e); if (ret) -- cgit v1.2.3 From 365fe4e0ce218dc5ad10df17b150a366b6015499 Mon Sep 17 00:00:00 2001 From: Antti Palosaari Date: Wed, 30 Nov 2016 22:08:27 -0200 Subject: [media] mn88472: fix chip id check on probe A register used to identify chip during probe was overwritten during firmware download and due to that later probe's for warm chip were failing. Detect chip from the another register, which is located on different register bank 2. Fixes: 94d0eaa41987 ("[media] mn88472: move out of staging to media") Cc: # v4.8+ Signed-off-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/dvb-frontends/mn88472.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/media/dvb-frontends/mn88472.c b/drivers/media/dvb-frontends/mn88472.c index b6f5f8337cfd..29dd13b36c28 100644 --- a/drivers/media/dvb-frontends/mn88472.c +++ b/drivers/media/dvb-frontends/mn88472.c @@ -488,18 +488,6 @@ static int mn88472_probe(struct i2c_client *client, goto err_kfree; } - /* Check demod answers with correct chip id */ - ret = regmap_read(dev->regmap[0], 0xff, &utmp); - if (ret) - goto err_regmap_0_regmap_exit; - - dev_dbg(&client->dev, "chip id=%02x\n", utmp); - - if (utmp != 0x02) { - ret = -ENODEV; - goto err_regmap_0_regmap_exit; - } - /* * Chip has three I2C addresses for different register banks. Used * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients, @@ -536,6 +524,18 @@ static int mn88472_probe(struct i2c_client *client, } i2c_set_clientdata(dev->client[2], dev); + /* Check demod answers with correct chip id */ + ret = regmap_read(dev->regmap[2], 0xff, &utmp); + if (ret) + goto err_regmap_2_regmap_exit; + + dev_dbg(&client->dev, "chip id=%02x\n", utmp); + + if (utmp != 0x02) { + ret = -ENODEV; + goto err_regmap_2_regmap_exit; + } + /* Sleep because chip is active by default */ ret = regmap_write(dev->regmap[2], 0x05, 0x3e); if (ret) -- cgit v1.2.3 From 59dbc86cdc42b6d8766218066429f00186b021c2 Mon Sep 17 00:00:00 2001 From: Marc Gonzalez Date: Thu, 1 Dec 2016 11:22:14 +0100 Subject: mtd: nand: tango: Add standard legalese header Provide proper copyright notice and license information. Signed-off-by: Marc Gonzalez Signed-off-by: Brian Norris --- drivers/mtd/nand/tango_nand.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/tango_nand.c b/drivers/mtd/nand/tango_nand.c index ec87516b87f5..28c7f474be77 100644 --- a/drivers/mtd/nand/tango_nand.c +++ b/drivers/mtd/nand/tango_nand.c @@ -1,3 +1,11 @@ +/* + * Copyright (C) 2016 Sigma Designs + * + * 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 -- cgit v1.2.3 From 445caaa20c4d6da74f426464f90513b81157ad77 Mon Sep 17 00:00:00 2001 From: Steve Longerbeam Date: Thu, 4 Aug 2016 19:31:15 +0530 Subject: mtd: Allocate bdi objects dynamically The MTD backing dev info objects mtd_bdi was statically allocated. So when MTD is built as a loadable module, this object fall in the vmalloc address space. The problem with that, is that the BDI APIs use wake_up_bit(), which calls virt_to_page() to retrieve the memory zone of the page containing the wait_queue to wake up, and virt_to_page() is not valid for vmalloc or highmem addresses. Fix this by allocating the BDI objects dynamically with kmalloc. The objects now fall in the logical address space so that BDI APIs will work in all cases (mtd builtin or module). Signed-off-by: Steve Longerbeam Signed-off-by: Jim Baxter Signed-off-by: Sandeep Jain Reviewed-by: Richard Weinberger Reviewed-by: Marek Vasut Signed-off-by: Brian Norris --- drivers/mtd/mtdcore.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index ca661cee9b77..052772f7caef 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -46,8 +46,7 @@ #include "mtdcore.h" -static struct backing_dev_info mtd_bdi = { -}; +static struct backing_dev_info *mtd_bdi; #ifdef CONFIG_PM_SLEEP @@ -500,7 +499,7 @@ int add_mtd_device(struct mtd_info *mtd) if (WARN_ONCE(mtd->backing_dev_info, "MTD already registered\n")) return -EEXIST; - mtd->backing_dev_info = &mtd_bdi; + mtd->backing_dev_info = mtd_bdi; BUG_ON(mtd->writesize == 0); mutex_lock(&mtd_table_mutex); @@ -1771,18 +1770,20 @@ static const struct file_operations mtd_proc_ops = { /*====================================================================*/ /* Init code */ -static int __init mtd_bdi_init(struct backing_dev_info *bdi, const char *name) +static struct backing_dev_info * __init mtd_bdi_init(char *name) { + struct backing_dev_info *bdi; int ret; - ret = bdi_init(bdi); - if (!ret) - ret = bdi_register(bdi, NULL, "%s", name); + bdi = kzalloc(sizeof(*bdi), GFP_KERNEL); + if (!bdi) + return ERR_PTR(-ENOMEM); + ret = bdi_setup_and_register(bdi, name); if (ret) - bdi_destroy(bdi); + kfree(bdi); - return ret; + return ret ? ERR_PTR(ret) : bdi; } static struct proc_dir_entry *proc_mtd; @@ -1795,9 +1796,11 @@ static int __init init_mtd(void) if (ret) goto err_reg; - ret = mtd_bdi_init(&mtd_bdi, "mtd"); - if (ret) + mtd_bdi = mtd_bdi_init("mtd"); + if (IS_ERR(mtd_bdi)) { + ret = PTR_ERR(mtd_bdi); goto err_bdi; + } proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops); @@ -1810,6 +1813,8 @@ static int __init init_mtd(void) out_procfs: if (proc_mtd) remove_proc_entry("mtd", NULL); + bdi_destroy(mtd_bdi); + kfree(mtd_bdi); err_bdi: class_unregister(&mtd_class); err_reg: @@ -1823,7 +1828,8 @@ static void __exit cleanup_mtd(void) if (proc_mtd) remove_proc_entry("mtd", NULL); class_unregister(&mtd_class); - bdi_destroy(&mtd_bdi); + bdi_destroy(mtd_bdi); + kfree(mtd_bdi); idr_destroy(&mtd_idr); } -- cgit v1.2.3 From efd95c71f4892ad5d0d33099db25085763f4c6c3 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 29 Nov 2016 15:44:41 +0000 Subject: extcon: arizona: Use SoC component pin control functions The name of a codec pin can have an optional prefix string, which is defined by the SoC machine driver. The snd_soc_dapm_x_pin functions take the fully-specified name including the prefix and so the existing code would fail to find the pin if the audio machine driver had added a prefix. Switch to using the snd_soc_component_x_pin equivalent functions that take a specified SoC component and automatically add the name prefix to the provided pin name. Signed-off-by: Richard Fitzgerald Acked-by: Chanwoo Choi Signed-off-by: Mark Brown --- drivers/extcon/extcon-arizona.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/extcon/extcon-arizona.c b/drivers/extcon/extcon-arizona.c index 56e6c4c7c60d..d836d4ce5ee4 100644 --- a/drivers/extcon/extcon-arizona.c +++ b/drivers/extcon/extcon-arizona.c @@ -274,9 +274,10 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) struct arizona *arizona = info->arizona; const char *widget = arizona_extcon_get_micbias(info); struct snd_soc_dapm_context *dapm = arizona->dapm; + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); int ret; - ret = snd_soc_dapm_force_enable_pin(dapm, widget); + ret = snd_soc_component_force_enable_pin(component, widget); if (ret != 0) dev_warn(arizona->dev, "Failed to enable %s: %d\n", widget, ret); @@ -284,7 +285,7 @@ static void arizona_extcon_pulse_micbias(struct arizona_extcon_info *info) snd_soc_dapm_sync(dapm); if (!arizona->pdata.micd_force_micbias) { - ret = snd_soc_dapm_disable_pin(arizona->dapm, widget); + ret = snd_soc_component_disable_pin(component, widget); if (ret != 0) dev_warn(arizona->dev, "Failed to disable %s: %d\n", widget, ret); @@ -349,6 +350,7 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) struct arizona *arizona = info->arizona; const char *widget = arizona_extcon_get_micbias(info); struct snd_soc_dapm_context *dapm = arizona->dapm; + struct snd_soc_component *component = snd_soc_dapm_to_component(dapm); bool change; int ret; @@ -356,7 +358,7 @@ static void arizona_stop_mic(struct arizona_extcon_info *info) ARIZONA_MICD_ENA, 0, &change); - ret = snd_soc_dapm_disable_pin(dapm, widget); + ret = snd_soc_component_disable_pin(component, widget); if (ret != 0) dev_warn(arizona->dev, "Failed to disable %s: %d\n", -- cgit v1.2.3 From 931afc4114c59b8fe8386db9fcdfe69a1322cae6 Mon Sep 17 00:00:00 2001 From: Richard Fitzgerald Date: Tue, 29 Nov 2016 15:44:42 +0000 Subject: Input: arizona-haptics - Use SoC component pin control functions The name of a codec pin can have an optional prefix string, which is defined by the SoC machine driver. The snd_soc_dapm_x_pin functions take the fully-specified name including the prefix and so the existing code would fail to find the pin if the audio machine driver had added a prefix. Switch to using the snd_soc_component_x_pin equivalent functions that take a specified SoC component and automatically add the name prefix to the provided pin name. Signed-off-by: Richard Fitzgerald Acked-by: Dmitry Torokhov Signed-off-by: Mark Brown --- drivers/input/misc/arizona-haptics.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/arizona-haptics.c b/drivers/input/misc/arizona-haptics.c index 982936334537..07ec465f1095 100644 --- a/drivers/input/misc/arizona-haptics.c +++ b/drivers/input/misc/arizona-haptics.c @@ -37,6 +37,8 @@ static void arizona_haptics_work(struct work_struct *work) struct arizona_haptics, work); struct arizona *arizona = haptics->arizona; + struct snd_soc_component *component = + snd_soc_dapm_to_component(arizona->dapm); int ret; if (!haptics->arizona->dapm) { @@ -66,7 +68,7 @@ static void arizona_haptics_work(struct work_struct *work) return; } - ret = snd_soc_dapm_enable_pin(arizona->dapm, "HAPTICS"); + ret = snd_soc_component_enable_pin(component, "HAPTICS"); if (ret != 0) { dev_err(arizona->dev, "Failed to start HAPTICS: %d\n", ret); @@ -81,7 +83,7 @@ static void arizona_haptics_work(struct work_struct *work) } } else { /* This disable sequence will be a noop if already enabled */ - ret = snd_soc_dapm_disable_pin(arizona->dapm, "HAPTICS"); + ret = snd_soc_component_disable_pin(component, "HAPTICS"); if (ret != 0) { dev_err(arizona->dev, "Failed to disable HAPTICS: %d\n", ret); @@ -140,11 +142,14 @@ static int arizona_haptics_play(struct input_dev *input, void *data, static void arizona_haptics_close(struct input_dev *input) { struct arizona_haptics *haptics = input_get_drvdata(input); + struct snd_soc_component *component; cancel_work_sync(&haptics->work); - if (haptics->arizona->dapm) - snd_soc_dapm_disable_pin(haptics->arizona->dapm, "HAPTICS"); + if (haptics->arizona->dapm) { + component = snd_soc_dapm_to_component(haptics->arizona->dapm); + snd_soc_component_disable_pin(component, "HAPTICS"); + } } static int arizona_haptics_probe(struct platform_device *pdev) -- cgit v1.2.3 From 00710984eac523ffed4e92850511d7610cfe908b Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 30 Nov 2016 14:47:13 -0600 Subject: ACPI: Add acpi_resource_consumer() to find device that claims a resource Add acpi_resource_consumer(). This takes a struct resource and searches the ACPI namespace for a device whose current resource settings (_CRS) includes the resource. It returns the device if it exists, or NULL if no device uses the resource. If more than one device uses the resource (this may happen in the case of bridges), acpi_resource_consumer() returns the first one found by acpi_get_devices() in its modified depth-first walk of the namespace. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/acpi/resource.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++ include/linux/acpi.h | 7 ++++++ 2 files changed, 64 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c index 56241eb341f4..cb57962ef7c4 100644 --- a/drivers/acpi/resource.c +++ b/drivers/acpi/resource.c @@ -664,3 +664,60 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares, return (type & types) ? 0 : 1; } EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type); + +static int acpi_dev_consumes_res(struct acpi_device *adev, struct resource *res) +{ + struct list_head resource_list; + struct resource_entry *rentry; + int ret, found = 0; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); + if (ret < 0) + return 0; + + list_for_each_entry(rentry, &resource_list, node) { + if (resource_contains(rentry->res, res)) { + found = 1; + break; + } + + } + + acpi_dev_free_resource_list(&resource_list); + return found; +} + +static acpi_status acpi_res_consumer_cb(acpi_handle handle, u32 depth, + void *context, void **ret) +{ + struct resource *res = context; + struct acpi_device **consumer = (struct acpi_device **) ret; + struct acpi_device *adev; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + if (acpi_dev_consumes_res(adev, res)) { + *consumer = adev; + return AE_CTRL_TERMINATE; + } + + return AE_OK; +} + +/** + * acpi_resource_consumer - Find the ACPI device that consumes @res. + * @res: Resource to search for. + * + * Search the current resource settings (_CRS) of every ACPI device node + * for @res. If we find an ACPI device whose _CRS includes @res, return + * it. Otherwise, return NULL. + */ +struct acpi_device *acpi_resource_consumer(struct resource *res) +{ + struct acpi_device *consumer = NULL; + + acpi_get_devices(NULL, acpi_res_consumer_cb, res, (void **) &consumer); + return consumer; +} diff --git a/include/linux/acpi.h b/include/linux/acpi.h index ddbeda6dbdc8..b00ad73c946d 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -419,6 +419,8 @@ static inline int acpi_dev_filter_resource_type_cb(struct acpi_resource *ares, return acpi_dev_filter_resource_type(ares, (unsigned long)arg); } +struct acpi_device *acpi_resource_consumer(struct resource *res); + int acpi_check_resource_conflict(const struct resource *res); int acpi_check_region(resource_size_t start, resource_size_t n, @@ -762,6 +764,11 @@ static inline int acpi_reconfig_notifier_unregister(struct notifier_block *nb) return -EINVAL; } +static inline struct acpi_device *acpi_resource_consumer(struct resource *res) +{ + return NULL; +} + #endif /* !CONFIG_ACPI */ #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC -- cgit v1.2.3 From 6c14bdacdb29c391fe76e442139d96bc1bf1f59b Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Thu, 1 Dec 2016 12:04:37 +0100 Subject: i2c: pxa: Add definition of fast and high speed modes via the regs layout So far, the bit masks for the fast and high speed mode were statically defined. Some IP blocks might use different bits for these modes. This commit introduces new fields in order to enable the definition of different bit masks for these features. If these fields are undefined, ICR_FM and ICR_HS are selected to preserve backward compatibility with other IPs. Signed-off-by: Romain Perier Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index e28b825b0433..b4ac235c48ff 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -48,6 +48,8 @@ struct pxa_reg_layout { u32 isar; u32 ilcr; u32 iwcr; + u32 fm; + u32 hs; }; enum pxa_i2c_types { @@ -193,6 +195,8 @@ struct pxa_i2c { unsigned char master_code; unsigned long rate; bool highmode_enter; + u32 fm_mask; + u32 hs_mask; }; #define _IBMR(i2c) ((i2c)->reg_ibmr) @@ -503,8 +507,8 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) writel(i2c->slave_addr, _ISAR(i2c)); /* set control register values */ - writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c)); - writel(readl(_ICR(i2c)) | (i2c->high_mode ? ICR_HS : 0), _ICR(i2c)); + writel(I2C_ICR_INIT | (i2c->fast_mode ? i2c->fm_mask : 0), _ICR(i2c)); + writel(readl(_ICR(i2c)) | (i2c->high_mode ? i2c->hs_mask : 0), _ICR(i2c)); #ifdef CONFIG_I2C_PXA_SLAVE dev_info(&i2c->adap.dev, "Enabling slave mode\n"); @@ -1234,6 +1238,9 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; i2c->reg_icr = i2c->reg_base + pxa_reg_layout[i2c_type].icr; i2c->reg_isr = i2c->reg_base + pxa_reg_layout[i2c_type].isr; + i2c->fm_mask = pxa_reg_layout[i2c_type].fm ? : ICR_FM; + i2c->hs_mask = pxa_reg_layout[i2c_type].hs ? : ICR_HS; + if (i2c_type != REGS_CE4100) i2c->reg_isar = i2c->reg_base + pxa_reg_layout[i2c_type].isar; -- cgit v1.2.3 From 294be03c627b469f79ce391dafb163581d3158ba Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Thu, 1 Dec 2016 12:04:38 +0100 Subject: i2c: pxa: Add support for the I2C units found in Armada 3700 The Armada 3700 has two I2C controllers that is compliant with the I2C Bus Specificiation 2.1, supports multi-master and different bus speed: Standard mode (up to 100 KHz), Fast mode (up to 400 KHz), High speed mode (up to 3.4 Mhz). This IP block has a lot of similarity with the PXA, except some register offsets and bitfield. This commits adds a basic support for this I2C unit. Signed-off-by: Romain Perier Tested-by: Gregory CLEMENT Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- drivers/i2c/busses/i2c-pxa.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 6399ceab402b..3ff7c031e04a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -763,7 +763,7 @@ config I2C_PUV3 config I2C_PXA tristate "Intel PXA2XX I2C adapter" - depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF) + depends on ARCH_PXA || ARCH_MMP || ARCH_MVEBU || (X86_32 && PCI && OF) help If you have devices in the PXA I2C bus, say yes to this option. This driver can also be built as a module. If so, the module diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index b4ac235c48ff..6cf333ecc8b8 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -57,8 +57,12 @@ enum pxa_i2c_types { REGS_PXA3XX, REGS_CE4100, REGS_PXA910, + REGS_A3700, }; +#define ICR_BUSMODE_FM (1 << 16) /* shifted fast mode for armada-3700 */ +#define ICR_BUSMODE_HS (1 << 17) /* shifted high speed mode for armada-3700 */ + /* * I2C registers definitions */ @@ -93,6 +97,15 @@ static struct pxa_reg_layout pxa_reg_layout[] = { .ilcr = 0x28, .iwcr = 0x30, }, + [REGS_A3700] = { + .ibmr = 0x00, + .idbr = 0x04, + .icr = 0x08, + .isr = 0x0c, + .isar = 0x10, + .fm = ICR_BUSMODE_FM, + .hs = ICR_BUSMODE_HS, + }, }; static const struct platform_device_id i2c_pxa_id_table[] = { @@ -100,6 +113,7 @@ static const struct platform_device_id i2c_pxa_id_table[] = { { "pxa3xx-pwri2c", REGS_PXA3XX }, { "ce4100-i2c", REGS_CE4100 }, { "pxa910-i2c", REGS_PXA910 }, + { "armada-3700-i2c", REGS_A3700 }, { }, }; MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); @@ -1141,6 +1155,7 @@ static const struct of_device_id i2c_pxa_dt_ids[] = { { .compatible = "mrvl,pxa-i2c", .data = (void *)REGS_PXA2XX }, { .compatible = "mrvl,pwri2c", .data = (void *)REGS_PXA3XX }, { .compatible = "mrvl,mmp-twsi", .data = (void *)REGS_PXA910 }, + { .compatible = "marvell,armada-3700-i2c", .data = (void *)REGS_A3700 }, {} }; MODULE_DEVICE_TABLE(of, i2c_pxa_dt_ids); -- cgit v1.2.3 From 531ccabbe4cc2d09234e9009d47f7f2539c6d047 Mon Sep 17 00:00:00 2001 From: Alexander Stein Date: Wed, 30 Nov 2016 17:34:15 +0100 Subject: i2c: designware-pcidrv: Add 10bit address feature to medfield/merrifield Both Merrifield TRM and Medfield TRM state: "Both 7-bit and 10-bit addressing modes are supported." Signed-off-by: Alexander Stein Acked-by: Andy Shevchenko Acked-by: Jarkko Nikula Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-pcidrv.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 300802e75d2e..d6423cfac588 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -141,6 +141,7 @@ static struct dw_pci_controller dw_pci_controllers[] = { .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .tx_fifo_depth = 32, .rx_fifo_depth = 32, + .functionality = I2C_FUNC_10BIT_ADDR, .clk_khz = 25000, .setup = mfld_setup, }, @@ -149,6 +150,7 @@ static struct dw_pci_controller dw_pci_controllers[] = { .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST, .tx_fifo_depth = 64, .rx_fifo_depth = 64, + .functionality = I2C_FUNC_10BIT_ADDR, .scl_sda_cfg = &mrfld_config, .setup = mrfld_setup, }, -- cgit v1.2.3 From a55fa9d0e42e31b0292540e6324d481aad307644 Mon Sep 17 00:00:00 2001 From: Gao Pan Date: Wed, 30 Nov 2016 10:40:47 +0800 Subject: i2c: imx-lpi2c: add low power i2c bus driver This patch adds lpi2c bus driver to support new i.MX products which use lpi2c instead of the old imx i2c. The lpi2c can continue operating in stop mode when an appropriate clock is available. It is also designed for low CPU overhead with DMA offloading of FIFO register accesses. Signed-off-by: Gao Pan Reviewed-by: Fugang Duan Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-imx-lpi2c.c | 646 +++++++++++++++++++++++++++++++++++++ 3 files changed, 657 insertions(+) create mode 100644 drivers/i2c/busses/i2c-imx-lpi2c.c (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 3ff7c031e04a..8e43914023df 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -597,6 +597,16 @@ config I2C_IMX This driver can also be built as a module. If so, the module will be called i2c-imx. +config I2C_IMX_LPI2C + tristate "IMX Low Power I2C interface" + depends on ARCH_MXC || COMPILE_TEST + help + Say Y here if you want to use the Low Power IIC bus controller + on the Freescale i.MX processors. + + This driver can also be built as a module. If so, the module + will be called i2c-imx-lpi2c. + config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 645bf081bd6a..1c1bac87a9db 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_I2C_HIX5HD2) += i2c-hix5hd2.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o +obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c new file mode 100644 index 000000000000..9794ff6feefb --- /dev/null +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -0,0 +1,646 @@ +/* + * This is i.MX low power i2c controller driver. + * + * Copyright 2016 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 +#include +#include + +#define DRIVER_NAME "imx-lpi2c" + +#define LPI2C_PARAM 0x04 /* i2c RX/TX FIFO size */ +#define LPI2C_MCR 0x10 /* i2c contrl register */ +#define LPI2C_MSR 0x14 /* i2c status register */ +#define LPI2C_MIER 0x18 /* i2c interrupt enable */ +#define LPI2C_MCFGR0 0x20 /* i2c master configuration */ +#define LPI2C_MCFGR1 0x24 /* i2c master configuration */ +#define LPI2C_MCFGR2 0x28 /* i2c master configuration */ +#define LPI2C_MCFGR3 0x2C /* i2c master configuration */ +#define LPI2C_MCCR0 0x48 /* i2c master clk configuration */ +#define LPI2C_MCCR1 0x50 /* i2c master clk configuration */ +#define LPI2C_MFCR 0x58 /* i2c master FIFO control */ +#define LPI2C_MFSR 0x5C /* i2c master FIFO status */ +#define LPI2C_MTDR 0x60 /* i2c master TX data register */ +#define LPI2C_MRDR 0x70 /* i2c master RX data register */ + +/* i2c command */ +#define TRAN_DATA 0X00 +#define RECV_DATA 0X01 +#define GEN_STOP 0X02 +#define RECV_DISCARD 0X03 +#define GEN_START 0X04 +#define START_NACK 0X05 +#define START_HIGH 0X06 +#define START_HIGH_NACK 0X07 + +#define MCR_MEN BIT(0) +#define MCR_RST BIT(1) +#define MCR_DOZEN BIT(2) +#define MCR_DBGEN BIT(3) +#define MCR_RTF BIT(8) +#define MCR_RRF BIT(9) +#define MSR_TDF BIT(0) +#define MSR_RDF BIT(1) +#define MSR_SDF BIT(9) +#define MSR_NDF BIT(10) +#define MSR_ALF BIT(11) +#define MSR_MBF BIT(24) +#define MSR_BBF BIT(25) +#define MIER_TDIE BIT(0) +#define MIER_RDIE BIT(1) +#define MIER_SDIE BIT(9) +#define MIER_NDIE BIT(10) +#define MCFGR1_AUTOSTOP BIT(8) +#define MCFGR1_IGNACK BIT(9) +#define MRDR_RXEMPTY BIT(14) + +#define I2C_CLK_RATIO 2 +#define CHUNK_DATA 256 + +#define LPI2C_RX_FIFOSIZE 4 +#define LPI2C_TX_FIFOSIZE 4 + +#define LPI2C_DEFAULT_RATE 100000 +#define STARDARD_MAX_BITRATE 400000 +#define FAST_MAX_BITRATE 1000000 +#define FAST_PLUS_MAX_BITRATE 3400000 +#define HIGHSPEED_MAX_BITRATE 5000000 + +enum lpi2c_imx_mode { + STANDARD, /* 100+Kbps */ + FAST, /* 400+Kbps */ + FAST_PLUS, /* 1.0+Mbps */ + HS, /* 3.4+Mbps */ + ULTRA_FAST, /* 5.0+Mbps */ +}; + +enum lpi2c_imx_pincfg { + TWO_PIN_OD, + TWO_PIN_OO, + TWO_PIN_PP, + FOUR_PIN_PP, +}; + +struct lpi2c_imx_struct { + struct i2c_adapter adapter; + struct clk *clk; + void __iomem *base; + __u8 *rx_buf; + __u8 *tx_buf; + struct completion complete; + unsigned int msglen; + unsigned int delivered; + unsigned int block_data; + unsigned int bitrate; + enum lpi2c_imx_mode mode; +}; + +static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx, + unsigned int enable) +{ + writel(enable, lpi2c_imx->base + LPI2C_MIER); +} + +static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned long orig_jiffies = jiffies; + unsigned int temp; + + while (1) { + temp = readl(lpi2c_imx->base + LPI2C_MSR); + + /* check for arbitration lost, clear if set */ + if (temp & MSR_ALF) { + writel(temp, lpi2c_imx->base + LPI2C_MSR); + return -EAGAIN; + } + + if (temp & (MSR_BBF | MSR_MBF)) + break; + + if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { + dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n"); + return -ETIMEDOUT; + } + schedule(); + } + + return 0; +} + +static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned int bitrate = lpi2c_imx->bitrate; + enum lpi2c_imx_mode mode; + + if (bitrate < STARDARD_MAX_BITRATE) + mode = STANDARD; + else if (bitrate < FAST_MAX_BITRATE) + mode = FAST; + else if (bitrate < FAST_PLUS_MAX_BITRATE) + mode = FAST_PLUS; + else if (bitrate < HIGHSPEED_MAX_BITRATE) + mode = HS; + else + mode = ULTRA_FAST; + + lpi2c_imx->mode = mode; +} + +static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msgs) +{ + unsigned int temp; + u8 read; + + temp = readl(lpi2c_imx->base + LPI2C_MCR); + temp |= MCR_RRF | MCR_RTF; + writel(temp, lpi2c_imx->base + LPI2C_MCR); + writel(0x7f00, lpi2c_imx->base + LPI2C_MSR); + + read = msgs->flags & I2C_M_RD; + temp = (msgs->addr << 1 | read) | (GEN_START << 8); + writel(temp, lpi2c_imx->base + LPI2C_MTDR); + + return lpi2c_imx_bus_busy(lpi2c_imx); +} + +static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned long orig_jiffies = jiffies; + unsigned int temp; + + writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR); + + do { + temp = readl(lpi2c_imx->base + LPI2C_MSR); + if (temp & MSR_SDF) + break; + + if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { + dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n"); + break; + } + schedule(); + + } while (1); +} + +/* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */ +static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) +{ + u8 prescale, filt, sethold, clkhi, clklo, datavd; + unsigned int clk_rate, clk_cycle; + enum lpi2c_imx_pincfg pincfg; + unsigned int temp; + + lpi2c_imx_set_mode(lpi2c_imx); + + clk_rate = clk_get_rate(lpi2c_imx->clk); + if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST) + filt = 0; + else + filt = 2; + + for (prescale = 0; prescale <= 7; prescale++) { + clk_cycle = clk_rate / ((1 << prescale) * lpi2c_imx->bitrate) + - 3 - (filt >> 1); + clkhi = (clk_cycle + I2C_CLK_RATIO) / (I2C_CLK_RATIO + 1); + clklo = clk_cycle - clkhi; + if (clklo < 64) + break; + } + + if (prescale > 7) + return -EINVAL; + + /* set MCFGR1: PINCFG, PRESCALE, IGNACK */ + if (lpi2c_imx->mode == ULTRA_FAST) + pincfg = TWO_PIN_OO; + else + pincfg = TWO_PIN_OD; + temp = prescale | pincfg << 24; + + if (lpi2c_imx->mode == ULTRA_FAST) + temp |= MCFGR1_IGNACK; + + writel(temp, lpi2c_imx->base + LPI2C_MCFGR1); + + /* set MCFGR2: FILTSDA, FILTSCL */ + temp = (filt << 16) | (filt << 24); + writel(temp, lpi2c_imx->base + LPI2C_MCFGR2); + + /* set MCCR: DATAVD, SETHOLD, CLKHI, CLKLO */ + sethold = clkhi; + datavd = clkhi >> 1; + temp = datavd << 24 | sethold << 16 | clkhi << 8 | clklo; + + if (lpi2c_imx->mode == HS) + writel(temp, lpi2c_imx->base + LPI2C_MCCR1); + else + writel(temp, lpi2c_imx->base + LPI2C_MCCR0); + + return 0; +} + +static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned int temp; + int ret; + + ret = clk_enable(lpi2c_imx->clk); + if (ret) + return ret; + + temp = MCR_RST; + writel(temp, lpi2c_imx->base + LPI2C_MCR); + writel(0, lpi2c_imx->base + LPI2C_MCR); + + ret = lpi2c_imx_config(lpi2c_imx); + if (ret) + goto clk_disable; + + temp = readl(lpi2c_imx->base + LPI2C_MCR); + temp |= MCR_MEN; + writel(temp, lpi2c_imx->base + LPI2C_MCR); + + return 0; + +clk_disable: + clk_disable(lpi2c_imx->clk); + + return ret; +} + +static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx) +{ + u32 temp; + + temp = readl(lpi2c_imx->base + LPI2C_MCR); + temp &= ~MCR_MEN; + writel(temp, lpi2c_imx->base + LPI2C_MCR); + + clk_disable(lpi2c_imx->clk); + + return 0; +} + +static int lpi2c_imx_msg_complete(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned long timeout; + + timeout = wait_for_completion_timeout(&lpi2c_imx->complete, HZ); + + return timeout ? 0 : -ETIMEDOUT; +} + +static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned long orig_jiffies = jiffies; + u32 txcnt; + + do { + txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff; + + if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) { + dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n"); + return -EIO; + } + + if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { + dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n"); + return -ETIMEDOUT; + } + schedule(); + + } while (txcnt); + + return 0; +} + +static void lpi2c_imx_set_tx_watermark(struct lpi2c_imx_struct *lpi2c_imx) +{ + writel(LPI2C_TX_FIFOSIZE >> 1, lpi2c_imx->base + LPI2C_MFCR); +} + +static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned int temp, remaining; + + remaining = lpi2c_imx->msglen - lpi2c_imx->delivered; + + if (remaining > (LPI2C_RX_FIFOSIZE >> 1)) + temp = LPI2C_RX_FIFOSIZE >> 1; + else + temp = 0; + + writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR); +} + +static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned int data, txcnt; + + txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff; + + while (txcnt < LPI2C_TX_FIFOSIZE) { + if (lpi2c_imx->delivered == lpi2c_imx->msglen) + break; + + data = lpi2c_imx->tx_buf[lpi2c_imx->delivered++]; + writel(data, lpi2c_imx->base + LPI2C_MTDR); + txcnt++; + } + + if (lpi2c_imx->delivered < lpi2c_imx->msglen) + lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE); + else + complete(&lpi2c_imx->complete); +} + +static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned int blocklen, remaining; + unsigned int temp, data; + + do { + data = readl(lpi2c_imx->base + LPI2C_MRDR); + if (data & MRDR_RXEMPTY) + break; + + lpi2c_imx->rx_buf[lpi2c_imx->delivered++] = data & 0xff; + } while (1); + + /* + * First byte is the length of remaining packet in the SMBus block + * data read. Add it to msgs->len. + */ + if (lpi2c_imx->block_data) { + blocklen = lpi2c_imx->rx_buf[0]; + lpi2c_imx->msglen += blocklen; + } + + remaining = lpi2c_imx->msglen - lpi2c_imx->delivered; + + if (!remaining) { + complete(&lpi2c_imx->complete); + return; + } + + /* not finished, still waiting for rx data */ + lpi2c_imx_set_rx_watermark(lpi2c_imx); + + /* multiple receive commands */ + if (lpi2c_imx->block_data) { + lpi2c_imx->block_data = 0; + temp = remaining; + temp |= (RECV_DATA << 8); + writel(temp, lpi2c_imx->base + LPI2C_MTDR); + } else if (!(lpi2c_imx->delivered & 0xff)) { + temp = (remaining > CHUNK_DATA ? CHUNK_DATA : remaining) - 1; + temp |= (RECV_DATA << 8); + writel(temp, lpi2c_imx->base + LPI2C_MTDR); + } + + lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE); +} + +static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msgs) +{ + lpi2c_imx->tx_buf = msgs->buf; + lpi2c_imx_set_tx_watermark(lpi2c_imx); + lpi2c_imx_write_txfifo(lpi2c_imx); +} + +static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msgs) +{ + unsigned int temp; + + lpi2c_imx->rx_buf = msgs->buf; + lpi2c_imx->block_data = msgs->flags & I2C_M_RECV_LEN; + + lpi2c_imx_set_rx_watermark(lpi2c_imx); + temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1; + temp |= (RECV_DATA << 8); + writel(temp, lpi2c_imx->base + LPI2C_MTDR); + + lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE); +} + +static int lpi2c_imx_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, int num) +{ + struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(adapter); + unsigned int temp; + int i, result; + + result = lpi2c_imx_master_enable(lpi2c_imx); + if (result) + return result; + + for (i = 0; i < num; i++) { + result = lpi2c_imx_start(lpi2c_imx, &msgs[i]); + if (result) + goto disable; + + /* quick smbus */ + if (num == 1 && msgs[0].len == 0) + goto stop; + + lpi2c_imx->delivered = 0; + lpi2c_imx->msglen = msgs[i].len; + init_completion(&lpi2c_imx->complete); + + if (msgs[i].flags & I2C_M_RD) + lpi2c_imx_read(lpi2c_imx, &msgs[i]); + else + lpi2c_imx_write(lpi2c_imx, &msgs[i]); + + result = lpi2c_imx_msg_complete(lpi2c_imx); + if (result) + goto stop; + + if (!(msgs[i].flags & I2C_M_RD)) { + result = lpi2c_imx_txfifo_empty(lpi2c_imx); + if (result) + goto stop; + } + } + +stop: + lpi2c_imx_stop(lpi2c_imx); + + temp = readl(lpi2c_imx->base + LPI2C_MSR); + if ((temp & MSR_NDF) && !result) + result = -EIO; + +disable: + lpi2c_imx_master_disable(lpi2c_imx); + + dev_dbg(&lpi2c_imx->adapter.dev, "<%s> exit with: %s: %d\n", __func__, + (result < 0) ? "error" : "success msg", + (result < 0) ? result : num); + + return (result < 0) ? result : num; +} + +static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id) +{ + struct lpi2c_imx_struct *lpi2c_imx = dev_id; + unsigned int temp; + + lpi2c_imx_intctrl(lpi2c_imx, 0); + temp = readl(lpi2c_imx->base + LPI2C_MSR); + + if (temp & MSR_RDF) + lpi2c_imx_read_rxfifo(lpi2c_imx); + + if (temp & MSR_TDF) + lpi2c_imx_write_txfifo(lpi2c_imx); + + if (temp & MSR_NDF) + complete(&lpi2c_imx->complete); + + return IRQ_HANDLED; +} + +static u32 lpi2c_imx_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_SMBUS_READ_BLOCK_DATA; +} + +static struct i2c_algorithm lpi2c_imx_algo = { + .master_xfer = lpi2c_imx_xfer, + .functionality = lpi2c_imx_func, +}; + +static const struct of_device_id lpi2c_imx_of_match[] = { + { .compatible = "fsl,imx7ulp-lpi2c" }, + { .compatible = "fsl,imx8dv-lpi2c" }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match); + +static int lpi2c_imx_probe(struct platform_device *pdev) +{ + struct lpi2c_imx_struct *lpi2c_imx; + struct resource *res; + int irq, ret; + + lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL); + if (!lpi2c_imx) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lpi2c_imx->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(lpi2c_imx->base)) + return PTR_ERR(lpi2c_imx->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "can't get irq number\n"); + return irq; + } + + lpi2c_imx->adapter.owner = THIS_MODULE; + lpi2c_imx->adapter.algo = &lpi2c_imx_algo; + lpi2c_imx->adapter.dev.parent = &pdev->dev; + lpi2c_imx->adapter.dev.of_node = pdev->dev.of_node; + strlcpy(lpi2c_imx->adapter.name, pdev->name, + sizeof(lpi2c_imx->adapter.name)); + + lpi2c_imx->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(lpi2c_imx->clk)) { + dev_err(&pdev->dev, "can't get I2C peripheral clock\n"); + return PTR_ERR(lpi2c_imx->clk); + } + + ret = of_property_read_u32(pdev->dev.of_node, + "clock-frequency", &lpi2c_imx->bitrate); + if (ret) + lpi2c_imx->bitrate = LPI2C_DEFAULT_RATE; + + ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0, + pdev->name, lpi2c_imx); + if (ret) { + dev_err(&pdev->dev, "can't claim irq %d\n", irq); + return ret; + } + + i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx); + platform_set_drvdata(pdev, lpi2c_imx); + + ret = clk_prepare(lpi2c_imx->clk); + if (ret) { + dev_err(&pdev->dev, "clk prepare failed %d\n", ret); + return ret; + } + + ret = i2c_add_adapter(&lpi2c_imx->adapter); + if (ret) + goto clk_unprepare; + + dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n"); + + return 0; + +clk_unprepare: + clk_unprepare(lpi2c_imx->clk); + + return ret; +} + +static int lpi2c_imx_remove(struct platform_device *pdev) +{ + struct lpi2c_imx_struct *lpi2c_imx = platform_get_drvdata(pdev); + + i2c_del_adapter(&lpi2c_imx->adapter); + + clk_unprepare(lpi2c_imx->clk); + + return 0; +} + +static struct platform_driver lpi2c_imx_driver = { + .probe = lpi2c_imx_probe, + .remove = lpi2c_imx_remove, + .driver = { + .name = DRIVER_NAME, + .of_match_table = lpi2c_imx_of_match, + }, +}; + +module_platform_driver(lpi2c_imx_driver); + +MODULE_AUTHOR("Gao Pan "); +MODULE_DESCRIPTION("I2C adapter driver for LPI2C bus"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From d7baee6901b34c4895eb78efdbf13a49079d7404 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 30 Nov 2016 17:52:00 +1100 Subject: powerpc/iommu: Stop using @current in mm_iommu_xxx This changes mm_iommu_xxx helpers to take mm_struct as a parameter instead of getting it from @current which in some situations may not have a valid reference to mm. This changes helpers to receive @mm and moves all references to @current to the caller, including checks for !current and !current->mm; checks in mm_iommu_preregistered() are removed as there is no caller yet. This moves the mm_iommu_adjust_locked_vm() call to the caller as it receives mm_iommu_table_group_mem_t but it needs mm. This should cause no behavioral change. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Acked-by: Alex Williamson Signed-off-by: Michael Ellerman --- arch/powerpc/include/asm/mmu_context.h | 16 ++++++------ arch/powerpc/mm/mmu_context_iommu.c | 46 +++++++++++++--------------------- drivers/vfio/vfio_iommu_spapr_tce.c | 14 ++++++++--- 3 files changed, 36 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/mmu_context.h b/arch/powerpc/include/asm/mmu_context.h index 424844bc2a57..b9e3f0aca261 100644 --- a/arch/powerpc/include/asm/mmu_context.h +++ b/arch/powerpc/include/asm/mmu_context.h @@ -19,16 +19,18 @@ extern void destroy_context(struct mm_struct *mm); struct mm_iommu_table_group_mem_t; extern int isolate_lru_page(struct page *page); /* from internal.h */ -extern bool mm_iommu_preregistered(void); -extern long mm_iommu_get(unsigned long ua, unsigned long entries, +extern bool mm_iommu_preregistered(struct mm_struct *mm); +extern long mm_iommu_get(struct mm_struct *mm, + unsigned long ua, unsigned long entries, struct mm_iommu_table_group_mem_t **pmem); -extern long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem); +extern long mm_iommu_put(struct mm_struct *mm, + struct mm_iommu_table_group_mem_t *mem); extern void mm_iommu_init(struct mm_struct *mm); extern void mm_iommu_cleanup(struct mm_struct *mm); -extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua, - unsigned long size); -extern struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua, - unsigned long entries); +extern struct mm_iommu_table_group_mem_t *mm_iommu_lookup(struct mm_struct *mm, + unsigned long ua, unsigned long size); +extern struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, + unsigned long ua, unsigned long entries); extern long mm_iommu_ua_to_hpa(struct mm_iommu_table_group_mem_t *mem, unsigned long ua, unsigned long *hpa); extern long mm_iommu_mapped_inc(struct mm_iommu_table_group_mem_t *mem); diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index ad2e575fd418..4c6db09e77ad 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c @@ -56,7 +56,7 @@ static long mm_iommu_adjust_locked_vm(struct mm_struct *mm, } pr_debug("[%d] RLIMIT_MEMLOCK HASH64 %c%ld %ld/%ld\n", - current->pid, + current ? current->pid : 0, incr ? '+' : '-', npages << PAGE_SHIFT, mm->locked_vm << PAGE_SHIFT, @@ -66,12 +66,9 @@ static long mm_iommu_adjust_locked_vm(struct mm_struct *mm, return ret; } -bool mm_iommu_preregistered(void) +bool mm_iommu_preregistered(struct mm_struct *mm) { - if (!current || !current->mm) - return false; - - return !list_empty(¤t->mm->context.iommu_group_mem_list); + return !list_empty(&mm->context.iommu_group_mem_list); } EXPORT_SYMBOL_GPL(mm_iommu_preregistered); @@ -124,19 +121,16 @@ static int mm_iommu_move_page_from_cma(struct page *page) return 0; } -long mm_iommu_get(unsigned long ua, unsigned long entries, +long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries, struct mm_iommu_table_group_mem_t **pmem) { struct mm_iommu_table_group_mem_t *mem; long i, j, ret = 0, locked_entries = 0; struct page *page = NULL; - if (!current || !current->mm) - return -ESRCH; /* process exited */ - mutex_lock(&mem_list_mutex); - list_for_each_entry_rcu(mem, ¤t->mm->context.iommu_group_mem_list, + list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list, next) { if ((mem->ua == ua) && (mem->entries == entries)) { ++mem->used; @@ -154,7 +148,7 @@ long mm_iommu_get(unsigned long ua, unsigned long entries, } - ret = mm_iommu_adjust_locked_vm(current->mm, entries, true); + ret = mm_iommu_adjust_locked_vm(mm, entries, true); if (ret) goto unlock_exit; @@ -215,11 +209,11 @@ populate: mem->entries = entries; *pmem = mem; - list_add_rcu(&mem->next, ¤t->mm->context.iommu_group_mem_list); + list_add_rcu(&mem->next, &mm->context.iommu_group_mem_list); unlock_exit: if (locked_entries && ret) - mm_iommu_adjust_locked_vm(current->mm, locked_entries, false); + mm_iommu_adjust_locked_vm(mm, locked_entries, false); mutex_unlock(&mem_list_mutex); @@ -264,17 +258,13 @@ static void mm_iommu_free(struct rcu_head *head) static void mm_iommu_release(struct mm_iommu_table_group_mem_t *mem) { list_del_rcu(&mem->next); - mm_iommu_adjust_locked_vm(current->mm, mem->entries, false); call_rcu(&mem->rcu, mm_iommu_free); } -long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem) +long mm_iommu_put(struct mm_struct *mm, struct mm_iommu_table_group_mem_t *mem) { long ret = 0; - if (!current || !current->mm) - return -ESRCH; /* process exited */ - mutex_lock(&mem_list_mutex); if (mem->used == 0) { @@ -297,6 +287,8 @@ long mm_iommu_put(struct mm_iommu_table_group_mem_t *mem) /* @mapped became 0 so now mappings are disabled, release the region */ mm_iommu_release(mem); + mm_iommu_adjust_locked_vm(mm, mem->entries, false); + unlock_exit: mutex_unlock(&mem_list_mutex); @@ -304,14 +296,12 @@ unlock_exit: } EXPORT_SYMBOL_GPL(mm_iommu_put); -struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua, - unsigned long size) +struct mm_iommu_table_group_mem_t *mm_iommu_lookup(struct mm_struct *mm, + unsigned long ua, unsigned long size) { struct mm_iommu_table_group_mem_t *mem, *ret = NULL; - list_for_each_entry_rcu(mem, - ¤t->mm->context.iommu_group_mem_list, - next) { + list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list, next) { if ((mem->ua <= ua) && (ua + size <= mem->ua + (mem->entries << PAGE_SHIFT))) { @@ -324,14 +314,12 @@ struct mm_iommu_table_group_mem_t *mm_iommu_lookup(unsigned long ua, } EXPORT_SYMBOL_GPL(mm_iommu_lookup); -struct mm_iommu_table_group_mem_t *mm_iommu_find(unsigned long ua, - unsigned long entries) +struct mm_iommu_table_group_mem_t *mm_iommu_find(struct mm_struct *mm, + unsigned long ua, unsigned long entries) { struct mm_iommu_table_group_mem_t *mem, *ret = NULL; - list_for_each_entry_rcu(mem, - ¤t->mm->context.iommu_group_mem_list, - next) { + list_for_each_entry_rcu(mem, &mm->context.iommu_group_mem_list, next) { if ((mem->ua == ua) && (mem->entries == entries)) { ret = mem; break; diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 80378ddadc5c..d0c38b201267 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -107,14 +107,17 @@ static long tce_iommu_unregister_pages(struct tce_container *container, { struct mm_iommu_table_group_mem_t *mem; + if (!current || !current->mm) + return -ESRCH; /* process exited */ + if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK)) return -EINVAL; - mem = mm_iommu_find(vaddr, size >> PAGE_SHIFT); + mem = mm_iommu_find(current->mm, vaddr, size >> PAGE_SHIFT); if (!mem) return -ENOENT; - return mm_iommu_put(mem); + return mm_iommu_put(current->mm, mem); } static long tce_iommu_register_pages(struct tce_container *container, @@ -124,11 +127,14 @@ static long tce_iommu_register_pages(struct tce_container *container, struct mm_iommu_table_group_mem_t *mem = NULL; unsigned long entries = size >> PAGE_SHIFT; + if (!current || !current->mm) + return -ESRCH; /* process exited */ + if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) || ((vaddr + size) < vaddr)) return -EINVAL; - ret = mm_iommu_get(vaddr, entries, &mem); + ret = mm_iommu_get(current->mm, vaddr, entries, &mem); if (ret) return ret; @@ -375,7 +381,7 @@ static int tce_iommu_prereg_ua_to_hpa(unsigned long tce, unsigned long size, long ret = 0; struct mm_iommu_table_group_mem_t *mem; - mem = mm_iommu_lookup(tce, size); + mem = mm_iommu_lookup(current->mm, tce, size); if (!mem) return -EINVAL; -- cgit v1.2.3 From 39701e56f5f16ea0cf8fc9e8472e645f8de91d23 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 30 Nov 2016 17:52:01 +1100 Subject: vfio/spapr: Postpone allocation of userspace version of TCE table The iommu_table struct manages a hardware TCE table and a vmalloc'd table with corresponding userspace addresses. Both are allocated when the default DMA window is created and this happens when the very first group is attached to a container. As we are going to allow the userspace to configure container in one memory context and pas container fd to another, we have to postpones such allocations till a container fd is passed to the destination user process so we would account locked memory limit against the actual container user constrainsts. This postpones the it_userspace array allocation till it is used first time for mapping. The unmapping patch already checks if the array is allocated. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Acked-by: Alex Williamson Signed-off-by: Michael Ellerman --- drivers/vfio/vfio_iommu_spapr_tce.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index d0c38b201267..4efd2b20c35c 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -515,6 +515,12 @@ static long tce_iommu_build_v2(struct tce_container *container, unsigned long hpa; enum dma_data_direction dirtmp; + if (!tbl->it_userspace) { + ret = tce_iommu_userspace_view_alloc(tbl); + if (ret) + return ret; + } + for (i = 0; i < pages; ++i) { struct mm_iommu_table_group_mem_t *mem = NULL; unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, @@ -588,15 +594,6 @@ static long tce_iommu_create_table(struct tce_container *container, WARN_ON(!ret && !(*ptbl)->it_ops->free); WARN_ON(!ret && ((*ptbl)->it_allocated_size != table_size)); - if (!ret && container->v2) { - ret = tce_iommu_userspace_view_alloc(*ptbl); - if (ret) - (*ptbl)->it_ops->free(*ptbl); - } - - if (ret) - decrement_locked_vm(table_size >> PAGE_SHIFT); - return ret; } @@ -1068,10 +1065,7 @@ static int tce_iommu_take_ownership(struct tce_container *container, if (!tbl || !tbl->it_map) continue; - rc = tce_iommu_userspace_view_alloc(tbl); - if (!rc) - rc = iommu_take_ownership(tbl); - + rc = iommu_take_ownership(tbl); if (rc) { for (j = 0; j < i; ++j) iommu_release_ownership( -- cgit v1.2.3 From 6f01cc692a16405235d5c34056455b182682123c Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 30 Nov 2016 17:52:02 +1100 Subject: vfio/spapr: Add a helper to create default DMA window There is already a helper to create a DMA window which does allocate a table and programs it to the IOMMU group. However tce_iommu_take_ownership_ddw() did not use it and did these 2 calls itself to simplify error path. Since we are going to delay the default window creation till the default window is accessed/removed or new window is added, we need a helper to create a default window from all these cases. This adds tce_iommu_create_default_window(). Since it relies on a VFIO container to have at least one IOMMU group (for future use), this changes tce_iommu_attach_group() to add a group to the container first and then call the new helper. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Acked-by: Alex Williamson Signed-off-by: Michael Ellerman --- drivers/vfio/vfio_iommu_spapr_tce.c | 87 ++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 45 deletions(-) (limited to 'drivers') diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 4efd2b20c35c..a67bbfdd86d5 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -710,6 +710,29 @@ static long tce_iommu_remove_window(struct tce_container *container, return 0; } +static long tce_iommu_create_default_window(struct tce_container *container) +{ + long ret; + __u64 start_addr = 0; + struct tce_iommu_group *tcegrp; + struct iommu_table_group *table_group; + + if (!tce_groups_attached(container)) + return -ENODEV; + + tcegrp = list_first_entry(&container->group_list, + struct tce_iommu_group, next); + table_group = iommu_group_get_iommudata(tcegrp->grp); + if (!table_group) + return -ENODEV; + + ret = tce_iommu_create_window(container, IOMMU_PAGE_SHIFT_4K, + table_group->tce32_size, 1, &start_addr); + WARN_ON_ONCE(!ret && start_addr); + + return ret; +} + static long tce_iommu_ioctl(void *iommu_data, unsigned int cmd, unsigned long arg) { @@ -1100,9 +1123,6 @@ static void tce_iommu_release_ownership_ddw(struct tce_container *container, static long tce_iommu_take_ownership_ddw(struct tce_container *container, struct iommu_table_group *table_group) { - long i, ret = 0; - struct iommu_table *tbl = NULL; - if (!table_group->ops->create_table || !table_group->ops->set_window || !table_group->ops->release_ownership) { WARN_ON_ONCE(1); @@ -1111,47 +1131,7 @@ static long tce_iommu_take_ownership_ddw(struct tce_container *container, table_group->ops->take_ownership(table_group); - /* - * If it the first group attached, check if there is - * a default DMA window and create one if none as - * the userspace expects it to exist. - */ - if (!tce_groups_attached(container) && !container->tables[0]) { - ret = tce_iommu_create_table(container, - table_group, - 0, /* window number */ - IOMMU_PAGE_SHIFT_4K, - table_group->tce32_size, - 1, /* default levels */ - &tbl); - if (ret) - goto release_exit; - else - container->tables[0] = tbl; - } - - /* Set all windows to the new group */ - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) { - tbl = container->tables[i]; - - if (!tbl) - continue; - - /* Set the default window to a new group */ - ret = table_group->ops->set_window(table_group, i, tbl); - if (ret) - goto release_exit; - } - return 0; - -release_exit: - for (i = 0; i < IOMMU_TABLE_GROUP_MAX_TABLES; ++i) - table_group->ops->unset_window(table_group, i); - - table_group->ops->release_ownership(table_group); - - return ret; } static int tce_iommu_attach_group(void *iommu_data, @@ -1161,6 +1141,7 @@ static int tce_iommu_attach_group(void *iommu_data, struct tce_container *container = iommu_data; struct iommu_table_group *table_group; struct tce_iommu_group *tcegrp = NULL; + bool create_default_window = false; mutex_lock(&container->lock); @@ -1203,14 +1184,30 @@ static int tce_iommu_attach_group(void *iommu_data, } if (!table_group->ops || !table_group->ops->take_ownership || - !table_group->ops->release_ownership) + !table_group->ops->release_ownership) { ret = tce_iommu_take_ownership(container, table_group); - else + } else { ret = tce_iommu_take_ownership_ddw(container, table_group); + if (!tce_groups_attached(container) && !container->tables[0]) + create_default_window = true; + } if (!ret) { tcegrp->grp = iommu_group; list_add(&tcegrp->next, &container->group_list); + /* + * If it the first group attached, check if there is + * a default DMA window and create one if none as + * the userspace expects it to exist. + */ + if (create_default_window) { + ret = tce_iommu_create_default_window(container); + if (ret) { + list_del(&tcegrp->next); + tce_iommu_release_ownership_ddw(container, + table_group); + } + } } unlock_exit: -- cgit v1.2.3 From d9c728949ddc9de5734bf3b12ea906ca8a77f2a0 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 30 Nov 2016 17:52:03 +1100 Subject: vfio/spapr: Postpone default window creation We are going to allow the userspace to configure container in one memory context and pass container fd to another so we are postponing memory allocations accounted against the locked memory limit. One of previous patches took care of it_userspace. At the moment we create the default DMA window when the first group is attached to a container; this is done for the userspace which is not DDW-aware but familiar with the SPAPR TCE IOMMU v2 in the part of memory pre-registration - such client expects the default DMA window to exist. This postpones the default DMA window allocation till one of the folliwing happens: 1. first map/unmap request arrives; 2. new window is requested; This adds noop for the case when the userspace requested removal of the default window which has not been created yet. Signed-off-by: Alexey Kardashevskiy Reviewed-by: David Gibson Acked-by: Alex Williamson Signed-off-by: Michael Ellerman --- drivers/vfio/vfio_iommu_spapr_tce.c | 40 +++++++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index a67bbfdd86d5..88622be0d6b5 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -97,6 +97,7 @@ struct tce_container { struct mutex lock; bool enabled; bool v2; + bool def_window_pending; unsigned long locked_pages; struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES]; struct list_head group_list; @@ -717,6 +718,9 @@ static long tce_iommu_create_default_window(struct tce_container *container) struct tce_iommu_group *tcegrp; struct iommu_table_group *table_group; + if (!container->def_window_pending) + return 0; + if (!tce_groups_attached(container)) return -ENODEV; @@ -730,6 +734,9 @@ static long tce_iommu_create_default_window(struct tce_container *container) table_group->tce32_size, 1, &start_addr); WARN_ON_ONCE(!ret && start_addr); + if (!ret) + container->def_window_pending = false; + return ret; } @@ -823,6 +830,10 @@ static long tce_iommu_ioctl(void *iommu_data, VFIO_DMA_MAP_FLAG_WRITE)) return -EINVAL; + ret = tce_iommu_create_default_window(container); + if (ret) + return ret; + num = tce_iommu_find_table(container, param.iova, &tbl); if (num < 0) return -ENXIO; @@ -886,6 +897,10 @@ static long tce_iommu_ioctl(void *iommu_data, if (param.flags) return -EINVAL; + ret = tce_iommu_create_default_window(container); + if (ret) + return ret; + num = tce_iommu_find_table(container, param.iova, &tbl); if (num < 0) return -ENXIO; @@ -1012,6 +1027,10 @@ static long tce_iommu_ioctl(void *iommu_data, mutex_lock(&container->lock); + ret = tce_iommu_create_default_window(container); + if (ret) + return ret; + ret = tce_iommu_create_window(container, create.page_shift, create.window_size, create.levels, &create.start_addr); @@ -1044,6 +1063,11 @@ static long tce_iommu_ioctl(void *iommu_data, if (remove.flags) return -EINVAL; + if (container->def_window_pending && !remove.start_addr) { + container->def_window_pending = false; + return 0; + } + mutex_lock(&container->lock); ret = tce_iommu_remove_window(container, remove.start_addr); @@ -1141,7 +1165,6 @@ static int tce_iommu_attach_group(void *iommu_data, struct tce_container *container = iommu_data; struct iommu_table_group *table_group; struct tce_iommu_group *tcegrp = NULL; - bool create_default_window = false; mutex_lock(&container->lock); @@ -1189,25 +1212,12 @@ static int tce_iommu_attach_group(void *iommu_data, } else { ret = tce_iommu_take_ownership_ddw(container, table_group); if (!tce_groups_attached(container) && !container->tables[0]) - create_default_window = true; + container->def_window_pending = true; } if (!ret) { tcegrp->grp = iommu_group; list_add(&tcegrp->next, &container->group_list); - /* - * If it the first group attached, check if there is - * a default DMA window and create one if none as - * the userspace expects it to exist. - */ - if (create_default_window) { - ret = tce_iommu_create_default_window(container); - if (ret) { - list_del(&tcegrp->next); - tce_iommu_release_ownership_ddw(container, - table_group); - } - } } unlock_exit: -- cgit v1.2.3 From bc82d122ae4a0e9f971f13403995898fcfa0c09e Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 30 Nov 2016 17:52:04 +1100 Subject: vfio/spapr: Reference mm in tce_container In some situations the userspace memory context may live longer than the userspace process itself so if we need to do proper memory context cleanup, we better have tce_container take a reference to mm_struct and use it later when the process is gone (@current or @current->mm is NULL). This references mm and stores the pointer in the container; this is done in a new helper - tce_iommu_mm_set() - when one of the following happens: - a container is enabled (IOMMU v1); - a first attempt to pre-register memory is made (IOMMU v2); - a DMA window is created (IOMMU v2). The @mm stays referenced till the container is destroyed. This replaces current->mm with container->mm everywhere except debug prints. This adds a check that current->mm is the same as the one stored in the container to prevent userspace from making changes to a memory context of other processes. DMA map/unmap ioctls() do not check for @mm as they already check for @enabled which is set after tce_iommu_mm_set() is called. This does not reference a task as multiple threads within the same mm are allowed to ioctl() to vfio and supposedly they will have same limits and capabilities and if they do not, we'll just fail with no harm made. Signed-off-by: Alexey Kardashevskiy Acked-by: Alex Williamson Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- drivers/vfio/vfio_iommu_spapr_tce.c | 160 ++++++++++++++++++++++-------------- 1 file changed, 100 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 88622be0d6b5..4c03c8525c26 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -31,49 +31,49 @@ static void tce_iommu_detach_group(void *iommu_data, struct iommu_group *iommu_group); -static long try_increment_locked_vm(long npages) +static long try_increment_locked_vm(struct mm_struct *mm, long npages) { long ret = 0, locked, lock_limit; - if (!current || !current->mm) - return -ESRCH; /* process exited */ + if (WARN_ON_ONCE(!mm)) + return -EPERM; if (!npages) return 0; - down_write(¤t->mm->mmap_sem); - locked = current->mm->locked_vm + npages; + down_write(&mm->mmap_sem); + locked = mm->locked_vm + npages; lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; if (locked > lock_limit && !capable(CAP_IPC_LOCK)) ret = -ENOMEM; else - current->mm->locked_vm += npages; + mm->locked_vm += npages; pr_debug("[%d] RLIMIT_MEMLOCK +%ld %ld/%ld%s\n", current->pid, npages << PAGE_SHIFT, - current->mm->locked_vm << PAGE_SHIFT, + mm->locked_vm << PAGE_SHIFT, rlimit(RLIMIT_MEMLOCK), ret ? " - exceeded" : ""); - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); return ret; } -static void decrement_locked_vm(long npages) +static void decrement_locked_vm(struct mm_struct *mm, long npages) { - if (!current || !current->mm || !npages) - return; /* process exited */ + if (!mm || !npages) + return; - down_write(¤t->mm->mmap_sem); - if (WARN_ON_ONCE(npages > current->mm->locked_vm)) - npages = current->mm->locked_vm; - current->mm->locked_vm -= npages; + down_write(&mm->mmap_sem); + if (WARN_ON_ONCE(npages > mm->locked_vm)) + npages = mm->locked_vm; + mm->locked_vm -= npages; pr_debug("[%d] RLIMIT_MEMLOCK -%ld %ld/%ld\n", current->pid, npages << PAGE_SHIFT, - current->mm->locked_vm << PAGE_SHIFT, + mm->locked_vm << PAGE_SHIFT, rlimit(RLIMIT_MEMLOCK)); - up_write(¤t->mm->mmap_sem); + up_write(&mm->mmap_sem); } /* @@ -99,26 +99,38 @@ struct tce_container { bool v2; bool def_window_pending; unsigned long locked_pages; + struct mm_struct *mm; struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES]; struct list_head group_list; }; +static long tce_iommu_mm_set(struct tce_container *container) +{ + if (container->mm) { + if (container->mm == current->mm) + return 0; + return -EPERM; + } + BUG_ON(!current->mm); + container->mm = current->mm; + atomic_inc(&container->mm->mm_count); + + return 0; +} + static long tce_iommu_unregister_pages(struct tce_container *container, __u64 vaddr, __u64 size) { struct mm_iommu_table_group_mem_t *mem; - if (!current || !current->mm) - return -ESRCH; /* process exited */ - if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK)) return -EINVAL; - mem = mm_iommu_find(current->mm, vaddr, size >> PAGE_SHIFT); + mem = mm_iommu_find(container->mm, vaddr, size >> PAGE_SHIFT); if (!mem) return -ENOENT; - return mm_iommu_put(current->mm, mem); + return mm_iommu_put(container->mm, mem); } static long tce_iommu_register_pages(struct tce_container *container, @@ -128,14 +140,11 @@ static long tce_iommu_register_pages(struct tce_container *container, struct mm_iommu_table_group_mem_t *mem = NULL; unsigned long entries = size >> PAGE_SHIFT; - if (!current || !current->mm) - return -ESRCH; /* process exited */ - if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) || ((vaddr + size) < vaddr)) return -EINVAL; - ret = mm_iommu_get(current->mm, vaddr, entries, &mem); + ret = mm_iommu_get(container->mm, vaddr, entries, &mem); if (ret) return ret; @@ -144,7 +153,8 @@ static long tce_iommu_register_pages(struct tce_container *container, return 0; } -static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl) +static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl, + struct mm_struct *mm) { unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) * tbl->it_size, PAGE_SIZE); @@ -153,13 +163,13 @@ static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl) BUG_ON(tbl->it_userspace); - ret = try_increment_locked_vm(cb >> PAGE_SHIFT); + ret = try_increment_locked_vm(mm, cb >> PAGE_SHIFT); if (ret) return ret; uas = vzalloc(cb); if (!uas) { - decrement_locked_vm(cb >> PAGE_SHIFT); + decrement_locked_vm(mm, cb >> PAGE_SHIFT); return -ENOMEM; } tbl->it_userspace = uas; @@ -167,7 +177,8 @@ static long tce_iommu_userspace_view_alloc(struct iommu_table *tbl) return 0; } -static void tce_iommu_userspace_view_free(struct iommu_table *tbl) +static void tce_iommu_userspace_view_free(struct iommu_table *tbl, + struct mm_struct *mm) { unsigned long cb = _ALIGN_UP(sizeof(tbl->it_userspace[0]) * tbl->it_size, PAGE_SIZE); @@ -177,7 +188,7 @@ static void tce_iommu_userspace_view_free(struct iommu_table *tbl) vfree(tbl->it_userspace); tbl->it_userspace = NULL; - decrement_locked_vm(cb >> PAGE_SHIFT); + decrement_locked_vm(mm, cb >> PAGE_SHIFT); } static bool tce_page_is_contained(struct page *page, unsigned page_shift) @@ -237,9 +248,6 @@ static int tce_iommu_enable(struct tce_container *container) struct iommu_table_group *table_group; struct tce_iommu_group *tcegrp; - if (!current->mm) - return -ESRCH; /* process exited */ - if (container->enabled) return -EBUSY; @@ -284,8 +292,12 @@ static int tce_iommu_enable(struct tce_container *container) if (!table_group->tce32_size) return -EPERM; + ret = tce_iommu_mm_set(container); + if (ret) + return ret; + locked = table_group->tce32_size >> PAGE_SHIFT; - ret = try_increment_locked_vm(locked); + ret = try_increment_locked_vm(container->mm, locked); if (ret) return ret; @@ -303,10 +315,8 @@ static void tce_iommu_disable(struct tce_container *container) container->enabled = false; - if (!current->mm) - return; - - decrement_locked_vm(container->locked_pages); + BUG_ON(!container->mm); + decrement_locked_vm(container->mm, container->locked_pages); } static void *tce_iommu_open(unsigned long arg) @@ -333,7 +343,8 @@ static void *tce_iommu_open(unsigned long arg) static int tce_iommu_clear(struct tce_container *container, struct iommu_table *tbl, unsigned long entry, unsigned long pages); -static void tce_iommu_free_table(struct iommu_table *tbl); +static void tce_iommu_free_table(struct tce_container *container, + struct iommu_table *tbl); static void tce_iommu_release(void *iommu_data) { @@ -358,10 +369,12 @@ static void tce_iommu_release(void *iommu_data) continue; tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); - tce_iommu_free_table(tbl); + tce_iommu_free_table(container, tbl); } tce_iommu_disable(container); + if (container->mm) + mmdrop(container->mm); mutex_destroy(&container->lock); kfree(container); @@ -376,13 +389,14 @@ static void tce_iommu_unuse_page(struct tce_container *container, put_page(page); } -static int tce_iommu_prereg_ua_to_hpa(unsigned long tce, unsigned long size, +static int tce_iommu_prereg_ua_to_hpa(struct tce_container *container, + unsigned long tce, unsigned long size, unsigned long *phpa, struct mm_iommu_table_group_mem_t **pmem) { long ret = 0; struct mm_iommu_table_group_mem_t *mem; - mem = mm_iommu_lookup(current->mm, tce, size); + mem = mm_iommu_lookup(container->mm, tce, size); if (!mem) return -EINVAL; @@ -395,18 +409,18 @@ static int tce_iommu_prereg_ua_to_hpa(unsigned long tce, unsigned long size, return 0; } -static void tce_iommu_unuse_page_v2(struct iommu_table *tbl, - unsigned long entry) +static void tce_iommu_unuse_page_v2(struct tce_container *container, + struct iommu_table *tbl, unsigned long entry) { struct mm_iommu_table_group_mem_t *mem = NULL; int ret; unsigned long hpa = 0; unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry); - if (!pua || !current || !current->mm) + if (!pua) return; - ret = tce_iommu_prereg_ua_to_hpa(*pua, IOMMU_PAGE_SIZE(tbl), + ret = tce_iommu_prereg_ua_to_hpa(container, *pua, IOMMU_PAGE_SIZE(tbl), &hpa, &mem); if (ret) pr_debug("%s: tce %lx at #%lx was not cached, ret=%d\n", @@ -436,7 +450,7 @@ static int tce_iommu_clear(struct tce_container *container, continue; if (container->v2) { - tce_iommu_unuse_page_v2(tbl, entry); + tce_iommu_unuse_page_v2(container, tbl, entry); continue; } @@ -517,7 +531,7 @@ static long tce_iommu_build_v2(struct tce_container *container, enum dma_data_direction dirtmp; if (!tbl->it_userspace) { - ret = tce_iommu_userspace_view_alloc(tbl); + ret = tce_iommu_userspace_view_alloc(tbl, container->mm); if (ret) return ret; } @@ -527,8 +541,8 @@ static long tce_iommu_build_v2(struct tce_container *container, unsigned long *pua = IOMMU_TABLE_USERSPACE_ENTRY(tbl, entry + i); - ret = tce_iommu_prereg_ua_to_hpa(tce, IOMMU_PAGE_SIZE(tbl), - &hpa, &mem); + ret = tce_iommu_prereg_ua_to_hpa(container, + tce, IOMMU_PAGE_SIZE(tbl), &hpa, &mem); if (ret) break; @@ -549,7 +563,7 @@ static long tce_iommu_build_v2(struct tce_container *container, ret = iommu_tce_xchg(tbl, entry + i, &hpa, &dirtmp); if (ret) { /* dirtmp cannot be DMA_NONE here */ - tce_iommu_unuse_page_v2(tbl, entry + i); + tce_iommu_unuse_page_v2(container, tbl, entry + i); pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%ld\n", __func__, entry << tbl->it_page_shift, tce, ret); @@ -557,7 +571,7 @@ static long tce_iommu_build_v2(struct tce_container *container, } if (dirtmp != DMA_NONE) - tce_iommu_unuse_page_v2(tbl, entry + i); + tce_iommu_unuse_page_v2(container, tbl, entry + i); *pua = tce; @@ -585,7 +599,7 @@ static long tce_iommu_create_table(struct tce_container *container, if (!table_size) return -EINVAL; - ret = try_increment_locked_vm(table_size >> PAGE_SHIFT); + ret = try_increment_locked_vm(container->mm, table_size >> PAGE_SHIFT); if (ret) return ret; @@ -598,13 +612,14 @@ static long tce_iommu_create_table(struct tce_container *container, return ret; } -static void tce_iommu_free_table(struct iommu_table *tbl) +static void tce_iommu_free_table(struct tce_container *container, + struct iommu_table *tbl) { unsigned long pages = tbl->it_allocated_size >> PAGE_SHIFT; - tce_iommu_userspace_view_free(tbl); + tce_iommu_userspace_view_free(tbl, container->mm); tbl->it_ops->free(tbl); - decrement_locked_vm(pages); + decrement_locked_vm(container->mm, pages); } static long tce_iommu_create_window(struct tce_container *container, @@ -667,7 +682,7 @@ unset_exit: table_group = iommu_group_get_iommudata(tcegrp->grp); table_group->ops->unset_window(table_group, num); } - tce_iommu_free_table(tbl); + tce_iommu_free_table(container, tbl); return ret; } @@ -705,7 +720,7 @@ static long tce_iommu_remove_window(struct tce_container *container, /* Free table */ tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); - tce_iommu_free_table(tbl); + tce_iommu_free_table(container, tbl); container->tables[num] = NULL; return 0; @@ -760,7 +775,17 @@ static long tce_iommu_ioctl(void *iommu_data, } return (ret < 0) ? 0 : ret; + } + + /* + * Sanity check to prevent one userspace from manipulating + * another userspace mm. + */ + BUG_ON(!container); + if (container->mm && container->mm != current->mm) + return -EPERM; + switch (cmd) { case VFIO_IOMMU_SPAPR_TCE_GET_INFO: { struct vfio_iommu_spapr_tce_info info; struct tce_iommu_group *tcegrp; @@ -929,6 +954,10 @@ static long tce_iommu_ioctl(void *iommu_data, minsz = offsetofend(struct vfio_iommu_spapr_register_memory, size); + ret = tce_iommu_mm_set(container); + if (ret) + return ret; + if (copy_from_user(¶m, (void __user *)arg, minsz)) return -EFAULT; @@ -952,6 +981,9 @@ static long tce_iommu_ioctl(void *iommu_data, if (!container->v2) break; + if (!container->mm) + return -EPERM; + minsz = offsetofend(struct vfio_iommu_spapr_register_memory, size); @@ -1010,6 +1042,10 @@ static long tce_iommu_ioctl(void *iommu_data, if (!container->v2) break; + ret = tce_iommu_mm_set(container); + if (ret) + return ret; + if (!tce_groups_attached(container)) return -ENXIO; @@ -1048,6 +1084,10 @@ static long tce_iommu_ioctl(void *iommu_data, if (!container->v2) break; + ret = tce_iommu_mm_set(container); + if (ret) + return ret; + if (!tce_groups_attached(container)) return -ENXIO; @@ -1093,7 +1133,7 @@ static void tce_iommu_release_ownership(struct tce_container *container, continue; tce_iommu_clear(container, tbl, tbl->it_offset, tbl->it_size); - tce_iommu_userspace_view_free(tbl); + tce_iommu_userspace_view_free(tbl, container->mm); if (tbl->it_map) iommu_release_ownership(tbl); -- cgit v1.2.3 From 4b6fad7097f883335b6d9627c883cb7f276d94c9 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Wed, 30 Nov 2016 17:52:05 +1100 Subject: powerpc/mm/iommu, vfio/spapr: Put pages on VFIO container shutdown At the moment the userspace tool is expected to request pinning of the entire guest RAM when VFIO IOMMU SPAPR v2 driver is present. When the userspace process finishes, all the pinned pages need to be put; this is done as a part of the userspace memory context (MM) destruction which happens on the very last mmdrop(). This approach has a problem that a MM of the userspace process may live longer than the userspace process itself as kernel threads use userspace process MMs which was runnning on a CPU where the kernel thread was scheduled to. If this happened, the MM remains referenced until this exact kernel thread wakes up again and releases the very last reference to the MM, on an idle system this can take even hours. This moves preregistered regions tracking from MM to VFIO; insteads of using mm_iommu_table_group_mem_t::used, tce_container::prereg_list is added so each container releases regions which it has pre-registered. This changes the userspace interface to return EBUSY if a memory region is already registered in a container. However it should not have any practical effect as the only userspace tool available now does register memory region once per container anyway. As tce_iommu_register_pages/tce_iommu_unregister_pages are called under container->lock, this does not need additional locking. Signed-off-by: Alexey Kardashevskiy Reviewed-by: Nicholas Piggin Acked-by: Alex Williamson Reviewed-by: David Gibson Signed-off-by: Michael Ellerman --- arch/powerpc/mm/mmu_context_book3s64.c | 4 +-- arch/powerpc/mm/mmu_context_iommu.c | 11 ------ drivers/vfio/vfio_iommu_spapr_tce.c | 61 +++++++++++++++++++++++++++++++++- 3 files changed, 61 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c index ad8273590975..73bf6e14c3aa 100644 --- a/arch/powerpc/mm/mmu_context_book3s64.c +++ b/arch/powerpc/mm/mmu_context_book3s64.c @@ -156,13 +156,11 @@ static inline void destroy_pagetable_page(struct mm_struct *mm) } #endif - void destroy_context(struct mm_struct *mm) { #ifdef CONFIG_SPAPR_TCE_IOMMU - mm_iommu_cleanup(mm); + WARN_ON_ONCE(!list_empty(&mm->context.iommu_group_mem_list)); #endif - #ifdef CONFIG_PPC_ICSWX drop_cop(mm->context.acop, mm); kfree(mm->context.cop_lockp); diff --git a/arch/powerpc/mm/mmu_context_iommu.c b/arch/powerpc/mm/mmu_context_iommu.c index 4c6db09e77ad..104bad029ce9 100644 --- a/arch/powerpc/mm/mmu_context_iommu.c +++ b/arch/powerpc/mm/mmu_context_iommu.c @@ -365,14 +365,3 @@ void mm_iommu_init(struct mm_struct *mm) { INIT_LIST_HEAD_RCU(&mm->context.iommu_group_mem_list); } - -void mm_iommu_cleanup(struct mm_struct *mm) -{ - struct mm_iommu_table_group_mem_t *mem, *tmp; - - list_for_each_entry_safe(mem, tmp, &mm->context.iommu_group_mem_list, - next) { - list_del_rcu(&mem->next); - mm_iommu_do_free(mem); - } -} diff --git a/drivers/vfio/vfio_iommu_spapr_tce.c b/drivers/vfio/vfio_iommu_spapr_tce.c index 4c03c8525c26..c8823578a1b2 100644 --- a/drivers/vfio/vfio_iommu_spapr_tce.c +++ b/drivers/vfio/vfio_iommu_spapr_tce.c @@ -88,6 +88,15 @@ struct tce_iommu_group { struct iommu_group *grp; }; +/* + * A container needs to remember which preregistered region it has + * referenced to do proper cleanup at the userspace process exit. + */ +struct tce_iommu_prereg { + struct list_head next; + struct mm_iommu_table_group_mem_t *mem; +}; + /* * The container descriptor supports only a single group per container. * Required by the API as the container is not supplied with the IOMMU group @@ -102,6 +111,7 @@ struct tce_container { struct mm_struct *mm; struct iommu_table *tables[IOMMU_TABLE_GROUP_MAX_TABLES]; struct list_head group_list; + struct list_head prereg_list; }; static long tce_iommu_mm_set(struct tce_container *container) @@ -118,10 +128,27 @@ static long tce_iommu_mm_set(struct tce_container *container) return 0; } +static long tce_iommu_prereg_free(struct tce_container *container, + struct tce_iommu_prereg *tcemem) +{ + long ret; + + ret = mm_iommu_put(container->mm, tcemem->mem); + if (ret) + return ret; + + list_del(&tcemem->next); + kfree(tcemem); + + return 0; +} + static long tce_iommu_unregister_pages(struct tce_container *container, __u64 vaddr, __u64 size) { struct mm_iommu_table_group_mem_t *mem; + struct tce_iommu_prereg *tcemem; + bool found = false; if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK)) return -EINVAL; @@ -130,7 +157,17 @@ static long tce_iommu_unregister_pages(struct tce_container *container, if (!mem) return -ENOENT; - return mm_iommu_put(container->mm, mem); + list_for_each_entry(tcemem, &container->prereg_list, next) { + if (tcemem->mem == mem) { + found = true; + break; + } + } + + if (!found) + return -ENOENT; + + return tce_iommu_prereg_free(container, tcemem); } static long tce_iommu_register_pages(struct tce_container *container, @@ -138,16 +175,29 @@ static long tce_iommu_register_pages(struct tce_container *container, { long ret = 0; struct mm_iommu_table_group_mem_t *mem = NULL; + struct tce_iommu_prereg *tcemem; unsigned long entries = size >> PAGE_SHIFT; if ((vaddr & ~PAGE_MASK) || (size & ~PAGE_MASK) || ((vaddr + size) < vaddr)) return -EINVAL; + mem = mm_iommu_find(container->mm, vaddr, entries); + if (mem) { + list_for_each_entry(tcemem, &container->prereg_list, next) { + if (tcemem->mem == mem) + return -EBUSY; + } + } + ret = mm_iommu_get(container->mm, vaddr, entries, &mem); if (ret) return ret; + tcemem = kzalloc(sizeof(*tcemem), GFP_KERNEL); + tcemem->mem = mem; + list_add(&tcemem->next, &container->prereg_list); + container->enabled = true; return 0; @@ -334,6 +384,7 @@ static void *tce_iommu_open(unsigned long arg) mutex_init(&container->lock); INIT_LIST_HEAD_RCU(&container->group_list); + INIT_LIST_HEAD_RCU(&container->prereg_list); container->v2 = arg == VFIO_SPAPR_TCE_v2_IOMMU; @@ -372,6 +423,14 @@ static void tce_iommu_release(void *iommu_data) tce_iommu_free_table(container, tbl); } + while (!list_empty(&container->prereg_list)) { + struct tce_iommu_prereg *tcemem; + + tcemem = list_first_entry(&container->prereg_list, + struct tce_iommu_prereg, next); + WARN_ON_ONCE(tce_iommu_prereg_free(container, tcemem)); + } + tce_iommu_disable(container); if (container->mm) mmdrop(container->mm); -- cgit v1.2.3 From c5e8848fc98e363ea51b68de01392366312d9efa Mon Sep 17 00:00:00 2001 From: Lyude Paul Date: Fri, 2 Dec 2016 16:59:07 -0800 Subject: Input: synaptics-rmi4 - add support for F03 This adds basic functionality for PS/2 passthrough on Synaptics Touchpads using RMI4 through smbus. Reviewed-by: Andrew Duggan Signed-off-by: Lyude Paul Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/Kconfig | 9 ++ drivers/input/rmi4/Makefile | 1 + drivers/input/rmi4/rmi_bus.c | 3 + drivers/input/rmi4/rmi_driver.h | 1 + drivers/input/rmi4/rmi_f03.c | 232 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 246 insertions(+) create mode 100644 drivers/input/rmi4/rmi_f03.c (limited to 'drivers') diff --git a/drivers/input/rmi4/Kconfig b/drivers/input/rmi4/Kconfig index a9c36a5fe708..30cc627a4f45 100644 --- a/drivers/input/rmi4/Kconfig +++ b/drivers/input/rmi4/Kconfig @@ -39,6 +39,15 @@ config RMI4_SMB To compile this driver as a module, choose M here: the module will be called rmi_smbus. +config RMI4_F03 + bool "RMI4 Function 03 (PS2 Guest)" + depends on RMI4_CORE && SERIO + help + Say Y here if you want to add support for RMI4 function 03. + + Function 03 provides PS2 guest support for RMI4 devices. This + includes support for TrackPoints on TouchPads. + config RMI4_2D_SENSOR bool depends on RMI4_CORE diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index e7f4ca6c0508..a199cbe9c27d 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -4,6 +4,7 @@ rmi_core-y := rmi_bus.o rmi_driver.o rmi_f01.o rmi_core-$(CONFIG_RMI4_2D_SENSOR) += rmi_2d_sensor.o # Function drivers +rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o diff --git a/drivers/input/rmi4/rmi_bus.c b/drivers/input/rmi4/rmi_bus.c index 2534331ad9dc..df97d8679bad 100644 --- a/drivers/input/rmi4/rmi_bus.c +++ b/drivers/input/rmi4/rmi_bus.c @@ -306,6 +306,9 @@ struct bus_type rmi_bus_type = { static struct rmi_function_handler *fn_handlers[] = { &rmi_f01_handler, +#ifdef CONFIG_RMI4_F03 + &rmi_f03_handler, +#endif #ifdef CONFIG_RMI4_F11 &rmi_f11_handler, #endif diff --git a/drivers/input/rmi4/rmi_driver.h b/drivers/input/rmi4/rmi_driver.h index cc9458522279..24f8f764d171 100644 --- a/drivers/input/rmi4/rmi_driver.h +++ b/drivers/input/rmi4/rmi_driver.h @@ -121,6 +121,7 @@ static inline void rmi_f34_remove_sysfs(struct rmi_device *rmi_dev) #endif /* CONFIG_RMI_F34 */ extern struct rmi_function_handler rmi_f01_handler; +extern struct rmi_function_handler rmi_f03_handler; extern struct rmi_function_handler rmi_f11_handler; extern struct rmi_function_handler rmi_f12_handler; extern struct rmi_function_handler rmi_f30_handler; diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c new file mode 100644 index 000000000000..24c7375aa361 --- /dev/null +++ b/drivers/input/rmi4/rmi_f03.c @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2015-2016 Red Hat + * Copyright (C) 2015 Lyude Paul + * + * 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 "rmi_driver.h" + +#define RMI_F03_RX_DATA_OFB 0x01 +#define RMI_F03_OB_SIZE 2 + +#define RMI_F03_OB_OFFSET 2 +#define RMI_F03_OB_DATA_OFFSET 1 +#define RMI_F03_OB_FLAG_TIMEOUT BIT(6) +#define RMI_F03_OB_FLAG_PARITY BIT(7) + +#define RMI_F03_DEVICE_COUNT 0x07 +#define RMI_F03_BYTES_PER_DEVICE 0x07 +#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4 +#define RMI_F03_QUEUE_LENGTH 0x0F + +struct f03_data { + struct rmi_function *fn; + + struct serio *serio; + + u8 device_count; + u8 rx_queue_length; +}; + +static int rmi_f03_pt_write(struct serio *id, unsigned char val) +{ + struct f03_data *f03 = id->port_data; + int error; + + rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev, + "%s: Wrote %.2hhx to PS/2 passthrough address", + __func__, val); + + error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val); + if (error) { + dev_err(&f03->fn->dev, + "%s: Failed to write to F03 TX register (%d).\n", + __func__, error); + return error; + } + + return 0; +} + +static int rmi_f03_initialize(struct f03_data *f03) +{ + struct rmi_function *fn = f03->fn; + struct device *dev = &fn->dev; + int error; + u8 bytes_per_device; + u8 query1; + u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE]; + size_t query2_len; + + error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1); + if (error) { + dev_err(dev, "Failed to read query register (%d).\n", error); + return error; + } + + f03->device_count = query1 & RMI_F03_DEVICE_COUNT; + bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) & + RMI_F03_BYTES_PER_DEVICE; + + query2_len = f03->device_count * bytes_per_device; + + /* + * The first generation of image sensors don't have a second part to + * their f03 query, as such we have to set some of these values manually + */ + if (query2_len < 1) { + f03->device_count = 1; + f03->rx_queue_length = 7; + } else { + error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1, + query2, query2_len); + if (error) { + dev_err(dev, + "Failed to read second set of query registers (%d).\n", + error); + return error; + } + + f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH; + } + + return 0; +} + +static int rmi_f03_register_pt(struct f03_data *f03) +{ + struct serio *serio; + + serio = kzalloc(sizeof(struct serio), GFP_KERNEL); + if (!serio) + return -ENOMEM; + + serio->id.type = SERIO_8042; + serio->write = rmi_f03_pt_write; + serio->port_data = f03; + + strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through", + sizeof(serio->name)); + strlcpy(serio->phys, "synaptics-rmi4-pt/serio1", + sizeof(serio->phys)); + serio->dev.parent = &f03->fn->dev; + + f03->serio = serio; + + serio_register_port(serio); + + return 0; +} + +static int rmi_f03_probe(struct rmi_function *fn) +{ + struct device *dev = &fn->dev; + struct f03_data *f03; + int error; + + f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL); + if (!f03) + return -ENOMEM; + + f03->fn = fn; + + error = rmi_f03_initialize(f03); + if (error < 0) + return error; + + if (f03->device_count != 1) + dev_warn(dev, "found %d devices on PS/2 passthrough", + f03->device_count); + + dev_set_drvdata(dev, f03); + + error = rmi_f03_register_pt(f03); + if (error) + return error; + + return 0; +} + +static int rmi_f03_config(struct rmi_function *fn) +{ + fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask); + + return 0; +} + +static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits) +{ + struct f03_data *f03 = dev_get_drvdata(&fn->dev); + u16 data_addr = fn->fd.data_base_addr; + const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE; + u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE]; + u8 ob_status; + u8 ob_data; + unsigned int serio_flags; + int i; + int error; + + /* Grab all of the data registers, and check them for data */ + error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET, + &obs, ob_len); + if (error) { + dev_err(&fn->dev, + "%s: Failed to read F03 output buffers: %d\n", + __func__, error); + serio_interrupt(f03->serio, 0, SERIO_TIMEOUT); + return error; + } + + for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) { + ob_status = obs[i]; + ob_data = obs[i + RMI_F03_OB_DATA_OFFSET]; + serio_flags = 0; + + if (!(ob_status & RMI_F03_RX_DATA_OFB)) + continue; + + if (ob_status & RMI_F03_OB_FLAG_TIMEOUT) + serio_flags |= SERIO_TIMEOUT; + if (ob_status & RMI_F03_OB_FLAG_PARITY) + serio_flags |= SERIO_PARITY; + + rmi_dbg(RMI_DEBUG_FN, &fn->dev, + "%s: Received %.2hhx from PS2 guest T: %c P: %c\n", + __func__, ob_data, + serio_flags & SERIO_TIMEOUT ? 'Y' : 'N', + serio_flags & SERIO_PARITY ? 'Y' : 'N'); + + serio_interrupt(f03->serio, ob_data, serio_flags); + } + + return 0; +} + +static void rmi_f03_remove(struct rmi_function *fn) +{ + struct f03_data *f03 = dev_get_drvdata(&fn->dev); + + serio_unregister_port(f03->serio); +} + +struct rmi_function_handler rmi_f03_handler = { + .driver = { + .name = "rmi4_f03", + }, + .func = 0x03, + .probe = rmi_f03_probe, + .config = rmi_f03_config, + .attention = rmi_f03_attention, + .remove = rmi_f03_remove, +}; + +MODULE_AUTHOR("Lyude Paul "); +MODULE_DESCRIPTION("RMI F03 module"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From e621132f934f5922e8a3968edd236f97cdad60cf Mon Sep 17 00:00:00 2001 From: Dennis Wassenberg Date: Fri, 2 Dec 2016 17:45:29 -0800 Subject: Input: synaptics-rmi4 - f03 - grab data passed by transport device First check if there are data available passed by the transport device. If data available use these data. If there are no data available try to read the rmi block if dsata are passed this way. This is the way the other rmi function handlers will do this. This patch is needed on HID devices because the firmware reads F03 data registers and adds them to the HID attention report. Reading those registers from the driver after the firmware read them will result in invalid data. Reviewed-by: Andrew Duggan Signed-off-by: Dennis Wassenberg Signed-off-by: Benjamin Tissoires Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f03.c | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c index 24c7375aa361..7a3ec0ed0c27 100644 --- a/drivers/input/rmi4/rmi_f03.c +++ b/drivers/input/rmi4/rmi_f03.c @@ -163,6 +163,7 @@ static int rmi_f03_config(struct rmi_function *fn) static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits) { + struct rmi_device *rmi_dev = fn->rmi_dev; struct f03_data *f03 = dev_get_drvdata(&fn->dev); u16 data_addr = fn->fd.data_base_addr; const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE; @@ -173,15 +174,31 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits) int i; int error; - /* Grab all of the data registers, and check them for data */ - error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET, - &obs, ob_len); - if (error) { - dev_err(&fn->dev, - "%s: Failed to read F03 output buffers: %d\n", - __func__, error); - serio_interrupt(f03->serio, 0, SERIO_TIMEOUT); - return error; + if (!rmi_dev || !rmi_dev->xport) + return -ENODEV; + + if (rmi_dev->xport->attn_data) { + /* First grab the data passed by the transport device */ + if (rmi_dev->xport->attn_size < ob_len) { + dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n"); + return 0; + } + + memcpy(obs, rmi_dev->xport->attn_data, ob_len); + + rmi_dev->xport->attn_data += ob_len; + rmi_dev->xport->attn_size -= ob_len; + } else { + /* Grab all of the data registers, and check them for data */ + error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET, + &obs, ob_len); + if (error) { + dev_err(&fn->dev, + "%s: Failed to read F03 output buffers: %d\n", + __func__, error); + serio_interrupt(f03->serio, 0, SERIO_TIMEOUT); + return error; + } } for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) { -- cgit v1.2.3 From b908d3cd812abe3f4a74d7550bbf0a8cbcfbe6ed Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 2 Dec 2016 17:48:51 -0800 Subject: Input: synaptics-rmi4 - allow to add attention data The HID implementation of RMI4 provides the data during the interrupt (in the input report). We need to provide a way for this transport driver to provide the attention data while calling an IRQ. We use a fifo in rmi_core to not lose any incoming event. Signed-off-by: Benjamin Tissoires Reviewed-by: Andrew Duggan Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 49 +++++++++++++++++++++++++++++++++++++++-- include/linux/rmi.h | 11 +++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index a718e51afb0b..85062e414e73 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -191,16 +191,53 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) return 0; } +void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status, + void *data, size_t size) +{ + struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); + struct rmi4_attn_data attn_data; + void *fifo_data; + + if (!drvdata->enabled) + return; + + fifo_data = kmemdup(data, size, GFP_ATOMIC); + if (!fifo_data) + return; + + attn_data.irq_status = irq_status; + attn_data.size = size; + attn_data.data = fifo_data; + + kfifo_put(&drvdata->attn_fifo, attn_data); +} +EXPORT_SYMBOL_GPL(rmi_set_attn_data); + static irqreturn_t rmi_irq_fn(int irq, void *dev_id) { struct rmi_device *rmi_dev = dev_id; - int ret; + struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); + struct rmi4_attn_data attn_data = {0}; + int ret, count; + + count = kfifo_get(&drvdata->attn_fifo, &attn_data); + if (count) { + *(drvdata->irq_status) = attn_data.irq_status; + rmi_dev->xport->attn_data = attn_data.data; + rmi_dev->xport->attn_size = attn_data.size; + } ret = rmi_process_interrupt_requests(rmi_dev); if (ret) rmi_dbg(RMI_DEBUG_CORE, &rmi_dev->dev, "Failed to process interrupt request: %d\n", ret); + if (count) + kfree(attn_data.data); + + if (!kfifo_is_empty(&drvdata->attn_fifo)) + return rmi_irq_fn(irq, dev_id); + return IRQ_HANDLED; } @@ -880,8 +917,9 @@ void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake) { struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); + struct rmi4_attn_data attn_data = {0}; int irq = pdata->irq; - int retval; + int retval, count; mutex_lock(&data->enabled_mutex); @@ -898,6 +936,13 @@ void rmi_disable_irq(struct rmi_device *rmi_dev, bool enable_wake) retval); } + /* make sure the fifo is clean */ + while (!kfifo_is_empty(&data->attn_fifo)) { + count = kfifo_get(&data->attn_fifo, &attn_data); + if (count) + kfree(attn_data.data); + } + out: mutex_unlock(&data->enabled_mutex); } diff --git a/include/linux/rmi.h b/include/linux/rmi.h index 7780e40a2573..1d4865621493 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -331,6 +332,12 @@ struct rmi_device { }; +struct rmi4_attn_data { + unsigned long irq_status; + size_t size; + void *data; +}; + struct rmi_driver_data { struct list_head function_list; @@ -357,11 +364,15 @@ struct rmi_driver_data { bool enabled; struct mutex enabled_mutex; + DECLARE_KFIFO(attn_fifo, struct rmi4_attn_data, 16); }; int rmi_register_transport_device(struct rmi_transport_dev *xport); void rmi_unregister_transport_device(struct rmi_transport_dev *xport); +void rmi_set_attn_data(struct rmi_device *rmi_dev, unsigned long irq_status, + void *data, size_t size); + int rmi_driver_suspend(struct rmi_device *rmi_dev, bool enable_wake); int rmi_driver_resume(struct rmi_device *rmi_dev, bool clear_wake); #endif -- cgit v1.2.3 From ae9979c31007d5366b73640ee7dcbb271357053e Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 2 Dec 2016 17:49:10 -0800 Subject: Input: synaptics-rmi4 - store the attn data in the driver Now that we have a proper API to set the attention data, there is no point in keeping it in the transport driver. Signed-off-by: Benjamin Tissoires Reviewed-by: Andrew Duggan Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_driver.c | 5 ++--- drivers/input/rmi4/rmi_f03.c | 13 +++++++------ drivers/input/rmi4/rmi_f11.c | 12 ++++++------ drivers/input/rmi4/rmi_f12.c | 43 +++++++++++++++++++++-------------------- drivers/input/rmi4/rmi_f30.c | 11 ++++++----- include/linux/rmi.h | 5 ++--- 6 files changed, 45 insertions(+), 44 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 85062e414e73..05a3c4bc9778 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -155,7 +155,7 @@ static int rmi_process_interrupt_requests(struct rmi_device *rmi_dev) if (!data) return 0; - if (!rmi_dev->xport->attn_data) { + if (!data->attn_data.data) { error = rmi_read_block(rmi_dev, data->f01_container->fd.data_base_addr + 1, data->irq_status, data->num_of_irq_regs); @@ -223,8 +223,7 @@ static irqreturn_t rmi_irq_fn(int irq, void *dev_id) count = kfifo_get(&drvdata->attn_fifo, &attn_data); if (count) { *(drvdata->irq_status) = attn_data.irq_status; - rmi_dev->xport->attn_data = attn_data.data; - rmi_dev->xport->attn_size = attn_data.size; + drvdata->attn_data = attn_data; } ret = rmi_process_interrupt_requests(rmi_dev); diff --git a/drivers/input/rmi4/rmi_f03.c b/drivers/input/rmi4/rmi_f03.c index 7a3ec0ed0c27..8a7ca3e2f95e 100644 --- a/drivers/input/rmi4/rmi_f03.c +++ b/drivers/input/rmi4/rmi_f03.c @@ -164,6 +164,7 @@ static int rmi_f03_config(struct rmi_function *fn) static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits) { struct rmi_device *rmi_dev = fn->rmi_dev; + struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); struct f03_data *f03 = dev_get_drvdata(&fn->dev); u16 data_addr = fn->fd.data_base_addr; const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE; @@ -174,20 +175,20 @@ static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits) int i; int error; - if (!rmi_dev || !rmi_dev->xport) + if (!rmi_dev) return -ENODEV; - if (rmi_dev->xport->attn_data) { + if (drvdata->attn_data.data) { /* First grab the data passed by the transport device */ - if (rmi_dev->xport->attn_size < ob_len) { + if (drvdata->attn_data.size < ob_len) { dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n"); return 0; } - memcpy(obs, rmi_dev->xport->attn_data, ob_len); + memcpy(obs, drvdata->attn_data.data, ob_len); - rmi_dev->xport->attn_data += ob_len; - rmi_dev->xport->attn_size -= ob_len; + drvdata->attn_data.data += ob_len; + drvdata->attn_data.size -= ob_len; } else { /* Grab all of the data registers, and check them for data */ error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET, diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c index ffcbbc1745de..68279f3c5130 100644 --- a/drivers/input/rmi4/rmi_f11.c +++ b/drivers/input/rmi4/rmi_f11.c @@ -1285,19 +1285,19 @@ static int rmi_f11_attention(struct rmi_function *fn, unsigned long *irq_bits) int error; int valid_bytes = f11->sensor.pkt_size; - if (rmi_dev->xport->attn_data) { + if (drvdata->attn_data.data) { /* * The valid data in the attention report is less then * expected. Only process the complete fingers. */ - if (f11->sensor.attn_size > rmi_dev->xport->attn_size) - valid_bytes = rmi_dev->xport->attn_size; + if (f11->sensor.attn_size > drvdata->attn_data.size) + valid_bytes = drvdata->attn_data.size; else valid_bytes = f11->sensor.attn_size; - memcpy(f11->sensor.data_pkt, rmi_dev->xport->attn_data, + memcpy(f11->sensor.data_pkt, drvdata->attn_data.data, valid_bytes); - rmi_dev->xport->attn_data += f11->sensor.attn_size; - rmi_dev->xport->attn_size -= f11->sensor.attn_size; + drvdata->attn_data.data += f11->sensor.attn_size; + drvdata->attn_data.size -= f11->sensor.attn_size; } else { error = rmi_read_block(rmi_dev, data_base_addr, f11->sensor.data_pkt, diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 82a4964e5eb9..8c5360c25266 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -208,19 +208,20 @@ static int rmi_f12_attention(struct rmi_function *fn, { int retval; struct rmi_device *rmi_dev = fn->rmi_dev; + struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); struct f12_data *f12 = dev_get_drvdata(&fn->dev); struct rmi_2d_sensor *sensor = &f12->sensor; int valid_bytes = sensor->pkt_size; - if (rmi_dev->xport->attn_data) { - if (sensor->attn_size > rmi_dev->xport->attn_size) - valid_bytes = rmi_dev->xport->attn_size; + if (drvdata->attn_data.data) { + if (sensor->attn_size > drvdata->attn_data.size) + valid_bytes = drvdata->attn_data.size; else valid_bytes = sensor->attn_size; - memcpy(sensor->data_pkt, rmi_dev->xport->attn_data, + memcpy(sensor->data_pkt, drvdata->attn_data.data, valid_bytes); - rmi_dev->xport->attn_data += sensor->attn_size; - rmi_dev->xport->attn_size -= sensor->attn_size; + drvdata->attn_data.data += sensor->attn_size; + drvdata->attn_data.size -= sensor->attn_size; } else { retval = rmi_read_block(rmi_dev, f12->data_addr, sensor->data_pkt, sensor->pkt_size); @@ -323,7 +324,7 @@ static int rmi_f12_probe(struct rmi_function *fn) const struct rmi_register_desc_item *item; struct rmi_2d_sensor *sensor; struct rmi_device_platform_data *pdata = rmi_get_platform_data(rmi_dev); - struct rmi_transport_dev *xport = rmi_dev->xport; + struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); u16 data_offset = 0; rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s\n", __func__); @@ -422,7 +423,7 @@ static int rmi_f12_probe(struct rmi_function *fn) * HID attention reports. */ item = rmi_get_register_desc_item(&f12->data_reg_desc, 0); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 1); @@ -436,15 +437,15 @@ static int rmi_f12_probe(struct rmi_function *fn) } item = rmi_get_register_desc_item(&f12->data_reg_desc, 2); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 3); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 4); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 5); @@ -456,22 +457,22 @@ static int rmi_f12_probe(struct rmi_function *fn) } item = rmi_get_register_desc_item(&f12->data_reg_desc, 6); - if (item && !xport->attn_data) { + if (item && !drvdata->attn_data.data) { f12->data6 = item; f12->data6_offset = data_offset; data_offset += item->reg_size; } item = rmi_get_register_desc_item(&f12->data_reg_desc, 7); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 8); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 9); - if (item && !xport->attn_data) { + if (item && !drvdata->attn_data.data) { f12->data9 = item; f12->data9_offset = data_offset; data_offset += item->reg_size; @@ -480,27 +481,27 @@ static int rmi_f12_probe(struct rmi_function *fn) } item = rmi_get_register_desc_item(&f12->data_reg_desc, 10); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 11); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 12); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 13); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 14); - if (item && !xport->attn_data) + if (item && !drvdata->attn_data.data) data_offset += item->reg_size; item = rmi_get_register_desc_item(&f12->data_reg_desc, 15); - if (item && !xport->attn_data) { + if (item && !drvdata->attn_data.data) { f12->data15 = item; f12->data15_offset = data_offset; data_offset += item->reg_size; diff --git a/drivers/input/rmi4/rmi_f30.c b/drivers/input/rmi4/rmi_f30.c index f696137a56f5..f4b491e3e0fd 100644 --- a/drivers/input/rmi4/rmi_f30.c +++ b/drivers/input/rmi4/rmi_f30.c @@ -99,6 +99,7 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits) { struct f30_data *f30 = dev_get_drvdata(&fn->dev); struct rmi_device *rmi_dev = fn->rmi_dev; + struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev); int retval; int gpiled = 0; int value = 0; @@ -109,15 +110,15 @@ static int rmi_f30_attention(struct rmi_function *fn, unsigned long *irq_bits) return 0; /* Read the gpi led data. */ - if (rmi_dev->xport->attn_data) { - if (rmi_dev->xport->attn_size < f30->register_count) { + if (drvdata->attn_data.data) { + if (drvdata->attn_data.size < f30->register_count) { dev_warn(&fn->dev, "F30 interrupted, but data is missing\n"); return 0; } - memcpy(f30->data_regs, rmi_dev->xport->attn_data, + memcpy(f30->data_regs, drvdata->attn_data.data, f30->register_count); - rmi_dev->xport->attn_data += f30->register_count; - rmi_dev->xport->attn_size -= f30->register_count; + drvdata->attn_data.data += f30->register_count; + drvdata->attn_data.size -= f30->register_count; } else { retval = rmi_read_block(rmi_dev, fn->fd.data_base_addr, f30->data_regs, f30->register_count); diff --git a/include/linux/rmi.h b/include/linux/rmi.h index 1d4865621493..ac910f730688 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -272,9 +272,6 @@ struct rmi_transport_dev { struct rmi_device_platform_data pdata; struct input_dev *input; - - void *attn_data; - int attn_size; }; /** @@ -364,6 +361,8 @@ struct rmi_driver_data { bool enabled; struct mutex enabled_mutex; + + struct rmi4_attn_data attn_data; DECLARE_KFIFO(attn_fifo, struct rmi4_attn_data, 16); }; -- cgit v1.2.3 From 47af2c676ae1e84140225d261a00bdf88f1f9f7e Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 28 Nov 2016 16:22:44 -0500 Subject: iio: 104-quad-8: Fix index control configuration The LS7266R1 requires bits 5 & 6 to be high in order to select the Index Control Register. This patch fixes a typo that incorrectly selects the Input/Output Control Register where the Index Control Register was desired. Fixes: 28e5d3bb0325 ("iio: 104-quad-8: Add IIO support for the ACCES 104-QUAD-8") Signed-off-by: William Breathitt Gray Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/counter/104-quad-8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c index 2d2ee353dde7..c0a69d7e9ce7 100644 --- a/drivers/iio/counter/104-quad-8.c +++ b/drivers/iio/counter/104-quad-8.c @@ -362,7 +362,7 @@ static int quad8_set_synchronous_mode(struct iio_dev *indio_dev, priv->synchronous_mode[chan->channel] = synchronous_mode; /* Load Index Control configuration to Index Control Register */ - outb(0x40 | idr_cfg, base_offset); + outb(0x60 | idr_cfg, base_offset); return 0; } @@ -444,7 +444,7 @@ static int quad8_set_index_polarity(struct iio_dev *indio_dev, priv->index_polarity[chan->channel] = index_polarity; /* Load Index Control configuration to Index Control Register */ - outb(0x40 | idr_cfg, base_offset); + outb(0x60 | idr_cfg, base_offset); return 0; } -- cgit v1.2.3 From 7e1c4058e741c781b262b15a2e86a40602aaa6b6 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Mon, 28 Nov 2016 16:55:34 -0500 Subject: iio: 104-quad-8: Fix off-by-one errors when addressing IOR The Input/Output Control register (IOR) is offset by 1 from the respective channel data register. This patch fixes off-by-one errors when attempting to write to a channel IOR where the base address was not properly offset. Fixes: 28e5d3bb0325 ("iio: 104-quad-8: Add IIO support for the ACCES 104-QUAD-8") Signed-off-by: William Breathitt Gray Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/counter/104-quad-8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c index c0a69d7e9ce7..07b6d20c0756 100644 --- a/drivers/iio/counter/104-quad-8.c +++ b/drivers/iio/counter/104-quad-8.c @@ -153,7 +153,7 @@ static int quad8_write_raw(struct iio_dev *indio_dev, ior_cfg = val | priv->preset_enable[chan->channel] << 1; /* Load I/O control configuration */ - outb(0x40 | ior_cfg, base_offset); + outb(0x40 | ior_cfg, base_offset + 1); return 0; case IIO_CHAN_INFO_SCALE: @@ -241,7 +241,7 @@ static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, size_t len) { struct quad8_iio *const priv = iio_priv(indio_dev); - const int base_offset = priv->base + 2 * chan->channel; + const int base_offset = priv->base + 2 * chan->channel + 1; bool preset_enable; int ret; unsigned int ior_cfg; -- cgit v1.2.3 From e91c3dfcd3ff88218c972cb24f932c4d434bbb09 Mon Sep 17 00:00:00 2001 From: William Breathitt Gray Date: Tue, 29 Nov 2016 10:51:48 -0500 Subject: iio: 104-quad-8: Fix active level mismatch for the preset enable option The set_to_preset_on_index sysfs attribute provides a boolean configuration option to enable a preset operation on the respective channel's counter when Index occurs. However, the corresponding configuration bit on the Input/Output Control register must be set low to enable the preset operation. This patch inverts the internal driver boolean logic exposed via the set_to_preset_on_index attribute in order to correctly configure the device which expects an active low bit. Fixes: 28e5d3bb0325 ("iio: 104-quad-8: Add IIO support for the ACCES 104-QUAD-8") Signed-off-by: William Breathitt Gray Cc: Signed-off-by: Jonathan Cameron --- drivers/iio/counter/104-quad-8.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/iio/counter/104-quad-8.c b/drivers/iio/counter/104-quad-8.c index 07b6d20c0756..a5913e97945e 100644 --- a/drivers/iio/counter/104-quad-8.c +++ b/drivers/iio/counter/104-quad-8.c @@ -233,7 +233,7 @@ static ssize_t quad8_read_set_to_preset_on_index(struct iio_dev *indio_dev, const struct quad8_iio *const priv = iio_priv(indio_dev); return snprintf(buf, PAGE_SIZE, "%u\n", - priv->preset_enable[chan->channel]); + !priv->preset_enable[chan->channel]); } static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, @@ -250,6 +250,9 @@ static ssize_t quad8_write_set_to_preset_on_index(struct iio_dev *indio_dev, if (ret) return ret; + /* Preset enable is active low in Input/Output Control register */ + preset_enable = !preset_enable; + priv->preset_enable[chan->channel] = preset_enable; ior_cfg = priv->ab_enable[chan->channel] | -- cgit v1.2.3 From 2716243212241855cd9070883779f6e58967dec5 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:09 +0200 Subject: IB/mad: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/mad.c | 40 ++++++---------------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 40cbd6bdb73b..dadce12e9056 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -816,7 +816,6 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, local = kmalloc(sizeof *local, GFP_ATOMIC); if (!local) { ret = -ENOMEM; - dev_err(&device->dev, "No memory for ib_mad_local_private\n"); goto out; } local->mad_priv = NULL; @@ -824,7 +823,6 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, mad_priv = alloc_mad_private(mad_size, GFP_ATOMIC); if (!mad_priv) { ret = -ENOMEM; - dev_err(&device->dev, "No memory for local response MAD\n"); kfree(local); goto out; } @@ -947,9 +945,6 @@ static int alloc_send_rmpp_list(struct ib_mad_send_wr_private *send_wr, for (left = send_buf->data_len + pad; left > 0; left -= seg_size) { seg = kmalloc(sizeof (*seg) + seg_size, gfp_mask); if (!seg) { - dev_err(&send_buf->mad_agent->device->dev, - "alloc_send_rmpp_segs: RMPP mem alloc failed for len %zd, gfp %#x\n", - sizeof (*seg) + seg_size, gfp_mask); free_send_rmpp_list(send_wr); return -ENOMEM; } @@ -1362,12 +1357,7 @@ static int allocate_method_table(struct ib_mad_mgmt_method_table **method) { /* Allocate management method table */ *method = kzalloc(sizeof **method, GFP_ATOMIC); - if (!*method) { - pr_err("No memory for ib_mad_mgmt_method_table\n"); - return -ENOMEM; - } - - return 0; + return (*method) ? 0 : (-ENOMEM); } /* @@ -1458,8 +1448,6 @@ static int add_nonoui_reg_req(struct ib_mad_reg_req *mad_reg_req, /* Allocate management class table for "new" class version */ *class = kzalloc(sizeof **class, GFP_ATOMIC); if (!*class) { - dev_err(&agent_priv->agent.device->dev, - "No memory for ib_mad_mgmt_class_table\n"); ret = -ENOMEM; goto error1; } @@ -1524,22 +1512,16 @@ static int add_oui_reg_req(struct ib_mad_reg_req *mad_reg_req, if (!*vendor_table) { /* Allocate mgmt vendor class table for "new" class version */ vendor = kzalloc(sizeof *vendor, GFP_ATOMIC); - if (!vendor) { - dev_err(&agent_priv->agent.device->dev, - "No memory for ib_mad_mgmt_vendor_class_table\n"); + if (!vendor) goto error1; - } *vendor_table = vendor; } if (!(*vendor_table)->vendor_class[vclass]) { /* Allocate table for this management vendor class */ vendor_class = kzalloc(sizeof *vendor_class, GFP_ATOMIC); - if (!vendor_class) { - dev_err(&agent_priv->agent.device->dev, - "No memory for ib_mad_mgmt_vendor_class\n"); + if (!vendor_class) goto error2; - } (*vendor_table)->vendor_class[vclass] = vendor_class; } @@ -2238,11 +2220,8 @@ static void ib_mad_recv_done(struct ib_cq *cq, struct ib_wc *wc) mad_size = recv->mad_size; response = alloc_mad_private(mad_size, GFP_KERNEL); - if (!response) { - dev_err(&port_priv->device->dev, - "%s: no memory for response buffer\n", __func__); + if (!response) goto out; - } if (rdma_cap_ib_switch(port_priv->device)) port_num = wc->port_num; @@ -2869,8 +2848,6 @@ static int ib_mad_post_receive_mads(struct ib_mad_qp_info *qp_info, mad_priv = alloc_mad_private(port_mad_size(qp_info->port_priv), GFP_ATOMIC); if (!mad_priv) { - dev_err(&qp_info->port_priv->device->dev, - "No memory for receive buffer\n"); ret = -ENOMEM; break; } @@ -2961,11 +2938,8 @@ static int ib_mad_port_start(struct ib_mad_port_private *port_priv) u16 pkey_index; attr = kmalloc(sizeof *attr, GFP_KERNEL); - if (!attr) { - dev_err(&port_priv->device->dev, - "Couldn't kmalloc ib_qp_attr\n"); + if (!attr) return -ENOMEM; - } ret = ib_find_pkey(port_priv->device, port_priv->port_num, IB_DEFAULT_PKEY_FULL, &pkey_index); @@ -3135,10 +3109,8 @@ static int ib_mad_port_open(struct ib_device *device, /* Create new device info */ port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); - if (!port_priv) { - dev_err(&device->dev, "No memory for ib_mad_port_private\n"); + if (!port_priv) return -ENOMEM; - } port_priv->device = device; port_priv->port_num = port_num; -- cgit v1.2.3 From a0b3455fcb2d1b3e486349a4a51803c3cb3847b5 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:10 +0200 Subject: IB/core: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/agent.c | 1 - drivers/infiniband/core/device.c | 5 +---- drivers/infiniband/core/fmr_pool.c | 1 - drivers/infiniband/core/iwpm_msg.c | 1 - drivers/infiniband/core/iwpm_util.c | 12 ++++-------- drivers/infiniband/core/roce_gid_mgmt.c | 21 ++++++--------------- 6 files changed, 11 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/agent.c b/drivers/infiniband/core/agent.c index 4fa524dfb6cf..11dacd97a667 100644 --- a/drivers/infiniband/core/agent.c +++ b/drivers/infiniband/core/agent.c @@ -156,7 +156,6 @@ int ib_agent_port_open(struct ib_device *device, int port_num) /* Create new device info */ port_priv = kzalloc(sizeof *port_priv, GFP_KERNEL); if (!port_priv) { - dev_err(&device->dev, "No memory for ib_agent_port_private\n"); ret = -ENOMEM; goto error1; } diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 760ef603a468..571974cd3919 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c @@ -254,11 +254,8 @@ static int add_client_context(struct ib_device *device, struct ib_client *client unsigned long flags; context = kmalloc(sizeof *context, GFP_KERNEL); - if (!context) { - pr_warn("Couldn't allocate client context for %s/%s\n", - device->name, client->name); + if (!context) return -ENOMEM; - } context->client = client; context->data = NULL; diff --git a/drivers/infiniband/core/fmr_pool.c b/drivers/infiniband/core/fmr_pool.c index cdbb1f1a6d97..cdfad5f26212 100644 --- a/drivers/infiniband/core/fmr_pool.c +++ b/drivers/infiniband/core/fmr_pool.c @@ -247,7 +247,6 @@ struct ib_fmr_pool *ib_create_fmr_pool(struct ib_pd *pd, kmalloc(IB_FMR_HASH_SIZE * sizeof *pool->cache_bucket, GFP_KERNEL); if (!pool->cache_bucket) { - pr_warn(PFX "Failed to allocate cache in pool\n"); ret = -ENOMEM; goto out_free_pool; } diff --git a/drivers/infiniband/core/iwpm_msg.c b/drivers/infiniband/core/iwpm_msg.c index 1c41b95cefec..a0e7c16d8bd8 100644 --- a/drivers/infiniband/core/iwpm_msg.c +++ b/drivers/infiniband/core/iwpm_msg.c @@ -604,7 +604,6 @@ int iwpm_remote_info_cb(struct sk_buff *skb, struct netlink_callback *cb) } rem_info = kzalloc(sizeof(struct iwpm_remote_info), GFP_ATOMIC); if (!rem_info) { - pr_err("%s: Unable to allocate a remote info\n", __func__); ret = -ENOMEM; return ret; } diff --git a/drivers/infiniband/core/iwpm_util.c b/drivers/infiniband/core/iwpm_util.c index ade71e7f0131..3ef51a96bbf1 100644 --- a/drivers/infiniband/core/iwpm_util.c +++ b/drivers/infiniband/core/iwpm_util.c @@ -62,7 +62,6 @@ int iwpm_init(u8 nl_client) sizeof(struct hlist_head), GFP_KERNEL); if (!iwpm_hash_bucket) { ret = -ENOMEM; - pr_err("%s Unable to create mapinfo hash table\n", __func__); goto init_exit; } iwpm_reminfo_bucket = kzalloc(IWPM_REMINFO_HASH_SIZE * @@ -70,7 +69,6 @@ int iwpm_init(u8 nl_client) if (!iwpm_reminfo_bucket) { kfree(iwpm_hash_bucket); ret = -ENOMEM; - pr_err("%s Unable to create reminfo hash table\n", __func__); goto init_exit; } } @@ -128,10 +126,9 @@ int iwpm_create_mapinfo(struct sockaddr_storage *local_sockaddr, if (!iwpm_valid_client(nl_client)) return ret; map_info = kzalloc(sizeof(struct iwpm_mapping_info), GFP_KERNEL); - if (!map_info) { - pr_err("%s: Unable to allocate a mapping info\n", __func__); + if (!map_info) return -ENOMEM; - } + memcpy(&map_info->local_sockaddr, local_sockaddr, sizeof(struct sockaddr_storage)); memcpy(&map_info->mapped_sockaddr, mapped_sockaddr, @@ -309,10 +306,9 @@ struct iwpm_nlmsg_request *iwpm_get_nlmsg_request(__u32 nlmsg_seq, unsigned long flags; nlmsg_request = kzalloc(sizeof(struct iwpm_nlmsg_request), gfp); - if (!nlmsg_request) { - pr_err("%s Unable to allocate a nlmsg_request\n", __func__); + if (!nlmsg_request) return NULL; - } + spin_lock_irqsave(&iwpm_nlmsg_req_lock, flags); list_add_tail(&nlmsg_request->inprocess_list, &iwpm_nlmsg_req_list); spin_unlock_irqrestore(&iwpm_nlmsg_req_lock, flags); diff --git a/drivers/infiniband/core/roce_gid_mgmt.c b/drivers/infiniband/core/roce_gid_mgmt.c index 06556c34606d..c86ddcea7675 100644 --- a/drivers/infiniband/core/roce_gid_mgmt.c +++ b/drivers/infiniband/core/roce_gid_mgmt.c @@ -304,10 +304,9 @@ static void enum_netdev_ipv4_ips(struct ib_device *ib_dev, for_ifa(in_dev) { struct sin_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - pr_warn("roce_gid_mgmt: couldn't allocate entry for IPv4 update\n"); + if (!entry) continue; - } + entry->ip.sin_family = AF_INET; entry->ip.sin_addr.s_addr = ifa->ifa_address; list_add_tail(&entry->list, &sin_list); @@ -348,10 +347,8 @@ static void enum_netdev_ipv6_ips(struct ib_device *ib_dev, list_for_each_entry(ifp, &in6_dev->addr_list, if_list) { struct sin6_list *entry = kzalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - pr_warn("roce_gid_mgmt: couldn't allocate entry for IPv6 update\n"); + if (!entry) continue; - } entry->sin6.sin6_family = AF_INET6; entry->sin6.sin6_addr = ifp->addr; @@ -459,10 +456,8 @@ static void handle_netdev_upper(struct ib_device *ib_dev, u8 port, struct upper_list *entry = kmalloc(sizeof(*entry), GFP_ATOMIC); - if (!entry) { - pr_info("roce_gid_mgmt: couldn't allocate entry to delete ndev\n"); + if (!entry) continue; - } list_add_tail(&entry->list, &upper_list); dev_hold(upper); @@ -555,10 +550,8 @@ static int netdevice_queue_work(struct netdev_event_work_cmd *cmds, struct netdev_event_work *ndev_work = kmalloc(sizeof(*ndev_work), GFP_KERNEL); - if (!ndev_work) { - pr_warn("roce_gid_mgmt: can't allocate work for netdevice_event\n"); + if (!ndev_work) return NOTIFY_DONE; - } memcpy(ndev_work->cmds, cmds, sizeof(ndev_work->cmds)); for (i = 0; i < ARRAY_SIZE(ndev_work->cmds) && ndev_work->cmds[i].cb; i++) { @@ -692,10 +685,8 @@ static int addr_event(struct notifier_block *this, unsigned long event, } work = kmalloc(sizeof(*work), GFP_ATOMIC); - if (!work) { - pr_warn("roce_gid_mgmt: Couldn't allocate work for addr_event\n"); + if (!work) return NOTIFY_DONE; - } INIT_WORK(&work->work, update_gid_event_work_handler); -- cgit v1.2.3 From aa6aae38f7fb2c030f326a6dd10b58fff1851dfa Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:11 +0200 Subject: IB/core: Release allocated memory in cache setup failure The failure in ib_cache_setup_one function during ib_register_device will leave leaked allocated memory. Fixes: 03db3a2d81e6 ("IB/core: Add RoCE GID table management") Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/cache.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cache.c b/drivers/infiniband/core/cache.c index 1a2984c28b95..ae04826e82fc 100644 --- a/drivers/infiniband/core/cache.c +++ b/drivers/infiniband/core/cache.c @@ -770,12 +770,8 @@ static int _gid_table_setup_one(struct ib_device *ib_dev) int err = 0; table = kcalloc(ib_dev->phys_port_cnt, sizeof(*table), GFP_KERNEL); - - if (!table) { - pr_warn("failed to allocate ib gid cache for %s\n", - ib_dev->name); + if (!table) return -ENOMEM; - } for (port = 0; port < ib_dev->phys_port_cnt; port++) { u8 rdma_port = port + rdma_start_port(ib_dev); @@ -1170,14 +1166,13 @@ int ib_cache_setup_one(struct ib_device *device) GFP_KERNEL); if (!device->cache.pkey_cache || !device->cache.lmc_cache) { - pr_warn("Couldn't allocate cache for %s\n", device->name); - return -ENOMEM; + err = -ENOMEM; + goto free; } err = gid_table_setup_one(device); if (err) - /* Allocated memory will be cleaned in the release function */ - return err; + goto free; for (p = 0; p <= rdma_end_port(device) - rdma_start_port(device); ++p) ib_cache_update(device, p + rdma_start_port(device)); @@ -1192,6 +1187,9 @@ int ib_cache_setup_one(struct ib_device *device) err: gid_table_cleanup_one(device); +free: + kfree(device->cache.pkey_cache); + kfree(device->cache.lmc_cache); return err; } -- cgit v1.2.3 From 15d4626e498c09b66c0f74a107a83bd95abb175c Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:12 +0200 Subject: IB/mlx4: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/alias_GUID.c | 4 +--- drivers/infiniband/hw/mlx4/cm.c | 4 +--- drivers/infiniband/hw/mlx4/mad.c | 9 ++------- drivers/infiniband/hw/mlx4/main.c | 16 +++------------- drivers/infiniband/hw/mlx4/mcg.c | 5 +---- 5 files changed, 8 insertions(+), 30 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c index 5e9939045852..06020c54db20 100644 --- a/drivers/infiniband/hw/mlx4/alias_GUID.c +++ b/drivers/infiniband/hw/mlx4/alias_GUID.c @@ -755,10 +755,8 @@ static void alias_guid_work(struct work_struct *work) struct mlx4_ib_dev *dev = container_of(ib_sriov, struct mlx4_ib_dev, sriov); rec = kzalloc(sizeof *rec, GFP_KERNEL); - if (!rec) { - pr_err("alias_guid_work: No Memory\n"); + if (!rec) return; - } pr_debug("starting [port: %d]...\n", sriov_alias_port->port + 1); ret = get_next_record_to_update(dev, sriov_alias_port->port, rec); diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c index 39a488889fc7..d64845335e87 100644 --- a/drivers/infiniband/hw/mlx4/cm.c +++ b/drivers/infiniband/hw/mlx4/cm.c @@ -247,10 +247,8 @@ id_map_alloc(struct ib_device *ibdev, int slave_id, u32 sl_cm_id) struct mlx4_ib_sriov *sriov = &to_mdev(ibdev)->sriov; ent = kmalloc(sizeof (struct id_map_entry), GFP_KERNEL); - if (!ent) { - mlx4_ib_warn(ibdev, "Couldn't allocate id cache entry - out of memory\n"); + if (!ent) return ERR_PTR(-ENOMEM); - } ent->sl_cm_id = sl_cm_id; ent->slave_id = slave_id; diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c index 1672907ff219..b0cd66336fcb 100644 --- a/drivers/infiniband/hw/mlx4/mad.c +++ b/drivers/infiniband/hw/mlx4/mad.c @@ -1102,10 +1102,8 @@ static void handle_slaves_guid_change(struct mlx4_ib_dev *dev, u8 port_num, in_mad = kmalloc(sizeof *in_mad, GFP_KERNEL); out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); - if (!in_mad || !out_mad) { - mlx4_ib_warn(&dev->ib_dev, "failed to allocate memory for guid info mads\n"); + if (!in_mad || !out_mad) goto out; - } guid_tbl_blk_num *= 4; @@ -1916,11 +1914,8 @@ static int alloc_pv_object(struct mlx4_ib_dev *dev, int slave, int port, *ret_ctx = NULL; ctx = kzalloc(sizeof (struct mlx4_ib_demux_pv_ctx), GFP_KERNEL); - if (!ctx) { - pr_err("failed allocating pv resource context " - "for port %d, slave %d\n", port, slave); + if (!ctx) return -ENOMEM; - } ctx->ib_dev = &dev->ib_dev; ctx->port = port; diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index b597e8227591..1b54786d13d0 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2814,11 +2814,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) kmalloc(BITS_TO_LONGS(ibdev->steer_qpn_count) * sizeof(long), GFP_KERNEL); - if (!ibdev->ib_uc_qpns_bitmap) { - dev_err(&dev->persist->pdev->dev, - "bit map alloc failed\n"); + if (!ibdev->ib_uc_qpns_bitmap) goto err_steer_qp_release; - } bitmap_zero(ibdev->ib_uc_qpns_bitmap, ibdev->steer_qpn_count); @@ -3055,15 +3052,12 @@ static void do_slave_init(struct mlx4_ib_dev *ibdev, int slave, int do_init) first_port = find_first_bit(actv_ports.ports, dev->caps.num_ports); dm = kcalloc(ports, sizeof(*dm), GFP_ATOMIC); - if (!dm) { - pr_err("failed to allocate memory for tunneling qp update\n"); + if (!dm) return; - } for (i = 0; i < ports; i++) { dm[i] = kmalloc(sizeof (struct mlx4_ib_demux_work), GFP_ATOMIC); if (!dm[i]) { - pr_err("failed to allocate memory for tunneling qp update work struct\n"); while (--i >= 0) kfree(dm[i]); goto out; @@ -3223,8 +3217,6 @@ void mlx4_sched_ib_sl2vl_update_work(struct mlx4_ib_dev *ibdev, ew->port = port; ew->ib_dev = ibdev; queue_work(wq, &ew->work); - } else { - pr_err("failed to allocate memory for sl2vl update work\n"); } } @@ -3284,10 +3276,8 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr, case MLX4_DEV_EVENT_PORT_MGMT_CHANGE: ew = kmalloc(sizeof *ew, GFP_ATOMIC); - if (!ew) { - pr_err("failed to allocate memory for events work\n"); + if (!ew) break; - } INIT_WORK(&ew->work, handle_port_mgmt_change_event); memcpy(&ew->ib_eqe, eqe, sizeof *eqe); diff --git a/drivers/infiniband/hw/mlx4/mcg.c b/drivers/infiniband/hw/mlx4/mcg.c index a21d37f02f35..e010fe459e67 100644 --- a/drivers/infiniband/hw/mlx4/mcg.c +++ b/drivers/infiniband/hw/mlx4/mcg.c @@ -1142,7 +1142,6 @@ void mlx4_ib_mcg_port_cleanup(struct mlx4_ib_demux_ctx *ctx, int destroy_wq) work = kmalloc(sizeof *work, GFP_KERNEL); if (!work) { ctx->flushing = 0; - mcg_warn("failed allocating work for cleanup\n"); return; } @@ -1202,10 +1201,8 @@ static int push_deleteing_req(struct mcast_group *group, int slave) return 0; req = kzalloc(sizeof *req, GFP_KERNEL); - if (!req) { - mcg_warn_group(group, "failed allocation - may leave stall groups\n"); + if (!req) return -ENOMEM; - } if (!list_empty(&group->func[slave].pending)) { pend_req = list_entry(group->func[slave].pending.prev, struct mcast_req, group_list); -- cgit v1.2.3 From 0886d8f0b7c9bb2f85fa8b71c4842f92308de641 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:13 +0200 Subject: IB/mlx5: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/srq.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index 3857dbd9c956..c676133750b7 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -203,8 +203,6 @@ static int create_srq_kernel(struct mlx5_ib_dev *dev, struct mlx5_ib_srq *srq, srq->wrid = kmalloc(srq->msrq.max * sizeof(u64), GFP_KERNEL); if (!srq->wrid) { - mlx5_ib_dbg(dev, "kmalloc failed %lu\n", - (unsigned long)(srq->msrq.max * sizeof(u64))); err = -ENOMEM; goto err_in; } -- cgit v1.2.3 From 5ce9f115bd796be4f0dd8230e6b8baeb2c558311 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:14 +0200 Subject: IB/hfi1: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/pio.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 50a3a36d9363..d15ffed48a39 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -2053,7 +2053,6 @@ int init_credit_return(struct hfi1_devdata *dd) sizeof(struct credit_return_base), GFP_KERNEL); if (!dd->cr_base) { - dd_dev_err(dd, "Unable to allocate credit return base\n"); ret = -ENOMEM; goto done; } -- cgit v1.2.3 From 51ad2bae213fdd4c63d7c3f2906bfe4e244bad46 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:15 +0200 Subject: IB/cxgb3: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb3/cxio_dbg.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb3/cxio_dbg.c b/drivers/infiniband/hw/cxgb3/cxio_dbg.c index 8bca6b4ec9af..445e89e5e7cf 100644 --- a/drivers/infiniband/hw/cxgb3/cxio_dbg.c +++ b/drivers/infiniband/hw/cxgb3/cxio_dbg.c @@ -45,10 +45,9 @@ void cxio_dump_tpt(struct cxio_rdev *rdev, u32 stag) int size = 32; m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); - if (!m) { - PDBG("%s couldn't allocate memory.\n", __func__); + if (!m) return; - } + m->mem_id = MEM_PMRX; m->addr = (stag>>8) * 32 + rdev->rnic_info.tpt_base; m->len = size; @@ -82,10 +81,9 @@ void cxio_dump_pbl(struct cxio_rdev *rdev, u32 pbl_addr, uint len, u8 shift) size = npages * sizeof(u64); m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); - if (!m) { - PDBG("%s couldn't allocate memory.\n", __func__); + if (!m) return; - } + m->mem_id = MEM_PMRX; m->addr = pbl_addr; m->len = size; @@ -144,10 +142,9 @@ void cxio_dump_rqt(struct cxio_rdev *rdev, u32 hwtid, int nents) int rc; m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); - if (!m) { - PDBG("%s couldn't allocate memory.\n", __func__); + if (!m) return; - } + m->mem_id = MEM_PMRX; m->addr = ((hwtid)<<10) + rdev->rnic_info.rqt_base; m->len = size; @@ -177,10 +174,9 @@ void cxio_dump_tcb(struct cxio_rdev *rdev, u32 hwtid) int rc; m = kmalloc(sizeof(*m) + size, GFP_ATOMIC); - if (!m) { - PDBG("%s couldn't allocate memory.\n", __func__); + if (!m) return; - } + m->mem_id = MEM_CM; m->addr = hwtid * size; m->len = size; -- cgit v1.2.3 From 9a88f96f21b27b0fccb69601fb725f03fbab841b Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:16 +0200 Subject: IB/cxgb4: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/device.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 93e3d270a98a..11a25ec1ce03 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -841,8 +841,6 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) if (rdev->wr_log) { rdev->wr_log_size = 1 << c4iw_wr_log_size_order; atomic_set(&rdev->wr_log_idx, 0); - } else { - pr_err(MOD "error allocating wr_log. Logging disabled\n"); } } @@ -1424,8 +1422,6 @@ static void recover_queues(struct uld_ctx *ctx) qp_list.qps = kzalloc(count * sizeof *qp_list.qps, GFP_ATOMIC); if (!qp_list.qps) { - printk(KERN_ERR MOD "%s: Fatal error - DB overflow recovery failed\n", - pci_name(ctx->lldi.pdev)); spin_unlock_irq(&ctx->dev->lock); return; } -- cgit v1.2.3 From 315b41480bb956b223a04c6556f04c9b7c74c8c2 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:17 +0200 Subject: IB/i40iw: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 2 -- drivers/infiniband/hw/i40iw/i40iw_main.c | 5 ++--- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 1 - 3 files changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 85637696f6e9..47d1bbce9561 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -1675,7 +1675,6 @@ static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev, "Allocating child listener %p\n", child_listen_node); if (!child_listen_node) { - i40iw_pr_err("listener memory allocation\n"); ret = I40IW_ERR_NO_MEMORY; goto exit; } @@ -1751,7 +1750,6 @@ static enum i40iw_status_code i40iw_add_mqh_4( "Allocating child listener %p\n", child_listen_node); if (!child_listen_node) { - i40iw_pr_err("listener memory allocation\n"); in_dev_put(idev); ret = I40IW_ERR_NO_MEMORY; goto exit; diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index ac2f3cd9478c..a6ad913a30dd 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -1301,10 +1301,9 @@ static enum i40iw_status_code i40iw_initialize_dev(struct i40iw_device *iwdev, size = sizeof(struct i40iw_hmc_pble_rsrc) + sizeof(struct i40iw_hmc_info) + (sizeof(struct i40iw_hmc_obj_info) * I40IW_HMC_IW_MAX); iwdev->hmc_info_mem = kzalloc(size, GFP_KERNEL); - if (!iwdev->hmc_info_mem) { - i40iw_pr_err("memory alloc fail\n"); + if (!iwdev->hmc_info_mem) return I40IW_ERR_NO_MEMORY; - } + iwdev->pble_rsrc = (struct i40iw_hmc_pble_rsrc *)iwdev->hmc_info_mem; dev->hmc_info = &iwdev->hw.hmc; dev->hmc_info->hmc_obj = (struct i40iw_hmc_obj_info *)(iwdev->pble_rsrc + 1); diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 6329c971c22f..62e068b9bf4c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2654,7 +2654,6 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev iwibdev->ibdev.iwcm = kzalloc(sizeof(*iwibdev->ibdev.iwcm), GFP_KERNEL); if (!iwibdev->ibdev.iwcm) { ib_dealloc_device(&iwibdev->ibdev); - i40iw_pr_err("iwcm == NULL\n"); return NULL; } -- cgit v1.2.3 From c40a83b9786e99a78c849f2f33448426bf8fa0f2 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:18 +0200 Subject: IB/qib: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qib/qib_diag.c | 6 +---- drivers/infiniband/hw/qib/qib_eeprom.c | 6 +---- drivers/infiniband/hw/qib/qib_iba6120.c | 8 +----- drivers/infiniband/hw/qib/qib_iba7220.c | 8 +----- drivers/infiniband/hw/qib/qib_iba7322.c | 22 ++++----------- drivers/infiniband/hw/qib/qib_init.c | 47 ++++++--------------------------- 6 files changed, 17 insertions(+), 80 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c index 8c34b23e5bf6..775018b32b0d 100644 --- a/drivers/infiniband/hw/qib/qib_diag.c +++ b/drivers/infiniband/hw/qib/qib_diag.c @@ -609,8 +609,6 @@ static ssize_t qib_diagpkt_write(struct file *fp, tmpbuf = vmalloc(plen); if (!tmpbuf) { - qib_devinfo(dd->pcidev, - "Unable to allocate tmp buffer, failing\n"); ret = -ENOMEM; goto bail; } @@ -702,10 +700,8 @@ int qib_register_observer(struct qib_devdata *dd, if (!dd || !op) return -EINVAL; olp = vmalloc(sizeof(*olp)); - if (!olp) { - pr_err("vmalloc for observer failed\n"); + if (!olp) return -ENOMEM; - } spin_lock_irqsave(&dd->qib_diag_trans_lock, flags); olp->op = op; diff --git a/drivers/infiniband/hw/qib/qib_eeprom.c b/drivers/infiniband/hw/qib/qib_eeprom.c index 311ee6c3dd5e..33a2e74c8495 100644 --- a/drivers/infiniband/hw/qib/qib_eeprom.c +++ b/drivers/infiniband/hw/qib/qib_eeprom.c @@ -182,12 +182,8 @@ void qib_get_eeprom_info(struct qib_devdata *dd) * */ len = sizeof(struct qib_flash); buf = vmalloc(len); - if (!buf) { - qib_dev_err(dd, - "Couldn't allocate memory to read %u bytes from eeprom for GUID\n", - len); + if (!buf) goto bail; - } /* * Use "public" eeprom read function, which does locking and diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c index a3733f25280f..92399d3ffd15 100644 --- a/drivers/infiniband/hw/qib/qib_iba6120.c +++ b/drivers/infiniband/hw/qib/qib_iba6120.c @@ -1759,9 +1759,7 @@ static void pe_boardname(struct qib_devdata *dd) } namelen = strlen(n) + 1; dd->boardname = kmalloc(namelen, GFP_KERNEL); - if (!dd->boardname) - qib_dev_err(dd, "Failed allocation for board name: %s\n", n); - else + if (dd->boardname) snprintf(dd->boardname, namelen, "%s", n); if (dd->majrev != 4 || !dd->minrev || dd->minrev > 2) @@ -2533,8 +2531,6 @@ static void init_6120_cntrnames(struct qib_devdata *dd) dd->cspec->cntrnamelen = 1 + s - cntr6120names; dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs * sizeof(u64), GFP_KERNEL); - if (!dd->cspec->cntrs) - qib_dev_err(dd, "Failed allocation for counters\n"); for (i = 0, s = (char *)portcntr6120names; s; i++) s = strchr(s + 1, '\n'); @@ -2542,8 +2538,6 @@ static void init_6120_cntrnames(struct qib_devdata *dd) dd->cspec->portcntrnamelen = sizeof(portcntr6120names) - 1; dd->cspec->portcntrs = kmalloc(dd->cspec->nportcntrs * sizeof(u64), GFP_KERNEL); - if (!dd->cspec->portcntrs) - qib_dev_err(dd, "Failed allocation for portcounters\n"); } static u32 qib_read_6120cntrs(struct qib_devdata *dd, loff_t pos, char **namep, diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c index 00b2af211157..e55e31a69195 100644 --- a/drivers/infiniband/hw/qib/qib_iba7220.c +++ b/drivers/infiniband/hw/qib/qib_iba7220.c @@ -2070,9 +2070,7 @@ static void qib_7220_boardname(struct qib_devdata *dd) namelen = strlen(n) + 1; dd->boardname = kmalloc(namelen, GFP_KERNEL); - if (!dd->boardname) - qib_dev_err(dd, "Failed allocation for board name: %s\n", n); - else + if (dd->boardname) snprintf(dd->boardname, namelen, "%s", n); if (dd->majrev != 5 || !dd->minrev || dd->minrev > 2) @@ -3179,8 +3177,6 @@ static void init_7220_cntrnames(struct qib_devdata *dd) dd->cspec->cntrnamelen = 1 + s - cntr7220names; dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs * sizeof(u64), GFP_KERNEL); - if (!dd->cspec->cntrs) - qib_dev_err(dd, "Failed allocation for counters\n"); for (i = 0, s = (char *)portcntr7220names; s; i++) s = strchr(s + 1, '\n'); @@ -3188,8 +3184,6 @@ static void init_7220_cntrnames(struct qib_devdata *dd) dd->cspec->portcntrnamelen = sizeof(portcntr7220names) - 1; dd->cspec->portcntrs = kmalloc(dd->cspec->nportcntrs * sizeof(u64), GFP_KERNEL); - if (!dd->cspec->portcntrs) - qib_dev_err(dd, "Failed allocation for portcounters\n"); } static u32 qib_read_7220cntrs(struct qib_devdata *dd, loff_t pos, char **namep, diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c index ded27172320e..c4a3616062f1 100644 --- a/drivers/infiniband/hw/qib/qib_iba7322.c +++ b/drivers/infiniband/hw/qib/qib_iba7322.c @@ -3627,9 +3627,7 @@ static unsigned qib_7322_boardname(struct qib_devdata *dd) namelen = strlen(n) + 1; dd->boardname = kmalloc(namelen, GFP_KERNEL); - if (!dd->boardname) - qib_dev_err(dd, "Failed allocation for board name: %s\n", n); - else + if (dd->boardname) snprintf(dd->boardname, namelen, "%s", n); snprintf(dd->boardversion, sizeof(dd->boardversion), @@ -3656,7 +3654,7 @@ static unsigned qib_7322_boardname(struct qib_devdata *dd) static int qib_do_7322_reset(struct qib_devdata *dd) { u64 val; - u64 *msix_vecsave; + u64 *msix_vecsave = NULL; int i, msix_entries, ret = 1; u16 cmdval; u8 int_line, clinesz; @@ -3677,10 +3675,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd) /* can be up to 512 bytes, too big for stack */ msix_vecsave = kmalloc(2 * dd->cspec->num_msix_entries * sizeof(u64), GFP_KERNEL); - if (!msix_vecsave) - qib_dev_err(dd, "No mem to save MSIx data\n"); - } else - msix_vecsave = NULL; + } /* * Core PCI (as of 2.6.18) doesn't save or rewrite the full vector @@ -5043,8 +5038,6 @@ static void init_7322_cntrnames(struct qib_devdata *dd) dd->cspec->cntrnamelen = 1 + s - cntr7322names; dd->cspec->cntrs = kmalloc(dd->cspec->ncntrs * sizeof(u64), GFP_KERNEL); - if (!dd->cspec->cntrs) - qib_dev_err(dd, "Failed allocation for counters\n"); for (i = 0, s = (char *)portcntr7322names; s; i++) s = strchr(s + 1, '\n'); @@ -5053,9 +5046,6 @@ static void init_7322_cntrnames(struct qib_devdata *dd) for (i = 0; i < dd->num_pports; ++i) { dd->pport[i].cpspec->portcntrs = kmalloc(dd->cspec->nportcntrs * sizeof(u64), GFP_KERNEL); - if (!dd->pport[i].cpspec->portcntrs) - qib_dev_err(dd, - "Failed allocation for portcounters\n"); } } @@ -6461,7 +6451,6 @@ static int qib_init_7322_variables(struct qib_devdata *dd) sizeof(*dd->cspec->sendibchk), GFP_KERNEL); if (!dd->cspec->sendchkenable || !dd->cspec->sendgrhchk || !dd->cspec->sendibchk) { - qib_dev_err(dd, "Failed allocation for hdrchk bitmaps\n"); ret = -ENOMEM; goto bail; } @@ -7338,10 +7327,9 @@ struct qib_devdata *qib_init_iba7322_funcs(struct pci_dev *pdev, tabsize = actual_cnt; dd->cspec->msix_entries = kzalloc(tabsize * sizeof(struct qib_msix_entry), GFP_KERNEL); - if (!dd->cspec->msix_entries) { - qib_dev_err(dd, "No memory for MSIx table\n"); + if (!dd->cspec->msix_entries) tabsize = 0; - } + for (i = 0; i < tabsize; i++) dd->cspec->msix_entries[i].msix.entry = i; diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c index 1730aa839a47..b50240b1d5a4 100644 --- a/drivers/infiniband/hw/qib/qib_init.c +++ b/drivers/infiniband/hw/qib/qib_init.c @@ -133,11 +133,8 @@ int qib_create_ctxts(struct qib_devdata *dd) * cleanup iterates across all possible ctxts. */ dd->rcd = kcalloc(dd->ctxtcnt, sizeof(*dd->rcd), GFP_KERNEL); - if (!dd->rcd) { - qib_dev_err(dd, - "Unable to allocate ctxtdata array, failing\n"); + if (!dd->rcd) return -ENOMEM; - } /* create (one or more) kctxt */ for (i = 0; i < dd->first_user_ctxt; ++i) { @@ -265,39 +262,23 @@ int qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd, size = IB_CC_TABLE_CAP_DEFAULT * sizeof(struct ib_cc_table_entry) * IB_CCT_ENTRIES; ppd->ccti_entries = kzalloc(size, GFP_KERNEL); - if (!ppd->ccti_entries) { - qib_dev_err(dd, - "failed to allocate congestion control table for port %d!\n", - port); + if (!ppd->ccti_entries) goto bail; - } size = IB_CC_CCS_ENTRIES * sizeof(struct ib_cc_congestion_entry); ppd->congestion_entries = kzalloc(size, GFP_KERNEL); - if (!ppd->congestion_entries) { - qib_dev_err(dd, - "failed to allocate congestion setting list for port %d!\n", - port); + if (!ppd->congestion_entries) goto bail_1; - } size = sizeof(struct cc_table_shadow); ppd->ccti_entries_shadow = kzalloc(size, GFP_KERNEL); - if (!ppd->ccti_entries_shadow) { - qib_dev_err(dd, - "failed to allocate shadow ccti list for port %d!\n", - port); + if (!ppd->ccti_entries_shadow) goto bail_2; - } size = sizeof(struct ib_cc_congestion_setting_attr); ppd->congestion_entries_shadow = kzalloc(size, GFP_KERNEL); - if (!ppd->congestion_entries_shadow) { - qib_dev_err(dd, - "failed to allocate shadow congestion setting list for port %d!\n", - port); + if (!ppd->congestion_entries_shadow) goto bail_3; - } return 0; @@ -391,18 +372,12 @@ static void init_shadow_tids(struct qib_devdata *dd) dma_addr_t *addrs; pages = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(struct page *)); - if (!pages) { - qib_dev_err(dd, - "failed to allocate shadow page * array, no expected sends!\n"); + if (!pages) goto bail; - } addrs = vzalloc(dd->cfgctxts * dd->rcvtidcnt * sizeof(dma_addr_t)); - if (!addrs) { - qib_dev_err(dd, - "failed to allocate shadow dma handle array, no expected sends!\n"); + if (!addrs) goto bail_free; - } dd->pageshadow = pages; dd->physshadow = addrs; @@ -1026,11 +1001,8 @@ static void qib_verify_pioperf(struct qib_devdata *dd) cnt = 1024; addr = vmalloc(cnt); - if (!addr) { - qib_devinfo(dd->pcidev, - "Couldn't get memory for checking PIO perf, skipping\n"); + if (!addr) goto done; - } preempt_disable(); /* we want reasonably accurate elapsed time */ msecs = 1 + jiffies_to_msecs(jiffies); @@ -1172,9 +1144,6 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra) sizeof(long), GFP_KERNEL); if (qib_cpulist) qib_cpulist_count = count; - else - qib_early_err(&pdev->dev, - "Could not alloc cpulist info, cpu affinity might be wrong\n"); } #ifdef CONFIG_DEBUG_FS qib_dbg_ibdev_init(&dd->verbs_dev); -- cgit v1.2.3 From 2e65835a1ba0607cb212ec687e509ee6c24a68ed Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:19 +0200 Subject: IB/nes: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/nes/nes.c | 1 - drivers/infiniband/hw/nes/nes_cm.c | 4 +--- drivers/infiniband/hw/nes/nes_hw.c | 6 ++---- drivers/infiniband/hw/nes/nes_mgt.c | 10 +++------- drivers/infiniband/hw/nes/nes_verbs.c | 4 ---- 5 files changed, 6 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index 35cbb17bec12..9badd0224ec5 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -516,7 +516,6 @@ static int nes_probe(struct pci_dev *pcidev, const struct pci_device_id *ent) /* Allocate hardware structure */ nesdev = kzalloc(sizeof(struct nes_device), GFP_KERNEL); if (!nesdev) { - printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n", pci_name(pcidev)); ret = -ENOMEM; goto bail2; } diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index 57db9b332f44..8e703479e7ce 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -2282,10 +2282,8 @@ static struct nes_cm_listener *mini_cm_listen(struct nes_cm_core *cm_core, if (!listener) { /* create a CM listen node (1/2 node to compare incoming traffic to) */ listener = kzalloc(sizeof(*listener), GFP_ATOMIC); - if (!listener) { - nes_debug(NES_DBG_CM, "Not creating listener memory allocation failed\n"); + if (!listener) return NULL; - } listener->loc_addr = cm_info->loc_addr; listener->loc_port = cm_info->loc_port; diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index a1c6481d8038..19acd13c6cb1 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -351,9 +351,8 @@ struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) { /* allocate a new adapter struct */ nesadapter = kzalloc(adapter_size, GFP_KERNEL); - if (nesadapter == NULL) { + if (!nesadapter) return NULL; - } nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n", nesadapter, (u32)sizeof(struct nes_adapter), adapter_size); @@ -1007,8 +1006,7 @@ int nes_init_cqp(struct nes_device *nesdev) /* Allocate a twice the number of CQP requests as the SQ size */ nesdev->nes_cqp_requests = kzalloc(sizeof(struct nes_cqp_request) * 2 * NES_CQP_SQ_SIZE, GFP_KERNEL); - if (nesdev->nes_cqp_requests == NULL) { - nes_debug(NES_DBG_INIT, "Unable to allocate memory CQP request entries.\n"); + if (!nesdev->nes_cqp_requests) { pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase, nesdev->cqp.sq_pbase); return -ENOMEM; diff --git a/drivers/infiniband/hw/nes/nes_mgt.c b/drivers/infiniband/hw/nes/nes_mgt.c index 416645259b0f..33624f17c347 100644 --- a/drivers/infiniband/hw/nes/nes_mgt.c +++ b/drivers/infiniband/hw/nes/nes_mgt.c @@ -320,8 +320,7 @@ static int get_fpdu_info(struct nes_device *nesdev, struct nes_qp *nesqp, /* Found one */ fpdu_info = kzalloc(sizeof(*fpdu_info), GFP_ATOMIC); - if (fpdu_info == NULL) { - nes_debug(NES_DBG_PAU, "Failed to alloc a fpdu_info.\n"); + if (!fpdu_info) { rc = -ENOMEM; goto out; } @@ -729,8 +728,7 @@ static int nes_change_quad_hash(struct nes_device *nesdev, } qh_chg = kmalloc(sizeof *qh_chg, GFP_ATOMIC); - if (qh_chg == NULL) { - nes_debug(NES_DBG_PAU, "Failed to get a cqp_request.\n"); + if (!qh_chg) { ret = -ENOMEM; goto chg_qh_err; } @@ -880,10 +878,8 @@ int nes_init_mgt_qp(struct nes_device *nesdev, struct net_device *netdev, struct /* Allocate space the all mgt QPs once */ mgtvnic = kzalloc(NES_MGT_QP_COUNT * sizeof(struct nes_vnic_mgt), GFP_KERNEL); - if (mgtvnic == NULL) { - nes_debug(NES_DBG_INIT, "Unable to allocate memory for mgt structure\n"); + if (!mgtvnic) return -ENOMEM; - } /* Allocate fragment, RQ, and CQ; Reuse CEQ based on the PCI function */ /* We are not sending from this NIC so sq is not allocated */ diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index bd69125731c1..42ab31d06ef9 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -1075,7 +1075,6 @@ static struct ib_qp *nes_create_qp(struct ib_pd *ibpd, mem = kzalloc(sizeof(*nesqp)+NES_SW_CONTEXT_ALIGN-1, GFP_KERNEL); if (!mem) { nes_free_resource(nesadapter, nesadapter->allocated_qps, qp_num); - nes_debug(NES_DBG_QP, "Unable to allocate QP\n"); return ERR_PTR(-ENOMEM); } u64nesqp = (unsigned long)mem; @@ -1475,7 +1474,6 @@ static struct ib_cq *nes_create_cq(struct ib_device *ibdev, nescq = kzalloc(sizeof(struct nes_cq), GFP_KERNEL); if (!nescq) { nes_free_resource(nesadapter, nesadapter->allocated_cqs, cq_num); - nes_debug(NES_DBG_CQ, "Unable to allocate nes_cq struct\n"); return ERR_PTR(-ENOMEM); } @@ -2408,7 +2406,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, } nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL); if (!nespbl) { - nes_debug(NES_DBG_MR, "Unable to allocate PBL\n"); ib_umem_release(region); return ERR_PTR(-ENOMEM); } @@ -2416,7 +2413,6 @@ static struct ib_mr *nes_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, if (!nesmr) { ib_umem_release(region); kfree(nespbl); - nes_debug(NES_DBG_MR, "Unable to allocate nesmr\n"); return ERR_PTR(-ENOMEM); } nesmr->region = region; -- cgit v1.2.3 From 870b2852455266996e55b3152a5ef40b45e853ec Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:20 +0200 Subject: IB/mthca: Remove debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mthca/mthca_reset.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_reset.c b/drivers/infiniband/hw/mthca/mthca_reset.c index 6727af27c017..2a6979e4ae1c 100644 --- a/drivers/infiniband/hw/mthca/mthca_reset.c +++ b/drivers/infiniband/hw/mthca/mthca_reset.c @@ -96,8 +96,6 @@ int mthca_reset(struct mthca_dev *mdev) hca_header = kmalloc(256, GFP_KERNEL); if (!hca_header) { err = -ENOMEM; - mthca_err(mdev, "Couldn't allocate memory to save HCA " - "PCI header, aborting.\n"); goto put_dev; } @@ -119,8 +117,6 @@ int mthca_reset(struct mthca_dev *mdev) bridge_header = kmalloc(256, GFP_KERNEL); if (!bridge_header) { err = -ENOMEM; - mthca_err(mdev, "Couldn't allocate memory to save HCA " - "bridge PCI header, aborting.\n"); goto free_hca; } -- cgit v1.2.3 From 02d93f8e6b8bfef8453c4dfa61220335cabbb138 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:21 +0200 Subject: IB/usninc: Remove and fix debug prints after allocation failure This patch removes unneeded prints after allocation failure and moves one debug print into the appropriate place. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c | 10 +--------- drivers/infiniband/hw/usnic/usnic_vnic.c | 22 ++++++---------------- 2 files changed, 7 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c index 5b0248adf4ce..0e813ecbcd7d 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c @@ -228,8 +228,6 @@ create_roce_custom_flow(struct usnic_ib_qp_grp *qp_grp, flow = usnic_fwd_alloc_flow(qp_grp->ufdev, &filter, &uaction); if (IS_ERR_OR_NULL(flow)) { - usnic_err("Unable to alloc flow failed with err %ld\n", - PTR_ERR(flow)); err = flow ? PTR_ERR(flow) : -EFAULT; goto out_unreserve_port; } @@ -303,8 +301,6 @@ create_udp_flow(struct usnic_ib_qp_grp *qp_grp, flow = usnic_fwd_alloc_flow(qp_grp->ufdev, &filter, &uaction); if (IS_ERR_OR_NULL(flow)) { - usnic_err("Unable to alloc flow failed with err %ld\n", - PTR_ERR(flow)); err = flow ? PTR_ERR(flow) : -EFAULT; goto out_put_sock; } @@ -694,18 +690,14 @@ usnic_ib_qp_grp_create(struct usnic_fwd_dev *ufdev, struct usnic_ib_vf *vf, } qp_grp = kzalloc(sizeof(*qp_grp), GFP_ATOMIC); - if (!qp_grp) { - usnic_err("Unable to alloc qp_grp - Out of memory\n"); + if (!qp_grp) return NULL; - } qp_grp->res_chunk_list = alloc_res_chunk_list(vf->vnic, res_spec, qp_grp); if (IS_ERR_OR_NULL(qp_grp->res_chunk_list)) { err = qp_grp->res_chunk_list ? PTR_ERR(qp_grp->res_chunk_list) : -ENOMEM; - usnic_err("Unable to alloc res for %d with err %d\n", - qp_grp->grp_id, err); goto out_free_qp_grp; } diff --git a/drivers/infiniband/hw/usnic/usnic_vnic.c b/drivers/infiniband/hw/usnic/usnic_vnic.c index 887510718690..e7b0030254da 100644 --- a/drivers/infiniband/hw/usnic/usnic_vnic.c +++ b/drivers/infiniband/hw/usnic/usnic_vnic.c @@ -241,17 +241,12 @@ usnic_vnic_get_resources(struct usnic_vnic *vnic, enum usnic_vnic_res_type type, return ERR_PTR(-EINVAL); ret = kzalloc(sizeof(*ret), GFP_ATOMIC); - if (!ret) { - usnic_err("Failed to allocate chunk for %s - Out of memory\n", - usnic_vnic_pci_name(vnic)); + if (!ret) return ERR_PTR(-ENOMEM); - } if (cnt > 0) { ret->res = kcalloc(cnt, sizeof(*(ret->res)), GFP_ATOMIC); if (!ret->res) { - usnic_err("Failed to allocate resources for %s. Out of memory\n", - usnic_vnic_pci_name(vnic)); kfree(ret); return ERR_PTR(-ENOMEM); } @@ -311,8 +306,10 @@ static int usnic_vnic_alloc_res_chunk(struct usnic_vnic *vnic, struct usnic_vnic_res *res; cnt = vnic_dev_get_res_count(vnic->vdev, _to_vnic_res_type(type)); - if (cnt < 1) + if (cnt < 1) { + usnic_err("Wrong res count with cnt %d\n", cnt); return -EINVAL; + } chunk->cnt = chunk->free_cnt = cnt; chunk->res = kzalloc(sizeof(*(chunk->res))*cnt, GFP_KERNEL); @@ -384,12 +381,8 @@ static int usnic_vnic_discover_resources(struct pci_dev *pdev, res_type < USNIC_VNIC_RES_TYPE_MAX; res_type++) { err = usnic_vnic_alloc_res_chunk(vnic, res_type, &vnic->chunks[res_type]); - if (err) { - usnic_err("Failed to alloc res %s with err %d\n", - usnic_vnic_res_type_to_str(res_type), - err); + if (err) goto out_clean_chunks; - } } return 0; @@ -454,11 +447,8 @@ struct usnic_vnic *usnic_vnic_alloc(struct pci_dev *pdev) } vnic = kzalloc(sizeof(*vnic), GFP_KERNEL); - if (!vnic) { - usnic_err("Failed to alloc vnic for %s - out of memory\n", - pci_name(pdev)); + if (!vnic) return ERR_PTR(-ENOMEM); - } spin_lock_init(&vnic->res_lock); -- cgit v1.2.3 From 740c330ee677f4e79c3865f85c6af5a5c961fe34 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:22 +0200 Subject: IB/ocrdma: Remove and fix debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 5 ++--- drivers/infiniband/hw/ocrdma/ocrdma_stats.c | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 67fc0b6857e1..12b27e7bc6a7 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -1596,10 +1596,9 @@ void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev) dev->pd_mgr = kzalloc(sizeof(struct ocrdma_pd_resource_mgr), GFP_KERNEL); - if (!dev->pd_mgr) { - pr_err("%s(%d)Memory allocation failure.\n", __func__, dev->id); + if (!dev->pd_mgr) return; - } + status = ocrdma_mbx_alloc_pd_range(dev); if (status) { pr_err("%s(%d) Unable to initialize PD pool, using default.\n", diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c index 8bef09a8c49f..f8e4b0a6486f 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c @@ -84,10 +84,8 @@ bool ocrdma_alloc_stats_resources(struct ocrdma_dev *dev) /* Alloc debugfs mem */ mem->debugfs_mem = kzalloc(OCRDMA_MAX_DBGFS_MEM, GFP_KERNEL); - if (!mem->debugfs_mem) { - pr_err("%s: stats debugfs mem allocation failed\n", __func__); + if (!mem->debugfs_mem) return false; - } return true; } -- cgit v1.2.3 From 907610bfdf1a7f3d173a9593fde70f67d63476d1 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:23 +0200 Subject: IB/rxe: Remove and fix debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_pool.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_pool.c b/drivers/infiniband/sw/rxe/rxe_pool.c index 6bac0717c540..d723947a8542 100644 --- a/drivers/infiniband/sw/rxe/rxe_pool.c +++ b/drivers/infiniband/sw/rxe/rxe_pool.c @@ -180,7 +180,6 @@ static int rxe_pool_init_index(struct rxe_pool *pool, u32 max, u32 min) size = BITS_TO_LONGS(max - min + 1) * sizeof(long); pool->table = kmalloc(size, GFP_KERNEL); if (!pool->table) { - pr_warn("no memory for bit table\n"); err = -ENOMEM; goto out; } -- cgit v1.2.3 From 93b80f29044639ce98baabd3431af9d78e9d1223 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:24 +0200 Subject: IB/isert: Remove and fix debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Acked-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/isert/ib_isert.c | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 6dd43f63238e..225cb8255563 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -184,7 +184,7 @@ isert_alloc_rx_descriptors(struct isert_conn *isert_conn) isert_conn->rx_descs = kzalloc(ISERT_QP_MAX_RECV_DTOS * sizeof(struct iser_rx_desc), GFP_KERNEL); if (!isert_conn->rx_descs) - goto fail; + return -ENOMEM; rx_desc = isert_conn->rx_descs; @@ -213,9 +213,7 @@ dma_map_fail: } kfree(isert_conn->rx_descs); isert_conn->rx_descs = NULL; -fail: isert_err("conn %p failed to allocate rx descriptors\n", isert_conn); - return -ENOMEM; } @@ -269,10 +267,8 @@ isert_alloc_comps(struct isert_device *device) device->comps = kcalloc(device->comps_used, sizeof(struct isert_comp), GFP_KERNEL); - if (!device->comps) { - isert_err("Unable to allocate completion contexts\n"); + if (!device->comps) return -ENOMEM; - } max_cqe = min(ISER_MAX_CQ_LEN, device->ib_device->attrs.max_cqe); @@ -432,10 +428,8 @@ isert_alloc_login_buf(struct isert_conn *isert_conn, isert_conn->login_req_buf = kzalloc(sizeof(*isert_conn->login_req_buf), GFP_KERNEL); - if (!isert_conn->login_req_buf) { - isert_err("Unable to allocate isert_conn->login_buf\n"); + if (!isert_conn->login_req_buf) return -ENOMEM; - } isert_conn->login_req_dma = ib_dma_map_single(ib_dev, isert_conn->login_req_buf, @@ -1276,11 +1270,8 @@ isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd if (payload_length) { text_in = kzalloc(payload_length, GFP_KERNEL); - if (!text_in) { - isert_err("Unable to allocate text_in of payload_length: %u\n", - payload_length); + if (!text_in) return -ENOMEM; - } } cmd->text_in_ptr = text_in; @@ -2307,10 +2298,9 @@ isert_setup_np(struct iscsi_np *np, int ret; isert_np = kzalloc(sizeof(struct isert_np), GFP_KERNEL); - if (!isert_np) { - isert_err("Unable to allocate struct isert_np\n"); + if (!isert_np) return -ENOMEM; - } + sema_init(&isert_np->sem, 0); mutex_init(&isert_np->mutex); INIT_LIST_HEAD(&isert_np->accepted); @@ -2651,7 +2641,6 @@ static int __init isert_init(void) WQ_UNBOUND | WQ_HIGHPRI, 0); if (!isert_comp_wq) { isert_err("Unable to allocate isert_comp_wq\n"); - ret = -ENOMEM; return -ENOMEM; } -- cgit v1.2.3 From 74226649f42d34a8ade2799bfb4f3941f4adfa95 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Thu, 3 Nov 2016 16:44:25 +0200 Subject: IB/ipoib: Remove and fix debug prints after allocation failure The prints after [k|v][m|z|c]alloc() functions are not needed, because in case of failure, allocator will print their internal error prints anyway. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib_cm.c | 8 +------- drivers/infiniband/ulp/ipoib/ipoib_ib.c | 5 +---- drivers/infiniband/ulp/ipoib/ipoib_main.c | 5 +---- 3 files changed, 3 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 4ad297d3de89..44f152e431cb 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -355,11 +355,8 @@ static int ipoib_cm_nonsrq_init_rx(struct net_device *dev, struct ib_cm_id *cm_i int i; rx->rx_ring = vzalloc(ipoib_recvq_size * sizeof *rx->rx_ring); - if (!rx->rx_ring) { - printk(KERN_WARNING "%s: failed to allocate CM non-SRQ ring (%d entries)\n", - priv->ca->name, ipoib_recvq_size); + if (!rx->rx_ring) return -ENOMEM; - } t = kmalloc(sizeof *t, GFP_KERNEL); if (!t) { @@ -1133,7 +1130,6 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, p->tx_ring = __vmalloc(ipoib_sendq_size * sizeof *p->tx_ring, GFP_NOIO, PAGE_KERNEL); if (!p->tx_ring) { - ipoib_warn(priv, "failed to allocate tx ring\n"); ret = -ENOMEM; goto err_tx; } @@ -1549,8 +1545,6 @@ static void ipoib_cm_create_srq(struct net_device *dev, int max_sge) priv->cm.srq_ring = vzalloc(ipoib_recvq_size * sizeof *priv->cm.srq_ring); if (!priv->cm.srq_ring) { - printk(KERN_WARNING "%s: failed to allocate CM SRQ ring (%d entries)\n", - priv->ca->name, ipoib_recvq_size); ib_destroy_srq(priv->cm.srq); priv->cm.srq = NULL; return; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index be11d5d5b8c1..43cf8b8a8d2e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -418,11 +418,8 @@ static void ipoib_ib_handle_tx_wc(struct net_device *dev, struct ib_wc *wc) "(status=%d, wrid=%d vend_err %x)\n", wc->status, wr_id, wc->vendor_err); qp_work = kzalloc(sizeof(*qp_work), GFP_ATOMIC); - if (!qp_work) { - ipoib_warn(priv, "%s Failed alloc ipoib_qp_state_validate for qp: 0x%x\n", - __func__, priv->qp->qp_num); + if (!qp_work) return; - } INIT_WORK(&qp_work->work, ipoib_qp_state_validate_work); qp_work->priv = priv; diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 5636fc3da6b8..423b30dfe2d8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -1594,11 +1594,8 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port) /* Allocate RX/TX "rings" to hold queued skbs */ priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring, GFP_KERNEL); - if (!priv->rx_ring) { - printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n", - ca->name, ipoib_recvq_size); + if (!priv->rx_ring) goto out; - } priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring); if (!priv->tx_ring) { -- cgit v1.2.3 From f73a1dbc45a58ea3ae5c3d60c71e58a8a9563914 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 21 Nov 2016 19:38:20 +0200 Subject: infiniband: remove WARN that is not kernel bug On Mon, Nov 21, 2016 at 09:52:53AM -0700, Jason Gunthorpe wrote: > On Mon, Nov 21, 2016 at 02:14:08PM +0200, Leon Romanovsky wrote: > > > > > > In ib_ucm_write function there is a wrong prefix: > > > > > > + pr_err_once("ucm_write: process %d (%s) tried to do something hinky\n", > > > > I did it intentionally to have the same errors for all flows. > > Lets actually use a good message too please? > > pr_err_once("ucm_write: process %d (%s) changed security contexts after opening FD, this is not allowed.\n", > > Jason >From 70f95b2d35aea42e5b97e7d27ab2f4e8effcbe67 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Mon, 21 Nov 2016 13:30:59 +0200 Subject: [PATCH rdma-next V2] IB/{core, qib}: Remove WARN that is not kernel bug WARNINGs mean kernel bugs, in this case, they are placed to mark programming errors and/or malicious attempts. BUG/WARNs that are not kernel bugs hinder automated testing efforts. Signed-off-by: Dmitry Vyukov Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/ucm.c | 5 ++++- drivers/infiniband/core/ucma.c | 5 ++++- drivers/infiniband/core/uverbs_main.c | 5 ++++- drivers/infiniband/hw/qib/qib_file_ops.c | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 7713ef089c3c..579f9a7f6283 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -1104,8 +1104,11 @@ static ssize_t ib_ucm_write(struct file *filp, const char __user *buf, struct ib_ucm_cmd_hdr hdr; ssize_t result; - if (WARN_ON_ONCE(!ib_safe_file_access(filp))) + if (!ib_safe_file_access(filp)) { + pr_err_once("ucm_write: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", + task_tgid_vnr(current), current->comm); return -EACCES; + } if (len < sizeof(hdr)) return -EINVAL; diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c index 9520154f1d7c..e12f8faf8c23 100644 --- a/drivers/infiniband/core/ucma.c +++ b/drivers/infiniband/core/ucma.c @@ -1584,8 +1584,11 @@ static ssize_t ucma_write(struct file *filp, const char __user *buf, struct rdma_ucm_cmd_hdr hdr; ssize_t ret; - if (WARN_ON_ONCE(!ib_safe_file_access(filp))) + if (!ib_safe_file_access(filp)) { + pr_err_once("ucma_write: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", + task_tgid_vnr(current), current->comm); return -EACCES; + } if (len < sizeof(hdr)) return -EINVAL; diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 0012fa58c105..3efec031c253 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -749,8 +749,11 @@ static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf, int srcu_key; ssize_t ret; - if (WARN_ON_ONCE(!ib_safe_file_access(filp))) + if (!ib_safe_file_access(filp)) { + pr_err_once("uverbs_write: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", + task_tgid_vnr(current), current->comm); return -EACCES; + } if (count < sizeof hdr) return -EINVAL; diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c index 382466a90da7..2d1eacf1dfed 100644 --- a/drivers/infiniband/hw/qib/qib_file_ops.c +++ b/drivers/infiniband/hw/qib/qib_file_ops.c @@ -2066,8 +2066,11 @@ static ssize_t qib_write(struct file *fp, const char __user *data, ssize_t ret = 0; void *dest; - if (WARN_ON_ONCE(!ib_safe_file_access(fp))) + if (!ib_safe_file_access(fp)) { + pr_err_once("qib_write: process %d (%s) changed security contexts after opening file descriptor, this is not allowed.\n", + task_tgid_vnr(current), current->comm); return -EACCES; + } if (count < sizeof(cmd.type)) { ret = -EINVAL; -- cgit v1.2.3 From 9eefa953f475897636f9290d833e45009d58a55d Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 23 Nov 2016 19:40:59 +0000 Subject: IB/hns: Add the interface for querying QP1 In old code, It only added the interface for querying non-specific QP. This patch mainly adds an interface for querying QP1. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 83 +++++++++++++++++++++++++++++- drivers/infiniband/hw/hns/hns_roce_hw_v1.h | 6 ++- 2 files changed, 86 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 71232e5fabf6..7f2c26bd6232 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2630,8 +2630,78 @@ static int hns_roce_v1_query_qpc(struct hns_roce_dev *hr_dev, return ret; } -int hns_roce_v1_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, - int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr) +static int hns_roce_v1_q_sqp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); + struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); + struct hns_roce_sqp_context context; + u32 addr; + + mutex_lock(&hr_qp->mutex); + + if (hr_qp->state == IB_QPS_RESET) { + qp_attr->qp_state = IB_QPS_RESET; + goto done; + } + + addr = ROCEE_QP1C_CFG0_0_REG + + hr_qp->port * sizeof(struct hns_roce_sqp_context); + context.qp1c_bytes_4 = roce_read(hr_dev, addr); + context.sq_rq_bt_l = roce_read(hr_dev, addr + 1); + context.qp1c_bytes_12 = roce_read(hr_dev, addr + 2); + context.qp1c_bytes_16 = roce_read(hr_dev, addr + 3); + context.qp1c_bytes_20 = roce_read(hr_dev, addr + 4); + context.cur_rq_wqe_ba_l = roce_read(hr_dev, addr + 5); + context.qp1c_bytes_28 = roce_read(hr_dev, addr + 6); + context.qp1c_bytes_32 = roce_read(hr_dev, addr + 7); + context.cur_sq_wqe_ba_l = roce_read(hr_dev, addr + 8); + context.qp1c_bytes_40 = roce_read(hr_dev, addr + 9); + + hr_qp->state = roce_get_field(context.qp1c_bytes_4, + QP1C_BYTES_4_QP_STATE_M, + QP1C_BYTES_4_QP_STATE_S); + qp_attr->qp_state = hr_qp->state; + qp_attr->path_mtu = IB_MTU_256; + qp_attr->path_mig_state = IB_MIG_ARMED; + qp_attr->qkey = QKEY_VAL; + qp_attr->rq_psn = 0; + qp_attr->sq_psn = 0; + qp_attr->dest_qp_num = 1; + qp_attr->qp_access_flags = 6; + + qp_attr->pkey_index = roce_get_field(context.qp1c_bytes_20, + QP1C_BYTES_20_PKEY_IDX_M, + QP1C_BYTES_20_PKEY_IDX_S); + qp_attr->port_num = hr_qp->port + 1; + qp_attr->sq_draining = 0; + qp_attr->max_rd_atomic = 0; + qp_attr->max_dest_rd_atomic = 0; + qp_attr->min_rnr_timer = 0; + qp_attr->timeout = 0; + qp_attr->retry_cnt = 0; + qp_attr->rnr_retry = 0; + qp_attr->alt_timeout = 0; + +done: + qp_attr->cur_qp_state = qp_attr->qp_state; + qp_attr->cap.max_recv_wr = hr_qp->rq.wqe_cnt; + qp_attr->cap.max_recv_sge = hr_qp->rq.max_gs; + qp_attr->cap.max_send_wr = hr_qp->sq.wqe_cnt; + qp_attr->cap.max_send_sge = hr_qp->sq.max_gs; + qp_attr->cap.max_inline_data = 0; + qp_init_attr->cap = qp_attr->cap; + qp_init_attr->create_flags = 0; + + mutex_unlock(&hr_qp->mutex); + + return 0; +} + +static int hns_roce_v1_q_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, + int qp_attr_mask, + struct ib_qp_init_attr *qp_init_attr) { struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); @@ -2767,6 +2837,15 @@ out: return ret; } +int hns_roce_v1_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, + int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr) +{ + struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); + + return hr_qp->doorbell_qpn <= 1 ? + hns_roce_v1_q_sqp(ibqp, qp_attr, qp_attr_mask, qp_init_attr) : + hns_roce_v1_q_qp(ibqp, qp_attr, qp_attr_mask, qp_init_attr); +} static void hns_roce_v1_destroy_qp_common(struct hns_roce_dev *hr_dev, struct hns_roce_qp *hr_qp, int is_user) diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h index 539b0a3b92b0..2e1878bf4836 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h @@ -480,13 +480,17 @@ struct hns_roce_sqp_context { u32 qp1c_bytes_12; u32 qp1c_bytes_16; u32 qp1c_bytes_20; - u32 qp1c_bytes_28; u32 cur_rq_wqe_ba_l; + u32 qp1c_bytes_28; u32 qp1c_bytes_32; u32 cur_sq_wqe_ba_l; u32 qp1c_bytes_40; }; +#define QP1C_BYTES_4_QP_STATE_S 0 +#define QP1C_BYTES_4_QP_STATE_M \ + (((1UL << 3) - 1) << QP1C_BYTES_4_QP_STATE_S) + #define QP1C_BYTES_4_SQ_WQE_SHIFT_S 8 #define QP1C_BYTES_4_SQ_WQE_SHIFT_M \ (((1UL << 4) - 1) << QP1C_BYTES_4_SQ_WQE_SHIFT_S) -- cgit v1.2.3 From 8f3e9f3ea0871a988ec9540a4cde48a20c1cb98b Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Wed, 23 Nov 2016 19:41:00 +0000 Subject: IB/hns: Add code for refreshing CQ CI using TPTR This patch added the code for refreshing CQ CI using TPTR in hip06 SoC. We will send a doorbell to hardware for refreshing CQ CI when user succeed to poll a cqe. But it will be failed if the doorbell has been blocked. So hardware will read a special buffer called TPTR to get the lastest CI value when the cq is almost full. This patch support the special CI buffer as follows: a) Alloc the memory for TPTR in the hns_roce_tptr_init function and free it in hns_roce_tptr_free function, these two functions will be called in probe function and in the remove function. b) Add the code for computing offset(every cq need 2 bytes) and write the dma addr to every cq context to notice hardware in the function named hns_roce_v1_write_cqc. c) Add code for mapping TPTR buffer to user space in function named hns_roce_mmap. The mapping distinguish TPTR and UAR of user mode by vm_pgoff(0: UAR, 1: TPTR, others:invaild) in hip06. d) Alloc the code for refreshing CQ CI using TPTR in the function named hns_roce_v1_poll_cq. e) Add some variable definitions to the related structure. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Dongdong Huang(Donald) Signed-off-by: Lijun Ou Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_common.h | 2 - drivers/infiniband/hw/hns/hns_roce_cq.c | 9 ++++ drivers/infiniband/hw/hns/hns_roce_device.h | 6 ++- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 79 +++++++++++++++++++++++++---- drivers/infiniband/hw/hns/hns_roce_hw_v1.h | 9 ++++ drivers/infiniband/hw/hns/hns_roce_main.c | 13 +++-- 6 files changed, 103 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_common.h b/drivers/infiniband/hw/hns/hns_roce_common.h index 297016103aa7..0dcb620e91dd 100644 --- a/drivers/infiniband/hw/hns/hns_roce_common.h +++ b/drivers/infiniband/hw/hns/hns_roce_common.h @@ -253,8 +253,6 @@ #define ROCEE_VENDOR_ID_REG 0x0 #define ROCEE_VENDOR_PART_ID_REG 0x4 -#define ROCEE_HW_VERSION_REG 0x8 - #define ROCEE_SYS_IMAGE_GUID_L_REG 0xC #define ROCEE_SYS_IMAGE_GUID_H_REG 0x10 diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 097365932b09..5dc8d92e79fd 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -349,6 +349,15 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, goto err_mtt; } + /* + * For the QP created by kernel space, tptr value should be initialized + * to zero; For the QP created by user space, it will cause synchronous + * problems if tptr is set to zero here, so we initialze it in user + * space. + */ + if (!context) + *hr_cq->tptr_addr = 0; + /* Get created cq handler and carry out event */ hr_cq->comp = hns_roce_ib_cq_comp; hr_cq->event = hns_roce_ib_cq_event; diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 341731553a60..7242b1438873 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -37,6 +37,8 @@ #define DRV_NAME "hns_roce" +#define HNS_ROCE_HW_VER1 ('h' << 24 | 'i' << 16 | '0' << 8 | '6') + #define MAC_ADDR_OCTET_NUM 6 #define HNS_ROCE_MAX_MSG_LEN 0x80000000 @@ -296,7 +298,7 @@ struct hns_roce_cq { u32 cq_depth; u32 cons_index; void __iomem *cq_db_l; - void __iomem *tptr_addr; + u16 *tptr_addr; unsigned long cqn; u32 vector; atomic_t refcount; @@ -553,6 +555,8 @@ struct hns_roce_dev { int cmd_mod; int loop_idc; + dma_addr_t tptr_dma_addr; /*only for hw v1*/ + u32 tptr_size; /*only for hw v1*/ struct hns_roce_hw *hw; }; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 7f2c26bd6232..957f0de866cd 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -849,6 +849,45 @@ static void hns_roce_bt_free(struct hns_roce_dev *hr_dev) priv->bt_table.qpc_buf.buf, priv->bt_table.qpc_buf.map); } +static int hns_roce_tptr_init(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_buf_list *tptr_buf; + struct hns_roce_v1_priv *priv; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + tptr_buf = &priv->tptr_table.tptr_buf; + + /* + * This buffer will be used for CQ's tptr(tail pointer), also + * named ci(customer index). Every CQ will use 2 bytes to save + * cqe ci in hip06. Hardware will read this area to get new ci + * when the queue is almost full. + */ + tptr_buf->buf = dma_alloc_coherent(dev, HNS_ROCE_V1_TPTR_BUF_SIZE, + &tptr_buf->map, GFP_KERNEL); + if (!tptr_buf->buf) + return -ENOMEM; + + hr_dev->tptr_dma_addr = tptr_buf->map; + hr_dev->tptr_size = HNS_ROCE_V1_TPTR_BUF_SIZE; + + return 0; +} + +static void hns_roce_tptr_free(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_buf_list *tptr_buf; + struct hns_roce_v1_priv *priv; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + tptr_buf = &priv->tptr_table.tptr_buf; + + dma_free_coherent(dev, HNS_ROCE_V1_TPTR_BUF_SIZE, + tptr_buf->buf, tptr_buf->map); +} + /** * hns_roce_v1_reset - reset RoCE * @hr_dev: RoCE device struct pointer @@ -906,12 +945,11 @@ void hns_roce_v1_profile(struct hns_roce_dev *hr_dev) hr_dev->vendor_id = le32_to_cpu(roce_read(hr_dev, ROCEE_VENDOR_ID_REG)); hr_dev->vendor_part_id = le32_to_cpu(roce_read(hr_dev, ROCEE_VENDOR_PART_ID_REG)); - hr_dev->hw_rev = le32_to_cpu(roce_read(hr_dev, ROCEE_HW_VERSION_REG)); - hr_dev->sys_image_guid = le32_to_cpu(roce_read(hr_dev, ROCEE_SYS_IMAGE_GUID_L_REG)) | ((u64)le32_to_cpu(roce_read(hr_dev, ROCEE_SYS_IMAGE_GUID_H_REG)) << 32); + hr_dev->hw_rev = HNS_ROCE_HW_VER1; caps->num_qps = HNS_ROCE_V1_MAX_QP_NUM; caps->max_wqes = HNS_ROCE_V1_MAX_WQE_NUM; @@ -1009,8 +1047,17 @@ int hns_roce_v1_init(struct hns_roce_dev *hr_dev) goto error_failed_bt_init; } + ret = hns_roce_tptr_init(hr_dev); + if (ret) { + dev_err(dev, "tptr init failed!\n"); + goto error_failed_tptr_init; + } + return 0; +error_failed_tptr_init: + hns_roce_bt_free(hr_dev); + error_failed_bt_init: hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); hns_roce_raq_free(hr_dev); @@ -1022,6 +1069,7 @@ error_failed_raq_init: void hns_roce_v1_exit(struct hns_roce_dev *hr_dev) { + hns_roce_tptr_free(hr_dev); hns_roce_bt_free(hr_dev); hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); hns_roce_raq_free(hr_dev); @@ -1339,14 +1387,21 @@ void hns_roce_v1_write_cqc(struct hns_roce_dev *hr_dev, dma_addr_t dma_handle, int nent, u32 vector) { struct hns_roce_cq_context *cq_context = NULL; - void __iomem *tptr_addr; + struct hns_roce_buf_list *tptr_buf; + struct hns_roce_v1_priv *priv; + dma_addr_t tptr_dma_addr; + int offset; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + tptr_buf = &priv->tptr_table.tptr_buf; cq_context = mb_buf; memset(cq_context, 0, sizeof(*cq_context)); - tptr_addr = 0; - hr_dev->priv_addr = tptr_addr; - hr_cq->tptr_addr = tptr_addr; + /* Get the tptr for this CQ. */ + offset = hr_cq->cqn * HNS_ROCE_V1_TPTR_ENTRY_SIZE; + tptr_dma_addr = tptr_buf->map + offset; + hr_cq->tptr_addr = (u16 *)(tptr_buf->buf + offset); /* Register cq_context members */ roce_set_field(cq_context->cqc_byte_4, @@ -1390,10 +1445,10 @@ void hns_roce_v1_write_cqc(struct hns_roce_dev *hr_dev, roce_set_field(cq_context->cqc_byte_20, CQ_CONTEXT_CQC_BYTE_20_CQE_TPTR_ADDR_H_M, CQ_CONTEXT_CQC_BYTE_20_CQE_TPTR_ADDR_H_S, - (u64)tptr_addr >> 44); + tptr_dma_addr >> 44); cq_context->cqc_byte_20 = cpu_to_le32(cq_context->cqc_byte_20); - cq_context->cqe_tptr_addr_l = (u32)((u64)tptr_addr >> 12); + cq_context->cqe_tptr_addr_l = (u32)(tptr_dma_addr >> 12); roce_set_field(cq_context->cqc_byte_32, CQ_CONTEXT_CQC_BYTE_32_CUR_CQE_BA1_H_M, @@ -1659,8 +1714,14 @@ int hns_roce_v1_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) break; } - if (npolled) + if (npolled) { + *hr_cq->tptr_addr = hr_cq->cons_index & + ((hr_cq->cq_depth << 1) - 1); + + /* Memroy barrier */ + wmb(); hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index); + } spin_unlock_irqrestore(&hr_cq->lock, flags); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h index 2e1878bf4836..6004c7f39542 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h @@ -104,6 +104,10 @@ #define HNS_ROCE_BT_RSV_BUF_SIZE (1 << 17) +#define HNS_ROCE_V1_TPTR_ENTRY_SIZE 2 +#define HNS_ROCE_V1_TPTR_BUF_SIZE \ + (HNS_ROCE_V1_TPTR_ENTRY_SIZE * HNS_ROCE_V1_MAX_CQ_NUM) + #define HNS_ROCE_ODB_POLL_MODE 0 #define HNS_ROCE_SDB_NORMAL_MODE 0 @@ -983,10 +987,15 @@ struct hns_roce_bt_table { struct hns_roce_buf_list cqc_buf; }; +struct hns_roce_tptr_table { + struct hns_roce_buf_list tptr_buf; +}; + struct hns_roce_v1_priv { struct hns_roce_db_table db_table; struct hns_roce_raq_table raq_table; struct hns_roce_bt_table bt_table; + struct hns_roce_tptr_table tptr_table; }; int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset); diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 764e35a54457..67701719bad1 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -549,6 +549,8 @@ static int hns_roce_dealloc_ucontext(struct ib_ucontext *ibcontext) static int hns_roce_mmap(struct ib_ucontext *context, struct vm_area_struct *vma) { + struct hns_roce_dev *hr_dev = to_hr_dev(context->device); + if (((vma->vm_end - vma->vm_start) % PAGE_SIZE) != 0) return -EINVAL; @@ -558,10 +560,15 @@ static int hns_roce_mmap(struct ib_ucontext *context, to_hr_ucontext(context)->uar.pfn, PAGE_SIZE, vma->vm_page_prot)) return -EAGAIN; - - } else { + } else if (vma->vm_pgoff == 1 && hr_dev->hw_rev == HNS_ROCE_HW_VER1) { + /* vm_pgoff: 1 -- TPTR */ + if (io_remap_pfn_range(vma, vma->vm_start, + hr_dev->tptr_dma_addr >> PAGE_SHIFT, + hr_dev->tptr_size, + vma->vm_page_prot)) + return -EAGAIN; + } else return -EINVAL; - } return 0; } -- cgit v1.2.3 From 8d497eb0f325e98fa87b59ac86069deea64e8d5d Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Wed, 23 Nov 2016 19:41:01 +0000 Subject: IB/hns: Optimize the logic of allocating memory using APIs This patch modified the logic of allocating memory using APIs in hns RoCE driver. We used kcalloc instead of kmalloc_array and bitmap_zero. And When kcalloc failed, call vzalloc to alloc memory. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Ping Zhang Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_mr.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index fb87883ead34..d87d189cb3d8 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -137,11 +137,13 @@ static int hns_roce_buddy_init(struct hns_roce_buddy *buddy, int max_order) for (i = 0; i <= buddy->max_order; ++i) { s = BITS_TO_LONGS(1 << (buddy->max_order - i)); - buddy->bits[i] = kmalloc_array(s, sizeof(long), GFP_KERNEL); - if (!buddy->bits[i]) - goto err_out_free; - - bitmap_zero(buddy->bits[i], 1 << (buddy->max_order - i)); + buddy->bits[i] = kcalloc(s, sizeof(long), GFP_KERNEL | + __GFP_NOWARN); + if (!buddy->bits[i]) { + buddy->bits[i] = vzalloc(s * sizeof(long)); + if (!buddy->bits[i]) + goto err_out_free; + } } set_bit(0, buddy->bits[buddy->max_order]); @@ -151,7 +153,7 @@ static int hns_roce_buddy_init(struct hns_roce_buddy *buddy, int max_order) err_out_free: for (i = 0; i <= buddy->max_order; ++i) - kfree(buddy->bits[i]); + kvfree(buddy->bits[i]); err_out: kfree(buddy->bits); @@ -164,7 +166,7 @@ static void hns_roce_buddy_cleanup(struct hns_roce_buddy *buddy) int i; for (i = 0; i <= buddy->max_order; ++i) - kfree(buddy->bits[i]); + kvfree(buddy->bits[i]); kfree(buddy->bits); kfree(buddy->num_free); -- cgit v1.2.3 From 543bfe6c3c1602d1781504047795a4266076233b Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 23 Nov 2016 19:41:02 +0000 Subject: IB/hns: add self loopback for CM This patch mainly adds self loopback support for CM. Signed-off-by: Lijun Ou Signed-off-by: Peter Chen Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 11 +++++++++++ drivers/infiniband/hw/hns/hns_roce_hw_v1.h | 2 ++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 957f0de866cd..48c71e839c6a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -32,6 +32,7 @@ #include #include +#include #include #include "hns_roce_common.h" #include "hns_roce_device.h" @@ -72,6 +73,8 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, int nreq = 0; u32 ind = 0; int ret = 0; + u8 *smac; + int loopback; if (unlikely(ibqp->qp_type != IB_QPT_GSI && ibqp->qp_type != IB_QPT_RC)) { @@ -129,6 +132,14 @@ int hns_roce_v1_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, UD_SEND_WQE_U32_8_DMAC_5_M, UD_SEND_WQE_U32_8_DMAC_5_S, ah->av.mac[5]); + + smac = (u8 *)hr_dev->dev_addr[qp->port]; + loopback = ether_addr_equal_unaligned(ah->av.mac, + smac) ? 1 : 0; + roce_set_bit(ud_sq_wqe->u32_8, + UD_SEND_WQE_U32_8_LOOPBACK_INDICATOR_S, + loopback); + roce_set_field(ud_sq_wqe->u32_8, UD_SEND_WQE_U32_8_OPERATION_TYPE_M, UD_SEND_WQE_U32_8_OPERATION_TYPE_S, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h index 6004c7f39542..cf28f1b6492c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h @@ -440,6 +440,8 @@ struct hns_roce_ud_send_wqe { #define UD_SEND_WQE_U32_8_DMAC_5_M \ (((1UL << 8) - 1) << UD_SEND_WQE_U32_8_DMAC_5_S) +#define UD_SEND_WQE_U32_8_LOOPBACK_INDICATOR_S 22 + #define UD_SEND_WQE_U32_8_OPERATION_TYPE_S 16 #define UD_SEND_WQE_U32_8_OPERATION_TYPE_M \ (((1UL << 4) - 1) << UD_SEND_WQE_U32_8_OPERATION_TYPE_S) -- cgit v1.2.3 From 80596c6717a7b0e9969ffbd03c7e1dd33112f7e9 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 23 Nov 2016 19:41:03 +0000 Subject: IB/hns: Modify the condition of notifying hardware loopback This patch modified the condition of notifying hardware loopback. In hip06, RoCE Engine has several ports, one QP is related to one port. hardware only support loopback in the same port, not in the different ports. So, If QP related to port N, the dmac in the QP context equals the smac of the local port N or the loop_idc is 1, we should set loopback bit in QP context to notify hardware. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Lijun Ou Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 48c71e839c6a..c1a9dac25d7b 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2244,24 +2244,14 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, QP_CONTEXT_QPC_BYTE_32_SIGNALING_TYPE_S, hr_qp->sq_signal_bits); - for (port = 0; port < hr_dev->caps.num_ports; port++) { - smac = (u8 *)hr_dev->dev_addr[port]; - dev_dbg(dev, "smac: %2x: %2x: %2x: %2x: %2x: %2x\n", - smac[0], smac[1], smac[2], smac[3], smac[4], - smac[5]); - if ((dmac[0] == smac[0]) && (dmac[1] == smac[1]) && - (dmac[2] == smac[2]) && (dmac[3] == smac[3]) && - (dmac[4] == smac[4]) && (dmac[5] == smac[5])) { - roce_set_bit(context->qpc_bytes_32, - QP_CONTEXT_QPC_BYTE_32_LOOPBACK_INDICATOR_S, - 1); - break; - } - } - - if (hr_dev->loop_idc == 0x1) + port = (attr_mask & IB_QP_PORT) ? (attr->port_num - 1) : + hr_qp->port; + smac = (u8 *)hr_dev->dev_addr[port]; + /* when dmac equals smac or loop_idc is 1, it should loopback */ + if (ether_addr_equal_unaligned(dmac, smac) || + hr_dev->loop_idc == 0x1) roce_set_bit(context->qpc_bytes_32, - QP_CONTEXT_QPC_BYTE_32_LOOPBACK_INDICATOR_S, 1); + QP_CONTEXT_QPC_BYTE_32_LOOPBACK_INDICATOR_S, 1); roce_set_bit(context->qpc_bytes_32, QP_CONTEXT_QPC_BYTE_32_GLOBAL_HEADER_S, -- cgit v1.2.3 From 1dec243ac00c6e10217c994c5a500bc85fe0f649 Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Wed, 23 Nov 2016 19:41:04 +0000 Subject: IB/hns: Fix the bug for qp state in hns_roce_v1_m_qp() In old code, the value of qp state from qpc was assigned for attr->qp_state. The value may be an error while attr_mask & IB_QP_STATE is zero. Signed-off-by: Lijun Ou Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index c1a9dac25d7b..528cb84975b4 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2571,7 +2571,7 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, /* Every status migrate must change state */ roce_set_field(context->qpc_bytes_144, QP_CONTEXT_QPC_BYTES_144_QP_STATE_M, - QP_CONTEXT_QPC_BYTES_144_QP_STATE_S, attr->qp_state); + QP_CONTEXT_QPC_BYTES_144_QP_STATE_S, new_state); /* SW pass context to HW */ ret = hns_roce_v1_qp_modify(hr_dev, &hr_qp->mtt, -- cgit v1.2.3 From 6b877c32bc40bfa9fa13659ac4e1413b67ff1c3d Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Wed, 23 Nov 2016 19:41:05 +0000 Subject: IB/hns: Modify the macro for the timeout when cmd process This patch modified the macro for the timeout when cmd is processing as follows: Before modification: enum { HNS_ROCE_CMD_TIME_CLASS_A = 10000, HNS_ROCE_CMD_TIME_CLASS_B = 10000, HNS_ROCE_CMD_TIME_CLASS_C = 10000, }; After modification: #define HNS_ROCE_CMD_TIMEOUT_MSECS 10000 Signed-off-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cmd.h | 7 +------ drivers/infiniband/hw/hns/hns_roce_cq.c | 4 ++-- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 8 ++++---- drivers/infiniband/hw/hns/hns_roce_mr.c | 4 ++-- 4 files changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.h b/drivers/infiniband/hw/hns/hns_roce_cmd.h index e3997d312c55..ed14ad3d06ef 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cmd.h +++ b/drivers/infiniband/hw/hns/hns_roce_cmd.h @@ -34,6 +34,7 @@ #define _HNS_ROCE_CMD_H #define HNS_ROCE_MAILBOX_SIZE 4096 +#define HNS_ROCE_CMD_TIMEOUT_MSECS 10000 enum { /* TPT commands */ @@ -57,12 +58,6 @@ enum { HNS_ROCE_CMD_QUERY_QP = 0x22, }; -enum { - HNS_ROCE_CMD_TIME_CLASS_A = 10000, - HNS_ROCE_CMD_TIME_CLASS_B = 10000, - HNS_ROCE_CMD_TIME_CLASS_C = 10000, -}; - struct hns_roce_cmd_mailbox { void *buf; dma_addr_t dma; diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 5dc8d92e79fd..461a27330e83 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -77,7 +77,7 @@ static int hns_roce_sw2hw_cq(struct hns_roce_dev *dev, unsigned long cq_num) { return hns_roce_cmd_mbox(dev, mailbox->dma, 0, cq_num, 0, - HNS_ROCE_CMD_SW2HW_CQ, HNS_ROCE_CMD_TIME_CLASS_A); + HNS_ROCE_CMD_SW2HW_CQ, HNS_ROCE_CMD_TIMEOUT_MSECS); } static int hns_roce_cq_alloc(struct hns_roce_dev *hr_dev, int nent, @@ -176,7 +176,7 @@ static int hns_roce_hw2sw_cq(struct hns_roce_dev *dev, { return hns_roce_cmd_mbox(dev, 0, mailbox ? mailbox->dma : 0, cq_num, mailbox ? 0 : 1, HNS_ROCE_CMD_HW2SW_CQ, - HNS_ROCE_CMD_TIME_CLASS_A); + HNS_ROCE_CMD_TIMEOUT_MSECS); } static void hns_roce_free_cq(struct hns_roce_dev *hr_dev, diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 528cb84975b4..f7e0fdf33bb1 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1871,12 +1871,12 @@ static int hns_roce_v1_qp_modify(struct hns_roce_dev *hr_dev, if (op[cur_state][new_state] == HNS_ROCE_CMD_2RST_QP) return hns_roce_cmd_mbox(hr_dev, 0, 0, hr_qp->qpn, 2, HNS_ROCE_CMD_2RST_QP, - HNS_ROCE_CMD_TIME_CLASS_A); + HNS_ROCE_CMD_TIMEOUT_MSECS); if (op[cur_state][new_state] == HNS_ROCE_CMD_2ERR_QP) return hns_roce_cmd_mbox(hr_dev, 0, 0, hr_qp->qpn, 2, HNS_ROCE_CMD_2ERR_QP, - HNS_ROCE_CMD_TIME_CLASS_A); + HNS_ROCE_CMD_TIMEOUT_MSECS); mailbox = hns_roce_alloc_cmd_mailbox(hr_dev); if (IS_ERR(mailbox)) @@ -1886,7 +1886,7 @@ static int hns_roce_v1_qp_modify(struct hns_roce_dev *hr_dev, ret = hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, hr_qp->qpn, 0, op[cur_state][new_state], - HNS_ROCE_CMD_TIME_CLASS_C); + HNS_ROCE_CMD_TIMEOUT_MSECS); hns_roce_free_cmd_mailbox(hr_dev, mailbox); return ret; @@ -2681,7 +2681,7 @@ static int hns_roce_v1_query_qpc(struct hns_roce_dev *hr_dev, ret = hns_roce_cmd_mbox(hr_dev, 0, mailbox->dma, hr_qp->qpn, 0, HNS_ROCE_CMD_QUERY_QP, - HNS_ROCE_CMD_TIME_CLASS_A); + HNS_ROCE_CMD_TIMEOUT_MSECS); if (!ret) memcpy(hr_context, mailbox->buf, sizeof(*hr_context)); else diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index d87d189cb3d8..a5bd64586848 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -53,7 +53,7 @@ static int hns_roce_sw2hw_mpt(struct hns_roce_dev *hr_dev, { return hns_roce_cmd_mbox(hr_dev, mailbox->dma, 0, mpt_index, 0, HNS_ROCE_CMD_SW2HW_MPT, - HNS_ROCE_CMD_TIME_CLASS_B); + HNS_ROCE_CMD_TIMEOUT_MSECS); } static int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev, @@ -62,7 +62,7 @@ static int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev, { return hns_roce_cmd_mbox(hr_dev, 0, mailbox ? mailbox->dma : 0, mpt_index, !mailbox, HNS_ROCE_CMD_HW2SW_MPT, - HNS_ROCE_CMD_TIME_CLASS_B); + HNS_ROCE_CMD_TIMEOUT_MSECS); } static int hns_roce_buddy_alloc(struct hns_roce_buddy *buddy, int order, -- cgit v1.2.3 From dd783a212c023b309e91ab9752c07e22f759461e Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Wed, 23 Nov 2016 19:41:06 +0000 Subject: IB/hns: Modify query info named port_num when querying RC QP This patch modified the output query info qp_attr->port_num to fix bug in hip06. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index f7e0fdf33bb1..cc64230d44c0 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -2857,9 +2857,7 @@ static int hns_roce_v1_q_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, qp_attr->pkey_index = roce_get_field(context->qpc_bytes_12, QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_M, QP_CONTEXT_QPC_BYTES_12_P_KEY_INDEX_S); - qp_attr->port_num = (u8)roce_get_field(context->qpc_bytes_156, - QP_CONTEXT_QPC_BYTES_156_PORT_NUM_M, - QP_CONTEXT_QPC_BYTES_156_PORT_NUM_S) + 1; + qp_attr->port_num = hr_qp->port + 1; qp_attr->sq_draining = 0; qp_attr->max_rd_atomic = roce_get_field(context->qpc_bytes_156, QP_CONTEXT_QPC_BYTES_156_INITIATOR_DEPTH_M, -- cgit v1.2.3 From 5e6ff78a229c2f231f2f743b017987621e469858 Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Wed, 23 Nov 2016 19:41:07 +0000 Subject: IB/hns: Change qpn allocation to round-robin mode. When using CM to establish connections, qp number that was freed just now will be rejected by ib core. To fix these problem, We change qpn allocation to round-robin mode. We added the round-robin mode for allocating resources using bitmap. We use round-robin mode for qp number and non round-robing mode for other resources like cq number, pd number etc. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_alloc.c | 11 +++++++---- drivers/infiniband/hw/hns/hns_roce_cq.c | 4 ++-- drivers/infiniband/hw/hns/hns_roce_device.h | 9 +++++++-- drivers/infiniband/hw/hns/hns_roce_mr.c | 2 +- drivers/infiniband/hw/hns/hns_roce_pd.c | 5 +++-- drivers/infiniband/hw/hns/hns_roce_qp.c | 2 +- 6 files changed, 21 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_alloc.c b/drivers/infiniband/hw/hns/hns_roce_alloc.c index 863a17a2de40..605962f2828c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_alloc.c +++ b/drivers/infiniband/hw/hns/hns_roce_alloc.c @@ -61,9 +61,10 @@ int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj) return ret; } -void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj) +void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj, + int rr) { - hns_roce_bitmap_free_range(bitmap, obj, 1); + hns_roce_bitmap_free_range(bitmap, obj, 1, rr); } int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt, @@ -106,7 +107,8 @@ int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt, } void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap, - unsigned long obj, int cnt) + unsigned long obj, int cnt, + int rr) { int i; @@ -116,7 +118,8 @@ void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap, for (i = 0; i < cnt; i++) clear_bit(obj + i, bitmap->table); - bitmap->last = min(bitmap->last, obj); + if (!rr) + bitmap->last = min(bitmap->last, obj); bitmap->top = (bitmap->top + bitmap->max + bitmap->reserved_top) & bitmap->mask; spin_unlock(&bitmap->lock); diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index 461a27330e83..c9f6c3dce83c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -166,7 +166,7 @@ err_put: hns_roce_table_put(hr_dev, &cq_table->table, hr_cq->cqn); err_out: - hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn); + hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn, BITMAP_NO_RR); return ret; } @@ -204,7 +204,7 @@ static void hns_roce_free_cq(struct hns_roce_dev *hr_dev, spin_unlock_irq(&cq_table->lock); hns_roce_table_put(hr_dev, &cq_table->table, hr_cq->cqn); - hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn); + hns_roce_bitmap_free(&cq_table->bitmap, hr_cq->cqn, BITMAP_NO_RR); } static int hns_roce_ib_get_cq_umem(struct hns_roce_dev *hr_dev, diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 7242b1438873..593a42a198f6 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -72,6 +72,9 @@ #define HNS_ROCE_MAX_GID_NUM 16 #define HNS_ROCE_GID_SIZE 16 +#define BITMAP_NO_RR 0 +#define BITMAP_RR 1 + #define MR_TYPE_MR 0x00 #define MR_TYPE_DMA 0x03 @@ -661,7 +664,8 @@ void hns_roce_cleanup_cq_table(struct hns_roce_dev *hr_dev); void hns_roce_cleanup_qp_table(struct hns_roce_dev *hr_dev); int hns_roce_bitmap_alloc(struct hns_roce_bitmap *bitmap, unsigned long *obj); -void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj); +void hns_roce_bitmap_free(struct hns_roce_bitmap *bitmap, unsigned long obj, + int rr); int hns_roce_bitmap_init(struct hns_roce_bitmap *bitmap, u32 num, u32 mask, u32 reserved_bot, u32 resetrved_top); void hns_roce_bitmap_cleanup(struct hns_roce_bitmap *bitmap); @@ -669,7 +673,8 @@ void hns_roce_cleanup_bitmap(struct hns_roce_dev *hr_dev); int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt, int align, unsigned long *obj); void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap, - unsigned long obj, int cnt); + unsigned long obj, int cnt, + int rr); struct ib_ah *hns_roce_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); int hns_roce_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index a5bd64586848..9b8a1ad4ee6c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -289,7 +289,7 @@ static void hns_roce_mr_free(struct hns_roce_dev *hr_dev, } hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap, - key_to_hw_index(mr->key)); + key_to_hw_index(mr->key), BITMAP_NO_RR); } static int hns_roce_mr_enable(struct hns_roce_dev *hr_dev, diff --git a/drivers/infiniband/hw/hns/hns_roce_pd.c b/drivers/infiniband/hw/hns/hns_roce_pd.c index 05db7d59812a..a64500fa1145 100644 --- a/drivers/infiniband/hw/hns/hns_roce_pd.c +++ b/drivers/infiniband/hw/hns/hns_roce_pd.c @@ -40,7 +40,7 @@ static int hns_roce_pd_alloc(struct hns_roce_dev *hr_dev, unsigned long *pdn) static void hns_roce_pd_free(struct hns_roce_dev *hr_dev, unsigned long pdn) { - hns_roce_bitmap_free(&hr_dev->pd_bitmap, pdn); + hns_roce_bitmap_free(&hr_dev->pd_bitmap, pdn, BITMAP_NO_RR); } int hns_roce_init_pd_table(struct hns_roce_dev *hr_dev) @@ -121,7 +121,8 @@ int hns_roce_uar_alloc(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar) void hns_roce_uar_free(struct hns_roce_dev *hr_dev, struct hns_roce_uar *uar) { - hns_roce_bitmap_free(&hr_dev->uar_table.bitmap, uar->index); + hns_roce_bitmap_free(&hr_dev->uar_table.bitmap, uar->index, + BITMAP_NO_RR); } int hns_roce_init_uar_table(struct hns_roce_dev *hr_dev) diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index e86dd8d06777..4775b5c725a9 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -250,7 +250,7 @@ void hns_roce_release_range_qp(struct hns_roce_dev *hr_dev, int base_qpn, if (base_qpn < SQP_NUM) return; - hns_roce_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt); + hns_roce_bitmap_free_range(&qp_table->bitmap, base_qpn, cnt, BITMAP_RR); } static int hns_roce_set_rq_size(struct hns_roce_dev *hr_dev, -- cgit v1.2.3 From 82547469782a952452c84c055c7911e635c77cd0 Mon Sep 17 00:00:00 2001 From: Shaobo Xu Date: Wed, 23 Nov 2016 19:41:08 +0000 Subject: IB/hns: Implement the add_gid/del_gid and optimize the GIDs management IB core has implemented the calculation of GIDs and the management of GID tables, and it is now responsible to supply query function for GIDs. So the calculation of GIDs and the management of GID tables in the RoCE driver is redundant. The patch is to implement the add_gid/del_gid to set the GIDs in the RoCE driver, remove the redundant calculation and management of GIDs in the notifier call of the net device and the inet, and update the query_gid. Signed-off-by: Shaobo Xu Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_device.h | 2 - drivers/infiniband/hw/hns/hns_roce_main.c | 270 +++++----------------------- 2 files changed, 48 insertions(+), 224 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 593a42a198f6..9ef1cc3ec930 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -429,8 +429,6 @@ struct hns_roce_ib_iboe { struct net_device *netdevs[HNS_ROCE_MAX_PORTS]; struct notifier_block nb; struct notifier_block nb_inet; - /* 16 GID is shared by 6 port in v1 engine. */ - union ib_gid gid_table[HNS_ROCE_MAX_GID_NUM]; u8 phy_port[HNS_ROCE_MAX_PORTS]; }; diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 67701719bad1..795ef97bfcbf 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -35,51 +35,12 @@ #include #include #include +#include #include "hns_roce_common.h" #include "hns_roce_device.h" #include "hns_roce_user.h" #include "hns_roce_hem.h" -/** - * hns_roce_addrconf_ifid_eui48 - Get default gid. - * @eui: eui. - * @vlan_id: gid - * @dev: net device - * Description: - * MAC convert to GID - * gid[0..7] = fe80 0000 0000 0000 - * gid[8] = mac[0] ^ 2 - * gid[9] = mac[1] - * gid[10] = mac[2] - * gid[11] = ff (VLAN ID high byte (4 MS bits)) - * gid[12] = fe (VLAN ID low byte) - * gid[13] = mac[3] - * gid[14] = mac[4] - * gid[15] = mac[5] - */ -static void hns_roce_addrconf_ifid_eui48(u8 *eui, u16 vlan_id, - struct net_device *dev) -{ - memcpy(eui, dev->dev_addr, 3); - memcpy(eui + 5, dev->dev_addr + 3, 3); - if (vlan_id < 0x1000) { - eui[3] = vlan_id >> 8; - eui[4] = vlan_id & 0xff; - } else { - eui[3] = 0xff; - eui[4] = 0xfe; - } - eui[0] ^= 2; -} - -static void hns_roce_make_default_gid(struct net_device *dev, union ib_gid *gid) -{ - memset(gid, 0, sizeof(*gid)); - gid->raw[0] = 0xFE; - gid->raw[1] = 0x80; - hns_roce_addrconf_ifid_eui48(&gid->raw[8], 0xffff, dev); -} - /** * hns_get_gid_index - Get gid index. * @hr_dev: pointer to structure hns_roce_dev. @@ -96,30 +57,6 @@ int hns_get_gid_index(struct hns_roce_dev *hr_dev, u8 port, int gid_index) return gid_index * hr_dev->caps.num_ports + port; } -static int hns_roce_set_gid(struct hns_roce_dev *hr_dev, u8 port, int gid_index, - union ib_gid *gid) -{ - struct device *dev = &hr_dev->pdev->dev; - u8 gid_idx = 0; - - if (gid_index >= hr_dev->caps.gid_table_len[port]) { - dev_err(dev, "gid_index %d illegal, port %d gid range: 0~%d\n", - gid_index, port, hr_dev->caps.gid_table_len[port] - 1); - return -EINVAL; - } - - gid_idx = hns_get_gid_index(hr_dev, port, gid_index); - - if (!memcmp(gid, &hr_dev->iboe.gid_table[gid_idx], sizeof(*gid))) - return -EINVAL; - - memcpy(&hr_dev->iboe.gid_table[gid_idx], gid, sizeof(*gid)); - - hr_dev->hw->set_gid(hr_dev, port, gid_index, gid); - - return 0; -} - static void hns_roce_set_mac(struct hns_roce_dev *hr_dev, u8 port, u8 *addr) { u8 phy_port; @@ -147,15 +84,44 @@ static void hns_roce_set_mtu(struct hns_roce_dev *hr_dev, u8 port, int mtu) hr_dev->hw->set_mtu(hr_dev, phy_port, tmp); } -static void hns_roce_update_gids(struct hns_roce_dev *hr_dev, int port) +static int hns_roce_add_gid(struct ib_device *device, u8 port_num, + unsigned int index, const union ib_gid *gid, + const struct ib_gid_attr *attr, void **context) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(device); + u8 port = port_num - 1; + unsigned long flags; + + if (port >= hr_dev->caps.num_ports) + return -EINVAL; + + spin_lock_irqsave(&hr_dev->iboe.lock, flags); + + hr_dev->hw->set_gid(hr_dev, port, index, (union ib_gid *)gid); + + spin_unlock_irqrestore(&hr_dev->iboe.lock, flags); + + return 0; +} + +static int hns_roce_del_gid(struct ib_device *device, u8 port_num, + unsigned int index, void **context) { - struct ib_event event; + struct hns_roce_dev *hr_dev = to_hr_dev(device); + union ib_gid zgid = { {0} }; + u8 port = port_num - 1; + unsigned long flags; + + if (port >= hr_dev->caps.num_ports) + return -EINVAL; - /* Refresh gid in ib_cache */ - event.device = &hr_dev->ib_dev; - event.element.port_num = port + 1; - event.event = IB_EVENT_GID_CHANGE; - ib_dispatch_event(&event); + spin_lock_irqsave(&hr_dev->iboe.lock, flags); + + hr_dev->hw->set_gid(hr_dev, port, index, &zgid); + + spin_unlock_irqrestore(&hr_dev->iboe.lock, flags); + + return 0; } static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, @@ -164,8 +130,6 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, struct device *dev = &hr_dev->pdev->dev; struct net_device *netdev; unsigned long flags; - union ib_gid gid; - int ret = 0; netdev = hr_dev->iboe.netdevs[port]; if (!netdev) { @@ -181,10 +145,6 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, case NETDEV_REGISTER: case NETDEV_CHANGEADDR: hns_roce_set_mac(hr_dev, port, netdev->dev_addr); - hns_roce_make_default_gid(netdev, &gid); - ret = hns_roce_set_gid(hr_dev, port, 0, &gid); - if (!ret) - hns_roce_update_gids(hr_dev, port); break; case NETDEV_DOWN: /* @@ -197,7 +157,7 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, } spin_unlock_irqrestore(&hr_dev->iboe.lock, flags); - return ret; + return 0; } static int hns_roce_netdev_event(struct notifier_block *self, @@ -224,118 +184,17 @@ static int hns_roce_netdev_event(struct notifier_block *self, return NOTIFY_DONE; } -static void hns_roce_addr_event(int event, struct net_device *event_netdev, - struct hns_roce_dev *hr_dev, union ib_gid *gid) -{ - struct hns_roce_ib_iboe *iboe = NULL; - int gid_table_len = 0; - unsigned long flags; - union ib_gid zgid; - u8 gid_idx = 0; - u8 port = 0; - int i = 0; - int free; - struct net_device *real_dev = rdma_vlan_dev_real_dev(event_netdev) ? - rdma_vlan_dev_real_dev(event_netdev) : - event_netdev; - - if (event != NETDEV_UP && event != NETDEV_DOWN) - return; - - iboe = &hr_dev->iboe; - while (port < hr_dev->caps.num_ports) { - if (real_dev == iboe->netdevs[port]) - break; - port++; - } - - if (port >= hr_dev->caps.num_ports) { - dev_dbg(&hr_dev->pdev->dev, "can't find netdev\n"); - return; - } - - memset(zgid.raw, 0, sizeof(zgid.raw)); - free = -1; - gid_table_len = hr_dev->caps.gid_table_len[port]; - - spin_lock_irqsave(&hr_dev->iboe.lock, flags); - - for (i = 0; i < gid_table_len; i++) { - gid_idx = hns_get_gid_index(hr_dev, port, i); - if (!memcmp(gid->raw, iboe->gid_table[gid_idx].raw, - sizeof(gid->raw))) - break; - if (free < 0 && !memcmp(zgid.raw, - iboe->gid_table[gid_idx].raw, sizeof(zgid.raw))) - free = i; - } - - if (i >= gid_table_len) { - if (free < 0) { - spin_unlock_irqrestore(&hr_dev->iboe.lock, flags); - dev_dbg(&hr_dev->pdev->dev, - "gid_index overflow, port(%d)\n", port); - return; - } - if (!hns_roce_set_gid(hr_dev, port, free, gid)) - hns_roce_update_gids(hr_dev, port); - } else if (event == NETDEV_DOWN) { - if (!hns_roce_set_gid(hr_dev, port, i, &zgid)) - hns_roce_update_gids(hr_dev, port); - } - - spin_unlock_irqrestore(&hr_dev->iboe.lock, flags); -} - -static int hns_roce_inet_event(struct notifier_block *self, unsigned long event, - void *ptr) -{ - struct in_ifaddr *ifa = ptr; - struct hns_roce_dev *hr_dev; - struct net_device *dev = ifa->ifa_dev->dev; - union ib_gid gid; - - ipv6_addr_set_v4mapped(ifa->ifa_address, (struct in6_addr *)&gid); - - hr_dev = container_of(self, struct hns_roce_dev, iboe.nb_inet); - - hns_roce_addr_event(event, dev, hr_dev, &gid); - - return NOTIFY_DONE; -} - -static int hns_roce_setup_mtu_gids(struct hns_roce_dev *hr_dev) +static int hns_roce_setup_mtu_mac(struct hns_roce_dev *hr_dev) { - struct in_ifaddr *ifa_list = NULL; - union ib_gid gid = {{0} }; - u32 ipaddr = 0; - int index = 0; - int ret = 0; - u8 i = 0; + u8 i; for (i = 0; i < hr_dev->caps.num_ports; i++) { hns_roce_set_mtu(hr_dev, i, ib_mtu_enum_to_int(hr_dev->caps.max_mtu)); hns_roce_set_mac(hr_dev, i, hr_dev->iboe.netdevs[i]->dev_addr); - - if (hr_dev->iboe.netdevs[i]->ip_ptr) { - ifa_list = hr_dev->iboe.netdevs[i]->ip_ptr->ifa_list; - index = 1; - while (ifa_list) { - ipaddr = ifa_list->ifa_address; - ipv6_addr_set_v4mapped(ipaddr, - (struct in6_addr *)&gid); - ret = hns_roce_set_gid(hr_dev, i, index, &gid); - if (ret) - break; - index++; - ifa_list = ifa_list->ifa_next; - } - hns_roce_update_gids(hr_dev, i); - } } - return ret; + return 0; } static int hns_roce_query_device(struct ib_device *ib_dev, @@ -444,31 +303,6 @@ static enum rdma_link_layer hns_roce_get_link_layer(struct ib_device *device, static int hns_roce_query_gid(struct ib_device *ib_dev, u8 port_num, int index, union ib_gid *gid) { - struct hns_roce_dev *hr_dev = to_hr_dev(ib_dev); - struct device *dev = &hr_dev->pdev->dev; - u8 gid_idx = 0; - u8 port; - - if (port_num < 1 || port_num > hr_dev->caps.num_ports || - index >= hr_dev->caps.gid_table_len[port_num - 1]) { - dev_err(dev, - "port_num %d index %d illegal! correct range: port_num 1~%d index 0~%d!\n", - port_num, index, hr_dev->caps.num_ports, - hr_dev->caps.gid_table_len[port_num - 1] - 1); - return -EINVAL; - } - - port = port_num - 1; - gid_idx = hns_get_gid_index(hr_dev, port, index); - if (gid_idx >= HNS_ROCE_MAX_GID_NUM) { - dev_err(dev, "port_num %d index %d illegal! total gid num %d!\n", - port_num, index, HNS_ROCE_MAX_GID_NUM); - return -EINVAL; - } - - memcpy(gid->raw, hr_dev->iboe.gid_table[gid_idx].raw, - HNS_ROCE_GID_SIZE); - return 0; } @@ -646,6 +480,8 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) ib_dev->get_link_layer = hns_roce_get_link_layer; ib_dev->get_netdev = hns_roce_get_netdev; ib_dev->query_gid = hns_roce_query_gid; + ib_dev->add_gid = hns_roce_add_gid; + ib_dev->del_gid = hns_roce_del_gid; ib_dev->query_pkey = hns_roce_query_pkey; ib_dev->alloc_ucontext = hns_roce_alloc_ucontext; ib_dev->dealloc_ucontext = hns_roce_dealloc_ucontext; @@ -688,32 +524,22 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) return ret; } - ret = hns_roce_setup_mtu_gids(hr_dev); + ret = hns_roce_setup_mtu_mac(hr_dev); if (ret) { - dev_err(dev, "roce_setup_mtu_gids failed!\n"); - goto error_failed_setup_mtu_gids; + dev_err(dev, "setup_mtu_mac failed!\n"); + goto error_failed_setup_mtu_mac; } iboe->nb.notifier_call = hns_roce_netdev_event; ret = register_netdevice_notifier(&iboe->nb); if (ret) { dev_err(dev, "register_netdevice_notifier failed!\n"); - goto error_failed_setup_mtu_gids; - } - - iboe->nb_inet.notifier_call = hns_roce_inet_event; - ret = register_inetaddr_notifier(&iboe->nb_inet); - if (ret) { - dev_err(dev, "register inet addr notifier failed!\n"); - goto error_failed_register_inetaddr_notifier; + goto error_failed_setup_mtu_mac; } return 0; -error_failed_register_inetaddr_notifier: - unregister_netdevice_notifier(&iboe->nb); - -error_failed_setup_mtu_gids: +error_failed_setup_mtu_mac: ib_unregister_device(ib_dev); return ret; -- cgit v1.2.3 From e84e40be8e7bc29599da7056b340490d25ff87b5 Mon Sep 17 00:00:00 2001 From: Salil Date: Wed, 23 Nov 2016 19:41:09 +0000 Subject: IB/hns: Fix for Checkpatch.pl comment style errors This patch correct the comment style errors caught by checkpatch.pl script Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cmd.c | 8 ++--- drivers/infiniband/hw/hns/hns_roce_device.h | 28 +++++++-------- drivers/infiniband/hw/hns/hns_roce_eq.c | 6 ++-- drivers/infiniband/hw/hns/hns_roce_hem.c | 6 ++-- drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 56 ++++++++++++++--------------- drivers/infiniband/hw/hns/hns_roce_main.c | 28 +++++++-------- 6 files changed, 66 insertions(+), 66 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.c b/drivers/infiniband/hw/hns/hns_roce_cmd.c index 2a0b6c05da5f..8c1f7a6f84d2 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cmd.c +++ b/drivers/infiniband/hw/hns/hns_roce_cmd.c @@ -216,10 +216,10 @@ static int __hns_roce_cmd_mbox_wait(struct hns_roce_dev *hr_dev, u64 in_param, goto out; /* - * It is timeout when wait_for_completion_timeout return 0 - * The return value is the time limit set in advance - * how many seconds showing - */ + * It is timeout when wait_for_completion_timeout return 0 + * The return value is the time limit set in advance + * how many seconds showing + */ if (!wait_for_completion_timeout(&context->done, msecs_to_jiffies(timeout))) { dev_err(dev, "[cmd]wait_for_completion_timeout timeout\n"); diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 9ef1cc3ec930..e48464ddd2b0 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -201,9 +201,9 @@ struct hns_roce_bitmap { /* Order = 0: bitmap is biggest, order = max bitmap is least (only a bit) */ /* Every bit repesent to a partner free/used status in bitmap */ /* -* Initial, bits of other bitmap are all 0 except that a bit of max_order is 1 -* Bit = 1 represent to idle and available; bit = 0: not available -*/ + * Initial, bits of other bitmap are all 0 except that a bit of max_order is 1 + * Bit = 1 represent to idle and available; bit = 0: not available + */ struct hns_roce_buddy { /* Members point to every order level bitmap */ unsigned long **bits; @@ -365,25 +365,25 @@ struct hns_roce_cmdq { struct mutex hcr_mutex; struct semaphore poll_sem; /* - * Event mode: cmd register mutex protection, - * ensure to not exceed max_cmds and user use limit region - */ + * Event mode: cmd register mutex protection, + * ensure to not exceed max_cmds and user use limit region + */ struct semaphore event_sem; int max_cmds; spinlock_t context_lock; int free_head; struct hns_roce_cmd_context *context; /* - * Result of get integer part - * which max_comds compute according a power of 2 - */ + * Result of get integer part + * which max_comds compute according a power of 2 + */ u16 token_mask; /* - * Process whether use event mode, init default non-zero - * After the event queue of cmd event ready, - * can switch into event mode - * close device, switch into poll mode(non event mode) - */ + * Process whether use event mode, init default non-zero + * After the event queue of cmd event ready, + * can switch into event mode + * close device, switch into poll mode(non event mode) + */ u8 use_events; u8 toggle; }; diff --git a/drivers/infiniband/hw/hns/hns_roce_eq.c b/drivers/infiniband/hw/hns/hns_roce_eq.c index 21e21b03cfb5..50f864935a0e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_eq.c +++ b/drivers/infiniband/hw/hns/hns_roce_eq.c @@ -371,9 +371,9 @@ static int hns_roce_aeq_ovf_int(struct hns_roce_dev *hr_dev, int i = 0; /** - * AEQ overflow ECC mult bit err CEQ overflow alarm - * must clear interrupt, mask irq, clear irq, cancel mask operation - */ + * AEQ overflow ECC mult bit err CEQ overflow alarm + * must clear interrupt, mask irq, clear irq, cancel mask operation + */ aeshift_val = roce_read(hr_dev, ROCEE_CAEP_AEQC_AEQE_SHIFT_REG); if (roce_get_bit(aeshift_val, diff --git a/drivers/infiniband/hw/hns/hns_roce_hem.c b/drivers/infiniband/hw/hns/hns_roce_hem.c index 250d8f280390..c5104e0b2916 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hem.c +++ b/drivers/infiniband/hw/hns/hns_roce_hem.c @@ -80,9 +80,9 @@ struct hns_roce_hem *hns_roce_alloc_hem(struct hns_roce_dev *hr_dev, int npages, --order; /* - * Alloc memory one time. If failed, don't alloc small block - * memory, directly return fail. - */ + * Alloc memory one time. If failed, don't alloc small block + * memory, directly return fail. + */ mem = &chunk->mem[chunk->npages]; buf = dma_alloc_coherent(&hr_dev->pdev->dev, PAGE_SIZE << order, &sg_dma_address(mem), gfp_mask); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index cc64230d44c0..125ab90157f6 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -1352,9 +1352,9 @@ static void __hns_roce_v1_cq_clean(struct hns_roce_cq *hr_cq, u32 qpn, } /* - * Now backwards through the CQ, removing CQ entries - * that match our QP by overwriting them with next entries. - */ + * Now backwards through the CQ, removing CQ entries + * that match our QP by overwriting them with next entries. + */ while ((int) --prod_index - (int) hr_cq->cons_index >= 0) { cqe = get_cqe(hr_cq, prod_index & hr_cq->ib_cq.cqe); if ((roce_get_field(cqe->cqe_byte_16, CQE_BYTE_16_LOCAL_QPN_M, @@ -1376,9 +1376,9 @@ static void __hns_roce_v1_cq_clean(struct hns_roce_cq *hr_cq, u32 qpn, if (nfreed) { hr_cq->cons_index += nfreed; /* - * Make sure update of buffer contents is done before - * updating consumer index. - */ + * Make sure update of buffer contents is done before + * updating consumer index. + */ wmb(); hns_roce_v1_cq_set_ci(hr_cq, hr_cq->cons_index); @@ -1473,7 +1473,7 @@ void hns_roce_v1_write_cqc(struct hns_roce_dev *hr_dev, roce_set_bit(cq_context->cqc_byte_32, CQ_CQNTEXT_CQC_BYTE_32_TYPE_OF_COMPLETION_NOTIFICATION_S, 0); - /*The initial value of cq's ci is 0 */ + /* The initial value of cq's ci is 0 */ roce_set_field(cq_context->cqc_byte_32, CQ_CONTEXT_CQC_BYTE_32_CQ_CONS_IDX_M, CQ_CONTEXT_CQC_BYTE_32_CQ_CONS_IDX_S, 0); @@ -1490,9 +1490,9 @@ int hns_roce_v1_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) notification_flag = (flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? CQ_DB_REQ_NOT : CQ_DB_REQ_NOT_SOL; /* - * flags = 0; Notification Flag = 1, next - * flags = 1; Notification Flag = 0, solocited - */ + * flags = 0; Notification Flag = 1, next + * flags = 1; Notification Flag = 0, solocited + */ doorbell[0] = hr_cq->cons_index & ((hr_cq->cq_depth << 1) - 1); roce_set_bit(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_HW_SYNS_S, 1); roce_set_field(doorbell[1], ROCEE_DB_OTHERS_H_ROCEE_DB_OTH_CMD_M, @@ -1647,10 +1647,10 @@ static int hns_roce_v1_poll_one(struct hns_roce_cq *hr_cq, wq = &(*cur_qp)->sq; if ((*cur_qp)->sq_signal_bits) { /* - * If sg_signal_bit is 1, - * firstly tail pointer updated to wqe - * which current cqe correspond to - */ + * If sg_signal_bit is 1, + * firstly tail pointer updated to wqe + * which current cqe correspond to + */ wqe_ctr = (u16)roce_get_field(cqe->cqe_byte_4, CQE_BYTE_4_WQE_INDEX_M, CQE_BYTE_4_WQE_INDEX_S); @@ -2072,11 +2072,11 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, } /* - *Reset to init - * Mandatory param: - * IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS - * Optional param: NA - */ + * Reset to init + * Mandatory param: + * IB_QP_STATE | IB_QP_PKEY_INDEX | IB_QP_PORT | IB_QP_ACCESS_FLAGS + * Optional param: NA + */ if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { roce_set_field(context->qpc_bytes_4, QP_CONTEXT_QPC_BYTES_4_TRANSPORT_SERVICE_TYPE_M, @@ -2584,9 +2584,9 @@ static int hns_roce_v1_m_qp(struct ib_qp *ibqp, const struct ib_qp_attr *attr, } /* - * Use rst2init to instead of init2init with drv, - * need to hw to flash RQ HEAD by DB again - */ + * Use rst2init to instead of init2init with drv, + * need to hw to flash RQ HEAD by DB again + */ if (cur_state == IB_QPS_INIT && new_state == IB_QPS_INIT) { /* Memory barrier */ wmb(); @@ -2921,9 +2921,9 @@ static void hns_roce_v1_destroy_qp_common(struct hns_roce_dev *hr_dev, if (hr_qp->ibqp.qp_type == IB_QPT_RC) { if (hr_qp->state != IB_QPS_RESET) { /* - * Set qp to ERR, - * waiting for hw complete processing all dbs - */ + * Set qp to ERR, + * waiting for hw complete processing all dbs + */ if (hns_roce_v1_qp_modify(hr_dev, NULL, to_hns_roce_state( (enum ib_qp_state)hr_qp->state), @@ -2936,9 +2936,9 @@ static void hns_roce_v1_destroy_qp_common(struct hns_roce_dev *hr_dev, sdbisusepr_val = roce_read(hr_dev, ROCEE_SDB_ISSUE_PTR_REG); /* - * Query db process status, - * until hw process completely - */ + * Query db process status, + * until hw process completely + */ end = msecs_to_jiffies( HNS_ROCE_QP_DESTROY_TIMEOUT_MSECS) + jiffies; do { diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 795ef97bfcbf..914d0ac7881c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -148,8 +148,8 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, break; case NETDEV_DOWN: /* - * In v1 engine, only support all ports closed together. - */ + * In v1 engine, only support all ports closed together. + */ break; default: dev_dbg(dev, "NETDEV event = 0x%x!\n", (u32)(event)); @@ -773,10 +773,10 @@ err_unmap_mtt: } /** -* hns_roce_setup_hca - setup host channel adapter -* @hr_dev: pointer to hns roce device -* Return : int -*/ + * hns_roce_setup_hca - setup host channel adapter + * @hr_dev: pointer to hns roce device + * Return : int + */ static int hns_roce_setup_hca(struct hns_roce_dev *hr_dev) { int ret; @@ -841,11 +841,11 @@ err_uar_table_free: } /** -* hns_roce_probe - RoCE driver entrance -* @pdev: pointer to platform device -* Return : int -* -*/ + * hns_roce_probe - RoCE driver entrance + * @pdev: pointer to platform device + * Return : int + * + */ static int hns_roce_probe(struct platform_device *pdev) { int ret; @@ -958,9 +958,9 @@ error_failed_get_cfg: } /** -* hns_roce_remove - remove RoCE device -* @pdev: pointer to platform device -*/ + * hns_roce_remove - remove RoCE device + * @pdev: pointer to platform device + */ static int hns_roce_remove(struct platform_device *pdev) { struct hns_roce_dev *hr_dev = platform_get_drvdata(pdev); -- cgit v1.2.3 From d838c481e025db374171e16d5cc463b85cffec9f Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Tue, 29 Nov 2016 23:10:25 +0000 Subject: IB/hns: Fix the bug when destroy qp If send queue is still working when qp is in reset state by modify qp in destroy qp function, hardware will hold on and don't work in hip06 SoC. In current codes, RoCE driver check hardware pointer of sending and hardware pointer of processing to ensure that hardware has processed all the dbs of this qp. But while the environment of wire becomes not good, The checking time maybe too long. In order to solve this problem, RoCE driver created a workqueue at probe function. If there is a timeout when checking the status of qp, driver initialize work entry and push it into the workqueue, Work function will finish checking and release the related resources later. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Lijun Ou Signed-off-by: Dongdong Huang(Donald) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_common.h | 40 +++ drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 435 ++++++++++++++++++++++------ drivers/infiniband/hw/hns/hns_roce_hw_v1.h | 23 ++ 3 files changed, 402 insertions(+), 96 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_common.h b/drivers/infiniband/hw/hns/hns_roce_common.h index 0dcb620e91dd..a0556323a678 100644 --- a/drivers/infiniband/hw/hns/hns_roce_common.h +++ b/drivers/infiniband/hw/hns/hns_roce_common.h @@ -57,6 +57,32 @@ #define roce_set_bit(origin, shift, val) \ roce_set_field((origin), (1ul << (shift)), (shift), (val)) +/* + * roce_hw_index_cmp_lt - Compare two hardware index values in hisilicon + * SOC, check if a is less than b. + * @a: hardware index value + * @b: hardware index value + * @bits: the number of bits of a and b, range: 0~31. + * + * Hardware index increases continuously till max value, and then restart + * from zero, again and again. Because the bits of reg field is often + * limited, the reg field can only hold the low bits of the hardware index + * in hisilicon SOC. + * In some scenes we need to compare two values(a,b) getted from two reg + * fields in this driver, for example: + * If a equals 0xfffe, b equals 0x1 and bits equals 16, we think b has + * incresed from 0xffff to 0x1 and a is less than b. + * If a equals 0xfffe, b equals 0x0xf001 and bits equals 16, we think a + * is bigger than b. + * + * Return true on a less than b, otherwise false. + */ +#define roce_hw_index_mask(bits) ((1ul << (bits)) - 1) +#define roce_hw_index_shift(bits) (32 - (bits)) +#define roce_hw_index_cmp_lt(a, b, bits) \ + ((int)((((a) - (b)) & roce_hw_index_mask(bits)) << \ + roce_hw_index_shift(bits)) < 0) + #define ROCEE_GLB_CFG_ROCEE_DB_SQ_MODE_S 3 #define ROCEE_GLB_CFG_ROCEE_DB_OTH_MODE_S 4 @@ -245,10 +271,22 @@ #define ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M \ (((1UL << 28) - 1) << ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S) +#define ROCEE_SDB_PTR_CMP_BITS 28 + #define ROCEE_SDB_INV_CNT_SDB_INV_CNT_S 0 #define ROCEE_SDB_INV_CNT_SDB_INV_CNT_M \ (((1UL << 16) - 1) << ROCEE_SDB_INV_CNT_SDB_INV_CNT_S) +#define ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_S 0 +#define ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_M \ + (((1UL << 16) - 1) << ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_S) + +#define ROCEE_SDB_CNT_CMP_BITS 16 + +#define ROCEE_TSP_BP_ST_QH_FIFO_ENTRY_S 20 + +#define ROCEE_CNT_CLR_CE_CNT_CLR_CE_S 0 + /*************ROCEE_REG DEFINITION****************/ #define ROCEE_VENDOR_ID_REG 0x0 #define ROCEE_VENDOR_PART_ID_REG 0x4 @@ -317,6 +355,8 @@ #define ROCEE_SDB_ISSUE_PTR_REG 0x758 #define ROCEE_SDB_SEND_PTR_REG 0x75C #define ROCEE_SDB_INV_CNT_REG 0x9A4 +#define ROCEE_SDB_RETRY_CNT_REG 0x9AC +#define ROCEE_TSP_BP_ST_REG 0x9EC #define ROCEE_ECC_UCERR_ALM0_REG 0xB34 #define ROCEE_ECC_CERR_ALM0_REG 0xB40 diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index 125ab90157f6..aee1d01ca70c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -948,6 +948,38 @@ int hns_roce_v1_reset(struct hns_roce_dev *hr_dev, bool dereset) return ret; } +static int hns_roce_des_qp_init(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_v1_priv *priv; + struct hns_roce_des_qp *des_qp; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + des_qp = &priv->des_qp; + + des_qp->requeue_flag = 1; + des_qp->qp_wq = create_singlethread_workqueue("hns_roce_destroy_qp"); + if (!des_qp->qp_wq) { + dev_err(dev, "Create destroy qp workqueue failed!\n"); + return -ENOMEM; + } + + return 0; +} + +static void hns_roce_des_qp_free(struct hns_roce_dev *hr_dev) +{ + struct hns_roce_v1_priv *priv; + struct hns_roce_des_qp *des_qp; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + des_qp = &priv->des_qp; + + des_qp->requeue_flag = 0; + flush_workqueue(des_qp->qp_wq); + destroy_workqueue(des_qp->qp_wq); +} + void hns_roce_v1_profile(struct hns_roce_dev *hr_dev) { int i = 0; @@ -1050,8 +1082,6 @@ int hns_roce_v1_init(struct hns_roce_dev *hr_dev) goto error_failed_raq_init; } - hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_UP); - ret = hns_roce_bt_init(hr_dev); if (ret) { dev_err(dev, "bt init failed!\n"); @@ -1064,13 +1094,23 @@ int hns_roce_v1_init(struct hns_roce_dev *hr_dev) goto error_failed_tptr_init; } + ret = hns_roce_des_qp_init(hr_dev); + if (ret) { + dev_err(dev, "des qp init failed!\n"); + goto error_failed_des_qp_init; + } + + hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_UP); + return 0; +error_failed_des_qp_init: + hns_roce_tptr_free(hr_dev); + error_failed_tptr_init: hns_roce_bt_free(hr_dev); error_failed_bt_init: - hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); hns_roce_raq_free(hr_dev); error_failed_raq_init: @@ -1080,9 +1120,10 @@ error_failed_raq_init: void hns_roce_v1_exit(struct hns_roce_dev *hr_dev) { + hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); + hns_roce_des_qp_free(hr_dev); hns_roce_tptr_free(hr_dev); hns_roce_bt_free(hr_dev); - hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); hns_roce_raq_free(hr_dev); hns_roce_db_free(hr_dev); } @@ -2906,132 +2947,334 @@ int hns_roce_v1_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, hns_roce_v1_q_sqp(ibqp, qp_attr, qp_attr_mask, qp_init_attr) : hns_roce_v1_q_qp(ibqp, qp_attr, qp_attr_mask, qp_init_attr); } -static void hns_roce_v1_destroy_qp_common(struct hns_roce_dev *hr_dev, - struct hns_roce_qp *hr_qp, - int is_user) + +static int check_qp_db_process_status(struct hns_roce_dev *hr_dev, + struct hns_roce_qp *hr_qp, + u32 sdb_issue_ptr, + u32 *sdb_inv_cnt, + u32 *wait_stage) { - u32 sdbinvcnt; - unsigned long end = 0; - u32 sdbinvcnt_val; - u32 sdbsendptr_val; - u32 sdbisusepr_val; - struct hns_roce_cq *send_cq, *recv_cq; struct device *dev = &hr_dev->pdev->dev; + u32 sdb_retry_cnt, old_retry; + u32 sdb_send_ptr, old_send; + u32 success_flags = 0; + u32 cur_cnt, old_cnt; + unsigned long end; + u32 send_ptr; + u32 inv_cnt; + u32 tsp_st; + + if (*wait_stage > HNS_ROCE_V1_DB_STAGE2 || + *wait_stage < HNS_ROCE_V1_DB_STAGE1) { + dev_err(dev, "QP(0x%lx) db status wait stage(%d) error!\n", + hr_qp->qpn, *wait_stage); + return -EINVAL; + } - if (hr_qp->ibqp.qp_type == IB_QPT_RC) { - if (hr_qp->state != IB_QPS_RESET) { - /* - * Set qp to ERR, - * waiting for hw complete processing all dbs - */ - if (hns_roce_v1_qp_modify(hr_dev, NULL, - to_hns_roce_state( - (enum ib_qp_state)hr_qp->state), - HNS_ROCE_QP_STATE_ERR, NULL, - hr_qp)) - dev_err(dev, "modify QP %06lx to ERR failed.\n", - hr_qp->qpn); - - /* Record issued doorbell */ - sdbisusepr_val = roce_read(hr_dev, - ROCEE_SDB_ISSUE_PTR_REG); - /* - * Query db process status, - * until hw process completely - */ - end = msecs_to_jiffies( - HNS_ROCE_QP_DESTROY_TIMEOUT_MSECS) + jiffies; - do { - sdbsendptr_val = roce_read(hr_dev, + /* Calculate the total timeout for the entire verification process */ + end = msecs_to_jiffies(HNS_ROCE_V1_CHECK_DB_TIMEOUT_MSECS) + jiffies; + + if (*wait_stage == HNS_ROCE_V1_DB_STAGE1) { + /* Query db process status, until hw process completely */ + sdb_send_ptr = roce_read(hr_dev, ROCEE_SDB_SEND_PTR_REG); + while (roce_hw_index_cmp_lt(sdb_send_ptr, sdb_issue_ptr, + ROCEE_SDB_PTR_CMP_BITS)) { + if (!time_before(jiffies, end)) { + dev_dbg(dev, "QP(0x%lx) db process stage1 timeout. issue 0x%x send 0x%x.\n", + hr_qp->qpn, sdb_issue_ptr, + sdb_send_ptr); + return 0; + } + + msleep(HNS_ROCE_V1_CHECK_DB_SLEEP_MSECS); + sdb_send_ptr = roce_read(hr_dev, ROCEE_SDB_SEND_PTR_REG); - if (!time_before(jiffies, end)) { - dev_err(dev, "destroy qp(0x%lx) timeout!!!", - hr_qp->qpn); - break; - } - } while ((short)(roce_get_field(sdbsendptr_val, - ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M, - ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S) - - roce_get_field(sdbisusepr_val, - ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_M, - ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_S) - ) < 0); + } - /* Get list pointer */ - sdbinvcnt = roce_read(hr_dev, ROCEE_SDB_INV_CNT_REG); + if (roce_get_field(sdb_issue_ptr, + ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_M, + ROCEE_SDB_ISSUE_PTR_SDB_ISSUE_PTR_S) == + roce_get_field(sdb_send_ptr, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S)) { + old_send = roce_read(hr_dev, ROCEE_SDB_SEND_PTR_REG); + old_retry = roce_read(hr_dev, ROCEE_SDB_RETRY_CNT_REG); - /* Query db's list status, until hw reversal */ do { - sdbinvcnt_val = roce_read(hr_dev, - ROCEE_SDB_INV_CNT_REG); + tsp_st = roce_read(hr_dev, ROCEE_TSP_BP_ST_REG); + if (roce_get_bit(tsp_st, + ROCEE_TSP_BP_ST_QH_FIFO_ENTRY_S) == 1) { + *wait_stage = HNS_ROCE_V1_DB_WAIT_OK; + return 0; + } + if (!time_before(jiffies, end)) { - dev_err(dev, "destroy qp(0x%lx) timeout!!!", - hr_qp->qpn); - dev_err(dev, "SdbInvCnt = 0x%x\n", - sdbinvcnt_val); - break; + dev_dbg(dev, "QP(0x%lx) db process stage1 timeout when send ptr equals issue ptr.\n" + "issue 0x%x send 0x%x.\n", + hr_qp->qpn, sdb_issue_ptr, + sdb_send_ptr); + return 0; } - } while ((short)(roce_get_field(sdbinvcnt_val, - ROCEE_SDB_INV_CNT_SDB_INV_CNT_M, - ROCEE_SDB_INV_CNT_SDB_INV_CNT_S) - - (sdbinvcnt + SDB_INV_CNT_OFFSET)) < 0); - - /* Modify qp to reset before destroying qp */ - if (hns_roce_v1_qp_modify(hr_dev, NULL, - to_hns_roce_state( - (enum ib_qp_state)hr_qp->state), - HNS_ROCE_QP_STATE_RST, NULL, hr_qp)) - dev_err(dev, "modify QP %06lx to RESET failed.\n", - hr_qp->qpn); + + msleep(HNS_ROCE_V1_CHECK_DB_SLEEP_MSECS); + + sdb_send_ptr = roce_read(hr_dev, + ROCEE_SDB_SEND_PTR_REG); + sdb_retry_cnt = roce_read(hr_dev, + ROCEE_SDB_RETRY_CNT_REG); + cur_cnt = roce_get_field(sdb_send_ptr, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S) + + roce_get_field(sdb_retry_cnt, + ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_M, + ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_S); + if (!roce_get_bit(tsp_st, + ROCEE_CNT_CLR_CE_CNT_CLR_CE_S)) { + old_cnt = roce_get_field(old_send, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S) + + roce_get_field(old_retry, + ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_M, + ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_S); + if (cur_cnt - old_cnt > SDB_ST_CMP_VAL) + success_flags = 1; + } else { + old_cnt = roce_get_field(old_send, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S); + if (cur_cnt - old_cnt > SDB_ST_CMP_VAL) + success_flags = 1; + else { + send_ptr = roce_get_field(old_send, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S) + + roce_get_field(sdb_retry_cnt, + ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_M, + ROCEE_SDB_RETRY_CNT_SDB_RETRY_CT_S); + roce_set_field(old_send, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_M, + ROCEE_SDB_SEND_PTR_SDB_SEND_PTR_S, + send_ptr); + } + } + } while (!success_flags); + } + + *wait_stage = HNS_ROCE_V1_DB_STAGE2; + + /* Get list pointer */ + *sdb_inv_cnt = roce_read(hr_dev, ROCEE_SDB_INV_CNT_REG); + dev_dbg(dev, "QP(0x%lx) db process stage2. inv cnt = 0x%x.\n", + hr_qp->qpn, *sdb_inv_cnt); + } + + if (*wait_stage == HNS_ROCE_V1_DB_STAGE2) { + /* Query db's list status, until hw reversal */ + inv_cnt = roce_read(hr_dev, ROCEE_SDB_INV_CNT_REG); + while (roce_hw_index_cmp_lt(inv_cnt, + *sdb_inv_cnt + SDB_INV_CNT_OFFSET, + ROCEE_SDB_CNT_CMP_BITS)) { + if (!time_before(jiffies, end)) { + dev_dbg(dev, "QP(0x%lx) db process stage2 timeout. inv cnt 0x%x.\n", + hr_qp->qpn, inv_cnt); + return 0; + } + + msleep(HNS_ROCE_V1_CHECK_DB_SLEEP_MSECS); + inv_cnt = roce_read(hr_dev, ROCEE_SDB_INV_CNT_REG); } + + *wait_stage = HNS_ROCE_V1_DB_WAIT_OK; + } + + return 0; +} + +static int check_qp_reset_state(struct hns_roce_dev *hr_dev, + struct hns_roce_qp *hr_qp, + struct hns_roce_qp_work *qp_work_entry, + int *is_timeout) +{ + struct device *dev = &hr_dev->pdev->dev; + u32 sdb_issue_ptr; + int ret; + + if (hr_qp->state != IB_QPS_RESET) { + /* Set qp to ERR, waiting for hw complete processing all dbs */ + ret = hns_roce_v1_modify_qp(&hr_qp->ibqp, NULL, 0, hr_qp->state, + IB_QPS_ERR); + if (ret) { + dev_err(dev, "Modify QP(0x%lx) to ERR failed!\n", + hr_qp->qpn); + return ret; + } + + /* Record issued doorbell */ + sdb_issue_ptr = roce_read(hr_dev, ROCEE_SDB_ISSUE_PTR_REG); + qp_work_entry->sdb_issue_ptr = sdb_issue_ptr; + qp_work_entry->db_wait_stage = HNS_ROCE_V1_DB_STAGE1; + + /* Query db process status, until hw process completely */ + ret = check_qp_db_process_status(hr_dev, hr_qp, sdb_issue_ptr, + &qp_work_entry->sdb_inv_cnt, + &qp_work_entry->db_wait_stage); + if (ret) { + dev_err(dev, "Check QP(0x%lx) db process status failed!\n", + hr_qp->qpn); + return ret; + } + + if (qp_work_entry->db_wait_stage != HNS_ROCE_V1_DB_WAIT_OK) { + qp_work_entry->sche_cnt = 0; + *is_timeout = 1; + return 0; + } + + /* Modify qp to reset before destroying qp */ + ret = hns_roce_v1_modify_qp(&hr_qp->ibqp, NULL, 0, hr_qp->state, + IB_QPS_RESET); + if (ret) { + dev_err(dev, "Modify QP(0x%lx) to RST failed!\n", + hr_qp->qpn); + return ret; + } + } + + return 0; +} + +static void hns_roce_v1_destroy_qp_work_fn(struct work_struct *work) +{ + struct hns_roce_qp_work *qp_work_entry; + struct hns_roce_v1_priv *priv; + struct hns_roce_dev *hr_dev; + struct hns_roce_qp *hr_qp; + struct device *dev; + int ret; + + qp_work_entry = container_of(work, struct hns_roce_qp_work, work); + hr_dev = to_hr_dev(qp_work_entry->ib_dev); + dev = &hr_dev->pdev->dev; + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + hr_qp = qp_work_entry->qp; + + dev_dbg(dev, "Schedule destroy QP(0x%lx) work.\n", hr_qp->qpn); + + qp_work_entry->sche_cnt++; + + /* Query db process status, until hw process completely */ + ret = check_qp_db_process_status(hr_dev, hr_qp, + qp_work_entry->sdb_issue_ptr, + &qp_work_entry->sdb_inv_cnt, + &qp_work_entry->db_wait_stage); + if (ret) { + dev_err(dev, "Check QP(0x%lx) db process status failed!\n", + hr_qp->qpn); + return; + } + + if (qp_work_entry->db_wait_stage != HNS_ROCE_V1_DB_WAIT_OK && + priv->des_qp.requeue_flag) { + queue_work(priv->des_qp.qp_wq, work); + return; + } + + /* Modify qp to reset before destroying qp */ + ret = hns_roce_v1_modify_qp(&hr_qp->ibqp, NULL, 0, hr_qp->state, + IB_QPS_RESET); + if (ret) { + dev_err(dev, "Modify QP(0x%lx) to RST failed!\n", hr_qp->qpn); + return; + } + + hns_roce_qp_remove(hr_dev, hr_qp); + hns_roce_qp_free(hr_dev, hr_qp); + + if (hr_qp->ibqp.qp_type == IB_QPT_RC) { + /* RC QP, release QPN */ + hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1); + kfree(hr_qp); + } else + kfree(hr_to_hr_sqp(hr_qp)); + + kfree(qp_work_entry); + + dev_dbg(dev, "Accomplished destroy QP(0x%lx) work.\n", hr_qp->qpn); +} + +int hns_roce_v1_destroy_qp(struct ib_qp *ibqp) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); + struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_qp_work qp_work_entry; + struct hns_roce_qp_work *qp_work; + struct hns_roce_v1_priv *priv; + struct hns_roce_cq *send_cq, *recv_cq; + int is_user = !!ibqp->pd->uobject; + int is_timeout = 0; + int ret; + + ret = check_qp_reset_state(hr_dev, hr_qp, &qp_work_entry, &is_timeout); + if (ret) { + dev_err(dev, "QP reset state check failed(%d)!\n", ret); + return ret; } send_cq = to_hr_cq(hr_qp->ibqp.send_cq); recv_cq = to_hr_cq(hr_qp->ibqp.recv_cq); hns_roce_lock_cqs(send_cq, recv_cq); - if (!is_user) { __hns_roce_v1_cq_clean(recv_cq, hr_qp->qpn, hr_qp->ibqp.srq ? to_hr_srq(hr_qp->ibqp.srq) : NULL); if (send_cq != recv_cq) __hns_roce_v1_cq_clean(send_cq, hr_qp->qpn, NULL); } - - hns_roce_qp_remove(hr_dev, hr_qp); - hns_roce_unlock_cqs(send_cq, recv_cq); - hns_roce_qp_free(hr_dev, hr_qp); + if (!is_timeout) { + hns_roce_qp_remove(hr_dev, hr_qp); + hns_roce_qp_free(hr_dev, hr_qp); - /* Not special_QP, free their QPN */ - if ((hr_qp->ibqp.qp_type == IB_QPT_RC) || - (hr_qp->ibqp.qp_type == IB_QPT_UC) || - (hr_qp->ibqp.qp_type == IB_QPT_UD)) - hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1); + /* RC QP, release QPN */ + if (hr_qp->ibqp.qp_type == IB_QPT_RC) + hns_roce_release_range_qp(hr_dev, hr_qp->qpn, 1); + } hns_roce_mtt_cleanup(hr_dev, &hr_qp->mtt); - if (is_user) { + if (is_user) ib_umem_release(hr_qp->umem); - } else { + else { kfree(hr_qp->sq.wrid); kfree(hr_qp->rq.wrid); + hns_roce_buf_free(hr_dev, hr_qp->buff_size, &hr_qp->hr_buf); } -} -int hns_roce_v1_destroy_qp(struct ib_qp *ibqp) -{ - struct hns_roce_dev *hr_dev = to_hr_dev(ibqp->device); - struct hns_roce_qp *hr_qp = to_hr_qp(ibqp); - - hns_roce_v1_destroy_qp_common(hr_dev, hr_qp, !!ibqp->pd->uobject); - - if (hr_qp->ibqp.qp_type == IB_QPT_GSI) - kfree(hr_to_hr_sqp(hr_qp)); - else - kfree(hr_qp); + if (!is_timeout) { + if (hr_qp->ibqp.qp_type == IB_QPT_RC) + kfree(hr_qp); + else + kfree(hr_to_hr_sqp(hr_qp)); + } else { + qp_work = kzalloc(sizeof(*qp_work), GFP_KERNEL); + if (!qp_work) + return -ENOMEM; + + INIT_WORK(&qp_work->work, hns_roce_v1_destroy_qp_work_fn); + qp_work->ib_dev = &hr_dev->ib_dev; + qp_work->qp = hr_qp; + qp_work->db_wait_stage = qp_work_entry.db_wait_stage; + qp_work->sdb_issue_ptr = qp_work_entry.sdb_issue_ptr; + qp_work->sdb_inv_cnt = qp_work_entry.sdb_inv_cnt; + qp_work->sche_cnt = qp_work_entry.sche_cnt; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + queue_work(priv->des_qp.qp_wq, &qp_work->work); + dev_dbg(dev, "Begin destroy QP(0x%lx) work.\n", hr_qp->qpn); + } return 0; } diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h index cf28f1b6492c..1d250c026c10 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h @@ -102,6 +102,12 @@ #define HNS_ROCE_V1_EXT_ODB_ALFUL \ (HNS_ROCE_V1_EXT_ODB_DEPTH - HNS_ROCE_V1_DB_RSVD) +#define HNS_ROCE_V1_DB_WAIT_OK 0 +#define HNS_ROCE_V1_DB_STAGE1 1 +#define HNS_ROCE_V1_DB_STAGE2 2 +#define HNS_ROCE_V1_CHECK_DB_TIMEOUT_MSECS 10000 +#define HNS_ROCE_V1_CHECK_DB_SLEEP_MSECS 20 + #define HNS_ROCE_BT_RSV_BUF_SIZE (1 << 17) #define HNS_ROCE_V1_TPTR_ENTRY_SIZE 2 @@ -144,6 +150,7 @@ #define SQ_PSN_SHIFT 8 #define QKEY_VAL 0x80010000 #define SDB_INV_CNT_OFFSET 8 +#define SDB_ST_CMP_VAL 8 struct hns_roce_cq_context { u32 cqc_byte_4; @@ -993,11 +1000,27 @@ struct hns_roce_tptr_table { struct hns_roce_buf_list tptr_buf; }; +struct hns_roce_qp_work { + struct work_struct work; + struct ib_device *ib_dev; + struct hns_roce_qp *qp; + u32 db_wait_stage; + u32 sdb_issue_ptr; + u32 sdb_inv_cnt; + u32 sche_cnt; +}; + +struct hns_roce_des_qp { + struct workqueue_struct *qp_wq; + int requeue_flag; +}; + struct hns_roce_v1_priv { struct hns_roce_db_table db_table; struct hns_roce_raq_table raq_table; struct hns_roce_bt_table bt_table; struct hns_roce_tptr_table tptr_table; + struct hns_roce_des_qp des_qp; }; int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset); -- cgit v1.2.3 From bfcc681bd09d6cd96aa0ec667533a867253731aa Mon Sep 17 00:00:00 2001 From: Shaobo Xu Date: Tue, 29 Nov 2016 23:10:26 +0000 Subject: IB/hns: Fix the bug when free mr If the resources of mr are freed while executing the user case, hardware can not been notified in hip06 SoC. Then hardware will hold on when it reads the payload by the PA which has been released. In order to slove this problem, RoCE driver creates 8 reserved loopback QPs to ensure zero wqe when free mr. When the mac address is reset, in order to avoid loopback failure, we need to release the reserved loopback QPs and recreate them. Signed-off-by: Shaobo Xu Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cmd.h | 5 - drivers/infiniband/hw/hns/hns_roce_device.h | 10 + drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 485 ++++++++++++++++++++++++++++ drivers/infiniband/hw/hns/hns_roce_hw_v1.h | 34 ++ drivers/infiniband/hw/hns/hns_roce_main.c | 5 +- drivers/infiniband/hw/hns/hns_roce_mr.c | 21 +- 6 files changed, 545 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_cmd.h b/drivers/infiniband/hw/hns/hns_roce_cmd.h index ed14ad3d06ef..f5a9ee2fc53d 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cmd.h +++ b/drivers/infiniband/hw/hns/hns_roce_cmd.h @@ -58,11 +58,6 @@ enum { HNS_ROCE_CMD_QUERY_QP = 0x22, }; -struct hns_roce_cmd_mailbox { - void *buf; - dma_addr_t dma; -}; - int hns_roce_cmd_mbox(struct hns_roce_dev *hr_dev, u64 in_param, u64 out_param, unsigned long in_modifier, u8 op_modifier, u16 op, unsigned long timeout); diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index e48464ddd2b0..1050829da642 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -388,6 +388,11 @@ struct hns_roce_cmdq { u8 toggle; }; +struct hns_roce_cmd_mailbox { + void *buf; + dma_addr_t dma; +}; + struct hns_roce_dev; struct hns_roce_qp { @@ -522,6 +527,7 @@ struct hns_roce_hw { struct ib_recv_wr **bad_recv_wr); int (*req_notify_cq)(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); int (*poll_cq)(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); + int (*dereg_mr)(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr); void *priv; }; @@ -688,6 +694,10 @@ struct ib_mr *hns_roce_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, u64 virt_addr, int access_flags, struct ib_udata *udata); int hns_roce_dereg_mr(struct ib_mr *ibmr); +int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev, + struct hns_roce_cmd_mailbox *mailbox, + unsigned long mpt_index); +unsigned long key_to_hw_index(u32 key); void hns_roce_buf_free(struct hns_roce_dev *hr_dev, u32 size, struct hns_roce_buf *buf); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index aee1d01ca70c..f67a3bfd4c55 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -295,6 +295,8 @@ out: roce_set_field(sq_db.u32_4, SQ_DOORBELL_U32_4_SQ_HEAD_M, SQ_DOORBELL_U32_4_SQ_HEAD_S, (qp->sq.head & ((qp->sq.wqe_cnt << 1) - 1))); + roce_set_field(sq_db.u32_4, SQ_DOORBELL_U32_4_SL_M, + SQ_DOORBELL_U32_4_SL_S, qp->sl); roce_set_field(sq_db.u32_4, SQ_DOORBELL_U32_4_PORT_M, SQ_DOORBELL_U32_4_PORT_S, qp->phy_port); roce_set_field(sq_db.u32_8, SQ_DOORBELL_U32_8_QPN_M, @@ -622,6 +624,213 @@ ext_sdb_buf_fail_out: return ret; } +static struct hns_roce_qp *hns_roce_v1_create_lp_qp(struct hns_roce_dev *hr_dev, + struct ib_pd *pd) +{ + struct device *dev = &hr_dev->pdev->dev; + struct ib_qp_init_attr init_attr; + struct ib_qp *qp; + + memset(&init_attr, 0, sizeof(struct ib_qp_init_attr)); + init_attr.qp_type = IB_QPT_RC; + init_attr.sq_sig_type = IB_SIGNAL_ALL_WR; + init_attr.cap.max_recv_wr = HNS_ROCE_MIN_WQE_NUM; + init_attr.cap.max_send_wr = HNS_ROCE_MIN_WQE_NUM; + + qp = hns_roce_create_qp(pd, &init_attr, NULL); + if (IS_ERR(qp)) { + dev_err(dev, "Create loop qp for mr free failed!"); + return NULL; + } + + return to_hr_qp(qp); +} + +static int hns_roce_v1_rsv_lp_qp(struct hns_roce_dev *hr_dev) +{ + struct hns_roce_caps *caps = &hr_dev->caps; + struct device *dev = &hr_dev->pdev->dev; + struct ib_cq_init_attr cq_init_attr; + struct hns_roce_free_mr *free_mr; + struct ib_qp_attr attr = { 0 }; + struct hns_roce_v1_priv *priv; + struct hns_roce_qp *hr_qp; + struct ib_cq *cq; + struct ib_pd *pd; + u64 subnet_prefix; + int attr_mask = 0; + int i; + int ret; + u8 phy_port; + u8 sl; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + free_mr = &priv->free_mr; + + /* Reserved cq for loop qp */ + cq_init_attr.cqe = HNS_ROCE_MIN_WQE_NUM * 2; + cq_init_attr.comp_vector = 0; + cq = hns_roce_ib_create_cq(&hr_dev->ib_dev, &cq_init_attr, NULL, NULL); + if (IS_ERR(cq)) { + dev_err(dev, "Create cq for reseved loop qp failed!"); + return -ENOMEM; + } + free_mr->mr_free_cq = to_hr_cq(cq); + free_mr->mr_free_cq->ib_cq.device = &hr_dev->ib_dev; + free_mr->mr_free_cq->ib_cq.uobject = NULL; + free_mr->mr_free_cq->ib_cq.comp_handler = NULL; + free_mr->mr_free_cq->ib_cq.event_handler = NULL; + free_mr->mr_free_cq->ib_cq.cq_context = NULL; + atomic_set(&free_mr->mr_free_cq->ib_cq.usecnt, 0); + + pd = hns_roce_alloc_pd(&hr_dev->ib_dev, NULL, NULL); + if (IS_ERR(pd)) { + dev_err(dev, "Create pd for reseved loop qp failed!"); + ret = -ENOMEM; + goto alloc_pd_failed; + } + free_mr->mr_free_pd = to_hr_pd(pd); + free_mr->mr_free_pd->ibpd.device = &hr_dev->ib_dev; + free_mr->mr_free_pd->ibpd.uobject = NULL; + atomic_set(&free_mr->mr_free_pd->ibpd.usecnt, 0); + + attr.qp_access_flags = IB_ACCESS_REMOTE_WRITE; + attr.pkey_index = 0; + attr.min_rnr_timer = 0; + /* Disable read ability */ + attr.max_dest_rd_atomic = 0; + attr.max_rd_atomic = 0; + /* Use arbitrary values as rq_psn and sq_psn */ + attr.rq_psn = 0x0808; + attr.sq_psn = 0x0808; + attr.retry_cnt = 7; + attr.rnr_retry = 7; + attr.timeout = 0x12; + attr.path_mtu = IB_MTU_256; + attr.ah_attr.ah_flags = 1; + attr.ah_attr.static_rate = 3; + attr.ah_attr.grh.sgid_index = 0; + attr.ah_attr.grh.hop_limit = 1; + attr.ah_attr.grh.flow_label = 0; + attr.ah_attr.grh.traffic_class = 0; + + subnet_prefix = cpu_to_be64(0xfe80000000000000LL); + for (i = 0; i < HNS_ROCE_V1_RESV_QP; i++) { + free_mr->mr_free_qp[i] = hns_roce_v1_create_lp_qp(hr_dev, pd); + if (IS_ERR(free_mr->mr_free_qp[i])) { + dev_err(dev, "Create loop qp failed!\n"); + goto create_lp_qp_failed; + } + hr_qp = free_mr->mr_free_qp[i]; + + sl = i / caps->num_ports; + + if (caps->num_ports == HNS_ROCE_MAX_PORTS) + phy_port = (i >= HNS_ROCE_MAX_PORTS) ? (i - 2) : + (i % caps->num_ports); + else + phy_port = i % caps->num_ports; + + hr_qp->port = phy_port + 1; + hr_qp->phy_port = phy_port; + hr_qp->ibqp.qp_type = IB_QPT_RC; + hr_qp->ibqp.device = &hr_dev->ib_dev; + hr_qp->ibqp.uobject = NULL; + atomic_set(&hr_qp->ibqp.usecnt, 0); + hr_qp->ibqp.pd = pd; + hr_qp->ibqp.recv_cq = cq; + hr_qp->ibqp.send_cq = cq; + + attr.ah_attr.port_num = phy_port + 1; + attr.ah_attr.sl = sl; + attr.port_num = phy_port + 1; + + attr.dest_qp_num = hr_qp->qpn; + memcpy(attr.ah_attr.dmac, hr_dev->dev_addr[phy_port], + MAC_ADDR_OCTET_NUM); + + memcpy(attr.ah_attr.grh.dgid.raw, + &subnet_prefix, sizeof(u64)); + memcpy(&attr.ah_attr.grh.dgid.raw[8], + hr_dev->dev_addr[phy_port], 3); + memcpy(&attr.ah_attr.grh.dgid.raw[13], + hr_dev->dev_addr[phy_port] + 3, 3); + attr.ah_attr.grh.dgid.raw[11] = 0xff; + attr.ah_attr.grh.dgid.raw[12] = 0xfe; + attr.ah_attr.grh.dgid.raw[8] ^= 2; + + attr_mask |= IB_QP_PORT; + + ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, &attr, attr_mask, + IB_QPS_RESET, IB_QPS_INIT); + if (ret) { + dev_err(dev, "modify qp failed(%d)!\n", ret); + goto create_lp_qp_failed; + } + + ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, &attr, attr_mask, + IB_QPS_INIT, IB_QPS_RTR); + if (ret) { + dev_err(dev, "modify qp failed(%d)!\n", ret); + goto create_lp_qp_failed; + } + + ret = hr_dev->hw->modify_qp(&hr_qp->ibqp, &attr, attr_mask, + IB_QPS_RTR, IB_QPS_RTS); + if (ret) { + dev_err(dev, "modify qp failed(%d)!\n", ret); + goto create_lp_qp_failed; + } + } + + return 0; + +create_lp_qp_failed: + for (i -= 1; i >= 0; i--) { + hr_qp = free_mr->mr_free_qp[i]; + if (hns_roce_v1_destroy_qp(&hr_qp->ibqp)) + dev_err(dev, "Destroy qp %d for mr free failed!\n", i); + } + + if (hns_roce_dealloc_pd(pd)) + dev_err(dev, "Destroy pd for create_lp_qp failed!\n"); + +alloc_pd_failed: + if (hns_roce_ib_destroy_cq(cq)) + dev_err(dev, "Destroy cq for create_lp_qp failed!\n"); + + return -EINVAL; +} + +static void hns_roce_v1_release_lp_qp(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_free_mr *free_mr; + struct hns_roce_v1_priv *priv; + struct hns_roce_qp *hr_qp; + int ret; + int i; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + free_mr = &priv->free_mr; + + for (i = 0; i < HNS_ROCE_V1_RESV_QP; i++) { + hr_qp = free_mr->mr_free_qp[i]; + ret = hns_roce_v1_destroy_qp(&hr_qp->ibqp); + if (ret) + dev_err(dev, "Destroy qp %d for mr free failed(%d)!\n", + i, ret); + } + + ret = hns_roce_ib_destroy_cq(&free_mr->mr_free_cq->ib_cq); + if (ret) + dev_err(dev, "Destroy cq for mr_free failed(%d)!\n", ret); + + ret = hns_roce_dealloc_pd(&free_mr->mr_free_pd->ibpd); + if (ret) + dev_err(dev, "Destroy pd for mr_free failed(%d)!\n", ret); +} + static int hns_roce_db_init(struct hns_roce_dev *hr_dev) { struct device *dev = &hr_dev->pdev->dev; @@ -659,6 +868,223 @@ static int hns_roce_db_init(struct hns_roce_dev *hr_dev) return 0; } +void hns_roce_v1_recreate_lp_qp_work_fn(struct work_struct *work) +{ + struct hns_roce_recreate_lp_qp_work *lp_qp_work; + struct hns_roce_dev *hr_dev; + + lp_qp_work = container_of(work, struct hns_roce_recreate_lp_qp_work, + work); + hr_dev = to_hr_dev(lp_qp_work->ib_dev); + + hns_roce_v1_release_lp_qp(hr_dev); + + if (hns_roce_v1_rsv_lp_qp(hr_dev)) + dev_err(&hr_dev->pdev->dev, "create reserver qp failed\n"); + + if (lp_qp_work->comp_flag) + complete(lp_qp_work->comp); + + kfree(lp_qp_work); +} + +static int hns_roce_v1_recreate_lp_qp(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_recreate_lp_qp_work *lp_qp_work; + struct hns_roce_free_mr *free_mr; + struct hns_roce_v1_priv *priv; + struct completion comp; + unsigned long end = + msecs_to_jiffies(HNS_ROCE_V1_RECREATE_LP_QP_TIMEOUT_MSECS) + jiffies; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + free_mr = &priv->free_mr; + + lp_qp_work = kzalloc(sizeof(struct hns_roce_recreate_lp_qp_work), + GFP_KERNEL); + + INIT_WORK(&(lp_qp_work->work), hns_roce_v1_recreate_lp_qp_work_fn); + + lp_qp_work->ib_dev = &(hr_dev->ib_dev); + lp_qp_work->comp = ∁ + lp_qp_work->comp_flag = 1; + + init_completion(lp_qp_work->comp); + + queue_work(free_mr->free_mr_wq, &(lp_qp_work->work)); + + while (time_before_eq(jiffies, end)) { + if (try_wait_for_completion(&comp)) + return 0; + msleep(HNS_ROCE_V1_RECREATE_LP_QP_WAIT_VALUE); + } + + lp_qp_work->comp_flag = 0; + if (try_wait_for_completion(&comp)) + return 0; + + dev_warn(dev, "recreate lp qp failed 20s timeout and return failed!\n"); + return -ETIMEDOUT; +} + +static int hns_roce_v1_send_lp_wqe(struct hns_roce_qp *hr_qp) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(hr_qp->ibqp.device); + struct device *dev = &hr_dev->pdev->dev; + struct ib_send_wr send_wr, *bad_wr; + int ret; + + memset(&send_wr, 0, sizeof(send_wr)); + send_wr.next = NULL; + send_wr.num_sge = 0; + send_wr.send_flags = 0; + send_wr.sg_list = NULL; + send_wr.wr_id = (unsigned long long)&send_wr; + send_wr.opcode = IB_WR_RDMA_WRITE; + + ret = hns_roce_v1_post_send(&hr_qp->ibqp, &send_wr, &bad_wr); + if (ret) { + dev_err(dev, "Post write wqe for mr free failed(%d)!", ret); + return ret; + } + + return 0; +} + +static void hns_roce_v1_mr_free_work_fn(struct work_struct *work) +{ + struct hns_roce_mr_free_work *mr_work; + struct ib_wc wc[HNS_ROCE_V1_RESV_QP]; + struct hns_roce_free_mr *free_mr; + struct hns_roce_cq *mr_free_cq; + struct hns_roce_v1_priv *priv; + struct hns_roce_dev *hr_dev; + struct hns_roce_mr *hr_mr; + struct hns_roce_qp *hr_qp; + struct device *dev; + unsigned long end = + msecs_to_jiffies(HNS_ROCE_V1_FREE_MR_TIMEOUT_MSECS) + jiffies; + int i; + int ret; + int ne; + + mr_work = container_of(work, struct hns_roce_mr_free_work, work); + hr_mr = (struct hns_roce_mr *)mr_work->mr; + hr_dev = to_hr_dev(mr_work->ib_dev); + dev = &hr_dev->pdev->dev; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + free_mr = &priv->free_mr; + mr_free_cq = free_mr->mr_free_cq; + + for (i = 0; i < HNS_ROCE_V1_RESV_QP; i++) { + hr_qp = free_mr->mr_free_qp[i]; + ret = hns_roce_v1_send_lp_wqe(hr_qp); + if (ret) { + dev_err(dev, + "Send wqe (qp:0x%lx) for mr free failed(%d)!\n", + hr_qp->qpn, ret); + goto free_work; + } + } + + ne = HNS_ROCE_V1_RESV_QP; + do { + ret = hns_roce_v1_poll_cq(&mr_free_cq->ib_cq, ne, wc); + if (ret < 0) { + dev_err(dev, + "(qp:0x%lx) starts, Poll cqe failed(%d) for mr 0x%x free! Remain %d cqe\n", + hr_qp->qpn, ret, hr_mr->key, ne); + goto free_work; + } + ne -= ret; + msleep(HNS_ROCE_V1_FREE_MR_WAIT_VALUE); + } while (ne && time_before_eq(jiffies, end)); + + if (ne != 0) + dev_err(dev, + "Poll cqe for mr 0x%x free timeout! Remain %d cqe\n", + hr_mr->key, ne); + +free_work: + if (mr_work->comp_flag) + complete(mr_work->comp); + kfree(mr_work); +} + +int hns_roce_v1_dereg_mr(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_mr_free_work *mr_work; + struct hns_roce_free_mr *free_mr; + struct hns_roce_v1_priv *priv; + struct completion comp; + unsigned long end = + msecs_to_jiffies(HNS_ROCE_V1_FREE_MR_TIMEOUT_MSECS) + jiffies; + unsigned long start = jiffies; + int npages; + int ret = 0; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + free_mr = &priv->free_mr; + + if (mr->enabled) { + if (hns_roce_hw2sw_mpt(hr_dev, NULL, key_to_hw_index(mr->key) + & (hr_dev->caps.num_mtpts - 1))) + dev_warn(dev, "HW2SW_MPT failed!\n"); + } + + mr_work = kzalloc(sizeof(*mr_work), GFP_KERNEL); + if (!mr_work) { + ret = -ENOMEM; + goto free_mr; + } + + INIT_WORK(&(mr_work->work), hns_roce_v1_mr_free_work_fn); + + mr_work->ib_dev = &(hr_dev->ib_dev); + mr_work->comp = ∁ + mr_work->comp_flag = 1; + mr_work->mr = (void *)mr; + init_completion(mr_work->comp); + + queue_work(free_mr->free_mr_wq, &(mr_work->work)); + + while (time_before_eq(jiffies, end)) { + if (try_wait_for_completion(&comp)) + goto free_mr; + msleep(HNS_ROCE_V1_FREE_MR_WAIT_VALUE); + } + + mr_work->comp_flag = 0; + if (try_wait_for_completion(&comp)) + goto free_mr; + + dev_warn(dev, "Free mr work 0x%x over 50s and failed!\n", mr->key); + ret = -ETIMEDOUT; + +free_mr: + dev_dbg(dev, "Free mr 0x%x use 0x%x us.\n", + mr->key, jiffies_to_usecs(jiffies) - jiffies_to_usecs(start)); + + if (mr->size != ~0ULL) { + npages = ib_umem_page_count(mr->umem); + dma_free_coherent(dev, npages * 8, mr->pbl_buf, + mr->pbl_dma_addr); + } + + hns_roce_bitmap_free(&hr_dev->mr_table.mtpt_bitmap, + key_to_hw_index(mr->key), 0); + + if (mr->umem) + ib_umem_release(mr->umem); + + kfree(mr); + + return ret; +} + static void hns_roce_db_free(struct hns_roce_dev *hr_dev) { struct device *dev = &hr_dev->pdev->dev; @@ -899,6 +1325,46 @@ static void hns_roce_tptr_free(struct hns_roce_dev *hr_dev) tptr_buf->buf, tptr_buf->map); } +static int hns_roce_free_mr_init(struct hns_roce_dev *hr_dev) +{ + struct device *dev = &hr_dev->pdev->dev; + struct hns_roce_free_mr *free_mr; + struct hns_roce_v1_priv *priv; + int ret = 0; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + free_mr = &priv->free_mr; + + free_mr->free_mr_wq = create_singlethread_workqueue("hns_roce_free_mr"); + if (!free_mr->free_mr_wq) { + dev_err(dev, "Create free mr workqueue failed!\n"); + return -ENOMEM; + } + + ret = hns_roce_v1_rsv_lp_qp(hr_dev); + if (ret) { + dev_err(dev, "Reserved loop qp failed(%d)!\n", ret); + flush_workqueue(free_mr->free_mr_wq); + destroy_workqueue(free_mr->free_mr_wq); + } + + return ret; +} + +static void hns_roce_free_mr_free(struct hns_roce_dev *hr_dev) +{ + struct hns_roce_free_mr *free_mr; + struct hns_roce_v1_priv *priv; + + priv = (struct hns_roce_v1_priv *)hr_dev->hw->priv; + free_mr = &priv->free_mr; + + flush_workqueue(free_mr->free_mr_wq); + destroy_workqueue(free_mr->free_mr_wq); + + hns_roce_v1_release_lp_qp(hr_dev); +} + /** * hns_roce_v1_reset - reset RoCE * @hr_dev: RoCE device struct pointer @@ -1100,10 +1566,19 @@ int hns_roce_v1_init(struct hns_roce_dev *hr_dev) goto error_failed_des_qp_init; } + ret = hns_roce_free_mr_init(hr_dev); + if (ret) { + dev_err(dev, "free mr init failed!\n"); + goto error_failed_free_mr_init; + } + hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_UP); return 0; +error_failed_free_mr_init: + hns_roce_des_qp_free(hr_dev); + error_failed_des_qp_init: hns_roce_tptr_free(hr_dev); @@ -1121,6 +1596,7 @@ error_failed_raq_init: void hns_roce_v1_exit(struct hns_roce_dev *hr_dev) { hns_roce_port_enable(hr_dev, HNS_ROCE_PORT_DOWN); + hns_roce_free_mr_free(hr_dev); hns_roce_des_qp_free(hr_dev); hns_roce_tptr_free(hr_dev); hns_roce_bt_free(hr_dev); @@ -1161,6 +1637,14 @@ void hns_roce_v1_set_mac(struct hns_roce_dev *hr_dev, u8 phy_port, u8 *addr) u32 *p; u32 val; + /* + * When mac changed, loopback may fail + * because of smac not equal to dmac. + * We Need to release and create reserved qp again. + */ + if (hr_dev->hw->dereg_mr && hns_roce_v1_recreate_lp_qp(hr_dev)) + dev_warn(&hr_dev->pdev->dev, "recreate lp qp timeout!\n"); + p = (u32 *)(&addr[0]); reg_smac_l = *p; roce_raw_write(reg_smac_l, hr_dev->reg_base + ROCEE_SMAC_L_0_REG + @@ -3299,5 +3783,6 @@ struct hns_roce_hw hns_roce_hw_v1 = { .post_recv = hns_roce_v1_post_recv, .req_notify_cq = hns_roce_v1_req_notify_cq, .poll_cq = hns_roce_v1_poll_cq, + .dereg_mr = hns_roce_v1_dereg_mr, .priv = &hr_v1_priv, }; diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h index 1d250c026c10..b213b5e6fef1 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.h +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.h @@ -58,6 +58,7 @@ #define HNS_ROCE_V1_PHY_UAR_NUM 8 #define HNS_ROCE_V1_GID_NUM 16 +#define HNS_ROCE_V1_RESV_QP 8 #define HNS_ROCE_V1_NUM_COMP_EQE 0x8000 #define HNS_ROCE_V1_NUM_ASYNC_EQE 0x400 @@ -107,6 +108,10 @@ #define HNS_ROCE_V1_DB_STAGE2 2 #define HNS_ROCE_V1_CHECK_DB_TIMEOUT_MSECS 10000 #define HNS_ROCE_V1_CHECK_DB_SLEEP_MSECS 20 +#define HNS_ROCE_V1_FREE_MR_TIMEOUT_MSECS 50000 +#define HNS_ROCE_V1_RECREATE_LP_QP_TIMEOUT_MSECS 10000 +#define HNS_ROCE_V1_FREE_MR_WAIT_VALUE 5 +#define HNS_ROCE_V1_RECREATE_LP_QP_WAIT_VALUE 20 #define HNS_ROCE_BT_RSV_BUF_SIZE (1 << 17) @@ -969,6 +974,10 @@ struct hns_roce_sq_db { #define SQ_DOORBELL_U32_4_SQ_HEAD_M \ (((1UL << 15) - 1) << SQ_DOORBELL_U32_4_SQ_HEAD_S) +#define SQ_DOORBELL_U32_4_SL_S 16 +#define SQ_DOORBELL_U32_4_SL_M \ + (((1UL << 2) - 1) << SQ_DOORBELL_U32_4_SL_S) + #define SQ_DOORBELL_U32_4_PORT_S 18 #define SQ_DOORBELL_U32_4_PORT_M (((1UL << 3) - 1) << SQ_DOORBELL_U32_4_PORT_S) @@ -1015,14 +1024,39 @@ struct hns_roce_des_qp { int requeue_flag; }; +struct hns_roce_mr_free_work { + struct work_struct work; + struct ib_device *ib_dev; + struct completion *comp; + int comp_flag; + void *mr; +}; + +struct hns_roce_recreate_lp_qp_work { + struct work_struct work; + struct ib_device *ib_dev; + struct completion *comp; + int comp_flag; +}; + +struct hns_roce_free_mr { + struct workqueue_struct *free_mr_wq; + struct hns_roce_qp *mr_free_qp[HNS_ROCE_V1_RESV_QP]; + struct hns_roce_cq *mr_free_cq; + struct hns_roce_pd *mr_free_pd; +}; + struct hns_roce_v1_priv { struct hns_roce_db_table db_table; struct hns_roce_raq_table raq_table; struct hns_roce_bt_table bt_table; struct hns_roce_tptr_table tptr_table; struct hns_roce_des_qp des_qp; + struct hns_roce_free_mr free_mr; }; int hns_dsaf_roce_reset(struct fwnode_handle *dsaf_fwnode, bool dereset); +int hns_roce_v1_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); +int hns_roce_v1_destroy_qp(struct ib_qp *ibqp); #endif diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 914d0ac7881c..0cedec0c5576 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -129,7 +129,6 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, { struct device *dev = &hr_dev->pdev->dev; struct net_device *netdev; - unsigned long flags; netdev = hr_dev->iboe.netdevs[port]; if (!netdev) { @@ -137,7 +136,7 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, return -ENODEV; } - spin_lock_irqsave(&hr_dev->iboe.lock, flags); + spin_lock_bh(&hr_dev->iboe.lock); switch (event) { case NETDEV_UP: @@ -156,7 +155,7 @@ static int handle_en_event(struct hns_roce_dev *hr_dev, u8 port, break; } - spin_unlock_irqrestore(&hr_dev->iboe.lock, flags); + spin_unlock_bh(&hr_dev->iboe.lock); return 0; } diff --git a/drivers/infiniband/hw/hns/hns_roce_mr.c b/drivers/infiniband/hw/hns/hns_roce_mr.c index 9b8a1ad4ee6c..4139abee3b54 100644 --- a/drivers/infiniband/hw/hns/hns_roce_mr.c +++ b/drivers/infiniband/hw/hns/hns_roce_mr.c @@ -42,7 +42,7 @@ static u32 hw_index_to_key(unsigned long ind) return (u32)(ind >> 24) | (ind << 8); } -static unsigned long key_to_hw_index(u32 key) +unsigned long key_to_hw_index(u32 key) { return (key << 24) | (key >> 8); } @@ -56,7 +56,7 @@ static int hns_roce_sw2hw_mpt(struct hns_roce_dev *hr_dev, HNS_ROCE_CMD_TIMEOUT_MSECS); } -static int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev, +int hns_roce_hw2sw_mpt(struct hns_roce_dev *hr_dev, struct hns_roce_cmd_mailbox *mailbox, unsigned long mpt_index) { @@ -607,13 +607,20 @@ err_free: int hns_roce_dereg_mr(struct ib_mr *ibmr) { + struct hns_roce_dev *hr_dev = to_hr_dev(ibmr->device); struct hns_roce_mr *mr = to_hr_mr(ibmr); + int ret = 0; - hns_roce_mr_free(to_hr_dev(ibmr->device), mr); - if (mr->umem) - ib_umem_release(mr->umem); + if (hr_dev->hw->dereg_mr) { + ret = hr_dev->hw->dereg_mr(hr_dev, mr); + } else { + hns_roce_mr_free(hr_dev, mr); - kfree(mr); + if (mr->umem) + ib_umem_release(mr->umem); - return 0; + kfree(mr); + } + + return ret; } -- cgit v1.2.3 From 9daed0affa1378cbfbc549de6a2b25c778c15bda Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Tue, 29 Nov 2016 23:10:27 +0000 Subject: IB/hns: Fix the bug of setting port mtu In hns_roce driver, we need not call iboe_get_mtu to reduce IB headers from effective IBoE MTU because hr_dev->caps.max_mtu has already been reduced. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_main.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 0cedec0c5576..5e620f9f13d2 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -72,18 +72,6 @@ static void hns_roce_set_mac(struct hns_roce_dev *hr_dev, u8 port, u8 *addr) hr_dev->hw->set_mac(hr_dev, phy_port, addr); } -static void hns_roce_set_mtu(struct hns_roce_dev *hr_dev, u8 port, int mtu) -{ - u8 phy_port = hr_dev->iboe.phy_port[port]; - enum ib_mtu tmp; - - tmp = iboe_get_mtu(mtu); - if (!tmp) - tmp = IB_MTU_256; - - hr_dev->hw->set_mtu(hr_dev, phy_port, tmp); -} - static int hns_roce_add_gid(struct ib_device *device, u8 port_num, unsigned int index, const union ib_gid *gid, const struct ib_gid_attr *attr, void **context) @@ -188,8 +176,8 @@ static int hns_roce_setup_mtu_mac(struct hns_roce_dev *hr_dev) u8 i; for (i = 0; i < hr_dev->caps.num_ports; i++) { - hns_roce_set_mtu(hr_dev, i, - ib_mtu_enum_to_int(hr_dev->caps.max_mtu)); + hr_dev->hw->set_mtu(hr_dev, hr_dev->iboe.phy_port[i], + hr_dev->caps.max_mtu); hns_roce_set_mac(hr_dev, i, hr_dev->iboe.netdevs[i]->dev_addr); } -- cgit v1.2.3 From 19a408efa099e6ebe5458d4fc1ba4630d9daf9d4 Mon Sep 17 00:00:00 2001 From: "Wei Hu (Xavier)" Date: Tue, 29 Nov 2016 23:10:28 +0000 Subject: IB/hns: Delete the redundant memset operation It deleted the redundant memset operation because the memory allocated by ib_alloc_device has been set zero. Signed-off-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_main.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 5e620f9f13d2..28a8f24366df 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -843,9 +843,6 @@ static int hns_roce_probe(struct platform_device *pdev) if (!hr_dev) return -ENOMEM; - memset((u8 *)hr_dev + sizeof(struct ib_device), 0, - sizeof(struct hns_roce_dev) - sizeof(struct ib_device)); - hr_dev->pdev = pdev; platform_set_drvdata(pdev, hr_dev); -- cgit v1.2.3 From afb6b092d6507b17c75df394b1d1b2a6e1674627 Mon Sep 17 00:00:00 2001 From: Shaobo Xu Date: Tue, 29 Nov 2016 23:10:29 +0000 Subject: IB/hns: Fix the bug when free cq If the resources of cq are freed while executing the user case, hardware can not been notified in hip06 SoC. Then hardware will hold on when it writes the cq buffer which has been released. In order to slove this problem, RoCE driver checks the CQE counter, and ensure that the outstanding CQE have been written. Then the cq buffer can be released. Signed-off-by: Shaobo Xu Reviewed-by: Wei Hu (Xavier) Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_common.h | 2 ++ drivers/infiniband/hw/hns/hns_roce_cq.c | 27 +++++++++------ drivers/infiniband/hw/hns/hns_roce_device.h | 8 +++++ drivers/infiniband/hw/hns/hns_roce_hw_v1.c | 53 +++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_common.h b/drivers/infiniband/hw/hns/hns_roce_common.h index a0556323a678..4af403e1348c 100644 --- a/drivers/infiniband/hw/hns/hns_roce_common.h +++ b/drivers/infiniband/hw/hns/hns_roce_common.h @@ -354,6 +354,8 @@ #define ROCEE_SDB_ISSUE_PTR_REG 0x758 #define ROCEE_SDB_SEND_PTR_REG 0x75C +#define ROCEE_CAEP_CQE_WCMD_EMPTY 0x850 +#define ROCEE_SCAEP_WR_CQE_CNT 0x8D0 #define ROCEE_SDB_INV_CNT_REG 0x9A4 #define ROCEE_SDB_RETRY_CNT_REG 0x9AC #define ROCEE_TSP_BP_ST_REG 0x9EC diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index c9f6c3dce83c..ff9a6a3c826a 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -179,8 +179,7 @@ static int hns_roce_hw2sw_cq(struct hns_roce_dev *dev, HNS_ROCE_CMD_TIMEOUT_MSECS); } -static void hns_roce_free_cq(struct hns_roce_dev *hr_dev, - struct hns_roce_cq *hr_cq) +void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq) { struct hns_roce_cq_table *cq_table = &hr_dev->cq_table; struct device *dev = &hr_dev->pdev->dev; @@ -392,19 +391,25 @@ int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq) { struct hns_roce_dev *hr_dev = to_hr_dev(ib_cq->device); struct hns_roce_cq *hr_cq = to_hr_cq(ib_cq); + int ret = 0; - hns_roce_free_cq(hr_dev, hr_cq); - hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt); + if (hr_dev->hw->destroy_cq) { + ret = hr_dev->hw->destroy_cq(ib_cq); + } else { + hns_roce_free_cq(hr_dev, hr_cq); + hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt); - if (ib_cq->uobject) - ib_umem_release(hr_cq->umem); - else - /* Free the buff of stored cq */ - hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf, ib_cq->cqe); + if (ib_cq->uobject) + ib_umem_release(hr_cq->umem); + else + /* Free the buff of stored cq */ + hns_roce_ib_free_cq_buf(hr_dev, &hr_cq->hr_buf, + ib_cq->cqe); - kfree(hr_cq); + kfree(hr_cq); + } - return 0; + return ret; } void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn) diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 1050829da642..d4f0fce98587 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -56,6 +56,12 @@ #define HNS_ROCE_MAX_INNER_MTPT_NUM 0x7 #define HNS_ROCE_MAX_MTPT_PBL_NUM 0x100000 +#define HNS_ROCE_EACH_FREE_CQ_WAIT_MSECS 20 +#define HNS_ROCE_MAX_FREE_CQ_WAIT_CNT \ + (5000 / HNS_ROCE_EACH_FREE_CQ_WAIT_MSECS) +#define HNS_ROCE_CQE_WCMD_EMPTY_BIT 0x2 +#define HNS_ROCE_MIN_CQE_CNT 16 + #define HNS_ROCE_MAX_IRQ_NUM 34 #define HNS_ROCE_COMP_VEC_NUM 32 @@ -528,6 +534,7 @@ struct hns_roce_hw { int (*req_notify_cq)(struct ib_cq *ibcq, enum ib_cq_notify_flags flags); int (*poll_cq)(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); int (*dereg_mr)(struct hns_roce_dev *hr_dev, struct hns_roce_mr *mr); + int (*destroy_cq)(struct ib_cq *ibcq); void *priv; }; @@ -734,6 +741,7 @@ struct ib_cq *hns_roce_ib_create_cq(struct ib_device *ib_dev, struct ib_udata *udata); int hns_roce_ib_destroy_cq(struct ib_cq *ib_cq); +void hns_roce_free_cq(struct hns_roce_dev *hr_dev, struct hns_roce_cq *hr_cq); void hns_roce_cq_completion(struct hns_roce_dev *hr_dev, u32 cqn); void hns_roce_cq_event(struct hns_roce_dev *hr_dev, u32 cqn, int event_type); diff --git a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c index f67a3bfd4c55..b8111b0c8877 100644 --- a/drivers/infiniband/hw/hns/hns_roce_hw_v1.c +++ b/drivers/infiniband/hw/hns/hns_roce_hw_v1.c @@ -3763,6 +3763,58 @@ int hns_roce_v1_destroy_qp(struct ib_qp *ibqp) return 0; } +int hns_roce_v1_destroy_cq(struct ib_cq *ibcq) +{ + struct hns_roce_dev *hr_dev = to_hr_dev(ibcq->device); + struct hns_roce_cq *hr_cq = to_hr_cq(ibcq); + struct device *dev = &hr_dev->pdev->dev; + u32 cqe_cnt_ori; + u32 cqe_cnt_cur; + u32 cq_buf_size; + int wait_time = 0; + int ret = 0; + + hns_roce_free_cq(hr_dev, hr_cq); + + /* + * Before freeing cq buffer, we need to ensure that the outstanding CQE + * have been written by checking the CQE counter. + */ + cqe_cnt_ori = roce_read(hr_dev, ROCEE_SCAEP_WR_CQE_CNT); + while (1) { + if (roce_read(hr_dev, ROCEE_CAEP_CQE_WCMD_EMPTY) & + HNS_ROCE_CQE_WCMD_EMPTY_BIT) + break; + + cqe_cnt_cur = roce_read(hr_dev, ROCEE_SCAEP_WR_CQE_CNT); + if ((cqe_cnt_cur - cqe_cnt_ori) >= HNS_ROCE_MIN_CQE_CNT) + break; + + msleep(HNS_ROCE_EACH_FREE_CQ_WAIT_MSECS); + if (wait_time > HNS_ROCE_MAX_FREE_CQ_WAIT_CNT) { + dev_warn(dev, "Destroy cq 0x%lx timeout!\n", + hr_cq->cqn); + ret = -ETIMEDOUT; + break; + } + wait_time++; + } + + hns_roce_mtt_cleanup(hr_dev, &hr_cq->hr_buf.hr_mtt); + + if (ibcq->uobject) + ib_umem_release(hr_cq->umem); + else { + /* Free the buff of stored cq */ + cq_buf_size = (ibcq->cqe + 1) * hr_dev->caps.cq_entry_sz; + hns_roce_buf_free(hr_dev, cq_buf_size, &hr_cq->hr_buf.hr_buf); + } + + kfree(hr_cq); + + return ret; +} + struct hns_roce_v1_priv hr_v1_priv; struct hns_roce_hw hns_roce_hw_v1 = { @@ -3784,5 +3836,6 @@ struct hns_roce_hw hns_roce_hw_v1 = { .req_notify_cq = hns_roce_v1_req_notify_cq, .poll_cq = hns_roce_v1_poll_cq, .dereg_mr = hns_roce_v1_dereg_mr, + .destroy_cq = hns_roce_v1_destroy_cq, .priv = &hr_v1_priv, }; -- cgit v1.2.3 From 3b5184be89449275e5396512ab0127fc19ce359e Mon Sep 17 00:00:00 2001 From: Lijun Ou Date: Tue, 29 Nov 2016 23:10:30 +0000 Subject: IB/hns: Fix the IB device name This patch mainly fix the name for IB device in order to match with libhns. Signed-off-by: Lijun Ou Signed-off-by: Salil Mehta Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index 28a8f24366df..eddb053ff0ba 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -433,7 +433,7 @@ static int hns_roce_register_device(struct hns_roce_dev *hr_dev) spin_lock_init(&iboe->lock); ib_dev = &hr_dev->ib_dev; - strlcpy(ib_dev->name, "hisi_%d", IB_DEVICE_NAME_MAX); + strlcpy(ib_dev->name, "hns_%d", IB_DEVICE_NAME_MAX); ib_dev->owner = THIS_MODULE; ib_dev->node_type = RDMA_NODE_IB_CA; -- cgit v1.2.3 From 4d4099584c2c4dca6c04d78ded4cc81f50cc3634 Mon Sep 17 00:00:00 2001 From: Leon Romanovsky Date: Wed, 19 Oct 2016 20:13:07 +0300 Subject: IB/hns: Move HNS RoCE user vendor structures This patch moves HNS vendor's specific structures to common UAPI folder which will be visible to all consumers. Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hns/hns_roce_cq.c | 2 +- drivers/infiniband/hw/hns/hns_roce_main.c | 2 +- drivers/infiniband/hw/hns/hns_roce_qp.c | 2 +- drivers/infiniband/hw/hns/hns_roce_user.h | 53 ------------------------------ include/uapi/rdma/Kbuild | 1 + include/uapi/rdma/hns-abi.h | 54 +++++++++++++++++++++++++++++++ 6 files changed, 58 insertions(+), 56 deletions(-) delete mode 100644 drivers/infiniband/hw/hns/hns_roce_user.h create mode 100644 include/uapi/rdma/hns-abi.h (limited to 'drivers') diff --git a/drivers/infiniband/hw/hns/hns_roce_cq.c b/drivers/infiniband/hw/hns/hns_roce_cq.c index ff9a6a3c826a..589496c8fb9e 100644 --- a/drivers/infiniband/hw/hns/hns_roce_cq.c +++ b/drivers/infiniband/hw/hns/hns_roce_cq.c @@ -35,7 +35,7 @@ #include "hns_roce_device.h" #include "hns_roce_cmd.h" #include "hns_roce_hem.h" -#include "hns_roce_user.h" +#include #include "hns_roce_common.h" static void hns_roce_ib_cq_comp(struct hns_roce_cq *hr_cq) diff --git a/drivers/infiniband/hw/hns/hns_roce_main.c b/drivers/infiniband/hw/hns/hns_roce_main.c index eddb053ff0ba..4953d9cb83a7 100644 --- a/drivers/infiniband/hw/hns/hns_roce_main.c +++ b/drivers/infiniband/hw/hns/hns_roce_main.c @@ -38,7 +38,7 @@ #include #include "hns_roce_common.h" #include "hns_roce_device.h" -#include "hns_roce_user.h" +#include #include "hns_roce_hem.h" /** diff --git a/drivers/infiniband/hw/hns/hns_roce_qp.c b/drivers/infiniband/hw/hns/hns_roce_qp.c index 4775b5c725a9..f036f32f15d3 100644 --- a/drivers/infiniband/hw/hns/hns_roce_qp.c +++ b/drivers/infiniband/hw/hns/hns_roce_qp.c @@ -37,7 +37,7 @@ #include "hns_roce_common.h" #include "hns_roce_device.h" #include "hns_roce_hem.h" -#include "hns_roce_user.h" +#include #define SQP_NUM (2 * HNS_ROCE_MAX_PORTS) diff --git a/drivers/infiniband/hw/hns/hns_roce_user.h b/drivers/infiniband/hw/hns/hns_roce_user.h deleted file mode 100644 index a28f761a9f65..000000000000 --- a/drivers/infiniband/hw/hns/hns_roce_user.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2016 Hisilicon Limited. - * - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available from the file - * COPYING in the main directory of this source tree, or the - * OpenIB.org BSD license below: - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above - * copyright notice, this list of conditions and the following - * disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef _HNS_ROCE_USER_H -#define _HNS_ROCE_USER_H - -struct hns_roce_ib_create_cq { - __u64 buf_addr; -}; - -struct hns_roce_ib_create_qp { - __u64 buf_addr; - __u64 db_addr; - __u8 log_sq_bb_count; - __u8 log_sq_stride; - __u8 sq_no_prefetch; - __u8 reserved[5]; -}; - -struct hns_roce_ib_alloc_ucontext_resp { - __u32 qp_tab_size; -}; - -#endif /*_HNS_ROCE_USER_H */ diff --git a/include/uapi/rdma/Kbuild b/include/uapi/rdma/Kbuild index f14ab7ff5fee..b54f10d3c1f7 100644 --- a/include/uapi/rdma/Kbuild +++ b/include/uapi/rdma/Kbuild @@ -14,3 +14,4 @@ header-y += mlx5-abi.h header-y += mthca-abi.h header-y += nes-abi.h header-y += ocrdma-abi.h +header-y += hns-abi.h diff --git a/include/uapi/rdma/hns-abi.h b/include/uapi/rdma/hns-abi.h new file mode 100644 index 000000000000..5d7401963e35 --- /dev/null +++ b/include/uapi/rdma/hns-abi.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2016 Hisilicon Limited. + * + * This software is available to you under a choice of one of two + * licenses. You may choose to be licensed under the terms of the GNU + * General Public License (GPL) Version 2, available from the file + * COPYING in the main directory of this source tree, or the + * OpenIB.org BSD license below: + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef HNS_ABI_USER_H +#define HNS_ABI_USER_H + +#include + +struct hns_roce_ib_create_cq { + __u64 buf_addr; +}; + +struct hns_roce_ib_create_qp { + __u64 buf_addr; + __u64 db_addr; + __u8 log_sq_bb_count; + __u8 log_sq_stride; + __u8 sq_no_prefetch; + __u8 reserved[5]; +}; + +struct hns_roce_ib_alloc_ucontext_resp { + __u32 qp_tab_size; +}; +#endif /* HNS_ABI_USER_H */ -- cgit v1.2.3 From 0fc2dc58896f182daeeb4a7b5fc8d763afec3117 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Mon, 10 Oct 2016 21:12:10 -0500 Subject: i40iw: Add Quality of Service support Add support for QoS on QPs. Upon device initialization, a map is created from user priority to queue set handles. On QP creation, use ToS to look up the queue set handle for use with the QP. Signed-off-by: Faisal Latif Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw.h | 9 ++ drivers/infiniband/hw/i40iw/i40iw_cm.c | 30 +++++- drivers/infiniband/hw/i40iw/i40iw_cm.h | 2 +- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 151 +++++++++++++++++++++++++++++- drivers/infiniband/hw/i40iw/i40iw_d.h | 2 + drivers/infiniband/hw/i40iw/i40iw_hw.c | 25 ++--- drivers/infiniband/hw/i40iw/i40iw_main.c | 66 +++++++++++-- drivers/infiniband/hw/i40iw/i40iw_osdep.h | 2 + drivers/infiniband/hw/i40iw/i40iw_p.h | 2 + drivers/infiniband/hw/i40iw/i40iw_puda.c | 3 +- drivers/infiniband/hw/i40iw/i40iw_type.h | 18 +++- drivers/infiniband/hw/i40iw/i40iw_utils.c | 45 +++++++++ drivers/infiniband/hw/i40iw/i40iw_verbs.c | 6 +- 13 files changed, 325 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index 8ec09e470f84..4a0c12bd9caa 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -210,6 +210,12 @@ struct i40iw_msix_vector { u32 ceq_id; }; +struct l2params_work { + struct work_struct work; + struct i40iw_device *iwdev; + struct i40iw_l2params l2params; +}; + #define I40IW_MSIX_TABLE_SIZE 65 struct virtchnl_work { @@ -514,6 +520,9 @@ void i40iw_add_pdusecount(struct i40iw_pd *iwpd); void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp, struct i40iw_modify_qp_info *info, bool wait); +void i40iw_qp_suspend_resume(struct i40iw_sc_dev *dev, + struct i40iw_sc_qp *qp, + bool suspend); enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev, struct i40iw_cm_info *cminfo, enum i40iw_quad_entry_type etype, diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 85637696f6e9..24b22e99003c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -221,6 +221,7 @@ static void i40iw_get_addr_info(struct i40iw_cm_node *cm_node, memcpy(cm_info->rem_addr, cm_node->rem_addr, sizeof(cm_info->rem_addr)); cm_info->loc_port = cm_node->loc_port; cm_info->rem_port = cm_node->rem_port; + cm_info->user_pri = cm_node->user_pri; } /** @@ -396,6 +397,7 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, u32 opts_len = 0; u32 pd_len = 0; u32 hdr_len = 0; + u16 vtag; sqbuf = i40iw_puda_get_bufpool(dev->ilq); if (!sqbuf) @@ -445,7 +447,8 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, ether_addr_copy(ethh->h_source, cm_node->loc_mac); if (cm_node->vlan_id < VLAN_TAG_PRESENT) { ((struct vlan_ethhdr *)ethh)->h_vlan_proto = htons(ETH_P_8021Q); - ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(cm_node->vlan_id); + vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) | cm_node->vlan_id; + ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag); ((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto = htons(ETH_P_IP); } else { @@ -474,7 +477,8 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, ether_addr_copy(ethh->h_source, cm_node->loc_mac); if (cm_node->vlan_id < VLAN_TAG_PRESENT) { ((struct vlan_ethhdr *)ethh)->h_vlan_proto = htons(ETH_P_8021Q); - ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(cm_node->vlan_id); + vtag = (cm_node->user_pri << VLAN_PRIO_SHIFT) | cm_node->vlan_id; + ((struct vlan_ethhdr *)ethh)->h_vlan_TCI = htons(vtag); ((struct vlan_ethhdr *)ethh)->h_vlan_encapsulated_proto = htons(ETH_P_IPV6); } else { ethh->h_proto = htons(ETH_P_IPV6); @@ -1880,6 +1884,7 @@ static int i40iw_dec_refcnt_listen(struct i40iw_cm_core *cm_core, nfo.loc_port = listener->loc_port; nfo.ipv4 = listener->ipv4; nfo.vlan_id = listener->vlan_id; + nfo.user_pri = listener->user_pri; if (!list_empty(&listener->child_listen_list)) { i40iw_del_multiple_qhash(listener->iwdev, &nfo, listener); @@ -2138,6 +2143,11 @@ static struct i40iw_cm_node *i40iw_make_cm_node( /* set our node specific transport info */ cm_node->ipv4 = cm_info->ipv4; cm_node->vlan_id = cm_info->vlan_id; + if ((cm_node->vlan_id == I40IW_NO_VLAN) && iwdev->dcb) + cm_node->vlan_id = 0; + cm_node->user_pri = cm_info->user_pri; + if (listener) + cm_node->user_pri = listener->user_pri; memcpy(cm_node->loc_addr, cm_info->loc_addr, sizeof(cm_node->loc_addr)); memcpy(cm_node->rem_addr, cm_info->rem_addr, sizeof(cm_node->rem_addr)); cm_node->loc_port = cm_info->loc_port; @@ -3055,6 +3065,7 @@ void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf) struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; struct i40iw_cm_core *cm_core = &iwdev->cm_core; struct vlan_ethhdr *ethh; + u16 vtag; /* if vlan, then maclen = 18 else 14 */ iph = (struct iphdr *)rbuf->iph; @@ -3068,7 +3079,9 @@ void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf) ethh = (struct vlan_ethhdr *)rbuf->mem.va; if (ethh->h_vlan_proto == htons(ETH_P_8021Q)) { - cm_info.vlan_id = ntohs(ethh->h_vlan_TCI) & VLAN_VID_MASK; + vtag = ntohs(ethh->h_vlan_TCI); + cm_info.user_pri = (vtag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; + cm_info.vlan_id = vtag & VLAN_VID_MASK; i40iw_debug(cm_core->dev, I40IW_DEBUG_CM, "%s vlan_id=%d\n", @@ -3309,6 +3322,8 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp, ctx_info->tcp_info_valid = true; ctx_info->iwarp_info_valid = true; + ctx_info->add_to_qoslist = true; + ctx_info->user_pri = cm_node->user_pri; i40iw_init_tcp_ctx(cm_node, &tcp_info, iwqp); if (cm_node->snd_mark_en) { @@ -3326,6 +3341,7 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp, /* once tcp_info is set, no need to do it again */ ctx_info->tcp_info_valid = false; ctx_info->iwarp_info_valid = false; + ctx_info->add_to_qoslist = false; } /** @@ -3759,6 +3775,9 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) i40iw_netdev_vlan_ipv6(cm_info.loc_addr, &cm_info.vlan_id, NULL); } cm_info.cm_id = cm_id; + cm_info.user_pri = rt_tos2priority(cm_id->tos); + i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "%s TOS:[%d] UP:[%d]\n", + __func__, cm_id->tos, cm_info.user_pri); if ((cm_info.ipv4 && (laddr->sin_addr.s_addr != raddr->sin_addr.s_addr)) || (!cm_info.ipv4 && memcmp(laddr6->sin6_addr.in6_u.u6_addr32, raddr6->sin6_addr.in6_u.u6_addr32, @@ -3904,6 +3923,11 @@ int i40iw_create_listen(struct iw_cm_id *cm_id, int backlog) cm_id->provider_data = cm_listen_node; + cm_listen_node->user_pri = rt_tos2priority(cm_id->tos); + cm_info.user_pri = cm_listen_node->user_pri; + i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "%s TOS:[%d] UP:[%d]\n", + __func__, cm_id->tos, cm_listen_node->user_pri); + if (!cm_listen_node->reused_node) { if (wildcard) { if (cm_info.ipv4) diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.h b/drivers/infiniband/hw/i40iw/i40iw_cm.h index e9046d9f9645..945ed26f8dba 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.h +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.h @@ -368,7 +368,7 @@ struct i40iw_cm_info { u32 rem_addr[4]; u16 vlan_id; int backlog; - u16 user_pri; + u8 user_pri; bool ipv4; }; diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 2c4b4d072d6a..31c4a0c26786 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -222,6 +222,133 @@ static enum i40iw_status_code i40iw_sc_parse_fpm_query_buf( return 0; } +/** + * i40iw_fill_qos_list - Change all unknown qs handles to available ones + * @qs_list: list of qs_handles to be fixed with valid qs_handles + */ +static void i40iw_fill_qos_list(u16 *qs_list) +{ + u16 qshandle = qs_list[0]; + int i; + + for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) { + if (qs_list[i] == QS_HANDLE_UNKNOWN) + qs_list[i] = qshandle; + else + qshandle = qs_list[i]; + } +} + +/** + * i40iw_qp_from_entry - Given entry, get to the qp structure + * @entry: Points to list of qp structure + */ +static struct i40iw_sc_qp *i40iw_qp_from_entry(struct list_head *entry) +{ + if (!entry) + return NULL; + + return (struct i40iw_sc_qp *)((char *)entry - offsetof(struct i40iw_sc_qp, list)); +} + +/** + * i40iw_get_qp - get the next qp from the list given current qp + * @head: Listhead of qp's + * @qp: current qp + */ +static struct i40iw_sc_qp *i40iw_get_qp(struct list_head *head, struct i40iw_sc_qp *qp) +{ + struct list_head *entry = NULL; + struct list_head *lastentry; + + if (list_empty(head)) + return NULL; + + if (!qp) { + entry = head->next; + } else { + lastentry = &qp->list; + entry = (lastentry != head) ? lastentry->next : NULL; + } + + return i40iw_qp_from_entry(entry); +} + +/** + * i40iw_change_l2params - given the new l2 parameters, change all qp + * @dev: IWARP device pointer + * @l2params: New paramaters from l2 + */ +void i40iw_change_l2params(struct i40iw_sc_dev *dev, struct i40iw_l2params *l2params) +{ + struct i40iw_sc_qp *qp = NULL; + bool qs_handle_change = false; + bool mss_change = false; + unsigned long flags; + u16 qs_handle; + int i; + + if (dev->mss != l2params->mss) { + mss_change = true; + dev->mss = l2params->mss; + } + + i40iw_fill_qos_list(l2params->qs_handle_list); + for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) { + qs_handle = l2params->qs_handle_list[i]; + if (dev->qos[i].qs_handle != qs_handle) + qs_handle_change = true; + else if (!mss_change) + continue; /* no MSS nor qs handle change */ + spin_lock_irqsave(&dev->qos[i].lock, flags); + qp = i40iw_get_qp(&dev->qos[i].qplist, qp); + while (qp) { + if (mss_change) + i40iw_qp_mss_modify(dev, qp); + if (qs_handle_change) { + qp->qs_handle = qs_handle; + /* issue cqp suspend command */ + i40iw_qp_suspend_resume(dev, qp, true); + } + qp = i40iw_get_qp(&dev->qos[i].qplist, qp); + } + spin_unlock_irqrestore(&dev->qos[i].lock, flags); + dev->qos[i].qs_handle = qs_handle; + } +} + +/** + * i40iw_qp_rem_qos - remove qp from qos lists during destroy qp + * @dev: IWARP device pointer + * @qp: qp to be removed from qos + */ +static void i40iw_qp_rem_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) +{ + unsigned long flags; + + if (!qp->on_qoslist) + return; + spin_lock_irqsave(&dev->qos[qp->user_pri].lock, flags); + list_del(&qp->list); + spin_unlock_irqrestore(&dev->qos[qp->user_pri].lock, flags); +} + +/** + * i40iw_qp_add_qos - called during setctx fot qp to be added to qos + * @dev: IWARP device pointer + * @qp: qp to be added to qos + */ +void i40iw_qp_add_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) +{ + unsigned long flags; + + spin_lock_irqsave(&dev->qos[qp->user_pri].lock, flags); + qp->qs_handle = dev->qos[qp->user_pri].qs_handle; + list_add(&qp->list, &dev->qos[qp->user_pri].qplist); + qp->on_qoslist = true; + spin_unlock_irqrestore(&dev->qos[qp->user_pri].lock, flags); +} + /** * i40iw_sc_pd_init - initialize sc pd struct * @dev: sc device struct @@ -1082,7 +1209,7 @@ static enum i40iw_status_code i40iw_sc_manage_qhash_table_entry( LS_64(info->dest_ip[2], I40IW_CQPSQ_QHASH_ADDR2) | LS_64(info->dest_ip[3], I40IW_CQPSQ_QHASH_ADDR3)); } - qw2 = LS_64(cqp->dev->qs_handle, I40IW_CQPSQ_QHASH_QS_HANDLE); + qw2 = LS_64(cqp->dev->qos[info->user_pri].qs_handle, I40IW_CQPSQ_QHASH_QS_HANDLE); if (info->vlan_valid) qw2 |= LS_64(info->vlan_id, I40IW_CQPSQ_QHASH_VLANID); set_64bit_val(wqe, 16, qw2); @@ -2151,7 +2278,7 @@ static enum i40iw_status_code i40iw_sc_qp_init(struct i40iw_sc_qp *qp, qp->rq_tph_en = info->rq_tph_en; qp->rcv_tph_en = info->rcv_tph_en; qp->xmit_tph_en = info->xmit_tph_en; - qp->qs_handle = qp->pd->dev->qs_handle; + qp->qs_handle = qp->pd->dev->qos[qp->user_pri].qs_handle; qp->exception_lan_queue = qp->pd->dev->exception_lan_queue; return 0; @@ -2296,6 +2423,7 @@ static enum i40iw_status_code i40iw_sc_qp_destroy( struct i40iw_sc_cqp *cqp; u64 header; + i40iw_qp_rem_qos(qp->pd->dev, qp); cqp = qp->pd->dev->cqp; wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch); if (!wqe) @@ -2447,6 +2575,12 @@ static enum i40iw_status_code i40iw_sc_qp_setctx( iw = info->iwarp_info; tcp = info->tcp_info; + if (info->add_to_qoslist) { + qp->user_pri = info->user_pri; + i40iw_qp_add_qos(qp->pd->dev, qp); + i40iw_debug(qp->dev, I40IW_DEBUG_DCB, "%s qp[%d] UP[%d] qset[%d]\n", + __func__, qp->qp_uk.qp_id, qp->user_pri, qp->qs_handle); + } qw0 = LS_64(qp->qp_uk.rq_wqe_size, I40IWQPC_RQWQESIZE) | LS_64(info->err_rq_idx_valid, I40IWQPC_ERR_RQ_IDX_VALID) | LS_64(qp->rcv_tph_en, I40IWQPC_RCVTPHEN) | @@ -3959,7 +4093,7 @@ enum i40iw_status_code i40iw_process_cqp_cmd(struct i40iw_sc_dev *dev, struct cqp_commands_info *pcmdinfo) { enum i40iw_status_code status = 0; - unsigned long flags; + unsigned long flags; spin_lock_irqsave(&dev->cqp_lock, flags); if (list_empty(&dev->cqp_cmd_head) && !i40iw_ring_full(dev->cqp)) @@ -3978,7 +4112,7 @@ enum i40iw_status_code i40iw_process_bh(struct i40iw_sc_dev *dev) { enum i40iw_status_code status = 0; struct cqp_commands_info *pcmdinfo; - unsigned long flags; + unsigned long flags; spin_lock_irqsave(&dev->cqp_lock, flags); while (!list_empty(&dev->cqp_cmd_head) && !i40iw_ring_full(dev->cqp)) { @@ -4742,6 +4876,7 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, u16 hmc_fcn = 0; enum i40iw_status_code ret_code = 0; u8 db_size; + int i; spin_lock_init(&dev->cqp_lock); INIT_LIST_HEAD(&dev->cqp_cmd_head); /* for the cqp commands backlog. */ @@ -4757,7 +4892,13 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, return ret_code; } dev->hmc_fn_id = info->hmc_fn_id; - dev->qs_handle = info->qs_handle; + i40iw_fill_qos_list(info->l2params.qs_handle_list); + for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) { + dev->qos[i].qs_handle = info->l2params.qs_handle_list[i]; + i40iw_debug(dev, I40IW_DEBUG_DCB, "qset[%d]: %d\n", i, dev->qos[i].qs_handle); + spin_lock_init(&dev->qos[i].lock); + INIT_LIST_HEAD(&dev->qos[i].qplist); + } dev->exception_lan_queue = info->exception_lan_queue; dev->is_pf = info->is_pf; diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h index 2fac1db0e0a0..e184c0e99cb1 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_d.h +++ b/drivers/infiniband/hw/i40iw/i40iw_d.h @@ -74,6 +74,8 @@ #define RS_32_1(val, bits) (u32)(val >> bits) #define I40E_HI_DWORD(x) ((u32)((((x) >> 16) >> 16) & 0xFFFFFFFF)) +#define QS_HANDLE_UNKNOWN 0xffff + #define LS_64(val, field) (((u64)val << field ## _SHIFT) & (field ## _MASK)) #define RS_64(val, field) ((u64)(val & field ## _MASK) >> field ## _SHIFT) diff --git a/drivers/infiniband/hw/i40iw/i40iw_hw.c b/drivers/infiniband/hw/i40iw/i40iw_hw.c index 0c92a40b3e86..b94727ffc862 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_hw.c +++ b/drivers/infiniband/hw/i40iw/i40iw_hw.c @@ -359,6 +359,9 @@ void i40iw_process_aeq(struct i40iw_device *iwdev) continue; i40iw_cm_disconn(iwqp); break; + case I40IW_AE_QP_SUSPEND_COMPLETE: + i40iw_qp_suspend_resume(dev, &iwqp->sc_qp, false); + break; case I40IW_AE_TERMINATE_SENT: i40iw_terminate_send_fin(qp); break; @@ -404,19 +407,18 @@ void i40iw_process_aeq(struct i40iw_device *iwdev) case I40IW_AE_LCE_CQ_CATASTROPHIC: case I40IW_AE_UDA_XMIT_DGRAM_TOO_LONG: case I40IW_AE_UDA_XMIT_IPADDR_MISMATCH: - case I40IW_AE_QP_SUSPEND_COMPLETE: ctx_info->err_rq_idx_valid = false; default: - if (!info->sq && ctx_info->err_rq_idx_valid) { - ctx_info->err_rq_idx = info->wqe_idx; - ctx_info->tcp_info_valid = false; - ctx_info->iwarp_info_valid = false; - ret = dev->iw_priv_qp_ops->qp_setctx(&iwqp->sc_qp, - iwqp->host_ctx.va, - ctx_info); - } - i40iw_terminate_connection(qp, info); - break; + if (!info->sq && ctx_info->err_rq_idx_valid) { + ctx_info->err_rq_idx = info->wqe_idx; + ctx_info->tcp_info_valid = false; + ctx_info->iwarp_info_valid = false; + ret = dev->iw_priv_qp_ops->qp_setctx(&iwqp->sc_qp, + iwqp->host_ctx.va, + ctx_info); + } + i40iw_terminate_connection(qp, info); + break; } if (info->qp) i40iw_rem_ref(&iwqp->ibqp); @@ -560,6 +562,7 @@ enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev, } info->ipv4_valid = cminfo->ipv4; + info->user_pri = cminfo->user_pri; ether_addr_copy(info->mac_addr, iwdev->netdev->dev_addr); info->qp_num = cpu_to_le32(dev->ilq->qp_id); info->dest_port = cpu_to_le16(cminfo->loc_port); diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index ac2f3cd9478c..40aac87c128c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -939,7 +939,7 @@ static enum i40iw_status_code i40iw_initialize_ilq(struct i40iw_device *iwdev) info.rq_size = 8192; info.buf_size = 1024; info.tx_buf_cnt = 16384; - info.mss = iwdev->mss; + info.mss = iwdev->sc_dev.mss; info.receive = i40iw_receive_ilq; info.xmit_complete = i40iw_free_sqbuf; status = i40iw_puda_create_rsrc(&iwdev->sc_dev, &info); @@ -967,7 +967,7 @@ static enum i40iw_status_code i40iw_initialize_ieq(struct i40iw_device *iwdev) info.sq_size = 8192; info.rq_size = 8192; info.buf_size = 2048; - info.mss = iwdev->mss; + info.mss = iwdev->sc_dev.mss; info.tx_buf_cnt = 16384; status = i40iw_puda_create_rsrc(&iwdev->sc_dev, &info); if (status) @@ -1296,6 +1296,9 @@ static enum i40iw_status_code i40iw_initialize_dev(struct i40iw_device *iwdev, struct i40iw_device_init_info info; struct i40iw_dma_mem mem; u32 size; + u16 last_qset = I40IW_NO_QSET; + u16 qset; + u32 i; memset(&info, 0, sizeof(info)); size = sizeof(struct i40iw_hmc_pble_rsrc) + sizeof(struct i40iw_hmc_info) + @@ -1325,7 +1328,16 @@ static enum i40iw_status_code i40iw_initialize_dev(struct i40iw_device *iwdev, info.bar0 = ldev->hw_addr; info.hw = &iwdev->hw; info.debug_mask = debug; - info.qs_handle = ldev->params.qos.prio_qos[0].qs_handle; + info.l2params.mss = + (ldev->params.mtu) ? ldev->params.mtu - I40IW_MTU_TO_MSS : I40IW_DEFAULT_MSS; + for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) { + qset = ldev->params.qos.prio_qos[i].qs_handle; + info.l2params.qs_handle_list[i] = qset; + if (last_qset == I40IW_NO_QSET) + last_qset = qset; + else if ((qset != last_qset) && (qset != I40IW_NO_QSET)) + iwdev->dcb = true; + } info.exception_lan_queue = 1; info.vchnl_send = i40iw_virtchnl_send; status = i40iw_device_init(&iwdev->sc_dev, &info); @@ -1416,6 +1428,8 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset, bool del struct i40iw_sc_dev *dev = &iwdev->sc_dev; i40iw_pr_info("state = %d\n", iwdev->init_state); + if (iwdev->param_wq) + destroy_workqueue(iwdev->param_wq); switch (iwdev->init_state) { case RDMA_DEV_REGISTERED: @@ -1630,6 +1644,9 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client) iwdev->init_state = RDMA_DEV_REGISTERED; iwdev->iw_status = 1; i40iw_port_ibevent(iwdev); + iwdev->param_wq = alloc_ordered_workqueue("l2params", WQ_MEM_RECLAIM); + if(iwdev->param_wq == NULL) + break; i40iw_pr_info("i40iw_open completed\n"); return 0; } while (0); @@ -1640,25 +1657,58 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client) } /** - * i40iw_l2param_change : handle qs handles for qos and mss change + * i40iw_l2params_worker - worker for l2 params change + * @work: work pointer for l2 params + */ +static void i40iw_l2params_worker(struct work_struct *work) +{ + struct l2params_work *dwork = + container_of(work, struct l2params_work, work); + struct i40iw_device *iwdev = dwork->iwdev; + + i40iw_change_l2params(&iwdev->sc_dev, &dwork->l2params); + atomic_dec(&iwdev->params_busy); + kfree(work); +} + +/** + * i40iw_l2param_change - handle qs handles for qos and mss change * @ldev: lan device information * @client: client for paramater change * @params: new parameters from L2 */ -static void i40iw_l2param_change(struct i40e_info *ldev, - struct i40e_client *client, +static void i40iw_l2param_change(struct i40e_info *ldev, struct i40e_client *client, struct i40e_params *params) { struct i40iw_handler *hdl; + struct i40iw_l2params *l2params; + struct l2params_work *work; struct i40iw_device *iwdev; + int i; hdl = i40iw_find_i40e_handler(ldev); if (!hdl) return; iwdev = &hdl->device; - if (params->mtu) - iwdev->mss = params->mtu - I40IW_MTU_TO_MSS; + + if (atomic_read(&iwdev->params_busy)) + return; + + + work = kzalloc(sizeof(*work), GFP_ATOMIC); + if (!work) + return; + + atomic_inc(&iwdev->params_busy); + + work->iwdev = iwdev; + l2params = &work->l2params; + for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) + l2params->qs_handle_list[i] = params->qos.prio_qos[i].qs_handle; + + INIT_WORK(&work->work, i40iw_l2params_worker); + queue_work(iwdev->param_wq, &work->work); } /** diff --git a/drivers/infiniband/hw/i40iw/i40iw_osdep.h b/drivers/infiniband/hw/i40iw/i40iw_osdep.h index 80f422bf3967..a6b18cd42e67 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_osdep.h +++ b/drivers/infiniband/hw/i40iw/i40iw_osdep.h @@ -198,6 +198,8 @@ enum i40iw_status_code i40iw_cqp_manage_vf_pble_bp(struct i40iw_sc_dev *dev, void i40iw_cqp_spawn_worker(struct i40iw_sc_dev *dev, struct i40iw_virtchnl_work_info *work_info, u32 iw_vf_idx); void *i40iw_remove_head(struct list_head *list); +void i40iw_qp_suspend_resume(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp, bool suspend); +void i40iw_qp_mss_modify(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); void i40iw_term_modify_qp(struct i40iw_sc_qp *qp, u8 next_state, u8 term, u8 term_len); void i40iw_terminate_done(struct i40iw_sc_qp *qp, int timeout_occurred); diff --git a/drivers/infiniband/hw/i40iw/i40iw_p.h b/drivers/infiniband/hw/i40iw/i40iw_p.h index a0b8ca10d67e..c9e8cb8c4410 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_p.h +++ b/drivers/infiniband/hw/i40iw/i40iw_p.h @@ -65,6 +65,8 @@ enum i40iw_status_code i40iw_pf_init_vfhmc(struct i40iw_sc_dev *dev, u8 vf_hmc_f u32 *vf_cnt_array); /* cqp misc functions */ +void i40iw_change_l2params(struct i40iw_sc_dev *dev, struct i40iw_l2params *l2params); +void i40iw_qp_add_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); void i40iw_terminate_send_fin(struct i40iw_sc_qp *qp); diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c index c62d354f7810..7541b0dada59 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.c +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c @@ -608,7 +608,8 @@ static enum i40iw_status_code i40iw_puda_qp_create(struct i40iw_puda_rsrc *rsrc) ukqp->wqe_alloc_reg = (u32 __iomem *)(i40iw_get_hw_addr(qp->pd->dev) + I40E_VFPE_WQEALLOC1); - qp->qs_handle = qp->dev->qs_handle; + qp->user_pri = 0; + i40iw_qp_add_qos(rsrc->dev, qp); i40iw_puda_qp_setctx(rsrc); ret = i40iw_puda_qp_wqe(rsrc); if (ret) diff --git a/drivers/infiniband/hw/i40iw/i40iw_type.h b/drivers/infiniband/hw/i40iw/i40iw_type.h index 2b1a04e9ca3c..b6f448a8d2e0 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_type.h +++ b/drivers/infiniband/hw/i40iw/i40iw_type.h @@ -397,6 +397,9 @@ struct i40iw_sc_qp { bool virtual_map; bool flush_sq; bool flush_rq; + u8 user_pri; + struct list_head list; + bool on_qoslist; bool sq_flush; enum i40iw_flush_opcode flush_code; enum i40iw_term_eventtypes eventtype; @@ -424,6 +427,12 @@ struct i40iw_vchnl_vf_msg_buffer { char parm_buffer[I40IW_VCHNL_MAX_VF_MSG_SIZE - 1]; }; +struct i40iw_qos { + struct list_head qplist; + spinlock_t lock; /* qos list */ + u16 qs_handle; +}; + struct i40iw_vfdev { struct i40iw_sc_dev *pf_dev; u8 *hmc_info_mem; @@ -482,7 +491,8 @@ struct i40iw_sc_dev { const struct i40iw_vf_cqp_ops *iw_vf_cqp_ops; struct i40iw_hmc_fpm_misc hmc_fpm_misc; - u16 qs_handle; + struct i40iw_qos qos[I40IW_MAX_USER_PRIORITY]; + u16 mss; u32 debug_mask; u16 exception_lan_queue; u8 hmc_fn_id; @@ -564,7 +574,7 @@ struct i40iw_device_init_info { struct i40iw_hw *hw; void __iomem *bar0; enum i40iw_status_code (*vchnl_send)(struct i40iw_sc_dev *, u32, u8 *, u16); - u16 qs_handle; + struct i40iw_l2params l2params; u16 exception_lan_queue; u8 hmc_fn_id; bool is_pf; @@ -722,6 +732,8 @@ struct i40iw_qp_host_ctx_info { bool iwarp_info_valid; bool err_rq_idx_valid; u16 err_rq_idx; + bool add_to_qoslist; + u8 user_pri; }; struct i40iw_aeqe_info { @@ -886,7 +898,7 @@ struct i40iw_qhash_table_info { bool ipv4_valid; u8 mac_addr[6]; u16 vlan_id; - u16 qs_handle; + u8 user_pri; u32 qp_num; u32 dest_ip[4]; u32 src_ip[4]; diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index 6fd043b1d714..cd9890263cd2 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -711,6 +711,51 @@ enum i40iw_status_code i40iw_cqp_sds_cmd(struct i40iw_sc_dev *dev, return status; } +/** + * i40iw_qp_suspend_resume - cqp command for suspend/resume + * @dev: hardware control device structure + * @qp: hardware control qp + * @suspend: flag if suspend or resume + */ +void i40iw_qp_suspend_resume(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp, bool suspend) +{ + struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; + struct i40iw_cqp_request *cqp_request; + struct i40iw_sc_cqp *cqp = dev->cqp; + struct cqp_commands_info *cqp_info; + enum i40iw_status_code status; + + cqp_request = i40iw_get_cqp_request(&iwdev->cqp, false); + if (!cqp_request) + return; + + cqp_info = &cqp_request->info; + cqp_info->cqp_cmd = (suspend) ? OP_SUSPEND : OP_RESUME; + cqp_info->in.u.suspend_resume.cqp = cqp; + cqp_info->in.u.suspend_resume.qp = qp; + cqp_info->in.u.suspend_resume.scratch = (uintptr_t)cqp_request; + status = i40iw_handle_cqp_op(iwdev, cqp_request); + if (status) + i40iw_pr_err("CQP-OP QP Suspend/Resume fail"); +} + +/** + * i40iw_qp_mss_modify - modify mss for qp + * @dev: hardware control device structure + * @qp: hardware control qp + */ +void i40iw_qp_mss_modify(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) +{ + struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; + struct i40iw_qp *iwqp = (struct i40iw_qp *)qp->back_qp; + struct i40iw_modify_qp_info info; + + memset(&info, 0, sizeof(info)); + info.mss_change = true; + info.new_mss = dev->mss; + i40iw_hw_modify_qp(iwdev, iwqp, &info, false); +} + /** * i40iw_term_modify_qp - modify qp for term message * @qp: hardware control qp diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 6329c971c22f..56e1c2c6ec34 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -254,7 +254,6 @@ static void i40iw_alloc_push_page(struct i40iw_device *iwdev, struct i40iw_sc_qp { struct i40iw_cqp_request *cqp_request; struct cqp_commands_info *cqp_info; - struct i40iw_sc_dev *dev = &iwdev->sc_dev; enum i40iw_status_code status; if (qp->push_idx != I40IW_INVALID_PUSH_PAGE_INDEX) @@ -270,7 +269,7 @@ static void i40iw_alloc_push_page(struct i40iw_device *iwdev, struct i40iw_sc_qp cqp_info->cqp_cmd = OP_MANAGE_PUSH_PAGE; cqp_info->post_sq = 1; - cqp_info->in.u.manage_push_page.info.qs_handle = dev->qs_handle; + cqp_info->in.u.manage_push_page.info.qs_handle = qp->qs_handle; cqp_info->in.u.manage_push_page.info.free_page = 0; cqp_info->in.u.manage_push_page.cqp = &iwdev->cqp.sc_cqp; cqp_info->in.u.manage_push_page.scratch = (uintptr_t)cqp_request; @@ -292,7 +291,6 @@ static void i40iw_dealloc_push_page(struct i40iw_device *iwdev, struct i40iw_sc_ { struct i40iw_cqp_request *cqp_request; struct cqp_commands_info *cqp_info; - struct i40iw_sc_dev *dev = &iwdev->sc_dev; enum i40iw_status_code status; if (qp->push_idx == I40IW_INVALID_PUSH_PAGE_INDEX) @@ -307,7 +305,7 @@ static void i40iw_dealloc_push_page(struct i40iw_device *iwdev, struct i40iw_sc_ cqp_info->post_sq = 1; cqp_info->in.u.manage_push_page.info.push_idx = qp->push_idx; - cqp_info->in.u.manage_push_page.info.qs_handle = dev->qs_handle; + cqp_info->in.u.manage_push_page.info.qs_handle = qp->qs_handle; cqp_info->in.u.manage_push_page.info.free_page = 1; cqp_info->in.u.manage_push_page.cqp = &iwdev->cqp.sc_cqp; cqp_info->in.u.manage_push_page.scratch = (uintptr_t)cqp_request; -- cgit v1.2.3 From d62d563424e3da0c0a1176f38c0d49c7ad91fbc1 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 19 Oct 2016 15:32:53 -0500 Subject: i40iw: Enable message packing Remove the parameter to disable message packing and always enable it. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 5 ----- drivers/infiniband/hw/i40iw/i40iw_main.c | 2 +- drivers/infiniband/hw/i40iw/i40iw_type.h | 2 +- 3 files changed, 2 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 31c4a0c26786..6c6a1ef02d46 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -429,12 +429,10 @@ static enum i40iw_status_code i40iw_sc_cqp_init(struct i40iw_sc_cqp *cqp, /** * i40iw_sc_cqp_create - create cqp during bringup * @cqp: struct for cqp hw - * @disable_pfpdus: if pfpdu to be disabled * @maj_err: If error, major err number * @min_err: If error, minor err number */ static enum i40iw_status_code i40iw_sc_cqp_create(struct i40iw_sc_cqp *cqp, - bool disable_pfpdus, u16 *maj_err, u16 *min_err) { @@ -453,9 +451,6 @@ static enum i40iw_status_code i40iw_sc_cqp_create(struct i40iw_sc_cqp *cqp, temp = LS_64(cqp->hw_sq_size, I40IW_CQPHC_SQSIZE) | LS_64(cqp->struct_ver, I40IW_CQPHC_SVER); - if (disable_pfpdus) - temp |= LS_64(1, I40IW_CQPHC_DISABLE_PFPDUS); - set_64bit_val(cqp->host_ctx, 0, temp); set_64bit_val(cqp->host_ctx, 8, cqp->sq_pa); temp = LS_64(cqp->enabled_vf_count, I40IW_CQPHC_ENABLED_VFS) | diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index 40aac87c128c..e6abdafd1b6f 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -603,7 +603,7 @@ static enum i40iw_status_code i40iw_create_cqp(struct i40iw_device *iwdev) i40iw_pr_err("cqp init status %d\n", status); goto exit; } - status = dev->cqp_ops->cqp_create(dev->cqp, true, &maj_err, &min_err); + status = dev->cqp_ops->cqp_create(dev->cqp, &maj_err, &min_err); if (status) { i40iw_pr_err("cqp create status %d maj_err %d min_err %d\n", status, maj_err, min_err); diff --git a/drivers/infiniband/hw/i40iw/i40iw_type.h b/drivers/infiniband/hw/i40iw/i40iw_type.h index b6f448a8d2e0..d1847e693025 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_type.h +++ b/drivers/infiniband/hw/i40iw/i40iw_type.h @@ -988,7 +988,7 @@ struct i40iw_cqp_query_fpm_values { struct i40iw_cqp_ops { enum i40iw_status_code (*cqp_init)(struct i40iw_sc_cqp *, struct i40iw_cqp_init_info *); - enum i40iw_status_code (*cqp_create)(struct i40iw_sc_cqp *, bool, u16 *, u16 *); + enum i40iw_status_code (*cqp_create)(struct i40iw_sc_cqp *, u16 *, u16 *); void (*cqp_post_sq)(struct i40iw_sc_cqp *); u64 *(*cqp_get_next_send_wqe)(struct i40iw_sc_cqp *, u64 scratch); enum i40iw_status_code (*cqp_destroy)(struct i40iw_sc_cqp *); -- cgit v1.2.3 From 7581e96ca4de26da7237d507ac9cf519753e1787 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 19 Oct 2016 15:33:32 -0500 Subject: i40iw: Remove workaround for pre-production errata Pre-production silicon incorrectly truncates 4 bytes of the MPA packet in UDP loopback case. Remove the workaround as it is no longer necessary. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 26 +++----------------------- drivers/infiniband/hw/i40iw/i40iw_cm.h | 2 -- drivers/infiniband/hw/i40iw/i40iw_utils.c | 2 +- 3 files changed, 4 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 24b22e99003c..9e447b5951fc 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -361,15 +361,6 @@ static void i40iw_cleanup_retrans_entry(struct i40iw_cm_node *cm_node) spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); } -static bool is_remote_ne020_or_chelsio(struct i40iw_cm_node *cm_node) -{ - if ((cm_node->rem_mac[0] == 0x0) && - (((cm_node->rem_mac[1] == 0x12) && (cm_node->rem_mac[2] == 0x55)) || - ((cm_node->rem_mac[1] == 0x07 && (cm_node->rem_mac[2] == 0x43))))) - return true; - return false; -} - /** * i40iw_form_cm_frame - get a free packet and build frame * @cm_node: connection's node ionfo to use in frame @@ -410,11 +401,8 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, if (hdr) hdr_len = hdr->size; - if (pdata) { + if (pdata) pd_len = pdata->size; - if (!is_remote_ne020_or_chelsio(cm_node)) - pd_len += MPA_ZERO_PAD_LEN; - } if (cm_node->vlan_id < VLAN_TAG_PRESENT) eth_hlen += 4; @@ -3587,7 +3575,7 @@ int i40iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) iwqp->cm_node = (void *)cm_node; cm_node->iwqp = iwqp; - buf_len = conn_param->private_data_len + I40IW_MAX_IETF_SIZE + MPA_ZERO_PAD_LEN; + buf_len = conn_param->private_data_len + I40IW_MAX_IETF_SIZE; status = i40iw_allocate_dma_mem(dev->hw, &iwqp->ietf_mem, buf_len, 1); @@ -3621,18 +3609,10 @@ int i40iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) iwqp->lsmm_mr = ibmr; if (iwqp->page) iwqp->sc_qp.qp_uk.sq_base = kmap(iwqp->page); - if (is_remote_ne020_or_chelsio(cm_node)) - dev->iw_priv_qp_ops->qp_send_lsmm( - &iwqp->sc_qp, + dev->iw_priv_qp_ops->qp_send_lsmm(&iwqp->sc_qp, iwqp->ietf_mem.va, (accept.size + conn_param->private_data_len), ibmr->lkey); - else - dev->iw_priv_qp_ops->qp_send_lsmm( - &iwqp->sc_qp, - iwqp->ietf_mem.va, - (accept.size + conn_param->private_data_len + MPA_ZERO_PAD_LEN), - ibmr->lkey); } else { if (iwqp->page) diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.h b/drivers/infiniband/hw/i40iw/i40iw_cm.h index 945ed26f8dba..24615c24cb04 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.h +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.h @@ -56,8 +56,6 @@ #define I40IW_MAX_IETF_SIZE 32 -#define MPA_ZERO_PAD_LEN 4 - /* IETF RTR MSG Fields */ #define IETF_PEER_TO_PEER 0x8000 #define IETF_FLPDU_ZERO_LEN 0x4000 diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index cd9890263cd2..4e880e8689eb 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -1253,7 +1253,7 @@ enum i40iw_status_code i40iw_puda_get_tcpip_info(struct i40iw_puda_completion_in buf->totallen = pkt_len + buf->maclen; - if (info->payload_len < buf->totallen - 4) { + if (info->payload_len < buf->totallen) { i40iw_pr_err("payload_len = 0x%x totallen expected0x%x\n", info->payload_len, buf->totallen); return I40IW_ERR_INVALID_SIZE; -- cgit v1.2.3 From 7cba2cc13e12c824ad7e414b3834dc3df05fbf46 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 19 Oct 2016 15:33:58 -0500 Subject: i40iw: Set MAX IRD, MAX ORD size to max supported value Set the MAX_IRD and MAX_ORD size negotiated to the maximum supported values. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 5 ----- drivers/infiniband/hw/i40iw/i40iw_user.h | 5 ++--- 2 files changed, 2 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 6c6a1ef02d46..6bf2a19f3cba 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -2621,11 +2621,6 @@ static enum i40iw_status_code i40iw_sc_qp_setctx( 152, LS_64(iw->last_byte_sent, I40IWQPC_LASTBYTESENT)); - /* - * Hard-code IRD_SIZE to hw-limit, 128, in qpctx, i.e matching an - *advertisable IRD of 64 - */ - iw->ird_size = I40IW_QPCTX_ENCD_MAXIRD; set_64bit_val(qp_ctx, 160, LS_64(iw->ord_size, I40IWQPC_ORDSIZE) | diff --git a/drivers/infiniband/hw/i40iw/i40iw_user.h b/drivers/infiniband/hw/i40iw/i40iw_user.h index 276bcefffd7e..e65c2baa7db2 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_user.h +++ b/drivers/infiniband/hw/i40iw/i40iw_user.h @@ -72,10 +72,9 @@ enum i40iw_device_capabilities_const { I40IW_MAX_SQ_PAYLOAD_SIZE = 2145386496, I40IW_MAX_INLINE_DATA_SIZE = 48, I40IW_MAX_PUSHMODE_INLINE_DATA_SIZE = 48, - I40IW_MAX_IRD_SIZE = 32, - I40IW_QPCTX_ENCD_MAXIRD = 3, + I40IW_MAX_IRD_SIZE = 63, + I40IW_MAX_ORD_SIZE = 127, I40IW_MAX_WQ_ENTRIES = 2048, - I40IW_MAX_ORD_SIZE = 32, I40IW_Q2_BUFFER_SIZE = (248 + 100), I40IW_QP_CTX_SIZE = 248 }; -- cgit v1.2.3 From b1226c7db1d997fa6955cd3b54ba333bd0d8a29c Mon Sep 17 00:00:00 2001 From: Adit Ranadive Date: Sun, 2 Oct 2016 19:10:21 -0700 Subject: vmxnet3: Move PCI Id to pci_ids.h The VMXNet3 PCI Id will be shared with our paravirtual RDMA driver. Moved it to the shared location in pci_ids.h. Suggested-by: Leon Romanovsky Acked-by: Bjorn Helgaas Reviewed-by: Yuval Shaia Signed-off-by: Adit Ranadive Signed-off-by: Doug Ledford --- drivers/net/vmxnet3/vmxnet3_int.h | 3 +-- include/linux/pci_ids.h | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h index 7dc37a090549..59e077be8829 100644 --- a/drivers/net/vmxnet3/vmxnet3_int.h +++ b/drivers/net/vmxnet3/vmxnet3_int.h @@ -119,9 +119,8 @@ enum { }; /* - * PCI vendor and device IDs. + * Maximum devices supported. */ -#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0 #define MAX_ETHERNET_CARDS 10 #define MAX_PCI_PASSTHRU_DEVICE 6 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index c58752fe16c4..98bb455302cf 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2251,6 +2251,7 @@ #define PCI_DEVICE_ID_RASTEL_2PORT 0x2000 #define PCI_VENDOR_ID_VMWARE 0x15ad +#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07b0 #define PCI_VENDOR_ID_ZOLTRIX 0x15b0 #define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0 -- cgit v1.2.3 From d37806dc37b42b05515849b0444f09f493cb4cba Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 4 Dec 2016 10:45:13 -0800 Subject: libnvdimm: remove else after return in nsio_rw_bytes() else after return is not needed. Signed-off-by: Fabian Frederick [djbw: removed some now unnecessary newlines] Signed-off-by: Dan Williams --- drivers/nvdimm/claim.c | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 4638b9ea5229..3376da1fb263 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -242,29 +242,26 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) return -EIO; return memcpy_from_pmem(buf, nsio->addr + offset, size); - } else { - - if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { - if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) { - long cleared; - - cleared = nvdimm_clear_poison(&ndns->dev, - offset, size); - if (cleared != size) { - size = cleared; - rc = -EIO; - } - - badblocks_clear(&nsio->bb, sector, - cleared >> 9); - } else + } + + if (unlikely(is_bad_pmem(&nsio->bb, sector, sz_align))) { + if (IS_ALIGNED(offset, 512) && IS_ALIGNED(size, 512)) { + long cleared; + + cleared = nvdimm_clear_poison(&ndns->dev, offset, size); + if (cleared != size) { + size = cleared; rc = -EIO; - } + } - memcpy_to_pmem(nsio->addr + offset, buf, size); - nvdimm_flush(to_nd_region(ndns->dev.parent)); + badblocks_clear(&nsio->bb, sector, cleared >> 9); + } else + rc = -EIO; } + memcpy_to_pmem(nsio->addr + offset, buf, size); + nvdimm_flush(to_nd_region(ndns->dev.parent)); + return rc; } -- cgit v1.2.3 From 0a3f27b9a6a8f76f1df270e1a18b096f8f5d5dbc Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 4 Dec 2016 10:48:58 -0800 Subject: libnvdimm, namespace: avoid multiple sector calculations Use sector_t for cleared Suggested-by: Dan Williams Signed-off-by: Fabian Frederick Signed-off-by: Dan Williams --- drivers/nvdimm/pmem.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 34f16a17c07b..bcc359a4e64d 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -51,17 +51,16 @@ static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, unsigned int len) { struct device *dev = to_dev(pmem); - sector_t sector; - long cleared; + sector_t sector, cleared; sector = (offset - pmem->data_offset) / 512; - cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len); + cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len) / 512; - if (cleared > 0 && cleared / 512) { + if (cleared) { dev_dbg(dev, "%s: %#llx clear %ld sector%s\n", __func__, (unsigned long long) sector, - cleared / 512, cleared / 512 > 1 ? "s" : ""); - badblocks_clear(&pmem->bb, sector, cleared / 512); + cleared, cleared > 1 ? "s" : ""); + badblocks_clear(&pmem->bb, sector, cleared); } invalidate_pmem(pmem->virt_addr + offset, len); } -- cgit v1.2.3 From b44fe760433a58f2284d2a544afd91dd685ac677 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 4 Dec 2016 10:54:08 -0800 Subject: libnvdimm, namespace: use octal for permissions According to commit f90774e1fd27 ("checkpatch: look for symbolic permissions and suggest octal instead") Signed-off-by: Fabian Frederick Signed-off-by: Dan Williams --- drivers/nvdimm/namespace_devs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 61636d135105..8817f8a0cf38 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1132,7 +1132,7 @@ static ssize_t size_show(struct device *dev, return sprintf(buf, "%llu\n", (unsigned long long) nvdimm_namespace_capacity(to_ndns(dev))); } -static DEVICE_ATTR(size, S_IRUGO, size_show, size_store); +static DEVICE_ATTR(size, 0444, size_show, size_store); static u8 *namespace_to_uuid(struct device *dev) { @@ -1456,7 +1456,7 @@ static umode_t namespace_visible(struct kobject *kobj, if (is_namespace_pmem(dev) || is_namespace_blk(dev)) { if (a == &dev_attr_size.attr) - return S_IWUSR | S_IRUGO; + return 0644; if (is_namespace_pmem(dev) && a == &dev_attr_sector_size.attr) return 0; -- cgit v1.2.3 From 450630975da9e7dffe540753e169dc4da5fe7c29 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 4 Dec 2016 18:24:56 -0500 Subject: don't open-code file_inode() Signed-off-by: Al Viro --- drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 20 ++++++++++---------- drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c | 2 +- drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 4 ++-- drivers/staging/greybus/camera.c | 4 ++-- drivers/staging/greybus/es2.c | 6 +++--- drivers/staging/greybus/svc.c | 6 +++--- drivers/staging/greybus/timesync.c | 2 +- drivers/target/target_core_configfs.c | 2 +- fs/aio.c | 6 +++--- fs/autofs4/inode.c | 2 +- fs/fcntl.c | 2 +- fs/orangefs/file.c | 2 +- fs/orangefs/orangefs-debugfs.c | 6 ++++-- fs/overlayfs/copy_up.c | 2 +- kernel/audit_watch.c | 4 ++-- kernel/events/core.c | 2 +- kernel/locking/qspinlock_stat.h | 12 ++---------- security/smack/smack_lsm.c | 2 +- 18 files changed, 40 insertions(+), 46 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c index 3161d77bf299..3c2858972217 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c @@ -2501,7 +2501,7 @@ static void amdgpu_debugfs_remove_files(struct amdgpu_device *adev) static ssize_t amdgpu_debugfs_regs_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; bool pm_pg_lock, use_bank; @@ -2570,7 +2570,7 @@ end: static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -2601,7 +2601,7 @@ static ssize_t amdgpu_debugfs_regs_write(struct file *f, const char __user *buf, static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -2628,7 +2628,7 @@ static ssize_t amdgpu_debugfs_regs_pcie_read(struct file *f, char __user *buf, static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -2656,7 +2656,7 @@ static ssize_t amdgpu_debugfs_regs_pcie_write(struct file *f, const char __user static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -2683,7 +2683,7 @@ static ssize_t amdgpu_debugfs_regs_didt_read(struct file *f, char __user *buf, static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -2711,7 +2711,7 @@ static ssize_t amdgpu_debugfs_regs_didt_write(struct file *f, const char __user static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -2738,7 +2738,7 @@ static ssize_t amdgpu_debugfs_regs_smc_read(struct file *f, char __user *buf, static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -2766,7 +2766,7 @@ static ssize_t amdgpu_debugfs_regs_smc_write(struct file *f, const char __user * static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; uint32_t *config, no_regs = 0; @@ -2836,7 +2836,7 @@ static ssize_t amdgpu_debugfs_gca_config_read(struct file *f, char __user *buf, static ssize_t amdgpu_debugfs_sensor_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; int idx, r; int32_t value; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c index 3cb5e903cd62..2636f619569e 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ring.c @@ -283,7 +283,7 @@ void amdgpu_ring_fini(struct amdgpu_ring *ring) static ssize_t amdgpu_debugfs_ring_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_ring *ring = (struct amdgpu_ring*)f->f_inode->i_private; + struct amdgpu_ring *ring = file_inode(f)->i_private; int r, i; uint32_t value, result, early[3]; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c index dcaf691f56b5..a5d00ef2b421 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c @@ -1412,7 +1412,7 @@ static const struct drm_info_list amdgpu_ttm_debugfs_list[] = { static ssize_t amdgpu_ttm_vram_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; @@ -1456,7 +1456,7 @@ static const struct file_operations amdgpu_ttm_vram_fops = { static ssize_t amdgpu_ttm_gtt_read(struct file *f, char __user *buf, size_t size, loff_t *pos) { - struct amdgpu_device *adev = f->f_inode->i_private; + struct amdgpu_device *adev = file_inode(f)->i_private; ssize_t result = 0; int r; diff --git a/drivers/staging/greybus/camera.c b/drivers/staging/greybus/camera.c index 491bdd720c0c..cebb76e7d55c 100644 --- a/drivers/staging/greybus/camera.c +++ b/drivers/staging/greybus/camera.c @@ -1091,7 +1091,7 @@ static ssize_t gb_camera_debugfs_read(struct file *file, char __user *buf, size_t len, loff_t *offset) { const struct gb_camera_debugfs_entry *op = file->private_data; - struct gb_camera *gcam = file->f_inode->i_private; + struct gb_camera *gcam = file_inode(file)->i_private; struct gb_camera_debugfs_buffer *buffer; ssize_t ret; @@ -1113,7 +1113,7 @@ static ssize_t gb_camera_debugfs_write(struct file *file, loff_t *offset) { const struct gb_camera_debugfs_entry *op = file->private_data; - struct gb_camera *gcam = file->f_inode->i_private; + struct gb_camera *gcam = file_inode(file)->i_private; ssize_t ret; char *kbuf; diff --git a/drivers/staging/greybus/es2.c b/drivers/staging/greybus/es2.c index baab460eeaa3..d367cdffaa10 100644 --- a/drivers/staging/greybus/es2.c +++ b/drivers/staging/greybus/es2.c @@ -1250,7 +1250,7 @@ static int apb_log_poll(void *data) static ssize_t apb_log_read(struct file *f, char __user *buf, size_t count, loff_t *ppos) { - struct es2_ap_dev *es2 = f->f_inode->i_private; + struct es2_ap_dev *es2 = file_inode(f)->i_private; ssize_t ret; size_t copied; char *tmp_buf; @@ -1304,7 +1304,7 @@ static void usb_log_disable(struct es2_ap_dev *es2) static ssize_t apb_log_enable_read(struct file *f, char __user *buf, size_t count, loff_t *ppos) { - struct es2_ap_dev *es2 = f->f_inode->i_private; + struct es2_ap_dev *es2 = file_inode(f)->i_private; int enable = !IS_ERR_OR_NULL(es2->apb_log_task); char tmp_buf[3]; @@ -1317,7 +1317,7 @@ static ssize_t apb_log_enable_write(struct file *f, const char __user *buf, { int enable; ssize_t retval; - struct es2_ap_dev *es2 = f->f_inode->i_private; + struct es2_ap_dev *es2 = file_inode(f)->i_private; retval = kstrtoint_from_user(buf, count, 10, &enable); if (retval) diff --git a/drivers/staging/greybus/svc.c b/drivers/staging/greybus/svc.c index 550055ec27a5..8779270cadc1 100644 --- a/drivers/staging/greybus/svc.c +++ b/drivers/staging/greybus/svc.c @@ -757,7 +757,7 @@ static int gb_svc_version_request(struct gb_operation *op) static ssize_t pwr_debugfs_voltage_read(struct file *file, char __user *buf, size_t len, loff_t *offset) { - struct svc_debugfs_pwrmon_rail *pwrmon_rails = file->f_inode->i_private; + struct svc_debugfs_pwrmon_rail *pwrmon_rails = file_inode(file)->i_private; struct gb_svc *svc = pwrmon_rails->svc; int ret, desc; u32 value; @@ -780,7 +780,7 @@ static ssize_t pwr_debugfs_voltage_read(struct file *file, char __user *buf, static ssize_t pwr_debugfs_current_read(struct file *file, char __user *buf, size_t len, loff_t *offset) { - struct svc_debugfs_pwrmon_rail *pwrmon_rails = file->f_inode->i_private; + struct svc_debugfs_pwrmon_rail *pwrmon_rails = file_inode(file)->i_private; struct gb_svc *svc = pwrmon_rails->svc; int ret, desc; u32 value; @@ -803,7 +803,7 @@ static ssize_t pwr_debugfs_current_read(struct file *file, char __user *buf, static ssize_t pwr_debugfs_power_read(struct file *file, char __user *buf, size_t len, loff_t *offset) { - struct svc_debugfs_pwrmon_rail *pwrmon_rails = file->f_inode->i_private; + struct svc_debugfs_pwrmon_rail *pwrmon_rails = file_inode(file)->i_private; struct gb_svc *svc = pwrmon_rails->svc; int ret, desc; u32 value; diff --git a/drivers/staging/greybus/timesync.c b/drivers/staging/greybus/timesync.c index 2e68af7dea6d..09ce00484b3f 100644 --- a/drivers/staging/greybus/timesync.c +++ b/drivers/staging/greybus/timesync.c @@ -921,7 +921,7 @@ EXPORT_SYMBOL_GPL(gb_timesync_schedule_asynchronous); static ssize_t gb_timesync_ping_read(struct file *file, char __user *ubuf, size_t len, loff_t *offset, bool ktime) { - struct gb_timesync_svc *timesync_svc = file->f_inode->i_private; + struct gb_timesync_svc *timesync_svc = file_inode(file)->i_private; char *buf; ssize_t ret = 0; diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 2001005bef45..a35a347ec357 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -143,7 +143,7 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item, pr_err("db_root: cannot open: %s\n", db_root_stage); return -EINVAL; } - if (!S_ISDIR(fp->f_inode->i_mode)) { + if (!S_ISDIR(file_inode(fp)->i_mode)) { filp_close(fp, 0); mutex_unlock(&g_tf_lock); pr_err("db_root: not a directory: %s\n", db_root_stage); diff --git a/fs/aio.c b/fs/aio.c index 428484f2f841..8edf253484af 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -277,10 +277,10 @@ static void put_aio_ring_file(struct kioctx *ctx) struct address_space *i_mapping; if (aio_ring_file) { - truncate_setsize(aio_ring_file->f_inode, 0); + truncate_setsize(file_inode(aio_ring_file), 0); /* Prevent further access to the kioctx from migratepages */ - i_mapping = aio_ring_file->f_inode->i_mapping; + i_mapping = aio_ring_file->f_mapping; spin_lock(&i_mapping->private_lock); i_mapping->private_data = NULL; ctx->aio_ring_file = NULL; @@ -483,7 +483,7 @@ static int aio_setup_ring(struct kioctx *ctx) for (i = 0; i < nr_pages; i++) { struct page *page; - page = find_or_create_page(file->f_inode->i_mapping, + page = find_or_create_page(file->f_mapping, i, GFP_HIGHUSER | __GFP_ZERO); if (!page) break; diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index 438b5bf675b6..09e7d68dff02 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -94,7 +94,7 @@ static int autofs4_show_options(struct seq_file *m, struct dentry *root) seq_printf(m, ",indirect"); #ifdef CONFIG_CHECKPOINT_RESTORE if (sbi->pipe) - seq_printf(m, ",pipe_ino=%ld", sbi->pipe->f_inode->i_ino); + seq_printf(m, ",pipe_ino=%ld", file_inode(sbi->pipe)->i_ino); else seq_printf(m, ",pipe_ino=-1"); #endif diff --git a/fs/fcntl.c b/fs/fcntl.c index 350a2c8cfd28..6e2771c210f6 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -52,7 +52,7 @@ static int setfl(int fd, struct file * filp, unsigned long arg) arg |= O_NONBLOCK; /* Pipe packetized mode is controlled by O_DIRECT flag */ - if (!S_ISFIFO(filp->f_inode->i_mode) && (arg & O_DIRECT)) { + if (!S_ISFIFO(inode->i_mode) && (arg & O_DIRECT)) { if (!filp->f_mapping || !filp->f_mapping->a_ops || !filp->f_mapping->a_ops->direct_IO) return -EINVAL; diff --git a/fs/orangefs/file.c b/fs/orangefs/file.c index 02cc6139ec90..e6bbc8083d77 100644 --- a/fs/orangefs/file.c +++ b/fs/orangefs/file.c @@ -724,7 +724,7 @@ static int orangefs_lock(struct file *filp, int cmd, struct file_lock *fl) { int rc = -EINVAL; - if (ORANGEFS_SB(filp->f_inode->i_sb)->flags & ORANGEFS_OPT_LOCAL_LOCK) { + if (ORANGEFS_SB(file_inode(filp)->i_sb)->flags & ORANGEFS_OPT_LOCAL_LOCK) { if (cmd == F_GETLK) { rc = 0; posix_test_lock(filp, fl); diff --git a/fs/orangefs/orangefs-debugfs.c b/fs/orangefs/orangefs-debugfs.c index 38887cc5577f..f1e824979aad 100644 --- a/fs/orangefs/orangefs-debugfs.c +++ b/fs/orangefs/orangefs-debugfs.c @@ -434,6 +434,7 @@ static ssize_t orangefs_debug_write(struct file *file, char *debug_string; struct orangefs_kernel_op_s *new_op = NULL; struct client_debug_mask c_mask = { NULL, 0, 0 }; + char *s; gossip_debug(GOSSIP_DEBUGFS_DEBUG, "orangefs_debug_write: %pD\n", @@ -521,8 +522,9 @@ static ssize_t orangefs_debug_write(struct file *file, } mutex_lock(&orangefs_debug_lock); - memset(file->f_inode->i_private, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); - sprintf((char *)file->f_inode->i_private, "%s\n", debug_string); + s = file_inode(file)->i_private; + memset(s, 0, ORANGEFS_MAX_DEBUG_STRING_LEN); + sprintf(s, "%s\n", debug_string); mutex_unlock(&orangefs_debug_lock); *ppos += count; diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 36795eed40b0..2838bddb1f91 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -33,7 +33,7 @@ static int ovl_check_fd(const void *data, struct file *f, unsigned int fd) { const struct dentry *dentry = data; - if (f->f_inode == d_inode(dentry)) + if (file_inode(f) == d_inode(dentry)) pr_warn_ratelimited("overlayfs: Warning: Copying up %pD, but open R/O on fd %u which will cease to be coherent [pid=%d %s]\n", f, fd, current->pid, current->comm); return 0; diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c index 0d302a87f21b..99401efef7ac 100644 --- a/kernel/audit_watch.c +++ b/kernel/audit_watch.c @@ -548,8 +548,8 @@ int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark) exe_file = get_task_exe_file(tsk); if (!exe_file) return 0; - ino = exe_file->f_inode->i_ino; - dev = exe_file->f_inode->i_sb->s_dev; + ino = file_inode(exe_file)->i_ino; + dev = file_inode(exe_file)->i_sb->s_dev; fput(exe_file); return audit_mark_compare(mark, ino, dev); } diff --git a/kernel/events/core.c b/kernel/events/core.c index 6ee1febdf6ff..5134a1c17186 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -6701,7 +6701,7 @@ static bool perf_addr_filter_match(struct perf_addr_filter *filter, struct file *file, unsigned long offset, unsigned long size) { - if (filter->inode != file->f_inode) + if (filter->inode != file_inode(file)) return false; if (filter->offset > offset + size) diff --git a/kernel/locking/qspinlock_stat.h b/kernel/locking/qspinlock_stat.h index eb0a599fcf58..e852be4851fc 100644 --- a/kernel/locking/qspinlock_stat.h +++ b/kernel/locking/qspinlock_stat.h @@ -108,11 +108,7 @@ static ssize_t qstat_read(struct file *file, char __user *user_buf, /* * Get the counter ID stored in file->f_inode->i_private */ - if (!file->f_inode) { - WARN_ON_ONCE(1); - return -EBADF; - } - counter = (long)(file->f_inode->i_private); + counter = (long)file_inode(file)->i_private; if (counter >= qstat_num) return -EBADF; @@ -177,11 +173,7 @@ static ssize_t qstat_write(struct file *file, const char __user *user_buf, /* * Get the counter ID stored in file->f_inode->i_private */ - if (!file->f_inode) { - WARN_ON_ONCE(1); - return -EBADF; - } - if ((long)(file->f_inode->i_private) != qstat_reset_cnts) + if ((long)file_inode(file)->i_private != qstat_reset_cnts) return count; for_each_possible_cpu(cpu) { diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c index 1cb060293505..ad170310a856 100644 --- a/security/smack/smack_lsm.c +++ b/security/smack/smack_lsm.c @@ -225,7 +225,7 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file, { struct task_smack *tsp = cred->security; struct smack_known *sskp = tsp->smk_task; - struct inode *inode = file->f_inode; + struct inode *inode = file_inode(file); struct inode_smack *isp = inode->i_security; char acc[SMK_NUM_ACCESS_TYPE + 1]; -- cgit v1.2.3 From c9492b4bea2630dacd18e16f8e8b0dcf91a6edcf Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Nov 2016 23:04:21 +0800 Subject: soc/fsl/qe: use builtin_platform_driver Use builtin_platform_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Scott Wood --- drivers/soc/fsl/qe/qe.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qe/qe.c b/drivers/soc/fsl/qe/qe.c index 2707a827261b..ade168f5328e 100644 --- a/drivers/soc/fsl/qe/qe.c +++ b/drivers/soc/fsl/qe/qe.c @@ -717,9 +717,5 @@ static struct platform_driver qe_driver = { .resume = qe_resume, }; -static int __init qe_drv_init(void) -{ - return platform_driver_register(&qe_driver); -} -device_initcall(qe_drv_init); +builtin_platform_driver(qe_driver); #endif /* defined(CONFIG_SUSPEND) && defined(CONFIG_PPC_85xx) */ -- cgit v1.2.3 From d7544424169e0ba1ffdc39edbdfa822711a59c5f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Mon, 17 Oct 2016 15:13:59 +0000 Subject: soc/fsl/bman: Use resource_size instead of computation Use resource_size function on resource object instead of explicit computation. Generated by: scripts/coccinelle/api/resource_size.cocci Signed-off-by: Wei Yongjun Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/bman_ccsr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/bman_ccsr.c b/drivers/soc/fsl/qbman/bman_ccsr.c index 9deb0524543f..a8e8389a6894 100644 --- a/drivers/soc/fsl/qbman/bman_ccsr.c +++ b/drivers/soc/fsl/qbman/bman_ccsr.c @@ -181,8 +181,7 @@ static int fsl_bman_probe(struct platform_device *pdev) node->full_name); return -ENXIO; } - bm_ccsr_start = devm_ioremap(dev, res->start, - res->end - res->start + 1); + bm_ccsr_start = devm_ioremap(dev, res->start, resource_size(res)); if (!bm_ccsr_start) return -ENXIO; -- cgit v1.2.3 From 3a71b3c8946fd44cd2599d9e87ac8f90c71318e1 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Mon, 5 Dec 2016 09:23:20 +0100 Subject: libnvdimm, e820: use module_platform_driver Use module_platform_driver for the e820 driver instead of open-coding it. Signed-off-by: Johannes Thumshirn Signed-off-by: Dan Williams --- drivers/nvdimm/e820.c | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/e820.c b/drivers/nvdimm/e820.c index 11ea90120542..6f9a6ffd7cde 100644 --- a/drivers/nvdimm/e820.c +++ b/drivers/nvdimm/e820.c @@ -84,18 +84,8 @@ static struct platform_driver e820_pmem_driver = { }, }; -static __init int e820_pmem_init(void) -{ - return platform_driver_register(&e820_pmem_driver); -} - -static __exit void e820_pmem_exit(void) -{ - platform_driver_unregister(&e820_pmem_driver); -} +module_platform_driver(e820_pmem_driver); MODULE_ALIAS("platform:e820_pmem*"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Intel Corporation"); -module_init(e820_pmem_init); -module_exit(e820_pmem_exit); -- cgit v1.2.3 From cbbd26b8b1a6af9c02e2b6523e12bd50cc765059 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 1 Nov 2016 22:09:04 -0400 Subject: [iov_iter] new primitives - copy_from_iter_full() and friends copy_from_iter_full(), copy_from_iter_full_nocache() and csum_and_copy_from_iter_full() - counterparts of copy_from_iter() et.al., advancing iterator only in case of successful full copy and returning whether it had been successful or not. Convert some obvious users. *NOTE* - do not blindly assume that something is a good candidate for those unless you are sure that not advancing iov_iter in failure case is the right thing in this case. Anything that does short read/short write kind of stuff (or is in a loop, etc.) is unlikely to be a good one. Signed-off-by: Al Viro --- drivers/bluetooth/hci_vhci.c | 2 +- drivers/net/macvtap.c | 4 +- drivers/net/tun.c | 7 +-- drivers/usb/gadget/function/f_fs.c | 2 +- drivers/usb/gadget/legacy/inode.c | 2 +- drivers/vhost/scsi.c | 3 +- drivers/vhost/vhost.c | 3 +- fs/ncpfs/file.c | 2 +- fs/orangefs/devorangefs-req.c | 13 ++--- include/linux/uio.h | 3 ++ kernel/printk/printk.c | 2 +- lib/iov_iter.c | 98 +++++++++++++++++++++++++++++++++++++- net/atm/common.c | 2 +- net/bluetooth/l2cap_core.c | 6 +-- net/packet/af_packet.c | 5 +- net/tipc/msg.c | 4 +- security/keys/keyctl.c | 2 +- 17 files changed, 121 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index c4a75a18dcae..233e850fdac7 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -181,7 +181,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data, if (!skb) return -ENOMEM; - if (copy_from_iter(skb_put(skb, len), len, from) != len) { + if (!copy_from_iter_full(skb_put(skb, len), len, from)) { kfree_skb(skb); return -EFAULT; } diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c index 070e3290aa6e..19d81ca3fb49 100644 --- a/drivers/net/macvtap.c +++ b/drivers/net/macvtap.c @@ -673,7 +673,6 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, int depth; bool zerocopy = false; size_t linear; - ssize_t n; if (q->flags & IFF_VNET_HDR) { vnet_hdr_len = q->vnet_hdr_sz; @@ -684,8 +683,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m, len -= vnet_hdr_len; err = -EFAULT; - n = copy_from_iter(&vnet_hdr, sizeof(vnet_hdr), from); - if (n != sizeof(vnet_hdr)) + if (!copy_from_iter_full(&vnet_hdr, sizeof(vnet_hdr), from)) goto err; iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr)); if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 8093e39ae263..4fa2d756548a 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1171,7 +1171,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, bool zerocopy = false; int err; u32 rxhash; - ssize_t n; if (!(tun->dev->flags & IFF_UP)) return -EIO; @@ -1181,8 +1180,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, return -EINVAL; len -= sizeof(pi); - n = copy_from_iter(&pi, sizeof(pi), from); - if (n != sizeof(pi)) + if (!copy_from_iter_full(&pi, sizeof(pi), from)) return -EFAULT; } @@ -1191,8 +1189,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile, return -EINVAL; len -= tun->vnet_hdr_sz; - n = copy_from_iter(&gso, sizeof(gso), from); - if (n != sizeof(gso)) + if (!copy_from_iter_full(&gso, sizeof(gso), from)) return -EFAULT; if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) && diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c index 17989b72cdae..0bfd1e25b431 100644 --- a/drivers/usb/gadget/function/f_fs.c +++ b/drivers/usb/gadget/function/f_fs.c @@ -949,7 +949,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data) goto error_mutex; } if (!io_data->read && - copy_from_iter(data, data_len, &io_data->data) != data_len) { + !copy_from_iter_full(data, data_len, &io_data->data)) { ret = -EFAULT; goto error_mutex; } diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index bd82dd12deff..10b2576f8b6a 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -667,7 +667,7 @@ ep_write_iter(struct kiocb *iocb, struct iov_iter *from) return -ENOMEM; } - if (unlikely(copy_from_iter(buf, len, from) != len)) { + if (unlikely(!copy_from_iter_full(buf, len, from))) { value = -EFAULT; goto out; } diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 6e29d053843d..b296985fda0d 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -922,8 +922,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) */ iov_iter_init(&out_iter, WRITE, vq->iov, out, out_size); - ret = copy_from_iter(req, req_size, &out_iter); - if (unlikely(ret != req_size)) { + if (unlikely(!copy_from_iter_full(req, req_size, &out_iter))) { vq_err(vq, "Faulted on copy_from_iter\n"); vhost_scsi_send_bad_target(vs, vq, head, out); continue; diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index c6f2d89c0e97..06e8b81b6253 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -1862,8 +1862,7 @@ static int get_indirect(struct vhost_virtqueue *vq, i, count); return -EINVAL; } - if (unlikely(copy_from_iter(&desc, sizeof(desc), &from) != - sizeof(desc))) { + if (unlikely(!copy_from_iter_full(&desc, sizeof(desc), &from))) { vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n", i, (size_t)vhost64_to_cpu(vq, indirect->addr) + i * sizeof desc); return -EINVAL; diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index dd38ca1f2ecb..83ca77231707 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -203,7 +203,7 @@ ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from) bufsize - (pos % bufsize), iov_iter_count(from)); - if (copy_from_iter(bouncebuffer, to_write, from) != to_write) { + if (!copy_from_iter_full(bouncebuffer, to_write, from)) { errno = -EFAULT; break; } diff --git a/fs/orangefs/devorangefs-req.c b/fs/orangefs/devorangefs-req.c index 516ffb4dc9a0..b0ced669427e 100644 --- a/fs/orangefs/devorangefs-req.c +++ b/fs/orangefs/devorangefs-req.c @@ -355,7 +355,6 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, __u64 tag; } head; int total = ret = iov_iter_count(iter); - int n; int downcall_size = sizeof(struct orangefs_downcall_s); int head_size = sizeof(head); @@ -372,8 +371,7 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, return -EFAULT; } - n = copy_from_iter(&head, head_size, iter); - if (n < head_size) { + if (!copy_from_iter_full(&head, head_size, iter)) { gossip_err("%s: failed to copy head.\n", __func__); return -EFAULT; } @@ -407,8 +405,7 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, return ret; } - n = copy_from_iter(&op->downcall, downcall_size, iter); - if (n != downcall_size) { + if (!copy_from_iter_full(&op->downcall, downcall_size, iter)) { gossip_err("%s: failed to copy downcall.\n", __func__); goto Efault; } @@ -462,10 +459,8 @@ static ssize_t orangefs_devreq_write_iter(struct kiocb *iocb, goto Enomem; } memset(op->downcall.trailer_buf, 0, op->downcall.trailer_size); - n = copy_from_iter(op->downcall.trailer_buf, - op->downcall.trailer_size, - iter); - if (n != op->downcall.trailer_size) { + if (!copy_from_iter_full(op->downcall.trailer_buf, + op->downcall.trailer_size, iter)) { gossip_err("%s: failed to copy trailer.\n", __func__); vfree(op->downcall.trailer_buf); goto Efault; diff --git a/include/linux/uio.h b/include/linux/uio.h index 6e22b544d039..e57c0ccd61c6 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -89,7 +89,9 @@ size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, struct iov_iter *i); size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i); size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i); +bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i); size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); +bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i); size_t iov_iter_zero(size_t bytes, struct iov_iter *); unsigned long iov_iter_alignment(const struct iov_iter *i); unsigned long iov_iter_gap_alignment(const struct iov_iter *i); @@ -155,6 +157,7 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count) } size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); +bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); int import_iovec(int type, const struct iovec __user * uvector, unsigned nr_segs, unsigned fast_segs, diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c index f7a55e9ff2f7..f6bda15396df 100644 --- a/kernel/printk/printk.c +++ b/kernel/printk/printk.c @@ -748,7 +748,7 @@ static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) return -ENOMEM; buf[len] = '\0'; - if (copy_from_iter(buf, len, from) != len) { + if (!copy_from_iter_full(buf, len, from)) { kfree(buf); return -EFAULT; } diff --git a/lib/iov_iter.c b/lib/iov_iter.c index f2bd21b93dfc..83c00b7f59b5 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -568,6 +568,31 @@ size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) } EXPORT_SYMBOL(copy_from_iter); +bool copy_from_iter_full(void *addr, size_t bytes, struct iov_iter *i) +{ + char *to = addr; + if (unlikely(i->type & ITER_PIPE)) { + WARN_ON(1); + return false; + } + if (unlikely(i->count < bytes)) \ + return false; + + iterate_all_kinds(i, bytes, v, ({ + if (__copy_from_user((to += v.iov_len) - v.iov_len, + v.iov_base, v.iov_len)) + return false; + 0;}), + memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len), + memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) + ) + + iov_iter_advance(i, bytes); + return true; +} +EXPORT_SYMBOL(copy_from_iter_full); + size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) { char *to = addr; @@ -587,6 +612,30 @@ size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) } EXPORT_SYMBOL(copy_from_iter_nocache); +bool copy_from_iter_full_nocache(void *addr, size_t bytes, struct iov_iter *i) +{ + char *to = addr; + if (unlikely(i->type & ITER_PIPE)) { + WARN_ON(1); + return false; + } + if (unlikely(i->count < bytes)) \ + return false; + iterate_all_kinds(i, bytes, v, ({ + if (__copy_from_user_nocache((to += v.iov_len) - v.iov_len, + v.iov_base, v.iov_len)) + return false; + 0;}), + memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, + v.bv_offset, v.bv_len), + memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) + ) + + iov_iter_advance(i, bytes); + return true; +} +EXPORT_SYMBOL(copy_from_iter_full_nocache); + size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, struct iov_iter *i) { @@ -1008,7 +1057,7 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, } iterate_and_advance(i, bytes, v, ({ int err = 0; - next = csum_and_copy_from_user(v.iov_base, + next = csum_and_copy_from_user(v.iov_base, (to += v.iov_len) - v.iov_len, v.iov_len, 0, &err); if (!err) { @@ -1037,6 +1086,51 @@ size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, } EXPORT_SYMBOL(csum_and_copy_from_iter); +bool csum_and_copy_from_iter_full(void *addr, size_t bytes, __wsum *csum, + struct iov_iter *i) +{ + char *to = addr; + __wsum sum, next; + size_t off = 0; + sum = *csum; + if (unlikely(i->type & ITER_PIPE)) { + WARN_ON(1); + return false; + } + if (unlikely(i->count < bytes)) + return false; + iterate_all_kinds(i, bytes, v, ({ + int err = 0; + next = csum_and_copy_from_user(v.iov_base, + (to += v.iov_len) - v.iov_len, + v.iov_len, 0, &err); + if (err) + return false; + sum = csum_block_add(sum, next, off); + off += v.iov_len; + 0; + }), ({ + char *p = kmap_atomic(v.bv_page); + next = csum_partial_copy_nocheck(p + v.bv_offset, + (to += v.bv_len) - v.bv_len, + v.bv_len, 0); + kunmap_atomic(p); + sum = csum_block_add(sum, next, off); + off += v.bv_len; + }),({ + next = csum_partial_copy_nocheck(v.iov_base, + (to += v.iov_len) - v.iov_len, + v.iov_len, 0); + sum = csum_block_add(sum, next, off); + off += v.iov_len; + }) + ) + *csum = sum; + iov_iter_advance(i, bytes); + return true; +} +EXPORT_SYMBOL(csum_and_copy_from_iter_full); + size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, struct iov_iter *i) { @@ -1051,7 +1145,7 @@ size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, iterate_and_advance(i, bytes, v, ({ int err = 0; next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len, - v.iov_base, + v.iov_base, v.iov_len, 0, &err); if (!err) { sum = csum_block_add(sum, next, off); diff --git a/net/atm/common.c b/net/atm/common.c index 6dc12305799e..a3ca922d307b 100644 --- a/net/atm/common.c +++ b/net/atm/common.c @@ -630,7 +630,7 @@ int vcc_sendmsg(struct socket *sock, struct msghdr *m, size_t size) goto out; skb->dev = NULL; /* for paths shared with net_device interfaces */ ATM_SKB(skb)->atm_options = vcc->atm_options; - if (copy_from_iter(skb_put(skb, size), size, &m->msg_iter) != size) { + if (!copy_from_iter_full(skb_put(skb, size), size, &m->msg_iter)) { kfree_skb(skb); error = -EFAULT; goto out; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 577f1c01454a..ce0b5dd01953 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2127,7 +2127,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, struct sk_buff **frag; int sent = 0; - if (copy_from_iter(skb_put(skb, count), count, &msg->msg_iter) != count) + if (!copy_from_iter_full(skb_put(skb, count), count, &msg->msg_iter)) return -EFAULT; sent += count; @@ -2147,8 +2147,8 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, *frag = tmp; - if (copy_from_iter(skb_put(*frag, count), count, - &msg->msg_iter) != count) + if (!copy_from_iter_full(skb_put(*frag, count), count, + &msg->msg_iter)) return -EFAULT; sent += count; diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index d2238b204691..588ec202d5ba 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -2432,14 +2432,11 @@ static int __packet_snd_vnet_parse(struct virtio_net_hdr *vnet_hdr, size_t len) static int packet_snd_vnet_parse(struct msghdr *msg, size_t *len, struct virtio_net_hdr *vnet_hdr) { - int n; - if (*len < sizeof(*vnet_hdr)) return -EINVAL; *len -= sizeof(*vnet_hdr); - n = copy_from_iter(vnet_hdr, sizeof(*vnet_hdr), &msg->msg_iter); - if (n != sizeof(*vnet_hdr)) + if (!copy_from_iter_full(vnet_hdr, sizeof(*vnet_hdr), &msg->msg_iter)) return -EFAULT; return __packet_snd_vnet_parse(vnet_hdr, *len); diff --git a/net/tipc/msg.c b/net/tipc/msg.c index 17201aa8423d..a22be502f1bd 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -268,7 +268,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, __skb_queue_tail(list, skb); skb_copy_to_linear_data(skb, mhdr, mhsz); pktpos = skb->data + mhsz; - if (copy_from_iter(pktpos, dsz, &m->msg_iter) == dsz) + if (copy_from_iter_full(pktpos, dsz, &m->msg_iter)) return dsz; rc = -EFAULT; goto error; @@ -299,7 +299,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct msghdr *m, if (drem < pktrem) pktrem = drem; - if (copy_from_iter(pktpos, pktrem, &m->msg_iter) != pktrem) { + if (!copy_from_iter_full(pktpos, pktrem, &m->msg_iter)) { rc = -EFAULT; goto error; } diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c index d580ad06b792..f89f1900e58d 100644 --- a/security/keys/keyctl.c +++ b/security/keys/keyctl.c @@ -1074,7 +1074,7 @@ long keyctl_instantiate_key_common(key_serial_t id, } ret = -EFAULT; - if (copy_from_iter(payload, plen, from) != plen) + if (!copy_from_iter_full(payload, plen, from)) goto error2; } -- cgit v1.2.3 From 68583ca2a183c6368f4c333fa989685fba7cf325 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Sat, 19 Nov 2016 20:26:25 -0600 Subject: i40iw: Convert page_size to encoded value Passed in page_size was used as encoded value for writing the WQE and passed in value was usually 4096. This was working out since bit 0 was 0 and implies 4KB pages, but would not work for other page sizes. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 12 +++++++++--- drivers/infiniband/hw/i40iw/i40iw_type.h | 5 +++++ 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 6bf2a19f3cba..8417452a7a9c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -2747,7 +2747,9 @@ static enum i40iw_status_code i40iw_sc_alloc_stag( u64 *wqe; struct i40iw_sc_cqp *cqp; u64 header; + enum i40iw_page_size page_size; + page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K; cqp = dev->cqp; wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch); if (!wqe) @@ -2767,7 +2769,7 @@ static enum i40iw_status_code i40iw_sc_alloc_stag( LS_64(1, I40IW_CQPSQ_STAG_MR) | LS_64(info->access_rights, I40IW_CQPSQ_STAG_ARIGHTS) | LS_64(info->chunk_size, I40IW_CQPSQ_STAG_LPBLSIZE) | - LS_64(info->page_size, I40IW_CQPSQ_STAG_HPAGESIZE) | + LS_64(page_size, I40IW_CQPSQ_STAG_HPAGESIZE) | LS_64(info->remote_access, I40IW_CQPSQ_STAG_REMACCENABLED) | LS_64(info->use_hmc_fcn_index, I40IW_CQPSQ_STAG_USEHMCFNIDX) | LS_64(info->use_pf_rid, I40IW_CQPSQ_STAG_USEPFRID) | @@ -2803,7 +2805,9 @@ static enum i40iw_status_code i40iw_sc_mr_reg_non_shared( u32 pble_obj_cnt; bool remote_access; u8 addr_type; + enum i40iw_page_size page_size; + page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K; if (info->access_rights & (I40IW_ACCESS_FLAGS_REMOTEREAD_ONLY | I40IW_ACCESS_FLAGS_REMOTEWRITE_ONLY)) remote_access = true; @@ -2846,7 +2850,7 @@ static enum i40iw_status_code i40iw_sc_mr_reg_non_shared( header = LS_64(I40IW_CQP_OP_REG_MR, I40IW_CQPSQ_OPCODE) | LS_64(1, I40IW_CQPSQ_STAG_MR) | LS_64(info->chunk_size, I40IW_CQPSQ_STAG_LPBLSIZE) | - LS_64(info->page_size, I40IW_CQPSQ_STAG_HPAGESIZE) | + LS_64(page_size, I40IW_CQPSQ_STAG_HPAGESIZE) | LS_64(info->access_rights, I40IW_CQPSQ_STAG_ARIGHTS) | LS_64(remote_access, I40IW_CQPSQ_STAG_REMACCENABLED) | LS_64(addr_type, I40IW_CQPSQ_STAG_VABASEDTO) | @@ -3061,7 +3065,9 @@ enum i40iw_status_code i40iw_sc_mr_fast_register( u64 temp, header; u64 *wqe; u32 wqe_idx; + enum i40iw_page_size page_size; + page_size = (info->page_size == 0x200000) ? I40IW_PAGE_SIZE_2M : I40IW_PAGE_SIZE_4K; wqe = i40iw_qp_get_next_send_wqe(&qp->qp_uk, &wqe_idx, I40IW_QP_WQE_MIN_SIZE, 0, info->wr_id); if (!wqe) @@ -3088,7 +3094,7 @@ enum i40iw_status_code i40iw_sc_mr_fast_register( LS_64(info->stag_idx, I40IWQPSQ_STAGINDEX) | LS_64(I40IWQP_OP_FAST_REGISTER, I40IWQPSQ_OPCODE) | LS_64(info->chunk_size, I40IWQPSQ_LPBLSIZE) | - LS_64(info->page_size, I40IWQPSQ_HPAGESIZE) | + LS_64(page_size, I40IWQPSQ_HPAGESIZE) | LS_64(info->access_rights, I40IWQPSQ_STAGRIGHTS) | LS_64(info->addr_type, I40IWQPSQ_VABASEDTO) | LS_64(info->read_fence, I40IWQPSQ_READFENCE) | diff --git a/drivers/infiniband/hw/i40iw/i40iw_type.h b/drivers/infiniband/hw/i40iw/i40iw_type.h index d1847e693025..928d91b956a8 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_type.h +++ b/drivers/infiniband/hw/i40iw/i40iw_type.h @@ -74,6 +74,11 @@ struct i40iw_priv_qp_ops; struct i40iw_priv_cq_ops; struct i40iw_hmc_ops; +enum i40iw_page_size { + I40IW_PAGE_SIZE_4K, + I40IW_PAGE_SIZE_2M +}; + enum i40iw_resource_indicator_type { I40IW_RSRC_INDICATOR_TYPE_ADAPTER = 0, I40IW_RSRC_INDICATOR_TYPE_CQ, -- cgit v1.2.3 From e69c5093617afdbd2ab02c289d0adaac044dff66 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:24:48 -0600 Subject: i40iw: Use vector when creating CQs Assign each CEQ vector to a different CPU when possible, then when creating a CQ, use the vector for the CEQ id. This allows completion work to be distributed over multiple cores. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_main.c | 8 +++++++- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 5 +++-- 2 files changed, 10 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index e6abdafd1b6f..ed24831344b1 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -270,6 +270,7 @@ static void i40iw_disable_irq(struct i40iw_sc_dev *dev, i40iw_wr32(dev->hw, I40E_PFINT_DYN_CTLN(msix_vec->idx - 1), 0); else i40iw_wr32(dev->hw, I40E_VFINT_DYN_CTLN1(msix_vec->idx - 1), 0); + irq_set_affinity_hint(msix_vec->irq, NULL); free_irq(msix_vec->irq, dev_id); } @@ -688,6 +689,7 @@ static enum i40iw_status_code i40iw_configure_ceq_vector(struct i40iw_device *iw struct i40iw_msix_vector *msix_vec) { enum i40iw_status_code status; + cpumask_t mask; if (iwdev->msix_shared && !ceq_id) { tasklet_init(&iwdev->dpc_tasklet, i40iw_dpc, (unsigned long)iwdev); @@ -697,12 +699,15 @@ static enum i40iw_status_code i40iw_configure_ceq_vector(struct i40iw_device *iw status = request_irq(msix_vec->irq, i40iw_ceq_handler, 0, "CEQ", iwceq); } + cpumask_clear(&mask); + cpumask_set_cpu(msix_vec->cpu_affinity, &mask); + irq_set_affinity_hint(msix_vec->irq, &mask); + if (status) { i40iw_pr_err("ceq irq config fail\n"); return I40IW_ERR_CONFIG; } msix_vec->ceq_id = ceq_id; - msix_vec->cpu_affinity = 0; return 0; } @@ -1396,6 +1401,7 @@ static enum i40iw_status_code i40iw_save_msix_info(struct i40iw_device *iwdev, for (i = 0, ceq_idx = 0; i < iwdev->msix_count; i++, iw_qvinfo++) { iwdev->iw_msixtbl[i].idx = ldev->msix_entries[i].entry; iwdev->iw_msixtbl[i].irq = ldev->msix_entries[i].vector; + iwdev->iw_msixtbl[i].cpu_affinity = ceq_idx; if (i == 0) { iw_qvinfo->aeq_idx = 0; if (iwdev->msix_shared) diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 56e1c2c6ec34..aacaa0fcfb77 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -1135,7 +1135,8 @@ static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev, ukinfo->cq_id = cq_num; iwcq->ibcq.cqe = info.cq_uk_init_info.cq_size; info.ceqe_mask = 0; - info.ceq_id = 0; + if (attr->comp_vector < iwdev->ceqs_count) + info.ceq_id = attr->comp_vector; info.ceq_id_valid = true; info.ceqe_mask = 1; info.type = I40IW_CQ_TYPE_IWARP; @@ -2619,7 +2620,7 @@ static struct i40iw_ib_device *i40iw_init_rdma_device(struct i40iw_device *iwdev (1ull << IB_USER_VERBS_CMD_POST_RECV) | (1ull << IB_USER_VERBS_CMD_POST_SEND); iwibdev->ibdev.phys_port_cnt = 1; - iwibdev->ibdev.num_comp_vectors = 1; + iwibdev->ibdev.num_comp_vectors = iwdev->ceqs_count; iwibdev->ibdev.dma_device = &pcidev->dev; iwibdev->ibdev.dev.parent = &pcidev->dev; iwibdev->ibdev.query_port = i40iw_query_port; -- cgit v1.2.3 From 01d0b36798732d826fbf84de8961a09b3a2fbf3f Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:26:39 -0600 Subject: i40iw: Correct values for max_recv_sge, max_send_sge When creating QPs, ensure init_attr->cap.max_recv_sge is clipped to MAX_FRAG_COUNT. Expose MAX_FRAG_COUNT for max_recv_sge and max_send_sge in i40iw_query_qp(). Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Reviewed-By: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index aacaa0fcfb77..6b516d6156dc 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -608,6 +608,9 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, if (init_attr->cap.max_send_sge > I40IW_MAX_WQ_FRAGMENT_COUNT) init_attr->cap.max_send_sge = I40IW_MAX_WQ_FRAGMENT_COUNT; + if (init_attr->cap.max_recv_sge > I40IW_MAX_WQ_FRAGMENT_COUNT) + init_attr->cap.max_recv_sge = I40IW_MAX_WQ_FRAGMENT_COUNT; + memset(&init_info, 0, sizeof(init_info)); sq_size = init_attr->cap.max_send_wr; @@ -813,8 +816,9 @@ static int i40iw_query_qp(struct ib_qp *ibqp, attr->qp_access_flags = 0; attr->cap.max_send_wr = qp->qp_uk.sq_size; attr->cap.max_recv_wr = qp->qp_uk.rq_size; - attr->cap.max_recv_sge = 1; attr->cap.max_inline_data = I40IW_MAX_INLINE_DATA_SIZE; + attr->cap.max_send_sge = I40IW_MAX_WQ_FRAGMENT_COUNT; + attr->cap.max_recv_sge = I40IW_MAX_WQ_FRAGMENT_COUNT; init_attr->event_handler = iwqp->ibqp.event_handler; init_attr->qp_context = iwqp->ibqp.qp_context; init_attr->send_cq = iwqp->ibqp.send_cq; -- cgit v1.2.3 From c38d7e0d08421a53cea4e09b76b3453d499fbd67 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:27:02 -0600 Subject: i40iw: Fix for LAN handler removal If i40iw_open() fails for any reason, the LAN handler is not being removed. Modify i40iw_deinit_device() to always remove the handler. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_main.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index ed24831344b1..db9fd31b5c72 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -1422,12 +1422,11 @@ static enum i40iw_status_code i40iw_save_msix_info(struct i40iw_device *iwdev, * i40iw_deinit_device - clean up the device resources * @iwdev: iwarp device * @reset: true if called before reset - * @del_hdl: true if delete hdl entry * * Destroy the ib device interface, remove the mac ip entry and ipv4/ipv6 addresses, * destroy the device queues and free the pble and the hmc objects */ -static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset, bool del_hdl) +static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset) { struct i40e_info *ldev = iwdev->ldev; @@ -1492,8 +1491,7 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset, bool del break; } - if (del_hdl) - i40iw_del_handler(i40iw_find_i40e_handler(ldev)); + i40iw_del_handler(i40iw_find_i40e_handler(ldev)); kfree(iwdev->hdl); } @@ -1658,7 +1656,7 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client) } while (0); i40iw_pr_err("status = %d last completion = %d\n", status, iwdev->init_state); - i40iw_deinit_device(iwdev, false, false); + i40iw_deinit_device(iwdev, false); return -ERESTART; } @@ -1736,7 +1734,7 @@ static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client, bool iwdev = &hdl->device; destroy_workqueue(iwdev->virtchnl_wq); - i40iw_deinit_device(iwdev, reset, true); + i40iw_deinit_device(iwdev, reset); } /** -- cgit v1.2.3 From e7f9774af591d346990f1d6dfca0ee9caeb52756 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:28:02 -0600 Subject: i40iw: Optimize inline data copy Use memcpy for inline data copy in sends and writes instead of byte by byte copy. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_uk.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_uk.c b/drivers/infiniband/hw/i40iw/i40iw_uk.c index 4d28c3cb03cc..47cb2e063ee3 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_uk.c +++ b/drivers/infiniband/hw/i40iw/i40iw_uk.c @@ -430,7 +430,7 @@ static enum i40iw_status_code i40iw_inline_rdma_write(struct i40iw_qp_uk *qp, struct i40iw_inline_rdma_write *op_info; u64 *push; u64 header = 0; - u32 i, wqe_idx; + u32 wqe_idx; enum i40iw_status_code ret_code; bool read_fence = false; u8 wqe_size; @@ -465,14 +465,12 @@ static enum i40iw_status_code i40iw_inline_rdma_write(struct i40iw_qp_uk *qp, src = (u8 *)(op_info->data); if (op_info->len <= 16) { - for (i = 0; i < op_info->len; i++, src++, dest++) - *dest = *src; + memcpy(dest, src, op_info->len); } else { - for (i = 0; i < 16; i++, src++, dest++) - *dest = *src; + memcpy(dest, src, 16); + src += 16; dest = (u8 *)wqe + 32; - for (; i < op_info->len; i++, src++, dest++) - *dest = *src; + memcpy(dest, src, op_info->len - 16); } wmb(); /* make sure WQE is populated before valid bit is set */ @@ -507,7 +505,7 @@ static enum i40iw_status_code i40iw_inline_send(struct i40iw_qp_uk *qp, u8 *dest, *src; struct i40iw_post_inline_send *op_info; u64 header; - u32 wqe_idx, i; + u32 wqe_idx; enum i40iw_status_code ret_code; bool read_fence = false; u8 wqe_size; @@ -540,14 +538,12 @@ static enum i40iw_status_code i40iw_inline_send(struct i40iw_qp_uk *qp, src = (u8 *)(op_info->data); if (op_info->len <= 16) { - for (i = 0; i < op_info->len; i++, src++, dest++) - *dest = *src; + memcpy(dest, src, op_info->len); } else { - for (i = 0; i < 16; i++, src++, dest++) - *dest = *src; + memcpy(dest, src, 16); + src += 16; dest = (u8 *)wqe + 32; - for (; i < op_info->len; i++, src++, dest++) - *dest = *src; + memcpy(dest, src, op_info->len - 16); } wmb(); /* make sure WQE is populated before valid bit is set */ -- cgit v1.2.3 From 85a87c90ee90217da1b05a77bbb47ebe31a2f124 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:30:28 -0600 Subject: i40iw: Query device accounts for internal rsrc Some resources are consumed internally and not available to the user. After hw is initialized, figure out how many resources are consumed and subtract those numbers from the initial max device capability in i40iw_query_device(). Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw.h | 4 ++++ drivers/infiniband/hw/i40iw/i40iw_hw.c | 2 +- drivers/infiniband/hw/i40iw/i40iw_main.c | 15 +++++++++++++++ drivers/infiniband/hw/i40iw/i40iw_user.h | 3 ++- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 8 ++++---- 5 files changed, 26 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index 4a0c12bd9caa..dac9a6bcc631 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -303,6 +303,10 @@ struct i40iw_device { u32 mr_stagmask; u32 mpa_version; bool dcb; + u32 used_pds; + u32 used_cqs; + u32 used_mrs; + u32 used_qps; }; struct i40iw_ib_device { diff --git a/drivers/infiniband/hw/i40iw/i40iw_hw.c b/drivers/infiniband/hw/i40iw/i40iw_hw.c index b94727ffc862..5e2c16c725e3 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_hw.c +++ b/drivers/infiniband/hw/i40iw/i40iw_hw.c @@ -62,7 +62,7 @@ u32 i40iw_initialize_hw_resources(struct i40iw_device *iwdev) max_mr = iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_MR].cnt; arp_table_size = iwdev->sc_dev.hmc_info->hmc_obj[I40IW_HMC_IW_ARP].cnt; iwdev->max_cqe = 0xFFFFF; - num_pds = max_qp * 4; + num_pds = I40IW_MAX_PDS; resources_size = sizeof(struct i40iw_arp_entry) * arp_table_size; resources_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp); resources_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr); diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index db9fd31b5c72..9d3b9ee20ba7 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -1557,6 +1557,20 @@ exit: return status; } +/** + * i40iw_get_used_rsrc - determine resources used internally + * @iwdev: iwarp device + * + * Called after internal allocations + */ +static void i40iw_get_used_rsrc(struct i40iw_device *iwdev) +{ + iwdev->used_pds = find_next_zero_bit(iwdev->allocated_pds, iwdev->max_pd, 0); + iwdev->used_qps = find_next_zero_bit(iwdev->allocated_qps, iwdev->max_qp, 0); + iwdev->used_cqs = find_next_zero_bit(iwdev->allocated_cqs, iwdev->max_cq, 0); + iwdev->used_mrs = find_next_zero_bit(iwdev->allocated_mrs, iwdev->max_mr, 0); +} + /** * i40iw_open - client interface operation open for iwarp/uda device * @ldev: lan device information @@ -1629,6 +1643,7 @@ static int i40iw_open(struct i40e_info *ldev, struct i40e_client *client) status = i40iw_initialize_hw_resources(iwdev); if (status) break; + i40iw_get_used_rsrc(iwdev); dev->ccq_ops->ccq_arm(dev->ccq); status = i40iw_hmc_init_pble(&iwdev->sc_dev, iwdev->pble_rsrc); if (status) diff --git a/drivers/infiniband/hw/i40iw/i40iw_user.h b/drivers/infiniband/hw/i40iw/i40iw_user.h index e65c2baa7db2..66263fced68f 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_user.h +++ b/drivers/infiniband/hw/i40iw/i40iw_user.h @@ -76,7 +76,8 @@ enum i40iw_device_capabilities_const { I40IW_MAX_ORD_SIZE = 127, I40IW_MAX_WQ_ENTRIES = 2048, I40IW_Q2_BUFFER_SIZE = (248 + 100), - I40IW_QP_CTX_SIZE = 248 + I40IW_QP_CTX_SIZE = 248, + I40IW_MAX_PDS = 32768 }; #define i40iw_handle void * diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 6b516d6156dc..d20ee118f366 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -67,13 +67,13 @@ static int i40iw_query_device(struct ib_device *ibdev, props->vendor_part_id = iwdev->ldev->pcidev->device; props->hw_ver = (u32)iwdev->sc_dev.hw_rev; props->max_mr_size = I40IW_MAX_OUTBOUND_MESSAGE_SIZE; - props->max_qp = iwdev->max_qp; + props->max_qp = iwdev->max_qp - iwdev->used_qps; props->max_qp_wr = (I40IW_MAX_WQ_ENTRIES >> 2) - 1; props->max_sge = I40IW_MAX_WQ_FRAGMENT_COUNT; - props->max_cq = iwdev->max_cq; + props->max_cq = iwdev->max_cq - iwdev->used_cqs; props->max_cqe = iwdev->max_cqe; - props->max_mr = iwdev->max_mr; - props->max_pd = iwdev->max_pd; + props->max_mr = iwdev->max_mr - iwdev->used_mrs; + props->max_pd = iwdev->max_pd - iwdev->used_pds; props->max_sge_rd = I40IW_MAX_SGE_RD; props->max_qp_rd_atom = I40IW_MAX_IRD_SIZE; props->max_qp_init_rd_atom = props->max_qp_rd_atom; -- cgit v1.2.3 From 799749979dbf41a878a00abdae00cf484c21a5b2 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:32:03 -0600 Subject: i40iw: Remove checks for more than 48 bytes inline data Remove dead code, which isn't executed because we return error if the data size is greater than 48 bytes. Inline data size greater than 48 bytes isn't supported and the maximum WQE size is 64 bytes. Signed-off-by: Tatyana Nikolova Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_uk.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_uk.c b/drivers/infiniband/hw/i40iw/i40iw_uk.c index 47cb2e063ee3..5d9c3bfb7310 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_uk.c +++ b/drivers/infiniband/hw/i40iw/i40iw_uk.c @@ -1186,12 +1186,8 @@ enum i40iw_status_code i40iw_inline_data_size_to_wqesize(u32 data_size, if (data_size <= 16) *wqe_size = I40IW_QP_WQE_MIN_SIZE; - else if (data_size <= 48) - *wqe_size = 64; - else if (data_size <= 80) - *wqe_size = 96; else - *wqe_size = 128; + *wqe_size = 64; return 0; } -- cgit v1.2.3 From 1ad19f739f494eda2f8e9611ab6c3056244b70fc Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:32:25 -0600 Subject: i40iw: Remove NULL check for cm_node->iwdev It is not necessary to check cm_node->iwdev in i40iw_rem_ref_cm_node() as it can never be NULL after a successful call out of i40iw_make_cm_node(). Signed-off-by: Chien Tin Tung Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 9e447b5951fc..cbd77eb30385 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -2234,7 +2234,7 @@ static void i40iw_rem_ref_cm_node(struct i40iw_cm_node *cm_node) i40iw_dec_refcnt_listen(cm_core, cm_node->listener, 0, true); } else { if (!i40iw_listen_port_in_use(cm_core, cm_node->loc_port) && - cm_node->apbvt_set && cm_node->iwdev) { + cm_node->apbvt_set) { i40iw_manage_apbvt(cm_node->iwdev, cm_node->loc_port, I40IW_MANAGE_APBVT_DEL); -- cgit v1.2.3 From e67791858e7b8d1389833386cb2dd0ca30d06862 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:33:32 -0600 Subject: i40iw: Use actual page size In i40iw_post_send, use the actual page size instead of encoded page size. This is to be consistent with the rest of the file. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index d20ee118f366..dcf08b8994ec 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2145,7 +2145,6 @@ static int i40iw_post_send(struct ib_qp *ibqp, case IB_WR_REG_MR: { struct i40iw_mr *iwmr = to_iwmr(reg_wr(ib_wr)->mr); - int page_shift = ilog2(reg_wr(ib_wr)->mr->page_size); int flags = reg_wr(ib_wr)->access; struct i40iw_pble_alloc *palloc = &iwmr->iwpbl.pble_alloc; struct i40iw_sc_dev *dev = &iwqp->iwdev->sc_dev; @@ -2156,6 +2155,7 @@ static int i40iw_post_send(struct ib_qp *ibqp, info.access_rights |= i40iw_get_user_access(flags); info.stag_key = reg_wr(ib_wr)->key & 0xff; info.stag_idx = reg_wr(ib_wr)->key >> 8; + info.page_size = reg_wr(ib_wr)->mr->page_size; info.wr_id = ib_wr->wr_id; info.addr_type = I40IW_ADDR_TYPE_VA_BASED; @@ -2169,9 +2169,6 @@ static int i40iw_post_send(struct ib_qp *ibqp, if (iwmr->npages > I40IW_MIN_PAGES_PER_FMR) info.chunk_size = 1; - if (page_shift == 21) - info.page_size = 1; /* 2M page */ - ret = dev->iw_priv_qp_ops->iw_mr_fast_register(&iwqp->sc_qp, &info, true); if (ret) err = -ENOMEM; -- cgit v1.2.3 From 5ebcb0ff54e594668e506583fa7344d101e3d05e Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:34:02 -0600 Subject: i40iw: Use runtime check for IS_ENABLED(CONFIG_IPV6) To be consistent, use the runtime check instead of conditional compile. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index cbd77eb30385..b60e34653ec1 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -1583,9 +1583,10 @@ static enum i40iw_status_code i40iw_del_multiple_qhash( static struct net_device *i40iw_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id, u8 *mac) { struct net_device *ip_dev = NULL; -#if IS_ENABLED(CONFIG_IPV6) struct in6_addr laddr6; + if (!IS_ENABLED(CONFIG_IPV6)) + return NULL; i40iw_copy_ip_htonl(laddr6.in6_u.u6_addr32, addr); if (vlan_id) *vlan_id = I40IW_NO_VLAN; @@ -1602,7 +1603,6 @@ static struct net_device *i40iw_netdev_vlan_ipv6(u32 *addr, u16 *vlan_id, u8 *ma } } rcu_read_unlock(); -#endif return ip_dev; } -- cgit v1.2.3 From dfd9c43b3ce97e1b66a6dc1d9dcc95db9a27cc4b Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 21:42:26 -0600 Subject: i40iw: Remove check on return from device_init_pestat() Remove unnecessary check for return code from device_init_pestat() and change func to void. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 10 ++-------- drivers/infiniband/hw/i40iw/i40iw_p.h | 2 +- drivers/infiniband/hw/i40iw/i40iw_virtchnl.c | 6 +----- 3 files changed, 4 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 8417452a7a9c..5dde358349ee 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -4853,10 +4853,9 @@ static const struct i40iw_device_pestat_ops iw_device_pestat_ops = { * i40iw_device_init_pestat - Initialize the pestat structure * @dev: pestat struct */ -enum i40iw_status_code i40iw_device_init_pestat(struct i40iw_dev_pestat *devstat) +void i40iw_device_init_pestat(struct i40iw_dev_pestat *devstat) { devstat->ops = iw_device_pestat_ops; - return 0; } /** @@ -4881,12 +4880,7 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, dev->debug_mask = info->debug_mask; - ret_code = i40iw_device_init_pestat(&dev->dev_pestat); - if (ret_code) { - i40iw_debug(dev, I40IW_DEBUG_DEV, - "%s: i40iw_device_init_pestat failed\n", __func__); - return ret_code; - } + i40iw_device_init_pestat(&dev->dev_pestat); dev->hmc_fn_id = info->hmc_fn_id; i40iw_fill_qos_list(info->l2params.qs_handle_list); for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) { diff --git a/drivers/infiniband/hw/i40iw/i40iw_p.h b/drivers/infiniband/hw/i40iw/i40iw_p.h index c9e8cb8c4410..2a4bd3233b41 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_p.h +++ b/drivers/infiniband/hw/i40iw/i40iw_p.h @@ -47,7 +47,7 @@ void i40iw_debug_buf(struct i40iw_sc_dev *dev, enum i40iw_debug_flag mask, enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, struct i40iw_device_init_info *info); -enum i40iw_status_code i40iw_device_init_pestat(struct i40iw_dev_pestat *); +void i40iw_device_init_pestat(struct i40iw_dev_pestat *devstat); void i40iw_sc_cqp_post_sq(struct i40iw_sc_cqp *cqp); diff --git a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c b/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c index 3041003c94d2..dbd39c4af946 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c @@ -496,11 +496,7 @@ enum i40iw_status_code i40iw_vchnl_recv_pf(struct i40iw_sc_dev *dev, i40iw_debug(dev, I40IW_DEBUG_VIRT, "VF%u error CQP HMC Function operation.\n", vf_id); - ret_code = i40iw_device_init_pestat(&vf_dev->dev_pestat); - if (ret_code) - i40iw_debug(dev, I40IW_DEBUG_VIRT, - "VF%u - i40iw_device_init_pestat failed\n", - vf_id); + i40iw_device_init_pestat(&vf_dev->dev_pestat); vf_dev->dev_pestat.ops.iw_hw_stat_init(&vf_dev->dev_pestat, (u8)vf_dev->pmf_index, dev->hw, false); -- cgit v1.2.3 From 78e945aace5b9aaf19404799cd29b4d155806053 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 9 Nov 2016 22:20:31 -0600 Subject: i40iw: Remove variable flush_code and check to set qp->sq_flush The flush_code variable in i40iw_bld_terminate_hdr() is obsolete and the check to set qp->sq_flush is unreachable. Currently flush code is populated in setup_term_hdr() and both SQ and RQ are flushed always as part of the tear down flow. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 5dde358349ee..a13503715f20 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -4185,7 +4185,6 @@ static int i40iw_bld_terminate_hdr(struct i40iw_sc_qp *qp, u16 ddp_seg_len; int copy_len = 0; u8 is_tagged = 0; - enum i40iw_flush_opcode flush_code = FLUSH_INVALID; u32 opcode; struct i40iw_terminate_hdr *termhdr; @@ -4358,9 +4357,6 @@ static int i40iw_bld_terminate_hdr(struct i40iw_sc_qp *qp, if (copy_len) memcpy(termhdr + 1, pkt, copy_len); - if (flush_code && !info->in_rdrsp_wr) - qp->sq_flush = (info->sq) ? true : false; - return sizeof(struct i40iw_terminate_hdr) + copy_len; } -- cgit v1.2.3 From d4165e3abdf16707602c10f0d678d4d564a87e35 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Tue, 22 Nov 2016 09:44:20 -0600 Subject: i40iw: Fix incorrect assignment of SQ head The SQ head is incorrectly incremented when the number of WQEs required is greater than the number available. The fix is to use the I40IW_RING_MOV_HEAD_BY_COUNT macro. This checks for the SQ full condition first and only if SQ has room for the request, then we move the head appropriately. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_uk.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_uk.c b/drivers/infiniband/hw/i40iw/i40iw_uk.c index 5d9c3bfb7310..4376cd628774 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_uk.c +++ b/drivers/infiniband/hw/i40iw/i40iw_uk.c @@ -175,12 +175,10 @@ u64 *i40iw_qp_get_next_send_wqe(struct i40iw_qp_uk *qp, if (!*wqe_idx) qp->swqe_polarity = !qp->swqe_polarity; } - - for (i = 0; i < wqe_size / I40IW_QP_WQE_MIN_SIZE; i++) { - I40IW_RING_MOVE_HEAD(qp->sq_ring, ret_code); - if (ret_code) - return NULL; - } + I40IW_RING_MOVE_HEAD_BY_COUNT(qp->sq_ring, + wqe_size / I40IW_QP_WQE_MIN_SIZE, ret_code); + if (ret_code) + return NULL; wqe = qp->sq_base[*wqe_idx].elem; -- cgit v1.2.3 From b6a529da69ce880ee4d0f3730ef46ead7f7cd0d3 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 30 Nov 2016 14:56:14 -0600 Subject: i40iw: Utilize physically mapped memory regions Add support to use physically mapped WQ's and MR's if determined that the OS registered user-memory for the region is physically contiguous. This feature will eliminate the need for unnecessarily setting up and using PBL's when not required. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 102 +++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index dcf08b8994ec..43bae5b14a71 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -1355,11 +1355,63 @@ static void i40iw_copy_user_pgaddrs(struct i40iw_mr *iwmr, } } +/** + * i40iw_check_mem_contiguous - check if pbls stored in arr are contiguous + * @arr: lvl1 pbl array + * @npages: page count + * pg_size: page size + * + */ +static bool i40iw_check_mem_contiguous(u64 *arr, u32 npages, u32 pg_size) +{ + u32 pg_idx; + + for (pg_idx = 0; pg_idx < npages; pg_idx++) { + if ((*arr + (pg_size * pg_idx)) != arr[pg_idx]) + return false; + } + return true; +} + +/** + * i40iw_check_mr_contiguous - check if MR is physically contiguous + * @palloc: pbl allocation struct + * pg_size: page size + */ +static bool i40iw_check_mr_contiguous(struct i40iw_pble_alloc *palloc, u32 pg_size) +{ + struct i40iw_pble_level2 *lvl2 = &palloc->level2; + struct i40iw_pble_info *leaf = lvl2->leaf; + u64 *arr = NULL; + u64 *start_addr = NULL; + int i; + bool ret; + + if (palloc->level == I40IW_LEVEL_1) { + arr = (u64 *)palloc->level1.addr; + ret = i40iw_check_mem_contiguous(arr, palloc->total_cnt, pg_size); + return ret; + } + + start_addr = (u64 *)leaf->addr; + + for (i = 0; i < lvl2->leaf_cnt; i++, leaf++) { + arr = (u64 *)leaf->addr; + if ((*start_addr + (i * pg_size * PBLE_PER_PAGE)) != *arr) + return false; + ret = i40iw_check_mem_contiguous(arr, leaf->cnt, pg_size); + if (!ret) + return false; + } + + return true; +} + /** * i40iw_setup_pbles - copy user pg address to pble's * @iwdev: iwarp device * @iwmr: mr pointer for this memory registration - * @use_pbles: flag if to use pble's or memory (level 0) + * @use_pbles: flag if to use pble's */ static int i40iw_setup_pbles(struct i40iw_device *iwdev, struct i40iw_mr *iwmr, @@ -1372,9 +1424,6 @@ static int i40iw_setup_pbles(struct i40iw_device *iwdev, enum i40iw_status_code status; enum i40iw_pble_level level = I40IW_LEVEL_1; - if (!use_pbles && (iwmr->page_cnt > MAX_SAVE_PAGE_ADDRS)) - return -ENOMEM; - if (use_pbles) { mutex_lock(&iwdev->pbl_mutex); status = i40iw_get_pble(&iwdev->sc_dev, iwdev->pble_rsrc, palloc, iwmr->page_cnt); @@ -1391,6 +1440,10 @@ static int i40iw_setup_pbles(struct i40iw_device *iwdev, } i40iw_copy_user_pgaddrs(iwmr, pbl, level); + + if (use_pbles) + iwmr->pgaddrmem[0] = *pbl; + return 0; } @@ -1412,14 +1465,18 @@ static int i40iw_handle_q_mem(struct i40iw_device *iwdev, struct i40iw_cq_mr *cqmr = &iwpbl->cq_mr; struct i40iw_hmc_pble *hmc_p; u64 *arr = iwmr->pgaddrmem; + u32 pg_size; int err; int total; + bool ret = true; total = req->sq_pages + req->rq_pages + req->cq_pages; + pg_size = iwmr->region->page_size; err = i40iw_setup_pbles(iwdev, iwmr, use_pbles); if (err) return err; + if (use_pbles && (palloc->level != I40IW_LEVEL_1)) { i40iw_free_pble(iwdev->pble_rsrc, palloc); iwpbl->pbl_allocated = false; @@ -1428,26 +1485,44 @@ static int i40iw_handle_q_mem(struct i40iw_device *iwdev, if (use_pbles) arr = (u64 *)palloc->level1.addr; - if (req->reg_type == IW_MEMREG_TYPE_QP) { + + if (iwmr->type == IW_MEMREG_TYPE_QP) { hmc_p = &qpmr->sq_pbl; qpmr->shadow = (dma_addr_t)arr[total]; + if (use_pbles) { + ret = i40iw_check_mem_contiguous(arr, req->sq_pages, pg_size); + if (ret) + ret = i40iw_check_mem_contiguous(&arr[req->sq_pages], req->rq_pages, pg_size); + } + + if (!ret) { hmc_p->idx = palloc->level1.idx; hmc_p = &qpmr->rq_pbl; hmc_p->idx = palloc->level1.idx + req->sq_pages; } else { hmc_p->addr = arr[0]; hmc_p = &qpmr->rq_pbl; - hmc_p->addr = arr[1]; + hmc_p->addr = arr[req->sq_pages]; } } else { /* CQ */ hmc_p = &cqmr->cq_pbl; cqmr->shadow = (dma_addr_t)arr[total]; + if (use_pbles) + ret = i40iw_check_mem_contiguous(arr, req->cq_pages, pg_size); + + if (!ret) hmc_p->idx = palloc->level1.idx; else hmc_p->addr = arr[0]; } + + if (use_pbles && ret) { + i40iw_free_pble(iwdev->pble_rsrc, palloc); + iwpbl->pbl_allocated = false; + } + return err; } @@ -1646,7 +1721,7 @@ static int i40iw_hwreg_mr(struct i40iw_device *iwdev, stag_info->pd_id = iwpd->sc_pd.pd_id; stag_info->addr_type = I40IW_ADDR_TYPE_VA_BASED; - if (iwmr->page_cnt > 1) { + if (iwpbl->pbl_allocated) { if (palloc->level == I40IW_LEVEL_1) { stag_info->first_pm_pbl_index = palloc->level1.idx; stag_info->chunk_size = 1; @@ -1702,6 +1777,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, bool use_pbles = false; unsigned long flags; int err = -ENOSYS; + int ret; if (length > I40IW_MAX_MR_SIZE) return ERR_PTR(-EINVAL); @@ -1758,13 +1834,21 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, spin_unlock_irqrestore(&ucontext->cq_reg_mem_list_lock, flags); break; case IW_MEMREG_TYPE_MEM: + use_pbles = (iwmr->page_cnt != 1); access = I40IW_ACCESS_FLAGS_LOCALREAD; - use_pbles = (iwmr->page_cnt != 1); err = i40iw_setup_pbles(iwdev, iwmr, use_pbles); if (err) goto error; + if (use_pbles) { + ret = i40iw_check_mr_contiguous(palloc, region->page_size); + if (ret) { + i40iw_free_pble(iwdev->pble_rsrc, palloc); + iwpbl->pbl_allocated = false; + } + } + access |= i40iw_get_user_access(acc); stag = i40iw_create_stag(iwdev); if (!stag) { @@ -1792,7 +1876,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, return &iwmr->ibmr; error: - if (palloc->level != I40IW_LEVEL_0) + if (palloc->level != I40IW_LEVEL_0 && iwpbl->pbl_allocated) i40iw_free_pble(iwdev->pble_rsrc, palloc); ib_umem_release(region); kfree(iwmr); -- cgit v1.2.3 From f26c7c83395b72f30d111f4e3adb3437c0a30b77 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 30 Nov 2016 14:57:40 -0600 Subject: i40iw: Add 2MB page support Add support to allow each independent memory region to be configured for 2MB page size in addition to 4KB page size. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 59 +++++++++++++++++++++++++------ drivers/infiniband/hw/i40iw/i40iw_verbs.h | 2 ++ 2 files changed, 51 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 43bae5b14a71..1c2f0a19bd63 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1305,13 +1306,11 @@ static u32 i40iw_create_stag(struct i40iw_device *iwdev) /** * i40iw_next_pbl_addr - Get next pbl address - * @palloc: Poiner to allocated pbles * @pbl: pointer to a pble * @pinfo: info pointer * @idx: index */ -static inline u64 *i40iw_next_pbl_addr(struct i40iw_pble_alloc *palloc, - u64 *pbl, +static inline u64 *i40iw_next_pbl_addr(u64 *pbl, struct i40iw_pble_info **pinfo, u32 *idx) { @@ -1339,9 +1338,11 @@ static void i40iw_copy_user_pgaddrs(struct i40iw_mr *iwmr, struct i40iw_pble_alloc *palloc = &iwpbl->pble_alloc; struct i40iw_pble_info *pinfo; struct scatterlist *sg; + u64 pg_addr = 0; u32 idx = 0; pinfo = (level == I40IW_LEVEL_1) ? NULL : palloc->level2.leaf; + pg_shift = ffs(region->page_size) - 1; for_each_sg(region->sg_head.sgl, sg, region->nmap, entry) { chunk_pages = sg_dma_len(sg) >> pg_shift; @@ -1349,8 +1350,35 @@ static void i40iw_copy_user_pgaddrs(struct i40iw_mr *iwmr, !iwpbl->qp_mr.sq_page) iwpbl->qp_mr.sq_page = sg_page(sg); for (i = 0; i < chunk_pages; i++) { - *pbl = cpu_to_le64(sg_dma_address(sg) + region->page_size * i); - pbl = i40iw_next_pbl_addr(palloc, pbl, &pinfo, &idx); + pg_addr = sg_dma_address(sg) + region->page_size * i; + + if ((entry + i) == 0) + *pbl = cpu_to_le64(pg_addr & iwmr->page_msk); + else if (!(pg_addr & ~iwmr->page_msk)) + *pbl = cpu_to_le64(pg_addr); + else + continue; + pbl = i40iw_next_pbl_addr(pbl, &pinfo, &idx); + } + } +} + +/** + * i40iw_set_hugetlb_params - set MR pg size and mask to huge pg values. + * @addr: virtual address + * @iwmr: mr pointer for this memory registration + */ +static void i40iw_set_hugetlb_values(u64 addr, struct i40iw_mr *iwmr) +{ + struct vm_area_struct *vma; + struct hstate *h; + + vma = find_vma(current->mm, addr); + if (vma && is_vm_hugetlb_page(vma)) { + h = hstate_vma(vma); + if (huge_page_size(h) == 0x200000) { + iwmr->page_size = huge_page_size(h); + iwmr->page_msk = huge_page_mask(h); } } } @@ -1471,7 +1499,7 @@ static int i40iw_handle_q_mem(struct i40iw_device *iwdev, bool ret = true; total = req->sq_pages + req->rq_pages + req->cq_pages; - pg_size = iwmr->region->page_size; + pg_size = iwmr->page_size; err = i40iw_setup_pbles(iwdev, iwmr, use_pbles); if (err) @@ -1720,6 +1748,7 @@ static int i40iw_hwreg_mr(struct i40iw_device *iwdev, stag_info->access_rights = access; stag_info->pd_id = iwpd->sc_pd.pd_id; stag_info->addr_type = I40IW_ADDR_TYPE_VA_BASED; + stag_info->page_size = iwmr->page_size; if (iwpbl->pbl_allocated) { if (palloc->level == I40IW_LEVEL_1) { @@ -1778,6 +1807,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, unsigned long flags; int err = -ENOSYS; int ret; + int pg_shift; if (length > I40IW_MAX_MR_SIZE) return ERR_PTR(-EINVAL); @@ -1802,9 +1832,17 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, iwmr->ibmr.pd = pd; iwmr->ibmr.device = pd->device; ucontext = to_ucontext(pd->uobject->context); - region_length = region->length + (start & 0xfff); - pbl_depth = region_length >> 12; - pbl_depth += (region_length & (4096 - 1)) ? 1 : 0; + + iwmr->page_size = region->page_size; + iwmr->page_msk = PAGE_MASK; + + if (region->hugetlb && (req.reg_type == IW_MEMREG_TYPE_MEM)) + i40iw_set_hugetlb_values(start, iwmr); + + region_length = region->length + (start & (iwmr->page_size - 1)); + pg_shift = ffs(iwmr->page_size) - 1; + pbl_depth = region_length >> pg_shift; + pbl_depth += (region_length & (iwmr->page_size - 1)) ? 1 : 0; iwmr->length = region->length; iwpbl->user_base = virt; @@ -1842,7 +1880,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, goto error; if (use_pbles) { - ret = i40iw_check_mr_contiguous(palloc, region->page_size); + ret = i40iw_check_mr_contiguous(palloc, iwmr->page_size); if (ret) { i40iw_free_pble(iwdev->pble_rsrc, palloc); iwpbl->pbl_allocated = false; @@ -1865,6 +1903,7 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, i40iw_free_stag(iwdev, stag); goto error; } + break; default: goto error; diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.h b/drivers/infiniband/hw/i40iw/i40iw_verbs.h index 0069be8a5a38..6549c939500f 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.h +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.h @@ -92,6 +92,8 @@ struct i40iw_mr { struct ib_umem *region; u16 type; u32 page_cnt; + u32 page_size; + u64 page_msk; u32 npages; u32 stag; u64 length; -- cgit v1.2.3 From d59659340c61e777208524f77c268fe6edc6fe37 Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Wed, 30 Nov 2016 14:59:26 -0600 Subject: i40iw: Add missing cleanup on device close On i40iw device close, disconnect all connected QPs by moving them to error state; and block further QPs, PDs and CQs from being created. Additionally, make sure all resources have been freed before deallocating the ibdev as part of the device close. Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw.h | 5 +++++ drivers/infiniband/hw/i40iw/i40iw_cm.c | 31 +++++++++++++++++++++++++++++++ drivers/infiniband/hw/i40iw/i40iw_cm.h | 2 ++ drivers/infiniband/hw/i40iw/i40iw_d.h | 2 ++ drivers/infiniband/hw/i40iw/i40iw_main.c | 4 ++++ drivers/infiniband/hw/i40iw/i40iw_utils.c | 21 +++++++++++++++++++++ drivers/infiniband/hw/i40iw/i40iw_verbs.c | 25 +++++++++++++++++++++++++ 7 files changed, 90 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index dac9a6bcc631..c795c6160261 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -303,10 +303,13 @@ struct i40iw_device { u32 mr_stagmask; u32 mpa_version; bool dcb; + bool closing; u32 used_pds; u32 used_cqs; u32 used_mrs; u32 used_qps; + wait_queue_head_t close_wq; + atomic64_t use_count; }; struct i40iw_ib_device { @@ -521,6 +524,8 @@ int i40iw_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *) void i40iw_rem_pdusecount(struct i40iw_pd *iwpd, struct i40iw_device *iwdev); void i40iw_add_pdusecount(struct i40iw_pd *iwpd); +void i40iw_rem_devusecount(struct i40iw_device *iwdev); +void i40iw_add_devusecount(struct i40iw_device *iwdev); void i40iw_hw_modify_qp(struct i40iw_device *iwdev, struct i40iw_qp *iwqp, struct i40iw_modify_qp_info *info, bool wait); diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index b60e34653ec1..11ef0b09c843 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -4128,3 +4128,34 @@ static void i40iw_cm_post_event(struct i40iw_cm_event *event) queue_work(event->cm_node->cm_core->event_wq, &event->event_work); } + +/** + * i40iw_cm_disconnect_all - disconnect all connected qp's + * @iwdev: device pointer + */ +void i40iw_cm_disconnect_all(struct i40iw_device *iwdev) +{ + struct i40iw_cm_core *cm_core = &iwdev->cm_core; + struct list_head *list_core_temp; + struct list_head *list_node; + struct i40iw_cm_node *cm_node; + unsigned long flags; + struct list_head connected_list; + struct ib_qp_attr attr; + + INIT_LIST_HEAD(&connected_list); + spin_lock_irqsave(&cm_core->ht_lock, flags); + list_for_each_safe(list_node, list_core_temp, &cm_core->connected_nodes) { + cm_node = container_of(list_node, struct i40iw_cm_node, list); + atomic_inc(&cm_node->ref_count); + list_add(&cm_node->connected_entry, &connected_list); + } + spin_unlock_irqrestore(&cm_core->ht_lock, flags); + + list_for_each_safe(list_node, list_core_temp, &connected_list) { + cm_node = container_of(list_node, struct i40iw_cm_node, connected_entry); + attr.qp_state = IB_QPS_ERR; + i40iw_modify_qp(&cm_node->iwqp->ibqp, &attr, IB_QP_STATE, NULL); + i40iw_rem_ref_cm_node(cm_node); + } +} diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.h b/drivers/infiniband/hw/i40iw/i40iw_cm.h index 24615c24cb04..0381b7f5e20d 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.h +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.h @@ -339,6 +339,7 @@ struct i40iw_cm_node { int accept_pend; struct list_head timer_entry; struct list_head reset_entry; + struct list_head connected_entry; atomic_t passive_state; bool qhash_set; u8 user_pri; @@ -443,4 +444,5 @@ int i40iw_arp_table(struct i40iw_device *iwdev, u8 *mac_addr, u32 action); +void i40iw_cm_disconnect_all(struct i40iw_device *iwdev); #endif /* I40IW_CM_H */ diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h index e184c0e99cb1..1bd4badb26d3 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_d.h +++ b/drivers/infiniband/hw/i40iw/i40iw_d.h @@ -35,6 +35,8 @@ #ifndef I40IW_D_H #define I40IW_D_H +#define I40IW_FIRST_USER_QP_ID 2 + #define I40IW_DB_ADDR_OFFSET (4 * 1024 * 1024 - 64 * 1024) #define I40IW_VF_DB_ADDR_OFFSET (64 * 1024) diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index 9d3b9ee20ba7..d86bb6e98f07 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -1546,6 +1546,7 @@ static enum i40iw_status_code i40iw_setup_init_state(struct i40iw_handler *hdl, init_waitqueue_head(&iwdev->vchnl_waitq); init_waitqueue_head(&dev->vf_reqs); + init_waitqueue_head(&iwdev->close_wq); status = i40iw_initialize_dev(iwdev, ldev); exit: @@ -1748,6 +1749,9 @@ static void i40iw_close(struct i40e_info *ldev, struct i40e_client *client, bool return; iwdev = &hdl->device; + iwdev->closing = true; + + i40iw_cm_disconnect_all(iwdev); destroy_workqueue(iwdev->virtchnl_wq); i40iw_deinit_device(iwdev, reset); } diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index 4e880e8689eb..58151280828d 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -392,6 +392,7 @@ static void i40iw_free_qp(struct i40iw_cqp_request *cqp_request, u32 num) i40iw_rem_pdusecount(iwqp->iwpd, iwdev); i40iw_free_qp_resources(iwdev, iwqp, qp_num); + i40iw_rem_devusecount(iwdev); } /** @@ -458,6 +459,26 @@ enum i40iw_status_code i40iw_handle_cqp_op(struct i40iw_device *iwdev, return status; } +/** + * i40iw_add_devusecount - add dev refcount + * @iwdev: dev for refcount + */ +void i40iw_add_devusecount(struct i40iw_device *iwdev) +{ + atomic64_inc(&iwdev->use_count); +} + +/** + * i40iw_rem_devusecount - decrement refcount for dev + * @iwdev: device + */ +void i40iw_rem_devusecount(struct i40iw_device *iwdev) +{ + if (!atomic64_dec_and_test(&iwdev->use_count)) + return; + wake_up(&iwdev->close_wq); +} + /** * i40iw_add_pdusecount - add pd refcount * @iwpd: pd for refcount diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 1c2f0a19bd63..bc24086989e3 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -336,6 +336,9 @@ static struct ib_pd *i40iw_alloc_pd(struct ib_device *ibdev, u32 pd_id = 0; int err; + if (iwdev->closing) + return ERR_PTR(-ENODEV); + err = i40iw_alloc_resource(iwdev, iwdev->allocated_pds, iwdev->max_pd, &pd_id, &iwdev->next_pd); if (err) { @@ -601,6 +604,9 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, struct i40iwarp_offload_info *iwarp_info; unsigned long flags; + if (iwdev->closing) + return ERR_PTR(-ENODEV); + if (init_attr->create_flags) return ERR_PTR(-EINVAL); if (init_attr->cap.max_inline_data > I40IW_MAX_INLINE_DATA_SIZE) @@ -776,6 +782,7 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, iwqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0; iwdev->qp_table[qp_num] = iwqp; i40iw_add_pdusecount(iwqp->iwpd); + i40iw_add_devusecount(iwdev); if (ibpd->uobject && udata) { memset(&uresp, 0, sizeof(uresp)); uresp.actual_sq_size = sq_size; @@ -887,6 +894,11 @@ int i40iw_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, spin_lock_irqsave(&iwqp->lock, flags); if (attr_mask & IB_QP_STATE) { + if (iwdev->closing && attr->qp_state != IB_QPS_ERR) { + err = -EINVAL; + goto exit; + } + switch (attr->qp_state) { case IB_QPS_INIT: case IB_QPS_RTR: @@ -1086,6 +1098,7 @@ static int i40iw_destroy_cq(struct ib_cq *ib_cq) cq_wq_destroy(iwdev, cq); cq_free_resources(iwdev, iwcq); kfree(iwcq); + i40iw_rem_devusecount(iwdev); return 0; } @@ -1116,6 +1129,9 @@ static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev, int err_code; int entries = attr->cqe; + if (iwdev->closing) + return ERR_PTR(-ENODEV); + if (entries > iwdev->max_cqe) return ERR_PTR(-EINVAL); @@ -1233,6 +1249,7 @@ static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev, } } + i40iw_add_devusecount(iwdev); return (struct ib_cq *)iwcq; cq_destroy: @@ -1270,6 +1287,7 @@ static void i40iw_free_stag(struct i40iw_device *iwdev, u32 stag) stag_idx = (stag & iwdev->mr_stagmask) >> I40IW_CQPSQ_STAG_IDX_SHIFT; i40iw_free_resource(iwdev, iwdev->allocated_mrs, stag_idx); + i40iw_rem_devusecount(iwdev); } /** @@ -1300,6 +1318,7 @@ static u32 i40iw_create_stag(struct i40iw_device *iwdev) stag = stag_index << I40IW_CQPSQ_STAG_IDX_SHIFT; stag |= driver_key; stag += (u32)consumer_key; + i40iw_add_devusecount(iwdev); } return stag; } @@ -1809,6 +1828,9 @@ static struct ib_mr *i40iw_reg_user_mr(struct ib_pd *pd, int ret; int pg_shift; + if (iwdev->closing) + return ERR_PTR(-ENODEV); + if (length > I40IW_MAX_MR_SIZE) return ERR_PTR(-EINVAL); region = ib_umem_get(pd->uobject->context, start, length, acc, 0); @@ -2842,6 +2864,9 @@ void i40iw_destroy_rdma_device(struct i40iw_ib_device *iwibdev) i40iw_unregister_rdma_device(iwibdev); kfree(iwibdev->ibdev.iwcm); iwibdev->ibdev.iwcm = NULL; + wait_event_timeout(iwibdev->iwdev->close_wq, + !atomic64_read(&iwibdev->iwdev->use_count), + I40IW_EVENT_TIMEOUT); ib_dealloc_device(&iwibdev->ibdev); } -- cgit v1.2.3 From e5e74b61b16503acbd914f673b783fa2a1532a64 Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Wed, 30 Nov 2016 15:07:30 -0600 Subject: i40iw: Add IP addr handling on netdev events Disable listeners and disconnect all connected QPs on a netdev interface down event. On an interface up event, the listeners are re-enabled. Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 138 +++++++++++++++++++++++++++++- drivers/infiniband/hw/i40iw/i40iw_cm.h | 2 + drivers/infiniband/hw/i40iw/i40iw_utils.c | 58 ++++--------- 3 files changed, 156 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 11ef0b09c843..93ae764fc44e 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -1556,9 +1556,15 @@ static enum i40iw_status_code i40iw_del_multiple_qhash( memcpy(cm_info->loc_addr, child_listen_node->loc_addr, sizeof(cm_info->loc_addr)); cm_info->vlan_id = child_listen_node->vlan_id; - ret = i40iw_manage_qhash(iwdev, cm_info, - I40IW_QHASH_TYPE_TCP_SYN, - I40IW_QHASH_MANAGE_TYPE_DELETE, NULL, false); + if (child_listen_node->qhash_set) { + ret = i40iw_manage_qhash(iwdev, cm_info, + I40IW_QHASH_TYPE_TCP_SYN, + I40IW_QHASH_MANAGE_TYPE_DELETE, + NULL, false); + child_listen_node->qhash_set = false; + } else { + ret = I40IW_SUCCESS; + } i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM, "freed pointer = %p\n", @@ -1687,6 +1693,7 @@ static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev, I40IW_QHASH_MANAGE_TYPE_ADD, NULL, true); if (!ret) { + child_listen_node->qhash_set = true; spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags); list_add(&child_listen_node->child_listen_list, &cm_parent_listen_node->child_listen_list); @@ -1765,6 +1772,7 @@ static enum i40iw_status_code i40iw_add_mqh_4( NULL, true); if (!ret) { + child_listen_node->qhash_set = true; spin_lock_irqsave(&iwdev->cm_core.listen_list_lock, flags); list_add(&child_listen_node->child_listen_list, &cm_parent_listen_node->child_listen_list); @@ -4129,6 +4137,73 @@ static void i40iw_cm_post_event(struct i40iw_cm_event *event) queue_work(event->cm_node->cm_core->event_wq, &event->event_work); } +/** + * i40iw_qhash_ctrl - enable/disable qhash for list + * @iwdev: device pointer + * @parent_listen_node: parent listen node + * @nfo: cm info node + * @ipaddr: Pointer to IPv4 or IPv6 address + * @ipv4: flag indicating IPv4 when true + * @ifup: flag indicating interface up when true + * + * Enables or disables the qhash for the node in the child + * listen list that matches ipaddr. If no matching IP was found + * it will allocate and add a new child listen node to the + * parent listen node. The listen_list_lock is assumed to be + * held when called. + */ +static void i40iw_qhash_ctrl(struct i40iw_device *iwdev, + struct i40iw_cm_listener *parent_listen_node, + struct i40iw_cm_info *nfo, + u32 *ipaddr, bool ipv4, bool ifup) +{ + struct list_head *child_listen_list = &parent_listen_node->child_listen_list; + struct i40iw_cm_listener *child_listen_node; + struct list_head *pos, *tpos; + enum i40iw_status_code ret; + bool node_allocated = false; + enum i40iw_quad_hash_manage_type op = + ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE; + + list_for_each_safe(pos, tpos, child_listen_list) { + child_listen_node = + list_entry(pos, + struct i40iw_cm_listener, + child_listen_list); + if (!memcmp(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16)) + goto set_qhash; + } + + /* if not found then add a child listener if interface is going up */ + if (!ifup) + return; + child_listen_node = kzalloc(sizeof(*child_listen_node), GFP_ATOMIC); + if (!child_listen_node) + return; + node_allocated = true; + memcpy(child_listen_node, parent_listen_node, sizeof(*child_listen_node)); + + memcpy(child_listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16); + +set_qhash: + memcpy(nfo->loc_addr, + child_listen_node->loc_addr, + sizeof(nfo->loc_addr)); + nfo->vlan_id = child_listen_node->vlan_id; + ret = i40iw_manage_qhash(iwdev, nfo, + I40IW_QHASH_TYPE_TCP_SYN, + op, + NULL, false); + if (!ret) { + child_listen_node->qhash_set = ifup; + if (node_allocated) + list_add(&child_listen_node->child_listen_list, + &parent_listen_node->child_listen_list); + } else if (node_allocated) { + kfree(child_listen_node); + } +} + /** * i40iw_cm_disconnect_all - disconnect all connected qp's * @iwdev: device pointer @@ -4159,3 +4234,60 @@ void i40iw_cm_disconnect_all(struct i40iw_device *iwdev) i40iw_rem_ref_cm_node(cm_node); } } + +/** + * i40iw_ifdown_notify - process an ifdown on an interface + * @iwdev: device pointer + * @ipaddr: Pointer to IPv4 or IPv6 address + * @ipv4: flag indicating IPv4 when true + * @ifup: flag indicating interface up when true + */ +void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev, + u32 *ipaddr, bool ipv4, bool ifup) +{ + struct i40iw_cm_core *cm_core = &iwdev->cm_core; + unsigned long flags; + struct i40iw_cm_listener *listen_node; + static const u32 ip_zero[4] = { 0, 0, 0, 0 }; + struct i40iw_cm_info nfo; + u16 vlan_id = rdma_vlan_dev_vlan_id(netdev); + enum i40iw_status_code ret; + enum i40iw_quad_hash_manage_type op = + ifup ? I40IW_QHASH_MANAGE_TYPE_ADD : I40IW_QHASH_MANAGE_TYPE_DELETE; + + /* Disable or enable qhash for listeners */ + spin_lock_irqsave(&cm_core->listen_list_lock, flags); + list_for_each_entry(listen_node, &cm_core->listen_nodes, list) { + if (vlan_id == listen_node->vlan_id && + (!memcmp(listen_node->loc_addr, ipaddr, ipv4 ? 4 : 16) || + !memcmp(listen_node->loc_addr, ip_zero, ipv4 ? 4 : 16))) { + memcpy(nfo.loc_addr, listen_node->loc_addr, + sizeof(nfo.loc_addr)); + nfo.loc_port = listen_node->loc_port; + nfo.ipv4 = listen_node->ipv4; + nfo.vlan_id = listen_node->vlan_id; + nfo.user_pri = listen_node->user_pri; + if (!list_empty(&listen_node->child_listen_list)) { + i40iw_qhash_ctrl(iwdev, + listen_node, + &nfo, + ipaddr, ipv4, ifup); + } else if (memcmp(listen_node->loc_addr, ip_zero, + ipv4 ? 4 : 16)) { + ret = i40iw_manage_qhash(iwdev, + &nfo, + I40IW_QHASH_TYPE_TCP_SYN, + op, + NULL, + false); + if (!ret) + listen_node->qhash_set = ifup; + } + } + } + spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); + + /* disconnect any connected qp's on ifdown */ + if (!ifup) + i40iw_cm_disconnect_all(iwdev); +} diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.h b/drivers/infiniband/hw/i40iw/i40iw_cm.h index 0381b7f5e20d..49ed7a52a84d 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.h +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.h @@ -444,5 +444,7 @@ int i40iw_arp_table(struct i40iw_device *iwdev, u8 *mac_addr, u32 action); +void i40iw_if_notify(struct i40iw_device *iwdev, struct net_device *netdev, + u32 *ipaddr, bool ipv4, bool ifup); void i40iw_cm_disconnect_all(struct i40iw_device *iwdev); #endif /* I40IW_CM_H */ diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index 58151280828d..641f00f3dda1 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -153,6 +153,7 @@ int i40iw_inetaddr_event(struct notifier_block *notifier, struct i40iw_device *iwdev; struct i40iw_handler *hdl; u32 local_ipaddr; + u32 action = I40IW_ARP_ADD; hdl = i40iw_find_netdev(event_netdev); if (!hdl) @@ -164,44 +165,25 @@ int i40iw_inetaddr_event(struct notifier_block *notifier, if (netdev != event_netdev) return NOTIFY_DONE; + if (upper_dev) + local_ipaddr = ntohl( + ((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address); + else + local_ipaddr = ntohl(ifa->ifa_address); switch (event) { case NETDEV_DOWN: - if (upper_dev) - local_ipaddr = ntohl( - ((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address); - else - local_ipaddr = ntohl(ifa->ifa_address); - i40iw_manage_arp_cache(iwdev, - netdev->dev_addr, - &local_ipaddr, - true, - I40IW_ARP_DELETE); - return NOTIFY_OK; + action = I40IW_ARP_DELETE; + /* Fall through */ case NETDEV_UP: - if (upper_dev) - local_ipaddr = ntohl( - ((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address); - else - local_ipaddr = ntohl(ifa->ifa_address); - i40iw_manage_arp_cache(iwdev, - netdev->dev_addr, - &local_ipaddr, - true, - I40IW_ARP_ADD); - break; + /* Fall through */ case NETDEV_CHANGEADDR: - /* Add the address to the IP table */ - if (upper_dev) - local_ipaddr = ntohl( - ((struct in_device *)upper_dev->ip_ptr)->ifa_list->ifa_address); - else - local_ipaddr = ntohl(ifa->ifa_address); - i40iw_manage_arp_cache(iwdev, netdev->dev_addr, &local_ipaddr, true, - I40IW_ARP_ADD); + action); + i40iw_if_notify(iwdev, netdev, &local_ipaddr, true, + (action == I40IW_ARP_ADD) ? true : false); break; default: break; @@ -225,6 +207,7 @@ int i40iw_inet6addr_event(struct notifier_block *notifier, struct i40iw_device *iwdev; struct i40iw_handler *hdl; u32 local_ipaddr6[4]; + u32 action = I40IW_ARP_ADD; hdl = i40iw_find_netdev(event_netdev); if (!hdl) @@ -235,24 +218,21 @@ int i40iw_inet6addr_event(struct notifier_block *notifier, if (netdev != event_netdev) return NOTIFY_DONE; + i40iw_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32); switch (event) { case NETDEV_DOWN: - i40iw_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32); - i40iw_manage_arp_cache(iwdev, - netdev->dev_addr, - local_ipaddr6, - false, - I40IW_ARP_DELETE); - return NOTIFY_OK; + action = I40IW_ARP_DELETE; + /* Fall through */ case NETDEV_UP: /* Fall through */ case NETDEV_CHANGEADDR: - i40iw_copy_ip_ntohl(local_ipaddr6, ifa->addr.in6_u.u6_addr32); i40iw_manage_arp_cache(iwdev, netdev->dev_addr, local_ipaddr6, false, - I40IW_ARP_ADD); + action); + i40iw_if_notify(iwdev, netdev, local_ipaddr6, false, + (action == I40IW_ARP_ADD) ? true : false); break; default: break; -- cgit v1.2.3 From a05e15135b67d71f30f70ab45dede4706f988439 Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Wed, 30 Nov 2016 15:08:34 -0600 Subject: i40iw: Replace list_for_each_entry macro with safe version Use list_for_each_entry_safe macro for the IPv6 addr list as IPv6 addresses can be deleted while going through the list. Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 4 ++-- drivers/infiniband/hw/i40iw/i40iw_main.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 93ae764fc44e..9a14880fe85a 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -1644,7 +1644,7 @@ static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev, { struct net_device *ip_dev; struct inet6_dev *idev; - struct inet6_ifaddr *ifp; + struct inet6_ifaddr *ifp, *tmp; enum i40iw_status_code ret = 0; struct i40iw_cm_listener *child_listen_node; unsigned long flags; @@ -1659,7 +1659,7 @@ static enum i40iw_status_code i40iw_add_mqh_6(struct i40iw_device *iwdev, i40iw_pr_err("idev == NULL\n"); break; } - list_for_each_entry(ifp, &idev->addr_list, if_list) { + list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) { i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM, "IP=%pI6, vlan_id=%d, MAC=%pM\n", diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index d86bb6e98f07..4ce05b8e8f0a 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -1164,7 +1164,7 @@ static void i40iw_add_ipv6_addr(struct i40iw_device *iwdev) { struct net_device *ip_dev; struct inet6_dev *idev; - struct inet6_ifaddr *ifp; + struct inet6_ifaddr *ifp, *tmp; u32 local_ipaddr6[4]; rcu_read_lock(); @@ -1177,7 +1177,7 @@ static void i40iw_add_ipv6_addr(struct i40iw_device *iwdev) i40iw_pr_err("ipv6 inet device not found\n"); break; } - list_for_each_entry(ifp, &idev->addr_list, if_list) { + list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) { i40iw_pr_info("IP=%pI6, vlan_id=%d, MAC=%pM\n", &ifp->addr, rdma_vlan_dev_vlan_id(ip_dev), ip_dev->dev_addr); i40iw_copy_ip_ntohl(local_ipaddr6, -- cgit v1.2.3 From e0b010da87e3aaf7ca9d28ba5d141924a7f8c66d Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Wed, 30 Nov 2016 15:09:07 -0600 Subject: i40iw: Add NULL check for ibqp event handler Add NULL check for ibqp event handler before calling it to report QP events, as it might not initialized. Signed-off-by: Shiraz Saleem Signed-off-by: Faisal Latif Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 9a14880fe85a..13b6dee4d57c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -3474,7 +3474,7 @@ static void i40iw_cm_disconn_true(struct i40iw_qp *iwqp) /* Flush the queues */ i40iw_flush_wqes(iwdev, iwqp); - if (qp->term_flags) { + if (qp->term_flags && iwqp->ibqp.event_handler) { ibevent.device = iwqp->ibqp.device; ibevent.event = (qp->eventtype == TERM_EVENT_QP_FATAL) ? IB_EVENT_QP_FATAL : IB_EVENT_QP_ACCESS_ERR; -- cgit v1.2.3 From 7eb2bde7f3900f044ab351e450adc41623ff2f5c Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Wed, 30 Nov 2016 15:09:34 -0600 Subject: i40iw: Set TOS field in IP header Set the TOS field in IP header with the value passed in from application. If there is mismatch between the remote client's TOS and listener, set the listener Tos to the higher of the two values. Signed-off-by: Shiraz Saleem Signed-off-by: Faisal Latif Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 25 +++++++++++++++++++------ drivers/infiniband/hw/i40iw/i40iw_cm.h | 3 +++ 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 13b6dee4d57c..0c92037d4f7c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -445,7 +445,7 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, iph->version = IPVERSION; iph->ihl = 5; /* 5 * 4Byte words, IP headr len */ - iph->tos = 0; + iph->tos = cm_node->tos; iph->tot_len = htons(packetsize); iph->id = htons(++cm_node->tcp_cntxt.loc_id); @@ -472,7 +472,8 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, ethh->h_proto = htons(ETH_P_IPV6); } ip6h->version = 6; - ip6h->flow_lbl[0] = 0; + ip6h->priority = cm_node->tos >> 4; + ip6h->flow_lbl[0] = cm_node->tos << 4; ip6h->flow_lbl[1] = 0; ip6h->flow_lbl[2] = 0; ip6h->payload_len = htons(packetsize - sizeof(*ip6h)); @@ -2141,9 +2142,18 @@ static struct i40iw_cm_node *i40iw_make_cm_node( cm_node->vlan_id = cm_info->vlan_id; if ((cm_node->vlan_id == I40IW_NO_VLAN) && iwdev->dcb) cm_node->vlan_id = 0; + cm_node->tos = cm_info->tos; cm_node->user_pri = cm_info->user_pri; - if (listener) - cm_node->user_pri = listener->user_pri; + if (listener) { + if (listener->tos != cm_info->tos) + i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, + "application TOS[%d] and remote client TOS[%d] mismatch\n", + listener->tos, cm_info->tos); + cm_node->tos = max(listener->tos, cm_info->tos); + cm_node->user_pri = rt_tos2priority(cm_node->tos); + i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "listener: TOS:[%d] UP:[%d]\n", + cm_node->tos, cm_node->user_pri); + } memcpy(cm_node->loc_addr, cm_info->loc_addr, sizeof(cm_node->loc_addr)); memcpy(cm_node->rem_addr, cm_info->rem_addr, sizeof(cm_node->rem_addr)); cm_node->loc_port = cm_info->loc_port; @@ -3092,6 +3102,7 @@ void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf) cm_info.loc_addr[0] = ntohl(iph->daddr); cm_info.rem_addr[0] = ntohl(iph->saddr); cm_info.ipv4 = true; + cm_info.tos = iph->tos; } else { ip6h = (struct ipv6hdr *)rbuf->iph; i40iw_copy_ip_ntohl(cm_info.loc_addr, @@ -3099,6 +3110,7 @@ void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf) i40iw_copy_ip_ntohl(cm_info.rem_addr, ip6h->saddr.in6_u.u6_addr32); cm_info.ipv4 = false; + cm_info.tos = (ip6h->priority << 4) | (ip6h->flow_lbl[0] >> 4); } cm_info.loc_port = ntohs(tcph->dest); cm_info.rem_port = ntohs(tcph->source); @@ -3331,6 +3343,7 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp, cm_node->state = I40IW_CM_STATE_OFFLOADED; tcp_info.tcp_state = I40IW_TCP_STATE_ESTABLISHED; tcp_info.src_mac_addr_idx = iwdev->mac_ip_table_idx; + tcp_info.tos = cm_node->tos; dev->iw_priv_qp_ops->qp_setctx(&iwqp->sc_qp, (u64 *)(iwqp->host_ctx.va), ctx_info); @@ -3763,6 +3776,7 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) i40iw_netdev_vlan_ipv6(cm_info.loc_addr, &cm_info.vlan_id, NULL); } cm_info.cm_id = cm_id; + cm_info.tos = cm_id->tos; cm_info.user_pri = rt_tos2priority(cm_id->tos); i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "%s TOS:[%d] UP:[%d]\n", __func__, cm_id->tos, cm_info.user_pri); @@ -3911,10 +3925,9 @@ int i40iw_create_listen(struct iw_cm_id *cm_id, int backlog) cm_id->provider_data = cm_listen_node; + cm_listen_node->tos = cm_id->tos; cm_listen_node->user_pri = rt_tos2priority(cm_id->tos); cm_info.user_pri = cm_listen_node->user_pri; - i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_DCB, "%s TOS:[%d] UP:[%d]\n", - __func__, cm_id->tos, cm_listen_node->user_pri); if (!cm_listen_node->reused_node) { if (wildcard) { diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.h b/drivers/infiniband/hw/i40iw/i40iw_cm.h index 49ed7a52a84d..2e52e38ffcf3 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.h +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.h @@ -297,6 +297,7 @@ struct i40iw_cm_listener { enum i40iw_cm_listener_state listener_state; u32 reused_node; u8 user_pri; + u8 tos; u16 vlan_id; bool qhash_set; bool ipv4; @@ -343,6 +344,7 @@ struct i40iw_cm_node { atomic_t passive_state; bool qhash_set; u8 user_pri; + u8 tos; bool ipv4; bool snd_mark_en; u16 lsmm_size; @@ -368,6 +370,7 @@ struct i40iw_cm_info { u16 vlan_id; int backlog; u8 user_pri; + u8 tos; bool ipv4; }; -- cgit v1.2.3 From fd4e906b2e2c04056e8c1773b5b6e06d307239e6 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Wed, 30 Nov 2016 15:12:11 -0600 Subject: i40iw: Fill in IRD value when on connect request IRD is not populated on connect request and application is getting 0 for the value. Fill in the correct value on connect request. Signed-off-by: Shiraz Saleem Signed-off-by: Faisal Latif Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 0c92037d4f7c..2f14de77cb1a 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -272,6 +272,7 @@ static int i40iw_send_cm_event(struct i40iw_cm_node *cm_node, event.provider_data = (void *)cm_node; event.private_data = (void *)cm_node->pdata_buf; event.private_data_len = (u8)cm_node->pdata.size; + event.ird = cm_node->ird_size; break; case IW_CM_EVENT_CONNECT_REPLY: i40iw_get_cmevent_info(cm_node, cm_id, &event); -- cgit v1.2.3 From bf69f494c337cf3c43d3358ad66642dbde50fe03 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Wed, 30 Nov 2016 15:12:35 -0600 Subject: i40iw: Correctly fail loopback connection if no listener Fail the connect and return the proper error code if a client is started with local IP address and there is no corresponding loopback listener. Signed-off-by: Shiraz Saleem Signed-off-by: Faisal Latif Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 62 +++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 2f14de77cb1a..25af89a3cdce 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -2878,7 +2878,7 @@ static struct i40iw_cm_node *i40iw_create_cm_node( /* create a CM connection node */ cm_node = i40iw_make_cm_node(cm_core, iwdev, cm_info, NULL); if (!cm_node) - return NULL; + return ERR_PTR(-ENOMEM); /* set our node side to client (active) side */ cm_node->tcp_cntxt.client = 1; cm_node->tcp_cntxt.rcv_wscale = I40IW_CM_DEFAULT_RCV_WND_SCALE; @@ -2891,7 +2891,8 @@ static struct i40iw_cm_node *i40iw_create_cm_node( cm_node->vlan_id, I40IW_CM_LISTENER_ACTIVE_STATE); if (!loopback_remotelistener) { - i40iw_create_event(cm_node, I40IW_CM_EVENT_ABORTED); + i40iw_rem_ref_cm_node(cm_node); + return ERR_PTR(-ECONNREFUSED); } else { loopback_cm_info = *cm_info; loopback_cm_info.loc_port = cm_info->rem_port; @@ -2904,7 +2905,7 @@ static struct i40iw_cm_node *i40iw_create_cm_node( loopback_remotelistener); if (!loopback_remotenode) { i40iw_rem_ref_cm_node(cm_node); - return NULL; + return ERR_PTR(-ENOMEM); } cm_core->stats_loopbacks++; loopback_remotenode->loopbackpartner = cm_node; @@ -3732,6 +3733,7 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) struct sockaddr_in6 *raddr6; bool qhash_set = false; int apbvt_set = 0; + int err = 0; enum i40iw_status_code status; ibqp = i40iw_get_qp(cm_id->device, conn_param->qpn); @@ -3812,8 +3814,11 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) conn_param->private_data_len, (void *)conn_param->private_data, &cm_info); - if (!cm_node) - goto err; + + if (IS_ERR(cm_node)) { + err = PTR_ERR(cm_node); + goto err_out; + } i40iw_record_ird_ord(cm_node, (u16)conn_param->ird, (u16)conn_param->ord); if (cm_node->send_rdma0_op == SEND_RDMA_READ_ZERO && @@ -3827,10 +3832,12 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) iwqp->cm_id = cm_id; i40iw_add_ref(&iwqp->ibqp); - if (cm_node->state == I40IW_CM_STATE_SYN_SENT) { - if (i40iw_send_syn(cm_node, 0)) { + if (cm_node->state != I40IW_CM_STATE_OFFLOADED) { + cm_node->state = I40IW_CM_STATE_SYN_SENT; + err = i40iw_send_syn(cm_node, 0); + if (err) { i40iw_rem_ref_cm_node(cm_node); - goto err; + goto err_out; } } @@ -3842,24 +3849,25 @@ int i40iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) cm_node->cm_id); return 0; -err: - if (cm_node) { - if (cm_node->ipv4) - i40iw_debug(cm_node->dev, - I40IW_DEBUG_CM, - "Api - connect() FAILED: dest addr=%pI4", - cm_node->rem_addr); - else - i40iw_debug(cm_node->dev, I40IW_DEBUG_CM, - "Api - connect() FAILED: dest addr=%pI6", - cm_node->rem_addr); - } - i40iw_manage_qhash(iwdev, - &cm_info, - I40IW_QHASH_TYPE_TCP_ESTABLISHED, - I40IW_QHASH_MANAGE_TYPE_DELETE, - NULL, - false); +err_out: + if (cm_info.ipv4) + i40iw_debug(&iwdev->sc_dev, + I40IW_DEBUG_CM, + "Api - connect() FAILED: dest addr=%pI4", + cm_info.rem_addr); + else + i40iw_debug(&iwdev->sc_dev, + I40IW_DEBUG_CM, + "Api - connect() FAILED: dest addr=%pI6", + cm_info.rem_addr); + + if (qhash_set) + i40iw_manage_qhash(iwdev, + &cm_info, + I40IW_QHASH_TYPE_TCP_ESTABLISHED, + I40IW_QHASH_MANAGE_TYPE_DELETE, + NULL, + false); if (apbvt_set && !i40iw_listen_port_in_use(&iwdev->cm_core, cm_info.loc_port)) @@ -3868,7 +3876,7 @@ err: I40IW_MANAGE_APBVT_DEL); cm_id->rem_ref(cm_id); iwdev->cm_core.stats_connect_errs++; - return -ENOMEM; + return err; } /** -- cgit v1.2.3 From 1ef936b229c54e73a3cce9f4eb8dd5a146add073 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 30 Nov 2016 15:13:47 -0600 Subject: i40iw: Code cleanup, remove check of PBLE pages Remove check for zero 'pages' of unallocated pbles calculated in add_pble_pool(); as it can never be true. Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_pble.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_pble.c b/drivers/infiniband/hw/i40iw/i40iw_pble.c index 85993dc44f6e..c87ba1617087 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_pble.c +++ b/drivers/infiniband/hw/i40iw/i40iw_pble.c @@ -353,10 +353,6 @@ static enum i40iw_status_code add_pble_pool(struct i40iw_sc_dev *dev, pages = (idx->rel_pd_idx) ? (I40IW_HMC_PD_CNT_IN_SD - idx->rel_pd_idx) : I40IW_HMC_PD_CNT_IN_SD; pages = min(pages, pble_rsrc->unallocated_pble >> PBLE_512_SHIFT); - if (!pages) { - ret_code = I40IW_ERR_NO_PBLCHUNKS_AVAILABLE; - goto error; - } info.chunk = chunk; info.hmc_info = hmc_info; info.pages = pages; -- cgit v1.2.3 From 78300cf8152f87adb20fbe71a600e0d8d72aabe8 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Wed, 30 Nov 2016 15:14:15 -0600 Subject: i40iw: Add request for reset on CQP timeout When CQP times out, send a request to LAN driver for reset. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw.h | 1 + drivers/infiniband/hw/i40iw/i40iw_utils.c | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index c795c6160261..ef188e6b1f89 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -304,6 +304,7 @@ struct i40iw_device { u32 mpa_version; bool dcb; bool closing; + bool reset; u32 used_pds; u32 used_cqs; u32 used_mrs; diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index 641f00f3dda1..4a08ffb75d2e 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -396,7 +396,10 @@ static int i40iw_wait_event(struct i40iw_device *iwdev, i40iw_pr_err("error cqp command 0x%x timed out ret = %d\n", info->cqp_cmd, timeout_ret); err_code = -ETIME; - i40iw_request_reset(iwdev); + if (!iwdev->reset) { + iwdev->reset = true; + i40iw_request_reset(iwdev); + } goto done; } cqp_error = cqp_request->compl_info.error; @@ -426,6 +429,11 @@ enum i40iw_status_code i40iw_handle_cqp_op(struct i40iw_device *iwdev, struct cqp_commands_info *info = &cqp_request->info; int err_code = 0; + if (iwdev->reset) { + i40iw_free_cqp_request(&iwdev->cqp, cqp_request); + return I40IW_ERR_CQP_COMPL_ERROR; + } + status = i40iw_process_cqp_cmd(dev, info); if (status) { i40iw_pr_err("error cqp command 0x%x failed\n", info->cqp_cmd); -- cgit v1.2.3 From 71215a75ceddf38ba9d4563481da8dd943de10fc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sun, 20 Nov 2016 19:30:18 -0500 Subject: constify get_dcookie() and friends Signed-off-by: Al Viro --- arch/powerpc/oprofile/cell/spu_task_sync.c | 2 +- drivers/oprofile/buffer_sync.c | 2 +- fs/dcookies.c | 4 ++-- include/linux/dcookies.h | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c index 83d2b4ef7f0d..44d67b167e0b 100644 --- a/arch/powerpc/oprofile/cell/spu_task_sync.c +++ b/arch/powerpc/oprofile/cell/spu_task_sync.c @@ -295,7 +295,7 @@ out: * dcookie user still being registered (namely, the reader * of the event buffer). */ -static inline unsigned long fast_get_dcookie(struct path *path) +static inline unsigned long fast_get_dcookie(const struct path *path) { unsigned long cookie; diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c index 82f7000a285d..642478d35e99 100644 --- a/drivers/oprofile/buffer_sync.c +++ b/drivers/oprofile/buffer_sync.c @@ -206,7 +206,7 @@ void sync_stop(void) * because we cannot reach this code without at least one * dcookie user still being registered (namely, the reader * of the event buffer). */ -static inline unsigned long fast_get_dcookie(struct path *path) +static inline unsigned long fast_get_dcookie(const struct path *path) { unsigned long cookie; diff --git a/fs/dcookies.c b/fs/dcookies.c index ac44a69fbea9..a26a701ef512 100644 --- a/fs/dcookies.c +++ b/fs/dcookies.c @@ -90,7 +90,7 @@ static void hash_dcookie(struct dcookie_struct * dcs) } -static struct dcookie_struct *alloc_dcookie(struct path *path) +static struct dcookie_struct *alloc_dcookie(const struct path *path) { struct dcookie_struct *dcs = kmem_cache_alloc(dcookie_cache, GFP_KERNEL); @@ -113,7 +113,7 @@ static struct dcookie_struct *alloc_dcookie(struct path *path) /* This is the main kernel-side routine that retrieves the cookie * value for a dentry/vfsmnt pair. */ -int get_dcookie(struct path *path, unsigned long *cookie) +int get_dcookie(const struct path *path, unsigned long *cookie) { int err = 0; struct dcookie_struct * dcs; diff --git a/include/linux/dcookies.h b/include/linux/dcookies.h index 5ac3bdd5cee6..699b6c499c4f 100644 --- a/include/linux/dcookies.h +++ b/include/linux/dcookies.h @@ -44,7 +44,7 @@ void dcookie_unregister(struct dcookie_user * user); * * Returns 0 on success, with *cookie filled in */ -int get_dcookie(struct path *path, unsigned long *cookie); +int get_dcookie(const struct path *path, unsigned long *cookie); #else @@ -58,7 +58,7 @@ static inline void dcookie_unregister(struct dcookie_user * user) return; } -static inline int get_dcookie(struct path *path, unsigned long *cookie) +static inline int get_dcookie(const struct path *path, unsigned long *cookie) { return -ENOSYS; } -- cgit v1.2.3 From b424d2a0a186e7fe4b70db1d616a39d4c3fefd31 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Fri, 2 Dec 2016 22:49:01 +0800 Subject: dmaengine: ioat: set error code on failures In function ioat_dma_self_test(), when the calls to dma_mapping_error() fails, the value of return variable err is 0 (indicates no error). As a result, the return value may be inconsistent with the execution status. This patch fixes the bug by assigning -ENOMEM to err on the error path. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=188591 Signed-off-by: Pan Bian Acked-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/init.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 015f7110b96d..32383ef524c4 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -340,11 +340,13 @@ static int ioat_dma_self_test(struct ioatdma_device *ioat_dma) dma_src = dma_map_single(dev, src, IOAT_TEST_SIZE, DMA_TO_DEVICE); if (dma_mapping_error(dev, dma_src)) { dev_err(dev, "mapping src buffer failed\n"); + err = -ENOMEM; goto free_resources; } dma_dest = dma_map_single(dev, dest, IOAT_TEST_SIZE, DMA_FROM_DEVICE); if (dma_mapping_error(dev, dma_dest)) { dev_err(dev, "mapping dest buffer failed\n"); + err = -ENOMEM; goto unmap_src; } flags = DMA_PREP_INTERRUPT; -- cgit v1.2.3 From 7393fca924e22ad3c071d8bbcc5acda21d0c2710 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Fri, 2 Dec 2016 22:50:38 +0800 Subject: dmaengine: ioat: set error code on failures In function ioat_xor_val_self_test(), when the calls to dma_mapping_error() fail, the value of return variable err is 0 (indicates no error). As a result, the return value may be inconsistent with the execution status. This patch fixes the bug by assigning "-ENOMEM" to err on the error path. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=188601 Signed-off-by: Pan Bian Acked-by: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/init.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 32383ef524c4..3d589f413011 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -829,16 +829,20 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma) op = IOAT_OP_XOR; dest_dma = dma_map_page(dev, dest, 0, PAGE_SIZE, DMA_FROM_DEVICE); - if (dma_mapping_error(dev, dest_dma)) + if (dma_mapping_error(dev, dest_dma)) { + err = -ENOMEM; goto free_resources; + } for (i = 0; i < IOAT_NUM_SRC_TEST; i++) dma_srcs[i] = DMA_ERROR_CODE; for (i = 0; i < IOAT_NUM_SRC_TEST; i++) { dma_srcs[i] = dma_map_page(dev, xor_srcs[i], 0, PAGE_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(dev, dma_srcs[i])) + if (dma_mapping_error(dev, dma_srcs[i])) { + err = -ENOMEM; goto dma_unmap; + } } tx = dma->device_prep_dma_xor(dma_chan, dest_dma, dma_srcs, IOAT_NUM_SRC_TEST, PAGE_SIZE, @@ -906,8 +910,10 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma) for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++) { dma_srcs[i] = dma_map_page(dev, xor_val_srcs[i], 0, PAGE_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(dev, dma_srcs[i])) + if (dma_mapping_error(dev, dma_srcs[i])) { + err = -ENOMEM; goto dma_unmap; + } } tx = dma->device_prep_dma_xor_val(dma_chan, dma_srcs, IOAT_NUM_SRC_TEST + 1, PAGE_SIZE, @@ -959,8 +965,10 @@ static int ioat_xor_val_self_test(struct ioatdma_device *ioat_dma) for (i = 0; i < IOAT_NUM_SRC_TEST + 1; i++) { dma_srcs[i] = dma_map_page(dev, xor_val_srcs[i], 0, PAGE_SIZE, DMA_TO_DEVICE); - if (dma_mapping_error(dev, dma_srcs[i])) + if (dma_mapping_error(dev, dma_srcs[i])) { + err = -ENOMEM; goto dma_unmap; + } } tx = dma->device_prep_dma_xor_val(dma_chan, dma_srcs, IOAT_NUM_SRC_TEST + 1, PAGE_SIZE, -- cgit v1.2.3 From d3f8dc42024b09974a4a1501d4e8852a025f1c15 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 1 Dec 2016 11:49:03 +0100 Subject: dmaengine: at_xdmac: don't restore unsaved status save_gs is supposed to save the channel status in order to be restored at resume time but it is never updated and is always 0. Anyway, the channel status is updated in the per channel loop later in the resume function. Signed-off-by: Alexandre Belloni Acked-by: Nicolas Ferre Acked-by: Ludovic Desroches Signed-off-by: Vinod Koul --- drivers/dma/at_xdmac.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c index 40287ff92768..7d4e0bcda9af 100644 --- a/drivers/dma/at_xdmac.c +++ b/drivers/dma/at_xdmac.c @@ -221,7 +221,6 @@ struct at_xdmac { int irq; struct clk *clk; u32 save_gim; - u32 save_gs; struct dma_pool *at_xdmac_desc_pool; struct at_xdmac_chan chan[0]; }; @@ -1895,7 +1894,6 @@ static int atmel_xdmac_resume(struct device *dev) } at_xdmac_write(atxdmac, AT_XDMAC_GIE, atxdmac->save_gim); - at_xdmac_write(atxdmac, AT_XDMAC_GE, atxdmac->save_gs); list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) { atchan = to_at_xdmac_chan(chan); at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc); -- cgit v1.2.3 From 18b709beb503bfc9a96a2e4b93d3cae4f5b17df0 Mon Sep 17 00:00:00 2001 From: Lorenzo Pieralisi Date: Tue, 6 Dec 2016 14:20:11 +0000 Subject: ACPI/IORT: Make dma masks set-up IORT specific The introduction of acpi_dma_configure() allows to configure DMA and related IOMMU for any device that is DMA capable. To achieve that goal it ensures DMA masks are set-up to sane default values before proceeding with IOMMU and DMA ops configuration. On x86/ia64 systems, through acpi_bind_one(), acpi_dma_configure() is called for every device that has an ACPI companion, in that every device is considered DMA capable on x86/ia64 systems (ie acpi_get_dma_attr() API), which has the side effect of initializing dma masks also for pseudo-devices (eg CPUs and memory nodes) and potentially for devices whose dma masks were not set-up before the acpi_dma_configure() API was introduced, which may have noxious side effects. Therefore, in preparation for IORT firmware specific DMA masks set-up, wrap the default DMA masks set-up in acpi_dma_configure() inside an IORT specific wrapper that reverts to a NOP on x86/ia64 systems, restoring the default expected behaviour on x86/ia64 systems and keeping DMA default masks set-up on IORT based (ie ARM) arch configurations. Signed-off-by: Lorenzo Pieralisi Acked-by: Will Deacon Acked-by: Rafael J. Wysocki Reviewed-by: Hanjun Guo Tested-by: Hanjun Guo Cc: Will Deacon Cc: Hanjun Guo Cc: Bjorn Helgaas Cc: Robin Murphy Cc: Tomasz Nowicki Cc: Joerg Roedel Cc: "Rafael J. Wysocki" Cc: Sricharan R Signed-off-by: Joerg Roedel --- drivers/acpi/arm64/iort.c | 22 ++++++++++++++++++++++ drivers/acpi/scan.c | 14 +------------- include/linux/acpi_iort.h | 2 ++ 3 files changed, 25 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c index 47bace8eafb6..e0d2e6e6e40c 100644 --- a/drivers/acpi/arm64/iort.c +++ b/drivers/acpi/arm64/iort.c @@ -546,6 +546,28 @@ static const struct iommu_ops *iort_iommu_xlate(struct device *dev, return ret ? NULL : ops; } +/** + * iort_set_dma_mask - Set-up dma mask for a device. + * + * @dev: device to configure + */ +void iort_set_dma_mask(struct device *dev) +{ + /* + * Set default coherent_dma_mask to 32 bit. Drivers are expected to + * setup the correct supported mask. + */ + if (!dev->coherent_dma_mask) + dev->coherent_dma_mask = DMA_BIT_MASK(32); + + /* + * Set it to coherent_dma_mask by default if the architecture + * code has not set it. + */ + if (!dev->dma_mask) + dev->dma_mask = &dev->coherent_dma_mask; +} + /** * iort_iommu_configure - Set-up IOMMU configuration for a device. * diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 80698d3c5feb..93b00cf4eb39 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1380,19 +1380,7 @@ void acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) { const struct iommu_ops *iommu; - /* - * Set default coherent_dma_mask to 32 bit. Drivers are expected to - * setup the correct supported mask. - */ - if (!dev->coherent_dma_mask) - dev->coherent_dma_mask = DMA_BIT_MASK(32); - - /* - * Set it to coherent_dma_mask by default if the architecture - * code has not set it. - */ - if (!dev->dma_mask) - dev->dma_mask = &dev->coherent_dma_mask; + iort_set_dma_mask(dev); iommu = iort_iommu_configure(dev); diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h index dcb2b601e152..77e08099e554 100644 --- a/include/linux/acpi_iort.h +++ b/include/linux/acpi_iort.h @@ -35,6 +35,7 @@ bool iort_node_match(u8 type); u32 iort_msi_map_rid(struct device *dev, u32 req_id); struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id); /* IOMMU interface */ +void iort_set_dma_mask(struct device *dev); const struct iommu_ops *iort_iommu_configure(struct device *dev); #else static inline void acpi_iort_init(void) { } @@ -45,6 +46,7 @@ static inline struct irq_domain *iort_get_device_domain(struct device *dev, u32 req_id) { return NULL; } /* IOMMU interface */ +static inline void iort_set_dma_mask(struct device *dev) { } static inline const struct iommu_ops *iort_iommu_configure(struct device *dev) { return NULL; } -- cgit v1.2.3 From 13983eb89d5afaa65acd4479fad151cbd4de5509 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 9 Sep 2016 21:24:03 +0200 Subject: PCI/ACPI: Extend pci_mcfg_lookup() to return ECAM config accessors pci_mcfg_lookup() is the external interface to the generic MCFG code. Previously it merely looked up the ECAM base address for a given domain and bus range. We want a way to add MCFG quirks, some of which may require special config accessors and adjustments to the ECAM address range. Extend pci_mcfg_lookup() so it can return a pointer to a pci_ecam_ops structure and a struct resource for the ECAM address space. For now, it always returns &pci_generic_ecam_ops (the standard accessor) and the resource described by the MCFG. No functional changes intended. [bhelgaas: changelog] Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas --- arch/arm64/kernel/pci.c | 17 +++++------------ drivers/acpi/pci_mcfg.c | 28 +++++++++++++++++++++++++--- include/linux/pci-acpi.h | 4 +++- 3 files changed, 33 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/arch/arm64/kernel/pci.c b/arch/arm64/kernel/pci.c index 266a7b2d4184..4f0e3ebfea4b 100644 --- a/arch/arm64/kernel/pci.c +++ b/arch/arm64/kernel/pci.c @@ -137,25 +137,18 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) struct device *dev = &root->device->dev; struct resource *bus_res = &root->secondary; u16 seg = root->segment; + struct pci_ecam_ops *ecam_ops; struct resource cfgres; struct acpi_device *adev; struct pci_config_window *cfg; - unsigned int bsz; + int ret; - /* Use address from _CBA if present, otherwise lookup MCFG */ - if (!root->mcfg_addr) - root->mcfg_addr = pci_mcfg_lookup(seg, bus_res); - - if (!root->mcfg_addr) { + ret = pci_mcfg_lookup(root, &cfgres, &ecam_ops); + if (ret) { dev_err(dev, "%04x:%pR ECAM region not found\n", seg, bus_res); return NULL; } - bsz = 1 << pci_generic_ecam_ops.bus_shift; - cfgres.start = root->mcfg_addr + bus_res->start * bsz; - cfgres.end = cfgres.start + resource_size(bus_res) * bsz - 1; - cfgres.flags = IORESOURCE_MEM; - adev = acpi_resource_consumer(&cfgres); if (adev) dev_info(dev, "ECAM area %pR reserved by %s\n", &cfgres, @@ -164,7 +157,7 @@ pci_acpi_setup_ecam_mapping(struct acpi_pci_root *root) dev_warn(dev, FW_BUG "ECAM area %pR not reserved in ACPI namespace\n", &cfgres); - cfg = pci_ecam_create(dev, &cfgres, bus_res, &pci_generic_ecam_ops); + cfg = pci_ecam_create(dev, &cfgres, bus_res, ecam_ops); if (IS_ERR(cfg)) { dev_err(dev, "%04x:%pR error %ld mapping ECAM\n", seg, bus_res, PTR_ERR(cfg)); diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index b5b376e081f5..ffcc6513e851 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -22,6 +22,7 @@ #include #include #include +#include /* Structure to hold entries from the MCFG table */ struct mcfg_entry { @@ -35,9 +36,18 @@ struct mcfg_entry { /* List to save MCFG entries */ static LIST_HEAD(pci_mcfg_list); -phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res) +int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, + struct pci_ecam_ops **ecam_ops) { + struct pci_ecam_ops *ops = &pci_generic_ecam_ops; + struct resource *bus_res = &root->secondary; + u16 seg = root->segment; struct mcfg_entry *e; + struct resource res; + + /* Use address from _CBA if present, otherwise lookup MCFG */ + if (root->mcfg_addr) + goto skip_lookup; /* * We expect exact match, unless MCFG entry end bus covers more than @@ -45,10 +55,22 @@ phys_addr_t pci_mcfg_lookup(u16 seg, struct resource *bus_res) */ list_for_each_entry(e, &pci_mcfg_list, list) { if (e->segment == seg && e->bus_start == bus_res->start && - e->bus_end >= bus_res->end) - return e->addr; + e->bus_end >= bus_res->end) { + root->mcfg_addr = e->addr; + } + } + if (!root->mcfg_addr) + return -ENXIO; + +skip_lookup: + memset(&res, 0, sizeof(res)); + res.start = root->mcfg_addr + (bus_res->start << 20); + res.end = res.start + (resource_size(bus_res) << 20) - 1; + res.flags = IORESOURCE_MEM; + *cfgres = res; + *ecam_ops = ops; return 0; } diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h index 7d63a66e8ed4..7a4e83a8c89c 100644 --- a/include/linux/pci-acpi.h +++ b/include/linux/pci-acpi.h @@ -24,7 +24,9 @@ static inline acpi_status pci_acpi_remove_pm_notifier(struct acpi_device *dev) } extern phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle); -extern phys_addr_t pci_mcfg_lookup(u16 domain, struct resource *bus_res); +struct pci_ecam_ops; +extern int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, + struct pci_ecam_ops **ecam_ops); static inline acpi_handle acpi_find_root_bridge_handle(struct pci_dev *pdev) { -- cgit v1.2.3 From 5b69b85ba1ddd36be01f5c57830b37a3c8256009 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Fri, 9 Sep 2016 21:24:04 +0200 Subject: PCI/ACPI: Check for platform-specific MCFG quirks The PCIe spec (r3.0, sec 7.2.2) specifies an "Enhanced Configuration Access Mechanism" (ECAM) for memory-mapped access to configuration space. ECAM is required for PCIe systems unless there's a standard firmware interface for config access. In the absence of a firmware interface, we use pci_generic_ecam_ops, and on ACPI systems, we discover the ECAM space via the MCFG table and/or the _CBA method. Unfortunately some systems provide MCFG but don't implement ECAM according to spec, so we need a mechanism for quirks to make those systems work. Add an MCFG quirk mechanism to override the config accessor functions and/or the memory-mapped address space. A quirk is selected if it matches all of the following: - OEM ID - OEM Table ID - OEM Revision - PCI segment (from _SEG) - PCI bus number range (from _CRS, wildcard allowed) If the quirk specifies config accessor functions or a memory-mapped address range, these override the defaults. [bhelgaas: changelog, reorder quirk matching, fix oem_revision typo per Duc, add under #ifdef CONFIG_PCI_QUIRKS] Signed-off-by: Tomasz Nowicki Signed-off-by: Dongdong Liu Signed-off-by: Christopher Covington Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_mcfg.c | 92 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index ffcc6513e851..1ef72857b710 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -33,6 +33,69 @@ struct mcfg_entry { u8 bus_end; }; +#ifdef CONFIG_PCI_QUIRKS +struct mcfg_fixup { + char oem_id[ACPI_OEM_ID_SIZE + 1]; + char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1]; + u32 oem_revision; + u16 segment; + struct resource bus_range; + struct pci_ecam_ops *ops; + struct resource cfgres; +}; + +#define MCFG_BUS_RANGE(start, end) DEFINE_RES_NAMED((start), \ + ((end) - (start) + 1), \ + NULL, IORESOURCE_BUS) +#define MCFG_BUS_ANY MCFG_BUS_RANGE(0x0, 0xff) + +static struct mcfg_fixup mcfg_quirks[] = { +/* { OEM_ID, OEM_TABLE_ID, REV, SEGMENT, BUS_RANGE, ops, cfgres }, */ +}; + +static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; +static char mcfg_oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; +static u32 mcfg_oem_revision; + +static int pci_mcfg_quirk_matches(struct mcfg_fixup *f, u16 segment, + struct resource *bus_range) +{ + if (!memcmp(f->oem_id, mcfg_oem_id, ACPI_OEM_ID_SIZE) && + !memcmp(f->oem_table_id, mcfg_oem_table_id, + ACPI_OEM_TABLE_ID_SIZE) && + f->oem_revision == mcfg_oem_revision && + f->segment == segment && + resource_contains(&f->bus_range, bus_range)) + return 1; + + return 0; +} +#endif + +static void pci_mcfg_apply_quirks(struct acpi_pci_root *root, + struct resource *cfgres, + struct pci_ecam_ops **ecam_ops) +{ +#ifdef CONFIG_PCI_QUIRKS + u16 segment = root->segment; + struct resource *bus_range = &root->secondary; + struct mcfg_fixup *f; + int i; + + for (i = 0, f = mcfg_quirks; i < ARRAY_SIZE(mcfg_quirks); i++, f++) { + if (pci_mcfg_quirk_matches(f, segment, bus_range)) { + if (f->cfgres.start) + *cfgres = f->cfgres; + if (f->ops) + *ecam_ops = f->ops; + dev_info(&root->device->dev, "MCFG quirk: ECAM at %pR for %pR with %ps\n", + cfgres, bus_range, *ecam_ops); + return; + } + } +#endif +} + /* List to save MCFG entries */ static LIST_HEAD(pci_mcfg_list); @@ -61,14 +124,24 @@ int pci_mcfg_lookup(struct acpi_pci_root *root, struct resource *cfgres, } - if (!root->mcfg_addr) - return -ENXIO; - skip_lookup: memset(&res, 0, sizeof(res)); - res.start = root->mcfg_addr + (bus_res->start << 20); - res.end = res.start + (resource_size(bus_res) << 20) - 1; - res.flags = IORESOURCE_MEM; + if (root->mcfg_addr) { + res.start = root->mcfg_addr + (bus_res->start << 20); + res.end = res.start + (resource_size(bus_res) << 20) - 1; + res.flags = IORESOURCE_MEM; + } + + /* + * Allow quirks to override default ECAM ops and CFG resource + * range. This may even fabricate a CFG resource range in case + * MCFG does not have it. Invalid CFG start address means MCFG + * firmware bug or we need another quirk in array. + */ + pci_mcfg_apply_quirks(root, &res, &ops); + if (!res.start) + return -ENXIO; + *cfgres = res; *ecam_ops = ops; return 0; @@ -101,6 +174,13 @@ static __init int pci_mcfg_parse(struct acpi_table_header *header) list_add(&e->list, &pci_mcfg_list); } +#ifdef CONFIG_PCI_QUIRKS + /* Save MCFG IDs and revision for quirks matching */ + memcpy(mcfg_oem_id, header->oem_id, ACPI_OEM_ID_SIZE); + memcpy(mcfg_oem_table_id, header->oem_table_id, ACPI_OEM_TABLE_ID_SIZE); + mcfg_oem_revision = header->oem_revision; +#endif + pr_info("MCFG table detected, %d entries\n", n); return 0; } -- cgit v1.2.3 From 169de969c0188be69bd5ff1e148d42a49bf47738 Mon Sep 17 00:00:00 2001 From: Dongdong Liu Date: Thu, 1 Dec 2016 00:33:42 -0600 Subject: PCI/ACPI: Provide acpi_get_rc_resources() for ARM64 platform The acpi_get_rc_resources() is used to get the RC register address that can not be described in MCFG. It takes the _HID & segment to look for and outputs the RC address resource. Use PNP0C02 devices to describe such RC address resource. Use _UID to match segment to tell which root bus the PNP0C02 resource belongs to. [bhelgaas: add dev argument, wrap in #ifdef CONFIG_PCI_QUIRKS] Signed-off-by: Dongdong Liu Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas --- drivers/pci/pci-acpi.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 5 ++++ 2 files changed, 81 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index d966d47c9e80..92384dece4b4 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -29,6 +29,82 @@ const u8 pci_acpi_dsm_uuid[] = { 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d }; +#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64) +static int acpi_get_rc_addr(struct acpi_device *adev, struct resource *res) +{ + struct device *dev = &adev->dev; + struct resource_entry *entry; + struct list_head list; + unsigned long flags; + int ret; + + INIT_LIST_HEAD(&list); + flags = IORESOURCE_MEM; + ret = acpi_dev_get_resources(adev, &list, + acpi_dev_filter_resource_type_cb, + (void *) flags); + if (ret < 0) { + dev_err(dev, "failed to parse _CRS method, error code %d\n", + ret); + return ret; + } + + if (ret == 0) { + dev_err(dev, "no IO and memory resources present in _CRS\n"); + return -EINVAL; + } + + entry = list_first_entry(&list, struct resource_entry, node); + *res = *entry->res; + acpi_dev_free_resource_list(&list); + return 0; +} + +static acpi_status acpi_match_rc(acpi_handle handle, u32 lvl, void *context, + void **retval) +{ + u16 *segment = context; + unsigned long long uid; + acpi_status status; + + status = acpi_evaluate_integer(handle, "_UID", NULL, &uid); + if (ACPI_FAILURE(status) || uid != *segment) + return AE_CTRL_DEPTH; + + *(acpi_handle *)retval = handle; + return AE_CTRL_TERMINATE; +} + +int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment, + struct resource *res) +{ + struct acpi_device *adev; + acpi_status status; + acpi_handle handle; + int ret; + + status = acpi_get_devices(hid, acpi_match_rc, &segment, &handle); + if (ACPI_FAILURE(status)) { + dev_err(dev, "can't find _HID %s device to locate resources\n", + hid); + return -ENODEV; + } + + ret = acpi_bus_get_device(handle, &adev); + if (ret) + return ret; + + ret = acpi_get_rc_addr(adev, res); + if (ret) { + dev_err(dev, "can't get resource from %s\n", + dev_name(&adev->dev)); + return ret; + } + + return 0; +} +#endif + phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle) { acpi_status status = AE_NOT_EXIST; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 451856210e18..72b128efa344 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -356,4 +356,9 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) } #endif +#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64) +int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment, + struct resource *res); +#endif + #endif /* DRIVERS_PCI_H */ -- cgit v1.2.3 From 2ca5b8ddc6f70d77a51851ba5e5cd0d39c27dd88 Mon Sep 17 00:00:00 2001 From: Christopher Covington Date: Wed, 2 Nov 2016 11:11:27 -0500 Subject: PCI: Add MCFG quirks for Qualcomm QDF2432 host controller The Qualcomm Technologies QDF2432 SoC does not support accesses smaller than 32 bits to the PCI configuration space. Register the appropriate quirk. [bhelgaas: add QCOM_ECAM32 macro, ifdef for ACPI and PCI_QUIRKS] Signed-off-by: Christopher Covington Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_mcfg.c | 11 +++++++++++ drivers/pci/ecam.c | 12 ++++++++++++ include/linux/pci-ecam.h | 4 ++++ 3 files changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index 1ef72857b710..cee33b078d3d 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -51,6 +51,17 @@ struct mcfg_fixup { static struct mcfg_fixup mcfg_quirks[] = { /* { OEM_ID, OEM_TABLE_ID, REV, SEGMENT, BUS_RANGE, ops, cfgres }, */ + +#define QCOM_ECAM32(seg) \ + { "QCOM ", "QDF2432 ", 1, seg, MCFG_BUS_ANY, &pci_32b_ops } + QCOM_ECAM32(0), + QCOM_ECAM32(1), + QCOM_ECAM32(2), + QCOM_ECAM32(3), + QCOM_ECAM32(4), + QCOM_ECAM32(5), + QCOM_ECAM32(6), + QCOM_ECAM32(7), }; static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/ecam.c b/drivers/pci/ecam.c index 43ed08dd8b01..2fee61bb6559 100644 --- a/drivers/pci/ecam.c +++ b/drivers/pci/ecam.c @@ -162,3 +162,15 @@ struct pci_ecam_ops pci_generic_ecam_ops = { .write = pci_generic_config_write, } }; + +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) +/* ECAM ops for 32-bit access only (non-compliant) */ +struct pci_ecam_ops pci_32b_ops = { + .bus_shift = 20, + .pci_ops = { + .map_bus = pci_ecam_map_bus, + .read = pci_generic_config_read32, + .write = pci_generic_config_write32, + } +}; +#endif diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 7adad206b1f4..739d2330fd9e 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -59,6 +59,10 @@ void __iomem *pci_ecam_map_bus(struct pci_bus *bus, unsigned int devfn, /* default ECAM ops */ extern struct pci_ecam_ops pci_generic_ecam_ops; +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) +extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */ +#endif + #ifdef CONFIG_PCI_HOST_GENERIC /* for DT-based PCI controllers that support ECAM */ int pci_host_common_probe(struct platform_device *pdev, -- cgit v1.2.3 From 5f00f1a0178cf52928366a5e1f376a65f1f3f389 Mon Sep 17 00:00:00 2001 From: Dongdong Liu Date: Thu, 1 Dec 2016 00:45:35 -0600 Subject: PCI: Add MCFG quirks for HiSilicon Hip05/06/07 host controllers The PCIe controller in Hip05/Hip06/Hip07 SoCs is not completely ECAM-compliant. It is non-ECAM only for the RC bus config space; for any other bus underneath the root bus it does support ECAM access. Add specific quirks for PCI config space accessors. This involves: 1. New initialization call hisi_pcie_init() to obtain RC base addresses from PNP0C02 at the root of the ACPI namespace (under \_SB). 2. New entry in common quirk array. [bhelgaas: move to pcie-hisi.c and change Makefile/ifdefs so quirk doesn't depend on CONFIG_PCI_HISI] Signed-off-by: Dongdong Liu Signed-off-by: Gabriele Paoloni Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_mcfg.c | 12 +++++ drivers/pci/host/Makefile | 2 +- drivers/pci/host/pcie-hisi.c | 101 +++++++++++++++++++++++++++++++++++++++++++ include/linux/pci-ecam.h | 1 + 4 files changed, 115 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index cee33b078d3d..dd162248c3ee 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -62,6 +62,18 @@ static struct mcfg_fixup mcfg_quirks[] = { QCOM_ECAM32(5), QCOM_ECAM32(6), QCOM_ECAM32(7), + +#define HISI_QUAD_DOM(table_id, seg, ops) \ + { "HISI ", table_id, 0, (seg) + 0, MCFG_BUS_ANY, ops }, \ + { "HISI ", table_id, 0, (seg) + 1, MCFG_BUS_ANY, ops }, \ + { "HISI ", table_id, 0, (seg) + 2, MCFG_BUS_ANY, ops }, \ + { "HISI ", table_id, 0, (seg) + 3, MCFG_BUS_ANY, ops } + HISI_QUAD_DOM("HIP05 ", 0, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP06 ", 0, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 0, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops), + HISI_QUAD_DOM("HIP07 ", 12, &hisi_pcie_ops), }; static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 084cb4983645..64845f0d6138 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -25,7 +25,7 @@ obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o -obj-$(CONFIG_PCI_HISI) += pcie-hisi.o +obj-$(CONFIG_ARM64) += pcie-hisi.o obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o diff --git a/drivers/pci/host/pcie-hisi.c b/drivers/pci/host/pcie-hisi.c index 56154c25980c..9bfa1ab27365 100644 --- a/drivers/pci/host/pcie-hisi.c +++ b/drivers/pci/host/pcie-hisi.c @@ -18,7 +18,106 @@ #include #include #include +#include +#include +#include #include +#include "../pci.h" + +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) + +static int hisi_pcie_acpi_rd_conf(struct pci_bus *bus, u32 devfn, int where, + int size, u32 *val) +{ + struct pci_config_window *cfg = bus->sysdata; + int dev = PCI_SLOT(devfn); + + if (bus->number == cfg->busr.start) { + /* access only one slot on each root port */ + if (dev > 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return pci_generic_config_read32(bus, devfn, where, + size, val); + } + + return pci_generic_config_read(bus, devfn, where, size, val); +} + +static int hisi_pcie_acpi_wr_conf(struct pci_bus *bus, u32 devfn, + int where, int size, u32 val) +{ + struct pci_config_window *cfg = bus->sysdata; + int dev = PCI_SLOT(devfn); + + if (bus->number == cfg->busr.start) { + /* access only one slot on each root port */ + if (dev > 0) + return PCIBIOS_DEVICE_NOT_FOUND; + else + return pci_generic_config_write32(bus, devfn, where, + size, val); + } + + return pci_generic_config_write(bus, devfn, where, size, val); +} + +static void __iomem *hisi_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, + int where) +{ + struct pci_config_window *cfg = bus->sysdata; + void __iomem *reg_base = cfg->priv; + + if (bus->number == cfg->busr.start) + return reg_base + where; + else + return pci_ecam_map_bus(bus, devfn, where); +} + +static int hisi_pcie_init(struct pci_config_window *cfg) +{ + struct device *dev = cfg->parent; + struct acpi_device *adev = to_acpi_device(dev); + struct acpi_pci_root *root = acpi_driver_data(adev); + struct resource *res; + void __iomem *reg_base; + int ret; + + /* + * Retrieve RC base and size from a HISI0081 device with _UID + * matching our segment. + */ + res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL); + if (!res) + return -ENOMEM; + + ret = acpi_get_rc_resources(dev, "HISI0081", root->segment, res); + if (ret) { + dev_err(dev, "can't get rc base address\n"); + return -ENOMEM; + } + + reg_base = devm_ioremap(dev, res->start, resource_size(res)); + if (!reg_base) + return -ENOMEM; + + cfg->priv = reg_base; + return 0; +} + +struct pci_ecam_ops hisi_pcie_ops = { + .bus_shift = 20, + .init = hisi_pcie_init, + .pci_ops = { + .map_bus = hisi_pcie_map_bus, + .read = hisi_pcie_acpi_rd_conf, + .write = hisi_pcie_acpi_wr_conf, + } +}; + +#endif + +#ifdef CONFIG_PCI_HISI #include "pcie-designware.h" @@ -227,3 +326,5 @@ static struct platform_driver hisi_pcie_driver = { }, }; builtin_platform_driver(hisi_pcie_driver); + +#endif diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 739d2330fd9e..bdacbc883a22 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -61,6 +61,7 @@ extern struct pci_ecam_ops pci_generic_ecam_ops; #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */ +extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */ #endif #ifdef CONFIG_PCI_HOST_GENERIC -- cgit v1.2.3 From 0d414268fb8d0844030f87027e904f69d96706be Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Wed, 30 Nov 2016 23:57:56 -0600 Subject: PCI: thunder-pem: Factor out resource lookup Pull the register resource lookup out of thunder_pem_init() so we can easily add a corresponding lookup using ACPI. No functional change intended. Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-thunder-pem.c | 50 ++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index 6abaf80ffb39..c3276eede82a 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c @@ -284,35 +284,16 @@ static int thunder_pem_config_write(struct pci_bus *bus, unsigned int devfn, return pci_generic_config_write(bus, devfn, where, size, val); } -static int thunder_pem_init(struct pci_config_window *cfg) +static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg, + struct resource *res_pem) { - struct device *dev = cfg->parent; - resource_size_t bar4_start; - struct resource *res_pem; struct thunder_pem_pci *pem_pci; - struct platform_device *pdev; - - /* Only OF support for now */ - if (!dev->of_node) - return -EINVAL; + resource_size_t bar4_start; pem_pci = devm_kzalloc(dev, sizeof(*pem_pci), GFP_KERNEL); if (!pem_pci) return -ENOMEM; - pdev = to_platform_device(dev); - - /* - * The second register range is the PEM bridge to the PCIe - * bus. It has a different config access method than those - * devices behind the bridge. - */ - res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1); - if (!res_pem) { - dev_err(dev, "missing \"reg[1]\"property\n"); - return -EINVAL; - } - pem_pci->pem_reg_base = devm_ioremap(dev, res_pem->start, 0x10000); if (!pem_pci->pem_reg_base) return -ENOMEM; @@ -332,9 +313,32 @@ static int thunder_pem_init(struct pci_config_window *cfg) return 0; } +static int thunder_pem_platform_init(struct pci_config_window *cfg) +{ + struct device *dev = cfg->parent; + struct platform_device *pdev = to_platform_device(dev); + struct resource *res_pem; + + if (!dev->of_node) + return -EINVAL; + + /* + * The second register range is the PEM bridge to the PCIe + * bus. It has a different config access method than those + * devices behind the bridge. + */ + res_pem = platform_get_resource(pdev, IORESOURCE_MEM, 1); + if (!res_pem) { + dev_err(dev, "missing \"reg[1]\"property\n"); + return -EINVAL; + } + + return thunder_pem_init(dev, cfg, res_pem); +} + static struct pci_ecam_ops pci_thunder_pem_ops = { .bus_shift = 24, - .init = thunder_pem_init, + .init = thunder_pem_platform_init, .pci_ops = { .map_bus = pci_ecam_map_bus, .read = thunder_pem_config_read, -- cgit v1.2.3 From 44f22bd91e88f9a1203a6e564a237e593f5f2f74 Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Thu, 1 Dec 2016 00:07:56 -0600 Subject: PCI: Add MCFG quirks for Cavium ThunderX pass2.x host controller ThunderX PCIe controller to off-chip devices (so-called PEM) is not fully compliant with ECAM standard. It uses non-standard configuration space accessors (see thunder_pem_ecam_ops) and custom configuration space granulation (see bus_shift = 24). In order to access configuration space and probe PEM as ACPI-based PCI host controller we need to add MCFG quirk infrastructure. This involves: 1. A new thunder_pem_acpi_init() init function to locate PEM-specific register ranges using ACPI. 2. Export PEM thunder_pem_ecam_ops structure so it is visible to MCFG quirk code. 3. New quirk entries for each PEM segment. Each contains platform IDs, mentioned thunder_pem_ecam_ops and CFG resources. Quirk is considered for ThunderX silicon pass2.x only which is identified via MCFG revision 1. ThunderX pass 2.x requires the following accessors: NUMA Node 0 PCI segments 0- 3: pci_generic_ecam_ops (ECAM-compliant) NUMA Node 0 PCI segments 4- 9: thunder_pem_ecam_ops (MCFG quirk) NUMA Node 1 PCI segments 10-13: pci_generic_ecam_ops (ECAM-compliant) NUMA Node 1 PCI segments 14-19: thunder_pem_ecam_ops (MCFG quirk) [bhelgaas: adapt to use acpi_get_rc_resources(), update Makefile/ifdefs so quirk doesn't depend on CONFIG_PCI_HOST_THUNDER_PEM] Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_mcfg.c | 19 ++++++++++++++++ drivers/pci/host/Kconfig | 3 ++- drivers/pci/host/Makefile | 2 +- drivers/pci/host/pci-thunder-pem.c | 44 ++++++++++++++++++++++++++++++++++++++ include/linux/pci-ecam.h | 1 + 5 files changed, 67 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index dd162248c3ee..17cbb07ce16c 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -74,6 +74,25 @@ static struct mcfg_fixup mcfg_quirks[] = { HISI_QUAD_DOM("HIP07 ", 4, &hisi_pcie_ops), HISI_QUAD_DOM("HIP07 ", 8, &hisi_pcie_ops), HISI_QUAD_DOM("HIP07 ", 12, &hisi_pcie_ops), + +#define THUNDER_PEM_RES(addr, node) \ + DEFINE_RES_MEM((addr) + ((u64) (node) << 44), 0x39 * SZ_16M) +#define THUNDER_PEM_QUIRK(rev, node) \ + { "CAVIUM", "THUNDERX", rev, 4 + (10 * (node)), MCFG_BUS_ANY, \ + &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88001f000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 5 + (10 * (node)), MCFG_BUS_ANY, \ + &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x884057000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 6 + (10 * (node)), MCFG_BUS_ANY, \ + &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x88808f000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 7 + (10 * (node)), MCFG_BUS_ANY, \ + &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89001f000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 8 + (10 * (node)), MCFG_BUS_ANY, \ + &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x894057000000UL, node) }, \ + { "CAVIUM", "THUNDERX", rev, 9 + (10 * (node)), MCFG_BUS_ANY, \ + &thunder_pem_ecam_ops, THUNDER_PEM_RES(0x89808f000000UL, node) } + /* SoC pass2.x */ + THUNDER_PEM_QUIRK(1, 0), + THUNDER_PEM_QUIRK(1, 1), }; static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index d7e7c0a827c3..1239a8e63368 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -240,7 +240,8 @@ config PCIE_QCOM config PCI_HOST_THUNDER_PEM bool "Cavium Thunder PCIe controller to off-chip devices" - depends on OF && ARM64 + depends on ARM64 + depends on OF || (ACPI && PCI_QUIRKS) select PCI_HOST_COMMON help Say Y here if you want PCIe support for CN88XX Cavium Thunder SoCs. diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 64845f0d6138..97e6bfc55772 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -28,7 +28,7 @@ obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o obj-$(CONFIG_ARM64) += pcie-hisi.o obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o -obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o +obj-$(CONFIG_ARM64) += pci-thunder-pem.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o diff --git a/drivers/pci/host/pci-thunder-pem.c b/drivers/pci/host/pci-thunder-pem.c index c3276eede82a..af722eb0ca75 100644 --- a/drivers/pci/host/pci-thunder-pem.c +++ b/drivers/pci/host/pci-thunder-pem.c @@ -18,8 +18,12 @@ #include #include #include +#include #include #include +#include "../pci.h" + +#if defined(CONFIG_PCI_HOST_THUNDER_PEM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) #define PEM_CFG_WR 0x28 #define PEM_CFG_RD 0x30 @@ -313,6 +317,43 @@ static int thunder_pem_init(struct device *dev, struct pci_config_window *cfg, return 0; } +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) + +static int thunder_pem_acpi_init(struct pci_config_window *cfg) +{ + struct device *dev = cfg->parent; + struct acpi_device *adev = to_acpi_device(dev); + struct acpi_pci_root *root = acpi_driver_data(adev); + struct resource *res_pem; + int ret; + + res_pem = devm_kzalloc(&adev->dev, sizeof(*res_pem), GFP_KERNEL); + if (!res_pem) + return -ENOMEM; + + ret = acpi_get_rc_resources(dev, "THRX0002", root->segment, res_pem); + if (ret) { + dev_err(dev, "can't get rc base address\n"); + return ret; + } + + return thunder_pem_init(dev, cfg, res_pem); +} + +struct pci_ecam_ops thunder_pem_ecam_ops = { + .bus_shift = 24, + .init = thunder_pem_acpi_init, + .pci_ops = { + .map_bus = pci_ecam_map_bus, + .read = thunder_pem_config_read, + .write = thunder_pem_config_write, + } +}; + +#endif + +#ifdef CONFIG_PCI_HOST_THUNDER_PEM + static int thunder_pem_platform_init(struct pci_config_window *cfg) { struct device *dev = cfg->parent; @@ -364,3 +405,6 @@ static struct platform_driver thunder_pem_driver = { .probe = thunder_pem_probe, }; builtin_platform_driver(thunder_pem_driver); + +#endif +#endif diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index bdacbc883a22..e88d7db74200 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -62,6 +62,7 @@ extern struct pci_ecam_ops pci_generic_ecam_ops; #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */ extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */ +extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 2.x */ #endif #ifdef CONFIG_PCI_HOST_GENERIC -- cgit v1.2.3 From 648d93fc77da4f655cf13108417f33c91d745e2c Mon Sep 17 00:00:00 2001 From: Tomasz Nowicki Date: Wed, 30 Nov 2016 23:16:34 -0600 Subject: PCI: Add MCFG quirks for Cavium ThunderX pass1.x host controller ThunderX pass1.x requires to emulate the EA headers for on-chip devices hence it has to use custom pci_thunder_ecam_ops for accessing PCI config space (pci-thunder-ecam.c). Add new entries to MCFG quirk array where it can be applied while probing ACPI based PCI host controller. ThunderX pass1.x is using the same way for accessing off-chip devices (so-called PEM) as silicon pass-2.x so we need to add PEM quirk entries too. Quirk is considered for ThunderX silicon pass1.x only which is identified via MCFG revision 2. ThunderX pass 1.x requires the following accessors: NUMA node 0 PCI segments 0- 3: pci_thunder_ecam_ops (MCFG quirk) NUMA node 0 PCI segments 4- 9: thunder_pem_ecam_ops (MCFG quirk) NUMA node 1 PCI segments 10-13: pci_thunder_ecam_ops (MCFG quirk) NUMA node 1 PCI segments 14-19: thunder_pem_ecam_ops (MCFG quirk) [bhelgaas: change Makefile/ifdefs so quirk doesn't depend on CONFIG_PCI_HOST_THUNDER_ECAM] Signed-off-by: Tomasz Nowicki Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_mcfg.c | 15 +++++++++++++++ drivers/pci/host/Kconfig | 3 ++- drivers/pci/host/Makefile | 2 +- drivers/pci/host/pci-thunder-ecam.c | 9 ++++++++- include/linux/pci-ecam.h | 3 ++- 5 files changed, 28 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index 17cbb07ce16c..1cfe65d87adf 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -93,6 +93,21 @@ static struct mcfg_fixup mcfg_quirks[] = { /* SoC pass2.x */ THUNDER_PEM_QUIRK(1, 0), THUNDER_PEM_QUIRK(1, 1), + +#define THUNDER_ECAM_QUIRK(rev, seg) \ + { "CAVIUM", "THUNDERX", rev, seg, MCFG_BUS_ANY, \ + &pci_thunder_ecam_ops } + /* SoC pass1.x */ + THUNDER_PEM_QUIRK(2, 0), /* off-chip devices */ + THUNDER_PEM_QUIRK(2, 1), /* off-chip devices */ + THUNDER_ECAM_QUIRK(2, 0), + THUNDER_ECAM_QUIRK(2, 1), + THUNDER_ECAM_QUIRK(2, 2), + THUNDER_ECAM_QUIRK(2, 3), + THUNDER_ECAM_QUIRK(2, 10), + THUNDER_ECAM_QUIRK(2, 11), + THUNDER_ECAM_QUIRK(2, 12), + THUNDER_ECAM_QUIRK(2, 13), }; static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index 1239a8e63368..c983892e56a0 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -248,7 +248,8 @@ config PCI_HOST_THUNDER_PEM config PCI_HOST_THUNDER_ECAM bool "Cavium Thunder ECAM controller to on-chip devices on pass-1.x silicon" - depends on OF && ARM64 + depends on ARM64 + depends on OF || (ACPI && PCI_QUIRKS) select PCI_HOST_COMMON help Say Y here if you want ECAM support for CN88XX-Pass-1.x Cavium Thunder SoCs. diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 97e6bfc55772..639494a55c51 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o obj-$(CONFIG_ARM64) += pcie-hisi.o obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o -obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o +obj-$(CONFIG_ARM64) += pci-thunder-ecam.o obj-$(CONFIG_ARM64) += pci-thunder-pem.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o diff --git a/drivers/pci/host/pci-thunder-ecam.c b/drivers/pci/host/pci-thunder-ecam.c index d50a3dc2d8db..3f54a43bbbea 100644 --- a/drivers/pci/host/pci-thunder-ecam.c +++ b/drivers/pci/host/pci-thunder-ecam.c @@ -14,6 +14,8 @@ #include #include +#if defined(CONFIG_PCI_HOST_THUNDER_ECAM) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) + static void set_val(u32 v, int where, int size, u32 *val) { int shift = (where & 3) * 8; @@ -346,7 +348,7 @@ static int thunder_ecam_config_write(struct pci_bus *bus, unsigned int devfn, return pci_generic_config_write(bus, devfn, where, size, val); } -static struct pci_ecam_ops pci_thunder_ecam_ops = { +struct pci_ecam_ops pci_thunder_ecam_ops = { .bus_shift = 20, .pci_ops = { .map_bus = pci_ecam_map_bus, @@ -355,6 +357,8 @@ static struct pci_ecam_ops pci_thunder_ecam_ops = { } }; +#ifdef CONFIG_PCI_HOST_THUNDER_ECAM + static const struct of_device_id thunder_ecam_of_match[] = { { .compatible = "cavium,pci-host-thunder-ecam" }, { }, @@ -373,3 +377,6 @@ static struct platform_driver thunder_ecam_driver = { .probe = thunder_ecam_probe, }; builtin_platform_driver(thunder_ecam_driver); + +#endif +#endif diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index e88d7db74200..00eb8eb774e2 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -62,7 +62,8 @@ extern struct pci_ecam_ops pci_generic_ecam_ops; #if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */ extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */ -extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 2.x */ +extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */ +extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */ #endif #ifdef CONFIG_PCI_HOST_GENERIC -- cgit v1.2.3 From c5d4603961009c39de94725213d8b5420f110f9e Mon Sep 17 00:00:00 2001 From: Duc Dang Date: Thu, 1 Dec 2016 18:27:07 -0800 Subject: PCI: Add MCFG quirks for X-Gene host controller PCIe controllers in X-Gene SoCs are not ECAM compliant: software needs to configure additional controller's register to address device at bus:dev:function. Add a quirk to discover controller MMIO register space and configure controller registers to select and address the target secondary device. The quirk will only be applied for X-Gene PCIe MCFG table with OEM revison 1, 2, 3 or 4 (PCIe controller v1 and v2 on X-Gene SoCs). Tested-by: Jon Masters Signed-off-by: Duc Dang Signed-off-by: Bjorn Helgaas --- drivers/acpi/pci_mcfg.c | 25 +++++++++ drivers/pci/host/Kconfig | 4 +- drivers/pci/host/Makefile | 2 +- drivers/pci/host/pci-xgene.c | 126 ++++++++++++++++++++++++++++++++++++++++--- include/linux/pci-ecam.h | 2 + 5 files changed, 149 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/pci_mcfg.c b/drivers/acpi/pci_mcfg.c index 1cfe65d87adf..a6a4ceaa6cc3 100644 --- a/drivers/acpi/pci_mcfg.c +++ b/drivers/acpi/pci_mcfg.c @@ -108,6 +108,31 @@ static struct mcfg_fixup mcfg_quirks[] = { THUNDER_ECAM_QUIRK(2, 11), THUNDER_ECAM_QUIRK(2, 12), THUNDER_ECAM_QUIRK(2, 13), + +#define XGENE_V1_ECAM_MCFG(rev, seg) \ + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ + &xgene_v1_pcie_ecam_ops } +#define XGENE_V2_ECAM_MCFG(rev, seg) \ + {"APM ", "XGENE ", rev, seg, MCFG_BUS_ANY, \ + &xgene_v2_pcie_ecam_ops } + /* X-Gene SoC with v1 PCIe controller */ + XGENE_V1_ECAM_MCFG(1, 0), + XGENE_V1_ECAM_MCFG(1, 1), + XGENE_V1_ECAM_MCFG(1, 2), + XGENE_V1_ECAM_MCFG(1, 3), + XGENE_V1_ECAM_MCFG(1, 4), + XGENE_V1_ECAM_MCFG(2, 0), + XGENE_V1_ECAM_MCFG(2, 1), + XGENE_V1_ECAM_MCFG(2, 2), + XGENE_V1_ECAM_MCFG(2, 3), + XGENE_V1_ECAM_MCFG(2, 4), + /* X-Gene SoC with v2.1 PCIe controller */ + XGENE_V2_ECAM_MCFG(3, 0), + XGENE_V2_ECAM_MCFG(3, 1), + /* X-Gene SoC with v2.2 PCIe controller */ + XGENE_V2_ECAM_MCFG(4, 0), + XGENE_V2_ECAM_MCFG(4, 1), + XGENE_V2_ECAM_MCFG(4, 2), }; static char mcfg_oem_id[ACPI_OEM_ID_SIZE]; diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index c983892e56a0..1fb55182ccaf 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -133,8 +133,8 @@ config PCIE_XILINX config PCI_XGENE bool "X-Gene PCIe controller" - depends on ARCH_XGENE - depends on OF + depends on ARM64 + depends on OF || (ACPI && PCI_QUIRKS) select PCIEPORTBUS help Say Y here if you want internal PCI support on APM X-Gene SoC. diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 639494a55c51..6cc84b4f3a4d 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -15,7 +15,7 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o -obj-$(CONFIG_PCI_XGENE) += pci-xgene.o +obj-$(CONFIG_ARM64) += pci-xgene.o obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c index 1de23d74783f..7c3b54b9eb17 100644 --- a/drivers/pci/host/pci-xgene.c +++ b/drivers/pci/host/pci-xgene.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -64,7 +66,9 @@ /* PCIe IP version */ #define XGENE_PCIE_IP_VER_UNKN 0 #define XGENE_PCIE_IP_VER_1 1 +#define XGENE_PCIE_IP_VER_2 2 +#if defined(CONFIG_PCI_XGENE) || (defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS)) struct xgene_pcie_port { struct device_node *node; struct device *dev; @@ -91,13 +95,24 @@ static inline u32 pcie_bar_low_val(u32 addr, u32 flags) return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags; } +static inline struct xgene_pcie_port *pcie_bus_to_port(struct pci_bus *bus) +{ + struct pci_config_window *cfg; + + if (acpi_disabled) + return (struct xgene_pcie_port *)(bus->sysdata); + + cfg = bus->sysdata; + return (struct xgene_pcie_port *)(cfg->priv); +} + /* * When the address bit [17:16] is 2'b01, the Configuration access will be * treated as Type 1 and it will be forwarded to external PCIe device. */ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) { - struct xgene_pcie_port *port = bus->sysdata; + struct xgene_pcie_port *port = pcie_bus_to_port(bus); if (bus->number >= (bus->primary + 1)) return port->cfg_base + AXI_EP_CFG_ACCESS; @@ -111,7 +126,7 @@ static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus) */ static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn) { - struct xgene_pcie_port *port = bus->sysdata; + struct xgene_pcie_port *port = pcie_bus_to_port(bus); unsigned int b, d, f; u32 rtdid_val = 0; @@ -158,7 +173,7 @@ static void __iomem *xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val) { - struct xgene_pcie_port *port = bus->sysdata; + struct xgene_pcie_port *port = pcie_bus_to_port(bus); if (pci_generic_config_read32(bus, devfn, where & ~0x3, 4, val) != PCIBIOS_SUCCESSFUL) @@ -182,13 +197,103 @@ static int xgene_pcie_config_read32(struct pci_bus *bus, unsigned int devfn, return PCIBIOS_SUCCESSFUL; } +#endif -static struct pci_ops xgene_pcie_ops = { - .map_bus = xgene_pcie_map_bus, - .read = xgene_pcie_config_read32, - .write = pci_generic_config_write32, +#if defined(CONFIG_ACPI) && defined(CONFIG_PCI_QUIRKS) +static int xgene_get_csr_resource(struct acpi_device *adev, + struct resource *res) +{ + struct device *dev = &adev->dev; + struct resource_entry *entry; + struct list_head list; + unsigned long flags; + int ret; + + INIT_LIST_HEAD(&list); + flags = IORESOURCE_MEM; + ret = acpi_dev_get_resources(adev, &list, + acpi_dev_filter_resource_type_cb, + (void *) flags); + if (ret < 0) { + dev_err(dev, "failed to parse _CRS method, error code %d\n", + ret); + return ret; + } + + if (ret == 0) { + dev_err(dev, "no IO and memory resources present in _CRS\n"); + return -EINVAL; + } + + entry = list_first_entry(&list, struct resource_entry, node); + *res = *entry->res; + acpi_dev_free_resource_list(&list); + return 0; +} + +static int xgene_pcie_ecam_init(struct pci_config_window *cfg, u32 ipversion) +{ + struct device *dev = cfg->parent; + struct acpi_device *adev = to_acpi_device(dev); + struct xgene_pcie_port *port; + struct resource csr; + int ret; + + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL); + if (!port) + return -ENOMEM; + + ret = xgene_get_csr_resource(adev, &csr); + if (ret) { + dev_err(dev, "can't get CSR resource\n"); + kfree(port); + return ret; + } + port->csr_base = devm_ioremap_resource(dev, &csr); + if (IS_ERR(port->csr_base)) { + kfree(port); + return -ENOMEM; + } + + port->cfg_base = cfg->win; + port->version = ipversion; + + cfg->priv = port; + return 0; +} + +static int xgene_v1_pcie_ecam_init(struct pci_config_window *cfg) +{ + return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_1); +} + +struct pci_ecam_ops xgene_v1_pcie_ecam_ops = { + .bus_shift = 16, + .init = xgene_v1_pcie_ecam_init, + .pci_ops = { + .map_bus = xgene_pcie_map_bus, + .read = xgene_pcie_config_read32, + .write = pci_generic_config_write, + } +}; + +static int xgene_v2_pcie_ecam_init(struct pci_config_window *cfg) +{ + return xgene_pcie_ecam_init(cfg, XGENE_PCIE_IP_VER_2); +} + +struct pci_ecam_ops xgene_v2_pcie_ecam_ops = { + .bus_shift = 16, + .init = xgene_v2_pcie_ecam_init, + .pci_ops = { + .map_bus = xgene_pcie_map_bus, + .read = xgene_pcie_config_read32, + .write = pci_generic_config_write, + } }; +#endif +#if defined(CONFIG_PCI_XGENE) static u64 xgene_pcie_set_ib_mask(struct xgene_pcie_port *port, u32 addr, u32 flags, u64 size) { @@ -521,6 +626,12 @@ static int xgene_pcie_setup(struct xgene_pcie_port *port, return 0; } +static struct pci_ops xgene_pcie_ops = { + .map_bus = xgene_pcie_map_bus, + .read = xgene_pcie_config_read32, + .write = pci_generic_config_write32, +}; + static int xgene_pcie_probe_bridge(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -591,3 +702,4 @@ static struct platform_driver xgene_pcie_driver = { .probe = xgene_pcie_probe_bridge, }; builtin_platform_driver(xgene_pcie_driver); +#endif diff --git a/include/linux/pci-ecam.h b/include/linux/pci-ecam.h index 00eb8eb774e2..f0d2b9451270 100644 --- a/include/linux/pci-ecam.h +++ b/include/linux/pci-ecam.h @@ -64,6 +64,8 @@ extern struct pci_ecam_ops pci_32b_ops; /* 32-bit accesses only */ extern struct pci_ecam_ops hisi_pcie_ops; /* HiSilicon */ extern struct pci_ecam_ops thunder_pem_ecam_ops; /* Cavium ThunderX 1.x & 2.x */ extern struct pci_ecam_ops pci_thunder_ecam_ops; /* Cavium ThunderX 1.x */ +extern struct pci_ecam_ops xgene_v1_pcie_ecam_ops; /* APM X-Gene PCIe v1 */ +extern struct pci_ecam_ops xgene_v2_pcie_ecam_ops; /* APM X-Gene PCIe v2.x */ #endif #ifdef CONFIG_PCI_HOST_GENERIC -- cgit v1.2.3 From b80609a161f05caec677216f74188701a3b23149 Mon Sep 17 00:00:00 2001 From: Marcus Folkesson Date: Mon, 28 Nov 2016 12:53:28 -0500 Subject: crypto: caam - check caam_emi_slow instead of re-lookup platform Signed-off-by: Marcus Folkesson Signed-off-by: Herbert Xu --- drivers/crypto/caam/ctrl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c index be62a7f482ac..d5ca5b824641 100644 --- a/drivers/crypto/caam/ctrl.c +++ b/drivers/crypto/caam/ctrl.c @@ -330,7 +330,7 @@ static int caam_remove(struct platform_device *pdev) clk_disable_unprepare(ctrlpriv->caam_ipg); clk_disable_unprepare(ctrlpriv->caam_mem); clk_disable_unprepare(ctrlpriv->caam_aclk); - if (!of_machine_is_compatible("fsl,imx6ul")) + if (ctrlpriv->caam_emi_slow) clk_disable_unprepare(ctrlpriv->caam_emi_slow); return 0; } @@ -506,7 +506,7 @@ static int caam_probe(struct platform_device *pdev) goto disable_caam_mem; } - if (!of_machine_is_compatible("fsl,imx6ul")) { + if (ctrlpriv->caam_emi_slow) { ret = clk_prepare_enable(ctrlpriv->caam_emi_slow); if (ret < 0) { dev_err(&pdev->dev, "can't enable CAAM emi slow clock: %d\n", @@ -830,7 +830,7 @@ caam_remove: iounmap_ctrl: iounmap(ctrl); disable_caam_emi_slow: - if (!of_machine_is_compatible("fsl,imx6ul")) + if (ctrlpriv->caam_emi_slow) clk_disable_unprepare(ctrlpriv->caam_emi_slow); disable_caam_aclk: clk_disable_unprepare(ctrlpriv->caam_aclk); -- cgit v1.2.3 From 9a97ffd49ca9421c17ecde672a58b618d61f4f58 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 1 Dec 2016 23:49:37 +0300 Subject: crypto: chcr - checking for IS_ERR() instead of NULL The create_hash_wr() function never returns error pointers. It returns NULL on error. Fixes: 358961d1cd1e ("crypto: chcr - Added new structure chcr_wr") Signed-off-by: Dan Carpenter Signed-off-by: Herbert Xu --- drivers/crypto/chelsio/chcr_algo.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/chelsio/chcr_algo.c b/drivers/crypto/chelsio/chcr_algo.c index e73b9809591d..57b49ecdcad4 100644 --- a/drivers/crypto/chelsio/chcr_algo.c +++ b/drivers/crypto/chelsio/chcr_algo.c @@ -956,9 +956,8 @@ static int chcr_ahash_update(struct ahash_request *req) req_ctx->result = 0; req_ctx->data_len += params.sg_len + params.bfr_len; skb = create_hash_wr(req, ¶ms); - - if (IS_ERR(skb)) - return PTR_ERR(skb); + if (!skb) + return -ENOMEM; if (remainder) { u8 *temp; @@ -1021,8 +1020,8 @@ static int chcr_ahash_final(struct ahash_request *req) params.more = 0; } skb = create_hash_wr(req, ¶ms); - if (IS_ERR(skb)) - return PTR_ERR(skb); + if (!skb) + return -ENOMEM; skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); @@ -1072,8 +1071,8 @@ static int chcr_ahash_finup(struct ahash_request *req) } skb = create_hash_wr(req, ¶ms); - if (IS_ERR(skb)) - return PTR_ERR(skb); + if (!skb) + return -ENOMEM; skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); @@ -1123,8 +1122,8 @@ static int chcr_ahash_digest(struct ahash_request *req) } skb = create_hash_wr(req, ¶ms); - if (IS_ERR(skb)) - return PTR_ERR(skb); + if (!skb) + return -ENOMEM; skb->dev = u_ctx->lldi.ports[0]; set_wr_txq(skb, CPL_PRIORITY_DATA, ctx->tx_channel_id); -- cgit v1.2.3 From 01835fadf5eda4afdca5c0aa7a89e210ee45bec6 Mon Sep 17 00:00:00 2001 From: Srikant Ritolia Date: Tue, 29 Nov 2016 11:04:37 +0000 Subject: rtc: ds1374: Merge conditional + WARN_ON() WARN_ON does both these things in one statement. Using a better pattern with WARN_ON(). Signed-off-by: Srikant Ritolia Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 3b3049c8c9e0..52429f0a57cc 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -89,10 +89,8 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time, int ret; int i; - if (nbytes > 4) { - WARN_ON(1); + if (WARN_ON(nbytes > 4)) return -EINVAL; - } ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf); -- cgit v1.2.3 From b88e0ae958267dc63bea661d66c15f61ba1dd93c Mon Sep 17 00:00:00 2001 From: Martin Kaiser Date: Sat, 19 Nov 2016 14:03:33 +0100 Subject: rtc: imxdi: (trivial) fix a typo Fix a typo Signed-off-by: Martin Kaiser Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-imxdi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 8d8049bdfaf6..67b56b80dc70 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -67,7 +67,7 @@ #define DSR_ETAD (1 << 21) /* External tamper A detected */ #define DSR_EBD (1 << 20) /* External boot detected */ #define DSR_SAD (1 << 19) /* SCC alarm detected */ -#define DSR_TTD (1 << 18) /* Temperatur tamper detected */ +#define DSR_TTD (1 << 18) /* Temperature tamper detected */ #define DSR_CTD (1 << 17) /* Clock tamper detected */ #define DSR_VTD (1 << 16) /* Voltage tamper detected */ #define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */ -- cgit v1.2.3 From 37d6a0a6f4700ad3ae7bbf8db38b4557e97b3fe4 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 25 Nov 2016 11:57:09 +0100 Subject: PCI: Add pci_register_host_bridge() interface Make the existing pci_host_bridge structure a proper device that is usable by PCI host drivers in a more standard way. In addition to the existing pci_scan_bus(), pci_scan_root_bus(), pci_scan_root_bus_msi(), and pci_create_root_bus() interfaces, this unfortunately means having to add yet another interface doing basically the same thing, and add some extra code in the initial step. However, this time it's more likely to be extensible enough that we won't have to do another one again in the future, and we should be able to reduce code much more as a result. The main idea is to pull the allocation of 'struct pci_host_bridge' out of the registration, and let individual host drivers and architecture code fill the members before calling the registration function. There are a number of things we can do based on this: * Use a single memory allocation for the driver-specific structure and the generic PCI host bridge * consolidate the contents of driver-specific structures by moving them into pci_host_bridge * Add a consistent interface for removing a PCI host bridge again when unloading a host driver module * Replace the architecture specific __weak pcibios_*() functions with callbacks in a pci_host_bridge device * Move common boilerplate code from host drivers into the generic function, based on contents of the structure * Extend pci_host_bridge with additional members when needed without having to add arguments to pci_scan_*(). * Move members of struct pci_bus into pci_host_bridge to avoid having lots of identical copies. Signed-off-by: Arnd Bergmann Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 238 +++++++++++++++++++++++++++++++--------------------- include/linux/pci.h | 4 + 2 files changed, 145 insertions(+), 97 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ab002671fa60..4853c8fbd701 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -521,7 +521,7 @@ static void pci_release_host_bridge_dev(struct device *dev) kfree(bridge); } -static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) +static struct pci_host_bridge *pci_alloc_host_bridge(void) { struct pci_host_bridge *bridge; @@ -530,7 +530,7 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) return NULL; INIT_LIST_HEAD(&bridge->windows); - bridge->bus = b; + return bridge; } @@ -717,6 +717,122 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus) dev_set_msi_domain(&bus->dev, d); } +static int pci_register_host_bridge(struct pci_host_bridge *bridge) +{ + struct device *parent = bridge->dev.parent; + struct resource_entry *window, *n; + struct pci_bus *bus, *b; + resource_size_t offset; + LIST_HEAD(resources); + struct resource *res; + char addr[64], *fmt; + const char *name; + int err; + + bus = pci_alloc_bus(NULL); + if (!bus) + return -ENOMEM; + + bridge->bus = bus; + + /* temporarily move resources off the list */ + list_splice_init(&bridge->windows, &resources); + bus->sysdata = bridge->sysdata; + bus->msi = bridge->msi; + bus->ops = bridge->ops; + bus->number = bus->busn_res.start = bridge->busnr; +#ifdef CONFIG_PCI_DOMAINS_GENERIC + bus->domain_nr = pci_bus_find_domain_nr(bus, parent); +#endif + + b = pci_find_bus(pci_domain_nr(bus), bridge->busnr); + if (b) { + /* If we already got to this bus through a different bridge, ignore it */ + dev_dbg(&b->dev, "bus already known\n"); + err = -EEXIST; + goto free; + } + + dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(bus), + bridge->busnr); + + err = pcibios_root_bridge_prepare(bridge); + if (err) + goto free; + + err = device_register(&bridge->dev); + if (err) + put_device(&bridge->dev); + + bus->bridge = get_device(&bridge->dev); + device_enable_async_suspend(bus->bridge); + pci_set_bus_of_node(bus); + pci_set_bus_msi_domain(bus); + + if (!parent) + set_dev_node(bus->bridge, pcibus_to_node(bus)); + + bus->dev.class = &pcibus_class; + bus->dev.parent = bus->bridge; + + dev_set_name(&bus->dev, "%04x:%02x", pci_domain_nr(bus), bus->number); + name = dev_name(&bus->dev); + + err = device_register(&bus->dev); + if (err) + goto unregister; + + pcibios_add_bus(bus); + + /* Create legacy_io and legacy_mem files for this bus */ + pci_create_legacy_files(bus); + + if (parent) + dev_info(parent, "PCI host bridge to bus %s\n", name); + else + pr_info("PCI host bridge to bus %s\n", name); + + /* Add initial resources to the bus */ + resource_list_for_each_entry_safe(window, n, &resources) { + list_move_tail(&window->node, &bridge->windows); + offset = window->offset; + res = window->res; + + if (res->flags & IORESOURCE_BUS) + pci_bus_insert_busn_res(bus, bus->number, res->end); + else + pci_bus_add_resource(bus, res, 0); + + if (offset) { + if (resource_type(res) == IORESOURCE_IO) + fmt = " (bus address [%#06llx-%#06llx])"; + else + fmt = " (bus address [%#010llx-%#010llx])"; + + snprintf(addr, sizeof(addr), fmt, + (unsigned long long)(res->start - offset), + (unsigned long long)(res->end - offset)); + } else + addr[0] = '\0'; + + dev_info(&bus->dev, "root bus resource %pR%s\n", res, addr); + } + + down_write(&pci_bus_sem); + list_add_tail(&bus->node, &pci_root_buses); + up_write(&pci_bus_sem); + + return 0; + +unregister: + put_device(&bridge->dev); + device_unregister(&bridge->dev); + +free: + kfree(bus); + return err; +} + static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) { @@ -2130,113 +2246,43 @@ void __weak pcibios_remove_bus(struct pci_bus *bus) { } -struct pci_bus *pci_create_root_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, struct list_head *resources) +static struct pci_bus *pci_create_root_bus_msi(struct device *parent, + int bus, struct pci_ops *ops, void *sysdata, + struct list_head *resources, struct msi_controller *msi) { int error; struct pci_host_bridge *bridge; - struct pci_bus *b, *b2; - struct resource_entry *window, *n; - struct resource *res; - resource_size_t offset; - char bus_addr[64]; - char *fmt; - - b = pci_alloc_bus(NULL); - if (!b) - return NULL; - b->sysdata = sysdata; - b->ops = ops; - b->number = b->busn_res.start = bus; -#ifdef CONFIG_PCI_DOMAINS_GENERIC - b->domain_nr = pci_bus_find_domain_nr(b, parent); -#endif - b2 = pci_find_bus(pci_domain_nr(b), bus); - if (b2) { - /* If we already got to this bus through a different bridge, ignore it */ - dev_dbg(&b2->dev, "bus already known\n"); - goto err_out; - } - - bridge = pci_alloc_host_bridge(b); + bridge = pci_alloc_host_bridge(); if (!bridge) - goto err_out; + return NULL; bridge->dev.parent = parent; bridge->dev.release = pci_release_host_bridge_dev; - dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus); - error = pcibios_root_bridge_prepare(bridge); - if (error) { - kfree(bridge); - goto err_out; - } - - error = device_register(&bridge->dev); - if (error) { - put_device(&bridge->dev); - goto err_out; - } - b->bridge = get_device(&bridge->dev); - device_enable_async_suspend(b->bridge); - pci_set_bus_of_node(b); - pci_set_bus_msi_domain(b); - if (!parent) - set_dev_node(b->bridge, pcibus_to_node(b)); - - b->dev.class = &pcibus_class; - b->dev.parent = b->bridge; - dev_set_name(&b->dev, "%04x:%02x", pci_domain_nr(b), bus); - error = device_register(&b->dev); - if (error) - goto class_dev_reg_err; + list_splice_init(resources, &bridge->windows); + bridge->sysdata = sysdata; + bridge->busnr = bus; + bridge->ops = ops; + bridge->msi = msi; - pcibios_add_bus(b); - - /* Create legacy_io and legacy_mem files for this bus */ - pci_create_legacy_files(b); - - if (parent) - dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev)); - else - printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev)); - - /* Add initial resources to the bus */ - resource_list_for_each_entry_safe(window, n, resources) { - list_move_tail(&window->node, &bridge->windows); - res = window->res; - offset = window->offset; - if (res->flags & IORESOURCE_BUS) - pci_bus_insert_busn_res(b, bus, res->end); - else - pci_bus_add_resource(b, res, 0); - if (offset) { - if (resource_type(res) == IORESOURCE_IO) - fmt = " (bus address [%#06llx-%#06llx])"; - else - fmt = " (bus address [%#010llx-%#010llx])"; - snprintf(bus_addr, sizeof(bus_addr), fmt, - (unsigned long long) (res->start - offset), - (unsigned long long) (res->end - offset)); - } else - bus_addr[0] = '\0'; - dev_info(&b->dev, "root bus resource %pR%s\n", res, bus_addr); - } + error = pci_register_host_bridge(bridge); + if (error < 0) + goto err_out; - down_write(&pci_bus_sem); - list_add_tail(&b->node, &pci_root_buses); - up_write(&pci_bus_sem); + return bridge->bus; - return b; - -class_dev_reg_err: - put_device(&bridge->dev); - device_unregister(&bridge->dev); err_out: - kfree(b); + kfree(bridge); return NULL; } + +struct pci_bus *pci_create_root_bus(struct device *parent, int bus, + struct pci_ops *ops, void *sysdata, struct list_head *resources) +{ + return pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, + NULL); +} EXPORT_SYMBOL_GPL(pci_create_root_bus); int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int bus_max) @@ -2317,12 +2363,10 @@ struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, break; } - b = pci_create_root_bus(parent, bus, ops, sysdata, resources); + b = pci_create_root_bus_msi(parent, bus, ops, sysdata, resources, msi); if (!b) return NULL; - b->msi = msi; - if (!found) { dev_info(&b->dev, "No busn resource found for root bus, will use [bus %02x-ff]\n", diff --git a/include/linux/pci.h b/include/linux/pci.h index 0e49f70dbd9b..f79634612fbf 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -420,9 +420,13 @@ static inline int pci_channel_offline(struct pci_dev *pdev) struct pci_host_bridge { struct device dev; struct pci_bus *bus; /* root bus */ + struct pci_ops *ops; + void *sysdata; + int busnr; struct list_head windows; /* resource_entry */ void (*release_fn)(struct pci_host_bridge *); void *release_data; + struct msi_controller *msi; unsigned int ignore_reset_delay:1; /* for entire hierarchy */ /* Resource alignment requirements */ resource_size_t (*align_resource)(struct pci_dev *dev, -- cgit v1.2.3 From 5909406598d9fab58be860b72dff9409bff11653 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Nov 2016 11:57:10 +0100 Subject: PCI: Allow driver-specific data in host bridge Provide a way to allocate driver-specific data along with a PCI host bridge structure. The bridge's ->private field points to this data. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 6 +++--- include/linux/pci.h | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 4853c8fbd701..cf9cb6f30782 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -521,11 +521,11 @@ static void pci_release_host_bridge_dev(struct device *dev) kfree(bridge); } -static struct pci_host_bridge *pci_alloc_host_bridge(void) +static struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) { struct pci_host_bridge *bridge; - bridge = kzalloc(sizeof(*bridge), GFP_KERNEL); + bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL); if (!bridge) return NULL; @@ -2253,7 +2253,7 @@ static struct pci_bus *pci_create_root_bus_msi(struct device *parent, int error; struct pci_host_bridge *bridge; - bridge = pci_alloc_host_bridge(); + bridge = pci_alloc_host_bridge(0); if (!bridge) return NULL; diff --git a/include/linux/pci.h b/include/linux/pci.h index f79634612fbf..beacb17e81fb 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -434,10 +434,21 @@ struct pci_host_bridge { resource_size_t start, resource_size_t size, resource_size_t align); + unsigned long private[0] ____cacheline_aligned; }; #define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev) +static inline void *pci_host_bridge_priv(struct pci_host_bridge *bridge) +{ + return (void *)bridge->private; +} + +static inline struct pci_host_bridge *pci_host_bridge_from_priv(void *priv) +{ + return container_of(priv, struct pci_host_bridge, private); +} + struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus); void pci_set_host_bridge_release(struct pci_host_bridge *bridge, -- cgit v1.2.3 From a52d1443bba1db98907521414727eee22ae8c380 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Nov 2016 11:57:11 +0100 Subject: PCI: Export host bridge registration interface Allow PCI host bridge drivers to use the new host bridge interfaces to register their host bridge. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/probe.c | 6 ++++-- include/linux/pci.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index cf9cb6f30782..f85ecb595c30 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -521,7 +521,7 @@ static void pci_release_host_bridge_dev(struct device *dev) kfree(bridge); } -static struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) +struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) { struct pci_host_bridge *bridge; @@ -533,6 +533,7 @@ static struct pci_host_bridge *pci_alloc_host_bridge(size_t priv) return bridge; } +EXPORT_SYMBOL(pci_alloc_host_bridge); static const unsigned char pcix_bus_speed[] = { PCI_SPEED_UNKNOWN, /* 0 */ @@ -717,7 +718,7 @@ static void pci_set_bus_msi_domain(struct pci_bus *bus) dev_set_msi_domain(&bus->dev, d); } -static int pci_register_host_bridge(struct pci_host_bridge *bridge) +int pci_register_host_bridge(struct pci_host_bridge *bridge) { struct device *parent = bridge->dev.parent; struct resource_entry *window, *n; @@ -832,6 +833,7 @@ free: kfree(bus); return err; } +EXPORT_SYMBOL(pci_register_host_bridge); static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent, struct pci_dev *bridge, int busnr) diff --git a/include/linux/pci.h b/include/linux/pci.h index beacb17e81fb..aa5e8af16cfc 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -449,6 +449,8 @@ static inline struct pci_host_bridge *pci_host_bridge_from_priv(void *priv) return container_of(priv, struct pci_host_bridge, private); } +struct pci_host_bridge *pci_alloc_host_bridge(size_t priv); +int pci_register_host_bridge(struct pci_host_bridge *bridge); struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus); void pci_set_host_bridge_release(struct pci_host_bridge *bridge, -- cgit v1.2.3 From 76f254149171a93e676139b53fcc83043d55a047 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 25 Nov 2016 11:57:12 +0100 Subject: PCI: tegra: Use new pci_register_host_bridge() interface Tegra is one of the remaining platforms that still use the traditional pci_common_init_dev() interface for probing PCI host bridges. This demonstrates how to convert it to the pci_register_host interface I just added in a previous patch. This leads to a more linear probe sequence that can handle errors better because we avoid callbacks into the driver, and it makes the driver architecture independent. Signed-off-by: Arnd Bergmann Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-tegra.c | 105 ++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 51 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 8dfccf733241..d5206fa53353 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -322,11 +322,6 @@ struct tegra_pcie_bus { unsigned int nr; }; -static inline struct tegra_pcie *sys_to_pcie(struct pci_sys_data *sys) -{ - return sys->private_data; -} - static inline void afi_writel(struct tegra_pcie *pcie, u32 value, unsigned long offset) { @@ -430,7 +425,8 @@ free: static int tegra_pcie_add_bus(struct pci_bus *bus) { - struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata); + struct pci_host_bridge *host = pci_find_host_bridge(bus); + struct tegra_pcie *pcie = pci_host_bridge_priv(host); struct tegra_pcie_bus *b; b = tegra_pcie_bus_alloc(pcie, bus->number); @@ -444,7 +440,8 @@ static int tegra_pcie_add_bus(struct pci_bus *bus) static void tegra_pcie_remove_bus(struct pci_bus *child) { - struct tegra_pcie *pcie = sys_to_pcie(child->sysdata); + struct pci_host_bridge *host = pci_find_host_bridge(child); + struct tegra_pcie *pcie = pci_host_bridge_priv(host); struct tegra_pcie_bus *bus, *tmp; list_for_each_entry_safe(bus, tmp, &pcie->buses, list) { @@ -461,7 +458,8 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus, unsigned int devfn, int where) { - struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata); + struct pci_host_bridge *host = pci_find_host_bridge(bus); + struct tegra_pcie *pcie = pci_host_bridge_priv(host); struct device *dev = pcie->dev; void __iomem *addr = NULL; @@ -610,39 +608,31 @@ static void tegra_pcie_relax_enable(struct pci_dev *dev) } DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable); -static int tegra_pcie_setup(int nr, struct pci_sys_data *sys) +static int tegra_pcie_request_resources(struct tegra_pcie *pcie) { - struct tegra_pcie *pcie = sys_to_pcie(sys); + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); + struct list_head *windows = &host->windows; struct device *dev = pcie->dev; int err; - sys->mem_offset = pcie->offset.mem; - sys->io_offset = pcie->offset.io; + pci_add_resource_offset(windows, &pcie->pio, pcie->offset.io); + pci_add_resource_offset(windows, &pcie->mem, pcie->offset.mem); + pci_add_resource_offset(windows, &pcie->prefetch, pcie->offset.mem); + pci_add_resource(windows, &pcie->busn); - err = devm_request_resource(dev, &iomem_resource, &pcie->io); + err = devm_request_pci_bus_resources(dev, windows); if (err < 0) return err; - err = pci_remap_iospace(&pcie->pio, pcie->io.start); - if (!err) - pci_add_resource_offset(&sys->resources, &pcie->pio, - sys->io_offset); - - pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset); - pci_add_resource_offset(&sys->resources, &pcie->prefetch, - sys->mem_offset); - pci_add_resource(&sys->resources, &pcie->busn); - - err = devm_request_pci_bus_resources(dev, &sys->resources); - if (err < 0) - return err; + pci_remap_iospace(&pcie->pio, pcie->io.start); - return 1; + return 0; } static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin) { - struct tegra_pcie *pcie = sys_to_pcie(pdev->bus->sysdata); + struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus); + struct tegra_pcie *pcie = pci_host_bridge_priv(host); int irq; tegra_cpuidle_pcie_irqs_in_use(); @@ -1499,10 +1489,11 @@ static const struct irq_domain_ops msi_domain_ops = { static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) { - struct device *dev = pcie->dev; - struct platform_device *pdev = to_platform_device(dev); + struct pci_host_bridge *host = pci_host_bridge_from_priv(pcie); + struct platform_device *pdev = to_platform_device(pcie->dev); const struct tegra_pcie_soc *soc = pcie->soc; struct tegra_msi *msi = &pcie->msi; + struct device *dev = pcie->dev; unsigned long base; int err; u32 reg; @@ -1559,6 +1550,8 @@ static int tegra_pcie_enable_msi(struct tegra_pcie *pcie) reg |= AFI_INTR_MASK_MSI_MASK; afi_writel(pcie, reg, AFI_INTR_MASK); + host->msi = &msi->chip; + return 0; err: @@ -2021,11 +2014,10 @@ retry: return false; } -static int tegra_pcie_enable(struct tegra_pcie *pcie) +static void tegra_pcie_enable_ports(struct tegra_pcie *pcie) { struct device *dev = pcie->dev; struct tegra_pcie_port *port, *tmp; - struct hw_pci hw; list_for_each_entry_safe(port, tmp, &pcie->ports, list) { dev_info(dev, "probing port %u, using %u lanes\n", @@ -2041,21 +2033,6 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie) tegra_pcie_port_disable(port); tegra_pcie_port_free(port); } - - memset(&hw, 0, sizeof(hw)); - -#ifdef CONFIG_PCI_MSI - hw.msi_ctrl = &pcie->msi.chip; -#endif - - hw.nr_controllers = 1; - hw.private_data = (void **)&pcie; - hw.setup = tegra_pcie_setup; - hw.map_irq = tegra_pcie_map_irq; - hw.ops = &tegra_pcie_ops; - - pci_common_init_dev(dev, &hw); - return 0; } static const struct tegra_pcie_soc tegra20_pcie = { @@ -2217,13 +2194,17 @@ remove: static int tegra_pcie_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct pci_host_bridge *host; struct tegra_pcie *pcie; + struct pci_bus *child; int err; - pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL); - if (!pcie) + host = pci_alloc_host_bridge(sizeof(*pcie)); + if (!host) return -ENOMEM; + pcie = pci_host_bridge_priv(host); + pcie->soc = of_device_get_match_data(dev); INIT_LIST_HEAD(&pcie->buses); INIT_LIST_HEAD(&pcie->ports); @@ -2243,6 +2224,10 @@ static int tegra_pcie_probe(struct platform_device *pdev) if (err) goto put_resources; + err = tegra_pcie_request_resources(pcie); + if (err) + goto put_resources; + /* setup the AFI address translations */ tegra_pcie_setup_translations(pcie); @@ -2254,12 +2239,30 @@ static int tegra_pcie_probe(struct platform_device *pdev) } } - err = tegra_pcie_enable(pcie); + tegra_pcie_enable_ports(pcie); + + pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS); + host->busnr = pcie->busn.start; + host->dev.parent = &pdev->dev; + host->ops = &tegra_pcie_ops; + + err = pci_register_host_bridge(host); if (err < 0) { - dev_err(dev, "failed to enable PCIe ports: %d\n", err); + dev_err(dev, "failed to register host: %d\n", err); goto disable_msi; } + pci_scan_child_bus(host->bus); + + pci_fixup_irqs(pci_common_swizzle, tegra_pcie_map_irq); + pci_bus_size_bridges(host->bus); + pci_bus_assign_resources(host->bus); + + list_for_each_entry(child, &host->bus->children, node) + pcie_bus_configure_settings(child); + + pci_bus_add_devices(host->bus); + if (IS_ENABLED(CONFIG_DEBUG_FS)) { err = tegra_pcie_debugfs_init(pcie); if (err < 0) -- cgit v1.2.3 From 76245ca2dfa848bf044acccb5f0d1c07f6e42411 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Nov 2016 11:57:14 +0100 Subject: PCI: tegra: Implement PCA enable workaround Tegra210's PCIe controller has a bug that requires the PCA (performance counter) feature to be enabled. If this isn't done, accesses to device configuration space will hang the chip for tens of seconds. Implement the workaround. Based on commit 514e19138af2 ("pci: tegra: implement PCA enable workaround") from U-Boot by Stephen Warren . Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-tegra.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index d5206fa53353..4bfaac6d3582 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -188,6 +188,9 @@ #define RP_VEND_XP 0x00000f00 #define RP_VEND_XP_DL_UP (1 << 30) +#define RP_VEND_CTL2 0x00000fa8 +#define RP_VEND_CTL2_PCA_ENABLE (1 << 7) + #define RP_PRIV_MISC 0x00000fe0 #define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xe << 0) #define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xf << 0) @@ -252,6 +255,7 @@ struct tegra_pcie_soc { bool has_intr_prsnt_sense; bool has_cml_clk; bool has_gen2; + bool force_pca_enable; }; static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip) @@ -556,6 +560,12 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port) afi_writel(port->pcie, value, ctrl); tegra_pcie_port_reset(port); + + if (soc->force_pca_enable) { + value = readl(port->base + RP_VEND_CTL2); + value |= RP_VEND_CTL2_PCA_ENABLE; + writel(value, port->base + RP_VEND_CTL2); + } } static void tegra_pcie_port_disable(struct tegra_pcie_port *port) @@ -2046,6 +2056,7 @@ static const struct tegra_pcie_soc tegra20_pcie = { .has_intr_prsnt_sense = false, .has_cml_clk = false, .has_gen2 = false, + .force_pca_enable = false, }; static const struct tegra_pcie_soc tegra30_pcie = { @@ -2060,6 +2071,7 @@ static const struct tegra_pcie_soc tegra30_pcie = { .has_intr_prsnt_sense = true, .has_cml_clk = true, .has_gen2 = false, + .force_pca_enable = false, }; static const struct tegra_pcie_soc tegra124_pcie = { @@ -2073,6 +2085,7 @@ static const struct tegra_pcie_soc tegra124_pcie = { .has_intr_prsnt_sense = true, .has_cml_clk = true, .has_gen2 = true, + .force_pca_enable = false, }; static const struct of_device_id tegra_pcie_of_match[] = { -- cgit v1.2.3 From c7a091c7627c9a76d7a5c706820cb510f6992cdf Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Nov 2016 11:57:15 +0100 Subject: PCI: tegra: Add Tegra210 support The PCIe host controller found on Tegra X1 is very similar to its predecessor on Tegra K1. A bug was introduced in the new revision that is worked around by always enabling the performance counter, otherwise accesses to configuration space will block for a number of seconds. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-tegra.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c index 4bfaac6d3582..ed8a93f2bfb5 100644 --- a/drivers/pci/host/pci-tegra.c +++ b/drivers/pci/host/pci-tegra.c @@ -51,10 +51,6 @@ #include #include -#include -#include -#include - #define INT_PCI_MSI_NR (8 * 32) /* register definitions */ @@ -384,8 +380,7 @@ static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie, unsigned int busnr) { struct device *dev = pcie->dev; - pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | L_PTE_DIRTY | - L_PTE_XN | L_PTE_MT_DEV_SHARED | L_PTE_SHARED); + pgprot_t prot = pgprot_device(PAGE_KERNEL); phys_addr_t cs = pcie->cs->start; struct tegra_pcie_bus *bus; unsigned int i; @@ -1612,7 +1607,8 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes, struct device *dev = pcie->dev; struct device_node *np = dev->of_node; - if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) { + if (of_device_is_compatible(np, "nvidia,tegra124-pcie") || + of_device_is_compatible(np, "nvidia,tegra210-pcie")) { switch (lanes) { case 0x0000104: dev_info(dev, "4x1, 1x1 configuration\n"); @@ -1733,7 +1729,22 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask) struct device_node *np = dev->of_node; unsigned int i = 0; - if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) { + if (of_device_is_compatible(np, "nvidia,tegra210-pcie")) { + pcie->num_supplies = 6; + + pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies, + sizeof(*pcie->supplies), + GFP_KERNEL); + if (!pcie->supplies) + return -ENOMEM; + + pcie->supplies[i++].supply = "avdd-pll-uerefe"; + pcie->supplies[i++].supply = "hvddio-pex"; + pcie->supplies[i++].supply = "dvddio-pex"; + pcie->supplies[i++].supply = "dvdd-pex-pll"; + pcie->supplies[i++].supply = "hvdd-pex-pll-e"; + pcie->supplies[i++].supply = "vddio-pex-ctl"; + } else if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) { pcie->num_supplies = 7; pcie->supplies = devm_kcalloc(dev, pcie->num_supplies, @@ -2088,7 +2099,22 @@ static const struct tegra_pcie_soc tegra124_pcie = { .force_pca_enable = false, }; +static const struct tegra_pcie_soc tegra210_pcie = { + .num_ports = 2, + .msi_base_shift = 8, + .pads_pll_ctl = PADS_PLL_CTL_TEGRA30, + .tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN, + .pads_refclk_cfg0 = 0x90b890b8, + .has_pex_clkreq_en = true, + .has_pex_bias_ctrl = true, + .has_intr_prsnt_sense = true, + .has_cml_clk = true, + .has_gen2 = true, + .force_pca_enable = true, +}; + static const struct of_device_id tegra_pcie_of_match[] = { + { .compatible = "nvidia,tegra210-pcie", .data = &tegra210_pcie }, { .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie }, { .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie }, { .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie }, -- cgit v1.2.3 From 7ac0271397ab2d389f18f4d191730dc4d4b33c11 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Fri, 25 Nov 2016 11:57:16 +0100 Subject: PCI: tegra: Enable the driver on 64-bit ARM The Tegra PCI host controller driver no longer relies on any of the 32-bit ARM glue for PCI, so it can be enabled on 64-bit configurations. Signed-off-by: Thierry Reding Signed-off-by: Bjorn Helgaas --- drivers/pci/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index d7e7c0a827c3..bdec31a83d01 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -69,7 +69,7 @@ config PCI_IMX6 config PCI_TEGRA bool "NVIDIA Tegra PCIe controller" - depends on ARCH_TEGRA && !ARM64 + depends on ARCH_TEGRA help Say Y here if you want support for the PCIe host controller found on NVIDIA Tegra SoCs. -- cgit v1.2.3 From 3906b91844d603153c094f636205ec9aa5454b2f Mon Sep 17 00:00:00 2001 From: Jon Derrick Date: Fri, 11 Nov 2016 16:08:45 -0700 Subject: PCI: vmd: Use SRCU as a local RCU to prevent delaying global RCU SRCU lets synchronize_srcu() depend on VMD-local RCU primitives, preventing long delays from locking up RCU in other systems. VMD performs a synchronize when removing a device, but will hit all IRQ lists if the device uses all VMD vectors. This patch will not help VMD's RCU synchronization, but will isolate the read side delays to the VMD subsystem. Additionally, the use of SRCU in VMD's ISR will keep it isolated from any other RCU waiters in the rest of the system. Tested using concurrent FIO and NVMe resets: [global] rw=read bs=4k direct=1 ioengine=libaio iodepth=32 norandommap timeout=300 runtime=1000000000 [nvme0] cpus_allowed=0-63 numjobs=8 filename=/dev/nvme0n1 [nvme1] cpus_allowed=0-63 numjobs=8 filename=/dev/nvme1n1 while (true) do for i in /sys/class/nvme/nvme*; do echo "Resetting ${i##*/}" echo 1 > $i/reset_controller; sleep 5 done; done Signed-off-by: Jon Derrick Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/host/Kconfig | 2 +- drivers/pci/host/vmd.c | 27 +++++++++++++++++++++------ 2 files changed, 22 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index d7e7c0a827c3..e020359b09bc 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -286,7 +286,7 @@ config PCIE_ROCKCHIP 4 slots. config VMD - depends on PCI_MSI && X86_64 + depends on PCI_MSI && X86_64 && SRCU tristate "Intel Volume Management Device Driver" default N ---help--- diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c index 6614b3552b9c..6c5b7fd9f0c5 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/host/vmd.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -39,7 +40,6 @@ static DEFINE_RAW_SPINLOCK(list_lock); /** * struct vmd_irq - private data to map driver IRQ to the VMD shared vector * @node: list item for parent traversal. - * @rcu: RCU callback item for freeing. * @irq: back pointer to parent. * @enabled: true if driver enabled IRQ * @virq: the virtual IRQ value provided to the requesting driver. @@ -49,7 +49,6 @@ static DEFINE_RAW_SPINLOCK(list_lock); */ struct vmd_irq { struct list_head node; - struct rcu_head rcu; struct vmd_irq_list *irq; bool enabled; unsigned int virq; @@ -58,11 +57,13 @@ struct vmd_irq { /** * struct vmd_irq_list - list of driver requested IRQs mapping to a VMD vector * @irq_list: the list of irq's the VMD one demuxes to. + * @srcu: SRCU struct for local synchronization. * @count: number of child IRQs assigned to this vector; used to track * sharing. */ struct vmd_irq_list { struct list_head irq_list; + struct srcu_struct srcu; unsigned int count; }; @@ -224,14 +225,14 @@ static void vmd_msi_free(struct irq_domain *domain, struct vmd_irq *vmdirq = irq_get_chip_data(virq); unsigned long flags; - synchronize_rcu(); + synchronize_srcu(&vmdirq->irq->srcu); /* XXX: Potential optimization to rebalance */ raw_spin_lock_irqsave(&list_lock, flags); vmdirq->irq->count--; raw_spin_unlock_irqrestore(&list_lock, flags); - kfree_rcu(vmdirq, rcu); + kfree(vmdirq); } static int vmd_msi_prepare(struct irq_domain *domain, struct device *dev, @@ -646,11 +647,12 @@ static irqreturn_t vmd_irq(int irq, void *data) { struct vmd_irq_list *irqs = data; struct vmd_irq *vmdirq; + int idx; - rcu_read_lock(); + idx = srcu_read_lock(&irqs->srcu); list_for_each_entry_rcu(vmdirq, &irqs->irq_list, node) generic_handle_irq(vmdirq->virq); - rcu_read_unlock(); + srcu_read_unlock(&irqs->srcu, idx); return IRQ_HANDLED; } @@ -696,6 +698,10 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENOMEM; for (i = 0; i < vmd->msix_count; i++) { + err = init_srcu_struct(&vmd->irqs[i].srcu); + if (err) + return err; + INIT_LIST_HEAD(&vmd->irqs[i].irq_list); err = devm_request_irq(&dev->dev, pci_irq_vector(dev, i), vmd_irq, 0, "vmd", &vmd->irqs[i]); @@ -714,11 +720,20 @@ static int vmd_probe(struct pci_dev *dev, const struct pci_device_id *id) return 0; } +static void vmd_cleanup_srcu(struct vmd_dev *vmd) +{ + int i; + + for (i = 0; i < vmd->msix_count; i++) + cleanup_srcu_struct(&vmd->irqs[i].srcu); +} + static void vmd_remove(struct pci_dev *dev) { struct vmd_dev *vmd = pci_get_drvdata(dev); vmd_detach_resources(vmd); + vmd_cleanup_srcu(vmd); sysfs_remove_link(&vmd->dev->dev.kobj, "domain"); pci_stop_root_bus(vmd->bus); pci_remove_root_bus(vmd->bus); -- cgit v1.2.3 From 42db500a551f97551a901e2258f84a60baf4edfc Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 26 Nov 2016 19:29:57 +0100 Subject: PCI: vmd: Fix suspend handlers defined-but-not-used warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix the following warnings: drivers/pci/host/vmd.c:731:12: warning: ‘vmd_suspend’ defined but not used [-Wunused-function] static int vmd_suspend(struct device *dev) ^ drivers/pci/host/vmd.c:739:12: warning: ‘vmd_resume’ defined but not used [-Wunused-function] static int vmd_resume(struct device *dev) ^ Signed-off-by: Borislav Petkov Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/host/vmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/vmd.c b/drivers/pci/host/vmd.c index 6c5b7fd9f0c5..18ef1a93c10a 100644 --- a/drivers/pci/host/vmd.c +++ b/drivers/pci/host/vmd.c @@ -741,7 +741,7 @@ static void vmd_remove(struct pci_dev *dev) irq_domain_remove(vmd->irq_domain); } -#ifdef CONFIG_PM +#ifdef CONFIG_PM_SLEEP static int vmd_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); -- cgit v1.2.3 From 554d9ec7b4c3f4bd439333135882a873bd734b4e Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Wed, 23 Nov 2016 22:55:07 +0800 Subject: PCI: spear: Use builtin_platform_driver() to simplify the code Use builtin_platform_driver() helper to simplify the code. Signed-off-by: Geliang Tang Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-spear13xx.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c index 3cf197ba7f37..dafe8b88d97d 100644 --- a/drivers/pci/host/pcie-spear13xx.c +++ b/drivers/pci/host/pcie-spear13xx.c @@ -296,8 +296,4 @@ static struct platform_driver spear13xx_pcie_driver = { }, }; -static int __init spear13xx_pcie_init(void) -{ - return platform_driver_register(&spear13xx_pcie_driver); -} -device_initcall(spear13xx_pcie_init); +builtin_platform_driver(spear13xx_pcie_driver); -- cgit v1.2.3 From ca5ab37b19dfd1d77787d0474b767ec1185670f4 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 6 Dec 2016 14:27:59 -0600 Subject: PCI: Explain ARM64 ACPI/MCFG quirk Kconfig and build strategy Add Makefile comments to explain the Kconfig and build strategy for ARM64 drivers that work around not-quite-ECAM issues. No functional change intended. Signed-off-by: Bjorn Helgaas --- drivers/pci/host/Makefile | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile index 6cc84b4f3a4d..bfe3179ae74c 100644 --- a/drivers/pci/host/Makefile +++ b/drivers/pci/host/Makefile @@ -15,7 +15,6 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o obj-$(CONFIG_PCIE_XILINX_NWL) += pcie-xilinx-nwl.o -obj-$(CONFIG_ARM64) += pci-xgene.o obj-$(CONFIG_PCI_XGENE_MSI) += pci-xgene-msi.o obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o @@ -25,11 +24,23 @@ obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o obj-$(CONFIG_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o obj-$(CONFIG_PCIE_ALTERA) += pcie-altera.o obj-$(CONFIG_PCIE_ALTERA_MSI) += pcie-altera-msi.o -obj-$(CONFIG_ARM64) += pcie-hisi.o obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o -obj-$(CONFIG_ARM64) += pci-thunder-ecam.o -obj-$(CONFIG_ARM64) += pci-thunder-pem.o obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o obj-$(CONFIG_PCIE_ARTPEC6) += pcie-artpec6.o obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o obj-$(CONFIG_VMD) += vmd.o + +# The following drivers are for devices that use the generic ACPI +# pci_root.c driver but don't support standard ECAM config access. +# They contain MCFG quirks to replace the generic ECAM accessors with +# device-specific ones that are shared with the DT driver. + +# The ACPI driver is generic and should not require driver-specific +# config options to be enabled, so we always build these drivers on +# ARM64 and use internal ifdefs to only build the pieces we need +# depending on whether ACPI, the DT driver, or both are enabled. + +obj-$(CONFIG_ARM64) += pcie-hisi.o +obj-$(CONFIG_ARM64) += pci-thunder-ecam.o +obj-$(CONFIG_ARM64) += pci-thunder-pem.o +obj-$(CONFIG_ARM64) += pci-xgene.o -- cgit v1.2.3 From 4816c4c7b82b55bb46cb9b85ef8e6780fc618592 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 7 Dec 2016 15:05:58 -0600 Subject: PCI: rockchip: Provide captured slot power limit and scale If vpcie3v3 is available, we could provide these information via RC's configure register to make EP able to know the power limit. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index e04f69beb42d..36f5eeb530f5 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -135,6 +135,10 @@ #define PCIE_RC_CONFIG_VENDOR (PCIE_RC_CONFIG_BASE + 0x00) #define PCIE_RC_CONFIG_RID_CCR (PCIE_RC_CONFIG_BASE + 0x08) #define PCIE_RC_CONFIG_SCC_SHIFT 16 +#define PCIE_RC_CONFIG_DCR (PCIE_RC_CONFIG_BASE + 0xc4) +#define PCIE_RC_CONFIG_DCR_CSPL_SHIFT 18 +#define PCIE_RC_CONFIG_DCR_CSPL_LIMIT 0xff +#define PCIE_RC_CONFIG_DCR_CPLS_SHIFT 26 #define PCIE_RC_CONFIG_LCS (PCIE_RC_CONFIG_BASE + 0xd0) #define PCIE_RC_CONFIG_LCS_RETRAIN_LINK BIT(5) #define PCIE_RC_CONFIG_LCS_LBMIE BIT(10) @@ -398,6 +402,40 @@ static struct pci_ops rockchip_pcie_ops = { .write = rockchip_pcie_wr_conf, }; +static void rockchip_pcie_set_power_limit(struct rockchip_pcie *rockchip) +{ + u32 status, curr, scale, power; + + if (IS_ERR(rockchip->vpcie3v3)) + return; + + /* + * Set RC's captured slot power limit and scale if + * vpcie3v3 available. The default values are both zero + * which means the software should set these two according + * to the actual power supply. + */ + curr = regulator_get_current_limit(rockchip->vpcie3v3); + if (curr > 0) { + scale = 3; /* 0.001x */ + curr = curr / 1000; /* convert to mA */ + power = (curr * 3300) / 1000; /* milliwatt */ + while (power > PCIE_RC_CONFIG_DCR_CSPL_LIMIT) { + if (!scale) { + dev_warn(rockchip->dev, "invalid power supply\n"); + return; + } + scale--; + power = power / 10; + } + + status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_DCR); + status |= (power << PCIE_RC_CONFIG_DCR_CSPL_SHIFT) | + (scale << PCIE_RC_CONFIG_DCR_CPLS_SHIFT); + rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_DCR); + } +} + /** * rockchip_pcie_init_port - Initialize hardware * @rockchip: PCIe port information @@ -537,6 +575,8 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) (PCIE_CORE_CTRL_PLC1_FTS_CNT << PCIE_CORE_CTRL_PLC1_FTS_SHIFT); rockchip_pcie_write(rockchip, status, PCIE_CORE_CTRL_PLC1); + rockchip_pcie_set_power_limit(rockchip); + /* Enable Gen1 training */ rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE, PCIE_CLIENT_CONFIG); -- cgit v1.2.3 From b8ab8e041cc0356323c1e4aee8047ea479650340 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 7 Dec 2016 15:05:58 -0600 Subject: PCI: rockchip: Mark RC as common clock architecture The default value of common clock configuration is zero indicating Rockchip's RC is using asynchronous clock architecture but actually we are using common clock. This will confuse some EP drivers if they need some different settings referring to this value. Set the Common Clock Configuration bit in the Link Control Register. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 36f5eeb530f5..b296808ccc71 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -141,6 +141,7 @@ #define PCIE_RC_CONFIG_DCR_CPLS_SHIFT 26 #define PCIE_RC_CONFIG_LCS (PCIE_RC_CONFIG_BASE + 0xd0) #define PCIE_RC_CONFIG_LCS_RETRAIN_LINK BIT(5) +#define PCIE_RC_CONFIG_LCS_CCC BIT(6) #define PCIE_RC_CONFIG_LCS_LBMIE BIT(10) #define PCIE_RC_CONFIG_LCS_LABIE BIT(11) #define PCIE_RC_CONFIG_LCS_LBMS BIT(30) @@ -577,6 +578,11 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) rockchip_pcie_set_power_limit(rockchip); + /* Set RC's clock architecture as common clock */ + status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); + status |= PCIE_RC_CONFIG_LCS_CCC; + rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); + /* Enable Gen1 training */ rockchip_pcie_write(rockchip, PCIE_CLIENT_LINK_TRAIN_ENABLE, PCIE_CLIENT_CONFIG); -- cgit v1.2.3 From 1177f76a7e7e52d4be3c78247b30ab73cabf7164 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 7 Dec 2016 15:05:59 -0600 Subject: PCI: rockchip: Add Kconfig COMPILE_TEST Allow selection of the Rockchip driver for compile testing, even if we aren't building for ARCH_ROCKCHIP. [bhelgaas: changelog] Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig index d7e7c0a827c3..096440ec75f9 100644 --- a/drivers/pci/host/Kconfig +++ b/drivers/pci/host/Kconfig @@ -276,7 +276,7 @@ config PCIE_ARTPEC6 config PCIE_ROCKCHIP bool "Rockchip PCIe controller" - depends on ARCH_ROCKCHIP + depends on ARCH_ROCKCHIP || COMPILE_TEST depends on OF depends on PCI_MSI_IRQ_DOMAIN select MFD_SYSCON -- cgit v1.2.3 From 45e9320f3a4ef9588ee50a2eb1891c4bfdbb07df Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 7 Dec 2016 15:05:59 -0600 Subject: PCI: rockchip: Fix negotiated lanes calculation The calculation of negotiated lanes is wrong: it should be shifted by PCIE_CORE_PL_CONF_LANE_SHIFT, but it is shifted by PCIE_CORE_PL_CONF_LANE_MASK instead. Let's fix it. Fixes: e77f847df54c ("PCI: rockchip: Add Rockchip PCIe controller support") Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index b296808ccc71..f641a4e6f605 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -636,8 +636,8 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) /* Check the final link width from negotiated lane counter from MGMT */ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL); - status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >> - PCIE_CORE_PL_CONF_LANE_MASK); + status = 0x1 << ((status & PCIE_CORE_PL_CONF_LANE_MASK) >> + PCIE_CORE_PL_CONF_LANE_SHIFT); dev_dbg(dev, "current link width is x%d\n", status); rockchip_pcie_write(rockchip, ROCKCHIP_VENDOR_ID, -- cgit v1.2.3 From f2fb5b8f2a0cb67ba4535eb08d9cfb301ac92429 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 7 Dec 2016 15:05:59 -0600 Subject: PCI: rockchip: Specify the link capability rk3399 supports PCIe 2.x link speeds marginally at best, and on some boards, the link won't train at 5 GT/s at all. Rather than sacrifice 500ms waiting for training that will never happen, let's use the helper function, of_pci_get_max_link_speed(), to get the max link speed from DT and specify link capability. Signed-off-by: Brian Norris Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 60 +++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index f641a4e6f605..13e0dd6097a4 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -53,6 +53,7 @@ #define PCIE_CLIENT_ARI_ENABLE HIWORD_UPDATE_BIT(0x0008) #define PCIE_CLIENT_CONF_LANE_NUM(x) HIWORD_UPDATE(0x0030, ENCODE_LANES(x)) #define PCIE_CLIENT_MODE_RC HIWORD_UPDATE_BIT(0x0040) +#define PCIE_CLIENT_GEN_SEL_1 HIWORD_UPDATE(0x0080, 0) #define PCIE_CLIENT_GEN_SEL_2 HIWORD_UPDATE_BIT(0x0080) #define PCIE_CLIENT_BASIC_STATUS1 (PCIE_CLIENT_BASE + 0x48) #define PCIE_CLIENT_LINK_STATUS_UP 0x00300000 @@ -208,6 +209,7 @@ struct rockchip_pcie { struct gpio_desc *ep_gpio; u32 lanes; u8 root_bus_nr; + int link_gen; struct device *dev; struct irq_domain *irq_domain; }; @@ -518,14 +520,20 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) return err; } + if (rockchip->link_gen == 2) + rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2, + PCIE_CLIENT_CONFIG); + else + rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_1, + PCIE_CLIENT_CONFIG); + rockchip_pcie_write(rockchip, PCIE_CLIENT_CONF_ENABLE | PCIE_CLIENT_LINK_TRAIN_ENABLE | PCIE_CLIENT_ARI_ENABLE | PCIE_CLIENT_CONF_LANE_NUM(rockchip->lanes) | - PCIE_CLIENT_MODE_RC | - PCIE_CLIENT_GEN_SEL_2, - PCIE_CLIENT_CONFIG); + PCIE_CLIENT_MODE_RC, + PCIE_CLIENT_CONFIG); err = phy_power_on(rockchip->phy); if (err) { @@ -609,29 +617,31 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) msleep(20); } - /* - * Enable retrain for gen2. This should be configured only after - * gen1 finished. - */ - status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); - status |= PCIE_RC_CONFIG_LCS_RETRAIN_LINK; - rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); + if (rockchip->link_gen == 2) { + /* + * Enable retrain for gen2. This should be configured only after + * gen1 finished. + */ + status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); + status |= PCIE_RC_CONFIG_LCS_RETRAIN_LINK; + rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); + + timeout = jiffies + msecs_to_jiffies(500); + for (;;) { + status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL); + if ((status & PCIE_CORE_PL_CONF_SPEED_MASK) == + PCIE_CORE_PL_CONF_SPEED_5G) { + dev_dbg(dev, "PCIe link training gen2 pass!\n"); + break; + } - timeout = jiffies + msecs_to_jiffies(500); - for (;;) { - status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL); - if ((status & PCIE_CORE_PL_CONF_SPEED_MASK) == - PCIE_CORE_PL_CONF_SPEED_5G) { - dev_dbg(dev, "PCIe link training gen2 pass!\n"); - break; - } + if (time_after(jiffies, timeout)) { + dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n"); + break; + } - if (time_after(jiffies, timeout)) { - dev_dbg(dev, "PCIe link training gen2 timeout, fall back to gen1!\n"); - break; + msleep(20); } - - msleep(20); } /* Check the final link width from negotiated lane counter from MGMT */ @@ -840,6 +850,10 @@ static int rockchip_pcie_parse_dt(struct rockchip_pcie *rockchip) rockchip->lanes = 1; } + rockchip->link_gen = of_pci_get_max_link_speed(node); + if (rockchip->link_gen < 0 || rockchip->link_gen > 2) + rockchip->link_gen = 2; + rockchip->core_rst = devm_reset_control_get(dev, "core"); if (IS_ERR(rockchip->core_rst)) { if (PTR_ERR(rockchip->core_rst) != -EPROBE_DEFER) -- cgit v1.2.3 From 77bc68cf17973ee81e1cbc21d634c99aa8dca014 Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 7 Dec 2016 15:05:59 -0600 Subject: PCI: rockchip: Remove the pointer to L1 substate cap Per the errata of TRM, the RC can't support L1 substate, so remove the L1 substate cap as well as operation for PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2. Tested-by: Brian Norris Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 13e0dd6097a4..17df584742ff 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -148,6 +148,8 @@ #define PCIE_RC_CONFIG_LCS_LBMS BIT(30) #define PCIE_RC_CONFIG_LCS_LAMS BIT(31) #define PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 (PCIE_RC_CONFIG_BASE + 0x90c) +#define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274) +#define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20) #define PCIE_CORE_AXI_CONF_BASE 0xc00000 #define PCIE_CORE_OB_REGION_ADDR0 (PCIE_CORE_AXI_CONF_BASE + 0x0) @@ -569,15 +571,6 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) return err; } - /* - * We need to read/write PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 before - * enabling ASPM. Otherwise L1PwrOnSc and L1PwrOnVal isn't - * reliable and enabling ASPM doesn't work. This is a controller - * bug we need to work around. - */ - status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2); - rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2); - /* Fix the transmitted FTS count desired to exit from L0s. */ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL_PLC1); status = (status & PCIE_CORE_CTRL_PLC1_FTS_MASK) | @@ -655,6 +648,12 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) rockchip_pcie_write(rockchip, PCI_CLASS_BRIDGE_PCI << PCIE_RC_CONFIG_SCC_SHIFT, PCIE_RC_CONFIG_RID_CCR); + + /* Clear THP cap's next cap pointer to remove L1 substate cap */ + status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_THP_CAP); + status &= ~PCIE_RC_CONFIG_THP_CAP_NEXT_MASK; + rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_THP_CAP); + rockchip_pcie_write(rockchip, 0x0, PCIE_RC_BAR_CONF); rockchip_pcie_write(rockchip, -- cgit v1.2.3 From a45e2611b9bbd81288d97d02ce7e74a60a698d43 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Wed, 7 Dec 2016 15:06:00 -0600 Subject: PCI: rockchip: Correct the use of FTS mask We're trying to mask out bits[23:8] while retaining [32:24, 7:0], but we're doing the inverse. That doesn't have too much effect, since we're setting all the [23:8] bits to 1, and the other bits are only relevant for modes we're currently not using. But we should get this right. Fixes: ca1989084054 ("PCI: rockchip: Fix wrong transmitted FTS count") Signed-off-by: Brian Norris Signed-off-by: Bjorn Helgaas Acked-by: Shawn Lin --- drivers/pci/host/pcie-rockchip.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 17df584742ff..5ff2f698e03a 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -573,7 +573,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) /* Fix the transmitted FTS count desired to exit from L0s. */ status = rockchip_pcie_read(rockchip, PCIE_CORE_CTRL_PLC1); - status = (status & PCIE_CORE_CTRL_PLC1_FTS_MASK) | + status = (status & ~PCIE_CORE_CTRL_PLC1_FTS_MASK) | (PCIE_CORE_CTRL_PLC1_FTS_CNT << PCIE_CORE_CTRL_PLC1_FTS_SHIFT); rockchip_pcie_write(rockchip, status, PCIE_CORE_CTRL_PLC1); -- cgit v1.2.3 From f37500b8aac47b436fe3fe3e63b7169f8eff190d Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Wed, 7 Dec 2016 15:06:00 -0600 Subject: PCI: rockchip: Clean up bit definitions for PCIE_RC_CONFIG_LCS PCIE_RC_CONFIG_LCS contains control and status bits specific to the PCIe link. The layout for this register looks the same as the existing PCI_EXP_LNKCTL and PCI_EXP_LNKSTA. So let's reuse them. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rockchip.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 5ff2f698e03a..989642761877 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -141,12 +141,6 @@ #define PCIE_RC_CONFIG_DCR_CSPL_LIMIT 0xff #define PCIE_RC_CONFIG_DCR_CPLS_SHIFT 26 #define PCIE_RC_CONFIG_LCS (PCIE_RC_CONFIG_BASE + 0xd0) -#define PCIE_RC_CONFIG_LCS_RETRAIN_LINK BIT(5) -#define PCIE_RC_CONFIG_LCS_CCC BIT(6) -#define PCIE_RC_CONFIG_LCS_LBMIE BIT(10) -#define PCIE_RC_CONFIG_LCS_LABIE BIT(11) -#define PCIE_RC_CONFIG_LCS_LBMS BIT(30) -#define PCIE_RC_CONFIG_LCS_LAMS BIT(31) #define PCIE_RC_CONFIG_L1_SUBSTATE_CTRL2 (PCIE_RC_CONFIG_BASE + 0x90c) #define PCIE_RC_CONFIG_THP_CAP (PCIE_RC_CONFIG_BASE + 0x274) #define PCIE_RC_CONFIG_THP_CAP_NEXT_MASK GENMASK(31, 20) @@ -232,7 +226,7 @@ static void rockchip_pcie_enable_bw_int(struct rockchip_pcie *rockchip) u32 status; status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); - status |= (PCIE_RC_CONFIG_LCS_LBMIE | PCIE_RC_CONFIG_LCS_LABIE); + status |= (PCI_EXP_LNKCTL_LBMIE | PCI_EXP_LNKCTL_LABIE); rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); } @@ -241,7 +235,7 @@ static void rockchip_pcie_clr_bw_int(struct rockchip_pcie *rockchip) u32 status; status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); - status |= (PCIE_RC_CONFIG_LCS_LBMS | PCIE_RC_CONFIG_LCS_LAMS); + status |= (PCI_EXP_LNKSTA_LBMS | PCI_EXP_LNKSTA_LABS) << 16; rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); } @@ -581,7 +575,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) /* Set RC's clock architecture as common clock */ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); - status |= PCIE_RC_CONFIG_LCS_CCC; + status |= PCI_EXP_LNKCTL_CCC; rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); /* Enable Gen1 training */ @@ -616,7 +610,7 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) * gen1 finished. */ status = rockchip_pcie_read(rockchip, PCIE_RC_CONFIG_LCS); - status |= PCIE_RC_CONFIG_LCS_RETRAIN_LINK; + status |= PCI_EXP_LNKCTL_RL; rockchip_pcie_write(rockchip, status, PCIE_RC_CONFIG_LCS); timeout = jiffies + msecs_to_jiffies(500); -- cgit v1.2.3 From 9e663d3f11ee34dfe92dcea98992151cae55e1ea Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 24 Nov 2016 09:54:20 +0800 Subject: PCI: rockchip: Split out rockchip_cfg_atu() Split out a new function, rockchip_cfg_atu(), in order to re-configure the ATU when missing these information after wakeup from S3. [bhelgaas: add "dev" temporary, return 0 when known] Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris --- drivers/pci/host/pcie-rockchip.c | 104 +++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 49 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 989642761877..89c219d935b5 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -208,6 +208,11 @@ struct rockchip_pcie { int link_gen; struct device *dev; struct irq_domain *irq_domain; + u32 io_size; + int offset; + phys_addr_t io_bus_addr; + u32 mem_size; + phys_addr_t mem_bus_addr; }; static u32 rockchip_pcie_read(struct rockchip_pcie *rockchip, u32 reg) @@ -1140,6 +1145,50 @@ static int rockchip_pcie_prog_ib_atu(struct rockchip_pcie *rockchip, return 0; } +static int rockchip_cfg_atu(struct rockchip_pcie *rockchip) +{ + struct device *dev = rockchip->dev; + int offset; + int err; + int reg_no; + + for (reg_no = 0; reg_no < (rockchip->mem_size >> 20); reg_no++) { + err = rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1, + AXI_WRAPPER_MEM_WRITE, + 20 - 1, + rockchip->mem_bus_addr + + (reg_no << 20), + 0); + if (err) { + dev_err(dev, "program RC mem outbound ATU failed\n"); + return err; + } + } + + err = rockchip_pcie_prog_ib_atu(rockchip, 2, 32 - 1, 0x0, 0); + if (err) { + dev_err(dev, "program RC mem inbound ATU failed\n"); + return err; + } + + offset = rockchip->mem_size >> 20; + for (reg_no = 0; reg_no < (rockchip->io_size >> 20); reg_no++) { + err = rockchip_pcie_prog_ob_atu(rockchip, + reg_no + 1 + offset, + AXI_WRAPPER_IO_WRITE, + 20 - 1, + rockchip->io_bus_addr + + (reg_no << 20), + 0); + if (err) { + dev_err(dev, "program RC io outbound ATU failed\n"); + return err; + } + } + + return 0; +} + static int rockchip_pcie_probe(struct platform_device *pdev) { struct rockchip_pcie *rockchip; @@ -1149,13 +1198,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) resource_size_t io_base; struct resource *mem; struct resource *io; - phys_addr_t io_bus_addr = 0; - u32 io_size; - phys_addr_t mem_bus_addr = 0; - u32 mem_size = 0; - int reg_no; int err; - int offset; LIST_HEAD(res); @@ -1222,14 +1265,13 @@ static int rockchip_pcie_probe(struct platform_device *pdev) goto err_vpcie; /* Get the I/O and memory ranges from DT */ - io_size = 0; resource_list_for_each_entry(win, &res) { switch (resource_type(win->res)) { case IORESOURCE_IO: io = win->res; io->name = "I/O"; - io_size = resource_size(io); - io_bus_addr = io->start - win->offset; + rockchip->io_size = resource_size(io); + rockchip->io_bus_addr = io->start - win->offset; err = pci_remap_iospace(io, io_base); if (err) { dev_warn(dev, "error %d: failed to map resource %pR\n", @@ -1240,8 +1282,8 @@ static int rockchip_pcie_probe(struct platform_device *pdev) case IORESOURCE_MEM: mem = win->res; mem->name = "MEM"; - mem_size = resource_size(mem); - mem_bus_addr = mem->start - win->offset; + rockchip->mem_size = resource_size(mem); + rockchip->mem_bus_addr = mem->start - win->offset; break; case IORESOURCE_BUS: rockchip->root_bus_nr = win->res->start; @@ -1251,45 +1293,9 @@ static int rockchip_pcie_probe(struct platform_device *pdev) } } - if (mem_size) { - for (reg_no = 0; reg_no < (mem_size >> 20); reg_no++) { - err = rockchip_pcie_prog_ob_atu(rockchip, reg_no + 1, - AXI_WRAPPER_MEM_WRITE, - 20 - 1, - mem_bus_addr + - (reg_no << 20), - 0); - if (err) { - dev_err(dev, "program RC mem outbound ATU failed\n"); - goto err_vpcie; - } - } - } - - err = rockchip_pcie_prog_ib_atu(rockchip, 2, 32 - 1, 0x0, 0); - if (err) { - dev_err(dev, "program RC mem inbound ATU failed\n"); + err = rockchip_cfg_atu(rockchip); + if (err) goto err_vpcie; - } - - offset = mem_size >> 20; - - if (io_size) { - for (reg_no = 0; reg_no < (io_size >> 20); reg_no++) { - err = rockchip_pcie_prog_ob_atu(rockchip, - reg_no + 1 + offset, - AXI_WRAPPER_IO_WRITE, - 20 - 1, - io_bus_addr + - (reg_no << 20), - 0); - if (err) { - dev_err(dev, "program RC io outbound ATU failed\n"); - goto err_vpcie; - } - } - } - bus = pci_scan_root_bus(&pdev->dev, 0, &rockchip_pcie_ops, rockchip, &res); if (!bus) { err = -ENOMEM; -- cgit v1.2.3 From 0722bdd2962a4a0f6d5e8973b0d274d147adacfb Mon Sep 17 00:00:00 2001 From: Shawn Lin Date: Thu, 24 Nov 2016 09:54:21 +0800 Subject: PCI: rockchip: Move the deassert of pm/aclk/pclk after phy_init() Move deassert of pm/aclk/pclk after phy_init() as we want to optimize the logic of reset control and reuse rockchip_pcie_init_port() later which should fully follow the cold boot procedure of ROM code. Signed-off-by: Shawn Lin Signed-off-by: Bjorn Helgaas Reviewed-by: Brian Norris --- drivers/pci/host/pcie-rockchip.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c index 89c219d935b5..460fd3cf4aa0 100644 --- a/drivers/pci/host/pcie-rockchip.c +++ b/drivers/pci/host/pcie-rockchip.c @@ -471,26 +471,6 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) return err; } - udelay(10); - - err = reset_control_deassert(rockchip->pm_rst); - if (err) { - dev_err(dev, "deassert pm_rst err %d\n", err); - return err; - } - - err = reset_control_deassert(rockchip->aclk_rst); - if (err) { - dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err); - return err; - } - - err = reset_control_deassert(rockchip->pclk_rst); - if (err) { - dev_err(dev, "deassert mgmt_sticky_rst err %d\n", err); - return err; - } - err = phy_init(rockchip->phy); if (err < 0) { dev_err(dev, "fail to init phy, err %d\n", err); @@ -521,6 +501,26 @@ static int rockchip_pcie_init_port(struct rockchip_pcie *rockchip) return err; } + udelay(10); + + err = reset_control_deassert(rockchip->pm_rst); + if (err) { + dev_err(dev, "deassert pm_rst err %d\n", err); + return err; + } + + err = reset_control_deassert(rockchip->aclk_rst); + if (err) { + dev_err(dev, "deassert aclk_rst err %d\n", err); + return err; + } + + err = reset_control_deassert(rockchip->pclk_rst); + if (err) { + dev_err(dev, "deassert pclk_rst err %d\n", err); + return err; + } + if (rockchip->link_gen == 2) rockchip_pcie_write(rockchip, PCIE_CLIENT_GEN_SEL_2, PCIE_CLIENT_CONFIG); -- cgit v1.2.3 From 7b99d94277ba49f401b7a5c1ad8a9084cc6c34a6 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 6 Dec 2016 16:51:29 +0100 Subject: PCI: rcar-gen2: Use gen2 fallback compatibility last Improve readability by listing fallback compatibility strings after the more-specific compatibility strings they provide a fallback for. This does not affect run-time behaviour as it is the order in the DTB that determines which compatibility string is used. Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pci-rcar-gen2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c index 1eeefa4df64c..85348590848b 100644 --- a/drivers/pci/host/pci-rcar-gen2.c +++ b/drivers/pci/host/pci-rcar-gen2.c @@ -430,10 +430,10 @@ static int rcar_pci_probe(struct platform_device *pdev) } static struct of_device_id rcar_pci_of_match[] = { - { .compatible = "renesas,pci-rcar-gen2", }, { .compatible = "renesas,pci-r8a7790", }, { .compatible = "renesas,pci-r8a7791", }, { .compatible = "renesas,pci-r8a7794", }, + { .compatible = "renesas,pci-rcar-gen2", }, { }, }; -- cgit v1.2.3 From d83a328ad185b1e487a82479f840435ae297bee1 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 6 Dec 2016 16:51:30 +0100 Subject: PCI: rcar: Use gen2 fallback compatibility last Improve readability by listing fallback compatibility strings after the more-specific compatibility strings they provide a fallback for. This does not affect run-time behaviour as it is the order in the DTB that determines which compatibility string is used. Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas --- drivers/pci/host/pcie-rcar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 62700d1896f4..85971bc276c6 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -1071,12 +1071,12 @@ static int rcar_pcie_parse_map_dma_ranges(struct rcar_pcie *pcie, static const struct of_device_id rcar_pcie_of_match[] = { { .compatible = "renesas,pcie-r8a7779", .data = rcar_pcie_hw_init_h1 }, - { .compatible = "renesas,pcie-rcar-gen2", - .data = rcar_pcie_hw_init_gen2 }, { .compatible = "renesas,pcie-r8a7790", .data = rcar_pcie_hw_init_gen2 }, { .compatible = "renesas,pcie-r8a7791", .data = rcar_pcie_hw_init_gen2 }, + { .compatible = "renesas,pcie-rcar-gen2", + .data = rcar_pcie_hw_init_gen2 }, { .compatible = "renesas,pcie-r8a7795", .data = rcar_pcie_hw_init }, {}, }; -- cgit v1.2.3 From 49da21108f773b50b01b9fd0b6ca97b91b6ff216 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 6 Dec 2016 16:51:31 +0100 Subject: PCI: rcar: Add gen3 fallback compatibility string for pcie-rcar Add fallback compatibility string for the R-Car Gen 3 family. This is in keeping with the both the existing fallback compatibility string for the R-Car Gen 2 family and the fallback scheme being adopted wherever appropriate for drivers for Renesas SoCs. Signed-off-by: Simon Horman Signed-off-by: Bjorn Helgaas --- Documentation/devicetree/bindings/pci/rcar-pci.txt | 1 + drivers/pci/host/pcie-rcar.c | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/pci/rcar-pci.txt b/Documentation/devicetree/bindings/pci/rcar-pci.txt index 6cf99690eef9..eee518db90b9 100644 --- a/Documentation/devicetree/bindings/pci/rcar-pci.txt +++ b/Documentation/devicetree/bindings/pci/rcar-pci.txt @@ -7,6 +7,7 @@ compatible: "renesas,pcie-r8a7779" for the R8A7779 SoC; "renesas,pcie-r8a7793" for the R8A7793 SoC; "renesas,pcie-r8a7795" for the R8A7795 SoC; "renesas,pcie-rcar-gen2" for a generic R-Car Gen2 compatible device. + "renesas,pcie-rcar-gen3" for a generic R-Car Gen3 compatible device. When compatible with the generic version, nodes must list the SoC-specific version corresponding to the platform first diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c index 85971bc276c6..aca85be101f8 100644 --- a/drivers/pci/host/pcie-rcar.c +++ b/drivers/pci/host/pcie-rcar.c @@ -1078,6 +1078,7 @@ static const struct of_device_id rcar_pcie_of_match[] = { { .compatible = "renesas,pcie-rcar-gen2", .data = rcar_pcie_hw_init_gen2 }, { .compatible = "renesas,pcie-r8a7795", .data = rcar_pcie_hw_init }, + { .compatible = "renesas,pcie-rcar-gen3", .data = rcar_pcie_hw_init }, {}, }; -- cgit v1.2.3 From 385895fef6b5f4723e33d0e58251c45bc708132d Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Sat, 19 Nov 2016 00:32:45 -0800 Subject: PCI: pciehp: Prioritize data-link event over presence detect If Slot Status indicates changes in both Data Link Layer Status and Presence Detect, prioritize the Link status change. When both events are observed, pciehp currently relies on the Slot Status Presence Detect State (PDS) to agree with the Link Status Data Link Layer Active status. The Presence Detect State, however, may be set to 1 through out-of-band presence detect even if the link is down, which creates conflicting events. Since the Link Status accurately reflects the reachability of the downstream bus, the Link Status event should take precedence over a Presence Detect event. Skip checking the PDC status if we handled a link event in the same handler. Signed-off-by: Ashok Raj Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/hotplug/pciehp_hpc.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_hpc.c b/drivers/pci/hotplug/pciehp_hpc.c index b57fc6d6e28a..026830a138ae 100644 --- a/drivers/pci/hotplug/pciehp_hpc.c +++ b/drivers/pci/hotplug/pciehp_hpc.c @@ -620,8 +620,18 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id) pciehp_queue_interrupt_event(slot, INT_BUTTON_PRESS); } - /* Check Presence Detect Changed */ - if (events & PCI_EXP_SLTSTA_PDC) { + /* + * Check Link Status Changed at higher precedence than Presence + * Detect Changed. The PDS value may be set to "card present" from + * out-of-band detection, which may be in conflict with a Link Down + * and cause the wrong event to queue. + */ + if (events & PCI_EXP_SLTSTA_DLLSC) { + ctrl_info(ctrl, "Slot(%s): Link %s\n", slot_name(slot), + link ? "Up" : "Down"); + pciehp_queue_interrupt_event(slot, link ? INT_LINK_UP : + INT_LINK_DOWN); + } else if (events & PCI_EXP_SLTSTA_PDC) { present = !!(status & PCI_EXP_SLTSTA_PDS); ctrl_info(ctrl, "Slot(%s): Card %spresent\n", slot_name(slot), present ? "" : "not "); @@ -636,13 +646,6 @@ static irqreturn_t pciehp_isr(int irq, void *dev_id) pciehp_queue_interrupt_event(slot, INT_POWER_FAULT); } - if (events & PCI_EXP_SLTSTA_DLLSC) { - ctrl_info(ctrl, "Slot(%s): Link %s\n", slot_name(slot), - link ? "Up" : "Down"); - pciehp_queue_interrupt_event(slot, link ? INT_LINK_UP : - INT_LINK_DOWN); - } - return IRQ_HANDLED; } -- cgit v1.2.3 From 5d244f7effafeaa5272ca5daa37d8b7bb17967a8 Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Wed, 7 Dec 2016 17:20:06 -0800 Subject: Input: synaptics-rmi4 - fix debug for sensor clip The debug would only ever output zero for the clip information. Signed-off-by: Nick Dyer Reviewed-by: Andrew Duggan Tested-by: Chris Healy Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/rmi_f12.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/input/rmi4/rmi_f12.c b/drivers/input/rmi4/rmi_f12.c index 8c5360c25266..07aff4356fe0 100644 --- a/drivers/input/rmi4/rmi_f12.c +++ b/drivers/input/rmi4/rmi_f12.c @@ -71,10 +71,6 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) u8 buf[15]; int pitch_x = 0; int pitch_y = 0; - int clip_x_low = 0; - int clip_x_high = 0; - int clip_y_low = 0; - int clip_y_high = 0; int rx_receivers = 0; int tx_receivers = 0; int sensor_flags = 0; @@ -127,7 +123,9 @@ static int rmi_f12_read_sensor_tuning(struct f12_data *f12) } rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: x low: %d x high: %d y low: %d y high: %d\n", - __func__, clip_x_low, clip_x_high, clip_y_low, clip_y_high); + __func__, + sensor->axis_align.clip_x_low, sensor->axis_align.clip_x_high, + sensor->axis_align.clip_y_low, sensor->axis_align.clip_y_high); if (rmi_register_desc_has_subpacket(item, 3)) { rx_receivers = buf[offset]; -- cgit v1.2.3 From 951a086437b7c29a9f352e0ee6272fa1d90d783e Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 7 Dec 2016 17:22:36 -0800 Subject: Input: lpc32xx-keys - fix invalid error handling of a requested irq Semantics of NR_IRQS is different on machines with SPARSE_IRQ option disabled or enabled, in the latter case IRQs are allocated starting at least from the value specified by NR_IRQS and going upwards, so the check of (irq >= NR_IRQ) to decide about an error code returned by platform_get_irq() is completely invalid, don't attempt to overrule irq subsystem in the driver. The change fixes lpc32xx_keys driver initialization on boot: lpc32xx_keys 40050000.key: failed to get platform irq lpc32xx_keys: probe of 40050000.key failed with error -22 Signed-off-by: Vladimir Zapolskiy Acked-by: Sylvain Lemieux Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/lpc32xx-keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/keyboard/lpc32xx-keys.c b/drivers/input/keyboard/lpc32xx-keys.c index 265d641c40e2..632523d4f5dc 100644 --- a/drivers/input/keyboard/lpc32xx-keys.c +++ b/drivers/input/keyboard/lpc32xx-keys.c @@ -182,7 +182,7 @@ static int lpc32xx_kscan_probe(struct platform_device *pdev) } irq = platform_get_irq(pdev, 0); - if (irq < 0 || irq >= NR_IRQS) { + if (irq < 0) { dev_err(&pdev->dev, "failed to get platform irq\n"); return -EINVAL; } -- cgit v1.2.3 From 15f7e3c21b76598bc6e5816d2577ce843b2b963f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 17 Sep 2016 00:41:37 +0000 Subject: iw_cxgb4: Fix error return code in c4iw_rdev_open() Fix to return error code -ENOMEM from the __get_free_page() error handling case instead of 0, as done elsewhere in this function. Fixes: 05eb23893c2c ("cxgb4/iw_cxgb4: Doorbell Drop Avoidance Bug Fixes") Signed-off-by: Wei Yongjun Acked-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c index 93e3d270a98a..b99dc9e0ffb2 100644 --- a/drivers/infiniband/hw/cxgb4/device.c +++ b/drivers/infiniband/hw/cxgb4/device.c @@ -828,8 +828,10 @@ static int c4iw_rdev_open(struct c4iw_rdev *rdev) } rdev->status_page = (struct t4_dev_status_page *) __get_free_page(GFP_KERNEL); - if (!rdev->status_page) + if (!rdev->status_page) { + err = -ENOMEM; goto destroy_ocqp_pool; + } rdev->status_page->qp_start = rdev->lldi.vr->qp.start; rdev->status_page->qp_size = rdev->lldi.vr->qp.size; rdev->status_page->cq_start = rdev->lldi.vr->cq.start; -- cgit v1.2.3 From 12154c87374c90b3b6bc169e1162aa4a27e91a63 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 7 Dec 2016 09:36:22 +0530 Subject: dmaengine: at_hdmac: move to dma_pool_zalloc Replace dma_pool_alloc & memset with dma_pool_zalloc. Signed-off-by: Vinod Koul --- drivers/dma/at_hdmac.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c index a4c8f80db29d..1baf3404a365 100644 --- a/drivers/dma/at_hdmac.c +++ b/drivers/dma/at_hdmac.c @@ -111,9 +111,8 @@ static struct at_desc *atc_alloc_descriptor(struct dma_chan *chan, struct at_dma *atdma = to_at_dma(chan->device); dma_addr_t phys; - desc = dma_pool_alloc(atdma->dma_desc_pool, gfp_flags, &phys); + desc = dma_pool_zalloc(atdma->dma_desc_pool, gfp_flags, &phys); if (desc) { - memset(desc, 0, sizeof(struct at_desc)); INIT_LIST_HEAD(&desc->tx_list); dma_async_tx_descriptor_init(&desc->txd, chan); /* txd.flags will be overwritten in prep functions */ -- cgit v1.2.3 From 646b3b569e9ac54436b93bd91e0c0e111178bec0 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Wed, 7 Dec 2016 09:36:22 +0530 Subject: dmaengine: k3dma: move to dma_pool_zalloc Replace dma_pool_alloc & memset with dma_pool_zalloc. Acked-by: Zhangfei Gao Signed-off-by: Vinod Koul --- drivers/dma/k3dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c index aabcb7934b05..01e25c68dd5a 100644 --- a/drivers/dma/k3dma.c +++ b/drivers/dma/k3dma.c @@ -458,13 +458,12 @@ static struct k3_dma_desc_sw *k3_dma_alloc_desc_resource(int num, if (!ds) return NULL; - ds->desc_hw = dma_pool_alloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli); + ds->desc_hw = dma_pool_zalloc(d->pool, GFP_NOWAIT, &ds->desc_hw_lli); if (!ds->desc_hw) { dev_dbg(chan->device->dev, "vch %p: dma alloc fail\n", &c->vc); kfree(ds); return NULL; } - memset(ds->desc_hw, 0, sizeof(struct k3_desc_hw) * num); ds->desc_num = num; return ds; } -- cgit v1.2.3 From d07c9e1e212c9687f9198bfeba582e86cae3f6f9 Mon Sep 17 00:00:00 2001 From: Vladimir Murzin Date: Wed, 7 Dec 2016 13:17:40 +0000 Subject: dmaengine: pl330: do not generate unaligned access When PL330 is used with !MMU the following fault is seen: Unhandled fault: alignment exception (0x801) at 0x8f26a002 Internal error: : 801 [#1] ARM Modules linked in: CPU: 0 PID: 640 Comm: dma0chan0-copy0 Not tainted 4.8.0-6a82063-clean+ #1600 Hardware name: ARM-Versatile Express task: 8f1baa80 task.stack: 8e6fe000 PC is at _setup_req+0x4c/0x350 LR is at 0x8f2cbc00 pc : [<801ea538>] lr : [<8f2cbc00>] psr: 60000093 sp : 8e6ffdc0 ip : 00000000 fp : 00000000 r10: 00000000 r9 : 8f2cba10 r8 : 8f2cbc00 r7 : 80000013 r6 : 8f21a050 r5 : 8f21a000 r4 : 8f2ac800 r3 : 8e6ffe18 r2 : 00944251 r1 : ffffffbc r0 : 8f26a000 Flags: nZCv IRQs off FIQs on Mode SVC_32 ISA ARM Segment none Control: 00c5387c Process dma0chan0-copy0 (pid: 640, stack limit = 0x8e6fe210) Stack: (0x8e6ffdc0 to 0x8e700000) fdc0: 00000001 60000093 00000000 8f2cba10 8f26a000 00000004 8f0ae000 8f2cbc00 fde0: 8f0ae000 8f2ac800 8f21a000 8f21a050 80000013 8f2cbc00 8f2cba10 00000000 fe00: 60000093 801ebca0 8e6ffe18 000013ff 40000093 00000000 00944251 8f2ac800 fe20: a0000013 8f2b1320 00001986 00000000 00000001 000013ff 8f1e4f00 8f2cba10 fe40: 8e6fff6c 801e9044 00000003 00000000 fef98c80 002faf07 8e6ffe7c 00000000 fe60: 00000002 00000000 00001986 8f1f158d 8f1e4f00 80568de4 00000002 00000000 fe80: 00001986 8f1f53ff 40000001 80580500 8f1f158d 8001e00c 00000000 cfdfdfdf fea0: fdae2a25 00000001 00000004 8e6fe000 00000008 00000010 00000000 00000005 fec0: 8f2b1330 8f2b1334 8e6ffe80 8e6ffe8c 00001986 00000000 8f21a014 00000001 fee0: 8e6ffe60 8e6ffe78 00000002 00000000 000013ff 00000001 80568de4 8f1e8018 ff00: 0000158d 8055ec30 00000001 803f6b00 00001986 8f2cba10 fdae2a25 00000001 ff20: 8f1baca8 8e6fff24 8e6fff24 00000000 8e6fff24 ac6f3037 00000000 00000000 ff40: 00000000 8e6fe000 8f1e4f40 00000000 8f1e4f40 8f1e4f00 801e84ec 00000000 ff60: 00000000 00000000 00000000 80031714 dfdfdfcf 00000000 dfdfdfcf 8f1e4f00 ff80: 00000000 8e6fff84 8e6fff84 00000000 8e6fff90 8e6fff90 8e6fffac 8f1e4f40 ffa0: 80031640 00000000 00000000 8000f548 00000000 00000000 00000000 00000000 ffc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ffe0: 00000000 00000000 00000000 00000000 00000013 00000000 dfdfdfcf cfdfdfdf [<801ea538>] (_setup_req) from [<801ebca0>] (pl330_tasklet+0x41c/0x490) [<801ebca0>] (pl330_tasklet) from [<801e9044>] (dmatest_func+0xb58/0x149c) [<801e9044>] (dmatest_func) from [<80031714>] (kthread+0xd4/0xec) [<80031714>] (kthread) from [<8000f548>] (ret_from_fork+0x14/0x2c) Code: e3a03001 e3e01043 e5c03001 e59d3048 (e5802002) This happens because _emit_{ADDH,MOV,GO) accessing to unaligned data while writing to buffer. Fix it with writing to buffer byte by byte. Reviewed-by: Robin Murphy Tested-by: Robin Murphy Signed-off-by: Vladimir Murzin Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 458a712a9da1..2f3e063c406f 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -570,7 +570,8 @@ static inline u32 _emit_ADDH(unsigned dry_run, u8 buf[], buf[0] = CMD_DMAADDH; buf[0] |= (da << 1); - *((__le16 *)&buf[1]) = cpu_to_le16(val); + buf[1] = val; + buf[2] = val >> 8; PL330_DBGCMD_DUMP(SZ_DMAADDH, "\tDMAADDH %s %u\n", da == 1 ? "DA" : "SA", val); @@ -724,7 +725,10 @@ static inline u32 _emit_MOV(unsigned dry_run, u8 buf[], buf[0] = CMD_DMAMOV; buf[1] = dst; - *((__le32 *)&buf[2]) = cpu_to_le32(val); + buf[2] = val; + buf[3] = val >> 8; + buf[4] = val >> 16; + buf[5] = val >> 24; PL330_DBGCMD_DUMP(SZ_DMAMOV, "\tDMAMOV %s 0x%x\n", dst == SAR ? "SAR" : (dst == DAR ? "DAR" : "CCR"), val); @@ -899,10 +903,11 @@ static inline u32 _emit_GO(unsigned dry_run, u8 buf[], buf[0] = CMD_DMAGO; buf[0] |= (ns << 1); - buf[1] = chan & 0x7; - - *((__le32 *)&buf[2]) = cpu_to_le32(addr); + buf[2] = addr; + buf[3] = addr >> 8; + buf[4] = addr >> 16; + buf[5] = addr >> 24; return SZ_DMAGO; } -- cgit v1.2.3 From c4ae2adedb38240be5a1a16588406980b948a3e7 Mon Sep 17 00:00:00 2001 From: Ashok Raj Date: Sat, 19 Nov 2016 00:32:46 -0800 Subject: PCI: pciehp: Leave power indicator on when enabling already-enabled slot If an error occurs when enabling a slot, pciehp_power_thread() turns off the power indicator. But if the only error is that the slot was already enabled, we should leave the power indicator on. Return success if called to enable an already-enabled slot. This is in the same spirit of the special handling for EEXISTS when pciehp_configure_device() determines the slot devices already exist. Signed-off-by: Ashok Raj Signed-off-by: Bjorn Helgaas Reviewed-by: Keith Busch --- drivers/pci/hotplug/pciehp_ctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c index efe69e879455..ec0b4c11ccd9 100644 --- a/drivers/pci/hotplug/pciehp_ctrl.c +++ b/drivers/pci/hotplug/pciehp_ctrl.c @@ -410,7 +410,7 @@ int pciehp_enable_slot(struct slot *p_slot) if (getstatus) { ctrl_info(ctrl, "Slot(%s): Already enabled\n", slot_name(p_slot)); - return -EINVAL; + return 0; } } -- cgit v1.2.3 From ffbd796821472c6571b09962cdbd13cd2815e2c1 Mon Sep 17 00:00:00 2001 From: Andy Gospodarek Date: Thu, 1 Dec 2016 15:34:52 -0500 Subject: PCI: iproc: Skip check for legacy IRQ on PAXC buses PAXC and PAXCv2 buses do not support legacy IRQs so there is no reason to even try and map them. Without a change like this, one cannot create VFs on Nitro ports since legacy interrupts are checked as part of the PCI device creation process. Testing on PAXC hardware showed that VFs are properly created with only the change to not set pcie->map_irq, but just to be safe the change in iproc_pcie_setup() will ensure that pdev_fixup_irq() will not panic. Signed-off-by: Andy Gospodarek Signed-off-by: Bjorn Helgaas Acked-by: Ray Jui --- drivers/pci/host/pcie-iproc-platform.c | 9 ++++++++- drivers/pci/host/pcie-iproc.c | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/host/pcie-iproc-platform.c b/drivers/pci/host/pcie-iproc-platform.c index fd3ed9bccaff..22d814a78a78 100644 --- a/drivers/pci/host/pcie-iproc-platform.c +++ b/drivers/pci/host/pcie-iproc-platform.c @@ -108,7 +108,14 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev) return ret; } - pcie->map_irq = of_irq_parse_and_map_pci; + /* PAXC doesn't support legacy IRQs, skip mapping */ + switch (pcie->type) { + case IPROC_PCIE_PAXC: + case IPROC_PCIE_PAXC_V2: + break; + default: + pcie->map_irq = of_irq_parse_and_map_pci; + } ret = iproc_pcie_setup(pcie, &res); if (ret) diff --git a/drivers/pci/host/pcie-iproc.c b/drivers/pci/host/pcie-iproc.c index cd513342b913..3ebc025499b9 100644 --- a/drivers/pci/host/pcie-iproc.c +++ b/drivers/pci/host/pcie-iproc.c @@ -1274,7 +1274,10 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res) pci_scan_child_bus(bus); pci_assign_unassigned_bus_resources(bus); - pci_fixup_irqs(pci_common_swizzle, pcie->map_irq); + + if (pcie->map_irq) + pci_fixup_irqs(pci_common_swizzle, pcie->map_irq); + pci_bus_add_devices(bus); return 0; -- cgit v1.2.3 From e53f9a28bee35932a0ae4d2ec2784f55491ec6d3 Mon Sep 17 00:00:00 2001 From: David Daney Date: Thu, 17 Nov 2016 14:25:01 -0800 Subject: PCI/ASPM: Don't retrain link if ASPM not possible Some (defective) PCIe devices are not able to reliably do link retraining. Check to see if ASPM is possible between link partners before configuring common clocking, and doing the resulting link retraining. If ASPM is not possible, there is no reason to risk losing access to a device due to an unnecessary link retraining. Signed-off-by: David Daney Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aspm.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c index 3b14d9e85dee..17ac1dce3286 100644 --- a/drivers/pci/pcie/aspm.c +++ b/drivers/pci/pcie/aspm.c @@ -351,12 +351,26 @@ static void pcie_aspm_cap_init(struct pcie_link_state *link, int blacklist) return; } + /* Get upstream/downstream components' register state */ + pcie_get_aspm_reg(parent, &upreg); + child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); + pcie_get_aspm_reg(child, &dwreg); + + /* + * If ASPM not supported, don't mess with the clocks and link, + * bail out now. + */ + if (!(upreg.support & dwreg.support)) + return; + /* Configure common clock before checking latencies */ pcie_aspm_configure_common_clock(link); - /* Get upstream/downstream components' register state */ + /* + * Re-read upstream/downstream components' register state + * after clock configuration + */ pcie_get_aspm_reg(parent, &upreg); - child = list_entry(linkbus->devices.next, struct pci_dev, bus_list); pcie_get_aspm_reg(child, &dwreg); /* -- cgit v1.2.3 From 89fa9b5cb08c9d8ad709415b88395be463eceeee Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 5 Dec 2016 01:07:19 -0500 Subject: scsi: g_NCR5380: Check for chip presence before calling NCR5380_init() Write and read back mode register to check that a chip is really there. If no card is present, reads result in 0xff. Signed-off-by: Ondrej Zary Signed-off-by: Finn Thain Tested-by: Ondrej Zary Signed-off-by: Martin K. Petersen --- drivers/scsi/g_NCR5380.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index de5147a8c959..76e37455480e 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -248,6 +248,13 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, } } + /* Check for vacant slot */ + NCR5380_write(MODE_REG, 0); + if (NCR5380_read(MODE_REG) != 0) { + ret = -ENODEV; + goto out_unregister; + } + ret = NCR5380_init(instance, flags | FLAG_LATE_DMA_SETUP); if (ret) goto out_unregister; -- cgit v1.2.3 From 906e4a3c7e03701008d343daec8952d6cf49f82b Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Mon, 5 Dec 2016 01:07:20 -0500 Subject: scsi: g_NCR5380: Use probe_irq_*() for IRQ probing Use standard probe_irq_on() and probe_irq_off() functions instead of own implementation. This prevents warning messages like this in the kernel log: genirq: Flags mismatch irq 1. 00000000 (NCR-probe) vs. 00000080 (i8042) Move the IRQ trigger code from NCR5380 to g_NCR5380 where it is used. Also clear interrupt flag before and after the probe. Signed-off-by: Ondrej Zary Signed-off-by: Finn Thain Tested-by: Ondrej Zary Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 77 +----------------------------------------------- drivers/scsi/NCR5380.h | 11 ------- drivers/scsi/g_NCR5380.c | 52 +++++++++++++++++++++++++++++++- drivers/scsi/g_NCR5380.h | 2 ++ 4 files changed, 54 insertions(+), 88 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index d849ffa378b1..4f5ca794bb71 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -97,9 +97,6 @@ * and macros and include this file in your driver. * * These macros control options : - * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be - * defined. - * * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically * for commands that return with a CHECK CONDITION status. * @@ -127,9 +124,7 @@ * NCR5380_dma_residual - residual byte count * * The generic driver is initialized by calling NCR5380_init(instance), - * after setting the appropriate host specific fields and ID. If the - * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance, - * possible) function may be used. + * after setting the appropriate host specific fields and ID. */ #ifndef NCR5380_io_delay @@ -351,76 +346,6 @@ static void NCR5380_print_phase(struct Scsi_Host *instance) } #endif - -static int probe_irq; - -/** - * probe_intr - helper for IRQ autoprobe - * @irq: interrupt number - * @dev_id: unused - * @regs: unused - * - * Set a flag to indicate the IRQ in question was received. This is - * used by the IRQ probe code. - */ - -static irqreturn_t probe_intr(int irq, void *dev_id) -{ - probe_irq = irq; - return IRQ_HANDLED; -} - -/** - * NCR5380_probe_irq - find the IRQ of an NCR5380 - * @instance: NCR5380 controller - * @possible: bitmask of ISA IRQ lines - * - * Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ - * and then looking to see what interrupt actually turned up. - */ - -static int __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance, - int possible) -{ - struct NCR5380_hostdata *hostdata = shost_priv(instance); - unsigned long timeout; - int trying_irqs, i, mask; - - for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1) - if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0)) - trying_irqs |= mask; - - timeout = jiffies + msecs_to_jiffies(250); - probe_irq = NO_IRQ; - - /* - * A interrupt is triggered whenever BSY = false, SEL = true - * and a bit set in the SELECT_ENABLE_REG is asserted on the - * SCSI bus. - * - * Note that the bus is only driven when the phase control signals - * (I/O, C/D, and MSG) match those in the TCR, so we must reset that - * to zero. - */ - - NCR5380_write(TARGET_COMMAND_REG, 0); - NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); - NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); - - while (probe_irq == NO_IRQ && time_before(jiffies, timeout)) - schedule_timeout_uninterruptible(1); - - NCR5380_write(SELECT_ENABLE_REG, 0); - NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - - for (i = 1, mask = 2; i < 16; ++i, mask <<= 1) - if (trying_irqs & mask) - free_irq(i, NULL); - - return probe_irq; -} - /** * NCR58380_info - report driver and host information * @instance: relevant scsi host instance diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index 3c6ce5434449..51a3567a6fb2 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -199,16 +199,6 @@ #define PHASE_SR_TO_TCR(phase) ((phase) >> 2) -/* - * These are "special" values for the irq and dma_channel fields of the - * Scsi_Host structure - */ - -#define DMA_NONE 255 -#define IRQ_AUTO 254 -#define DMA_AUTO 254 -#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */ - #ifndef NO_IRQ #define NO_IRQ 0 #endif @@ -290,7 +280,6 @@ static void NCR5380_print(struct Scsi_Host *instance); #define NCR5380_dprint_phase(flg, arg) do {} while (0) #endif -static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible); static int NCR5380_init(struct Scsi_Host *instance, int flags); static int NCR5380_maybe_reset_bus(struct Scsi_Host *); static void NCR5380_exit(struct Scsi_Host *instance); diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 76e37455480e..6d245a7b9363 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -67,6 +67,56 @@ MODULE_PARM_DESC(card, "card type (0=NCR5380, 1=NCR53C400, 2=NCR53C400A, 3=DTC31 MODULE_ALIAS("g_NCR5380_mmio"); MODULE_LICENSE("GPL"); +static void g_NCR5380_trigger_irq(struct Scsi_Host *instance) +{ + struct NCR5380_hostdata *hostdata = shost_priv(instance); + + /* + * An interrupt is triggered whenever BSY = false, SEL = true + * and a bit set in the SELECT_ENABLE_REG is asserted on the + * SCSI bus. + * + * Note that the bus is only driven when the phase control signals + * (I/O, C/D, and MSG) match those in the TCR. + */ + NCR5380_write(TARGET_COMMAND_REG, + PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK)); + NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); + NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask); + NCR5380_write(INITIATOR_COMMAND_REG, + ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL); + + msleep(1); + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(SELECT_ENABLE_REG, 0); + NCR5380_write(TARGET_COMMAND_REG, 0); +} + +/** + * g_NCR5380_probe_irq - find the IRQ of a NCR5380 or equivalent + * @instance: SCSI host instance + * + * Autoprobe for the IRQ line used by the card by triggering an IRQ + * and then looking to see what interrupt actually turned up. + */ + +static int g_NCR5380_probe_irq(struct Scsi_Host *instance) +{ + struct NCR5380_hostdata *hostdata = shost_priv(instance); + int irq_mask, irq; + + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + irq_mask = probe_irq_on(); + g_NCR5380_trigger_irq(instance); + irq = probe_irq_off(irq_mask); + NCR5380_read(RESET_PARITY_INTERRUPT_REG); + + if (irq <= 0) + return NO_IRQ; + return irq; +} + /* * Configure I/O address of 53C400A or DTC436 by writing magic numbers * to ports 0x779 and 0x379. @@ -272,7 +322,7 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, if (irq != IRQ_AUTO) instance->irq = irq; else - instance->irq = NCR5380_probe_irq(instance, 0xffff); + instance->irq = g_NCR5380_probe_irq(instance); /* Compatibility with documented NCR5380 kernel parameters */ if (instance->irq == 255) diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h index 3ce5b65ccb00..81b22d989648 100644 --- a/drivers/scsi/g_NCR5380.h +++ b/drivers/scsi/g_NCR5380.h @@ -51,4 +51,6 @@ #define BOARD_DTC3181E 3 #define BOARD_HP_C2502 4 +#define IRQ_AUTO 254 + #endif /* GENERIC_NCR5380_H */ -- cgit v1.2.3 From 145c3ae4c1933d0dceb11d19a36de3458d1872cb Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 5 Dec 2016 01:07:20 -0500 Subject: scsi: g_NCR5380: Fix automatic IRQ on HP C2502 cards When IRQ_AUTO is used, the interrupt for HP C2502 cards gets disabled. Fix this by programming the card for a suitable free irq. The code for the free irq search comes from ALSA. Also allow IRQ 9 to work (it aliases to IRQ 2 on the card), as per Ondrej Zary's patch. Suggested-by: Ondrej Zary Signed-off-by: Finn Thain Tested-by: Ondrej Zary Signed-off-by: Martin K. Petersen --- drivers/scsi/g_NCR5380.c | 70 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 6d245a7b9363..58a0b826eb51 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -131,14 +131,33 @@ static void magic_configure(int idx, u8 irq, u8 magic[]) outb(magic[3], 0x379); outb(magic[4], 0x379); - /* allowed IRQs for HP C2502 */ - if (irq != 2 && irq != 3 && irq != 4 && irq != 5 && irq != 7) - irq = 0; + if (irq == 9) + irq = 2; + if (idx >= 0 && idx <= 7) cfg = 0x80 | idx | (irq << 4); outb(cfg, 0x379); } +static irqreturn_t legacy_empty_irq_handler(int irq, void *dev_id) +{ + return IRQ_HANDLED; +} + +static int legacy_find_free_irq(int *irq_table) +{ + while (*irq_table != -1) { + if (!request_irq(*irq_table, legacy_empty_irq_handler, + IRQF_PROBE_SHARED, "Test IRQ", + (void *)irq_table)) { + free_irq(*irq_table, (void *) irq_table); + return *irq_table; + } + irq_table++; + } + return -1; +} + static unsigned int ncr_53c400a_ports[] = { 0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0 }; @@ -151,6 +170,9 @@ static u8 ncr_53c400a_magic[] = { /* 53C400A & DTC436 */ static u8 hp_c2502_magic[] = { /* HP C2502 */ 0x0f, 0x22, 0xf0, 0x20, 0x80 }; +static int hp_c2502_irqs[] = { + 9, 5, 7, 3, 4, -1 +}; static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, struct device *pdev, int base, int irq, int board) @@ -319,19 +341,41 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, NCR5380_maybe_reset_bus(instance); - if (irq != IRQ_AUTO) - instance->irq = irq; - else - instance->irq = g_NCR5380_probe_irq(instance); - /* Compatibility with documented NCR5380 kernel parameters */ - if (instance->irq == 255) - instance->irq = NO_IRQ; + if (irq == 255 || irq == 0) + irq = NO_IRQ; + + if (board == BOARD_HP_C2502) { + int *irq_table = hp_c2502_irqs; + int board_irq = -1; + + switch (irq) { + case NO_IRQ: + board_irq = 0; + break; + case IRQ_AUTO: + board_irq = legacy_find_free_irq(irq_table); + break; + default: + while (*irq_table != -1) + if (*irq_table++ == irq) + board_irq = irq; + } + + if (board_irq <= 0) { + board_irq = 0; + irq = NO_IRQ; + } + + magic_configure(port_idx, board_irq, magic); + } + + if (irq == IRQ_AUTO) + instance->irq = g_NCR5380_probe_irq(instance); + else + instance->irq = irq; if (instance->irq != NO_IRQ) { - /* set IRQ for HP C2502 */ - if (board == BOARD_HP_C2502) - magic_configure(port_idx, instance->irq, magic); if (request_irq(instance->irq, generic_NCR5380_intr, 0, "NCR5380", instance)) { printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); -- cgit v1.2.3 From 70439e93345ec5605f1cb3fa7a8f70bc968e6cb2 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Mon, 5 Dec 2016 01:07:20 -0500 Subject: scsi: g_NCR5380: Autoprobe board IRQ by default Automatically probe the board irq when no irq parameter is provided, to simulate PnP. The old default behaviour was to disable the irq. Update driver documentation accordingly and add some printk messages to make this behaviour visible. Signed-off-by: Finn Thain Tested-by: Ondrej Zary Signed-off-by: Martin K. Petersen --- Documentation/scsi/g_NCR5380.txt | 46 ++++++++++++++++++++-------------------- drivers/scsi/g_NCR5380.c | 30 +++++++++++++++----------- 2 files changed, 41 insertions(+), 35 deletions(-) (limited to 'drivers') diff --git a/Documentation/scsi/g_NCR5380.txt b/Documentation/scsi/g_NCR5380.txt index e2c187947e58..37b1967a00a9 100644 --- a/Documentation/scsi/g_NCR5380.txt +++ b/Documentation/scsi/g_NCR5380.txt @@ -6,17 +6,15 @@ NCR53c400 extensions (c) 1994,1995,1996 Kevin Lentin This file documents the NCR53c400 extensions by Kevin Lentin and some enhancements to the NCR5380 core. -This driver supports both NCR5380 and NCR53c400 cards in port or memory -mapped modes. Currently this driver can only support one of those mapping -modes at a time but it does support both of these chips at the same time. -The next release of this driver will support port & memory mapped cards at -the same time. It should be able to handle multiple different cards in the -same machine. +This driver supports NCR5380 and NCR53c400 and compatible cards in port or +memory mapped modes. -The drivers/scsi/Makefile has an override in it for the most common -NCR53c400 card, the Trantor T130B in its default configuration: - Port: 0x350 - IRQ : 5 +Use of an interrupt is recommended, if supported by the board, as this will +allow targets to disconnect and thereby improve SCSI bus utilization. + +If the irq parameter is 254 or is omitted entirely, the driver will probe +for the correct IRQ line automatically. If the irq parameter is 0 or 255 +then no IRQ will be used. The NCR53c400 does not support DMA but it does have Pseudo-DMA which is supported by the driver. @@ -47,22 +45,24 @@ These old-style parameters can support only one card: dtc_3181e=1 to set up for a Domex Technology Corp 3181E board hp_c2502=1 to set up for a Hewlett Packard C2502 board -e.g. -OLD: modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1 -NEW: modprobe g_NCR5380 irq=5 base=0x350 card=0 - for a port mapped NCR5380 board or - -OLD: modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 -NEW: modprobe g_NCR5380 irq=255 base=0xc8000 card=1 - for a memory mapped NCR53C400 board with interrupts disabled or +E.g. Trantor T130B in its default configuration: +modprobe g_NCR5380 irq=5 base=0x350 card=1 +or alternatively, using the old syntax, +modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_53c400=1 -NEW: modprobe g_NCR5380 irq=0,7 base=0x240,0x300 card=3,4 - for two cards: DTC3181 (in non-PnP mode) at 0x240 with no IRQ - and HP C2502 at 0x300 with IRQ 7 +E.g. a port mapped NCR5380 board, driver to probe for IRQ: +modprobe g_NCR5380 base=0x350 card=0 +or alternatively, +modprobe g_NCR5380 ncr_addr=0x350 ncr_5380=1 -(255 should be specified for no or DMA interrupt, 254 to autoprobe for an - IRQ line if overridden on the command line.) +E.g. a memory mapped NCR53C400 board with no IRQ: +modprobe g_NCR5380 irq=255 base=0xc8000 card=1 +or alternatively, +modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1 +E.g. two cards, DTC3181 (in non-PnP mode) at 0x240 with no IRQ +and HP C2502 at 0x300 with IRQ 7: +modprobe g_NCR5380 irq=0,7 base=0x240,0x300 card=3,4 Kevin Lentin K.Lentin@cs.monash.edu.au diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c index 58a0b826eb51..6f9665d50d84 100644 --- a/drivers/scsi/g_NCR5380.c +++ b/drivers/scsi/g_NCR5380.c @@ -37,7 +37,7 @@ #define MAX_CARDS 8 /* old-style parameters for compatibility */ -static int ncr_irq; +static int ncr_irq = -1; static int ncr_addr; static int ncr_5380; static int ncr_53c400; @@ -52,9 +52,9 @@ module_param(ncr_53c400a, int, 0); module_param(dtc_3181e, int, 0); module_param(hp_c2502, int, 0); -static int irq[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static int irq[] = { -1, -1, -1, -1, -1, -1, -1, -1 }; module_param_array(irq, int, NULL, 0); -MODULE_PARM_DESC(irq, "IRQ number(s)"); +MODULE_PARM_DESC(irq, "IRQ number(s) (0=none, 254=auto [default])"); static int base[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; module_param_array(base, int, NULL, 0); @@ -344,6 +344,8 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, /* Compatibility with documented NCR5380 kernel parameters */ if (irq == 255 || irq == 0) irq = NO_IRQ; + else if (irq == -1) + irq = IRQ_AUTO; if (board == BOARD_HP_C2502) { int *irq_table = hp_c2502_irqs; @@ -370,24 +372,28 @@ static int generic_NCR5380_init_one(struct scsi_host_template *tpnt, magic_configure(port_idx, board_irq, magic); } - if (irq == IRQ_AUTO) + if (irq == IRQ_AUTO) { instance->irq = g_NCR5380_probe_irq(instance); - else + if (instance->irq == NO_IRQ) + shost_printk(KERN_INFO, instance, "no irq detected\n"); + } else { instance->irq = irq; + if (instance->irq == NO_IRQ) + shost_printk(KERN_INFO, instance, "no irq provided\n"); + } if (instance->irq != NO_IRQ) { if (request_irq(instance->irq, generic_NCR5380_intr, 0, "NCR5380", instance)) { - printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq); instance->irq = NO_IRQ; + shost_printk(KERN_INFO, instance, + "irq %d denied\n", instance->irq); + } else { + shost_printk(KERN_INFO, instance, + "irq %d acquired\n", instance->irq); } } - if (instance->irq == NO_IRQ) { - printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no); - printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no); - } - ret = scsi_add_host(instance, pdev); if (ret) goto out_free_irq; @@ -698,7 +704,7 @@ static int __init generic_NCR5380_init(void) int ret = 0; /* compatibility with old-style parameters */ - if (irq[0] == 0 && base[0] == 0 && card[0] == -1) { + if (irq[0] == -1 && base[0] == 0 && card[0] == -1) { irq[0] = ncr_irq; base[0] = ncr_addr; if (ncr_5380) -- cgit v1.2.3 From c01848c67d48aa51c4e80c76e1d08d9891d27a5a Mon Sep 17 00:00:00 2001 From: Yaniv Gardi Date: Mon, 5 Dec 2016 19:25:02 -0800 Subject: scsi: ufs: add support for UFS HCI 2.1 The UFS HCI v2.1 includes a few additional registers. This change updates the HCI register, the UFS version register content and the Interrupt Status register. Signed-off-by: Yaniv Gardi Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 29 +++++++++++++++++++++++++---- drivers/scsi/ufs/ufshci.h | 7 +++++++ 2 files changed, 32 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 0c75c75217f8..7af70aa0b750 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -288,10 +288,24 @@ int ufshcd_wait_for_register(struct ufs_hba *hba, u32 reg, u32 mask, */ static inline u32 ufshcd_get_intr_mask(struct ufs_hba *hba) { - if (hba->ufs_version == UFSHCI_VERSION_10) - return INTERRUPT_MASK_ALL_VER_10; - else - return INTERRUPT_MASK_ALL_VER_11; + u32 intr_mask = 0; + + switch (hba->ufs_version) { + case UFSHCI_VERSION_10: + intr_mask = INTERRUPT_MASK_ALL_VER_10; + break; + /* allow fall through */ + case UFSHCI_VERSION_11: + case UFSHCI_VERSION_20: + intr_mask = INTERRUPT_MASK_ALL_VER_11; + break; + /* allow fall through */ + case UFSHCI_VERSION_21: + default: + intr_mask = INTERRUPT_MASK_ALL_VER_21; + } + + return intr_mask; } /** @@ -6667,6 +6681,13 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) /* Get UFS version supported by the controller */ hba->ufs_version = ufshcd_get_ufs_version(hba); + if ((hba->ufs_version != UFSHCI_VERSION_10) && + (hba->ufs_version != UFSHCI_VERSION_11) && + (hba->ufs_version != UFSHCI_VERSION_20) && + (hba->ufs_version != UFSHCI_VERSION_21)) + dev_err(hba->dev, "invalid UFS version 0x%x\n", + hba->ufs_version); + /* Get Interrupt bit mask per version */ hba->intr_mask = ufshcd_get_intr_mask(hba); diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index 5d978867be57..8c5190e2e1c9 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -72,6 +72,10 @@ enum { REG_UIC_COMMAND_ARG_1 = 0x94, REG_UIC_COMMAND_ARG_2 = 0x98, REG_UIC_COMMAND_ARG_3 = 0x9C, + REG_UFS_CCAP = 0x100, + REG_UFS_CRYPTOCAP = 0x104, + + UFSHCI_CRYPTO_REG_SPACE_SIZE = 0x400, }; /* Controller capability masks */ @@ -275,6 +279,9 @@ enum { /* Interrupt disable mask for UFSHCI v1.1 */ INTERRUPT_MASK_ALL_VER_11 = 0x31FFF, + + /* Interrupt disable mask for UFSHCI v2.1 */ + INTERRUPT_MASK_ALL_VER_21 = 0x71FFF, }; /* -- cgit v1.2.3 From ab436706e4a86719595012424ecefbdf4a84cc30 Mon Sep 17 00:00:00 2001 From: Yaniv Gardi Date: Mon, 5 Dec 2016 19:25:15 -0800 Subject: scsi: ufs-qcom: add probe_defer in case phy driver not probed yet In case UFS driver is probed before the phy driver does, the UFS driver should return a PROBE_DEFER code. Signed-off-by: Yaniv Gardi Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index aa43bfea0d00..ff614613bf89 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1194,7 +1194,16 @@ static int ufs_qcom_init(struct ufs_hba *hba) */ host->generic_phy = devm_phy_get(dev, "ufsphy"); - if (IS_ERR(host->generic_phy)) { + if (host->generic_phy == ERR_PTR(-EPROBE_DEFER)) { + /* + * UFS driver might be probed before the phy driver does. + * In that case we would like to return EPROBE_DEFER code. + */ + err = -EPROBE_DEFER; + dev_warn(dev, "%s: required phy device. hasn't probed yet. err = %d\n", + __func__, err); + goto out_variant_clear; + } else if (IS_ERR(host->generic_phy)) { err = PTR_ERR(host->generic_phy); dev_err(dev, "%s: PHY get failed %d\n", __func__, err); goto out_variant_clear; -- cgit v1.2.3 From 56d4a1866d748732fd8d690b2c2156bbc9c9eb02 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Mon, 5 Dec 2016 19:25:32 -0800 Subject: scsi: ufs: add quirk to increase host PA_SaveConfigTime The maximum value PA_SaveConfigTime is 250 (10us) but this is not enough for some vendors. Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTime. Gear switch can be issued by host controller as an error recovery and any software delay will not help on this case so we need to increase PA_SaveConfigTime to >32us as per vendor recommendation. This change adds a quirk to increase the PA_SaveConfigTime parameter. Reviewed-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 30 ++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-qcom.h | 1 + drivers/scsi/ufs/ufs_quirks.h | 30 +++++++++--------------------- drivers/scsi/ufs/ufshcd.c | 26 ++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 12 ++++++++++-- 5 files changed, 76 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index ff614613bf89..2943a68b6d69 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -23,6 +23,7 @@ #include "unipro.h" #include "ufs-qcom.h" #include "ufshci.h" +#include "ufs_quirks.h" #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) @@ -1031,6 +1032,34 @@ out: return ret; } +static int ufs_qcom_quirk_host_pa_saveconfigtime(struct ufs_hba *hba) +{ + int err; + u32 pa_vs_config_reg1; + + err = ufshcd_dme_get(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), + &pa_vs_config_reg1); + if (err) + goto out; + + /* Allow extension of MSB bits of PA_SaveConfigTime attribute */ + err = ufshcd_dme_set(hba, UIC_ARG_MIB(PA_VS_CONFIG_REG1), + (pa_vs_config_reg1 | (1 << 12))); + +out: + return err; +} + +static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) +{ + int err = 0; + + if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME) + err = ufs_qcom_quirk_host_pa_saveconfigtime(hba); + + return err; +} + static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -1618,6 +1647,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { .hce_enable_notify = ufs_qcom_hce_enable_notify, .link_startup_notify = ufs_qcom_link_startup_notify, .pwr_change_notify = ufs_qcom_pwr_change_notify, + .apply_dev_quirks = ufs_qcom_apply_dev_quirks, .suspend = ufs_qcom_suspend, .resume = ufs_qcom_resume, .dbg_register_dump = ufs_qcom_dump_dbg_regs, diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index a19307a57ce2..fe517cd7dac3 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -142,6 +142,7 @@ enum ufs_qcom_phy_init_type { UFS_QCOM_DBG_PRINT_TEST_BUS_EN) /* QUniPro Vendor specific attributes */ +#define PA_VS_CONFIG_REG1 0x9000 #define DME_VS_CORE_CLK_CTRL 0xD002 /* bit and mask definitions for DME_VS_CORE_CLK_CTRL attribute */ #define DME_VS_CORE_CLK_CTRL_CORE_CLK_DIV_EN_BIT BIT(8) diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index f7983058f3f7..08b799d4efcc 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -134,29 +134,17 @@ struct ufs_dev_fix { */ #define UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE (1 << 7) +/* + * The max. value PA_SaveConfigTime is 250 (10us) but this is not enough for + * some vendors. + * Gear switch from PWM to HS may fail even with this max. PA_SaveConfigTime. + * Gear switch can be issued by host controller as an error recovery and any + * software delay will not help on this case so we need to increase + * PA_SaveConfigTime to >32us as per vendor recommendation. + */ +#define UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME (1 << 8) struct ufs_hba; void ufs_advertise_fixup_device(struct ufs_hba *hba); -static struct ufs_dev_fix ufs_fixups[] = { - /* UFS cards deviations table */ - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_NO_FASTAUTO), - UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), - UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, - UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), - UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", - UFS_DEVICE_QUIRK_PA_TACTIVATE), - UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", - UFS_DEVICE_QUIRK_PA_TACTIVATE), - UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), - - END_FIX -}; #endif /* UFS_QUIRKS_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 7af70aa0b750..af7e0285f004 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -185,6 +185,30 @@ ufs_get_pm_lvl_to_link_pwr_state(enum ufs_pm_level lvl) return ufs_pm_lvl_states[lvl].link_state; } +static struct ufs_dev_fix ufs_fixups[] = { + /* UFS cards deviations table */ + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_NO_FASTAUTO), + UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE), + UFS_FIX(UFS_VENDOR_TOSHIBA, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_DELAY_BEFORE_LPM), + UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG", + UFS_DEVICE_QUIRK_PA_TACTIVATE), + UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG", + UFS_DEVICE_QUIRK_PA_TACTIVATE), + UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ), + UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME), + + END_FIX +}; + static void ufshcd_tmc_handler(struct ufs_hba *hba); static void ufshcd_async_scan(void *data, async_cookie_t cookie); static int ufshcd_reset_and_restore(struct ufs_hba *hba); @@ -5213,6 +5237,8 @@ static void ufshcd_tune_unipro_params(struct ufs_hba *hba) if (hba->dev_quirks & UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE) ufshcd_quirk_tune_host_pa_tactivate(hba); + + ufshcd_vops_apply_dev_quirks(hba); } /** diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 7d9ff22acfea..08cd26ed2382 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -266,7 +266,7 @@ struct ufs_pwr_mode_info { * @setup_task_mgmt: called before any task management request is issued * to set some things * @hibern8_notify: called around hibern8 enter/exit - * to configure some things + * @apply_dev_quirks: called to apply device specific quirks * @suspend: called during host controller PM callback * @resume: called during host controller PM callback * @dbg_register_dump: used to dump controller debug information @@ -293,7 +293,8 @@ struct ufs_hba_variant_ops { void (*setup_xfer_req)(struct ufs_hba *, int, bool); void (*setup_task_mgmt)(struct ufs_hba *, int, u8); void (*hibern8_notify)(struct ufs_hba *, enum uic_cmd_dme, - enum ufs_notify_change_status); + enum ufs_notify_change_status); + int (*apply_dev_quirks)(struct ufs_hba *); int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op); void (*dbg_register_dump)(struct ufs_hba *hba); @@ -839,6 +840,13 @@ static inline void ufshcd_vops_hibern8_notify(struct ufs_hba *hba, return hba->vops->hibern8_notify(hba, cmd, status); } +static inline int ufshcd_vops_apply_dev_quirks(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->apply_dev_quirks) + return hba->vops->apply_dev_quirks(hba); + return 0; +} + static inline int ufshcd_vops_suspend(struct ufs_hba *hba, enum ufs_pm_op op) { if (hba->vops && hba->vops->suspend) -- cgit v1.2.3 From b84ca6e9c74d30e4a1ebc19a7f6a6e616e08dfd4 Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Mon, 5 Dec 2016 19:25:42 -0800 Subject: scsi: ufs-qcom: fix bug with read/modify write of UFS_CFG1 ufs_qcom_print_hw_debug_reg_all() function is having a bug where it might incorrectly modify undesired bits in UFS_CFG1 register, this change fixes it. Reviewed-by: Venkat Gopalakrishnan Signed-off-by: Subhash Jadavani Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index 2943a68b6d69..abe617372661 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -1470,7 +1470,8 @@ static void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba, reg = ufs_qcom_get_debug_reg_offset(host, UFS_UFS_DBG_RD_PRDT_RAM); print_fn(hba, reg, 64, "UFS_UFS_DBG_RD_PRDT_RAM ", priv); - ufshcd_writel(hba, (reg & ~UFS_BIT(17)), REG_UFS_CFG1); + /* clear bit 17 - UTP_DBG_RAMS_EN */ + ufshcd_rmwl(hba, UFS_BIT(17), 0, REG_UFS_CFG1); reg = ufs_qcom_get_debug_reg_offset(host, UFS_DBG_RD_REG_UAWM); print_fn(hba, reg, 4, "UFS_DBG_RD_REG_UAWM ", priv); -- cgit v1.2.3 From 32d6e4b6e4ea589cf46518e99f8e6a25ccef023e Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Wed, 7 Dec 2016 16:04:35 -0600 Subject: scsi: ibmvscsi: add vscsi hosts to global list_head Add each vscsi host adatper to a new global list_head named ibmvscsi_head. There is no functional change. This is meant primarily as a convience for locating adapters from within the debugger or crash utility. [mkp: fixed typo] Signed-off-by: Tyrel Datwyler Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 3 +++ drivers/scsi/ibmvscsi/ibmvscsi.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index d9534ee6ef52..a0ee16f56f58 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -95,6 +95,7 @@ static int fast_fail = 1; static int client_reserve = 1; static char partition_name[97] = "UNKNOWN"; static unsigned int partition_number = -1; +static LIST_HEAD(ibmvscsi_head); static struct scsi_transport_template *ibmvscsi_transport_template; @@ -2270,6 +2271,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) } dev_set_drvdata(&vdev->dev, hostdata); + list_add_tail(&hostdata->host_list, &ibmvscsi_head); return 0; add_srp_port_failed: @@ -2291,6 +2293,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) static int ibmvscsi_remove(struct vio_dev *vdev) { struct ibmvscsi_host_data *hostdata = dev_get_drvdata(&vdev->dev); + list_del(&hostdata->host_list); unmap_persist_bufs(hostdata); release_event_pool(&hostdata->pool, hostdata); ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index e0f6c3aeb4ee..3a7875575616 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -90,6 +90,7 @@ struct event_pool { /* all driver data associated with a host adapter */ struct ibmvscsi_host_data { + struct list_head host_list; atomic_t request_limit; int client_migrated; int reset_crq; -- cgit v1.2.3 From 15c9274699e8b6dd4bfd7a205c0dc06653e6400d Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Wed, 7 Dec 2016 16:04:36 -0600 Subject: scsi: ibmvscsi: log bad SRP response opcode in hex format An unrecogonized or unsupported SRP response has its opcode currently logged in decimal format. Log it in hex format instead so it can easily be validated against the SRP specs values which are in hex. Signed-off-by: Tyrel Datwyler Reviewed-by: Johannes Thumshirn Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index a0ee16f56f58..7752656c3d21 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -993,7 +993,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct) if (unlikely(rsp->opcode != SRP_RSP)) { if (printk_ratelimit()) dev_warn(evt_struct->hostdata->dev, - "bad SRP RSP type %d\n", rsp->opcode); + "bad SRP RSP type %#02x\n", rsp->opcode); } if (cmnd) { -- cgit v1.2.3 From b39205d248b9c3ce0548859ed786badb2e0db0bd Mon Sep 17 00:00:00 2001 From: Tyrel Datwyler Date: Wed, 7 Dec 2016 17:31:26 -0600 Subject: scsi: ibmvscsi: add write memory barrier to CRQ processing The first byte of each CRQ entry is used to indicate whether an entry is a valid response or free for the VIOS to use. After processing a response the driver sets the valid byte to zero to indicate the entry is now free to be reused. Add a memory barrier after this write to ensure no other stores are reordered when updating the valid byte. Signed-off-by: Tyrel Datwyler Reviewed-by: Brian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 7752656c3d21..50cd01165e35 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -233,6 +233,7 @@ static void ibmvscsi_task(void *data) while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) { ibmvscsi_handle_crq(crq, hostdata); crq->valid = VIOSRP_CRQ_FREE; + wmb(); } vio_enable_interrupts(vdev); @@ -241,6 +242,7 @@ static void ibmvscsi_task(void *data) vio_disable_interrupts(vdev); ibmvscsi_handle_crq(crq, hostdata); crq->valid = VIOSRP_CRQ_FREE; + wmb(); } else { done = 1; } -- cgit v1.2.3 From ae2aae2421983f6f68eb7c4692624bc43ea50712 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Thu, 8 Dec 2016 10:29:29 -0600 Subject: scsi: aacraid: remove wildcard for series 9 controllers Controllers with this PCI ID never shipped outside of PMCS/Microsemi. Remove the ID from the aacraid driver. smartpqi is the correct driver for these controllers. [mkp: patch description] Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/linit.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index e4f3e22fcbd9..3ecbf20ca29f 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -160,7 +160,6 @@ static const struct pci_device_id aac_pci_tbl[] = { { 0x9005, 0x028b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 62 }, /* Adaptec PMC Series 6 (Tupelo) */ { 0x9005, 0x028c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 63 }, /* Adaptec PMC Series 7 (Denali) */ { 0x9005, 0x028d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 64 }, /* Adaptec PMC Series 8 */ - { 0x9005, 0x028f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 65 }, /* Adaptec PMC Series 9 */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -239,7 +238,6 @@ static struct aac_driver_ident aac_drivers[] = { { aac_src_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 6 (Tupelo) */ { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 7 (Denali) */ { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC }, /* Adaptec PMC Series 8 */ - { aac_srcv_init, "aacraid", "ADAPTEC ", "RAID ", 2, AAC_QUIRK_SRC } /* Adaptec PMC Series 9 */ }; /** -- cgit v1.2.3 From 8cf868affdc459beee1a941df0cfaba1673740e3 Mon Sep 17 00:00:00 2001 From: "Steven Rostedt (Red Hat)" Date: Mon, 28 Nov 2016 13:03:21 -0500 Subject: tracing: Have the reg function allow to fail Some tracepoints have a registration function that gets enabled when the tracepoint is enabled. There may be cases that the registraction function must fail (for example, can't allocate enough memory). In this case, the tracepoint should also fail to register, otherwise the user would not know why the tracepoint is not working. Cc: David Howells Cc: Seiji Aguchi Cc: Anton Blanchard Cc: Mathieu Desnoyers Signed-off-by: Steven Rostedt --- arch/powerpc/include/asm/trace.h | 4 ++-- arch/powerpc/platforms/powernv/opal-tracepoints.c | 6 ++++-- arch/powerpc/platforms/pseries/lpar.c | 6 ++++-- arch/x86/include/asm/trace/exceptions.h | 2 +- arch/x86/include/asm/trace/irq_vectors.h | 2 +- arch/x86/kernel/tracepoint.c | 3 ++- drivers/i2c/i2c-core.c | 3 ++- include/linux/tracepoint-defs.h | 2 +- include/linux/tracepoint.h | 2 +- include/trace/events/i2c.h | 2 +- kernel/trace/trace_benchmark.c | 3 ++- kernel/trace/trace_benchmark.h | 2 +- kernel/tracepoint.c | 12 +++++++++--- samples/trace_events/trace-events-sample.c | 3 ++- samples/trace_events/trace-events-sample.h | 2 +- 15 files changed, 34 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/include/asm/trace.h b/arch/powerpc/include/asm/trace.h index 32e36b16773f..c05cef6ee06c 100644 --- a/arch/powerpc/include/asm/trace.h +++ b/arch/powerpc/include/asm/trace.h @@ -54,7 +54,7 @@ DEFINE_EVENT(ppc64_interrupt_class, timer_interrupt_exit, ); #ifdef CONFIG_PPC_PSERIES -extern void hcall_tracepoint_regfunc(void); +extern int hcall_tracepoint_regfunc(void); extern void hcall_tracepoint_unregfunc(void); TRACE_EVENT_FN_COND(hcall_entry, @@ -104,7 +104,7 @@ TRACE_EVENT_FN_COND(hcall_exit, #endif #ifdef CONFIG_PPC_POWERNV -extern void opal_tracepoint_regfunc(void); +extern int opal_tracepoint_regfunc(void); extern void opal_tracepoint_unregfunc(void); TRACE_EVENT_FN(opal_entry, diff --git a/arch/powerpc/platforms/powernv/opal-tracepoints.c b/arch/powerpc/platforms/powernv/opal-tracepoints.c index 1e496b780efd..3c447002edff 100644 --- a/arch/powerpc/platforms/powernv/opal-tracepoints.c +++ b/arch/powerpc/platforms/powernv/opal-tracepoints.c @@ -6,9 +6,10 @@ #ifdef HAVE_JUMP_LABEL struct static_key opal_tracepoint_key = STATIC_KEY_INIT; -void opal_tracepoint_regfunc(void) +int opal_tracepoint_regfunc(void) { static_key_slow_inc(&opal_tracepoint_key); + return 0; } void opal_tracepoint_unregfunc(void) @@ -25,9 +26,10 @@ void opal_tracepoint_unregfunc(void) /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ extern long opal_tracepoint_refcount; -void opal_tracepoint_regfunc(void) +int opal_tracepoint_regfunc(void) { opal_tracepoint_refcount++; + return 0; } void opal_tracepoint_unregfunc(void) diff --git a/arch/powerpc/platforms/pseries/lpar.c b/arch/powerpc/platforms/pseries/lpar.c index aa35245d8d6d..c0423ce3955c 100644 --- a/arch/powerpc/platforms/pseries/lpar.c +++ b/arch/powerpc/platforms/pseries/lpar.c @@ -661,9 +661,10 @@ EXPORT_SYMBOL(arch_free_page); #ifdef HAVE_JUMP_LABEL struct static_key hcall_tracepoint_key = STATIC_KEY_INIT; -void hcall_tracepoint_regfunc(void) +int hcall_tracepoint_regfunc(void) { static_key_slow_inc(&hcall_tracepoint_key); + return 0; } void hcall_tracepoint_unregfunc(void) @@ -680,9 +681,10 @@ void hcall_tracepoint_unregfunc(void) /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ extern long hcall_tracepoint_refcount; -void hcall_tracepoint_regfunc(void) +int hcall_tracepoint_regfunc(void) { hcall_tracepoint_refcount++; + return 0; } void hcall_tracepoint_unregfunc(void) diff --git a/arch/x86/include/asm/trace/exceptions.h b/arch/x86/include/asm/trace/exceptions.h index 2fbc66c7885b..2422b14c50a7 100644 --- a/arch/x86/include/asm/trace/exceptions.h +++ b/arch/x86/include/asm/trace/exceptions.h @@ -6,7 +6,7 @@ #include -extern void trace_irq_vector_regfunc(void); +extern int trace_irq_vector_regfunc(void); extern void trace_irq_vector_unregfunc(void); DECLARE_EVENT_CLASS(x86_exceptions, diff --git a/arch/x86/include/asm/trace/irq_vectors.h b/arch/x86/include/asm/trace/irq_vectors.h index 38a09a13a9bc..32dd6a9e343c 100644 --- a/arch/x86/include/asm/trace/irq_vectors.h +++ b/arch/x86/include/asm/trace/irq_vectors.h @@ -6,7 +6,7 @@ #include -extern void trace_irq_vector_regfunc(void); +extern int trace_irq_vector_regfunc(void); extern void trace_irq_vector_unregfunc(void); DECLARE_EVENT_CLASS(x86_irq_vector, diff --git a/arch/x86/kernel/tracepoint.c b/arch/x86/kernel/tracepoint.c index 1c113db9ed57..15515132bf0d 100644 --- a/arch/x86/kernel/tracepoint.c +++ b/arch/x86/kernel/tracepoint.c @@ -34,7 +34,7 @@ static void switch_idt(void *arg) local_irq_restore(flags); } -void trace_irq_vector_regfunc(void) +int trace_irq_vector_regfunc(void) { mutex_lock(&irq_vector_mutex); if (!trace_irq_vector_refcount) { @@ -44,6 +44,7 @@ void trace_irq_vector_regfunc(void) } trace_irq_vector_refcount++; mutex_unlock(&irq_vector_mutex); + return 0; } void trace_irq_vector_unregfunc(void) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index b432b64e307a..6a2b995d7fc4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -77,9 +77,10 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE; static bool is_registered; -void i2c_transfer_trace_reg(void) +int i2c_transfer_trace_reg(void) { static_key_slow_inc(&i2c_trace_msg); + return 0; } void i2c_transfer_trace_unreg(void) diff --git a/include/linux/tracepoint-defs.h b/include/linux/tracepoint-defs.h index 4ac89acb6136..a03192052066 100644 --- a/include/linux/tracepoint-defs.h +++ b/include/linux/tracepoint-defs.h @@ -29,7 +29,7 @@ struct tracepoint_func { struct tracepoint { const char *name; /* Tracepoint name */ struct static_key key; - void (*regfunc)(void); + int (*regfunc)(void); void (*unregfunc)(void); struct tracepoint_func __rcu *funcs; }; diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index be586c632a0c..f72fcfe0e66a 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -81,7 +81,7 @@ static inline void tracepoint_synchronize_unregister(void) } #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS -extern void syscall_regfunc(void); +extern int syscall_regfunc(void); extern void syscall_unregfunc(void); #endif /* CONFIG_HAVE_SYSCALL_TRACEPOINTS */ diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h index fe17187df65d..4abb8eab34d3 100644 --- a/include/trace/events/i2c.h +++ b/include/trace/events/i2c.h @@ -20,7 +20,7 @@ /* * drivers/i2c/i2c-core.c */ -extern void i2c_transfer_trace_reg(void); +extern int i2c_transfer_trace_reg(void); extern void i2c_transfer_trace_unreg(void); /* diff --git a/kernel/trace/trace_benchmark.c b/kernel/trace/trace_benchmark.c index 0f109c4130d3..f76d0416dd83 100644 --- a/kernel/trace/trace_benchmark.c +++ b/kernel/trace/trace_benchmark.c @@ -164,11 +164,12 @@ static int benchmark_event_kthread(void *arg) * When the benchmark tracepoint is enabled, it calls this * function and the thread that calls the tracepoint is created. */ -void trace_benchmark_reg(void) +int trace_benchmark_reg(void) { bm_event_thread = kthread_run(benchmark_event_kthread, NULL, "event_benchmark"); WARN_ON(!bm_event_thread); + return 0; } /* diff --git a/kernel/trace/trace_benchmark.h b/kernel/trace/trace_benchmark.h index 3c1df1df4e29..ebdbfc2f2a64 100644 --- a/kernel/trace/trace_benchmark.h +++ b/kernel/trace/trace_benchmark.h @@ -6,7 +6,7 @@ #include -extern void trace_benchmark_reg(void); +extern int trace_benchmark_reg(void); extern void trace_benchmark_unreg(void); #define BENCHMARK_EVENT_STRLEN 128 diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index d0639d917899..1f9a31f934a4 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c @@ -194,9 +194,13 @@ static int tracepoint_add_func(struct tracepoint *tp, struct tracepoint_func *func, int prio) { struct tracepoint_func *old, *tp_funcs; + int ret; - if (tp->regfunc && !static_key_enabled(&tp->key)) - tp->regfunc(); + if (tp->regfunc && !static_key_enabled(&tp->key)) { + ret = tp->regfunc(); + if (ret < 0) + return ret; + } tp_funcs = rcu_dereference_protected(tp->funcs, lockdep_is_held(&tracepoints_mutex)); @@ -529,7 +533,7 @@ EXPORT_SYMBOL_GPL(for_each_kernel_tracepoint); /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ static int sys_tracepoint_refcount; -void syscall_regfunc(void) +int syscall_regfunc(void) { struct task_struct *p, *t; @@ -541,6 +545,8 @@ void syscall_regfunc(void) read_unlock(&tasklist_lock); } sys_tracepoint_refcount++; + + return 0; } void syscall_unregfunc(void) diff --git a/samples/trace_events/trace-events-sample.c b/samples/trace_events/trace-events-sample.c index 880a7d1d27d2..30e282d33d4d 100644 --- a/samples/trace_events/trace-events-sample.c +++ b/samples/trace_events/trace-events-sample.c @@ -79,7 +79,7 @@ static int simple_thread_fn(void *arg) static DEFINE_MUTEX(thread_mutex); -void foo_bar_reg(void) +int foo_bar_reg(void) { pr_info("Starting thread for foo_bar_fn\n"); /* @@ -90,6 +90,7 @@ void foo_bar_reg(void) mutex_lock(&thread_mutex); simple_tsk_fn = kthread_run(simple_thread_fn, NULL, "event-sample-fn"); mutex_unlock(&thread_mutex); + return 0; } void foo_bar_unreg(void) diff --git a/samples/trace_events/trace-events-sample.h b/samples/trace_events/trace-events-sample.h index d6b75bb495b3..76a75ab7a608 100644 --- a/samples/trace_events/trace-events-sample.h +++ b/samples/trace_events/trace-events-sample.h @@ -354,7 +354,7 @@ TRACE_EVENT_CONDITION(foo_bar_with_cond, TP_printk("foo %s %d", __get_str(foo), __entry->bar) ); -void foo_bar_reg(void); +int foo_bar_reg(void); void foo_bar_unreg(void); /* -- cgit v1.2.3 From dfeef68862edd7d4bafe68ef7aeb5f658ef24bb5 Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 9 Dec 2016 16:45:04 +0100 Subject: vfs: remove ".readlink = generic_readlink" assignments If .readlink == NULL implies generic_readlink(). Generated by: to_del="\.readlink.*=.*generic_readlink" for i in `git grep -l $to_del`; do sed -i "/$to_del"/d $i; done Signed-off-by: Miklos Szeredi --- drivers/staging/lustre/lustre/llite/symlink.c | 1 - fs/9p/vfs_inode.c | 1 - fs/9p/vfs_inode_dotl.c | 1 - fs/affs/symlink.c | 1 - fs/autofs4/symlink.c | 1 - fs/btrfs/inode.c | 1 - fs/ceph/inode.c | 1 - fs/cifs/cifsfs.c | 1 - fs/coda/cnode.c | 1 - fs/configfs/symlink.c | 1 - fs/ecryptfs/inode.c | 1 - fs/ext2/symlink.c | 2 -- fs/ext4/symlink.c | 3 --- fs/f2fs/namei.c | 2 -- fs/fuse/dir.c | 1 - fs/gfs2/inode.c | 1 - fs/hostfs/hostfs_kern.c | 1 - fs/jffs2/symlink.c | 1 - fs/jfs/symlink.c | 2 -- fs/kernfs/symlink.c | 1 - fs/libfs.c | 1 - fs/minix/inode.c | 1 - fs/namei.c | 1 - fs/ncpfs/inode.c | 1 - fs/nfs/symlink.c | 1 - fs/nilfs2/namei.c | 1 - fs/ocfs2/symlink.c | 1 - fs/orangefs/symlink.c | 1 - fs/overlayfs/inode.c | 1 - fs/proc/inode.c | 1 - fs/proc/self.c | 1 - fs/proc/thread_self.c | 1 - fs/reiserfs/namei.c | 1 - fs/squashfs/symlink.c | 1 - fs/sysv/inode.c | 1 - fs/ubifs/file.c | 1 - fs/xfs/xfs_iops.c | 2 -- mm/shmem.c | 2 -- 38 files changed, 45 deletions(-) (limited to 'drivers') diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c index 82c7c48aa619..cd77b55d3895 100644 --- a/drivers/staging/lustre/lustre/llite/symlink.c +++ b/drivers/staging/lustre/lustre/llite/symlink.c @@ -149,7 +149,6 @@ static const char *ll_get_link(struct dentry *dentry, } const struct inode_operations ll_fast_symlink_inode_operations = { - .readlink = generic_readlink, .setattr = ll_setattr, .get_link = ll_get_link, .getattr = ll_getattr, diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 30ca770c5e0b..f4f4450119e4 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1464,7 +1464,6 @@ static const struct inode_operations v9fs_file_inode_operations = { }; static const struct inode_operations v9fs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = v9fs_vfs_get_link, .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr, diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index afaa4b6de801..5999bd050678 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c @@ -979,7 +979,6 @@ const struct inode_operations v9fs_file_inode_operations_dotl = { }; const struct inode_operations v9fs_symlink_inode_operations_dotl = { - .readlink = generic_readlink, .get_link = v9fs_vfs_get_link_dotl, .getattr = v9fs_vfs_getattr_dotl, .setattr = v9fs_vfs_setattr_dotl, diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index 69b03dbb792f..ae622cdce142 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -70,7 +70,6 @@ const struct address_space_operations affs_symlink_aops = { }; const struct inode_operations affs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .setattr = affs_notify_change, }; diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index 99aab00dc217..ab0b4285a202 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -25,6 +25,5 @@ static const char *autofs4_get_link(struct dentry *dentry, } const struct inode_operations autofs4_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = autofs4_get_link }; diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 8e3a5a266917..d9c0eb7c16d4 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -10668,7 +10668,6 @@ static const struct inode_operations btrfs_special_inode_operations = { .update_time = btrfs_update_time, }; static const struct inode_operations btrfs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .getattr = btrfs_getattr, .setattr = btrfs_setattr, diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index ef4d04647325..9f125204c487 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c @@ -1879,7 +1879,6 @@ retry: * symlinks */ static const struct inode_operations ceph_symlink_iops = { - .readlink = generic_readlink, .get_link = simple_get_link, .setattr = ceph_setattr, .getattr = ceph_getattr, diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 15261ba464c5..e6efb9a88598 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -914,7 +914,6 @@ const struct inode_operations cifs_file_inode_ops = { }; const struct inode_operations cifs_symlink_inode_ops = { - .readlink = generic_readlink, .get_link = cifs_get_link, .permission = cifs_permission, .listxattr = cifs_listxattr, diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 1bfb7ba4e85e..f13e09057c6b 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -17,7 +17,6 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) } static const struct inode_operations coda_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .setattr = coda_setattr, }; diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index db6d69289608..a6ab012a2c6a 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -305,7 +305,6 @@ static const char *configfs_get_link(struct dentry *dentry, const struct inode_operations configfs_symlink_inode_operations = { .get_link = configfs_get_link, - .readlink = generic_readlink, .setattr = configfs_setattr, }; diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 4ea9d69152dc..e7413f82d27b 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -1084,7 +1084,6 @@ out: } const struct inode_operations ecryptfs_symlink_iops = { - .readlink = generic_readlink, .get_link = ecryptfs_get_link, .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 8437b191bf5d..eeffb0138a17 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -21,7 +21,6 @@ #include "xattr.h" const struct inode_operations ext2_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .setattr = ext2_setattr, #ifdef CONFIG_EXT2_FS_XATTR @@ -30,7 +29,6 @@ const struct inode_operations ext2_symlink_inode_operations = { }; const struct inode_operations ext2_fast_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = simple_get_link, .setattr = ext2_setattr, #ifdef CONFIG_EXT2_FS_XATTR diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index 557b3b0d668c..73b184d161fc 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -83,21 +83,18 @@ errout: } const struct inode_operations ext4_encrypted_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = ext4_encrypted_get_link, .setattr = ext4_setattr, .listxattr = ext4_listxattr, }; const struct inode_operations ext4_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .setattr = ext4_setattr, .listxattr = ext4_listxattr, }; const struct inode_operations ext4_fast_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = simple_get_link, .setattr = ext4_setattr, .listxattr = ext4_listxattr, diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c index 489fa0d5f914..fcb00e7c3054 100644 --- a/fs/f2fs/namei.c +++ b/fs/f2fs/namei.c @@ -1075,7 +1075,6 @@ errout: } const struct inode_operations f2fs_encrypted_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = f2fs_encrypted_get_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, @@ -1105,7 +1104,6 @@ const struct inode_operations f2fs_dir_inode_operations = { }; const struct inode_operations f2fs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = f2fs_get_link, .getattr = f2fs_getattr, .setattr = f2fs_setattr, diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index b3ebe512d64c..0c07d0c651de 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1834,7 +1834,6 @@ static const struct inode_operations fuse_common_inode_operations = { static const struct inode_operations fuse_symlink_inode_operations = { .setattr = fuse_setattr, .get_link = fuse_get_link, - .readlink = generic_readlink, .getattr = fuse_getattr, .listxattr = fuse_listxattr, }; diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index fe3f84995c48..6cd9f84967b8 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c @@ -2067,7 +2067,6 @@ const struct inode_operations gfs2_dir_iops = { }; const struct inode_operations gfs2_symlink_iops = { - .readlink = generic_readlink, .get_link = gfs2_get_link, .permission = gfs2_permission, .setattr = gfs2_setattr, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 23e15ea53e45..e61261a7417e 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -920,7 +920,6 @@ static const char *hostfs_get_link(struct dentry *dentry, } static const struct inode_operations hostfs_link_iops = { - .readlink = generic_readlink, .get_link = hostfs_get_link, }; diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index 8f3f0855fcd2..d2fa138a868c 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -13,7 +13,6 @@ const struct inode_operations jffs2_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = simple_get_link, .setattr = jffs2_setattr, .listxattr = jffs2_listxattr, diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index c82404fee6cd..38320607993e 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -22,14 +22,12 @@ #include "jfs_xattr.h" const struct inode_operations jfs_fast_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = simple_get_link, .setattr = jfs_setattr, .listxattr = jfs_listxattr, }; const struct inode_operations jfs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .setattr = jfs_setattr, .listxattr = jfs_listxattr, diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c index 9b43ca02b7ab..1684af4a8b9b 100644 --- a/fs/kernfs/symlink.c +++ b/fs/kernfs/symlink.c @@ -135,7 +135,6 @@ static const char *kernfs_iop_get_link(struct dentry *dentry, const struct inode_operations kernfs_symlink_iops = { .listxattr = kernfs_iop_listxattr, - .readlink = generic_readlink, .get_link = kernfs_iop_get_link, .setattr = kernfs_iop_setattr, .getattr = kernfs_iop_getattr, diff --git a/fs/libfs.c b/fs/libfs.c index 48826d4da189..06e7e0c918e1 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -1129,7 +1129,6 @@ EXPORT_SYMBOL(simple_get_link); const struct inode_operations simple_symlink_inode_operations = { .get_link = simple_get_link, - .readlink = generic_readlink }; EXPORT_SYMBOL(simple_symlink_inode_operations); diff --git a/fs/minix/inode.c b/fs/minix/inode.c index f975d667c539..e7d9bf86d975 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -434,7 +434,6 @@ static const struct address_space_operations minix_aops = { }; static const struct inode_operations minix_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .getattr = minix_getattr, }; diff --git a/fs/namei.c b/fs/namei.c index b87465d67c60..c9baf3b3ffd7 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -4813,7 +4813,6 @@ int page_symlink(struct inode *inode, const char *symname, int len) EXPORT_SYMBOL(page_symlink); const struct inode_operations page_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, }; EXPORT_SYMBOL(page_symlink_inode_operations); diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index f6cf4c7e92b1..ba611bf1aff3 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -243,7 +243,6 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) static const struct inode_operations ncp_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .setattr = ncp_notify_change, }; diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 4fe3eead3868..5a1d0ded8979 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -77,7 +77,6 @@ static const char *nfs_get_link(struct dentry *dentry, * symlinks can't do much... */ const struct inode_operations nfs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = nfs_get_link, .getattr = nfs_getattr, .setattr = nfs_setattr, diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c index 2b71c60fe982..515d13c196da 100644 --- a/fs/nilfs2/namei.c +++ b/fs/nilfs2/namei.c @@ -568,7 +568,6 @@ const struct inode_operations nilfs_special_inode_operations = { }; const struct inode_operations nilfs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .permission = nilfs_permission, }; diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index 6ad8eecefe21..94cfacc9bad7 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c @@ -87,7 +87,6 @@ const struct address_space_operations ocfs2_fast_symlink_aops = { }; const struct inode_operations ocfs2_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .getattr = ocfs2_getattr, .setattr = ocfs2_setattr, diff --git a/fs/orangefs/symlink.c b/fs/orangefs/symlink.c index 10b0b06e075e..02b1bbdbcc42 100644 --- a/fs/orangefs/symlink.c +++ b/fs/orangefs/symlink.c @@ -9,7 +9,6 @@ #include "orangefs-bufmap.h" const struct inode_operations orangefs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = simple_get_link, .setattr = orangefs_setattr, .getattr = orangefs_getattr, diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index 7fb53d055537..19e0089c3dbf 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c @@ -348,7 +348,6 @@ static const struct inode_operations ovl_file_inode_operations = { static const struct inode_operations ovl_symlink_inode_operations = { .setattr = ovl_setattr, .get_link = ovl_get_link, - .readlink = generic_readlink, .getattr = ovl_getattr, .listxattr = ovl_listxattr, .update_time = ovl_update_time, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index e69ebe648a34..827c0df5baa6 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -410,7 +410,6 @@ static const char *proc_get_link(struct dentry *dentry, } const struct inode_operations proc_link_inode_operations = { - .readlink = generic_readlink, .get_link = proc_get_link, }; diff --git a/fs/proc/self.c b/fs/proc/self.c index b7a29e55f802..39857f6db5cf 100644 --- a/fs/proc/self.c +++ b/fs/proc/self.c @@ -26,7 +26,6 @@ static const char *proc_self_get_link(struct dentry *dentry, } static const struct inode_operations proc_self_inode_operations = { - .readlink = generic_readlink, .get_link = proc_self_get_link, }; diff --git a/fs/proc/thread_self.c b/fs/proc/thread_self.c index adaba20b59b6..20614b62a9b7 100644 --- a/fs/proc/thread_self.c +++ b/fs/proc/thread_self.c @@ -27,7 +27,6 @@ static const char *proc_thread_self_get_link(struct dentry *dentry, } static const struct inode_operations proc_thread_self_inode_operations = { - .readlink = generic_readlink, .get_link = proc_thread_self_get_link, }; diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index e6a2b406af36..bd39a998843d 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1665,7 +1665,6 @@ const struct inode_operations reiserfs_dir_inode_operations = { * stuff added */ const struct inode_operations reiserfs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .setattr = reiserfs_setattr, .listxattr = reiserfs_listxattr, diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index 79b9c31a0c8f..befeba0fa70a 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c @@ -118,7 +118,6 @@ const struct address_space_operations squashfs_symlink_aops = { }; const struct inode_operations squashfs_symlink_inode_ops = { - .readlink = generic_readlink, .get_link = page_get_link, .listxattr = squashfs_listxattr }; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d62c423a5a2d..858fb72f9e0f 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -145,7 +145,6 @@ static inline void write3byte(struct sysv_sb_info *sbi, } static const struct inode_operations sysv_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = page_get_link, .getattr = sysv_getattr, }; diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index b4fbeefba246..a7eae181e1bd 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -1628,7 +1628,6 @@ const struct inode_operations ubifs_file_inode_operations = { }; const struct inode_operations ubifs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = simple_get_link, .setattr = ubifs_setattr, .getattr = ubifs_getattr, diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c index 405a65cd9d6b..de79f29c7e5b 100644 --- a/fs/xfs/xfs_iops.c +++ b/fs/xfs/xfs_iops.c @@ -1122,7 +1122,6 @@ static const struct inode_operations xfs_dir_ci_inode_operations = { }; static const struct inode_operations xfs_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = xfs_vn_get_link, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, @@ -1131,7 +1130,6 @@ static const struct inode_operations xfs_symlink_inode_operations = { }; static const struct inode_operations xfs_inline_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = xfs_vn_get_link_inline, .getattr = xfs_vn_getattr, .setattr = xfs_vn_setattr, diff --git a/mm/shmem.c b/mm/shmem.c index 166ebf5d2bce..aa47e6baecde 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -3174,7 +3174,6 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) #endif /* CONFIG_TMPFS_XATTR */ static const struct inode_operations shmem_short_symlink_operations = { - .readlink = generic_readlink, .get_link = simple_get_link, #ifdef CONFIG_TMPFS_XATTR .listxattr = shmem_listxattr, @@ -3182,7 +3181,6 @@ static const struct inode_operations shmem_short_symlink_operations = { }; static const struct inode_operations shmem_symlink_inode_operations = { - .readlink = generic_readlink, .get_link = shmem_get_link, #ifdef CONFIG_TMPFS_XATTR .listxattr = shmem_listxattr, -- cgit v1.2.3 From 4aa663444048396799b49b5b782552c1ba15c39d Mon Sep 17 00:00:00 2001 From: Marcin Nowakowski Date: Thu, 1 Dec 2016 09:00:55 +0100 Subject: drivers/of: fix missing pr_cont()s in of_print_phandle_args Since the KERN_CONT changes, the current debug printks have a lot of empty lines making the log messages very hard to read. Signed-off-by: Marcin Nowakowski Signed-off-by: Rob Herring --- drivers/of/base.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 128e114f9210..5e04572e692a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -1566,9 +1566,12 @@ void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) { int i; printk("%s %s", msg, of_node_full_name(args->np)); - for (i = 0; i < args->args_count; i++) - printk(i ? ",%08x" : ":%08x", args->args[i]); - printk("\n"); + for (i = 0; i < args->args_count; i++) { + const char delim = i ? ',' : ':'; + + pr_cont("%c%08x", delim, args->args[i]); + } + pr_cont("\n"); } int of_phandle_iterator_init(struct of_phandle_iterator *it, -- cgit v1.2.3 From 32bed310ad32b1cf66525fae89913d76dde4d797 Mon Sep 17 00:00:00 2001 From: Moritz Fischer Date: Thu, 1 Dec 2016 22:10:25 -0800 Subject: of: Fix issue where code would fall through to error case. No longer fall through into the error case that prints out an error if no error (err = 0) occurred. Fixes d9181b20a83(of: Add back an error message, restructured) Signed-off-by: Moritz Fischer Reviewed-by: Frank Rowand Signed-off-by: Rob Herring --- drivers/of/resolver.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c index 783bd09463b5..8bf12e904fd2 100644 --- a/drivers/of/resolver.c +++ b/drivers/of/resolver.c @@ -298,12 +298,12 @@ int of_resolve_phandles(struct device_node *overlay) if (!overlay) { pr_err("null overlay\n"); err = -EINVAL; - goto err_out; + goto out; } if (!of_node_check_flag(overlay, OF_DETACHED)) { pr_err("overlay not detached\n"); err = -EINVAL; - goto err_out; + goto out; } phandle_delta = live_tree_max_phandle() + 1; @@ -315,7 +315,7 @@ int of_resolve_phandles(struct device_node *overlay) err = adjust_local_phandle_references(local_fixups, overlay, phandle_delta); if (err) - goto err_out; + goto out; overlay_fixups = NULL; @@ -333,7 +333,7 @@ int of_resolve_phandles(struct device_node *overlay) if (!tree_symbols) { pr_err("no symbols in root of device tree.\n"); err = -EINVAL; - goto err_out; + goto out; } for_each_property_of_node(overlay_fixups, prop) { @@ -345,12 +345,12 @@ int of_resolve_phandles(struct device_node *overlay) err = of_property_read_string(tree_symbols, prop->name, &refpath); if (err) - goto err_out; + goto out; refnode = of_find_node_by_path(refpath); if (!refnode) { err = -ENOENT; - goto err_out; + goto out; } phandle = refnode->phandle; @@ -361,9 +361,9 @@ int of_resolve_phandles(struct device_node *overlay) break; } -err_out: - pr_err("overlay phandle fixup failed: %d\n", err); out: + if (err) + pr_err("overlay phandle fixup failed: %d\n", err); of_node_put(tree_symbols); return err; -- cgit v1.2.3 From 0a8b13eab1349337db4a4b5755466460bfbbaa1e Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Fri, 9 Dec 2016 10:33:48 -0600 Subject: Revert "of: base: add support to get machine model name" This reverts commit e5269794d2e9046dd45be15bdb213a229df46b7e. --- drivers/of/base.c | 32 -------------------------------- include/linux/of.h | 6 ------ 2 files changed, 38 deletions(-) (limited to 'drivers') diff --git a/drivers/of/base.c b/drivers/of/base.c index 5e04572e692a..60b878e88a48 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -545,38 +545,6 @@ int of_machine_is_compatible(const char *compat) } EXPORT_SYMBOL(of_machine_is_compatible); -/** - * of_machine_get_model_name - Find and read the model name or the compatible - * value for the machine. - * @model: pointer to null terminated return string, modified only if - * return value is 0. - * - * Returns a string containing either the model name or the compatible value - * of the machine if found, else return error. - * - * Search for a machine model name or the compatible if model name is missing - * in a device tree node and retrieve a null terminated string value (pointer - * to data, not a copy). Returns 0 on success, -EINVAL if root of the device - * tree is not found and other error returned by of_property_read_string on - * failure. - */ -int of_machine_get_model_name(const char **model) -{ - int error; - - if (!of_node_get(of_root)) - return -EINVAL; - - error = of_property_read_string(of_root, "model", model); - if (error) - error = of_property_read_string_index(of_root, "compatible", - 0, model); - of_node_put(of_root); - - return error; -} -EXPORT_SYMBOL(of_machine_get_model_name); - /** * __of_device_is_available - check if a device is available for use * diff --git a/include/linux/of.h b/include/linux/of.h index 9eb8eb3c587e..299aeb192727 100644 --- a/include/linux/of.h +++ b/include/linux/of.h @@ -367,7 +367,6 @@ extern int of_alias_get_id(struct device_node *np, const char *stem); extern int of_alias_get_highest_id(const char *stem); extern int of_machine_is_compatible(const char *compat); -extern int of_machine_get_model_name(const char **model); extern int of_add_property(struct device_node *np, struct property *prop); extern int of_remove_property(struct device_node *np, struct property *prop); @@ -789,11 +788,6 @@ static inline int of_machine_is_compatible(const char *compat) return 0; } -static inline int of_machine_get_model_name(const char **model) -{ - return -EINVAL; -} - static inline bool of_console_check(const struct device_node *dn, const char *name, int index) { return false; -- cgit v1.2.3 From 8cc3bb0789eab91e5543c7b9fbc3bde7f9c8973b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 18 Nov 2016 15:45:56 -0800 Subject: target: Use NULL instead of 0 to represent a pointer This has been detected by sparse. Signed-off-by: Bart Van Assche --- drivers/target/target_core_configfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index 2001005bef45..3bf6384c0f96 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c @@ -144,12 +144,12 @@ static ssize_t target_core_item_dbroot_store(struct config_item *item, return -EINVAL; } if (!S_ISDIR(fp->f_inode->i_mode)) { - filp_close(fp, 0); + filp_close(fp, NULL); mutex_unlock(&g_tf_lock); pr_err("db_root: not a directory: %s\n", db_root_stage); return -EINVAL; } - filp_close(fp, 0); + filp_close(fp, NULL); strncpy(db_root, db_root_stage, read_bytes); -- cgit v1.2.3 From ecaf597b411e9a7b071bf7a36a4cf750c529cd28 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 18 Nov 2016 15:32:59 -0800 Subject: target/user: Fix a data type in tcmu_queue_cmd() This patch avoids that sparse reports the following error messages: drivers/target/target_core_user.c:547:13: warning: incorrect type in assignment (different base types) drivers/target/target_core_user.c:547:13: expected int [signed] ret drivers/target/target_core_user.c:547:13: got restricted sense_reason_t drivers/target/target_core_user.c:548:20: warning: restricted sense_reason_t degrades to integer drivers/target/target_core_user.c:557:16: warning: incorrect type in return expression (different base types) drivers/target/target_core_user.c:557:16: expected restricted sense_reason_t drivers/target/target_core_user.c:557:16: got int [signed] ret Signed-off-by: Bart Van Assche --- drivers/target/target_core_user.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 47562509b489..b9eb0b605b0b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -537,7 +537,7 @@ tcmu_queue_cmd(struct se_cmd *se_cmd) struct se_device *se_dev = se_cmd->se_dev; struct tcmu_dev *udev = TCMU_DEV(se_dev); struct tcmu_cmd *tcmu_cmd; - int ret; + sense_reason_t ret; tcmu_cmd = tcmu_alloc_cmd(se_cmd); if (!tcmu_cmd) -- cgit v1.2.3 From 8456066a57940b3884aa080c58b166567dc9de39 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 18 Nov 2016 15:40:31 -0800 Subject: sbp-target: Fix second argument of percpu_ida_alloc() Pass a task state as second argument to percpu_ida_alloc(). Fixes: commit 5a3ee221b543 ("sbp-target: Conversion to percpu_ida tag pre-allocation") Signed-off-by: Bart Van Assche Cc: Chris Boot --- drivers/target/sbp/sbp_target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 58bb6ed18185..6ca388eca33b 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -928,7 +928,7 @@ static struct sbp_target_request *sbp_mgt_get_req(struct sbp_session *sess, struct sbp_target_request *req; int tag; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); if (tag < 0) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From 03274445c01562d5352ea522431ab8c6175e2bbf Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 18 Nov 2016 15:42:41 -0800 Subject: usb: gadget: Fix second argument of percpu_ida_alloc() Pass a task state as second argument to percpu_ida_alloc(). Fixes: commit 71e7ae8e1fb2 ("usb-gadget/tcm: Conversion to percpu_ida tag pre-allocation") Signed-off-by: Bart Van Assche Cc: Nicholas Bellinger Cc: Andrzej Pietrasiewicz Cc: Sebastian Andrzej Siewior Cc: Felipe Balbi --- drivers/usb/gadget/function/f_tcm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_tcm.c b/drivers/usb/gadget/function/f_tcm.c index 197f73386fac..d2351139342f 100644 --- a/drivers/usb/gadget/function/f_tcm.c +++ b/drivers/usb/gadget/function/f_tcm.c @@ -1073,7 +1073,7 @@ static struct usbg_cmd *usbg_get_cmd(struct f_uas *fu, struct usbg_cmd *cmd; int tag; - tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC); + tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING); if (tag < 0) return ERR_PTR(-ENOMEM); -- cgit v1.2.3 From 09ce66aee7763686a22ab26fbe8a889e0cec64e9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 15 Nov 2016 11:21:46 -0800 Subject: qla2xxx: Add an #include directive The following statement in qla_isr.c needs the size of struct t10_pi_tuple: spt += j; Hence include the header file. Signed-off-by: Bart Van Assche Acked-by: Himanshu Madhani --- drivers/scsi/qla2xxx/qla_isr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 068c4e47fac9..df083cc4d1d6 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -9,6 +9,7 @@ #include #include +#include #include #include #include -- cgit v1.2.3 From 4323e65b79e587b2f5ba27e1bdd91b6b54aea6b2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 15 Nov 2016 11:23:01 -0800 Subject: sbp-target: Add an #include directive usleep_range() is called from sbp_target.c. Hence include header file . Signed-off-by: Bart Van Assche Cc: Chris Boot --- drivers/target/sbp/sbp_target.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/target/sbp/sbp_target.c b/drivers/target/sbp/sbp_target.c index 6ca388eca33b..e5c3e5f827d0 100644 --- a/drivers/target/sbp/sbp_target.c +++ b/drivers/target/sbp/sbp_target.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From e9409b2672500ed53374377d861337f594f38f58 Mon Sep 17 00:00:00 2001 From: "Bryant G. Ly" Date: Wed, 16 Nov 2016 09:06:23 -0800 Subject: ibmvscsi_tgt: Add two #include directives Signed-off-by: Bryant G. Ly Signed-off-by: Bart Van Assche --- drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c | 1 + drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h | 1 + 2 files changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c index 642b739ad0da..e9321a5e3f97 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff --git a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h index 981a0c992b6c..3fb32fa26584 100644 --- a/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h +++ b/drivers/scsi/ibmvscsi_tgt/ibmvscsi_tgt.h @@ -26,6 +26,7 @@ #ifndef __H_IBMVSCSI_TGT #define __H_IBMVSCSI_TGT +#include #include "libsrp.h" #define SYS_ID_NAME_LEN 64 -- cgit v1.2.3 From 3bc71e1f43d52cca2c1823bf7816f68cf84f0d2c Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Sun, 20 Nov 2016 09:09:53 -0800 Subject: cxgbit: Add an #include directive Include header to ensure that the definition of before() is available. Signed-off-by: Bart Van Assche Cc: Varun Prakash Cc: Nicholas Bellinger --- drivers/target/iscsi/cxgbit/cxgbit_target.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/target/iscsi/cxgbit/cxgbit_target.c b/drivers/target/iscsi/cxgbit/cxgbit_target.c index d02bf58aea6d..8bcb9b71f764 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_target.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_target.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include "cxgbit.h" -- cgit v1.2.3 From f5045724578babc7bd3460087f34cc787a8b0e20 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 18 Nov 2016 15:31:45 -0800 Subject: target/user: Add an #include directive Since this driver uses kmap_atomic(), include the highmem header file. Signed-off-by: Bart Van Assche Cc: Nicholas Bellinger Cc: Andy Grover --- drivers/target/target_core_user.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index b9eb0b605b0b..1bf1d37aa2e3 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 8dcf07be2d0bcbfcebc49b9451a4feaf83e3428b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 14 Nov 2016 15:47:14 -0800 Subject: target: Minimize #include directives Remove superfluous #include directives from the include/target/*.h files. Add missing #include directives to other *.h and *.c files. Use forward declarations for structures where possible. This change reduces the build time for make M=drivers/target on my laptop from 27.1s to 18.7s or by about 30%. Signed-off-by: Bart Van Assche Cc: Christoph Hellwig Cc: Bryant G. Ly --- drivers/target/iscsi/iscsi_target.c | 2 ++ drivers/target/iscsi/iscsi_target.h | 12 ++++++++++++ drivers/target/iscsi/iscsi_target_auth.c | 2 +- drivers/target/iscsi/iscsi_target_auth.h | 5 +++++ drivers/target/iscsi/iscsi_target_configfs.c | 3 ++- drivers/target/iscsi/iscsi_target_datain_values.c | 2 +- drivers/target/iscsi/iscsi_target_datain_values.h | 3 +++ drivers/target/iscsi/iscsi_target_device.h | 3 +++ drivers/target/iscsi/iscsi_target_erl0.h | 6 ++++++ drivers/target/iscsi/iscsi_target_erl1.c | 1 + drivers/target/iscsi/iscsi_target_erl1.h | 10 ++++++++++ drivers/target/iscsi/iscsi_target_erl2.c | 1 + drivers/target/iscsi/iscsi_target_erl2.h | 7 +++++++ drivers/target/iscsi/iscsi_target_login.c | 2 ++ drivers/target/iscsi/iscsi_target_login.h | 7 +++++++ drivers/target/iscsi/iscsi_target_nego.c | 2 ++ drivers/target/iscsi/iscsi_target_nego.h | 4 ++++ drivers/target/iscsi/iscsi_target_nodeattrib.h | 5 +++++ drivers/target/iscsi/iscsi_target_parameters.c | 2 +- drivers/target/iscsi/iscsi_target_parameters.h | 6 ++++++ drivers/target/iscsi/iscsi_target_seq_pdu_list.h | 5 +++++ drivers/target/iscsi/iscsi_target_tmr.h | 6 ++++++ drivers/target/iscsi/iscsi_target_tpg.c | 2 +- drivers/target/iscsi/iscsi_target_tpg.h | 9 +++++++++ drivers/target/iscsi/iscsi_target_transport.c | 1 + drivers/target/iscsi/iscsi_target_util.c | 1 + drivers/target/iscsi/iscsi_target_util.h | 8 ++++++++ drivers/target/loopback/tcm_loop.h | 4 ++++ drivers/target/target_core_alua.c | 3 +++ drivers/target/target_core_alua.h | 2 ++ drivers/target/target_core_device.c | 1 + drivers/target/target_core_file.c | 1 + drivers/target/target_core_file.h | 2 ++ drivers/target/target_core_iblock.h | 3 +++ drivers/target/target_core_internal.h | 5 +++++ drivers/target/target_core_pr.c | 2 ++ drivers/target/target_core_pr.h | 4 ++++ drivers/target/target_core_pscsi.h | 7 ++++--- drivers/target/target_core_rd.c | 2 ++ drivers/target/target_core_rd.h | 4 ++++ drivers/target/target_core_sbc.c | 1 + drivers/target/target_core_ua.h | 2 ++ drivers/target/target_core_xcopy.c | 1 + drivers/target/target_core_xcopy.h | 2 ++ drivers/target/tcm_fc/tcm_fc.h | 3 +++ include/target/iscsi/iscsi_target_core.h | 14 ++++++++------ include/target/iscsi/iscsi_target_stat.h | 4 ++++ include/target/iscsi/iscsi_transport.h | 6 +++--- include/target/target_core_backend.h | 6 ++++++ include/target/target_core_base.h | 12 ++++-------- include/target/target_core_fabric.h | 4 ++++ 51 files changed, 187 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index b7d747e92c7a..da2c73a255de 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include #include diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index 4cf2c0f2ba2f..e0db2ceb0f87 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h @@ -1,6 +1,18 @@ #ifndef ISCSI_TARGET_H #define ISCSI_TARGET_H +#include +#include + +struct iscsi_cmd; +struct iscsi_conn; +struct iscsi_np; +struct iscsi_portal_group; +struct iscsi_session; +struct iscsi_tpg_np; +struct kref; +struct sockaddr_storage; + extern struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *); extern struct iscsi_tiqn *iscsit_get_tiqn(unsigned char *, int); extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *); diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index e116f0e845c0..903b667f8e01 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -20,8 +20,8 @@ #include #include #include +#include #include - #include #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h index d22f7b96a06c..1b91c13cc965 100644 --- a/drivers/target/iscsi/iscsi_target_auth.h +++ b/drivers/target/iscsi/iscsi_target_auth.h @@ -1,6 +1,8 @@ #ifndef _ISCSI_CHAP_H_ #define _ISCSI_CHAP_H_ +#include + #define CHAP_DIGEST_UNKNOWN 0 #define CHAP_DIGEST_MD5 5 #define CHAP_DIGEST_SHA 6 @@ -18,6 +20,9 @@ #define CHAP_STAGE_CLIENT_NRIC 4 #define CHAP_STAGE_SERVER_NR 5 +struct iscsi_node_auth; +struct iscsi_conn; + extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *, char *, int *, int *); diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 923c032f0b95..7bfb16d407b9 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -21,10 +21,11 @@ #include #include #include +#include +#include #include #include #include - #include #include "iscsi_target_parameters.h" #include "iscsi_target_device.h" diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c index 647d4a5dca52..173ddd93c757 100644 --- a/drivers/target/iscsi/iscsi_target_datain_values.c +++ b/drivers/target/iscsi/iscsi_target_datain_values.c @@ -16,8 +16,8 @@ * GNU General Public License for more details. ******************************************************************************/ +#include #include - #include #include "iscsi_target_seq_pdu_list.h" #include "iscsi_target_erl1.h" diff --git a/drivers/target/iscsi/iscsi_target_datain_values.h b/drivers/target/iscsi/iscsi_target_datain_values.h index 646429ac5a02..16edeeeb7777 100644 --- a/drivers/target/iscsi/iscsi_target_datain_values.h +++ b/drivers/target/iscsi/iscsi_target_datain_values.h @@ -1,6 +1,9 @@ #ifndef ISCSI_TARGET_DATAIN_VALUES_H #define ISCSI_TARGET_DATAIN_VALUES_H +struct iscsi_cmd; +struct iscsi_datain; + extern struct iscsi_datain_req *iscsit_allocate_datain_req(void); extern void iscsit_attach_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *); extern void iscsit_free_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *); diff --git a/drivers/target/iscsi/iscsi_target_device.h b/drivers/target/iscsi/iscsi_target_device.h index a0e2df9e8090..06dbff5cd520 100644 --- a/drivers/target/iscsi/iscsi_target_device.h +++ b/drivers/target/iscsi/iscsi_target_device.h @@ -1,6 +1,9 @@ #ifndef ISCSI_TARGET_DEVICE_H #define ISCSI_TARGET_DEVICE_H +struct iscsi_cmd; +struct iscsi_session; + extern void iscsit_determine_maxcmdsn(struct iscsi_session *); extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *); diff --git a/drivers/target/iscsi/iscsi_target_erl0.h b/drivers/target/iscsi/iscsi_target_erl0.h index a9e2f9497fb2..60e69e2af6ed 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.h +++ b/drivers/target/iscsi/iscsi_target_erl0.h @@ -1,6 +1,12 @@ #ifndef ISCSI_TARGET_ERL0_H #define ISCSI_TARGET_ERL0_H +#include + +struct iscsi_cmd; +struct iscsi_conn; +struct iscsi_session; + extern void iscsit_set_dataout_sequence_values(struct iscsi_cmd *); extern int iscsit_check_pre_dataout(struct iscsi_cmd *, unsigned char *); extern int iscsit_check_post_dataout(struct iscsi_cmd *, unsigned char *, u8); diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 9214c9dafa2b..fe9b7f1e44ac 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c @@ -17,6 +17,7 @@ ******************************************************************************/ #include +#include #include #include #include diff --git a/drivers/target/iscsi/iscsi_target_erl1.h b/drivers/target/iscsi/iscsi_target_erl1.h index 2a3ebf118a34..54d36bd25bea 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.h +++ b/drivers/target/iscsi/iscsi_target_erl1.h @@ -1,6 +1,16 @@ #ifndef ISCSI_TARGET_ERL1_H #define ISCSI_TARGET_ERL1_H +#include +#include /* itt_t */ + +struct iscsi_cmd; +struct iscsi_conn; +struct iscsi_datain_req; +struct iscsi_ooo_cmdsn; +struct iscsi_pdu; +struct iscsi_session; + extern int iscsit_dump_data_payload(struct iscsi_conn *, u32, int); extern int iscsit_create_recovery_datain_values_datasequenceinorder_yes( struct iscsi_cmd *, struct iscsi_datain_req *); diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index e24f1c7c5862..faf9ae014b30 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c @@ -17,6 +17,7 @@ * GNU General Public License for more details. ******************************************************************************/ +#include #include #include #include diff --git a/drivers/target/iscsi/iscsi_target_erl2.h b/drivers/target/iscsi/iscsi_target_erl2.h index 63f2501f3fe0..7965f1e86506 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.h +++ b/drivers/target/iscsi/iscsi_target_erl2.h @@ -1,6 +1,13 @@ #ifndef ISCSI_TARGET_ERL2_H #define ISCSI_TARGET_ERL2_H +#include + +struct iscsi_cmd; +struct iscsi_conn; +struct iscsi_conn_recovery; +struct iscsi_session; + extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, __be32); extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *); extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 15f79a2ca34a..450f51deb2a2 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c @@ -20,6 +20,8 @@ #include #include #include +#include /* TCP_NODELAY */ +#include /* ipv6_addr_v4mapped() */ #include #include #include diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index b597aa2c61a1..0e1fd6cedd54 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h @@ -1,6 +1,13 @@ #ifndef ISCSI_TARGET_LOGIN_H #define ISCSI_TARGET_LOGIN_H +#include + +struct iscsi_conn; +struct iscsi_login; +struct iscsi_np; +struct sockaddr_storage; + extern int iscsi_login_setup_crypto(struct iscsi_conn *); extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *); extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32); diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 89d34bd6d87f..46388c9e08da 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include #include diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h index f021cbd330e5..53438bfca4c6 100644 --- a/drivers/target/iscsi/iscsi_target_nego.h +++ b/drivers/target/iscsi/iscsi_target_nego.h @@ -4,6 +4,10 @@ #define DECIMAL 0 #define HEX 1 +struct iscsi_conn; +struct iscsi_login; +struct iscsi_np; + extern void convert_null_to_semi(char *, int); extern int extract_param(const char *, const char *, unsigned int, char *, unsigned char *); diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.h b/drivers/target/iscsi/iscsi_target_nodeattrib.h index 0c69a46a62ec..79cdf06ade48 100644 --- a/drivers/target/iscsi/iscsi_target_nodeattrib.h +++ b/drivers/target/iscsi/iscsi_target_nodeattrib.h @@ -1,6 +1,11 @@ #ifndef ISCSI_TARGET_NODEATTRIB_H #define ISCSI_TARGET_NODEATTRIB_H +#include + +struct iscsi_node_acl; +struct iscsi_portal_group; + extern void iscsit_set_default_node_attribues(struct iscsi_node_acl *, struct iscsi_portal_group *); extern int iscsit_na_dataout_timeout(struct iscsi_node_acl *, u32); diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 0efa80bb8962..e65bf78ceef3 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c @@ -17,7 +17,7 @@ ******************************************************************************/ #include - +#include /* struct kvec */ #include #include "iscsi_target_util.h" #include "iscsi_target_parameters.h" diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h index a0751e3f0813..9962ccf0ccd7 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.h +++ b/drivers/target/iscsi/iscsi_target_parameters.h @@ -1,6 +1,7 @@ #ifndef ISCSI_PARAMETERS_H #define ISCSI_PARAMETERS_H +#include #include struct iscsi_extra_response { @@ -23,6 +24,11 @@ struct iscsi_param { struct list_head p_list; } ____cacheline_aligned; +struct iscsi_conn; +struct iscsi_conn_ops; +struct iscsi_param_list; +struct iscsi_sess_ops; + extern int iscsi_login_rx_data(struct iscsi_conn *, char *, int); extern int iscsi_login_tx_data(struct iscsi_conn *, char *, char *, int); extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *); diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.h b/drivers/target/iscsi/iscsi_target_seq_pdu_list.h index d5b153751a8d..be1234362271 100644 --- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.h +++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.h @@ -1,6 +1,9 @@ #ifndef ISCSI_SEQ_AND_PDU_LIST_H #define ISCSI_SEQ_AND_PDU_LIST_H +#include +#include + /* struct iscsi_pdu->status */ #define DATAOUT_PDU_SENT 1 @@ -78,6 +81,8 @@ struct iscsi_seq { u32 xfer_len; } ____cacheline_aligned; +struct iscsi_cmd; + extern int iscsit_build_pdu_and_seq_lists(struct iscsi_cmd *, u32); extern struct iscsi_pdu *iscsit_get_pdu_holder(struct iscsi_cmd *, u32, u32); extern struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(struct iscsi_cmd *, struct iscsi_seq *); diff --git a/drivers/target/iscsi/iscsi_target_tmr.h b/drivers/target/iscsi/iscsi_target_tmr.h index 142e992cb097..64cc5c07e47c 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.h +++ b/drivers/target/iscsi/iscsi_target_tmr.h @@ -1,6 +1,12 @@ #ifndef ISCSI_TARGET_TMR_H #define ISCSI_TARGET_TMR_H +#include + +struct iscsi_cmd; +struct iscsi_conn; +struct iscsi_tmr_req; + extern u8 iscsit_tmr_abort_task(struct iscsi_cmd *, unsigned char *); extern int iscsit_tmr_task_warm_reset(struct iscsi_conn *, struct iscsi_tmr_req *, unsigned char *); diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 0814e5894a96..552151579a28 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -16,9 +16,9 @@ * GNU General Public License for more details. ******************************************************************************/ +#include #include #include - #include #include "iscsi_target_erl0.h" #include "iscsi_target_login.h" diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index 2da211920c18..ceba29851167 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h @@ -1,6 +1,15 @@ #ifndef ISCSI_TARGET_TPG_H #define ISCSI_TARGET_TPG_H +#include + +struct iscsi_np; +struct iscsi_session; +struct iscsi_tiqn; +struct iscsi_tpg_np; +struct se_node_acl; +struct sockaddr_storage; + extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *, u16); extern int iscsit_load_discovery_tpg(void); extern void iscsit_release_discovery_tpg(void); diff --git a/drivers/target/iscsi/iscsi_target_transport.c b/drivers/target/iscsi/iscsi_target_transport.c index 08217d62fb0d..c4eb141c6435 100644 --- a/drivers/target/iscsi/iscsi_target_transport.c +++ b/drivers/target/iscsi/iscsi_target_transport.c @@ -1,5 +1,6 @@ #include #include +#include #include static LIST_HEAD(g_transport_list); diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 1f38177207e0..b5a1b4ccba12 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c @@ -18,6 +18,7 @@ #include #include +#include /* ipv6_addr_equal() */ #include #include #include diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 995f1cb29d0e..8ff08856516a 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h @@ -1,8 +1,16 @@ #ifndef ISCSI_TARGET_UTIL_H #define ISCSI_TARGET_UTIL_H +#include +#include /* itt_t */ + #define MARKER_SIZE 8 +struct iscsi_cmd; +struct iscsi_conn; +struct iscsi_conn_recovery; +struct iscsi_session; + extern int iscsit_add_r2t_to_list(struct iscsi_cmd *, u32, u32, int, u32); extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32); extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *); diff --git a/drivers/target/loopback/tcm_loop.h b/drivers/target/loopback/tcm_loop.h index 4346462094a1..a8a230b4e6b5 100644 --- a/drivers/target/loopback/tcm_loop.h +++ b/drivers/target/loopback/tcm_loop.h @@ -1,3 +1,7 @@ +#include +#include +#include /* struct se_cmd */ + #define TCM_LOOP_VERSION "v2.1-rc2" #define TL_WWN_ADDR_LEN 256 #define TL_TPGS_PER_HBA 32 diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index 4c82bbe19003..f5e330099bfc 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c @@ -26,8 +26,11 @@ #include #include #include +#include #include +#include #include +#include #include #include diff --git a/drivers/target/target_core_alua.h b/drivers/target/target_core_alua.h index 9b250f9b33bf..c69c11baf07f 100644 --- a/drivers/target/target_core_alua.h +++ b/drivers/target/target_core_alua.h @@ -1,6 +1,8 @@ #ifndef TARGET_CORE_ALUA_H #define TARGET_CORE_ALUA_H +#include + /* * INQUIRY response data, TPGS Field * diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 6b423485c5d6..1ebd13ef7bd3 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index d545993df18b..87aa376a1a1a 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index 068966fce308..526595a072de 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h @@ -1,6 +1,8 @@ #ifndef TARGET_CORE_FILE_H #define TARGET_CORE_FILE_H +#include + #define FD_VERSION "4.0" #define FD_MAX_DEV_NAME 256 diff --git a/drivers/target/target_core_iblock.h b/drivers/target/target_core_iblock.h index 01c2afd81500..718d3fcd3e7c 100644 --- a/drivers/target/target_core_iblock.h +++ b/drivers/target/target_core_iblock.h @@ -1,6 +1,9 @@ #ifndef TARGET_CORE_IBLOCK_H #define TARGET_CORE_IBLOCK_H +#include +#include + #define IBLOCK_VERSION "4.0" #define IBLOCK_MAX_CDBS 16 diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index e2c970a9d61c..9ab7090f7c83 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h @@ -1,6 +1,11 @@ #ifndef TARGET_CORE_INTERNAL_H #define TARGET_CORE_INTERNAL_H +#include +#include +#include +#include + #define TARGET_CORE_NAME_MAX_LEN 64 #define TARGET_FABRIC_NAME_SIZE 32 diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 47463c99c318..d7fe569eece5 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include diff --git a/drivers/target/target_core_pr.h b/drivers/target/target_core_pr.h index e3d26e9126a0..847bd470339c 100644 --- a/drivers/target/target_core_pr.h +++ b/drivers/target/target_core_pr.h @@ -1,5 +1,9 @@ #ifndef TARGET_CORE_PR_H #define TARGET_CORE_PR_H + +#include +#include + /* * PERSISTENT_RESERVE_OUT service action codes * diff --git a/drivers/target/target_core_pscsi.h b/drivers/target/target_core_pscsi.h index 6d2007e35df6..8a02fa47c7e8 100644 --- a/drivers/target/target_core_pscsi.h +++ b/drivers/target/target_core_pscsi.h @@ -15,11 +15,12 @@ #define PS_TIMEOUT_DISK (15*HZ) #define PS_TIMEOUT_OTHER (500*HZ) -#include -#include -#include +#include /* ___cacheline_aligned */ +#include /* struct se_device */ +struct block_device; struct scsi_device; +struct Scsi_Host; struct pscsi_plugin_task { unsigned char pscsi_sense[TRANSPORT_SENSE_BUFFER]; diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 24b36fd785f1..ddc216c9f1f6 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c @@ -26,7 +26,9 @@ #include #include +#include #include +#include #include #include #include diff --git a/drivers/target/target_core_rd.h b/drivers/target/target_core_rd.h index cc46a6a89b38..91fc1a34791d 100644 --- a/drivers/target/target_core_rd.h +++ b/drivers/target/target_core_rd.h @@ -1,6 +1,10 @@ #ifndef TARGET_CORE_RD_H #define TARGET_CORE_RD_H +#include +#include +#include + #define RD_HBA_VERSION "v4.0" #define RD_MCP_VERSION "4.0" diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 04f616b3ba0a..4879e70e2eef 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/target/target_core_ua.h b/drivers/target/target_core_ua.h index bd6e78ba153d..97402856a8f0 100644 --- a/drivers/target/target_core_ua.h +++ b/drivers/target/target_core_ua.h @@ -1,6 +1,8 @@ #ifndef TARGET_CORE_UA_H #define TARGET_CORE_UA_H +#include + /* * From spc4r17, Table D.1: ASC and ASCQ Assignement */ diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 094a1440eacb..37d5caebffa6 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h index 700a981c7b41..4d3d4dd060f2 100644 --- a/drivers/target/target_core_xcopy.h +++ b/drivers/target/target_core_xcopy.h @@ -1,3 +1,5 @@ +#include + #define XCOPY_TARGET_DESC_LEN 32 #define XCOPY_SEGMENT_DESC_LEN 28 #define XCOPY_NAA_IEEE_REGEX_LEN 16 diff --git a/drivers/target/tcm_fc/tcm_fc.h b/drivers/target/tcm_fc/tcm_fc.h index e28209b99b59..11d27b93b413 100644 --- a/drivers/target/tcm_fc/tcm_fc.h +++ b/drivers/target/tcm_fc/tcm_fc.h @@ -17,6 +17,9 @@ #ifndef __TCM_FC_H__ #define __TCM_FC_H__ +#include +#include + #define FT_VERSION "0.4" #define FT_NAMELEN 32 /* length of ASCII WWPNs including pad */ diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 4ac24f5a3308..275581d483dd 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h @@ -1,12 +1,14 @@ #ifndef ISCSI_TARGET_CORE_H #define ISCSI_TARGET_CORE_H -#include -#include -#include -#include -#include -#include +#include /* enum dma_data_direction */ +#include /* struct list_head */ +#include /* struct sockaddr_storage */ +#include /* u8 */ +#include /* itt_t */ +#include /* struct se_cmd */ + +struct sock; #define ISCSIT_VERSION "v4.1.0" #define ISCSI_MAX_DATASN_MISSING_COUNT 16 diff --git a/include/target/iscsi/iscsi_target_stat.h b/include/target/iscsi/iscsi_target_stat.h index e615bb485d0b..c27dd471656d 100644 --- a/include/target/iscsi/iscsi_target_stat.h +++ b/include/target/iscsi/iscsi_target_stat.h @@ -1,6 +1,10 @@ #ifndef ISCSI_TARGET_STAT_H #define ISCSI_TARGET_STAT_H +#include +#include +#include + /* * For struct iscsi_tiqn->tiqn_wwn default groups */ diff --git a/include/target/iscsi/iscsi_transport.h b/include/target/iscsi/iscsi_transport.h index 40ac7cd80150..1277e9ba0318 100644 --- a/include/target/iscsi/iscsi_transport.h +++ b/include/target/iscsi/iscsi_transport.h @@ -1,6 +1,6 @@ -#include -#include -#include "iscsi_target_core.h" +#include "iscsi_target_core.h" /* struct iscsi_cmd */ + +struct sockaddr_storage; struct iscsit_transport { #define ISCSIT_TRANSPORT_NAME 16 diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index f6f3bc52c1ac..b54b98dc2d4a 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h @@ -1,8 +1,14 @@ #ifndef TARGET_CORE_BACKEND_H #define TARGET_CORE_BACKEND_H +#include +#include + #define TRANSPORT_FLAG_PASSTHROUGH 1 +struct request_queue; +struct scatterlist; + struct target_backend_ops { char name[16]; char inquiry_prod[16]; diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c2119008990a..ca8ec7218f39 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -1,14 +1,10 @@ #ifndef TARGET_CORE_BASE_H #define TARGET_CORE_BASE_H -#include -#include -#include -#include -#include -#include -#include -#include +#include /* struct config_group */ +#include /* enum dma_data_direction */ +#include /* struct percpu_ida */ +#include /* struct semaphore */ #define TARGET_CORE_VERSION "v5.0" diff --git a/include/target/target_core_fabric.h b/include/target/target_core_fabric.h index 5cd6faa6e0d1..358041bad1da 100644 --- a/include/target/target_core_fabric.h +++ b/include/target/target_core_fabric.h @@ -1,6 +1,10 @@ #ifndef TARGET_CORE_FABRIC_H #define TARGET_CORE_FABRIC_H +#include +#include +#include + struct target_core_fabric_ops { struct module *module; const char *name; -- cgit v1.2.3 From 39e7ac1bcf0fd1e2a607a35c30ebba4012a12d90 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Sun, 4 Dec 2016 13:44:59 +0100 Subject: soc/fsl/qman: test: use DEFINE_SPINLOCK() Signed-off-by: Fabian Frederick Signed-off-by: Scott Wood --- drivers/soc/fsl/qbman/qman_test_stash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/soc/fsl/qbman/qman_test_stash.c b/drivers/soc/fsl/qbman/qman_test_stash.c index b9795f39bcc8..e87b65403b67 100644 --- a/drivers/soc/fsl/qbman/qman_test_stash.c +++ b/drivers/soc/fsl/qbman/qman_test_stash.c @@ -175,7 +175,7 @@ static DEFINE_PER_CPU(struct hp_cpu, hp_cpus); /* links together the hp_cpu structs, in first-come first-serve order. */ static LIST_HEAD(hp_cpu_list); -static spinlock_t hp_lock = __SPIN_LOCK_UNLOCKED(hp_lock); +static DEFINE_SPINLOCK(hp_lock); static unsigned int hp_cpu_list_length; -- cgit v1.2.3 From af7d9f0c57941b465043681cb5c3410f7f3f1a41 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 10 Dec 2016 08:12:05 -0800 Subject: libnvdimm, pfn: fix align attribute Fix the format specifier so that the attribute can be parsed correctly. Currently it returns decimal 1000 for a 4096-byte alignment. Cc: Reported-by: Dave Jiang Fixes: 315c562536c4 ("libnvdimm, pfn: add 'align' attribute, default to HPAGE_SIZE") Signed-off-by: Dan Williams --- drivers/nvdimm/pfn_devs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/nvdimm/pfn_devs.c b/drivers/nvdimm/pfn_devs.c index cea8350fbc7e..a2ac9e641aa9 100644 --- a/drivers/nvdimm/pfn_devs.c +++ b/drivers/nvdimm/pfn_devs.c @@ -108,7 +108,7 @@ static ssize_t align_show(struct device *dev, { struct nd_pfn *nd_pfn = to_nd_pfn_safe(dev); - return sprintf(buf, "%lx\n", nd_pfn->align); + return sprintf(buf, "%ld\n", nd_pfn->align); } static ssize_t __align_store(struct nd_pfn *nd_pfn, const char *buf) -- cgit v1.2.3 From 62aeddbf28fa63872e8f13f47177338b0f1fd8b5 Mon Sep 17 00:00:00 2001 From: Dean Luick Date: Wed, 7 Dec 2016 19:32:15 -0800 Subject: IB/hfi1: Read new EPROM format Add the ability to read the new EPROM format. Reviewed-by: Easwar Hariharan Signed-off-by: Dean Luick Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/eprom.c | 211 +++++++++++++++++++++++++++++++++++-- 1 file changed, 203 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/eprom.c b/drivers/infiniband/hw/hfi1/eprom.c index e70c223801b4..26da124c88e2 100644 --- a/drivers/infiniband/hw/hfi1/eprom.c +++ b/drivers/infiniband/hw/hfi1/eprom.c @@ -207,6 +207,40 @@ done_asic: /* magic character sequence that trails an image */ #define IMAGE_TRAIL_MAGIC "egamiAPO" +/* EPROM file types */ +#define HFI1_EFT_PLATFORM_CONFIG 2 + +/* segment size - 128 KiB */ +#define SEG_SIZE (128 * 1024) + +struct hfi1_eprom_footer { + u32 oprom_size; /* size of the oprom, in bytes */ + u16 num_table_entries; + u16 version; /* version of this footer */ + u32 magic; /* must be last */ +}; + +struct hfi1_eprom_table_entry { + u32 type; /* file type */ + u32 offset; /* file offset from start of EPROM */ + u32 size; /* file size, in bytes */ +}; + +/* + * Calculate the max number of table entries that will fit within a directory + * buffer of size 'dir_size'. + */ +#define MAX_TABLE_ENTRIES(dir_size) \ + (((dir_size) - sizeof(struct hfi1_eprom_footer)) / \ + sizeof(struct hfi1_eprom_table_entry)) + +#define DIRECTORY_SIZE(n) (sizeof(struct hfi1_eprom_footer) + \ + (sizeof(struct hfi1_eprom_table_entry) * (n))) + +#define MAGIC4(a, b, c, d) ((d) << 24 | (c) << 16 | (b) << 8 | (a)) +#define FOOTER_MAGIC MAGIC4('e', 'p', 'r', 'm') +#define FOOTER_VERSION 1 + /* * Read all of partition 1. The actual file is at the front. Adjust * the returned size if a trailing image magic is found. @@ -241,6 +275,167 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data, return 0; } +/* + * The segment magic has been checked. There is a footer and table of + * contents present. + * + * directory is a u32 aligned buffer of size EP_PAGE_SIZE. + */ +static int read_segment_platform_config(struct hfi1_devdata *dd, + void *directory, void **data, u32 *size) +{ + struct hfi1_eprom_footer *footer; + struct hfi1_eprom_table_entry *table; + struct hfi1_eprom_table_entry *entry; + void *buffer = NULL; + void *table_buffer = NULL; + int ret, i; + u32 directory_size; + u32 seg_base, seg_offset; + u32 bytes_available, ncopied, to_copy; + + /* the footer is at the end of the directory */ + footer = (struct hfi1_eprom_footer *) + (directory + EP_PAGE_SIZE - sizeof(*footer)); + + /* make sure the structure version is supported */ + if (footer->version != FOOTER_VERSION) + return -EINVAL; + + /* oprom size cannot be larger than a segment */ + if (footer->oprom_size >= SEG_SIZE) + return -EINVAL; + + /* the file table must fit in a segment with the oprom */ + if (footer->num_table_entries > + MAX_TABLE_ENTRIES(SEG_SIZE - footer->oprom_size)) + return -EINVAL; + + /* find the file table start, which precedes the footer */ + directory_size = DIRECTORY_SIZE(footer->num_table_entries); + if (directory_size <= EP_PAGE_SIZE) { + /* the file table fits into the directory buffer handed in */ + table = (struct hfi1_eprom_table_entry *) + (directory + EP_PAGE_SIZE - directory_size); + } else { + /* need to allocate and read more */ + table_buffer = kmalloc(directory_size, GFP_KERNEL); + if (!table_buffer) + return -ENOMEM; + ret = read_length(dd, SEG_SIZE - directory_size, + directory_size, table_buffer); + if (ret) + goto done; + table = table_buffer; + } + + /* look for the platform configuration file in the table */ + for (entry = NULL, i = 0; i < footer->num_table_entries; i++) { + if (table[i].type == HFI1_EFT_PLATFORM_CONFIG) { + entry = &table[i]; + break; + } + } + if (!entry) { + ret = -ENOENT; + goto done; + } + + /* + * Sanity check on the configuration file size - it should never + * be larger than 4 KiB. + */ + if (entry->size > (4 * 1024)) { + dd_dev_err(dd, "Bad configuration file size 0x%x\n", + entry->size); + ret = -EINVAL; + goto done; + } + + /* check for bogus offset and size that wrap when added together */ + if (entry->offset + entry->size < entry->offset) { + dd_dev_err(dd, + "Bad configuration file start + size 0x%x+0x%x\n", + entry->offset, entry->size); + ret = -EINVAL; + goto done; + } + + /* allocate the buffer to return */ + buffer = kmalloc(entry->size, GFP_KERNEL); + if (!buffer) { + ret = -ENOMEM; + goto done; + } + + /* + * Extract the file by looping over segments until it is fully read. + */ + seg_offset = entry->offset % SEG_SIZE; + seg_base = entry->offset - seg_offset; + ncopied = 0; + while (ncopied < entry->size) { + /* calculate data bytes available in this segment */ + + /* start with the bytes from the current offset to the end */ + bytes_available = SEG_SIZE - seg_offset; + /* subtract off footer and table from segment 0 */ + if (seg_base == 0) { + /* + * Sanity check: should not have a starting point + * at or within the directory. + */ + if (bytes_available <= directory_size) { + dd_dev_err(dd, + "Bad configuration file - offset 0x%x within footer+table\n", + entry->offset); + ret = -EINVAL; + goto done; + } + bytes_available -= directory_size; + } + + /* calculate bytes wanted */ + to_copy = entry->size - ncopied; + + /* max out at the available bytes in this segment */ + if (to_copy > bytes_available) + to_copy = bytes_available; + + /* + * Read from the EPROM. + * + * The sanity check for entry->offset is done in read_length(). + * The EPROM offset is validated against what the hardware + * addressing supports. In addition, if the offset is larger + * than the actual EPROM, it silently wraps. It will work + * fine, though the reader may not get what they expected + * from the EPROM. + */ + ret = read_length(dd, seg_base + seg_offset, to_copy, + buffer + ncopied); + if (ret) + goto done; + + ncopied += to_copy; + + /* set up for next segment */ + seg_offset = footer->oprom_size; + seg_base += SEG_SIZE; + } + + /* success */ + ret = 0; + *data = buffer; + *size = entry->size; + +done: + kfree(table_buffer); + if (ret) + kfree(buffer); + return ret; +} + /* * Read the platform configuration file from the EPROM. * @@ -253,6 +448,7 @@ static int read_partition_platform_config(struct hfi1_devdata *dd, void **data, * -EBUSY - not able to acquire access to the EPROM * -ENOENT - no recognizable file written * -ENOMEM - buffer could not be allocated + * -EINVAL - invalid EPROM contentents found */ int eprom_read_platform_config(struct hfi1_devdata *dd, void **data, u32 *size) { @@ -266,21 +462,20 @@ int eprom_read_platform_config(struct hfi1_devdata *dd, void **data, u32 *size) if (ret) return -EBUSY; - /* read the last page of P0 for the EPROM format magic */ - ret = read_length(dd, P1_START - EP_PAGE_SIZE, EP_PAGE_SIZE, directory); + /* read the last page of the segment for the EPROM format magic */ + ret = read_length(dd, SEG_SIZE - EP_PAGE_SIZE, EP_PAGE_SIZE, directory); if (ret) goto done; - /* last dword of P0 contains a magic indicator */ - if (directory[EP_PAGE_DWORDS - 1] == 0) { + /* last dword of the segment contains a magic value */ + if (directory[EP_PAGE_DWORDS - 1] == FOOTER_MAGIC) { + /* segment format */ + ret = read_segment_platform_config(dd, directory, data, size); + } else { /* partition format */ ret = read_partition_platform_config(dd, data, size); - goto done; } - /* nothing recognized */ - ret = -ENOENT; - done: release_chip_resource(dd, CR_EPROM); return ret; -- cgit v1.2.3 From d7cf4ccf6fe52694142f65cce82decb3fe833f48 Mon Sep 17 00:00:00 2001 From: Dean Luick Date: Wed, 7 Dec 2016 19:32:22 -0800 Subject: IB/hfi1: Fix dc8051 multiple qword memory reads When reading multiple dc8051 data memory locations at once, the read enabled field must be toggled at every address change. Do that by writing only the address first, then writing the enable. Reviewed-by: Ira Weiny Reviewed-by: Dennis Dalessandro Signed-off-by: Dean Luick Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/firmware.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/firmware.c b/drivers/infiniband/hw/hfi1/firmware.c index 9a36c8c2f8a1..bcf7da4599c4 100644 --- a/drivers/infiniband/hw/hfi1/firmware.c +++ b/drivers/infiniband/hw/hfi1/firmware.c @@ -263,11 +263,13 @@ static int __read_8051_data(struct hfi1_devdata *dd, u32 addr, u64 *result) u64 reg; int count; - /* start the read at the given address */ - reg = ((addr & DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_MASK) - << DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_SHIFT) - | DC_DC8051_CFG_RAM_ACCESS_CTRL_READ_ENA_SMASK; + /* step 1: set the address, clear enable */ + reg = (addr & DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_MASK) + << DC_DC8051_CFG_RAM_ACCESS_CTRL_ADDRESS_SHIFT; write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_CTRL, reg); + /* step 2: enable */ + write_csr(dd, DC_DC8051_CFG_RAM_ACCESS_CTRL, + reg | DC_DC8051_CFG_RAM_ACCESS_CTRL_READ_ENA_SMASK); /* wait until ACCESS_COMPLETED is set */ count = 0; -- cgit v1.2.3 From 53e91d264be9e9adbf34b83b8ce5c12452f6765e Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Wed, 7 Dec 2016 19:32:28 -0800 Subject: IB/hfi1: Use non-atomic __test_and_clear_bit in hot path qp->r_aflags is already protected by qp->r_lock, therefore, test_and_clear_bit() doesn't need to be atomic. Profile shows this function call is costly. Change the test_and_clear_bit() call to use the non-atomic variant. Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/rc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index 8bc5013f39a1..aaca8588e199 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -2295,7 +2295,7 @@ send_last: hfi1_copy_sge(&qp->r_sge, data, tlen, 1, copy_last); rvt_put_ss(&qp->r_sge); qp->r_msn++; - if (!test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) + if (!__test_and_clear_bit(RVT_R_WRID_VALID, &qp->r_aflags)) break; wc.wr_id = qp->r_wr_id; wc.status = IB_WC_SUCCESS; -- cgit v1.2.3 From 1b9e7749335281c086243c2dc75d2ad7c2b32abe Mon Sep 17 00:00:00 2001 From: Dean Luick Date: Wed, 7 Dec 2016 19:32:34 -0800 Subject: IB/hfi1: Export 8051 memory and LCB registers via debugfs Both the 8051 memory and LCB register access require multiple steps and coordination with the driver. This cannot be safely done with resource0 alone. The 8051 memory is exported read-only. LCB is exported read/write. Reviewed-by: Dennis Dalessandro Signed-off-by: Dean Luick Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/debugfs.c | 110 +++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/debugfs.c b/drivers/infiniband/hw/hfi1/debugfs.c index 632ba21759ab..8725f4c086cf 100644 --- a/drivers/infiniband/hw/hfi1/debugfs.c +++ b/drivers/infiniband/hw/hfi1/debugfs.c @@ -541,6 +541,114 @@ static ssize_t asic_flags_write(struct file *file, const char __user *buf, return ret; } +/* read the dc8051 memory */ +static ssize_t dc8051_memory_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct hfi1_pportdata *ppd = private2ppd(file); + ssize_t rval; + void *tmp; + loff_t start, end; + + /* the checks below expect the position to be positive */ + if (*ppos < 0) + return -EINVAL; + + tmp = kzalloc(DC8051_DATA_MEM_SIZE, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + /* + * Fill in the requested portion of the temporary buffer from the + * 8051 memory. The 8051 memory read is done in terms of 8 bytes. + * Adjust start and end to fit. Skip reading anything if out of + * range. + */ + start = *ppos & ~0x7; /* round down */ + if (start < DC8051_DATA_MEM_SIZE) { + end = (*ppos + count + 7) & ~0x7; /* round up */ + if (end > DC8051_DATA_MEM_SIZE) + end = DC8051_DATA_MEM_SIZE; + rval = read_8051_data(ppd->dd, start, end - start, + (u64 *)(tmp + start)); + if (rval) + goto done; + } + + rval = simple_read_from_buffer(buf, count, ppos, tmp, + DC8051_DATA_MEM_SIZE); +done: + kfree(tmp); + return rval; +} + +static ssize_t debugfs_lcb_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct hfi1_pportdata *ppd = private2ppd(file); + struct hfi1_devdata *dd = ppd->dd; + unsigned long total, csr_off; + u64 data; + + if (*ppos < 0) + return -EINVAL; + /* only read 8 byte quantities */ + if ((count % 8) != 0) + return -EINVAL; + /* offset must be 8-byte aligned */ + if ((*ppos % 8) != 0) + return -EINVAL; + /* do nothing if out of range or zero count */ + if (*ppos >= (LCB_END - LCB_START) || !count) + return 0; + /* reduce count if needed */ + if (*ppos + count > LCB_END - LCB_START) + count = (LCB_END - LCB_START) - *ppos; + + csr_off = LCB_START + *ppos; + for (total = 0; total < count; total += 8, csr_off += 8) { + if (read_lcb_csr(dd, csr_off, (u64 *)&data)) + break; /* failed */ + if (put_user(data, (unsigned long __user *)(buf + total))) + break; + } + *ppos += total; + return total; +} + +static ssize_t debugfs_lcb_write(struct file *file, const char __user *buf, + size_t count, loff_t *ppos) +{ + struct hfi1_pportdata *ppd = private2ppd(file); + struct hfi1_devdata *dd = ppd->dd; + unsigned long total, csr_off, data; + + if (*ppos < 0) + return -EINVAL; + /* only write 8 byte quantities */ + if ((count % 8) != 0) + return -EINVAL; + /* offset must be 8-byte aligned */ + if ((*ppos % 8) != 0) + return -EINVAL; + /* do nothing if out of range or zero count */ + if (*ppos >= (LCB_END - LCB_START) || !count) + return 0; + /* reduce count if needed */ + if (*ppos + count > LCB_END - LCB_START) + count = (LCB_END - LCB_START) - *ppos; + + csr_off = LCB_START + *ppos; + for (total = 0; total < count; total += 8, csr_off += 8) { + if (get_user(data, (unsigned long __user *)(buf + total))) + break; + if (write_lcb_csr(dd, csr_off, data)) + break; /* failed */ + } + *ppos += total; + return total; +} + /* * read the per-port QSFP data for ppd */ @@ -931,6 +1039,8 @@ static const struct counter_info port_cntr_ops[] = { DEBUGFS_XOPS("qsfp2", qsfp2_debugfs_read, qsfp2_debugfs_write, qsfp2_debugfs_open, qsfp2_debugfs_release), DEBUGFS_OPS("asic_flags", asic_flags_read, asic_flags_write), + DEBUGFS_OPS("dc8051_memory", dc8051_memory_read, NULL), + DEBUGFS_OPS("lcb", debugfs_lcb_read, debugfs_lcb_write), }; static void *_sdma_cpu_list_seq_start(struct seq_file *s, loff_t *pos) -- cgit v1.2.3 From e730139b3464cc740c33131c872f7d173744ef11 Mon Sep 17 00:00:00 2001 From: Jakub Pawlak Date: Wed, 7 Dec 2016 19:32:41 -0800 Subject: IB/hfi1: Disable header suppression for short packets For the received packets with payload less or equal 8DWS RxDmaDataFifoRdUncErr is not reported. There is set RHF.EccErr if the header is not suppressed. When such packet is detected on the send side the header suppression mechanism is disabled by clearing SH bit in the packet header. Reviewed-by: Mitko Haralanov Signed-off-by: Jakub Pawlak Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/user_sdma.c | 60 ++++++++++++++++++++++++---------- include/uapi/rdma/hfi/hfi1_user.h | 2 +- 2 files changed, 44 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/user_sdma.c b/drivers/infiniband/hw/hfi1/user_sdma.c index a761f804111e..663980ef01a8 100644 --- a/drivers/infiniband/hw/hfi1/user_sdma.c +++ b/drivers/infiniband/hw/hfi1/user_sdma.c @@ -115,6 +115,7 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12 #define KDETH_HCRC_LOWER_MASK 0xff #define AHG_KDETH_INTR_SHIFT 12 +#define AHG_KDETH_SH_SHIFT 13 #define PBC2LRH(x) ((((x) & 0xfff) << 2) - 4) #define LRH2PBC(x) ((((x) >> 2) + 1) & 0xfff) @@ -144,8 +145,9 @@ MODULE_PARM_DESC(sdma_comp_size, "Size of User SDMA completion ring. Default: 12 #define KDETH_OM_LARGE 64 #define KDETH_OM_MAX_SIZE (1 << ((KDETH_OM_LARGE / KDETH_OM_SMALL) + 1)) -/* Last packet in the request */ -#define TXREQ_FLAGS_REQ_LAST_PKT BIT(0) +/* Tx request flag bits */ +#define TXREQ_FLAGS_REQ_ACK BIT(0) /* Set the ACK bit in the header */ +#define TXREQ_FLAGS_REQ_DISABLE_SH BIT(1) /* Disable header suppression */ /* SDMA request flag bits */ #define SDMA_REQ_FOR_THREAD 1 @@ -943,8 +945,13 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) tx->busycount = 0; INIT_LIST_HEAD(&tx->list); + /* + * For the last packet set the ACK request + * and disable header suppression. + */ if (req->seqnum == req->info.npkts - 1) - tx->flags |= TXREQ_FLAGS_REQ_LAST_PKT; + tx->flags |= (TXREQ_FLAGS_REQ_ACK | + TXREQ_FLAGS_REQ_DISABLE_SH); /* * Calculate the payload size - this is min of the fragment @@ -963,11 +970,22 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) } datalen = compute_data_length(req, tx); + + /* + * Disable header suppression for the payload <= 8DWS. + * If there is an uncorrectable error in the receive + * data FIFO when the received payload size is less than + * or equal to 8DWS then the RxDmaDataFifoRdUncErr is + * not reported.There is set RHF.EccErr if the header + * is not suppressed. + */ if (!datalen) { SDMA_DBG(req, "Request has data but pkt len is 0"); ret = -EFAULT; goto free_tx; + } else if (datalen <= 32) { + tx->flags |= TXREQ_FLAGS_REQ_DISABLE_SH; } } @@ -990,6 +1008,10 @@ static int user_sdma_send_pkts(struct user_sdma_request *req, unsigned maxpkts) LRH2PBC(lrhlen); tx->hdr.pbc[0] = cpu_to_le16(pbclen); } + ret = check_header_template(req, &tx->hdr, + lrhlen, datalen); + if (ret) + goto free_tx; ret = sdma_txinit_ahg(&tx->txreq, SDMA_TXREQ_F_AHG_COPY, sizeof(tx->hdr) + datalen, @@ -1351,7 +1373,7 @@ static int set_txreq_header(struct user_sdma_request *req, req->seqnum)); /* Set ACK request on last packet */ - if (unlikely(tx->flags & TXREQ_FLAGS_REQ_LAST_PKT)) + if (unlikely(tx->flags & TXREQ_FLAGS_REQ_ACK)) hdr->bth[2] |= cpu_to_be32(1UL << 31); /* Set the new offset */ @@ -1384,8 +1406,8 @@ static int set_txreq_header(struct user_sdma_request *req, /* Set KDETH.TID based on value for this TID */ KDETH_SET(hdr->kdeth.ver_tid_offset, TID, EXP_TID_GET(tidval, IDX)); - /* Clear KDETH.SH only on the last packet */ - if (unlikely(tx->flags & TXREQ_FLAGS_REQ_LAST_PKT)) + /* Clear KDETH.SH when DISABLE_SH flag is set */ + if (unlikely(tx->flags & TXREQ_FLAGS_REQ_DISABLE_SH)) KDETH_SET(hdr->kdeth.ver_tid_offset, SH, 0); /* * Set the KDETH.OFFSET and KDETH.OM based on size of @@ -1429,7 +1451,7 @@ static int set_txreq_header_ahg(struct user_sdma_request *req, /* BTH.PSN and BTH.A */ val32 = (be32_to_cpu(hdr->bth[2]) + req->seqnum) & (HFI1_CAP_IS_KSET(EXTENDED_PSN) ? 0x7fffffff : 0xffffff); - if (unlikely(tx->flags & TXREQ_FLAGS_REQ_LAST_PKT)) + if (unlikely(tx->flags & TXREQ_FLAGS_REQ_ACK)) val32 |= 1UL << 31; AHG_HEADER_SET(req->ahg, diff, 6, 0, 16, cpu_to_be16(val32 >> 16)); AHG_HEADER_SET(req->ahg, diff, 6, 16, 16, cpu_to_be16(val32 & 0xffff)); @@ -1468,19 +1490,23 @@ static int set_txreq_header_ahg(struct user_sdma_request *req, AHG_HEADER_SET(req->ahg, diff, 7, 0, 16, ((!!(req->omfactor - KDETH_OM_SMALL)) << 15 | ((req->tidoffset / req->omfactor) & 0x7fff))); - /* KDETH.TIDCtrl, KDETH.TID */ + /* KDETH.TIDCtrl, KDETH.TID, KDETH.Intr, KDETH.SH */ val = cpu_to_le16(((EXP_TID_GET(tidval, CTRL) & 0x3) << 10) | - (EXP_TID_GET(tidval, IDX) & 0x3ff)); - /* Clear KDETH.SH on last packet */ - if (unlikely(tx->flags & TXREQ_FLAGS_REQ_LAST_PKT)) { - val |= cpu_to_le16(KDETH_GET(hdr->kdeth.ver_tid_offset, - INTR) << - AHG_KDETH_INTR_SHIFT); - val &= cpu_to_le16(~(1U << 13)); - AHG_HEADER_SET(req->ahg, diff, 7, 16, 14, val); + (EXP_TID_GET(tidval, IDX) & 0x3ff)); + + if (unlikely(tx->flags & TXREQ_FLAGS_REQ_DISABLE_SH)) { + val |= cpu_to_le16((KDETH_GET(hdr->kdeth.ver_tid_offset, + INTR) << + AHG_KDETH_INTR_SHIFT)); } else { - AHG_HEADER_SET(req->ahg, diff, 7, 16, 12, val); + val |= KDETH_GET(hdr->kdeth.ver_tid_offset, SH) ? + cpu_to_le16(0x1 << AHG_KDETH_SH_SHIFT) : + cpu_to_le16((KDETH_GET(hdr->kdeth.ver_tid_offset, + INTR) << + AHG_KDETH_INTR_SHIFT)); } + + AHG_HEADER_SET(req->ahg, diff, 7, 16, 14, val); } trace_hfi1_sdma_user_header_ahg(pq->dd, pq->ctxt, pq->subctxt, diff --git a/include/uapi/rdma/hfi/hfi1_user.h b/include/uapi/rdma/hfi/hfi1_user.h index d15e7289d835..587b7360e820 100644 --- a/include/uapi/rdma/hfi/hfi1_user.h +++ b/include/uapi/rdma/hfi/hfi1_user.h @@ -75,7 +75,7 @@ * may not be implemented; the user code must deal with this if it * cares, or it must abort after initialization reports the difference. */ -#define HFI1_USER_SWMINOR 2 +#define HFI1_USER_SWMINOR 3 /* * We will encode the major/minor inside a single 32bit version number. -- cgit v1.2.3 From cf4c2f8c9d0483f7585883d3f6733ebf09ea837c Mon Sep 17 00:00:00 2001 From: Dennis Dalessandro Date: Wed, 7 Dec 2016 19:32:47 -0800 Subject: IB/rdmavt: Fix trace hierarchy Split rdmavt traces into separate files to preserve the original hierarchy since only one trace sub system may now be defined per header file. Reviewed-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/trace.h | 140 +------------------------------ drivers/infiniband/sw/rdmavt/trace_qp.h | 96 +++++++++++++++++++++ drivers/infiniband/sw/rdmavt/trace_rvt.h | 81 ++++++++++++++++++ drivers/infiniband/sw/rdmavt/trace_tx.h | 132 +++++++++++++++++++++++++++++ 4 files changed, 312 insertions(+), 137 deletions(-) create mode 100644 drivers/infiniband/sw/rdmavt/trace_qp.h create mode 100644 drivers/infiniband/sw/rdmavt/trace_rvt.h create mode 100644 drivers/infiniband/sw/rdmavt/trace_tx.h (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/trace.h b/drivers/infiniband/sw/rdmavt/trace.h index 6c0457db5499..11a2afbc8e76 100644 --- a/drivers/infiniband/sw/rdmavt/trace.h +++ b/drivers/infiniband/sw/rdmavt/trace.h @@ -45,143 +45,9 @@ * */ -#undef TRACE_SYSTEM_VAR -#define TRACE_SYSTEM_VAR rdmavt - -#if !defined(__RDMAVT_TRACE_H) || defined(TRACE_HEADER_MULTI_READ) -#define __RDMAVT_TRACE_H - -#include -#include - -#include -#include - #define RDI_DEV_ENTRY(rdi) __string(dev, rdi->driver_f.get_card_name(rdi)) #define RDI_DEV_ASSIGN(rdi) __assign_str(dev, rdi->driver_f.get_card_name(rdi)) -#undef TRACE_SYSTEM -#define TRACE_SYSTEM rdmavt - -TRACE_EVENT(rvt_dbg, - TP_PROTO(struct rvt_dev_info *rdi, - const char *msg), - TP_ARGS(rdi, msg), - TP_STRUCT__entry( - RDI_DEV_ENTRY(rdi) - __string(msg, msg) - ), - TP_fast_assign( - RDI_DEV_ASSIGN(rdi); - __assign_str(msg, msg); - ), - TP_printk("[%s]: %s", __get_str(dev), __get_str(msg)) -); - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM rvt_qphash -DECLARE_EVENT_CLASS(rvt_qphash_template, - TP_PROTO(struct rvt_qp *qp, u32 bucket), - TP_ARGS(qp, bucket), - TP_STRUCT__entry( - RDI_DEV_ENTRY(ib_to_rvt(qp->ibqp.device)) - __field(u32, qpn) - __field(u32, bucket) - ), - TP_fast_assign( - RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device)) - __entry->qpn = qp->ibqp.qp_num; - __entry->bucket = bucket; - ), - TP_printk( - "[%s] qpn 0x%x bucket %u", - __get_str(dev), - __entry->qpn, - __entry->bucket - ) -); - -DEFINE_EVENT(rvt_qphash_template, rvt_qpinsert, - TP_PROTO(struct rvt_qp *qp, u32 bucket), - TP_ARGS(qp, bucket)); - -DEFINE_EVENT(rvt_qphash_template, rvt_qpremove, - TP_PROTO(struct rvt_qp *qp, u32 bucket), - TP_ARGS(qp, bucket)); - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM rvt_tx - -#define wr_opcode_name(opcode) { IB_WR_##opcode, #opcode } -#define show_wr_opcode(opcode) \ -__print_symbolic(opcode, \ - wr_opcode_name(RDMA_WRITE), \ - wr_opcode_name(RDMA_WRITE_WITH_IMM), \ - wr_opcode_name(SEND), \ - wr_opcode_name(SEND_WITH_IMM), \ - wr_opcode_name(RDMA_READ), \ - wr_opcode_name(ATOMIC_CMP_AND_SWP), \ - wr_opcode_name(ATOMIC_FETCH_AND_ADD), \ - wr_opcode_name(LSO), \ - wr_opcode_name(SEND_WITH_INV), \ - wr_opcode_name(RDMA_READ_WITH_INV), \ - wr_opcode_name(LOCAL_INV), \ - wr_opcode_name(MASKED_ATOMIC_CMP_AND_SWP), \ - wr_opcode_name(MASKED_ATOMIC_FETCH_AND_ADD)) - -#define POS_PRN \ -"[%s] wr_id %llx qpn %x psn 0x%x lpsn 0x%x length %u opcode 0x%.2x,%s size %u avail %u head %u last %u" - -TRACE_EVENT( - rvt_post_one_wr, - TP_PROTO(struct rvt_qp *qp, struct rvt_swqe *wqe), - TP_ARGS(qp, wqe), - TP_STRUCT__entry( - RDI_DEV_ENTRY(ib_to_rvt(qp->ibqp.device)) - __field(u64, wr_id) - __field(u32, qpn) - __field(u32, psn) - __field(u32, lpsn) - __field(u32, length) - __field(u32, opcode) - __field(u32, size) - __field(u32, avail) - __field(u32, head) - __field(u32, last) - ), - TP_fast_assign( - RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device)) - __entry->wr_id = wqe->wr.wr_id; - __entry->qpn = qp->ibqp.qp_num; - __entry->psn = wqe->psn; - __entry->lpsn = wqe->lpsn; - __entry->length = wqe->length; - __entry->opcode = wqe->wr.opcode; - __entry->size = qp->s_size; - __entry->avail = qp->s_avail; - __entry->head = qp->s_head; - __entry->last = qp->s_last; - ), - TP_printk( - POS_PRN, - __get_str(dev), - __entry->wr_id, - __entry->qpn, - __entry->psn, - __entry->lpsn, - __entry->length, - __entry->opcode, show_wr_opcode(__entry->opcode), - __entry->size, - __entry->avail, - __entry->head, - __entry->last - ) -); - -#endif /* __RDMAVT_TRACE_H */ - -#undef TRACE_INCLUDE_PATH -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_PATH . -#define TRACE_INCLUDE_FILE trace -#include +#include "trace_rvt.h" +#include "trace_qp.h" +#include "trace_tx.h" diff --git a/drivers/infiniband/sw/rdmavt/trace_qp.h b/drivers/infiniband/sw/rdmavt/trace_qp.h new file mode 100644 index 000000000000..4c77a3119bda --- /dev/null +++ b/drivers/infiniband/sw/rdmavt/trace_qp.h @@ -0,0 +1,96 @@ +/* + * Copyright(c) 2016 Intel Corporation. + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#if !defined(__RVT_TRACE_QP_H) || defined(TRACE_HEADER_MULTI_READ) +#define __RVT_TRACE_QP_H + +#include +#include + +#include +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rvt_qp + +DECLARE_EVENT_CLASS(rvt_qphash_template, + TP_PROTO(struct rvt_qp *qp, u32 bucket), + TP_ARGS(qp, bucket), + TP_STRUCT__entry( + RDI_DEV_ENTRY(ib_to_rvt(qp->ibqp.device)) + __field(u32, qpn) + __field(u32, bucket) + ), + TP_fast_assign( + RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device)) + __entry->qpn = qp->ibqp.qp_num; + __entry->bucket = bucket; + ), + TP_printk( + "[%s] qpn 0x%x bucket %u", + __get_str(dev), + __entry->qpn, + __entry->bucket + ) +); + +DEFINE_EVENT(rvt_qphash_template, rvt_qpinsert, + TP_PROTO(struct rvt_qp *qp, u32 bucket), + TP_ARGS(qp, bucket)); + +DEFINE_EVENT(rvt_qphash_template, rvt_qpremove, + TP_PROTO(struct rvt_qp *qp, u32 bucket), + TP_ARGS(qp, bucket)); + + +#endif /* __RVT_TRACE_QP_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace_qp +#include + diff --git a/drivers/infiniband/sw/rdmavt/trace_rvt.h b/drivers/infiniband/sw/rdmavt/trace_rvt.h new file mode 100644 index 000000000000..746f33461d9a --- /dev/null +++ b/drivers/infiniband/sw/rdmavt/trace_rvt.h @@ -0,0 +1,81 @@ +/* + * Copyright(c) 2016 Intel Corporation. + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#if !defined(__RVT_TRACE_RVT_H) || defined(TRACE_HEADER_MULTI_READ) +#define __RVT_TRACE_RVT_H + +#include +#include + +#include +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rvt + +TRACE_EVENT(rvt_dbg, + TP_PROTO(struct rvt_dev_info *rdi, + const char *msg), + TP_ARGS(rdi, msg), + TP_STRUCT__entry( + RDI_DEV_ENTRY(rdi) + __string(msg, msg) + ), + TP_fast_assign( + RDI_DEV_ASSIGN(rdi); + __assign_str(msg, msg); + ), + TP_printk("[%s]: %s", __get_str(dev), __get_str(msg)) +); + +#endif /* __RVT_TRACE_MISC_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace_rvt +#include + diff --git a/drivers/infiniband/sw/rdmavt/trace_tx.h b/drivers/infiniband/sw/rdmavt/trace_tx.h new file mode 100644 index 000000000000..0e03173662d8 --- /dev/null +++ b/drivers/infiniband/sw/rdmavt/trace_tx.h @@ -0,0 +1,132 @@ +/* + * Copyright(c) 2016 Intel Corporation. + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#if !defined(__RVT_TRACE_TX_H) || defined(TRACE_HEADER_MULTI_READ) +#define __RVT_TRACE_TX_H + +#include +#include + +#include +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rvt_tx + +#define wr_opcode_name(opcode) { IB_WR_##opcode, #opcode } +#define show_wr_opcode(opcode) \ +__print_symbolic(opcode, \ + wr_opcode_name(RDMA_WRITE), \ + wr_opcode_name(RDMA_WRITE_WITH_IMM), \ + wr_opcode_name(SEND), \ + wr_opcode_name(SEND_WITH_IMM), \ + wr_opcode_name(RDMA_READ), \ + wr_opcode_name(ATOMIC_CMP_AND_SWP), \ + wr_opcode_name(ATOMIC_FETCH_AND_ADD), \ + wr_opcode_name(LSO), \ + wr_opcode_name(SEND_WITH_INV), \ + wr_opcode_name(RDMA_READ_WITH_INV), \ + wr_opcode_name(LOCAL_INV), \ + wr_opcode_name(MASKED_ATOMIC_CMP_AND_SWP), \ + wr_opcode_name(MASKED_ATOMIC_FETCH_AND_ADD)) + +#define POS_PRN \ +"[%s] wr_id %llx qpn %x psn 0x%x lpsn 0x%x length %u opcode 0x%.2x,%s size %u avail %u head %u last %u" + +TRACE_EVENT( + rvt_post_one_wr, + TP_PROTO(struct rvt_qp *qp, struct rvt_swqe *wqe), + TP_ARGS(qp, wqe), + TP_STRUCT__entry( + RDI_DEV_ENTRY(ib_to_rvt(qp->ibqp.device)) + __field(u64, wr_id) + __field(u32, qpn) + __field(u32, psn) + __field(u32, lpsn) + __field(u32, length) + __field(u32, opcode) + __field(u32, size) + __field(u32, avail) + __field(u32, head) + __field(u32, last) + ), + TP_fast_assign( + RDI_DEV_ASSIGN(ib_to_rvt(qp->ibqp.device)) + __entry->wr_id = wqe->wr.wr_id; + __entry->qpn = qp->ibqp.qp_num; + __entry->psn = wqe->psn; + __entry->lpsn = wqe->lpsn; + __entry->length = wqe->length; + __entry->opcode = wqe->wr.opcode; + __entry->size = qp->s_size; + __entry->avail = qp->s_avail; + __entry->head = qp->s_head; + __entry->last = qp->s_last; + ), + TP_printk( + POS_PRN, + __get_str(dev), + __entry->wr_id, + __entry->qpn, + __entry->psn, + __entry->lpsn, + __entry->length, + __entry->opcode, show_wr_opcode(__entry->opcode), + __entry->size, + __entry->avail, + __entry->head, + __entry->last + ) +); + +#endif /* __RVT_TRACE_TX_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace_tx +#include + -- cgit v1.2.3 From b7481944b06e99dc84f4c7da2681ac89528b2020 Mon Sep 17 00:00:00 2001 From: Jianxin Xiong Date: Wed, 7 Dec 2016 19:32:53 -0800 Subject: IB/hfi1: Show statistics counters under IB stats interface Previously tools like hfi1stats had to access these counters through debugfs, which often caused permission issue for non-root users. It is not always acceptable to change the debugfs mounting permission due to security concerns. When exposed under the IB stats interface, the counters are universally readable by default. Reviewed-by: Ira Weiny Signed-off-by: Jianxin Xiong Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/verbs.c | 154 +++++++++++++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index f1dead369258..09132582e09c 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -1609,6 +1609,154 @@ static void hfi1_get_dev_fw_str(struct ib_device *ibdev, char *str, dc8051_ver_min(ver)); } +static const char * const driver_cntr_names[] = { + /* must be element 0*/ + "DRIVER_KernIntr", + "DRIVER_ErrorIntr", + "DRIVER_Tx_Errs", + "DRIVER_Rcv_Errs", + "DRIVER_HW_Errs", + "DRIVER_NoPIOBufs", + "DRIVER_CtxtsOpen", + "DRIVER_RcvLen_Errs", + "DRIVER_EgrBufFull", + "DRIVER_EgrHdrFull" +}; + +static const char **dev_cntr_names; +static const char **port_cntr_names; +static int num_driver_cntrs = ARRAY_SIZE(driver_cntr_names); +static int num_dev_cntrs; +static int num_port_cntrs; +static int cntr_names_initialized; + +/* + * Convert a list of names separated by '\n' into an array of NULL terminated + * strings. Optionally some entries can be reserved in the array to hold extra + * external strings. + */ +static int init_cntr_names(const char *names_in, + const int names_len, + int num_extra_names, + int *num_cntrs, + const char ***cntr_names) +{ + char *names_out, *p, **q; + int i, n; + + n = 0; + for (i = 0; i < names_len; i++) + if (names_in[i] == '\n') + n++; + + names_out = kmalloc((n + num_extra_names) * sizeof(char *) + names_len, + GFP_KERNEL); + if (!names_out) { + *num_cntrs = 0; + *cntr_names = NULL; + return -ENOMEM; + } + + p = names_out + (n + num_extra_names) * sizeof(char *); + memcpy(p, names_in, names_len); + + q = (char **)names_out; + for (i = 0; i < n; i++) { + q[i] = p; + p = strchr(p, '\n'); + *p++ = '\0'; + } + + *num_cntrs = n; + *cntr_names = (const char **)names_out; + return 0; +} + +static struct rdma_hw_stats *alloc_hw_stats(struct ib_device *ibdev, + u8 port_num) +{ + int i, err; + + if (!cntr_names_initialized) { + struct hfi1_devdata *dd = dd_from_ibdev(ibdev); + + err = init_cntr_names(dd->cntrnames, + dd->cntrnameslen, + num_driver_cntrs, + &num_dev_cntrs, + &dev_cntr_names); + if (err) + return NULL; + + for (i = 0; i < num_driver_cntrs; i++) + dev_cntr_names[num_dev_cntrs + i] = + driver_cntr_names[i]; + + err = init_cntr_names(dd->portcntrnames, + dd->portcntrnameslen, + 0, + &num_port_cntrs, + &port_cntr_names); + if (err) { + kfree(dev_cntr_names); + dev_cntr_names = NULL; + return NULL; + } + cntr_names_initialized = 1; + } + + if (!port_num) + return rdma_alloc_hw_stats_struct( + dev_cntr_names, + num_dev_cntrs + num_driver_cntrs, + RDMA_HW_STATS_DEFAULT_LIFESPAN); + else + return rdma_alloc_hw_stats_struct( + port_cntr_names, + num_port_cntrs, + RDMA_HW_STATS_DEFAULT_LIFESPAN); +} + +static u64 hfi1_sps_ints(void) +{ + unsigned long flags; + struct hfi1_devdata *dd; + u64 sps_ints = 0; + + spin_lock_irqsave(&hfi1_devs_lock, flags); + list_for_each_entry(dd, &hfi1_dev_list, list) { + sps_ints += get_all_cpu_total(dd->int_counter); + } + spin_unlock_irqrestore(&hfi1_devs_lock, flags); + return sps_ints; +} + +static int get_hw_stats(struct ib_device *ibdev, struct rdma_hw_stats *stats, + u8 port, int index) +{ + u64 *values; + int count; + + if (!port) { + u64 *stats = (u64 *)&hfi1_stats; + int i; + + hfi1_read_cntrs(dd_from_ibdev(ibdev), NULL, &values); + values[num_dev_cntrs] = hfi1_sps_ints(); + for (i = 1; i < num_driver_cntrs; i++) + values[num_dev_cntrs + i] = stats[i]; + count = num_dev_cntrs + num_driver_cntrs; + } else { + struct hfi1_ibport *ibp = to_iport(ibdev, port); + + hfi1_read_portcntrs(ppd_from_ibp(ibp), NULL, &values); + count = num_port_cntrs; + } + + memcpy(stats->value, values, count * sizeof(u64)); + return count; +} + /** * hfi1_register_ib_device - register our device with the infiniband core * @dd: the device data structure @@ -1656,6 +1804,8 @@ int hfi1_register_ib_device(struct hfi1_devdata *dd) ibdev->phys_port_cnt = dd->num_pports; ibdev->dma_device = &dd->pcidev->dev; ibdev->modify_device = modify_device; + ibdev->alloc_hw_stats = alloc_hw_stats; + ibdev->get_hw_stats = get_hw_stats; /* keep process mad in the driver */ ibdev->process_mad = hfi1_process_mad; @@ -1770,6 +1920,10 @@ void hfi1_unregister_ib_device(struct hfi1_devdata *dd) del_timer_sync(&dev->mem_timer); verbs_txreq_exit(dev); + + kfree(dev_cntr_names); + kfree(port_cntr_names); + cntr_names_initialized = 0; } void hfi1_cnp_rcv(struct hfi1_packet *packet) -- cgit v1.2.3 From e922ae06e90a37ab0b212f844e8aed9b6021cf21 Mon Sep 17 00:00:00 2001 From: Don Hiatt Date: Wed, 7 Dec 2016 19:33:00 -0800 Subject: IB/hfi1: Remove dependence on qp->s_cur_size The qp->s_cur_size field assumes that the S_BUSY bit protects the field from modification after the slock is dropped. Scaling the send engine to multiple cores would break that assumption. Correct the issue by carrying the payload size in the txreq structure. Reviewed-by: Mike Marciniszyn Signed-off-by: Don Hiatt Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/rc.c | 4 ++-- drivers/infiniband/hw/hfi1/ruc.c | 4 ++-- drivers/infiniband/hw/hfi1/uc.c | 2 +- drivers/infiniband/hw/hfi1/ud.c | 2 +- drivers/infiniband/hw/hfi1/verbs.c | 6 +++--- drivers/infiniband/hw/hfi1/verbs_txreq.h | 1 + 6 files changed, 10 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index aaca8588e199..e69161e007db 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -351,7 +351,7 @@ normal: qp->s_rdma_ack_cnt++; qp->s_hdrwords = hwords; ps->s_txreq->sde = priv->s_sde; - qp->s_cur_size = len; + ps->s_txreq->s_cur_size = len; hfi1_make_ruc_header(qp, ohdr, bth0, bth2, middle, ps); /* pbc */ ps->s_txreq->hdr_dwords = qp->s_hdrwords + 2; @@ -802,7 +802,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) qp->s_hdrwords = hwords; ps->s_txreq->sde = priv->s_sde; qp->s_cur_sge = ss; - qp->s_cur_size = len; + ps->s_txreq->s_cur_size = len; hfi1_make_ruc_header( qp, ohdr, diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index 5a70e91b5191..2ec3e908691b 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -767,8 +767,8 @@ void hfi1_make_ruc_header(struct rvt_qp *qp, struct ib_other_headers *ohdr, u32 bth1; /* Construct the header. */ - extra_bytes = -qp->s_cur_size & 3; - nwords = (qp->s_cur_size + extra_bytes) >> 2; + extra_bytes = -ps->s_txreq->s_cur_size & 3; + nwords = (ps->s_txreq->s_cur_size + extra_bytes) >> 2; lrh0 = HFI1_LRH_BTH; if (unlikely(qp->remote_ah_attr.ah_flags & IB_AH_GRH)) { qp->s_hdrwords += hfi1_make_grh(ibp, diff --git a/drivers/infiniband/hw/hfi1/uc.c b/drivers/infiniband/hw/hfi1/uc.c index 5e6d1bac4914..d062c3537f7c 100644 --- a/drivers/infiniband/hw/hfi1/uc.c +++ b/drivers/infiniband/hw/hfi1/uc.c @@ -259,7 +259,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) qp->s_hdrwords = hwords; ps->s_txreq->sde = priv->s_sde; qp->s_cur_sge = &qp->s_sge; - qp->s_cur_size = len; + ps->s_txreq->s_cur_size = len; hfi1_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24), mask_psn(qp->s_psn++), middle, ps); /* pbc */ diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c index 97ae24b6314c..d742ac1af947 100644 --- a/drivers/infiniband/hw/hfi1/ud.c +++ b/drivers/infiniband/hw/hfi1/ud.c @@ -354,7 +354,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ qp->s_hdrwords = 7; - qp->s_cur_size = wqe->length; + ps->s_txreq->s_cur_size = wqe->length; qp->s_cur_sge = &qp->s_sge; qp->s_srate = ah_attr->static_rate; qp->srate_mbps = ib_rate_to_mbps(qp->s_srate); diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 09132582e09c..65f2f1d76fc8 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -895,7 +895,7 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps, struct hfi1_ahg_info *ahg_info = priv->s_ahg; u32 hdrwords = qp->s_hdrwords; struct rvt_sge_state *ss = qp->s_cur_sge; - u32 len = qp->s_cur_size; + u32 len = ps->s_txreq->s_cur_size; u32 plen = hdrwords + ((len + 3) >> 2) + 2; /* includes pbc */ struct hfi1_ibdev *dev = ps->dev; struct hfi1_pportdata *ppd = ps->ppd; @@ -1012,7 +1012,7 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps, struct hfi1_qp_priv *priv = qp->priv; u32 hdrwords = qp->s_hdrwords; struct rvt_sge_state *ss = qp->s_cur_sge; - u32 len = qp->s_cur_size; + u32 len = ps->s_txreq->s_cur_size; u32 dwords = (len + 3) >> 2; u32 plen = hdrwords + dwords + 2; /* includes pbc */ struct hfi1_pportdata *ppd = ps->ppd; @@ -1240,7 +1240,7 @@ static inline send_routine get_send_routine(struct rvt_qp *qp, u8 op = get_opcode(h); if (piothreshold && - qp->s_cur_size <= min(piothreshold, qp->pmtu) && + tx->s_cur_size <= min(piothreshold, qp->pmtu) && (BIT(op & OPMASK) & pio_opmask[op >> 5]) && iowait_sdma_pending(&priv->s_iowait) == 0 && !sdma_txreq_built(&tx->txreq)) diff --git a/drivers/infiniband/hw/hfi1/verbs_txreq.h b/drivers/infiniband/hw/hfi1/verbs_txreq.h index 5660897593ba..76216f2ef35a 100644 --- a/drivers/infiniband/hw/hfi1/verbs_txreq.h +++ b/drivers/infiniband/hw/hfi1/verbs_txreq.h @@ -65,6 +65,7 @@ struct verbs_txreq { struct sdma_engine *sde; struct send_context *psc; u16 hdr_dwords; + u16 s_cur_size; }; struct hfi1_ibdev; -- cgit v1.2.3 From 6e40b59cfa99710fcbf849439783e8fc98d183bf Mon Sep 17 00:00:00 2001 From: Tadeusz Struk Date: Wed, 7 Dec 2016 19:33:06 -0800 Subject: IB/hfi1: Remove definition of unused hfi1_affinity struct The struct hfi1_affinity is not used anymore. We use the struct hfi1_affinity_node and hfi1_affinity_node_list instead. Reviewed-by: Dennis Dalessandro Signed-off-by: Tadeusz Struk Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/affinity.h | 8 -------- drivers/infiniband/hw/hfi1/hfi.h | 1 - 2 files changed, 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/affinity.h b/drivers/infiniband/hw/hfi1/affinity.h index b89ea3c0ee1a..ef4ebc358619 100644 --- a/drivers/infiniband/hw/hfi1/affinity.h +++ b/drivers/infiniband/hw/hfi1/affinity.h @@ -70,14 +70,6 @@ struct cpu_mask_set { uint gen; }; -struct hfi1_affinity { - struct cpu_mask_set def_intr; - struct cpu_mask_set rcv_intr; - struct cpumask real_cpu_mask; - /* spin lock to protect affinity struct */ - spinlock_t lock; -}; - struct hfi1_msix_entry; /* Initialize non-HT cpu cores mask */ diff --git a/drivers/infiniband/hw/hfi1/hfi.h b/drivers/infiniband/hw/hfi1/hfi.h index a66d198199ff..4163596ce4c9 100644 --- a/drivers/infiniband/hw/hfi1/hfi.h +++ b/drivers/infiniband/hw/hfi1/hfi.h @@ -1185,7 +1185,6 @@ struct hfi1_devdata { /* Number of verbs contexts which have disabled ASPM */ atomic_t aspm_disabled_cnt; - struct hfi1_affinity *affinity; bool eprom_available; /* true if EPROM is available for this device */ bool aspm_supported; /* Does HW support ASPM */ bool aspm_enabled; /* ASPM state: enabled/disabled */ -- cgit v1.2.3 From 5213006ade47153f5f2c2e5a42e84312afccabfd Mon Sep 17 00:00:00 2001 From: Dean Luick Date: Wed, 7 Dec 2016 19:33:13 -0800 Subject: IB/hfi1: Add special setting for low power AOC Low power QSFP AOC cables require a different SerDes Tx PLL bandwidth setting than the default. The 8051 firmware does not know the details, so the driver needs to tell the firmware through a special setting. Reviewed-by: Easwar Hariharan Signed-off-by: Dean Luick Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/platform.c | 44 ++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/platform.c b/drivers/infiniband/hw/hfi1/platform.c index 0e7043801bb1..838fe84e285a 100644 --- a/drivers/infiniband/hw/hfi1/platform.c +++ b/drivers/infiniband/hw/hfi1/platform.c @@ -637,6 +637,38 @@ static void apply_tx_lanes(struct hfi1_pportdata *ppd, u8 field_id, } } +/* + * Return a special SerDes setting for low power AOC cables. The power class + * threshold and setting being used were all found by empirical testing. + * + * Summary of the logic: + * + * if (QSFP and QSFP_TYPE == AOC and QSFP_POWER_CLASS < 4) + * return 0xe + * return 0; // leave at default + */ +static u8 aoc_low_power_setting(struct hfi1_pportdata *ppd) +{ + u8 *cache = ppd->qsfp_info.cache; + int power_class; + + /* QSFP only */ + if (ppd->port_type != PORT_TYPE_QSFP) + return 0; /* leave at default */ + + /* active optical cables only */ + switch ((cache[QSFP_MOD_TECH_OFFS] & 0xF0) >> 4) { + case 0x0 ... 0x9: /* fallthrough */ + case 0xC: /* fallthrough */ + case 0xE: + /* active AOC */ + power_class = get_qsfp_power_class(cache[QSFP_MOD_PWR_OFFS]); + if (power_class < QSFP_POWER_CLASS_4) + return 0xe; + } + return 0; /* leave at default */ +} + static void apply_tunings( struct hfi1_pportdata *ppd, u32 tx_preset_index, u8 tuning_method, u32 total_atten, u8 limiting_active) @@ -705,7 +737,17 @@ static void apply_tunings( tx_preset_index, TX_PRESET_TABLE_POSTCUR, &tx_preset, 4); postcur = tx_preset; - config_data = precur | (attn << 8) | (postcur << 16); + /* + * NOTES: + * o The aoc_low_power_setting is applied to all lanes even + * though only lane 0's value is examined by the firmware. + * o A lingering low power setting after a cable swap does + * not occur. On cable unplug the 8051 is reset and + * restarted on cable insert. This resets all settings to + * their default, erasing any previous low power setting. + */ + config_data = precur | (attn << 8) | (postcur << 16) | + (aoc_low_power_setting(ppd) << 24); apply_tx_lanes(ppd, TX_EQ_SETTINGS, config_data, "Applying TX settings"); -- cgit v1.2.3 From fcb29a6668a254104d38c0132d1853d0644af066 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Wed, 7 Dec 2016 19:33:20 -0800 Subject: IB/rdmavt: Add trace of MR segs Add tracing of MR segment information. Reviewed-by: Dennis Dalessandro Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/mr.c | 4 ++ drivers/infiniband/sw/rdmavt/trace.h | 1 + drivers/infiniband/sw/rdmavt/trace_mr.h | 112 ++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 drivers/infiniband/sw/rdmavt/trace_mr.h (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c index 4acf179adf3b..562cf78b6ae9 100644 --- a/drivers/infiniband/sw/rdmavt/mr.c +++ b/drivers/infiniband/sw/rdmavt/mr.c @@ -51,6 +51,7 @@ #include #include "vt.h" #include "mr.h" +#include "trace.h" /** * rvt_driver_mr_init - Init MR resources per driver @@ -403,6 +404,7 @@ struct ib_mr *rvt_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, } mr->mr.map[m]->segs[n].vaddr = vaddr; mr->mr.map[m]->segs[n].length = umem->page_size; + trace_rvt_mr_user_seg(&mr->mr, m, n, vaddr, umem->page_size); n++; if (n == RVT_SEGSZ) { m++; @@ -507,6 +509,7 @@ static int rvt_set_page(struct ib_mr *ibmr, u64 addr) n = mapped_segs % RVT_SEGSZ; mr->mr.map[m]->segs[n].vaddr = (void *)addr; mr->mr.map[m]->segs[n].length = ps; + trace_rvt_mr_page_seg(&mr->mr, m, n, (void *)addr, ps); mr->mr.length += ps; return 0; @@ -693,6 +696,7 @@ int rvt_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list, for (i = 0; i < list_len; i++) { fmr->mr.map[m]->segs[n].vaddr = (void *)page_list[i]; fmr->mr.map[m]->segs[n].length = ps; + trace_rvt_mr_fmr_seg(&fmr->mr, m, n, (void *)page_list[i], ps); if (++n == RVT_SEGSZ) { m++; n = 0; diff --git a/drivers/infiniband/sw/rdmavt/trace.h b/drivers/infiniband/sw/rdmavt/trace.h index 11a2afbc8e76..e2d23acb6a7d 100644 --- a/drivers/infiniband/sw/rdmavt/trace.h +++ b/drivers/infiniband/sw/rdmavt/trace.h @@ -51,3 +51,4 @@ #include "trace_rvt.h" #include "trace_qp.h" #include "trace_tx.h" +#include "trace_mr.h" diff --git a/drivers/infiniband/sw/rdmavt/trace_mr.h b/drivers/infiniband/sw/rdmavt/trace_mr.h new file mode 100644 index 000000000000..3318a6c36373 --- /dev/null +++ b/drivers/infiniband/sw/rdmavt/trace_mr.h @@ -0,0 +1,112 @@ +/* + * Copyright(c) 2016 Intel Corporation. + * + * This file is provided under a dual BSD/GPLv2 license. When using or + * redistributing this file, you may do so under either license. + * + * GPL LICENSE SUMMARY + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * BSD LICENSE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * - Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ +#if !defined(__RVT_TRACE_MR_H) || defined(TRACE_HEADER_MULTI_READ) +#define __RVT_TRACE_MR_H + +#include +#include + +#include +#include +#include + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM rvt_mr +DECLARE_EVENT_CLASS( + rvt_mr_template, + TP_PROTO(struct rvt_mregion *mr, u16 m, u16 n, void *v, size_t len), + TP_ARGS(mr, m, n, v, len), + TP_STRUCT__entry( + RDI_DEV_ENTRY(ib_to_rvt(mr->pd->device)) + __field(void *, vaddr) + __field(struct page *, page) + __field(size_t, len) + __field(u32, lkey) + __field(u16, m) + __field(u16, n) + ), + TP_fast_assign( + RDI_DEV_ASSIGN(ib_to_rvt(mr->pd->device)); + __entry->vaddr = v; + __entry->page = virt_to_page(v); + __entry->m = m; + __entry->n = n; + __entry->len = len; + ), + TP_printk( + "[%s] vaddr %p page %p m %u n %u len %ld", + __get_str(dev), + __entry->vaddr, + __entry->page, + __entry->m, + __entry->n, + __entry->len + ) +); + +DEFINE_EVENT( + rvt_mr_template, rvt_mr_page_seg, + TP_PROTO(struct rvt_mregion *mr, u16 m, u16 n, void *v, size_t len), + TP_ARGS(mr, m, n, v, len)); + +DEFINE_EVENT( + rvt_mr_template, rvt_mr_fmr_seg, + TP_PROTO(struct rvt_mregion *mr, u16 m, u16 n, void *v, size_t len), + TP_ARGS(mr, m, n, v, len)); + +DEFINE_EVENT( + rvt_mr_template, rvt_mr_user_seg, + TP_PROTO(struct rvt_mregion *mr, u16 m, u16 n, void *v, size_t len), + TP_ARGS(mr, m, n, v, len)); + +#endif /* __RVT_TRACE_MR_H */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE +#define TRACE_INCLUDE_PATH . +#define TRACE_INCLUDE_FILE trace_mr +#include -- cgit v1.2.3 From b777f154a0c21e1187c1806ababf9c5ba3e49eea Mon Sep 17 00:00:00 2001 From: Mitko Haralanov Date: Wed, 7 Dec 2016 19:33:27 -0800 Subject: IB/hfi1: Remove usage of qp->s_cur_sge The s_cur_sge field in the qp structure holds a pointer to the SGE of the currently processed WQE. It assumes the protection of the RVT_S_BUSY flag to prevent the changing of this field while the send engine is using it. This scheme works as long as there is only one instance of the send engine running at a time. Scaling of the send engine to multiple cores would break this assumption as there could be multiple instances of the send engine running on different CPUs. This opens a window where the QP's RVT_S_BUSY flag is not set but the send engine is still running. To prevent accidental changing of the s_cur_sge pointer, the QP's dependence on it is removed. The SGE pointer is now stored in the verbs_txreq, which is a per-packet data structure. This ensures that each individual packet has it's own pointer, which is setup while the RVT_S_BUSY flag is set. Reviewed-by: Mike Marciniszyn Reviewed-by: Dennis Dalessandro Signed-off-by: Mitko Haralanov Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/rc.c | 10 +++++----- drivers/infiniband/hw/hfi1/uc.c | 2 +- drivers/infiniband/hw/hfi1/ud.c | 2 +- drivers/infiniband/hw/hfi1/verbs.c | 14 ++++++-------- 4 files changed, 13 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index e69161e007db..c996a373837e 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -276,7 +276,7 @@ static int make_rc_ack(struct hfi1_ibdev *dev, struct rvt_qp *qp, rvt_get_mr(ps->s_txreq->mr); qp->s_ack_rdma_sge.sge = e->rdma_sge; qp->s_ack_rdma_sge.num_sge = 1; - qp->s_cur_sge = &qp->s_ack_rdma_sge; + ps->s_txreq->ss = &qp->s_ack_rdma_sge; if (len > pmtu) { len = pmtu; qp->s_ack_state = OP(RDMA_READ_RESPONSE_FIRST); @@ -290,7 +290,7 @@ static int make_rc_ack(struct hfi1_ibdev *dev, struct rvt_qp *qp, bth2 = mask_psn(qp->s_ack_rdma_psn++); } else { /* COMPARE_SWAP or FETCH_ADD */ - qp->s_cur_sge = NULL; + ps->s_txreq->ss = NULL; len = 0; qp->s_ack_state = OP(ATOMIC_ACKNOWLEDGE); ohdr->u.at.aeth = hfi1_compute_aeth(qp); @@ -306,7 +306,7 @@ static int make_rc_ack(struct hfi1_ibdev *dev, struct rvt_qp *qp, qp->s_ack_state = OP(RDMA_READ_RESPONSE_MIDDLE); /* FALLTHROUGH */ case OP(RDMA_READ_RESPONSE_MIDDLE): - qp->s_cur_sge = &qp->s_ack_rdma_sge; + ps->s_txreq->ss = &qp->s_ack_rdma_sge; ps->s_txreq->mr = qp->s_ack_rdma_sge.sge.mr; if (ps->s_txreq->mr) rvt_get_mr(ps->s_txreq->mr); @@ -335,7 +335,7 @@ normal: */ qp->s_ack_state = OP(SEND_ONLY); qp->s_flags &= ~RVT_S_ACK_PENDING; - qp->s_cur_sge = NULL; + ps->s_txreq->ss = NULL; if (qp->s_nak_state) ohdr->u.aeth = cpu_to_be32((qp->r_msn & HFI1_MSN_MASK) | @@ -801,7 +801,7 @@ int hfi1_make_rc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) qp->s_len -= len; qp->s_hdrwords = hwords; ps->s_txreq->sde = priv->s_sde; - qp->s_cur_sge = ss; + ps->s_txreq->ss = ss; ps->s_txreq->s_cur_size = len; hfi1_make_ruc_header( qp, diff --git a/drivers/infiniband/hw/hfi1/uc.c b/drivers/infiniband/hw/hfi1/uc.c index d062c3537f7c..b141a78ae38b 100644 --- a/drivers/infiniband/hw/hfi1/uc.c +++ b/drivers/infiniband/hw/hfi1/uc.c @@ -258,7 +258,7 @@ int hfi1_make_uc_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) qp->s_len -= len; qp->s_hdrwords = hwords; ps->s_txreq->sde = priv->s_sde; - qp->s_cur_sge = &qp->s_sge; + ps->s_txreq->ss = &qp->s_sge; ps->s_txreq->s_cur_size = len; hfi1_make_ruc_header(qp, ohdr, bth0 | (qp->s_state << 24), mask_psn(qp->s_psn++), middle, ps); diff --git a/drivers/infiniband/hw/hfi1/ud.c b/drivers/infiniband/hw/hfi1/ud.c index d742ac1af947..c071955c0272 100644 --- a/drivers/infiniband/hw/hfi1/ud.c +++ b/drivers/infiniband/hw/hfi1/ud.c @@ -355,7 +355,7 @@ int hfi1_make_ud_req(struct rvt_qp *qp, struct hfi1_pkt_state *ps) /* header size in 32-bit words LRH+BTH+DETH = (8+12+8)/4. */ qp->s_hdrwords = 7; ps->s_txreq->s_cur_size = wqe->length; - qp->s_cur_sge = &qp->s_sge; + ps->s_txreq->ss = &qp->s_sge; qp->s_srate = ah_attr->static_rate; qp->srate_mbps = ib_rate_to_mbps(qp->s_srate); qp->s_wqe = wqe; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 65f2f1d76fc8..3b7bfd817647 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -790,10 +790,10 @@ static int wait_kmem(struct hfi1_ibdev *dev, */ static noinline int build_verbs_ulp_payload( struct sdma_engine *sde, - struct rvt_sge_state *ss, u32 length, struct verbs_txreq *tx) { + struct rvt_sge_state *ss = tx->ss; struct rvt_sge *sg_list = ss->sg_list; struct rvt_sge sge = ss->sge; u8 num_sge = ss->num_sge; @@ -837,7 +837,6 @@ bail_txadd: /* New API */ static int build_verbs_tx_desc( struct sdma_engine *sde, - struct rvt_sge_state *ss, u32 length, struct verbs_txreq *tx, struct hfi1_ahg_info *ahg_info, @@ -881,9 +880,9 @@ static int build_verbs_tx_desc( goto bail_txadd; } - /* add the ulp payload - if any. ss can be NULL for acks */ - if (ss) - ret = build_verbs_ulp_payload(sde, ss, length, tx); + /* add the ulp payload - if any. tx->ss can be NULL for acks */ + if (tx->ss) + ret = build_verbs_ulp_payload(sde, length, tx); bail_txadd: return ret; } @@ -894,7 +893,6 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps, struct hfi1_qp_priv *priv = qp->priv; struct hfi1_ahg_info *ahg_info = priv->s_ahg; u32 hdrwords = qp->s_hdrwords; - struct rvt_sge_state *ss = qp->s_cur_sge; u32 len = ps->s_txreq->s_cur_size; u32 plen = hdrwords + ((len + 3) >> 2) + 2; /* includes pbc */ struct hfi1_ibdev *dev = ps->dev; @@ -920,7 +918,7 @@ int hfi1_verbs_send_dma(struct rvt_qp *qp, struct hfi1_pkt_state *ps, plen); } tx->wqe = qp->s_wqe; - ret = build_verbs_tx_desc(tx->sde, ss, len, tx, ahg_info, pbc); + ret = build_verbs_tx_desc(tx->sde, len, tx, ahg_info, pbc); if (unlikely(ret)) goto bail_build; } @@ -1011,7 +1009,7 @@ int hfi1_verbs_send_pio(struct rvt_qp *qp, struct hfi1_pkt_state *ps, { struct hfi1_qp_priv *priv = qp->priv; u32 hdrwords = qp->s_hdrwords; - struct rvt_sge_state *ss = qp->s_cur_sge; + struct rvt_sge_state *ss = ps->s_txreq->ss; u32 len = ps->s_txreq->s_cur_size; u32 dwords = (len + 3) >> 2; u32 plen = hdrwords + dwords + 2; /* includes pbc */ -- cgit v1.2.3 From 9b86071c5ef7a8c0a0d6d541cb79df5a8b115d91 Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Wed, 7 Dec 2016 19:33:33 -0800 Subject: IB/hfi1: Remove critical section gap in sc_buffer_alloc() In sc_buffer_alloc(), the sc->alloc_lock is released before calling sc_release_update(), and it is reacquired after the function call. This causes CPU lock trading. Fix it by not dropping the lock before calling sc_release_update(). Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/pio.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 86a7f365b624..75c4dea84c4b 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -1419,9 +1419,7 @@ retry: (sc->fill - sc->alloc_free); if (blocks > avail) { /* still no room, actively update */ - spin_unlock_irqrestore(&sc->alloc_lock, flags); sc_release_update(sc); - spin_lock_irqsave(&sc->alloc_lock, flags); sc->alloc_free = ACCESS_ONCE(sc->free); trycount++; goto retry; -- cgit v1.2.3 From 008016746720d4295e38e940e22dbd116c90c95b Mon Sep 17 00:00:00 2001 From: Dean Luick Date: Wed, 7 Dec 2016 19:33:40 -0800 Subject: IB/hfi1: Preserve external device completed bit The driver should not change the external device request completed bit when not actually doing an external device request. Reviewed-by: Easwar Hariharan Signed-off-by: Dean Luick Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/chip.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/chip.c b/drivers/infiniband/hw/hfi1/chip.c index f87d80567572..37d8af50cc13 100644 --- a/drivers/infiniband/hw/hfi1/chip.c +++ b/drivers/infiniband/hw/hfi1/chip.c @@ -8488,7 +8488,10 @@ static int do_8051_command( */ if (type == HCMD_WRITE_LCB_CSR) { in_data |= ((*out_data) & 0xffffffffffull) << 8; - reg = ((((*out_data) >> 40) & 0xff) << + /* must preserve COMPLETED - it is tied to hardware */ + reg = read_csr(dd, DC_DC8051_CFG_EXT_DEV_0); + reg &= DC_DC8051_CFG_EXT_DEV_0_COMPLETED_SMASK; + reg |= ((((*out_data) >> 40) & 0xff) << DC_DC8051_CFG_EXT_DEV_0_RETURN_CODE_SHIFT) | ((((*out_data) >> 48) & 0xffff) << DC_DC8051_CFG_EXT_DEV_0_RSP_DATA_SHIFT); -- cgit v1.2.3 From b44980f8794faf3561d970fe8c05e34765fbdc9b Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Wed, 7 Dec 2016 19:33:46 -0800 Subject: IB/hfi1: Replace qp->refcount release code with standard driver wrapper Some parts of the code don't use the standard release wrapper rvt_put_qp() for decrementing and testing the refcount to then try to use a resource. Replace this code with the standard driver wrapper. Fixes: Commit 4d6f85c3fa55 ("IB/rdmavt, IB/qib, IB/hfi1: Use new QP put get routines") Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/driver.c | 3 +-- drivers/infiniband/sw/rdmavt/mcast.c | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/driver.c b/drivers/infiniband/hw/hfi1/driver.c index 6563e4d38b80..d4261163bd25 100644 --- a/drivers/infiniband/hw/hfi1/driver.c +++ b/drivers/infiniband/hw/hfi1/driver.c @@ -793,8 +793,7 @@ static inline void process_rcv_qp_work(struct hfi1_packet *packet) hfi1_schedule_send(qp); spin_unlock_irqrestore(&qp->s_lock, flags); } - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); + rvt_put_qp(qp); } } diff --git a/drivers/infiniband/sw/rdmavt/mcast.c b/drivers/infiniband/sw/rdmavt/mcast.c index 983d319ac976..05c8c2afb0e3 100644 --- a/drivers/infiniband/sw/rdmavt/mcast.c +++ b/drivers/infiniband/sw/rdmavt/mcast.c @@ -81,7 +81,7 @@ static struct rvt_mcast_qp *rvt_mcast_qp_alloc(struct rvt_qp *qp) goto bail; mqp->qp = qp; - atomic_inc(&qp->refcount); + rvt_get_qp(qp); bail: return mqp; @@ -92,8 +92,7 @@ static void rvt_mcast_qp_free(struct rvt_mcast_qp *mqp) struct rvt_qp *qp = mqp->qp; /* Notify hfi1_destroy_qp() if it is waiting. */ - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); + rvt_put_qp(qp); kfree(mqp); } -- cgit v1.2.3 From f84dfa26e61c6f31a3a0366532296911df763170 Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Wed, 7 Dec 2016 19:33:53 -0800 Subject: IB/hfi1: Use reference count wrapper for MRs Some parts of the code don't use the standard driver wrapper for memory region reference counters. Use the standard driver wrapper throughout the code. Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/mr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/mr.c b/drivers/infiniband/sw/rdmavt/mr.c index 562cf78b6ae9..52fd15276ee6 100644 --- a/drivers/infiniband/sw/rdmavt/mr.c +++ b/drivers/infiniband/sw/rdmavt/mr.c @@ -793,7 +793,7 @@ int rvt_lkey_ok(struct rvt_lkey_table *rkt, struct rvt_pd *pd, mr = rcu_dereference(dev->dma_mr); if (!mr) goto bail; - atomic_inc(&mr->refcount); + rvt_get_mr(mr); rcu_read_unlock(); isge->mr = mr; @@ -814,7 +814,7 @@ int rvt_lkey_ok(struct rvt_lkey_table *rkt, struct rvt_pd *pd, off + sge->length > mr->length || (mr->access_flags & acc) != acc)) goto bail; - atomic_inc(&mr->refcount); + rvt_get_mr(mr); rcu_read_unlock(); off += mr->offset; @@ -892,7 +892,7 @@ int rvt_rkey_ok(struct rvt_qp *qp, struct rvt_sge *sge, mr = rcu_dereference(rdi->dma_mr); if (!mr) goto bail; - atomic_inc(&mr->refcount); + rvt_get_mr(mr); rcu_read_unlock(); sge->mr = mr; @@ -913,7 +913,7 @@ int rvt_rkey_ok(struct rvt_qp *qp, struct rvt_sge *sge, if (unlikely(vaddr < mr->iova || off + len > mr->length || (mr->access_flags & acc) == 0)) goto bail; - atomic_inc(&mr->refcount); + rvt_get_mr(mr); rcu_read_unlock(); off += mr->offset; -- cgit v1.2.3 From 238b1862b4608ee8c28733be67e08f0447963090 Mon Sep 17 00:00:00 2001 From: Sebastian Sanchez Date: Wed, 7 Dec 2016 19:34:00 -0800 Subject: IB/qib: Use standard refcount wrapper for QPs Use the standard driver wrapper for QP reference counters. This makes the code more maintainable. Fixes: Commit 4d6f85c3fa55 ("IB/rdmavt, IB/qib, IB/hfi1: Use new QP put get routines") Reviewed-by: Mike Marciniszyn Signed-off-by: Sebastian Sanchez Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qib/qib_driver.c | 3 +-- drivers/infiniband/hw/qib/qib_verbs.c | 20 ++++++++------------ 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c index 728e0a030d2e..2b5982f743ef 100644 --- a/drivers/infiniband/hw/qib/qib_driver.c +++ b/drivers/infiniband/hw/qib/qib_driver.c @@ -420,8 +420,7 @@ static u32 qib_rcv_hdrerr(struct qib_ctxtdata *rcd, struct qib_pportdata *ppd, if (list_empty(&qp->rspwait)) { qp->r_flags |= RVT_R_RSP_NAK; - atomic_inc( - &qp->refcount); + rvt_get_qp(qp); list_add_tail( &qp->rspwait, &rcd->qp_wait_list); diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 954f15064514..204482468953 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -464,7 +464,7 @@ static void mem_timer(unsigned long data) priv = list_entry(list->next, struct qib_qp_priv, iowait); qp = priv->owner; list_del_init(&priv->iowait); - atomic_inc(&qp->refcount); + rvt_get_qp(qp); if (!list_empty(list)) mod_timer(&dev->mem_timer, jiffies + 1); } @@ -477,8 +477,7 @@ static void mem_timer(unsigned long data) qib_schedule_send(qp); } spin_unlock_irqrestore(&qp->s_lock, flags); - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); + rvt_put_qp(qp); } } @@ -762,7 +761,7 @@ void qib_put_txreq(struct qib_verbs_txreq *tx) iowait); qp = priv->owner; list_del_init(&priv->iowait); - atomic_inc(&qp->refcount); + rvt_get_qp(qp); spin_unlock_irqrestore(&dev->rdi.pending_lock, flags); spin_lock_irqsave(&qp->s_lock, flags); @@ -772,8 +771,7 @@ void qib_put_txreq(struct qib_verbs_txreq *tx) } spin_unlock_irqrestore(&qp->s_lock, flags); - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); + rvt_put_qp(qp); } else spin_unlock_irqrestore(&dev->rdi.pending_lock, flags); } @@ -808,7 +806,7 @@ void qib_verbs_sdma_desc_avail(struct qib_pportdata *ppd, unsigned avail) break; avail -= qpp->s_tx->txreq.sg_count; list_del_init(&qpp->iowait); - atomic_inc(&qp->refcount); + rvt_get_qp(qp); qps[n++] = qp; } @@ -822,8 +820,7 @@ void qib_verbs_sdma_desc_avail(struct qib_pportdata *ppd, unsigned avail) qib_schedule_send(qp); } spin_unlock(&qp->s_lock); - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); + rvt_put_qp(qp); } } @@ -1288,7 +1285,7 @@ void qib_ib_piobufavail(struct qib_devdata *dd) priv = list_entry(list->next, struct qib_qp_priv, iowait); qp = priv->owner; list_del_init(&priv->iowait); - atomic_inc(&qp->refcount); + rvt_get_qp(qp); qps[n++] = qp; } dd->f_wantpiobuf_intr(dd, 0); @@ -1306,8 +1303,7 @@ full: spin_unlock_irqrestore(&qp->s_lock, flags); /* Notify qib_destroy_qp() if it is waiting. */ - if (atomic_dec_and_test(&qp->refcount)) - wake_up(&qp->wait); + rvt_put_qp(qp); } } -- cgit v1.2.3 From f2dc9cdce83c4aac2f8b6c803b0327df1c7d44a6 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Wed, 7 Dec 2016 19:34:06 -0800 Subject: IB/rdmavt: Add a send completion helper This is for use by client drivers to drive send completions into a CQ. A new exported table allows for the mapping of ib_wr_opcode into a ib_wc_opcode. Reviewed-by: Ashutosh Dixit Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/qp.c | 17 +++++++++++++++++ include/rdma/rdmavt_qp.h | 40 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 6500c3b5a89c..9e14addd690c 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -76,6 +76,23 @@ const int ib_rvt_state_ops[IB_QPS_ERR + 1] = { }; EXPORT_SYMBOL(ib_rvt_state_ops); +/* + * Translate ib_wr_opcode into ib_wc_opcode. + */ +const enum ib_wc_opcode ib_rvt_wc_opcode[] = { + [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE, + [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, + [IB_WR_SEND] = IB_WC_SEND, + [IB_WR_SEND_WITH_IMM] = IB_WC_SEND, + [IB_WR_RDMA_READ] = IB_WC_RDMA_READ, + [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP, + [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD, + [IB_WR_SEND_WITH_INV] = IB_WC_SEND, + [IB_WR_LOCAL_INV] = IB_WC_LOCAL_INV, + [IB_WR_REG_MR] = IB_WC_REG_MR +}; +EXPORT_SYMBOL(ib_rvt_wc_opcode); + static void get_map_page(struct rvt_qpn_table *qpt, struct rvt_qpn_map *map, gfp_t gfp) diff --git a/include/rdma/rdmavt_qp.h b/include/rdma/rdmavt_qp.h index 2c5183ef0243..d78e99cf6c11 100644 --- a/include/rdma/rdmavt_qp.h +++ b/include/rdma/rdmavt_qp.h @@ -51,6 +51,7 @@ #include #include #include +#include /* * Atomic bit definitions for r_aflags. */ @@ -527,7 +528,44 @@ static inline void rvt_qp_wqe_unreserve( } } -extern const int ib_rvt_state_ops[]; +extern const enum ib_wc_opcode ib_rvt_wc_opcode[]; + +/** + * rvt_qp_swqe_complete() - insert send completion + * @qp - the qp + * @wqe - the send wqe + * @status - completion status + * + * Insert a send completion into the completion + * queue if the qp indicates it should be done. + * + * See IBTA 10.7.3.1 for info on completion + * control. + */ +static inline void rvt_qp_swqe_complete( + struct rvt_qp *qp, + struct rvt_swqe *wqe, + enum ib_wc_status status) +{ + if (unlikely(wqe->wr.send_flags & RVT_SEND_RESERVE_USED)) + return; + if (!(qp->s_flags & RVT_S_SIGNAL_REQ_WR) || + (wqe->wr.send_flags & IB_SEND_SIGNALED) || + status != IB_WC_SUCCESS) { + struct ib_wc wc; + + memset(&wc, 0, sizeof(wc)); + wc.wr_id = wqe->wr.wr_id; + wc.status = status; + wc.opcode = ib_rvt_wc_opcode[wqe->wr.opcode]; + wc.qp = &qp->ibqp; + wc.byte_len = wqe->length; + rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &wc, + status != IB_WC_SUCCESS); + } +} + +extern const int ib_rvt_state_ops[]; struct rvt_dev_info; int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err); -- cgit v1.2.3 From 0771da5a6e9d67e48207a81ddf6c8e739e9493bd Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Wed, 7 Dec 2016 19:34:12 -0800 Subject: IB/hfi1,IB/qib: Use new send completion helper Convert cq completion returns in both rdmavt drivers to use the new helper. Reviewed-by: Ashutosh Dixit Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/rc.c | 26 ++------------------------ drivers/infiniband/hw/hfi1/ruc.c | 17 +---------------- drivers/infiniband/hw/hfi1/verbs.c | 16 ---------------- drivers/infiniband/hw/qib/qib_rc.c | 26 ++------------------------ drivers/infiniband/hw/qib/qib_ruc.c | 17 +---------------- drivers/infiniband/hw/qib/qib_verbs.c | 13 ------------- 6 files changed, 6 insertions(+), 109 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index c996a373837e..3df1c0650571 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -1146,7 +1146,6 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) { struct ib_other_headers *ohdr; struct rvt_swqe *wqe; - struct ib_wc wc; unsigned i; u32 opcode; u32 psn; @@ -1200,17 +1199,7 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) rvt_put_mr(sge->mr); } - /* Post a send completion queue entry if requested. */ - if (!(qp->s_flags & RVT_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - memset(&wc, 0, sizeof(wc)); - wc.wr_id = wqe->wr.wr_id; - wc.status = IB_WC_SUCCESS; - wc.opcode = ib_hfi1_wc_opcode[wqe->wr.opcode]; - wc.byte_len = wqe->length; - wc.qp = &qp->ibqp; - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &wc, 0); - } + rvt_qp_swqe_complete(qp, wqe, IB_WC_SUCCESS); } /* * If we were waiting for sends to complete before re-sending, @@ -1240,7 +1229,6 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, struct rvt_swqe *wqe, struct hfi1_ibport *ibp) { - struct ib_wc wc; unsigned i; lockdep_assert_held(&qp->s_lock); @@ -1264,17 +1252,7 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, qp->s_last = s_last; /* see post_send() */ barrier(); - /* Post a send completion queue entry if requested. */ - if (!(qp->s_flags & RVT_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - memset(&wc, 0, sizeof(wc)); - wc.wr_id = wqe->wr.wr_id; - wc.status = IB_WC_SUCCESS; - wc.opcode = ib_hfi1_wc_opcode[wqe->wr.opcode]; - wc.byte_len = wqe->length; - wc.qp = &qp->ibqp; - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &wc, 0); - } + rvt_qp_swqe_complete(qp, wqe, IB_WC_SUCCESS); } else { struct hfi1_pportdata *ppd = ppd_from_ibp(ibp); diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index 2ec3e908691b..03c89315f1c7 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -964,22 +964,7 @@ void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, qp->ibqp.qp_type == IB_QPT_GSI) atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount); - /* See ch. 11.2.4.1 and 10.7.3.1 */ - if (!(qp->s_flags & RVT_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED) || - status != IB_WC_SUCCESS) { - struct ib_wc wc; - - memset(&wc, 0, sizeof(wc)); - wc.wr_id = wqe->wr.wr_id; - wc.status = status; - wc.opcode = ib_hfi1_wc_opcode[wqe->wr.opcode]; - wc.qp = &qp->ibqp; - if (status == IB_WC_SUCCESS) - wc.byte_len = wqe->length; - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &wc, - status != IB_WC_SUCCESS); - } + rvt_qp_swqe_complete(qp, wqe, status); if (qp->s_acked == old_last) qp->s_acked = last; diff --git a/drivers/infiniband/hw/hfi1/verbs.c b/drivers/infiniband/hw/hfi1/verbs.c index 3b7bfd817647..95ed4d6da510 100644 --- a/drivers/infiniband/hw/hfi1/verbs.c +++ b/drivers/infiniband/hw/hfi1/verbs.c @@ -296,22 +296,6 @@ static inline int wss_exceeds_threshold(void) return atomic_read(&wss.total_count) >= wss.threshold; } -/* - * Translate ib_wr_opcode into ib_wc_opcode. - */ -const enum ib_wc_opcode ib_hfi1_wc_opcode[] = { - [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE, - [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, - [IB_WR_SEND] = IB_WC_SEND, - [IB_WR_SEND_WITH_IMM] = IB_WC_SEND, - [IB_WR_RDMA_READ] = IB_WC_RDMA_READ, - [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP, - [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD, - [IB_WR_SEND_WITH_INV] = IB_WC_SEND, - [IB_WR_LOCAL_INV] = IB_WC_LOCAL_INV, - [IB_WR_REG_MR] = IB_WC_REG_MR -}; - /* * Length of header by opcode, 0 --> not supported */ diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index 2097512e75aa..d54990514730 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -941,7 +941,6 @@ void qib_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) { struct ib_other_headers *ohdr; struct rvt_swqe *wqe; - struct ib_wc wc; unsigned i; u32 opcode; u32 psn; @@ -993,17 +992,7 @@ void qib_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) rvt_put_mr(sge->mr); } - /* Post a send completion queue entry if requested. */ - if (!(qp->s_flags & RVT_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - memset(&wc, 0, sizeof(wc)); - wc.wr_id = wqe->wr.wr_id; - wc.status = IB_WC_SUCCESS; - wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode]; - wc.byte_len = wqe->length; - wc.qp = &qp->ibqp; - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &wc, 0); - } + rvt_qp_swqe_complete(qp, wqe, IB_WC_SUCCESS); } /* * If we were waiting for sends to complete before resending, @@ -1032,7 +1021,6 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, struct rvt_swqe *wqe, struct qib_ibport *ibp) { - struct ib_wc wc; unsigned i; /* @@ -1055,17 +1043,7 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, qp->s_last = s_last; /* see post_send() */ barrier(); - /* Post a send completion queue entry if requested. */ - if (!(qp->s_flags & RVT_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED)) { - memset(&wc, 0, sizeof(wc)); - wc.wr_id = wqe->wr.wr_id; - wc.status = IB_WC_SUCCESS; - wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode]; - wc.byte_len = wqe->length; - wc.qp = &qp->ibqp; - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &wc, 0); - } + rvt_qp_swqe_complete(qp, wqe, IB_WC_SUCCESS); } else this_cpu_inc(*ibp->rvp.rc_delayed_comp); diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c index de1bde5950f5..87e3eb5a836b 100644 --- a/drivers/infiniband/hw/qib/qib_ruc.c +++ b/drivers/infiniband/hw/qib/qib_ruc.c @@ -815,22 +815,7 @@ void qib_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, qp->ibqp.qp_type == IB_QPT_GSI) atomic_dec(&ibah_to_rvtah(wqe->ud_wr.ah)->refcount); - /* See ch. 11.2.4.1 and 10.7.3.1 */ - if (!(qp->s_flags & RVT_S_SIGNAL_REQ_WR) || - (wqe->wr.send_flags & IB_SEND_SIGNALED) || - status != IB_WC_SUCCESS) { - struct ib_wc wc; - - memset(&wc, 0, sizeof(wc)); - wc.wr_id = wqe->wr.wr_id; - wc.status = status; - wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode]; - wc.qp = &qp->ibqp; - if (status == IB_WC_SUCCESS) - wc.byte_len = wqe->length; - rvt_cq_enter(ibcq_to_rvtcq(qp->ibqp.send_cq), &wc, - status != IB_WC_SUCCESS); - } + rvt_qp_swqe_complete(qp, wqe, status); if (qp->s_acked == old_last) qp->s_acked = last; diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c index 204482468953..4b54c0ddd08a 100644 --- a/drivers/infiniband/hw/qib/qib_verbs.c +++ b/drivers/infiniband/hw/qib/qib_verbs.c @@ -113,19 +113,6 @@ static unsigned int ib_qib_disable_sma; module_param_named(disable_sma, ib_qib_disable_sma, uint, S_IWUSR | S_IRUGO); MODULE_PARM_DESC(disable_sma, "Disable the SMA"); -/* - * Translate ib_wr_opcode into ib_wc_opcode. - */ -const enum ib_wc_opcode ib_qib_wc_opcode[] = { - [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE, - [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, - [IB_WR_SEND] = IB_WC_SEND, - [IB_WR_SEND_WITH_IMM] = IB_WC_SEND, - [IB_WR_RDMA_READ] = IB_WC_RDMA_READ, - [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP, - [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD -}; - /* * System image GUID. */ -- cgit v1.2.3 From 9d8145a604937780898c0e4bdb124a57988fc2ed Mon Sep 17 00:00:00 2001 From: Harish Chegondi Date: Wed, 7 Dec 2016 19:34:19 -0800 Subject: IB/hfi1: Avoid credit return allocation for cpu-less NUMA nodes Do not allocate credit return base and DMA memory for NUMA nodes without CPUs. Reviewed-by: Mike Marciniszyn Signed-off-by: Harish Chegondi Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/affinity.c | 3 ++- drivers/infiniband/hw/hfi1/affinity.h | 1 + drivers/infiniband/hw/hfi1/pio.c | 20 +++----------------- 3 files changed, 6 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/affinity.c b/drivers/infiniband/hw/hfi1/affinity.c index a26a9a0bfc41..4962b6ef1f34 100644 --- a/drivers/infiniband/hw/hfi1/affinity.c +++ b/drivers/infiniband/hw/hfi1/affinity.c @@ -125,6 +125,7 @@ int node_affinity_init(void) cpumask_weight(topology_sibling_cpumask( cpumask_first(&node_affinity.proc.mask) )); + node_affinity.num_possible_nodes = num_possible_nodes(); node_affinity.num_online_nodes = num_online_nodes(); node_affinity.num_online_cpus = num_online_cpus(); @@ -135,7 +136,7 @@ int node_affinity_init(void) */ init_real_cpu_mask(); - hfi1_per_node_cntr = kcalloc(num_possible_nodes(), + hfi1_per_node_cntr = kcalloc(node_affinity.num_possible_nodes, sizeof(*hfi1_per_node_cntr), GFP_KERNEL); if (!hfi1_per_node_cntr) return -ENOMEM; diff --git a/drivers/infiniband/hw/hfi1/affinity.h b/drivers/infiniband/hw/hfi1/affinity.h index ef4ebc358619..c9453b3d47b4 100644 --- a/drivers/infiniband/hw/hfi1/affinity.h +++ b/drivers/infiniband/hw/hfi1/affinity.h @@ -111,6 +111,7 @@ struct hfi1_affinity_node_list { struct cpumask real_cpu_mask; struct cpu_mask_set proc; int num_core_siblings; + int num_possible_nodes; int num_online_nodes; int num_online_cpus; struct mutex lock; /* protects affinity nodes */ diff --git a/drivers/infiniband/hw/hfi1/pio.c b/drivers/infiniband/hw/hfi1/pio.c index 75c4dea84c4b..3d5dac2f5266 100644 --- a/drivers/infiniband/hw/hfi1/pio.c +++ b/drivers/infiniband/hw/hfi1/pio.c @@ -2036,21 +2036,10 @@ freesc15: int init_credit_return(struct hfi1_devdata *dd) { int ret; - int num_numa; int i; - num_numa = num_online_nodes(); - /* enforce the expectation that the numas are compact */ - for (i = 0; i < num_numa; i++) { - if (!node_online(i)) { - dd_dev_err(dd, "NUMA nodes are not compact\n"); - ret = -EINVAL; - goto done; - } - } - dd->cr_base = kcalloc( - num_numa, + node_affinity.num_possible_nodes, sizeof(struct credit_return_base), GFP_KERNEL); if (!dd->cr_base) { @@ -2058,7 +2047,7 @@ int init_credit_return(struct hfi1_devdata *dd) ret = -ENOMEM; goto done; } - for (i = 0; i < num_numa; i++) { + for_each_node_with_cpus(i) { int bytes = TXE_NUM_CONTEXTS * sizeof(struct credit_return); set_dev_node(&dd->pcidev->dev, i); @@ -2085,14 +2074,11 @@ done: void free_credit_return(struct hfi1_devdata *dd) { - int num_numa; int i; if (!dd->cr_base) return; - - num_numa = num_online_nodes(); - for (i = 0; i < num_numa; i++) { + for (i = 0; i < node_affinity.num_possible_nodes; i++) { if (dd->cr_base[i].va) { dma_free_coherent(&dd->pcidev->dev, TXE_NUM_CONTEXTS * -- cgit v1.2.3 From c64607aa8abd16ba584523bdf83a708fae91986a Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Wed, 7 Dec 2016 19:34:31 -0800 Subject: IB/hfi1,IB/qib: use rvt swqe mr deref helper Convert to use new swqe put routine. Reviewed-by: Brian Welty Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/rc.c | 15 ++------------- drivers/infiniband/hw/hfi1/ruc.c | 7 +------ drivers/infiniband/hw/qib/qib_rc.c | 15 ++------------- drivers/infiniband/hw/qib/qib_ruc.c | 7 +------ 4 files changed, 6 insertions(+), 38 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index 3df1c0650571..ddc02237e5f6 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -1146,7 +1146,6 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) { struct ib_other_headers *ohdr; struct rvt_swqe *wqe; - unsigned i; u32 opcode; u32 psn; @@ -1194,11 +1193,7 @@ void hfi1_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) qp->s_last = s_last; /* see post_send() */ barrier(); - for (i = 0; i < wqe->wr.num_sge; i++) { - struct rvt_sge *sge = &wqe->sg_list[i]; - - rvt_put_mr(sge->mr); - } + rvt_put_swqe(wqe); rvt_qp_swqe_complete(qp, wqe, IB_WC_SUCCESS); } /* @@ -1229,8 +1224,6 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, struct rvt_swqe *wqe, struct hfi1_ibport *ibp) { - unsigned i; - lockdep_assert_held(&qp->s_lock); /* * Don't decrement refcount and don't generate a @@ -1241,11 +1234,7 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, cmp_psn(qp->s_sending_psn, qp->s_sending_hpsn) > 0) { u32 s_last; - for (i = 0; i < wqe->wr.num_sge; i++) { - struct rvt_sge *sge = &wqe->sg_list[i]; - - rvt_put_mr(sge->mr); - } + rvt_put_swqe(wqe); s_last = qp->s_last; if (++s_last >= qp->s_size) s_last = 0; diff --git a/drivers/infiniband/hw/hfi1/ruc.c b/drivers/infiniband/hw/hfi1/ruc.c index 03c89315f1c7..717ed4b159d3 100644 --- a/drivers/infiniband/hw/hfi1/ruc.c +++ b/drivers/infiniband/hw/hfi1/ruc.c @@ -942,7 +942,6 @@ void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, enum ib_wc_status status) { u32 old_last, last; - unsigned i; if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND)) return; @@ -954,11 +953,7 @@ void hfi1_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, qp->s_last = last; /* See post_send() */ barrier(); - for (i = 0; i < wqe->wr.num_sge; i++) { - struct rvt_sge *sge = &wqe->sg_list[i]; - - rvt_put_mr(sge->mr); - } + rvt_put_swqe(wqe); if (qp->ibqp.qp_type == IB_QPT_UD || qp->ibqp.qp_type == IB_QPT_SMI || qp->ibqp.qp_type == IB_QPT_GSI) diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index d54990514730..e23ee6ce435a 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -941,7 +941,6 @@ void qib_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) { struct ib_other_headers *ohdr; struct rvt_swqe *wqe; - unsigned i; u32 opcode; u32 psn; @@ -987,11 +986,7 @@ void qib_rc_send_complete(struct rvt_qp *qp, struct ib_header *hdr) qp->s_last = s_last; /* see post_send() */ barrier(); - for (i = 0; i < wqe->wr.num_sge; i++) { - struct rvt_sge *sge = &wqe->sg_list[i]; - - rvt_put_mr(sge->mr); - } + rvt_put_swqe(wqe); rvt_qp_swqe_complete(qp, wqe, IB_WC_SUCCESS); } /* @@ -1021,8 +1016,6 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, struct rvt_swqe *wqe, struct qib_ibport *ibp) { - unsigned i; - /* * Don't decrement refcount and don't generate a * completion if the SWQE is being resent until the send @@ -1032,11 +1025,7 @@ static struct rvt_swqe *do_rc_completion(struct rvt_qp *qp, qib_cmp24(qp->s_sending_psn, qp->s_sending_hpsn) > 0) { u32 s_last; - for (i = 0; i < wqe->wr.num_sge; i++) { - struct rvt_sge *sge = &wqe->sg_list[i]; - - rvt_put_mr(sge->mr); - } + rvt_put_swqe(wqe); s_last = qp->s_last; if (++s_last >= qp->s_size) s_last = 0; diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c index 87e3eb5a836b..e54a2feeeb10 100644 --- a/drivers/infiniband/hw/qib/qib_ruc.c +++ b/drivers/infiniband/hw/qib/qib_ruc.c @@ -793,7 +793,6 @@ void qib_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, enum ib_wc_status status) { u32 old_last, last; - unsigned i; if (!(ib_rvt_state_ops[qp->state] & RVT_PROCESS_OR_FLUSH_SEND)) return; @@ -805,11 +804,7 @@ void qib_send_complete(struct rvt_qp *qp, struct rvt_swqe *wqe, qp->s_last = last; /* See post_send() */ barrier(); - for (i = 0; i < wqe->wr.num_sge; i++) { - struct rvt_sge *sge = &wqe->sg_list[i]; - - rvt_put_mr(sge->mr); - } + rvt_put_swqe(wqe); if (qp->ibqp.qp_type == IB_QPT_UD || qp->ibqp.qp_type == IB_QPT_SMI || qp->ibqp.qp_type == IB_QPT_GSI) -- cgit v1.2.3 From 5dc806052a9fc8c44e111646f9a9f436877749d0 Mon Sep 17 00:00:00 2001 From: Mike Marciniszyn Date: Wed, 7 Dec 2016 19:34:37 -0800 Subject: IB/rdmavt, IB/hfi1, IB/qib: Add inlines for mtu division Add rvt_div_round_up_mtu() and rvt_div_mtu() routines to do the computation based on the pmtu and the log_pmtu. Change divides in qib, hfi1 to use the new inlines. Reviewed-by: Kaike Wan Signed-off-by: Mike Marciniszyn Signed-off-by: Dennis Dalessandro Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/rc.c | 3 +-- drivers/infiniband/hw/qib/qib_rc.c | 3 +-- include/rdma/rdmavt_qp.h | 24 +++++++++++++++++++++++- 3 files changed, 25 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/rc.c b/drivers/infiniband/hw/hfi1/rc.c index ddc02237e5f6..9db260fe782a 100644 --- a/drivers/infiniband/hw/hfi1/rc.c +++ b/drivers/infiniband/hw/hfi1/rc.c @@ -2377,8 +2377,7 @@ send_last: * Update the next expected PSN. We add 1 later * below, so only add the remainder here. */ - if (len > pmtu) - qp->r_psn += (len - 1) / pmtu; + qp->r_psn += rvt_div_mtu(qp, len - 1); } else { e->rdma_sge.mr = NULL; e->rdma_sge.vaddr = NULL; diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c index e23ee6ce435a..031433cb7206 100644 --- a/drivers/infiniband/hw/qib/qib_rc.c +++ b/drivers/infiniband/hw/qib/qib_rc.c @@ -2079,8 +2079,7 @@ send_last: * Update the next expected PSN. We add 1 later * below, so only add the remainder here. */ - if (len > pmtu) - qp->r_psn += (len - 1) / pmtu; + qp->r_psn += rvt_div_mtu(qp, len - 1); } else { e->rdma_sge.mr = NULL; e->rdma_sge.vaddr = NULL; diff --git a/include/rdma/rdmavt_qp.h b/include/rdma/rdmavt_qp.h index 04facda681e0..f3dbd157ae5c 100644 --- a/include/rdma/rdmavt_qp.h +++ b/include/rdma/rdmavt_qp.h @@ -582,7 +582,29 @@ static inline void rvt_qp_swqe_complete( } } -extern const int ib_rvt_state_ops[]; +/** + * @qp - the qp pair + * @len - the length + * + * Perform a shift based mtu round up divide + */ +static inline u32 rvt_div_round_up_mtu(struct rvt_qp *qp, u32 len) +{ + return (len + qp->pmtu - 1) >> qp->log_pmtu; +} + +/** + * @qp - the qp pair + * @len - the length + * + * Perform a shift based mtu divide + */ +static inline u32 rvt_div_mtu(struct rvt_qp *qp, u32 len) +{ + return len >> qp->log_pmtu; +} + +extern const int ib_rvt_state_ops[]; struct rvt_dev_info; int rvt_error_qp(struct rvt_qp *qp, enum ib_wc_status err); -- cgit v1.2.3 From 0fc859a6576aaa747c5359c2bf622aac3158e2c7 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sat, 19 Nov 2016 15:17:48 +0530 Subject: IB/hfi1: constify mmu_notifier_ops structure Declare the structure mmu_notifier_ops as const as it is only stored in the ops field of a mmu_notifier structure. The ops field is of type const struct mmu_notifier_ops *, so mmu_notifier_ops structures having this property can be declared as const. Done using coccinelle: @r1 disable optional_qualifier @ identifier i; position p; @@ static struct mmu_notifier_ops i@p = {...}; @ok1@ identifier r1.i; position p; struct mmu_rb_handler handler; @@ handler.mn.ops=&i@p @bad@ position p!={r1.p,ok1.p}; identifier r1.i; @@ i@p @depends on !bad disable optional_qualifier@ identifier r1.i; @@ static +const struct mmu_notifier_ops i={...}; @depends on !bad disable optional_qualifier@ identifier r1.i; @@ +const struct mmu_notifier_ops i; File size before: text data bss dec hex filename 3566 72 16 3654 e46 drivers/infiniband/hw/hfi1/mmu_rb.o File size after: text data bss dec hex filename 3658 0 16 3674 e5a drivers/infiniband/hw/hfi1/mmu_rb.o Signed-off-by: Bhumika Goyal Reviewed-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/mmu_rb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/mmu_rb.c b/drivers/infiniband/hw/hfi1/mmu_rb.c index 7ad30898fc19..ccbf52c8ff6f 100644 --- a/drivers/infiniband/hw/hfi1/mmu_rb.c +++ b/drivers/infiniband/hw/hfi1/mmu_rb.c @@ -81,7 +81,7 @@ static void do_remove(struct mmu_rb_handler *handler, struct list_head *del_list); static void handle_remove(struct work_struct *work); -static struct mmu_notifier_ops mn_opts = { +static const struct mmu_notifier_ops mn_opts = { .invalidate_page = mmu_notifier_page, .invalidate_range_start = mmu_notifier_range_start, }; -- cgit v1.2.3 From 66431b0e8657e2406742105f89175f571340090b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 5 Dec 2016 16:48:11 -0800 Subject: IB/hfi1: Define platform_config_table_limits once Defining static data structures in a header file is wrong because this causes the data structure to be instantiated once in every .c file it is included in. Hence move the definition of a static array from a header file into the only .c file in which it is used. Signed-off-by: Bart Van Assche Cc: Dennis Dalessandro Cc: Dean Luick Signed-off-by: Doug Ledford --- drivers/infiniband/hw/hfi1/firmware.c | 10 ++++++++++ drivers/infiniband/hw/hfi1/platform.h | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/hfi1/firmware.c b/drivers/infiniband/hw/hfi1/firmware.c index bcf7da4599c4..0dd50cdb039a 100644 --- a/drivers/infiniband/hw/hfi1/firmware.c +++ b/drivers/infiniband/hw/hfi1/firmware.c @@ -239,6 +239,16 @@ static const u8 all_fabric_serdes_broadcast = 0xe1; const u8 pcie_serdes_broadcast[2] = { 0xe2, 0xe3 }; static const u8 all_pcie_serdes_broadcast = 0xe0; +static const u32 platform_config_table_limits[PLATFORM_CONFIG_TABLE_MAX] = { + 0, + SYSTEM_TABLE_MAX, + PORT_TABLE_MAX, + RX_PRESET_TABLE_MAX, + TX_PRESET_TABLE_MAX, + QSFP_ATTEN_TABLE_MAX, + VARIABLE_SETTINGS_TABLE_MAX +}; + /* forwards */ static void dispose_one_firmware(struct firmware_details *fdet); static int load_fabric_serdes_firmware(struct hfi1_devdata *dd, diff --git a/drivers/infiniband/hw/hfi1/platform.h b/drivers/infiniband/hw/hfi1/platform.h index 31155401a95b..eed0aa9124fa 100644 --- a/drivers/infiniband/hw/hfi1/platform.h +++ b/drivers/infiniband/hw/hfi1/platform.h @@ -168,16 +168,6 @@ struct platform_config_cache { struct platform_config_data config_tables[PLATFORM_CONFIG_TABLE_MAX]; }; -static const u32 platform_config_table_limits[PLATFORM_CONFIG_TABLE_MAX] = { - 0, - SYSTEM_TABLE_MAX, - PORT_TABLE_MAX, - RX_PRESET_TABLE_MAX, - TX_PRESET_TABLE_MAX, - QSFP_ATTEN_TABLE_MAX, - VARIABLE_SETTINGS_TABLE_MAX -}; - /* This section defines default values and encodings for the * fields defined for each table above */ -- cgit v1.2.3 From ad4a8dc3fec6485b18654d1090ef8012fcfc37b8 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Tue, 6 Dec 2016 17:01:28 +0100 Subject: i2c: rcar: Add per-Generation fallback bindings In the case of Renesas R-Car hardware we know that there are generations of SoCs, e.g. Gen 2 and Gen 3. But beyond that it's not clear what the relationship between IP blocks might be. For example, I believe that r8a7790 is older than r8a7791 but that doesn't imply that the latter is a descendant of the former or vice versa. We can, however, by examining the documentation and behaviour of the hardware at run-time observe that the current driver implementation appears to be compatible with the IP blocks on SoCs within a given generation. For the above reasons and convenience when enabling new SoCs a per-generation fallback compatibility string scheme is being adopted for drivers for Renesas SoCs. Also: * Deprecate renesas,i2c-rcar. It seems poorly named as it is only compatible with R-Car Gen 1. It also appears unused in mainline. * Add some text to describe per-SoC bindings Signed-off-by: Simon Horman Reviewed-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-rcar.txt | 32 ++++++++++++++-------- drivers/i2c/busses/i2c-rcar.c | 5 +++- 2 files changed, 24 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index 239632a0d709..2b8bd33dbf8d 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -1,17 +1,25 @@ I2C for R-Car platforms Required properties: -- compatible: Must be one of - "renesas,i2c-rcar" - "renesas,i2c-r8a7778" - "renesas,i2c-r8a7779" - "renesas,i2c-r8a7790" - "renesas,i2c-r8a7791" - "renesas,i2c-r8a7792" - "renesas,i2c-r8a7793" - "renesas,i2c-r8a7794" - "renesas,i2c-r8a7795" - "renesas,i2c-r8a7796" +- compatible: + "renesas,i2c-r8a7778" if the device is a part of a R8A7778 SoC. + "renesas,i2c-r8a7779" if the device is a part of a R8A7779 SoC. + "renesas,i2c-r8a7790" if the device is a part of a R8A7790 SoC. + "renesas,i2c-r8a7791" if the device is a part of a R8A7791 SoC. + "renesas,i2c-r8a7792" if the device is a part of a R8A7792 SoC. + "renesas,i2c-r8a7793" if the device is a part of a R8A7793 SoC. + "renesas,i2c-r8a7794" if the device is a part of a R8A7794 SoC. + "renesas,i2c-r8a7795" if the device is a part of a R8A7795 SoC. + "renesas,i2c-r8a7796" if the device is a part of a R8A7796 SoC. + "renesas,rcar-gen1-i2c" for a generic R-Car Gen1 compatible device. + "renesas,rcar-gen2-i2c" for a generic R-Car Gen2 compatible device. + "renesas,rcar-gen3-i2c" for a generic R-Car Gen3 compatible device. + "renesas,i2c-rcar" (deprecated) + + When compatible with the generic version, nodes must list the + SoC-specific version corresponding to the platform first followed + by the generic version. + - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt specifier. @@ -33,7 +41,7 @@ Examples : i2c0: i2c@e6508000 { #address-cells = <1>; #size-cells = <0>; - compatible = "renesas,i2c-r8a7791"; + compatible = "renesas,i2c-r8a7791", "renesas,rcar-gen2-i2c"; reg = <0 0xe6508000 0 0x40>; interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp9_clks R8A7791_CLK_I2C0>; diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 726615e54f2a..26f2ff22e97e 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -793,7 +793,6 @@ static const struct i2c_algorithm rcar_i2c_algo = { }; static const struct of_device_id rcar_i2c_dt_ids[] = { - { .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 }, @@ -803,6 +802,10 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 }, { .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 }, + { .compatible = "renesas,i2c-rcar", .data = (void *)I2C_RCAR_GEN1 }, /* Deprecated */ + { .compatible = "renesas,rcar-gen1-i2c", .data = (void *)I2C_RCAR_GEN1 }, + { .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 }, + { .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); -- cgit v1.2.3 From b880ccaf1742c28e91534ad7820c4405c04dabf9 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Wed, 7 Dec 2016 11:39:36 +0100 Subject: i2c: sh_mobile: Add per-Generation fallback bindings Add per-Generation fallback bindings for R-Car SoCs. This is in keeping with the compatibility string scheme is being adopted for drivers for Renesas SoCs. Also, improve readability by listing the rmobile fallback compatibility string after the more-specific compatibility strings they provide a fallback for. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt | 17 ++++++++++++++--- drivers/i2c/busses/i2c-sh_mobile.c | 4 +++- 2 files changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt index 214f94c25d37..7716acc55dec 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt @@ -1,8 +1,7 @@ Device tree configuration for Renesas IIC (sh_mobile) driver Required properties: -- compatible : "renesas,iic-". "renesas,rmobile-iic" as fallback - Examples with soctypes are: +- compatible : - "renesas,iic-r8a73a4" (R-Mobile APE6) - "renesas,iic-r8a7740" (R-Mobile A1) - "renesas,iic-r8a7790" (R-Car H2) @@ -12,6 +11,17 @@ Required properties: - "renesas,iic-r8a7794" (R-Car E2) - "renesas,iic-r8a7795" (R-Car H3) - "renesas,iic-sh73a0" (SH-Mobile AG5) + - "renesas,rcar-gen2-iic" (generic R-Car Gen2 compatible device) + - "renesas,rcar-gen3-iic" (generic R-Car Gen3 compatible device) + - "renesas,rmobile-iic" (generic device) + + When compatible with a generic R-Car version, nodes + must list the SoC-specific version corresponding to + the platform first followed by the generic R-Car + version. + + renesas,rmobile-iic must always follow. + - reg : address start and address range size of device - interrupts : interrupt of device - clocks : clock for device @@ -31,7 +41,8 @@ Pinctrl properties might be needed, too. See there. Example: iic0: i2c@e6500000 { - compatible = "renesas,iic-r8a7790", "renesas,rmobile-iic"; + compatible = "renesas,iic-r8a7790", "renesas,rcar-gen2-iic", + "renesas,rmobile-iic"; reg = <0 0xe6500000 0 0x425>; interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>; clocks = <&mstp3_clks R8A7790_CLK_IIC0>; diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 192f36f00e4d..3d9ebe6e5716 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -827,7 +827,6 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = { }; static const struct of_device_id sh_mobile_i2c_dt_ids[] = { - { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config }, { .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config }, @@ -835,8 +834,11 @@ static const struct of_device_id sh_mobile_i2c_dt_ids[] = { { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config }, + { .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config }, + { .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config }, + { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, {}, }; MODULE_DEVICE_TABLE(of, sh_mobile_i2c_dt_ids); -- cgit v1.2.3 From f8989783d7a4b076cf11eea1347ed068ff4c2c77 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Thu, 8 Dec 2016 09:47:58 +0000 Subject: i2c: cadence: Allow Cadence I2C to be selected for Cadence Xtensa CPUs This patch allows Cadence I2C controller to be selected in systems using Cadence Xtensa processors. Signed-off-by: Jan Kotas Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 8e43914023df..0cdc8443deab 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -426,7 +426,7 @@ config I2C_BLACKFIN_TWI_CLK_KHZ config I2C_CADENCE tristate "Cadence I2C Controller" - depends on ARCH_ZYNQ || ARM64 + depends on ARCH_ZYNQ || ARM64 || XTENSA help Say yes here to select Cadence I2C Host Controller. This controller is e.g. used by Xilinx Zynq. -- cgit v1.2.3 From ccee1a4cdcd02e748d39d2b121f7f82041893121 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 9 Dec 2016 10:31:55 +0100 Subject: i2c: octeon: thunderx: TWSI software reset in recovery I've seen i2c recovery reporting long loops of: [ 1035.887818] i2c i2c-4: SCL is stuck low, exit recovery [ 1037.999748] i2c i2c-4: SCL is stuck low, exit recovery [ 1040.111694] i2c i2c-4: SCL is stuck low, exit recovery ... Add a TWSI software reset which clears the status and STA,STP,IFLG in SW_TWSI_EOP_TWSI_CTL. With this the recovery works fine and above message is not seen. Signed-off-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-octeon-core.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 419b54bfc7c7..0b020703017d 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -791,6 +791,9 @@ static void octeon_i2c_prepare_recovery(struct i2c_adapter *adap) struct octeon_i2c *i2c = i2c_get_adapdata(adap); octeon_i2c_hlc_disable(i2c); + octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0); + /* wait for software reset to settle */ + udelay(5); /* * Bring control register to a good state regardless -- cgit v1.2.3 From 38190dfb7056678e388f85cb9c79f8e479a4b263 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 9 Dec 2016 10:31:56 +0100 Subject: i2c: octeon: thunderx: Remove double-check after interrupt Commit 1bb1ff3e7c74 ("i2c: octeon: Improve performance if interrupt is early") added a double-check around the wait_event_timeout() condition. The performance problem that this commit tried to work-around could not be reproduced. It also makes the wait condition more complicated then it should be. Therefore remove the double-check. Signed-off-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-octeon-core.c | 43 ++---------------------------------- 1 file changed, 2 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 0b020703017d..1d8775799056 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -36,24 +36,6 @@ static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c) return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG); } -static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first) -{ - if (octeon_i2c_test_iflg(i2c)) - return true; - - if (*first) { - *first = false; - return false; - } - - /* - * IRQ has signaled an event but IFLG hasn't changed. - * Sleep and retry once. - */ - usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_test_iflg(i2c); -} - /** * octeon_i2c_wait - wait for the IFLG to be set * @i2c: The struct octeon_i2c @@ -63,7 +45,6 @@ static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first) static int octeon_i2c_wait(struct octeon_i2c *i2c) { long time_left; - bool first = true; /* * Some chip revisions don't assert the irq in the interrupt @@ -80,7 +61,7 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) } i2c->int_enable(i2c); - time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first), + time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_iflg(i2c), i2c->adap.timeout); i2c->int_disable(i2c); @@ -102,25 +83,6 @@ static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c) return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0; } -static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first) -{ - /* check if valid bit is cleared */ - if (octeon_i2c_hlc_test_valid(i2c)) - return true; - - if (*first) { - *first = false; - return false; - } - - /* - * IRQ has signaled an event but valid bit isn't cleared. - * Sleep and retry once. - */ - usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_hlc_test_valid(i2c); -} - static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c) { /* clear ST/TS events, listen for neither */ @@ -176,7 +138,6 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c) */ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) { - bool first = true; int time_left; /* @@ -195,7 +156,7 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) i2c->hlc_int_enable(i2c); time_left = wait_event_timeout(i2c->queue, - octeon_i2c_hlc_test_ready(i2c, &first), + octeon_i2c_hlc_test_valid(i2c), i2c->adap.timeout); i2c->hlc_int_disable(i2c); if (!time_left) -- cgit v1.2.3 From 6eb89ef029fe22aee518a9dc75b9ee5d6ef9b3fe Mon Sep 17 00:00:00 2001 From: Gao Pan Date: Fri, 2 Dec 2016 11:38:16 +0800 Subject: i2c: fsl-lpi2c: read lpi2c fifo size in probe() The lpi2c fifo size is a read only parameter resides Parameter Register. It's better to read lpi2c tx/rx fifo size in probe() other than just define a macro for it. Signed-off-by: Gao Pan Reviewed-by: Vladimir Zapolskiy Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx-lpi2c.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 9794ff6feefb..c62b7cd475f8 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -83,9 +83,6 @@ #define I2C_CLK_RATIO 2 #define CHUNK_DATA 256 -#define LPI2C_RX_FIFOSIZE 4 -#define LPI2C_TX_FIFOSIZE 4 - #define LPI2C_DEFAULT_RATE 100000 #define STARDARD_MAX_BITRATE 400000 #define FAST_MAX_BITRATE 1000000 @@ -118,6 +115,8 @@ struct lpi2c_imx_struct { unsigned int delivered; unsigned int block_data; unsigned int bitrate; + unsigned int txfifosize; + unsigned int rxfifosize; enum lpi2c_imx_mode mode; }; @@ -346,7 +345,7 @@ static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx) static void lpi2c_imx_set_tx_watermark(struct lpi2c_imx_struct *lpi2c_imx) { - writel(LPI2C_TX_FIFOSIZE >> 1, lpi2c_imx->base + LPI2C_MFCR); + writel(lpi2c_imx->txfifosize >> 1, lpi2c_imx->base + LPI2C_MFCR); } static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx) @@ -355,8 +354,8 @@ static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx) remaining = lpi2c_imx->msglen - lpi2c_imx->delivered; - if (remaining > (LPI2C_RX_FIFOSIZE >> 1)) - temp = LPI2C_RX_FIFOSIZE >> 1; + if (remaining > (lpi2c_imx->rxfifosize >> 1)) + temp = lpi2c_imx->rxfifosize >> 1; else temp = 0; @@ -369,7 +368,7 @@ static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx) txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff; - while (txcnt < LPI2C_TX_FIFOSIZE) { + while (txcnt < lpi2c_imx->txfifosize) { if (lpi2c_imx->delivered == lpi2c_imx->msglen) break; @@ -554,6 +553,7 @@ static int lpi2c_imx_probe(struct platform_device *pdev) { struct lpi2c_imx_struct *lpi2c_imx; struct resource *res; + unsigned int temp; int irq, ret; lpi2c_imx = devm_kzalloc(&pdev->dev, sizeof(*lpi2c_imx), GFP_KERNEL); @@ -599,12 +599,18 @@ static int lpi2c_imx_probe(struct platform_device *pdev) i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx); platform_set_drvdata(pdev, lpi2c_imx); - ret = clk_prepare(lpi2c_imx->clk); + ret = clk_prepare_enable(lpi2c_imx->clk); if (ret) { - dev_err(&pdev->dev, "clk prepare failed %d\n", ret); + dev_err(&pdev->dev, "clk enable failed %d\n", ret); return ret; } + temp = readl(lpi2c_imx->base + LPI2C_PARAM); + lpi2c_imx->txfifosize = 1 << (temp & 0x0f); + lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); + + clk_disable(lpi2c_imx->clk); + ret = i2c_add_adapter(&lpi2c_imx->adapter); if (ret) goto clk_unprepare; -- cgit v1.2.3 From ea48c3680829c0c522a799a4a9e0fb6cc5afd0a4 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Dec 2016 14:53:26 -0200 Subject: [media] em28xx: don't change the device's name Changing the device name, causes it to be unable to remove the sysfs file, causing troubles if a device is removed and then re-inserted. [ 1010.310320] WARNING: CPU: 3 PID: 119 at fs/sysfs/dir.c:31 sysfs_warn_dup+0x7b/0x90 [ 1010.310323] sysfs: cannot create duplicate filename '/bus/usb/devices/1-3.3' [ 1010.310325] Modules linked in: lgdt330x em28xx_dvb dvb_core em28xx_alsa tuner_xc2028 tuner tvp5150 em28xx_v4l videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 videobuf2_core em28xx tveeprom v4l2_common videodev media xt_CHECKSUM iptable_mangle ipt_MASQUERADE nf_nat_masquerade_ipv4 iptable_nat nf_nat_ipv4 nf_nat nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack ipt_REJECT nf_reject_ipv4 xt_tcpudp tun bridge stp llc ebtable_filter ebtables ip6table_filter ip6_tables iptable_filter ip_tables x_tables cmac bnep cpufreq_powersave cpufreq_conservative cpufreq_userspace binfmt_misc parport_pc ppdev lp parport snd_hda_codec_hdmi iTCO_wdt snd_hda_codec_realtek iTCO_vendor_support snd_hda_codec_generic arc4 intel_rapl x86_pkg_temp_thermal iwlmvm intel_powerclamp coretemp kvm_intel mac80211 kvm i915 [ 1010.310383] irqbypass crct10dif_pclmul crc32_pclmul ghash_clmulni_intel iwlwifi pl2303 aesni_intel btusb aes_x86_64 usbserial lrw btrtl gf128mul glue_helper btbcm ablk_helper cryptd btintel bluetooth drm_kms_helper cfg80211 drm psmouse pcspkr i2c_i801 e1000e serio_raw snd_hda_intel snd_soc_rt5640 snd_hda_codec snd_soc_rl6231 snd_soc_ssm4567 mei_me i2c_smbus rfkill snd_hda_core ptp mei snd_soc_core ehci_pci sg lpc_ich shpchp mfd_core ehci_hcd pps_core snd_hwdep i2c_algo_bit snd_compress snd_pcm sdhci_acpi snd_timer battery snd sdhci elan_i2c snd_soc_sst_acpi mmc_core fjes dw_dmac i2c_hid soundcore snd_soc_sst_match i2c_designware_platform video i2c_designware_core acpi_pad acpi_als kfifo_buf tpm_tis button industrialio tpm_tis_core tpm ext4 crc16 jbd2 fscrypto mbcache dm_mod joydev evdev hid_logitech_hidpp [ 1010.310449] sd_mod hid_logitech_dj usbhid hid ahci libahci crc32c_intel libata xhci_pci xhci_hcd scsi_mod usbcore fan thermal [ 1010.310464] CPU: 3 PID: 119 Comm: kworker/3:2 Not tainted 4.9.0-rc8+ #14 [ 1010.310466] Hardware name: /NUC5i7RYB, BIOS RYBDWi35.86A.0350.2015.0812.1722 08/12/2015 [ 1010.310487] Workqueue: usb_hub_wq hub_event [usbcore] [ 1010.310490] 0000000000000000 ffffffff848f56c5 ffff8803b1f7f858 0000000000000000 [ 1010.310496] ffffffff8414f8f8 ffff88030000001f ffffed00763eff07 ffff8803b1f7f8f0 [ 1010.310501] ffff8803b3ea1e60 0000000000000001 ffffffffffffffef ffff8803b45c6840 [ 1010.310505] Call Trace: [ 1010.310517] [] ? dump_stack+0x5c/0x77 [ 1010.310522] [] ? __warn+0x168/0x1a0 [ 1010.310526] [] ? warn_slowpath_fmt+0xb4/0xf0 [ 1010.310529] [] ? __warn+0x1a0/0x1a0 [ 1010.310534] [] ? kasan_kmalloc+0xa6/0xd0 [ 1010.310539] [] ? kernfs_path_from_node+0x4a/0x60 [ 1010.310543] [] ? sysfs_warn_dup+0x7b/0x90 [ 1010.310547] [] ? sysfs_do_create_link_sd.isra.2+0xb6/0xd0 [ 1010.310553] [] ? bus_add_device+0x318/0x6b0 [ 1010.310557] [] ? sysfs_create_groups+0x83/0x110 [ 1010.310562] [] ? device_add+0x777/0x1350 [ 1010.310567] [] ? device_private_init+0x180/0x180 [ 1010.310583] [] ? usb_new_device+0x707/0x1030 [usbcore] [ 1010.310598] [] ? hub_event+0x1d65/0x3280 [usbcore] [ 1010.310604] [] ? account_entity_dequeue+0x30b/0x4a0 [ 1010.310618] [] ? hub_port_debounce+0x280/0x280 [usbcore] [ 1010.310624] [] ? compat_start_thread+0x80/0x80 [ 1010.310629] [] ? __schedule+0x704/0x1770 [ 1010.310633] [] ? io_schedule_timeout+0x390/0x390 [ 1010.310638] [] ? cache_reap+0x173/0x200 [ 1010.310642] [] ? process_one_work+0x4ed/0xe60 [ 1010.310646] [] ? worker_thread+0xe2/0xfd0 [ 1010.310650] [] ? __wake_up_common+0xbc/0x160 [ 1010.310654] [] ? process_one_work+0xe60/0xe60 [ 1010.310658] [] ? kthread+0x1cc/0x220 [ 1010.310663] [] ? kthread_park+0x80/0x80 [ 1010.310667] [] ? kthread_park+0x80/0x80 [ 1010.310671] [] ? kthread_park+0x80/0x80 [ 1010.310675] [] ? ret_from_fork+0x25/0x30 Tested-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-cards.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index b516c691b9eb..50e4c6e51ee7 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3236,8 +3236,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, int minor) { int retval; - static const char *default_chip_name = "em28xx"; - const char *chip_name = default_chip_name; + const char *chip_name = NULL; dev->udev = udev; mutex_init(&dev->ctrl_urb_lock); @@ -3324,14 +3323,9 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, break; } } - - dev_set_name(&dev->udev->dev, "%d-%s: %s#%d", - dev->udev->bus->busnum, dev->udev->devpath, - chip_name, dev->devno); - - if (chip_name == default_chip_name) - dev_info(&dev->udev->dev, - "unknown em28xx chip ID (%d)\n", dev->chip_id); + if (!chip_name) + dev_info(&dev->udev->dev, + "unknown em28xx chip ID (%d)\n", dev->chip_id); else dev_info(&dev->udev->dev, "chip ID is %s\n", chip_name); -- cgit v1.2.3 From 29b05e22f5c68c657f5ec30a31023b81124287fb Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Dec 2016 13:48:10 -0200 Subject: [media] em28xx: use usb_interface for dev_foo() calls The usb_device->dev is not the right device for dev_foo() calls. Instead, it should use usb_interface->dev. Tested-by: Antti Palosaari Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 34 ++++++------ drivers/media/usb/em28xx/em28xx-camera.c | 30 +++++------ drivers/media/usb/em28xx/em28xx-cards.c | 61 ++++++++++----------- drivers/media/usb/em28xx/em28xx-core.c | 48 ++++++++--------- drivers/media/usb/em28xx/em28xx-dvb.c | 61 ++++++++++----------- drivers/media/usb/em28xx/em28xx-i2c.c | 92 ++++++++++++++++---------------- drivers/media/usb/em28xx/em28xx-input.c | 32 +++++------ drivers/media/usb/em28xx/em28xx-vbi.c | 2 +- drivers/media/usb/em28xx/em28xx-video.c | 68 +++++++++++------------ drivers/media/usb/em28xx/em28xx.h | 1 + 10 files changed, 216 insertions(+), 213 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 7060e5146e31..7f8601427b7f 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -56,7 +56,7 @@ MODULE_PARM_DESC(debug, "activates debug info"); #define dprintk(fmt, arg...) do { \ if (debug) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "video: %s: " fmt, __func__, ## arg); \ } while (0) @@ -166,7 +166,7 @@ static void em28xx_audio_isocirq(struct urb *urb) status = usb_submit_urb(urb, GFP_ATOMIC); if (status < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "resubmit of audio urb failed (error=%i)\n", status); return; @@ -185,7 +185,7 @@ static int em28xx_init_audio_isoc(struct em28xx *dev) errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); if (errCode) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "submit of audio urb failed (error=%i)\n", errCode); em28xx_deinit_isoc_audio(dev); @@ -322,7 +322,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) err: mutex_unlock(&dev->lock); - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Error while configuring em28xx mixer\n"); return ret; } @@ -761,7 +761,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) intf = usb_ifnum_to_if(dev->udev, dev->ifnum); if (intf->num_altsetting <= alt) { - dev_err(&dev->udev->dev, "alt %d doesn't exist on interface %d\n", + dev_err(&dev->intf->dev, "alt %d doesn't exist on interface %d\n", dev->ifnum, alt); return -ENODEV; } @@ -777,14 +777,14 @@ static int em28xx_audio_urb_init(struct em28xx *dev) } if (!ep) { - dev_err(&dev->udev->dev, "Couldn't find an audio endpoint"); + dev_err(&dev->intf->dev, "Couldn't find an audio endpoint"); return -ENODEV; } ep_size = em28xx_audio_ep_packet_size(dev->udev, ep); interval = 1 << (ep->bInterval - 1); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed), dev->ifnum, alt, interval, ep_size); @@ -824,7 +824,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) if (urb_size > ep_size * npackets) npackets = DIV_ROUND_UP(urb_size, ep_size); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Number of URBs: %d, with %d packets and %d size\n", num_urb, npackets, urb_size); @@ -863,7 +863,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC, &urb->transfer_dma); if (!buf) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "usb_alloc_coherent failed!\n"); em28xx_audio_free_urb(dev); return -ENOMEM; @@ -904,16 +904,16 @@ static int em28xx_audio_init(struct em28xx *dev) return 0; } - dev_info(&dev->udev->dev, "Binding audio extension\n"); + dev_info(&dev->intf->dev, "Binding audio extension\n"); kref_get(&dev->ref); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n"); - err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio", + err = snd_card_new(&dev->intf->dev, index[devnr], "Em28xx Audio", THIS_MODULE, 0, &card); if (err < 0) return err; @@ -961,7 +961,7 @@ static int em28xx_audio_init(struct em28xx *dev) if (err < 0) goto urb_free; - dev_info(&dev->udev->dev, "Audio extension successfully initialized\n"); + dev_info(&dev->intf->dev, "Audio extension successfully initialized\n"); return 0; urb_free: @@ -986,7 +986,7 @@ static int em28xx_audio_fini(struct em28xx *dev) return 0; } - dev_info(&dev->udev->dev, "Closing audio extension\n"); + dev_info(&dev->intf->dev, "Closing audio extension\n"); if (dev->adev.sndcard) { snd_card_disconnect(dev->adev.sndcard); @@ -1010,7 +1010,7 @@ static int em28xx_audio_suspend(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - dev_info(&dev->udev->dev, "Suspending audio extension\n"); + dev_info(&dev->intf->dev, "Suspending audio extension\n"); em28xx_deinit_isoc_audio(dev); atomic_set(&dev->adev.stream_started, 0); return 0; @@ -1024,7 +1024,7 @@ static int em28xx_audio_resume(struct em28xx *dev) if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) return 0; - dev_info(&dev->udev->dev, "Resuming audio extension\n"); + dev_info(&dev->intf->dev, "Resuming audio extension\n"); /* Nothing to do other than schedule_work() ?? */ schedule_work(&dev->adev.wq_trigger); return 0; diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c index 2e24b65901ec..89c890ba7dd6 100644 --- a/drivers/media/usb/em28xx/em28xx-camera.c +++ b/drivers/media/usb/em28xx/em28xx-camera.c @@ -121,14 +121,14 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) ret = i2c_master_send(&client, ®, 1); if (ret < 0) { if (ret != -ENXIO) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -138,14 +138,14 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) reg = 0xff; ret = i2c_master_send(&client, ®, 1); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; } ret = i2c_master_recv(&client, (u8 *)&id_be, 2); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -185,16 +185,16 @@ static int em28xx_probe_sensor_micron(struct em28xx *dev) dev->em28xx_sensor = EM28XX_MT9M001; break; default: - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "unknown Micron sensor detected: 0x%04x\n", id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "unsupported sensor detected: %s\n", name); else - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "sensor %s detected\n", name); dev->i2c_client[dev->def_i2c_bus].addr = client.addr; @@ -225,7 +225,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { if (ret != -ENXIO) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -234,7 +234,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x1d; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -247,7 +247,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x0a; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -256,7 +256,7 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) reg = 0x0b; ret = i2c_smbus_read_byte_data(&client, reg); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "couldn't read from i2c device 0x%02x: error %i\n", client.addr << 1, ret); continue; @@ -296,17 +296,17 @@ static int em28xx_probe_sensor_omnivision(struct em28xx *dev) name = "OV9655"; break; default: - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "unknown OmniVision sensor detected: 0x%04x\n", id); return 0; } if (dev->em28xx_sensor == EM28XX_NOSENSOR) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "unsupported sensor detected: %s\n", name); else - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "sensor %s detected\n", name); dev->i2c_client[dev->def_i2c_bus].addr = client.addr; @@ -331,7 +331,7 @@ int em28xx_detect_sensor(struct em28xx *dev) */ if (dev->em28xx_sensor == EM28XX_NOSENSOR && ret < 0) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "No sensor detected\n"); return -ENODEV; } diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 50e4c6e51ee7..56739ce6ce16 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2677,7 +2677,7 @@ static int em28xx_wait_until_ac97_features_equals(struct em28xx *dev, msleep(50); } - dev_warn(&dev->udev->dev, "AC97 registers access is not reliable !\n"); + dev_warn(&dev->intf->dev, "AC97 registers access is not reliable !\n"); return -ETIMEDOUT; } @@ -2831,7 +2831,7 @@ static int em28xx_hint_board(struct em28xx *dev) dev->model = em28xx_eeprom_hash[i].model; dev->tuner_type = em28xx_eeprom_hash[i].tuner; - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Your board has no unique USB ID.\n" "A hint were successfully done, based on eeprom hash.\n" "This method is not 100%% failproof.\n" @@ -2861,7 +2861,7 @@ static int em28xx_hint_board(struct em28xx *dev) if (dev->i2c_hash == em28xx_i2c_hash[i].hash) { dev->model = em28xx_i2c_hash[i].model; dev->tuner_type = em28xx_i2c_hash[i].tuner; - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Your board has no unique USB ID.\n" "A hint were successfully done, based on i2c devicelist hash.\n" "This method is not 100%% failproof.\n" @@ -2874,7 +2874,7 @@ static int em28xx_hint_board(struct em28xx *dev) } } - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Your board has no unique USB ID and thus need a hint to be detected.\n" "You may try to use card= insmod option to workaround that.\n" "Please send an email with this log to:\n" @@ -2883,10 +2883,10 @@ static int em28xx_hint_board(struct em28xx *dev) "Board i2c devicelist hash is 0x%08lx\n", dev->hash, dev->i2c_hash); - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Here is a list of valid choices for the card= insmod option:\n"); for (i = 0; i < em28xx_bcount; i++) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, " card=%d -> %s\n", i, em28xx_boards[i].name); } return -1; @@ -2921,7 +2921,7 @@ static void em28xx_card_setup(struct em28xx *dev) * hash identities which has not been determined as yet. */ if (em28xx_hint_board(dev) < 0) - dev_err(&dev->udev->dev, "Board not discovered\n"); + dev_err(&dev->intf->dev, "Board not discovered\n"); else { em28xx_set_model(dev); em28xx_pre_card_setup(dev); @@ -2931,7 +2931,7 @@ static void em28xx_card_setup(struct em28xx *dev) em28xx_set_model(dev); } - dev_info(&dev->udev->dev, "Identified as %s (card=%d)\n", + dev_info(&dev->intf->dev, "Identified as %s (card=%d)\n", dev->board.name, dev->model); dev->tuner_type = em28xx_boards[dev->model].tuner_type; @@ -3030,7 +3030,7 @@ static void em28xx_card_setup(struct em28xx *dev) } if (dev->board.valid == EM28XX_BOARD_NOT_VALIDATED) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "\n\n" "The support for this board weren't valid yet.\n" "Please send a report of having this working\n" @@ -3161,7 +3161,7 @@ static int em28xx_media_device_init(struct em28xx *dev, else if (udev->manufacturer) media_device_usb_init(mdev, udev, udev->manufacturer); else - media_device_usb_init(mdev, udev, dev_name(&dev->udev->dev)); + media_device_usb_init(mdev, udev, dev_name(&dev->intf->dev)); dev->media_dev = mdev; #endif @@ -3217,7 +3217,7 @@ void em28xx_free_device(struct kref *ref) { struct em28xx *dev = kref_to_dev(ref); - dev_info(&dev->udev->dev, "Freeing device\n"); + dev_info(&dev->intf->dev, "Freeing device\n"); if (!dev->disconnected) em28xx_release_resources(dev); @@ -3239,6 +3239,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, const char *chip_name = NULL; dev->udev = udev; + dev->intf = interface; mutex_init(&dev->ctrl_urb_lock); spin_lock_init(&dev->slock); @@ -3324,10 +3325,10 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, } } if (!chip_name) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "unknown em28xx chip ID (%d)\n", dev->chip_id); else - dev_info(&dev->udev->dev, "chip ID is %s\n", chip_name); + dev_info(&dev->intf->dev, "chip ID is %s\n", chip_name); em28xx_media_device_init(dev, udev); @@ -3346,7 +3347,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, /* Resets I2C speed */ retval = em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed); if (retval < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: em28xx_write_reg failed! retval [%d]\n", __func__, retval); return retval; @@ -3361,7 +3362,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, else retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: em28xx_i2c_register bus 0 - error [%d]!\n", __func__, retval); return retval; @@ -3376,7 +3377,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, retval = em28xx_i2c_register(dev, 1, EM28XX_I2C_ALGO_EM28XX); if (retval < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: em28xx_i2c_register bus 1 - error [%d]!\n", __func__, retval); @@ -3417,7 +3418,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS); if (nr >= EM28XX_MAXBOARDS) { /* No free device slots */ - dev_err(&udev->dev, + dev_err(&interface->dev, "Driver supports up to %i em28xx boards.\n", EM28XX_MAXBOARDS); retval = -ENOMEM; @@ -3427,7 +3428,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Don't register audio interfaces */ if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { - dev_err(&udev->dev, + dev_err(&interface->dev, "audio device (%04x:%04x): interface %i, class %i\n", le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), @@ -3488,7 +3489,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (usb_endpoint_xfer_isoc(e)) { has_vendor_audio = true; } else { - dev_err(&udev->dev, + dev_err(&interface->dev, "error: skipping audio endpoint 0x83, because it uses bulk transfers !\n"); } break; @@ -3562,7 +3563,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, speed = "unknown"; } - dev_err(&udev->dev, + dev_err(&interface->dev, "New device %s %s @ %s Mbps (%04x:%04x, interface %d, class %d)\n", udev->manufacturer ? udev->manufacturer : "", udev->product ? udev->product : "", @@ -3578,8 +3579,8 @@ static int em28xx_usb_probe(struct usb_interface *interface, * not enough even for most Digital TV streams. */ if (udev->speed != USB_SPEED_HIGH && disable_usb_speed_check == 0) { - dev_err(&udev->dev, "Device initialization failed.\n"); - dev_err(&udev->dev, + dev_err(&interface->dev, "Device initialization failed.\n"); + dev_err(&interface->dev, "Device must be connected to a high-speed USB 2.0 port.\n"); retval = -ENODEV; goto err_free; @@ -3593,7 +3594,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, dev->ifnum = ifnum; if (has_vendor_audio) { - dev_err(&udev->dev, + dev_err(&interface->dev, "Audio interface %i found (Vendor Class)\n", ifnum); dev->usb_audio_type = EM28XX_USB_AUDIO_VENDOR; } @@ -3603,7 +3604,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) { if (has_vendor_audio) - dev_err(&udev->dev, + dev_err(&interface->dev, "em28xx: device seems to have vendor AND usb audio class interfaces !\n" "\t\tThe vendor interface will be ignored. Please contact the developers \n"); dev->usb_audio_type = EM28XX_USB_AUDIO_CLASS; @@ -3612,12 +3613,12 @@ static int em28xx_usb_probe(struct usb_interface *interface, } if (has_video) - dev_err(&udev->dev, "Video interface %i found:%s%s\n", + dev_err(&interface->dev, "Video interface %i found:%s%s\n", ifnum, dev->analog_ep_bulk ? " bulk" : "", dev->analog_ep_isoc ? " isoc" : ""); if (has_dvb) - dev_err(&udev->dev, "DVB interface %i found:%s%s\n", + dev_err(&interface->dev, "DVB interface %i found:%s%s\n", ifnum, dev->dvb_ep_bulk ? " bulk" : "", dev->dvb_ep_isoc ? " isoc" : ""); @@ -3649,7 +3650,7 @@ static int em28xx_usb_probe(struct usb_interface *interface, /* Disable V4L2 if the device doesn't have a decoder */ if (has_video && dev->board.decoder == EM28XX_NODECODER && !dev->board.is_webcam) { - dev_err(&udev->dev, + dev_err(&interface->dev, "Currently, V4L2 is not supported on this model\n"); has_video = false; dev->has_video = false; @@ -3659,13 +3660,13 @@ static int em28xx_usb_probe(struct usb_interface *interface, if (has_video) { if (!dev->analog_ep_isoc || (try_bulk && dev->analog_ep_bulk)) dev->analog_xfer_bulk = 1; - dev_err(&udev->dev, "analog set to %s mode.\n", + dev_err(&interface->dev, "analog set to %s mode.\n", dev->analog_xfer_bulk ? "bulk" : "isoc"); } if (has_dvb) { if (!dev->dvb_ep_isoc || (try_bulk && dev->dvb_ep_bulk)) dev->dvb_xfer_bulk = 1; - dev_err(&udev->dev, "dvb set to %s mode.\n", + dev_err(&interface->dev, "dvb set to %s mode.\n", dev->dvb_xfer_bulk ? "bulk" : "isoc"); } @@ -3713,7 +3714,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface) dev->disconnected = 1; - dev_err(&dev->udev->dev, "Disconnecting\n"); + dev_err(&dev->intf->dev, "Disconnecting\n"); flush_request_modules(dev); diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index 7f1fe5d9d685..f1b4681f3c90 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -52,7 +52,7 @@ MODULE_PARM_DESC(core_debug, "enable debug messages [core and isoc]"); #define em28xx_coredbg(fmt, arg...) do { \ if (core_debug) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "core: %s: " fmt, __func__, ## arg); \ } while (0) @@ -63,14 +63,14 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]"); #define em28xx_regdbg(fmt, arg...) do { \ if (reg_debug) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "reg: %s: " fmt, __func__, ## arg); \ } while (0) /* FIXME: don't abuse core_debug */ #define em28xx_isocdbg(fmt, arg...) do { \ if (core_debug) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "core: %s: " fmt, __func__, ## arg); \ } while (0) @@ -258,7 +258,7 @@ static int em28xx_is_ac97_ready(struct em28xx *dev) msleep(5); } - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "AC97 command still being executed: not handled properly!\n"); return -EBUSY; } @@ -352,7 +352,7 @@ static int set_ac97_input(struct em28xx *dev) ret = em28xx_write_ac97(dev, inputs[i].reg, 0x8000); if (ret < 0) - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "couldn't setup AC97 register %d\n", inputs[i].reg); } @@ -437,7 +437,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) for (i = 0; i < ARRAY_SIZE(outputs); i++) { ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000); if (ret < 0) - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "couldn't setup AC97 register %d\n", outputs[i].reg); } @@ -476,7 +476,7 @@ int em28xx_audio_analog_set(struct em28xx *dev) ret = em28xx_write_ac97(dev, outputs[i].reg, vol); if (ret < 0) - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "couldn't setup AC97 register %d\n", outputs[i].reg); } @@ -514,7 +514,7 @@ int em28xx_audio_setup(struct em28xx *dev) /* See how this device is configured */ cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG); - dev_info(&dev->udev->dev, "Config register raw data: 0x%02x\n", cfg); + dev_info(&dev->intf->dev, "Config register raw data: 0x%02x\n", cfg); if (cfg < 0) { /* Register read error */ /* Be conservative */ dev->int_audio_type = EM28XX_INT_AUDIO_AC97; @@ -535,7 +535,7 @@ int em28xx_audio_setup(struct em28xx *dev) i2s_samplerates = 5; else i2s_samplerates = 3; - dev_info(&dev->udev->dev, "I2S Audio (%d sample rate(s))\n", + dev_info(&dev->intf->dev, "I2S Audio (%d sample rate(s))\n", i2s_samplerates); /* Skip the code that does AC97 vendor detection */ dev->audio_mode.ac97 = EM28XX_NO_AC97; @@ -553,7 +553,7 @@ int em28xx_audio_setup(struct em28xx *dev) * Note: (some) em2800 devices without eeprom reports 0x91 on * CHIPCFG register, even not having an AC97 chip */ - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "AC97 chip type couldn't be determined\n"); dev->audio_mode.ac97 = EM28XX_NO_AC97; if (dev->usb_audio_type == EM28XX_USB_AUDIO_VENDOR) @@ -567,13 +567,13 @@ int em28xx_audio_setup(struct em28xx *dev) goto init_audio; vid = vid1 << 16 | vid2; - dev_warn(&dev->udev->dev, "AC97 vendor ID = 0x%08x\n", vid); + dev_warn(&dev->intf->dev, "AC97 vendor ID = 0x%08x\n", vid); feat = em28xx_read_ac97(dev, AC97_RESET); if (feat < 0) goto init_audio; - dev_warn(&dev->udev->dev, "AC97 features = 0x%04x\n", feat); + dev_warn(&dev->intf->dev, "AC97 features = 0x%04x\n", feat); /* Try to identify what audio processor we have */ if (((vid == 0xffffffff) || (vid == 0x83847650)) && (feat == 0x6a90)) @@ -585,19 +585,19 @@ init_audio: /* Reports detected AC97 processor */ switch (dev->audio_mode.ac97) { case EM28XX_NO_AC97: - dev_info(&dev->udev->dev, "No AC97 audio processor\n"); + dev_info(&dev->intf->dev, "No AC97 audio processor\n"); break; case EM28XX_AC97_EM202: - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Empia 202 AC97 audio processor detected\n"); break; case EM28XX_AC97_SIGMATEL: - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Sigmatel audio processor detected (stac 97%02x)\n", vid & 0xff); break; case EM28XX_AC97_OTHER: - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "Unknown AC97 audio processor detected!\n"); break; default: @@ -882,7 +882,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, if (mode == EM28XX_DIGITAL_MODE) { if ((xfer_bulk && !dev->dvb_ep_bulk) || (!xfer_bulk && !dev->dvb_ep_isoc)) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "no endpoint for DVB mode and transfer type %d\n", xfer_bulk > 0); return -EINVAL; @@ -891,14 +891,14 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, } else if (mode == EM28XX_ANALOG_MODE) { if ((xfer_bulk && !dev->analog_ep_bulk) || (!xfer_bulk && !dev->analog_ep_isoc)) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "no endpoint for analog mode and transfer type %d\n", xfer_bulk > 0); return -EINVAL; } usb_bufs = &dev->usb_ctl.analog_bufs; } else { - dev_err(&dev->udev->dev, "invalid mode selected\n"); + dev_err(&dev->intf->dev, "invalid mode selected\n"); return -EINVAL; } @@ -940,7 +940,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, usb_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!usb_bufs->transfer_buffer[i]) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "unable to allocate %i bytes for transfer buffer %i%s\n", sb_size, i, in_interrupt() ? " while in int" : ""); @@ -1023,7 +1023,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, if (xfer_bulk) { rc = usb_clear_halt(dev->udev, usb_bufs->urb[0]->pipe); if (rc < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", rc); em28xx_uninit_usb_xfer(dev, mode); @@ -1040,7 +1040,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, for (i = 0; i < usb_bufs->num_bufs; i++) { rc = usb_submit_urb(usb_bufs->urb[i], GFP_ATOMIC); if (rc) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "submit of urb %i failed (error=%i)\n", i, rc); em28xx_uninit_usb_xfer(dev, mode); return rc; @@ -1123,7 +1123,7 @@ int em28xx_suspend_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - dev_info(&dev->udev->dev, "Suspending extensions\n"); + dev_info(&dev->intf->dev, "Suspending extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->suspend) @@ -1137,7 +1137,7 @@ int em28xx_resume_extension(struct em28xx *dev) { const struct em28xx_ops *ops = NULL; - dev_info(&dev->udev->dev, "Resuming extensions\n"); + dev_info(&dev->intf->dev, "Resuming extensions\n"); mutex_lock(&em28xx_devlist_mutex); list_for_each_entry(ops, &em28xx_extension_devlist, next) { if (ops->resume) diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index 445e51db636f..d7cfcbe3bf19 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -75,7 +75,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define dprintk(level, fmt, arg...) do { \ if (debug >= level) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "dvb: " fmt, ## arg); \ } while (0) @@ -736,13 +736,13 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe) ret = gpio_request_one(dvb->lna_gpio, flags, NULL); if (ret) - dev_err(&dev->udev->dev, "gpio request failed %d\n", ret); + dev_err(&dev->intf->dev, "gpio request failed %d\n", ret); else gpio_free(dvb->lna_gpio); return ret; #else - dev_warn(&dev->udev->dev, "%s: LNA control is disabled (lna=%u)\n", + dev_warn(&dev->intf->dev, "%s: LNA control is disabled (lna=%u)\n", KBUILD_MODNAME, c->lna); return 0; #endif @@ -936,20 +936,20 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev) cfg.ctrl = &ctl; if (!dev->dvb->fe[0]) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "dvb frontend not attached. Can't attach xc3028\n"); return -EINVAL; } fe = dvb_attach(xc2028_attach, dev->dvb->fe[0], &cfg); if (!fe) { - dev_err(&dev->udev->dev, "xc3028 attach failed\n"); + dev_err(&dev->intf->dev, "xc3028 attach failed\n"); dvb_frontend_detach(dev->dvb->fe[0]); dev->dvb->fe[0] = NULL; return -EINVAL; } - dev_info(&dev->udev->dev, "xc3028 attached\n"); + dev_info(&dev->intf->dev, "xc3028 attached\n"); return 0; } @@ -966,10 +966,10 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, /* register adapter */ result = dvb_register_adapter(&dvb->adapter, - dev_name(&dev->udev->dev), module, + dev_name(&dev->intf->dev), module, device, adapter_nr); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "dvb_register_adapter failed (errno = %d)\n", result); goto fail_adapter; @@ -988,7 +988,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, /* register frontend */ result = dvb_register_frontend(&dvb->adapter, dvb->fe[0]); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "dvb_register_frontend failed (errno = %d)\n", result); goto fail_frontend0; @@ -998,7 +998,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, if (dvb->fe[1]) { result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "2nd dvb_register_frontend failed (errno = %d)\n", result); goto fail_frontend1; @@ -1017,7 +1017,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, result = dvb_dmx_init(&dvb->demux); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "dvb_dmx_init failed (errno = %d)\n", result); goto fail_dmx; @@ -1028,7 +1028,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, dvb->dmxdev.capabilities = 0; result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "dvb_dmxdev_init failed (errno = %d)\n", result); goto fail_dmxdev; @@ -1037,7 +1037,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, dvb->fe_hw.source = DMX_FRONTEND_0; result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "add_frontend failed (DMX_FRONTEND_0, errno = %d)\n", result); goto fail_fe_hw; @@ -1046,7 +1046,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, dvb->fe_mem.source = DMX_MEMORY_FE; result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "add_frontend failed (DMX_MEMORY_FE, errno = %d)\n", result); goto fail_fe_mem; @@ -1054,7 +1054,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module, result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw); if (result < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "connect_frontend failed (errno = %d)\n", result); goto fail_fe_conn; @@ -1128,7 +1128,7 @@ static int em28xx_dvb_init(struct em28xx *dev) return 0; } - dev_info(&dev->udev->dev, "Binding DVB extension\n"); + dev_info(&dev->intf->dev, "Binding DVB extension\n"); dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL); if (!dvb) @@ -1152,7 +1152,7 @@ static int em28xx_dvb_init(struct em28xx *dev) EM28XX_DVB_NUM_ISOC_PACKETS); } if (result) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to pre-allocate USB transfer buffers for DVB.\n"); kfree(dvb); dev->dvb = NULL; @@ -1270,7 +1270,8 @@ static int em28xx_dvb_init(struct em28xx *dev) case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2: case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E: dvb->fe[0] = dvb_attach(drxd_attach, &em28xx_drxd, NULL, - &dev->i2c_adap[dev->def_i2c_bus], &dev->udev->dev); + &dev->i2c_adap[dev->def_i2c_bus], + &dev->intf->dev); if (em28xx_attach_xc3028(0x61, dev) < 0) { result = -EINVAL; goto out_free; @@ -1332,7 +1333,7 @@ static int em28xx_dvb_init(struct em28xx *dev) result = gpio_request_one(dvb->lna_gpio, GPIOF_OUT_INIT_LOW, NULL); if (result) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "gpio request failed %d\n", result); else @@ -1949,12 +1950,12 @@ static int em28xx_dvb_init(struct em28xx *dev) } break; default: - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "The frontend of your DVB/ATSC card isn't supported yet\n"); break; } if (NULL == dvb->fe[0]) { - dev_err(&dev->udev->dev, "frontend initialization failed\n"); + dev_err(&dev->intf->dev, "frontend initialization failed\n"); result = -EINVAL; goto out_free; } @@ -1964,12 +1965,12 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->fe[1]->callback = em28xx_tuner_callback; /* register everything */ - result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev); + result = em28xx_register_dvb(dvb, THIS_MODULE, dev, &dev->intf->dev); if (result < 0) goto out_free; - dev_info(&dev->udev->dev, "DVB extension successfully initialized\n"); + dev_info(&dev->intf->dev, "DVB extension successfully initialized\n"); kref_get(&dev->ref); @@ -2009,7 +2010,7 @@ static int em28xx_dvb_fini(struct em28xx *dev) if (!dev->dvb) return 0; - dev_info(&dev->udev->dev, "Closing DVB extension\n"); + dev_info(&dev->intf->dev, "Closing DVB extension\n"); dvb = dev->dvb; @@ -2067,17 +2068,17 @@ static int em28xx_dvb_suspend(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - dev_info(&dev->udev->dev, "Suspending DVB extension\n"); + dev_info(&dev->intf->dev, "Suspending DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_suspend(dvb->fe[0]); - dev_info(&dev->udev->dev, "fe0 suspend %d\n", ret); + dev_info(&dev->intf->dev, "fe0 suspend %d\n", ret); } if (dvb->fe[1]) { dvb_frontend_suspend(dvb->fe[1]); - dev_info(&dev->udev->dev, "fe1 suspend %d\n", ret); + dev_info(&dev->intf->dev, "fe1 suspend %d\n", ret); } } @@ -2094,18 +2095,18 @@ static int em28xx_dvb_resume(struct em28xx *dev) if (!dev->board.has_dvb) return 0; - dev_info(&dev->udev->dev, "Resuming DVB extension\n"); + dev_info(&dev->intf->dev, "Resuming DVB extension\n"); if (dev->dvb) { struct em28xx_dvb *dvb = dev->dvb; if (dvb->fe[0]) { ret = dvb_frontend_resume(dvb->fe[0]); - dev_info(&dev->udev->dev, "fe0 resume %d\n", ret); + dev_info(&dev->intf->dev, "fe0 resume %d\n", ret); } if (dvb->fe[1]) { ret = dvb_frontend_resume(dvb->fe[1]); - dev_info(&dev->udev->dev, "fe1 resume %d\n", ret); + dev_info(&dev->intf->dev, "fe1 resume %d\n", ret); } } diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c index 00e39edc0837..8c472d5adb50 100644 --- a/drivers/media/usb/em28xx/em28xx-i2c.c +++ b/drivers/media/usb/em28xx/em28xx-i2c.c @@ -46,7 +46,7 @@ MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I #define dprintk(level, fmt, arg...) do { \ if (i2c_debug > level) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "i2c: %s: " fmt, __func__, ## arg); \ } while (0) @@ -78,7 +78,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) /* trigger write */ ret = dev->em28xx_write_regs(dev, 4 - len, &b2[4 - len], 2 + len); if (ret != 2 + len) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "failed to trigger write to i2c address 0x%x (error=%i)\n", addr, ret); return (ret < 0) ? ret : -EIO; @@ -93,7 +93,7 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) return -ENXIO; } if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; @@ -123,7 +123,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) buf2[0] = addr; ret = dev->em28xx_write_regs(dev, 0x04, buf2, 2); if (ret != 2) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "failed to trigger read from i2c address 0x%x (error=%i)\n", addr, ret); return (ret < 0) ? ret : -EIO; @@ -140,7 +140,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) return -ENXIO; } if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; @@ -154,7 +154,7 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len) /* get the received message */ ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len); if (ret != len) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "reading from i2c device at 0x%x failed: couldn't get the received message from the bridge (error=%i)\n", addr, ret); return (ret < 0) ? ret : -EIO; @@ -200,12 +200,12 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_write_regs_req(dev, stop ? 2 : 3, addr, buf, len); if (ret != len) { if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; } else { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", len, addr, ret); return -EIO; @@ -223,7 +223,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, return -ENXIO; } if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; @@ -244,7 +244,7 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, return -ETIMEDOUT; } - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "write to i2c device at 0x%x failed with unknown error (status=%i)\n", addr, ret); return -EIO; @@ -268,7 +268,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) /* Read data from i2c device */ ret = dev->em28xx_read_reg_req_len(dev, 2, addr, buf, len); if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "reading from i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; @@ -287,7 +287,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) if (ret == 0) /* success */ return len; if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "failed to get i2c transfer status from bridge register (error=%i)\n", ret); return ret; @@ -306,7 +306,7 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len) return -ETIMEDOUT; } - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "write to i2c device at 0x%x failed with unknown error (status=%i)\n", addr, ret); return -EIO; @@ -347,12 +347,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf, ret = dev->em28xx_write_regs_req(dev, 0x06, addr, buf, len); if (ret != len) { if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "writing to i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; } else { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "%i bytes write to i2c device at 0x%x requested, but %i bytes written\n", len, addr, ret); return -EIO; @@ -398,7 +398,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, /* Read value */ ret = dev->em28xx_read_reg_req_len(dev, 0x06, addr, buf, len); if (ret < 0) { - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "reading from i2c device at 0x%x failed (error=%i)\n", addr, ret); return ret; @@ -672,7 +672,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, /* Check if board has eeprom */ err = i2c_master_recv(&dev->i2c_client[bus], &buf, 0); if (err < 0) { - dev_info(&dev->udev->dev, "board has no eeprom\n"); + dev_info(&dev->intf->dev, "board has no eeprom\n"); return -ENODEV; } @@ -685,7 +685,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, dev->eeprom_addrwidth_16bit, len, data); if (err != len) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to read eeprom (err=%d)\n", err); goto error; } @@ -696,7 +696,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, 16, 1, data, len, true); if (dev->eeprom_addrwidth_16bit) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "eeprom %06x: ... (skipped)\n", 256); } @@ -709,12 +709,12 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, dev->hash = em28xx_hash_mem(data, len, 32); mc_start = (data[1] << 8) + 4; /* usually 0x0004 */ - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", data[0], data[1], data[2], data[3], dev->hash); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "EEPROM info:\n"); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "\tmicrocode start address = 0x%04x, boot configuration = 0x%02x\n", mc_start, data[2]); /* @@ -734,7 +734,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, err = em28xx_i2c_read_block(dev, bus, mc_start + 46, 1, 2, data); if (err != 2) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to read hardware configuration data from eeprom (err=%d)\n", err); goto error; @@ -753,7 +753,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, err = em28xx_i2c_read_block(dev, bus, hwconf_offset, 1, len, data); if (err != len) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to read hardware configuration data from eeprom (err=%d)\n", err); goto error; @@ -763,7 +763,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, /* NOTE: not all devices provide this type of dataset */ if (data[0] != 0x1a || data[1] != 0xeb || data[2] != 0x67 || data[3] != 0x95) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "\tno hardware configuration dataset found in eeprom\n"); kfree(data); return 0; @@ -775,13 +775,13 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, data[0] == 0x1a && data[1] == 0xeb && data[2] == 0x67 && data[3] == 0x95) { dev->hash = em28xx_hash_mem(data, len, 32); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "EEPROM ID = %02x %02x %02x %02x, EEPROM hash = 0x%08lx\n", data[0], data[1], data[2], data[3], dev->hash); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "EEPROM info:\n"); } else { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "unknown eeprom format or eeprom corrupted !\n"); err = -ENODEV; goto error; @@ -793,50 +793,50 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus, switch (le16_to_cpu(dev_config->chip_conf) >> 4 & 0x3) { case 0: - dev_info(&dev->udev->dev, "\tNo audio on board.\n"); + dev_info(&dev->intf->dev, "\tNo audio on board.\n"); break; case 1: - dev_info(&dev->udev->dev, "\tAC97 audio (5 sample rates)\n"); + dev_info(&dev->intf->dev, "\tAC97 audio (5 sample rates)\n"); break; case 2: if (dev->chip_id < CHIP_ID_EM2860) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "\tI2S audio, sample rate=32k\n"); else - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "\tI2S audio, 3 sample rates\n"); break; case 3: if (dev->chip_id < CHIP_ID_EM2860) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "\tI2S audio, 3 sample rates\n"); else - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "\tI2S audio, 5 sample rates\n"); break; } if (le16_to_cpu(dev_config->chip_conf) & 1 << 3) - dev_info(&dev->udev->dev, "\tUSB Remote wakeup capable\n"); + dev_info(&dev->intf->dev, "\tUSB Remote wakeup capable\n"); if (le16_to_cpu(dev_config->chip_conf) & 1 << 2) - dev_info(&dev->udev->dev, "\tUSB Self power capable\n"); + dev_info(&dev->intf->dev, "\tUSB Self power capable\n"); switch (le16_to_cpu(dev_config->chip_conf) & 0x3) { case 0: - dev_info(&dev->udev->dev, "\t500mA max power\n"); + dev_info(&dev->intf->dev, "\t500mA max power\n"); break; case 1: - dev_info(&dev->udev->dev, "\t400mA max power\n"); + dev_info(&dev->intf->dev, "\t400mA max power\n"); break; case 2: - dev_info(&dev->udev->dev, "\t300mA max power\n"); + dev_info(&dev->intf->dev, "\t300mA max power\n"); break; case 3: - dev_info(&dev->udev->dev, "\t200mA max power\n"); + dev_info(&dev->intf->dev, "\t200mA max power\n"); break; } - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "\tTable at offset 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n", dev_config->string_idx_table, le16_to_cpu(dev_config->string1), @@ -930,7 +930,7 @@ void em28xx_do_i2c_scan(struct em28xx *dev, unsigned bus) if (rc < 0) continue; i2c_devicelist[i] = i; - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "found i2c device @ 0x%x on bus %d [%s]\n", i << 1, bus, i2c_devs[i] ? i2c_devs[i] : "???"); } @@ -956,8 +956,8 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, return -ENODEV; dev->i2c_adap[bus] = em28xx_adap_template; - dev->i2c_adap[bus].dev.parent = &dev->udev->dev; - strcpy(dev->i2c_adap[bus].name, dev_name(&dev->udev->dev)); + dev->i2c_adap[bus].dev.parent = &dev->intf->dev; + strcpy(dev->i2c_adap[bus].name, dev_name(&dev->intf->dev)); dev->i2c_bus[bus].bus = bus; dev->i2c_bus[bus].algo_type = algo_type; @@ -966,7 +966,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, retval = i2c_add_adapter(&dev->i2c_adap[bus]); if (retval < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: i2c_add_adapter failed! retval [%d]\n", __func__, retval); return retval; @@ -979,7 +979,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus, if (!bus) { retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len); if ((retval < 0) && (retval != -ENODEV)) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: em28xx_i2_eeprom failed! retval [%d]\n", __func__, retval); diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index a1904e2230ea..0082ea6d6c08 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -43,7 +43,7 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]"); #define dprintk( fmt, arg...) do { \ if (ir_debug) \ - dev_printk(KERN_DEBUG, &ir->dev->udev->dev, \ + dev_printk(KERN_DEBUG, &ir->dev->intf->dev, \ "input: %s: " fmt, __func__, ## arg); \ } while (0) @@ -459,7 +459,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type) case CHIP_ID_EM28178: return em2874_ir_change_protocol(rc_dev, rc_type); default: - dev_err(&ir->dev->udev->dev, + dev_err(&ir->dev->intf->dev, "Unrecognized em28xx chip id 0x%02x: IR not supported\n", dev->chip_id); return -EINVAL; @@ -569,7 +569,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) struct input_dev *input_dev; int err; - dev_info(&dev->udev->dev, "Registering snapshot button...\n"); + dev_info(&dev->intf->dev, "Registering snapshot button...\n"); input_dev = input_allocate_device(); if (!input_dev) return -ENOMEM; @@ -589,11 +589,11 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); input_dev->id.version = 1; - input_dev->dev.parent = &dev->udev->dev; + input_dev->dev.parent = &dev->intf->dev; err = input_register_device(input_dev); if (err) { - dev_err(&dev->udev->dev, "input_register_device failed\n"); + dev_err(&dev->intf->dev, "input_register_device failed\n"); input_free_device(input_dev); return err; } @@ -633,7 +633,7 @@ static void em28xx_init_buttons(struct em28xx *dev) } else if (button->role == EM28XX_BUTTON_ILLUMINATION) { /* Check sanity */ if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "BUG: illumination button defined, but no illumination LED.\n"); goto next_button; } @@ -670,7 +670,7 @@ static void em28xx_shutdown_buttons(struct em28xx *dev) dev->num_button_polling_addresses = 0; /* Deregister input devices */ if (dev->sbutton_input_dev != NULL) { - dev_info(&dev->udev->dev, "Deregistering snapshot button\n"); + dev_info(&dev->intf->dev, "Deregistering snapshot button\n"); input_unregister_device(dev->sbutton_input_dev); dev->sbutton_input_dev = NULL; } @@ -699,7 +699,7 @@ static int em28xx_ir_init(struct em28xx *dev) i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev); if (!i2c_rc_dev_addr) { dev->board.has_ir_i2c = 0; - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "No i2c IR remote control device found.\n"); return -ENODEV; } @@ -707,12 +707,12 @@ static int em28xx_ir_init(struct em28xx *dev) if (dev->board.ir_codes == NULL && !dev->board.has_ir_i2c) { /* No remote control support */ - dev_warn(&dev->udev->dev, + dev_warn(&dev->intf->dev, "Remote control support is not available for this card.\n"); return 0; } - dev_info(&dev->udev->dev, "Registering input extension\n"); + dev_info(&dev->intf->dev, "Registering input extension\n"); ir = kzalloc(sizeof(*ir), GFP_KERNEL); if (!ir) @@ -797,7 +797,7 @@ static int em28xx_ir_init(struct em28xx *dev) /* init input device */ snprintf(ir->name, sizeof(ir->name), "%s IR", - dev_name(&dev->udev->dev)); + dev_name(&dev->intf->dev)); usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); @@ -808,7 +808,7 @@ static int em28xx_ir_init(struct em28xx *dev) rc->input_id.version = 1; rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); - rc->dev.parent = &dev->udev->dev; + rc->dev.parent = &dev->intf->dev; rc->driver_name = MODULE_NAME; /* all done */ @@ -816,7 +816,7 @@ static int em28xx_ir_init(struct em28xx *dev) if (err) goto error; - dev_info(&dev->udev->dev, "Input extension successfully initalized\n"); + dev_info(&dev->intf->dev, "Input extension successfully initalized\n"); return 0; @@ -837,7 +837,7 @@ static int em28xx_ir_fini(struct em28xx *dev) return 0; } - dev_info(&dev->udev->dev, "Closing input extension\n"); + dev_info(&dev->intf->dev, "Closing input extension\n"); em28xx_shutdown_buttons(dev); @@ -866,7 +866,7 @@ static int em28xx_ir_suspend(struct em28xx *dev) if (dev->is_audio_only) return 0; - dev_info(&dev->udev->dev, "Suspending input extension\n"); + dev_info(&dev->intf->dev, "Suspending input extension\n"); if (ir) cancel_delayed_work_sync(&ir->work); cancel_delayed_work_sync(&dev->buttons_query_work); @@ -883,7 +883,7 @@ static int em28xx_ir_resume(struct em28xx *dev) if (dev->is_audio_only) return 0; - dev_info(&dev->udev->dev, "Resuming input extension\n"); + dev_info(&dev->intf->dev, "Resuming input extension\n"); /* if suspend calls ir_raw_event_unregister(), the should call ir_raw_event_register() */ if (ir) diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c index 1b21d001cc7e..0bac552bbe87 100644 --- a/drivers/media/usb/em28xx/em28xx-vbi.c +++ b/drivers/media/usb/em28xx/em28xx-vbi.c @@ -65,7 +65,7 @@ static int vbi_buffer_prepare(struct vb2_buffer *vb) size = v4l2->vbi_width * v4l2->vbi_height * 2; if (vb2_plane_size(vb, 0) < size) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "%s data will not fit into plane (%lu < %lu)\n", __func__, vb2_plane_size(vb, 0), size); return -EINVAL; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 2d282ed9aac0..4780f6492329 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -66,13 +66,13 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint"); #define em28xx_videodbg(fmt, arg...) do { \ if (video_debug) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "video: %s: " fmt, __func__, ## arg); \ } while (0) #define em28xx_isocdbg(fmt, arg...) do {\ if (isoc_debug) \ - dev_printk(KERN_DEBUG, &dev->udev->dev, \ + dev_printk(KERN_DEBUG, &dev->intf->dev, \ "isoc: %s: " fmt, __func__, ## arg); \ } while (0) @@ -413,7 +413,7 @@ set_alt: dev->alt, dev->max_pkt_size); errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); if (errCode < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "cannot change alternate number to %d (error=%i)\n", dev->alt, errCode); return errCode; @@ -926,7 +926,7 @@ static int em28xx_enable_analog_tuner(struct em28xx *dev) ret = media_entity_setup_link(link, flags); if (ret) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Couldn't change link %s->%s to %s. Error %d\n", source->name, sink->name, flags ? "enabled" : "disabled", @@ -958,7 +958,7 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) v4l2->video_pad.flags = MEDIA_PAD_FL_SINK; ret = media_entity_pads_init(&v4l2->vdev.entity, 1, &v4l2->video_pad); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to initialize video media entity!\n"); if (em28xx_vbi_supported(dev)) { @@ -966,7 +966,7 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) ret = media_entity_pads_init(&v4l2->vbi_dev.entity, 1, &v4l2->vbi_pad); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to initialize vbi media entity!\n"); } @@ -1000,12 +1000,12 @@ static void em28xx_v4l2_create_entities(struct em28xx *dev) ret = media_entity_pads_init(ent, 1, &dev->input_pad[i]); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to initialize input pad[%d]!\n", i); ret = media_device_register_entity(dev->media_dev, ent); if (ret < 0) - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to register input entity %d!\n", i); } #endif @@ -2053,7 +2053,7 @@ static int em28xx_v4l2_open(struct file *filp) ret = v4l2_fh_open(filp); if (ret) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: v4l2_fh_open() returned error %d\n", __func__, ret); mutex_unlock(&dev->lock); @@ -2109,7 +2109,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev) if (v4l2 == NULL) return 0; - dev_info(&dev->udev->dev, "Closing video extension\n"); + dev_info(&dev->intf->dev, "Closing video extension\n"); mutex_lock(&dev->lock); @@ -2120,17 +2120,17 @@ static int em28xx_v4l2_fini(struct em28xx *dev) em28xx_v4l2_media_release(dev); if (video_is_registered(&v4l2->radio_dev)) { - dev_info(&dev->udev->dev, "V4L2 device %s deregistered\n", + dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { - dev_info(&dev->udev->dev, "V4L2 device %s deregistered\n", + dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { - dev_info(&dev->udev->dev, "V4L2 device %s deregistered\n", + dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); } @@ -2160,7 +2160,7 @@ static int em28xx_v4l2_suspend(struct em28xx *dev) if (!dev->has_video) return 0; - dev_info(&dev->udev->dev, "Suspending video extension\n"); + dev_info(&dev->intf->dev, "Suspending video extension\n"); em28xx_stop_urbs(dev); return 0; } @@ -2173,7 +2173,7 @@ static int em28xx_v4l2_resume(struct em28xx *dev) if (!dev->has_video) return 0; - dev_info(&dev->udev->dev, "Resuming video extension\n"); + dev_info(&dev->intf->dev, "Resuming video extension\n"); /* what do we do here */ return 0; } @@ -2210,7 +2210,7 @@ static int em28xx_v4l2_close(struct file *filp) em28xx_videodbg("setting alternate 0\n"); errCode = usb_set_interface(dev->udev, 0, 0); if (errCode < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "cannot change alternate number to 0 (error=%i)\n", errCode); } @@ -2345,7 +2345,7 @@ static void em28xx_vdev_init(struct em28xx *dev, vfd->tvnorms = 0; snprintf(vfd->name, sizeof(vfd->name), "%s %s", - dev_name(&dev->udev->dev), type_name); + dev_name(&dev->intf->dev), type_name); video_set_drvdata(vfd, dev); } @@ -2429,7 +2429,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) return 0; } - dev_info(&dev->udev->dev, "Registering V4L2 extension\n"); + dev_info(&dev->intf->dev, "Registering V4L2 extension\n"); mutex_lock(&dev->lock); @@ -2445,9 +2445,9 @@ static int em28xx_v4l2_init(struct em28xx *dev) #ifdef CONFIG_MEDIA_CONTROLLER v4l2->v4l2_dev.mdev = dev->media_dev; #endif - ret = v4l2_device_register(&dev->udev->dev, &v4l2->v4l2_dev); + ret = v4l2_device_register(&dev->intf->dev, &v4l2->v4l2_dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "Call to v4l2_device_register() failed!\n"); goto err; } @@ -2532,7 +2532,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Configure audio */ ret = em28xx_audio_setup(dev); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: Error while setting audio - error [%d]!\n", __func__, ret); goto unregister_dev; @@ -2561,7 +2561,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* Send a reset to other chips via gpio */ ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n", __func__, ret); goto unregister_dev; @@ -2570,7 +2570,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n", __func__, ret); goto unregister_dev; @@ -2673,7 +2673,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->vdev, VFL_TYPE_GRABBER, video_nr[dev->devno]); if (ret) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "unable to register video device (error=%i).\n", ret); goto unregister_dev; } @@ -2703,7 +2703,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->vbi_dev, VFL_TYPE_VBI, vbi_nr[dev->devno]); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "unable to register vbi device\n"); goto unregister_dev; } @@ -2715,11 +2715,11 @@ static int em28xx_v4l2_init(struct em28xx *dev) ret = video_register_device(&v4l2->radio_dev, VFL_TYPE_RADIO, radio_nr[dev->devno]); if (ret < 0) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "can't register radio device\n"); goto unregister_dev; } - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "Registered radio device as %s\n", video_device_node_name(&v4l2->radio_dev)); } @@ -2730,19 +2730,19 @@ static int em28xx_v4l2_init(struct em28xx *dev) #ifdef CONFIG_MEDIA_CONTROLLER ret = v4l2_mc_create_media_graph(dev->media_dev); if (ret) { - dev_err(&dev->udev->dev, + dev_err(&dev->intf->dev, "failed to create media graph\n"); em28xx_v4l2_media_release(dev); goto unregister_dev; } #endif - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "V4L2 video device registered as %s\n", video_device_node_name(&v4l2->vdev)); if (video_is_registered(&v4l2->vbi_dev)) - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "V4L2 VBI device registered as %s\n", video_device_node_name(&v4l2->vbi_dev)); @@ -2752,7 +2752,7 @@ static int em28xx_v4l2_init(struct em28xx *dev) /* initialize videobuf2 stuff */ em28xx_vb2_setup(dev); - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "V4L2 extension successfully initialized\n"); kref_get(&dev->ref); @@ -2762,19 +2762,19 @@ static int em28xx_v4l2_init(struct em28xx *dev) unregister_dev: if (video_is_registered(&v4l2->radio_dev)) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->radio_dev)); video_unregister_device(&v4l2->radio_dev); } if (video_is_registered(&v4l2->vbi_dev)) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vbi_dev)); video_unregister_device(&v4l2->vbi_dev); } if (video_is_registered(&v4l2->vdev)) { - dev_info(&dev->udev->dev, + dev_info(&dev->intf->dev, "V4L2 device %s deregistered\n", video_device_node_name(&v4l2->vdev)); video_unregister_device(&v4l2->vdev); diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 3e5ace497a4e..5182b1bf0d15 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -678,6 +678,7 @@ struct em28xx { /* usb transfer */ struct usb_device *udev; /* the usb device */ + struct usb_interface *intf; /* the usb interface */ u8 ifnum; /* number of the assigned usb interface */ u8 analog_ep_isoc; /* address of isoc endpoint for analog */ u8 analog_ep_bulk; /* address of bulk endpoint for analog */ -- cgit v1.2.3 From c6d48134cb2682516ed50ca0cea2675d27d985e8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 7 Dec 2016 14:34:22 -0200 Subject: [media] em28xx: don't store usb_device at struct em28xx Now that we're storing usb_interface at em28xx struct, there's no good reason to keep storing usb_device, as we can get it from usb_interface. So, get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/media/usb/em28xx/em28xx-audio.c | 23 ++++++++++++++--------- drivers/media/usb/em28xx/em28xx-cards.c | 10 +++++----- drivers/media/usb/em28xx/em28xx-core.c | 29 +++++++++++++++++------------ drivers/media/usb/em28xx/em28xx-dvb.c | 3 ++- drivers/media/usb/em28xx/em28xx-input.c | 14 ++++++++------ drivers/media/usb/em28xx/em28xx-video.c | 9 ++++++--- drivers/media/usb/em28xx/em28xx.h | 1 - 7 files changed, 52 insertions(+), 37 deletions(-) (limited to 'drivers') diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c index 7f8601427b7f..7969ddb9e2dd 100644 --- a/drivers/media/usb/em28xx/em28xx-audio.c +++ b/drivers/media/usb/em28xx/em28xx-audio.c @@ -279,6 +279,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) if (dev->adev.users == 0) { if (dev->alt == 0 || dev->is_audio_only) { + struct usb_device *udev = interface_to_usbdev(dev->intf); + if (dev->is_audio_only) /* audio is on a separate interface */ dev->alt = 1; @@ -296,7 +298,7 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream) */ dprintk("changing alternate number on interface %d to %d\n", dev->ifnum, dev->alt); - usb_set_interface(dev->udev, dev->ifnum, dev->alt); + usb_set_interface(udev, dev->ifnum, dev->alt); } /* Sets volume, mute, etc */ @@ -714,6 +716,7 @@ static const struct snd_pcm_ops snd_em28xx_pcm_capture = { static void em28xx_audio_free_urb(struct em28xx *dev) { + struct usb_device *udev = interface_to_usbdev(dev->intf); int i; for (i = 0; i < dev->adev.num_urb; i++) { @@ -722,7 +725,7 @@ static void em28xx_audio_free_urb(struct em28xx *dev) if (!urb) continue; - usb_free_coherent(dev->udev, urb->transfer_buffer_length, + usb_free_coherent(udev, urb->transfer_buffer_length, dev->adev.transfer_buffer[i], urb->transfer_dma); @@ -749,6 +752,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) { struct usb_interface *intf; struct usb_endpoint_descriptor *e, *ep = NULL; + struct usb_device *udev = interface_to_usbdev(dev->intf); int i, ep_size, interval, num_urb, npackets; int urb_size, bytes_per_transfer; u8 alt; @@ -758,7 +762,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) else alt = 7; - intf = usb_ifnum_to_if(dev->udev, dev->ifnum); + intf = usb_ifnum_to_if(udev, dev->ifnum); if (intf->num_altsetting <= alt) { dev_err(&dev->intf->dev, "alt %d doesn't exist on interface %d\n", @@ -781,12 +785,12 @@ static int em28xx_audio_urb_init(struct em28xx *dev) return -ENODEV; } - ep_size = em28xx_audio_ep_packet_size(dev->udev, ep); + ep_size = em28xx_audio_ep_packet_size(udev, ep); interval = 1 << (ep->bInterval - 1); dev_info(&dev->intf->dev, "Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", - EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed), + EM28XX_EP_AUDIO, usb_speed_string(udev->speed), dev->ifnum, alt, interval, ep_size); /* Calculate the number and size of URBs to better fit the audio samples */ @@ -860,7 +864,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) } dev->adev.urb[i] = urb; - buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC, + buf = usb_alloc_coherent(udev, npackets * ep_size, GFP_ATOMIC, &urb->transfer_dma); if (!buf) { dev_err(&dev->intf->dev, @@ -870,9 +874,9 @@ static int em28xx_audio_urb_init(struct em28xx *dev) } dev->adev.transfer_buffer[i] = buf; - urb->dev = dev->udev; + urb->dev = udev; urb->context = dev; - urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO); + urb->pipe = usb_rcvisocpipe(udev, EM28XX_EP_AUDIO); urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; urb->transfer_buffer = buf; urb->interval = interval; @@ -892,6 +896,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev) static int em28xx_audio_init(struct em28xx *dev) { struct em28xx_audio *adev = &dev->adev; + struct usb_device *udev = interface_to_usbdev(dev->intf); struct snd_pcm *pcm; struct snd_card *card; static int devnr; @@ -920,7 +925,7 @@ static int em28xx_audio_init(struct em28xx *dev) spin_lock_init(&adev->slock); adev->sndcard = card; - adev->udev = dev->udev; + adev->udev = udev; err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); if (err < 0) diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 56739ce6ce16..23c67494762d 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -3188,6 +3188,8 @@ static void em28xx_unregister_media_device(struct em28xx *dev) */ static void em28xx_release_resources(struct em28xx *dev) { + struct usb_device *udev = interface_to_usbdev(dev->intf); + /*FIXME: I2C IR should be disconnected */ mutex_lock(&dev->lock); @@ -3198,7 +3200,7 @@ static void em28xx_release_resources(struct em28xx *dev) em28xx_i2c_unregister(dev, 1); em28xx_i2c_unregister(dev, 0); - usb_put_dev(dev->udev); + usb_put_dev(udev); /* Mark device as unused */ clear_bit(dev->devno, em28xx_devused); @@ -3238,7 +3240,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, int retval; const char *chip_name = NULL; - dev->udev = udev; dev->intf = interface; mutex_init(&dev->ctrl_urb_lock); spin_lock_init(&dev->slock); @@ -3277,9 +3278,8 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev, break; case CHIP_ID_EM2820: chip_name = "em2710/2820"; - if (le16_to_cpu(dev->udev->descriptor.idVendor) - == 0xeb1a) { - __le16 idProd = dev->udev->descriptor.idProduct; + if (le16_to_cpu(udev->descriptor.idVendor) == 0xeb1a) { + __le16 idProd = udev->descriptor.idProduct; if (le16_to_cpu(idProd) == 0x2710) chip_name = "em2710"; diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c index f1b4681f3c90..19ccff41c7eb 100644 --- a/drivers/media/usb/em28xx/em28xx-core.c +++ b/drivers/media/usb/em28xx/em28xx-core.c @@ -82,7 +82,8 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, char *buf, int len) { int ret; - int pipe = usb_rcvctrlpipe(dev->udev, 0); + struct usb_device *udev = interface_to_usbdev(dev->intf); + int pipe = usb_rcvctrlpipe(udev, 0); if (dev->disconnected) return -ENODEV; @@ -97,7 +98,7 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg, len & 0xff, len >> 8); mutex_lock(&dev->ctrl_urb_lock); - ret = usb_control_msg(dev->udev, pipe, req, + ret = usb_control_msg(udev, pipe, req, USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, len, HZ); if (ret < 0) { @@ -154,7 +155,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, int len) { int ret; - int pipe = usb_sndctrlpipe(dev->udev, 0); + struct usb_device *udev = interface_to_usbdev(dev->intf); + int pipe = usb_sndctrlpipe(udev, 0); if (dev->disconnected) return -ENODEV; @@ -171,7 +173,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf, mutex_lock(&dev->ctrl_urb_lock); memcpy(dev->urb_buf, buf, len); - ret = usb_control_msg(dev->udev, pipe, req, + ret = usb_control_msg(udev, pipe, req, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 0x0000, reg, dev->urb_buf, len, HZ); mutex_unlock(&dev->ctrl_urb_lock); @@ -797,6 +799,7 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode) { struct urb *urb; struct em28xx_usb_bufs *usb_bufs; + struct usb_device *udev = interface_to_usbdev(dev->intf); int i; em28xx_isocdbg("em28xx: called em28xx_uninit_usb_xfer in mode %d\n", @@ -816,7 +819,7 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode) usb_unlink_urb(urb); if (usb_bufs->transfer_buffer[i]) { - usb_free_coherent(dev->udev, + usb_free_coherent(udev, urb->transfer_buffer_length, usb_bufs->transfer_buffer[i], urb->transfer_dma); @@ -870,9 +873,10 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, int num_bufs, int max_pkt_size, int packet_multiplier) { struct em28xx_usb_bufs *usb_bufs; + struct urb *urb; + struct usb_device *udev = interface_to_usbdev(dev->intf); int i; int sb_size, pipe; - struct urb *urb; int j, k; em28xx_isocdbg("em28xx: called em28xx_alloc_isoc in mode %d\n", mode); @@ -937,7 +941,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, } usb_bufs->urb[i] = urb; - usb_bufs->transfer_buffer[i] = usb_alloc_coherent(dev->udev, + usb_bufs->transfer_buffer[i] = usb_alloc_coherent(udev, sb_size, GFP_KERNEL, &urb->transfer_dma); if (!usb_bufs->transfer_buffer[i]) { dev_err(&dev->intf->dev, @@ -950,20 +954,20 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk, memset(usb_bufs->transfer_buffer[i], 0, sb_size); if (xfer_bulk) { /* bulk */ - pipe = usb_rcvbulkpipe(dev->udev, + pipe = usb_rcvbulkpipe(udev, mode == EM28XX_ANALOG_MODE ? dev->analog_ep_bulk : dev->dvb_ep_bulk); - usb_fill_bulk_urb(urb, dev->udev, pipe, + usb_fill_bulk_urb(urb, udev, pipe, usb_bufs->transfer_buffer[i], sb_size, em28xx_irq_callback, dev); urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP; } else { /* isoc */ - pipe = usb_rcvisocpipe(dev->udev, + pipe = usb_rcvisocpipe(udev, mode == EM28XX_ANALOG_MODE ? dev->analog_ep_isoc : dev->dvb_ep_isoc); - usb_fill_int_urb(urb, dev->udev, pipe, + usb_fill_int_urb(urb, udev, pipe, usb_bufs->transfer_buffer[i], sb_size, em28xx_irq_callback, dev, 1); urb->transfer_flags = URB_ISO_ASAP | @@ -995,6 +999,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, struct em28xx_dmaqueue *dma_q = &dev->vidq; struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq; struct em28xx_usb_bufs *usb_bufs; + struct usb_device *udev = interface_to_usbdev(dev->intf); int i; int rc; int alloc; @@ -1021,7 +1026,7 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode, } if (xfer_bulk) { - rc = usb_clear_halt(dev->udev, usb_bufs->urb[0]->pipe); + rc = usb_clear_halt(udev, usb_bufs->urb[0]->pipe); if (rc < 0) { dev_err(&dev->intf->dev, "failed to clear USB bulk endpoint stall/halt condition (error=%i)\n", diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index d7cfcbe3bf19..75a75dab2e8e 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -198,6 +198,7 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) int rc; struct em28xx_i2c_bus *i2c_bus = dvb->adapter.priv; struct em28xx *dev = i2c_bus->dev; + struct usb_device *udev = interface_to_usbdev(dev->intf); int dvb_max_packet_size, packet_multiplier, dvb_alt; if (dev->dvb_xfer_bulk) { @@ -216,7 +217,7 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb) dvb_alt = dev->dvb_alt_isoc; } - usb_set_interface(dev->udev, dev->ifnum, dvb_alt); + usb_set_interface(udev, dev->ifnum, dvb_alt); rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE); if (rc < 0) return rc; diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c index 0082ea6d6c08..782ce095c8c5 100644 --- a/drivers/media/usb/em28xx/em28xx-input.c +++ b/drivers/media/usb/em28xx/em28xx-input.c @@ -566,6 +566,7 @@ static void em28xx_query_buttons(struct work_struct *work) static int em28xx_register_snapshot_button(struct em28xx *dev) { + struct usb_device *udev = interface_to_usbdev(dev->intf); struct input_dev *input_dev; int err; @@ -574,7 +575,7 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) if (!input_dev) return -ENOMEM; - usb_make_path(dev->udev, dev->snapshot_button_path, + usb_make_path(udev, dev->snapshot_button_path, sizeof(dev->snapshot_button_path)); strlcat(dev->snapshot_button_path, "/sbutton", sizeof(dev->snapshot_button_path)); @@ -586,8 +587,8 @@ static int em28xx_register_snapshot_button(struct em28xx *dev) input_dev->keycodesize = 0; input_dev->keycodemax = 0; input_dev->id.bustype = BUS_USB; - input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + input_dev->id.vendor = le16_to_cpu(udev->descriptor.idVendor); + input_dev->id.product = le16_to_cpu(udev->descriptor.idProduct); input_dev->id.version = 1; input_dev->dev.parent = &dev->intf->dev; @@ -678,6 +679,7 @@ static void em28xx_shutdown_buttons(struct em28xx *dev) static int em28xx_ir_init(struct em28xx *dev) { + struct usb_device *udev = interface_to_usbdev(dev->intf); struct em28xx_IR *ir; struct rc_dev *rc; int err = -ENOMEM; @@ -799,15 +801,15 @@ static int em28xx_ir_init(struct em28xx *dev) snprintf(ir->name, sizeof(ir->name), "%s IR", dev_name(&dev->intf->dev)); - usb_make_path(dev->udev, ir->phys, sizeof(ir->phys)); + usb_make_path(udev, ir->phys, sizeof(ir->phys)); strlcat(ir->phys, "/input0", sizeof(ir->phys)); rc->input_name = ir->name; rc->input_phys = ir->phys; rc->input_id.bustype = BUS_USB; rc->input_id.version = 1; - rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor); - rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct); + rc->input_id.vendor = le16_to_cpu(udev->descriptor.idVendor); + rc->input_id.product = le16_to_cpu(udev->descriptor.idProduct); rc->dev.parent = &dev->intf->dev; rc->driver_name = MODULE_NAME; diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index 4780f6492329..8d93100334ea 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -360,6 +360,7 @@ static int em28xx_resolution_set(struct em28xx *dev) static int em28xx_set_alternate(struct em28xx *dev) { struct em28xx_v4l2 *v4l2 = dev->v4l2; + struct usb_device *udev = interface_to_usbdev(dev->intf); int errCode; int i; unsigned int min_pkt_size = v4l2->width * 2 + 4; @@ -411,7 +412,7 @@ set_alt: } em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n", dev->alt, dev->max_pkt_size); - errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt); + errCode = usb_set_interface(udev, dev->ifnum, dev->alt); if (errCode < 0) { dev_err(&dev->intf->dev, "cannot change alternate number to %d (error=%i)\n", @@ -1859,10 +1860,11 @@ static int vidioc_querycap(struct file *file, void *priv, struct video_device *vdev = video_devdata(file); struct em28xx *dev = video_drvdata(file); struct em28xx_v4l2 *v4l2 = dev->v4l2; + struct usb_device *udev = interface_to_usbdev(dev->intf); strlcpy(cap->driver, "em28xx", sizeof(cap->driver)); strlcpy(cap->card, em28xx_boards[dev->model].name, sizeof(cap->card)); - usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info)); + usb_make_path(udev, cap->bus_info, sizeof(cap->bus_info)); if (vdev->vfl_type == VFL_TYPE_GRABBER) cap->device_caps = V4L2_CAP_READWRITE | @@ -2187,6 +2189,7 @@ static int em28xx_v4l2_close(struct file *filp) { struct em28xx *dev = video_drvdata(filp); struct em28xx_v4l2 *v4l2 = dev->v4l2; + struct usb_device *udev = interface_to_usbdev(dev->intf); int errCode; em28xx_videodbg("users=%d\n", v4l2->users); @@ -2208,7 +2211,7 @@ static int em28xx_v4l2_close(struct file *filp) /* set alternate 0 */ dev->alt = 0; em28xx_videodbg("setting alternate 0\n"); - errCode = usb_set_interface(dev->udev, 0, 0); + errCode = usb_set_interface(udev, 0, 0); if (errCode < 0) { dev_err(&dev->intf->dev, "cannot change alternate number to 0 (error=%i)\n", diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h index 5182b1bf0d15..ca59e2d4fccf 100644 --- a/drivers/media/usb/em28xx/em28xx.h +++ b/drivers/media/usb/em28xx/em28xx.h @@ -677,7 +677,6 @@ struct em28xx { spinlock_t slock; /* usb transfer */ - struct usb_device *udev; /* the usb device */ struct usb_interface *intf; /* the usb interface */ u8 ifnum; /* number of the assigned usb interface */ u8 analog_ep_isoc; /* address of isoc endpoint for analog */ -- cgit v1.2.3 From 406ff67d5820f592ff2b5ac2643a75f001b1d21f Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 8 Dec 2016 20:22:41 -0200 Subject: [media] v4l: tvp5150: Compile tvp5150_link_setup out if !CONFIG_MEDIA_CONTROLLER The function is only referenced as a handler in the tvp5150_sd_media_ops structure, which is only used when CONFIG_MEDIA_CONTROLLER is set. Don't define the function and the structure when the configuration option is unset to avoid an unused function warning. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 6737685d5be5..08384951c9e5 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -1013,11 +1013,11 @@ static int tvp5150_enum_frame_size(struct v4l2_subdev *sd, Media entity ops ****************************************************************************/ +#ifdef CONFIG_MEDIA_CONTROLLER static int tvp5150_link_setup(struct media_entity *entity, const struct media_pad *local, const struct media_pad *remote, u32 flags) { -#ifdef CONFIG_MEDIA_CONTROLLER struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); struct tvp5150 *decoder = to_tvp5150(sd); int i; @@ -1034,7 +1034,6 @@ static int tvp5150_link_setup(struct media_entity *entity, decoder->input = i; tvp5150_selmux(sd); -#endif return 0; } @@ -1042,6 +1041,7 @@ static int tvp5150_link_setup(struct media_entity *entity, static const struct media_entity_operations tvp5150_sd_media_ops = { .link_setup = tvp5150_link_setup, }; +#endif /**************************************************************************** I2C Command -- cgit v1.2.3 From 6e98bee2899549c7482b05b0740bf195493ef9dc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 8 Dec 2016 20:22:42 -0200 Subject: [media] v4l: tvp5150: Don't inline the tvp5150_selmux() function The function is large and called in several places, don't inline it. Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index 08384951c9e5..febe6833a504 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -258,7 +258,7 @@ static int tvp5150_log_status(struct v4l2_subdev *sd) Basic functions ****************************************************************************/ -static inline void tvp5150_selmux(struct v4l2_subdev *sd) +static void tvp5150_selmux(struct v4l2_subdev *sd) { int opmode = 0; struct tvp5150 *decoder = to_tvp5150(sd); -- cgit v1.2.3 From d183e4efcae8d88a2f252e546978658ca6d273cc Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Thu, 8 Dec 2016 20:22:43 -0200 Subject: [media] v4l: tvp5150: Add missing break in set control handler A break is missing resulting in the hue control enabling or disabling the decode completely. Fix it. Fixes: c43875f66140 ("[media] tvp5150: replace MEDIA_ENT_F_CONN_TEST by a control") Cc: stable@vger.kernel.org Signed-off-by: Laurent Pinchart Signed-off-by: Mauro Carvalho Chehab --- drivers/media/i2c/tvp5150.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c index febe6833a504..3a0fe8cc64e9 100644 --- a/drivers/media/i2c/tvp5150.c +++ b/drivers/media/i2c/tvp5150.c @@ -818,6 +818,7 @@ static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl) return 0; case V4L2_CID_HUE: tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val); + break; case V4L2_CID_TEST_PATTERN: decoder->enable = ctrl->val ? false : true; tvp5150_selmux(sd); -- cgit v1.2.3 From c931225480aeabc6f867f2c1dea3738b3e1622a4 Mon Sep 17 00:00:00 2001 From: Lukas Wunner Date: Mon, 12 Dec 2016 09:45:47 -0600 Subject: x86/platform/intel-mid: Constify mid_pci_platform_pm This struct never needs to be modified. The size of pci-mid.o ELF sections changes thusly: -.data 56 +.data 0 -.rodata 32 +.rodata 88 Signed-off-by: Lukas Wunner Acked-by: Andy Shevchenko Acked-by: Bjorn Helgaas --- drivers/pci/pci-mid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/pci-mid.c b/drivers/pci/pci-mid.c index 55f453de562e..23ed7316c891 100644 --- a/drivers/pci/pci-mid.c +++ b/drivers/pci/pci-mid.c @@ -49,7 +49,7 @@ static bool mid_pci_need_resume(struct pci_dev *dev) return false; } -static struct pci_platform_pm_ops mid_pci_platform_pm = { +static const struct pci_platform_pm_ops mid_pci_platform_pm = { .is_manageable = mid_pci_power_manageable, .set_state = mid_pci_set_power_state, .choose_state = mid_pci_choose_state, -- cgit v1.2.3 From cc10385b6fde3e5d3a3edaabf10a4e211ee8fe72 Mon Sep 17 00:00:00 2001 From: Wang Sheng-Hui Date: Thu, 22 Sep 2016 09:05:46 +0800 Subject: PCI: Move config space size macros to pci_regs.h Move PCI configuration space size macros (PCI_CFG_SPACE_SIZE and PCI_CFG_SPACE_EXP_SIZE) from drivers/pci/pci.h to include/uapi/linux/pci_regs.h so they can be used by more drivers and eliminate duplicate definitions. [bhelgaas: Expand comment to include PCI-X details] Signed-off-by: Wang Sheng-Hui Signed-off-by: Bjorn Helgaas --- drivers/pci/pci.h | 3 --- drivers/vfio/pci/vfio_pci_config.c | 2 -- include/uapi/linux/pci_regs.h | 8 ++++++++ 3 files changed, 8 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 451856210e18..9cbcf1dd740b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -1,9 +1,6 @@ #ifndef DRIVERS_PCI_H #define DRIVERS_PCI_H -#define PCI_CFG_SPACE_SIZE 256 -#define PCI_CFG_SPACE_EXP_SIZE 4096 - #define PCI_FIND_CAP_TTL 48 extern const unsigned char pcie_link_speed[]; diff --git a/drivers/vfio/pci/vfio_pci_config.c b/drivers/vfio/pci/vfio_pci_config.c index 65d4a3015542..871af74fc4ce 100644 --- a/drivers/vfio/pci/vfio_pci_config.c +++ b/drivers/vfio/pci/vfio_pci_config.c @@ -31,8 +31,6 @@ #include "vfio_pci_private.h" -#define PCI_CFG_SPACE_SIZE 256 - /* Fake capability ID for standard config space */ #define PCI_CAP_ID_BASIC 0 diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h index e5a2e68b2236..174d1147081b 100644 --- a/include/uapi/linux/pci_regs.h +++ b/include/uapi/linux/pci_regs.h @@ -22,6 +22,14 @@ #ifndef LINUX_PCI_REGS_H #define LINUX_PCI_REGS_H +/* + * Conventional PCI and PCI-X Mode 1 devices have 256 bytes of + * configuration space. PCI-X Mode 2 and PCIe devices have 4096 bytes of + * configuration space. + */ +#define PCI_CFG_SPACE_SIZE 256 +#define PCI_CFG_SPACE_EXP_SIZE 4096 + /* * Under PCI, each device has 256 bytes of configuration address space, * of which the first 64 bytes are standardized as follows: -- cgit v1.2.3 From 0a1e1b26f560411cb58066201dddad5c224e8b9e Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Nov 2016 11:30:45 -0600 Subject: PCI/PME: Drop unused support for PMEs from Root Complex Event Collectors Since we register pcie_pme_driver only for PCI_EXP_TYPE_ROOT_PORT, the PME driver never claims Root Complex Event Collectors. Remove unused code related to Root Complex Event Collectors. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pcie/pme.c | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 884bad5320f8..9e8aa9d0a952 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -319,23 +319,8 @@ static int pcie_pme_set_native(struct pci_dev *dev, void *ign) static void pcie_pme_mark_devices(struct pci_dev *port) { pcie_pme_set_native(port, NULL); - if (port->subordinate) { + if (port->subordinate) pci_walk_bus(port->subordinate, pcie_pme_set_native, NULL); - } else { - struct pci_bus *bus = port->bus; - struct pci_dev *dev; - - /* Check if this is a root port event collector. */ - if (pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC || !bus) - return; - - down_read(&pci_bus_sem); - list_for_each_entry(dev, &bus->devices, bus_list) - if (pci_is_pcie(dev) - && pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END) - pcie_pme_set_native(dev, NULL); - up_read(&pci_bus_sem); - } } /** -- cgit v1.2.3 From a902d81ac802ca5eb06a140e024b903825117eaf Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Nov 2016 15:07:53 -0600 Subject: PCI/PME: Log PME IRQ when claiming Root Port We already log a "Signaling PME" whenever the PME service driver claims a Root Port. In fact, we also log the same message for every device in the hierarchy below the Root Port. Log the "Signaling PME" once (only for the Root Port, since we can trivially find out which devices are below the Root Port), and include the IRQ number in the message to help connect the dots with /proc/interrupts. Signed-off-by: Bjorn Helgaas Acked-by: Rafael J. Wysocki --- drivers/pci/pcie/pme.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/pme.c b/drivers/pci/pcie/pme.c index 9e8aa9d0a952..717529331dac 100644 --- a/drivers/pci/pcie/pme.c +++ b/drivers/pci/pcie/pme.c @@ -300,8 +300,6 @@ static irqreturn_t pcie_pme_irq(int irq, void *context) */ static int pcie_pme_set_native(struct pci_dev *dev, void *ign) { - dev_info(&dev->dev, "Signaling PME through PCIe PME interrupt\n"); - device_set_run_wake(&dev->dev, true); dev->pme_interrupt = true; return 0; @@ -349,12 +347,14 @@ static int pcie_pme_probe(struct pcie_device *srv) ret = request_irq(srv->irq, pcie_pme_irq, IRQF_SHARED, "PCIe PME", srv); if (ret) { kfree(data); - } else { - pcie_pme_mark_devices(port); - pcie_pme_interrupt_enable(port, true); + return ret; } - return ret; + dev_info(&port->dev, "Signaling PME with IRQ %d\n", srv->irq); + + pcie_pme_mark_devices(port); + pcie_pme_interrupt_enable(port, true); + return 0; } static bool pcie_pme_check_wakeup(struct pci_bus *bus) -- cgit v1.2.3 From 2298a7aaa837f460ac28458851d388b4abb38faa Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Nov 2016 15:19:29 -0600 Subject: PCI/AER: Remove unused version macros Remove the unused DRIVER_VERSION, DRIVER_AUTHOR, and DRIVER_DESC macros. The author information is already included in a comment above. Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 139150b2bdfd..1c189e61039d 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -30,13 +30,6 @@ #include "aerdrv.h" #include "../../pci.h" -/* - * Version Information - */ -#define DRIVER_VERSION "v1.0" -#define DRIVER_AUTHOR "tom.l.nguyen@intel.com" -#define DRIVER_DESC "Root Port Advanced Error Reporting Driver" - static int aer_probe(struct pcie_device *dev); static void aer_remove(struct pcie_device *dev); static pci_ers_result_t aer_error_detected(struct pci_dev *dev, -- cgit v1.2.3 From 576700b67a39ea422d28af085458748b50d591dc Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Nov 2016 15:24:25 -0600 Subject: PCI/AER: Log errors with PCI device, not PCIe service device All other AER-related log messages use the PCI device, e.g., "pci 0000:00:1c.0", not the PCIe service device, e.g., "aer 0000:00:1c.0:pcie02". Change the probe error messages to match the rest and include a little context. Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 1c189e61039d..60e63d60bb31 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -290,12 +290,12 @@ static int aer_probe(struct pcie_device *dev) { int status; struct aer_rpc *rpc; - struct device *device = &dev->device; + struct device *device = &dev->port->dev; /* Alloc rpc data structure */ rpc = aer_alloc_rpc(dev); if (!rpc) { - dev_printk(KERN_DEBUG, device, "alloc rpc failed\n"); + dev_printk(KERN_DEBUG, device, "alloc AER rpc failed\n"); aer_remove(dev); return -ENOMEM; } @@ -303,7 +303,8 @@ static int aer_probe(struct pcie_device *dev) /* Request IRQ ISR */ status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv", dev); if (status) { - dev_printk(KERN_DEBUG, device, "request IRQ failed\n"); + dev_printk(KERN_DEBUG, device, "request AER IRQ %d failed\n", + dev->irq); aer_remove(dev); return status; } -- cgit v1.2.3 From 68a55ae5c01356c4c45a3a26d8abd8186638b2a7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Mon, 21 Nov 2016 15:34:02 -0600 Subject: PCI/AER: Log AER IRQ when claiming Root Port Add a log message when we enable AER on a Root Port and the hierarchy below it. Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/aer/aerdrv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/aer/aerdrv.c b/drivers/pci/pcie/aer/aerdrv.c index 60e63d60bb31..dea186a9d6b6 100644 --- a/drivers/pci/pcie/aer/aerdrv.c +++ b/drivers/pci/pcie/aer/aerdrv.c @@ -312,8 +312,8 @@ static int aer_probe(struct pcie_device *dev) rpc->isr = 1; aer_enable_rootport(rpc); - - return status; + dev_info(device, "AER enabled with IRQ %d\n", dev->irq); + return 0; } /** -- cgit v1.2.3 From 98892fae40ed03ddf6f3bff847993e9d9dd8946a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 15 Nov 2016 07:54:19 -0600 Subject: PCI: Remove service driver load/unload messages Remove the "service driver %s loaded" and unloaded messages. All service drivers already log something in their probe functions, where they can log more useful details. Signed-off-by: Bjorn Helgaas --- drivers/pci/pcie/portdrv_core.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c index e9270b4026f3..9698289f105c 100644 --- a/drivers/pci/pcie/portdrv_core.c +++ b/drivers/pci/pcie/portdrv_core.c @@ -499,7 +499,6 @@ static int pcie_port_probe_service(struct device *dev) if (status) return status; - dev_printk(KERN_DEBUG, dev, "service driver %s loaded\n", driver->name); get_device(dev); return 0; } @@ -524,8 +523,6 @@ static int pcie_port_remove_service(struct device *dev) pciedev = to_pcie_device(dev); driver = to_service_driver(dev->driver); if (driver && driver->remove) { - dev_printk(KERN_DEBUG, dev, "unloading service driver %s\n", - driver->name); driver->remove(pciedev); put_device(dev); } -- cgit v1.2.3 From d9b47d5496fa613d0a091b1832245f65a3e8fc0a Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 15 Nov 2016 07:55:51 -0600 Subject: PCI: hotplug: Remove hotplug core message Remove the "PCI Hot Plug PCI Core" version message. I don't think it contains any useful information. Remove unused #defines and move the author information to a comment. Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pci_hotplug_core.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index fea0b8b33589..56013d0daf7f 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -23,6 +23,9 @@ * * Send feedback to * + * Authors: + * Greg Kroah-Hartman + * Scott Murray */ #include /* try_module_get & module_put */ @@ -50,15 +53,9 @@ #define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME, ## arg) #define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME, ## arg) - /* local variables */ static bool debug; -#define DRIVER_VERSION "0.5" -#define DRIVER_AUTHOR "Greg Kroah-Hartman , Scott Murray " -#define DRIVER_DESC "PCI Hot Plug PCI Core" - - static LIST_HEAD(pci_hotplug_slot_list); static DEFINE_MUTEX(pci_hp_mutex); @@ -534,7 +531,6 @@ static int __init pci_hotplug_init(void) return result; } - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); return result; } device_initcall(pci_hotplug_init); -- cgit v1.2.3 From 5fbeef63774878548a4a9244c8a5f5456a1b38a7 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 15 Nov 2016 07:57:30 -0600 Subject: PCI: pciehp: Remove loading message Remove the "PCI Express Hot Plug Controller Driver" version message. I don't think it contains any useful information. Remove unused #defines and move the author information to a comment. Signed-off-by: Bjorn Helgaas --- drivers/pci/hotplug/pciehp_core.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c index 7d32fa33dcef..35d84845d5af 100644 --- a/drivers/pci/hotplug/pciehp_core.c +++ b/drivers/pci/hotplug/pciehp_core.c @@ -25,6 +25,10 @@ * * Send feedback to , * + * Authors: + * Dan Zink + * Greg Kroah-Hartman + * Dely Sy " */ #include @@ -42,10 +46,6 @@ bool pciehp_poll_mode; int pciehp_poll_time; static bool pciehp_force; -#define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Dan Zink , Greg Kroah-Hartman , Dely Sy " -#define DRIVER_DESC "PCI Express Hot Plug Controller Driver" - /* * not really modular, but the easiest way to keep compat with existing * bootargs behaviour is to continue using module_param here. @@ -333,7 +333,6 @@ static int __init pcied_init(void) retval = pcie_port_service_register(&hpdriver_portdrv); dbg("pcie_port_service_register = %d\n", retval); - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); if (retval) dbg("Failure to register service\n"); -- cgit v1.2.3 From 044bc425bb72ffdecfb2a66d50cb1d024ecb96d0 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Tue, 15 Nov 2016 08:01:17 -0600 Subject: PCI: Expand "VPD access disabled" quirk message It's not very enlightening to see pci 0000:07:00.0: [Firmware Bug]: VPD access disabled in the dmesg log because there's no clue about what the firmware bug is. Expand the message to explain why we're disabling VPD. Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index c232729f5b1b..7329796a896f 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -2156,7 +2156,7 @@ static void quirk_blacklist_vpd(struct pci_dev *dev) { if (dev->vpd) { dev->vpd->len = 0; - dev_warn(&dev->dev, FW_BUG "VPD access disabled\n"); + dev_warn(&dev->dev, FW_BUG "disabling VPD access (can't determine size of non-standard VPD format)\n"); } } -- cgit v1.2.3 From 1c7de2b4ff886a45fbd2f4c3d4627e0f37a9dd77 Mon Sep 17 00:00:00 2001 From: Alexey Kardashevskiy Date: Mon, 24 Oct 2016 18:04:17 +1100 Subject: PCI: Enable access to non-standard VPD for Chelsio devices (cxgb3) There is at least one Chelsio 10Gb card which uses VPD area to store some non-standard blocks (example below). However pci_vpd_size() returns the length of the first block only assuming that there can be only one VPD "End Tag". Since 4e1a635552d3 ("vfio/pci: Use kernel VPD access functions"), VFIO blocks access beyond that offset, which prevents the guest "cxgb3" driver from probing the device. The host system does not have this problem as its driver accesses the config space directly without pci_read_vpd(). Add a quirk to override the VPD size to a bigger value. The maximum size is taken from EEPROMSIZE in drivers/net/ethernet/chelsio/cxgb3/common.h. We do not read the tag as the cxgb3 driver does as the driver supports writing to EEPROM/VPD and when it writes, it only checks for 8192 bytes boundary. The quirk is registered for all devices supported by the cxgb3 driver. This adds a quirk to the PCI layer (not to the cxgb3 driver) as the cxgb3 driver itself accesses VPD directly and the problem only exists with the vfio-pci driver (when cxgb3 is not running on the host and may not be even loaded) which blocks accesses beyond the first block of VPD data. However vfio-pci itself does not have quirks mechanism so we add it to PCI. This is the controller: Ethernet controller [0200]: Chelsio Communications Inc T310 10GbE Single Port Adapter [1425:0030] This is what I parsed from its VPD: === b'\x82*\x0010 Gigabit Ethernet-SR PCI Express Adapter\x90J\x00EC\x07D76809 FN\x0746K' 0000 Large item 42 bytes; name 0x2 Identifier String b'10 Gigabit Ethernet-SR PCI Express Adapter' 002d Large item 74 bytes; name 0x10 #00 [EC] len=7: b'D76809 ' #0a [FN] len=7: b'46K7897' #14 [PN] len=7: b'46K7897' #1e [MN] len=4: b'1037' #25 [FC] len=4: b'5769' #2c [SN] len=12: b'YL102035603V' #3b [NA] len=12: b'00145E992ED1' 007a Small item 1 bytes; name 0xf End Tag 0c00 Large item 16 bytes; name 0x2 Identifier String b'S310E-SR-X ' 0c13 Large item 234 bytes; name 0x10 #00 [PN] len=16: b'TBD ' #13 [EC] len=16: b'110107730D2 ' #26 [SN] len=16: b'97YL102035603V ' #39 [NA] len=12: b'00145E992ED1' #48 [V0] len=6: b'175000' #51 [V1] len=6: b'266666' #5a [V2] len=6: b'266666' #63 [V3] len=6: b'2000 ' #6c [V4] len=2: b'1 ' #71 [V5] len=6: b'c2 ' #7a [V6] len=6: b'0 ' #83 [V7] len=2: b'1 ' #88 [V8] len=2: b'0 ' #8d [V9] len=2: b'0 ' #92 [VA] len=2: b'0 ' #97 [RV] len=80: b's\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'... 0d00 Large item 252 bytes; name 0x11 #00 [VC] len=16: b'122310_1222 dp ' #13 [VD] len=16: b'610-0001-00 H1\x00\x00' #26 [VE] len=16: b'122310_1353 fp ' #39 [VF] len=16: b'610-0001-00 H1\x00\x00' #4c [RW] len=173: b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'... 0dff Small item 0 bytes; name 0xf End Tag 10f3 Large item 13315 bytes; name 0x62 !!! unknown item name 98: b'\xd0\x03\x00@`\x0c\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00' === Signed-off-by: Alexey Kardashevskiy Signed-off-by: Bjorn Helgaas --- drivers/pci/quirks.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers') diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 7329796a896f..bdc23ce2cd42 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c @@ -3255,6 +3255,25 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PORT_RIDGE, quirk_thunderbolt_hotplug_msi); +static void quirk_chelsio_extend_vpd(struct pci_dev *dev) +{ + pci_set_vpd_size(dev, 8192); +} + +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x20, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x21, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x22, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x23, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x24, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x25, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x26, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x30, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x31, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x32, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x35, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x36, quirk_chelsio_extend_vpd); +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_CHELSIO, 0x37, quirk_chelsio_extend_vpd); + #ifdef CONFIG_ACPI /* * Apple: Shutdown Cactus Ridge Thunderbolt controller. -- cgit v1.2.3 From 56c492f34110f85d6af3686df48755b85a912827 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: ioat: remove unused ‘is_raid_device’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ioat3_dma_probe(), variable ‘is_raid_device’ is initialized but never used, which leads to warning with W=1 drivers/dma/ioat/init.c: In function ‘ioat3_dma_probe’: drivers/dma/ioat/init.c:1084:7: warning: variable ‘is_raid_device’ set but not used [-Wunused-but-set-variable] bool is_raid_device = false; So remove it. Cc: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/init.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ioat/init.c b/drivers/dma/ioat/init.c index 015f7110b96d..a7af149e7ba2 100644 --- a/drivers/dma/ioat/init.c +++ b/drivers/dma/ioat/init.c @@ -1071,7 +1071,6 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca) struct dma_device *dma; struct dma_chan *c; struct ioatdma_chan *ioat_chan; - bool is_raid_device = false; int err; u16 val16; @@ -1095,7 +1094,6 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca) ioat_dma->cap &= ~(IOAT_CAP_XOR|IOAT_CAP_PQ); if (ioat_dma->cap & IOAT_CAP_XOR) { - is_raid_device = true; dma->max_xor = 8; dma_cap_set(DMA_XOR, dma->cap_mask); @@ -1106,7 +1104,6 @@ static int ioat3_dma_probe(struct ioatdma_device *ioat_dma, int dca) } if (ioat_dma->cap & IOAT_CAP_PQ) { - is_raid_device = true; dma->device_prep_dma_pq = ioat_prep_pq; dma->device_prep_dma_pq_val = ioat_prep_pq_val; -- cgit v1.2.3 From 4cc8044148e7c3b1de3074b061d5b1aa224f3635 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: ioat: remove unused ‘ioat_dma’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In ioat_tx_submit_unlock(), variable ‘ioat_dma’ is initialized but never used, which leads to warning with W=1 drivers/dma/ioat/dma.c: In function ‘ioat_alloc_ring_ent’: drivers/dma/ioat/dma.c:341:25: warning: variable ‘ioat_dma’ set but not used [-Wunused-but-set-variable] struct ioatdma_device *ioat_dma; So remove it. Cc: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/dma.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 49386ce04bf5..1350b880bc0d 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -341,15 +341,12 @@ ioat_alloc_ring_ent(struct dma_chan *chan, int idx, gfp_t flags) { struct ioat_dma_descriptor *hw; struct ioat_ring_ent *desc; - struct ioatdma_device *ioat_dma; struct ioatdma_chan *ioat_chan = to_ioat_chan(chan); int chunk; dma_addr_t phys; u8 *pos; off_t offs; - ioat_dma = to_ioatdma_device(chan->device); - chunk = idx / IOAT_DESCS_PER_2M; idx &= (IOAT_DESCS_PER_2M - 1); offs = idx * IOAT_DESC_SZ; -- cgit v1.2.3 From eef2c22cc3397bb8cf9f47226241fc65c04339aa Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: ioat: remove unused ‘res’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In __cleanup(), variable ‘res’ is initialized but never used, which leads to warning with W=1 drivers/dma/ioat/dma.c: In function ‘__cleanup’: drivers/dma/ioat/dma.c:614:28: warning: variable ‘res’ set but not used [-Wunused-but-set-variable] struct dmaengine_result res; So remove it. Cc: Dave Jiang Signed-off-by: Vinod Koul --- drivers/dma/ioat/dma.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/ioat/dma.c b/drivers/dma/ioat/dma.c index 1350b880bc0d..c867db765936 100644 --- a/drivers/dma/ioat/dma.c +++ b/drivers/dma/ioat/dma.c @@ -611,11 +611,8 @@ static void __cleanup(struct ioatdma_chan *ioat_chan, dma_addr_t phys_complete) tx = &desc->txd; if (tx->cookie) { - struct dmaengine_result res; - dma_cookie_complete(tx); dma_descriptor_unmap(tx); - res.result = DMA_TRANS_NOERROR; dmaengine_desc_get_callback_invoke(tx, NULL); tx->callback = NULL; tx->callback_result = NULL; -- cgit v1.2.3 From 7833a31df71dea6cd7342a5a0cc5277f0016c515 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: usb-dmac: remove unused ‘uchan’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In usb_dmac_of_xlate(), variable ‘uchan’ is initialized but never used, which leads to warning with W=1 drivers/dma/sh/usb-dmac.c: In function ‘usb_dmac_of_xlate’: drivers/dma/sh/usb-dmac.c:655:24: warning: variable ‘uchan’ set but not used [-Wunused-but-set-variable] struct usb_dmac_chan *uchan; So remove it. Cc: Yoshihiro Shimoda Signed-off-by: Vinod Koul --- drivers/dma/sh/usb-dmac.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/sh/usb-dmac.c b/drivers/dma/sh/usb-dmac.c index 06ecdc38cee0..72c649713ace 100644 --- a/drivers/dma/sh/usb-dmac.c +++ b/drivers/dma/sh/usb-dmac.c @@ -652,7 +652,6 @@ static bool usb_dmac_chan_filter(struct dma_chan *chan, void *arg) static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma) { - struct usb_dmac_chan *uchan; struct dma_chan *chan; dma_cap_mask_t mask; @@ -667,8 +666,6 @@ static struct dma_chan *usb_dmac_of_xlate(struct of_phandle_args *dma_spec, if (!chan) return NULL; - uchan = to_usb_dmac_chan(chan); - return chan; } -- cgit v1.2.3 From e5a6b3d5deeee7b7b45fe8765b5e48033adc9e8a Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: img-mdc: remove unused ‘prev_phys’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In mdc_prep_dma_memcpy(), mdc_prep_dma_cyclic() and mdc_prep_slave_sg() variable ‘prev_phys’ is initialized but never used, which leads to warning with W=1 drivers/dma/img-mdc-dma.c: In function ‘mdc_prep_dma_memcpy’: drivers/dma/img-mdc-dma.c:295:24: warning: variable ‘prev_phys’ set but not used [-Wunused-but-set-variable] dma_addr_t curr_phys, prev_phys; drivers/dma/img-mdc-dma.c: In function ‘mdc_prep_dma_cyclic’: drivers/dma/img-mdc-dma.c:378:24: warning: variable ‘prev_phys’ set but not used [-Wunused-but-set-variable] dma_addr_t curr_phys, prev_phys; drivers/dma/img-mdc-dma.c: In function ‘mdc_prep_slave_sg’: drivers/dma/img-mdc-dma.c:461:24: warning: variable ‘prev_phys’ set but not used [-Wunused-but-set-variable] dma_addr_t curr_phys, prev_phys; So remove it. Cc: Damien.Horsley Signed-off-by: Vinod Koul --- drivers/dma/img-mdc-dma.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c index 624f1e1e9c55..54db1411ce73 100644 --- a/drivers/dma/img-mdc-dma.c +++ b/drivers/dma/img-mdc-dma.c @@ -292,7 +292,7 @@ static struct dma_async_tx_descriptor *mdc_prep_dma_memcpy( struct mdc_dma *mdma = mchan->mdma; struct mdc_tx_desc *mdesc; struct mdc_hw_list_desc *curr, *prev = NULL; - dma_addr_t curr_phys, prev_phys; + dma_addr_t curr_phys; if (!len) return NULL; @@ -324,7 +324,6 @@ static struct dma_async_tx_descriptor *mdc_prep_dma_memcpy( xfer_size); prev = curr; - prev_phys = curr_phys; mdesc->list_len++; src += xfer_size; @@ -375,7 +374,7 @@ static struct dma_async_tx_descriptor *mdc_prep_dma_cyclic( struct mdc_dma *mdma = mchan->mdma; struct mdc_tx_desc *mdesc; struct mdc_hw_list_desc *curr, *prev = NULL; - dma_addr_t curr_phys, prev_phys; + dma_addr_t curr_phys; if (!buf_len && !period_len) return NULL; @@ -430,7 +429,6 @@ static struct dma_async_tx_descriptor *mdc_prep_dma_cyclic( } prev = curr; - prev_phys = curr_phys; mdesc->list_len++; buf_addr += xfer_size; @@ -458,7 +456,7 @@ static struct dma_async_tx_descriptor *mdc_prep_slave_sg( struct mdc_tx_desc *mdesc; struct scatterlist *sg; struct mdc_hw_list_desc *curr, *prev = NULL; - dma_addr_t curr_phys, prev_phys; + dma_addr_t curr_phys; unsigned int i; if (!sgl) @@ -509,7 +507,6 @@ static struct dma_async_tx_descriptor *mdc_prep_slave_sg( } prev = curr; - prev_phys = curr_phys; mdesc->list_len++; mdesc->list_xfer_size += xfer_size; -- cgit v1.2.3 From 765d2a6548f6e5b2968001481d19322bf9b78d83 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: mic_x100_dma: remove unused ‘data’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In mic_dma_init(), variable ‘data’ is initialized but never used, which leads to warning with W=1 drivers/dma/mic_x100_dma.c: In function ‘mic_dma_init’: drivers/dma/mic_x100_dma.c:557:17: warning: variable ‘data’ set but not used [-Wunused-but-set-variable] unsigned long data; So remove it. Cc: Sudeep Dutt Signed-off-by: Vinod Koul --- drivers/dma/mic_x100_dma.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/mic_x100_dma.c b/drivers/dma/mic_x100_dma.c index 818255844a3c..5ba5714d0b7c 100644 --- a/drivers/dma/mic_x100_dma.c +++ b/drivers/dma/mic_x100_dma.c @@ -554,9 +554,7 @@ static int mic_dma_init(struct mic_dma_device *mic_dma_dev, int ret; for (i = first_chan; i < first_chan + MIC_DMA_NUM_CHAN; i++) { - unsigned long data; ch = &mic_dma_dev->mic_ch[i]; - data = (unsigned long)ch; ch->ch_num = i; ch->owner = owner; spin_lock_init(&ch->cleanup_lock); -- cgit v1.2.3 From b33f7832bbf24dd40322fd673b2d7e3493c8515f Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: pch_dma: remove unused ‘cookie’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In pd_tx_submit(), variable ‘cookie’ is initialized but never used, which leads to warning with W=1 drivers/dma/pch_dma.c: In function ‘pd_tx_submit’: drivers/dma/pch_dma.c:420:15: warning: variable ‘cookie’ set but not used [-Wunused-but-set-variable] dma_cookie_t cookie; So remove it. Signed-off-by: Vinod Koul --- drivers/dma/pch_dma.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c index b8d858c7a7a5..f9028e9d0dfc 100644 --- a/drivers/dma/pch_dma.c +++ b/drivers/dma/pch_dma.c @@ -417,10 +417,8 @@ static dma_cookie_t pd_tx_submit(struct dma_async_tx_descriptor *txd) { struct pch_dma_desc *desc = to_pd_desc(txd); struct pch_dma_chan *pd_chan = to_pd_chan(txd->chan); - dma_cookie_t cookie; spin_lock(&pd_chan->lock); - cookie = dma_cookie_assign(txd); if (list_empty(&pd_chan->active_list)) { list_add_tail(&desc->desc_node, &pd_chan->active_list); -- cgit v1.2.3 From 1bc4f06c24a0fccd2ff9d81ca4b2ee4d3acb7fbb Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: stm32-dma: remove unused ‘sfcr’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In stm32_dma_chan_irq(), variable ‘sfcr’ is initialized but never used, which leads to warning with W=1 drivers/dma/stm32-dma.c: In function ‘stm32_dma_chan_irq’: drivers/dma/stm32-dma.c:530:19: warning: variable ‘sfcr’ set but not used [-Wunused-but-set-variable] u32 status, scr, sfcr; So remove it. Reviewed-by: M'boumba Cedric Madianga Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 307547f4848d..7f18192774e4 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -527,13 +527,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) { struct stm32_dma_chan *chan = devid; struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); - u32 status, scr, sfcr; + u32 status, scr; spin_lock(&chan->vchan.lock); status = stm32_dma_irq_status(chan); scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); - sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); if ((status & STM32_DMA_TCI) && (scr & STM32_DMA_SCR_TCIE)) { stm32_dma_irq_clear(chan, STM32_DMA_TCI); -- cgit v1.2.3 From 2a440bd417a57d26453c361951052656e4c837b1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: stm32-dma: remove unused ‘dst_addr’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In stm32_dma_set_xfer_param(), variable ‘dst_addr’ is initialized but never used, which leads to warning with W=1 drivers/dma/stm32-dma.c: In function ‘stm32_dma_set_xfer_param’: drivers/dma/stm32-dma.c:577:23: warning: variable ‘dst_addr’ set but not used [-Wunused-but-set-variable] dma_addr_t src_addr, dst_addr; So remove it. Reviewed-by: M'boumba Cedric Madianga Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 7f18192774e4..1f09189e31d9 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -573,7 +573,7 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, int src_bus_width, dst_bus_width; int src_burst_size, dst_burst_size; u32 src_maxburst, dst_maxburst; - dma_addr_t src_addr, dst_addr; + dma_addr_t src_addr; u32 dma_scr = 0; src_addr_width = chan->dma_sconfig.src_addr_width; @@ -581,7 +581,6 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, src_maxburst = chan->dma_sconfig.src_maxburst; dst_maxburst = chan->dma_sconfig.dst_maxburst; src_addr = chan->dma_sconfig.src_addr; - dst_addr = chan->dma_sconfig.dst_addr; switch (direction) { case DMA_MEM_TO_DEV: -- cgit v1.2.3 From cad0eca39fc001e17d422f08e64d67c6f9155cbe Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: stm32-dma: remove unused ‘src_addr’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In stm32_dma_set_xfer_param(), variable ‘src_addr’ is initialized but never used, which leads to warning with W=1 drivers/dma/stm32-dma.c: In function ‘stm32_dma_set_xfer_param’: drivers/dma/stm32-dma.c:577:13: warning: variable ‘src_addr’ set but not used [-Wunused-but-set-variable] dma_addr_t src_addr, dst_addr; So remove it. Reviewed-by: M'boumba Cedric Madianga Signed-off-by: Vinod Koul --- drivers/dma/stm32-dma.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c index 1f09189e31d9..3688d0873a3e 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -573,14 +573,12 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, int src_bus_width, dst_bus_width; int src_burst_size, dst_burst_size; u32 src_maxburst, dst_maxburst; - dma_addr_t src_addr; u32 dma_scr = 0; src_addr_width = chan->dma_sconfig.src_addr_width; dst_addr_width = chan->dma_sconfig.dst_addr_width; src_maxburst = chan->dma_sconfig.src_maxburst; dst_maxburst = chan->dma_sconfig.dst_maxburst; - src_addr = chan->dma_sconfig.src_addr; switch (direction) { case DMA_MEM_TO_DEV: -- cgit v1.2.3 From 963173fe4875d77320360628f827b0a818d6772e Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: s3c24xx: remove unused ‘cdata’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In s3c24xx_dma_get_phy(), variable ‘cdata’ is initialized but never used, which leads to warning with W=1. Removing this make pdata unused. drivers/dma/s3c24xx-dma.c: In function ‘s3c24xx_dma_get_phy’: drivers/dma/s3c24xx-dma.c:293:30: warning: variable ‘cdata’ set but not used [-Wunused-but-set-variable] struct s3c24xx_dma_channel *cdata; So remove both of them. Reviewed-by: Krzysztof Kozlowski Signed-off-by: Vinod Koul --- drivers/dma/s3c24xx-dma.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c index 3c579abbabb7..f04c4702d98b 100644 --- a/drivers/dma/s3c24xx-dma.c +++ b/drivers/dma/s3c24xx-dma.c @@ -289,16 +289,11 @@ static struct s3c24xx_dma_phy *s3c24xx_dma_get_phy(struct s3c24xx_dma_chan *s3cchan) { struct s3c24xx_dma_engine *s3cdma = s3cchan->host; - const struct s3c24xx_dma_platdata *pdata = s3cdma->pdata; - struct s3c24xx_dma_channel *cdata; struct s3c24xx_dma_phy *phy = NULL; unsigned long flags; int i; int ret; - if (s3cchan->slave) - cdata = &pdata->channels[s3cchan->id]; - for (i = 0; i < s3cdma->pdata->num_phy_channels; i++) { phy = &s3cdma->phy_chans[i]; -- cgit v1.2.3 From 920e00d62ef9a818a4af7b2f9e1dbca23f846fc1 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: pl330: remove unused ‘regs’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In pl330_add(), variable ‘regs’ is initialized but never used, which leads to warning with W=1. drivers/dma/pl330.c: In function 'pl330_add': drivers/dma/pl330.c:1891:16: warning: variable 'regs' set but not used [-Wunused-but-set-variable] So remove it. Cc: Linus Walleij Signed-off-by: Vinod Koul --- drivers/dma/pl330.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c index 2f3e063c406f..87fd01539fcb 100644 --- a/drivers/dma/pl330.c +++ b/drivers/dma/pl330.c @@ -1888,11 +1888,8 @@ static int dmac_alloc_resources(struct pl330_dmac *pl330) static int pl330_add(struct pl330_dmac *pl330) { - void __iomem *regs; int i, ret; - regs = pl330->base; - /* Check if we can handle this DMAC */ if ((pl330->pcfg.periph_id & 0xfffff) != PERIPH_ID_VAL) { dev_err(pl330->ddma.dev, "PERIPH_ID 0x%x !\n", -- cgit v1.2.3 From 2ef7ff03a9b050f393344a4537efb176de0c7eb2 Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Fri, 9 Dec 2016 15:24:12 +0530 Subject: dmaengine: sirf-dma: remove unused ‘sdesc’ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In sirfsoc_dma_pm_suspend(), variable ‘sdesc’ is initialized but never used, which leads to warning with W=1. drivers/dma/sirf-dma.c: In function 'sirfsoc_dma_pm_suspend': drivers/dma/sirf-dma.c:1014:27: warning: variable 'sdesc' set but not used [-Wunused-but-set-variable] So remove it. Signed-off-by: Vinod Koul --- drivers/dma/sirf-dma.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c index 8f62edad51be..a0733ac3edb1 100644 --- a/drivers/dma/sirf-dma.c +++ b/drivers/dma/sirf-dma.c @@ -1011,7 +1011,6 @@ static int __maybe_unused sirfsoc_dma_pm_suspend(struct device *dev) { struct sirfsoc_dma *sdma = dev_get_drvdata(dev); struct sirfsoc_dma_regs *save = &sdma->regs_save; - struct sirfsoc_dma_desc *sdesc; struct sirfsoc_dma_chan *schan; int ch; int ret; @@ -1044,9 +1043,6 @@ static int __maybe_unused sirfsoc_dma_pm_suspend(struct device *dev) schan = &sdma->channels[ch]; if (list_empty(&schan->active)) continue; - sdesc = list_first_entry(&schan->active, - struct sirfsoc_dma_desc, - node); save->ctrl[ch] = readl_relaxed(sdma->base + ch * 0x10 + SIRFSOC_DMA_CH_CTRL); } -- cgit v1.2.3 From 4d46f0148ed1bfaaf74e30653a140927b1d3a809 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Fri, 9 Dec 2016 17:59:56 -0800 Subject: Input: i8042 - comment #else/#endif of CONFIG_PNP As this define check if huge, this makes easier to read the code. Signed-off-by: Marcos Paulo de Souza Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index b42787e21d0a..21e134798ba3 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -1052,10 +1052,10 @@ static int __init i8042_pnp_init(void) return 0; } -#else +#else /* !CONFIG_PNP */ static inline int i8042_pnp_init(void) { return 0; } static inline void i8042_pnp_exit(void) { } -#endif +#endif /* CONFIG_PNP */ static int __init i8042_platform_init(void) { -- cgit v1.2.3 From 7343d11906788214220b124c379f5b0e1cec834f Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Mon, 12 Dec 2016 10:59:56 -0800 Subject: Input: ALPS - fix protcol -> protocol MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcos Paulo de Souza Reviewed-by: Pali Rohár Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/alps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h index 72b9efc5217b..cde6f4bd8ea2 100644 --- a/drivers/input/mouse/alps.h +++ b/drivers/input/mouse/alps.h @@ -166,7 +166,7 @@ struct alps_protocol_info { * (aka command mode response) identifies the firmware minor version. This * can be used to distinguish different hardware models which are not * uniquely identifiable through their E7 responses. - * @protocol_info: information about protcol used by the device. + * @protocol_info: information about protocol used by the device. * * Many (but not all) ALPS touchpads can be identified by looking at the * values returned in the "E7 report" and/or the "EC report." This table -- cgit v1.2.3 From 74c82dae6c474933f2be401976e1530b5f623221 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 10 Dec 2016 22:56:21 -0800 Subject: Input: drv260x - fix initializing overdrive voltage We were accidentally initializing haptics->rated_voltage twice, and did not initialize overdrive voltage. Acked-by: Dan Murphy Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 2adfd86c869a..9789d4fb6e51 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -521,7 +521,7 @@ static int drv260x_probe(struct i2c_client *client, if (!haptics) return -ENOMEM; - haptics->rated_voltage = DRV260X_DEF_OD_CLAMP_VOLT; + haptics->overdrive_voltage = DRV260X_DEF_OD_CLAMP_VOLT; haptics->rated_voltage = DRV260X_DEF_RATED_VOLT; if (pdata) { -- cgit v1.2.3 From 5191d88acc688743eef56f1c598a4e4cddf6c6cd Mon Sep 17 00:00:00 2001 From: Nick Dyer Date: Sat, 10 Dec 2016 23:27:32 -0800 Subject: Input: synaptics-rmi4 - add support for F34 V7 bootloader Port firmware update code from Samsung Galaxy S7 driver into mainline framework. This patch has been tested on Synaptics S7813. Signed-off-by: Nick Dyer Tested-by: Chris Healy Signed-off-by: Dmitry Torokhov --- drivers/input/rmi4/Makefile | 2 +- drivers/input/rmi4/rmi_driver.c | 56 +- drivers/input/rmi4/rmi_f34.c | 40 +- drivers/input/rmi4/rmi_f34.h | 250 ++++++- drivers/input/rmi4/rmi_f34v7.c | 1372 +++++++++++++++++++++++++++++++++++++++ include/linux/rmi.h | 2 +- 6 files changed, 1688 insertions(+), 34 deletions(-) create mode 100644 drivers/input/rmi4/rmi_f34v7.c (limited to 'drivers') diff --git a/drivers/input/rmi4/Makefile b/drivers/input/rmi4/Makefile index a199cbe9c27d..9aaac3dd8613 100644 --- a/drivers/input/rmi4/Makefile +++ b/drivers/input/rmi4/Makefile @@ -8,7 +8,7 @@ rmi_core-$(CONFIG_RMI4_F03) += rmi_f03.o rmi_core-$(CONFIG_RMI4_F11) += rmi_f11.o rmi_core-$(CONFIG_RMI4_F12) += rmi_f12.o rmi_core-$(CONFIG_RMI4_F30) += rmi_f30.o -rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o +rmi_core-$(CONFIG_RMI4_F34) += rmi_f34.o rmi_f34v7.o rmi_core-$(CONFIG_RMI4_F54) += rmi_f54.o rmi_core-$(CONFIG_RMI4_F55) += rmi_f55.o diff --git a/drivers/input/rmi4/rmi_driver.c b/drivers/input/rmi4/rmi_driver.c index 05a3c4bc9778..cb6efe693302 100644 --- a/drivers/input/rmi4/rmi_driver.c +++ b/drivers/input/rmi4/rmi_driver.c @@ -544,7 +544,7 @@ static int rmi_scan_pdt_page(struct rmi_device *rmi_dev, else *empty_pages = 0; - return (data->f01_bootloader_mode || *empty_pages >= 2) ? + return (data->bootloader_mode || *empty_pages >= 2) ? RMI_SCAN_DONE : RMI_SCAN_CONTINUE; } @@ -749,41 +749,49 @@ bool rmi_register_desc_has_subpacket(const struct rmi_register_desc_item *item, subpacket) == subpacket; } -/* Indicates that flash programming is enabled (bootloader mode). */ -#define RMI_F01_STATUS_BOOTLOADER(status) (!!((status) & 0x40)) - -/* - * Given the PDT entry for F01, read the device status register to determine - * if we're stuck in bootloader mode or not. - * - */ static int rmi_check_bootloader_mode(struct rmi_device *rmi_dev, const struct pdt_entry *pdt) { - int error; - u8 device_status; + struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); + int ret; + u8 status; - error = rmi_read(rmi_dev, pdt->data_base_addr + pdt->page_start, - &device_status); - if (error) { - dev_err(&rmi_dev->dev, - "Failed to read device status: %d.\n", error); - return error; + if (pdt->function_number == 0x34 && pdt->function_version > 1) { + ret = rmi_read(rmi_dev, pdt->data_base_addr, &status); + if (ret) { + dev_err(&rmi_dev->dev, + "Failed to read F34 status: %d.\n", ret); + return ret; + } + + if (status & BIT(7)) + data->bootloader_mode = true; + } else if (pdt->function_number == 0x01) { + ret = rmi_read(rmi_dev, pdt->data_base_addr, &status); + if (ret) { + dev_err(&rmi_dev->dev, + "Failed to read F01 status: %d.\n", ret); + return ret; + } + + if (status & BIT(6)) + data->bootloader_mode = true; } - return RMI_F01_STATUS_BOOTLOADER(device_status); + return 0; } static int rmi_count_irqs(struct rmi_device *rmi_dev, void *ctx, const struct pdt_entry *pdt) { - struct rmi_driver_data *data = dev_get_drvdata(&rmi_dev->dev); int *irq_count = ctx; + int ret; *irq_count += pdt->interrupt_source_count; - if (pdt->function_number == 0x01) - data->f01_bootloader_mode = - rmi_check_bootloader_mode(rmi_dev, pdt); + + ret = rmi_check_bootloader_mode(rmi_dev, pdt); + if (ret < 0) + return ret; return RMI_SCAN_CONTINUE; } @@ -1024,13 +1032,15 @@ int rmi_probe_interrupts(struct rmi_driver_data *data) */ rmi_dbg(RMI_DEBUG_CORE, dev, "%s: Counting IRQs.\n", __func__); irq_count = 0; + data->bootloader_mode = false; + retval = rmi_scan_pdt(rmi_dev, &irq_count, rmi_count_irqs); if (retval < 0) { dev_err(dev, "IRQ counting failed with code %d.\n", retval); return retval; } - if (data->f01_bootloader_mode) + if (data->bootloader_mode) dev_warn(&rmi_dev->dev, "Device in bootloader mode.\n"); data->irq_count = irq_count; diff --git a/drivers/input/rmi4/rmi_f34.c b/drivers/input/rmi4/rmi_f34.c index 01936a4a9a6c..9774dfbab9bb 100644 --- a/drivers/input/rmi4/rmi_f34.c +++ b/drivers/input/rmi4/rmi_f34.c @@ -12,6 +12,7 @@ #include #include #include +#include #include "rmi_driver.h" #include "rmi_f34.h" @@ -105,6 +106,9 @@ static int rmi_f34_attention(struct rmi_function *fn, unsigned long *irq_bits) struct f34_data *f34 = dev_get_drvdata(&fn->dev); int ret; + if (f34->bl_version != 5) + return 0; + ret = rmi_read(f34->fn->rmi_dev, f34->v5.ctrl_address, &f34->v5.status); rmi_dbg(RMI_DEBUG_FN, &fn->dev, "%s: status: %#02x, ret: %d\n", __func__, f34->v5.status, ret); @@ -292,17 +296,24 @@ static int rmi_firmware_update(struct rmi_driver_data *data, return -EINVAL; } - /* Only version 0 currently supported */ - if (data->f34_container->fd.function_version != 0) { + f34 = dev_get_drvdata(&data->f34_container->dev); + + if (f34->bl_version == 7) { + if (data->pdt_props & HAS_BSR) { + dev_err(dev, "%s: LTS not supported\n", __func__); + return -ENODEV; + } + } else if (f34->bl_version != 5) { dev_warn(dev, "F34 V%d not supported!\n", data->f34_container->fd.function_version); return -ENODEV; } - f34 = dev_get_drvdata(&data->f34_container->dev); - /* Enter flash mode */ - ret = rmi_f34_enable_flash(f34); + if (f34->bl_version == 7) + ret = rmi_f34v7_start_reflash(f34, fw); + else + ret = rmi_f34_enable_flash(f34); if (ret) return ret; @@ -319,7 +330,7 @@ static int rmi_firmware_update(struct rmi_driver_data *data, if (ret) return ret; - if (!data->f01_bootloader_mode || !data->f34_container) { + if (!data->bootloader_mode || !data->f34_container) { dev_warn(dev, "%s: No F34 present or not in bootloader!\n", __func__); return -EINVAL; @@ -330,7 +341,10 @@ static int rmi_firmware_update(struct rmi_driver_data *data, f34 = dev_get_drvdata(&data->f34_container->dev); /* Perform firmware update */ - ret = rmi_f34_update_firmware(f34, fw); + if (f34->bl_version == 7) + ret = rmi_f34v7_do_reflash(f34, fw); + else + ret = rmi_f34_update_firmware(f34, fw); dev_info(&f34->fn->dev, "Firmware update complete, status:%d\n", ret); @@ -363,6 +377,9 @@ static int rmi_firmware_update(struct rmi_driver_data *data, return ret; } +static int rmi_firmware_update(struct rmi_driver_data *data, + const struct firmware *fw); + static ssize_t rmi_driver_update_fw_store(struct device *dev, struct device_attribute *dattr, const char *buf, size_t count) @@ -411,6 +428,7 @@ static int rmi_f34_probe(struct rmi_function *fn) struct f34_data *f34; unsigned char f34_queries[9]; bool has_config_id; + u8 version = fn->fd.function_version; int ret; f34 = devm_kzalloc(&fn->dev, sizeof(struct f34_data), GFP_KERNEL); @@ -420,6 +438,14 @@ static int rmi_f34_probe(struct rmi_function *fn) f34->fn = fn; dev_set_drvdata(&fn->dev, f34); + /* v5 code only supported version 0, try V7 probe */ + if (version > 0) + return rmi_f34v7_probe(f34); + else if (version != 0) + return -ENODEV; + + f34->bl_version = 5; + ret = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr, f34_queries, sizeof(f34_queries)); if (ret) { diff --git a/drivers/input/rmi4/rmi_f34.h b/drivers/input/rmi4/rmi_f34.h index 6cee5282fbb4..2c21056dc375 100644 --- a/drivers/input/rmi4/rmi_f34.h +++ b/drivers/input/rmi4/rmi_f34.h @@ -33,6 +33,216 @@ #define F34_BOOTLOADER_ID_LEN 2 +/* F34 V7 defines */ +#define V7_FLASH_STATUS_OFFSET 0 +#define V7_PARTITION_ID_OFFSET 1 +#define V7_BLOCK_NUMBER_OFFSET 2 +#define V7_TRANSFER_LENGTH_OFFSET 3 +#define V7_COMMAND_OFFSET 4 +#define V7_PAYLOAD_OFFSET 5 +#define V7_BOOTLOADER_ID_OFFSET 1 + +#define IMAGE_HEADER_VERSION_10 0x10 + +#define CONFIG_ID_SIZE 32 +#define PRODUCT_ID_SIZE 10 + +#define ENABLE_WAIT_MS (1 * 1000) +#define WRITE_WAIT_MS (3 * 1000) + +#define MIN_SLEEP_TIME_US 50 +#define MAX_SLEEP_TIME_US 100 + +#define HAS_BSR BIT(5) +#define HAS_CONFIG_ID BIT(3) +#define HAS_GUEST_CODE BIT(6) +#define HAS_DISP_CFG BIT(5) + +/* F34 V7 commands */ +#define CMD_V7_IDLE 0 +#define CMD_V7_ENTER_BL 1 +#define CMD_V7_READ 2 +#define CMD_V7_WRITE 3 +#define CMD_V7_ERASE 4 +#define CMD_V7_ERASE_AP 5 +#define CMD_V7_SENSOR_ID 6 + +#define v7_CMD_IDLE 0 +#define v7_CMD_WRITE_FW 1 +#define v7_CMD_WRITE_CONFIG 2 +#define v7_CMD_WRITE_LOCKDOWN 3 +#define v7_CMD_WRITE_GUEST_CODE 4 +#define v7_CMD_READ_CONFIG 5 +#define v7_CMD_ERASE_ALL 6 +#define v7_CMD_ERASE_UI_FIRMWARE 7 +#define v7_CMD_ERASE_UI_CONFIG 8 +#define v7_CMD_ERASE_BL_CONFIG 9 +#define v7_CMD_ERASE_DISP_CONFIG 10 +#define v7_CMD_ERASE_FLASH_CONFIG 11 +#define v7_CMD_ERASE_GUEST_CODE 12 +#define v7_CMD_ENABLE_FLASH_PROG 13 + +#define v7_UI_CONFIG_AREA 0 +#define v7_PM_CONFIG_AREA 1 +#define v7_BL_CONFIG_AREA 2 +#define v7_DP_CONFIG_AREA 3 +#define v7_FLASH_CONFIG_AREA 4 + +/* F34 V7 partition IDs */ +#define BOOTLOADER_PARTITION 1 +#define DEVICE_CONFIG_PARTITION 2 +#define FLASH_CONFIG_PARTITION 3 +#define MANUFACTURING_BLOCK_PARTITION 4 +#define GUEST_SERIALIZATION_PARTITION 5 +#define GLOBAL_PARAMETERS_PARTITION 6 +#define CORE_CODE_PARTITION 7 +#define CORE_CONFIG_PARTITION 8 +#define GUEST_CODE_PARTITION 9 +#define DISPLAY_CONFIG_PARTITION 10 + +/* F34 V7 container IDs */ +#define TOP_LEVEL_CONTAINER 0 +#define UI_CONTAINER 1 +#define UI_CONFIG_CONTAINER 2 +#define BL_CONTAINER 3 +#define BL_IMAGE_CONTAINER 4 +#define BL_CONFIG_CONTAINER 5 +#define BL_LOCKDOWN_INFO_CONTAINER 6 +#define PERMANENT_CONFIG_CONTAINER 7 +#define GUEST_CODE_CONTAINER 8 +#define BL_PROTOCOL_DESCRIPTOR_CONTAINER 9 +#define UI_PROTOCOL_DESCRIPTOR_CONTAINER 10 +#define RMI_SELF_DISCOVERY_CONTAINER 11 +#define RMI_PAGE_CONTENT_CONTAINER 12 +#define GENERAL_INFORMATION_CONTAINER 13 +#define DEVICE_CONFIG_CONTAINER 14 +#define FLASH_CONFIG_CONTAINER 15 +#define GUEST_SERIALIZATION_CONTAINER 16 +#define GLOBAL_PARAMETERS_CONTAINER 17 +#define CORE_CODE_CONTAINER 18 +#define CORE_CONFIG_CONTAINER 19 +#define DISPLAY_CONFIG_CONTAINER 20 + +struct f34v7_query_1_7 { + u8 bl_minor_revision; /* query 1 */ + u8 bl_major_revision; + __le32 bl_fw_id; /* query 2 */ + u8 minimum_write_size; /* query 3 */ + __le16 block_size; + __le16 flash_page_size; + __le16 adjustable_partition_area_size; /* query 4 */ + __le16 flash_config_length; /* query 5 */ + __le16 payload_length; /* query 6 */ + u8 partition_support[4]; /* query 7 */ +} __packed; + +struct f34v7_data_1_5 { + u8 partition_id; + __le16 block_offset; + __le16 transfer_length; + u8 command; + u8 payload[2]; +} __packed; + +struct block_data { + const void *data; + int size; +}; + +struct partition_table { + u8 partition_id; + u8 byte_1_reserved; + __le16 partition_length; + __le16 start_physical_address; + __le16 partition_properties; +} __packed; + +struct physical_address { + u16 ui_firmware; + u16 ui_config; + u16 dp_config; + u16 guest_code; +}; + +struct container_descriptor { + __le32 content_checksum; + __le16 container_id; + u8 minor_version; + u8 major_version; + u8 reserved_08; + u8 reserved_09; + u8 reserved_0a; + u8 reserved_0b; + u8 container_option_flags[4]; + __le32 content_options_length; + __le32 content_options_address; + __le32 content_length; + __le32 content_address; +} __packed; + +struct block_count { + u16 ui_firmware; + u16 ui_config; + u16 dp_config; + u16 fl_config; + u16 pm_config; + u16 bl_config; + u16 lockdown; + u16 guest_code; +}; + +struct image_header_10 { + __le32 checksum; + u8 reserved_04; + u8 reserved_05; + u8 minor_header_version; + u8 major_header_version; + u8 reserved_08; + u8 reserved_09; + u8 reserved_0a; + u8 reserved_0b; + __le32 top_level_container_start_addr; +}; + +struct image_metadata { + bool contains_firmware_id; + bool contains_bootloader; + bool contains_display_cfg; + bool contains_guest_code; + bool contains_flash_config; + unsigned int firmware_id; + unsigned int checksum; + unsigned int bootloader_size; + unsigned int display_cfg_offset; + unsigned char bl_version; + unsigned char product_id[PRODUCT_ID_SIZE + 1]; + unsigned char cstmr_product_id[PRODUCT_ID_SIZE + 1]; + struct block_data bootloader; + struct block_data ui_firmware; + struct block_data ui_config; + struct block_data dp_config; + struct block_data fl_config; + struct block_data bl_config; + struct block_data guest_code; + struct block_data lockdown; + struct block_count blkcount; + struct physical_address phyaddr; +}; + +struct register_offset { + u8 properties; + u8 properties_2; + u8 block_size; + u8 block_count; + u8 gc_block_count; + u8 flash_status; + u8 partition_id; + u8 block_number; + u8 transfer_length; + u8 flash_cmd; + u8 payload; +}; + struct rmi_f34_firmware { __le32 checksum; u8 pad1[3]; @@ -56,13 +266,49 @@ struct f34v5_data { struct mutex flash_mutex; }; +struct f34v7_data { + bool has_display_cfg; + bool has_guest_code; + bool force_update; + bool in_bl_mode; + u8 *read_config_buf; + size_t read_config_buf_size; + u8 command; + u8 flash_status; + u16 block_size; + u16 config_block_count; + u16 config_size; + u16 config_area; + u16 flash_config_length; + u16 payload_length; + u8 partitions; + u16 partition_table_bytes; + bool new_partition_table; + + struct register_offset off; + struct block_count blkcount; + struct physical_address phyaddr; + struct image_metadata img; + + const void *config_data; + const void *image; +}; + struct f34_data { struct rmi_function *fn; + u8 bl_version; unsigned char bootloader_id[5]; - unsigned char configuration_id[9]; + unsigned char configuration_id[CONFIG_ID_SIZE*2 + 1]; - struct f34v5_data v5; + union { + struct f34v5_data v5; + struct f34v7_data v7; + }; }; +int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw); +int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw); +int rmi_f34v7_probe(struct f34_data *f34); + #endif /* _RMI_F34_H */ diff --git a/drivers/input/rmi4/rmi_f34v7.c b/drivers/input/rmi4/rmi_f34v7.c new file mode 100644 index 000000000000..ca31f9539d9b --- /dev/null +++ b/drivers/input/rmi4/rmi_f34v7.c @@ -0,0 +1,1372 @@ +/* + * Copyright (c) 2016, Zodiac Inflight Innovations + * Copyright (c) 2007-2016, Synaptics Incorporated + * Copyright (C) 2012 Alexandra Chin + * Copyright (C) 2012 Scott Lin + * + * 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 "rmi_driver.h" +#include "rmi_f34.h" + +static int rmi_f34v7_read_flash_status(struct f34_data *f34) +{ + u8 status; + u8 command; + int ret; + + ret = rmi_read_block(f34->fn->rmi_dev, + f34->fn->fd.data_base_addr + f34->v7.off.flash_status, + &status, + sizeof(status)); + if (ret < 0) { + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Failed to read flash status\n", __func__); + return ret; + } + + f34->v7.in_bl_mode = status >> 7; + f34->v7.flash_status = status & 0x1f; + + if (f34->v7.flash_status != 0x00) { + dev_err(&f34->fn->dev, "%s: status=%d, command=0x%02x\n", + __func__, f34->v7.flash_status, f34->v7.command); + } + + ret = rmi_read_block(f34->fn->rmi_dev, + f34->fn->fd.data_base_addr + f34->v7.off.flash_cmd, + &command, + sizeof(command)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to read flash command\n", + __func__); + return ret; + } + + f34->v7.command = command; + + return 0; +} + +static int rmi_f34v7_wait_for_idle(struct f34_data *f34, int timeout_ms) +{ + int count = 0; + int timeout_count = ((timeout_ms * 1000) / MAX_SLEEP_TIME_US) + 1; + + do { + usleep_range(MIN_SLEEP_TIME_US, MAX_SLEEP_TIME_US); + + count++; + + rmi_f34v7_read_flash_status(f34); + + if ((f34->v7.command == v7_CMD_IDLE) + && (f34->v7.flash_status == 0x00)) { + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "Idle status detected\n"); + return 0; + } + } while (count < timeout_count); + + dev_err(&f34->fn->dev, + "%s: Timed out waiting for idle status\n", __func__); + + return -ETIMEDOUT; +} + +static int rmi_f34v7_write_command_single_transaction(struct f34_data *f34, + u8 cmd) +{ + int ret; + u8 base; + struct f34v7_data_1_5 data_1_5; + + base = f34->fn->fd.data_base_addr; + + memset(&data_1_5, 0, sizeof(data_1_5)); + + switch (cmd) { + case v7_CMD_ERASE_ALL: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE_AP; + break; + case v7_CMD_ERASE_UI_FIRMWARE: + data_1_5.partition_id = CORE_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_BL_CONFIG: + data_1_5.partition_id = GLOBAL_PARAMETERS_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_UI_CONFIG: + data_1_5.partition_id = CORE_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_DISP_CONFIG: + data_1_5.partition_id = DISPLAY_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_FLASH_CONFIG: + data_1_5.partition_id = FLASH_CONFIG_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ERASE_GUEST_CODE: + data_1_5.partition_id = GUEST_CODE_PARTITION; + data_1_5.command = CMD_V7_ERASE; + break; + case v7_CMD_ENABLE_FLASH_PROG: + data_1_5.partition_id = BOOTLOADER_PARTITION; + data_1_5.command = CMD_V7_ENTER_BL; + break; + } + + data_1_5.payload[0] = f34->bootloader_id[0]; + data_1_5.payload[1] = f34->bootloader_id[1]; + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.partition_id, + &data_1_5, sizeof(data_1_5)); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Failed to write single transaction command\n", + __func__); + return ret; + } + + return 0; +} + +static int rmi_f34v7_write_command(struct f34_data *f34, u8 cmd) +{ + int ret; + u8 base; + u8 command; + + base = f34->fn->fd.data_base_addr; + + switch (cmd) { + case v7_CMD_WRITE_FW: + case v7_CMD_WRITE_CONFIG: + case v7_CMD_WRITE_GUEST_CODE: + command = CMD_V7_WRITE; + break; + case v7_CMD_READ_CONFIG: + command = CMD_V7_READ; + break; + case v7_CMD_ERASE_ALL: + command = CMD_V7_ERASE_AP; + break; + case v7_CMD_ERASE_UI_FIRMWARE: + case v7_CMD_ERASE_BL_CONFIG: + case v7_CMD_ERASE_UI_CONFIG: + case v7_CMD_ERASE_DISP_CONFIG: + case v7_CMD_ERASE_FLASH_CONFIG: + case v7_CMD_ERASE_GUEST_CODE: + command = CMD_V7_ERASE; + break; + case v7_CMD_ENABLE_FLASH_PROG: + command = CMD_V7_ENTER_BL; + break; + default: + dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + } + + f34->v7.command = command; + + switch (cmd) { + case v7_CMD_ERASE_ALL: + case v7_CMD_ERASE_UI_FIRMWARE: + case v7_CMD_ERASE_BL_CONFIG: + case v7_CMD_ERASE_UI_CONFIG: + case v7_CMD_ERASE_DISP_CONFIG: + case v7_CMD_ERASE_FLASH_CONFIG: + case v7_CMD_ERASE_GUEST_CODE: + case v7_CMD_ENABLE_FLASH_PROG: + ret = rmi_f34v7_write_command_single_transaction(f34, cmd); + if (ret < 0) + return ret; + else + return 0; + default: + break; + } + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: writing cmd %02X\n", + __func__, command); + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.flash_cmd, + &command, sizeof(command)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to write flash command\n", + __func__); + return ret; + } + + return 0; +} + +static int rmi_f34v7_write_partition_id(struct f34_data *f34, u8 cmd) +{ + int ret; + u8 base; + u8 partition; + + base = f34->fn->fd.data_base_addr; + + switch (cmd) { + case v7_CMD_WRITE_FW: + partition = CORE_CODE_PARTITION; + break; + case v7_CMD_WRITE_CONFIG: + case v7_CMD_READ_CONFIG: + if (f34->v7.config_area == v7_UI_CONFIG_AREA) + partition = CORE_CONFIG_PARTITION; + else if (f34->v7.config_area == v7_DP_CONFIG_AREA) + partition = DISPLAY_CONFIG_PARTITION; + else if (f34->v7.config_area == v7_PM_CONFIG_AREA) + partition = GUEST_SERIALIZATION_PARTITION; + else if (f34->v7.config_area == v7_BL_CONFIG_AREA) + partition = GLOBAL_PARAMETERS_PARTITION; + else if (f34->v7.config_area == v7_FLASH_CONFIG_AREA) + partition = FLASH_CONFIG_PARTITION; + break; + case v7_CMD_WRITE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case v7_CMD_ERASE_ALL: + partition = CORE_CODE_PARTITION; + break; + case v7_CMD_ERASE_BL_CONFIG: + partition = GLOBAL_PARAMETERS_PARTITION; + break; + case v7_CMD_ERASE_UI_CONFIG: + partition = CORE_CONFIG_PARTITION; + break; + case v7_CMD_ERASE_DISP_CONFIG: + partition = DISPLAY_CONFIG_PARTITION; + break; + case v7_CMD_ERASE_FLASH_CONFIG: + partition = FLASH_CONFIG_PARTITION; + break; + case v7_CMD_ERASE_GUEST_CODE: + partition = GUEST_CODE_PARTITION; + break; + case v7_CMD_ENABLE_FLASH_PROG: + partition = BOOTLOADER_PARTITION; + break; + default: + dev_err(&f34->fn->dev, "%s: Invalid command 0x%02x\n", + __func__, cmd); + return -EINVAL; + } + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.partition_id, + &partition, sizeof(partition)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to write partition ID\n", + __func__); + return ret; + } + + return 0; +} + +static int rmi_f34v7_read_f34v7_partition_table(struct f34_data *f34) +{ + int ret; + u8 base; + __le16 length; + u16 block_number = 0; + + base = f34->fn->fd.data_base_addr; + + f34->v7.config_area = v7_FLASH_CONFIG_AREA; + + ret = rmi_f34v7_write_partition_id(f34, v7_CMD_READ_CONFIG); + if (ret < 0) + return ret; + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.block_number, + &block_number, sizeof(block_number)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to write block number\n", + __func__); + return ret; + } + + put_unaligned_le16(f34->v7.flash_config_length, &length); + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.transfer_length, + &length, sizeof(length)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to write transfer length\n", + __func__); + return ret; + } + + ret = rmi_f34v7_write_command(f34, v7_CMD_READ_CONFIG); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to write command\n", + __func__); + return ret; + } + + ret = rmi_f34v7_wait_for_idle(f34, WRITE_WAIT_MS); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to wait for idle status\n", + __func__); + return ret; + } + + ret = rmi_read_block(f34->fn->rmi_dev, + base + f34->v7.off.payload, + f34->v7.read_config_buf, + f34->v7.partition_table_bytes); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to read block data\n", + __func__); + return ret; + } + + return 0; +} + +static void rmi_f34v7_parse_partition_table(struct f34_data *f34, + const void *partition_table, + struct block_count *blkcount, + struct physical_address *phyaddr) +{ + int i; + int index; + u16 partition_length; + u16 physical_address; + const struct partition_table *ptable; + + for (i = 0; i < f34->v7.partitions; i++) { + index = i * 8 + 2; + ptable = partition_table + index; + partition_length = le16_to_cpu(ptable->partition_length); + physical_address = le16_to_cpu(ptable->start_physical_address); + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Partition entry %d: %*ph\n", + __func__, i, sizeof(struct partition_table), ptable); + switch (ptable->partition_id & 0x1f) { + case CORE_CODE_PARTITION: + blkcount->ui_firmware = partition_length; + phyaddr->ui_firmware = physical_address; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Core code block count: %d\n", + __func__, blkcount->ui_firmware); + break; + case CORE_CONFIG_PARTITION: + blkcount->ui_config = partition_length; + phyaddr->ui_config = physical_address; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Core config block count: %d\n", + __func__, blkcount->ui_config); + break; + case DISPLAY_CONFIG_PARTITION: + blkcount->dp_config = partition_length; + phyaddr->dp_config = physical_address; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Display config block count: %d\n", + __func__, blkcount->dp_config); + break; + case FLASH_CONFIG_PARTITION: + blkcount->fl_config = partition_length; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Flash config block count: %d\n", + __func__, blkcount->fl_config); + break; + case GUEST_CODE_PARTITION: + blkcount->guest_code = partition_length; + phyaddr->guest_code = physical_address; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Guest code block count: %d\n", + __func__, blkcount->guest_code); + break; + case GUEST_SERIALIZATION_PARTITION: + blkcount->pm_config = partition_length; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Guest serialization block count: %d\n", + __func__, blkcount->pm_config); + break; + case GLOBAL_PARAMETERS_PARTITION: + blkcount->bl_config = partition_length; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Global parameters block count: %d\n", + __func__, blkcount->bl_config); + break; + case DEVICE_CONFIG_PARTITION: + blkcount->lockdown = partition_length; + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Device config block count: %d\n", + __func__, blkcount->lockdown); + break; + } + } +} + +static int rmi_f34v7_read_queries_bl_version(struct f34_data *f34) +{ + int ret; + u8 base; + int offset; + u8 query_0; + struct f34v7_query_1_7 query_1_7; + + base = f34->fn->fd.query_base_addr; + + ret = rmi_read_block(f34->fn->rmi_dev, + base, + &query_0, + sizeof(query_0)); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Failed to read query 0\n", __func__); + return ret; + } + + offset = (query_0 & 0x7) + 1; + + ret = rmi_read_block(f34->fn->rmi_dev, + base + offset, + &query_1_7, + sizeof(query_1_7)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n", + __func__); + return ret; + } + + f34->bootloader_id[0] = query_1_7.bl_minor_revision; + f34->bootloader_id[1] = query_1_7.bl_major_revision; + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Bootloader V%d.%d\n", + f34->bootloader_id[1], f34->bootloader_id[0]); + + return 0; +} + +static int rmi_f34v7_read_queries(struct f34_data *f34) +{ + int ret; + int i, j; + u8 base; + int offset; + u8 *ptable; + u8 query_0; + struct f34v7_query_1_7 query_1_7; + + base = f34->fn->fd.query_base_addr; + + ret = rmi_read_block(f34->fn->rmi_dev, + base, + &query_0, + sizeof(query_0)); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Failed to read query 0\n", __func__); + return ret; + } + + offset = (query_0 & 0x07) + 1; + + ret = rmi_read_block(f34->fn->rmi_dev, + base + offset, + &query_1_7, + sizeof(query_1_7)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to read queries 1 to 7\n", + __func__); + return ret; + } + + f34->bootloader_id[0] = query_1_7.bl_minor_revision; + f34->bootloader_id[1] = query_1_7.bl_major_revision; + + f34->v7.block_size = le16_to_cpu(query_1_7.block_size); + f34->v7.flash_config_length = + le16_to_cpu(query_1_7.flash_config_length); + f34->v7.payload_length = le16_to_cpu(query_1_7.payload_length); + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.block_size = %d\n", + __func__, f34->v7.block_size); + + f34->v7.off.flash_status = V7_FLASH_STATUS_OFFSET; + f34->v7.off.partition_id = V7_PARTITION_ID_OFFSET; + f34->v7.off.block_number = V7_BLOCK_NUMBER_OFFSET; + f34->v7.off.transfer_length = V7_TRANSFER_LENGTH_OFFSET; + f34->v7.off.flash_cmd = V7_COMMAND_OFFSET; + f34->v7.off.payload = V7_PAYLOAD_OFFSET; + + f34->v7.has_display_cfg = query_1_7.partition_support[1] & HAS_DISP_CFG; + f34->v7.has_guest_code = + query_1_7.partition_support[1] & HAS_GUEST_CODE; + + if (query_0 & HAS_CONFIG_ID) { + char f34_ctrl[CONFIG_ID_SIZE]; + int i = 0; + u8 *p = f34->configuration_id; + *p = '\0'; + + ret = rmi_read_block(f34->fn->rmi_dev, + f34->fn->fd.control_base_addr, + f34_ctrl, + sizeof(f34_ctrl)); + if (ret) + return ret; + + /* Eat leading zeros */ + while (i < sizeof(f34_ctrl) && !f34_ctrl[i]) + i++; + + for (; i < sizeof(f34_ctrl); i++) + p += snprintf(p, f34->configuration_id + + sizeof(f34->configuration_id) - p, + "%02X", f34_ctrl[i]); + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "Configuration ID: %s\n", + f34->configuration_id); + } + + f34->v7.partitions = 0; + for (i = 0; i < sizeof(query_1_7.partition_support); i++) + for (j = 0; j < 8; j++) + if (query_1_7.partition_support[i] & (1 << j)) + f34->v7.partitions++; + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: Supported partitions: %*ph\n", + __func__, sizeof(query_1_7.partition_support), + query_1_7.partition_support); + + + f34->v7.partition_table_bytes = f34->v7.partitions * 8 + 2; + + f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev, + f34->v7.partition_table_bytes, + GFP_KERNEL); + if (!f34->v7.read_config_buf) { + f34->v7.read_config_buf_size = 0; + return -ENOMEM; + } + + f34->v7.read_config_buf_size = f34->v7.partition_table_bytes; + ptable = f34->v7.read_config_buf; + + ret = rmi_f34v7_read_f34v7_partition_table(f34); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to read partition table\n", + __func__); + return ret; + } + + rmi_f34v7_parse_partition_table(f34, ptable, + &f34->v7.blkcount, &f34->v7.phyaddr); + + return 0; +} + +static int rmi_f34v7_check_ui_firmware_size(struct f34_data *f34) +{ + u16 block_count; + + block_count = f34->v7.img.ui_firmware.size / f34->v7.block_size; + + if (block_count != f34->v7.blkcount.ui_firmware) { + dev_err(&f34->fn->dev, + "UI firmware size mismatch: %d != %d\n", + block_count, f34->v7.blkcount.ui_firmware); + return -EINVAL; + } + + return 0; +} + +static int rmi_f34v7_check_ui_config_size(struct f34_data *f34) +{ + u16 block_count; + + block_count = f34->v7.img.ui_config.size / f34->v7.block_size; + + if (block_count != f34->v7.blkcount.ui_config) { + dev_err(&f34->fn->dev, "UI config size mismatch\n"); + return -EINVAL; + } + + return 0; +} + +static int rmi_f34v7_check_dp_config_size(struct f34_data *f34) +{ + u16 block_count; + + block_count = f34->v7.img.dp_config.size / f34->v7.block_size; + + if (block_count != f34->v7.blkcount.dp_config) { + dev_err(&f34->fn->dev, "Display config size mismatch\n"); + return -EINVAL; + } + + return 0; +} + +static int rmi_f34v7_check_guest_code_size(struct f34_data *f34) +{ + u16 block_count; + + block_count = f34->v7.img.guest_code.size / f34->v7.block_size; + if (block_count != f34->v7.blkcount.guest_code) { + dev_err(&f34->fn->dev, "Guest code size mismatch\n"); + return -EINVAL; + } + + return 0; +} + +static int rmi_f34v7_check_bl_config_size(struct f34_data *f34) +{ + u16 block_count; + + block_count = f34->v7.img.bl_config.size / f34->v7.block_size; + + if (block_count != f34->v7.blkcount.bl_config) { + dev_err(&f34->fn->dev, "Bootloader config size mismatch\n"); + return -EINVAL; + } + + return 0; +} + +static int rmi_f34v7_erase_config(struct f34_data *f34) +{ + int ret; + + dev_info(&f34->fn->dev, "Erasing config...\n"); + + switch (f34->v7.config_area) { + case v7_UI_CONFIG_AREA: + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_CONFIG); + if (ret < 0) + return ret; + break; + case v7_DP_CONFIG_AREA: + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_DISP_CONFIG); + if (ret < 0) + return ret; + break; + case v7_BL_CONFIG_AREA: + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_BL_CONFIG); + if (ret < 0) + return ret; + break; + } + + ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + if (ret < 0) + return ret; + + return ret; +} + +static int rmi_f34v7_erase_guest_code(struct f34_data *f34) +{ + int ret; + + dev_info(&f34->fn->dev, "Erasing guest code...\n"); + + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_GUEST_CODE); + if (ret < 0) + return ret; + + ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + if (ret < 0) + return ret; + + return 0; +} + +static int rmi_f34v7_erase_all(struct f34_data *f34) +{ + int ret; + + dev_info(&f34->fn->dev, "Erasing firmware...\n"); + + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_UI_FIRMWARE); + if (ret < 0) + return ret; + + ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + if (ret < 0) + return ret; + + f34->v7.config_area = v7_UI_CONFIG_AREA; + ret = rmi_f34v7_erase_config(f34); + if (ret < 0) + return ret; + + if (f34->v7.has_display_cfg) { + f34->v7.config_area = v7_DP_CONFIG_AREA; + ret = rmi_f34v7_erase_config(f34); + if (ret < 0) + return ret; + } + + if (f34->v7.new_partition_table && f34->v7.has_guest_code) { + ret = rmi_f34v7_erase_guest_code(f34); + if (ret < 0) + return ret; + } + + return 0; +} + +static int rmi_f34v7_read_f34v7_blocks(struct f34_data *f34, u16 block_cnt, + u8 command) +{ + int ret; + u8 base; + __le16 length; + u16 transfer; + u16 max_transfer; + u16 remaining = block_cnt; + u16 block_number = 0; + u16 index = 0; + + base = f34->fn->fd.data_base_addr; + + ret = rmi_f34v7_write_partition_id(f34, command); + if (ret < 0) + return ret; + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.block_number, + &block_number, sizeof(block_number)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to write block number\n", + __func__); + return ret; + } + + max_transfer = min(f34->v7.payload_length, + (u16)(PAGE_SIZE / f34->v7.block_size)); + + do { + transfer = min(remaining, max_transfer); + put_unaligned_le16(transfer, &length); + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.transfer_length, + &length, sizeof(length)); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Write transfer length fail (%d remaining)\n", + __func__, remaining); + return ret; + } + + ret = rmi_f34v7_write_command(f34, command); + if (ret < 0) + return ret; + + ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Wait for idle failed (%d blks remaining)\n", + __func__, remaining); + return ret; + } + + ret = rmi_read_block(f34->fn->rmi_dev, + base + f34->v7.off.payload, + &f34->v7.read_config_buf[index], + transfer * f34->v7.block_size); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Read block failed (%d blks remaining)\n", + __func__, remaining); + return ret; + } + + index += (transfer * f34->v7.block_size); + remaining -= transfer; + } while (remaining); + + return 0; +} + +static int rmi_f34v7_write_f34v7_blocks(struct f34_data *f34, + const void *block_ptr, u16 block_cnt, + u8 command) +{ + int ret; + u8 base; + __le16 length; + u16 transfer; + u16 max_transfer; + u16 remaining = block_cnt; + u16 block_number = 0; + + base = f34->fn->fd.data_base_addr; + + ret = rmi_f34v7_write_partition_id(f34, command); + if (ret < 0) + return ret; + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.block_number, + &block_number, sizeof(block_number)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to write block number\n", + __func__); + return ret; + } + + if (f34->v7.payload_length > (PAGE_SIZE / f34->v7.block_size)) + max_transfer = PAGE_SIZE / f34->v7.block_size; + else + max_transfer = f34->v7.payload_length; + + do { + transfer = min(remaining, max_transfer); + put_unaligned_le16(transfer, &length); + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.transfer_length, + &length, sizeof(length)); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Write transfer length fail (%d remaining)\n", + __func__, remaining); + return ret; + } + + ret = rmi_f34v7_write_command(f34, command); + if (ret < 0) + return ret; + + ret = rmi_write_block(f34->fn->rmi_dev, + base + f34->v7.off.payload, + block_ptr, transfer * f34->v7.block_size); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Failed writing data (%d blks remaining)\n", + __func__, remaining); + return ret; + } + + ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + if (ret < 0) { + dev_err(&f34->fn->dev, + "%s: Failed wait for idle (%d blks remaining)\n", + __func__, remaining); + return ret; + } + + block_ptr += (transfer * f34->v7.block_size); + remaining -= transfer; + } while (remaining); + + return 0; +} + +static int rmi_f34v7_write_config(struct f34_data *f34) +{ + return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.config_data, + f34->v7.config_block_count, + v7_CMD_WRITE_CONFIG); +} + +static int rmi_f34v7_write_ui_config(struct f34_data *f34) +{ + f34->v7.config_area = v7_UI_CONFIG_AREA; + f34->v7.config_data = f34->v7.img.ui_config.data; + f34->v7.config_size = f34->v7.img.ui_config.size; + f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; + + return rmi_f34v7_write_config(f34); +} + +static int rmi_f34v7_write_dp_config(struct f34_data *f34) +{ + f34->v7.config_area = v7_DP_CONFIG_AREA; + f34->v7.config_data = f34->v7.img.dp_config.data; + f34->v7.config_size = f34->v7.img.dp_config.size; + f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; + + return rmi_f34v7_write_config(f34); +} + +static int rmi_f34v7_write_guest_code(struct f34_data *f34) +{ + return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.guest_code.data, + f34->v7.img.guest_code.size / + f34->v7.block_size, + v7_CMD_WRITE_GUEST_CODE); +} + +static int rmi_f34v7_write_flash_config(struct f34_data *f34) +{ + int ret; + + f34->v7.config_area = v7_FLASH_CONFIG_AREA; + f34->v7.config_data = f34->v7.img.fl_config.data; + f34->v7.config_size = f34->v7.img.fl_config.size; + f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; + + if (f34->v7.config_block_count != f34->v7.blkcount.fl_config) { + dev_err(&f34->fn->dev, "%s: Flash config size mismatch\n", + __func__); + return -EINVAL; + } + + ret = rmi_f34v7_write_command(f34, v7_CMD_ERASE_FLASH_CONFIG); + if (ret < 0) + return ret; + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: Erase flash config command written\n", __func__); + + ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + if (ret < 0) + return ret; + + ret = rmi_f34v7_write_config(f34); + if (ret < 0) + return ret; + + return 0; +} + +static int rmi_f34v7_write_partition_table(struct f34_data *f34) +{ + u16 block_count; + int ret; + + block_count = f34->v7.blkcount.bl_config; + f34->v7.config_area = v7_BL_CONFIG_AREA; + f34->v7.config_size = f34->v7.block_size * block_count; + devm_kfree(&f34->fn->dev, f34->v7.read_config_buf); + f34->v7.read_config_buf = devm_kzalloc(&f34->fn->dev, + f34->v7.config_size, GFP_KERNEL); + if (!f34->v7.read_config_buf) { + f34->v7.read_config_buf_size = 0; + return -ENOMEM; + } + + f34->v7.read_config_buf_size = f34->v7.config_size; + + ret = rmi_f34v7_read_f34v7_blocks(f34, block_count, v7_CMD_READ_CONFIG); + if (ret < 0) + return ret; + + ret = rmi_f34v7_erase_config(f34); + if (ret < 0) + return ret; + + ret = rmi_f34v7_write_flash_config(f34); + if (ret < 0) + return ret; + + f34->v7.config_area = v7_BL_CONFIG_AREA; + f34->v7.config_data = f34->v7.read_config_buf; + f34->v7.config_size = f34->v7.img.bl_config.size; + f34->v7.config_block_count = f34->v7.config_size / f34->v7.block_size; + + ret = rmi_f34v7_write_config(f34); + if (ret < 0) + return ret; + + return 0; +} + +static int rmi_f34v7_write_firmware(struct f34_data *f34) +{ + u16 blk_count; + + blk_count = f34->v7.img.ui_firmware.size / f34->v7.block_size; + + return rmi_f34v7_write_f34v7_blocks(f34, f34->v7.img.ui_firmware.data, + blk_count, v7_CMD_WRITE_FW); +} + +static void rmi_f34v7_compare_partition_tables(struct f34_data *f34) +{ + if (f34->v7.phyaddr.ui_firmware != f34->v7.img.phyaddr.ui_firmware) { + f34->v7.new_partition_table = true; + return; + } + + if (f34->v7.phyaddr.ui_config != f34->v7.img.phyaddr.ui_config) { + f34->v7.new_partition_table = true; + return; + } + + if (f34->v7.has_display_cfg && + f34->v7.phyaddr.dp_config != f34->v7.img.phyaddr.dp_config) { + f34->v7.new_partition_table = true; + return; + } + + if (f34->v7.has_guest_code && + f34->v7.phyaddr.guest_code != f34->v7.img.phyaddr.guest_code) { + f34->v7.new_partition_table = true; + return; + } + + f34->v7.new_partition_table = false; +} + +static void rmi_f34v7_parse_img_header_10_bl_container(struct f34_data *f34, + const void *image) +{ + int i; + int num_of_containers; + unsigned int addr; + unsigned int container_id; + unsigned int length; + const void *content; + const struct container_descriptor *descriptor; + + num_of_containers = f34->v7.img.bootloader.size / 4 - 1; + + for (i = 1; i <= num_of_containers; i++) { + addr = get_unaligned_le32(f34->v7.img.bootloader.data + i * 4); + descriptor = image + addr; + container_id = le16_to_cpu(descriptor->container_id); + content = image + le32_to_cpu(descriptor->content_address); + length = le32_to_cpu(descriptor->content_length); + switch (container_id) { + case BL_CONFIG_CONTAINER: + case GLOBAL_PARAMETERS_CONTAINER: + f34->v7.img.bl_config.data = content; + f34->v7.img.bl_config.size = length; + break; + case BL_LOCKDOWN_INFO_CONTAINER: + case DEVICE_CONFIG_CONTAINER: + f34->v7.img.lockdown.data = content; + f34->v7.img.lockdown.size = length; + break; + default: + break; + } + } +} + +static void rmi_f34v7_parse_image_header_10(struct f34_data *f34) +{ + unsigned int i; + unsigned int num_of_containers; + unsigned int addr; + unsigned int offset; + unsigned int container_id; + unsigned int length; + const void *image = f34->v7.image; + const u8 *content; + const struct container_descriptor *descriptor; + const struct image_header_10 *header = image; + + f34->v7.img.checksum = le32_to_cpu(header->checksum); + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, "%s: f34->v7.img.checksum=%X\n", + __func__, f34->v7.img.checksum); + + /* address of top level container */ + offset = le32_to_cpu(header->top_level_container_start_addr); + descriptor = image + offset; + + /* address of top level container content */ + offset = le32_to_cpu(descriptor->content_address); + num_of_containers = le32_to_cpu(descriptor->content_length) / 4; + + for (i = 0; i < num_of_containers; i++) { + addr = get_unaligned_le32(image + offset); + offset += 4; + descriptor = image + addr; + container_id = le16_to_cpu(descriptor->container_id); + content = image + le32_to_cpu(descriptor->content_address); + length = le32_to_cpu(descriptor->content_length); + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: container_id=%d, length=%d\n", __func__, + container_id, length); + + switch (container_id) { + case UI_CONTAINER: + case CORE_CODE_CONTAINER: + f34->v7.img.ui_firmware.data = content; + f34->v7.img.ui_firmware.size = length; + break; + case UI_CONFIG_CONTAINER: + case CORE_CONFIG_CONTAINER: + f34->v7.img.ui_config.data = content; + f34->v7.img.ui_config.size = length; + break; + case BL_CONTAINER: + f34->v7.img.bl_version = *content; + f34->v7.img.bootloader.data = content; + f34->v7.img.bootloader.size = length; + rmi_f34v7_parse_img_header_10_bl_container(f34, image); + break; + case GUEST_CODE_CONTAINER: + f34->v7.img.contains_guest_code = true; + f34->v7.img.guest_code.data = content; + f34->v7.img.guest_code.size = length; + break; + case DISPLAY_CONFIG_CONTAINER: + f34->v7.img.contains_display_cfg = true; + f34->v7.img.dp_config.data = content; + f34->v7.img.dp_config.size = length; + break; + case FLASH_CONFIG_CONTAINER: + f34->v7.img.contains_flash_config = true; + f34->v7.img.fl_config.data = content; + f34->v7.img.fl_config.size = length; + break; + case GENERAL_INFORMATION_CONTAINER: + f34->v7.img.contains_firmware_id = true; + f34->v7.img.firmware_id = + get_unaligned_le32(content + 4); + break; + default: + break; + } + } +} + +static int rmi_f34v7_parse_image_info(struct f34_data *f34) +{ + const struct image_header_10 *header = f34->v7.image; + + memset(&f34->v7.img, 0x00, sizeof(f34->v7.img)); + + rmi_dbg(RMI_DEBUG_FN, &f34->fn->dev, + "%s: header->major_header_version = %d\n", + __func__, header->major_header_version); + + switch (header->major_header_version) { + case IMAGE_HEADER_VERSION_10: + rmi_f34v7_parse_image_header_10(f34); + break; + default: + dev_err(&f34->fn->dev, "Unsupported image file format %02X\n", + header->major_header_version); + return -EINVAL; + } + + if (!f34->v7.img.contains_flash_config) { + dev_err(&f34->fn->dev, "%s: No flash config in fw image\n", + __func__); + return -EINVAL; + } + + rmi_f34v7_parse_partition_table(f34, f34->v7.img.fl_config.data, + &f34->v7.img.blkcount, &f34->v7.img.phyaddr); + + rmi_f34v7_compare_partition_tables(f34); + + return 0; +} + +int rmi_f34v7_do_reflash(struct f34_data *f34, const struct firmware *fw) +{ + int ret; + + rmi_f34v7_read_queries_bl_version(f34); + + f34->v7.image = fw->data; + + ret = rmi_f34v7_parse_image_info(f34); + if (ret < 0) + goto fail; + + if (!f34->v7.new_partition_table) { + ret = rmi_f34v7_check_ui_firmware_size(f34); + if (ret < 0) + goto fail; + + ret = rmi_f34v7_check_ui_config_size(f34); + if (ret < 0) + goto fail; + + if (f34->v7.has_display_cfg && + f34->v7.img.contains_display_cfg) { + ret = rmi_f34v7_check_dp_config_size(f34); + if (ret < 0) + goto fail; + } + + if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) { + ret = rmi_f34v7_check_guest_code_size(f34); + if (ret < 0) + goto fail; + } + } else { + ret = rmi_f34v7_check_bl_config_size(f34); + if (ret < 0) + goto fail; + } + + ret = rmi_f34v7_erase_all(f34); + if (ret < 0) + goto fail; + + if (f34->v7.new_partition_table) { + ret = rmi_f34v7_write_partition_table(f34); + if (ret < 0) + goto fail; + dev_info(&f34->fn->dev, "%s: Partition table programmed\n", + __func__); + } + + dev_info(&f34->fn->dev, "Writing firmware (%d bytes)...\n", + f34->v7.img.ui_firmware.size); + + ret = rmi_f34v7_write_firmware(f34); + if (ret < 0) + goto fail; + + dev_info(&f34->fn->dev, "Writing config (%d bytes)...\n", + f34->v7.img.ui_config.size); + + f34->v7.config_area = v7_UI_CONFIG_AREA; + ret = rmi_f34v7_write_ui_config(f34); + if (ret < 0) + goto fail; + + if (f34->v7.has_display_cfg && f34->v7.img.contains_display_cfg) { + dev_info(&f34->fn->dev, "Writing display config...\n"); + + ret = rmi_f34v7_write_dp_config(f34); + if (ret < 0) + goto fail; + } + + if (f34->v7.new_partition_table) { + if (f34->v7.has_guest_code && f34->v7.img.contains_guest_code) { + dev_info(&f34->fn->dev, "Writing guest code...\n"); + + ret = rmi_f34v7_write_guest_code(f34); + if (ret < 0) + goto fail; + } + } + +fail: + return ret; +} + +static int rmi_f34v7_enter_flash_prog(struct f34_data *f34) +{ + int ret; + + ret = rmi_f34v7_read_flash_status(f34); + if (ret < 0) + return ret; + + if (f34->v7.in_bl_mode) + return 0; + + ret = rmi_f34v7_write_command(f34, v7_CMD_ENABLE_FLASH_PROG); + if (ret < 0) + return ret; + + ret = rmi_f34v7_wait_for_idle(f34, ENABLE_WAIT_MS); + if (ret < 0) + return ret; + + if (!f34->v7.in_bl_mode) { + dev_err(&f34->fn->dev, "%s: BL mode not entered\n", __func__); + return -EINVAL; + } + + return 0; +} + +int rmi_f34v7_start_reflash(struct f34_data *f34, const struct firmware *fw) +{ + int ret = 0; + + f34->v7.config_area = v7_UI_CONFIG_AREA; + f34->v7.image = fw->data; + + ret = rmi_f34v7_parse_image_info(f34); + if (ret < 0) + goto exit; + + if (!f34->v7.force_update && f34->v7.new_partition_table) { + dev_err(&f34->fn->dev, "%s: Partition table mismatch\n", + __func__); + ret = -EINVAL; + goto exit; + } + + dev_info(&f34->fn->dev, "Firmware image OK\n"); + + ret = rmi_f34v7_read_flash_status(f34); + if (ret < 0) + goto exit; + + if (f34->v7.in_bl_mode) { + dev_info(&f34->fn->dev, "%s: Device in bootloader mode\n", + __func__); + } + + rmi_f34v7_enter_flash_prog(f34); + + return 0; + +exit: + return ret; +} + +int rmi_f34v7_probe(struct f34_data *f34) +{ + int ret; + + /* Read bootloader version */ + ret = rmi_read_block(f34->fn->rmi_dev, + f34->fn->fd.query_base_addr + V7_BOOTLOADER_ID_OFFSET, + f34->bootloader_id, + sizeof(f34->bootloader_id)); + if (ret < 0) { + dev_err(&f34->fn->dev, "%s: Failed to read bootloader ID\n", + __func__); + return ret; + } + + if (f34->bootloader_id[1] == '5') { + f34->bl_version = 5; + } else if (f34->bootloader_id[1] == '6') { + f34->bl_version = 6; + } else if (f34->bootloader_id[1] == 7) { + f34->bl_version = 7; + } else { + dev_err(&f34->fn->dev, "%s: Unrecognized bootloader version\n", + __func__); + return -EINVAL; + } + + memset(&f34->v7.blkcount, 0x00, sizeof(f34->v7.blkcount)); + memset(&f34->v7.phyaddr, 0x00, sizeof(f34->v7.phyaddr)); + rmi_f34v7_read_queries(f34); + + f34->v7.force_update = false; + return 0; +} diff --git a/include/linux/rmi.h b/include/linux/rmi.h index ac910f730688..64125443f8a6 100644 --- a/include/linux/rmi.h +++ b/include/linux/rmi.h @@ -342,7 +342,7 @@ struct rmi_driver_data { struct rmi_function *f01_container; struct rmi_function *f34_container; - bool f01_bootloader_mode; + bool bootloader_mode; int num_of_irq_regs; int irq_count; -- cgit v1.2.3 From 070cbd1d42aa0e359c9957cd73c2a529dec62047 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Fri, 25 Nov 2016 10:55:36 +0100 Subject: ipmi: create hardware-independent softdep for ipmi_devintf When a computer has an IPMI system interface, the device interface is most probably also desired. Autoloading of ipmi_devintf currently works only if ipmi_si has allocated a platform device. That doesn't happen if the SI interface was detected e.g. via ACPI. But ACPI detection is preferred these days, see e.g. kernel.org bug 46741. This patch introduces a softdep in place of the existing modalias for ipmi_devintf. Signed-off-by: Martin Wilck Suggested-by: Takashi Iwai I moved this to ipmi_msghandler.c, so it works for all IPMI interfaces. Retested by Martin. Tested-by: Martin Wilck Signed-off-by: Corey Minyard --- drivers/char/ipmi/ipmi_devintf.c | 1 - drivers/char/ipmi/ipmi_msghandler.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c index 1786574536b2..a21407de46ae 100644 --- a/drivers/char/ipmi/ipmi_devintf.c +++ b/drivers/char/ipmi/ipmi_devintf.c @@ -989,4 +989,3 @@ module_exit(cleanup_ipmi); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Corey Minyard "); MODULE_DESCRIPTION("Linux device interface for the IPMI message handler."); -MODULE_ALIAS("platform:ipmi_si"); diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c index be982d10d305..92e53acf2cd2 100644 --- a/drivers/char/ipmi/ipmi_msghandler.c +++ b/drivers/char/ipmi/ipmi_msghandler.c @@ -4646,3 +4646,4 @@ MODULE_AUTHOR("Corey Minyard "); MODULE_DESCRIPTION("Incoming and outgoing message routing for an IPMI" " interface."); MODULE_VERSION(IPMI_DRIVER_VERSION); +MODULE_SOFTDEP("post: ipmi_devintf"); -- cgit v1.2.3 From a0fa72683e78979ef1123d679b1c40ae28bd9096 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 19 Sep 2016 13:57:26 +0200 Subject: IB/rxe: avoid putting a large struct rxe_qp on stack A race condition fix added an rxe_qp structure to the stack in order to be able to perform rollback in rxe_requester(), but the structure is large enough to trigger the warning for possible stack overflow: drivers/infiniband/sw/rxe/rxe_req.c: In function 'rxe_requester': drivers/infiniband/sw/rxe/rxe_req.c:757:1: error: the frame size of 2064 bytes is larger than 1024 bytes [-Werror=frame-larger-than=] This changes the rollback function to only save the psn inside the qp, which is the only field we access in the rollback_qp anyway. Fixes: 3050b9985024 ("IB/rxe: Fix race condition between requester and completer") Signed-off-by: Arnd Bergmann Reviewed-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_req.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 832846b73ea0..205222909e53 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -548,23 +548,23 @@ static void update_wqe_psn(struct rxe_qp *qp, static void save_state(struct rxe_send_wqe *wqe, struct rxe_qp *qp, struct rxe_send_wqe *rollback_wqe, - struct rxe_qp *rollback_qp) + u32 *rollback_psn) { rollback_wqe->state = wqe->state; rollback_wqe->first_psn = wqe->first_psn; rollback_wqe->last_psn = wqe->last_psn; - rollback_qp->req.psn = qp->req.psn; + *rollback_psn = qp->req.psn; } static void rollback_state(struct rxe_send_wqe *wqe, struct rxe_qp *qp, struct rxe_send_wqe *rollback_wqe, - struct rxe_qp *rollback_qp) + u32 rollback_psn) { wqe->state = rollback_wqe->state; wqe->first_psn = rollback_wqe->first_psn; wqe->last_psn = rollback_wqe->last_psn; - qp->req.psn = rollback_qp->req.psn; + qp->req.psn = rollback_psn; } static void update_state(struct rxe_qp *qp, struct rxe_send_wqe *wqe, @@ -593,8 +593,8 @@ int rxe_requester(void *arg) int mtu; int opcode; int ret; - struct rxe_qp rollback_qp; struct rxe_send_wqe rollback_wqe; + u32 rollback_psn; next_wqe: if (unlikely(!qp->valid || qp->req.state == QP_STATE_ERROR)) @@ -718,7 +718,7 @@ next_wqe: * rxe_xmit_packet(). * Otherwise, completer might initiate an unjustified retry flow. */ - save_state(wqe, qp, &rollback_wqe, &rollback_qp); + save_state(wqe, qp, &rollback_wqe, &rollback_psn); update_wqe_state(qp, wqe, &pkt); update_wqe_psn(qp, wqe, &pkt, payload); ret = rxe_xmit_packet(to_rdev(qp->ibqp.device), qp, &pkt, skb); @@ -726,7 +726,7 @@ next_wqe: qp->need_req_skb = 1; kfree_skb(skb); - rollback_state(wqe, qp, &rollback_wqe, &rollback_qp); + rollback_state(wqe, qp, &rollback_wqe, rollback_psn); if (ret == -EAGAIN) { rxe_run_task(&qp->req.task, 1); -- cgit v1.2.3 From 4ac4707102d9ea1ffc9b5735891f6c5ee3d236e5 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 16:19:33 +0000 Subject: IB/rxe: Use DEFINE_SPINLOCK() for spinlock spinlock can be initialized automatically with DEFINE_SPINLOCK() rather than explicitly calling spin_lock_init(). Signed-off-by: Wei Yongjun Reviewed-by: Leon Romanosky Reviewed-by: Moni Shoua Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_net.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index b8258e4f0aea..4cb63780fa74 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -46,7 +46,7 @@ #include "rxe_loc.h" static LIST_HEAD(rxe_dev_list); -static spinlock_t dev_list_lock; /* spinlock for device list */ +static DEFINE_SPINLOCK(dev_list_lock); /* spinlock for device list */ struct rxe_dev *net_to_rxe(struct net_device *ndev) { @@ -663,8 +663,6 @@ struct notifier_block rxe_net_notifier = { int rxe_net_ipv4_init(void) { - spin_lock_init(&dev_list_lock); - recv_sockets.sk4 = rxe_setup_udp_tunnel(&init_net, htons(ROCE_V2_UDP_DPORT), false); if (IS_ERR(recv_sockets.sk4)) { @@ -680,8 +678,6 @@ int rxe_net_ipv6_init(void) { #if IS_ENABLED(CONFIG_IPV6) - spin_lock_init(&dev_list_lock); - recv_sockets.sk6 = rxe_setup_udp_tunnel(&init_net, htons(ROCE_V2_UDP_DPORT), true); if (IS_ERR(recv_sockets.sk6)) { -- cgit v1.2.3 From 95db9d05b717b1ec242799103c09acda8d728974 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 17 Nov 2016 14:00:05 +0300 Subject: IB/rxe: Remove unneeded cast in rxe_srq_from_attr() It makes me nervous when we cast pointer parameters. I would estimate that around 50% of the time, it indicates a bug. Here the cast is not needed becaue u32 and and unsigned int are the same thing. Removing the cast makes the code more robust and future proof in case any of the types change. Signed-off-by: Dan Carpenter Reviewed-by: Leon Romanovsky Reviewed-by: Yuval Shaia Acked-by: Moni Shoua Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_srq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_srq.c b/drivers/infiniband/sw/rxe/rxe_srq.c index 2a6e3cd2d4e8..efc832a2d7c6 100644 --- a/drivers/infiniband/sw/rxe/rxe_srq.c +++ b/drivers/infiniband/sw/rxe/rxe_srq.c @@ -169,7 +169,7 @@ int rxe_srq_from_attr(struct rxe_dev *rxe, struct rxe_srq *srq, } } - err = rxe_queue_resize(q, (unsigned int *)&attr->max_wr, + err = rxe_queue_resize(q, &attr->max_wr, rcv_wqe_size(srq->rq.max_sge), srq->rq.queue->ip ? srq->rq.queue->ip->context : -- cgit v1.2.3 From 6e9bb530ff8b07b3bbce79c937fc9dcb32da4eb9 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:17 -0500 Subject: IB/rxe: Remove buffer used for printing IP address Avoid smashing the stack when an ICRC error occurs on an IPv6 network. Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_recv.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_recv.c b/drivers/infiniband/sw/rxe/rxe_recv.c index 46f062842a9a..252b4d637d45 100644 --- a/drivers/infiniband/sw/rxe/rxe_recv.c +++ b/drivers/infiniband/sw/rxe/rxe_recv.c @@ -391,16 +391,15 @@ int rxe_rcv(struct sk_buff *skb) payload_size(pkt)); calc_icrc = cpu_to_be32(~calc_icrc); if (unlikely(calc_icrc != pack_icrc)) { - char saddr[sizeof(struct in6_addr)]; - if (skb->protocol == htons(ETH_P_IPV6)) - sprintf(saddr, "%pI6", &ipv6_hdr(skb)->saddr); + pr_warn_ratelimited("bad ICRC from %pI6c\n", + &ipv6_hdr(skb)->saddr); else if (skb->protocol == htons(ETH_P_IP)) - sprintf(saddr, "%pI4", &ip_hdr(skb)->saddr); + pr_warn_ratelimited("bad ICRC from %pI4\n", + &ip_hdr(skb)->saddr); else - sprintf(saddr, "unknown"); + pr_warn_ratelimited("bad ICRC from unknown\n"); - pr_warn_ratelimited("bad ICRC from %s\n", saddr); goto drop; } -- cgit v1.2.3 From dd753d87436ce7ef2a958d684b38d5acc99c9f5c Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:18 -0500 Subject: IB/rxe: Advance the consumer pointer before posting the CQE A simple userspace application might poll the CQ, find a completion, and then attempt to post a new WQE to the SQ. A spurious error can occur if the userspace application detects a full SQ in the instant before the kernel is able to advance the SQ consumer pointer. This is noticeable when using single-entry SQs with ibv_rc_pingpong if lots of kernel and userspace library debugging is enabled. Signed-off-by: Andrew Boyer Reviewed-by: Yonatan Cohen Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_comp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index 6c5e29db88e3..d46c49b33b13 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -420,11 +420,12 @@ static void do_complete(struct rxe_qp *qp, struct rxe_send_wqe *wqe) (wqe->wr.send_flags & IB_SEND_SIGNALED) || (qp->req.state == QP_STATE_ERROR)) { make_send_cqe(qp, wqe, &cqe); + advance_consumer(qp->sq.queue); rxe_cq_post(qp->scq, &cqe, 0); + } else { + advance_consumer(qp->sq.queue); } - advance_consumer(qp->sq.queue); - /* * we completed something so let req run again * if it is trying to fence -- cgit v1.2.3 From 2a7a85487e5432424eef7a394ed26ef1d8f0d192 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:19 -0500 Subject: IB/rxe: Don't update the response PSN unless it's going forwards A client might post a read followed by a send. The partner receives and acknowledges both transactions, posting an RCQ entry for the send, but something goes wrong with the read ACK. When the client retries the read, the partner's responder processes the duplicate read but incorrectly resets the PSN to the value preceding the original send. When the duplicate send arrives, the responder cannot tell that it is a duplicate, so the responder generates a duplicate RCQ entry, confusing the client. Signed-off-by: Andrew Boyer Reviewed-by: Yonatan Cohen Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_resp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index dd3d88adc003..cb3fd4cb0daa 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -742,7 +742,8 @@ static enum resp_states read_reply(struct rxe_qp *qp, } else { qp->resp.res = NULL; qp->resp.opcode = -1; - qp->resp.psn = res->cur_psn; + if (psn_compare(res->cur_psn, qp->resp.psn) >= 0) + qp->resp.psn = res->cur_psn; state = RESPST_CLEANUP; } -- cgit v1.2.3 From d38eb801aa145aedf4b97e8e0bb2e65763aa6149 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:20 -0500 Subject: IB/rxe: Unblock loopback by moving skb_out increment skb_out is decremented in rxe_skb_tx_dtor(), which is not called in the loopback() path. Move the increment to the send() path rather than rxe_xmit_packet(). Signed-off-by: Andrew Boyer Acked-by: Moni Shoua Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_loc.h | 2 -- drivers/infiniband/sw/rxe/rxe_net.c | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_loc.h b/drivers/infiniband/sw/rxe/rxe_loc.h index 73849a5a91b3..efe4c6a35442 100644 --- a/drivers/infiniband/sw/rxe/rxe_loc.h +++ b/drivers/infiniband/sw/rxe/rxe_loc.h @@ -266,8 +266,6 @@ static inline int rxe_xmit_packet(struct rxe_dev *rxe, struct rxe_qp *qp, return err; } - atomic_inc(&qp->skb_out); - if ((qp_type(qp) != IB_QPT_RC) && (pkt->mask & RXE_END_MASK)) { pkt->wqe->state = wqe_state_done; diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index 4cb63780fa74..a576603304f7 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -459,6 +459,8 @@ static int send(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, return -EAGAIN; } + if (pkt->qp) + atomic_inc(&pkt->qp->skb_out); kfree_skb(skb); return 0; -- cgit v1.2.3 From d4fb59256ac03d84f68e36c430b58d6fc76dd651 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:21 -0500 Subject: IB/rxe: Add support for zero-byte operations The last_psn algorithm fails in the zero-byte case: it calculates first_psn = N, last_psn = N-1. This makes the operation unretryable since the res structure will fail the (first_psn <= psn <= last_psn) test in find_resource(). While here, use BTH_PSN_MASK to mask the calculated last_psn. Signed-off-by: Andrew Boyer Reviewed-by: Moni Shoua Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_mr.c | 3 +++ drivers/infiniband/sw/rxe/rxe_resp.c | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_mr.c b/drivers/infiniband/sw/rxe/rxe_mr.c index 1869152f1d23..d0faca294006 100644 --- a/drivers/infiniband/sw/rxe/rxe_mr.c +++ b/drivers/infiniband/sw/rxe/rxe_mr.c @@ -355,6 +355,9 @@ int rxe_mem_copy(struct rxe_mem *mem, u64 iova, void *addr, int length, size_t offset; u32 crc = crcp ? (*crcp) : 0; + if (length == 0) + return 0; + if (mem->type == RXE_MEM_TYPE_DMA) { u8 *src, *dest; diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index cb3fd4cb0daa..a5e9ce34171b 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -444,6 +444,13 @@ static enum resp_states check_rkey(struct rxe_qp *qp, return RESPST_EXECUTE; } + /* A zero-byte op is not required to set an addr or rkey. */ + if ((pkt->mask & (RXE_READ_MASK | RXE_WRITE_OR_SEND)) && + (pkt->mask & RXE_RETH_MASK) && + reth_len(pkt) == 0) { + return RESPST_EXECUTE; + } + va = qp->resp.va; rkey = qp->resp.rkey; resid = qp->resp.resid; @@ -680,9 +687,14 @@ static enum resp_states read_reply(struct rxe_qp *qp, res->read.va_org = qp->resp.va; res->first_psn = req_pkt->psn; - res->last_psn = req_pkt->psn + - (reth_len(req_pkt) + mtu - 1) / - mtu - 1; + + if (reth_len(req_pkt)) { + res->last_psn = (req_pkt->psn + + (reth_len(req_pkt) + mtu - 1) / + mtu - 1) & BTH_PSN_MASK; + } else { + res->last_psn = res->first_psn; + } res->cur_psn = req_pkt->psn; res->read.resid = qp->resp.resid; -- cgit v1.2.3 From accacb8f51c299965939ac56926d1c718e2691a1 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:22 -0500 Subject: IB/rxe: Add support for IB_CQ_REPORT_MISSED_EVENTS Peek at the CQ after arming it so that we can return a hint. This avoids missed completions due to a race between posting CQEs and arming the CQ. For example, CM teardown waits on MAD requests to complete with ib_cq_poll_work(). Without this fix, the last completion might be left on the CQ, hanging the kthread doing the teardown. The console backtraces look like this: [ 4199.911284] Call Trace: [ 4199.911401] [] schedule+0x35/0x80 [ 4199.911556] [] schedule_timeout+0x22f/0x2c0 [ 4199.911727] [] ? __schedule+0x368/0xa20 [ 4199.911891] [] wait_for_completion+0xb3/0x130 [ 4199.912067] [] ? wake_up_q+0x70/0x70 [ 4199.912243] [] cm_destroy_id+0x13d/0x450 [ib_cm] [ 4199.912422] [] ? printk+0x57/0x73 [ 4199.912578] [] ib_destroy_cm_id+0x10/0x20 [ib_cm] [ 4199.912759] [] rdma_destroy_id+0xac/0x340 [rdma_cm] [ 4199.912941] [] 0xffffffffc076f2cc Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_verbs.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 19841c863daf..de39b0a081de 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -1007,11 +1007,19 @@ static int rxe_peek_cq(struct ib_cq *ibcq, int wc_cnt) static int rxe_req_notify_cq(struct ib_cq *ibcq, enum ib_cq_notify_flags flags) { struct rxe_cq *cq = to_rcq(ibcq); + unsigned long irq_flags; + int ret = 0; + spin_lock_irqsave(&cq->cq_lock, irq_flags); if (cq->notify != IB_CQ_NEXT_COMP) cq->notify = flags & IB_CQ_SOLICITED_MASK; - return 0; + if ((flags & IB_CQ_REPORT_MISSED_EVENTS) && !queue_empty(cq->queue)) + ret = 1; + + spin_unlock_irqrestore(&cq->cq_lock, irq_flags); + + return ret; } static struct ib_mr *rxe_get_dma_mr(struct ib_pd *ibpd, int access) -- cgit v1.2.3 From 5b9ea16c5488e577b26cc198ac63550b746ce3b9 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:23 -0500 Subject: IB/rxe: Fix ref leak in rxe_create_qp() The udata->inlen error path needs to clean up the ref added by rxe_alloc(). Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_verbs.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index de39b0a081de..071430c594b7 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -564,7 +564,7 @@ static struct ib_qp *rxe_create_qp(struct ib_pd *ibpd, if (udata) { if (udata->inlen) { err = -EINVAL; - goto err1; + goto err2; } qp->is_user = 1; } @@ -573,12 +573,13 @@ static struct ib_qp *rxe_create_qp(struct ib_pd *ibpd, err = rxe_qp_from_init(rxe, qp, pd, init, udata, ibpd); if (err) - goto err2; + goto err3; return &qp->ibqp; -err2: +err3: rxe_drop_index(qp); +err2: rxe_drop_ref(qp); err1: return ERR_PTR(err); -- cgit v1.2.3 From 5407f530122aa63cf304eb0874c938b3bdb8d3fb Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Wed, 23 Nov 2016 12:39:24 -0500 Subject: IB/rxe: Fix ref leak in duplicate_request() A ref was added after the call to skb_clone(). Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_resp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index a5e9ce34171b..8643797fb530 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -1145,6 +1145,7 @@ static enum resp_states duplicate_request(struct rxe_qp *qp, pkt, skb_copy); if (rc) { pr_err("Failed resending result. This flow is not handled - skb ignored\n"); + rxe_drop_ref(qp); kfree_skb(skb_copy); rc = RESPST_CLEANUP; goto out; -- cgit v1.2.3 From 07bf9627d5f1c0334fc543a5435a31a3b5907944 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Mon, 5 Dec 2016 08:43:20 -0500 Subject: IB/rxe: Wait for tasklets to finish before tearing down QP The system may crash when a malformed request is received and the error is detected by the responder. NodeA: $ ibv_rc_pingpong -g 0 -d rxe0 -i 1 -n 1 -s 50000 NodeB: $ ibv_rc_pingpong -g 0 -d rxe0 -i 1 -n 1 -s 1024 The responder generates a receive error on node B since the incoming SEND is oversized. If the client tears down the QP before the responder or the completer finish running, a page fault may occur. The fix makes the destroy operation spin until the tasks complete, which appears to be original intent of the design. Signed-off-by: Andrew Boyer Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_task.c | 19 +++++++++++++++++++ drivers/infiniband/sw/rxe/rxe_task.h | 1 + 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_task.c b/drivers/infiniband/sw/rxe/rxe_task.c index 1e19bf828a6e..d2a14a1bdc7f 100644 --- a/drivers/infiniband/sw/rxe/rxe_task.c +++ b/drivers/infiniband/sw/rxe/rxe_task.c @@ -121,6 +121,7 @@ int rxe_init_task(void *obj, struct rxe_task *task, task->arg = arg; task->func = func; snprintf(task->name, sizeof(task->name), "%s", name); + task->destroyed = false; tasklet_init(&task->tasklet, rxe_do_task, (unsigned long)task); @@ -132,11 +133,29 @@ int rxe_init_task(void *obj, struct rxe_task *task, void rxe_cleanup_task(struct rxe_task *task) { + unsigned long flags; + bool idle; + + /* + * Mark the task, then wait for it to finish. It might be + * running in a non-tasklet (direct call) context. + */ + task->destroyed = true; + + do { + spin_lock_irqsave(&task->state_lock, flags); + idle = (task->state == TASK_STATE_START); + spin_unlock_irqrestore(&task->state_lock, flags); + } while (!idle); + tasklet_kill(&task->tasklet); } void rxe_run_task(struct rxe_task *task, int sched) { + if (task->destroyed) + return; + if (sched) tasklet_schedule(&task->tasklet); else diff --git a/drivers/infiniband/sw/rxe/rxe_task.h b/drivers/infiniband/sw/rxe/rxe_task.h index d14aa6daed05..08ff42d451c6 100644 --- a/drivers/infiniband/sw/rxe/rxe_task.h +++ b/drivers/infiniband/sw/rxe/rxe_task.h @@ -54,6 +54,7 @@ struct rxe_task { int (*func)(void *arg); int ret; char name[16]; + bool destroyed; }; /* -- cgit v1.2.3 From 37f69f43fb5aba4288d38ea32bbe0dfdb412c763 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Mon, 5 Dec 2016 08:43:21 -0500 Subject: IB/rxe: Hold refs when running tasklets It might be possible for all of a QP's references to be dropped while one of that QP's tasklets is running. For example, the completer might run during QP destroy. If qp->valid is false, it will drop all of the packets on the resp_pkts list, potentially removing the last reference. Then it tries to advance the SQ consumer pointer. If the SQ's buffer has already been destroyed, the system will panic. To be safe, hold a reference on the QP for the duration of each tasklet. Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_comp.c | 4 ++++ drivers/infiniband/sw/rxe/rxe_req.c | 5 ++++- drivers/infiniband/sw/rxe/rxe_resp.c | 3 +++ 3 files changed, 11 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index d46c49b33b13..cd27cbde7652 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -511,6 +511,8 @@ int rxe_completer(void *arg) struct rxe_pkt_info *pkt = NULL; enum comp_state state; + rxe_add_ref(qp); + if (!qp->valid) { while ((skb = skb_dequeue(&qp->resp_pkts))) { rxe_drop_ref(qp); @@ -740,11 +742,13 @@ exit: /* we come here if we are done with processing and want the task to * exit from the loop calling us */ + rxe_drop_ref(qp); return -EAGAIN; done: /* we come here if we have processed a packet we want the task to call * us again to see if there is anything else to do */ + rxe_drop_ref(qp); return 0; } diff --git a/drivers/infiniband/sw/rxe/rxe_req.c b/drivers/infiniband/sw/rxe/rxe_req.c index 205222909e53..b246653cf713 100644 --- a/drivers/infiniband/sw/rxe/rxe_req.c +++ b/drivers/infiniband/sw/rxe/rxe_req.c @@ -596,6 +596,8 @@ int rxe_requester(void *arg) struct rxe_send_wqe rollback_wqe; u32 rollback_psn; + rxe_add_ref(qp); + next_wqe: if (unlikely(!qp->valid || qp->req.state == QP_STATE_ERROR)) goto exit; @@ -750,9 +752,10 @@ complete: while (rxe_completer(qp) == 0) ; } - + rxe_drop_ref(qp); return 0; exit: + rxe_drop_ref(qp); return -EAGAIN; } diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 8643797fb530..7a36ec9dbc0c 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -1212,6 +1212,8 @@ int rxe_responder(void *arg) struct rxe_pkt_info *pkt = NULL; int ret = 0; + rxe_add_ref(qp); + qp->resp.aeth_syndrome = AETH_ACK_UNLIMITED; if (!qp->valid) { @@ -1400,5 +1402,6 @@ int rxe_responder(void *arg) exit: ret = -EAGAIN; done: + rxe_drop_ref(qp); return ret; } -- cgit v1.2.3 From 5e589171225b6aeac5eaca0b0887bd83dc9376d8 Mon Sep 17 00:00:00 2001 From: Thomas Huth Date: Wed, 5 Oct 2016 13:55:38 +0200 Subject: i40iw: Remove macros I40IW_STAG_KEY_FROM_STAG and I40IW_STAG_INDEX_FROM_STAG The macros I40IW_STAG_KEY_FROM_STAG and I40IW_STAG_INDEX_FROM_STAG are apparently bad - they are using the logical "&&" operation which does not make sense here. It should have been a bitwise "&" instead. Since the macros seem to be completely unused, let's simply remove them so that nobody accidentially uses them in the future. And while we're at it, also remove the unused macro I40IW_CREATE_STAG. Signed-off-by: Thomas Huth Reviewed-by: Leon Romanovsky Acked-by: Faisal Latif Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_user.h | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_user.h b/drivers/infiniband/hw/i40iw/i40iw_user.h index 66263fced68f..80d9f464f65e 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_user.h +++ b/drivers/infiniband/hw/i40iw/i40iw_user.h @@ -96,12 +96,6 @@ enum i40iw_device_capabilities_const { #define i40iw_physical_fragment u64 #define i40iw_address_list u64 * -#define I40IW_CREATE_STAG(index, key) (((index) << 8) + (key)) - -#define I40IW_STAG_KEY_FROM_STAG(stag) ((stag) && 0x000000FF) - -#define I40IW_STAG_INDEX_FROM_STAG(stag) (((stag) && 0xFFFFFF00) >> 8) - #define I40IW_MAX_MR_SIZE 0x10000000000L struct i40iw_qp_uk; -- cgit v1.2.3 From 91c42b72f8e8b45961ff05a05009b644e6316ca2 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Fri, 11 Nov 2016 10:55:41 -0600 Subject: i40iw: Use correct src address in memcpy to rdma stats counters hw_stats is a pointer to i40_iw_dev_stats struct in i40iw_get_hw_stats(). Use hw_stats and not &hw_stats in the memcpy to copy the i40iw device stats data into rdma_hw_stats counters. Fixes: b40f4757daa1 ("IB/core: Make device counter infrastructure dynamic") Cc: stable@vger.kernel.org # 4.7+ Signed-off-by: Shiraz Saleem Signed-off-by: Faisal Latif Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index bc24086989e3..206d72b8a8bd 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2646,7 +2646,7 @@ static int i40iw_get_hw_stats(struct ib_device *ibdev, return -ENOSYS; } - memcpy(&stats->value[0], &hw_stats, sizeof(*hw_stats)); + memcpy(&stats->value[0], hw_stats, sizeof(*hw_stats)); return stats->num_counters; } -- cgit v1.2.3 From f4a87ca12a1c203913a5cc889ec49b817a1f45fc Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Tue, 6 Dec 2016 15:49:30 -0600 Subject: i40iw: Fix double free of QP A QP can be double freed if i40iw_cm_disconn() is called while it is currently being freed by i40iw_rem_ref(). The fix in i40iw_cm_disconn() will first check if the QP is already freed before making another request for the QP to be freed. Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw.h | 2 +- drivers/infiniband/hw/i40iw/i40iw_cm.c | 20 ++++++++++++++++---- drivers/infiniband/hw/i40iw/i40iw_hw.c | 4 +++- 3 files changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index ef188e6b1f89..51b828026b53 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -512,7 +512,7 @@ u32 i40iw_initialize_hw_resources(struct i40iw_device *iwdev); int i40iw_register_rdma_device(struct i40iw_device *iwdev); void i40iw_port_ibevent(struct i40iw_device *iwdev); -int i40iw_cm_disconn(struct i40iw_qp *); +void i40iw_cm_disconn(struct i40iw_qp *iwqp); void i40iw_cm_disconn_worker(void *); int mini_cm_recv_pkt(struct i40iw_cm_core *, struct i40iw_device *, struct sk_buff *); diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index 25af89a3cdce..ff95feaee105 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -3359,21 +3359,33 @@ static void i40iw_cm_init_tsa_conn(struct i40iw_qp *iwqp, * i40iw_cm_disconn - when a connection is being closed * @iwqp: associate qp for the connection */ -int i40iw_cm_disconn(struct i40iw_qp *iwqp) +void i40iw_cm_disconn(struct i40iw_qp *iwqp) { struct disconn_work *work; struct i40iw_device *iwdev = iwqp->iwdev; struct i40iw_cm_core *cm_core = &iwdev->cm_core; + unsigned long flags; work = kzalloc(sizeof(*work), GFP_ATOMIC); if (!work) - return -ENOMEM; /* Timer will clean up */ - + return; /* Timer will clean up */ + + spin_lock_irqsave(&iwdev->qptable_lock, flags); + if (!iwdev->qp_table[iwqp->ibqp.qp_num]) { + spin_unlock_irqrestore(&iwdev->qptable_lock, flags); + i40iw_debug(&iwdev->sc_dev, I40IW_DEBUG_CM, + "%s qp_id %d is already freed\n", + __func__, iwqp->ibqp.qp_num); + kfree(work); + return; + } i40iw_add_ref(&iwqp->ibqp); + spin_unlock_irqrestore(&iwdev->qptable_lock, flags); + work->iwqp = iwqp; INIT_WORK(&work->work, i40iw_disconnect_worker); queue_work(cm_core->disconn_wq, &work->work); - return 0; + return; } /** diff --git a/drivers/infiniband/hw/i40iw/i40iw_hw.c b/drivers/infiniband/hw/i40iw/i40iw_hw.c index 5e2c16c725e3..b2854b11a240 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_hw.c +++ b/drivers/infiniband/hw/i40iw/i40iw_hw.c @@ -308,7 +308,9 @@ void i40iw_process_aeq(struct i40iw_device *iwdev) iwqp = iwdev->qp_table[info->qp_cq_id]; if (!iwqp) { spin_unlock_irqrestore(&iwdev->qptable_lock, flags); - i40iw_pr_err("qp_id %d is already freed\n", info->qp_cq_id); + i40iw_debug(dev, I40IW_DEBUG_AEQ, + "%s qp_id %d is already freed\n", + __func__, info->qp_cq_id); continue; } i40iw_add_ref(&iwqp->ibqp); -- cgit v1.2.3 From 1cda28bb5b503bab734072d97a41b2e7eda6b6b9 Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Tue, 6 Dec 2016 15:49:31 -0600 Subject: i40iw: Fix QP flush to not hang on empty queues or failure When flush QP and there are no pending work requests, signal completion to unblock i40iw_drain_sq and i40iw_drain_rq which are waiting on completion for iwqp->sq_drained and iwqp->sq_drained respectively. Also, signal completion if flush QP fails to prevent the drain SQ or RQ from being blocked indefintely. Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw.h | 9 ++++++--- drivers/infiniband/hw/i40iw/i40iw_hw.c | 26 ++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index 51b828026b53..2aab85bbcbc7 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -112,9 +112,12 @@ #define I40IW_DRV_OPT_MCAST_LOGPORT_MAP 0x00000800 #define IW_HMC_OBJ_TYPE_NUM ARRAY_SIZE(iw_hmc_obj_types) -#define IW_CFG_FPM_QP_COUNT 32768 -#define I40IW_MAX_PAGES_PER_FMR 512 -#define I40IW_MIN_PAGES_PER_FMR 1 +#define IW_CFG_FPM_QP_COUNT 32768 +#define I40IW_MAX_PAGES_PER_FMR 512 +#define I40IW_MIN_PAGES_PER_FMR 1 +#define I40IW_CQP_COMPL_RQ_WQE_FLUSHED 2 +#define I40IW_CQP_COMPL_SQ_WQE_FLUSHED 3 +#define I40IW_CQP_COMPL_RQ_SQ_WQE_FLUSHED 4 #define I40IW_MTU_TO_MSS 40 #define I40IW_DEFAULT_MSS 1460 diff --git a/drivers/infiniband/hw/i40iw/i40iw_hw.c b/drivers/infiniband/hw/i40iw/i40iw_hw.c index b2854b11a240..4394a6713bdf 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_hw.c +++ b/drivers/infiniband/hw/i40iw/i40iw_hw.c @@ -622,6 +622,7 @@ enum i40iw_status_code i40iw_hw_flush_wqes(struct i40iw_device *iwdev, struct i40iw_qp_flush_info *hw_info; struct i40iw_cqp_request *cqp_request; struct cqp_commands_info *cqp_info; + struct i40iw_qp *iwqp = (struct i40iw_qp *)qp->back_qp; cqp_request = i40iw_get_cqp_request(&iwdev->cqp, wait); if (!cqp_request) @@ -636,9 +637,30 @@ enum i40iw_status_code i40iw_hw_flush_wqes(struct i40iw_device *iwdev, cqp_info->in.u.qp_flush_wqes.qp = qp; cqp_info->in.u.qp_flush_wqes.scratch = (uintptr_t)cqp_request; status = i40iw_handle_cqp_op(iwdev, cqp_request); - if (status) + if (status) { i40iw_pr_err("CQP-OP Flush WQE's fail"); - return status; + complete(&iwqp->sq_drained); + complete(&iwqp->rq_drained); + return status; + } + if (!cqp_request->compl_info.maj_err_code) { + switch (cqp_request->compl_info.min_err_code) { + case I40IW_CQP_COMPL_RQ_WQE_FLUSHED: + complete(&iwqp->sq_drained); + break; + case I40IW_CQP_COMPL_SQ_WQE_FLUSHED: + complete(&iwqp->rq_drained); + break; + case I40IW_CQP_COMPL_RQ_SQ_WQE_FLUSHED: + break; + default: + complete(&iwqp->sq_drained); + complete(&iwqp->rq_drained); + break; + } + } + + return 0; } /** -- cgit v1.2.3 From fd90d4d4c2dc815ef5a5f5d50a9c65c266c68ace Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Tue, 6 Dec 2016 15:49:32 -0600 Subject: i40iw: Fix memory leak in CQP destroy when in reset On a device close, the control QP (CQP) is destroyed by calling cqp_destroy which destroys the CQP and frees its SD buffer memory. However, if the reset flag is true, cqp_destroy is never called and leads to a memory leak on SD buffer memory. Fix this by always calling cqp_destroy, on device close, regardless of reset. The exception to this when CQP create fails. In this case, the SD buffer memory is already freed on an error check and there is no need to call cqp_destroy. Signed-off-by: Mustafa Ismail Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_main.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index 4ce05b8e8f0a..85d8fa63d5b5 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -237,14 +237,11 @@ static irqreturn_t i40iw_irq_handler(int irq, void *data) */ static void i40iw_destroy_cqp(struct i40iw_device *iwdev, bool free_hwcqp) { - enum i40iw_status_code status = 0; struct i40iw_sc_dev *dev = &iwdev->sc_dev; struct i40iw_cqp *cqp = &iwdev->cqp; - if (free_hwcqp && dev->cqp_ops->cqp_destroy) - status = dev->cqp_ops->cqp_destroy(dev->cqp); - if (status) - i40iw_pr_err("destroy cqp failed"); + if (free_hwcqp) + dev->cqp_ops->cqp_destroy(dev->cqp); i40iw_free_dma_mem(dev->hw, &cqp->sq); kfree(cqp->scratch_array); @@ -1475,7 +1472,7 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset) i40iw_del_hmc_objects(dev, dev->hmc_info, true, reset); /* fallthrough */ case CQP_CREATED: - i40iw_destroy_cqp(iwdev, !reset); + i40iw_destroy_cqp(iwdev, true); /* fallthrough */ case INITIAL_STATE: i40iw_cleanup_cm_core(&iwdev->cm_core); -- cgit v1.2.3 From d627b506313c887e7159580cde926f5d14797aaa Mon Sep 17 00:00:00 2001 From: Shiraz Saleem Date: Tue, 6 Dec 2016 15:49:33 -0600 Subject: i40iw: Fix race condition in terminate timer's handler Add a QP reference when terminate timer is started to ensure the destroy QP doesn't race ahead to free the QP while it is being referenced in the terminate timer's handler. Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_cm.c | 2 +- drivers/infiniband/hw/i40iw/i40iw_utils.c | 5 ++++- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index ff95feaee105..a217d2f34914 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -3471,7 +3471,7 @@ static void i40iw_cm_disconn_true(struct i40iw_qp *iwqp) *terminate-handler to issue cm_disconn which can re-free *a QP even after its refcnt=0. */ - del_timer(&iwqp->terminate_timer); + i40iw_terminate_del_timer(qp); if (!iwqp->flush_issued) { iwqp->flush_issued = 1; issue_flush = 1; diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index 4a08ffb75d2e..7d4af7759970 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -823,6 +823,7 @@ static void i40iw_terminate_timeout(unsigned long context) struct i40iw_sc_qp *qp = (struct i40iw_sc_qp *)&iwqp->sc_qp; i40iw_terminate_done(qp, 1); + i40iw_rem_ref(&iwqp->ibqp); } /** @@ -834,6 +835,7 @@ void i40iw_terminate_start_timer(struct i40iw_sc_qp *qp) struct i40iw_qp *iwqp; iwqp = (struct i40iw_qp *)qp->back_qp; + i40iw_add_ref(&iwqp->ibqp); init_timer(&iwqp->terminate_timer); iwqp->terminate_timer.function = i40iw_terminate_timeout; iwqp->terminate_timer.expires = jiffies + HZ; @@ -850,7 +852,8 @@ void i40iw_terminate_del_timer(struct i40iw_sc_qp *qp) struct i40iw_qp *iwqp; iwqp = (struct i40iw_qp *)qp->back_qp; - del_timer(&iwqp->terminate_timer); + if (del_timer(&iwqp->terminate_timer)) + i40iw_rem_ref(&iwqp->ibqp); } /** diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 206d72b8a8bd..18526e6f9d85 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -959,7 +959,7 @@ int i40iw_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, goto exit; } if (iwqp->sc_qp.term_flags) - del_timer(&iwqp->terminate_timer); + i40iw_terminate_del_timer(&iwqp->sc_qp); info.next_iwarp_state = I40IW_QP_STATE_ERROR; if ((iwqp->hw_tcp_state > I40IW_TCP_STATE_CLOSED) && iwdev->iw_status && -- cgit v1.2.3 From 6b0805c25657f9b702607ed4617c2821343158c0 Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Tue, 6 Dec 2016 15:49:34 -0600 Subject: i40iw: Assign MSS only when it is a new MTU Currently we are changing the MSS regardless of whether there is a change or not in MTU. Fix to make the assignment of MSS dependent on an MTU change. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Shiraz Saleem Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index 85d8fa63d5b5..cf9d288a79b3 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -1724,6 +1724,8 @@ static void i40iw_l2param_change(struct i40e_info *ldev, struct i40e_client *cli for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) l2params->qs_handle_list[i] = params->qos.prio_qos[i].qs_handle; + l2params->mss = (params->mtu) ? params->mtu - I40IW_MTU_TO_MSS : iwdev->mss; + INIT_WORK(&work->work, i40iw_l2params_worker); queue_work(iwdev->param_wq, &work->work); } -- cgit v1.2.3 From 0cc0d851ccf1746466822c1b7ce02c980406d57f Mon Sep 17 00:00:00 2001 From: Mustafa Ismail Date: Tue, 6 Dec 2016 15:49:35 -0600 Subject: i40iw: Fix incorrect check for error In i40iw_ieq_handle_partial() the check for !status is incorrect. Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_puda.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c index 7541b0dada59..c3d28baf8e3a 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.c +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c @@ -1132,7 +1132,7 @@ static enum i40iw_status_code i40iw_ieq_handle_partial(struct i40iw_puda_rsrc *i list_add(&buf->list, &pbufl); status = i40iw_ieq_create_pbufl(pfpdu, rxlist, &pbufl, buf, fpdu_len); - if (!status) + if (status) goto error; txbuf = i40iw_puda_get_bufpool(ieq); -- cgit v1.2.3 From d6f7bbcc2e419c8afd4a426af78b3dac44632268 Mon Sep 17 00:00:00 2001 From: Henry Orosco Date: Tue, 6 Dec 2016 16:16:20 -0600 Subject: i40iw: Reorganize structures to align with HW capabilities Some resources are incorrectly organized and at odds with HW capabilities. Specifically, ILQ, IEQ, QPs, MSS, QOS and statistics belong in a VSI. Signed-off-by: Faisal Latif Signed-off-by: Mustafa Ismail Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw.h | 7 +- drivers/infiniband/hw/i40iw/i40iw_cm.c | 36 +- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 527 +++++++++++++++------------ drivers/infiniband/hw/i40iw/i40iw_d.h | 21 +- drivers/infiniband/hw/i40iw/i40iw_hw.c | 4 +- drivers/infiniband/hw/i40iw/i40iw_main.c | 53 ++- drivers/infiniband/hw/i40iw/i40iw_osdep.h | 6 +- drivers/infiniband/hw/i40iw/i40iw_p.h | 23 +- drivers/infiniband/hw/i40iw/i40iw_puda.c | 268 ++++++++------ drivers/infiniband/hw/i40iw/i40iw_puda.h | 20 +- drivers/infiniband/hw/i40iw/i40iw_type.h | 79 ++-- drivers/infiniband/hw/i40iw/i40iw_utils.c | 150 +++++++- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 17 +- drivers/infiniband/hw/i40iw/i40iw_virtchnl.c | 29 +- 14 files changed, 775 insertions(+), 465 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw.h b/drivers/infiniband/hw/i40iw/i40iw.h index 2aab85bbcbc7..da2eb5a281fa 100644 --- a/drivers/infiniband/hw/i40iw/i40iw.h +++ b/drivers/infiniband/hw/i40iw/i40iw.h @@ -236,6 +236,7 @@ struct i40iw_device { struct net_device *netdev; wait_queue_head_t vchnl_waitq; struct i40iw_sc_dev sc_dev; + struct i40iw_sc_vsi vsi; struct i40iw_handler *hdl; struct i40e_info *ldev; struct i40e_client *client; @@ -289,7 +290,6 @@ struct i40iw_device { u32 sd_type; struct workqueue_struct *param_wq; atomic_t params_busy; - u32 mss; enum init_completion_state init_state; u16 mac_ip_table_idx; atomic_t vchnl_msgs; @@ -525,6 +525,7 @@ enum i40iw_status_code i40iw_handle_cqp_op(struct i40iw_device *iwdev, enum i40iw_status_code i40iw_add_mac_addr(struct i40iw_device *iwdev, u8 *mac_addr, u8 *mac_index); int i40iw_modify_qp(struct ib_qp *, struct ib_qp_attr *, int, struct ib_udata *); +void i40iw_cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq); void i40iw_rem_pdusecount(struct i40iw_pd *iwpd, struct i40iw_device *iwdev); void i40iw_add_pdusecount(struct i40iw_pd *iwpd); @@ -542,8 +543,8 @@ enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev, enum i40iw_quad_hash_manage_type mtype, void *cmnode, bool wait); -void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf); -void i40iw_free_sqbuf(struct i40iw_sc_dev *dev, void *bufp); +void i40iw_receive_ilq(struct i40iw_sc_vsi *vsi, struct i40iw_puda_buf *rbuf); +void i40iw_free_sqbuf(struct i40iw_sc_vsi *vsi, void *bufp); void i40iw_free_qp_resources(struct i40iw_device *iwdev, struct i40iw_qp *iwqp, u32 qp_num); diff --git a/drivers/infiniband/hw/i40iw/i40iw_cm.c b/drivers/infiniband/hw/i40iw/i40iw_cm.c index a217d2f34914..e4820bef90be 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_cm.c +++ b/drivers/infiniband/hw/i40iw/i40iw_cm.c @@ -68,13 +68,13 @@ static void i40iw_disconnect_worker(struct work_struct *work); /** * i40iw_free_sqbuf - put back puda buffer if refcount = 0 - * @dev: FPK device + * @vsi: pointer to vsi structure * @buf: puda buffer to free */ -void i40iw_free_sqbuf(struct i40iw_sc_dev *dev, void *bufp) +void i40iw_free_sqbuf(struct i40iw_sc_vsi *vsi, void *bufp) { struct i40iw_puda_buf *buf = (struct i40iw_puda_buf *)bufp; - struct i40iw_puda_rsrc *ilq = dev->ilq; + struct i40iw_puda_rsrc *ilq = vsi->ilq; if (!atomic_dec_return(&buf->refcount)) i40iw_puda_ret_bufpool(ilq, buf); @@ -337,13 +337,13 @@ static struct i40iw_cm_event *i40iw_create_event(struct i40iw_cm_node *cm_node, */ static void i40iw_free_retrans_entry(struct i40iw_cm_node *cm_node) { - struct i40iw_sc_dev *dev = cm_node->dev; + struct i40iw_device *iwdev = cm_node->iwdev; struct i40iw_timer_entry *send_entry; send_entry = cm_node->send_entry; if (send_entry) { cm_node->send_entry = NULL; - i40iw_free_sqbuf(dev, (void *)send_entry->sqbuf); + i40iw_free_sqbuf(&iwdev->vsi, (void *)send_entry->sqbuf); kfree(send_entry); atomic_dec(&cm_node->ref_count); } @@ -377,7 +377,7 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, u8 flags) { struct i40iw_puda_buf *sqbuf; - struct i40iw_sc_dev *dev = cm_node->dev; + struct i40iw_sc_vsi *vsi = &cm_node->iwdev->vsi; u8 *buf; struct tcphdr *tcph; @@ -391,7 +391,7 @@ static struct i40iw_puda_buf *i40iw_form_cm_frame(struct i40iw_cm_node *cm_node, u32 hdr_len = 0; u16 vtag; - sqbuf = i40iw_puda_get_bufpool(dev->ilq); + sqbuf = i40iw_puda_get_bufpool(vsi->ilq); if (!sqbuf) return NULL; buf = sqbuf->mem.va; @@ -1059,7 +1059,7 @@ int i40iw_schedule_cm_timer(struct i40iw_cm_node *cm_node, int send_retrans, int close_when_complete) { - struct i40iw_sc_dev *dev = cm_node->dev; + struct i40iw_sc_vsi *vsi = &cm_node->iwdev->vsi; struct i40iw_cm_core *cm_core = cm_node->cm_core; struct i40iw_timer_entry *new_send; int ret = 0; @@ -1068,7 +1068,7 @@ int i40iw_schedule_cm_timer(struct i40iw_cm_node *cm_node, new_send = kzalloc(sizeof(*new_send), GFP_ATOMIC); if (!new_send) { - i40iw_free_sqbuf(cm_node->dev, (void *)sqbuf); + i40iw_free_sqbuf(vsi, (void *)sqbuf); return -ENOMEM; } new_send->retrycount = I40IW_DEFAULT_RETRYS; @@ -1083,7 +1083,7 @@ int i40iw_schedule_cm_timer(struct i40iw_cm_node *cm_node, new_send->timetosend += (HZ / 10); if (cm_node->close_entry) { kfree(new_send); - i40iw_free_sqbuf(cm_node->dev, (void *)sqbuf); + i40iw_free_sqbuf(vsi, (void *)sqbuf); i40iw_pr_err("already close entry\n"); return -EINVAL; } @@ -1098,7 +1098,7 @@ int i40iw_schedule_cm_timer(struct i40iw_cm_node *cm_node, new_send->timetosend = jiffies + I40IW_RETRY_TIMEOUT; atomic_inc(&sqbuf->refcount); - i40iw_puda_send_buf(dev->ilq, sqbuf); + i40iw_puda_send_buf(vsi->ilq, sqbuf); if (!send_retrans) { i40iw_cleanup_retrans_entry(cm_node); if (close_when_complete) @@ -1195,6 +1195,7 @@ static void i40iw_cm_timer_tick(unsigned long pass) struct i40iw_cm_node *cm_node; struct i40iw_timer_entry *send_entry, *close_entry; struct list_head *list_core_temp; + struct i40iw_sc_vsi *vsi; struct list_head *list_node; struct i40iw_cm_core *cm_core = (struct i40iw_cm_core *)pass; u32 settimer = 0; @@ -1270,9 +1271,10 @@ static void i40iw_cm_timer_tick(unsigned long pass) cm_node->cm_core->stats_pkt_retrans++; spin_unlock_irqrestore(&cm_node->retrans_list_lock, flags); + vsi = &cm_node->iwdev->vsi; dev = cm_node->dev; atomic_inc(&send_entry->sqbuf->refcount); - i40iw_puda_send_buf(dev->ilq, send_entry->sqbuf); + i40iw_puda_send_buf(vsi->ilq, send_entry->sqbuf); spin_lock_irqsave(&cm_node->retrans_list_lock, flags); if (send_entry->send_retrans) { send_entry->retranscount--; @@ -1373,10 +1375,11 @@ int i40iw_send_syn(struct i40iw_cm_node *cm_node, u32 sendack) static void i40iw_send_ack(struct i40iw_cm_node *cm_node) { struct i40iw_puda_buf *sqbuf; + struct i40iw_sc_vsi *vsi = &cm_node->iwdev->vsi; sqbuf = i40iw_form_cm_frame(cm_node, NULL, NULL, NULL, SET_ACK); if (sqbuf) - i40iw_puda_send_buf(cm_node->dev->ilq, sqbuf); + i40iw_puda_send_buf(vsi->ilq, sqbuf); else i40iw_pr_err("no sqbuf\n"); } @@ -2179,7 +2182,7 @@ static struct i40iw_cm_node *i40iw_make_cm_node( I40IW_CM_DEFAULT_RCV_WND_SCALED >> I40IW_CM_DEFAULT_RCV_WND_SCALE; ts = current_kernel_time(); cm_node->tcp_cntxt.loc_seq_num = ts.tv_nsec; - cm_node->tcp_cntxt.mss = iwdev->mss; + cm_node->tcp_cntxt.mss = iwdev->vsi.mss; cm_node->iwdev = iwdev; cm_node->dev = &iwdev->sc_dev; @@ -3059,10 +3062,10 @@ static int i40iw_cm_close(struct i40iw_cm_node *cm_node) /** * i40iw_receive_ilq - recv an ETHERNET packet, and process it * through CM - * @dev: FPK dev struct + * @vsi: pointer to the vsi structure * @rbuf: receive buffer */ -void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf) +void i40iw_receive_ilq(struct i40iw_sc_vsi *vsi, struct i40iw_puda_buf *rbuf) { struct i40iw_cm_node *cm_node; struct i40iw_cm_listener *listener; @@ -3070,6 +3073,7 @@ void i40iw_receive_ilq(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *rbuf) struct ipv6hdr *ip6h; struct tcphdr *tcph; struct i40iw_cm_info cm_info; + struct i40iw_sc_dev *dev = vsi->dev; struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; struct i40iw_cm_core *cm_core = &iwdev->cm_core; struct vlan_ethhdr *ethh; diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index a13503715f20..392f78384a60 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -103,6 +103,7 @@ static enum i40iw_status_code i40iw_cqp_poll_registers( if (newtail != tail) { /* SUCCESS */ I40IW_RING_MOVE_TAIL(cqp->sq_ring); + cqp->dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS]++; return 0; } udelay(I40IW_SLEEP_COUNT); @@ -276,11 +277,12 @@ static struct i40iw_sc_qp *i40iw_get_qp(struct list_head *head, struct i40iw_sc_ /** * i40iw_change_l2params - given the new l2 parameters, change all qp - * @dev: IWARP device pointer + * @vsi: pointer to the vsi structure * @l2params: New paramaters from l2 */ -void i40iw_change_l2params(struct i40iw_sc_dev *dev, struct i40iw_l2params *l2params) +void i40iw_change_l2params(struct i40iw_sc_vsi *vsi, struct i40iw_l2params *l2params) { + struct i40iw_sc_dev *dev = vsi->dev; struct i40iw_sc_qp *qp = NULL; bool qs_handle_change = false; bool mss_change = false; @@ -288,20 +290,20 @@ void i40iw_change_l2params(struct i40iw_sc_dev *dev, struct i40iw_l2params *l2pa u16 qs_handle; int i; - if (dev->mss != l2params->mss) { + if (vsi->mss != l2params->mss) { mss_change = true; - dev->mss = l2params->mss; + vsi->mss = l2params->mss; } i40iw_fill_qos_list(l2params->qs_handle_list); for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) { qs_handle = l2params->qs_handle_list[i]; - if (dev->qos[i].qs_handle != qs_handle) + if (vsi->qos[i].qs_handle != qs_handle) qs_handle_change = true; else if (!mss_change) continue; /* no MSS nor qs handle change */ - spin_lock_irqsave(&dev->qos[i].lock, flags); - qp = i40iw_get_qp(&dev->qos[i].qplist, qp); + spin_lock_irqsave(&vsi->qos[i].lock, flags); + qp = i40iw_get_qp(&vsi->qos[i].qplist, qp); while (qp) { if (mss_change) i40iw_qp_mss_modify(dev, qp); @@ -310,43 +312,45 @@ void i40iw_change_l2params(struct i40iw_sc_dev *dev, struct i40iw_l2params *l2pa /* issue cqp suspend command */ i40iw_qp_suspend_resume(dev, qp, true); } - qp = i40iw_get_qp(&dev->qos[i].qplist, qp); + qp = i40iw_get_qp(&vsi->qos[i].qplist, qp); } - spin_unlock_irqrestore(&dev->qos[i].lock, flags); - dev->qos[i].qs_handle = qs_handle; + spin_unlock_irqrestore(&vsi->qos[i].lock, flags); + vsi->qos[i].qs_handle = qs_handle; } } /** * i40iw_qp_rem_qos - remove qp from qos lists during destroy qp - * @dev: IWARP device pointer * @qp: qp to be removed from qos */ -static void i40iw_qp_rem_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) +static void i40iw_qp_rem_qos(struct i40iw_sc_qp *qp) { + struct i40iw_sc_vsi *vsi = qp->vsi; unsigned long flags; if (!qp->on_qoslist) return; - spin_lock_irqsave(&dev->qos[qp->user_pri].lock, flags); + spin_lock_irqsave(&vsi->qos[qp->user_pri].lock, flags); list_del(&qp->list); - spin_unlock_irqrestore(&dev->qos[qp->user_pri].lock, flags); + spin_unlock_irqrestore(&vsi->qos[qp->user_pri].lock, flags); } /** * i40iw_qp_add_qos - called during setctx fot qp to be added to qos - * @dev: IWARP device pointer * @qp: qp to be added to qos */ -void i40iw_qp_add_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) +void i40iw_qp_add_qos(struct i40iw_sc_qp *qp) { + struct i40iw_sc_vsi *vsi = qp->vsi; unsigned long flags; - spin_lock_irqsave(&dev->qos[qp->user_pri].lock, flags); - qp->qs_handle = dev->qos[qp->user_pri].qs_handle; - list_add(&qp->list, &dev->qos[qp->user_pri].qplist); + if (qp->on_qoslist) + return; + spin_lock_irqsave(&vsi->qos[qp->user_pri].lock, flags); + qp->qs_handle = vsi->qos[qp->user_pri].qs_handle; + list_add(&qp->list, &vsi->qos[qp->user_pri].qplist); qp->on_qoslist = true; - spin_unlock_irqrestore(&dev->qos[qp->user_pri].lock, flags); + spin_unlock_irqrestore(&vsi->qos[qp->user_pri].lock, flags); } /** @@ -419,6 +423,9 @@ static enum i40iw_status_code i40iw_sc_cqp_init(struct i40iw_sc_cqp *cqp, info->dev->cqp = cqp; I40IW_RING_INIT(cqp->sq_ring, cqp->sq_size); + cqp->dev->cqp_cmd_stats[OP_REQUESTED_COMMANDS] = 0; + cqp->dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS] = 0; + i40iw_debug(cqp->dev, I40IW_DEBUG_WQE, "%s: sq_size[%04d] hw_sq_size[%04d] sq_base[%p] sq_pa[%llxh] cqp[%p] polarity[x%04X]\n", __func__, cqp->sq_size, cqp->hw_sq_size, @@ -546,6 +553,7 @@ u64 *i40iw_sc_cqp_get_next_send_wqe(struct i40iw_sc_cqp *cqp, u64 scratch) return NULL; } I40IW_ATOMIC_RING_MOVE_HEAD(cqp->sq_ring, wqe_idx, ret_code); + cqp->dev->cqp_cmd_stats[OP_REQUESTED_COMMANDS]++; if (ret_code) return NULL; if (!wqe_idx) @@ -681,6 +689,8 @@ static enum i40iw_status_code i40iw_sc_ccq_get_cqe_info( I40IW_RING_GETCURRENT_HEAD(ccq->cq_uk.cq_ring)); wmb(); /* write shadow area before tail */ I40IW_RING_MOVE_TAIL(cqp->sq_ring); + ccq->dev->cqp_cmd_stats[OP_COMPLETED_COMMANDS]++; + return ret_code; } @@ -1173,6 +1183,7 @@ static enum i40iw_status_code i40iw_sc_manage_qhash_table_entry( u64 qw1 = 0; u64 qw2 = 0; u64 temp; + struct i40iw_sc_vsi *vsi = info->vsi; wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch); if (!wqe) @@ -1204,7 +1215,7 @@ static enum i40iw_status_code i40iw_sc_manage_qhash_table_entry( LS_64(info->dest_ip[2], I40IW_CQPSQ_QHASH_ADDR2) | LS_64(info->dest_ip[3], I40IW_CQPSQ_QHASH_ADDR3)); } - qw2 = LS_64(cqp->dev->qos[info->user_pri].qs_handle, I40IW_CQPSQ_QHASH_QS_HANDLE); + qw2 = LS_64(vsi->qos[info->user_pri].qs_handle, I40IW_CQPSQ_QHASH_QS_HANDLE); if (info->vlan_valid) qw2 |= LS_64(info->vlan_id, I40IW_CQPSQ_QHASH_VLANID); set_64bit_val(wqe, 16, qw2); @@ -2225,6 +2236,7 @@ static enum i40iw_status_code i40iw_sc_qp_init(struct i40iw_sc_qp *qp, u32 offset; qp->dev = info->pd->dev; + qp->vsi = info->vsi; qp->sq_pa = info->sq_pa; qp->rq_pa = info->rq_pa; qp->hw_host_ctx_pa = info->host_ctx_pa; @@ -2273,7 +2285,7 @@ static enum i40iw_status_code i40iw_sc_qp_init(struct i40iw_sc_qp *qp, qp->rq_tph_en = info->rq_tph_en; qp->rcv_tph_en = info->rcv_tph_en; qp->xmit_tph_en = info->xmit_tph_en; - qp->qs_handle = qp->pd->dev->qos[qp->user_pri].qs_handle; + qp->qs_handle = qp->vsi->qos[qp->user_pri].qs_handle; qp->exception_lan_queue = qp->pd->dev->exception_lan_queue; return 0; @@ -2418,7 +2430,7 @@ static enum i40iw_status_code i40iw_sc_qp_destroy( struct i40iw_sc_cqp *cqp; u64 header; - i40iw_qp_rem_qos(qp->pd->dev, qp); + i40iw_qp_rem_qos(qp); cqp = qp->pd->dev->cqp; wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, scratch); if (!wqe) @@ -2566,13 +2578,17 @@ static enum i40iw_status_code i40iw_sc_qp_setctx( { struct i40iwarp_offload_info *iw; struct i40iw_tcp_offload_info *tcp; + struct i40iw_sc_vsi *vsi; + struct i40iw_sc_dev *dev; u64 qw0, qw3, qw7 = 0; iw = info->iwarp_info; tcp = info->tcp_info; + vsi = qp->vsi; + dev = qp->dev; if (info->add_to_qoslist) { qp->user_pri = info->user_pri; - i40iw_qp_add_qos(qp->pd->dev, qp); + i40iw_qp_add_qos(qp); i40iw_debug(qp->dev, I40IW_DEBUG_DCB, "%s qp[%d] UP[%d] qset[%d]\n", __func__, qp->qp_uk.qp_id, qp->user_pri, qp->qs_handle); } @@ -2616,7 +2632,10 @@ static enum i40iw_status_code i40iw_sc_qp_setctx( LS_64(iw->rdmap_ver, I40IWQPC_RDMAP_VER); qw7 |= LS_64(iw->pd_id, I40IWQPC_PDIDX); - set_64bit_val(qp_ctx, 144, qp->q2_pa); + set_64bit_val(qp_ctx, + 144, + LS_64(qp->q2_pa, I40IWQPC_Q2ADDR) | + LS_64(vsi->fcn_id, I40IWQPC_STAT_INDEX)); set_64bit_val(qp_ctx, 152, LS_64(iw->last_byte_sent, I40IWQPC_LASTBYTESENT)); @@ -2631,6 +2650,9 @@ static enum i40iw_status_code i40iw_sc_qp_setctx( LS_64(iw->bind_en, I40IWQPC_BINDEN) | LS_64(iw->fast_reg_en, I40IWQPC_FASTREGEN) | LS_64(iw->priv_mode_en, I40IWQPC_PRIVEN) | + LS_64((((vsi->stats_fcn_id_alloc) && + (dev->is_pf) && (vsi->fcn_id >= I40IW_FIRST_NON_PF_STAT)) ? 1 : 0), + I40IWQPC_USESTATSINSTANCE) | LS_64(1, I40IWQPC_IWARPMODE) | LS_64(iw->rcv_mark_en, I40IWQPC_RCVMARKERS) | LS_64(iw->align_hdrs, I40IWQPC_ALIGNHDRS) | @@ -4447,286 +4469,370 @@ void i40iw_terminate_received(struct i40iw_sc_qp *qp, struct i40iw_aeqe_info *in } /** - * i40iw_hw_stat_init - Initiliaze HW stats table - * @devstat: pestat struct + * i40iw_sc_vsi_init - Initialize virtual device + * @vsi: pointer to the vsi structure + * @info: parameters to initialize vsi + **/ +void i40iw_sc_vsi_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_init_info *info) +{ + int i; + + vsi->dev = info->dev; + vsi->back_vsi = info->back_vsi; + vsi->mss = info->params->mss; + i40iw_fill_qos_list(info->params->qs_handle_list); + + for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) { + vsi->qos[i].qs_handle = + info->params->qs_handle_list[i]; + i40iw_debug(vsi->dev, I40IW_DEBUG_DCB, "qset[%d]: %d\n", i, vsi->qos[i].qs_handle); + spin_lock_init(&vsi->qos[i].lock); + INIT_LIST_HEAD(&vsi->qos[i].qplist); + } +} + +/** + * i40iw_hw_stats_init - Initiliaze HW stats table + * @stats: pestat struct * @fcn_idx: PCI fn id - * @hw: PF i40iw_hw structure. * @is_pf: Is it a PF? * - * Populate the HW stat table with register offset addr for each - * stat. And start the perioidic stats timer. + * Populate the HW stats table with register offset addr for each + * stats. And start the perioidic stats timer. */ -static void i40iw_hw_stat_init(struct i40iw_dev_pestat *devstat, - u8 fcn_idx, - struct i40iw_hw *hw, bool is_pf) +void i40iw_hw_stats_init(struct i40iw_vsi_pestat *stats, u8 fcn_idx, bool is_pf) { - u32 stat_reg_offset; - u32 stat_index; - struct i40iw_dev_hw_stat_offsets *stat_table = - &devstat->hw_stat_offsets; - struct i40iw_dev_hw_stats *last_rd_stats = &devstat->last_read_hw_stats; - - devstat->hw = hw; + u32 stats_reg_offset; + u32 stats_index; + struct i40iw_dev_hw_stats_offsets *stats_table = + &stats->hw_stats_offsets; + struct i40iw_dev_hw_stats *last_rd_stats = &stats->last_read_hw_stats; if (is_pf) { - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP4RXDISCARD] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXDISCARD] = I40E_GLPES_PFIP4RXDISCARD(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP4RXTRUNC] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXTRUNC] = I40E_GLPES_PFIP4RXTRUNC(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] = I40E_GLPES_PFIP4TXNOROUTE(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP6RXDISCARD] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXDISCARD] = I40E_GLPES_PFIP6RXDISCARD(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP6RXTRUNC] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXTRUNC] = I40E_GLPES_PFIP6RXTRUNC(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP6TXNOROUTE] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6TXNOROUTE] = I40E_GLPES_PFIP6TXNOROUTE(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_TCPRTXSEG] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRTXSEG] = I40E_GLPES_PFTCPRTXSEG(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_TCPRXOPTERR] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXOPTERR] = I40E_GLPES_PFTCPRXOPTERR(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_TCPRXPROTOERR] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXPROTOERR] = I40E_GLPES_PFTCPRXPROTOERR(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXOCTS] = I40E_GLPES_PFIP4RXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXPKTS] = I40E_GLPES_PFIP4RXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXFRAGS] = I40E_GLPES_PFIP4RXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXMCPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXMCPKTS] = I40E_GLPES_PFIP4RXMCPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXOCTS] = I40E_GLPES_PFIP4TXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXPKTS] = I40E_GLPES_PFIP4TXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXFRAGS] = I40E_GLPES_PFIP4TXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXMCPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXMCPKTS] = I40E_GLPES_PFIP4TXMCPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXOCTS] = I40E_GLPES_PFIP6RXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXPKTS] = I40E_GLPES_PFIP6RXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXFRAGS] = I40E_GLPES_PFIP6RXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXMCPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXMCPKTS] = I40E_GLPES_PFIP6RXMCPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXOCTS] = I40E_GLPES_PFIP6TXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = I40E_GLPES_PFIP6TXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = I40E_GLPES_PFIP6TXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXFRAGS] = I40E_GLPES_PFIP6TXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_TCPRXSEGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPRXSEGS] = I40E_GLPES_PFTCPRXSEGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_TCPTXSEG] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPTXSEG] = I40E_GLPES_PFTCPTXSEGLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMARXRDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXRDS] = I40E_GLPES_PFRDMARXRDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMARXSNDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXSNDS] = I40E_GLPES_PFRDMARXSNDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMARXWRS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXWRS] = I40E_GLPES_PFRDMARXWRSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMATXRDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXRDS] = I40E_GLPES_PFRDMATXRDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMATXSNDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXSNDS] = I40E_GLPES_PFRDMATXSNDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMATXWRS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXWRS] = I40E_GLPES_PFRDMATXWRSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMAVBND] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVBND] = I40E_GLPES_PFRDMAVBNDLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMAVINV] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVINV] = I40E_GLPES_PFRDMAVINVLO(fcn_idx); } else { - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP4RXDISCARD] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXDISCARD] = I40E_GLPES_VFIP4RXDISCARD(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP4RXTRUNC] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4RXTRUNC] = I40E_GLPES_VFIP4RXTRUNC(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP4TXNOROUTE] = I40E_GLPES_VFIP4TXNOROUTE(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP6RXDISCARD] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXDISCARD] = I40E_GLPES_VFIP6RXDISCARD(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP6RXTRUNC] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6RXTRUNC] = I40E_GLPES_VFIP6RXTRUNC(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_IP6TXNOROUTE] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_IP6TXNOROUTE] = I40E_GLPES_VFIP6TXNOROUTE(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_TCPRTXSEG] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRTXSEG] = I40E_GLPES_VFTCPRTXSEG(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_TCPRXOPTERR] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXOPTERR] = I40E_GLPES_VFTCPRXOPTERR(fcn_idx); - stat_table->stat_offset_32[I40IW_HW_STAT_INDEX_TCPRXPROTOERR] = + stats_table->stats_offset_32[I40IW_HW_STAT_INDEX_TCPRXPROTOERR] = I40E_GLPES_VFTCPRXPROTOERR(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXOCTS] = I40E_GLPES_VFIP4RXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXPKTS] = I40E_GLPES_VFIP4RXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXFRAGS] = I40E_GLPES_VFIP4RXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4RXMCPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4RXMCPKTS] = I40E_GLPES_VFIP4RXMCPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXOCTS] = I40E_GLPES_VFIP4TXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXPKTS] = I40E_GLPES_VFIP4TXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXFRAGS] = I40E_GLPES_VFIP4TXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP4TXMCPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP4TXMCPKTS] = I40E_GLPES_VFIP4TXMCPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXOCTS] = I40E_GLPES_VFIP6RXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXPKTS] = I40E_GLPES_VFIP6RXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXFRAGS] = I40E_GLPES_VFIP6RXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6RXMCPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6RXMCPKTS] = I40E_GLPES_VFIP6RXMCPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXOCTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXOCTS] = I40E_GLPES_VFIP6TXOCTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = I40E_GLPES_VFIP6TXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXPKTS] = I40E_GLPES_VFIP6TXPKTSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_IP6TXFRAGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_IP6TXFRAGS] = I40E_GLPES_VFIP6TXFRAGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_TCPRXSEGS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPRXSEGS] = I40E_GLPES_VFTCPRXSEGSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_TCPTXSEG] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_TCPTXSEG] = I40E_GLPES_VFTCPTXSEGLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMARXRDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXRDS] = I40E_GLPES_VFRDMARXRDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMARXSNDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXSNDS] = I40E_GLPES_VFRDMARXSNDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMARXWRS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMARXWRS] = I40E_GLPES_VFRDMARXWRSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMATXRDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXRDS] = I40E_GLPES_VFRDMATXRDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMATXSNDS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXSNDS] = I40E_GLPES_VFRDMATXSNDSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMATXWRS] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMATXWRS] = I40E_GLPES_VFRDMATXWRSLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMAVBND] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVBND] = I40E_GLPES_VFRDMAVBNDLO(fcn_idx); - stat_table->stat_offset_64[I40IW_HW_STAT_INDEX_RDMAVINV] = + stats_table->stats_offset_64[I40IW_HW_STAT_INDEX_RDMAVINV] = I40E_GLPES_VFRDMAVINVLO(fcn_idx); } - for (stat_index = 0; stat_index < I40IW_HW_STAT_INDEX_MAX_64; - stat_index++) { - stat_reg_offset = stat_table->stat_offset_64[stat_index]; - last_rd_stats->stat_value_64[stat_index] = - readq(devstat->hw->hw_addr + stat_reg_offset); + for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_64; + stats_index++) { + stats_reg_offset = stats_table->stats_offset_64[stats_index]; + last_rd_stats->stats_value_64[stats_index] = + readq(stats->hw->hw_addr + stats_reg_offset); } - for (stat_index = 0; stat_index < I40IW_HW_STAT_INDEX_MAX_32; - stat_index++) { - stat_reg_offset = stat_table->stat_offset_32[stat_index]; - last_rd_stats->stat_value_32[stat_index] = - i40iw_rd32(devstat->hw, stat_reg_offset); + for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_32; + stats_index++) { + stats_reg_offset = stats_table->stats_offset_32[stats_index]; + last_rd_stats->stats_value_32[stats_index] = + i40iw_rd32(stats->hw, stats_reg_offset); } } /** - * i40iw_hw_stat_read_32 - Read 32-bit HW stat counters and accommodates for roll-overs. - * @devstat: pestat struct - * @index: index in HW stat table which contains offset reg-addr - * @value: hw stat value + * i40iw_hw_stats_read_32 - Read 32-bit HW stats counters and accommodates for roll-overs. + * @stat: pestat struct + * @index: index in HW stats table which contains offset reg-addr + * @value: hw stats value */ -static void i40iw_hw_stat_read_32(struct i40iw_dev_pestat *devstat, - enum i40iw_hw_stat_index_32b index, - u64 *value) +void i40iw_hw_stats_read_32(struct i40iw_vsi_pestat *stats, + enum i40iw_hw_stats_index_32b index, + u64 *value) { - struct i40iw_dev_hw_stat_offsets *stat_table = - &devstat->hw_stat_offsets; - struct i40iw_dev_hw_stats *last_rd_stats = &devstat->last_read_hw_stats; - struct i40iw_dev_hw_stats *hw_stats = &devstat->hw_stats; - u64 new_stat_value = 0; - u32 stat_reg_offset = stat_table->stat_offset_32[index]; - - new_stat_value = i40iw_rd32(devstat->hw, stat_reg_offset); + struct i40iw_dev_hw_stats_offsets *stats_table = + &stats->hw_stats_offsets; + struct i40iw_dev_hw_stats *last_rd_stats = &stats->last_read_hw_stats; + struct i40iw_dev_hw_stats *hw_stats = &stats->hw_stats; + u64 new_stats_value = 0; + u32 stats_reg_offset = stats_table->stats_offset_32[index]; + + new_stats_value = i40iw_rd32(stats->hw, stats_reg_offset); /*roll-over case */ - if (new_stat_value < last_rd_stats->stat_value_32[index]) - hw_stats->stat_value_32[index] += new_stat_value; + if (new_stats_value < last_rd_stats->stats_value_32[index]) + hw_stats->stats_value_32[index] += new_stats_value; else - hw_stats->stat_value_32[index] += - new_stat_value - last_rd_stats->stat_value_32[index]; - last_rd_stats->stat_value_32[index] = new_stat_value; - *value = hw_stats->stat_value_32[index]; + hw_stats->stats_value_32[index] += + new_stats_value - last_rd_stats->stats_value_32[index]; + last_rd_stats->stats_value_32[index] = new_stats_value; + *value = hw_stats->stats_value_32[index]; } /** - * i40iw_hw_stat_read_64 - Read HW stat counters (greater than 32-bit) and accommodates for roll-overs. - * @devstat: pestat struct - * @index: index in HW stat table which contains offset reg-addr - * @value: hw stat value + * i40iw_hw_stats_read_64 - Read HW stats counters (greater than 32-bit) and accommodates for roll-overs. + * @stats: pestat struct + * @index: index in HW stats table which contains offset reg-addr + * @value: hw stats value */ -static void i40iw_hw_stat_read_64(struct i40iw_dev_pestat *devstat, - enum i40iw_hw_stat_index_64b index, - u64 *value) +void i40iw_hw_stats_read_64(struct i40iw_vsi_pestat *stats, + enum i40iw_hw_stats_index_64b index, + u64 *value) { - struct i40iw_dev_hw_stat_offsets *stat_table = - &devstat->hw_stat_offsets; - struct i40iw_dev_hw_stats *last_rd_stats = &devstat->last_read_hw_stats; - struct i40iw_dev_hw_stats *hw_stats = &devstat->hw_stats; - u64 new_stat_value = 0; - u32 stat_reg_offset = stat_table->stat_offset_64[index]; - - new_stat_value = readq(devstat->hw->hw_addr + stat_reg_offset); + struct i40iw_dev_hw_stats_offsets *stats_table = + &stats->hw_stats_offsets; + struct i40iw_dev_hw_stats *last_rd_stats = &stats->last_read_hw_stats; + struct i40iw_dev_hw_stats *hw_stats = &stats->hw_stats; + u64 new_stats_value = 0; + u32 stats_reg_offset = stats_table->stats_offset_64[index]; + + new_stats_value = readq(stats->hw->hw_addr + stats_reg_offset); /*roll-over case */ - if (new_stat_value < last_rd_stats->stat_value_64[index]) - hw_stats->stat_value_64[index] += new_stat_value; + if (new_stats_value < last_rd_stats->stats_value_64[index]) + hw_stats->stats_value_64[index] += new_stats_value; else - hw_stats->stat_value_64[index] += - new_stat_value - last_rd_stats->stat_value_64[index]; - last_rd_stats->stat_value_64[index] = new_stat_value; - *value = hw_stats->stat_value_64[index]; + hw_stats->stats_value_64[index] += + new_stats_value - last_rd_stats->stats_value_64[index]; + last_rd_stats->stats_value_64[index] = new_stats_value; + *value = hw_stats->stats_value_64[index]; } /** - * i40iw_hw_stat_read_all - read all HW stat counters - * @devstat: pestat struct - * @stat_values: hw stats structure + * i40iw_hw_stats_read_all - read all HW stat counters + * @stats: pestat struct + * @stats_values: hw stats structure * * Read all the HW stat counters and populates hw_stats structure - * of passed-in dev's pestat as well as copy created in stat_values. + * of passed-in vsi's pestat as well as copy created in stat_values. */ -static void i40iw_hw_stat_read_all(struct i40iw_dev_pestat *devstat, - struct i40iw_dev_hw_stats *stat_values) +void i40iw_hw_stats_read_all(struct i40iw_vsi_pestat *stats, + struct i40iw_dev_hw_stats *stats_values) { - u32 stat_index; - - for (stat_index = 0; stat_index < I40IW_HW_STAT_INDEX_MAX_32; - stat_index++) - i40iw_hw_stat_read_32(devstat, stat_index, - &stat_values->stat_value_32[stat_index]); - for (stat_index = 0; stat_index < I40IW_HW_STAT_INDEX_MAX_64; - stat_index++) - i40iw_hw_stat_read_64(devstat, stat_index, - &stat_values->stat_value_64[stat_index]); + u32 stats_index; + unsigned long flags; + + spin_lock_irqsave(&stats->lock, flags); + + for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_32; + stats_index++) + i40iw_hw_stats_read_32(stats, stats_index, + &stats_values->stats_value_32[stats_index]); + for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_64; + stats_index++) + i40iw_hw_stats_read_64(stats, stats_index, + &stats_values->stats_value_64[stats_index]); + spin_unlock_irqrestore(&stats->lock, flags); } /** - * i40iw_hw_stat_refresh_all - Update all HW stat structs - * @devstat: pestat struct - * @stat_values: hw stats structure + * i40iw_hw_stats_refresh_all - Update all HW stats structs + * @stats: pestat struct * - * Read all the HW stat counters to refresh values in hw_stats structure + * Read all the HW stats counters to refresh values in hw_stats structure * of passed-in dev's pestat */ -static void i40iw_hw_stat_refresh_all(struct i40iw_dev_pestat *devstat) +void i40iw_hw_stats_refresh_all(struct i40iw_vsi_pestat *stats) +{ + u64 stats_value; + u32 stats_index; + unsigned long flags; + + spin_lock_irqsave(&stats->lock, flags); + + for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_32; + stats_index++) + i40iw_hw_stats_read_32(stats, stats_index, &stats_value); + for (stats_index = 0; stats_index < I40IW_HW_STAT_INDEX_MAX_64; + stats_index++) + i40iw_hw_stats_read_64(stats, stats_index, &stats_value); + spin_unlock_irqrestore(&stats->lock, flags); +} + +/** + * i40iw_get_fcn_id - Return the function id + * @dev: pointer to the device + */ +static u8 i40iw_get_fcn_id(struct i40iw_sc_dev *dev) +{ + u8 fcn_id = I40IW_INVALID_FCN_ID; + u8 i; + + for (i = I40IW_FIRST_NON_PF_STAT; i < I40IW_MAX_STATS_COUNT; i++) + if (!dev->fcn_id_array[i]) { + fcn_id = i; + dev->fcn_id_array[i] = true; + break; + } + return fcn_id; +} + +/** + * i40iw_vsi_stats_init - Initialize the vsi statistics + * @vsi: pointer to the vsi structure + * @info: The info structure used for initialization + */ +enum i40iw_status_code i40iw_vsi_stats_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_stats_info *info) { - u64 stat_value; - u32 stat_index; - - for (stat_index = 0; stat_index < I40IW_HW_STAT_INDEX_MAX_32; - stat_index++) - i40iw_hw_stat_read_32(devstat, stat_index, &stat_value); - for (stat_index = 0; stat_index < I40IW_HW_STAT_INDEX_MAX_64; - stat_index++) - i40iw_hw_stat_read_64(devstat, stat_index, &stat_value); + u8 fcn_id = info->fcn_id; + + if (info->alloc_fcn_id) + fcn_id = i40iw_get_fcn_id(vsi->dev); + + if (fcn_id == I40IW_INVALID_FCN_ID) + return I40IW_ERR_NOT_READY; + + vsi->pestat = info->pestat; + vsi->pestat->hw = vsi->dev->hw; + + if (info->stats_initialize) { + i40iw_hw_stats_init(vsi->pestat, fcn_id, true); + spin_lock_init(&vsi->pestat->lock); + i40iw_hw_stats_start_timer(vsi); + } + vsi->stats_fcn_id_alloc = info->alloc_fcn_id; + vsi->fcn_id = fcn_id; + return I40IW_SUCCESS; +} + +/** + * i40iw_vsi_stats_free - Free the vsi stats + * @vsi: pointer to the vsi structure + */ +void i40iw_vsi_stats_free(struct i40iw_sc_vsi *vsi) +{ + u8 fcn_id = vsi->fcn_id; + + if ((vsi->stats_fcn_id_alloc) && (fcn_id != I40IW_INVALID_FCN_ID)) + vsi->dev->fcn_id_array[fcn_id] = false; + i40iw_hw_stats_stop_timer(vsi); } static struct i40iw_cqp_ops iw_cqp_ops = { @@ -4837,23 +4943,6 @@ static struct i40iw_hmc_ops iw_hmc_ops = { NULL }; -static const struct i40iw_device_pestat_ops iw_device_pestat_ops = { - i40iw_hw_stat_init, - i40iw_hw_stat_read_32, - i40iw_hw_stat_read_64, - i40iw_hw_stat_read_all, - i40iw_hw_stat_refresh_all -}; - -/** - * i40iw_device_init_pestat - Initialize the pestat structure - * @dev: pestat struct - */ -void i40iw_device_init_pestat(struct i40iw_dev_pestat *devstat) -{ - devstat->ops = iw_device_pestat_ops; -} - /** * i40iw_device_init - Initialize IWARP device * @dev: IWARP device pointer @@ -4867,7 +4956,6 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, u16 hmc_fcn = 0; enum i40iw_status_code ret_code = 0; u8 db_size; - int i; spin_lock_init(&dev->cqp_lock); INIT_LIST_HEAD(&dev->cqp_cmd_head); /* for the cqp commands backlog. */ @@ -4876,15 +4964,7 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, dev->debug_mask = info->debug_mask; - i40iw_device_init_pestat(&dev->dev_pestat); dev->hmc_fn_id = info->hmc_fn_id; - i40iw_fill_qos_list(info->l2params.qs_handle_list); - for (i = 0; i < I40IW_MAX_USER_PRIORITY; i++) { - dev->qos[i].qs_handle = info->l2params.qs_handle_list[i]; - i40iw_debug(dev, I40IW_DEBUG_DCB, "qset[%d]: %d\n", i, dev->qos[i].qs_handle); - spin_lock_init(&dev->qos[i].lock); - INIT_LIST_HEAD(&dev->qos[i].qplist); - } dev->exception_lan_queue = info->exception_lan_queue; dev->is_pf = info->is_pf; @@ -4897,15 +4977,10 @@ enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, dev->hw = info->hw; dev->hw->hw_addr = info->bar0; - val = i40iw_rd32(dev->hw, I40E_GLPCI_DREVID); - dev->hw_rev = (u8)RS_32(val, I40E_GLPCI_DREVID_DEFAULT_REVID); - if (dev->is_pf) { - dev->dev_pestat.ops.iw_hw_stat_init(&dev->dev_pestat, - dev->hmc_fn_id, dev->hw, true); - spin_lock_init(&dev->dev_pestat.stats_lock); - /*start the periodic stats_timer */ - i40iw_hw_stats_start_timer(dev); + val = i40iw_rd32(dev->hw, I40E_GLPCI_DREVID); + dev->hw_rev = (u8)RS_32(val, I40E_GLPCI_DREVID_DEFAULT_REVID); + val = i40iw_rd32(dev->hw, I40E_GLPCI_LBARCTRL); db_size = (u8)RS_32(val, I40E_GLPCI_LBARCTRL_PE_DB_SIZE); if ((db_size != I40IW_PE_DB_SIZE_4M) && diff --git a/drivers/infiniband/hw/i40iw/i40iw_d.h b/drivers/infiniband/hw/i40iw/i40iw_d.h index 1bd4badb26d3..a39ac12b6a7e 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_d.h +++ b/drivers/infiniband/hw/i40iw/i40iw_d.h @@ -69,6 +69,9 @@ #define I40IW_STAG_TYPE_NONSHARED 1 #define I40IW_MAX_USER_PRIORITY 8 +#define I40IW_MAX_STATS_COUNT 16 +#define I40IW_FIRST_NON_PF_STAT 4 + #define LS_64_1(val, bits) ((u64)(uintptr_t)val << bits) #define RS_64_1(val, bits) ((u64)(uintptr_t)val >> bits) @@ -1203,8 +1206,11 @@ #define I40IWQPC_RXCQNUM_SHIFT 32 #define I40IWQPC_RXCQNUM_MASK (0x1ffffULL << I40IWQPC_RXCQNUM_SHIFT) -#define I40IWQPC_Q2ADDR_SHIFT I40IW_CQPHC_QPCTX_SHIFT -#define I40IWQPC_Q2ADDR_MASK I40IW_CQPHC_QPCTX_MASK +#define I40IWQPC_STAT_INDEX_SHIFT 0 +#define I40IWQPC_STAT_INDEX_MASK (0x1fULL << I40IWQPC_STAT_INDEX_SHIFT) + +#define I40IWQPC_Q2ADDR_SHIFT 0 +#define I40IWQPC_Q2ADDR_MASK (0xffffffffffffff00ULL << I40IWQPC_Q2ADDR_SHIFT) #define I40IWQPC_LASTBYTESENT_SHIFT 0 #define I40IWQPC_LASTBYTESENT_MASK (0xffUL << I40IWQPC_LASTBYTESENT_SHIFT) @@ -1236,11 +1242,8 @@ #define I40IWQPC_PRIVEN_SHIFT 25 #define I40IWQPC_PRIVEN_MASK (1UL << I40IWQPC_PRIVEN_SHIFT) -#define I40IWQPC_LSMMPRESENT_SHIFT 26 -#define I40IWQPC_LSMMPRESENT_MASK (1UL << I40IWQPC_LSMMPRESENT_SHIFT) - -#define I40IWQPC_ADJUSTFORLSMM_SHIFT 27 -#define I40IWQPC_ADJUSTFORLSMM_MASK (1UL << I40IWQPC_ADJUSTFORLSMM_SHIFT) +#define I40IWQPC_USESTATSINSTANCE_SHIFT 26 +#define I40IWQPC_USESTATSINSTANCE_MASK (1UL << I40IWQPC_USESTATSINSTANCE_SHIFT) #define I40IWQPC_IWARPMODE_SHIFT 28 #define I40IWQPC_IWARPMODE_MASK (1UL << I40IWQPC_IWARPMODE_SHIFT) @@ -1717,6 +1720,8 @@ enum i40iw_alignment { #define OP_MANAGE_VF_PBLE_BP 28 #define OP_QUERY_FPM_VALUES 29 #define OP_COMMIT_FPM_VALUES 30 -#define OP_SIZE_CQP_STAT_ARRAY 31 +#define OP_REQUESTED_COMMANDS 31 +#define OP_COMPLETED_COMMANDS 32 +#define OP_SIZE_CQP_STAT_ARRAY 33 #endif diff --git a/drivers/infiniband/hw/i40iw/i40iw_hw.c b/drivers/infiniband/hw/i40iw/i40iw_hw.c index 4394a6713bdf..476867a3f584 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_hw.c +++ b/drivers/infiniband/hw/i40iw/i40iw_hw.c @@ -542,6 +542,7 @@ enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev, { struct i40iw_qhash_table_info *info; struct i40iw_sc_dev *dev = &iwdev->sc_dev; + struct i40iw_sc_vsi *vsi = &iwdev->vsi; enum i40iw_status_code status; struct i40iw_cqp *iwcqp = &iwdev->cqp; struct i40iw_cqp_request *cqp_request; @@ -554,6 +555,7 @@ enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev, info = &cqp_info->in.u.manage_qhash_table_entry.info; memset(info, 0, sizeof(*info)); + info->vsi = &iwdev->vsi; info->manage = mtype; info->entry_type = etype; if (cminfo->vlan_id != 0xFFFF) { @@ -566,7 +568,7 @@ enum i40iw_status_code i40iw_manage_qhash(struct i40iw_device *iwdev, info->ipv4_valid = cminfo->ipv4; info->user_pri = cminfo->user_pri; ether_addr_copy(info->mac_addr, iwdev->netdev->dev_addr); - info->qp_num = cpu_to_le32(dev->ilq->qp_id); + info->qp_num = cpu_to_le32(vsi->ilq->qp_id); info->dest_port = cpu_to_le16(cminfo->loc_port); info->dest_ip[0] = cpu_to_le32(cminfo->loc_addr[0]); info->dest_ip[1] = cpu_to_le32(cminfo->loc_addr[1]); diff --git a/drivers/infiniband/hw/i40iw/i40iw_main.c b/drivers/infiniband/hw/i40iw/i40iw_main.c index cf9d288a79b3..2bdb8b0c8c88 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_main.c +++ b/drivers/infiniband/hw/i40iw/i40iw_main.c @@ -932,6 +932,7 @@ static enum i40iw_status_code i40iw_initialize_ilq(struct i40iw_device *iwdev) struct i40iw_puda_rsrc_info info; enum i40iw_status_code status; + memset(&info, 0, sizeof(info)); info.type = I40IW_PUDA_RSRC_TYPE_ILQ; info.cq_id = 1; info.qp_id = 0; @@ -941,10 +942,9 @@ static enum i40iw_status_code i40iw_initialize_ilq(struct i40iw_device *iwdev) info.rq_size = 8192; info.buf_size = 1024; info.tx_buf_cnt = 16384; - info.mss = iwdev->sc_dev.mss; info.receive = i40iw_receive_ilq; info.xmit_complete = i40iw_free_sqbuf; - status = i40iw_puda_create_rsrc(&iwdev->sc_dev, &info); + status = i40iw_puda_create_rsrc(&iwdev->vsi, &info); if (status) i40iw_pr_err("ilq create fail\n"); return status; @@ -961,6 +961,7 @@ static enum i40iw_status_code i40iw_initialize_ieq(struct i40iw_device *iwdev) struct i40iw_puda_rsrc_info info; enum i40iw_status_code status; + memset(&info, 0, sizeof(info)); info.type = I40IW_PUDA_RSRC_TYPE_IEQ; info.cq_id = 2; info.qp_id = iwdev->sc_dev.exception_lan_queue; @@ -969,9 +970,8 @@ static enum i40iw_status_code i40iw_initialize_ieq(struct i40iw_device *iwdev) info.sq_size = 8192; info.rq_size = 8192; info.buf_size = 2048; - info.mss = iwdev->sc_dev.mss; info.tx_buf_cnt = 16384; - status = i40iw_puda_create_rsrc(&iwdev->sc_dev, &info); + status = i40iw_puda_create_rsrc(&iwdev->vsi, &info); if (status) i40iw_pr_err("ieq create fail\n"); return status; @@ -1296,12 +1296,16 @@ static enum i40iw_status_code i40iw_initialize_dev(struct i40iw_device *iwdev, enum i40iw_status_code status; struct i40iw_sc_dev *dev = &iwdev->sc_dev; struct i40iw_device_init_info info; + struct i40iw_vsi_init_info vsi_info; struct i40iw_dma_mem mem; + struct i40iw_l2params l2params; u32 size; + struct i40iw_vsi_stats_info stats_info; u16 last_qset = I40IW_NO_QSET; u16 qset; u32 i; + memset(&l2params, 0, sizeof(l2params)); memset(&info, 0, sizeof(info)); size = sizeof(struct i40iw_hmc_pble_rsrc) + sizeof(struct i40iw_hmc_info) + (sizeof(struct i40iw_hmc_obj_info) * I40IW_HMC_IW_MAX); @@ -1330,16 +1334,17 @@ static enum i40iw_status_code i40iw_initialize_dev(struct i40iw_device *iwdev, info.bar0 = ldev->hw_addr; info.hw = &iwdev->hw; info.debug_mask = debug; - info.l2params.mss = + l2params.mss = (ldev->params.mtu) ? ldev->params.mtu - I40IW_MTU_TO_MSS : I40IW_DEFAULT_MSS; for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) { qset = ldev->params.qos.prio_qos[i].qs_handle; - info.l2params.qs_handle_list[i] = qset; + l2params.qs_handle_list[i] = qset; if (last_qset == I40IW_NO_QSET) last_qset = qset; else if ((qset != last_qset) && (qset != I40IW_NO_QSET)) iwdev->dcb = true; } + i40iw_pr_info("DCB is set/clear = %d\n", iwdev->dcb); info.exception_lan_queue = 1; info.vchnl_send = i40iw_virtchnl_send; status = i40iw_device_init(&iwdev->sc_dev, &info); @@ -1348,6 +1353,20 @@ exit: kfree(iwdev->hmc_info_mem); iwdev->hmc_info_mem = NULL; } + memset(&vsi_info, 0, sizeof(vsi_info)); + vsi_info.dev = &iwdev->sc_dev; + vsi_info.back_vsi = (void *)iwdev; + vsi_info.params = &l2params; + i40iw_sc_vsi_init(&iwdev->vsi, &vsi_info); + + if (dev->is_pf) { + memset(&stats_info, 0, sizeof(stats_info)); + stats_info.fcn_id = ldev->fid; + stats_info.pestat = kzalloc(sizeof(*stats_info.pestat), GFP_KERNEL); + stats_info.stats_initialize = true; + if (stats_info.pestat) + i40iw_vsi_stats_init(&iwdev->vsi, &stats_info); + } return status; } @@ -1457,10 +1476,10 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset) i40iw_destroy_aeq(iwdev, reset); /* fallthrough */ case IEQ_CREATED: - i40iw_puda_dele_resources(dev, I40IW_PUDA_RSRC_TYPE_IEQ, reset); + i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_IEQ, reset); /* fallthrough */ case ILQ_CREATED: - i40iw_puda_dele_resources(dev, I40IW_PUDA_RSRC_TYPE_ILQ, reset); + i40iw_puda_dele_resources(&iwdev->vsi, I40IW_PUDA_RSRC_TYPE_ILQ, reset); /* fallthrough */ case CCQ_CREATED: i40iw_destroy_ccq(iwdev, reset); @@ -1476,9 +1495,10 @@ static void i40iw_deinit_device(struct i40iw_device *iwdev, bool reset) /* fallthrough */ case INITIAL_STATE: i40iw_cleanup_cm_core(&iwdev->cm_core); - if (dev->is_pf) - i40iw_hw_stats_del_timer(dev); - + if (iwdev->vsi.pestat) { + i40iw_vsi_stats_free(&iwdev->vsi); + kfree(iwdev->vsi.pestat); + } i40iw_del_init_mem(iwdev); break; case INVALID_STATE: @@ -1523,7 +1543,6 @@ static enum i40iw_status_code i40iw_setup_init_state(struct i40iw_handler *hdl, iwdev->max_enabled_vfs = iwdev->max_rdma_vfs; iwdev->netdev = ldev->netdev; hdl->client = client; - iwdev->mss = (!ldev->params.mtu) ? I40IW_DEFAULT_MSS : ldev->params.mtu - I40IW_MTU_TO_MSS; if (!ldev->ftype) iwdev->db_start = pci_resource_start(ldev->pcidev, 0) + I40IW_DB_ADDR_OFFSET; else @@ -1683,7 +1702,7 @@ static void i40iw_l2params_worker(struct work_struct *work) container_of(work, struct l2params_work, work); struct i40iw_device *iwdev = dwork->iwdev; - i40iw_change_l2params(&iwdev->sc_dev, &dwork->l2params); + i40iw_change_l2params(&iwdev->vsi, &dwork->l2params); atomic_dec(&iwdev->params_busy); kfree(work); } @@ -1724,7 +1743,7 @@ static void i40iw_l2param_change(struct i40e_info *ldev, struct i40e_client *cli for (i = 0; i < I40E_CLIENT_MAX_USER_PRIORITY; i++) l2params->qs_handle_list[i] = params->qos.prio_qos[i].qs_handle; - l2params->mss = (params->mtu) ? params->mtu - I40IW_MTU_TO_MSS : iwdev->mss; + l2params->mss = (params->mtu) ? params->mtu - I40IW_MTU_TO_MSS : iwdev->vsi.mss; INIT_WORK(&work->work, i40iw_l2params_worker); queue_work(iwdev->param_wq, &work->work); @@ -1773,21 +1792,23 @@ static void i40iw_vf_reset(struct i40e_info *ldev, struct i40e_client *client, u struct i40iw_vfdev *tmp_vfdev; unsigned int i; unsigned long flags; + struct i40iw_device *iwdev; hdl = i40iw_find_i40e_handler(ldev); if (!hdl) return; dev = &hdl->device.sc_dev; + iwdev = (struct i40iw_device *)dev->back_dev; for (i = 0; i < I40IW_MAX_PE_ENABLED_VF_COUNT; i++) { if (!dev->vf_dev[i] || (dev->vf_dev[i]->vf_id != vf_id)) continue; /* free all resources allocated on behalf of vf */ tmp_vfdev = dev->vf_dev[i]; - spin_lock_irqsave(&dev->dev_pestat.stats_lock, flags); + spin_lock_irqsave(&iwdev->vsi.pestat->lock, flags); dev->vf_dev[i] = NULL; - spin_unlock_irqrestore(&dev->dev_pestat.stats_lock, flags); + spin_unlock_irqrestore(&iwdev->vsi.pestat->lock, flags); i40iw_del_hmc_objects(dev, &tmp_vfdev->hmc_info, false, false); /* remove vf hmc function */ memset(&hmc_fcn_info, 0, sizeof(hmc_fcn_info)); diff --git a/drivers/infiniband/hw/i40iw/i40iw_osdep.h b/drivers/infiniband/hw/i40iw/i40iw_osdep.h index a6b18cd42e67..aa66c1c63dfa 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_osdep.h +++ b/drivers/infiniband/hw/i40iw/i40iw_osdep.h @@ -209,9 +209,9 @@ void i40iw_terminate_del_timer(struct i40iw_sc_qp *qp); enum i40iw_status_code i40iw_hw_manage_vf_pble_bp(struct i40iw_device *iwdev, struct i40iw_manage_vf_pble_info *info, bool wait); -struct i40iw_dev_pestat; -void i40iw_hw_stats_start_timer(struct i40iw_sc_dev *); -void i40iw_hw_stats_del_timer(struct i40iw_sc_dev *); +struct i40iw_sc_vsi; +void i40iw_hw_stats_start_timer(struct i40iw_sc_vsi *vsi); +void i40iw_hw_stats_stop_timer(struct i40iw_sc_vsi *vsi); #define i40iw_mmiowb() mmiowb() void i40iw_wr32(struct i40iw_hw *hw, u32 reg, u32 value); u32 i40iw_rd32(struct i40iw_hw *hw, u32 reg); diff --git a/drivers/infiniband/hw/i40iw/i40iw_p.h b/drivers/infiniband/hw/i40iw/i40iw_p.h index 2a4bd3233b41..28a92fee0822 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_p.h +++ b/drivers/infiniband/hw/i40iw/i40iw_p.h @@ -47,8 +47,6 @@ void i40iw_debug_buf(struct i40iw_sc_dev *dev, enum i40iw_debug_flag mask, enum i40iw_status_code i40iw_device_init(struct i40iw_sc_dev *dev, struct i40iw_device_init_info *info); -void i40iw_device_init_pestat(struct i40iw_dev_pestat *devstat); - void i40iw_sc_cqp_post_sq(struct i40iw_sc_cqp *cqp); u64 *i40iw_sc_cqp_get_next_send_wqe(struct i40iw_sc_cqp *cqp, u64 scratch); @@ -64,9 +62,24 @@ enum i40iw_status_code i40iw_sc_init_iw_hmc(struct i40iw_sc_dev *dev, enum i40iw_status_code i40iw_pf_init_vfhmc(struct i40iw_sc_dev *dev, u8 vf_hmc_fn_id, u32 *vf_cnt_array); -/* cqp misc functions */ -void i40iw_change_l2params(struct i40iw_sc_dev *dev, struct i40iw_l2params *l2params); -void i40iw_qp_add_qos(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); +/* stats functions */ +void i40iw_hw_stats_refresh_all(struct i40iw_vsi_pestat *stats); +void i40iw_hw_stats_read_all(struct i40iw_vsi_pestat *stats, struct i40iw_dev_hw_stats *stats_values); +void i40iw_hw_stats_read_32(struct i40iw_vsi_pestat *stats, + enum i40iw_hw_stats_index_32b index, + u64 *value); +void i40iw_hw_stats_read_64(struct i40iw_vsi_pestat *stats, + enum i40iw_hw_stats_index_64b index, + u64 *value); +void i40iw_hw_stats_init(struct i40iw_vsi_pestat *stats, u8 index, bool is_pf); + +/* vsi misc functions */ +enum i40iw_status_code i40iw_vsi_stats_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_stats_info *info); +void i40iw_vsi_stats_free(struct i40iw_sc_vsi *vsi); +void i40iw_sc_vsi_init(struct i40iw_sc_vsi *vsi, struct i40iw_vsi_init_info *info); + +void i40iw_change_l2params(struct i40iw_sc_vsi *vsi, struct i40iw_l2params *l2params); +void i40iw_qp_add_qos(struct i40iw_sc_qp *qp); void i40iw_terminate_send_fin(struct i40iw_sc_qp *qp); diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c index c3d28baf8e3a..449ba8c81ce7 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.c +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c @@ -42,12 +42,13 @@ #include "i40iw_p.h" #include "i40iw_puda.h" -static void i40iw_ieq_receive(struct i40iw_sc_dev *dev, +static void i40iw_ieq_receive(struct i40iw_sc_vsi *vsi, struct i40iw_puda_buf *buf); -static void i40iw_ieq_tx_compl(struct i40iw_sc_dev *dev, void *sqwrid); +static void i40iw_ieq_tx_compl(struct i40iw_sc_vsi *vsi, void *sqwrid); static void i40iw_ilq_putback_rcvbuf(struct i40iw_sc_qp *qp, u32 wqe_idx); static enum i40iw_status_code i40iw_puda_replenish_rq(struct i40iw_puda_rsrc *rsrc, bool initial); +static void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp); /** * i40iw_puda_get_listbuf - get buffer from puda list * @list: list to use for buffers (ILQ or IEQ) @@ -292,7 +293,7 @@ enum i40iw_status_code i40iw_puda_poll_completion(struct i40iw_sc_dev *dev, unsigned long flags; if ((cq_type == I40IW_CQ_TYPE_ILQ) || (cq_type == I40IW_CQ_TYPE_IEQ)) { - rsrc = (cq_type == I40IW_CQ_TYPE_ILQ) ? dev->ilq : dev->ieq; + rsrc = (cq_type == I40IW_CQ_TYPE_ILQ) ? cq->vsi->ilq : cq->vsi->ieq; } else { i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s qp_type error\n", __func__); return I40IW_ERR_BAD_PTR; @@ -335,7 +336,7 @@ enum i40iw_status_code i40iw_puda_poll_completion(struct i40iw_sc_dev *dev, rsrc->stats_pkt_rcvd++; rsrc->compl_rxwqe_idx = info.wqe_idx; i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s RQ completion\n", __func__); - rsrc->receive(rsrc->dev, buf); + rsrc->receive(rsrc->vsi, buf); if (cq_type == I40IW_CQ_TYPE_ILQ) i40iw_ilq_putback_rcvbuf(&rsrc->qp, info.wqe_idx); else @@ -345,12 +346,12 @@ enum i40iw_status_code i40iw_puda_poll_completion(struct i40iw_sc_dev *dev, i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s SQ completion\n", __func__); sqwrid = (void *)(uintptr_t)qp->sq_wrtrk_array[info.wqe_idx].wrid; I40IW_RING_SET_TAIL(qp->sq_ring, info.wqe_idx); - rsrc->xmit_complete(rsrc->dev, sqwrid); + rsrc->xmit_complete(rsrc->vsi, sqwrid); spin_lock_irqsave(&rsrc->bufpool_lock, flags); rsrc->tx_wqe_avail_cnt++; spin_unlock_irqrestore(&rsrc->bufpool_lock, flags); - if (!list_empty(&dev->ilq->txpend)) - i40iw_puda_send_buf(dev->ilq, NULL); + if (!list_empty(&rsrc->vsi->ilq->txpend)) + i40iw_puda_send_buf(rsrc->vsi->ilq, NULL); } done: @@ -513,10 +514,8 @@ static void i40iw_puda_qp_setctx(struct i40iw_puda_rsrc *rsrc) * i40iw_puda_qp_wqe - setup wqe for qp create * @rsrc: resource for qp */ -static enum i40iw_status_code i40iw_puda_qp_wqe(struct i40iw_puda_rsrc *rsrc) +static enum i40iw_status_code i40iw_puda_qp_wqe(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) { - struct i40iw_sc_qp *qp = &rsrc->qp; - struct i40iw_sc_dev *dev = rsrc->dev; struct i40iw_sc_cqp *cqp; u64 *wqe; u64 header; @@ -582,6 +581,7 @@ static enum i40iw_status_code i40iw_puda_qp_create(struct i40iw_puda_rsrc *rsrc) qp->back_qp = (void *)rsrc; qp->sq_pa = mem->pa; qp->rq_pa = qp->sq_pa + sq_size; + qp->vsi = rsrc->vsi; ukqp->sq_base = mem->va; ukqp->rq_base = &ukqp->sq_base[rsrc->sq_size]; ukqp->shadow_area = ukqp->rq_base[rsrc->rq_size].elem; @@ -609,14 +609,61 @@ static enum i40iw_status_code i40iw_puda_qp_create(struct i40iw_puda_rsrc *rsrc) I40E_VFPE_WQEALLOC1); qp->user_pri = 0; - i40iw_qp_add_qos(rsrc->dev, qp); + i40iw_qp_add_qos(qp); i40iw_puda_qp_setctx(rsrc); - ret = i40iw_puda_qp_wqe(rsrc); + if (rsrc->ceq_valid) + ret = i40iw_cqp_qp_create_cmd(rsrc->dev, qp); + else + ret = i40iw_puda_qp_wqe(rsrc->dev, qp); if (ret) i40iw_free_dma_mem(rsrc->dev->hw, &rsrc->qpmem); return ret; } +/** + * i40iw_puda_cq_wqe - setup wqe for cq create + * @rsrc: resource for cq + */ +static enum i40iw_status_code i40iw_puda_cq_wqe(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq) +{ + u64 *wqe; + struct i40iw_sc_cqp *cqp; + u64 header; + struct i40iw_ccq_cqe_info compl_info; + enum i40iw_status_code status = 0; + + cqp = dev->cqp; + wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, 0); + if (!wqe) + return I40IW_ERR_RING_FULL; + + set_64bit_val(wqe, 0, cq->cq_uk.cq_size); + set_64bit_val(wqe, 8, RS_64_1(cq, 1)); + set_64bit_val(wqe, 16, + LS_64(cq->shadow_read_threshold, + I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD)); + set_64bit_val(wqe, 32, cq->cq_pa); + + set_64bit_val(wqe, 40, cq->shadow_area_pa); + + header = cq->cq_uk.cq_id | + LS_64(I40IW_CQP_OP_CREATE_CQ, I40IW_CQPSQ_OPCODE) | + LS_64(1, I40IW_CQPSQ_CQ_CHKOVERFLOW) | + LS_64(1, I40IW_CQPSQ_CQ_ENCEQEMASK) | + LS_64(1, I40IW_CQPSQ_CQ_CEQIDVALID) | + LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID); + set_64bit_val(wqe, 24, header); + + i40iw_debug_buf(dev, I40IW_DEBUG_PUDA, "PUDA CQE", + wqe, I40IW_CQP_WQE_SIZE * 8); + + i40iw_sc_cqp_post_sq(dev->cqp); + status = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp, + I40IW_CQP_OP_CREATE_CQ, + &compl_info); + return status; +} + /** * i40iw_puda_cq_create - create cq for resource * @rsrc: resource for which cq to create @@ -625,18 +672,13 @@ static enum i40iw_status_code i40iw_puda_cq_create(struct i40iw_puda_rsrc *rsrc) { struct i40iw_sc_dev *dev = rsrc->dev; struct i40iw_sc_cq *cq = &rsrc->cq; - u64 *wqe; - struct i40iw_sc_cqp *cqp; - u64 header; enum i40iw_status_code ret = 0; u32 tsize, cqsize; - u32 shadow_read_threshold = 128; struct i40iw_dma_mem *mem; - struct i40iw_ccq_cqe_info compl_info; struct i40iw_cq_init_info info; struct i40iw_cq_uk_init_info *init_info = &info.cq_uk_init_info; - cq->back_cq = (void *)rsrc; + cq->vsi = rsrc->vsi; cqsize = rsrc->cq_size * (sizeof(struct i40iw_cqe)); tsize = cqsize + sizeof(struct i40iw_cq_shadow_area); ret = i40iw_allocate_dma_mem(dev->hw, &rsrc->cqmem, tsize, @@ -657,43 +699,84 @@ static enum i40iw_status_code i40iw_puda_cq_create(struct i40iw_puda_rsrc *rsrc) init_info->shadow_area = (u64 *)((u8 *)mem->va + cqsize); init_info->cq_size = rsrc->cq_size; init_info->cq_id = rsrc->cq_id; + info.ceqe_mask = true; + info.ceq_id_valid = true; ret = dev->iw_priv_cq_ops->cq_init(cq, &info); if (ret) goto error; - cqp = dev->cqp; - wqe = i40iw_sc_cqp_get_next_send_wqe(cqp, 0); - if (!wqe) { - ret = I40IW_ERR_RING_FULL; - goto error; - } + if (rsrc->ceq_valid) + ret = i40iw_cqp_cq_create_cmd(dev, cq); + else + ret = i40iw_puda_cq_wqe(dev, cq); +error: + if (ret) + i40iw_free_dma_mem(dev->hw, &rsrc->cqmem); + return ret; +} - set_64bit_val(wqe, 0, rsrc->cq_size); - set_64bit_val(wqe, 8, RS_64_1(cq, 1)); - set_64bit_val(wqe, 16, LS_64(shadow_read_threshold, I40IW_CQPSQ_CQ_SHADOW_READ_THRESHOLD)); - set_64bit_val(wqe, 32, cq->cq_pa); +/** + * i40iw_puda_free_qp - free qp for resource + * @rsrc: resource for which qp to free + */ +static void i40iw_puda_free_qp(struct i40iw_puda_rsrc *rsrc) +{ + enum i40iw_status_code ret; + struct i40iw_ccq_cqe_info compl_info; + struct i40iw_sc_dev *dev = rsrc->dev; - set_64bit_val(wqe, 40, cq->shadow_area_pa); + if (rsrc->ceq_valid) { + i40iw_cqp_qp_destroy_cmd(dev, &rsrc->qp); + return; + } - header = rsrc->cq_id | - LS_64(I40IW_CQP_OP_CREATE_CQ, I40IW_CQPSQ_OPCODE) | - LS_64(1, I40IW_CQPSQ_CQ_CHKOVERFLOW) | - LS_64(1, I40IW_CQPSQ_CQ_ENCEQEMASK) | - LS_64(1, I40IW_CQPSQ_CQ_CEQIDVALID) | - LS_64(cqp->polarity, I40IW_CQPSQ_WQEVALID); - set_64bit_val(wqe, 24, header); + ret = dev->iw_priv_qp_ops->qp_destroy(&rsrc->qp, + 0, false, true, true); + if (ret) + i40iw_debug(dev, I40IW_DEBUG_PUDA, + "%s error puda qp destroy wqe\n", + __func__); - i40iw_debug_buf(dev, I40IW_DEBUG_PUDA, "PUDA CQE", - wqe, I40IW_CQP_WQE_SIZE * 8); + if (!ret) { + ret = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp, + I40IW_CQP_OP_DESTROY_QP, + &compl_info); + if (ret) + i40iw_debug(dev, I40IW_DEBUG_PUDA, + "%s error puda qp destroy failed\n", + __func__); + } +} - i40iw_sc_cqp_post_sq(dev->cqp); - ret = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp, - I40IW_CQP_OP_CREATE_CQ, - &compl_info); +/** + * i40iw_puda_free_cq - free cq for resource + * @rsrc: resource for which cq to free + */ +static void i40iw_puda_free_cq(struct i40iw_puda_rsrc *rsrc) +{ + enum i40iw_status_code ret; + struct i40iw_ccq_cqe_info compl_info; + struct i40iw_sc_dev *dev = rsrc->dev; + + if (rsrc->ceq_valid) { + i40iw_cqp_cq_destroy_cmd(dev, &rsrc->cq); + return; + } + ret = dev->iw_priv_cq_ops->cq_destroy(&rsrc->cq, 0, true); -error: if (ret) - i40iw_free_dma_mem(dev->hw, &rsrc->cqmem); - return ret; + i40iw_debug(dev, I40IW_DEBUG_PUDA, + "%s error ieq cq destroy\n", + __func__); + + if (!ret) { + ret = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp, + I40IW_CQP_OP_DESTROY_CQ, + &compl_info); + if (ret) + i40iw_debug(dev, I40IW_DEBUG_PUDA, + "%s error ieq qp destroy done\n", + __func__); + } } /** @@ -702,25 +785,24 @@ error: * @type: type of resource to dele * @reset: true if reset chip */ -void i40iw_puda_dele_resources(struct i40iw_sc_dev *dev, +void i40iw_puda_dele_resources(struct i40iw_sc_vsi *vsi, enum puda_resource_type type, bool reset) { - struct i40iw_ccq_cqe_info compl_info; + struct i40iw_sc_dev *dev = vsi->dev; struct i40iw_puda_rsrc *rsrc; struct i40iw_puda_buf *buf = NULL; struct i40iw_puda_buf *nextbuf = NULL; struct i40iw_virt_mem *vmem; - enum i40iw_status_code ret; switch (type) { case I40IW_PUDA_RSRC_TYPE_ILQ: - rsrc = dev->ilq; - vmem = &dev->ilq_mem; + rsrc = vsi->ilq; + vmem = &vsi->ilq_mem; break; case I40IW_PUDA_RSRC_TYPE_IEQ: - rsrc = dev->ieq; - vmem = &dev->ieq_mem; + rsrc = vsi->ieq; + vmem = &vsi->ieq_mem; break; default: i40iw_debug(dev, I40IW_DEBUG_PUDA, "%s: error resource type = 0x%x\n", @@ -732,45 +814,14 @@ void i40iw_puda_dele_resources(struct i40iw_sc_dev *dev, case PUDA_HASH_CRC_COMPLETE: i40iw_free_hash_desc(rsrc->hash_desc); case PUDA_QP_CREATED: - do { - if (reset) - break; - ret = dev->iw_priv_qp_ops->qp_destroy(&rsrc->qp, - 0, false, true, true); - if (ret) - i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA, - "%s error ieq qp destroy\n", - __func__); - - ret = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp, - I40IW_CQP_OP_DESTROY_QP, - &compl_info); - if (ret) - i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA, - "%s error ieq qp destroy done\n", - __func__); - } while (0); + if (!reset) + i40iw_puda_free_qp(rsrc); i40iw_free_dma_mem(dev->hw, &rsrc->qpmem); /* fallthrough */ case PUDA_CQ_CREATED: - do { - if (reset) - break; - ret = dev->iw_priv_cq_ops->cq_destroy(&rsrc->cq, 0, true); - if (ret) - i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA, - "%s error ieq cq destroy\n", - __func__); - - ret = dev->cqp_ops->poll_for_cqp_op_done(dev->cqp, - I40IW_CQP_OP_DESTROY_CQ, - &compl_info); - if (ret) - i40iw_debug(rsrc->dev, I40IW_DEBUG_PUDA, - "%s error ieq qp destroy done\n", - __func__); - } while (0); + if (!reset) + i40iw_puda_free_cq(rsrc); i40iw_free_dma_mem(dev->hw, &rsrc->cqmem); break; @@ -826,9 +877,10 @@ static enum i40iw_status_code i40iw_puda_allocbufs(struct i40iw_puda_rsrc *rsrc, * @dev: iwarp device * @info: resource information */ -enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_dev *dev, +enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_vsi *vsi, struct i40iw_puda_rsrc_info *info) { + struct i40iw_sc_dev *dev = vsi->dev; enum i40iw_status_code ret = 0; struct i40iw_puda_rsrc *rsrc; u32 pudasize; @@ -841,10 +893,10 @@ enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_dev *dev, rqwridsize = info->rq_size * 8; switch (info->type) { case I40IW_PUDA_RSRC_TYPE_ILQ: - vmem = &dev->ilq_mem; + vmem = &vsi->ilq_mem; break; case I40IW_PUDA_RSRC_TYPE_IEQ: - vmem = &dev->ieq_mem; + vmem = &vsi->ieq_mem; break; default: return I40IW_NOT_SUPPORTED; @@ -857,22 +909,22 @@ enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_dev *dev, rsrc = (struct i40iw_puda_rsrc *)vmem->va; spin_lock_init(&rsrc->bufpool_lock); if (info->type == I40IW_PUDA_RSRC_TYPE_ILQ) { - dev->ilq = (struct i40iw_puda_rsrc *)vmem->va; - dev->ilq_count = info->count; + vsi->ilq = (struct i40iw_puda_rsrc *)vmem->va; + vsi->ilq_count = info->count; rsrc->receive = info->receive; rsrc->xmit_complete = info->xmit_complete; } else { - vmem = &dev->ieq_mem; - dev->ieq_count = info->count; - dev->ieq = (struct i40iw_puda_rsrc *)vmem->va; + vmem = &vsi->ieq_mem; + vsi->ieq_count = info->count; + vsi->ieq = (struct i40iw_puda_rsrc *)vmem->va; rsrc->receive = i40iw_ieq_receive; rsrc->xmit_complete = i40iw_ieq_tx_compl; } + rsrc->ceq_valid = info->ceq_valid; rsrc->type = info->type; rsrc->sq_wrtrk_array = (struct i40iw_sq_uk_wr_trk_info *)((u8 *)vmem->va + pudasize); rsrc->rq_wrid_array = (u64 *)((u8 *)vmem->va + pudasize + sqwridsize); - rsrc->mss = info->mss; /* Initialize all ieq lists */ INIT_LIST_HEAD(&rsrc->bufpool); INIT_LIST_HEAD(&rsrc->txpend); @@ -886,6 +938,7 @@ enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_dev *dev, rsrc->cq_size = info->rq_size + info->sq_size; rsrc->buf_size = info->buf_size; rsrc->dev = dev; + rsrc->vsi = vsi; ret = i40iw_puda_cq_create(rsrc); if (!ret) { @@ -920,7 +973,7 @@ enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_dev *dev, dev->ccq_ops->ccq_arm(&rsrc->cq); return ret; error: - i40iw_puda_dele_resources(dev, info->type, false); + i40iw_puda_dele_resources(vsi, info->type, false); return ret; } @@ -1333,7 +1386,7 @@ static void i40iw_ieq_handle_exception(struct i40iw_puda_rsrc *ieq, } if (pfpdu->mode && (fps != pfpdu->fps)) { /* clean up qp as it is new partial sequence */ - i40iw_ieq_cleanup_qp(ieq->dev, qp); + i40iw_ieq_cleanup_qp(ieq, qp); i40iw_debug(ieq->dev, I40IW_DEBUG_IEQ, "%s: restarting new partial\n", __func__); pfpdu->mode = false; @@ -1345,7 +1398,7 @@ static void i40iw_ieq_handle_exception(struct i40iw_puda_rsrc *ieq, pfpdu->rcv_nxt = fps; pfpdu->fps = fps; pfpdu->mode = true; - pfpdu->max_fpdu_data = ieq->mss; + pfpdu->max_fpdu_data = ieq->vsi->mss; pfpdu->pmode_count++; INIT_LIST_HEAD(rxlist); i40iw_ieq_check_first_buf(buf, fps); @@ -1380,14 +1433,14 @@ static void i40iw_ieq_handle_exception(struct i40iw_puda_rsrc *ieq, * @dev: iwarp device * @buf: exception buffer received */ -static void i40iw_ieq_receive(struct i40iw_sc_dev *dev, +static void i40iw_ieq_receive(struct i40iw_sc_vsi *vsi, struct i40iw_puda_buf *buf) { - struct i40iw_puda_rsrc *ieq = dev->ieq; + struct i40iw_puda_rsrc *ieq = vsi->ieq; struct i40iw_sc_qp *qp = NULL; u32 wqe_idx = ieq->compl_rxwqe_idx; - qp = i40iw_ieq_get_qp(dev, buf); + qp = i40iw_ieq_get_qp(vsi->dev, buf); if (!qp) { ieq->stats_bad_qp_id++; i40iw_puda_ret_bufpool(ieq, buf); @@ -1405,12 +1458,12 @@ static void i40iw_ieq_receive(struct i40iw_sc_dev *dev, /** * i40iw_ieq_tx_compl - put back after sending completed exception buffer - * @dev: iwarp device + * @vsi: pointer to the vsi structure * @sqwrid: pointer to puda buffer */ -static void i40iw_ieq_tx_compl(struct i40iw_sc_dev *dev, void *sqwrid) +static void i40iw_ieq_tx_compl(struct i40iw_sc_vsi *vsi, void *sqwrid) { - struct i40iw_puda_rsrc *ieq = dev->ieq; + struct i40iw_puda_rsrc *ieq = vsi->ieq; struct i40iw_puda_buf *buf = (struct i40iw_puda_buf *)sqwrid; i40iw_puda_ret_bufpool(ieq, buf); @@ -1422,15 +1475,14 @@ static void i40iw_ieq_tx_compl(struct i40iw_sc_dev *dev, void *sqwrid) /** * i40iw_ieq_cleanup_qp - qp is being destroyed - * @dev: iwarp device + * @ieq: ieq resource * @qp: all pending fpdu buffers */ -void i40iw_ieq_cleanup_qp(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) +static void i40iw_ieq_cleanup_qp(struct i40iw_puda_rsrc *ieq, struct i40iw_sc_qp *qp) { struct i40iw_puda_buf *buf; struct i40iw_pfpdu *pfpdu = &qp->pfpdu; struct list_head *rxlist = &pfpdu->rxlist; - struct i40iw_puda_rsrc *ieq = dev->ieq; if (!pfpdu->mode) return; diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.h b/drivers/infiniband/hw/i40iw/i40iw_puda.h index 52bf7826ce4e..dba05ce7d392 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.h +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.h @@ -100,6 +100,7 @@ struct i40iw_puda_rsrc_info { enum puda_resource_type type; /* ILQ or IEQ */ u32 count; u16 pd_id; + bool ceq_valid; u32 cq_id; u32 qp_id; u32 sq_size; @@ -107,8 +108,8 @@ struct i40iw_puda_rsrc_info { u16 buf_size; u16 mss; u32 tx_buf_cnt; /* total bufs allocated will be rq_size + tx_buf_cnt */ - void (*receive)(struct i40iw_sc_dev *, struct i40iw_puda_buf *); - void (*xmit_complete)(struct i40iw_sc_dev *, void *); + void (*receive)(struct i40iw_sc_vsi *, struct i40iw_puda_buf *); + void (*xmit_complete)(struct i40iw_sc_vsi *, void *); }; struct i40iw_puda_rsrc { @@ -116,6 +117,7 @@ struct i40iw_puda_rsrc { struct i40iw_sc_qp qp; struct i40iw_sc_pd sc_pd; struct i40iw_sc_dev *dev; + struct i40iw_sc_vsi *vsi; struct i40iw_dma_mem cqmem; struct i40iw_dma_mem qpmem; struct i40iw_virt_mem ilq_mem; @@ -123,6 +125,7 @@ struct i40iw_puda_rsrc { enum puda_resource_type type; u16 buf_size; /*buffer must be max datalen + tcpip hdr + mac */ u16 mss; + bool ceq_valid; u32 cq_id; u32 qp_id; u32 sq_size; @@ -142,8 +145,8 @@ struct i40iw_puda_rsrc { u32 avail_buf_count; /* snapshot of currently available buffers */ spinlock_t bufpool_lock; struct i40iw_puda_buf *alloclist; - void (*receive)(struct i40iw_sc_dev *, struct i40iw_puda_buf *); - void (*xmit_complete)(struct i40iw_sc_dev *, void *); + void (*receive)(struct i40iw_sc_vsi *, struct i40iw_puda_buf *); + void (*xmit_complete)(struct i40iw_sc_vsi *, void *); /* puda stats */ u64 stats_buf_alloc_fail; u64 stats_pkt_rcvd; @@ -160,14 +163,13 @@ void i40iw_puda_send_buf(struct i40iw_puda_rsrc *rsrc, struct i40iw_puda_buf *buf); enum i40iw_status_code i40iw_puda_send(struct i40iw_sc_qp *qp, struct i40iw_puda_send_info *info); -enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_dev *dev, +enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_vsi *vsi, struct i40iw_puda_rsrc_info *info); -void i40iw_puda_dele_resources(struct i40iw_sc_dev *dev, +void i40iw_puda_dele_resources(struct i40iw_sc_vsi *vsi, enum puda_resource_type type, bool reset); enum i40iw_status_code i40iw_puda_poll_completion(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq, u32 *compl_err); -void i40iw_ieq_cleanup_qp(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); struct i40iw_sc_qp *i40iw_ieq_get_qp(struct i40iw_sc_dev *dev, struct i40iw_puda_buf *buf); @@ -180,4 +182,8 @@ void i40iw_ieq_mpa_crc_ae(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); void i40iw_free_hash_desc(struct shash_desc *desc); void i40iw_ieq_update_tcpip_info(struct i40iw_puda_buf *buf, u16 length, u32 seqnum); +enum i40iw_status_code i40iw_cqp_qp_create_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); +enum i40iw_status_code i40iw_cqp_cq_create_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq); +void i40iw_cqp_qp_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp); +void i40iw_cqp_cq_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq); #endif diff --git a/drivers/infiniband/hw/i40iw/i40iw_type.h b/drivers/infiniband/hw/i40iw/i40iw_type.h index 928d91b956a8..f3f8e9cc3c05 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_type.h +++ b/drivers/infiniband/hw/i40iw/i40iw_type.h @@ -61,7 +61,7 @@ struct i40iw_cq_shadow_area { struct i40iw_sc_dev; struct i40iw_hmc_info; -struct i40iw_dev_pestat; +struct i40iw_vsi_pestat; struct i40iw_cqp_ops; struct i40iw_ccq_ops; @@ -191,7 +191,7 @@ enum i40iw_debug_flag { I40IW_DEBUG_ALL = 0xFFFFFFFF }; -enum i40iw_hw_stat_index_32b { +enum i40iw_hw_stats_index_32b { I40IW_HW_STAT_INDEX_IP4RXDISCARD = 0, I40IW_HW_STAT_INDEX_IP4RXTRUNC, I40IW_HW_STAT_INDEX_IP4TXNOROUTE, @@ -204,7 +204,7 @@ enum i40iw_hw_stat_index_32b { I40IW_HW_STAT_INDEX_MAX_32 }; -enum i40iw_hw_stat_index_64b { +enum i40iw_hw_stats_index_64b { I40IW_HW_STAT_INDEX_IP4RXOCTS = 0, I40IW_HW_STAT_INDEX_IP4RXPKTS, I40IW_HW_STAT_INDEX_IP4RXFRAGS, @@ -234,32 +234,23 @@ enum i40iw_hw_stat_index_64b { I40IW_HW_STAT_INDEX_MAX_64 }; -struct i40iw_dev_hw_stat_offsets { - u32 stat_offset_32[I40IW_HW_STAT_INDEX_MAX_32]; - u32 stat_offset_64[I40IW_HW_STAT_INDEX_MAX_64]; +struct i40iw_dev_hw_stats_offsets { + u32 stats_offset_32[I40IW_HW_STAT_INDEX_MAX_32]; + u32 stats_offset_64[I40IW_HW_STAT_INDEX_MAX_64]; }; struct i40iw_dev_hw_stats { - u64 stat_value_32[I40IW_HW_STAT_INDEX_MAX_32]; - u64 stat_value_64[I40IW_HW_STAT_INDEX_MAX_64]; + u64 stats_value_32[I40IW_HW_STAT_INDEX_MAX_32]; + u64 stats_value_64[I40IW_HW_STAT_INDEX_MAX_64]; }; -struct i40iw_device_pestat_ops { - void (*iw_hw_stat_init)(struct i40iw_dev_pestat *, u8, struct i40iw_hw *, bool); - void (*iw_hw_stat_read_32)(struct i40iw_dev_pestat *, enum i40iw_hw_stat_index_32b, u64 *); - void (*iw_hw_stat_read_64)(struct i40iw_dev_pestat *, enum i40iw_hw_stat_index_64b, u64 *); - void (*iw_hw_stat_read_all)(struct i40iw_dev_pestat *, struct i40iw_dev_hw_stats *); - void (*iw_hw_stat_refresh_all)(struct i40iw_dev_pestat *); -}; - -struct i40iw_dev_pestat { +struct i40iw_vsi_pestat { struct i40iw_hw *hw; - struct i40iw_device_pestat_ops ops; struct i40iw_dev_hw_stats hw_stats; struct i40iw_dev_hw_stats last_read_hw_stats; - struct i40iw_dev_hw_stat_offsets hw_stat_offsets; + struct i40iw_dev_hw_stats_offsets hw_stats_offsets; struct timer_list stats_timer; - spinlock_t stats_lock; /* rdma stats lock */ + spinlock_t lock; /* rdma stats lock */ }; struct i40iw_hw { @@ -355,6 +346,7 @@ struct i40iw_sc_cq { u64 cq_pa; u64 shadow_area_pa; struct i40iw_sc_dev *dev; + struct i40iw_sc_vsi *vsi; void *pbl_list; void *back_cq; u32 ceq_id; @@ -378,6 +370,7 @@ struct i40iw_sc_qp { u64 shadow_area_pa; u64 q2_pa; struct i40iw_sc_dev *dev; + struct i40iw_sc_vsi *vsi; struct i40iw_sc_pd *pd; u64 *hw_host_ctx; void *llp_stream_handle; @@ -441,7 +434,7 @@ struct i40iw_qos { struct i40iw_vfdev { struct i40iw_sc_dev *pf_dev; u8 *hmc_info_mem; - struct i40iw_dev_pestat dev_pestat; + struct i40iw_vsi_pestat pestat; struct i40iw_hmc_pble_info *pble_info; struct i40iw_hmc_info hmc_info; struct i40iw_vchnl_vf_msg_buffer vf_msg_buffer; @@ -455,11 +448,28 @@ struct i40iw_vfdev { bool stats_initialized; }; +#define I40IW_INVALID_FCN_ID 0xff +struct i40iw_sc_vsi { + struct i40iw_sc_dev *dev; + void *back_vsi; /* Owned by OS */ + u32 ilq_count; + struct i40iw_virt_mem ilq_mem; + struct i40iw_puda_rsrc *ilq; + u32 ieq_count; + struct i40iw_virt_mem ieq_mem; + struct i40iw_puda_rsrc *ieq; + u16 mss; + u8 fcn_id; + bool stats_fcn_id_alloc; + struct i40iw_qos qos[I40IW_MAX_USER_PRIORITY]; + struct i40iw_vsi_pestat *pestat; +}; + struct i40iw_sc_dev { struct list_head cqp_cmd_head; /* head of the CQP command list */ spinlock_t cqp_lock; /* cqp list sync */ struct i40iw_dev_uk dev_uk; - struct i40iw_dev_pestat dev_pestat; + bool fcn_id_array[I40IW_MAX_STATS_COUNT]; struct i40iw_dma_mem vf_fpm_query_buf[I40IW_MAX_PE_ENABLED_VF_COUNT]; u64 fpm_query_buf_pa; u64 fpm_commit_buf_pa; @@ -486,18 +496,9 @@ struct i40iw_sc_dev { struct i40iw_cqp_misc_ops *cqp_misc_ops; struct i40iw_hmc_ops *hmc_ops; struct i40iw_vchnl_if vchnl_if; - u32 ilq_count; - struct i40iw_virt_mem ilq_mem; - struct i40iw_puda_rsrc *ilq; - u32 ieq_count; - struct i40iw_virt_mem ieq_mem; - struct i40iw_puda_rsrc *ieq; - const struct i40iw_vf_cqp_ops *iw_vf_cqp_ops; struct i40iw_hmc_fpm_misc hmc_fpm_misc; - struct i40iw_qos qos[I40IW_MAX_USER_PRIORITY]; - u16 mss; u32 debug_mask; u16 exception_lan_queue; u8 hmc_fn_id; @@ -571,6 +572,19 @@ struct i40iw_l2params { u16 mss; }; +struct i40iw_vsi_init_info { + struct i40iw_sc_dev *dev; + void *back_vsi; + struct i40iw_l2params *params; +}; + +struct i40iw_vsi_stats_info { + struct i40iw_vsi_pestat *pestat; + u8 fcn_id; + bool alloc_fcn_id; + bool stats_initialize; +}; + struct i40iw_device_init_info { u64 fpm_query_buf_pa; u64 fpm_commit_buf_pa; @@ -579,7 +593,6 @@ struct i40iw_device_init_info { struct i40iw_hw *hw; void __iomem *bar0; enum i40iw_status_code (*vchnl_send)(struct i40iw_sc_dev *, u32, u8 *, u16); - struct i40iw_l2params l2params; u16 exception_lan_queue; u8 hmc_fn_id; bool is_pf; @@ -831,6 +844,7 @@ struct i40iw_register_shared_stag { struct i40iw_qp_init_info { struct i40iw_qp_uk_init_info qp_uk_init_info; struct i40iw_sc_pd *pd; + struct i40iw_sc_vsi *vsi; u64 *host_ctx; u8 *q2; u64 sq_pa; @@ -897,6 +911,7 @@ enum i40iw_quad_hash_manage_type { }; struct i40iw_qhash_table_info { + struct i40iw_sc_vsi *vsi; enum i40iw_quad_hash_manage_type manage; enum i40iw_quad_entry_type entry_type; bool vlan_valid; diff --git a/drivers/infiniband/hw/i40iw/i40iw_utils.c b/drivers/infiniband/hw/i40iw/i40iw_utils.c index 7d4af7759970..0f5d43d1f5fc 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_utils.c +++ b/drivers/infiniband/hw/i40iw/i40iw_utils.c @@ -761,7 +761,7 @@ void i40iw_qp_mss_modify(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) memset(&info, 0, sizeof(info)); info.mss_change = true; - info.new_mss = dev->mss; + info.new_mss = qp->vsi->mss; i40iw_hw_modify_qp(iwdev, iwqp, &info, false); } @@ -1067,6 +1067,116 @@ enum i40iw_status_code i40iw_vf_wait_vchnl_resp(struct i40iw_sc_dev *dev) return 0; } +/** + * i40iw_cqp_cq_create_cmd - create a cq for the cqp + * @dev: device pointer + * @cq: pointer to created cq + */ +enum i40iw_status_code i40iw_cqp_cq_create_cmd(struct i40iw_sc_dev *dev, + struct i40iw_sc_cq *cq) +{ + struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; + struct i40iw_cqp *iwcqp = &iwdev->cqp; + struct i40iw_cqp_request *cqp_request; + struct cqp_commands_info *cqp_info; + enum i40iw_status_code status; + + cqp_request = i40iw_get_cqp_request(iwcqp, true); + if (!cqp_request) + return I40IW_ERR_NO_MEMORY; + + cqp_info = &cqp_request->info; + cqp_info->cqp_cmd = OP_CQ_CREATE; + cqp_info->post_sq = 1; + cqp_info->in.u.cq_create.cq = cq; + cqp_info->in.u.cq_create.scratch = (uintptr_t)cqp_request; + status = i40iw_handle_cqp_op(iwdev, cqp_request); + if (status) + i40iw_pr_err("CQP-OP Create QP fail"); + + return status; +} + +/** + * i40iw_cqp_qp_create_cmd - create a qp for the cqp + * @dev: device pointer + * @qp: pointer to created qp + */ +enum i40iw_status_code i40iw_cqp_qp_create_cmd(struct i40iw_sc_dev *dev, + struct i40iw_sc_qp *qp) +{ + struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; + struct i40iw_cqp *iwcqp = &iwdev->cqp; + struct i40iw_cqp_request *cqp_request; + struct cqp_commands_info *cqp_info; + struct i40iw_create_qp_info *qp_info; + enum i40iw_status_code status; + + cqp_request = i40iw_get_cqp_request(iwcqp, true); + if (!cqp_request) + return I40IW_ERR_NO_MEMORY; + + cqp_info = &cqp_request->info; + qp_info = &cqp_request->info.in.u.qp_create.info; + + memset(qp_info, 0, sizeof(*qp_info)); + + qp_info->cq_num_valid = true; + qp_info->next_iwarp_state = I40IW_QP_STATE_RTS; + + cqp_info->cqp_cmd = OP_QP_CREATE; + cqp_info->post_sq = 1; + cqp_info->in.u.qp_create.qp = qp; + cqp_info->in.u.qp_create.scratch = (uintptr_t)cqp_request; + status = i40iw_handle_cqp_op(iwdev, cqp_request); + if (status) + i40iw_pr_err("CQP-OP QP create fail"); + return status; +} + +/** + * i40iw_cqp_cq_destroy_cmd - destroy the cqp cq + * @dev: device pointer + * @cq: pointer to cq + */ +void i40iw_cqp_cq_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_cq *cq) +{ + struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; + + i40iw_cq_wq_destroy(iwdev, cq); +} + +/** + * i40iw_cqp_qp_destroy_cmd - destroy the cqp + * @dev: device pointer + * @qp: pointer to qp + */ +void i40iw_cqp_qp_destroy_cmd(struct i40iw_sc_dev *dev, struct i40iw_sc_qp *qp) +{ + struct i40iw_device *iwdev = (struct i40iw_device *)dev->back_dev; + struct i40iw_cqp *iwcqp = &iwdev->cqp; + struct i40iw_cqp_request *cqp_request; + struct cqp_commands_info *cqp_info; + enum i40iw_status_code status; + + cqp_request = i40iw_get_cqp_request(iwcqp, true); + if (!cqp_request) + return; + + cqp_info = &cqp_request->info; + memset(cqp_info, 0, sizeof(*cqp_info)); + + cqp_info->cqp_cmd = OP_QP_DESTROY; + cqp_info->post_sq = 1; + cqp_info->in.u.qp_destroy.qp = qp; + cqp_info->in.u.qp_destroy.scratch = (uintptr_t)cqp_request; + cqp_info->in.u.qp_destroy.remove_hash_idx = true; + status = i40iw_handle_cqp_op(iwdev, cqp_request); + if (status) + i40iw_pr_err("CQP QP_DESTROY fail"); +} + + /** * i40iw_ieq_mpa_crc_ae - generate AE for crc error * @dev: hardware control device structure @@ -1281,27 +1391,29 @@ enum i40iw_status_code i40iw_puda_get_tcpip_info(struct i40iw_puda_completion_in /** * i40iw_hw_stats_timeout - Stats timer-handler which updates all HW stats - * @dev: hardware control device structure + * @vsi: pointer to the vsi structure */ -static void i40iw_hw_stats_timeout(unsigned long dev) +static void i40iw_hw_stats_timeout(unsigned long vsi) { - struct i40iw_sc_dev *pf_dev = (struct i40iw_sc_dev *)dev; - struct i40iw_dev_pestat *pf_devstat = &pf_dev->dev_pestat; - struct i40iw_dev_pestat *vf_devstat = NULL; + struct i40iw_sc_vsi *sc_vsi = (struct i40iw_sc_vsi *)vsi; + struct i40iw_sc_dev *pf_dev = sc_vsi->dev; + struct i40iw_vsi_pestat *pf_devstat = sc_vsi->pestat; + struct i40iw_vsi_pestat *vf_devstat = NULL; u16 iw_vf_idx; unsigned long flags; /*PF*/ - pf_devstat->ops.iw_hw_stat_read_all(pf_devstat, &pf_devstat->hw_stats); + i40iw_hw_stats_read_all(pf_devstat, &pf_devstat->hw_stats); + for (iw_vf_idx = 0; iw_vf_idx < I40IW_MAX_PE_ENABLED_VF_COUNT; iw_vf_idx++) { - spin_lock_irqsave(&pf_devstat->stats_lock, flags); + spin_lock_irqsave(&pf_devstat->lock, flags); if (pf_dev->vf_dev[iw_vf_idx]) { if (pf_dev->vf_dev[iw_vf_idx]->stats_initialized) { - vf_devstat = &pf_dev->vf_dev[iw_vf_idx]->dev_pestat; - vf_devstat->ops.iw_hw_stat_read_all(vf_devstat, &vf_devstat->hw_stats); + vf_devstat = &pf_dev->vf_dev[iw_vf_idx]->pestat; + i40iw_hw_stats_read_all(vf_devstat, &vf_devstat->hw_stats); } } - spin_unlock_irqrestore(&pf_devstat->stats_lock, flags); + spin_unlock_irqrestore(&pf_devstat->lock, flags); } mod_timer(&pf_devstat->stats_timer, @@ -1310,26 +1422,26 @@ static void i40iw_hw_stats_timeout(unsigned long dev) /** * i40iw_hw_stats_start_timer - Start periodic stats timer - * @dev: hardware control device structure + * @vsi: pointer to the vsi structure */ -void i40iw_hw_stats_start_timer(struct i40iw_sc_dev *dev) +void i40iw_hw_stats_start_timer(struct i40iw_sc_vsi *vsi) { - struct i40iw_dev_pestat *devstat = &dev->dev_pestat; + struct i40iw_vsi_pestat *devstat = vsi->pestat; init_timer(&devstat->stats_timer); devstat->stats_timer.function = i40iw_hw_stats_timeout; - devstat->stats_timer.data = (unsigned long)dev; + devstat->stats_timer.data = (unsigned long)vsi; mod_timer(&devstat->stats_timer, jiffies + msecs_to_jiffies(STATS_TIMER_DELAY)); } /** - * i40iw_hw_stats_del_timer - Delete periodic stats timer - * @dev: hardware control device structure + * i40iw_hw_stats_stop_timer - Delete periodic stats timer + * @vsi: pointer to the vsi structure */ -void i40iw_hw_stats_del_timer(struct i40iw_sc_dev *dev) +void i40iw_hw_stats_stop_timer(struct i40iw_sc_vsi *vsi) { - struct i40iw_dev_pestat *devstat = &dev->dev_pestat; + struct i40iw_vsi_pestat *devstat = vsi->pestat; del_timer_sync(&devstat->stats_timer); } diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 18526e6f9d85..855e49957a1a 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -623,6 +623,7 @@ static struct ib_qp *i40iw_create_qp(struct ib_pd *ibpd, sq_size = init_attr->cap.max_send_wr; rq_size = init_attr->cap.max_recv_wr; + init_info.vsi = &iwdev->vsi; init_info.qp_uk_init_info.sq_size = sq_size; init_info.qp_uk_init_info.rq_size = rq_size; init_info.qp_uk_init_info.max_sq_frag_cnt = init_attr->cap.max_send_sge; @@ -1052,11 +1053,11 @@ static void cq_free_resources(struct i40iw_device *iwdev, struct i40iw_cq *iwcq) } /** - * cq_wq_destroy - send cq destroy cqp + * i40iw_cq_wq_destroy - send cq destroy cqp * @iwdev: iwarp device * @cq: hardware control cq */ -static void cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq) +void i40iw_cq_wq_destroy(struct i40iw_device *iwdev, struct i40iw_sc_cq *cq) { enum i40iw_status_code status; struct i40iw_cqp_request *cqp_request; @@ -1095,7 +1096,7 @@ static int i40iw_destroy_cq(struct ib_cq *ib_cq) iwcq = to_iwcq(ib_cq); iwdev = to_iwdev(ib_cq->device); cq = &iwcq->sc_cq; - cq_wq_destroy(iwdev, cq); + i40iw_cq_wq_destroy(iwdev, cq); cq_free_resources(iwdev, iwcq); kfree(iwcq); i40iw_rem_devusecount(iwdev); @@ -1253,7 +1254,7 @@ static struct ib_cq *i40iw_create_cq(struct ib_device *ibdev, return (struct ib_cq *)iwcq; cq_destroy: - cq_wq_destroy(iwdev, cq); + i40iw_cq_wq_destroy(iwdev, cq); cq_free_resources: cq_free_resources(iwdev, iwcq); error: @@ -2632,15 +2633,11 @@ static int i40iw_get_hw_stats(struct ib_device *ibdev, { struct i40iw_device *iwdev = to_iwdev(ibdev); struct i40iw_sc_dev *dev = &iwdev->sc_dev; - struct i40iw_dev_pestat *devstat = &dev->dev_pestat; + struct i40iw_vsi_pestat *devstat = iwdev->vsi.pestat; struct i40iw_dev_hw_stats *hw_stats = &devstat->hw_stats; - unsigned long flags; if (dev->is_pf) { - spin_lock_irqsave(&devstat->stats_lock, flags); - devstat->ops.iw_hw_stat_read_all(devstat, - &devstat->hw_stats); - spin_unlock_irqrestore(&devstat->stats_lock, flags); + i40iw_hw_stats_read_all(devstat, &devstat->hw_stats); } else { if (i40iw_vchnl_vf_get_pe_stats(dev, &devstat->hw_stats)) return -ENOSYS; diff --git a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c b/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c index dbd39c4af946..f4d13683a403 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_virtchnl.c @@ -402,6 +402,19 @@ del_out: vchnl_pf_send_error_resp(vf_dev->pf_dev, vf_dev->vf_id, vchnl_msg, (u16)ret_code); } +/** + * i40iw_vf_init_pestat - Initialize stats for VF + * @devL pointer to the VF Device + * @stats: Statistics structure pointer + * @index: Stats index + */ +static void i40iw_vf_init_pestat(struct i40iw_sc_dev *dev, struct i40iw_vsi_pestat *stats, u16 index) +{ + stats->hw = dev->hw; + i40iw_hw_stats_init(stats, (u8)index, false); + spin_lock_init(&stats->lock); +} + /** * i40iw_vchnl_recv_pf - Receive PF virtual channel messages * @dev: IWARP device pointer @@ -421,9 +434,8 @@ enum i40iw_status_code i40iw_vchnl_recv_pf(struct i40iw_sc_dev *dev, u16 first_avail_iw_vf = I40IW_MAX_PE_ENABLED_VF_COUNT; struct i40iw_virt_mem vf_dev_mem; struct i40iw_virtchnl_work_info work_info; - struct i40iw_dev_pestat *devstat; + struct i40iw_vsi_pestat *stats; enum i40iw_status_code ret_code; - unsigned long flags; if (!dev || !msg || !len) return I40IW_ERR_PARAM; @@ -496,10 +508,7 @@ enum i40iw_status_code i40iw_vchnl_recv_pf(struct i40iw_sc_dev *dev, i40iw_debug(dev, I40IW_DEBUG_VIRT, "VF%u error CQP HMC Function operation.\n", vf_id); - i40iw_device_init_pestat(&vf_dev->dev_pestat); - vf_dev->dev_pestat.ops.iw_hw_stat_init(&vf_dev->dev_pestat, - (u8)vf_dev->pmf_index, - dev->hw, false); + i40iw_vf_init_pestat(dev, &vf_dev->pestat, vf_dev->pmf_index); vf_dev->stats_initialized = true; } else { if (vf_dev) { @@ -530,12 +539,10 @@ enum i40iw_status_code i40iw_vchnl_recv_pf(struct i40iw_sc_dev *dev, case I40IW_VCHNL_OP_GET_STATS: if (!vf_dev) return I40IW_ERR_BAD_PTR; - devstat = &vf_dev->dev_pestat; - spin_lock_irqsave(&dev->dev_pestat.stats_lock, flags); - devstat->ops.iw_hw_stat_read_all(devstat, &devstat->hw_stats); - spin_unlock_irqrestore(&dev->dev_pestat.stats_lock, flags); + stats = &vf_dev->pestat; + i40iw_hw_stats_read_all(stats, &stats->hw_stats); vf_dev->msg_count--; - vchnl_pf_send_get_pe_stats_resp(dev, vf_id, vchnl_msg, &devstat->hw_stats); + vchnl_pf_send_get_pe_stats_resp(dev, vf_id, vchnl_msg, &stats->hw_stats); break; default: i40iw_debug(dev, I40IW_DEBUG_VIRT, -- cgit v1.2.3 From 5a8a6b89c15766446d845671d574a9243b6d8786 Mon Sep 17 00:00:00 2001 From: Jingkui Wang Date: Mon, 12 Dec 2016 13:51:46 -0800 Subject: Input: drv260x - fix input device's parent assignment We were assigning I2C bus controller instead of client as parent device. Besides being logically wrong, it messed up with devm handling of input device. As a result we were leaving input device and event node behind after rmmod-ing the driver, which lead to a kernel oops if one were to access the event node later. Let's remove the assignment and rely on devm_input_allocate_device() to set it up properly for us. Signed-off-by: Jingkui Wang Fixes: 7132fe4f5687 ("Input: drv260x - add TI drv260x haptics driver") Cc: stable@vger.kernel.org Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 9789d4fb6e51..251d64ca41ce 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -592,7 +592,6 @@ static int drv260x_probe(struct i2c_client *client, } haptics->input_dev->name = "drv260x:haptics"; - haptics->input_dev->dev.parent = client->dev.parent; haptics->input_dev->close = drv260x_close; input_set_drvdata(haptics->input_dev, haptics); input_set_capability(haptics->input_dev, EV_FF, FF_RUMBLE); -- cgit v1.2.3 From ba4cf3783854346051ed5a243220f37c0c865350 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 10 Dec 2016 23:03:33 -0800 Subject: Input: drv260x - use temporary for &client->dev Let's introduce a temporary for "client->dev" is probe() as we use it quite a few times and "dev" is shorter. Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) (limited to 'drivers') diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index 251d64ca41ce..a26aa548dd66 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -514,10 +514,11 @@ static int drv260x_probe(struct i2c_client *client, const struct i2c_device_id *id) { const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev); + struct device *dev = &client->dev; struct drv260x_data *haptics; int error; - haptics = devm_kzalloc(&client->dev, sizeof(*haptics), GFP_KERNEL); + haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL); if (!haptics) return -ENOMEM; @@ -536,22 +537,20 @@ static int drv260x_probe(struct i2c_client *client, if (error) return error; } else { - dev_err(&client->dev, "Platform data not set\n"); + dev_err(dev, "Platform data not set\n"); return -ENODEV; } if (haptics->mode < DRV260X_LRA_MODE || haptics->mode > DRV260X_ERM_MODE) { - dev_err(&client->dev, - "Vibrator mode is invalid: %i\n", - haptics->mode); + dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode); return -EINVAL; } if (haptics->library < DRV260X_LIB_EMPTY || haptics->library > DRV260X_ERM_LIB_F) { - dev_err(&client->dev, + dev_err(dev, "Library value is invalid: %i\n", haptics->library); return -EINVAL; } @@ -559,33 +558,30 @@ static int drv260x_probe(struct i2c_client *client, if (haptics->mode == DRV260X_LRA_MODE && haptics->library != DRV260X_LIB_EMPTY && haptics->library != DRV260X_LIB_LRA) { - dev_err(&client->dev, - "LRA Mode with ERM Library mismatch\n"); + dev_err(dev, "LRA Mode with ERM Library mismatch\n"); return -EINVAL; } if (haptics->mode == DRV260X_ERM_MODE && (haptics->library == DRV260X_LIB_EMPTY || haptics->library == DRV260X_LIB_LRA)) { - dev_err(&client->dev, - "ERM Mode with LRA Library mismatch\n"); + dev_err(dev, "ERM Mode with LRA Library mismatch\n"); return -EINVAL; } - haptics->regulator = devm_regulator_get(&client->dev, "vbat"); + haptics->regulator = devm_regulator_get(dev, "vbat"); if (IS_ERR(haptics->regulator)) { error = PTR_ERR(haptics->regulator); - dev_err(&client->dev, - "unable to get regulator, error: %d\n", error); + dev_err(dev, "unable to get regulator, error: %d\n", error); return error; } - haptics->enable_gpio = devm_gpiod_get_optional(&client->dev, "enable", + haptics->enable_gpio = devm_gpiod_get_optional(dev, "enable", GPIOD_OUT_HIGH); if (IS_ERR(haptics->enable_gpio)) return PTR_ERR(haptics->enable_gpio); - haptics->input_dev = devm_input_allocate_device(&client->dev); + haptics->input_dev = devm_input_allocate_device(dev); if (!haptics->input_dev) { dev_err(&client->dev, "Failed to allocate input device\n"); return -ENOMEM; @@ -599,8 +595,7 @@ static int drv260x_probe(struct i2c_client *client, error = input_ff_create_memless(haptics->input_dev, NULL, drv260x_haptics_play); if (error) { - dev_err(&client->dev, "input_ff_create() failed: %d\n", - error); + dev_err(dev, "input_ff_create() failed: %d\n", error); return error; } @@ -612,21 +607,19 @@ static int drv260x_probe(struct i2c_client *client, haptics->regmap = devm_regmap_init_i2c(client, &drv260x_regmap_config); if (IS_ERR(haptics->regmap)) { error = PTR_ERR(haptics->regmap); - dev_err(&client->dev, "Failed to allocate register map: %d\n", - error); + dev_err(dev, "Failed to allocate register map: %d\n", error); return error; } error = drv260x_init(haptics); if (error) { - dev_err(&client->dev, "Device init failed: %d\n", error); + dev_err(dev, "Device init failed: %d\n", error); return error; } error = input_register_device(haptics->input_dev); if (error) { - dev_err(&client->dev, "couldn't register input device: %d\n", - error); + dev_err(dev, "couldn't register input device: %d\n", error); return error; } -- cgit v1.2.3 From 34888602eb99df174e76eafeb613ad857f534ebb Mon Sep 17 00:00:00 2001 From: Jingkui Wang Date: Sat, 10 Dec 2016 22:44:10 -0800 Subject: Input: drv260x - use generic device properties Update driver drv260x to use generic device properties so that it can be used on non-DT systems. We also remove platform data as generic device properties work on static board code as well. Signed-off-by: Jingkui Wang Signed-off-by: Dmitry Torokhov --- drivers/input/misc/drv260x.c | 83 +++++++---------------------- include/linux/platform_data/drv260x-pdata.h | 28 ---------- 2 files changed, 19 insertions(+), 92 deletions(-) delete mode 100644 include/linux/platform_data/drv260x-pdata.h (limited to 'drivers') diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c index a26aa548dd66..0a2b865b1000 100644 --- a/drivers/input/misc/drv260x.c +++ b/drivers/input/misc/drv260x.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include @@ -27,7 +25,6 @@ #include #include -#include #define DRV260X_STATUS 0x0 #define DRV260X_MODE 0x1 @@ -468,86 +465,36 @@ static const struct regmap_config drv260x_regmap_config = { .cache_type = REGCACHE_NONE, }; -#ifdef CONFIG_OF -static int drv260x_parse_dt(struct device *dev, - struct drv260x_data *haptics) -{ - struct device_node *np = dev->of_node; - unsigned int voltage; - int error; - - error = of_property_read_u32(np, "mode", &haptics->mode); - if (error) { - dev_err(dev, "%s: No entry for mode\n", __func__); - return error; - } - - error = of_property_read_u32(np, "library-sel", &haptics->library); - if (error) { - dev_err(dev, "%s: No entry for library selection\n", - __func__); - return error; - } - - error = of_property_read_u32(np, "vib-rated-mv", &voltage); - if (!error) - haptics->rated_voltage = drv260x_calculate_voltage(voltage); - - - error = of_property_read_u32(np, "vib-overdrive-mv", &voltage); - if (!error) - haptics->overdrive_voltage = drv260x_calculate_voltage(voltage); - - return 0; -} -#else -static inline int drv260x_parse_dt(struct device *dev, - struct drv260x_data *haptics) -{ - dev_err(dev, "no platform data defined\n"); - - return -EINVAL; -} -#endif - static int drv260x_probe(struct i2c_client *client, const struct i2c_device_id *id) { - const struct drv260x_platform_data *pdata = dev_get_platdata(&client->dev); struct device *dev = &client->dev; struct drv260x_data *haptics; + u32 voltage; int error; haptics = devm_kzalloc(dev, sizeof(*haptics), GFP_KERNEL); if (!haptics) return -ENOMEM; - haptics->overdrive_voltage = DRV260X_DEF_OD_CLAMP_VOLT; - haptics->rated_voltage = DRV260X_DEF_RATED_VOLT; - - if (pdata) { - haptics->mode = pdata->mode; - haptics->library = pdata->library_selection; - if (pdata->vib_overdrive_voltage) - haptics->overdrive_voltage = drv260x_calculate_voltage(pdata->vib_overdrive_voltage); - if (pdata->vib_rated_voltage) - haptics->rated_voltage = drv260x_calculate_voltage(pdata->vib_rated_voltage); - } else if (client->dev.of_node) { - error = drv260x_parse_dt(&client->dev, haptics); - if (error) - return error; - } else { - dev_err(dev, "Platform data not set\n"); - return -ENODEV; + error = device_property_read_u32(dev, "mode", &haptics->mode); + if (error) { + dev_err(dev, "Can't fetch 'mode' property: %d\n", error); + return error; } - if (haptics->mode < DRV260X_LRA_MODE || haptics->mode > DRV260X_ERM_MODE) { dev_err(dev, "Vibrator mode is invalid: %i\n", haptics->mode); return -EINVAL; } + error = device_property_read_u32(dev, "library-sel", &haptics->library); + if (error) { + dev_err(dev, "Can't fetch 'library-sel' property: %d\n", error); + return error; + } + if (haptics->library < DRV260X_LIB_EMPTY || haptics->library > DRV260X_ERM_LIB_F) { dev_err(dev, @@ -569,6 +516,14 @@ static int drv260x_probe(struct i2c_client *client, return -EINVAL; } + error = device_property_read_u32(dev, "vib-rated-mv", &voltage); + haptics->rated_voltage = error ? DRV260X_DEF_RATED_VOLT : + drv260x_calculate_voltage(voltage); + + error = device_property_read_u32(dev, "vib-overdrive-mv", &voltage); + haptics->overdrive_voltage = error ? DRV260X_DEF_OD_CLAMP_VOLT : + drv260x_calculate_voltage(voltage); + haptics->regulator = devm_regulator_get(dev, "vbat"); if (IS_ERR(haptics->regulator)) { error = PTR_ERR(haptics->regulator); diff --git a/include/linux/platform_data/drv260x-pdata.h b/include/linux/platform_data/drv260x-pdata.h deleted file mode 100644 index 0a03b0944411..000000000000 --- a/include/linux/platform_data/drv260x-pdata.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Platform data for DRV260X haptics driver family - * - * Author: Dan Murphy - * - * Copyright: (C) 2014 Texas Instruments, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * 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 _LINUX_DRV260X_PDATA_H -#define _LINUX_DRV260X_PDATA_H - -struct drv260x_platform_data { - u32 library_selection; - u32 mode; - u32 vib_rated_voltage; - u32 vib_overdrive_voltage; -}; - -#endif -- cgit v1.2.3 From 9e9d68dad58c70f40f50adfeabd2fdaa39a743fd Mon Sep 17 00:00:00 2001 From: Sebastian Andrzej Siewior Date: Wed, 7 Dec 2016 20:06:08 +0100 Subject: ACPI / CPPC: Fix crash in acpi_cppc_processor_exit() First I had crashed what I bisected down to de966cf4a4fa (sched/x86: Change CONFIG_SCHED_ITMT to CONFIG_SCHED_MC_PRIO) because it made SCHED_ITMT the default. Then I run another bisect round and got here with the same backtrace: |BUG: unable to handle kernel NULL pointer dereference at (null) |IP: [] acpi_cppc_processor_exit+0x40/0x60 |PGD 0 [ 0.577616] |Oops: 0000 [#1] SMP |Modules linked in: |CPU: 3 PID: 1 Comm: swapper/0 Not tainted 4.9.0-rc6-00146-g17669006adf6 #51 |task: ffff88003f878000 task.stack: ffffc90000008000 |RIP: 0010:[] [] acpi_cppc_processor_exit+0x40/0x60 |RSP: 0000:ffffc9000000bd48 EFLAGS: 00010296 |RAX: 00000000000137e0 RBX: 0000000000000000 RCX: 0000000000000001 |RDX: ffff88003fc00000 RSI: 0000000000000000 RDI: ffff88003fbca130 |RBP: ffffc9000000bd60 R08: 0000000000000514 R09: 0000000000000000 |R10: 0000000000000001 R11: 0000000000000000 R12: 0000000000000002 |R13: 0000000000000020 R14: ffffffff8167cb00 R15: 0000000000000000 |FS: 0000000000000000(0000) GS:ffff88003fcc0000(0000) knlGS:0000000000000000 |CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 |CR2: 0000000000000000 CR3: 0000000001618000 CR4: 00000000000406e0 |Stack: | ffff88003f939848 ffff88003fbca130 0000000000000001 ffffc9000000bd80 | ffffffff812a4ccb ffff88003fc0cee8 0000000000000000 ffffc9000000bdb8 | ffffffff812dc20d ffff88003fc0cee8 ffffffff8167cb00 ffff88003fc0cf48 |Call Trace: | [] acpi_processor_stop+0xb2/0xc5 | [] driver_probe_device+0x14d/0x2f0 | [] __driver_attach+0x6e/0x90 | [] bus_for_each_dev+0x54/0x90 | [] driver_attach+0x19/0x20 | [] bus_add_driver+0xe6/0x200 | [] driver_register+0x83/0xc0 | [] acpi_processor_driver_init+0x20/0x94 | [] do_one_initcall+0x97/0x180 | [] kernel_init_freeable+0x112/0x1a6 | [] kernel_init+0x9/0xf0 | [] ret_from_fork+0x25/0x30 |Code: 02 00 00 00 48 8b 14 d5 e0 c3 55 81 48 8b 1c 02 4c 8d 6b 20 eb 15 49 8b 7d 00 48 85 ff 74 05 e8 39 8c d9 ff 41 ff c4 49 83 c5 20 <44> 3b 23 72 e6 48 8d bb a0 02 00 00 e8 b1 6f f9 ff 48 89 df e8 |RIP [] acpi_cppc_processor_exit+0x40/0x60 | RSP |CR2: 0000000000000000 |---[ end trace 917a625107b09711 ]--- Fix it. Fixes: 17669006adf6 (cpufreq/intel_pstate: Use CPPC to get max performance) Signed-off-by: Sebastian Andrzej Siewior [ rjw: Subject ] Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index e0ea8f56d2bf..ae2ad6e94132 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -826,6 +826,8 @@ void acpi_cppc_processor_exit(struct acpi_processor *pr) void __iomem *addr; cpc_ptr = per_cpu(cpc_desc_ptr, pr->id); + if (!cpc_ptr) + return; /* Free all the mapped sys mem areas for this CPU */ for (i = 2; i < cpc_ptr->num_entries; i++) { -- cgit v1.2.3 From 28076483afac9dd77df269f5d460e51a09dfb19f Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sat, 10 Dec 2016 00:52:28 +0100 Subject: ACPI / CPPC: Fix per-CPU pointer management in acpi_cppc_processor_probe() Fix a possible use-after-free scenario in acpi_cppc_processor_probe() that can happen if the function returns without cleaning up the per-CPU pointer set by it previously. Reported-by: Sebastian Andrzej Siewior Signed-off-by: Rafael J. Wysocki --- drivers/acpi/cppc_acpi.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/cppc_acpi.c b/drivers/acpi/cppc_acpi.c index ae2ad6e94132..3ca0729f7e0e 100644 --- a/drivers/acpi/cppc_acpi.c +++ b/drivers/acpi/cppc_acpi.c @@ -776,9 +776,6 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) init_waitqueue_head(&pcc_data.pcc_write_wait_q); } - /* Plug PSD data into this CPUs CPC descriptor. */ - per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr; - /* Everything looks okay */ pr_debug("Parsed CPC struct for CPU: %d\n", pr->id); @@ -789,10 +786,15 @@ int acpi_cppc_processor_probe(struct acpi_processor *pr) goto out_free; } + /* Plug PSD data into this CPUs CPC descriptor. */ + per_cpu(cpc_desc_ptr, pr->id) = cpc_ptr; + ret = kobject_init_and_add(&cpc_ptr->kobj, &cppc_ktype, &cpu_dev->kobj, "acpi_cppc"); - if (ret) + if (ret) { + per_cpu(cpc_desc_ptr, pr->id) = NULL; goto out_free; + } kfree(output.pointer); return 0; -- cgit v1.2.3 From d4c2269b3d5d06a8ea434b1841fbcaec336ed396 Mon Sep 17 00:00:00 2001 From: Ilya Dryomov Date: Tue, 6 Sep 2016 11:15:48 +0200 Subject: rbd: silence bogus -Wmaybe-uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/block/rbd.c: In function ‘rbd_watch_cb’: drivers/block/rbd.c:3690:5: error: ‘struct_v’ may be used uninitialized in this function [-Werror=maybe-uninitialized] drivers/block/rbd.c:3759:5: note: ‘struct_v’ was declared here Signed-off-by: Ilya Dryomov --- drivers/block/rbd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index 7b274ff4632c..36d2b9f4e836 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c @@ -3756,7 +3756,7 @@ static void rbd_watch_cb(void *arg, u64 notify_id, u64 cookie, struct rbd_device *rbd_dev = arg; void *p = data; void *const end = p + data_len; - u8 struct_v; + u8 struct_v = 0; u32 len; u32 notify_op; int ret; -- cgit v1.2.3 From a220871be66f99d8957c693cf22ec67ecbd9c23a Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Tue, 13 Dec 2016 14:23:05 +0800 Subject: virtio-net: correctly enable multiqueue Commit 4490001029012539937ff02778fe6180613fa949 ("virtio-net: enable multiqueue by default") blindly set the affinity instead of queues during probe which can cause a mismatch of #queues between guest and host. This patch fixes it by setting queues. Reported-by: Theodore Ts'o Tested-by: Theodore Ts'o Cc: Neil Horman Cc: Michael S. Tsirkin Fixes: 49000102901 ("virtio-net: enable multiqueue by default") Signed-off-by: Jason Wang Acked-by: Michael S. Tsirkin Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index b425fa1013af..fe9f7726e990 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1930,7 +1930,9 @@ static int virtnet_probe(struct virtio_device *vdev) goto free_unregister_netdev; } - virtnet_set_affinity(vi); + rtnl_lock(); + virtnet_set_queues(vi, vi->curr_queue_pairs); + rtnl_unlock(); /* Assume link up if device can't report link status, otherwise get link status from config. */ -- cgit v1.2.3 From 5241b1938a4d33eee3d3b43f23067c8e5b96db45 Mon Sep 17 00:00:00 2001 From: "Lee, Chun-Yi" Date: Tue, 1 Nov 2016 12:30:58 +0800 Subject: platform/x86: acer-wmi: Only supports AMW0_GUID1 on acer family MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The AMW0_GUID1 wmi is not only found on Acer family but also other machines like Lenovo, Fujitsu and Medion. In the past, acer-wmi handled those non-Acer machines by quirks list. But actually acer-wmi driver was loaded on any machine that had AMW0_GUID1. This behavior is strange because those machines should be supported by appropriate wmi drivers. e.g. fujitsu-laptop, ideapad-laptop. This patch adds the logic to check the machine that has AMW0_GUID1 should be in Acer/Packard Bell/Gateway white list. But, it still keeps the quirk list of those supported non-acer machines for backward compatibility. Tested-by: Bjørn Mork Signed-off-by: Lee, Chun-Yi Signed-off-by: Darren Hart --- drivers/platform/x86/acer-wmi.c | 56 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c index 79d64ea00bfb..a66192f692e3 100644 --- a/drivers/platform/x86/acer-wmi.c +++ b/drivers/platform/x86/acer-wmi.c @@ -355,6 +355,32 @@ static const struct dmi_system_id acer_blacklist[] __initconst = { {} }; +static const struct dmi_system_id amw0_whitelist[] __initconst = { + { + .ident = "Acer", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Acer"), + }, + }, + { + .ident = "Gateway", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Gateway"), + }, + }, + { + .ident = "Packard Bell", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Packard Bell"), + }, + }, + {} +}; + +/* + * This quirk table is only for Acer/Gateway/Packard Bell family + * that those machines are supported by acer-wmi driver. + */ static const struct dmi_system_id acer_quirks[] __initconst = { { .callback = dmi_matched, @@ -464,6 +490,17 @@ static const struct dmi_system_id acer_quirks[] __initconst = { }, .driver_data = &quirk_acer_travelmate_2490, }, + {} +}; + +/* + * This quirk list is for those non-acer machines that have AMW0_GUID1 + * but supported by acer-wmi in past days. Keeping this quirk list here + * is only for backward compatible. Please do not add new machine to + * here anymore. Those non-acer machines should be supported by + * appropriate wmi drivers. + */ +static const struct dmi_system_id non_acer_quirks[] __initconst = { { .callback = dmi_matched, .ident = "Fujitsu Siemens Amilo Li 1718", @@ -598,6 +635,7 @@ static void __init find_quirks(void) { if (!force_series) { dmi_check_system(acer_quirks); + dmi_check_system(non_acer_quirks); } else if (force_series == 2490) { quirks = &quirk_acer_travelmate_2490; } @@ -2107,6 +2145,24 @@ static int __init acer_wmi_init(void) find_quirks(); + /* + * The AMW0_GUID1 wmi is not only found on Acer family but also other + * machines like Lenovo, Fujitsu and Medion. In the past days, + * acer-wmi driver handled those non-Acer machines by quirks list. + * But actually acer-wmi driver was loaded on any machines that have + * AMW0_GUID1. This behavior is strange because those machines should + * be supported by appropriate wmi drivers. e.g. fujitsu-laptop, + * ideapad-laptop. So, here checks the machine that has AMW0_GUID1 + * should be in Acer/Gateway/Packard Bell white list, or it's already + * in the past quirk list. + */ + if (wmi_has_guid(AMW0_GUID1) && + !dmi_check_system(amw0_whitelist) && + quirks == &quirk_unknown) { + pr_err("Unsupported machine has AMW0_GUID1, unable to load\n"); + return -ENODEV; + } + /* * Detect which ACPI-WMI interface we're using. */ -- cgit v1.2.3 From 8434709ba71473f75572245c247d3c1e92509cf3 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 7 Oct 2016 16:01:12 +0530 Subject: platform/x86: intel_pmc_core: Fix PWRMBASE mask and mmio reg len On Sunrise Point PCH, the Power Management Controller provides 4K bytes of memory space for various power management and debug registers. This fix is needed to access power management & debug registers that are mapped at a higher offset. Also, this provides a fix for correctly masking the PWRMBASE as the initial bits (0-11) are reserved. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 1 + drivers/platform/x86/intel_pmc_core.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index e8b1b836ca2d..5774882a5300 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -149,6 +149,7 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) dev_dbg(&dev->dev, "PMC Core: failed to read PCI config space.\n"); return err; } + pmcdev->base_addr &= PMC_BASE_ADDR_MASK; dev_dbg(&dev->dev, "PMC Core: PWRMBASE is %#x\n", pmcdev->base_addr); pmcdev->regbase = devm_ioremap_nocache(ptr_dev, diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index e3f671f4d122..cde31ec02266 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -26,8 +26,9 @@ #define SPT_PMC_BASE_ADDR_OFFSET 0x48 #define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c -#define SPT_PMC_MMIO_REG_LEN 0x100 +#define SPT_PMC_MMIO_REG_LEN 0x1000 #define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x64 +#define PMC_BASE_ADDR_MASK ~(SPT_PMC_MMIO_REG_LEN - 1) /** * struct pmc_dev - pmc device structure -- cgit v1.2.3 From 0bdfaf429d1da662742708153bf8cc945bf4904b Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 7 Oct 2016 16:01:13 +0530 Subject: platform/x86: intel_pmc_core: Add PCH IP Power Gating Status This patch adds the support for reading the power gating status of various devices present on Sunrise Point PCH. This is intended to be used for debugging purpose while tuning the platform for power optimizations and also to understand which devices (on PCH) are blocking the system to enter a low power state. Power Management Controller on Sunrise Point PCH provides access to "PGD PFET Enable Ack Status Registers (ppfear)". This patch reads and decodes this register and dumps the output in formatted manner showing various devices present on the PCH and their "Power Gating" status. Further documentation can be found in Intel 7th Gen Core family mobile u/y processor io datasheet volume 2. Sample output (stripped and not in order): cat /sys/kernel/debug/pmc_core/pch_ip_power_gating_status PMC State: Not Power gated OPI-DMI State: Not Power gated XHCI State: Power gated LPSS State: Power gated CSME_PSF State: Not power gated Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 122 ++++++++++++++++++++++++++++++++-- drivers/platform/x86/intel_pmc_core.h | 67 +++++++++++++++++++ 2 files changed, 184 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 5774882a5300..14aac633479a 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -32,11 +32,65 @@ static struct pmc_dev pmc; +static const struct pmc_bit_map spt_pfear_map[] = { + {"PMC", SPT_PMC_BIT_PMC}, + {"OPI-DMI", SPT_PMC_BIT_OPI}, + {"SPI / eSPI", SPT_PMC_BIT_SPI}, + {"XHCI", SPT_PMC_BIT_XHCI}, + {"SPA", SPT_PMC_BIT_SPA}, + {"SPB", SPT_PMC_BIT_SPB}, + {"SPC", SPT_PMC_BIT_SPC}, + {"GBE", SPT_PMC_BIT_GBE}, + {"SATA", SPT_PMC_BIT_SATA}, + {"HDA-PGD0", SPT_PMC_BIT_HDA_PGD0}, + {"HDA-PGD1", SPT_PMC_BIT_HDA_PGD1}, + {"HDA-PGD2", SPT_PMC_BIT_HDA_PGD2}, + {"HDA-PGD3", SPT_PMC_BIT_HDA_PGD3}, + {"RSVD", SPT_PMC_BIT_RSVD_0B}, + {"LPSS", SPT_PMC_BIT_LPSS}, + {"LPC", SPT_PMC_BIT_LPC}, + {"SMB", SPT_PMC_BIT_SMB}, + {"ISH", SPT_PMC_BIT_ISH}, + {"P2SB", SPT_PMC_BIT_P2SB}, + {"DFX", SPT_PMC_BIT_DFX}, + {"SCC", SPT_PMC_BIT_SCC}, + {"RSVD", SPT_PMC_BIT_RSVD_0C}, + {"FUSE", SPT_PMC_BIT_FUSE}, + {"CAMERA", SPT_PMC_BIT_CAMREA}, + {"RSVD", SPT_PMC_BIT_RSVD_0D}, + {"USB3-OTG", SPT_PMC_BIT_USB3_OTG}, + {"EXI", SPT_PMC_BIT_EXI}, + {"CSE", SPT_PMC_BIT_CSE}, + {"CSME_KVM", SPT_PMC_BIT_CSME_KVM}, + {"CSME_PMT", SPT_PMC_BIT_CSME_PMT}, + {"CSME_CLINK", SPT_PMC_BIT_CSME_CLINK}, + {"CSME_PTIO", SPT_PMC_BIT_CSME_PTIO}, + {"CSME_USBR", SPT_PMC_BIT_CSME_USBR}, + {"CSME_SUSRAM", SPT_PMC_BIT_CSME_SUSRAM}, + {"CSME_SMT", SPT_PMC_BIT_CSME_SMT}, + {"RSVD", SPT_PMC_BIT_RSVD_1A}, + {"CSME_SMS2", SPT_PMC_BIT_CSME_SMS2}, + {"CSME_SMS1", SPT_PMC_BIT_CSME_SMS1}, + {"CSME_RTC", SPT_PMC_BIT_CSME_RTC}, + {"CSME_PSF", SPT_PMC_BIT_CSME_PSF}, + {}, +}; + +static const struct pmc_reg_map spt_reg_map = { + .pfear_sts = spt_pfear_map, +}; + static const struct pci_device_id pmc_pci_ids[] = { - { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), (kernel_ulong_t)NULL }, + { PCI_VDEVICE(INTEL, SPT_PMC_PCI_DEVICE_ID), + (kernel_ulong_t)&spt_reg_map }, { 0, }, }; +static inline u8 pmc_core_reg_read_byte(struct pmc_dev *pmcdev, int offset) +{ + return readb(pmcdev->regbase + offset); +} + static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset) { return readl(pmcdev->regbase + reg_offset); @@ -90,6 +144,45 @@ static int pmc_core_dev_state_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n"); +#if IS_ENABLED(CONFIG_DEBUG_FS) +static void pmc_core_display_map(struct seq_file *s, int index, + u8 pf_reg, const struct pmc_bit_map *pf_map) +{ + seq_printf(s, "PCH IP: %-2d - %-32s\tState: %s\n", + index, pf_map[index].name, + pf_map[index].bit_mask & pf_reg ? "Off" : "On"); +} + +static int pmc_core_ppfear_sts_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmcdev = s->private; + const struct pmc_bit_map *map = pmcdev->map->pfear_sts; + u8 pf_regs[NUM_ENTRIES]; + int index, iter; + + iter = SPT_PMC_XRAM_PPFEAR0A; + + for (index = 0; index < NUM_ENTRIES; index++, iter++) + pf_regs[index] = pmc_core_reg_read_byte(pmcdev, iter); + + for (index = 0; map[index].name; index++) + pmc_core_display_map(s, index, pf_regs[index / 8], map); + + return 0; +} + +static int pmc_core_ppfear_sts_open(struct inode *inode, struct file *file) +{ + return single_open(file, pmc_core_ppfear_sts_show, inode->i_private); +} + +static const struct file_operations pmc_core_ppfear_ops = { + .open = pmc_core_ppfear_sts_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { debugfs_remove_recursive(pmcdev->dbgfs_dir); @@ -106,14 +199,31 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) pmcdev->dbgfs_dir = dir; file = debugfs_create_file("slp_s0_residency_usec", S_IFREG | S_IRUGO, dir, pmcdev, &pmc_core_dev_state); + if (!file) + goto err; - if (!file) { - pmc_core_dbgfs_unregister(pmcdev); - return -ENODEV; - } + file = debugfs_create_file("pch_ip_power_gating_status", + S_IFREG | S_IRUGO, dir, pmcdev, + &pmc_core_ppfear_ops); + if (!file) + goto err; return 0; + +err: + pmc_core_dbgfs_unregister(pmcdev); + return -ENODEV; +} +#else +static inline int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) +{ + return 0; +} + +static inline void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) +{ } +#endif /* CONFIG_DEBUG_FS */ static const struct x86_cpu_id intel_pmc_core_ids[] = { { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_MOBILE, X86_FEATURE_MWAIT, @@ -128,6 +238,7 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) struct device *ptr_dev = &dev->dev; struct pmc_dev *pmcdev = &pmc; const struct x86_cpu_id *cpu_id; + const struct pmc_reg_map *map = (struct pmc_reg_map *)id->driver_data; int err; cpu_id = x86_match_cpu(intel_pmc_core_ids); @@ -164,6 +275,7 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) if (err < 0) dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); + pmcdev->map = map; pmc.has_slp_s0_res = true; return 0; } diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index cde31ec02266..d034cd309172 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -29,6 +29,70 @@ #define SPT_PMC_MMIO_REG_LEN 0x1000 #define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x64 #define PMC_BASE_ADDR_MASK ~(SPT_PMC_MMIO_REG_LEN - 1) +#define NUM_ENTRIES 5 + +/* Sunrise Point: PGD PFET Enable Ack Status Registers */ +enum ppfear_regs { + SPT_PMC_XRAM_PPFEAR0A = 0x590, + SPT_PMC_XRAM_PPFEAR0B, + SPT_PMC_XRAM_PPFEAR0C, + SPT_PMC_XRAM_PPFEAR0D, + SPT_PMC_XRAM_PPFEAR1A, +}; + +#define SPT_PMC_BIT_PMC BIT(0) +#define SPT_PMC_BIT_OPI BIT(1) +#define SPT_PMC_BIT_SPI BIT(2) +#define SPT_PMC_BIT_XHCI BIT(3) +#define SPT_PMC_BIT_SPA BIT(4) +#define SPT_PMC_BIT_SPB BIT(5) +#define SPT_PMC_BIT_SPC BIT(6) +#define SPT_PMC_BIT_GBE BIT(7) + +#define SPT_PMC_BIT_SATA BIT(0) +#define SPT_PMC_BIT_HDA_PGD0 BIT(1) +#define SPT_PMC_BIT_HDA_PGD1 BIT(2) +#define SPT_PMC_BIT_HDA_PGD2 BIT(3) +#define SPT_PMC_BIT_HDA_PGD3 BIT(4) +#define SPT_PMC_BIT_RSVD_0B BIT(5) +#define SPT_PMC_BIT_LPSS BIT(6) +#define SPT_PMC_BIT_LPC BIT(7) + +#define SPT_PMC_BIT_SMB BIT(0) +#define SPT_PMC_BIT_ISH BIT(1) +#define SPT_PMC_BIT_P2SB BIT(2) +#define SPT_PMC_BIT_DFX BIT(3) +#define SPT_PMC_BIT_SCC BIT(4) +#define SPT_PMC_BIT_RSVD_0C BIT(5) +#define SPT_PMC_BIT_FUSE BIT(6) +#define SPT_PMC_BIT_CAMREA BIT(7) + +#define SPT_PMC_BIT_RSVD_0D BIT(0) +#define SPT_PMC_BIT_USB3_OTG BIT(1) +#define SPT_PMC_BIT_EXI BIT(2) +#define SPT_PMC_BIT_CSE BIT(3) +#define SPT_PMC_BIT_CSME_KVM BIT(4) +#define SPT_PMC_BIT_CSME_PMT BIT(5) +#define SPT_PMC_BIT_CSME_CLINK BIT(6) +#define SPT_PMC_BIT_CSME_PTIO BIT(7) + +#define SPT_PMC_BIT_CSME_USBR BIT(0) +#define SPT_PMC_BIT_CSME_SUSRAM BIT(1) +#define SPT_PMC_BIT_CSME_SMT BIT(2) +#define SPT_PMC_BIT_RSVD_1A BIT(3) +#define SPT_PMC_BIT_CSME_SMS2 BIT(4) +#define SPT_PMC_BIT_CSME_SMS1 BIT(5) +#define SPT_PMC_BIT_CSME_RTC BIT(6) +#define SPT_PMC_BIT_CSME_PSF BIT(7) + +struct pmc_bit_map { + const char *name; + u32 bit_mask; +}; + +struct pmc_reg_map { + const struct pmc_bit_map *pfear_sts; +}; /** * struct pmc_dev - pmc device structure @@ -44,7 +108,10 @@ struct pmc_dev { u32 base_addr; void __iomem *regbase; + const struct pmc_reg_map *map; +#if IS_ENABLED(CONFIG_DEBUG_FS) struct dentry *dbgfs_dir; +#endif /* CONFIG_DEBUG_FS */ bool has_slp_s0_res; }; -- cgit v1.2.3 From 173943b3dae570d705e3f5237110a64a28c0bf74 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 7 Oct 2016 16:01:14 +0530 Subject: platform/x86: intel_pmc_core: ModPhy core lanes pg status The PCH implements a number of High Speed I/O (HSIO) lanes that are split between PCIe*, USB 3.0, SATA, GbE, USB OTG and SSIC. This patch shows the current power gating status of the available ModPhy Core lanes. This is done by sending a message to the PMC (MTPMC) that contains the XRAM register offset for the MPHY_CORE_STS_0 and MPHY_CORE_STS_1 and then by reading the response sent by the PMC (MFPMC). While enabling low power modes we often encounter situations when the ModPhy lanes are not power gated and it becomes hard to debug which lane is active and which is not in the absence of an external hardware debugger (JTAG/ITP). This patch eliminates the dependency on an external hardware debugger for reading the ModPhy Lanes power gating status. This patch requires PMC_READ_DISABLE setting to be disabled in the platform bios. cat /sys/kernel/debug/pmc_core/mphy_lanes_power_gating_status Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 145 +++++++++++++++++++++++++++++++++- drivers/platform/x86/intel_pmc_core.h | 31 ++++++++ 2 files changed, 175 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 14aac633479a..1d9d340492d8 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,26 @@ static struct pmc_dev pmc; +static const struct pmc_bit_map spt_mphy_map[] = { + {"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0}, + {"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1}, + {"MPHY CORE LANE 2", SPT_PMC_BIT_MPHY_LANE2}, + {"MPHY CORE LANE 3", SPT_PMC_BIT_MPHY_LANE3}, + {"MPHY CORE LANE 4", SPT_PMC_BIT_MPHY_LANE4}, + {"MPHY CORE LANE 5", SPT_PMC_BIT_MPHY_LANE5}, + {"MPHY CORE LANE 6", SPT_PMC_BIT_MPHY_LANE6}, + {"MPHY CORE LANE 7", SPT_PMC_BIT_MPHY_LANE7}, + {"MPHY CORE LANE 8", SPT_PMC_BIT_MPHY_LANE8}, + {"MPHY CORE LANE 9", SPT_PMC_BIT_MPHY_LANE9}, + {"MPHY CORE LANE 10", SPT_PMC_BIT_MPHY_LANE10}, + {"MPHY CORE LANE 11", SPT_PMC_BIT_MPHY_LANE11}, + {"MPHY CORE LANE 12", SPT_PMC_BIT_MPHY_LANE12}, + {"MPHY CORE LANE 13", SPT_PMC_BIT_MPHY_LANE13}, + {"MPHY CORE LANE 14", SPT_PMC_BIT_MPHY_LANE14}, + {"MPHY CORE LANE 15", SPT_PMC_BIT_MPHY_LANE15}, + {}, +}; + static const struct pmc_bit_map spt_pfear_map[] = { {"PMC", SPT_PMC_BIT_PMC}, {"OPI-DMI", SPT_PMC_BIT_OPI}, @@ -78,6 +99,7 @@ static const struct pmc_bit_map spt_pfear_map[] = { static const struct pmc_reg_map spt_reg_map = { .pfear_sts = spt_pfear_map, + .mphy_sts = spt_mphy_map, }; static const struct pci_device_id pmc_pci_ids[] = { @@ -96,6 +118,12 @@ static inline u32 pmc_core_reg_read(struct pmc_dev *pmcdev, int reg_offset) return readl(pmcdev->regbase + reg_offset); } +static inline void pmc_core_reg_write(struct pmc_dev *pmcdev, int + reg_offset, u32 val) +{ + writel(val, pmcdev->regbase + reg_offset); +} + static inline u32 pmc_core_adjust_slp_s0_step(u32 value) { return value * SPT_PMC_SLP_S0_RES_COUNTER_STEP; @@ -144,6 +172,16 @@ static int pmc_core_dev_state_get(void *data, u64 *val) DEFINE_DEBUGFS_ATTRIBUTE(pmc_core_dev_state, pmc_core_dev_state_get, NULL, "%llu\n"); +static int pmc_core_check_read_lock_bit(void) +{ + struct pmc_dev *pmcdev = &pmc; + u32 value; + + value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_CFG_OFFSET); + return test_bit(SPT_PMC_READ_DISABLE_BIT, + (unsigned long *)&value); +} + #if IS_ENABLED(CONFIG_DEBUG_FS) static void pmc_core_display_map(struct seq_file *s, int index, u8 pf_reg, const struct pmc_bit_map *pf_map) @@ -183,6 +221,102 @@ static const struct file_operations pmc_core_ppfear_ops = { .release = single_release, }; +/* This function should return link status, 0 means ready */ +static int pmc_core_mtpmc_link_status(void) +{ + struct pmc_dev *pmcdev = &pmc; + u32 value; + + value = pmc_core_reg_read(pmcdev, SPT_PMC_PM_STS_OFFSET); + return test_bit(SPT_PMC_MSG_FULL_STS_BIT, + (unsigned long *)&value); +} + +static int pmc_core_send_msg(u32 *addr_xram) +{ + struct pmc_dev *pmcdev = &pmc; + u32 dest; + int timeout; + + for (timeout = NUM_RETRIES; timeout > 0; timeout--) { + if (pmc_core_mtpmc_link_status() == 0) + break; + msleep(5); + } + + if (timeout <= 0 && pmc_core_mtpmc_link_status()) + return -EBUSY; + + dest = (*addr_xram & MTPMC_MASK) | (1U << 1); + pmc_core_reg_write(pmcdev, SPT_PMC_MTPMC_OFFSET, dest); + return 0; +} + +static int pmc_core_mphy_pg_sts_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmcdev = s->private; + const struct pmc_bit_map *map = pmcdev->map->mphy_sts; + u32 mphy_core_reg_low, mphy_core_reg_high; + u32 val_low, val_high; + int index, err = 0; + + if (pmcdev->pmc_xram_read_bit) { + seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); + return 0; + } + + mphy_core_reg_low = (SPT_PMC_MPHY_CORE_STS_0 << 16); + mphy_core_reg_high = (SPT_PMC_MPHY_CORE_STS_1 << 16); + + mutex_lock(&pmcdev->lock); + + if (pmc_core_send_msg(&mphy_core_reg_low) != 0) { + err = -EBUSY; + goto out_unlock; + } + + msleep(10); + val_low = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET); + + if (pmc_core_send_msg(&mphy_core_reg_high) != 0) { + err = -EBUSY; + goto out_unlock; + } + + msleep(10); + val_high = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET); + + for (index = 0; map[index].name && index < 8; index++) { + seq_printf(s, "%-32s\tState: %s\n", + map[index].name, + map[index].bit_mask & val_low ? "Not power gated" : + "Power gated"); + } + + for (index = 8; map[index].name; index++) { + seq_printf(s, "%-32s\tState: %s\n", + map[index].name, + map[index].bit_mask & val_high ? "Not power gated" : + "Power gated"); + } + +out_unlock: + mutex_unlock(&pmcdev->lock); + return err; +} + +static int pmc_core_mphy_pg_sts_open(struct inode *inode, struct file *file) +{ + return single_open(file, pmc_core_mphy_pg_sts_show, inode->i_private); +} + +static const struct file_operations pmc_core_mphy_pg_ops = { + .open = pmc_core_mphy_pg_sts_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { debugfs_remove_recursive(pmcdev->dbgfs_dir); @@ -208,6 +342,12 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) if (!file) goto err; + file = debugfs_create_file("mphy_core_lanes_power_gating_status", + S_IFREG | S_IRUGO, dir, pmcdev, + &pmc_core_mphy_pg_ops); + if (!file) + goto err; + return 0; err: @@ -271,11 +411,14 @@ static int pmc_core_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENOMEM; } + mutex_init(&pmcdev->lock); + pmcdev->pmc_xram_read_bit = pmc_core_check_read_lock_bit(); + pmcdev->map = map; + err = pmc_core_dbgfs_register(pmcdev); if (err < 0) dev_warn(&dev->dev, "PMC Core: debugfs register failed.\n"); - pmcdev->map = map; pmc.has_slp_s0_res = true; return 0; } diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index d034cd309172..62fe5d15a9b2 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -26,10 +26,20 @@ #define SPT_PMC_BASE_ADDR_OFFSET 0x48 #define SPT_PMC_SLP_S0_RES_COUNTER_OFFSET 0x13c +#define SPT_PMC_PM_CFG_OFFSET 0x18 +#define SPT_PMC_PM_STS_OFFSET 0x1c +#define SPT_PMC_MTPMC_OFFSET 0x20 +#define SPT_PMC_MFPMC_OFFSET 0x38 +#define SPT_PMC_MPHY_CORE_STS_0 0x1143 +#define SPT_PMC_MPHY_CORE_STS_1 0x1142 #define SPT_PMC_MMIO_REG_LEN 0x1000 #define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x64 #define PMC_BASE_ADDR_MASK ~(SPT_PMC_MMIO_REG_LEN - 1) +#define MTPMC_MASK 0xffff0000 #define NUM_ENTRIES 5 +#define SPT_PMC_READ_DISABLE_BIT 0x16 +#define SPT_PMC_MSG_FULL_STS_BIT 0x18 +#define NUM_RETRIES 100 /* Sunrise Point: PGD PFET Enable Ack Status Registers */ enum ppfear_regs { @@ -85,6 +95,24 @@ enum ppfear_regs { #define SPT_PMC_BIT_CSME_RTC BIT(6) #define SPT_PMC_BIT_CSME_PSF BIT(7) +#define SPT_PMC_BIT_MPHY_LANE0 BIT(0) +#define SPT_PMC_BIT_MPHY_LANE1 BIT(1) +#define SPT_PMC_BIT_MPHY_LANE2 BIT(2) +#define SPT_PMC_BIT_MPHY_LANE3 BIT(3) +#define SPT_PMC_BIT_MPHY_LANE4 BIT(4) +#define SPT_PMC_BIT_MPHY_LANE5 BIT(5) +#define SPT_PMC_BIT_MPHY_LANE6 BIT(6) +#define SPT_PMC_BIT_MPHY_LANE7 BIT(7) + +#define SPT_PMC_BIT_MPHY_LANE8 BIT(0) +#define SPT_PMC_BIT_MPHY_LANE9 BIT(1) +#define SPT_PMC_BIT_MPHY_LANE10 BIT(2) +#define SPT_PMC_BIT_MPHY_LANE11 BIT(3) +#define SPT_PMC_BIT_MPHY_LANE12 BIT(4) +#define SPT_PMC_BIT_MPHY_LANE13 BIT(5) +#define SPT_PMC_BIT_MPHY_LANE14 BIT(6) +#define SPT_PMC_BIT_MPHY_LANE15 BIT(7) + struct pmc_bit_map { const char *name; u32 bit_mask; @@ -92,6 +120,7 @@ struct pmc_bit_map { struct pmc_reg_map { const struct pmc_bit_map *pfear_sts; + const struct pmc_bit_map *mphy_sts; }; /** @@ -113,6 +142,8 @@ struct pmc_dev { struct dentry *dbgfs_dir; #endif /* CONFIG_DEBUG_FS */ bool has_slp_s0_res; + int pmc_xram_read_bit; + struct mutex lock; /* generic mutex lock for PMC Core */ }; #endif /* PMC_CORE_H */ -- cgit v1.2.3 From fe748227570107abaa4767c39be3eff934bdaf5c Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 7 Oct 2016 16:01:15 +0530 Subject: platform/x86: intel_pmc_core: Add MPHY PLL clock gating status ModPhy Common lanes can provide the clock gating status for the important system PLLs such as Gen2 USB3PCIE2 PLL, DMIPCIE3 PLL, SATA PLL and MIPI PLL. On SPT, in addition to the crystal oscillator clock, the 100Mhz Gen2 USB3PCI2 PLL clock is used as the PLL reference clock and Gen2 PLL idling is a necessary condition for the platform to go into low power states like PC10 and S0ix. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 63 ++++++++++++++++++++++++++++++++++- drivers/platform/x86/intel_pmc_core.h | 7 ++++ 2 files changed, 69 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 1d9d340492d8..bd1f4eff4553 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -33,6 +33,14 @@ static struct pmc_dev pmc; +static const struct pmc_bit_map spt_pll_map[] = { + {"MIPI PLL", SPT_PMC_BIT_MPHY_CMN_LANE0}, + {"GEN2 USB2PCIE2 PLL", SPT_PMC_BIT_MPHY_CMN_LANE1}, + {"DMIPCIE3 PLL", SPT_PMC_BIT_MPHY_CMN_LANE2}, + {"SATA PLL", SPT_PMC_BIT_MPHY_CMN_LANE3}, + {}, +}; + static const struct pmc_bit_map spt_mphy_map[] = { {"MPHY CORE LANE 0", SPT_PMC_BIT_MPHY_LANE0}, {"MPHY CORE LANE 1", SPT_PMC_BIT_MPHY_LANE1}, @@ -100,6 +108,7 @@ static const struct pmc_bit_map spt_pfear_map[] = { static const struct pmc_reg_map spt_reg_map = { .pfear_sts = spt_pfear_map, .mphy_sts = spt_mphy_map, + .pll_sts = spt_pll_map, }; static const struct pci_device_id pmc_pci_ids[] = { @@ -317,6 +326,53 @@ static const struct file_operations pmc_core_mphy_pg_ops = { .release = single_release, }; +static int pmc_core_pll_show(struct seq_file *s, void *unused) +{ + struct pmc_dev *pmcdev = s->private; + const struct pmc_bit_map *map = pmcdev->map->pll_sts; + u32 mphy_common_reg, val; + int index, err = 0; + + if (pmcdev->pmc_xram_read_bit) { + seq_puts(s, "Access denied: please disable PMC_READ_DISABLE setting in BIOS."); + return 0; + } + + mphy_common_reg = (SPT_PMC_MPHY_COM_STS_0 << 16); + mutex_lock(&pmcdev->lock); + + if (pmc_core_send_msg(&mphy_common_reg) != 0) { + err = -EBUSY; + goto out_unlock; + } + + /* Observed PMC HW response latency for MTPMC-MFPMC is ~10 ms */ + msleep(10); + val = pmc_core_reg_read(pmcdev, SPT_PMC_MFPMC_OFFSET); + + for (index = 0; map[index].name ; index++) { + seq_printf(s, "%-32s\tState: %s\n", + map[index].name, + map[index].bit_mask & val ? "Active" : "Idle"); + } + +out_unlock: + mutex_unlock(&pmcdev->lock); + return err; +} + +static int pmc_core_pll_open(struct inode *inode, struct file *file) +{ + return single_open(file, pmc_core_pll_show, inode->i_private); +} + +static const struct file_operations pmc_core_pll_ops = { + .open = pmc_core_pll_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { debugfs_remove_recursive(pmcdev->dbgfs_dir); @@ -348,8 +404,13 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) if (!file) goto err; - return 0; + file = debugfs_create_file("pll_status", + S_IFREG | S_IRUGO, dir, pmcdev, + &pmc_core_pll_ops); + if (!file) + goto err; + return 0; err: pmc_core_dbgfs_unregister(pmcdev); return -ENODEV; diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 62fe5d15a9b2..07161fb33bb6 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -32,6 +32,7 @@ #define SPT_PMC_MFPMC_OFFSET 0x38 #define SPT_PMC_MPHY_CORE_STS_0 0x1143 #define SPT_PMC_MPHY_CORE_STS_1 0x1142 +#define SPT_PMC_MPHY_COM_STS_0 0x1155 #define SPT_PMC_MMIO_REG_LEN 0x1000 #define SPT_PMC_SLP_S0_RES_COUNTER_STEP 0x64 #define PMC_BASE_ADDR_MASK ~(SPT_PMC_MMIO_REG_LEN - 1) @@ -113,6 +114,11 @@ enum ppfear_regs { #define SPT_PMC_BIT_MPHY_LANE14 BIT(6) #define SPT_PMC_BIT_MPHY_LANE15 BIT(7) +#define SPT_PMC_BIT_MPHY_CMN_LANE0 BIT(0) +#define SPT_PMC_BIT_MPHY_CMN_LANE1 BIT(1) +#define SPT_PMC_BIT_MPHY_CMN_LANE2 BIT(2) +#define SPT_PMC_BIT_MPHY_CMN_LANE3 BIT(3) + struct pmc_bit_map { const char *name; u32 bit_mask; @@ -121,6 +127,7 @@ struct pmc_bit_map { struct pmc_reg_map { const struct pmc_bit_map *pfear_sts; const struct pmc_bit_map *mphy_sts; + const struct pmc_bit_map *pll_sts; }; /** -- cgit v1.2.3 From 9c2ee19987ef02fe3dbe507d81ff5c7dd5bb4f21 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 7 Oct 2016 16:01:16 +0530 Subject: platform/x86: intel_pmc_core: Add LTR IGNORE debug feature SPT LTR_IGN register provides a means to make the PMC ignore the LTR values reported by the individual PCH devices. echo > /sys/kernel/debug/pmc_core/ltr_ignore. When a particular IP Offset bit is set the PMC will ignore the LTR value reported by the corresponding IP when the PMC performs the latency coalescing. IP Offset IP Name 0 SPA 1 SPB 2 SATA 3 GBE 4 XHCI 5 RSVD 6 ME 7 EVA 8 SPC 9 Azalia/ADSP 10 RSVD 11 LPSS 12 SPD 13 SPE 14 Camera 15 ESPI 16 SCC 17 ISH Signed-off-by: Rajneesh Bhardwaj [dvhart: pmc_core_ltr_ignore_write local declaration order cleanup] Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 57 ++++++++++++++++++++++++++++++++++- drivers/platform/x86/intel_pmc_core.h | 2 ++ 2 files changed, 58 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index bd1f4eff4553..0a81607d8e56 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -19,11 +19,12 @@ */ #include +#include #include #include #include #include -#include +#include #include #include @@ -373,6 +374,53 @@ static const struct file_operations pmc_core_pll_ops = { .release = single_release, }; +static ssize_t pmc_core_ltr_ignore_write(struct file *file, const char __user +*userbuf, size_t count, loff_t *ppos) +{ + struct pmc_dev *pmcdev = &pmc; + u32 val, buf_size, fd; + int err = 0; + + buf_size = count < 64 ? count : 64; + mutex_lock(&pmcdev->lock); + + if (kstrtou32_from_user(userbuf, buf_size, 10, &val)) { + err = -EFAULT; + goto out_unlock; + } + + if (val > NUM_IP_IGN_ALLOWED) { + err = -EINVAL; + goto out_unlock; + } + + fd = pmc_core_reg_read(pmcdev, SPT_PMC_LTR_IGNORE_OFFSET); + fd |= (1U << val); + pmc_core_reg_write(pmcdev, SPT_PMC_LTR_IGNORE_OFFSET, fd); + +out_unlock: + mutex_unlock(&pmcdev->lock); + return err == 0 ? count : err; +} + +static int pmc_core_ltr_ignore_show(struct seq_file *s, void *unused) +{ + return 0; +} + +static int pmc_core_ltr_ignore_open(struct inode *inode, struct file *file) +{ + return single_open(file, pmc_core_ltr_ignore_show, inode->i_private); +} + +static const struct file_operations pmc_core_ltr_ignore_ops = { + .open = pmc_core_ltr_ignore_open, + .read = seq_read, + .write = pmc_core_ltr_ignore_write, + .llseek = seq_lseek, + .release = single_release, +}; + static void pmc_core_dbgfs_unregister(struct pmc_dev *pmcdev) { debugfs_remove_recursive(pmcdev->dbgfs_dir); @@ -410,6 +458,13 @@ static int pmc_core_dbgfs_register(struct pmc_dev *pmcdev) if (!file) goto err; + file = debugfs_create_file("ltr_ignore", + S_IFREG | S_IRUGO, dir, pmcdev, + &pmc_core_ltr_ignore_ops); + + if (!file) + goto err; + return 0; err: pmc_core_dbgfs_unregister(pmcdev); diff --git a/drivers/platform/x86/intel_pmc_core.h b/drivers/platform/x86/intel_pmc_core.h index 07161fb33bb6..5a48e7728479 100644 --- a/drivers/platform/x86/intel_pmc_core.h +++ b/drivers/platform/x86/intel_pmc_core.h @@ -30,6 +30,7 @@ #define SPT_PMC_PM_STS_OFFSET 0x1c #define SPT_PMC_MTPMC_OFFSET 0x20 #define SPT_PMC_MFPMC_OFFSET 0x38 +#define SPT_PMC_LTR_IGNORE_OFFSET 0x30C #define SPT_PMC_MPHY_CORE_STS_0 0x1143 #define SPT_PMC_MPHY_CORE_STS_1 0x1142 #define SPT_PMC_MPHY_COM_STS_0 0x1155 @@ -41,6 +42,7 @@ #define SPT_PMC_READ_DISABLE_BIT 0x16 #define SPT_PMC_MSG_FULL_STS_BIT 0x18 #define NUM_RETRIES 100 +#define NUM_IP_IGN_ALLOWED 17 /* Sunrise Point: PGD PFET Enable Ack Status Registers */ enum ppfear_regs { -- cgit v1.2.3 From daf5d1433d6697ec8786604c30f69b2f9d4c7978 Mon Sep 17 00:00:00 2001 From: Rajneesh Bhardwaj Date: Fri, 7 Oct 2016 16:01:17 +0530 Subject: platform/x86: intel_pmc_core: Add KBL CPUID support This patch adds Kabylake CPU support for pmc_core driver. Signed-off-by: Rajneesh Bhardwaj Signed-off-by: Darren Hart --- drivers/platform/x86/intel_pmc_core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_pmc_core.c b/drivers/platform/x86/intel_pmc_core.c index 0a81607d8e56..b130b8c9b9d7 100644 --- a/drivers/platform/x86/intel_pmc_core.c +++ b/drivers/platform/x86/intel_pmc_core.c @@ -486,6 +486,10 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = { (kernel_ulong_t)NULL}, { X86_VENDOR_INTEL, 6, INTEL_FAM6_SKYLAKE_DESKTOP, X86_FEATURE_MWAIT, (kernel_ulong_t)NULL}, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_MOBILE, X86_FEATURE_MWAIT, + (kernel_ulong_t)NULL}, + { X86_VENDOR_INTEL, 6, INTEL_FAM6_KABYLAKE_DESKTOP, X86_FEATURE_MWAIT, + (kernel_ulong_t)NULL}, {} }; -- cgit v1.2.3 From 915ac0574c85e4202a4ede961d9e1230b1cca06f Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 28 Jul 2016 12:53:47 -0500 Subject: platform/x86: dell-wmi: Adjust wifi catcher to emit KEY_WLAN Wifi catcher is a slider switch, that when slid past the on position will emit an event that is intended for launching a wifi application or applet when the machine is turned on. Signed-off-by: Mario Limonciello Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index da2fe18162e1..46c20ec8aed2 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -114,7 +114,7 @@ static const struct key_entry dell_wmi_keymap_type_0000[] __initconst = { { KE_IGNORE, 0xe00e, { KEY_RESERVED } }, /* Wifi Catcher */ - { KE_KEY, 0xe011, { KEY_PROG2 } }, + { KE_KEY, 0xe011, { KEY_WLAN } }, /* Ambient light sensor toggle */ { KE_IGNORE, 0xe013, { KEY_RESERVED } }, -- cgit v1.2.3 From 5dc444b804eae57abaf6f05663d9cb9f030bb9d2 Mon Sep 17 00:00:00 2001 From: Mario Limonciello Date: Thu, 28 Jul 2016 12:53:48 -0500 Subject: platform/x86: dell-wmi: Add events created by Dell Rugged 2-in-1s The Dell Rugged 7202 has 3 programmable buttons (labeled P1, P2, P3) and a detachable keyboard/mouse dock. Signed-off-by: Mario Limonciello Reviewed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko --- drivers/platform/x86/dell-wmi.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-wmi.c b/drivers/platform/x86/dell-wmi.c index 46c20ec8aed2..75e637047d36 100644 --- a/drivers/platform/x86/dell-wmi.c +++ b/drivers/platform/x86/dell-wmi.c @@ -274,6 +274,16 @@ static const struct key_entry dell_wmi_keymap_type_0010[] __initconst = { /* Stealth mode toggle */ { KE_IGNORE, 0x155, { KEY_RESERVED } }, + + /* Rugged magnetic dock attach/detach events */ + { KE_IGNORE, 0x156, { KEY_RESERVED } }, + { KE_IGNORE, 0x157, { KEY_RESERVED } }, + + /* Rugged programmable (P1/P2/P3 keys) */ + { KE_KEY, 0x850, { KEY_PROG1 } }, + { KE_KEY, 0x851, { KEY_PROG2 } }, + { KE_KEY, 0x852, { KEY_PROG3 } }, + }; /* -- cgit v1.2.3 From 3526ecadc86cc1d485153255498cde7d0275dd37 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Mon, 19 Sep 2016 09:33:51 +0800 Subject: platform/x86: Use ACPI_FAILURE at appropriate places Use ACPI_FAILURE() to replace !ACPI_SUCCESS(), this avoid !! operations. Signed-off-by: Axel Lin Acked-by: Henrique de Moraes Holschuh Reviewed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-hid.c | 6 +++--- drivers/platform/x86/intel-smartconnect.c | 2 +- drivers/platform/x86/intel-vbtn.c | 2 +- drivers/platform/x86/panasonic-laptop.c | 2 +- drivers/platform/x86/thinkpad_acpi.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel-hid.c b/drivers/platform/x86/intel-hid.c index ed5874217ee7..00cbeca2108d 100644 --- a/drivers/platform/x86/intel-hid.c +++ b/drivers/platform/x86/intel-hid.c @@ -69,7 +69,7 @@ static int intel_hid_set_enable(struct device *device, int enable) arg0.integer.value = enable; status = acpi_evaluate_object(ACPI_HANDLE(device), "HDSM", &args, NULL); - if (!ACPI_SUCCESS(status)) { + if (ACPI_FAILURE(status)) { dev_warn(device, "failed to %sable hotkeys\n", enable ? "en" : "dis"); return -EIO; @@ -148,7 +148,7 @@ static void notify_handler(acpi_handle handle, u32 event, void *context) } status = acpi_evaluate_integer(handle, "HDEM", NULL, &ev_index); - if (!ACPI_SUCCESS(status)) { + if (ACPI_FAILURE(status)) { dev_warn(&device->dev, "failed to get event index\n"); return; } @@ -167,7 +167,7 @@ static int intel_hid_probe(struct platform_device *device) int err; status = acpi_evaluate_integer(handle, "HDMM", NULL, &mode); - if (!ACPI_SUCCESS(status)) { + if (ACPI_FAILURE(status)) { dev_warn(&device->dev, "failed to read mode\n"); return -ENODEV; } diff --git a/drivers/platform/x86/intel-smartconnect.c b/drivers/platform/x86/intel-smartconnect.c index 04cf5dffdfd9..bbe4c06c769f 100644 --- a/drivers/platform/x86/intel-smartconnect.c +++ b/drivers/platform/x86/intel-smartconnect.c @@ -29,7 +29,7 @@ static int smartconnect_acpi_init(struct acpi_device *acpi) acpi_status status; status = acpi_evaluate_integer(acpi->handle, "GAOS", NULL, &value); - if (!ACPI_SUCCESS(status)) + if (ACPI_FAILURE(status)) return -EINVAL; if (value & 0x1) { diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index 146d02f8c9bc..f04a394d52d6 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -97,7 +97,7 @@ static int intel_vbtn_probe(struct platform_device *device) int err; status = acpi_evaluate_object(handle, "VBDL", NULL, NULL); - if (!ACPI_SUCCESS(status)) { + if (ACPI_FAILURE(status)) { dev_warn(&device->dev, "failed to read Intel Virtual Button driver\n"); return -ENODEV; } diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c index 3f870972247c..59b8eb626dcc 100644 --- a/drivers/platform/x86/panasonic-laptop.c +++ b/drivers/platform/x86/panasonic-laptop.c @@ -458,7 +458,7 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc) rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY, NULL, &result); - if (!ACPI_SUCCESS(rc)) { + if (ACPI_FAILURE(rc)) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "error getting hotkey status\n")); return; diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index b65ce7519411..31fb979b1bfe 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -9018,7 +9018,7 @@ static int mute_led_on_off(struct tp_led_table *t, bool state) acpi_handle temp; int output; - if (!ACPI_SUCCESS(acpi_get_handle(hkey_handle, t->name, &temp))) { + if (ACPI_FAILURE(acpi_get_handle(hkey_handle, t->name, &temp))) { pr_warn("Thinkpad ACPI has no %s interface.\n", t->name); return -EIO; } -- cgit v1.2.3 From bb9ad484845d7cc48f0c8db199a91c3a669d908f Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Tue, 20 Sep 2016 17:01:24 +0800 Subject: platform/x86: intel-vbtn: Switch to use devm_input_allocate_device Use devm_input_allocate_device to simplify the error handling code. This conversion also makes input_register_device() to be called after acpi_remove_notify_handler. This avoid a small window that it's possible to call notify_handler after unregister input device. Signed-off-by: Axel Lin Reviewed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel-vbtn.c | 33 +++++---------------------------- 1 file changed, 5 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/intel-vbtn.c b/drivers/platform/x86/intel-vbtn.c index f04a394d52d6..bd7230a89f15 100644 --- a/drivers/platform/x86/intel-vbtn.c +++ b/drivers/platform/x86/intel-vbtn.c @@ -49,34 +49,19 @@ static int intel_vbtn_input_setup(struct platform_device *device) struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); int ret; - priv->input_dev = input_allocate_device(); + priv->input_dev = devm_input_allocate_device(&device->dev); if (!priv->input_dev) return -ENOMEM; ret = sparse_keymap_setup(priv->input_dev, intel_vbtn_keymap, NULL); if (ret) - goto err_free_device; + return ret; priv->input_dev->dev.parent = &device->dev; priv->input_dev->name = "Intel Virtual Button driver"; priv->input_dev->id.bustype = BUS_HOST; - ret = input_register_device(priv->input_dev); - if (ret) - goto err_free_device; - - return 0; - -err_free_device: - input_free_device(priv->input_dev); - return ret; -} - -static void intel_vbtn_input_destroy(struct platform_device *device) -{ - struct intel_vbtn_priv *priv = dev_get_drvdata(&device->dev); - - input_unregister_device(priv->input_dev); + return input_register_device(priv->input_dev); } static void notify_handler(acpi_handle handle, u32 event, void *context) @@ -117,24 +102,16 @@ static int intel_vbtn_probe(struct platform_device *device) ACPI_DEVICE_NOTIFY, notify_handler, device); - if (ACPI_FAILURE(status)) { - err = -EBUSY; - goto err_remove_input; - } + if (ACPI_FAILURE(status)) + return -EBUSY; return 0; - -err_remove_input: - intel_vbtn_input_destroy(device); - - return err; } static int intel_vbtn_remove(struct platform_device *device) { acpi_handle handle = ACPI_HANDLE(&device->dev); - intel_vbtn_input_destroy(device); acpi_remove_notify_handler(handle, ACPI_DEVICE_NOTIFY, notify_handler); /* -- cgit v1.2.3 From b4aca383f9afb5f84b05de272656e6d4a919d995 Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Sat, 26 Nov 2016 17:01:51 +0100 Subject: platform/x86: intel_mid_thermal: Fix suspend handlers unused warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix: drivers/platform/x86/intel_mid_thermal.c:424:12: warning: ‘mid_thermal_resume’ defined but not used [-Wunused-function] static int mid_thermal_resume(struct device *dev) ^ drivers/platform/x86/intel_mid_thermal.c:436:12: warning: ‘mid_thermal_suspend’ defined but not used [-Wunused-function] static int mid_thermal_suspend(struct device *dev) ^ which I see during randbuilds here. Signed-off-by: Borislav Petkov Cc: Darren Hart Cc: platform-driver-x86@vger.kernel.org Reviewed-by: Andy Shevchenko Signed-off-by: Andy Shevchenko --- drivers/platform/x86/intel_mid_thermal.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/intel_mid_thermal.c b/drivers/platform/x86/intel_mid_thermal.c index 9f713b832ba3..0df3c9d37509 100644 --- a/drivers/platform/x86/intel_mid_thermal.c +++ b/drivers/platform/x86/intel_mid_thermal.c @@ -415,6 +415,7 @@ static struct thermal_device_info *initialize_sensor(int index) return td_info; } +#ifdef CONFIG_PM_SLEEP /** * mid_thermal_resume - resume routine * @dev: device structure @@ -442,6 +443,7 @@ static int mid_thermal_suspend(struct device *dev) */ return configure_adc(0); } +#endif static SIMPLE_DEV_PM_OPS(mid_thermal_pm, mid_thermal_suspend, mid_thermal_resume); -- cgit v1.2.3 From 8023eff10e7b0327898f17f0b553d2e45c71cef3 Mon Sep 17 00:00:00 2001 From: Kai-Chuan Hsieh Date: Thu, 1 Sep 2016 23:55:55 +0800 Subject: platform/x86: asus-wmi: Set specified XUSB2PR value for X550LB The bluetooth adapter Atheros AR3012 can't be enumerated and make the bluetooth function broken. T: Bus=02 Lev=01 Prnt=01 Port=05 Cnt=02 Dev#= 5 Spd=12 MxCh= 0 D: Ver= 1.10 Cls=e0(wlcon) Sub=01 Prot=01 MxPS=64 #Cfgs= 1 P: Vendor=13d3 ProdID=3362 Rev=00.02 S: Manufacturer=Atheros Communications S: Product=Bluetooth USB Host Controller S: SerialNumber=Alaska Day 2006 C: #Ifs= 2 Cfg#= 1 Atr=e0 MxPwr=100mA I: If#= 0 Alt= 0 #EPs= 3 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb I: If#= 1 Alt= 0 #EPs= 2 Cls=e0(wlcon) Sub=01 Prot=01 Driver=btusb The error is: usb 2-6: device not accepting address 7, error -62 usb usb2-port6: unable to enumerate USB device It is caused by adapter's connected port is mapped to xHC controller, but the xHCI is not supported by the usb device. The output of 'sudo lspci -nnxxx -s 00:14.0': 00:14.0 USB controller [0c03]: Intel Corporation 8 Series USB xHCI HC [8086:9c31] (rev 04) 00: 86 80 31 9c 06 04 90 02 04 30 03 0c 00 00 00 00 10: 04 00 a0 f7 00 00 00 00 00 00 00 00 00 00 00 00 20: 00 00 00 00 00 00 00 00 00 00 00 00 43 10 1f 20 30: 00 00 00 00 70 00 00 00 00 00 00 00 0b 01 00 00 40: fd 01 36 80 89 c6 0f 80 00 00 00 00 00 00 00 00 50: 5f 2e ce 0f 00 00 00 00 00 00 00 00 00 00 00 00 60: 30 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 70: 01 80 c2 c1 08 00 00 00 00 00 00 00 00 00 00 00 80: 05 00 87 00 0c a0 e0 fe 00 00 00 00 a1 41 00 00 90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a0: 00 01 04 00 00 00 00 00 00 00 00 00 00 00 00 00 b0: 0f 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 c0: 03 c0 30 00 00 00 00 00 03 0c 00 00 00 00 00 00 d0: f9 01 00 00 f9 01 00 00 0f 00 00 00 0f 00 00 00 e0: 00 08 00 00 00 00 00 00 00 00 00 00 d8 d8 00 00 f0: 00 00 00 00 00 00 00 00 b1 0f 04 08 00 00 00 00 By referencing Intel Platform Controller Hub(PCH) datasheet, the xHC USB 2.0 Port Routing(XUSB2PR) at offset 0xD0-0xD3h decides the setting of mapping the port to EHCI controller or xHC controller. And the port mapped to xHC will enable xHCI during bus resume. The setting of disabling bluetooth adapter's connected port is 0x000001D9. The value can be obtained by few times 1 bit flip operation. The suited configuration should have the 'lsusb -t' result with bluetooth using ehci: /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/9p, 480M |__ Port 5: Dev 2, If 0, Class=Video, Driver=uvcvideo, 480M |__ Port 5: Dev 2, If 1, Class=Video, Driver=uvcvideo, 480M /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/8p, 480M |__ Port 6: Dev 3, If 0, Class=Wireless, Driver=btusb, 12M |__ Port 6: Dev 3, If 1, Class=Wireless, Driver=btusb, 12M Signed-off-by: Kai-Chuan Hsieh Acked-by: Corentin Chary Reviewed-by: Andy Shevchenko [andy: resolve merge conflict in asus-wmi.h] Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-nb-wmi.c | 13 +++++++++++++ drivers/platform/x86/asus-wmi.c | 29 +++++++++++++++++++++++++++++ drivers/platform/x86/asus-wmi.h | 1 + 3 files changed, 43 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 26e4cbc34db8..3ac4f48895dd 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -116,6 +116,10 @@ static struct quirk_entry quirk_asus_ux303ub = { .wmi_backlight_native = true, }; +static struct quirk_entry quirk_asus_x550lb = { + .xusb2pr = 0x01D9, +}; + static int dmi_matched(const struct dmi_system_id *dmi) { quirks = dmi->driver_data; @@ -398,6 +402,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_ux303ub, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X550LB", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X550LB"), + }, + .driver_data = &quirk_asus_x550lb, + }, {}, }; diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index ce6ca31a2d09..43cb680adbb4 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -156,6 +156,9 @@ MODULE_LICENSE("GPL"); #define ASUS_FAN_CTRL_MANUAL 1 #define ASUS_FAN_CTRL_AUTO 2 +#define USB_INTEL_XUSB2PR 0xD0 +#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31 + struct bios_args { u32 arg0; u32 arg1; @@ -1080,6 +1083,29 @@ exit: return result; } +static void asus_wmi_set_xusb2pr(struct asus_wmi *asus) +{ + struct pci_dev *xhci_pdev; + u32 orig_ports_available; + u32 ports_available = asus->driver->quirks->xusb2pr; + + xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI, + NULL); + + if (!xhci_pdev) + return; + + pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, + &orig_ports_available); + + pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR, + cpu_to_le32(ports_available)); + + pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n", + orig_ports_available, ports_available); +} + /* * Hwmon device */ @@ -2087,6 +2113,9 @@ static int asus_wmi_add(struct platform_device *pdev) if (asus->driver->quirks->wmi_backlight_native) acpi_video_set_dmi_backlight_type(acpi_backlight_native); + if (asus->driver->quirks->xusb2pr) + asus_wmi_set_xusb2pr(asus); + if (acpi_video_get_backlight_type() == acpi_backlight_vendor) { err = asus_wmi_backlight_init(asus); if (err && err != -ENODEV) diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h index 0e19014e9f54..fdff626c3b51 100644 --- a/drivers/platform/x86/asus-wmi.h +++ b/drivers/platform/x86/asus-wmi.h @@ -53,6 +53,7 @@ struct quirk_entry { * and let the ACPI interrupt to send out the key event. */ int no_display_toggle; + u32 xusb2pr; bool (*i8042_filter)(unsigned char data, unsigned char str, struct serio *serio); -- cgit v1.2.3 From 085370eb19d3b502d56b318abd269bef77524590 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Tue, 29 Nov 2016 23:08:49 -0200 Subject: platform/x86: asus-nb-wmi: Make use of dmi->ident Make use of dmi->ident as other drivers do, like fujitsu, intel, hp and samsung. Signed-off-by: Marcos Paulo de Souza Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-nb-wmi.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index 3ac4f48895dd..c39355d28a8c 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -122,6 +122,7 @@ static struct quirk_entry quirk_asus_x550lb = { static int dmi_matched(const struct dmi_system_id *dmi) { + pr_info("Identified laptop model '%s'\n", dmi->ident); quirks = dmi->driver_data; return 1; } -- cgit v1.2.3 From e74e259939275a5dd4e0d02845c694f421e249ad Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Tue, 29 Nov 2016 23:23:06 -0200 Subject: platform/x86: asus-nb-wmi.c: Add X45U quirk Without this patch, the Asus X45U wireless card can't be turned on (hard-blocked), but after a suspend/resume it just starts working. Following this bug report[1], there are other cases like this one, but this Asus is the only model that I can test. [1] https://ubuntuforums.org/showthread.php?t=2181558 Cc: stable@vger.kernel.org # 4.4.x- Signed-off-by: Marcos Paulo de Souza Signed-off-by: Andy Shevchenko --- drivers/platform/x86/asus-nb-wmi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c index c39355d28a8c..5be4783e40d4 100644 --- a/drivers/platform/x86/asus-nb-wmi.c +++ b/drivers/platform/x86/asus-nb-wmi.c @@ -178,6 +178,15 @@ static const struct dmi_system_id asus_quirks[] = { }, .driver_data = &quirk_asus_wapf4, }, + { + .callback = dmi_matched, + .ident = "ASUSTeK COMPUTER INC. X45U", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."), + DMI_MATCH(DMI_PRODUCT_NAME, "X45U"), + }, + .driver_data = &quirk_asus_wapf4, + }, { .callback = dmi_matched, .ident = "ASUSTeK COMPUTER INC. X456UA", -- cgit v1.2.3 From b31800283868746fc59686486a11fb24b103955b Mon Sep 17 00:00:00 2001 From: Lyude Date: Fri, 11 Nov 2016 15:15:02 -0500 Subject: platform/x86: thinkpad_acpi: Move tablet detection into separate function The hotkey events and ACPI handles used for detecting tablet mode on a few of the newer thinkpad models (Yoga X1 and the Yoga 260 specifically) have been changed around, so unfortunately this means we're definitely going to need to probe for multiple types of tablet mode support. Since the hotkey_init() is already a lot larger than it should be, let's split up this detection into its own function to make things a little easier to read. As well, since we're going to have multiple types of tablet modes, make hotkey_tablet into an enum so we can also use it to indicate the type of tablet mode reporting the machine supports. Suggested by Daniel Martin Signed-off-by: Lyude Cc: Daniel Martin Acked-by: Henrique de Moraes Holschuh Signed-off-by: Darren Hart --- drivers/platform/x86/thinkpad_acpi.c | 52 +++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 31fb979b1bfe..f3053de25cc5 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -302,7 +302,10 @@ static struct { u32 hotkey:1; u32 hotkey_mask:1; u32 hotkey_wlsw:1; - u32 hotkey_tablet:1; + enum { + TP_HOTKEY_TABLET_NONE = 0, + TP_HOTKEY_TABLET_USES_MHKG, + } hotkey_tablet; u32 kbdlight:1; u32 light:1; u32 light_status:1; @@ -3117,6 +3120,32 @@ static const struct tpacpi_quirk tpacpi_hotkey_qtable[] __initconst = { typedef u16 tpacpi_keymap_entry_t; typedef tpacpi_keymap_entry_t tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN]; +static int hotkey_init_tablet_mode(void) +{ + int in_tablet_mode, res; + char *type; + + /* For X41t, X60t, X61t Tablets... */ + if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) { + tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_MHKG; + in_tablet_mode = !!(res & TP_HOTKEY_TABLET_MASK); + type = "MHKG"; + } + + if (!tp_features.hotkey_tablet) + return 0; + + pr_info("Tablet mode switch found (type: %s), currently in %s mode\n", + type, in_tablet_mode ? "tablet" : "laptop"); + + res = add_to_attr_set(hotkey_dev_attributes, + &dev_attr_hotkey_tablet_mode.attr); + if (res) + return -1; + + return in_tablet_mode; +} + static int __init hotkey_init(struct ibm_init_struct *iibm) { /* Requirements for changing the default keymaps: @@ -3464,21 +3493,14 @@ static int __init hotkey_init(struct ibm_init_struct *iibm) res = add_to_attr_set(hotkey_dev_attributes, &dev_attr_hotkey_radio_sw.attr); - /* For X41t, X60t, X61t Tablets... */ - if (!res && acpi_evalf(hkey_handle, &status, "MHKG", "qd")) { - tp_features.hotkey_tablet = 1; - tabletsw_state = !!(status & TP_HOTKEY_TABLET_MASK); - pr_info("possible tablet mode switch found; " - "ThinkPad in %s mode\n", - (tabletsw_state) ? "tablet" : "laptop"); - res = add_to_attr_set(hotkey_dev_attributes, - &dev_attr_hotkey_tablet_mode.attr); - } + res = hotkey_init_tablet_mode(); + if (res < 0) + goto err_exit; - if (!res) - res = register_attr_set_with_sysfs( - hotkey_dev_attributes, - &tpacpi_pdev->dev.kobj); + tabletsw_state = res; + + res = register_attr_set_with_sysfs(hotkey_dev_attributes, + &tpacpi_pdev->dev.kobj); if (res) goto err_exit; -- cgit v1.2.3 From b03f4d49469f3bde9600192af15b8f17f8673679 Mon Sep 17 00:00:00 2001 From: Lyude Date: Fri, 11 Nov 2016 15:15:03 -0500 Subject: platform/x86: thinkpad_acpi: Add support for X1 Yoga (2016) Tablet Mode For whatever reason, the X1 Yoga doesn't support the normal method of querying for tablet mode. Instead of providing the MHKG method under the hotkey handle, we're instead given the CMMD method under the EC handle. Values on this handle are either 0x1, laptop mode, or 0x6, tablet mode. Tested-by: Daniel Martin Signed-off-by: Lyude Signed-off-by: Darren Hart --- Documentation/laptops/thinkpad-acpi.txt | 1 + drivers/platform/x86/thinkpad_acpi.c | 39 +++++++++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/Documentation/laptops/thinkpad-acpi.txt b/Documentation/laptops/thinkpad-acpi.txt index 72a150d8f3df..ba2e7d254842 100644 --- a/Documentation/laptops/thinkpad-acpi.txt +++ b/Documentation/laptops/thinkpad-acpi.txt @@ -540,6 +540,7 @@ Events that are propagated by the driver to userspace: 0x6022 ALARM: a sensor is extremely hot 0x6030 System thermal table changed 0x6040 Nvidia Optimus/AC adapter related (TO BE VERIFIED) +0x60C0 X1 Yoga 2016, Tablet mode status changed Battery nearly empty alarms are a last resort attempt to get the operating system to hibernate or shutdown cleanly (0x2313), or shutdown diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index f3053de25cc5..cd956de7c1b2 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -190,6 +190,9 @@ enum tpacpi_hkey_event_t { TP_HKEY_EV_LID_OPEN = 0x5002, /* laptop lid opened */ TP_HKEY_EV_TABLET_TABLET = 0x5009, /* tablet swivel up */ TP_HKEY_EV_TABLET_NOTEBOOK = 0x500a, /* tablet swivel down */ + TP_HKEY_EV_TABLET_CHANGED = 0x60c0, /* X1 Yoga (2016): + * enter/leave tablet mode + */ TP_HKEY_EV_PEN_INSERTED = 0x500b, /* tablet pen inserted */ TP_HKEY_EV_PEN_REMOVED = 0x500c, /* tablet pen removed */ TP_HKEY_EV_BRGHT_CHANGED = 0x5010, /* backlight control event */ @@ -305,6 +308,8 @@ static struct { enum { TP_HOTKEY_TABLET_NONE = 0, TP_HOTKEY_TABLET_USES_MHKG, + /* X1 Yoga 2016, seen on BIOS N1FET44W */ + TP_HOTKEY_TABLET_USES_CMMD, } hotkey_tablet; u32 kbdlight:1; u32 light:1; @@ -2062,6 +2067,8 @@ static void hotkey_poll_setup(const bool may_warn); /* HKEY.MHKG() return bits */ #define TP_HOTKEY_TABLET_MASK (1 << 3) +/* ThinkPad X1 Yoga (2016) */ +#define TP_EC_CMMD_TABLET_MODE 0x6 static int hotkey_get_wlsw(void) { @@ -2086,10 +2093,23 @@ static int hotkey_get_tablet_mode(int *status) { int s; - if (!acpi_evalf(hkey_handle, &s, "MHKG", "d")) - return -EIO; + switch (tp_features.hotkey_tablet) { + case TP_HOTKEY_TABLET_USES_MHKG: + if (!acpi_evalf(hkey_handle, &s, "MHKG", "d")) + return -EIO; + + *status = ((s & TP_HOTKEY_TABLET_MASK) != 0); + break; + case TP_HOTKEY_TABLET_USES_CMMD: + if (!acpi_evalf(ec_handle, &s, "CMMD", "d")) + return -EIO; + + *status = (s == TP_EC_CMMD_TABLET_MODE); + break; + default: + break; + } - *status = ((s & TP_HOTKEY_TABLET_MASK) != 0); return 0; } @@ -3125,11 +3145,16 @@ static int hotkey_init_tablet_mode(void) int in_tablet_mode, res; char *type; - /* For X41t, X60t, X61t Tablets... */ if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) { + /* For X41t, X60t, X61t Tablets... */ tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_MHKG; in_tablet_mode = !!(res & TP_HOTKEY_TABLET_MASK); type = "MHKG"; + } else if (acpi_evalf(ec_handle, &res, "CMMD", "qd")) { + /* For X1 Yoga (2016) */ + tp_features.hotkey_tablet = TP_HOTKEY_TABLET_USES_CMMD; + in_tablet_mode = res == TP_EC_CMMD_TABLET_MODE; + type = "CMMD"; } if (!tp_features.hotkey_tablet) @@ -3921,6 +3946,12 @@ static bool hotkey_notify_6xxx(const u32 hkey, *ignore_acpi_ev = true; return true; + case TP_HKEY_EV_TABLET_CHANGED: + tpacpi_input_send_tabletsw(); + hotkey_tablet_mode_notify_change(); + *send_acpi_ev = false; + break; + default: pr_warn("unknown possible thermal alarm or keyboard event received\n"); known = false; -- cgit v1.2.3 From a3c42a467a254a17236ab817d5c7c6bc054e4f84 Mon Sep 17 00:00:00 2001 From: Hui Wang Date: Tue, 8 Nov 2016 16:13:23 +0800 Subject: platform/x86: thinkpad_acpi: Adding new hotkey ID for Lenovo thinkpad Recently we met an issue on lots of Lenovo thinkpad laptops (those laptops are not released to market yet), the issue is that the thinkpad_acpi.ko can't be automatically loaded as before. Through debugging, we found the HKEY_HID is LEN0268 instead of LEN0068 on those machines, and the MHKV is 0x200 instead of 0x100. So adding the new ID into the driver. Signed-off-by: Hui Wang Acked-by: Henrique de Moraes Holschuh Signed-off-by: Darren Hart --- drivers/platform/x86/thinkpad_acpi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index cd956de7c1b2..78cee7671e11 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -128,6 +128,7 @@ enum { /* ACPI HIDs */ #define TPACPI_ACPI_IBM_HKEY_HID "IBM0068" #define TPACPI_ACPI_LENOVO_HKEY_HID "LEN0068" +#define TPACPI_ACPI_LENOVO_HKEY_V2_HID "LEN0268" #define TPACPI_ACPI_EC_HID "PNP0C09" /* Input IDs */ @@ -4196,6 +4197,7 @@ errexit: static const struct acpi_device_id ibm_htk_device_ids[] = { {TPACPI_ACPI_IBM_HKEY_HID, 0}, {TPACPI_ACPI_LENOVO_HKEY_HID, 0}, + {TPACPI_ACPI_LENOVO_HKEY_V2_HID, 0}, {"", 0}, }; -- cgit v1.2.3 From bb55a2ee76c2426686d320354f9ff7d9eadeb34b Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 25 Nov 2016 14:18:07 +0100 Subject: platform/x86: thinkpad_acpi: Fix old style declaration GCC warning Fix an [-Wold-style-declaration] GCC warning by moving the inline keyword before the return type. Signed-off-by: Tobias Klauser Acked-by: Henrique de Moraes Holschuh Signed-off-by: Darren Hart --- drivers/platform/x86/thinkpad_acpi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 78cee7671e11..69cb0da95be9 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -7771,7 +7771,7 @@ static struct ibm_struct volume_driver_data = { #define alsa_card NULL -static void inline volume_alsa_notify_change(void) +static inline void volume_alsa_notify_change(void) { } -- cgit v1.2.3 From 1d161d4cd719ac498545c94805803af8af9b642f Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 26 Oct 2016 17:17:44 +0200 Subject: platform/x86: dell-laptop: Use brightness_set_blocking for kbd_led_level_set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit kbd_led_level_set uses dell_smbios call which blocks, so the kbd_led classdev should use the brightness_set_blocking callback. Signed-off-by: Hans de Goede Reviewed-by: Pali Rohár Signed-off-by: Darren Hart --- drivers/platform/x86/dell-laptop.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/dell-laptop.c b/drivers/platform/x86/dell-laptop.c index 2c2f02b2e08a..14392a01ab36 100644 --- a/drivers/platform/x86/dell-laptop.c +++ b/drivers/platform/x86/dell-laptop.c @@ -1904,38 +1904,40 @@ static enum led_brightness kbd_led_level_get(struct led_classdev *led_cdev) return 0; } -static void kbd_led_level_set(struct led_classdev *led_cdev, - enum led_brightness value) +static int kbd_led_level_set(struct led_classdev *led_cdev, + enum led_brightness value) { struct kbd_state state; struct kbd_state new_state; u16 num; + int ret; if (kbd_get_max_level()) { - if (kbd_get_state(&state)) - return; + ret = kbd_get_state(&state); + if (ret) + return ret; new_state = state; - if (kbd_set_level(&new_state, value)) - return; - kbd_set_state_safe(&new_state, &state); - return; + ret = kbd_set_level(&new_state, value); + if (ret) + return ret; + return kbd_set_state_safe(&new_state, &state); } if (kbd_get_valid_token_counts()) { for (num = kbd_token_bits; num != 0 && value > 0; --value) num &= num - 1; /* clear the first bit set */ if (num == 0) - return; - kbd_set_token_bit(ffs(num) - 1); - return; + return 0; + return kbd_set_token_bit(ffs(num) - 1); } pr_warn("Keyboard brightness level control not supported\n"); + return -ENXIO; } static struct led_classdev kbd_led = { .name = "dell::kbd_backlight", - .brightness_set = kbd_led_level_set, + .brightness_set_blocking = kbd_led_level_set, .brightness_get = kbd_led_level_get, .groups = kbd_led_groups, }; -- cgit v1.2.3 From 1f22e454df2eb99ba6b7ace3f594f6805cdf5cbc Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Thu, 10 Nov 2016 11:31:00 +0200 Subject: IB/mlx4: When no DMFS for IPoIB, don't allow NET_IF QPs According to the firmware spec, FLOW_STEERING_IB_UC_QP_RANGE command is supported only if dmfs_ipoib bit is set. If it isn't set we want to ensure allocating NET_IF QPs fail. We do so by filling out the allocation bitmap. By thus, the NET_IF QPs allocating function won't find any free QP and will fail. Fixes: c1c98501121e ('IB/mlx4: Add support for steerable IB UD QPs') Signed-off-by: Eran Ben Elisha Signed-off-by: Daniel Jurgens Reviewed-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index 4054a1bfabb5..4a67ffc1ddfb 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -2823,14 +2823,19 @@ static void *mlx4_ib_add(struct mlx4_dev *dev) goto err_steer_qp_release; } - bitmap_zero(ibdev->ib_uc_qpns_bitmap, ibdev->steer_qpn_count); - - err = mlx4_FLOW_STEERING_IB_UC_QP_RANGE( - dev, ibdev->steer_qpn_base, - ibdev->steer_qpn_base + - ibdev->steer_qpn_count - 1); - if (err) - goto err_steer_free_bitmap; + if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_DMFS_IPOIB) { + bitmap_zero(ibdev->ib_uc_qpns_bitmap, + ibdev->steer_qpn_count); + err = mlx4_FLOW_STEERING_IB_UC_QP_RANGE( + dev, ibdev->steer_qpn_base, + ibdev->steer_qpn_base + + ibdev->steer_qpn_count - 1); + if (err) + goto err_steer_free_bitmap; + } else { + bitmap_fill(ibdev->ib_uc_qpns_bitmap, + ibdev->steer_qpn_count); + } } for (j = 1; j <= ibdev->dev->caps.num_ports; j++) -- cgit v1.2.3 From bf08e884bfd5be068fd2ccf2bc450f085d8dd853 Mon Sep 17 00:00:00 2001 From: Eran Ben Elisha Date: Thu, 10 Nov 2016 11:31:01 +0200 Subject: IB/mlx4: Check if GRH is available before using it Before reading GRH attributes, need to make sure AH contains GRH, and in addition, initialize GID type. Fixes: dbf727de7440 ('IB/core: Use GID table in AH creation and dmac resolution') Signed-off-by: Eran Ben Elisha Signed-off-by: Daniel Jurgens Reviewed-by: Mark Bloch Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/qp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 570bc866b1d6..0914731c9aac 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1764,14 +1764,14 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp, u8 port_num = mlx4_is_bonded(to_mdev(ibqp->device)->dev) ? 1 : attr_mask & IB_QP_PORT ? attr->port_num : qp->port; union ib_gid gid; - struct ib_gid_attr gid_attr; + struct ib_gid_attr gid_attr = {.gid_type = IB_GID_TYPE_IB}; u16 vlan = 0xffff; u8 smac[ETH_ALEN]; int status = 0; int is_eth = rdma_cap_eth_ah(&dev->ib_dev, port_num) && attr->ah_attr.ah_flags & IB_AH_GRH; - if (is_eth) { + if (is_eth && attr->ah_attr.ah_flags & IB_AH_GRH) { int index = attr->ah_attr.grh.sgid_index; status = ib_get_cached_gid(ibqp->device, port_num, -- cgit v1.2.3 From d680ebed91e0b45c43ae03a880a0b43211096161 Mon Sep 17 00:00:00 2001 From: Yonatan Cohen Date: Wed, 16 Nov 2016 10:39:16 +0200 Subject: IB/rxe: Increase max number of completions to 32k Increase limit of max CQE from 8K to 32K to allow demanding applications to work over SoftRoCE with same configuration as most RoCEv2 HW vendors have. Fixes: 8700e3e7c485 ("Soft RoCE driver") Signed-off-by: Yonatan Cohen Reviewed-by: Moni Shoua Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_param.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_param.h b/drivers/infiniband/sw/rxe/rxe_param.h index f459c43a77c8..13ed2cc6eaa2 100644 --- a/drivers/infiniband/sw/rxe/rxe_param.h +++ b/drivers/infiniband/sw/rxe/rxe_param.h @@ -82,7 +82,7 @@ enum rxe_device_param { RXE_MAX_SGE = 32, RXE_MAX_SGE_RD = 32, RXE_MAX_CQ = 16384, - RXE_MAX_LOG_CQE = 13, + RXE_MAX_LOG_CQE = 15, RXE_MAX_MR = 2 * 1024, RXE_MAX_PD = 0x7ffc, RXE_MAX_QP_RD_ATOM = 128, -- cgit v1.2.3 From 191ded4a4d991acf17207e0b4370fef070bce3e9 Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Mon, 31 Oct 2016 12:15:21 +0200 Subject: IB/mlx5: Report mlx5 multi packet WQE caps during query The capabilities whether hardware support multi packet WQE or not is exposed to user space through query_device by uhw. Signed-off-by: Bodong Wang Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 11 +++++++++++ include/uapi/rdma/mlx5-abi.h | 2 ++ 2 files changed, 13 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 46facd30e672..a16207c33333 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -672,6 +672,17 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, 1 << MLX5_CAP_GEN(dev->mdev, log_max_rq); } + if (field_avail(typeof(resp), mlx5_ib_support_multi_pkt_send_wqes, + uhw->outlen)) { + resp.mlx5_ib_support_multi_pkt_send_wqes = + MLX5_CAP_ETH(mdev, multi_pkt_send_wqe); + resp.response_length += + sizeof(resp.mlx5_ib_support_multi_pkt_send_wqes); + } + + if (field_avail(typeof(resp), reserved, uhw->outlen)) + resp.response_length += sizeof(resp.reserved); + if (uhw->outlen) { err = ib_copy_to_udata(uhw, &resp, resp.response_length); diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index f5d0f4e83b59..93d6b9fe8e78 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -129,6 +129,8 @@ struct mlx5_ib_query_device_resp { __u32 response_length; struct mlx5_ib_tso_caps tso_caps; struct mlx5_ib_rss_caps rss_caps; + __u32 mlx5_ib_support_multi_pkt_send_wqes; + __u32 reserved; }; struct mlx5_ib_create_cq { -- cgit v1.2.3 From 7e43a2a5bae39fedaa7cce21d637e0c8d96d8e54 Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Mon, 31 Oct 2016 12:16:44 +0200 Subject: IB/mlx5: Report mlx5 CQE compression caps during query The capabilities include: - Max number of compressed and aggregated CQEs in a single session, while zero means unsupported. - For Responder, there are two formats of mini CQE: mini CQE with Rx hash and mini CQE with checksum. They're mutual exclusive. Signed-off-by: Bodong Wang Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 10 ++++++++++ include/uapi/rdma/mlx5-abi.h | 12 ++++++++++++ 2 files changed, 22 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index a16207c33333..2687a93c4af2 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -683,6 +683,16 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, if (field_avail(typeof(resp), reserved, uhw->outlen)) resp.response_length += sizeof(resp.reserved); + if (field_avail(typeof(resp), cqe_comp_caps, uhw->outlen)) { + resp.cqe_comp_caps.max_num = + MLX5_CAP_GEN(dev->mdev, cqe_compression) ? + MLX5_CAP_GEN(dev->mdev, cqe_compression_max_num) : 0; + resp.cqe_comp_caps.supported_format = + MLX5_IB_CQE_RES_FORMAT_HASH | + MLX5_IB_CQE_RES_FORMAT_CSUM; + resp.response_length += sizeof(resp.cqe_comp_caps); + } + if (uhw->outlen) { err = ib_copy_to_udata(uhw, &resp, resp.response_length); diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index 93d6b9fe8e78..6649d13a2dbb 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -124,11 +124,23 @@ struct mlx5_ib_rss_caps { __u8 reserved[7]; }; +enum mlx5_ib_cqe_comp_res_format { + MLX5_IB_CQE_RES_FORMAT_HASH = 1 << 0, + MLX5_IB_CQE_RES_FORMAT_CSUM = 1 << 1, + MLX5_IB_CQE_RES_RESERVED = 1 << 2, +}; + +struct mlx5_ib_cqe_comp_caps { + __u32 max_num; + __u32 supported_format; /* enum mlx5_ib_cqe_comp_res_format */ +}; + struct mlx5_ib_query_device_resp { __u32 comp_mask; __u32 response_length; struct mlx5_ib_tso_caps tso_caps; struct mlx5_ib_rss_caps rss_caps; + struct mlx5_ib_cqe_comp_caps cqe_comp_caps; __u32 mlx5_ib_support_multi_pkt_send_wqes; __u32 reserved; }; -- cgit v1.2.3 From 1cbe6fc86ccfe05a910be4883da7c7bd28c190fe Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Mon, 31 Oct 2016 12:16:45 +0200 Subject: IB/mlx5: Add support for CQE compressing CQE compressing reduces PCI overhead by coalescing and compressing multiple CQEs into a single merged CQE. Successful compressing improves message rate especially for small packet traffic. CQE compressing is supported for all 64B CQE formats (with certain limitations) generated by RQ/Responder or by SQ/Requestor. Signed-off-by: Bodong Wang Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/cq.c | 30 +++++++++++++++++++++++++++++- include/uapi/rdma/mlx5-abi.h | 4 +++- 2 files changed, 32 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/cq.c b/drivers/infiniband/hw/mlx5/cq.c index 9e0598b5615f..d72a4367c891 100644 --- a/drivers/infiniband/hw/mlx5/cq.c +++ b/drivers/infiniband/hw/mlx5/cq.c @@ -731,7 +731,7 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, int entries, u32 **cqb, int *cqe_size, int *index, int *inlen) { - struct mlx5_ib_create_cq ucmd; + struct mlx5_ib_create_cq ucmd = {}; size_t ucmdlen; int page_shift; __be64 *pas; @@ -792,8 +792,36 @@ static int create_cq_user(struct mlx5_ib_dev *dev, struct ib_udata *udata, *index = to_mucontext(context)->uuari.uars[0].index; + if (ucmd.cqe_comp_en == 1) { + if (unlikely((*cqe_size != 64) || + !MLX5_CAP_GEN(dev->mdev, cqe_compression))) { + err = -EOPNOTSUPP; + mlx5_ib_warn(dev, "CQE compression is not supported for size %d!\n", + *cqe_size); + goto err_cqb; + } + + if (unlikely(!ucmd.cqe_comp_res_format || + !(ucmd.cqe_comp_res_format < + MLX5_IB_CQE_RES_RESERVED) || + (ucmd.cqe_comp_res_format & + (ucmd.cqe_comp_res_format - 1)))) { + err = -EOPNOTSUPP; + mlx5_ib_warn(dev, "CQE compression res format %d is not supported!\n", + ucmd.cqe_comp_res_format); + goto err_cqb; + } + + MLX5_SET(cqc, cqc, cqe_comp_en, 1); + MLX5_SET(cqc, cqc, mini_cqe_res_format, + ilog2(ucmd.cqe_comp_res_format)); + } + return 0; +err_cqb: + kfree(cqb); + err_db: mlx5_ib_db_unmap_user(to_mucontext(context), &cq->db); diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index 6649d13a2dbb..b0a41c8dc1fb 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -149,7 +149,9 @@ struct mlx5_ib_create_cq { __u64 buf_addr; __u64 db_addr; __u32 cqe_size; - __u32 reserved; /* explicit padding (optional on i386) */ + __u8 cqe_comp_en; + __u8 cqe_comp_res_format; + __u16 reserved; /* explicit padding (optional on i386) */ }; struct mlx5_ib_create_cq_resp { -- cgit v1.2.3 From 0dbf3332b7b683db33a385a3ce9baab157e3ff9a Mon Sep 17 00:00:00 2001 From: Moses Reuben Date: Mon, 14 Nov 2016 19:04:47 +0200 Subject: IB/core: Add flow spec tunneling support In order to support tunneling, that can be used by the QP, both struct ib_flow_spec_tunnel and struct ib_flow_tunnel_filter can be used to more IP or UDP based tunneling protocols (e.g NVGRE, GRE, etc). IB_FLOW_SPEC_VXLAN_TUNNEL type flow specification is added to use this functionality and match specific Vxlan packets. In similar to IPv6, we check overflow of the vni value by comparing with the maximum size. Signed-off-by: Moses Reuben Reviewed-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 15 +++++++++++++++ include/rdma/ib_verbs.h | 19 ++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 2690c9263ee4..deb06fa3548b 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -3175,6 +3175,21 @@ static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec, memcpy(&ib_spec->tcp_udp.val, kern_spec_val, actual_filter_sz); memcpy(&ib_spec->tcp_udp.mask, kern_spec_mask, actual_filter_sz); break; + case IB_FLOW_SPEC_VXLAN_TUNNEL: + ib_filter_sz = offsetof(struct ib_flow_tunnel_filter, real_sz); + actual_filter_sz = spec_filter_size(kern_spec_mask, + kern_filter_sz, + ib_filter_sz); + if (actual_filter_sz <= 0) + return -EINVAL; + ib_spec->tunnel.size = sizeof(struct ib_flow_spec_tunnel); + memcpy(&ib_spec->tunnel.val, kern_spec_val, actual_filter_sz); + memcpy(&ib_spec->tunnel.mask, kern_spec_mask, actual_filter_sz); + + if ((ntohl(ib_spec->tunnel.mask.tunnel_id)) >= BIT(24) || + (ntohl(ib_spec->tunnel.val.tunnel_id)) >= BIT(24)) + return -EINVAL; + break; default: return -EINVAL; } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 467a4b476e29..b8213818de89 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1599,7 +1599,8 @@ enum ib_flow_spec_type { IB_FLOW_SPEC_IPV6 = 0x31, /* L4 headers*/ IB_FLOW_SPEC_TCP = 0x40, - IB_FLOW_SPEC_UDP = 0x41 + IB_FLOW_SPEC_UDP = 0x41, + IB_FLOW_SPEC_VXLAN_TUNNEL = 0x50, }; #define IB_FLOW_SPEC_LAYER_MASK 0xF0 #define IB_FLOW_SPEC_SUPPORT_LAYERS 4 @@ -1707,6 +1708,21 @@ struct ib_flow_spec_tcp_udp { struct ib_flow_tcp_udp_filter mask; }; +struct ib_flow_tunnel_filter { + __be32 tunnel_id; + u8 real_sz[0]; +}; + +/* ib_flow_spec_tunnel describes the Vxlan tunnel + * the tunnel_id from val has the vni value + */ +struct ib_flow_spec_tunnel { + enum ib_flow_spec_type type; + u16 size; + struct ib_flow_tunnel_filter val; + struct ib_flow_tunnel_filter mask; +}; + union ib_flow_spec { struct { enum ib_flow_spec_type type; @@ -1717,6 +1733,7 @@ union ib_flow_spec { struct ib_flow_spec_ipv4 ipv4; struct ib_flow_spec_tcp_udp tcp_udp; struct ib_flow_spec_ipv6 ipv6; + struct ib_flow_spec_tunnel tunnel; }; struct ib_flow_attr { -- cgit v1.2.3 From ffb30d8f107b27820a069ae6772ab48e58cc0b2f Mon Sep 17 00:00:00 2001 From: Moses Reuben Date: Mon, 14 Nov 2016 19:04:50 +0200 Subject: IB/mlx5: Support Vxlan tunneling specification Add support to receive specific Vxlan packet in ConnectX-4. Signed-off-by: Moses Reuben Reviewed-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 2687a93c4af2..a9e5851365d3 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1539,6 +1539,7 @@ static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val) #define LAST_IPV4_FIELD tos #define LAST_IPV6_FIELD traffic_class #define LAST_TCP_UDP_FIELD src_port +#define LAST_TUNNEL_FIELD tunnel_id /* Field is the last supported field */ #define FIELDS_NOT_SUPPORTED(filter, field)\ @@ -1722,6 +1723,16 @@ static int parse_flow_attr(u32 *match_c, u32 *match_v, MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, udp_dport, ntohs(ib_spec->tcp_udp.val.dst_port)); break; + case IB_FLOW_SPEC_VXLAN_TUNNEL: + if (FIELDS_NOT_SUPPORTED(ib_spec->tunnel.mask, + LAST_TUNNEL_FIELD)) + return -ENOTSUPP; + + MLX5_SET(fte_match_set_misc, misc_params_c, vxlan_vni, + ntohl(ib_spec->tunnel.mask.tunnel_id)); + MLX5_SET(fte_match_set_misc, misc_params_v, vxlan_vni, + ntohl(ib_spec->tunnel.val.tunnel_id)); + break; default: return -EINVAL; } -- cgit v1.2.3 From fbf46860b19ddb485f00bef1ad1a43aabc9f71ad Mon Sep 17 00:00:00 2001 From: Moses Reuben Date: Mon, 14 Nov 2016 19:04:51 +0200 Subject: IB/core: Introduce inner flow steering For a tunneled packet which contains external and internal headers, we refer to the external headers as "outer fields" and the internal headers as "inner fields". Example of a tunneled packet: { L2 | L3 | L4 | tunnel header | L2 | L3 | l4 | data } | | | | | | | { outer fields }{ inner fields } This patch introduces a new flag for flow steering rules - IB_FLOW_SPEC_INNER - which specifies that the rule applies to the inner fields, rather than to the outer fields of the packet. Signed-off-by: Moses Reuben Reviewed-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 4 +++- include/rdma/ib_verbs.h | 17 +++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index deb06fa3548b..d84dcde7a8bb 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -3124,8 +3124,10 @@ static int kern_spec_to_ib_spec(struct ib_uverbs_flow_spec *kern_spec, kern_spec_val = (void *)kern_spec + sizeof(struct ib_uverbs_flow_spec_hdr); kern_spec_mask = kern_spec_val + kern_filter_sz; + if (ib_spec->type == (IB_FLOW_SPEC_INNER | IB_FLOW_SPEC_VXLAN_TUNNEL)) + return -EINVAL; - switch (ib_spec->type) { + switch (ib_spec->type & ~IB_FLOW_SPEC_INNER) { case IB_FLOW_SPEC_ETH: ib_filter_sz = offsetof(struct ib_flow_eth_filter, real_sz); actual_filter_sz = spec_filter_size(kern_spec_mask, diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 4bc748fddcac..6d0dd6525e14 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1601,9 +1601,10 @@ enum ib_flow_spec_type { IB_FLOW_SPEC_TCP = 0x40, IB_FLOW_SPEC_UDP = 0x41, IB_FLOW_SPEC_VXLAN_TUNNEL = 0x50, + IB_FLOW_SPEC_INNER = 0x100, }; #define IB_FLOW_SPEC_LAYER_MASK 0xF0 -#define IB_FLOW_SPEC_SUPPORT_LAYERS 4 +#define IB_FLOW_SPEC_SUPPORT_LAYERS 8 /* Flow steering rule priority is set according to it's domain. * Lower domain value means higher priority. @@ -1631,7 +1632,7 @@ struct ib_flow_eth_filter { }; struct ib_flow_spec_eth { - enum ib_flow_spec_type type; + u32 type; u16 size; struct ib_flow_eth_filter val; struct ib_flow_eth_filter mask; @@ -1645,7 +1646,7 @@ struct ib_flow_ib_filter { }; struct ib_flow_spec_ib { - enum ib_flow_spec_type type; + u32 type; u16 size; struct ib_flow_ib_filter val; struct ib_flow_ib_filter mask; @@ -1670,7 +1671,7 @@ struct ib_flow_ipv4_filter { }; struct ib_flow_spec_ipv4 { - enum ib_flow_spec_type type; + u32 type; u16 size; struct ib_flow_ipv4_filter val; struct ib_flow_ipv4_filter mask; @@ -1688,7 +1689,7 @@ struct ib_flow_ipv6_filter { }; struct ib_flow_spec_ipv6 { - enum ib_flow_spec_type type; + u32 type; u16 size; struct ib_flow_ipv6_filter val; struct ib_flow_ipv6_filter mask; @@ -1702,7 +1703,7 @@ struct ib_flow_tcp_udp_filter { }; struct ib_flow_spec_tcp_udp { - enum ib_flow_spec_type type; + u32 type; u16 size; struct ib_flow_tcp_udp_filter val; struct ib_flow_tcp_udp_filter mask; @@ -1717,7 +1718,7 @@ struct ib_flow_tunnel_filter { * the tunnel_id from val has the vni value */ struct ib_flow_spec_tunnel { - enum ib_flow_spec_type type; + u32 type; u16 size; struct ib_flow_tunnel_filter val; struct ib_flow_tunnel_filter mask; @@ -1725,7 +1726,7 @@ struct ib_flow_spec_tunnel { union ib_flow_spec { struct { - enum ib_flow_spec_type type; + u32 type; u16 size; }; struct ib_flow_spec_eth eth; -- cgit v1.2.3 From 2d1e697e9b716b8a692bc9c197e5f4ffd10d7307 Mon Sep 17 00:00:00 2001 From: Moses Reuben Date: Mon, 14 Nov 2016 19:04:52 +0200 Subject: IB/mlx5: Add support to match inner packet fields Add support to match packet fields which are tunneled, i.e. support matching the header of the inner packet which is the result of or bit operation of the original header and the IB_FLOW_SPEC_INNER type. The combination of IB_FLOW_SPEC_INNER | IB_FLOW_SPEC_VXLAN_TUNNEL is not needed to be checked, because the IB core has this check already. Signed-off-by: Moses Reuben Reviewed-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 131 +++++++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 53 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index a9e5851365d3..f7a299431e6c 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1526,6 +1526,22 @@ static void set_proto(void *outer_c, void *outer_v, u8 mask, u8 val) MLX5_SET(fte_match_set_lyr_2_4, outer_v, ip_protocol, val); } +static void set_flow_label(void *misc_c, void *misc_v, u8 mask, u8 val, + bool inner) +{ + if (inner) { + MLX5_SET(fte_match_set_misc, + misc_c, inner_ipv6_flow_label, mask); + MLX5_SET(fte_match_set_misc, + misc_v, inner_ipv6_flow_label, val); + } else { + MLX5_SET(fte_match_set_misc, + misc_c, outer_ipv6_flow_label, mask); + MLX5_SET(fte_match_set_misc, + misc_v, outer_ipv6_flow_label, val); + } +} + static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val) { MLX5_SET(fte_match_set_lyr_2_4, outer_c, ip_ecn, mask); @@ -1552,155 +1568,164 @@ static void set_tos(void *outer_c, void *outer_v, u8 mask, u8 val) static int parse_flow_attr(u32 *match_c, u32 *match_v, const union ib_flow_spec *ib_spec) { - void *outer_headers_c = MLX5_ADDR_OF(fte_match_param, match_c, - outer_headers); - void *outer_headers_v = MLX5_ADDR_OF(fte_match_param, match_v, - outer_headers); void *misc_params_c = MLX5_ADDR_OF(fte_match_param, match_c, misc_parameters); void *misc_params_v = MLX5_ADDR_OF(fte_match_param, match_v, misc_parameters); + void *headers_c; + void *headers_v; + + if (ib_spec->type & IB_FLOW_SPEC_INNER) { + headers_c = MLX5_ADDR_OF(fte_match_param, match_c, + inner_headers); + headers_v = MLX5_ADDR_OF(fte_match_param, match_v, + inner_headers); + } else { + headers_c = MLX5_ADDR_OF(fte_match_param, match_c, + outer_headers); + headers_v = MLX5_ADDR_OF(fte_match_param, match_v, + outer_headers); + } - switch (ib_spec->type) { + switch (ib_spec->type & ~IB_FLOW_SPEC_INNER) { case IB_FLOW_SPEC_ETH: if (FIELDS_NOT_SUPPORTED(ib_spec->eth.mask, LAST_ETH_FIELD)) return -ENOTSUPP; - ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, dmac_47_16), ib_spec->eth.mask.dst_mac); - ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v, + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, dmac_47_16), ib_spec->eth.val.dst_mac); - ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, smac_47_16), ib_spec->eth.mask.src_mac); - ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v, + ether_addr_copy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, smac_47_16), ib_spec->eth.val.src_mac); if (ib_spec->eth.mask.vlan_tag) { - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, vlan_tag, 1); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, vlan_tag, 1); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_vid, ntohs(ib_spec->eth.mask.vlan_tag)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_vid, ntohs(ib_spec->eth.val.vlan_tag)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_cfi, ntohs(ib_spec->eth.mask.vlan_tag) >> 12); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_cfi, ntohs(ib_spec->eth.val.vlan_tag) >> 12); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, first_prio, ntohs(ib_spec->eth.mask.vlan_tag) >> 13); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, first_prio, ntohs(ib_spec->eth.val.vlan_tag) >> 13); } - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype, ntohs(ib_spec->eth.mask.ether_type)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ntohs(ib_spec->eth.val.ether_type)); break; case IB_FLOW_SPEC_IPV4: if (FIELDS_NOT_SUPPORTED(ib_spec->ipv4.mask, LAST_IPV4_FIELD)) return -ENOTSUPP; - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype, 0xffff); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IP); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, src_ipv4_src_ipv6.ipv4_layout.ipv4), &ib_spec->ipv4.mask.src_ip, sizeof(ib_spec->ipv4.mask.src_ip)); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, src_ipv4_src_ipv6.ipv4_layout.ipv4), &ib_spec->ipv4.val.src_ip, sizeof(ib_spec->ipv4.val.src_ip)); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), &ib_spec->ipv4.mask.dst_ip, sizeof(ib_spec->ipv4.mask.dst_ip)); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, dst_ipv4_dst_ipv6.ipv4_layout.ipv4), &ib_spec->ipv4.val.dst_ip, sizeof(ib_spec->ipv4.val.dst_ip)); - set_tos(outer_headers_c, outer_headers_v, + set_tos(headers_c, headers_v, ib_spec->ipv4.mask.tos, ib_spec->ipv4.val.tos); - set_proto(outer_headers_c, outer_headers_v, + set_proto(headers_c, headers_v, ib_spec->ipv4.mask.proto, ib_spec->ipv4.val.proto); break; case IB_FLOW_SPEC_IPV6: if (FIELDS_NOT_SUPPORTED(ib_spec->ipv6.mask, LAST_IPV6_FIELD)) return -ENOTSUPP; - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ethertype, 0xffff); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ethertype, ETH_P_IPV6); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, src_ipv4_src_ipv6.ipv6_layout.ipv6), &ib_spec->ipv6.mask.src_ip, sizeof(ib_spec->ipv6.mask.src_ip)); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, src_ipv4_src_ipv6.ipv6_layout.ipv6), &ib_spec->ipv6.val.src_ip, sizeof(ib_spec->ipv6.val.src_ip)); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_c, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_c, dst_ipv4_dst_ipv6.ipv6_layout.ipv6), &ib_spec->ipv6.mask.dst_ip, sizeof(ib_spec->ipv6.mask.dst_ip)); - memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, outer_headers_v, + memcpy(MLX5_ADDR_OF(fte_match_set_lyr_2_4, headers_v, dst_ipv4_dst_ipv6.ipv6_layout.ipv6), &ib_spec->ipv6.val.dst_ip, sizeof(ib_spec->ipv6.val.dst_ip)); - set_tos(outer_headers_c, outer_headers_v, + set_tos(headers_c, headers_v, ib_spec->ipv6.mask.traffic_class, ib_spec->ipv6.val.traffic_class); - set_proto(outer_headers_c, outer_headers_v, + set_proto(headers_c, headers_v, ib_spec->ipv6.mask.next_hdr, ib_spec->ipv6.val.next_hdr); - MLX5_SET(fte_match_set_misc, misc_params_c, - outer_ipv6_flow_label, - ntohl(ib_spec->ipv6.mask.flow_label)); - MLX5_SET(fte_match_set_misc, misc_params_v, - outer_ipv6_flow_label, - ntohl(ib_spec->ipv6.val.flow_label)); + set_flow_label(misc_params_c, misc_params_v, + ntohl(ib_spec->ipv6.mask.flow_label), + ntohl(ib_spec->ipv6.val.flow_label), + ib_spec->type & IB_FLOW_SPEC_INNER); + break; case IB_FLOW_SPEC_TCP: if (FIELDS_NOT_SUPPORTED(ib_spec->tcp_udp.mask, LAST_TCP_UDP_FIELD)) return -ENOTSUPP; - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol, 0xff); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, ip_protocol, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_TCP); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, tcp_sport, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_sport, ntohs(ib_spec->tcp_udp.mask.src_port)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, tcp_sport, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_sport, ntohs(ib_spec->tcp_udp.val.src_port)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, tcp_dport, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, tcp_dport, ntohs(ib_spec->tcp_udp.mask.dst_port)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, tcp_dport, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, tcp_dport, ntohs(ib_spec->tcp_udp.val.dst_port)); break; case IB_FLOW_SPEC_UDP: @@ -1708,19 +1733,19 @@ static int parse_flow_attr(u32 *match_c, u32 *match_v, LAST_TCP_UDP_FIELD)) return -ENOTSUPP; - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, ip_protocol, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, ip_protocol, 0xff); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, ip_protocol, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, ip_protocol, IPPROTO_UDP); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, udp_sport, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_sport, ntohs(ib_spec->tcp_udp.mask.src_port)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, udp_sport, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_sport, ntohs(ib_spec->tcp_udp.val.src_port)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_c, udp_dport, + MLX5_SET(fte_match_set_lyr_2_4, headers_c, udp_dport, ntohs(ib_spec->tcp_udp.mask.dst_port)); - MLX5_SET(fte_match_set_lyr_2_4, outer_headers_v, udp_dport, + MLX5_SET(fte_match_set_lyr_2_4, headers_v, udp_dport, ntohs(ib_spec->tcp_udp.val.dst_port)); break; case IB_FLOW_SPEC_VXLAN_TUNNEL: -- cgit v1.2.3 From c90ea9d8e51196d9c528e57d9ab09ee7d41f0ba0 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 23 Nov 2016 08:23:22 +0200 Subject: IB/core: Change ib_resolve_eth_dmac to use it in create AH The function ib_resolve_eth_dmac() requires struct qp_attr * and qp_attr_mask as parameters while the function might be useful to resolve dmac for address handles. This patch changes the signature of the function so it can be used in the flow of creating an address handle. Signed-off-by: Moni Shoua Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/core_priv.h | 3 -- drivers/infiniband/core/uverbs_cmd.c | 8 ++-- drivers/infiniband/core/verbs.c | 84 ++++++++++++++++++------------------ include/rdma/ib_verbs.h | 2 + 4 files changed, 49 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index 19d499dcab76..1acc95b3aaa3 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h @@ -72,9 +72,6 @@ void ib_device_unregister_sysfs(struct ib_device *device); void ib_cache_setup(void); void ib_cache_cleanup(void); -int ib_resolve_eth_dmac(struct ib_qp *qp, - struct ib_qp_attr *qp_attr, int *qp_attr_mask); - typedef void (*roce_netdev_callback)(struct ib_device *device, u8 port, struct net_device *idev, void *cookie); diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index d84dcde7a8bb..77bb15f66414 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2402,9 +2402,11 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; if (qp->real_qp == qp) { - ret = ib_resolve_eth_dmac(qp, attr, &cmd.attr_mask); - if (ret) - goto release_qp; + if (cmd.attr_mask & IB_QP_AV) { + ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr); + if (ret) + goto release_qp; + } ret = qp->device->modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata); } else { diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index 98e10c5f2a96..cacee169cd55 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1198,66 +1198,66 @@ int ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state, } EXPORT_SYMBOL(ib_modify_qp_is_ok); -int ib_resolve_eth_dmac(struct ib_qp *qp, - struct ib_qp_attr *qp_attr, int *qp_attr_mask) +int ib_resolve_eth_dmac(struct ib_device *device, + struct ib_ah_attr *ah_attr) { int ret = 0; - if (*qp_attr_mask & IB_QP_AV) { - if (qp_attr->ah_attr.port_num < rdma_start_port(qp->device) || - qp_attr->ah_attr.port_num > rdma_end_port(qp->device)) - return -EINVAL; - - if (!rdma_cap_eth_ah(qp->device, qp_attr->ah_attr.port_num)) - return 0; - - if (rdma_link_local_addr((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw)) { - rdma_get_ll_mac((struct in6_addr *)qp_attr->ah_attr.grh.dgid.raw, - qp_attr->ah_attr.dmac); - } else { - union ib_gid sgid; - struct ib_gid_attr sgid_attr; - int ifindex; - int hop_limit; - - ret = ib_query_gid(qp->device, - qp_attr->ah_attr.port_num, - qp_attr->ah_attr.grh.sgid_index, - &sgid, &sgid_attr); - - if (ret || !sgid_attr.ndev) { - if (!ret) - ret = -ENXIO; - goto out; - } + if (ah_attr->port_num < rdma_start_port(device) || + ah_attr->port_num > rdma_end_port(device)) + return -EINVAL; - ifindex = sgid_attr.ndev->ifindex; + if (!rdma_cap_eth_ah(device, ah_attr->port_num)) + return 0; - ret = rdma_addr_find_l2_eth_by_grh(&sgid, - &qp_attr->ah_attr.grh.dgid, - qp_attr->ah_attr.dmac, - NULL, &ifindex, &hop_limit); + if (rdma_link_local_addr((struct in6_addr *)ah_attr->grh.dgid.raw)) { + rdma_get_ll_mac((struct in6_addr *)ah_attr->grh.dgid.raw, + ah_attr->dmac); + } else { + union ib_gid sgid; + struct ib_gid_attr sgid_attr; + int ifindex; + int hop_limit; + + ret = ib_query_gid(device, + ah_attr->port_num, + ah_attr->grh.sgid_index, + &sgid, &sgid_attr); + + if (ret || !sgid_attr.ndev) { + if (!ret) + ret = -ENXIO; + goto out; + } - dev_put(sgid_attr.ndev); + ifindex = sgid_attr.ndev->ifindex; - qp_attr->ah_attr.grh.hop_limit = hop_limit; - } + ret = rdma_addr_find_l2_eth_by_grh(&sgid, + &ah_attr->grh.dgid, + ah_attr->dmac, + NULL, &ifindex, &hop_limit); + + dev_put(sgid_attr.ndev); + + ah_attr->grh.hop_limit = hop_limit; } out: return ret; } EXPORT_SYMBOL(ib_resolve_eth_dmac); - int ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *qp_attr, int qp_attr_mask) { - int ret; - ret = ib_resolve_eth_dmac(qp, qp_attr, &qp_attr_mask); - if (ret) - return ret; + if (qp_attr_mask & IB_QP_AV) { + int ret; + + ret = ib_resolve_eth_dmac(qp->device, &qp_attr->ah_attr); + if (ret) + return ret; + } return qp->device->modify_qp(qp->real_qp, qp_attr, qp_attr_mask, NULL); } diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 6d0dd6525e14..0c6f973e407c 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -3394,4 +3394,6 @@ void ib_drain_rq(struct ib_qp *qp); void ib_drain_sq(struct ib_qp *qp); void ib_drain_qp(struct ib_qp *qp); +int ib_resolve_eth_dmac(struct ib_device *device, + struct ib_ah_attr *ah_attr); #endif /* IB_VERBS_H */ -- cgit v1.2.3 From 6ad279c5a2e55bf2bd100b4222090d4717de88d5 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 23 Nov 2016 08:23:23 +0200 Subject: IB/mlx5: Report that device has udata response in create_ah To make mlx5 user driver aware of whether kernel driver returns dmac in user data response add a new flag that will be returned back to user-space through alloc_ucontext. Signed-off-by: Moni Shoua Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 3 ++- include/uapi/rdma/mlx5-abi.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index f7a299431e6c..f2ef2a170d9f 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -1117,7 +1117,8 @@ static struct ib_ucontext *mlx5_ib_alloc_ucontext(struct ib_device *ibdev, resp.response_length += sizeof(resp.cqe_version); if (field_avail(typeof(resp), cmds_supp_uhw, udata->outlen)) { - resp.cmds_supp_uhw |= MLX5_USER_CMDS_SUPP_UHW_QUERY_DEVICE; + resp.cmds_supp_uhw |= MLX5_USER_CMDS_SUPP_UHW_QUERY_DEVICE | + MLX5_USER_CMDS_SUPP_UHW_CREATE_AH; resp.response_length += sizeof(resp.cmds_supp_uhw); } diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index b0a41c8dc1fb..ac28729a1245 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -82,6 +82,7 @@ enum mlx5_ib_alloc_ucontext_resp_mask { enum mlx5_user_cmds_supp_uhw { MLX5_USER_CMDS_SUPP_UHW_QUERY_DEVICE = 1 << 0, + MLX5_USER_CMDS_SUPP_UHW_CREATE_AH = 1 << 1, }; struct mlx5_ib_alloc_ucontext_resp { -- cgit v1.2.3 From 477864c8fcd953e5a988073ca5be18bb7fd93410 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 23 Nov 2016 08:23:24 +0200 Subject: IB/core: Let create_ah return extended response to user Add struct ib_udata to the signature of create_ah callback that is implemented by IB device drivers. This allows HW drivers to return extra data to the userspace library. This patch prepares the ground for mlx5 driver to resolve destination mac address for a given GID and return it to userspace. This patch was previously submitted by Knut Omang as a part of the patch set to support Oracle's Infiniband HCA (SIF). Signed-off-by: Knut Omang Signed-off-by: Moni Shoua Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs_cmd.c | 11 ++++++++++- drivers/infiniband/core/verbs.c | 2 +- drivers/infiniband/hw/cxgb3/iwch_provider.c | 3 ++- drivers/infiniband/hw/cxgb4/provider.c | 4 +++- drivers/infiniband/hw/hns/hns_roce_ah.c | 3 ++- drivers/infiniband/hw/hns/hns_roce_device.h | 3 ++- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 4 +++- drivers/infiniband/hw/mlx4/ah.c | 4 +++- drivers/infiniband/hw/mlx4/mlx4_ib.h | 3 ++- drivers/infiniband/hw/mlx5/ah.c | 4 +++- drivers/infiniband/hw/mlx5/mlx5_ib.h | 3 ++- drivers/infiniband/hw/mthca/mthca_provider.c | 4 +++- drivers/infiniband/hw/nes/nes_verbs.c | 3 ++- drivers/infiniband/hw/ocrdma/ocrdma_ah.c | 3 ++- drivers/infiniband/hw/ocrdma/ocrdma_ah.h | 4 +++- drivers/infiniband/hw/qedr/verbs.c | 3 ++- drivers/infiniband/hw/qedr/verbs.h | 3 ++- drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 4 +++- drivers/infiniband/hw/usnic/usnic_ib_verbs.h | 4 +++- drivers/infiniband/sw/rxe/rxe_verbs.c | 4 +++- include/rdma/ib_verbs.h | 3 ++- 21 files changed, 58 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 77bb15f66414..cdb935ddab69 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2877,6 +2877,7 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, struct ib_ah *ah; struct ib_ah_attr attr; int ret; + struct ib_udata udata; if (out_len < sizeof resp) return -ENOSPC; @@ -2884,6 +2885,10 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, if (copy_from_user(&cmd, buf, sizeof cmd)) return -EFAULT; + INIT_UDATA(&udata, buf + sizeof(cmd), + (unsigned long)cmd.response + sizeof(resp), + in_len - sizeof(cmd), out_len - sizeof(resp)); + uobj = kmalloc(sizeof *uobj, GFP_KERNEL); if (!uobj) return -ENOMEM; @@ -2910,12 +2915,16 @@ ssize_t ib_uverbs_create_ah(struct ib_uverbs_file *file, memset(&attr.dmac, 0, sizeof(attr.dmac)); memcpy(attr.grh.dgid.raw, cmd.attr.grh.dgid, 16); - ah = ib_create_ah(pd, &attr); + ah = pd->device->create_ah(pd, &attr, &udata); + if (IS_ERR(ah)) { ret = PTR_ERR(ah); goto err_put; } + ah->device = pd->device; + ah->pd = pd; + atomic_inc(&pd->usecnt); ah->uobject = uobj; uobj->object = ah; diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index cacee169cd55..c976f29f7ad2 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -315,7 +315,7 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) { struct ib_ah *ah; - ah = pd->device->create_ah(pd, ah_attr); + ah = pd->device->create_ah(pd, ah_attr, NULL); if (!IS_ERR(ah)) { ah->device = pd->device; diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c index cba57bb53dba..9d5fe1853da4 100644 --- a/drivers/infiniband/hw/cxgb3/iwch_provider.c +++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c @@ -62,7 +62,8 @@ #include "common.h" static struct ib_ah *iwch_ah_create(struct ib_pd *pd, - struct ib_ah_attr *ah_attr) + struct ib_ah_attr *ah_attr, + struct ib_udata *udata) { return ERR_PTR(-ENOSYS); } diff --git a/drivers/infiniband/hw/cxgb4/provider.c b/drivers/infiniband/hw/cxgb4/provider.c index 645e606a17c5..49b51b7e0fd7 100644 --- a/drivers/infiniband/hw/cxgb4/provider.c +++ b/drivers/infiniband/hw/cxgb4/provider.c @@ -59,7 +59,9 @@ module_param(fastreg_support, int, 0644); MODULE_PARM_DESC(fastreg_support, "Advertise fastreg support (default=1)"); static struct ib_ah *c4iw_ah_create(struct ib_pd *pd, - struct ib_ah_attr *ah_attr) + struct ib_ah_attr *ah_attr, + struct ib_udata *udata) + { return ERR_PTR(-ENOSYS); } diff --git a/drivers/infiniband/hw/hns/hns_roce_ah.c b/drivers/infiniband/hw/hns/hns_roce_ah.c index 24f79ee39fdf..0ac294db3b29 100644 --- a/drivers/infiniband/hw/hns/hns_roce_ah.c +++ b/drivers/infiniband/hw/hns/hns_roce_ah.c @@ -39,7 +39,8 @@ #define HNS_ROCE_VLAN_SL_BIT_MASK 7 #define HNS_ROCE_VLAN_SL_SHIFT 13 -struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *ah_attr) +struct ib_ah *hns_roce_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata) { struct hns_roce_dev *hr_dev = to_hr_dev(ibpd->device); struct device *dev = &hr_dev->pdev->dev; diff --git a/drivers/infiniband/hw/hns/hns_roce_device.h b/drivers/infiniband/hw/hns/hns_roce_device.h index 341731553a60..470615f7b517 100644 --- a/drivers/infiniband/hw/hns/hns_roce_device.h +++ b/drivers/infiniband/hw/hns/hns_roce_device.h @@ -667,7 +667,8 @@ int hns_roce_bitmap_alloc_range(struct hns_roce_bitmap *bitmap, int cnt, void hns_roce_bitmap_free_range(struct hns_roce_bitmap *bitmap, unsigned long obj, int cnt); -struct ib_ah *hns_roce_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); +struct ib_ah *hns_roce_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata); int hns_roce_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); int hns_roce_destroy_ah(struct ib_ah *ah); diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 6329c971c22f..f03fc1527d70 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -2562,7 +2562,9 @@ static int i40iw_query_pkey(struct ib_device *ibdev, * @ah_attr: address handle attributes */ static struct ib_ah *i40iw_create_ah(struct ib_pd *ibpd, - struct ib_ah_attr *attr) + struct ib_ah_attr *attr, + struct ib_udata *udata) + { return ERR_PTR(-ENOSYS); } diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c index 6be7dc320ff7..20c6d17ac8b8 100644 --- a/drivers/infiniband/hw/mlx4/ah.c +++ b/drivers/infiniband/hw/mlx4/ah.c @@ -126,7 +126,9 @@ static struct ib_ah *create_iboe_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr return &ah->ibah; } -struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata) + { struct mlx4_ib_ah *ah; struct ib_ah *ret; diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h index 35141f451e5c..7f3d976d81ed 100644 --- a/drivers/infiniband/hw/mlx4/mlx4_ib.h +++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h @@ -742,7 +742,8 @@ int mlx4_ib_arm_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); void __mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); void mlx4_ib_cq_clean(struct mlx4_ib_cq *cq, u32 qpn, struct mlx4_ib_srq *srq); -struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); +struct ib_ah *mlx4_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata); int mlx4_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); int mlx4_ib_destroy_ah(struct ib_ah *ah); diff --git a/drivers/infiniband/hw/mlx5/ah.c b/drivers/infiniband/hw/mlx5/ah.c index 745efa4cfc71..ecac9ea2c85f 100644 --- a/drivers/infiniband/hw/mlx5/ah.c +++ b/drivers/infiniband/hw/mlx5/ah.c @@ -64,7 +64,9 @@ static struct ib_ah *create_ib_ah(struct mlx5_ib_dev *dev, return &ah->ibah; } -struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata) + { struct mlx5_ib_ah *ah; struct mlx5_ib_dev *dev = to_mdev(pd->device); diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index 95937e7d2584..ff05afa864ee 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -739,7 +739,8 @@ void mlx5_ib_free_srq_wqe(struct mlx5_ib_srq *srq, int wqe_index); int mlx5_MAD_IFC(struct mlx5_ib_dev *dev, int ignore_mkey, int ignore_bkey, u8 port, const struct ib_wc *in_wc, const struct ib_grh *in_grh, const void *in_mad, void *response_mad); -struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr); +struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata); int mlx5_ib_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr); int mlx5_ib_destroy_ah(struct ib_ah *ah); struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c index 358930a41e36..d31708742ba5 100644 --- a/drivers/infiniband/hw/mthca/mthca_provider.c +++ b/drivers/infiniband/hw/mthca/mthca_provider.c @@ -410,7 +410,9 @@ static int mthca_dealloc_pd(struct ib_pd *pd) } static struct ib_ah *mthca_ah_create(struct ib_pd *pd, - struct ib_ah_attr *ah_attr) + struct ib_ah_attr *ah_attr, + struct ib_udata *udata) + { int err; struct mthca_ah *ah; diff --git a/drivers/infiniband/hw/nes/nes_verbs.c b/drivers/infiniband/hw/nes/nes_verbs.c index bd69125731c1..0bb857c7e439 100644 --- a/drivers/infiniband/hw/nes/nes_verbs.c +++ b/drivers/infiniband/hw/nes/nes_verbs.c @@ -771,7 +771,8 @@ static int nes_dealloc_pd(struct ib_pd *ibpd) /** * nes_create_ah */ -static struct ib_ah *nes_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr) +static struct ib_ah *nes_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata) { return ERR_PTR(-ENOSYS); } diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c index 797362a297b2..14d33b0f3950 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c @@ -154,7 +154,8 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah, return status; } -struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr) +struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr, + struct ib_udata *udata) { u32 *ahid_addr; int status; diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h index 3856dd4c7e3d..0704a24b17c8 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h +++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h @@ -50,7 +50,9 @@ enum { OCRDMA_AH_L3_TYPE_MASK = 0x03, OCRDMA_AH_L3_TYPE_SHIFT = 0x1D /* 29 bits */ }; -struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *); + +struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *, + struct ib_udata *); int ocrdma_destroy_ah(struct ib_ah *); int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *); int ocrdma_modify_ah(struct ib_ah *, struct ib_ah_attr *); diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index a61514296767..ccff6c6e3f33 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2094,7 +2094,8 @@ int qedr_destroy_qp(struct ib_qp *ibqp) return rc; } -struct ib_ah *qedr_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr) +struct ib_ah *qedr_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr, + struct ib_udata *udata) { struct qedr_ah *ah; diff --git a/drivers/infiniband/hw/qedr/verbs.h b/drivers/infiniband/hw/qedr/verbs.h index a9b5e67bb81e..070677ca4d19 100644 --- a/drivers/infiniband/hw/qedr/verbs.h +++ b/drivers/infiniband/hw/qedr/verbs.h @@ -70,7 +70,8 @@ int qedr_query_qp(struct ib_qp *, struct ib_qp_attr *qp_attr, int qp_attr_mask, struct ib_qp_init_attr *); int qedr_destroy_qp(struct ib_qp *ibqp); -struct ib_ah *qedr_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr); +struct ib_ah *qedr_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr, + struct ib_udata *udata); int qedr_destroy_ah(struct ib_ah *ibah); int qedr_dereg_mr(struct ib_mr *); diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index a5bfbba6bbac..fd2a50eb4c91 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -738,7 +738,9 @@ int usnic_ib_mmap(struct ib_ucontext *context, /* In ib callbacks section - Start of stub funcs */ struct ib_ah *usnic_ib_create_ah(struct ib_pd *pd, - struct ib_ah_attr *ah_attr) + struct ib_ah_attr *ah_attr, + struct ib_udata *udata) + { usnic_dbg("\n"); return ERR_PTR(-EPERM); diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.h b/drivers/infiniband/hw/usnic/usnic_ib_verbs.h index 0d9d2e6a14d5..0ed8e072329e 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.h +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.h @@ -75,7 +75,9 @@ int usnic_ib_dealloc_ucontext(struct ib_ucontext *ibcontext); int usnic_ib_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); struct ib_ah *usnic_ib_create_ah(struct ib_pd *pd, - struct ib_ah_attr *ah_attr); + struct ib_ah_attr *ah_attr, + struct ib_udata *udata); + int usnic_ib_destroy_ah(struct ib_ah *ah); int usnic_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, struct ib_send_wr **bad_wr); diff --git a/drivers/infiniband/sw/rxe/rxe_verbs.c b/drivers/infiniband/sw/rxe/rxe_verbs.c index 19841c863daf..187d85ccfe58 100644 --- a/drivers/infiniband/sw/rxe/rxe_verbs.c +++ b/drivers/infiniband/sw/rxe/rxe_verbs.c @@ -316,7 +316,9 @@ static int rxe_init_av(struct rxe_dev *rxe, struct ib_ah_attr *attr, return err; } -static struct ib_ah *rxe_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr) +static struct ib_ah *rxe_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr, + struct ib_udata *udata) + { int err; struct rxe_dev *rxe = to_rdev(ibpd->device); diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 0c6f973e407c..73417a22ee4d 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1951,7 +1951,8 @@ struct ib_device { struct ib_udata *udata); int (*dealloc_pd)(struct ib_pd *pd); struct ib_ah * (*create_ah)(struct ib_pd *pd, - struct ib_ah_attr *ah_attr); + struct ib_ah_attr *ah_attr, + struct ib_udata *udata); int (*modify_ah)(struct ib_ah *ah, struct ib_ah_attr *ah_attr); int (*query_ah)(struct ib_ah *ah, -- cgit v1.2.3 From 5097e71f3edafad3e7d8d4f9c4a137d9aad0fae2 Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 23 Nov 2016 08:23:25 +0200 Subject: IB/mlx5: Use kernel driver to help userspace create ah Resolving a MAC address for a given IP address in userspace is inefficient. This patch lets mlx5 user driver using the kernel driver to resolve the mac and get the answer in the private section of the response. Signed-off-by: Moni Shoua Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/ah.c | 21 +++++++++++++++++++++ include/uapi/rdma/mlx5-abi.h | 6 ++++++ 2 files changed, 27 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/ah.c b/drivers/infiniband/hw/mlx5/ah.c index ecac9ea2c85f..d090e96f6f01 100644 --- a/drivers/infiniband/hw/mlx5/ah.c +++ b/drivers/infiniband/hw/mlx5/ah.c @@ -77,6 +77,27 @@ struct ib_ah *mlx5_ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, if (ll == IB_LINK_LAYER_ETHERNET && !(ah_attr->ah_flags & IB_AH_GRH)) return ERR_PTR(-EINVAL); + if (ll == IB_LINK_LAYER_ETHERNET && udata) { + int err; + struct mlx5_ib_create_ah_resp resp = {}; + u32 min_resp_len = offsetof(typeof(resp), dmac) + + sizeof(resp.dmac); + + if (udata->outlen < min_resp_len) + return ERR_PTR(-EINVAL); + + resp.response_length = min_resp_len; + + err = ib_resolve_eth_dmac(pd->device, ah_attr); + if (err) + return ERR_PTR(err); + + memcpy(resp.dmac, ah_attr->dmac, ETH_ALEN); + err = ib_copy_to_udata(udata, &resp, resp.response_length); + if (err) + return ERR_PTR(err); + } + ah = kzalloc(sizeof(*ah), GFP_ATOMIC); if (!ah) return ERR_PTR(-ENOMEM); diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index ac28729a1245..3ebf3db24c34 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -249,6 +249,12 @@ struct mlx5_ib_create_wq { __u32 reserved; }; +struct mlx5_ib_create_ah_resp { + __u32 response_length; + __u8 dmac[ETH_ALEN]; + __u8 reserved[6]; +}; + struct mlx5_ib_create_wq_resp { __u32 response_length; __u32 reserved; -- cgit v1.2.3 From 41c450fd8da549c5f7cced6650354095b0d4312a Mon Sep 17 00:00:00 2001 From: Moni Shoua Date: Wed, 23 Nov 2016 08:23:26 +0200 Subject: IB/mlx5: Make create/destroy_ah available to userspace Advertise that create_ah and destroy_ah verbs are accessible from uverbs interface. Signed-off-by: Moni Shoua Reviewed-by: Yishai Hadas Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index f2ef2a170d9f..7e5b80361724 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3053,6 +3053,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_CREATE_AH) | + (1ull << IB_USER_VERBS_CMD_DESTROY_AH) | (1ull << IB_USER_VERBS_CMD_REG_MR) | (1ull << IB_USER_VERBS_CMD_REREG_MR) | (1ull << IB_USER_VERBS_CMD_DEREG_MR) | -- cgit v1.2.3 From c482af646d0809a8d5e1b7f4398cce3592589b98 Mon Sep 17 00:00:00 2001 From: Jack Morgenstein Date: Sun, 27 Nov 2016 15:18:19 +0200 Subject: IB/mlx4: Fix out-of-range array index in destroy qp flow For non-special QPs, the port value becomes non-zero only at the RESET-to-INIT transition. If the QP has not undergone that transition, its port number value is still zero. If such a QP is destroyed before being moved out of the RESET state, subtracting one from the qp port number results in a negative value. Using that negative value as an index into the qp1_proxy array results in an out-of-bounds array reference. Fix this by testing that the QP type is one that uses qp1_proxy before using the port number. For special QPs of all types, the port number is specified at QP creation time. Fixes: 9433c188915c ("IB/mlx4: Invoke UPDATE_QP for proxy QP1 on MAC changes") Signed-off-by: Jack Morgenstein Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index 0914731c9aac..c22454383976 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -1280,7 +1280,8 @@ static int _mlx4_ib_destroy_qp(struct ib_qp *qp) if (is_qp0(dev, mqp)) mlx4_CLOSE_PORT(dev->dev, mqp->port); - if (dev->qp1_proxy[mqp->port - 1] == mqp) { + if (mqp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI && + dev->qp1_proxy[mqp->port - 1] == mqp) { mutex_lock(&dev->qp1_proxy_lock[mqp->port - 1]); dev->qp1_proxy[mqp->port - 1] = NULL; mutex_unlock(&dev->qp1_proxy_lock[mqp->port - 1]); -- cgit v1.2.3 From c73b7911de97fad3ab9032a110af48d6ab2da48f Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Sun, 27 Nov 2016 15:18:20 +0200 Subject: IB/mlx5: Assign SRQ type earlier Move the SRQ type assignment to be before actually using it in create_srq_user() and in create_srq_kernel() functions. Fixes: af1ba291c5e4 ('{net, IB}/mlx5: Refactor internal SRQ API') Signed-off-by: Maor Gottlieb Reviewed-by: Majd Dibbiny Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/srq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/srq.c b/drivers/infiniband/hw/mlx5/srq.c index f384db5367fb..83588db2785f 100644 --- a/drivers/infiniband/hw/mlx5/srq.c +++ b/drivers/infiniband/hw/mlx5/srq.c @@ -282,6 +282,7 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, mlx5_ib_dbg(dev, "desc_size 0x%x, req wr 0x%x, srq size 0x%x, max_gs 0x%x, max_avail_gather 0x%x\n", desc_size, init_attr->attr.max_wr, srq->msrq.max, srq->msrq.max_gs, srq->msrq.max_avail_gather); + in.type = init_attr->srq_type; if (pd->uobject) err = create_srq_user(pd, srq, &in, udata, buf_size); @@ -294,7 +295,6 @@ struct ib_srq *mlx5_ib_create_srq(struct ib_pd *pd, goto err_srq; } - in.type = init_attr->srq_type; in.log_size = ilog2(srq->msrq.max); in.wqe_shift = srq->msrq.wqe_shift - 4; if (srq->wq_sig) -- cgit v1.2.3 From afd02cd3a9b6c04b41d946b5d7f6e17b3fc30c6b Mon Sep 17 00:00:00 2001 From: Eli Cohen Date: Sun, 27 Nov 2016 15:18:21 +0200 Subject: IB/mlx5: Avoid system crash when enabling many VFs When enabling many VFs, the total amount of DMA mappings increase significantly. This causes DMA allocations to take a lot of time since they are serialized in the kernel. As a result the driver enters into fatal condition due to timeout and the system hangs. To recover from this we disable MR cache for VFs. PFs will still have a full cache and VFs cache can be manipulated as usual after driver load. Fixes: e126ba97dba9 ('mlx5: Add driver for Mellanox Connect-IB adapters') Signed-off-by: Eli Cohen Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/mr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 6cbda901f259..5258ac870e6a 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -627,7 +627,8 @@ int mlx5_mr_cache_init(struct mlx5_ib_dev *dev) ent->order = i + 2; ent->dev = dev; - if (dev->mdev->profile->mask & MLX5_PROF_MASK_MR_CACHE) + if ((dev->mdev->profile->mask & MLX5_PROF_MASK_MR_CACHE) && + (mlx5_core_is_pf(dev->mdev))) limit = dev->mdev->profile->mr_cache[i].limit; else limit = 0; -- cgit v1.2.3 From b216af408c985092a79472ad10e6f216cb2973fc Mon Sep 17 00:00:00 2001 From: Maor Gottlieb Date: Sun, 27 Nov 2016 15:18:22 +0200 Subject: IB/mlx5: Use u64 for UMR length The fast_registration length is used to convey length for memory registrations through UMR which can be of any size up to 2^64. Change the length type to be u64. Fixes: 968e78dd9644 ('IB/mlx5: Enhance UMR support to allow partial page table update') Signed-off-by: Maor Gottlieb Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/mlx5_ib.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index ff05afa864ee..df3d6af3f683 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -420,7 +420,7 @@ struct mlx5_umr_wr { struct ib_pd *pd; unsigned int page_shift; unsigned int npages; - u32 length; + u64 length; int access_flags; u32 mkey; }; -- cgit v1.2.3 From d012f5d6f8597f936f44c79e46345fda86dcff4d Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 27 Nov 2016 16:51:34 +0200 Subject: IB/mlx5: Refactor registration to netdev notifier Refactor the netdev notifier registration into a small helper function. This is a pre-step towards having mlx5 IB device over an Ethernet port which doesn't support RoCE. Also, renamed the de-registration helper and the new helper as netdev notifier and not roce, to make it clear this is not only used with roce. This patch doesn't change any functionality. Signed-off-by: Or Gerlitz Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 7e5b80361724..0ee1e4ab02fa 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2843,7 +2843,21 @@ static void mlx5_roce_lag_cleanup(struct mlx5_ib_dev *dev) } } -static void mlx5_remove_roce_notifier(struct mlx5_ib_dev *dev) +static int mlx5_add_netdev_notifier(struct mlx5_ib_dev *dev) +{ + int err; + + dev->roce.nb.notifier_call = mlx5_netdev_event; + err = register_netdevice_notifier(&dev->roce.nb); + if (err) { + dev->roce.nb.notifier_call = NULL; + return err; + } + + return 0; +} + +static void mlx5_remove_netdev_notifier(struct mlx5_ib_dev *dev) { if (dev->roce.nb.notifier_call) { unregister_netdevice_notifier(&dev->roce.nb); @@ -2855,12 +2869,9 @@ static int mlx5_enable_roce(struct mlx5_ib_dev *dev) { int err; - dev->roce.nb.notifier_call = mlx5_netdev_event; - err = register_netdevice_notifier(&dev->roce.nb); - if (err) { - dev->roce.nb.notifier_call = NULL; + err = mlx5_add_netdev_notifier(dev); + if (err) return err; - } err = mlx5_nic_vport_enable_roce(dev->mdev); if (err) @@ -2876,7 +2887,7 @@ err_disable_roce: mlx5_nic_vport_disable_roce(dev->mdev); err_unregister_netdevice_notifier: - mlx5_remove_roce_notifier(dev); + mlx5_remove_netdev_notifier(dev); return err; } @@ -3242,7 +3253,7 @@ err_rsrc: err_disable_roce: if (ll == IB_LINK_LAYER_ETHERNET) { mlx5_disable_roce(dev); - mlx5_remove_roce_notifier(dev); + mlx5_remove_netdev_notifier(dev); } err_free_port: @@ -3259,7 +3270,7 @@ static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context) struct mlx5_ib_dev *dev = context; enum rdma_link_layer ll = mlx5_ib_port_link_layer(&dev->ib_dev, 1); - mlx5_remove_roce_notifier(dev); + mlx5_remove_netdev_notifier(dev); ib_unregister_device(&dev->ib_dev); mlx5_ib_dealloc_q_counters(dev); destroy_umrc_res(dev); -- cgit v1.2.3 From 45f95acd63222dd1dc752fa904536327b10f1082 Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 27 Nov 2016 16:51:35 +0200 Subject: IB/mlx5: Rename RoCE related helpers to reflect being Eth ones This is a pre-step towards having mlx5 IB device also over Eth ports where RoCE is not supported. We change the roce enable/disable and roce_lag init/fini function names to have _eth instead of _roce. This patch doesn't change any functionality. Signed-off-by: Or Gerlitz Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 0ee1e4ab02fa..b5b7459e9af0 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2802,7 +2802,7 @@ static void get_dev_fw_str(struct ib_device *ibdev, char *str, fw_rev_min(dev->mdev), fw_rev_sub(dev->mdev)); } -static int mlx5_roce_lag_init(struct mlx5_ib_dev *dev) +static int mlx5_eth_lag_init(struct mlx5_ib_dev *dev) { struct mlx5_core_dev *mdev = dev->mdev; struct mlx5_flow_namespace *ns = mlx5_get_flow_namespace(mdev, @@ -2831,7 +2831,7 @@ err_destroy_vport_lag: return err; } -static void mlx5_roce_lag_cleanup(struct mlx5_ib_dev *dev) +static void mlx5_eth_lag_cleanup(struct mlx5_ib_dev *dev) { struct mlx5_core_dev *mdev = dev->mdev; @@ -2865,7 +2865,7 @@ static void mlx5_remove_netdev_notifier(struct mlx5_ib_dev *dev) } } -static int mlx5_enable_roce(struct mlx5_ib_dev *dev) +static int mlx5_enable_eth(struct mlx5_ib_dev *dev) { int err; @@ -2877,7 +2877,7 @@ static int mlx5_enable_roce(struct mlx5_ib_dev *dev) if (err) goto err_unregister_netdevice_notifier; - err = mlx5_roce_lag_init(dev); + err = mlx5_eth_lag_init(dev); if (err) goto err_disable_roce; @@ -2891,9 +2891,9 @@ err_unregister_netdevice_notifier: return err; } -static void mlx5_disable_roce(struct mlx5_ib_dev *dev) +static void mlx5_disable_eth(struct mlx5_ib_dev *dev) { - mlx5_roce_lag_cleanup(dev); + mlx5_eth_lag_cleanup(dev); mlx5_nic_vport_disable_roce(dev->mdev); } @@ -3199,14 +3199,14 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) spin_lock_init(&dev->reset_flow_resource_lock); if (ll == IB_LINK_LAYER_ETHERNET) { - err = mlx5_enable_roce(dev); + err = mlx5_enable_eth(dev); if (err) goto err_dealloc; } err = create_dev_resources(&dev->devr); if (err) - goto err_disable_roce; + goto err_disable_eth; err = mlx5_ib_odp_init_one(dev); if (err) @@ -3250,9 +3250,9 @@ err_odp: err_rsrc: destroy_dev_resources(&dev->devr); -err_disable_roce: +err_disable_eth: if (ll == IB_LINK_LAYER_ETHERNET) { - mlx5_disable_roce(dev); + mlx5_disable_eth(dev); mlx5_remove_netdev_notifier(dev); } @@ -3277,7 +3277,7 @@ static void mlx5_ib_remove(struct mlx5_core_dev *mdev, void *context) mlx5_ib_odp_remove_one(dev); destroy_dev_resources(&dev->devr); if (ll == IB_LINK_LAYER_ETHERNET) - mlx5_disable_roce(dev); + mlx5_disable_eth(dev); kfree(dev->port); ib_dealloc_device(&dev->ib_dev); } -- cgit v1.2.3 From ca5b91d63192ceaa41a6145f8c923debb64c71fa Mon Sep 17 00:00:00 2001 From: Or Gerlitz Date: Sun, 27 Nov 2016 16:51:36 +0200 Subject: IB/mlx5: Support RAW Ethernet when RoCE is disabled On some environments, such as certain SRIOV VF configurations, RoCE is not supported for mlx5 Ethernet ports. Currently, the driver will not open IB device on that port. This is problematic, since we do want user-space RAW Ethernet (RAW_PACKET QPs) functionality to remain in place. For that end, enhance the relevant driver flows such that we do create a device instance in that case. Signed-off-by: Or Gerlitz Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index b5b7459e9af0..8b013f8b832a 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -2779,6 +2779,8 @@ static int mlx5_port_immutable(struct ib_device *ibdev, u8 port_num, struct ib_port_immutable *immutable) { struct ib_port_attr attr; + struct mlx5_ib_dev *dev = to_mdev(ibdev); + enum rdma_link_layer ll = mlx5_ib_port_link_layer(ibdev, port_num); int err; err = mlx5_ib_query_port(ibdev, port_num, &attr); @@ -2788,7 +2790,8 @@ static int mlx5_port_immutable(struct ib_device *ibdev, u8 port_num, immutable->pkey_tbl_len = attr.pkey_tbl_len; immutable->gid_tbl_len = attr.gid_tbl_len; immutable->core_cap_flags = get_core_cap_flags(ibdev); - immutable->max_mad_size = IB_MGMT_MAD_SIZE; + if ((ll == IB_LINK_LAYER_INFINIBAND) || MLX5_CAP_GEN(dev->mdev, roce)) + immutable->max_mad_size = IB_MGMT_MAD_SIZE; return 0; } @@ -2873,9 +2876,11 @@ static int mlx5_enable_eth(struct mlx5_ib_dev *dev) if (err) return err; - err = mlx5_nic_vport_enable_roce(dev->mdev); - if (err) - goto err_unregister_netdevice_notifier; + if (MLX5_CAP_GEN(dev->mdev, roce)) { + err = mlx5_nic_vport_enable_roce(dev->mdev); + if (err) + goto err_unregister_netdevice_notifier; + } err = mlx5_eth_lag_init(dev); if (err) @@ -2884,7 +2889,8 @@ static int mlx5_enable_eth(struct mlx5_ib_dev *dev) return 0; err_disable_roce: - mlx5_nic_vport_disable_roce(dev->mdev); + if (MLX5_CAP_GEN(dev->mdev, roce)) + mlx5_nic_vport_disable_roce(dev->mdev); err_unregister_netdevice_notifier: mlx5_remove_netdev_notifier(dev); @@ -2894,7 +2900,8 @@ err_unregister_netdevice_notifier: static void mlx5_disable_eth(struct mlx5_ib_dev *dev) { mlx5_eth_lag_cleanup(dev); - mlx5_nic_vport_disable_roce(dev->mdev); + if (MLX5_CAP_GEN(dev->mdev, roce)) + mlx5_nic_vport_disable_roce(dev->mdev); } static void mlx5_ib_dealloc_q_counters(struct mlx5_ib_dev *dev) @@ -3016,9 +3023,6 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) port_type_cap = MLX5_CAP_GEN(mdev, port_type); ll = mlx5_port_type_cap_to_rdma_ll(port_type_cap); - if ((ll == IB_LINK_LAYER_ETHERNET) && !MLX5_CAP_GEN(mdev, roce)) - return NULL; - printk_once(KERN_INFO "%s", mlx5_version); dev = (struct mlx5_ib_dev *)ib_alloc_device(sizeof(*dev)); -- cgit v1.2.3 From d949167d68b304c0a00331cf33ef49a29b65d85f Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Thu, 1 Dec 2016 13:43:13 +0200 Subject: IB/mlx5: Report mlx5 packet pacing capabilities when querying device Enable mlx5 based hardware to report packet pacing capabilities from kernel to user space. Packet pacing allows to limit the rate to any number between the maximum and minimum, based on user settings. The capabilities are exposed to user space through query_device by uhw. The following capabilities are reported: 1. The maximum and minimum rate limit in kbps supported by packet pacing. 2. Bitmap showing which QP types are supported by packet pacing operation. Signed-off-by: Bodong Wang Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 13 +++++++++++++ include/uapi/rdma/mlx5-abi.h | 13 +++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 8b013f8b832a..6c194000903d 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -693,6 +693,19 @@ static int mlx5_ib_query_device(struct ib_device *ibdev, resp.response_length += sizeof(resp.cqe_comp_caps); } + if (field_avail(typeof(resp), packet_pacing_caps, uhw->outlen)) { + if (MLX5_CAP_QOS(mdev, packet_pacing) && + MLX5_CAP_GEN(mdev, qos)) { + resp.packet_pacing_caps.qp_rate_limit_max = + MLX5_CAP_QOS(mdev, packet_pacing_max_rate); + resp.packet_pacing_caps.qp_rate_limit_min = + MLX5_CAP_QOS(mdev, packet_pacing_min_rate); + resp.packet_pacing_caps.supported_qpts |= + 1 << IB_QPT_RAW_PACKET; + } + resp.response_length += sizeof(resp.packet_pacing_caps); + } + if (uhw->outlen) { err = ib_copy_to_udata(uhw, &resp, resp.response_length); diff --git a/include/uapi/rdma/mlx5-abi.h b/include/uapi/rdma/mlx5-abi.h index 3ebf3db24c34..fae6cdaeb56d 100644 --- a/include/uapi/rdma/mlx5-abi.h +++ b/include/uapi/rdma/mlx5-abi.h @@ -136,12 +136,25 @@ struct mlx5_ib_cqe_comp_caps { __u32 supported_format; /* enum mlx5_ib_cqe_comp_res_format */ }; +struct mlx5_packet_pacing_caps { + __u32 qp_rate_limit_min; + __u32 qp_rate_limit_max; /* In kpbs */ + + /* Corresponding bit will be set if qp type from + * 'enum ib_qp_type' is supported, e.g. + * supported_qpts |= 1 << IB_QPT_RAW_PACKET + */ + __u32 supported_qpts; + __u32 reserved; +}; + struct mlx5_ib_query_device_resp { __u32 comp_mask; __u32 response_length; struct mlx5_ib_tso_caps tso_caps; struct mlx5_ib_rss_caps rss_caps; struct mlx5_ib_cqe_comp_caps cqe_comp_caps; + struct mlx5_packet_pacing_caps packet_pacing_caps; __u32 mlx5_ib_support_multi_pkt_send_wqes; __u32 reserved; }; -- cgit v1.2.3 From 528e5a1bd3f0e9b760cb3a1062fce7513712a15d Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Thu, 1 Dec 2016 13:43:14 +0200 Subject: IB/core: Support rate limit for packet pacing Add new member rate_limit to ib_qp_attr which holds the packet pacing rate in kbps, 0 means unlimited. IB_QP_RATE_LIMIT is added to ib_attr_mask and could be used by RAW QPs when changing QP state from RTR to RTS, RTS to RTS. Signed-off-by: Bodong Wang Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/verbs.c | 2 ++ include/rdma/ib_verbs.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c index c976f29f7ad2..71580cc28c9e 100644 --- a/drivers/infiniband/core/verbs.c +++ b/drivers/infiniband/core/verbs.c @@ -1016,6 +1016,7 @@ static const struct { IB_QP_QKEY), [IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY), + [IB_QPT_RAW_PACKET] = IB_QP_RATE_LIMIT, } } }, @@ -1049,6 +1050,7 @@ static const struct { IB_QP_QKEY), [IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY), + [IB_QPT_RAW_PACKET] = IB_QP_RATE_LIMIT, } }, [IB_QPS_SQD] = { diff --git a/include/rdma/ib_verbs.h b/include/rdma/ib_verbs.h index 73417a22ee4d..8029d2a51f14 100644 --- a/include/rdma/ib_verbs.h +++ b/include/rdma/ib_verbs.h @@ -1102,6 +1102,7 @@ enum ib_qp_attr_mask { IB_QP_RESERVED2 = (1<<22), IB_QP_RESERVED3 = (1<<23), IB_QP_RESERVED4 = (1<<24), + IB_QP_RATE_LIMIT = (1<<25), }; enum ib_qp_state { @@ -1151,6 +1152,7 @@ struct ib_qp_attr { u8 rnr_retry; u8 alt_port_num; u8 alt_timeout; + u32 rate_limit; }; enum ib_wr_opcode { -- cgit v1.2.3 From 189aba99e70030cfb56bd8f199bc5b077a1bc6ff Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Thu, 1 Dec 2016 13:43:15 +0200 Subject: IB/uverbs: Extend modify_qp and support packet pacing An new uverbs command ib_uverbs_ex_modify_qp is added to support more QP attributes. User driver should choose to call the legacy/extended API based on input mask. IB_USER_LAST_QP_ATTR_MASK is added to indicated the maximum bit position which supports legacy ib_uverbs_modify_qp. IB_USER_LEGACY_LAST_QP_ATTR_MASK indicates the maximum bit position which supports ib_uverbs_ex_modify_qp, the value of this mask should be updated if new mask is added later. Along with this change, rate_limit is supported by the extended command, user driver could use it to control packet packing. Signed-off-by: Bodong Wang Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/core/uverbs.h | 1 + drivers/infiniband/core/uverbs_cmd.c | 192 ++++++++++++++++++++++------------ drivers/infiniband/core/uverbs_main.c | 1 + include/uapi/rdma/ib_user_verbs.h | 21 ++++ 4 files changed, 146 insertions(+), 69 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h index df26a741cda6..455034ac994e 100644 --- a/drivers/infiniband/core/uverbs.h +++ b/drivers/infiniband/core/uverbs.h @@ -289,5 +289,6 @@ IB_UVERBS_DECLARE_EX_CMD(modify_wq); IB_UVERBS_DECLARE_EX_CMD(destroy_wq); IB_UVERBS_DECLARE_EX_CMD(create_rwq_ind_table); IB_UVERBS_DECLARE_EX_CMD(destroy_rwq_ind_table); +IB_UVERBS_DECLARE_EX_CMD(modify_qp); #endif /* UVERBS_H */ diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index cdb935ddab69..09b649159e6c 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -2328,96 +2328,88 @@ static int modify_qp_mask(enum ib_qp_type qp_type, int mask) } } -ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, - struct ib_device *ib_dev, - const char __user *buf, int in_len, - int out_len) +static int modify_qp(struct ib_uverbs_file *file, + struct ib_uverbs_ex_modify_qp *cmd, struct ib_udata *udata) { - struct ib_uverbs_modify_qp cmd; - struct ib_udata udata; - struct ib_qp *qp; - struct ib_qp_attr *attr; - int ret; - - if (copy_from_user(&cmd, buf, sizeof cmd)) - return -EFAULT; - - INIT_UDATA(&udata, buf + sizeof cmd, NULL, in_len - sizeof cmd, - out_len); + struct ib_qp_attr *attr; + struct ib_qp *qp; + int ret; attr = kmalloc(sizeof *attr, GFP_KERNEL); if (!attr) return -ENOMEM; - qp = idr_read_qp(cmd.qp_handle, file->ucontext); + qp = idr_read_qp(cmd->base.qp_handle, file->ucontext); if (!qp) { ret = -EINVAL; goto out; } - attr->qp_state = cmd.qp_state; - attr->cur_qp_state = cmd.cur_qp_state; - attr->path_mtu = cmd.path_mtu; - attr->path_mig_state = cmd.path_mig_state; - attr->qkey = cmd.qkey; - attr->rq_psn = cmd.rq_psn; - attr->sq_psn = cmd.sq_psn; - attr->dest_qp_num = cmd.dest_qp_num; - attr->qp_access_flags = cmd.qp_access_flags; - attr->pkey_index = cmd.pkey_index; - attr->alt_pkey_index = cmd.alt_pkey_index; - attr->en_sqd_async_notify = cmd.en_sqd_async_notify; - attr->max_rd_atomic = cmd.max_rd_atomic; - attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic; - attr->min_rnr_timer = cmd.min_rnr_timer; - attr->port_num = cmd.port_num; - attr->timeout = cmd.timeout; - attr->retry_cnt = cmd.retry_cnt; - attr->rnr_retry = cmd.rnr_retry; - attr->alt_port_num = cmd.alt_port_num; - attr->alt_timeout = cmd.alt_timeout; - - memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16); - attr->ah_attr.grh.flow_label = cmd.dest.flow_label; - attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index; - attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit; - attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class; - attr->ah_attr.dlid = cmd.dest.dlid; - attr->ah_attr.sl = cmd.dest.sl; - attr->ah_attr.src_path_bits = cmd.dest.src_path_bits; - attr->ah_attr.static_rate = cmd.dest.static_rate; - attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0; - attr->ah_attr.port_num = cmd.dest.port_num; - - memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16); - attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label; - attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index; - attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit; - attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class; - attr->alt_ah_attr.dlid = cmd.alt_dest.dlid; - attr->alt_ah_attr.sl = cmd.alt_dest.sl; - attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits; - attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate; - attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0; - attr->alt_ah_attr.port_num = cmd.alt_dest.port_num; + attr->qp_state = cmd->base.qp_state; + attr->cur_qp_state = cmd->base.cur_qp_state; + attr->path_mtu = cmd->base.path_mtu; + attr->path_mig_state = cmd->base.path_mig_state; + attr->qkey = cmd->base.qkey; + attr->rq_psn = cmd->base.rq_psn; + attr->sq_psn = cmd->base.sq_psn; + attr->dest_qp_num = cmd->base.dest_qp_num; + attr->qp_access_flags = cmd->base.qp_access_flags; + attr->pkey_index = cmd->base.pkey_index; + attr->alt_pkey_index = cmd->base.alt_pkey_index; + attr->en_sqd_async_notify = cmd->base.en_sqd_async_notify; + attr->max_rd_atomic = cmd->base.max_rd_atomic; + attr->max_dest_rd_atomic = cmd->base.max_dest_rd_atomic; + attr->min_rnr_timer = cmd->base.min_rnr_timer; + attr->port_num = cmd->base.port_num; + attr->timeout = cmd->base.timeout; + attr->retry_cnt = cmd->base.retry_cnt; + attr->rnr_retry = cmd->base.rnr_retry; + attr->alt_port_num = cmd->base.alt_port_num; + attr->alt_timeout = cmd->base.alt_timeout; + attr->rate_limit = cmd->rate_limit; + + memcpy(attr->ah_attr.grh.dgid.raw, cmd->base.dest.dgid, 16); + attr->ah_attr.grh.flow_label = cmd->base.dest.flow_label; + attr->ah_attr.grh.sgid_index = cmd->base.dest.sgid_index; + attr->ah_attr.grh.hop_limit = cmd->base.dest.hop_limit; + attr->ah_attr.grh.traffic_class = cmd->base.dest.traffic_class; + attr->ah_attr.dlid = cmd->base.dest.dlid; + attr->ah_attr.sl = cmd->base.dest.sl; + attr->ah_attr.src_path_bits = cmd->base.dest.src_path_bits; + attr->ah_attr.static_rate = cmd->base.dest.static_rate; + attr->ah_attr.ah_flags = cmd->base.dest.is_global ? + IB_AH_GRH : 0; + attr->ah_attr.port_num = cmd->base.dest.port_num; + + memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd->base.alt_dest.dgid, 16); + attr->alt_ah_attr.grh.flow_label = cmd->base.alt_dest.flow_label; + attr->alt_ah_attr.grh.sgid_index = cmd->base.alt_dest.sgid_index; + attr->alt_ah_attr.grh.hop_limit = cmd->base.alt_dest.hop_limit; + attr->alt_ah_attr.grh.traffic_class = cmd->base.alt_dest.traffic_class; + attr->alt_ah_attr.dlid = cmd->base.alt_dest.dlid; + attr->alt_ah_attr.sl = cmd->base.alt_dest.sl; + attr->alt_ah_attr.src_path_bits = cmd->base.alt_dest.src_path_bits; + attr->alt_ah_attr.static_rate = cmd->base.alt_dest.static_rate; + attr->alt_ah_attr.ah_flags = cmd->base.alt_dest.is_global ? + IB_AH_GRH : 0; + attr->alt_ah_attr.port_num = cmd->base.alt_dest.port_num; if (qp->real_qp == qp) { - if (cmd.attr_mask & IB_QP_AV) { + if (cmd->base.attr_mask & IB_QP_AV) { ret = ib_resolve_eth_dmac(qp->device, &attr->ah_attr); if (ret) goto release_qp; } ret = qp->device->modify_qp(qp, attr, - modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata); + modify_qp_mask(qp->qp_type, + cmd->base.attr_mask), + udata); } else { - ret = ib_modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask)); + ret = ib_modify_qp(qp, attr, + modify_qp_mask(qp->qp_type, + cmd->base.attr_mask)); } - if (ret) - goto release_qp; - - ret = in_len; - release_qp: put_qp_read(qp); @@ -2427,6 +2419,68 @@ out: return ret; } +ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file, + struct ib_device *ib_dev, + const char __user *buf, int in_len, + int out_len) +{ + struct ib_uverbs_ex_modify_qp cmd = {}; + struct ib_udata udata; + int ret; + + if (copy_from_user(&cmd.base, buf, sizeof(cmd.base))) + return -EFAULT; + + if (cmd.base.attr_mask & + ~((IB_USER_LEGACY_LAST_QP_ATTR_MASK << 1) - 1)) + return -EOPNOTSUPP; + + INIT_UDATA(&udata, buf + sizeof(cmd.base), NULL, + in_len - sizeof(cmd.base), out_len); + + ret = modify_qp(file, &cmd, &udata); + if (ret) + return ret; + + return in_len; +} + +int ib_uverbs_ex_modify_qp(struct ib_uverbs_file *file, + struct ib_device *ib_dev, + struct ib_udata *ucore, + struct ib_udata *uhw) +{ + struct ib_uverbs_ex_modify_qp cmd = {}; + int ret; + + /* + * Last bit is reserved for extending the attr_mask by + * using another field. + */ + BUILD_BUG_ON(IB_USER_LAST_QP_ATTR_MASK == (1 << 31)); + + if (ucore->inlen < sizeof(cmd.base)) + return -EINVAL; + + ret = ib_copy_from_udata(&cmd, ucore, min(sizeof(cmd), ucore->inlen)); + if (ret) + return ret; + + if (cmd.base.attr_mask & + ~((IB_USER_LAST_QP_ATTR_MASK << 1) - 1)) + return -EOPNOTSUPP; + + if (ucore->inlen > sizeof(cmd)) { + if (ib_is_udata_cleared(ucore, sizeof(cmd), + ucore->inlen - sizeof(cmd))) + return -EOPNOTSUPP; + } + + ret = modify_qp(file, &cmd, uhw); + + return ret; +} + ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file, struct ib_device *ib_dev, const char __user *buf, int in_len, diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 0012fa58c105..80839c31c887 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -137,6 +137,7 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file, [IB_USER_VERBS_EX_CMD_DESTROY_WQ] = ib_uverbs_ex_destroy_wq, [IB_USER_VERBS_EX_CMD_CREATE_RWQ_IND_TBL] = ib_uverbs_ex_create_rwq_ind_table, [IB_USER_VERBS_EX_CMD_DESTROY_RWQ_IND_TBL] = ib_uverbs_ex_destroy_rwq_ind_table, + [IB_USER_VERBS_EX_CMD_MODIFY_QP] = ib_uverbs_ex_modify_qp, }; static void ib_uverbs_add_one(struct ib_device *device); diff --git a/include/uapi/rdma/ib_user_verbs.h b/include/uapi/rdma/ib_user_verbs.h index 90ba5e88ec00..dfdfe4e92d31 100644 --- a/include/uapi/rdma/ib_user_verbs.h +++ b/include/uapi/rdma/ib_user_verbs.h @@ -37,6 +37,7 @@ #define IB_USER_VERBS_H #include +#include /* * Increment this value if any changes that break userspace ABI @@ -93,6 +94,7 @@ enum { IB_USER_VERBS_EX_CMD_QUERY_DEVICE = IB_USER_VERBS_CMD_QUERY_DEVICE, IB_USER_VERBS_EX_CMD_CREATE_CQ = IB_USER_VERBS_CMD_CREATE_CQ, IB_USER_VERBS_EX_CMD_CREATE_QP = IB_USER_VERBS_CMD_CREATE_QP, + IB_USER_VERBS_EX_CMD_MODIFY_QP = IB_USER_VERBS_CMD_MODIFY_QP, IB_USER_VERBS_EX_CMD_CREATE_FLOW = IB_USER_VERBS_CMD_THRESHOLD, IB_USER_VERBS_EX_CMD_DESTROY_FLOW, IB_USER_VERBS_EX_CMD_CREATE_WQ, @@ -545,6 +547,14 @@ enum { IB_UVERBS_CREATE_QP_SUP_COMP_MASK = IB_UVERBS_CREATE_QP_MASK_IND_TABLE, }; +enum { + IB_USER_LEGACY_LAST_QP_ATTR_MASK = IB_QP_DEST_QPN +}; + +enum { + IB_USER_LAST_QP_ATTR_MASK = IB_QP_RATE_LIMIT +}; + struct ib_uverbs_ex_create_qp { __u64 user_handle; __u32 pd_handle; @@ -684,9 +694,20 @@ struct ib_uverbs_modify_qp { __u64 driver_data[0]; }; +struct ib_uverbs_ex_modify_qp { + struct ib_uverbs_modify_qp base; + __u32 rate_limit; + __u32 reserved; +}; + struct ib_uverbs_modify_qp_resp { }; +struct ib_uverbs_ex_modify_qp_resp { + __u32 comp_mask; + __u32 response_length; +}; + struct ib_uverbs_destroy_qp { __u64 response; __u32 qp_handle; -- cgit v1.2.3 From 7d29f349a4b9dcf5bc9dcc05630d6a7f6b6b3ccd Mon Sep 17 00:00:00 2001 From: Bodong Wang Date: Thu, 1 Dec 2016 13:43:16 +0200 Subject: IB/mlx5: Properly adjust rate limit on QP state transitions - Add MODIFY_QP_EX CMD to extend modify_qp. - Rate limit will be updated in the following state transactions: RTR2RTS, RTS2RTS. The limit will be removed when SQ is in RST and ERR state. Signed-off-by: Bodong Wang Reviewed-by: Matan Barak Signed-off-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 3 +- drivers/infiniband/hw/mlx5/mlx5_ib.h | 1 + drivers/infiniband/hw/mlx5/qp.c | 74 ++++++++++++++++++++++++++++++++---- 3 files changed, 69 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index 6c194000903d..cda541ced141 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -3105,7 +3105,8 @@ static void *mlx5_ib_add(struct mlx5_core_dev *mdev) dev->ib_dev.uverbs_ex_cmd_mask = (1ull << IB_USER_VERBS_EX_CMD_QUERY_DEVICE) | (1ull << IB_USER_VERBS_EX_CMD_CREATE_CQ) | - (1ull << IB_USER_VERBS_EX_CMD_CREATE_QP); + (1ull << IB_USER_VERBS_EX_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_EX_CMD_MODIFY_QP); dev->ib_dev.query_device = mlx5_ib_query_device; dev->ib_dev.query_port = mlx5_ib_query_port; diff --git a/drivers/infiniband/hw/mlx5/mlx5_ib.h b/drivers/infiniband/hw/mlx5/mlx5_ib.h index df3d6af3f683..ab8961cc8bca 100644 --- a/drivers/infiniband/hw/mlx5/mlx5_ib.h +++ b/drivers/infiniband/hw/mlx5/mlx5_ib.h @@ -389,6 +389,7 @@ struct mlx5_ib_qp { struct list_head qps_list; struct list_head cq_recv_list; struct list_head cq_send_list; + u32 rate_limit; }; struct mlx5_ib_cq_buf { diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index aa27688f5ae9..a69524fb6032 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -78,12 +78,14 @@ struct mlx5_wqe_eth_pad { enum raw_qp_set_mask_map { MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID = 1UL << 0, + MLX5_RAW_QP_RATE_LIMIT = 1UL << 1, }; struct mlx5_modify_raw_qp_param { u16 operation; u32 set_mask; /* raw_qp_set_mask_map */ + u32 rate_limit; u8 rq_q_ctr_id; }; @@ -2470,8 +2472,14 @@ out: } static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev, - struct mlx5_ib_sq *sq, int new_state) + struct mlx5_ib_sq *sq, + int new_state, + const struct mlx5_modify_raw_qp_param *raw_qp_param) { + struct mlx5_ib_qp *ibqp = sq->base.container_mibqp; + u32 old_rate = ibqp->rate_limit; + u32 new_rate = old_rate; + u16 rl_index = 0; void *in; void *sqc; int inlen; @@ -2487,10 +2495,44 @@ static int modify_raw_packet_qp_sq(struct mlx5_core_dev *dev, sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx); MLX5_SET(sqc, sqc, state, new_state); + if (raw_qp_param->set_mask & MLX5_RAW_QP_RATE_LIMIT) { + if (new_state != MLX5_SQC_STATE_RDY) + pr_warn("%s: Rate limit can only be changed when SQ is moving to RDY\n", + __func__); + else + new_rate = raw_qp_param->rate_limit; + } + + if (old_rate != new_rate) { + if (new_rate) { + err = mlx5_rl_add_rate(dev, new_rate, &rl_index); + if (err) { + pr_err("Failed configuring rate %u: %d\n", + new_rate, err); + goto out; + } + } + + MLX5_SET64(modify_sq_in, in, modify_bitmask, 1); + MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index, rl_index); + } + err = mlx5_core_modify_sq(dev, sq->base.mqp.qpn, in, inlen); - if (err) + if (err) { + /* Remove new rate from table if failed */ + if (new_rate && + old_rate != new_rate) + mlx5_rl_remove_rate(dev, new_rate); goto out; + } + /* Only remove the old rate after new rate was set */ + if ((old_rate && + (old_rate != new_rate)) || + (new_state != MLX5_SQC_STATE_RDY)) + mlx5_rl_remove_rate(dev, old_rate); + + ibqp->rate_limit = new_rate; sq->state = new_state; out: @@ -2505,6 +2547,8 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, struct mlx5_ib_raw_packet_qp *raw_packet_qp = &qp->raw_packet_qp; struct mlx5_ib_rq *rq = &raw_packet_qp->rq; struct mlx5_ib_sq *sq = &raw_packet_qp->sq; + int modify_rq = !!qp->rq.wqe_cnt; + int modify_sq = !!qp->sq.wqe_cnt; int rq_state; int sq_state; int err; @@ -2522,10 +2566,18 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, rq_state = MLX5_RQC_STATE_RST; sq_state = MLX5_SQC_STATE_RST; break; - case MLX5_CMD_OP_INIT2INIT_QP: - case MLX5_CMD_OP_INIT2RTR_QP: case MLX5_CMD_OP_RTR2RTS_QP: case MLX5_CMD_OP_RTS2RTS_QP: + if (raw_qp_param->set_mask == + MLX5_RAW_QP_RATE_LIMIT) { + modify_rq = 0; + sq_state = sq->state; + } else { + return raw_qp_param->set_mask ? -EINVAL : 0; + } + break; + case MLX5_CMD_OP_INIT2INIT_QP: + case MLX5_CMD_OP_INIT2RTR_QP: if (raw_qp_param->set_mask) return -EINVAL; else @@ -2535,13 +2587,13 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, return -EINVAL; } - if (qp->rq.wqe_cnt) { - err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param); + if (modify_rq) { + err = modify_raw_packet_qp_rq(dev, rq, rq_state, raw_qp_param); if (err) return err; } - if (qp->sq.wqe_cnt) { + if (modify_sq) { if (tx_affinity) { err = modify_raw_packet_tx_affinity(dev->mdev, sq, tx_affinity); @@ -2549,7 +2601,7 @@ static int modify_raw_packet_qp(struct mlx5_ib_dev *dev, struct mlx5_ib_qp *qp, return err; } - return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state); + return modify_raw_packet_qp_sq(dev->mdev, sq, sq_state, raw_qp_param); } return 0; @@ -2804,6 +2856,12 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, raw_qp_param.rq_q_ctr_id = mibport->q_cnt_id; raw_qp_param.set_mask |= MLX5_RAW_QP_MOD_SET_RQ_Q_CTR_ID; } + + if (attr_mask & IB_QP_RATE_LIMIT) { + raw_qp_param.rate_limit = attr->rate_limit; + raw_qp_param.set_mask |= MLX5_RAW_QP_RATE_LIMIT; + } + err = modify_raw_packet_qp(dev, qp, &raw_qp_param, tx_affinity); } else { err = mlx5_core_qp_modify(dev->mdev, op, optpar, context, -- cgit v1.2.3 From d2a61918401ea8db8a6f922e98e86a66b4930cec Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Fri, 2 Dec 2016 21:14:15 -0700 Subject: nvme/pci: Log PCI_STATUS when the controller dies When debugging nvme controller crashes, it's nice to know whether the controller died cleanly so that the failure is just reflected in CSTS, it died and put an error in PCI_STATUS, or whether it died so badly that it stopped responding to PCI configuration space reads. I've seen a failure that gives 0xffff in PCI_STATUS on a Samsung "SM951 NVMe SAMSUNG 256GB" with firmware "BXW75D0Q". Reviewed-by: Christoph Hellwig Signed-off-by: Andy Lutomirski Reviewed-by: Keith Busch Fixed up white space and hunk reject. Signed-off-by: Jens Axboe --- drivers/nvme/host/pci.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index d6e6bce93d0c..2fd7dc2e8fc4 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -1282,6 +1282,24 @@ static bool nvme_should_reset(struct nvme_dev *dev, u32 csts) return true; } +static void nvme_warn_reset(struct nvme_dev *dev, u32 csts) +{ + /* Read a config register to help see what died. */ + u16 pci_status; + int result; + + result = pci_read_config_word(to_pci_dev(dev->dev), PCI_STATUS, + &pci_status); + if (result == PCIBIOS_SUCCESSFUL) + dev_warn(dev->dev, + "controller is down; will reset: CSTS=0x%x, PCI_STATUS=0x%hx\n", + csts, pci_status); + else + dev_warn(dev->dev, + "controller is down; will reset: CSTS=0x%x, PCI_STATUS read failed (%d)\n", + csts, result); +} + static void nvme_watchdog_timer(unsigned long data) { struct nvme_dev *dev = (struct nvme_dev *)data; @@ -1290,9 +1308,7 @@ static void nvme_watchdog_timer(unsigned long data) /* Skip controllers under certain specific conditions. */ if (nvme_should_reset(dev, csts)) { if (!nvme_reset(dev)) - dev_warn(dev->dev, - "Failed status: 0x%x, reset controller.\n", - csts); + nvme_warn_reset(dev, csts); return; } -- cgit v1.2.3 From 9165dabb2500b3dcb98fc648d27589a5a806227e Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Sat, 17 Sep 2016 23:44:17 +0900 Subject: treewide: Fix printk() message errors This patch fix spelling typos in printk and kconfig. Signed-off-by: Masanari Iida Acked-by: Randy Dunlap Signed-off-by: Jiri Kosina --- arch/arm64/kernel/hibernate.c | 4 ++-- arch/mips/kernel/asm-offsets.c | 2 +- arch/sh/kernel/cpu/Makefile | 2 +- arch/sh/kernel/cpu/irq/Makefile | 2 +- drivers/acpi/Kconfig | 2 +- drivers/isdn/hisax/q931.c | 2 +- drivers/media/usb/dvb-usb-v2/af9015.c | 2 +- drivers/mfd/max77620.c | 2 +- drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c | 2 +- drivers/net/ethernet/qlogic/qed/qed_int.c | 4 ++-- drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 2 +- drivers/net/wireless/ath/ath10k/pci.c | 2 +- drivers/net/wireless/ath/wil6210/txrx.c | 2 +- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c | 2 +- drivers/scsi/aic7xxx/aicasm/aicasm.c | 2 +- drivers/usb/dwc3/gadget.c | 2 +- scripts/gcc-plugins/latent_entropy_plugin.c | 2 +- scripts/gcc-plugins/sancov_plugin.c | 2 +- tools/power/acpi/tools/ec/ec_access.c | 2 +- 19 files changed, 21 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c index d55a7b09959b..fe301cbcb442 100644 --- a/arch/arm64/kernel/hibernate.c +++ b/arch/arm64/kernel/hibernate.c @@ -136,7 +136,7 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size) /* Save the mpidr of the cpu we called cpu_suspend() on... */ if (sleep_cpu < 0) { - pr_err("Failing to hibernate on an unkown CPU.\n"); + pr_err("Failing to hibernate on an unknown CPU.\n"); return -ENODEV; } hdr->sleep_cpu_mpidr = cpu_logical_map(sleep_cpu); @@ -547,7 +547,7 @@ out: int hibernate_resume_nonboot_cpu_disable(void) { if (sleep_cpu < 0) { - pr_err("Failing to resume from hibernate on an unkown CPU.\n"); + pr_err("Failing to resume from hibernate on an unknown CPU.\n"); return -ENODEV; } diff --git a/arch/mips/kernel/asm-offsets.c b/arch/mips/kernel/asm-offsets.c index fae2f9447792..6080582a26d1 100644 --- a/arch/mips/kernel/asm-offsets.c +++ b/arch/mips/kernel/asm-offsets.c @@ -341,7 +341,7 @@ void output_pm_defines(void) void output_kvm_defines(void) { - COMMENT(" KVM/MIPS Specfic offsets. "); + COMMENT(" KVM/MIPS Specific offsets. "); OFFSET(VCPU_FPR0, kvm_vcpu_arch, fpu.fpr[0]); OFFSET(VCPU_FPR1, kvm_vcpu_arch, fpu.fpr[1]); diff --git a/arch/sh/kernel/cpu/Makefile b/arch/sh/kernel/cpu/Makefile index accc7ca722e1..252e9fee687f 100644 --- a/arch/sh/kernel/cpu/Makefile +++ b/arch/sh/kernel/cpu/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the Linux/SuperH CPU-specifc backends. +# Makefile for the Linux/SuperH CPU-specific backends. # obj-$(CONFIG_CPU_SH2) = sh2/ diff --git a/arch/sh/kernel/cpu/irq/Makefile b/arch/sh/kernel/cpu/irq/Makefile index f0c7025a67d1..3f8e79402d7d 100644 --- a/arch/sh/kernel/cpu/irq/Makefile +++ b/arch/sh/kernel/cpu/irq/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the Linux/SuperH CPU-specifc IRQ handlers. +# Makefile for the Linux/SuperH CPU-specific IRQ handlers. # obj-$(CONFIG_SUPERH32) += imask.o obj-$(CONFIG_CPU_SH5) += intc-sh5.o diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 535e7828445a..a3c62f57672a 100644 --- a/drivers/acpi/Kconfig +++ b/drivers/acpi/Kconfig @@ -104,7 +104,7 @@ config ACPI_PROCFS_POWER Say N to delete power /proc/acpi/ directories that have moved to /sys/ config ACPI_REV_OVERRIDE_POSSIBLE - bool "Allow supported ACPI revision to be overriden" + bool "Allow supported ACPI revision to be overridden" depends on X86 default y help diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c index ba4beb25d872..298c8dba0321 100644 --- a/drivers/isdn/hisax/q931.c +++ b/drivers/isdn/hisax/q931.c @@ -855,7 +855,7 @@ struct DTag { /* Display tags */ { 0x8c, "Reason" }, { 0x8d, "Calling party name" }, { 0x8e, "Called party name" }, - { 0x8f, "Orignal called name" }, + { 0x8f, "Original called name" }, { 0x90, "Redirecting name" }, { 0x91, "Connected name" }, { 0x92, "Originating restrictions" }, diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c index 941ceff9b268..29011dfabb11 100644 --- a/drivers/media/usb/dvb-usb-v2/af9015.c +++ b/drivers/media/usb/dvb-usb-v2/af9015.c @@ -1455,7 +1455,7 @@ static const struct usb_device_id af9015_id_table[] = { { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CONCEPTRONIC_CTVDIGRCU, &af9015_props, "Conceptronic USB2.0 DVB-T CTVDIGRCU V3.0", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_MC810, - &af9015_props, "KWorld Digial MC-810", NULL) }, + &af9015_props, "KWorld Digital MC-810", NULL) }, { DVB_USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03, &af9015_props, "Genius TVGo DVB-T03", NULL) }, { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_399U_2, diff --git a/drivers/mfd/max77620.c b/drivers/mfd/max77620.c index 258757e216c4..b1700b5fa640 100644 --- a/drivers/mfd/max77620.c +++ b/drivers/mfd/max77620.c @@ -461,7 +461,7 @@ static int max77620_probe(struct i2c_client *client, chip->rmap = devm_regmap_init_i2c(client, rmap_config); if (IS_ERR(chip->rmap)) { ret = PTR_ERR(chip->rmap); - dev_err(chip->dev, "Failed to intialise regmap: %d\n", ret); + dev_err(chip->dev, "Failed to initialise regmap: %d\n", ret); return ret; } diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c index 3f77d0863543..6fad22adbbb9 100644 --- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c +++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_sriov.c @@ -585,7 +585,7 @@ int bnx2x_vf_mcast(struct bnx2x *bp, struct bnx2x_virtf *vf, mcast.mcast_list_len = mc_num; rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_SET); if (rc) - BNX2X_ERR("Faled to set multicasts\n"); + BNX2X_ERR("Failed to set multicasts\n"); } else { /* clear existing mcasts */ rc = bnx2x_config_mcast(bp, &mcast, BNX2X_MCAST_CMD_DEL); diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.c b/drivers/net/ethernet/qlogic/qed/qed_int.c index 2adedc6fb6cf..bed6bfd0201e 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_int.c +++ b/drivers/net/ethernet/qlogic/qed/qed_int.c @@ -1377,7 +1377,7 @@ static const char *attn_master_to_str(u8 master) case 9: return "DBU"; case 10: return "DMAE"; default: - return "Unkown"; + return "Unknown"; } } @@ -1555,7 +1555,7 @@ static int qed_dorq_attn_cb(struct qed_hwfn *p_hwfn) DORQ_REG_DB_DROP_DETAILS); DP_INFO(p_hwfn->cdev, - "DORQ db_drop: adress 0x%08x Opaque FID 0x%04x Size [bytes] 0x%08x Reason: 0x%08x\n", + "DORQ db_drop: address 0x%08x Opaque FID 0x%04x Size [bytes] 0x%08x Reason: 0x%08x\n", qed_rd(p_hwfn, p_hwfn->p_dpc_ptt, DORQ_REG_DB_DROP_DETAILS_ADDRESS), (u16)(details & QED_DORQ_ATTENTION_OPAQUE_MASK), diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c index 2888eb0628f8..c42c0ec49826 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c @@ -369,7 +369,7 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn, p_ramrod->personality = PERSONALITY_RDMA_AND_ETH; break; default: - DP_NOTICE(p_hwfn, "Unkown personality %d\n", + DP_NOTICE(p_hwfn, "Unknown personality %d\n", p_hwfn->hw_info.personality); p_ramrod->personality = PERSONALITY_ETH; } diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c index 0457e315d336..b541a1c74488 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -2091,7 +2091,7 @@ int ath10k_pci_init_config(struct ath10k *ar) ret = ath10k_pci_diag_read32(ar, ealloc_targ_addr, &ealloc_value); if (ret != 0) { - ath10k_err(ar, "Faile to get early alloc val: %d\n", ret); + ath10k_err(ar, "Failed to get early alloc val: %d\n", ret); return ret; } diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c index 4c38520d4dd2..3553e4f93b20 100644 --- a/drivers/net/wireless/ath/wil6210/txrx.c +++ b/drivers/net/wireless/ath/wil6210/txrx.c @@ -326,7 +326,7 @@ static void wil_rx_add_radiotap_header(struct wil6210_priv *wil, if (skb_headroom(skb) < rtap_len && pskb_expand_head(skb, rtap_len, 0, GFP_ATOMIC)) { - wil_err(wil, "Unable to expand headrom to %d\n", rtap_len); + wil_err(wil, "Unable to expand headroom to %d\n", rtap_len); return; } diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c index 1186755e55b8..e5505387260b 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/fw.c @@ -134,7 +134,7 @@ static void _rtl8723e_fill_h2c_command(struct ieee80211_hw *hw, u8 element_id, wait_h2c_limmit--; if (wait_h2c_limmit == 0) { RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, - "Wating too long for FW read clear HMEBox(%d)!\n", + "Waiting too long for FW read clear HMEBox(%d)!\n", boxnum); break; } diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c index 2e3117aa382f..21ac265280bf 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm.c +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c @@ -254,7 +254,7 @@ main(int argc, char *argv[]) argv += optind; if (argc != 1) { - fprintf(stderr, "%s: No input file specifiled\n", appname); + fprintf(stderr, "%s: No input file specified\n", appname); usage(); /* NOTREACHED */ } diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 1dfa56a5f1c5..40e9fc2355ca 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -2491,7 +2491,7 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc) */ WARN_ONCE(dwc->revision < DWC3_REVISION_240A && dwc->has_lpm_erratum, - "LPM Erratum not available on dwc3 revisisions < 2.40a\n"); + "LPM Erratum not available on dwc3 revisions < 2.40a\n"); if (dwc->has_lpm_erratum && dwc->revision >= DWC3_REVISION_240A) reg |= DWC3_DCTL_LPM_ERRATA(dwc->lpm_nyet_threshold); diff --git a/scripts/gcc-plugins/latent_entropy_plugin.c b/scripts/gcc-plugins/latent_entropy_plugin.c index 8160f1c1b56e..12541126575b 100644 --- a/scripts/gcc-plugins/latent_entropy_plugin.c +++ b/scripts/gcc-plugins/latent_entropy_plugin.c @@ -619,7 +619,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, enabled = false; continue; } - error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); + error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); } register_callback(plugin_name, PLUGIN_INFO, NULL, diff --git a/scripts/gcc-plugins/sancov_plugin.c b/scripts/gcc-plugins/sancov_plugin.c index 7ea0b3f50739..70f5fe0d590a 100644 --- a/scripts/gcc-plugins/sancov_plugin.c +++ b/scripts/gcc-plugins/sancov_plugin.c @@ -126,7 +126,7 @@ __visible int plugin_init(struct plugin_name_args *plugin_info, struct plugin_gc enable = false; continue; } - error(G_("unkown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); + error(G_("unknown option '-fplugin-arg-%s-%s'"), plugin_name, argv[i].key); } register_callback(plugin_name, PLUGIN_INFO, NULL, &sancov_plugin_info); diff --git a/tools/power/acpi/tools/ec/ec_access.c b/tools/power/acpi/tools/ec/ec_access.c index 6b8aaed44f2c..5f50642386db 100644 --- a/tools/power/acpi/tools/ec/ec_access.c +++ b/tools/power/acpi/tools/ec/ec_access.c @@ -46,7 +46,7 @@ void usage(char progname[], int exit_status) puts("\t-b offset : Read value at byte_offset (in hex)"); puts("\t-w offset -v value : Write value at byte_offset"); puts("\t-h : Print this help\n\n"); - puts("Offsets and values are in hexadecimal number sytem."); + puts("Offsets and values are in hexadecimal number system."); puts("The offset and value must be between 0 and 0xff."); exit(exit_status); } -- cgit v1.2.3 From 846221cfb8f64c613b7635c94e0c02549a666c14 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Thu, 3 Nov 2016 09:53:50 +0100 Subject: Remove references to dead make variable LINUX_INCLUDE Commit 4fd06960f120 ("Use the new x86 setup code for i386") introduced a reference to the make variable LINUX_INCLUDE. That reference got moved around a bit and copied twice and now there are three references to it. There has never been a definition of that variable. (Presumably that is because it started out as a mistyped reference to LINUXINCLUDE.) So this reference has always been an empty string. Let's remove it before it spreads any further. Signed-off-by: Paul Bolle Signed-off-by: Jiri Kosina --- arch/s390/boot/compressed/Makefile | 2 +- arch/x86/boot/compressed/Makefile | 2 +- drivers/firmware/efi/libstub/Makefile | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/arch/s390/boot/compressed/Makefile b/arch/s390/boot/compressed/Makefile index 0daa070d6c9d..6bd2c9022be3 100644 --- a/arch/s390/boot/compressed/Makefile +++ b/arch/s390/boot/compressed/Makefile @@ -10,7 +10,7 @@ targets := vmlinux.lds vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 targets += vmlinux.bin.xz vmlinux.bin.lzma vmlinux.bin.lzo vmlinux.bin.lz4 targets += misc.o piggy.o sizes.h head.o -KBUILD_CFLAGS := -m64 -D__KERNEL__ $(LINUX_INCLUDE) -O2 +KBUILD_CFLAGS := -m64 -D__KERNEL__ -O2 KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING KBUILD_CFLAGS += $(cflags-y) -fno-delete-null-pointer-checks -msoft-float KBUILD_CFLAGS += $(call cc-option,-mpacked-stack) diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile index 34d9e15857c3..44163e8c3868 100644 --- a/arch/x86/boot/compressed/Makefile +++ b/arch/x86/boot/compressed/Makefile @@ -25,7 +25,7 @@ KCOV_INSTRUMENT := n targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \ vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4 -KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 +KBUILD_CFLAGS := -m$(BITS) -D__KERNEL__ -O2 KBUILD_CFLAGS += -fno-strict-aliasing $(call cc-option, -fPIE, -fPIC) KBUILD_CFLAGS += -DDISABLE_BRANCH_PROFILING cflags-$(CONFIG_X86_32) := -march=i386 diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile index 5e23e2d305e7..25a86e78683d 100644 --- a/drivers/firmware/efi/libstub/Makefile +++ b/drivers/firmware/efi/libstub/Makefile @@ -6,7 +6,7 @@ # cflags-$(CONFIG_X86_32) := -march=i386 cflags-$(CONFIG_X86_64) := -mcmodel=small -cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ $(LINUX_INCLUDE) -O2 \ +cflags-$(CONFIG_X86) += -m$(BITS) -D__KERNEL__ -O2 \ -fPIC -fno-strict-aliasing -mno-red-zone \ -mno-mmx -mno-sse -- cgit v1.2.3 From ecbf12882f90d95decbc0e4cf100ef6935e96445 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 12 Nov 2016 17:54:43 +0000 Subject: misc: ibmasm: fix typo in error message Trivial fix to typo "repsonse" to "response" in error message. Signed-off-by: Colin Ian King Signed-off-by: Jiri Kosina --- drivers/misc/ibmasm/module.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/misc/ibmasm/module.c b/drivers/misc/ibmasm/module.c index 6b3bf9ab051d..c5a456b0a564 100644 --- a/drivers/misc/ibmasm/module.c +++ b/drivers/misc/ibmasm/module.c @@ -170,7 +170,7 @@ static void ibmasm_remove_one(struct pci_dev *pdev) ibmasm_unregister_uart(sp); dbg("Sending OS down message\n"); if (ibmasm_send_os_state(sp, SYSTEM_STATE_OS_DOWN)) - err("failed to get repsonse to 'Send OS State' command\n"); + err("failed to get response to 'Send OS State' command\n"); dbg("Disabling heartbeats\n"); ibmasm_heartbeat_exit(sp); dbg("Disabling interrupts\n"); -- cgit v1.2.3 From b3e8652bcbfa04807e44708d4d0c8cdad39c9215 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Wed, 12 Oct 2016 15:58:14 +0200 Subject: s390/zcrypt: Introduce CEX6 toleration Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 3 +++ drivers/s390/crypto/ap_bus.h | 1 + 2 files changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index f407b4f9d0ba..cac919d63b43 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -1708,6 +1708,9 @@ static void ap_scan_bus(struct work_struct *unused) ap_dev->queue_depth = queue_depth; ap_dev->raw_hwtype = device_type; ap_dev->device_type = device_type; + /* CEX6 toleration: map to CEX5 */ + if (device_type == AP_DEVICE_TYPE_CEX6) + ap_dev->device_type = AP_DEVICE_TYPE_CEX5; ap_dev->functions = device_functions; spin_lock_init(&ap_dev->lock); INIT_LIST_HEAD(&ap_dev->pendingq); diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index d7fdf5c024d7..fd66d2c450d5 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -105,6 +105,7 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr) #define AP_DEVICE_TYPE_CEX3C 9 #define AP_DEVICE_TYPE_CEX4 10 #define AP_DEVICE_TYPE_CEX5 11 +#define AP_DEVICE_TYPE_CEX6 12 /* * Known function facilities -- cgit v1.2.3 From fc1d3f02544a6fd5f417921b57c663388586a17a Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:11:30 +0200 Subject: s390/zcrypt: Move the ap bus into kernel Move the ap bus into the kernel and make it general available. Additionally include the message types and the API layer as a preparation for the workload management facility. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/Makefile | 10 +++++----- drivers/s390/crypto/ap_bus.c | 27 +++++++++++++++++++++++++-- drivers/s390/crypto/zcrypt_api.c | 7 ++++++- drivers/s390/crypto/zcrypt_msgtype50.c | 6 +----- drivers/s390/crypto/zcrypt_msgtype50.h | 2 +- drivers/s390/crypto/zcrypt_msgtype6.c | 6 +----- drivers/s390/crypto/zcrypt_msgtype6.h | 2 +- 7 files changed, 40 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index b8ab18676e69..d0549fc87247 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -3,9 +3,9 @@ # ap-objs := ap_bus.o -# zcrypt_api depends on ap -obj-$(CONFIG_ZCRYPT) += ap.o zcrypt_api.o -# msgtype* depend on zcrypt_api -obj-$(CONFIG_ZCRYPT) += zcrypt_msgtype6.o zcrypt_msgtype50.o -# adapter drivers depend on ap, zcrypt_api and msgtype* +obj-$(subst m,y,$(CONFIG_ZCRYPT)) += ap.o +# zcrypt_api.o and zcrypt_msgtype*.o depend on ap.o +zcrypt-objs := zcrypt_api.o zcrypt_msgtype6.o zcrypt_msgtype50.o +obj-$(CONFIG_ZCRYPT) += zcrypt.o +# adapter drivers depend on ap.o and zcrypt.o obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index cac919d63b43..c695219d70c4 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -62,6 +62,7 @@ MODULE_ALIAS_CRYPTO("z90crypt"); * Module parameter */ int ap_domain_index = -1; /* Adjunct Processor Domain Index */ +static DEFINE_SPINLOCK(ap_domain_lock); module_param_named(domain, ap_domain_index, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(domain, "domain index for ap devices"); EXPORT_SYMBOL(ap_domain_index); @@ -1481,7 +1482,21 @@ static ssize_t ap_domain_show(struct bus_type *bus, char *buf) return snprintf(buf, PAGE_SIZE, "%d\n", ap_domain_index); } -static BUS_ATTR(ap_domain, 0444, ap_domain_show, NULL); +static ssize_t ap_domain_store(struct bus_type *bus, + const char *buf, size_t count) +{ + int domain; + + if (sscanf(buf, "%i\n", &domain) != 1 || + domain < 0 || domain > ap_max_domain_id) + return -EINVAL; + spin_lock_bh(&ap_domain_lock); + ap_domain_index = domain; + spin_unlock_bh(&ap_domain_lock); + return count; +} + +static BUS_ATTR(ap_domain, 0644, ap_domain_show, ap_domain_store); static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) { @@ -1623,9 +1638,12 @@ static int ap_select_domain(void) * the "domain=" parameter or the domain with the maximum number * of devices. */ - if (ap_domain_index >= 0) + spin_lock_bh(&ap_domain_lock); + if (ap_domain_index >= 0) { /* Domain has already been selected. */ + spin_unlock_bh(&ap_domain_lock); return 0; + } best_domain = -1; max_count = 0; for (i = 0; i < AP_DOMAINS; i++) { @@ -1647,8 +1665,10 @@ static int ap_select_domain(void) } if (best_domain >= 0){ ap_domain_index = best_domain; + spin_unlock_bh(&ap_domain_lock); return 0; } + spin_unlock_bh(&ap_domain_lock); return -ENODEV; } @@ -1677,6 +1697,8 @@ static void ap_scan_bus(struct work_struct *unused) if (ap_select_domain() != 0) goto out; + + spin_lock_bh(&ap_domain_lock); for (i = 0; i < AP_DEVICES; i++) { qid = AP_MKQID(i, ap_domain_index); dev = bus_find_device(&ap_bus_type, NULL, @@ -1753,6 +1775,7 @@ static void ap_scan_bus(struct work_struct *unused) continue; } } + spin_unlock_bh(&ap_domain_lock); out: mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); } diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 5d3d04c040c2..7f61ae1b0b93 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -45,6 +45,7 @@ #include "zcrypt_api.h" #include "zcrypt_msgtype6.h" +#include "zcrypt_msgtype50.h" /* * Module description. @@ -1459,6 +1460,8 @@ int __init zcrypt_api_init(void) goto out_misc; } + zcrypt_msgtype6_init(); + zcrypt_msgtype50_init(); return 0; out_misc: @@ -1472,11 +1475,13 @@ out: * * The module termination code. */ -void zcrypt_api_exit(void) +void __exit zcrypt_api_exit(void) { remove_proc_entry("driver/z90crypt", NULL); misc_deregister(&zcrypt_misc_device); zcrypt_debug_exit(); + zcrypt_msgtype6_exit(); + zcrypt_msgtype50_exit(); } module_init(zcrypt_api_init); diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index eedfaa2cf715..7bafba83390a 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -518,16 +518,12 @@ static struct zcrypt_ops zcrypt_msgtype50_ops = { .variant = MSGTYPE50_VARIANT_DEFAULT, }; -int __init zcrypt_msgtype50_init(void) +void __init zcrypt_msgtype50_init(void) { zcrypt_msgtype_register(&zcrypt_msgtype50_ops); - return 0; } void __exit zcrypt_msgtype50_exit(void) { zcrypt_msgtype_unregister(&zcrypt_msgtype50_ops); } - -module_init(zcrypt_msgtype50_init); -module_exit(zcrypt_msgtype50_exit); diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h index 0a66e4aeeb50..eeb41c0f34ae 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.h +++ b/drivers/s390/crypto/zcrypt_msgtype50.h @@ -35,7 +35,7 @@ #define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/ -int zcrypt_msgtype50_init(void); +void zcrypt_msgtype50_init(void); void zcrypt_msgtype50_exit(void); #endif /* _ZCRYPT_MSGTYPE50_H_ */ diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 21959719daef..f71949685ff5 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -1145,12 +1145,11 @@ static struct zcrypt_ops zcrypt_msgtype6_ep11_ops = { .send_ep11_cprb = zcrypt_msgtype6_send_ep11_cprb, }; -int __init zcrypt_msgtype6_init(void) +void __init zcrypt_msgtype6_init(void) { zcrypt_msgtype_register(&zcrypt_msgtype6_norng_ops); zcrypt_msgtype_register(&zcrypt_msgtype6_ops); zcrypt_msgtype_register(&zcrypt_msgtype6_ep11_ops); - return 0; } void __exit zcrypt_msgtype6_exit(void) @@ -1159,6 +1158,3 @@ void __exit zcrypt_msgtype6_exit(void) zcrypt_msgtype_unregister(&zcrypt_msgtype6_ops); zcrypt_msgtype_unregister(&zcrypt_msgtype6_ep11_ops); } - -module_init(zcrypt_msgtype6_init); -module_exit(zcrypt_msgtype6_exit); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index 207247570623..5750c4377bfa 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -165,7 +165,7 @@ static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, ap_msg->length = sizeof(*msg); } -int zcrypt_msgtype6_init(void); +void zcrypt_msgtype6_init(void); void zcrypt_msgtype6_exit(void); #endif /* _ZCRYPT_MSGTYPE6_H_ */ -- cgit v1.2.3 From 236fb2ab95e9832880501d465d64eb2f2935b852 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Fri, 2 Sep 2016 15:21:45 +0200 Subject: s390/zcrypt: simplify message type handling Now that the message type modules are linked with the zcrypt_api into a single module the zcrypt_ops_list is initialized by the module init function of the zcyppt.ko module. After that the list is static and all message types are present. Drop the zcrypt_ops_list_lock spinlock and the module handling in regard to the message types. Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 49 +++++-------------------------------- drivers/s390/crypto/zcrypt_api.h | 3 +-- drivers/s390/crypto/zcrypt_cex2a.c | 6 +---- drivers/s390/crypto/zcrypt_cex4.c | 16 +++++------- drivers/s390/crypto/zcrypt_pcixcc.c | 11 +++------ 5 files changed, 18 insertions(+), 67 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 7f61ae1b0b93..dc6d891a7b48 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -71,7 +71,6 @@ EXPORT_SYMBOL(zcrypt_rescan_req); static int zcrypt_rng_device_add(void); static void zcrypt_rng_device_remove(void); -static DEFINE_SPINLOCK(zcrypt_ops_list_lock); static LIST_HEAD(zcrypt_ops_list); static debug_info_t *zcrypt_dbf_common; @@ -318,61 +317,25 @@ EXPORT_SYMBOL(zcrypt_device_unregister); void zcrypt_msgtype_register(struct zcrypt_ops *zops) { - spin_lock_bh(&zcrypt_ops_list_lock); list_add_tail(&zops->list, &zcrypt_ops_list); - spin_unlock_bh(&zcrypt_ops_list_lock); } -EXPORT_SYMBOL(zcrypt_msgtype_register); void zcrypt_msgtype_unregister(struct zcrypt_ops *zops) { - spin_lock_bh(&zcrypt_ops_list_lock); list_del_init(&zops->list); - spin_unlock_bh(&zcrypt_ops_list_lock); } -EXPORT_SYMBOL(zcrypt_msgtype_unregister); -static inline -struct zcrypt_ops *__ops_lookup(unsigned char *name, int variant) +struct zcrypt_ops *zcrypt_msgtype(unsigned char *name, int variant) { struct zcrypt_ops *zops; - int found = 0; - spin_lock_bh(&zcrypt_ops_list_lock); - list_for_each_entry(zops, &zcrypt_ops_list, list) { + list_for_each_entry(zops, &zcrypt_ops_list, list) if ((zops->variant == variant) && - (!strncmp(zops->name, name, sizeof(zops->name)))) { - found = 1; - break; - } - } - if (!found || !try_module_get(zops->owner)) - zops = NULL; - - spin_unlock_bh(&zcrypt_ops_list_lock); - - return zops; -} - -struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *name, int variant) -{ - struct zcrypt_ops *zops = NULL; - - zops = __ops_lookup(name, variant); - if (!zops) { - request_module("%s", name); - zops = __ops_lookup(name, variant); - } - return zops; -} -EXPORT_SYMBOL(zcrypt_msgtype_request); - -void zcrypt_msgtype_release(struct zcrypt_ops *zops) -{ - if (zops) - module_put(zops->owner); + (!strncmp(zops->name, name, sizeof(zops->name)))) + return zops; + return NULL; } -EXPORT_SYMBOL(zcrypt_msgtype_release); +EXPORT_SYMBOL(zcrypt_msgtype); /** * zcrypt_read (): Not supported beyond zcrypt 1.3.1. diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 38618f05ad92..326ecdc0417f 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -133,8 +133,7 @@ int zcrypt_device_register(struct zcrypt_device *); void zcrypt_device_unregister(struct zcrypt_device *); void zcrypt_msgtype_register(struct zcrypt_ops *); void zcrypt_msgtype_unregister(struct zcrypt_ops *); -struct zcrypt_ops *zcrypt_msgtype_request(unsigned char *, int); -void zcrypt_msgtype_release(struct zcrypt_ops *); +struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int); int zcrypt_api_init(void); void zcrypt_api_exit(void); diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 15104aaa075a..d892cb539139 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -122,8 +122,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) } if (!zdev) return -ENODEV; - zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, - MSGTYPE50_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); zdev->ap_dev = ap_dev; zdev->online = 1; ap_device_init_reply(ap_dev, &zdev->reply); @@ -131,7 +130,6 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) rc = zcrypt_device_register(zdev); if (rc) { ap_dev->private = NULL; - zcrypt_msgtype_release(zdev->ops); zcrypt_device_free(zdev); } return rc; @@ -144,10 +142,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) static void zcrypt_cex2a_remove(struct ap_device *ap_dev) { struct zcrypt_device *zdev = ap_dev->private; - struct zcrypt_ops *zops = zdev->ops; zcrypt_device_unregister(zdev); - zcrypt_msgtype_release(zops); } int __init zcrypt_cex2a_init(void) diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index ccb2e78ebf0e..e98bdbe45d2c 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -102,8 +102,8 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) CEX4A_MAX_MOD_SIZE_2K; } zdev->short_crt = 1; - zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME, - MSGTYPE50_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, + MSGTYPE50_VARIANT_DEFAULT); } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) { zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); if (!zdev) @@ -120,8 +120,8 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; zdev->short_crt = 0; - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) { zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); if (!zdev) @@ -138,8 +138,8 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; zdev->short_crt = 0; - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_EP11); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_EP11); } break; } @@ -151,7 +151,6 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) ap_dev->private = zdev; rc = zcrypt_device_register(zdev); if (rc) { - zcrypt_msgtype_release(zdev->ops); ap_dev->private = NULL; zcrypt_device_free(zdev); } @@ -165,12 +164,9 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) static void zcrypt_cex4_remove(struct ap_device *ap_dev) { struct zcrypt_device *zdev = ap_dev->private; - struct zcrypt_ops *zops; if (zdev) { - zops = zdev->ops; zcrypt_device_unregister(zdev); - zcrypt_msgtype_release(zops); } } diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index df8f0c4dacb7..8491541f72cf 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -322,11 +322,11 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) return rc; } if (rc) - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_DEFAULT); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); else - zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_NORNG); + zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_NORNG); ap_device_init_reply(ap_dev, &zdev->reply); ap_dev->private = zdev; rc = zcrypt_device_register(zdev); @@ -336,7 +336,6 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) out_free: ap_dev->private = NULL; - zcrypt_msgtype_release(zdev->ops); zcrypt_device_free(zdev); return rc; } @@ -348,10 +347,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) { struct zcrypt_device *zdev = ap_dev->private; - struct zcrypt_ops *zops = zdev->ops; zcrypt_device_unregister(zdev); - zcrypt_msgtype_release(zops); } int __init zcrypt_pcixcc_init(void) -- cgit v1.2.3 From 0db78559f965a2e652dbe8acf35333f2081bf872 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 21 Sep 2016 12:48:54 +0200 Subject: s390/zcrypt: header for the AP inline assmblies Move the inline assemblies for the AP bus into a separate header file. Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_asm.h | 191 +++++++++++++++++++++++++++++++++++++++++++ drivers/s390/crypto/ap_bus.c | 188 +++--------------------------------------- 2 files changed, 204 insertions(+), 175 deletions(-) create mode 100644 drivers/s390/crypto/ap_asm.h (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_asm.h b/drivers/s390/crypto/ap_asm.h new file mode 100644 index 000000000000..12fffdd1e8e8 --- /dev/null +++ b/drivers/s390/crypto/ap_asm.h @@ -0,0 +1,191 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Martin Schwidefsky + * + * Adjunct processor bus inline assemblies. + */ + +#ifndef _AP_ASM_H_ +#define _AP_ASM_H_ + +#include + +/** + * ap_intructions_available() - Test if AP instructions are available. + * + * Returns 0 if the AP instructions are installed. + */ +static inline int ap_instructions_available(void) +{ + register unsigned long reg0 asm ("0") = AP_MKQID(0, 0); + register unsigned long reg1 asm ("1") = -ENODEV; + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile( + " .long 0xb2af0000\n" /* PQAP(TAPQ) */ + "0: la %1,0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc"); + return reg1; +} + +/** + * ap_tapq(): Test adjunct processor queue. + * @qid: The AP queue number + * @info: Pointer to queue descriptor + * + * Returns AP queue status structure. + */ +static inline struct ap_queue_status ap_tapq(ap_qid_t qid, unsigned long *info) +{ + register unsigned long reg0 asm ("0") = qid; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ + : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + if (info) + *info = reg2; + return reg1; +} + +/** + * ap_pqap_rapq(): Reset adjunct processor queue. + * @qid: The AP queue number + * + * Returns AP queue status structure. + */ +static inline struct ap_queue_status ap_rapq(ap_qid_t qid) +{ + register unsigned long reg0 asm ("0") = qid | 0x01000000UL; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = 0UL; + + asm volatile( + ".long 0xb2af0000" /* PQAP(RAPQ) */ + : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); + return reg1; +} + +/** + * ap_aqic(): Enable interruption for a specific AP. + * @qid: The AP queue number + * @ind: The notification indicator byte + * + * Returns AP queue status. + */ +static inline struct ap_queue_status ap_aqic(ap_qid_t qid, void *ind) +{ + register unsigned long reg0 asm ("0") = qid | (3UL << 24); + register unsigned long reg1_in asm ("1") = (8UL << 44) | AP_ISC; + register struct ap_queue_status reg1_out asm ("1"); + register void *reg2 asm ("2") = ind; + + asm volatile( + ".long 0xb2af0000" /* PQAP(AQIC) */ + : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) + : + : "cc"); + return reg1_out; +} + +/** + * ap_qci(): Get AP configuration data + * + * Returns 0 on success, or -EOPNOTSUPP. + */ +static inline int ap_qci(void *config) +{ + register unsigned long reg0 asm ("0") = 0x04000000UL; + register unsigned long reg1 asm ("1") = -EINVAL; + register void *reg2 asm ("2") = (void *) config; + + asm volatile( + ".long 0xb2af0000\n" /* PQAP(QCI) */ + "0: la %1,0\n" + "1:\n" + EX_TABLE(0b, 1b) + : "+d" (reg0), "+d" (reg1), "+d" (reg2) + : + : "cc"); + + return reg1; +} + +/** + * ap_nqap(): Send message to adjunct processor queue. + * @qid: The AP queue number + * @psmid: The program supplied message identifier + * @msg: The message text + * @length: The message length + * + * Returns AP queue status structure. + * Condition code 1 on NQAP can't happen because the L bit is 1. + * Condition code 2 on NQAP also means the send is incomplete, + * because a segment boundary was reached. The NQAP is repeated. + */ +static inline struct ap_queue_status ap_nqap(ap_qid_t qid, + unsigned long long psmid, + void *msg, size_t length) +{ + struct msgblock { char _[length]; }; + register unsigned long reg0 asm ("0") = qid | 0x40000000UL; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm ("2") = (unsigned long) msg; + register unsigned long reg3 asm ("3") = (unsigned long) length; + register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); + register unsigned long reg5 asm ("5") = psmid & 0xffffffff; + + asm volatile ( + "0: .long 0xb2ad0042\n" /* NQAP */ + " brc 2,0b" + : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) + : "d" (reg4), "d" (reg5), "m" (*(struct msgblock *) msg) + : "cc"); + return reg1; +} + +/** + * ap_dqap(): Receive message from adjunct processor queue. + * @qid: The AP queue number + * @psmid: Pointer to program supplied message identifier + * @msg: The message text + * @length: The message length + * + * Returns AP queue status structure. + * Condition code 1 on DQAP means the receive has taken place + * but only partially. The response is incomplete, hence the + * DQAP is repeated. + * Condition code 2 on DQAP also means the receive is incomplete, + * this time because a segment boundary was reached. Again, the + * DQAP is repeated. + * Note that gpr2 is used by the DQAP instruction to keep track of + * any 'residual' length, in case the instruction gets interrupted. + * Hence it gets zeroed before the instruction. + */ +static inline struct ap_queue_status ap_dqap(ap_qid_t qid, + unsigned long long *psmid, + void *msg, size_t length) +{ + struct msgblock { char _[length]; }; + register unsigned long reg0 asm("0") = qid | 0x80000000UL; + register struct ap_queue_status reg1 asm ("1"); + register unsigned long reg2 asm("2") = 0UL; + register unsigned long reg4 asm("4") = (unsigned long) msg; + register unsigned long reg5 asm("5") = (unsigned long) length; + register unsigned long reg6 asm("6") = 0UL; + register unsigned long reg7 asm("7") = 0UL; + + + asm volatile( + "0: .long 0xb2ae0064\n" /* DQAP */ + " brc 6,0b\n" + : "+d" (reg0), "=d" (reg1), "+d" (reg2), + "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), + "=m" (*(struct msgblock *) msg) : : "cc"); + *psmid = (((unsigned long long) reg6) << 32) + reg7; + return reg1; +} + +#endif /* _AP_ASM_H_ */ diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index c695219d70c4..f6de22a4f7d9 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -48,6 +48,7 @@ #include #include "ap_bus.h" +#include "ap_asm.h" /* * Module description. @@ -129,26 +130,6 @@ static inline int ap_using_interrupts(void) return ap_airq_flag; } -/** - * ap_intructions_available() - Test if AP instructions are available. - * - * Returns 0 if the AP instructions are installed. - */ -static inline int ap_instructions_available(void) -{ - register unsigned long reg0 asm ("0") = AP_MKQID(0,0); - register unsigned long reg1 asm ("1") = -ENODEV; - register unsigned long reg2 asm ("2") = 0UL; - - asm volatile( - " .long 0xb2af0000\n" /* PQAP(TAPQ) */ - "0: la %1,0\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+d" (reg0), "+d" (reg1), "+d" (reg2) : : "cc" ); - return reg1; -} - /** * ap_interrupts_available(): Test if AP interrupts are available. * @@ -170,19 +151,6 @@ static int ap_configuration_available(void) return test_facility(12); } -static inline struct ap_queue_status -__pqap_tapq(ap_qid_t qid, unsigned long *info) -{ - register unsigned long reg0 asm ("0") = qid; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = 0UL; - - asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */ - : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); - *info = reg2; - return reg1; -} - /** * ap_test_queue(): Test adjunct processor queue. * @qid: The AP queue number @@ -193,85 +161,16 @@ __pqap_tapq(ap_qid_t qid, unsigned long *info) static inline struct ap_queue_status ap_test_queue(ap_qid_t qid, unsigned long *info) { - struct ap_queue_status aqs; - unsigned long _info; - if (test_facility(15)) qid |= 1UL << 23; /* set APFT T bit*/ - aqs = __pqap_tapq(qid, &_info); - if (info) - *info = _info; - return aqs; -} - -/** - * ap_reset_queue(): Reset adjunct processor queue. - * @qid: The AP queue number - * - * Returns AP queue status structure. - */ -static inline struct ap_queue_status ap_reset_queue(ap_qid_t qid) -{ - register unsigned long reg0 asm ("0") = qid | 0x01000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = 0UL; - - asm volatile( - ".long 0xb2af0000" /* PQAP(RAPQ) */ - : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc"); - return reg1; -} - -/** - * ap_queue_interruption_control(): Enable interruption for a specific AP. - * @qid: The AP queue number - * @ind: The notification indicator byte - * - * Returns AP queue status. - */ -static inline struct ap_queue_status -ap_queue_interruption_control(ap_qid_t qid, void *ind) -{ - register unsigned long reg0 asm ("0") = qid | 0x03000000UL; - register unsigned long reg1_in asm ("1") = 0x0000800000000000UL | AP_ISC; - register struct ap_queue_status reg1_out asm ("1"); - register void *reg2 asm ("2") = ind; - asm volatile( - ".long 0xb2af0000" /* PQAP(AQIC) */ - : "+d" (reg0), "+d" (reg1_in), "=d" (reg1_out), "+d" (reg2) - : - : "cc" ); - return reg1_out; -} - -/** - * ap_query_configuration(): Get AP configuration data - * - * Returns 0 on success, or -EOPNOTSUPP. - */ -static inline int __ap_query_configuration(void) -{ - register unsigned long reg0 asm ("0") = 0x04000000UL; - register unsigned long reg1 asm ("1") = -EINVAL; - register void *reg2 asm ("2") = (void *) ap_configuration; - - asm volatile( - ".long 0xb2af0000\n" /* PQAP(QCI) */ - "0: la %1,0\n" - "1:\n" - EX_TABLE(0b, 1b) - : "+d" (reg0), "+d" (reg1), "+d" (reg2) - : - : "cc"); - - return reg1; + return ap_tapq(qid, info); } static inline int ap_query_configuration(void) { if (!ap_configuration) return -EOPNOTSUPP; - return __ap_query_configuration(); + return ap_qci(ap_configuration); } /** @@ -336,15 +235,15 @@ static inline int ap_test_config_domain(unsigned int domain) * @qid: The AP queue number * @ind: the notification indicator byte * - * Enables interruption on AP queue via ap_queue_interruption_control(). Based - * on the return value it waits a while and tests the AP queue if interrupts + * Enables interruption on AP queue via ap_aqic(). Based on the return + * value it waits a while and tests the AP queue if interrupts * have been switched on using ap_test_queue(). */ static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind) { struct ap_queue_status status; - status = ap_queue_interruption_control(ap_dev->qid, ind); + status = ap_aqic(ap_dev->qid, ind); switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_OTHERWISE_CHANGED: @@ -363,26 +262,6 @@ static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind) } } -static inline struct ap_queue_status -__nqap(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) -{ - typedef struct { char _[length]; } msgblock; - register unsigned long reg0 asm ("0") = qid | 0x40000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm ("2") = (unsigned long) msg; - register unsigned long reg3 asm ("3") = (unsigned long) length; - register unsigned long reg4 asm ("4") = (unsigned int) (psmid >> 32); - register unsigned long reg5 asm ("5") = psmid & 0xffffffff; - - asm volatile ( - "0: .long 0xb2ad0042\n" /* NQAP */ - " brc 2,0b" - : "+d" (reg0), "=d" (reg1), "+d" (reg2), "+d" (reg3) - : "d" (reg4), "d" (reg5), "m" (*(msgblock *) msg) - : "cc"); - return reg1; -} - /** * __ap_send(): Send message to adjunct processor queue. * @qid: The AP queue number @@ -402,7 +281,7 @@ __ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, { if (special == 1) qid |= 0x400000UL; - return __nqap(qid, psmid, msg, length); + return ap_nqap(qid, psmid, msg, length); } int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) @@ -424,54 +303,13 @@ int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) } EXPORT_SYMBOL(ap_send); -/** - * __ap_recv(): Receive message from adjunct processor queue. - * @qid: The AP queue number - * @psmid: Pointer to program supplied message identifier - * @msg: The message text - * @length: The message length - * - * Returns AP queue status structure. - * Condition code 1 on DQAP means the receive has taken place - * but only partially. The response is incomplete, hence the - * DQAP is repeated. - * Condition code 2 on DQAP also means the receive is incomplete, - * this time because a segment boundary was reached. Again, the - * DQAP is repeated. - * Note that gpr2 is used by the DQAP instruction to keep track of - * any 'residual' length, in case the instruction gets interrupted. - * Hence it gets zeroed before the instruction. - */ -static inline struct ap_queue_status -__ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) -{ - typedef struct { char _[length]; } msgblock; - register unsigned long reg0 asm("0") = qid | 0x80000000UL; - register struct ap_queue_status reg1 asm ("1"); - register unsigned long reg2 asm("2") = 0UL; - register unsigned long reg4 asm("4") = (unsigned long) msg; - register unsigned long reg5 asm("5") = (unsigned long) length; - register unsigned long reg6 asm("6") = 0UL; - register unsigned long reg7 asm("7") = 0UL; - - - asm volatile( - "0: .long 0xb2ae0064\n" /* DQAP */ - " brc 6,0b\n" - : "+d" (reg0), "=d" (reg1), "+d" (reg2), - "+d" (reg4), "+d" (reg5), "+d" (reg6), "+d" (reg7), - "=m" (*(msgblock *) msg) : : "cc" ); - *psmid = (((unsigned long long) reg6) << 32) + reg7; - return reg1; -} - int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) { struct ap_queue_status status; if (msg == NULL) return -EINVAL; - status = __ap_recv(qid, psmid, msg, length); + status = ap_dqap(qid, psmid, msg, length); switch (status.response_code) { case AP_RESPONSE_NORMAL: return 0; @@ -577,8 +415,8 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev) struct ap_queue_status status; struct ap_message *ap_msg; - status = __ap_recv(ap_dev->qid, &ap_dev->reply->psmid, - ap_dev->reply->message, ap_dev->reply->length); + status = ap_dqap(ap_dev->qid, &ap_dev->reply->psmid, + ap_dev->reply->message, ap_dev->reply->length); switch (status.response_code) { case AP_RESPONSE_NORMAL: atomic_dec(&ap_poll_requests); @@ -739,7 +577,7 @@ static enum ap_wait ap_sm_reset(struct ap_device *ap_dev) { struct ap_queue_status status; - status = ap_reset_queue(ap_dev->qid); + status = ap_rapq(ap_dev->qid); switch (status.response_code) { case AP_RESPONSE_NORMAL: case AP_RESPONSE_RESET_IN_PROGRESS: @@ -1794,7 +1632,7 @@ static void ap_reset_domain(void) if (ap_domain_index == -1 || !ap_test_config_domain(ap_domain_index)) return; for (i = 0; i < AP_DEVICES; i++) - ap_reset_queue(AP_MKQID(i, ap_domain_index)); + ap_rapq(AP_MKQID(i, ap_domain_index)); } static void ap_reset_all(void) @@ -1807,7 +1645,7 @@ static void ap_reset_all(void) for (j = 0; j < AP_DEVICES; j++) { if (!ap_test_config_card_id(j)) continue; - ap_reset_queue(AP_MKQID(j, i)); + ap_rapq(AP_MKQID(j, i)); } } } -- cgit v1.2.3 From 9af3e04ee41e6841b2accb9dc96562bcf4e59916 Mon Sep 17 00:00:00 2001 From: Martin Schwidefsky Date: Wed, 21 Sep 2016 14:12:53 +0200 Subject: s390/zcrypt: get rid of ap_poll_requests The poll thread of the AP bus is burning CPU while waiting for crypto requests to complete. We can as well burn a few more cycles in the poll thread to check if there are pending requests and remove the atomic operations with the ap_poll_requests. This improves the code if the machine has adapter interrupts. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index f6de22a4f7d9..fe1cfa4b22c9 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -91,7 +91,6 @@ static DECLARE_WORK(ap_scan_work, ap_scan_bus); */ static void ap_tasklet_fn(unsigned long); static DECLARE_TASKLET(ap_tasklet, ap_tasklet_fn, 0); -static atomic_t ap_poll_requests = ATOMIC_INIT(0); static DECLARE_WAIT_QUEUE_HEAD(ap_poll_wait); static struct task_struct *ap_poll_kthread = NULL; static DEFINE_MUTEX(ap_poll_thread_mutex); @@ -419,7 +418,6 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev) ap_dev->reply->message, ap_dev->reply->length); switch (status.response_code) { case AP_RESPONSE_NORMAL: - atomic_dec(&ap_poll_requests); ap_dev->queue_count--; if (ap_dev->queue_count > 0) mod_timer(&ap_dev->timeout, @@ -436,7 +434,6 @@ static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev) if (!status.queue_empty || ap_dev->queue_count <= 0) break; /* The card shouldn't forget requests but who knows. */ - atomic_sub(ap_dev->queue_count, &ap_poll_requests); ap_dev->queue_count = 0; list_splice_init(&ap_dev->pendingq, &ap_dev->requestq); ap_dev->requestq_count += ap_dev->pendingq_count; @@ -524,7 +521,6 @@ static enum ap_wait ap_sm_write(struct ap_device *ap_dev) ap_msg->message, ap_msg->length, ap_msg->special); switch (status.response_code) { case AP_RESPONSE_NORMAL: - atomic_inc(&ap_poll_requests); ap_dev->queue_count++; if (ap_dev->queue_count == 1) mod_timer(&ap_dev->timeout, @@ -796,6 +792,27 @@ static void ap_tasklet_fn(unsigned long dummy) ap_sm_wait(wait); } +static int ap_pending_requests(void) +{ + struct ap_device *ap_dev; + int id, pending = 0; + + for (id = 0; pending == 0 && id < AP_DEVICES; id++) { + spin_lock_bh(&ap_device_list_lock); + list_for_each_entry(ap_dev, &ap_device_list, list) { + spin_lock_bh(&ap_dev->lock); + if (ap_dev->queue_count) + pending = 1; + spin_unlock_bh(&ap_dev->lock); + if (pending) + break; + } + spin_unlock_bh(&ap_device_list_lock); + } + + return pending; +} + /** * ap_poll_thread(): Thread that polls for finished requests. * @data: Unused pointer @@ -815,8 +832,7 @@ static int ap_poll_thread(void *data) while (!kthread_should_stop()) { add_wait_queue(&ap_poll_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); - if (ap_suspend_flag || - atomic_read(&ap_poll_requests) <= 0) { + if (ap_suspend_flag || !ap_pending_requests()) { schedule(); try_to_freeze(); } @@ -828,7 +844,8 @@ static int ap_poll_thread(void *data) continue; } ap_tasklet_fn(0); - } while (!kthread_should_stop()); + } + return 0; } @@ -1267,9 +1284,6 @@ static int ap_device_remove(struct device *dev) spin_unlock_bh(&ap_device_list_lock); if (ap_drv->remove) ap_drv->remove(ap_dev); - spin_lock_bh(&ap_dev->lock); - atomic_sub(ap_dev->queue_count, &ap_poll_requests); - spin_unlock_bh(&ap_dev->lock); return 0; } -- cgit v1.2.3 From 34a15167739412750846d4f1a5540d9e592fd815 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:14:15 +0200 Subject: s390/zcrypt: Introduce workload balancing Crypto requests are very different in complexity and thus runtime. Also various crypto adapters are differ with regard to the execution time. Crypto requests can be balanced much better when the request type and eligible crypto adapters are rated in a more precise granularity. Therefore, request weights and adapter speed rates for dedicated requests will be introduced. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_api.c | 308 ++++++++++++++++--------- drivers/s390/crypto/zcrypt_api.h | 26 ++- drivers/s390/crypto/zcrypt_cex2a.c | 12 +- drivers/s390/crypto/zcrypt_cex4.c | 36 +-- drivers/s390/crypto/zcrypt_msgtype50.c | 32 +++ drivers/s390/crypto/zcrypt_msgtype50.h | 3 + drivers/s390/crypto/zcrypt_msgtype6.c | 403 ++++++++++++++++++++++++--------- drivers/s390/crypto/zcrypt_msgtype6.h | 17 +- drivers/s390/crypto/zcrypt_pcixcc.c | 41 +++- 9 files changed, 629 insertions(+), 249 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index dc6d891a7b48..28913e540096 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -151,18 +151,16 @@ static inline int zcrypt_process_rescan(void) * Need to be called while holding the zcrypt device list lock. * Note: cards with speed_rating of 0 are kept at the end of the list. */ -static void __zcrypt_increase_preference(struct zcrypt_device *zdev) +static void __zcrypt_increase_preference(struct zcrypt_device *zdev, + unsigned int weight) { struct zcrypt_device *tmp; struct list_head *l; - if (zdev->speed_rating == 0) - return; + zdev->load -= weight; for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) { tmp = list_entry(l, struct zcrypt_device, list); - if ((tmp->request_count + 1) * tmp->speed_rating <= - (zdev->request_count + 1) * zdev->speed_rating && - tmp->speed_rating != 0) + if (tmp->load <= zdev->load) break; } if (l == zdev->list.prev) @@ -179,18 +177,16 @@ static void __zcrypt_increase_preference(struct zcrypt_device *zdev) * Need to be called while holding the zcrypt device list lock. * Note: cards with speed_rating of 0 are kept at the end of the list. */ -static void __zcrypt_decrease_preference(struct zcrypt_device *zdev) +static void __zcrypt_decrease_preference(struct zcrypt_device *zdev, + unsigned int weight) { struct zcrypt_device *tmp; struct list_head *l; - if (zdev->speed_rating == 0) - return; + zdev->load += weight; for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) { tmp = list_entry(l, struct zcrypt_device, list); - if ((tmp->request_count + 1) * tmp->speed_rating > - (zdev->request_count + 1) * zdev->speed_rating || - tmp->speed_rating == 0) + if (tmp->load > zdev->load) break; } if (l == zdev->list.next) @@ -270,7 +266,7 @@ int zcrypt_device_register(struct zcrypt_device *zdev) ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid, zdev->online); list_add_tail(&zdev->list, &zcrypt_device_list); - __zcrypt_increase_preference(zdev); + __zcrypt_increase_preference(zdev, 0); /* sort devices acc. weight */ zcrypt_device_count++; spin_unlock_bh(&zcrypt_device_lock); if (zdev->ops->rng) { @@ -386,8 +382,9 @@ static int zcrypt_release(struct inode *inode, struct file *filp) */ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; int rc; + unsigned int weight, func_code, pref_weight = 0; if (mex->outputdatalength < mex->inputdatalength) return -EINVAL; @@ -398,6 +395,10 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) */ mex->outputdatalength = mex->inputdatalength; + rc = get_rsa_modex_fc(mex, &func_code); + if (rc) + return rc; + spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { if (!zdev->online || @@ -405,34 +406,52 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) zdev->min_mod_size > mex->inputdatalength || zdev->max_mod_size < mex->inputdatalength) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->rsa_modexpo(zdev, mex); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); + weight = zdev->speed_rating[func_code]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; } - else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + __zcrypt_decrease_preference(pref_zdev, pref_weight); + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = -ENODEV; + rc = pref_zdev->ops->rsa_modexpo(pref_zdev, mex); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + + pref_zdev->request_count--; + __zcrypt_increase_preference(pref_zdev, pref_weight); + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; unsigned long long z1, z2, z3; int rc, copied; + unsigned int weight, func_code, pref_weight = 0; if (crt->outputdatalength < crt->inputdatalength) return -EINVAL; @@ -443,6 +462,10 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) */ crt->outputdatalength = crt->inputdatalength; + rc = get_rsa_crt_fc(crt, &func_code); + if (rc) + return rc; + copied = 0; restart: spin_lock_bh(&zcrypt_device_lock); @@ -489,33 +512,54 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) /* The device can't handle this request. */ continue; } - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->rsa_modexpo_crt(zdev, crt); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); + + weight = zdev->speed_rating[func_code]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; } - else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + __zcrypt_decrease_preference(pref_zdev, pref_weight); + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->rsa_modexpo_crt(pref_zdev, crt); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + pref_zdev->request_count--; + __zcrypt_increase_preference(pref_zdev, pref_weight); + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static long zcrypt_send_cprb(struct ica_xcRB *xcRB) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; + unsigned int weight = 0, func_code = 0, pref_weight = 0; int rc; + struct ap_message ap_msg; + + rc = get_cprb_fc(xcRB, &ap_msg, &func_code); + if (rc) + return rc; spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { @@ -524,27 +568,42 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) (xcRB->user_defined != AUTOSELECT && AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->send_cprb(zdev, xcRB); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); + + weight = speed_idx_cca(func_code) * zdev->speed_rating[SECKEY]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; } - else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + __zcrypt_decrease_preference(pref_zdev, pref_weight); + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->send_cprb(pref_zdev, xcRB, &ap_msg); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + pref_zdev->request_count--; + __zcrypt_increase_preference(pref_zdev, pref_weight); + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } struct ep11_target_dev_list { @@ -568,7 +627,9 @@ static bool is_desired_ep11dev(unsigned int dev_qid, static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; + struct ap_message ap_msg; + unsigned int weight = 0, func_code = 0, pref_weight = 0; bool autoselect = false; int rc; struct ep11_target_dev_list ep11_dev_list = { @@ -596,6 +657,10 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) return -EFAULT; } + rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); + if (rc) + return rc; + spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { /* check if device is eligible */ @@ -608,58 +673,93 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) !autoselect) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->send_ep11_cprb(zdev, xcrb); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); - } else { - rc = -EAGAIN; - } - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + weight = speed_idx_ep11(func_code) * zdev->speed_rating[SECKEY]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; + } + + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->send_ep11_cprb(pref_zdev, xcrb, &ap_msg); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else { + rc = -EAGAIN; } + pref_zdev->request_count--; + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static long zcrypt_rng(char *buffer) { - struct zcrypt_device *zdev; + struct zcrypt_device *zdev, *pref_zdev = NULL; + struct ap_message ap_msg; + unsigned int weight = 0, func_code = 0, pref_weight = 0; int rc; + rc = get_rng_fc(&ap_msg, &func_code); + if (rc) + return rc; + spin_lock_bh(&zcrypt_device_lock); list_for_each_entry(zdev, &zcrypt_device_list, list) { if (!zdev->online || !zdev->ops->rng) continue; - zcrypt_device_get(zdev); - get_device(&zdev->ap_dev->device); - zdev->request_count++; - __zcrypt_decrease_preference(zdev); - if (try_module_get(zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = zdev->ops->rng(zdev, buffer); - spin_lock_bh(&zcrypt_device_lock); - module_put(zdev->ap_dev->drv->driver.owner); - } else - rc = -EAGAIN; - zdev->request_count--; - __zcrypt_increase_preference(zdev); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); + + weight = zdev->speed_rating[func_code]; + if (!pref_zdev) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { + pref_zdev = zdev; + pref_weight = weight; + continue; + } + if ((pref_zdev->load + pref_weight) <= zdev->load) + break; /* Load on remaining devices too high - abort */ + } + if (!pref_zdev) { spin_unlock_bh(&zcrypt_device_lock); - return rc; + return -ENODEV; } + + zcrypt_device_get(pref_zdev); + get_device(&pref_zdev->ap_dev->device); + pref_zdev->request_count++; + if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { + spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zdev->ops->rng(pref_zdev, buffer, &ap_msg); + spin_lock_bh(&zcrypt_device_lock); + module_put(pref_zdev->ap_dev->drv->driver.owner); + } else + rc = -EAGAIN; + pref_zdev->request_count--; + put_device(&pref_zdev->ap_dev->device); + zcrypt_device_put(pref_zdev); spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; + return rc; } static void zcrypt_status_mask(char status[AP_DEVICES]) diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 326ecdc0417f..3d0d1e25d751 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -84,15 +84,32 @@ struct ica_z90_status { */ #define ZCRYPT_RNG_BUFFER_SIZE 4096 +/* + * Identifier for Crypto Request Performance Index + */ +enum crypto_ops { + MEX_1K = 0, + MEX_2K, + MEX_4K, + CRT_1K, + CRT_2K, + CRT_4K, + HWRNG, + SECKEY, + NUM_OPS +}; + struct zcrypt_device; struct zcrypt_ops { long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *); long (*rsa_modexpo_crt)(struct zcrypt_device *, struct ica_rsa_modexpo_crt *); - long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *); - long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *); - long (*rng)(struct zcrypt_device *, char *); + long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *, + struct ap_message *); + long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *, + struct ap_message *); + long (*rng)(struct zcrypt_device *, char *, struct ap_message *); struct list_head list; /* zcrypt ops list. */ struct module *owner; int variant; @@ -112,7 +129,8 @@ struct zcrypt_device { int min_mod_size; /* Min number of bits. */ int max_mod_size; /* Max number of bits. */ int short_crt; /* Card has crt length restriction. */ - int speed_rating; /* Speed of the crypto device. */ + int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */ + int load; /* Utilization of the crypto device */ int request_count; /* # current requests. */ diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index d892cb539139..4bb13eadd0f1 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -43,9 +43,6 @@ #define CEX3A_MIN_MOD_SIZE CEX2A_MIN_MOD_SIZE #define CEX3A_MAX_MOD_SIZE 512 /* 4096 bits */ -#define CEX2A_SPEED_RATING 970 -#define CEX3A_SPEED_RATING 900 /* Fixme: Needs finetuning */ - #define CEX2A_MAX_MESSAGE_SIZE 0x390 /* sizeof(struct type50_crb2_msg) */ #define CEX2A_MAX_RESPONSE_SIZE 0x110 /* max outputdatalength + type80_hdr */ @@ -87,6 +84,8 @@ static struct ap_driver zcrypt_cex2a_driver = { static int zcrypt_cex2a_probe(struct ap_device *ap_dev) { struct zcrypt_device *zdev = NULL; + int CEX2A_SPEED_IDX[] = { 800, 1000, 2000, 900, 1200, 2400, 0}; + int CEX3A_SPEED_IDX[] = { 400, 500, 1000, 450, 550, 1200, 0}; int rc = 0; switch (ap_dev->device_type) { @@ -99,7 +98,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; zdev->short_crt = 1; - zdev->speed_rating = CEX2A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX2A_SPEED_IDX, + sizeof(CEX2A_SPEED_IDX)); zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3A: @@ -117,7 +117,8 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; } zdev->short_crt = 1; - zdev->speed_rating = CEX3A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX3A_SPEED_IDX, + sizeof(CEX3A_SPEED_IDX)); break; } if (!zdev) @@ -125,6 +126,7 @@ static int zcrypt_cex2a_probe(struct ap_device *ap_dev) zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); zdev->ap_dev = ap_dev; zdev->online = 1; + zdev->load = zdev->speed_rating[0]; ap_device_init_reply(ap_dev, &zdev->reply); ap_dev->private = zdev; rc = zcrypt_device_register(zdev); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index e98bdbe45d2c..ff28ad543c30 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -24,13 +24,6 @@ #define CEX4C_MIN_MOD_SIZE 16 /* 256 bits */ #define CEX4C_MAX_MOD_SIZE 512 /* 4096 bits */ -#define CEX4A_SPEED_RATING 900 /* TODO new card, new speed rating */ -#define CEX4C_SPEED_RATING 6500 /* TODO new card, new speed rating */ -#define CEX4P_SPEED_RATING 7000 /* TODO new card, new speed rating */ -#define CEX5A_SPEED_RATING 450 /* TODO new card, new speed rating */ -#define CEX5C_SPEED_RATING 3250 /* TODO new card, new speed rating */ -#define CEX5P_SPEED_RATING 3500 /* TODO new card, new speed rating */ - #define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE #define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE @@ -71,6 +64,16 @@ static struct ap_driver zcrypt_cex4_driver = { static int zcrypt_cex4_probe(struct ap_device *ap_dev) { struct zcrypt_device *zdev = NULL; + /* + * Normalized speed ratings per crypto adapter + * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY + */ + int CEX4A_SPEED_IDX[] = { 5, 6, 59, 20, 115, 581, 0, 0}; + int CEX5A_SPEED_IDX[] = { 3, 3, 6, 8, 32, 218, 0, 0}; + int CEX4C_SPEED_IDX[] = { 24, 25, 82, 41, 138, 1111, 79, 8}; + int CEX5C_SPEED_IDX[] = { 10, 14, 23, 17, 45, 242, 63, 4}; + int CEX4P_SPEED_IDX[] = {142, 198, 1852, 203, 331, 1563, 0, 8}; + int CEX5P_SPEED_IDX[] = { 49, 67, 131, 52, 85, 287, 0, 4}; int rc = 0; switch (ap_dev->device_type) { @@ -82,10 +85,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENOMEM; if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { zdev->type_string = "CEX4A"; - zdev->speed_rating = CEX4A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX4A_SPEED_IDX, + sizeof(CEX4A_SPEED_IDX)); } else { zdev->type_string = "CEX5A"; - zdev->speed_rating = CEX5A_SPEED_RATING; + memcpy(zdev->speed_rating, CEX5A_SPEED_IDX, + sizeof(CEX5A_SPEED_IDX)); } zdev->user_space_type = ZCRYPT_CEX3A; zdev->min_mod_size = CEX4A_MIN_MOD_SIZE; @@ -110,10 +115,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENOMEM; if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { zdev->type_string = "CEX4C"; - zdev->speed_rating = CEX4C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX4C_SPEED_IDX, + sizeof(CEX4C_SPEED_IDX)); } else { zdev->type_string = "CEX5C"; - zdev->speed_rating = CEX5C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX5C_SPEED_IDX, + sizeof(CEX5C_SPEED_IDX)); } zdev->user_space_type = ZCRYPT_CEX3C; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; @@ -128,10 +135,12 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENOMEM; if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { zdev->type_string = "CEX4P"; - zdev->speed_rating = CEX4P_SPEED_RATING; + memcpy(zdev->speed_rating, CEX4P_SPEED_IDX, + sizeof(CEX4P_SPEED_IDX)); } else { zdev->type_string = "CEX5P"; - zdev->speed_rating = CEX5P_SPEED_RATING; + memcpy(zdev->speed_rating, CEX5P_SPEED_IDX, + sizeof(CEX5P_SPEED_IDX)); } zdev->user_space_type = ZCRYPT_CEX4; zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; @@ -147,6 +156,7 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev) return -ENODEV; zdev->ap_dev = ap_dev; zdev->online = 1; + zdev->load = zdev->speed_rating[0]; ap_device_init_reply(ap_dev, &zdev->reply); ap_dev->private = zdev; rc = zcrypt_device_register(zdev); diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index 7bafba83390a..fb97479af3f8 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -173,6 +173,38 @@ struct type80_hdr { unsigned char reserved3[8]; } __packed; +unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *mex, int *fcode) +{ + + if (!mex->inputdatalength) + return -EINVAL; + + if (mex->inputdatalength <= 128) /* 1024 bit */ + *fcode = MEX_1K; + else if (mex->inputdatalength <= 256) /* 2048 bit */ + *fcode = MEX_2K; + else /* 4096 bit */ + *fcode = MEX_4K; + + return 0; +} + +unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode) +{ + + if (!crt->inputdatalength) + return -EINVAL; + + if (crt->inputdatalength <= 128) /* 1024 bit */ + *fcode = CRT_1K; + else if (crt->inputdatalength <= 256) /* 2048 bit */ + *fcode = CRT_2K; + else /* 4096 bit */ + *fcode = CRT_4K; + + return 0; +} + /** * Convert a ICAMEX message to a type50 MEX message. * diff --git a/drivers/s390/crypto/zcrypt_msgtype50.h b/drivers/s390/crypto/zcrypt_msgtype50.h index eeb41c0f34ae..5cc280318ee7 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.h +++ b/drivers/s390/crypto/zcrypt_msgtype50.h @@ -35,6 +35,9 @@ #define MSGTYPE_ADJUSTMENT 0x08 /*type04 extension (not needed in type50)*/ +unsigned int get_rsa_modex_fc(struct ica_rsa_modexpo *, int *); +unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *, int *); + void zcrypt_msgtype50_init(void); void zcrypt_msgtype50_exit(void); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index f71949685ff5..957a88d5768b 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -149,6 +149,112 @@ static struct CPRBX static_cprbx = { .func_id = {0x54, 0x32}, }; +int speed_idx_cca(int req_type) +{ + switch (req_type) { + case 0x4142: + case 0x4149: + case 0x414D: + case 0x4341: + case 0x4344: + case 0x4354: + case 0x4358: + case 0x444B: + case 0x4558: + case 0x4643: + case 0x4651: + case 0x4C47: + case 0x4C4B: + case 0x4C51: + case 0x4F48: + case 0x504F: + case 0x5053: + case 0x5058: + case 0x5343: + case 0x5344: + case 0x5345: + case 0x5350: + return LOW; + case 0x414B: + case 0x4345: + case 0x4349: + case 0x434D: + case 0x4847: + case 0x4849: + case 0x484D: + case 0x4850: + case 0x4851: + case 0x4954: + case 0x4958: + case 0x4B43: + case 0x4B44: + case 0x4B45: + case 0x4B47: + case 0x4B48: + case 0x4B49: + case 0x4B4E: + case 0x4B50: + case 0x4B52: + case 0x4B54: + case 0x4B58: + case 0x4D50: + case 0x4D53: + case 0x4D56: + case 0x4D58: + case 0x5044: + case 0x5045: + case 0x5046: + case 0x5047: + case 0x5049: + case 0x504B: + case 0x504D: + case 0x5254: + case 0x5347: + case 0x5349: + case 0x534B: + case 0x534D: + case 0x5356: + case 0x5358: + case 0x5443: + case 0x544B: + case 0x5647: + return HIGH; + default: + return MEDIUM; + } +} + +int speed_idx_ep11(int req_type) +{ + switch (req_type) { + case 1: + case 2: + case 36: + case 37: + case 38: + case 39: + case 40: + return LOW; + case 17: + case 18: + case 19: + case 20: + case 21: + case 22: + case 26: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + return HIGH; + default: + return MEDIUM; + } +} + + /** * Convert a ICAMEX message to a type6 MEX message. * @@ -297,9 +403,9 @@ struct type86_fmt2_msg { struct type86_fmt2_ext fmt2; } __packed; -static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, - struct ap_message *ap_msg, - struct ica_xcRB *xcRB) +static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, + struct ica_xcRB *xcRB, + unsigned int *fcode) { static struct type6_hdr static_type6_hdrX = { .type = 0x06, @@ -379,6 +485,8 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, memcpy(msg->hdr.function_code, function_code, sizeof(msg->hdr.function_code)); + *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1]; + if (memcmp(function_code, "US", 2) == 0) ap_msg->special = 1; else @@ -392,12 +500,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev, return 0; } -static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, - struct ap_message *ap_msg, - struct ep11_urb *xcRB) +static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg, + struct ep11_urb *xcRB, + unsigned int *fcode) { - unsigned int lfmt; - static struct type6_hdr static_type6_ep11_hdr = { .type = 0x06, .rqid = {0x00, 0x01}, @@ -421,7 +527,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, unsigned char dom_tag; /* fixed value 0x4 */ unsigned char dom_len; /* fixed value 0x4 */ unsigned int dom_val; /* domain id */ - } __packed * payload_hdr; + } __packed * payload_hdr = NULL; if (CEIL4(xcRB->req_len) < xcRB->req_len) return -EINVAL; /* overflow after alignment*/ @@ -450,36 +556,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev, return -EFAULT; } - /* - The target domain field within the cprb body/payload block will be - replaced by the usage domain for non-management commands only. - Therefore we check the first bit of the 'flags' parameter for - management command indication. - 0 - non management command - 1 - management command - */ - if (!((msg->cprbx.flags & 0x80) == 0x80)) { - msg->cprbx.target_id = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); - - if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ - switch (msg->pld_lenfmt & 0x03) { - case 1: - lfmt = 2; - break; - case 2: - lfmt = 3; - break; - default: - return -EINVAL; - } - } else { - lfmt = 1; /* length format #1 */ - } - payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); - payload_hdr->dom_val = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); - } + *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF); return 0; } @@ -989,6 +1066,36 @@ out_free: return rc; } +unsigned int get_cprb_fc(struct ica_xcRB *xcRB, + struct ap_message *ap_msg, + int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_XCRB, + }; + int rc; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code); + if (rc) { + kzfree(ap_msg->message); + kzfree(ap_msg->private); + } + return rc; +} + /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a send_cprb request. @@ -997,37 +1104,55 @@ out_free: * @xcRB: pointer to the send_cprb request buffer */ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, - struct ica_xcRB *xcRB) + struct ica_xcRB *xcRB, + struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, - }; int rc; + struct response_type *rtype = (struct response_type *)(ap_msg->private); - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = XCRB_msg_to_type6CPRB_msgX(zdev, &ap_msg, xcRB); - if (rc) - goto out_free; - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_xcrb(zdev, &ap_msg, xcRB); + rc = convert_response_xcrb(zdev, ap_msg, xcRB); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); -out_free: - kzfree(ap_msg.message); + ap_cancel_message(zdev->ap_dev, ap_msg); + + kzfree(ap_msg->message); + kzfree(ap_msg->private); + return rc; +} + +unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, + struct ap_message *ap_msg, + int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_EP11, + }; + int rc; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive_ep11; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + rc = xcrb_msg_to_type6_ep11cprb_msgx(ap_msg, xcrb, func_code); + if (rc) { + kzfree(ap_msg->message); + kzfree(ap_msg->private); + } return rc; } @@ -1039,41 +1164,101 @@ out_free: * @xcRB: pointer to the ep11 user request block */ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, - struct ep11_urb *xcrb) + struct ep11_urb *xcrb, + struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_EP11, - }; int rc; + unsigned int lfmt; + struct response_type *rtype = (struct response_type *)(ap_msg->private); + struct { + struct type6_hdr hdr; + struct ep11_cprb cprbx; + unsigned char pld_tag; /* fixed value 0x30 */ + unsigned char pld_lenfmt; /* payload length format */ + } __packed * msg = ap_msg->message; + struct pld_hdr { + unsigned char func_tag; /* fixed value 0x4 */ + unsigned char func_len; /* fixed value 0x4 */ + unsigned int func_val; /* function ID */ + unsigned char dom_tag; /* fixed value 0x4 */ + unsigned char dom_len; /* fixed value 0x4 */ + unsigned int dom_val; /* domain id */ + } __packed * payload_hdr = NULL; - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive_ep11; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rc = xcrb_msg_to_type6_ep11cprb_msgx(zdev, &ap_msg, xcrb); - if (rc) - goto out_free; - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + + /** + * The target domain field within the cprb body/payload block will be + * replaced by the usage domain for non-management commands only. + * Therefore we check the first bit of the 'flags' parameter for + * management command indication. + * 0 - non management command + * 1 - management command + */ + if (!((msg->cprbx.flags & 0x80) == 0x80)) { + msg->cprbx.target_id = (unsigned int) + AP_QID_QUEUE(zdev->ap_dev->qid); + + if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ + switch (msg->pld_lenfmt & 0x03) { + case 1: + lfmt = 2; + break; + case 2: + lfmt = 3; + break; + default: + return -EINVAL; + } + } else { + lfmt = 1; /* length format #1 */ + } + payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); + payload_hdr->dom_val = (unsigned int) + AP_QID_QUEUE(zdev->ap_dev->qid); + } + + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_ep11_xcrb(zdev, &ap_msg, xcrb); + rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zdev->ap_dev, ap_msg); -out_free: - kzfree(ap_msg.message); + kzfree(ap_msg->message); + kzfree(ap_msg->private); return rc; } +unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) +{ + struct response_type resp_type = { + .type = PCIXCC_RESPONSE_TYPE_XCRB, + }; + + ap_init_message(ap_msg); + ap_msg->message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); + if (!ap_msg->message) + return -ENOMEM; + ap_msg->receive = zcrypt_msgtype6_receive; + ap_msg->psmid = (((unsigned long long) current->pid) << 32) + + atomic_inc_return(&zcrypt_step); + ap_msg->private = kmalloc(sizeof(resp_type), GFP_KERNEL); + if (!ap_msg->private) { + kzfree(ap_msg->message); + return -ENOMEM; + } + memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); + + rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE); + + *func_code = HWRNG; + return 0; +} + /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to generate random data. @@ -1081,36 +1266,36 @@ out_free: * PCIXCC/CEX2C device to the request distributor * @buffer: pointer to a memory page to return random data */ - static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, - char *buffer) + char *buffer, struct ap_message *ap_msg) { - struct ap_message ap_msg; - struct response_type resp_type = { - .type = PCIXCC_RESPONSE_TYPE_XCRB, - }; + struct { + struct type6_hdr hdr; + struct CPRBX cprbx; + char function_code[2]; + short int rule_length; + char rule[8]; + short int verb_length; + short int key_length; + } __packed * msg = ap_msg->message; + struct response_type *rtype = (struct response_type *)(ap_msg->private); int rc; - ap_init_message(&ap_msg); - ap_msg.message = kmalloc(MSGTYPE06_MAX_MSG_SIZE, GFP_KERNEL); - if (!ap_msg.message) - return -ENOMEM; - ap_msg.receive = zcrypt_msgtype6_receive; - ap_msg.psmid = (((unsigned long long) current->pid) << 32) + - atomic_inc_return(&zcrypt_step); - ap_msg.private = &resp_type; - rng_type6CPRB_msgX(zdev->ap_dev, &ap_msg, ZCRYPT_RNG_BUFFER_SIZE); - init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); - rc = wait_for_completion_interruptible(&resp_type.work); + msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + + init_completion(&rtype->work); + ap_queue_message(zdev->ap_dev, ap_msg); + rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { - rc = ap_msg.rc; + rc = ap_msg->rc; if (rc == 0) - rc = convert_response_rng(zdev, &ap_msg, buffer); + rc = convert_response_rng(zdev, ap_msg, buffer); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); - kfree(ap_msg.message); + ap_cancel_message(zdev->ap_dev, ap_msg); + + kzfree(ap_msg->message); + kzfree(ap_msg->private); return rc; } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index 5750c4377bfa..a360dbe3c7d2 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -116,15 +116,25 @@ struct type86_fmt2_ext { unsigned int offset4; /* 0x00000000 */ } __packed; +unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, int *); +unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, int *); +unsigned int get_rng_fc(struct ap_message *, int *); + +#define LOW 10 +#define MEDIUM 100 +#define HIGH 500 + +int speed_idx_cca(int); +int speed_idx_ep11(int); + /** * Prepare a type6 CPRB message for random number generation * * @ap_dev: AP device pointer * @ap_msg: pointer to AP message */ -static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, - struct ap_message *ap_msg, - unsigned random_number_length) +static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg, + unsigned int random_number_length) { struct { struct type6_hdr hdr; @@ -156,7 +166,6 @@ static inline void rng_type6CPRB_msgX(struct ap_device *ap_dev, msg->hdr.FromCardLen2 = random_number_length, msg->cprbx = local_cprbx; msg->cprbx.rpl_datal = random_number_length, - msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); memcpy(msg->function_code, msg->hdr.function_code, 0x02); msg->rule_length = 0x0a; memcpy(msg->rule, "RANDOM ", 8); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 8491541f72cf..43de39c74944 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -46,11 +46,6 @@ #define CEX3C_MIN_MOD_SIZE PCIXCC_MIN_MOD_SIZE #define CEX3C_MAX_MOD_SIZE 512 /* 4096 bits */ -#define PCIXCC_MCL2_SPEED_RATING 7870 -#define PCIXCC_MCL3_SPEED_RATING 7870 -#define CEX2C_SPEED_RATING 7000 -#define CEX3C_SPEED_RATING 6500 - #define PCIXCC_MAX_ICA_MESSAGE_SIZE 0x77c /* max size type6 v2 crt message */ #define PCIXCC_MAX_ICA_RESPONSE_SIZE 0x77c /* max size type86 v2 reply */ @@ -220,6 +215,15 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) struct type86_fmt2_ext fmt2; struct CPRBX cprbx; } __attribute__((packed)) *reply; + struct { + struct type6_hdr hdr; + struct CPRBX cprbx; + char function_code[2]; + short int rule_length; + char rule[8]; + short int verb_length; + short int key_length; + } __packed * msg; int rc, i; ap_init_message(&ap_msg); @@ -227,7 +231,11 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) if (!ap_msg.message) return -ENOMEM; - rng_type6CPRB_msgX(ap_dev, &ap_msg, 4); + rng_type6CPRB_msgX(&ap_msg, 4); + + msg = ap_msg.message; + msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); + rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message, ap_msg.length); if (rc) @@ -267,6 +275,14 @@ out_free: static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) { struct zcrypt_device *zdev; + /* + * Normalized speed ratings per crypto adapter + * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY + */ + int PCIXCC_MCL2_SPEED_IDX[] = {10, 10, 10, 10, 10, 10, 10, 10}; + int PCIXCC_MCL3_SPEED_IDX[] = { 8, 8, 8, 8, 8, 8, 8, 8}; + int CEX2C_SPEED_IDX[] = {1000, 1400, 2400, 1100, 1500, 2600, 100, 12}; + int CEX3C_SPEED_IDX[] = { 500, 700, 1400, 550, 800, 1500, 80, 10}; int rc = 0; zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); @@ -284,13 +300,15 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) zdev->user_space_type = rc; if (rc == ZCRYPT_PCIXCC_MCL2) { zdev->type_string = "PCIXCC_MCL2"; - zdev->speed_rating = PCIXCC_MCL2_SPEED_RATING; + memcpy(zdev->speed_rating, PCIXCC_MCL2_SPEED_IDX, + sizeof(PCIXCC_MCL2_SPEED_IDX)); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; } else { zdev->type_string = "PCIXCC_MCL3"; - zdev->speed_rating = PCIXCC_MCL3_SPEED_RATING; + memcpy(zdev->speed_rating, PCIXCC_MCL3_SPEED_IDX, + sizeof(PCIXCC_MCL3_SPEED_IDX)); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; @@ -299,7 +317,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) case AP_DEVICE_TYPE_CEX2C: zdev->user_space_type = ZCRYPT_CEX2C; zdev->type_string = "CEX2C"; - zdev->speed_rating = CEX2C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX2C_SPEED_IDX, + sizeof(CEX2C_SPEED_IDX)); zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; @@ -307,7 +326,8 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) case AP_DEVICE_TYPE_CEX3C: zdev->user_space_type = ZCRYPT_CEX3C; zdev->type_string = "CEX3C"; - zdev->speed_rating = CEX3C_SPEED_RATING; + memcpy(zdev->speed_rating, CEX3C_SPEED_IDX, + sizeof(CEX3C_SPEED_IDX)); zdev->min_mod_size = CEX3C_MIN_MOD_SIZE; zdev->max_mod_size = CEX3C_MAX_MOD_SIZE; zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; @@ -315,6 +335,7 @@ static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) default: goto out_free; } + zdev->load = zdev->speed_rating[0]; rc = zcrypt_pcixcc_rng_supported(ap_dev); if (rc < 0) { -- cgit v1.2.3 From e28d2af43614eb86f59812e7221735fc221bbc10 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:16:03 +0200 Subject: s390/zcrypt: add multi domain support Currently the ap infrastructure only supports one domain at a time. This feature extends the generic cryptographic device driver to support multiple cryptographic domains simultaneously. There are now card and queue devices on the AP bus with independent card and queue drivers. The new /sys layout is as follows: /sys/bus/ap devices . -> ../../../devices/ap/card/. ... card -> ../../../devices/ap/card ... drivers card card -> ../../../../devices/ap/card queue . -> ../../../../devices/ap/card/. ... /sys/devices/ap card . driver -> ../../../../bus/ap/drivers/queue ... driver -> ../../../bus/ap/drivers/card ... The two digit field is the card number, the four digit field is the queue number and is the name of the device driver, e.g. "cex4". For compatability /sys/bus/ap/card for the old layout has to exist, including the attributes that used to reside there. With additional contributions from Harald Freudenberger and Martin Schwidefsky. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/Makefile | 5 +- drivers/s390/crypto/ap_bus.c | 1089 ++++++++------------------------ drivers/s390/crypto/ap_bus.h | 94 ++- drivers/s390/crypto/ap_card.c | 172 +++++ drivers/s390/crypto/ap_queue.c | 700 ++++++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 929 +++++++++++---------------- drivers/s390/crypto/zcrypt_api.h | 84 ++- drivers/s390/crypto/zcrypt_card.c | 181 ++++++ drivers/s390/crypto/zcrypt_cex2a.c | 212 +++++-- drivers/s390/crypto/zcrypt_cex4.c | 317 ++++++---- drivers/s390/crypto/zcrypt_error.h | 38 +- drivers/s390/crypto/zcrypt_msgtype50.c | 90 +-- drivers/s390/crypto/zcrypt_msgtype6.c | 253 ++++---- drivers/s390/crypto/zcrypt_msgtype6.h | 12 +- drivers/s390/crypto/zcrypt_pcixcc.c | 358 +++++------ drivers/s390/crypto/zcrypt_queue.c | 221 +++++++ include/linux/mod_devicetable.h | 3 +- 17 files changed, 2768 insertions(+), 1990 deletions(-) create mode 100644 drivers/s390/crypto/ap_card.c create mode 100644 drivers/s390/crypto/ap_queue.c create mode 100644 drivers/s390/crypto/zcrypt_card.c create mode 100644 drivers/s390/crypto/zcrypt_queue.c (limited to 'drivers') diff --git a/drivers/s390/crypto/Makefile b/drivers/s390/crypto/Makefile index d0549fc87247..0a7fb83f35e5 100644 --- a/drivers/s390/crypto/Makefile +++ b/drivers/s390/crypto/Makefile @@ -2,10 +2,11 @@ # S/390 crypto devices # -ap-objs := ap_bus.o +ap-objs := ap_bus.o ap_card.o ap_queue.o obj-$(subst m,y,$(CONFIG_ZCRYPT)) += ap.o # zcrypt_api.o and zcrypt_msgtype*.o depend on ap.o -zcrypt-objs := zcrypt_api.o zcrypt_msgtype6.o zcrypt_msgtype50.o +zcrypt-objs := zcrypt_api.o zcrypt_card.o zcrypt_queue.o +zcrypt-objs += zcrypt_msgtype6.o zcrypt_msgtype50.o obj-$(CONFIG_ZCRYPT) += zcrypt.o # adapter drivers depend on ap.o and zcrypt.o obj-$(CONFIG_ZCRYPT) += zcrypt_pcixcc.o zcrypt_cex2a.o zcrypt_cex4.o diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index fe1cfa4b22c9..ac6c258300cf 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -46,6 +46,7 @@ #include #include #include +#include #include "ap_bus.h" #include "ap_asm.h" @@ -72,10 +73,12 @@ static int ap_thread_flag = 0; module_param_named(poll_thread, ap_thread_flag, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(poll_thread, "Turn on/off poll thread, default is 0 (off)."); -static struct device *ap_root_device = NULL; +static struct device *ap_root_device; + +DEFINE_SPINLOCK(ap_list_lock); +LIST_HEAD(ap_card_list); + static struct ap_config_info *ap_configuration; -static DEFINE_SPINLOCK(ap_device_list_lock); -static LIST_HEAD(ap_device_list); static bool initialised; /* @@ -129,6 +132,20 @@ static inline int ap_using_interrupts(void) return ap_airq_flag; } +/** + * ap_airq_ptr() - Get the address of the adapter interrupt indicator + * + * Returns the address of the local-summary-indicator of the adapter + * interrupt handler for AP, or NULL if adapter interrupts are not + * available. + */ +void *ap_airq_ptr(void) +{ + if (ap_using_interrupts()) + return ap_airq.lsi_ptr; + return NULL; +} + /** * ap_interrupts_available(): Test if AP interrupts are available. * @@ -229,101 +246,6 @@ static inline int ap_test_config_domain(unsigned int domain) return ap_test_config(ap_configuration->aqm, domain); } -/** - * ap_queue_enable_interruption(): Enable interruption on an AP. - * @qid: The AP queue number - * @ind: the notification indicator byte - * - * Enables interruption on AP queue via ap_aqic(). Based on the return - * value it waits a while and tests the AP queue if interrupts - * have been switched on using ap_test_queue(). - */ -static int ap_queue_enable_interruption(struct ap_device *ap_dev, void *ind) -{ - struct ap_queue_status status; - - status = ap_aqic(ap_dev->qid, ind); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - case AP_RESPONSE_OTHERWISE_CHANGED: - return 0; - case AP_RESPONSE_Q_NOT_AVAIL: - case AP_RESPONSE_DECONFIGURED: - case AP_RESPONSE_CHECKSTOPPED: - case AP_RESPONSE_INVALID_ADDRESS: - pr_err("Registering adapter interrupts for AP %d failed\n", - AP_QID_DEVICE(ap_dev->qid)); - return -EOPNOTSUPP; - case AP_RESPONSE_RESET_IN_PROGRESS: - case AP_RESPONSE_BUSY: - default: - return -EBUSY; - } -} - -/** - * __ap_send(): Send message to adjunct processor queue. - * @qid: The AP queue number - * @psmid: The program supplied message identifier - * @msg: The message text - * @length: The message length - * @special: Special Bit - * - * Returns AP queue status structure. - * Condition code 1 on NQAP can't happen because the L bit is 1. - * Condition code 2 on NQAP also means the send is incomplete, - * because a segment boundary was reached. The NQAP is repeated. - */ -static inline struct ap_queue_status -__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, - unsigned int special) -{ - if (special == 1) - qid |= 0x400000UL; - return ap_nqap(qid, psmid, msg, length); -} - -int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) -{ - struct ap_queue_status status; - - status = __ap_send(qid, psmid, msg, length, 0); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - return 0; - case AP_RESPONSE_Q_FULL: - case AP_RESPONSE_RESET_IN_PROGRESS: - return -EBUSY; - case AP_RESPONSE_REQ_FAC_NOT_INST: - return -EINVAL; - default: /* Device is gone. */ - return -ENODEV; - } -} -EXPORT_SYMBOL(ap_send); - -int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) -{ - struct ap_queue_status status; - - if (msg == NULL) - return -EINVAL; - status = ap_dqap(qid, psmid, msg, length); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - return 0; - case AP_RESPONSE_NO_PENDING_REPLY: - if (status.queue_empty) - return -ENOENT; - return -EBUSY; - case AP_RESPONSE_RESET_IN_PROGRESS: - return -EBUSY; - default: - return -ENODEV; - } -} -EXPORT_SYMBOL(ap_recv); - /** * ap_query_queue(): Check if an AP queue is available. * @qid: The AP queue number @@ -338,7 +260,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, unsigned long info; int nd; - if (!ap_test_config_card_id(AP_QID_DEVICE(qid))) + if (!ap_test_config_card_id(AP_QID_CARD(qid))) return -ENODEV; status = ap_test_queue(qid, &info); @@ -366,9 +288,7 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, } } -/* State machine definitions and helpers */ - -static void ap_sm_wait(enum ap_wait wait) +void ap_wait(enum ap_wait wait) { ktime_t hr_time; @@ -397,347 +317,21 @@ static void ap_sm_wait(enum ap_wait wait) } } -static enum ap_wait ap_sm_nop(struct ap_device *ap_dev) -{ - return AP_WAIT_NONE; -} - -/** - * ap_sm_recv(): Receive pending reply messages from an AP device but do - * not change the state of the device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -static struct ap_queue_status ap_sm_recv(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - struct ap_message *ap_msg; - - status = ap_dqap(ap_dev->qid, &ap_dev->reply->psmid, - ap_dev->reply->message, ap_dev->reply->length); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - ap_dev->queue_count--; - if (ap_dev->queue_count > 0) - mod_timer(&ap_dev->timeout, - jiffies + ap_dev->drv->request_timeout); - list_for_each_entry(ap_msg, &ap_dev->pendingq, list) { - if (ap_msg->psmid != ap_dev->reply->psmid) - continue; - list_del_init(&ap_msg->list); - ap_dev->pendingq_count--; - ap_msg->receive(ap_dev, ap_msg, ap_dev->reply); - break; - } - case AP_RESPONSE_NO_PENDING_REPLY: - if (!status.queue_empty || ap_dev->queue_count <= 0) - break; - /* The card shouldn't forget requests but who knows. */ - ap_dev->queue_count = 0; - list_splice_init(&ap_dev->pendingq, &ap_dev->requestq); - ap_dev->requestq_count += ap_dev->pendingq_count; - ap_dev->pendingq_count = 0; - break; - default: - break; - } - return status; -} - -/** - * ap_sm_read(): Receive pending reply messages from an AP device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -static enum ap_wait ap_sm_read(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - - if (!ap_dev->reply) - return AP_WAIT_NONE; - status = ap_sm_recv(ap_dev); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_dev->queue_count > 0) { - ap_dev->state = AP_STATE_WORKING; - return AP_WAIT_AGAIN; - } - ap_dev->state = AP_STATE_IDLE; - return AP_WAIT_NONE; - case AP_RESPONSE_NO_PENDING_REPLY: - if (ap_dev->queue_count > 0) - return AP_WAIT_INTERRUPT; - ap_dev->state = AP_STATE_IDLE; - return AP_WAIT_NONE; - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_suspend_read(): Receive pending reply messages from an AP device - * without changing the device state in between. In suspend mode we don't - * allow sending new requests, therefore just fetch pending replies. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE or AP_WAIT_AGAIN - */ -static enum ap_wait ap_sm_suspend_read(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - - if (!ap_dev->reply) - return AP_WAIT_NONE; - status = ap_sm_recv(ap_dev); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_dev->queue_count > 0) - return AP_WAIT_AGAIN; - /* fall through */ - default: - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_write(): Send messages from the request queue to an AP device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -static enum ap_wait ap_sm_write(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - struct ap_message *ap_msg; - - if (ap_dev->requestq_count <= 0) - return AP_WAIT_NONE; - /* Start the next request on the queue. */ - ap_msg = list_entry(ap_dev->requestq.next, struct ap_message, list); - status = __ap_send(ap_dev->qid, ap_msg->psmid, - ap_msg->message, ap_msg->length, ap_msg->special); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - ap_dev->queue_count++; - if (ap_dev->queue_count == 1) - mod_timer(&ap_dev->timeout, - jiffies + ap_dev->drv->request_timeout); - list_move_tail(&ap_msg->list, &ap_dev->pendingq); - ap_dev->requestq_count--; - ap_dev->pendingq_count++; - if (ap_dev->queue_count < ap_dev->queue_depth) { - ap_dev->state = AP_STATE_WORKING; - return AP_WAIT_AGAIN; - } - /* fall through */ - case AP_RESPONSE_Q_FULL: - ap_dev->state = AP_STATE_QUEUE_FULL; - return AP_WAIT_INTERRUPT; - case AP_RESPONSE_RESET_IN_PROGRESS: - ap_dev->state = AP_STATE_RESET_WAIT; - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_MESSAGE_TOO_BIG: - case AP_RESPONSE_REQ_FAC_NOT_INST: - list_del_init(&ap_msg->list); - ap_dev->requestq_count--; - ap_msg->rc = -EINVAL; - ap_msg->receive(ap_dev, ap_msg, NULL); - return AP_WAIT_AGAIN; - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_read_write(): Send and receive messages to/from an AP device. - * @ap_dev: pointer to the AP device - * - * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT - */ -static enum ap_wait ap_sm_read_write(struct ap_device *ap_dev) -{ - return min(ap_sm_read(ap_dev), ap_sm_write(ap_dev)); -} - -/** - * ap_sm_reset(): Reset an AP queue. - * @qid: The AP queue number - * - * Submit the Reset command to an AP queue. - */ -static enum ap_wait ap_sm_reset(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - - status = ap_rapq(ap_dev->qid); - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - case AP_RESPONSE_RESET_IN_PROGRESS: - ap_dev->state = AP_STATE_RESET_WAIT; - ap_dev->interrupt = AP_INTR_DISABLED; - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_BUSY: - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_Q_NOT_AVAIL: - case AP_RESPONSE_DECONFIGURED: - case AP_RESPONSE_CHECKSTOPPED: - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_reset_wait(): Test queue for completion of the reset operation - * @ap_dev: pointer to the AP device - * - * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. - */ -static enum ap_wait ap_sm_reset_wait(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - unsigned long info; - - if (ap_dev->queue_count > 0 && ap_dev->reply) - /* Try to read a completed message and get the status */ - status = ap_sm_recv(ap_dev); - else - /* Get the status with TAPQ */ - status = ap_test_queue(ap_dev->qid, &info); - - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_using_interrupts() && - ap_queue_enable_interruption(ap_dev, - ap_airq.lsi_ptr) == 0) - ap_dev->state = AP_STATE_SETIRQ_WAIT; - else - ap_dev->state = (ap_dev->queue_count > 0) ? - AP_STATE_WORKING : AP_STATE_IDLE; - return AP_WAIT_AGAIN; - case AP_RESPONSE_BUSY: - case AP_RESPONSE_RESET_IN_PROGRESS: - return AP_WAIT_TIMEOUT; - case AP_RESPONSE_Q_NOT_AVAIL: - case AP_RESPONSE_DECONFIGURED: - case AP_RESPONSE_CHECKSTOPPED: - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/** - * ap_sm_setirq_wait(): Test queue for completion of the irq enablement - * @ap_dev: pointer to the AP device - * - * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. - */ -static enum ap_wait ap_sm_setirq_wait(struct ap_device *ap_dev) -{ - struct ap_queue_status status; - unsigned long info; - - if (ap_dev->queue_count > 0 && ap_dev->reply) - /* Try to read a completed message and get the status */ - status = ap_sm_recv(ap_dev); - else - /* Get the status with TAPQ */ - status = ap_test_queue(ap_dev->qid, &info); - - if (status.int_enabled == 1) { - /* Irqs are now enabled */ - ap_dev->interrupt = AP_INTR_ENABLED; - ap_dev->state = (ap_dev->queue_count > 0) ? - AP_STATE_WORKING : AP_STATE_IDLE; - } - - switch (status.response_code) { - case AP_RESPONSE_NORMAL: - if (ap_dev->queue_count > 0) - return AP_WAIT_AGAIN; - /* fallthrough */ - case AP_RESPONSE_NO_PENDING_REPLY: - return AP_WAIT_TIMEOUT; - default: - ap_dev->state = AP_STATE_BORKED; - return AP_WAIT_NONE; - } -} - -/* - * AP state machine jump table - */ -static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = { - [AP_STATE_RESET_START] = { - [AP_EVENT_POLL] = ap_sm_reset, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_RESET_WAIT] = { - [AP_EVENT_POLL] = ap_sm_reset_wait, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_SETIRQ_WAIT] = { - [AP_EVENT_POLL] = ap_sm_setirq_wait, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_IDLE] = { - [AP_EVENT_POLL] = ap_sm_write, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_WORKING] = { - [AP_EVENT_POLL] = ap_sm_read_write, - [AP_EVENT_TIMEOUT] = ap_sm_reset, - }, - [AP_STATE_QUEUE_FULL] = { - [AP_EVENT_POLL] = ap_sm_read, - [AP_EVENT_TIMEOUT] = ap_sm_reset, - }, - [AP_STATE_SUSPEND_WAIT] = { - [AP_EVENT_POLL] = ap_sm_suspend_read, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, - [AP_STATE_BORKED] = { - [AP_EVENT_POLL] = ap_sm_nop, - [AP_EVENT_TIMEOUT] = ap_sm_nop, - }, -}; - -static inline enum ap_wait ap_sm_event(struct ap_device *ap_dev, - enum ap_event event) -{ - return ap_jumptable[ap_dev->state][event](ap_dev); -} - -static inline enum ap_wait ap_sm_event_loop(struct ap_device *ap_dev, - enum ap_event event) -{ - enum ap_wait wait; - - while ((wait = ap_sm_event(ap_dev, event)) == AP_WAIT_AGAIN) - ; - return wait; -} - /** * ap_request_timeout(): Handling of request timeouts * @data: Holds the AP device. * * Handles request timeouts. */ -static void ap_request_timeout(unsigned long data) +void ap_request_timeout(unsigned long data) { - struct ap_device *ap_dev = (struct ap_device *) data; + struct ap_queue *aq = (struct ap_queue *) data; if (ap_suspend_flag) return; - spin_lock_bh(&ap_dev->lock); - ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_TIMEOUT)); - spin_unlock_bh(&ap_dev->lock); + spin_lock_bh(&aq->lock); + ap_wait(ap_sm_event(aq, AP_EVENT_TIMEOUT)); + spin_unlock_bh(&aq->lock); } /** @@ -772,7 +366,8 @@ static void ap_interrupt_handler(struct airq_struct *airq) */ static void ap_tasklet_fn(unsigned long dummy) { - struct ap_device *ap_dev; + struct ap_card *ac; + struct ap_queue *aq; enum ap_wait wait = AP_WAIT_NONE; /* Reset the indicator if interrupts are used. Thus new interrupts can @@ -782,35 +377,35 @@ static void ap_tasklet_fn(unsigned long dummy) if (ap_using_interrupts()) xchg(ap_airq.lsi_ptr, 0); - spin_lock(&ap_device_list_lock); - list_for_each_entry(ap_dev, &ap_device_list, list) { - spin_lock_bh(&ap_dev->lock); - wait = min(wait, ap_sm_event_loop(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); + spin_lock_bh(&ap_list_lock); + for_each_ap_card(ac) { + for_each_ap_queue(aq, ac) { + spin_lock_bh(&aq->lock); + wait = min(wait, ap_sm_event_loop(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); + } } - spin_unlock(&ap_device_list_lock); - ap_sm_wait(wait); + spin_unlock_bh(&ap_list_lock); + + ap_wait(wait); } static int ap_pending_requests(void) { - struct ap_device *ap_dev; - int id, pending = 0; - - for (id = 0; pending == 0 && id < AP_DEVICES; id++) { - spin_lock_bh(&ap_device_list_lock); - list_for_each_entry(ap_dev, &ap_device_list, list) { - spin_lock_bh(&ap_dev->lock); - if (ap_dev->queue_count) - pending = 1; - spin_unlock_bh(&ap_dev->lock); - if (pending) - break; + struct ap_card *ac; + struct ap_queue *aq; + + spin_lock_bh(&ap_list_lock); + for_each_ap_card(ac) { + for_each_ap_queue(aq, ac) { + if (aq->queue_count == 0) + continue; + spin_unlock_bh(&ap_list_lock); + return 1; } - spin_unlock_bh(&ap_device_list_lock); } - - return pending; + spin_unlock_bh(&ap_list_lock); + return 0; } /** @@ -874,207 +469,8 @@ static void ap_poll_thread_stop(void) mutex_unlock(&ap_poll_thread_mutex); } -/** - * ap_queue_message(): Queue a request to an AP device. - * @ap_dev: The AP device to queue the message to - * @ap_msg: The message that is to be added - */ -void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg) -{ - /* For asynchronous message handling a valid receive-callback - * is required. */ - BUG_ON(!ap_msg->receive); - - spin_lock_bh(&ap_dev->lock); - /* Queue the message. */ - list_add_tail(&ap_msg->list, &ap_dev->requestq); - ap_dev->requestq_count++; - ap_dev->total_request_count++; - /* Send/receive as many request from the queue as possible. */ - ap_sm_wait(ap_sm_event_loop(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_queue_message); - -/** - * ap_cancel_message(): Cancel a crypto request. - * @ap_dev: The AP device that has the message queued - * @ap_msg: The message that is to be removed - * - * Cancel a crypto request. This is done by removing the request - * from the device pending or request queue. Note that the - * request stays on the AP queue. When it finishes the message - * reply will be discarded because the psmid can't be found. - */ -void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg) -{ - struct ap_message *tmp; - - spin_lock_bh(&ap_dev->lock); - if (!list_empty(&ap_msg->list)) { - list_for_each_entry(tmp, &ap_dev->pendingq, list) - if (tmp->psmid == ap_msg->psmid) { - ap_dev->pendingq_count--; - goto found; - } - ap_dev->requestq_count--; -found: - list_del_init(&ap_msg->list); - } - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_cancel_message); - -/* - * AP device related attributes. - */ -static ssize_t ap_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->device_type); -} - -static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); - -static ssize_t ap_raw_hwtype_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - - return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->raw_hwtype); -} - -static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL); - -static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - return snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->queue_depth); -} - -static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); -static ssize_t ap_request_count_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc; - - spin_lock_bh(&ap_dev->lock); - rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->total_request_count); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); - -static ssize_t ap_requestq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc; - - spin_lock_bh(&ap_dev->lock); - rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->requestq_count); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); - -static ssize_t ap_pendingq_count_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc; - - spin_lock_bh(&ap_dev->lock); - rc = snprintf(buf, PAGE_SIZE, "%d\n", ap_dev->pendingq_count); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); - -static ssize_t ap_reset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc = 0; - - spin_lock_bh(&ap_dev->lock); - switch (ap_dev->state) { - case AP_STATE_RESET_START: - case AP_STATE_RESET_WAIT: - rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n"); - break; - case AP_STATE_WORKING: - case AP_STATE_QUEUE_FULL: - rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); - break; - default: - rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); - } - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL); - -static ssize_t ap_interrupt_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - int rc = 0; - - spin_lock_bh(&ap_dev->lock); - if (ap_dev->state == AP_STATE_SETIRQ_WAIT) - rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); - else if (ap_dev->interrupt == AP_INTR_ENABLED) - rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); - else - rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); - spin_unlock_bh(&ap_dev->lock); - return rc; -} - -static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL); - -static ssize_t ap_modalias_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); -} - -static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); - -static ssize_t ap_functions_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct ap_device *ap_dev = to_ap_dev(dev); - return snprintf(buf, PAGE_SIZE, "0x%08X\n", ap_dev->functions); -} - -static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL); - -static struct attribute *ap_dev_attrs[] = { - &dev_attr_hwtype.attr, - &dev_attr_raw_hwtype.attr, - &dev_attr_depth.attr, - &dev_attr_request_count.attr, - &dev_attr_requestq_count.attr, - &dev_attr_pendingq_count.attr, - &dev_attr_reset.attr, - &dev_attr_interrupt.attr, - &dev_attr_modalias.attr, - &dev_attr_ap_functions.attr, - NULL -}; -static struct attribute_group ap_dev_attr_group = { - .attrs = ap_dev_attrs -}; +#define is_card_dev(x) ((x)->parent == ap_root_device) +#define is_queue_dev(x) ((x)->parent != ap_root_device) /** * ap_bus_match() @@ -1085,7 +481,6 @@ static struct attribute_group ap_dev_attr_group = { */ static int ap_bus_match(struct device *dev, struct device_driver *drv) { - struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = to_ap_drv(drv); struct ap_device_id *id; @@ -1094,10 +489,14 @@ static int ap_bus_match(struct device *dev, struct device_driver *drv) * supported types of the device_driver. */ for (id = ap_drv->ids; id->match_flags; id++) { - if ((id->match_flags & AP_DEVICE_ID_MATCH_DEVICE_TYPE) && - (id->dev_type != ap_dev->device_type)) - continue; - return 1; + if (is_card_dev(dev) && + id->match_flags & AP_DEVICE_ID_MATCH_CARD_TYPE && + id->dev_type == to_ap_dev(dev)->device_type) + return 1; + if (is_queue_dev(dev) && + id->match_flags & AP_DEVICE_ID_MATCH_QUEUE_TYPE && + id->dev_type == to_ap_dev(dev)->device_type) + return 1; } return 0; } @@ -1133,13 +532,17 @@ static int ap_dev_suspend(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); - /* Poll on the device until all requests are finished. */ - spin_lock_bh(&ap_dev->lock); - ap_dev->state = AP_STATE_SUSPEND_WAIT; - while (ap_sm_event(ap_dev, AP_EVENT_POLL) != AP_WAIT_NONE) - ; - ap_dev->state = AP_STATE_BORKED; - spin_unlock_bh(&ap_dev->lock); + if (ap_dev->drv && ap_dev->drv->suspend) + ap_dev->drv->suspend(ap_dev); + return 0; +} + +static int ap_dev_resume(struct device *dev) +{ + struct ap_device *ap_dev = to_ap_dev(dev); + + if (ap_dev->drv && ap_dev->drv->resume) + ap_dev->drv->resume(ap_dev); return 0; } @@ -1154,9 +557,25 @@ static void ap_bus_suspend(void) tasklet_disable(&ap_tasklet); } -static int __ap_devices_unregister(struct device *dev, void *dummy) +static int __ap_card_devices_unregister(struct device *dev, void *dummy) +{ + if (is_card_dev(dev)) + device_unregister(dev); + return 0; +} + +static int __ap_queue_devices_unregister(struct device *dev, void *dummy) +{ + if (is_queue_dev(dev)) + device_unregister(dev); + return 0; +} + +static int __ap_queue_devices_with_id_unregister(struct device *dev, void *data) { - device_unregister(dev); + if (is_queue_dev(dev) && + AP_QID_CARD(to_ap_queue(dev)->qid) == (int)(long) data) + device_unregister(dev); return 0; } @@ -1164,8 +583,13 @@ static void ap_bus_resume(void) { int rc; - /* Unconditionally remove all AP devices */ - bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_devices_unregister); + /* remove all queue devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_queue_devices_unregister); + /* remove all card devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_card_devices_unregister); + /* Reset thin interrupt setting */ if (ap_interrupts_available() && !ap_using_interrupts()) { rc = register_adapter_interrupt(&ap_airq); @@ -1207,7 +631,7 @@ static struct notifier_block ap_power_notifier = { .notifier_call = ap_power_event, }; -static SIMPLE_DEV_PM_OPS(ap_bus_pm_ops, ap_dev_suspend, NULL); +static SIMPLE_DEV_PM_OPS(ap_bus_pm_ops, ap_dev_suspend, ap_dev_resume); static struct bus_type ap_bus_type = { .name = "ap", @@ -1216,17 +640,6 @@ static struct bus_type ap_bus_type = { .pm = &ap_bus_pm_ops, }; -void ap_device_init_reply(struct ap_device *ap_dev, - struct ap_message *reply) -{ - ap_dev->reply = reply; - - spin_lock_bh(&ap_dev->lock); - ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_device_init_reply); - static int ap_device_probe(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); @@ -1240,58 +653,22 @@ static int ap_device_probe(struct device *dev) return rc; } -/** - * __ap_flush_queue(): Flush requests. - * @ap_dev: Pointer to the AP device - * - * Flush all requests from the request/pending queue of an AP device. - */ -static void __ap_flush_queue(struct ap_device *ap_dev) -{ - struct ap_message *ap_msg, *next; - - list_for_each_entry_safe(ap_msg, next, &ap_dev->pendingq, list) { - list_del_init(&ap_msg->list); - ap_dev->pendingq_count--; - ap_msg->rc = -EAGAIN; - ap_msg->receive(ap_dev, ap_msg, NULL); - } - list_for_each_entry_safe(ap_msg, next, &ap_dev->requestq, list) { - list_del_init(&ap_msg->list); - ap_dev->requestq_count--; - ap_msg->rc = -EAGAIN; - ap_msg->receive(ap_dev, ap_msg, NULL); - } -} - -void ap_flush_queue(struct ap_device *ap_dev) -{ - spin_lock_bh(&ap_dev->lock); - __ap_flush_queue(ap_dev); - spin_unlock_bh(&ap_dev->lock); -} -EXPORT_SYMBOL(ap_flush_queue); - static int ap_device_remove(struct device *dev) { struct ap_device *ap_dev = to_ap_dev(dev); struct ap_driver *ap_drv = ap_dev->drv; - ap_flush_queue(ap_dev); - del_timer_sync(&ap_dev->timeout); - spin_lock_bh(&ap_device_list_lock); - list_del_init(&ap_dev->list); - spin_unlock_bh(&ap_device_list_lock); + spin_lock_bh(&ap_list_lock); + if (is_card_dev(dev)) + list_del_init(&to_ap_card(dev)->list); + else + list_del_init(&to_ap_queue(dev)->list); + spin_unlock_bh(&ap_list_lock); if (ap_drv->remove) ap_drv->remove(ap_dev); return 0; } -static void ap_device_release(struct device *dev) -{ - kfree(to_ap_dev(dev)); -} - int ap_driver_register(struct ap_driver *ap_drv, struct module *owner, char *name) { @@ -1354,12 +731,7 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) { if (!ap_configuration) /* QCI not supported */ return snprintf(buf, PAGE_SIZE, "not supported\n"); - if (!test_facility(76)) - /* format 0 - 16 bit domain field */ - return snprintf(buf, PAGE_SIZE, "%08x%08x\n", - ap_configuration->adm[0], - ap_configuration->adm[1]); - /* format 1 - 256 bit domain field */ + return snprintf(buf, PAGE_SIZE, "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", ap_configuration->adm[0], ap_configuration->adm[1], @@ -1371,6 +743,22 @@ static ssize_t ap_control_domain_mask_show(struct bus_type *bus, char *buf) static BUS_ATTR(ap_control_domain_mask, 0444, ap_control_domain_mask_show, NULL); +static ssize_t ap_usage_domain_mask_show(struct bus_type *bus, char *buf) +{ + if (!ap_configuration) /* QCI not supported */ + return snprintf(buf, PAGE_SIZE, "not supported\n"); + + return snprintf(buf, PAGE_SIZE, + "0x%08x%08x%08x%08x%08x%08x%08x%08x\n", + ap_configuration->aqm[0], ap_configuration->aqm[1], + ap_configuration->aqm[2], ap_configuration->aqm[3], + ap_configuration->aqm[4], ap_configuration->aqm[5], + ap_configuration->aqm[6], ap_configuration->aqm[7]); +} + +static BUS_ATTR(ap_usage_domain_mask, 0444, + ap_usage_domain_mask_show, NULL); + static ssize_t ap_config_time_show(struct bus_type *bus, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", ap_config_time); @@ -1466,6 +854,7 @@ static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL); static struct bus_attribute *const ap_bus_attrs[] = { &bus_attr_ap_domain, &bus_attr_ap_control_domain_mask, + &bus_attr_ap_usage_domain_mask, &bus_attr_config_time, &bus_attr_poll_thread, &bus_attr_ap_interrupts, @@ -1524,110 +913,162 @@ static int ap_select_domain(void) return -ENODEV; } -/** - * __ap_scan_bus(): Scan the AP bus. - * @dev: Pointer to device - * @data: Pointer to data - * - * Scan the AP bus for new devices. +/* + * helper function to be used with bus_find_dev + * matches for the card device with the given id */ -static int __ap_scan_bus(struct device *dev, void *data) +static int __match_card_device_with_id(struct device *dev, void *data) { - return to_ap_dev(dev)->qid == (ap_qid_t)(unsigned long) data; + return is_card_dev(dev) && to_ap_card(dev)->id == (int)(long) data; } +/* helper function to be used with bus_find_dev + * matches for the queue device with a given qid + */ +static int __match_queue_device_with_qid(struct device *dev, void *data) +{ + return is_queue_dev(dev) && to_ap_queue(dev)->qid == (int)(long) data; +} + +/** + * ap_scan_bus(): Scan the AP bus for new devices + * Runs periodically, workqueue timer (ap_config_time) + */ static void ap_scan_bus(struct work_struct *unused) { - struct ap_device *ap_dev; + struct ap_queue *aq; + struct ap_card *ac; struct device *dev; ap_qid_t qid; - int queue_depth = 0, device_type = 0; - unsigned int device_functions = 0; - int rc, i, borked; + int depth = 0, type = 0; + unsigned int functions = 0; + int rc, id, dom, borked, domains; ap_query_configuration(); if (ap_select_domain() != 0) goto out; - - spin_lock_bh(&ap_domain_lock); - for (i = 0; i < AP_DEVICES; i++) { - qid = AP_MKQID(i, ap_domain_index); + for (id = 0; id < AP_DEVICES; id++) { + /* check if device is registered */ dev = bus_find_device(&ap_bus_type, NULL, - (void *)(unsigned long)qid, - __ap_scan_bus); - rc = ap_query_queue(qid, &queue_depth, &device_type, - &device_functions); - if (dev) { - ap_dev = to_ap_dev(dev); - spin_lock_bh(&ap_dev->lock); - if (rc == -ENODEV) - ap_dev->state = AP_STATE_BORKED; - borked = ap_dev->state == AP_STATE_BORKED; - spin_unlock_bh(&ap_dev->lock); - if (borked) /* Remove broken device */ + (void *)(long) id, + __match_card_device_with_id); + ac = dev ? to_ap_card(dev) : NULL; + if (!ap_test_config_card_id(id)) { + if (dev) { + /* Card device has been removed from + * configuration, remove the belonging + * queue devices. + */ + bus_for_each_dev(&ap_bus_type, NULL, + (void *)(long) id, + __ap_queue_devices_with_id_unregister); + /* now remove the card device */ device_unregister(dev); - put_device(dev); - if (!borked) - continue; - } - if (rc) - continue; - ap_dev = kzalloc(sizeof(*ap_dev), GFP_KERNEL); - if (!ap_dev) - break; - ap_dev->qid = qid; - ap_dev->state = AP_STATE_RESET_START; - ap_dev->interrupt = AP_INTR_DISABLED; - ap_dev->queue_depth = queue_depth; - ap_dev->raw_hwtype = device_type; - ap_dev->device_type = device_type; - /* CEX6 toleration: map to CEX5 */ - if (device_type == AP_DEVICE_TYPE_CEX6) - ap_dev->device_type = AP_DEVICE_TYPE_CEX5; - ap_dev->functions = device_functions; - spin_lock_init(&ap_dev->lock); - INIT_LIST_HEAD(&ap_dev->pendingq); - INIT_LIST_HEAD(&ap_dev->requestq); - INIT_LIST_HEAD(&ap_dev->list); - setup_timer(&ap_dev->timeout, ap_request_timeout, - (unsigned long) ap_dev); - - ap_dev->device.bus = &ap_bus_type; - ap_dev->device.parent = ap_root_device; - rc = dev_set_name(&ap_dev->device, "card%02x", - AP_QID_DEVICE(ap_dev->qid)); - if (rc) { - kfree(ap_dev); - continue; - } - /* Add to list of devices */ - spin_lock_bh(&ap_device_list_lock); - list_add(&ap_dev->list, &ap_device_list); - spin_unlock_bh(&ap_device_list_lock); - /* Start with a device reset */ - spin_lock_bh(&ap_dev->lock); - ap_sm_wait(ap_sm_event(ap_dev, AP_EVENT_POLL)); - spin_unlock_bh(&ap_dev->lock); - /* Register device */ - ap_dev->device.release = ap_device_release; - rc = device_register(&ap_dev->device); - if (rc) { - spin_lock_bh(&ap_dev->lock); - list_del_init(&ap_dev->list); - spin_unlock_bh(&ap_dev->lock); - put_device(&ap_dev->device); + put_device(dev); + } continue; } - /* Add device attributes. */ - rc = sysfs_create_group(&ap_dev->device.kobj, - &ap_dev_attr_group); - if (rc) { - device_unregister(&ap_dev->device); - continue; + /* According to the configuration there should be a card + * device, so check if there is at least one valid queue + * and maybe create queue devices and the card device. + */ + domains = 0; + for (dom = 0; dom < AP_DOMAINS; dom++) { + qid = AP_MKQID(id, dom); + dev = bus_find_device(&ap_bus_type, NULL, + (void *)(long) qid, + __match_queue_device_with_qid); + aq = dev ? to_ap_queue(dev) : NULL; + if (!ap_test_config_domain(dom)) { + if (dev) { + /* Queue device exists but has been + * removed from configuration. + */ + device_unregister(dev); + put_device(dev); + } + continue; + } + rc = ap_query_queue(qid, &depth, &type, &functions); + if (dev) { + spin_lock_bh(&aq->lock); + if (rc == -ENODEV || + /* adapter reconfiguration */ + (ac && ac->functions != functions)) + aq->state = AP_STATE_BORKED; + borked = aq->state == AP_STATE_BORKED; + spin_unlock_bh(&aq->lock); + if (borked) /* Remove broken device */ + device_unregister(dev); + put_device(dev); + if (!borked) { + domains++; + continue; + } + } + if (rc) + continue; + /* new queue device needed */ + if (!ac) { + /* but first create the card device */ + ac = ap_card_create(id, depth, + type, functions); + if (!ac) + continue; + ac->ap_dev.device.bus = &ap_bus_type; + ac->ap_dev.device.parent = ap_root_device; + dev_set_name(&ac->ap_dev.device, + "card%02x", id); + /* Register card with AP bus */ + rc = device_register(&ac->ap_dev.device); + if (rc) { + put_device(&ac->ap_dev.device); + ac = NULL; + break; + } + /* get it and thus adjust reference counter */ + get_device(&ac->ap_dev.device); + /* Add card device to card list */ + spin_lock_bh(&ap_list_lock); + list_add(&ac->list, &ap_card_list); + spin_unlock_bh(&ap_list_lock); + } + /* now create the new queue device */ + aq = ap_queue_create(qid, type); + if (!aq) + continue; + aq->card = ac; + aq->ap_dev.device.bus = &ap_bus_type; + aq->ap_dev.device.parent = &ac->ap_dev.device; + dev_set_name(&aq->ap_dev.device, + "%02x.%04x", id, dom); + /* Add queue device to card queue list */ + spin_lock_bh(&ap_list_lock); + list_add(&aq->list, &ac->queues); + spin_unlock_bh(&ap_list_lock); + /* Start with a device reset */ + spin_lock_bh(&aq->lock); + ap_wait(ap_sm_event(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); + /* Register device */ + rc = device_register(&aq->ap_dev.device); + if (rc) { + spin_lock_bh(&ap_list_lock); + list_del_init(&aq->list); + spin_unlock_bh(&ap_list_lock); + put_device(&aq->ap_dev.device); + continue; + } + domains++; + } /* end domain loop */ + if (ac) { + /* remove card dev if there are no queue devices */ + if (!domains) + device_unregister(&ac->ap_dev.device); + put_device(&ac->ap_dev.device); } - } - spin_unlock_bh(&ap_domain_lock); + } /* end device loop */ out: mod_timer(&ap_config_timer, jiffies + ap_config_time * HZ); } @@ -1787,7 +1228,15 @@ void ap_module_exit(void) del_timer_sync(&ap_config_timer); hrtimer_cancel(&ap_poll_timer); tasklet_kill(&ap_tasklet); - bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_devices_unregister); + + /* first remove queue devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_queue_devices_unregister); + /* now remove the card devices */ + bus_for_each_dev(&ap_bus_type, NULL, NULL, + __ap_card_devices_unregister); + + /* remove bus attributes */ for (i = 0; ap_bus_attrs[i]; i++) bus_remove_file(&ap_bus_type, ap_bus_attrs[i]); unregister_pm_notifier(&ap_power_notifier); diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index fd66d2c450d5..54b17e142792 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -27,7 +27,6 @@ #define _AP_BUS_H_ #include -#include #include #define AP_DEVICES 64 /* Number of AP devices. */ @@ -38,14 +37,17 @@ extern int ap_domain_index; +extern spinlock_t ap_list_lock; +extern struct list_head ap_card_list; + /** * The ap_qid_t identifier of an ap queue. It contains a - * 6 bit device index and a 4 bit queue index (domain). + * 6 bit card index and a 4 bit queue index (domain). */ typedef unsigned int ap_qid_t; -#define AP_MKQID(_device, _queue) (((_device) & 63) << 8 | ((_queue) & 255)) -#define AP_QID_DEVICE(_qid) (((_qid) >> 8) & 63) +#define AP_MKQID(_card, _queue) (((_card) & 63) << 8 | ((_queue) & 255)) +#define AP_QID_CARD(_qid) (((_qid) >> 8) & 63) #define AP_QID_QUEUE(_qid) ((_qid) & 255) /** @@ -55,7 +57,7 @@ typedef unsigned int ap_qid_t; * @queue_full: Is 1 if the queue is full * @pad: A 4 bit pad * @int_enabled: Shows if interrupts are enabled for the AP - * @response_conde: Holds the 8 bit response code + * @response_code: Holds the 8 bit response code * @pad2: A 16 bit pad * * The ap queue status word is returned by all three AP functions @@ -167,7 +169,8 @@ struct ap_driver { int (*probe)(struct ap_device *); void (*remove)(struct ap_device *); - int request_timeout; /* request timeout in jiffies */ + void (*suspend)(struct ap_device *); + void (*resume)(struct ap_device *); }; #define to_ap_drv(x) container_of((x), struct ap_driver, driver) @@ -175,38 +178,50 @@ struct ap_driver { int ap_driver_register(struct ap_driver *, struct module *, char *); void ap_driver_unregister(struct ap_driver *); -typedef enum ap_wait (ap_func_t)(struct ap_device *ap_dev); - struct ap_device { struct device device; struct ap_driver *drv; /* Pointer to AP device driver. */ - spinlock_t lock; /* Per device lock. */ - struct list_head list; /* private list of all AP devices. */ + int device_type; /* AP device type. */ +}; - enum ap_state state; /* State of the AP device. */ +#define to_ap_dev(x) container_of((x), struct ap_device, device) - ap_qid_t qid; /* AP queue id. */ - int queue_depth; /* AP queue depth.*/ - int device_type; /* AP device type. */ +struct ap_card { + struct ap_device ap_dev; + struct list_head list; /* Private list of AP cards. */ + struct list_head queues; /* List of assoc. AP queues */ + void *private; /* ap driver private pointer. */ int raw_hwtype; /* AP raw hardware type. */ unsigned int functions; /* AP device function bitfield. */ - struct timer_list timeout; /* Timer for request timeouts. */ + int queue_depth; /* AP queue depth.*/ + int id; /* AP card number. */ +}; + +#define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) +struct ap_queue { + struct ap_device ap_dev; + struct list_head list; /* Private list of AP queues. */ + struct ap_card *card; /* Ptr to assoc. AP card. */ + spinlock_t lock; /* Per device lock. */ + void *private; /* ap driver private pointer. */ + ap_qid_t qid; /* AP queue id. */ int interrupt; /* indicate if interrupts are enabled */ int queue_count; /* # messages currently on AP queue. */ - - struct list_head pendingq; /* List of message sent to AP queue. */ + enum ap_state state; /* State of the AP device. */ int pendingq_count; /* # requests on pendingq list. */ - struct list_head requestq; /* List of message yet to be sent. */ int requestq_count; /* # requests on requestq list. */ int total_request_count; /* # requests ever for this AP device. */ - + int request_timeout; /* Request timout in jiffies. */ + struct timer_list timeout; /* Timer for request timeouts. */ + struct list_head pendingq; /* List of message sent to AP queue. */ + struct list_head requestq; /* List of message yet to be sent. */ struct ap_message *reply; /* Per device reply message. */ - - void *private; /* ap driver private pointer. */ }; -#define to_ap_dev(x) container_of((x), struct ap_device, device) +#define to_ap_queue(x) container_of((x), struct ap_queue, ap_dev.device) + +typedef enum ap_wait (ap_func_t)(struct ap_queue *queue); struct ap_message { struct list_head list; /* Request queueing. */ @@ -218,7 +233,7 @@ struct ap_message { void *private; /* ap driver private pointer. */ unsigned int special:1; /* Used for special commands. */ /* receive is called from tasklet context */ - void (*receive)(struct ap_device *, struct ap_message *, + void (*receive)(struct ap_queue *, struct ap_message *, struct ap_message *); }; @@ -233,10 +248,6 @@ struct ap_config_info { unsigned char reserved4[16]; } __packed; -#define AP_DEVICE(dt) \ - .dev_type=(dt), \ - .match_flags=AP_DEVICE_ID_MATCH_DEVICE_TYPE, - /** * ap_init_message() - Initialize ap_message. * Initialize a message before using. Otherwise this might result in @@ -251,6 +262,12 @@ static inline void ap_init_message(struct ap_message *ap_msg) ap_msg->receive = NULL; } +#define for_each_ap_card(_ac) \ + list_for_each_entry(_ac, &ap_card_list, list) + +#define for_each_ap_queue(_aq, _ac) \ + list_for_each_entry(_aq, &(_ac)->queues, list) + /* * Note: don't use ap_send/ap_recv after using ap_queue_message * for the first time. Otherwise the ap message queue will get @@ -259,11 +276,26 @@ static inline void ap_init_message(struct ap_message *ap_msg) int ap_send(ap_qid_t, unsigned long long, void *, size_t); int ap_recv(ap_qid_t, unsigned long long *, void *, size_t); -void ap_queue_message(struct ap_device *ap_dev, struct ap_message *ap_msg); -void ap_cancel_message(struct ap_device *ap_dev, struct ap_message *ap_msg); -void ap_flush_queue(struct ap_device *ap_dev); +enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event); +enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event); + +void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg); +void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg); +void ap_flush_queue(struct ap_queue *aq); + +void *ap_airq_ptr(void); +void ap_wait(enum ap_wait wait); +void ap_request_timeout(unsigned long data); void ap_bus_force_rescan(void); -void ap_device_init_reply(struct ap_device *ap_dev, struct ap_message *ap_msg); + +void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *ap_msg); +struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type); +void ap_queue_remove(struct ap_queue *aq); +void ap_queue_suspend(struct ap_device *ap_dev); +void ap_queue_resume(struct ap_device *ap_dev); + +struct ap_card *ap_card_create(int id, int queue_depth, int device_type, + unsigned int device_functions); int ap_module_init(void); void ap_module_exit(void); diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c new file mode 100644 index 000000000000..731dc0dbfb75 --- /dev/null +++ b/drivers/s390/crypto/ap_card.c @@ -0,0 +1,172 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Martin Schwidefsky + * + * Adjunct processor bus, card related code. + */ + +#define KMSG_COMPONENT "ap" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include + +#include "ap_bus.h" +#include "ap_asm.h" + +/* + * AP card related attributes. + */ +static ssize_t ap_hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", ac->ap_dev.device_type); +} + +static DEVICE_ATTR(hwtype, 0444, ap_hwtype_show, NULL); + +static ssize_t ap_raw_hwtype_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", ac->raw_hwtype); +} + +static DEVICE_ATTR(raw_hwtype, 0444, ap_raw_hwtype_show, NULL); + +static ssize_t ap_depth_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", ac->queue_depth); +} + +static DEVICE_ATTR(depth, 0444, ap_depth_show, NULL); + +static ssize_t ap_functions_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + + return snprintf(buf, PAGE_SIZE, "0x%08X\n", ac->functions); +} + +static DEVICE_ATTR(ap_functions, 0444, ap_functions_show, NULL); + +static ssize_t ap_request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + struct ap_queue *aq; + unsigned int req_cnt; + + req_cnt = 0; + spin_lock_bh(&ap_list_lock); + for_each_ap_queue(aq, ac) + req_cnt += aq->total_request_count; + spin_unlock_bh(&ap_list_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); +} + +static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); + +static ssize_t ap_requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + struct ap_queue *aq; + unsigned int reqq_cnt; + + reqq_cnt = 0; + spin_lock_bh(&ap_list_lock); + for_each_ap_queue(aq, ac) + reqq_cnt += aq->requestq_count; + spin_unlock_bh(&ap_list_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); +} + +static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); + +static ssize_t ap_pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_card *ac = to_ap_card(dev); + struct ap_queue *aq; + unsigned int penq_cnt; + + penq_cnt = 0; + spin_lock_bh(&ap_list_lock); + for_each_ap_queue(aq, ac) + penq_cnt += aq->pendingq_count; + spin_unlock_bh(&ap_list_lock); + return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); +} + +static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); + +static ssize_t ap_modalias_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "ap:t%02X\n", to_ap_dev(dev)->device_type); +} + +static DEVICE_ATTR(modalias, 0444, ap_modalias_show, NULL); + +static struct attribute *ap_card_dev_attrs[] = { + &dev_attr_hwtype.attr, + &dev_attr_raw_hwtype.attr, + &dev_attr_depth.attr, + &dev_attr_ap_functions.attr, + &dev_attr_request_count.attr, + &dev_attr_requestq_count.attr, + &dev_attr_pendingq_count.attr, + &dev_attr_modalias.attr, + NULL +}; + +static struct attribute_group ap_card_dev_attr_group = { + .attrs = ap_card_dev_attrs +}; + +static const struct attribute_group *ap_card_dev_attr_groups[] = { + &ap_card_dev_attr_group, + NULL +}; + +struct device_type ap_card_type = { + .name = "ap_card", + .groups = ap_card_dev_attr_groups, +}; + +static void ap_card_device_release(struct device *dev) +{ + kfree(to_ap_card(dev)); +} + +struct ap_card *ap_card_create(int id, int queue_depth, int device_type, + unsigned int functions) +{ + struct ap_card *ac; + + ac = kzalloc(sizeof(*ac), GFP_KERNEL); + if (!ac) + return NULL; + INIT_LIST_HEAD(&ac->queues); + ac->ap_dev.device.release = ap_card_device_release; + ac->ap_dev.device.type = &ap_card_type; + ac->ap_dev.device_type = device_type; + /* CEX6 toleration: map to CEX5 */ + if (device_type == AP_DEVICE_TYPE_CEX6) + ac->ap_dev.device_type = AP_DEVICE_TYPE_CEX5; + ac->raw_hwtype = device_type; + ac->queue_depth = queue_depth; + ac->functions = functions; + ac->id = id; + return ac; +} diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c new file mode 100644 index 000000000000..8f95a071b670 --- /dev/null +++ b/drivers/s390/crypto/ap_queue.c @@ -0,0 +1,700 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Martin Schwidefsky + * + * Adjunct processor bus, queue related code. + */ + +#define KMSG_COMPONENT "ap" +#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt + +#include +#include +#include + +#include "ap_bus.h" +#include "ap_asm.h" + +/** + * ap_queue_enable_interruption(): Enable interruption on an AP queue. + * @qid: The AP queue number + * @ind: the notification indicator byte + * + * Enables interruption on AP queue via ap_aqic(). Based on the return + * value it waits a while and tests the AP queue if interrupts + * have been switched on using ap_test_queue(). + */ +static int ap_queue_enable_interruption(struct ap_queue *aq, void *ind) +{ + struct ap_queue_status status; + + status = ap_aqic(aq->qid, ind); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + case AP_RESPONSE_OTHERWISE_CHANGED: + return 0; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + case AP_RESPONSE_INVALID_ADDRESS: + pr_err("Registering adapter interrupts for AP device %02x.%04x failed\n", + AP_QID_CARD(aq->qid), + AP_QID_QUEUE(aq->qid)); + return -EOPNOTSUPP; + case AP_RESPONSE_RESET_IN_PROGRESS: + case AP_RESPONSE_BUSY: + default: + return -EBUSY; + } +} + +/** + * __ap_send(): Send message to adjunct processor queue. + * @qid: The AP queue number + * @psmid: The program supplied message identifier + * @msg: The message text + * @length: The message length + * @special: Special Bit + * + * Returns AP queue status structure. + * Condition code 1 on NQAP can't happen because the L bit is 1. + * Condition code 2 on NQAP also means the send is incomplete, + * because a segment boundary was reached. The NQAP is repeated. + */ +static inline struct ap_queue_status +__ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length, + unsigned int special) +{ + if (special == 1) + qid |= 0x400000UL; + return ap_nqap(qid, psmid, msg, length); +} + +int ap_send(ap_qid_t qid, unsigned long long psmid, void *msg, size_t length) +{ + struct ap_queue_status status; + + status = __ap_send(qid, psmid, msg, length, 0); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + return 0; + case AP_RESPONSE_Q_FULL: + case AP_RESPONSE_RESET_IN_PROGRESS: + return -EBUSY; + case AP_RESPONSE_REQ_FAC_NOT_INST: + return -EINVAL; + default: /* Device is gone. */ + return -ENODEV; + } +} +EXPORT_SYMBOL(ap_send); + +int ap_recv(ap_qid_t qid, unsigned long long *psmid, void *msg, size_t length) +{ + struct ap_queue_status status; + + if (msg == NULL) + return -EINVAL; + status = ap_dqap(qid, psmid, msg, length); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + return 0; + case AP_RESPONSE_NO_PENDING_REPLY: + if (status.queue_empty) + return -ENOENT; + return -EBUSY; + case AP_RESPONSE_RESET_IN_PROGRESS: + return -EBUSY; + default: + return -ENODEV; + } +} +EXPORT_SYMBOL(ap_recv); + +/* State machine definitions and helpers */ + +static enum ap_wait ap_sm_nop(struct ap_queue *aq) +{ + return AP_WAIT_NONE; +} + +/** + * ap_sm_recv(): Receive pending reply messages from an AP queue but do + * not change the state of the device. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static struct ap_queue_status ap_sm_recv(struct ap_queue *aq) +{ + struct ap_queue_status status; + struct ap_message *ap_msg; + + status = ap_dqap(aq->qid, &aq->reply->psmid, + aq->reply->message, aq->reply->length); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + aq->queue_count--; + if (aq->queue_count > 0) + mod_timer(&aq->timeout, + jiffies + aq->request_timeout); + list_for_each_entry(ap_msg, &aq->pendingq, list) { + if (ap_msg->psmid != aq->reply->psmid) + continue; + list_del_init(&ap_msg->list); + aq->pendingq_count--; + ap_msg->receive(aq, ap_msg, aq->reply); + break; + } + case AP_RESPONSE_NO_PENDING_REPLY: + if (!status.queue_empty || aq->queue_count <= 0) + break; + /* The card shouldn't forget requests but who knows. */ + aq->queue_count = 0; + list_splice_init(&aq->pendingq, &aq->requestq); + aq->requestq_count += aq->pendingq_count; + aq->pendingq_count = 0; + break; + default: + break; + } + return status; +} + +/** + * ap_sm_read(): Receive pending reply messages from an AP queue. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static enum ap_wait ap_sm_read(struct ap_queue *aq) +{ + struct ap_queue_status status; + + if (!aq->reply) + return AP_WAIT_NONE; + status = ap_sm_recv(aq); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (aq->queue_count > 0) { + aq->state = AP_STATE_WORKING; + return AP_WAIT_AGAIN; + } + aq->state = AP_STATE_IDLE; + return AP_WAIT_NONE; + case AP_RESPONSE_NO_PENDING_REPLY: + if (aq->queue_count > 0) + return AP_WAIT_INTERRUPT; + aq->state = AP_STATE_IDLE; + return AP_WAIT_NONE; + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_suspend_read(): Receive pending reply messages from an AP queue + * without changing the device state in between. In suspend mode we don't + * allow sending new requests, therefore just fetch pending replies. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE or AP_WAIT_AGAIN + */ +static enum ap_wait ap_sm_suspend_read(struct ap_queue *aq) +{ + struct ap_queue_status status; + + if (!aq->reply) + return AP_WAIT_NONE; + status = ap_sm_recv(aq); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (aq->queue_count > 0) + return AP_WAIT_AGAIN; + /* fall through */ + default: + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_write(): Send messages from the request queue to an AP queue. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static enum ap_wait ap_sm_write(struct ap_queue *aq) +{ + struct ap_queue_status status; + struct ap_message *ap_msg; + + if (aq->requestq_count <= 0) + return AP_WAIT_NONE; + /* Start the next request on the queue. */ + ap_msg = list_entry(aq->requestq.next, struct ap_message, list); + status = __ap_send(aq->qid, ap_msg->psmid, + ap_msg->message, ap_msg->length, ap_msg->special); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + aq->queue_count++; + if (aq->queue_count == 1) + mod_timer(&aq->timeout, jiffies + aq->request_timeout); + list_move_tail(&ap_msg->list, &aq->pendingq); + aq->requestq_count--; + aq->pendingq_count++; + if (aq->queue_count < aq->card->queue_depth) { + aq->state = AP_STATE_WORKING; + return AP_WAIT_AGAIN; + } + /* fall through */ + case AP_RESPONSE_Q_FULL: + aq->state = AP_STATE_QUEUE_FULL; + return AP_WAIT_INTERRUPT; + case AP_RESPONSE_RESET_IN_PROGRESS: + aq->state = AP_STATE_RESET_WAIT; + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_MESSAGE_TOO_BIG: + case AP_RESPONSE_REQ_FAC_NOT_INST: + list_del_init(&ap_msg->list); + aq->requestq_count--; + ap_msg->rc = -EINVAL; + ap_msg->receive(aq, ap_msg, NULL); + return AP_WAIT_AGAIN; + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_read_write(): Send and receive messages to/from an AP queue. + * @aq: pointer to the AP queue + * + * Returns AP_WAIT_NONE, AP_WAIT_AGAIN, or AP_WAIT_INTERRUPT + */ +static enum ap_wait ap_sm_read_write(struct ap_queue *aq) +{ + return min(ap_sm_read(aq), ap_sm_write(aq)); +} + +/** + * ap_sm_reset(): Reset an AP queue. + * @qid: The AP queue number + * + * Submit the Reset command to an AP queue. + */ +static enum ap_wait ap_sm_reset(struct ap_queue *aq) +{ + struct ap_queue_status status; + + status = ap_rapq(aq->qid); + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + case AP_RESPONSE_RESET_IN_PROGRESS: + aq->state = AP_STATE_RESET_WAIT; + aq->interrupt = AP_INTR_DISABLED; + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_BUSY: + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_reset_wait(): Test queue for completion of the reset operation + * @aq: pointer to the AP queue + * + * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. + */ +static enum ap_wait ap_sm_reset_wait(struct ap_queue *aq) +{ + struct ap_queue_status status; + void *lsi_ptr; + + if (aq->queue_count > 0 && aq->reply) + /* Try to read a completed message and get the status */ + status = ap_sm_recv(aq); + else + /* Get the status with TAPQ */ + status = ap_tapq(aq->qid, NULL); + + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + lsi_ptr = ap_airq_ptr(); + if (lsi_ptr && ap_queue_enable_interruption(aq, lsi_ptr) == 0) + aq->state = AP_STATE_SETIRQ_WAIT; + else + aq->state = (aq->queue_count > 0) ? + AP_STATE_WORKING : AP_STATE_IDLE; + return AP_WAIT_AGAIN; + case AP_RESPONSE_BUSY: + case AP_RESPONSE_RESET_IN_PROGRESS: + return AP_WAIT_TIMEOUT; + case AP_RESPONSE_Q_NOT_AVAIL: + case AP_RESPONSE_DECONFIGURED: + case AP_RESPONSE_CHECKSTOPPED: + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/** + * ap_sm_setirq_wait(): Test queue for completion of the irq enablement + * @aq: pointer to the AP queue + * + * Returns AP_POLL_IMMEDIATELY, AP_POLL_AFTER_TIMEROUT or 0. + */ +static enum ap_wait ap_sm_setirq_wait(struct ap_queue *aq) +{ + struct ap_queue_status status; + + if (aq->queue_count > 0 && aq->reply) + /* Try to read a completed message and get the status */ + status = ap_sm_recv(aq); + else + /* Get the status with TAPQ */ + status = ap_tapq(aq->qid, NULL); + + if (status.int_enabled == 1) { + /* Irqs are now enabled */ + aq->interrupt = AP_INTR_ENABLED; + aq->state = (aq->queue_count > 0) ? + AP_STATE_WORKING : AP_STATE_IDLE; + } + + switch (status.response_code) { + case AP_RESPONSE_NORMAL: + if (aq->queue_count > 0) + return AP_WAIT_AGAIN; + /* fallthrough */ + case AP_RESPONSE_NO_PENDING_REPLY: + return AP_WAIT_TIMEOUT; + default: + aq->state = AP_STATE_BORKED; + return AP_WAIT_NONE; + } +} + +/* + * AP state machine jump table + */ +static ap_func_t *ap_jumptable[NR_AP_STATES][NR_AP_EVENTS] = { + [AP_STATE_RESET_START] = { + [AP_EVENT_POLL] = ap_sm_reset, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_RESET_WAIT] = { + [AP_EVENT_POLL] = ap_sm_reset_wait, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_SETIRQ_WAIT] = { + [AP_EVENT_POLL] = ap_sm_setirq_wait, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_IDLE] = { + [AP_EVENT_POLL] = ap_sm_write, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_WORKING] = { + [AP_EVENT_POLL] = ap_sm_read_write, + [AP_EVENT_TIMEOUT] = ap_sm_reset, + }, + [AP_STATE_QUEUE_FULL] = { + [AP_EVENT_POLL] = ap_sm_read, + [AP_EVENT_TIMEOUT] = ap_sm_reset, + }, + [AP_STATE_SUSPEND_WAIT] = { + [AP_EVENT_POLL] = ap_sm_suspend_read, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, + [AP_STATE_BORKED] = { + [AP_EVENT_POLL] = ap_sm_nop, + [AP_EVENT_TIMEOUT] = ap_sm_nop, + }, +}; + +enum ap_wait ap_sm_event(struct ap_queue *aq, enum ap_event event) +{ + return ap_jumptable[aq->state][event](aq); +} + +enum ap_wait ap_sm_event_loop(struct ap_queue *aq, enum ap_event event) +{ + enum ap_wait wait; + + while ((wait = ap_sm_event(aq, event)) == AP_WAIT_AGAIN) + ; + return wait; +} + +/* + * Power management for queue devices + */ +void ap_queue_suspend(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + + /* Poll on the device until all requests are finished. */ + spin_lock_bh(&aq->lock); + aq->state = AP_STATE_SUSPEND_WAIT; + while (ap_sm_event(aq, AP_EVENT_POLL) != AP_WAIT_NONE) + ; + aq->state = AP_STATE_BORKED; + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_queue_suspend); + +void ap_queue_resume(struct ap_device *ap_dev) +{ +} +EXPORT_SYMBOL(ap_queue_resume); + +/* + * AP queue related attributes. + */ +static ssize_t ap_request_count_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + unsigned int req_cnt; + + spin_lock_bh(&aq->lock); + req_cnt = aq->total_request_count; + spin_unlock_bh(&aq->lock); + return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); +} + +static DEVICE_ATTR(request_count, 0444, ap_request_count_show, NULL); + +static ssize_t ap_requestq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + unsigned int reqq_cnt = 0; + + spin_lock_bh(&aq->lock); + reqq_cnt = aq->requestq_count; + spin_unlock_bh(&aq->lock); + return snprintf(buf, PAGE_SIZE, "%d\n", reqq_cnt); +} + +static DEVICE_ATTR(requestq_count, 0444, ap_requestq_count_show, NULL); + +static ssize_t ap_pendingq_count_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + unsigned int penq_cnt = 0; + + spin_lock_bh(&aq->lock); + penq_cnt = aq->pendingq_count; + spin_unlock_bh(&aq->lock); + return snprintf(buf, PAGE_SIZE, "%d\n", penq_cnt); +} + +static DEVICE_ATTR(pendingq_count, 0444, ap_pendingq_count_show, NULL); + +static ssize_t ap_reset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + int rc = 0; + + spin_lock_bh(&aq->lock); + switch (aq->state) { + case AP_STATE_RESET_START: + case AP_STATE_RESET_WAIT: + rc = snprintf(buf, PAGE_SIZE, "Reset in progress.\n"); + break; + case AP_STATE_WORKING: + case AP_STATE_QUEUE_FULL: + rc = snprintf(buf, PAGE_SIZE, "Reset Timer armed.\n"); + break; + default: + rc = snprintf(buf, PAGE_SIZE, "No Reset Timer set.\n"); + } + spin_unlock_bh(&aq->lock); + return rc; +} + +static DEVICE_ATTR(reset, 0444, ap_reset_show, NULL); + +static ssize_t ap_interrupt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ap_queue *aq = to_ap_queue(dev); + int rc = 0; + + spin_lock_bh(&aq->lock); + if (aq->state == AP_STATE_SETIRQ_WAIT) + rc = snprintf(buf, PAGE_SIZE, "Enable Interrupt pending.\n"); + else if (aq->interrupt == AP_INTR_ENABLED) + rc = snprintf(buf, PAGE_SIZE, "Interrupts enabled.\n"); + else + rc = snprintf(buf, PAGE_SIZE, "Interrupts disabled.\n"); + spin_unlock_bh(&aq->lock); + return rc; +} + +static DEVICE_ATTR(interrupt, 0444, ap_interrupt_show, NULL); + +static struct attribute *ap_queue_dev_attrs[] = { + &dev_attr_request_count.attr, + &dev_attr_requestq_count.attr, + &dev_attr_pendingq_count.attr, + &dev_attr_reset.attr, + &dev_attr_interrupt.attr, + NULL +}; + +static struct attribute_group ap_queue_dev_attr_group = { + .attrs = ap_queue_dev_attrs +}; + +static const struct attribute_group *ap_queue_dev_attr_groups[] = { + &ap_queue_dev_attr_group, + NULL +}; + +struct device_type ap_queue_type = { + .name = "ap_queue", + .groups = ap_queue_dev_attr_groups, +}; + +static void ap_queue_device_release(struct device *dev) +{ + kfree(to_ap_queue(dev)); +} + +struct ap_queue *ap_queue_create(ap_qid_t qid, int device_type) +{ + struct ap_queue *aq; + + aq = kzalloc(sizeof(*aq), GFP_KERNEL); + if (!aq) + return NULL; + aq->ap_dev.device.release = ap_queue_device_release; + aq->ap_dev.device.type = &ap_queue_type; + aq->ap_dev.device_type = device_type; + /* CEX6 toleration: map to CEX5 */ + if (device_type == AP_DEVICE_TYPE_CEX6) + aq->ap_dev.device_type = AP_DEVICE_TYPE_CEX5; + aq->qid = qid; + aq->state = AP_STATE_RESET_START; + aq->interrupt = AP_INTR_DISABLED; + spin_lock_init(&aq->lock); + INIT_LIST_HEAD(&aq->pendingq); + INIT_LIST_HEAD(&aq->requestq); + setup_timer(&aq->timeout, ap_request_timeout, (unsigned long) aq); + + return aq; +} + +void ap_queue_init_reply(struct ap_queue *aq, struct ap_message *reply) +{ + aq->reply = reply; + + spin_lock_bh(&aq->lock); + ap_wait(ap_sm_event(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_queue_init_reply); + +/** + * ap_queue_message(): Queue a request to an AP device. + * @aq: The AP device to queue the message to + * @ap_msg: The message that is to be added + */ +void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg) +{ + /* For asynchronous message handling a valid receive-callback + * is required. + */ + BUG_ON(!ap_msg->receive); + + spin_lock_bh(&aq->lock); + /* Queue the message. */ + list_add_tail(&ap_msg->list, &aq->requestq); + aq->requestq_count++; + aq->total_request_count++; + /* Send/receive as many request from the queue as possible. */ + ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL)); + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_queue_message); + +/** + * ap_cancel_message(): Cancel a crypto request. + * @aq: The AP device that has the message queued + * @ap_msg: The message that is to be removed + * + * Cancel a crypto request. This is done by removing the request + * from the device pending or request queue. Note that the + * request stays on the AP queue. When it finishes the message + * reply will be discarded because the psmid can't be found. + */ +void ap_cancel_message(struct ap_queue *aq, struct ap_message *ap_msg) +{ + struct ap_message *tmp; + + spin_lock_bh(&aq->lock); + if (!list_empty(&ap_msg->list)) { + list_for_each_entry(tmp, &aq->pendingq, list) + if (tmp->psmid == ap_msg->psmid) { + aq->pendingq_count--; + goto found; + } + aq->requestq_count--; +found: + list_del_init(&ap_msg->list); + } + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_cancel_message); + +/** + * __ap_flush_queue(): Flush requests. + * @aq: Pointer to the AP queue + * + * Flush all requests from the request/pending queue of an AP device. + */ +static void __ap_flush_queue(struct ap_queue *aq) +{ + struct ap_message *ap_msg, *next; + + list_for_each_entry_safe(ap_msg, next, &aq->pendingq, list) { + list_del_init(&ap_msg->list); + aq->pendingq_count--; + ap_msg->rc = -EAGAIN; + ap_msg->receive(aq, ap_msg, NULL); + } + list_for_each_entry_safe(ap_msg, next, &aq->requestq, list) { + list_del_init(&ap_msg->list); + aq->requestq_count--; + ap_msg->rc = -EAGAIN; + ap_msg->receive(aq, ap_msg, NULL); + } +} + +void ap_flush_queue(struct ap_queue *aq) +{ + spin_lock_bh(&aq->lock); + __ap_flush_queue(aq); + spin_unlock_bh(&aq->lock); +} +EXPORT_SYMBOL(ap_flush_queue); + +void ap_queue_remove(struct ap_queue *aq) +{ + ap_flush_queue(aq); + del_timer_sync(&aq->timeout); +} +EXPORT_SYMBOL(ap_queue_remove); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 28913e540096..fd0ae8cd2bee 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -59,71 +59,22 @@ static int zcrypt_hwrng_seed = 1; module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on)."); -static DEFINE_SPINLOCK(zcrypt_device_lock); -static LIST_HEAD(zcrypt_device_list); -static int zcrypt_device_count = 0; +DEFINE_SPINLOCK(zcrypt_list_lock); +LIST_HEAD(zcrypt_card_list); +int zcrypt_device_count; + static atomic_t zcrypt_open_count = ATOMIC_INIT(0); static atomic_t zcrypt_rescan_count = ATOMIC_INIT(0); atomic_t zcrypt_rescan_req = ATOMIC_INIT(0); EXPORT_SYMBOL(zcrypt_rescan_req); -static int zcrypt_rng_device_add(void); -static void zcrypt_rng_device_remove(void); - static LIST_HEAD(zcrypt_ops_list); -static debug_info_t *zcrypt_dbf_common; -static debug_info_t *zcrypt_dbf_devices; static struct dentry *debugfs_root; - -/* - * Device attributes common for all crypto devices. - */ -static ssize_t zcrypt_type_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zcrypt_device *zdev = to_ap_dev(dev)->private; - return snprintf(buf, PAGE_SIZE, "%s\n", zdev->type_string); -} - -static DEVICE_ATTR(type, 0444, zcrypt_type_show, NULL); - -static ssize_t zcrypt_online_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct zcrypt_device *zdev = to_ap_dev(dev)->private; - return snprintf(buf, PAGE_SIZE, "%d\n", zdev->online); -} - -static ssize_t zcrypt_online_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct zcrypt_device *zdev = to_ap_dev(dev)->private; - int online; - - if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) - return -EINVAL; - zdev->online = online; - ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dman", zdev->ap_dev->qid, - zdev->online); - if (!online) - ap_flush_queue(zdev->ap_dev); - return count; -} - -static DEVICE_ATTR(online, 0644, zcrypt_online_show, zcrypt_online_store); - -static struct attribute * zcrypt_device_attrs[] = { - &dev_attr_type.attr, - &dev_attr_online.attr, - NULL, -}; - -static struct attribute_group zcrypt_device_attr_group = { - .attrs = zcrypt_device_attrs, -}; +debug_info_t *zcrypt_dbf_common; +debug_info_t *zcrypt_dbf_devices; +debug_info_t *zcrypt_dbf_cards; /** * Process a rescan of the transport layer. @@ -143,174 +94,6 @@ static inline int zcrypt_process_rescan(void) return 0; } -/** - * __zcrypt_increase_preference(): Increase preference of a crypto device. - * @zdev: Pointer the crypto device - * - * Move the device towards the head of the device list. - * Need to be called while holding the zcrypt device list lock. - * Note: cards with speed_rating of 0 are kept at the end of the list. - */ -static void __zcrypt_increase_preference(struct zcrypt_device *zdev, - unsigned int weight) -{ - struct zcrypt_device *tmp; - struct list_head *l; - - zdev->load -= weight; - for (l = zdev->list.prev; l != &zcrypt_device_list; l = l->prev) { - tmp = list_entry(l, struct zcrypt_device, list); - if (tmp->load <= zdev->load) - break; - } - if (l == zdev->list.prev) - return; - /* Move zdev behind l */ - list_move(&zdev->list, l); -} - -/** - * __zcrypt_decrease_preference(): Decrease preference of a crypto device. - * @zdev: Pointer to a crypto device. - * - * Move the device towards the tail of the device list. - * Need to be called while holding the zcrypt device list lock. - * Note: cards with speed_rating of 0 are kept at the end of the list. - */ -static void __zcrypt_decrease_preference(struct zcrypt_device *zdev, - unsigned int weight) -{ - struct zcrypt_device *tmp; - struct list_head *l; - - zdev->load += weight; - for (l = zdev->list.next; l != &zcrypt_device_list; l = l->next) { - tmp = list_entry(l, struct zcrypt_device, list); - if (tmp->load > zdev->load) - break; - } - if (l == zdev->list.next) - return; - /* Move zdev before l */ - list_move_tail(&zdev->list, l); -} - -static void zcrypt_device_release(struct kref *kref) -{ - struct zcrypt_device *zdev = - container_of(kref, struct zcrypt_device, refcount); - zcrypt_device_free(zdev); -} - -void zcrypt_device_get(struct zcrypt_device *zdev) -{ - kref_get(&zdev->refcount); -} -EXPORT_SYMBOL(zcrypt_device_get); - -int zcrypt_device_put(struct zcrypt_device *zdev) -{ - return kref_put(&zdev->refcount, zcrypt_device_release); -} -EXPORT_SYMBOL(zcrypt_device_put); - -struct zcrypt_device *zcrypt_device_alloc(size_t max_response_size) -{ - struct zcrypt_device *zdev; - - zdev = kzalloc(sizeof(struct zcrypt_device), GFP_KERNEL); - if (!zdev) - return NULL; - zdev->reply.message = kmalloc(max_response_size, GFP_KERNEL); - if (!zdev->reply.message) - goto out_free; - zdev->reply.length = max_response_size; - spin_lock_init(&zdev->lock); - INIT_LIST_HEAD(&zdev->list); - zdev->dbf_area = zcrypt_dbf_devices; - return zdev; - -out_free: - kfree(zdev); - return NULL; -} -EXPORT_SYMBOL(zcrypt_device_alloc); - -void zcrypt_device_free(struct zcrypt_device *zdev) -{ - kfree(zdev->reply.message); - kfree(zdev); -} -EXPORT_SYMBOL(zcrypt_device_free); - -/** - * zcrypt_device_register() - Register a crypto device. - * @zdev: Pointer to a crypto device - * - * Register a crypto device. Returns 0 if successful. - */ -int zcrypt_device_register(struct zcrypt_device *zdev) -{ - int rc; - - if (!zdev->ops) - return -ENODEV; - rc = sysfs_create_group(&zdev->ap_dev->device.kobj, - &zcrypt_device_attr_group); - if (rc) - goto out; - get_device(&zdev->ap_dev->device); - kref_init(&zdev->refcount); - spin_lock_bh(&zcrypt_device_lock); - zdev->online = 1; /* New devices are online by default. */ - ZCRYPT_DBF_DEV(DBF_INFO, zdev, "dev%04xo%dreg", zdev->ap_dev->qid, - zdev->online); - list_add_tail(&zdev->list, &zcrypt_device_list); - __zcrypt_increase_preference(zdev, 0); /* sort devices acc. weight */ - zcrypt_device_count++; - spin_unlock_bh(&zcrypt_device_lock); - if (zdev->ops->rng) { - rc = zcrypt_rng_device_add(); - if (rc) - goto out_unregister; - } - return 0; - -out_unregister: - spin_lock_bh(&zcrypt_device_lock); - zcrypt_device_count--; - list_del_init(&zdev->list); - spin_unlock_bh(&zcrypt_device_lock); - sysfs_remove_group(&zdev->ap_dev->device.kobj, - &zcrypt_device_attr_group); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); -out: - return rc; -} -EXPORT_SYMBOL(zcrypt_device_register); - -/** - * zcrypt_device_unregister(): Unregister a crypto device. - * @zdev: Pointer to crypto device - * - * Unregister a crypto device. - */ -void zcrypt_device_unregister(struct zcrypt_device *zdev) -{ - if (zdev->ops->rng) - zcrypt_rng_device_remove(); - spin_lock_bh(&zcrypt_device_lock); - zcrypt_device_count--; - list_del_init(&zdev->list); - spin_unlock_bh(&zcrypt_device_lock); - sysfs_remove_group(&zdev->ap_dev->device.kobj, - &zcrypt_device_attr_group); - put_device(&zdev->ap_dev->device); - zcrypt_device_put(zdev); -} -EXPORT_SYMBOL(zcrypt_device_unregister); - void zcrypt_msgtype_register(struct zcrypt_ops *zops) { list_add_tail(&zops->list, &zcrypt_ops_list); @@ -377,14 +160,44 @@ static int zcrypt_release(struct inode *inode, struct file *filp) return 0; } +static inline struct zcrypt_queue *zcrypt_pick_queue(struct zcrypt_card *zc, + struct zcrypt_queue *zq, + unsigned int weight) +{ + if (!zq || !try_module_get(zq->queue->ap_dev.drv->driver.owner)) + return NULL; + zcrypt_queue_get(zq); + get_device(&zq->queue->ap_dev.device); + atomic_add(weight, &zc->load); + atomic_add(weight, &zq->load); + zq->request_count++; + return zq; +} + +static inline void zcrypt_drop_queue(struct zcrypt_card *zc, + struct zcrypt_queue *zq, + unsigned int weight) +{ + struct module *mod = zq->queue->ap_dev.drv->driver.owner; + + zq->request_count--; + atomic_sub(weight, &zc->load); + atomic_sub(weight, &zq->load); + put_device(&zq->queue->ap_dev.device); + zcrypt_queue_put(zq); + module_put(mod); +} + /* * zcrypt ioctls. */ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) { - struct zcrypt_device *zdev, *pref_zdev = NULL; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + unsigned int weight, pref_weight; + unsigned int func_code; int rc; - unsigned int weight, func_code, pref_weight = 0; if (mex->outputdatalength < mex->inputdatalength) return -EINVAL; @@ -399,59 +212,56 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) if (rc) return rc; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - if (!zdev->online || - !zdev->ops->rsa_modexpo || - zdev->min_mod_size > mex->inputdatalength || - zdev->max_mod_size < mex->inputdatalength) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online accelarator and CCA cards */ + if (!zc->online || !(zc->card->functions & 0x18000000)) continue; - weight = zdev->speed_rating[func_code]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* Check for size limits */ + if (zc->min_mod_size > mex->inputdatalength || + zc->max_mod_size < mex->inputdatalength) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = zc->speed_rating[func_code]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; + pref_weight = weight; } - if ((pref_zdev->load + pref_weight) <= zdev->load) - break; /* Load on remaining devices too high - abort */ } + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); - if (!pref_zdev) { - spin_unlock_bh(&zcrypt_device_lock); + if (!pref_zq) return -ENODEV; - } - __zcrypt_decrease_preference(pref_zdev, pref_weight); - zcrypt_device_get(pref_zdev); - get_device(&pref_zdev->ap_dev->device); - pref_zdev->request_count++; - if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = -ENODEV; - rc = pref_zdev->ops->rsa_modexpo(pref_zdev, mex); - spin_lock_bh(&zcrypt_device_lock); - module_put(pref_zdev->ap_dev->drv->driver.owner); - } else - rc = -EAGAIN; - pref_zdev->request_count--; - __zcrypt_increase_preference(pref_zdev, pref_weight); - put_device(&pref_zdev->ap_dev->device); - zcrypt_device_put(pref_zdev); - spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zq->ops->rsa_modexpo(pref_zq, mex); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + return rc; } static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) { - struct zcrypt_device *zdev, *pref_zdev = NULL; - unsigned long long z1, z2, z3; - int rc, copied; - unsigned int weight, func_code, pref_weight = 0; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + unsigned int weight, pref_weight; + unsigned int func_code; + int rc; if (crt->outputdatalength < crt->inputdatalength) return -EINVAL; @@ -466,385 +276,388 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) if (rc) return rc; - copied = 0; - restart: - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - if (!zdev->online || - !zdev->ops->rsa_modexpo_crt || - zdev->min_mod_size > crt->inputdatalength || - zdev->max_mod_size < crt->inputdatalength) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online accelarator and CCA cards */ + if (!zc->online || !(zc->card->functions & 0x18000000)) continue; - if (zdev->short_crt && crt->inputdatalength > 240) { - /* - * Check inputdata for leading zeros for cards - * that can't handle np_prime, bp_key, or - * u_mult_inv > 128 bytes. - */ - if (copied == 0) { - unsigned int len; - spin_unlock_bh(&zcrypt_device_lock); - /* len is max 256 / 2 - 120 = 8 - * For bigger device just assume len of leading - * 0s is 8 as stated in the requirements for - * ica_rsa_modexpo_crt struct in zcrypt.h. - */ - if (crt->inputdatalength <= 256) - len = crt->inputdatalength / 2 - 120; - else - len = 8; - if (len > sizeof(z1)) - return -EFAULT; - z1 = z2 = z3 = 0; - if (copy_from_user(&z1, crt->np_prime, len) || - copy_from_user(&z2, crt->bp_key, len) || - copy_from_user(&z3, crt->u_mult_inv, len)) - return -EFAULT; - z1 = z2 = z3 = 0; - copied = 1; - /* - * We have to restart device lookup - - * the device list may have changed by now. - */ - goto restart; - } - if (z1 != 0ULL || z2 != 0ULL || z3 != 0ULL) - /* The device can't handle this request. */ - continue; - } - - weight = zdev->speed_rating[func_code]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* Check for size limits */ + if (zc->min_mod_size > crt->inputdatalength || + zc->max_mod_size < crt->inputdatalength) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = zc->speed_rating[func_code]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; + pref_weight = weight; } - if ((pref_zdev->load + pref_weight) <= zdev->load) - break; /* Load on remaining devices too high - abort */ } - if (!pref_zdev) { - spin_unlock_bh(&zcrypt_device_lock); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + + if (!pref_zq) return -ENODEV; - } - __zcrypt_decrease_preference(pref_zdev, pref_weight); - zcrypt_device_get(pref_zdev); - get_device(&pref_zdev->ap_dev->device); - pref_zdev->request_count++; - if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = pref_zdev->ops->rsa_modexpo_crt(pref_zdev, crt); - spin_lock_bh(&zcrypt_device_lock); - module_put(pref_zdev->ap_dev->drv->driver.owner); - } else - rc = -EAGAIN; - pref_zdev->request_count--; - __zcrypt_increase_preference(pref_zdev, pref_weight); - put_device(&pref_zdev->ap_dev->device); - zcrypt_device_put(pref_zdev); - spin_unlock_bh(&zcrypt_device_lock); + + rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + return rc; } static long zcrypt_send_cprb(struct ica_xcRB *xcRB) { - struct zcrypt_device *zdev, *pref_zdev = NULL; - unsigned int weight = 0, func_code = 0, pref_weight = 0; - int rc; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; struct ap_message ap_msg; + unsigned int weight, pref_weight; + unsigned int func_code; + unsigned short *domain; + int rc; - rc = get_cprb_fc(xcRB, &ap_msg, &func_code); + rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); if (rc) return rc; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - if (!zdev->online || !zdev->ops->send_cprb || - (zdev->ops->variant == MSGTYPE06_VARIANT_EP11) || - (xcRB->user_defined != AUTOSELECT && - AP_QID_DEVICE(zdev->ap_dev->qid) != xcRB->user_defined)) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online CCA cards */ + if (!zc->online || !(zc->card->functions & 0x10000000)) continue; - - weight = speed_idx_cca(func_code) * zdev->speed_rating[SECKEY]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* Check for user selected CCA card */ + if (xcRB->user_defined != AUTOSELECT && + xcRB->user_defined != zc->card->id) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online || + ((*domain != (unsigned short) AUTOSELECT) && + (*domain != AP_QID_QUEUE(zq->queue->qid)))) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; + pref_weight = weight; } - if ((pref_zdev->load + pref_weight) <= zdev->load) - break; /* Load on remaining devices too high - abort */ } - if (!pref_zdev) { - spin_unlock_bh(&zcrypt_device_lock); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + + if (!pref_zq) return -ENODEV; - } - __zcrypt_decrease_preference(pref_zdev, pref_weight); - zcrypt_device_get(pref_zdev); - get_device(&pref_zdev->ap_dev->device); - pref_zdev->request_count++; - if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = pref_zdev->ops->send_cprb(pref_zdev, xcRB, &ap_msg); - spin_lock_bh(&zcrypt_device_lock); - module_put(pref_zdev->ap_dev->drv->driver.owner); - } else - rc = -EAGAIN; - pref_zdev->request_count--; - __zcrypt_increase_preference(pref_zdev, pref_weight); - put_device(&pref_zdev->ap_dev->device); - zcrypt_device_put(pref_zdev); - spin_unlock_bh(&zcrypt_device_lock); + + /* in case of auto select, provide the correct domain */ + if (*domain == (unsigned short) AUTOSELECT) + *domain = AP_QID_QUEUE(pref_zq->queue->qid); + + rc = pref_zq->ops->send_cprb(pref_zq, xcRB, &ap_msg); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); return rc; } -struct ep11_target_dev_list { - unsigned short targets_num; - struct ep11_target_dev *targets; -}; - -static bool is_desired_ep11dev(unsigned int dev_qid, - struct ep11_target_dev_list dev_list) +static bool is_desired_ep11_card(unsigned int dev_id, + unsigned short target_num, + struct ep11_target_dev *targets) { - int n; + while (target_num-- > 0) { + if (dev_id == targets->ap_id) + return true; + targets++; + } + return false; +} - for (n = 0; n < dev_list.targets_num; n++, dev_list.targets++) { - if ((AP_QID_DEVICE(dev_qid) == dev_list.targets->ap_id) && - (AP_QID_QUEUE(dev_qid) == dev_list.targets->dom_id)) { +static bool is_desired_ep11_queue(unsigned int dev_qid, + unsigned short target_num, + struct ep11_target_dev *targets) +{ + while (target_num-- > 0) { + if (AP_MKQID(targets->ap_id, targets->dom_id) == dev_qid) return true; - } + targets++; } return false; } static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) { - struct zcrypt_device *zdev, *pref_zdev = NULL; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + struct ep11_target_dev *targets; + unsigned short target_num; + unsigned int weight, pref_weight; + unsigned int func_code; struct ap_message ap_msg; - unsigned int weight = 0, func_code = 0, pref_weight = 0; - bool autoselect = false; int rc; - struct ep11_target_dev_list ep11_dev_list = { - .targets_num = 0x00, - .targets = NULL, - }; - ep11_dev_list.targets_num = (unsigned short) xcrb->targets_num; + target_num = (unsigned short) xcrb->targets_num; /* empty list indicates autoselect (all available targets) */ - if (ep11_dev_list.targets_num == 0) - autoselect = true; - else { - ep11_dev_list.targets = kcalloc((unsigned short) - xcrb->targets_num, - sizeof(struct ep11_target_dev), - GFP_KERNEL); - if (!ep11_dev_list.targets) + targets = NULL; + if (target_num != 0) { + struct ep11_target_dev __user *uptr; + + targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL); + if (!targets) return -ENOMEM; - if (copy_from_user(ep11_dev_list.targets, - (struct ep11_target_dev __force __user *) - xcrb->targets, xcrb->targets_num * - sizeof(struct ep11_target_dev))) + uptr = (struct ep11_target_dev __force __user *) xcrb->targets; + if (copy_from_user(targets, uptr, + target_num * sizeof(*targets))) return -EFAULT; } rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); if (rc) - return rc; + goto out_free; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - /* check if device is eligible */ - if (!zdev->online || - zdev->ops->variant != MSGTYPE06_VARIANT_EP11) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online EP11 cards */ + if (!zc->online || !(zc->card->functions & 0x04000000)) continue; - - /* check if device is selected as valid target */ - if (!is_desired_ep11dev(zdev->ap_dev->qid, ep11_dev_list) && - !autoselect) + /* Check for user selected EP11 card */ + if (targets && + !is_desired_ep11_card(zc->card->id, target_num, targets)) continue; - - weight = speed_idx_ep11(func_code) * zdev->speed_rating[SECKEY]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online || + (targets && + !is_desired_ep11_queue(zq->queue->qid, + target_num, targets))) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; pref_weight = weight; - continue; } - if ((pref_zdev->load + pref_weight) <= zdev->load) - break; /* Load on remaining devices too high - abort */ - } - if (!pref_zdev) { - spin_unlock_bh(&zcrypt_device_lock); - return -ENODEV; } + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); - zcrypt_device_get(pref_zdev); - get_device(&pref_zdev->ap_dev->device); - pref_zdev->request_count++; - if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = pref_zdev->ops->send_ep11_cprb(pref_zdev, xcrb, &ap_msg); - spin_lock_bh(&zcrypt_device_lock); - module_put(pref_zdev->ap_dev->drv->driver.owner); - } else { - rc = -EAGAIN; + if (!pref_zq) { + rc = -ENODEV; + goto out_free; } - pref_zdev->request_count--; - put_device(&pref_zdev->ap_dev->device); - zcrypt_device_put(pref_zdev); - spin_unlock_bh(&zcrypt_device_lock); + + rc = pref_zq->ops->send_ep11_cprb(pref_zq, xcrb, &ap_msg); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + +out_free: + kfree(targets); return rc; } static long zcrypt_rng(char *buffer) { - struct zcrypt_device *zdev, *pref_zdev = NULL; + struct zcrypt_card *zc, *pref_zc; + struct zcrypt_queue *zq, *pref_zq; + unsigned int weight, pref_weight; + unsigned int func_code; struct ap_message ap_msg; - unsigned int weight = 0, func_code = 0, pref_weight = 0; + unsigned int domain; int rc; - rc = get_rng_fc(&ap_msg, &func_code); + rc = get_rng_fc(&ap_msg, &func_code, &domain); if (rc) return rc; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - if (!zdev->online || !zdev->ops->rng) + pref_zc = NULL; + pref_zq = NULL; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + /* Check for online CCA cards */ + if (!zc->online || !(zc->card->functions & 0x10000000)) continue; - - weight = zdev->speed_rating[func_code]; - if (!pref_zdev) { - pref_zdev = zdev; - pref_weight = weight; + /* get weight index of the card device */ + weight = zc->speed_rating[func_code]; + if (pref_zc && atomic_read(&zc->load) + weight >= + atomic_read(&pref_zc->load) + pref_weight) continue; - } - if ((pref_zdev->load + pref_weight) > (zdev->load + weight)) { - pref_zdev = zdev; + for_each_zcrypt_queue(zq, zc) { + /* check if device is online and eligible */ + if (!zq->online) + continue; + if (pref_zq && atomic_read(&zq->load) + weight >= + atomic_read(&pref_zq->load) + pref_weight) + continue; + pref_zc = zc; + pref_zq = zq; pref_weight = weight; - continue; } - if ((pref_zdev->load + pref_weight) <= zdev->load) - break; /* Load on remaining devices too high - abort */ } - if (!pref_zdev) { - spin_unlock_bh(&zcrypt_device_lock); + pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); + + if (!pref_zq) return -ENODEV; - } - zcrypt_device_get(pref_zdev); - get_device(&pref_zdev->ap_dev->device); - pref_zdev->request_count++; - if (try_module_get(pref_zdev->ap_dev->drv->driver.owner)) { - spin_unlock_bh(&zcrypt_device_lock); - rc = pref_zdev->ops->rng(pref_zdev, buffer, &ap_msg); - spin_lock_bh(&zcrypt_device_lock); - module_put(pref_zdev->ap_dev->drv->driver.owner); - } else - rc = -EAGAIN; - pref_zdev->request_count--; - put_device(&pref_zdev->ap_dev->device); - zcrypt_device_put(pref_zdev); - spin_unlock_bh(&zcrypt_device_lock); + rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); + + spin_lock(&zcrypt_list_lock); + zcrypt_drop_queue(pref_zc, pref_zq, weight); + spin_unlock(&zcrypt_list_lock); return rc; } static void zcrypt_status_mask(char status[AP_DEVICES]) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; memset(status, 0, sizeof(char) * AP_DEVICES); - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - status[AP_QID_DEVICE(zdev->ap_dev->qid)] = - zdev->online ? zdev->user_space_type : 0x0d; - spin_unlock_bh(&zcrypt_device_lock); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + status[AP_QID_CARD(zq->queue->qid)] = + zc->online ? zc->user_space_type : 0x0d; + } + } + spin_unlock(&zcrypt_list_lock); } static void zcrypt_qdepth_mask(char qdepth[AP_DEVICES]) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; memset(qdepth, 0, sizeof(char) * AP_DEVICES); - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - qdepth[AP_QID_DEVICE(zdev->ap_dev->qid)] = - zdev->ap_dev->pendingq_count + - zdev->ap_dev->requestq_count; - spin_unlock(&zdev->ap_dev->lock); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + qdepth[AP_QID_CARD(zq->queue->qid)] = + zq->queue->pendingq_count + + zq->queue->requestq_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); } static void zcrypt_perdev_reqcnt(int reqcnt[AP_DEVICES]) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; memset(reqcnt, 0, sizeof(int) * AP_DEVICES); - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - reqcnt[AP_QID_DEVICE(zdev->ap_dev->qid)] = - zdev->ap_dev->total_request_count; - spin_unlock(&zdev->ap_dev->lock); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + reqcnt[AP_QID_CARD(zq->queue->qid)] = + zq->queue->total_request_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); } static int zcrypt_pendingq_count(void) { - struct zcrypt_device *zdev; - int pendingq_count = 0; - - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - pendingq_count += zdev->ap_dev->pendingq_count; - spin_unlock(&zdev->ap_dev->lock); + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + int pendingq_count; + + pendingq_count = 0; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + pendingq_count += zq->queue->pendingq_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); return pendingq_count; } static int zcrypt_requestq_count(void) { - struct zcrypt_device *zdev; - int requestq_count = 0; - - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) { - spin_lock(&zdev->ap_dev->lock); - requestq_count += zdev->ap_dev->requestq_count; - spin_unlock(&zdev->ap_dev->lock); + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + int requestq_count; + + requestq_count = 0; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + spin_lock(&zq->queue->lock); + requestq_count += zq->queue->requestq_count; + spin_unlock(&zq->queue->lock); + } } - spin_unlock_bh(&zcrypt_device_lock); + spin_unlock(&zcrypt_list_lock); return requestq_count; } static int zcrypt_count_type(int type) { - struct zcrypt_device *zdev; - int device_count = 0; - - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - if (zdev->user_space_type == type) + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + int device_count; + + device_count = 0; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + if (zc->card->id != type) + continue; + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; device_count++; - spin_unlock_bh(&zcrypt_device_lock); + } + } + spin_unlock(&zcrypt_list_lock); return device_count; } @@ -1313,29 +1126,36 @@ static int zcrypt_proc_open(struct inode *inode, struct file *file) static void zcrypt_disable_card(int index) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { - zdev->online = 0; - ap_flush_queue(zdev->ap_dev); - break; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + zq->online = 0; + ap_flush_queue(zq->queue); } - spin_unlock_bh(&zcrypt_device_lock); + } + spin_unlock(&zcrypt_list_lock); } static void zcrypt_enable_card(int index) { - struct zcrypt_device *zdev; + struct zcrypt_card *zc; + struct zcrypt_queue *zq; - spin_lock_bh(&zcrypt_device_lock); - list_for_each_entry(zdev, &zcrypt_device_list, list) - if (AP_QID_DEVICE(zdev->ap_dev->qid) == index) { - zdev->online = 1; - break; + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + if (AP_QID_QUEUE(zq->queue->qid) != ap_domain_index) + continue; + zq->online = 1; + ap_flush_queue(zq->queue); } - spin_unlock_bh(&zcrypt_device_lock); + } + spin_unlock(&zcrypt_list_lock); } static ssize_t zcrypt_proc_write(struct file *file, const char __user *buffer, @@ -1433,7 +1253,7 @@ static struct hwrng zcrypt_rng_dev = { .quality = 990, }; -static int zcrypt_rng_device_add(void) +int zcrypt_rng_device_add(void) { int rc = 0; @@ -1463,7 +1283,7 @@ out: return rc; } -static void zcrypt_rng_device_remove(void) +void zcrypt_rng_device_remove(void) { mutex_lock(&zcrypt_rng_mutex); zcrypt_rng_device_count--; @@ -1486,6 +1306,10 @@ int __init zcrypt_debug_init(void) debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view); debug_set_level(zcrypt_dbf_devices, DBF_ERR); + zcrypt_dbf_cards = debug_register("zcrypt_cards", 1, 1, 16); + debug_register_view(zcrypt_dbf_cards, &debug_hex_ascii_view); + debug_set_level(zcrypt_dbf_cards, DBF_ERR); + return 0; } @@ -1517,7 +1341,8 @@ int __init zcrypt_api_init(void) goto out; /* Set up the proc file system */ - zcrypt_entry = proc_create("driver/z90crypt", 0644, NULL, &zcrypt_proc_fops); + zcrypt_entry = proc_create("driver/z90crypt", 0644, NULL, + &zcrypt_proc_fops); if (!zcrypt_entry) { rc = -ENOMEM; goto out_misc; diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 3d0d1e25d751..4fb892b99f41 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -88,7 +88,7 @@ struct ica_z90_status { * Identifier for Crypto Request Performance Index */ enum crypto_ops { - MEX_1K = 0, + MEX_1K, MEX_2K, MEX_4K, CRT_1K, @@ -99,43 +99,56 @@ enum crypto_ops { NUM_OPS }; -struct zcrypt_device; +struct zcrypt_queue; struct zcrypt_ops { - long (*rsa_modexpo)(struct zcrypt_device *, struct ica_rsa_modexpo *); - long (*rsa_modexpo_crt)(struct zcrypt_device *, + long (*rsa_modexpo)(struct zcrypt_queue *, struct ica_rsa_modexpo *); + long (*rsa_modexpo_crt)(struct zcrypt_queue *, struct ica_rsa_modexpo_crt *); - long (*send_cprb)(struct zcrypt_device *, struct ica_xcRB *, + long (*send_cprb)(struct zcrypt_queue *, struct ica_xcRB *, struct ap_message *); - long (*send_ep11_cprb)(struct zcrypt_device *, struct ep11_urb *, + long (*send_ep11_cprb)(struct zcrypt_queue *, struct ep11_urb *, struct ap_message *); - long (*rng)(struct zcrypt_device *, char *, struct ap_message *); + long (*rng)(struct zcrypt_queue *, char *, struct ap_message *); struct list_head list; /* zcrypt ops list. */ struct module *owner; int variant; char name[128]; }; -struct zcrypt_device { +struct zcrypt_card { struct list_head list; /* Device list. */ - spinlock_t lock; /* Per device lock. */ + struct list_head zqueues; /* List of zcrypt queues */ struct kref refcount; /* device refcounting */ - struct ap_device *ap_dev; /* The "real" ap device. */ - struct zcrypt_ops *ops; /* Crypto operations. */ + struct ap_card *card; /* The "real" ap card device. */ int online; /* User online/offline */ int user_space_type; /* User space device id. */ char *type_string; /* User space device name. */ int min_mod_size; /* Min number of bits. */ int max_mod_size; /* Max number of bits. */ - int short_crt; /* Card has crt length restriction. */ + int max_exp_bit_length; int speed_rating[NUM_OPS]; /* Speed idx of crypto ops. */ - int load; /* Utilization of the crypto device */ + atomic_t load; /* Utilization of the crypto device */ + + int request_count; /* # current requests. */ + + debug_info_t *dbf_area; /* debugging */ +}; + +struct zcrypt_queue { + struct list_head list; /* Device list. */ + struct kref refcount; /* device refcounting */ + struct zcrypt_card *zcard; + struct zcrypt_ops *ops; /* Crypto operations. */ + struct ap_queue *queue; /* The "real" ap queue device. */ + int online; /* User online/offline */ + + atomic_t load; /* Utilization of the crypto device */ int request_count; /* # current requests. */ struct ap_message reply; /* Per-device reply structure. */ - int max_exp_bit_length; debug_info_t *dbf_area; /* debugging */ }; @@ -143,12 +156,43 @@ struct zcrypt_device { /* transport layer rescanning */ extern atomic_t zcrypt_rescan_req; -struct zcrypt_device *zcrypt_device_alloc(size_t); -void zcrypt_device_free(struct zcrypt_device *); -void zcrypt_device_get(struct zcrypt_device *); -int zcrypt_device_put(struct zcrypt_device *); -int zcrypt_device_register(struct zcrypt_device *); -void zcrypt_device_unregister(struct zcrypt_device *); +extern spinlock_t zcrypt_list_lock; +extern int zcrypt_device_count; +extern struct list_head zcrypt_card_list; + +extern debug_info_t *zcrypt_dbf_common; +extern debug_info_t *zcrypt_dbf_devices; +extern debug_info_t *zcrypt_dbf_cards; + +#define for_each_zcrypt_card(_zc) \ + list_for_each_entry(_zc, &zcrypt_card_list, list) + +#define for_each_zcrypt_queue(_zq, _zc) \ + list_for_each_entry(_zq, &(_zc)->zqueues, list) + +struct zcrypt_card *zcrypt_card_alloc(void); +void zcrypt_card_free(struct zcrypt_card *); +void zcrypt_card_get(struct zcrypt_card *); +int zcrypt_card_put(struct zcrypt_card *); +int zcrypt_card_register(struct zcrypt_card *); +void zcrypt_card_unregister(struct zcrypt_card *); +struct zcrypt_card *zcrypt_card_get_best(unsigned int *, + unsigned int, unsigned int); +void zcrypt_card_put_best(struct zcrypt_card *, unsigned int); + +struct zcrypt_queue *zcrypt_queue_alloc(size_t); +void zcrypt_queue_free(struct zcrypt_queue *); +void zcrypt_queue_get(struct zcrypt_queue *); +int zcrypt_queue_put(struct zcrypt_queue *); +int zcrypt_queue_register(struct zcrypt_queue *); +void zcrypt_queue_unregister(struct zcrypt_queue *); +void zcrypt_queue_force_online(struct zcrypt_queue *, int); +struct zcrypt_queue *zcrypt_queue_get_best(unsigned int, unsigned int); +void zcrypt_queue_put_best(struct zcrypt_queue *, unsigned int); + +int zcrypt_rng_device_add(void); +void zcrypt_rng_device_remove(void); + void zcrypt_msgtype_register(struct zcrypt_ops *); void zcrypt_msgtype_unregister(struct zcrypt_ops *); struct zcrypt_ops *zcrypt_msgtype(unsigned char *, int); diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c new file mode 100644 index 000000000000..57873d775e95 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_card.c @@ -0,0 +1,181 @@ +/* + * zcrypt 2.1.0 + * + * Copyright IBM Corp. 2001, 2012 + * Author(s): Robert Burroughs + * Eric Rossman (edrossma@us.ibm.com) + * Cornelia Huck + * + * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) + * Major cleanup & driver split: Martin Schwidefsky + * Ralph Wuerthner + * MSGTYPE restruct: Holger Dengler + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zcrypt_debug.h" +#include "zcrypt_api.h" + +#include "zcrypt_msgtype6.h" +#include "zcrypt_msgtype50.h" + +/* + * Device attributes common for all crypto card devices. + */ + +static ssize_t zcrypt_card_type_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct zcrypt_card *zc = to_ap_card(dev)->private; + + return snprintf(buf, PAGE_SIZE, "%s\n", zc->type_string); +} + +static DEVICE_ATTR(type, 0444, zcrypt_card_type_show, NULL); + +static ssize_t zcrypt_card_online_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zcrypt_card *zc = to_ap_card(dev)->private; + + return snprintf(buf, PAGE_SIZE, "%d\n", zc->online); +} + +static ssize_t zcrypt_card_online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zcrypt_card *zc = to_ap_card(dev)->private; + struct zcrypt_queue *zq; + int online, id; + + if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) + return -EINVAL; + + zc->online = online; + id = zc->card->id; + ZCRYPT_DBF_DEV(DBF_INFO, zc, "card%02xo%dman", id, online); + spin_lock(&zcrypt_list_lock); + list_for_each_entry(zq, &zc->zqueues, list) + zcrypt_queue_force_online(zq, online); + spin_unlock(&zcrypt_list_lock); + return count; +} + +static DEVICE_ATTR(online, 0644, zcrypt_card_online_show, + zcrypt_card_online_store); + +static struct attribute *zcrypt_card_attrs[] = { + &dev_attr_type.attr, + &dev_attr_online.attr, + NULL, +}; + +static struct attribute_group zcrypt_card_attr_group = { + .attrs = zcrypt_card_attrs, +}; + +struct zcrypt_card *zcrypt_card_alloc(void) +{ + struct zcrypt_card *zc; + + zc = kzalloc(sizeof(struct zcrypt_card), GFP_KERNEL); + if (!zc) + return NULL; + INIT_LIST_HEAD(&zc->list); + INIT_LIST_HEAD(&zc->zqueues); + zc->dbf_area = zcrypt_dbf_cards; + kref_init(&zc->refcount); + return zc; +} +EXPORT_SYMBOL(zcrypt_card_alloc); + +void zcrypt_card_free(struct zcrypt_card *zc) +{ + kfree(zc); +} +EXPORT_SYMBOL(zcrypt_card_free); + +static void zcrypt_card_release(struct kref *kref) +{ + struct zcrypt_card *zdev = + container_of(kref, struct zcrypt_card, refcount); + zcrypt_card_free(zdev); +} + +void zcrypt_card_get(struct zcrypt_card *zc) +{ + kref_get(&zc->refcount); +} +EXPORT_SYMBOL(zcrypt_card_get); + +int zcrypt_card_put(struct zcrypt_card *zc) +{ + return kref_put(&zc->refcount, zcrypt_card_release); +} +EXPORT_SYMBOL(zcrypt_card_put); + +/** + * zcrypt_card_register() - Register a crypto card device. + * @zc: Pointer to a crypto card device + * + * Register a crypto card device. Returns 0 if successful. + */ +int zcrypt_card_register(struct zcrypt_card *zc) +{ + int rc; + + rc = sysfs_create_group(&zc->card->ap_dev.device.kobj, + &zcrypt_card_attr_group); + if (rc) + return rc; + + spin_lock(&zcrypt_list_lock); + list_add_tail(&zc->list, &zcrypt_card_list); + spin_unlock(&zcrypt_list_lock); + + zc->online = 1; + return rc; +} +EXPORT_SYMBOL(zcrypt_card_register); + +/** + * zcrypt_card_unregister(): Unregister a crypto card device. + * @zc: Pointer to crypto card device + * + * Unregister a crypto card device. + */ +void zcrypt_card_unregister(struct zcrypt_card *zc) +{ + spin_lock(&zcrypt_list_lock); + list_del_init(&zc->list); + spin_unlock(&zcrypt_list_lock); + sysfs_remove_group(&zc->card->ap_dev.device.kobj, + &zcrypt_card_attr_group); +} +EXPORT_SYMBOL(zcrypt_card_unregister); diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index 4bb13eadd0f1..c7d48a18199e 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -31,6 +31,7 @@ #include #include #include +#include #include "ap_bus.h" #include "zcrypt_api.h" @@ -54,108 +55,195 @@ #define CEX2A_CLEANUP_TIME (15*HZ) #define CEX3A_CLEANUP_TIME CEX2A_CLEANUP_TIME -static struct ap_device_id zcrypt_cex2a_ids[] = { - { AP_DEVICE(AP_DEVICE_TYPE_CEX2A) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX3A) }, - { /* end of list */ }, -}; - -MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_ids); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("CEX2A Cryptographic Coprocessor device driver, " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static int zcrypt_cex2a_probe(struct ap_device *ap_dev); -static void zcrypt_cex2a_remove(struct ap_device *ap_dev); +static struct ap_device_id zcrypt_cex2a_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX2A, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3A, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { /* end of list */ }, +}; + +MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_card_ids); -static struct ap_driver zcrypt_cex2a_driver = { - .probe = zcrypt_cex2a_probe, - .remove = zcrypt_cex2a_remove, - .ids = zcrypt_cex2a_ids, - .request_timeout = CEX2A_CLEANUP_TIME, +static struct ap_device_id zcrypt_cex2a_queue_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX2A, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3A, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { /* end of list */ }, }; +MODULE_DEVICE_TABLE(ap, zcrypt_cex2a_queue_ids); + /** - * Probe function for CEX2A cards. It always accepts the AP device - * since the bus_match already checked the hardware type. + * Probe function for CEX2A card devices. It always accepts the AP device + * since the bus_match already checked the card type. * @ap_dev: pointer to the AP device. */ -static int zcrypt_cex2a_probe(struct ap_device *ap_dev) +static int zcrypt_cex2a_card_probe(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = NULL; - int CEX2A_SPEED_IDX[] = { 800, 1000, 2000, 900, 1200, 2400, 0}; - int CEX3A_SPEED_IDX[] = { 400, 500, 1000, 450, 550, 1200, 0}; + /* + * Normalized speed ratings per crypto adapter + * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY + */ + static const int CEX2A_SPEED_IDX[] = { + 800, 1000, 2000, 900, 1200, 2400, 0, 0}; + static const int CEX3A_SPEED_IDX[] = { + 400, 500, 1000, 450, 550, 1200, 0, 0}; + + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc; int rc = 0; + zc = zcrypt_card_alloc(); + if (!zc) + return -ENOMEM; + zc->card = ac; + ac->private = zc; + + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) { + zc->min_mod_size = CEX2A_MIN_MOD_SIZE; + zc->max_mod_size = CEX2A_MAX_MOD_SIZE; + memcpy(zc->speed_rating, CEX2A_SPEED_IDX, + sizeof(CEX2A_SPEED_IDX)); + zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; + zc->type_string = "CEX2A"; + zc->user_space_type = ZCRYPT_CEX2A; + } else if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX3A) { + zc->min_mod_size = CEX2A_MIN_MOD_SIZE; + zc->max_mod_size = CEX2A_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; + if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) && + ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) { + zc->max_mod_size = CEX3A_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; + } + memcpy(zc->speed_rating, CEX3A_SPEED_IDX, + sizeof(CEX3A_SPEED_IDX)); + zc->type_string = "CEX3A"; + zc->user_space_type = ZCRYPT_CEX3A; + } else { + zcrypt_card_free(zc); + return -ENODEV; + } + zc->online = 1; + + rc = zcrypt_card_register(zc); + if (rc) { + ac->private = NULL; + zcrypt_card_free(zc); + } + + return rc; +} + +/** + * This is called to remove the CEX2A card driver information + * if an AP card device is removed. + */ +static void zcrypt_cex2a_card_remove(struct ap_device *ap_dev) +{ + struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; + + if (zc) + zcrypt_card_unregister(zc); +} + +static struct ap_driver zcrypt_cex2a_card_driver = { + .probe = zcrypt_cex2a_card_probe, + .remove = zcrypt_cex2a_card_remove, + .ids = zcrypt_cex2a_card_ids, +}; + +/** + * Probe function for CEX2A queue devices. It always accepts the AP device + * since the bus_match already checked the queue type. + * @ap_dev: pointer to the AP device. + */ +static int zcrypt_cex2a_queue_probe(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = NULL; + int rc; + switch (ap_dev->device_type) { case AP_DEVICE_TYPE_CEX2A: - zdev = zcrypt_device_alloc(CEX2A_MAX_RESPONSE_SIZE); - if (!zdev) + zq = zcrypt_queue_alloc(CEX2A_MAX_RESPONSE_SIZE); + if (!zq) return -ENOMEM; - zdev->user_space_type = ZCRYPT_CEX2A; - zdev->type_string = "CEX2A"; - zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; - zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; - zdev->short_crt = 1; - memcpy(zdev->speed_rating, CEX2A_SPEED_IDX, - sizeof(CEX2A_SPEED_IDX)); - zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3A: - zdev = zcrypt_device_alloc(CEX3A_MAX_RESPONSE_SIZE); - if (!zdev) + zq = zcrypt_queue_alloc(CEX3A_MAX_RESPONSE_SIZE); + if (!zq) return -ENOMEM; - zdev->user_space_type = ZCRYPT_CEX3A; - zdev->type_string = "CEX3A"; - zdev->min_mod_size = CEX2A_MIN_MOD_SIZE; - zdev->max_mod_size = CEX2A_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX2A_MAX_MOD_SIZE; - if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && - ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { - zdev->max_mod_size = CEX3A_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX3A_MAX_MOD_SIZE; - } - zdev->short_crt = 1; - memcpy(zdev->speed_rating, CEX3A_SPEED_IDX, - sizeof(CEX3A_SPEED_IDX)); break; } - if (!zdev) + if (!zq) return -ENODEV; - zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); - zdev->ap_dev = ap_dev; - zdev->online = 1; - zdev->load = zdev->speed_rating[0]; - ap_device_init_reply(ap_dev, &zdev->reply); - ap_dev->private = zdev; - rc = zcrypt_device_register(zdev); + zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, MSGTYPE50_VARIANT_DEFAULT); + zq->queue = aq; + zq->online = 1; + atomic_set(&zq->load, 0); + ap_queue_init_reply(aq, &zq->reply); + aq->request_timeout = CEX2A_CLEANUP_TIME, + aq->private = zq; + rc = zcrypt_queue_register(zq); if (rc) { - ap_dev->private = NULL; - zcrypt_device_free(zdev); + aq->private = NULL; + zcrypt_queue_free(zq); } + return rc; } /** - * This is called to remove the extended CEX2A driver information - * if an AP device is removed. + * This is called to remove the CEX2A queue driver information + * if an AP queue device is removed. */ -static void zcrypt_cex2a_remove(struct ap_device *ap_dev) +static void zcrypt_cex2a_queue_remove(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = ap_dev->private; + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = aq->private; - zcrypt_device_unregister(zdev); + ap_queue_remove(aq); + if (zq) + zcrypt_queue_unregister(zq); } +static struct ap_driver zcrypt_cex2a_queue_driver = { + .probe = zcrypt_cex2a_queue_probe, + .remove = zcrypt_cex2a_queue_remove, + .suspend = ap_queue_suspend, + .resume = ap_queue_resume, + .ids = zcrypt_cex2a_queue_ids, +}; + int __init zcrypt_cex2a_init(void) { - return ap_driver_register(&zcrypt_cex2a_driver, THIS_MODULE, "cex2a"); + int rc; + + rc = ap_driver_register(&zcrypt_cex2a_card_driver, + THIS_MODULE, "cex2acard"); + if (rc) + return rc; + + rc = ap_driver_register(&zcrypt_cex2a_queue_driver, + THIS_MODULE, "cex2aqueue"); + if (rc) + ap_driver_unregister(&zcrypt_cex2a_card_driver); + + return rc; } void __exit zcrypt_cex2a_exit(void) { - ap_driver_unregister(&zcrypt_cex2a_driver); + ap_driver_unregister(&zcrypt_cex2a_queue_driver); + ap_driver_unregister(&zcrypt_cex2a_card_driver); } module_init(zcrypt_cex2a_init); diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c index ff28ad543c30..4e91163d70a6 100644 --- a/drivers/s390/crypto/zcrypt_cex4.c +++ b/drivers/s390/crypto/zcrypt_cex4.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "ap_bus.h" #include "zcrypt_api.h" @@ -34,160 +35,246 @@ */ #define CEX4_CLEANUP_TIME (900*HZ) -static struct ap_device_id zcrypt_cex4_ids[] = { - { AP_DEVICE(AP_DEVICE_TYPE_CEX4) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX5) }, - { /* end of list */ }, -}; - -MODULE_DEVICE_TABLE(ap, zcrypt_cex4_ids); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("CEX4 Cryptographic Card device driver, " \ "Copyright IBM Corp. 2012"); MODULE_LICENSE("GPL"); -static int zcrypt_cex4_probe(struct ap_device *ap_dev); -static void zcrypt_cex4_remove(struct ap_device *ap_dev); +static struct ap_device_id zcrypt_cex4_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX4, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX5, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { /* end of list */ }, +}; + +MODULE_DEVICE_TABLE(ap, zcrypt_cex4_card_ids); -static struct ap_driver zcrypt_cex4_driver = { - .probe = zcrypt_cex4_probe, - .remove = zcrypt_cex4_remove, - .ids = zcrypt_cex4_ids, - .request_timeout = CEX4_CLEANUP_TIME, +static struct ap_device_id zcrypt_cex4_queue_ids[] = { + { .dev_type = AP_DEVICE_TYPE_CEX4, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX5, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { /* end of list */ }, }; +MODULE_DEVICE_TABLE(ap, zcrypt_cex4_queue_ids); + /** - * Probe function for CEX4 cards. It always accepts the AP device + * Probe function for CEX4 card device. It always accepts the AP device * since the bus_match already checked the hardware type. * @ap_dev: pointer to the AP device. */ -static int zcrypt_cex4_probe(struct ap_device *ap_dev) +static int zcrypt_cex4_card_probe(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = NULL; /* * Normalized speed ratings per crypto adapter * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY */ - int CEX4A_SPEED_IDX[] = { 5, 6, 59, 20, 115, 581, 0, 0}; - int CEX5A_SPEED_IDX[] = { 3, 3, 6, 8, 32, 218, 0, 0}; - int CEX4C_SPEED_IDX[] = { 24, 25, 82, 41, 138, 1111, 79, 8}; - int CEX5C_SPEED_IDX[] = { 10, 14, 23, 17, 45, 242, 63, 4}; - int CEX4P_SPEED_IDX[] = {142, 198, 1852, 203, 331, 1563, 0, 8}; - int CEX5P_SPEED_IDX[] = { 49, 67, 131, 52, 85, 287, 0, 4}; + static const int CEX4A_SPEED_IDX[] = { + 5, 6, 59, 20, 115, 581, 0, 0}; + static const int CEX5A_SPEED_IDX[] = { + 3, 3, 6, 8, 32, 218, 0, 0}; + static const int CEX4C_SPEED_IDX[] = { + 24, 25, 82, 41, 138, 1111, 79, 8}; + static const int CEX5C_SPEED_IDX[] = { + 10, 14, 23, 17, 45, 242, 63, 4}; + static const int CEX4P_SPEED_IDX[] = { + 142, 198, 1852, 203, 331, 1563, 0, 8}; + static const int CEX5P_SPEED_IDX[] = { + 49, 67, 131, 52, 85, 287, 0, 4}; + + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc; int rc = 0; - switch (ap_dev->device_type) { - case AP_DEVICE_TYPE_CEX4: - case AP_DEVICE_TYPE_CEX5: - if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) { - zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE); - if (!zdev) - return -ENOMEM; - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { - zdev->type_string = "CEX4A"; - memcpy(zdev->speed_rating, CEX4A_SPEED_IDX, - sizeof(CEX4A_SPEED_IDX)); - } else { - zdev->type_string = "CEX5A"; - memcpy(zdev->speed_rating, CEX5A_SPEED_IDX, - sizeof(CEX5A_SPEED_IDX)); - } - zdev->user_space_type = ZCRYPT_CEX3A; - zdev->min_mod_size = CEX4A_MIN_MOD_SIZE; - if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) && - ap_test_bit(&ap_dev->functions, AP_FUNC_CRT4K)) { - zdev->max_mod_size = - CEX4A_MAX_MOD_SIZE_4K; - zdev->max_exp_bit_length = - CEX4A_MAX_MOD_SIZE_4K; - } else { - zdev->max_mod_size = - CEX4A_MAX_MOD_SIZE_2K; - zdev->max_exp_bit_length = - CEX4A_MAX_MOD_SIZE_2K; - } - zdev->short_crt = 1; - zdev->ops = zcrypt_msgtype(MSGTYPE50_NAME, - MSGTYPE50_VARIANT_DEFAULT); - } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) { - zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); - if (!zdev) - return -ENOMEM; - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { - zdev->type_string = "CEX4C"; - memcpy(zdev->speed_rating, CEX4C_SPEED_IDX, - sizeof(CEX4C_SPEED_IDX)); - } else { - zdev->type_string = "CEX5C"; - memcpy(zdev->speed_rating, CEX5C_SPEED_IDX, - sizeof(CEX5C_SPEED_IDX)); - } - zdev->user_space_type = ZCRYPT_CEX3C; - zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; - zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; - zdev->short_crt = 0; - zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_DEFAULT); - } else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) { - zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE); - if (!zdev) - return -ENOMEM; - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) { - zdev->type_string = "CEX4P"; - memcpy(zdev->speed_rating, CEX4P_SPEED_IDX, - sizeof(CEX4P_SPEED_IDX)); - } else { - zdev->type_string = "CEX5P"; - memcpy(zdev->speed_rating, CEX5P_SPEED_IDX, - sizeof(CEX5P_SPEED_IDX)); - } - zdev->user_space_type = ZCRYPT_CEX4; - zdev->min_mod_size = CEX4C_MIN_MOD_SIZE; - zdev->max_mod_size = CEX4C_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; - zdev->short_crt = 0; - zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_EP11); + zc = zcrypt_card_alloc(); + if (!zc) + return -ENOMEM; + zc->card = ac; + ac->private = zc; + if (ap_test_bit(&ac->functions, AP_FUNC_ACCEL)) { + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { + zc->type_string = "CEX4A"; + zc->user_space_type = ZCRYPT_CEX4; + memcpy(zc->speed_rating, CEX4A_SPEED_IDX, + sizeof(CEX4A_SPEED_IDX)); + } else { + zc->type_string = "CEX5A"; + zc->user_space_type = ZCRYPT_CEX5; + memcpy(zc->speed_rating, CEX5A_SPEED_IDX, + sizeof(CEX5A_SPEED_IDX)); } - break; - } - if (!zdev) + zc->min_mod_size = CEX4A_MIN_MOD_SIZE; + if (ap_test_bit(&ac->functions, AP_FUNC_MEX4K) && + ap_test_bit(&ac->functions, AP_FUNC_CRT4K)) { + zc->max_mod_size = CEX4A_MAX_MOD_SIZE_4K; + zc->max_exp_bit_length = + CEX4A_MAX_MOD_SIZE_4K; + } else { + zc->max_mod_size = CEX4A_MAX_MOD_SIZE_2K; + zc->max_exp_bit_length = + CEX4A_MAX_MOD_SIZE_2K; + } + } else if (ap_test_bit(&ac->functions, AP_FUNC_COPRO)) { + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { + zc->type_string = "CEX4C"; + /* wrong user space type, must be CEX4 + * just keep it for cca compatibility + */ + zc->user_space_type = ZCRYPT_CEX3C; + memcpy(zc->speed_rating, CEX4C_SPEED_IDX, + sizeof(CEX4C_SPEED_IDX)); + } else { + zc->type_string = "CEX5C"; + /* wrong user space type, must be CEX5 + * just keep it for cca compatibility + */ + zc->user_space_type = ZCRYPT_CEX3C; + memcpy(zc->speed_rating, CEX5C_SPEED_IDX, + sizeof(CEX5C_SPEED_IDX)); + } + zc->min_mod_size = CEX4C_MIN_MOD_SIZE; + zc->max_mod_size = CEX4C_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; + } else if (ap_test_bit(&ac->functions, AP_FUNC_EP11)) { + if (ac->ap_dev.device_type == AP_DEVICE_TYPE_CEX4) { + zc->type_string = "CEX4P"; + zc->user_space_type = ZCRYPT_CEX4; + memcpy(zc->speed_rating, CEX4P_SPEED_IDX, + sizeof(CEX4P_SPEED_IDX)); + } else { + zc->type_string = "CEX5P"; + zc->user_space_type = ZCRYPT_CEX5; + memcpy(zc->speed_rating, CEX5P_SPEED_IDX, + sizeof(CEX5P_SPEED_IDX)); + } + zc->min_mod_size = CEX4C_MIN_MOD_SIZE; + zc->max_mod_size = CEX4C_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX4C_MAX_MOD_SIZE; + } else { + zcrypt_card_free(zc); return -ENODEV; - zdev->ap_dev = ap_dev; - zdev->online = 1; - zdev->load = zdev->speed_rating[0]; - ap_device_init_reply(ap_dev, &zdev->reply); - ap_dev->private = zdev; - rc = zcrypt_device_register(zdev); + } + zc->online = 1; + + rc = zcrypt_card_register(zc); if (rc) { - ap_dev->private = NULL; - zcrypt_device_free(zdev); + ac->private = NULL; + zcrypt_card_free(zc); } + return rc; } /** - * This is called to remove the extended CEX4 driver information - * if an AP device is removed. + * This is called to remove the CEX4 card driver information + * if an AP card device is removed. */ -static void zcrypt_cex4_remove(struct ap_device *ap_dev) +static void zcrypt_cex4_card_remove(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = ap_dev->private; + struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; - if (zdev) { - zcrypt_device_unregister(zdev); + if (zc) + zcrypt_card_unregister(zc); +} + +static struct ap_driver zcrypt_cex4_card_driver = { + .probe = zcrypt_cex4_card_probe, + .remove = zcrypt_cex4_card_remove, + .ids = zcrypt_cex4_card_ids, +}; + +/** + * Probe function for CEX4 queue device. It always accepts the AP device + * since the bus_match already checked the hardware type. + * @ap_dev: pointer to the AP device. + */ +static int zcrypt_cex4_queue_probe(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq; + int rc; + + if (ap_test_bit(&aq->card->functions, AP_FUNC_ACCEL)) { + zq = zcrypt_queue_alloc(CEX4A_MAX_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->ops = zcrypt_msgtype(MSGTYPE50_NAME, + MSGTYPE50_VARIANT_DEFAULT); + } else if (ap_test_bit(&aq->card->functions, AP_FUNC_COPRO)) { + zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); + } else if (ap_test_bit(&aq->card->functions, AP_FUNC_EP11)) { + zq = zcrypt_queue_alloc(CEX4C_MAX_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_EP11); + } else { + return -ENODEV; } + zq->queue = aq; + zq->online = 1; + atomic_set(&zq->load, 0); + ap_queue_init_reply(aq, &zq->reply); + aq->request_timeout = CEX4_CLEANUP_TIME, + aq->private = zq; + rc = zcrypt_queue_register(zq); + if (rc) { + aq->private = NULL; + zcrypt_queue_free(zq); + } + + return rc; } +/** + * This is called to remove the CEX4 queue driver information + * if an AP queue device is removed. + */ +static void zcrypt_cex4_queue_remove(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = aq->private; + + ap_queue_remove(aq); + if (zq) + zcrypt_queue_unregister(zq); +} + +static struct ap_driver zcrypt_cex4_queue_driver = { + .probe = zcrypt_cex4_queue_probe, + .remove = zcrypt_cex4_queue_remove, + .suspend = ap_queue_suspend, + .resume = ap_queue_resume, + .ids = zcrypt_cex4_queue_ids, +}; + int __init zcrypt_cex4_init(void) { - return ap_driver_register(&zcrypt_cex4_driver, THIS_MODULE, "cex4"); + int rc; + + rc = ap_driver_register(&zcrypt_cex4_card_driver, + THIS_MODULE, "cex4card"); + if (rc) + return rc; + + rc = ap_driver_register(&zcrypt_cex4_queue_driver, + THIS_MODULE, "cex4queue"); + if (rc) + ap_driver_unregister(&zcrypt_cex4_card_driver); + + return rc; } void __exit zcrypt_cex4_exit(void) { - ap_driver_unregister(&zcrypt_cex4_driver); + ap_driver_unregister(&zcrypt_cex4_queue_driver); + ap_driver_unregister(&zcrypt_cex4_card_driver); } module_init(zcrypt_cex4_init); diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index de1b6c1d172c..09247331e9fb 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -87,7 +87,7 @@ struct error_hdr { #define REP88_ERROR_OPERAND 0x84 /* CEX2A */ #define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */ -static inline int convert_error(struct zcrypt_device *zdev, +static inline int convert_error(struct zcrypt_queue *zq, struct ap_message *reply) { struct error_hdr *ehdr = reply->message; @@ -110,11 +110,13 @@ static inline int convert_error(struct zcrypt_device *zdev, * and then repeat the request. */ atomic_set(&zcrypt_rescan_req, 1); - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), zq->online, ehdr->reply_code); return -EAGAIN; case REP82_ERROR_TRANSPORT_FAIL: @@ -122,19 +124,23 @@ static inline int convert_error(struct zcrypt_device *zdev, // REP88_ERROR_MODULE_FAILURE // '10' CEX2A /* If a card fails disable it and repeat the request. */ atomic_set(&zcrypt_rescan_req, 1); - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), zq->online, ehdr->reply_code); return -EAGAIN; default: - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), zq->online, ehdr->reply_code); return -EAGAIN; /* repeat the request on a different device. */ } diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index fb97479af3f8..a9873b436115 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -53,9 +53,6 @@ MODULE_DESCRIPTION("Cryptographic Accelerator (message type 50), " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static void zcrypt_cex2a_receive(struct ap_device *, struct ap_message *, - struct ap_message *); - /** * The type 50 message family is associated with a CEX2A card. * @@ -208,13 +205,13 @@ unsigned int get_rsa_crt_fc(struct ica_rsa_modexpo_crt *crt, int *fcode) /** * Convert a ICAMEX message to a type50 MEX message. * - * @zdev: crypto device pointer - * @zreq: crypto request pointer + * @zq: crypto queue pointer + * @ap_msg: crypto request pointer * @mex: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, +static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo *mex) { @@ -266,13 +263,13 @@ static int ICAMEX_msg_to_type50MEX_msg(struct zcrypt_device *zdev, /** * Convert a ICACRT message to a type50 CRT message. * - * @zdev: crypto device pointer - * @zreq: crypto request pointer + * @zq: crypto queue pointer + * @ap_msg: crypto request pointer * @crt: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, +static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo_crt *crt) { @@ -315,7 +312,7 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, u = crb2->u + sizeof(crb2->u) - short_len; inp = crb2->message + sizeof(crb2->message) - mod_len; } else if ((mod_len <= 512) && /* up to 4096 bit key size */ - (zdev->max_mod_size == CEX3A_MAX_MOD_SIZE)) { /* >= CEX3A */ + (zq->zcard->max_mod_size == CEX3A_MAX_MOD_SIZE)) { struct type50_crb3_msg *crb3 = ap_msg->message; memset(crb3, 0, sizeof(*crb3)); ap_msg->length = sizeof(*crb3); @@ -349,14 +346,14 @@ static int ICACRT_msg_to_type50CRT_msg(struct zcrypt_device *zdev, /** * Copy results from a type 80 reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @data: pointer to user output data * @length: size of user output data * * Returns 0 on success or -EFAULT. */ -static int convert_type80(struct zcrypt_device *zdev, +static int convert_type80(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -366,16 +363,18 @@ static int convert_type80(struct zcrypt_device *zdev, if (t80h->len < sizeof(*t80h) + outputdatalength) { /* The result is too short, the CEX2A card may not do that.. */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), - zdev->online, t80h->code); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online, t80h->code); return -EAGAIN; /* repeat the request on a different device. */ } - if (zdev->user_space_type == ZCRYPT_CEX2A) + if (zq->zcard->user_space_type == ZCRYPT_CEX2A) BUG_ON(t80h->len > CEX2A_MAX_RESPONSE_SIZE); else BUG_ON(t80h->len > CEX3A_MAX_RESPONSE_SIZE); @@ -385,7 +384,7 @@ static int convert_type80(struct zcrypt_device *zdev, return 0; } -static int convert_response(struct zcrypt_device *zdev, +static int convert_response(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -394,16 +393,19 @@ static int convert_response(struct zcrypt_device *zdev, switch (((unsigned char *) reply->message)[1]) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE80_RSP_CODE: - return convert_type80(zdev, reply, + return convert_type80(zq, reply, outputdata, outputdatalength); default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -412,11 +414,11 @@ static int convert_response(struct zcrypt_device *zdev, * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". * It is called from tasklet context. - * @ap_dev: pointer to the AP device + * @aq: pointer to the AP device * @msg: pointer to the AP message * @reply: pointer to the AP reply message */ -static void zcrypt_cex2a_receive(struct ap_device *ap_dev, +static void zcrypt_cex2a_receive(struct ap_queue *aq, struct ap_message *msg, struct ap_message *reply) { @@ -432,7 +434,7 @@ static void zcrypt_cex2a_receive(struct ap_device *ap_dev, goto out; /* ap_msg->rc indicates the error */ t80h = reply->message; if (t80h->type == TYPE80_RSP_CODE) { - if (ap_dev->device_type == AP_DEVICE_TYPE_CEX2A) + if (aq->ap_dev.device_type == AP_DEVICE_TYPE_CEX2A) length = min_t(int, CEX2A_MAX_RESPONSE_SIZE, t80h->len); else @@ -450,11 +452,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0); /** * The request distributor calls this function if it picked the CEX2A * device to handle a modexpo request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * CEX2A device to the request distributor * @mex: pointer to the modexpo request buffer */ -static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, +static long zcrypt_cex2a_modexpo(struct zcrypt_queue *zq, struct ica_rsa_modexpo *mex) { struct ap_message ap_msg; @@ -462,7 +464,7 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, int rc; ap_init_message(&ap_msg); - if (zdev->user_space_type == ZCRYPT_CEX2A) + if (zq->zcard->user_space_type == ZCRYPT_CEX2A) ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); else @@ -474,20 +476,20 @@ static long zcrypt_cex2a_modexpo(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; - rc = ICAMEX_msg_to_type50MEX_msg(zdev, &ap_msg, mex); + rc = ICAMEX_msg_to_type50MEX_msg(zq, &ap_msg, mex); if (rc) goto out_free; init_completion(&work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response(zdev, &ap_msg, mex->outputdata, + rc = convert_response(zq, &ap_msg, mex->outputdata, mex->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); out_free: kfree(ap_msg.message); return rc; @@ -496,11 +498,11 @@ out_free: /** * The request distributor calls this function if it picked the CEX2A * device to handle a modexpo_crt request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * CEX2A device to the request distributor * @crt: pointer to the modexpoc_crt request buffer */ -static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, +static long zcrypt_cex2a_modexpo_crt(struct zcrypt_queue *zq, struct ica_rsa_modexpo_crt *crt) { struct ap_message ap_msg; @@ -508,7 +510,7 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, int rc; ap_init_message(&ap_msg); - if (zdev->user_space_type == ZCRYPT_CEX2A) + if (zq->zcard->user_space_type == ZCRYPT_CEX2A) ap_msg.message = kmalloc(MSGTYPE50_CRB2_MAX_MSG_SIZE, GFP_KERNEL); else @@ -520,20 +522,20 @@ static long zcrypt_cex2a_modexpo_crt(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &work; - rc = ICACRT_msg_to_type50CRT_msg(zdev, &ap_msg, crt); + rc = ICACRT_msg_to_type50CRT_msg(zq, &ap_msg, crt); if (rc) goto out_free; init_completion(&work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response(zdev, &ap_msg, crt->outputdata, + rc = convert_response(zq, &ap_msg, crt->outputdata, crt->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); out_free: kfree(ap_msg.message); return rc; diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index 957a88d5768b..c6cfb9acec19 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -60,9 +60,6 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor (message type 6), " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static void zcrypt_msgtype6_receive(struct ap_device *, struct ap_message *, - struct ap_message *); - /** * CPRB * Note that all shorts, ints and longs are little-endian. @@ -258,13 +255,13 @@ int speed_idx_ep11(int req_type) /** * Convert a ICAMEX message to a type6 MEX message. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @ap_msg: pointer to AP message * @mex: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, +static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo *mex) { @@ -279,11 +276,6 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, .ulen = 10, .only_rule = {'M', 'R', 'P', ' ', ' ', ' ', ' ', ' '} }; - static struct function_and_rules_block static_pke_fnr_MCL2 = { - .function_code = {'P', 'K'}, - .ulen = 10, - .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} - }; struct { struct type6_hdr hdr; struct CPRBX cprbx; @@ -310,11 +302,10 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); msg->cprbx = static_cprbx; - msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); msg->cprbx.rpl_msgbl = msg->hdr.FromCardLen1; - msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? - static_pke_fnr_MCL2 : static_pke_fnr; + msg->fr = static_pke_fnr; msg->cprbx.req_parml = size - sizeof(msg->hdr) - sizeof(msg->cprbx); @@ -325,13 +316,13 @@ static int ICAMEX_msg_to_type6MEX_msgX(struct zcrypt_device *zdev, /** * Convert a ICACRT message to a type6 CRT message. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @ap_msg: pointer to AP message * @crt: pointer to user input data * * Returns 0 on success or -EFAULT. */ -static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, +static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_queue *zq, struct ap_message *ap_msg, struct ica_rsa_modexpo_crt *crt) { @@ -347,11 +338,6 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, .only_rule = {'Z', 'E', 'R', 'O', '-', 'P', 'A', 'D'} }; - static struct function_and_rules_block static_pkd_fnr_MCL2 = { - .function_code = {'P', 'D'}, - .ulen = 10, - .only_rule = {'P', 'K', 'C', 'S', '-', '1', '.', '2'} - }; struct { struct type6_hdr hdr; struct CPRBX cprbx; @@ -378,12 +364,11 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, msg->hdr.FromCardLen1 = PCIXCC_MAX_ICA_RESPONSE_SIZE - sizeof(msg->hdr); msg->cprbx = static_cprbx; - msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); msg->cprbx.req_parml = msg->cprbx.rpl_msgbl = size - sizeof(msg->hdr) - sizeof(msg->cprbx); - msg->fr = (zdev->user_space_type == ZCRYPT_PCIXCC_MCL2) ? - static_pkd_fnr_MCL2 : static_pkd_fnr; + msg->fr = static_pkd_fnr; ap_msg->length = size; return 0; @@ -392,7 +377,7 @@ static int ICACRT_msg_to_type6CRT_msgX(struct zcrypt_device *zdev, /** * Convert a XCRB message to a type6 CPRB message. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @ap_msg: pointer to AP message * @xcRB: pointer to user input data * @@ -405,7 +390,8 @@ struct type86_fmt2_msg { static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, struct ica_xcRB *xcRB, - unsigned int *fcode) + unsigned int *fcode, + unsigned short **dom) { static struct type6_hdr static_type6_hdrX = { .type = 0x06, @@ -486,6 +472,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, sizeof(msg->hdr.function_code)); *fcode = (msg->hdr.function_code[0] << 8) | msg->hdr.function_code[1]; + *dom = (unsigned short *)&msg->cprbx.domain; if (memcmp(function_code, "US", 2) == 0) ap_msg->special = 1; @@ -497,6 +484,7 @@ static int XCRB_msg_to_type6CPRB_msgX(struct ap_message *ap_msg, copy_from_user(req_data, xcRB->request_data_address, xcRB->request_data_length)) return -EFAULT; + return 0; } @@ -504,6 +492,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg, struct ep11_urb *xcRB, unsigned int *fcode) { + unsigned int lfmt; static struct type6_hdr static_type6_ep11_hdr = { .type = 0x06, .rqid = {0x00, 0x01}, @@ -556,14 +545,30 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct ap_message *ap_msg, return -EFAULT; } - *fcode = speed_idx_ep11(payload_hdr->func_val & 0xFFFF); + if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ + switch (msg->pld_lenfmt & 0x03) { + case 1: + lfmt = 2; + break; + case 2: + lfmt = 3; + break; + default: + return -EINVAL; + } + } else { + lfmt = 1; /* length format #1 */ + } + payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); + *fcode = payload_hdr->func_val & 0xFFFF; + return 0; } /** * Copy results from a type 86 ICA reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @data: pointer to user output data * @length: size of user output data @@ -585,7 +590,7 @@ struct type86_ep11_reply { struct ep11_cprb cprbx; } __packed; -static int convert_type86_ica(struct zcrypt_device *zdev, +static int convert_type86_ica(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -640,18 +645,22 @@ static int convert_type86_ica(struct zcrypt_device *zdev, if (service_rc == 8 && service_rs == 770) return -EINVAL; if (service_rc == 8 && service_rs == 783) { - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; + zq->zcard->min_mod_size = + PCIXCC_MIN_MOD_SIZE_OLD; return -EAGAIN; } if (service_rc == 12 && service_rs == 769) return -EINVAL; if (service_rc == 8 && service_rs == 72) return -EINVAL; - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%drc%d", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online, + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online, msg->hdr.reply_code); return -EAGAIN; /* repeat the request on a different device. */ } @@ -688,13 +697,13 @@ static int convert_type86_ica(struct zcrypt_device *zdev, /** * Copy results from a type 86 XCRB reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @xcRB: pointer to XCRB * * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. */ -static int convert_type86_xcrb(struct zcrypt_device *zdev, +static int convert_type86_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ica_xcRB *xcRB) { @@ -719,13 +728,13 @@ static int convert_type86_xcrb(struct zcrypt_device *zdev, /** * Copy results from a type 86 EP11 XCRB reply message back to user space. * - * @zdev: crypto device pointer + * @zq: crypto device pointer * @reply: reply AP message. * @xcRB: pointer to EP11 user request block * * Returns 0 on success or -EINVAL, -EFAULT, -EAGAIN in case of an error. */ -static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev, +static int convert_type86_ep11_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ep11_urb *xcRB) { @@ -743,7 +752,7 @@ static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev, return 0; } -static int convert_type86_rng(struct zcrypt_device *zdev, +static int convert_type86_rng(struct zcrypt_queue *zq, struct ap_message *reply, char *buffer) { @@ -760,7 +769,7 @@ static int convert_type86_rng(struct zcrypt_device *zdev, return msg->fmt2.count2; } -static int convert_response_ica(struct zcrypt_device *zdev, +static int convert_response_ica(struct zcrypt_queue *zq, struct ap_message *reply, char __user *outputdata, unsigned int outputdatalength) @@ -771,35 +780,38 @@ static int convert_response_ica(struct zcrypt_device *zdev, switch (((unsigned char *) reply->message)[1]) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE86_RSP_CODE: if (msg->cprbx.ccp_rtcode && (msg->cprbx.ccp_rscode == 0x14f) && (outputdatalength > 256)) { - if (zdev->max_exp_bit_length <= 17) { - zdev->max_exp_bit_length = 17; + if (zq->zcard->max_exp_bit_length <= 17) { + zq->zcard->max_exp_bit_length = 17; return -EAGAIN; } else return -EINVAL; } if (msg->hdr.reply_code) - return convert_error(zdev, reply); + return convert_error(zq, reply); if (msg->cprbx.cprb_ver_id == 0x02) - return convert_type86_ica(zdev, reply, + return convert_type86_ica(zq, reply, outputdata, outputdatalength); /* Fall through, no break, incorrect cprb version is an unknown * response */ default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } -static int convert_response_xcrb(struct zcrypt_device *zdev, +static int convert_response_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ica_xcRB *xcRB) { @@ -810,28 +822,31 @@ static int convert_response_xcrb(struct zcrypt_device *zdev, case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE86_RSP_CODE: if (msg->hdr.reply_code) { memcpy(&(xcRB->status), msg->fmt2.apfs, sizeof(u32)); - return convert_error(zdev, reply); + return convert_error(zq, reply); } if (msg->cprbx.cprb_ver_id == 0x02) - return convert_type86_xcrb(zdev, reply, xcRB); + return convert_type86_xcrb(zq, reply, xcRB); /* Fall through, no break, incorrect cprb version is an unknown * response */ default: /* Unknown response type, this should NEVER EVER happen */ xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } -static int convert_response_ep11_xcrb(struct zcrypt_device *zdev, +static int convert_response_ep11_xcrb(struct zcrypt_queue *zq, struct ap_message *reply, struct ep11_urb *xcRB) { struct type86_ep11_reply *msg = reply->message; @@ -840,24 +855,27 @@ static int convert_response_ep11_xcrb(struct zcrypt_device *zdev, switch (((unsigned char *)reply->message)[1]) { case TYPE82_RSP_CODE: case TYPE87_RSP_CODE: - return convert_error(zdev, reply); + return convert_error(zq, reply); case TYPE86_RSP_CODE: if (msg->hdr.reply_code) - return convert_error(zdev, reply); + return convert_error(zq, reply); if (msg->cprbx.cprb_ver_id == 0x04) - return convert_type86_ep11_xcrb(zdev, reply, xcRB); + return convert_type86_ep11_xcrb(zq, reply, xcRB); /* Fall through, no break, incorrect cprb version is an unknown resp.*/ default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } -static int convert_response_rng(struct zcrypt_device *zdev, +static int convert_response_rng(struct zcrypt_queue *zq, struct ap_message *reply, char *data) { @@ -871,15 +889,18 @@ static int convert_response_rng(struct zcrypt_device *zdev, if (msg->hdr.reply_code) return -EINVAL; if (msg->cprbx.cprb_ver_id == 0x02) - return convert_type86_rng(zdev, reply, data); + return convert_type86_rng(zq, reply, data); /* Fall through, no break, incorrect cprb version is an unknown * response */ default: /* Unknown response type, this should NEVER EVER happen */ - zdev->online = 0; - pr_err("Cryptographic device %x failed and was set offline\n", - AP_QID_DEVICE(zdev->ap_dev->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zdev, "dev%04xo%dfail", - AP_QID_DEVICE(zdev->ap_dev->qid), zdev->online); + zq->online = 0; + pr_err("Cryptographic device %02x.%04x failed and was set offline\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid)); + ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -888,11 +909,11 @@ static int convert_response_rng(struct zcrypt_device *zdev, * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". * It is called from tasklet context. - * @ap_dev: pointer to the AP device + * @aq: pointer to the AP queue * @msg: pointer to the AP message * @reply: pointer to the AP reply message */ -static void zcrypt_msgtype6_receive(struct ap_device *ap_dev, +static void zcrypt_msgtype6_receive(struct ap_queue *aq, struct ap_message *msg, struct ap_message *reply) { @@ -937,11 +958,11 @@ out: * This function is called from the AP bus code after a crypto request * "msg" has finished with the reply message "reply". * It is called from tasklet context. - * @ap_dev: pointer to the AP device + * @aq: pointer to the AP queue * @msg: pointer to the AP message * @reply: pointer to the AP reply message */ -static void zcrypt_msgtype6_receive_ep11(struct ap_device *ap_dev, +static void zcrypt_msgtype6_receive_ep11(struct ap_queue *aq, struct ap_message *msg, struct ap_message *reply) { @@ -981,11 +1002,11 @@ static atomic_t zcrypt_step = ATOMIC_INIT(0); /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a modexpo request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @mex: pointer to the modexpo request buffer */ -static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_modexpo(struct zcrypt_queue *zq, struct ica_rsa_modexpo *mex) { struct ap_message ap_msg; @@ -1002,21 +1023,21 @@ static long zcrypt_msgtype6_modexpo(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; - rc = ICAMEX_msg_to_type6MEX_msgX(zdev, &ap_msg, mex); + rc = ICAMEX_msg_to_type6MEX_msgX(zq, &ap_msg, mex); if (rc) goto out_free; init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&resp_type.work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response_ica(zdev, &ap_msg, + rc = convert_response_ica(zq, &ap_msg, mex->outputdata, mex->outputdatalength); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); out_free: free_page((unsigned long) ap_msg.message); return rc; @@ -1025,11 +1046,11 @@ out_free: /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a modexpo_crt request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @crt: pointer to the modexpoc_crt request buffer */ -static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_queue *zq, struct ica_rsa_modexpo_crt *crt) { struct ap_message ap_msg; @@ -1046,21 +1067,22 @@ static long zcrypt_msgtype6_modexpo_crt(struct zcrypt_device *zdev, ap_msg.psmid = (((unsigned long long) current->pid) << 32) + atomic_inc_return(&zcrypt_step); ap_msg.private = &resp_type; - rc = ICACRT_msg_to_type6CRT_msgX(zdev, &ap_msg, crt); + rc = ICACRT_msg_to_type6CRT_msgX(zq, &ap_msg, crt); if (rc) goto out_free; init_completion(&resp_type.work); - ap_queue_message(zdev->ap_dev, &ap_msg); + ap_queue_message(zq->queue, &ap_msg); rc = wait_for_completion_interruptible(&resp_type.work); if (rc == 0) { rc = ap_msg.rc; if (rc == 0) - rc = convert_response_ica(zdev, &ap_msg, + rc = convert_response_ica(zq, &ap_msg, crt->outputdata, crt->outputdatalength); - } else + } else { /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, &ap_msg); + ap_cancel_message(zq->queue, &ap_msg); + } out_free: free_page((unsigned long) ap_msg.message); return rc; @@ -1068,7 +1090,7 @@ out_free: unsigned int get_cprb_fc(struct ica_xcRB *xcRB, struct ap_message *ap_msg, - int *func_code) + unsigned int *func_code, unsigned short **dom) { struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_XCRB, @@ -1088,7 +1110,7 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, return -ENOMEM; } memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); - rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code); + rc = XCRB_msg_to_type6CPRB_msgX(ap_msg, xcRB, func_code, dom); if (rc) { kzfree(ap_msg->message); kzfree(ap_msg->private); @@ -1099,11 +1121,11 @@ unsigned int get_cprb_fc(struct ica_xcRB *xcRB, /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to handle a send_cprb request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @xcRB: pointer to the send_cprb request buffer */ -static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_send_cprb(struct zcrypt_queue *zq, struct ica_xcRB *xcRB, struct ap_message *ap_msg) { @@ -1111,15 +1133,15 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, struct response_type *rtype = (struct response_type *)(ap_msg->private); init_completion(&rtype->work); - ap_queue_message(zdev->ap_dev, ap_msg); + ap_queue_message(zq->queue, ap_msg); rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { rc = ap_msg->rc; if (rc == 0) - rc = convert_response_xcrb(zdev, ap_msg, xcRB); + rc = convert_response_xcrb(zq, ap_msg, xcRB); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, ap_msg); + ap_cancel_message(zq->queue, ap_msg); kzfree(ap_msg->message); kzfree(ap_msg->private); @@ -1128,7 +1150,7 @@ static long zcrypt_msgtype6_send_cprb(struct zcrypt_device *zdev, unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, struct ap_message *ap_msg, - int *func_code) + unsigned int *func_code) { struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_EP11, @@ -1159,11 +1181,11 @@ unsigned int get_ep11cprb_fc(struct ep11_urb *xcrb, /** * The request distributor calls this function if it picked the CEX4P * device to handle a send_ep11_cprb request. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * CEX4P device to the request distributor * @xcRB: pointer to the ep11 user request block */ -static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_queue *zq, struct ep11_urb *xcrb, struct ap_message *ap_msg) { @@ -1196,7 +1218,7 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, */ if (!((msg->cprbx.flags & 0x80) == 0x80)) { msg->cprbx.target_id = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); + AP_QID_QUEUE(zq->queue->qid); if ((msg->pld_lenfmt & 0x80) == 0x80) { /*ext.len.fmt 2 or 3*/ switch (msg->pld_lenfmt & 0x03) { @@ -1214,26 +1236,27 @@ static long zcrypt_msgtype6_send_ep11_cprb(struct zcrypt_device *zdev, } payload_hdr = (struct pld_hdr *)((&(msg->pld_lenfmt))+lfmt); payload_hdr->dom_val = (unsigned int) - AP_QID_QUEUE(zdev->ap_dev->qid); + AP_QID_QUEUE(zq->queue->qid); } init_completion(&rtype->work); - ap_queue_message(zdev->ap_dev, ap_msg); + ap_queue_message(zq->queue, ap_msg); rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { rc = ap_msg->rc; if (rc == 0) - rc = convert_response_ep11_xcrb(zdev, ap_msg, xcrb); + rc = convert_response_ep11_xcrb(zq, ap_msg, xcrb); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, ap_msg); + ap_cancel_message(zq->queue, ap_msg); kzfree(ap_msg->message); kzfree(ap_msg->private); return rc; } -unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) +unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code, + unsigned int *domain) { struct response_type resp_type = { .type = PCIXCC_RESPONSE_TYPE_XCRB, @@ -1253,7 +1276,7 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) } memcpy(ap_msg->private, &resp_type, sizeof(resp_type)); - rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE); + rng_type6CPRB_msgX(ap_msg, ZCRYPT_RNG_BUFFER_SIZE, domain); *func_code = HWRNG; return 0; @@ -1262,11 +1285,11 @@ unsigned int get_rng_fc(struct ap_message *ap_msg, int *func_code) /** * The request distributor calls this function if it picked the PCIXCC/CEX2C * device to generate random data. - * @zdev: pointer to zcrypt_device structure that identifies the + * @zq: pointer to zcrypt_queue structure that identifies the * PCIXCC/CEX2C device to the request distributor * @buffer: pointer to a memory page to return random data */ -static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, +static long zcrypt_msgtype6_rng(struct zcrypt_queue *zq, char *buffer, struct ap_message *ap_msg) { struct { @@ -1281,18 +1304,18 @@ static long zcrypt_msgtype6_rng(struct zcrypt_device *zdev, struct response_type *rtype = (struct response_type *)(ap_msg->private); int rc; - msg->cprbx.domain = AP_QID_QUEUE(zdev->ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(zq->queue->qid); init_completion(&rtype->work); - ap_queue_message(zdev->ap_dev, ap_msg); + ap_queue_message(zq->queue, ap_msg); rc = wait_for_completion_interruptible(&rtype->work); if (rc == 0) { rc = ap_msg->rc; if (rc == 0) - rc = convert_response_rng(zdev, ap_msg, buffer); + rc = convert_response_rng(zq, ap_msg, buffer); } else /* Signal pending. */ - ap_cancel_message(zdev->ap_dev, ap_msg); + ap_cancel_message(zq->queue, ap_msg); kzfree(ap_msg->message); kzfree(ap_msg->private); diff --git a/drivers/s390/crypto/zcrypt_msgtype6.h b/drivers/s390/crypto/zcrypt_msgtype6.h index a360dbe3c7d2..7a0d5b57821f 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.h +++ b/drivers/s390/crypto/zcrypt_msgtype6.h @@ -116,9 +116,11 @@ struct type86_fmt2_ext { unsigned int offset4; /* 0x00000000 */ } __packed; -unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, int *); -unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, int *); -unsigned int get_rng_fc(struct ap_message *, int *); +unsigned int get_cprb_fc(struct ica_xcRB *, struct ap_message *, + unsigned int *, unsigned short **); +unsigned int get_ep11cprb_fc(struct ep11_urb *, struct ap_message *, + unsigned int *); +unsigned int get_rng_fc(struct ap_message *, int *, unsigned int *); #define LOW 10 #define MEDIUM 100 @@ -134,7 +136,8 @@ int speed_idx_ep11(int); * @ap_msg: pointer to AP message */ static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg, - unsigned int random_number_length) + unsigned int random_number_length, + unsigned int *domain) { struct { struct type6_hdr hdr; @@ -172,6 +175,7 @@ static inline void rng_type6CPRB_msgX(struct ap_message *ap_msg, msg->verb_length = 0x02; msg->key_length = 0x02; ap_msg->length = sizeof(*msg); + *domain = (unsigned short)msg->cprbx.domain; } void zcrypt_msgtype6_init(void); diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 43de39c74944..26ceaa696765 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "ap_bus.h" #include "zcrypt_api.h" @@ -62,142 +63,34 @@ struct response_type { #define PCIXCC_RESPONSE_TYPE_ICA 0 #define PCIXCC_RESPONSE_TYPE_XCRB 1 -static struct ap_device_id zcrypt_pcixcc_ids[] = { - { AP_DEVICE(AP_DEVICE_TYPE_PCIXCC) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX2C) }, - { AP_DEVICE(AP_DEVICE_TYPE_CEX3C) }, - { /* end of list */ }, -}; - -MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_ids); MODULE_AUTHOR("IBM Corporation"); MODULE_DESCRIPTION("PCIXCC Cryptographic Coprocessor device driver, " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); -static int zcrypt_pcixcc_probe(struct ap_device *ap_dev); -static void zcrypt_pcixcc_remove(struct ap_device *ap_dev); - -static struct ap_driver zcrypt_pcixcc_driver = { - .probe = zcrypt_pcixcc_probe, - .remove = zcrypt_pcixcc_remove, - .ids = zcrypt_pcixcc_ids, - .request_timeout = PCIXCC_CLEANUP_TIME, +static struct ap_device_id zcrypt_pcixcc_card_ids[] = { + { .dev_type = AP_DEVICE_TYPE_PCIXCC, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX2C, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3C, + .match_flags = AP_DEVICE_ID_MATCH_CARD_TYPE }, + { /* end of list */ }, }; -/** - * Micro-code detection function. Its sends a message to a pcixcc card - * to find out the microcode level. - * @ap_dev: pointer to the AP device. - */ -static int zcrypt_pcixcc_mcl(struct ap_device *ap_dev) -{ - static unsigned char msg[] = { - 0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x58,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x43,0x41,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x00, - 0x00,0x00,0x01,0xC4,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x07,0x24,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0xDC,0x02,0x00,0x00,0x00,0x54,0x32, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE8, - 0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x24, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x04,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x50,0x4B,0x00,0x0A, - 0x4D,0x52,0x50,0x20,0x20,0x20,0x20,0x20, - 0x00,0x42,0x00,0x01,0x02,0x03,0x04,0x05, - 0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D, - 0x0E,0x0F,0x00,0x11,0x22,0x33,0x44,0x55, - 0x66,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD, - 0xEE,0xFF,0xFF,0xEE,0xDD,0xCC,0xBB,0xAA, - 0x99,0x88,0x77,0x66,0x55,0x44,0x33,0x22, - 0x11,0x00,0x01,0x23,0x45,0x67,0x89,0xAB, - 0xCD,0xEF,0xFE,0xDC,0xBA,0x98,0x76,0x54, - 0x32,0x10,0x00,0x9A,0x00,0x98,0x00,0x00, - 0x1E,0x00,0x00,0x94,0x00,0x00,0x00,0x00, - 0x04,0x00,0x00,0x8C,0x00,0x00,0x00,0x40, - 0x02,0x00,0x00,0x40,0xBA,0xE8,0x23,0x3C, - 0x75,0xF3,0x91,0x61,0xD6,0x73,0x39,0xCF, - 0x7B,0x6D,0x8E,0x61,0x97,0x63,0x9E,0xD9, - 0x60,0x55,0xD6,0xC7,0xEF,0xF8,0x1E,0x63, - 0x95,0x17,0xCC,0x28,0x45,0x60,0x11,0xC5, - 0xC4,0x4E,0x66,0xC6,0xE6,0xC3,0xDE,0x8A, - 0x19,0x30,0xCF,0x0E,0xD7,0xAA,0xDB,0x01, - 0xD8,0x00,0xBB,0x8F,0x39,0x9F,0x64,0x28, - 0xF5,0x7A,0x77,0x49,0xCC,0x6B,0xA3,0x91, - 0x97,0x70,0xE7,0x60,0x1E,0x39,0xE1,0xE5, - 0x33,0xE1,0x15,0x63,0x69,0x08,0x80,0x4C, - 0x67,0xC4,0x41,0x8F,0x48,0xDF,0x26,0x98, - 0xF1,0xD5,0x8D,0x88,0xD9,0x6A,0xA4,0x96, - 0xC5,0x84,0xD9,0x30,0x49,0x67,0x7D,0x19, - 0xB1,0xB3,0x45,0x4D,0xB2,0x53,0x9A,0x47, - 0x3C,0x7C,0x55,0xBF,0xCC,0x85,0x00,0x36, - 0xF1,0x3D,0x93,0x53 - }; - unsigned long long psmid; - struct CPRBX *cprbx; - char *reply; - int rc, i; - - reply = (void *) get_zeroed_page(GFP_KERNEL); - if (!reply) - return -ENOMEM; +MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_card_ids); - rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, msg, sizeof(msg)); - if (rc) - goto out_free; - - /* Wait for the test message to complete. */ - for (i = 0; i < 6; i++) { - msleep(300); - rc = ap_recv(ap_dev->qid, &psmid, reply, 4096); - if (rc == 0 && psmid == 0x0102030405060708ULL) - break; - } - - if (i >= 6) { - /* Got no answer. */ - rc = -ENODEV; - goto out_free; - } +static struct ap_device_id zcrypt_pcixcc_queue_ids[] = { + { .dev_type = AP_DEVICE_TYPE_PCIXCC, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX2C, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { .dev_type = AP_DEVICE_TYPE_CEX3C, + .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE }, + { /* end of list */ }, +}; - cprbx = (struct CPRBX *) (reply + 48); - if (cprbx->ccp_rtcode == 8 && cprbx->ccp_rscode == 33) - rc = ZCRYPT_PCIXCC_MCL2; - else - rc = ZCRYPT_PCIXCC_MCL3; -out_free: - free_page((unsigned long) reply); - return rc; -} +MODULE_DEVICE_TABLE(ap, zcrypt_pcixcc_queue_ids); /** * Large random number detection function. Its sends a message to a pcixcc @@ -206,10 +99,11 @@ out_free: * * Returns 1 if large random numbers are supported, 0 if not and < 0 on error. */ -static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) +static int zcrypt_pcixcc_rng_supported(struct ap_queue *aq) { struct ap_message ap_msg; unsigned long long psmid; + unsigned int domain; struct { struct type86_hdr hdr; struct type86_fmt2_ext fmt2; @@ -231,12 +125,12 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) if (!ap_msg.message) return -ENOMEM; - rng_type6CPRB_msgX(&ap_msg, 4); + rng_type6CPRB_msgX(&ap_msg, 4, &domain); msg = ap_msg.message; - msg->cprbx.domain = AP_QID_QUEUE(ap_dev->qid); + msg->cprbx.domain = AP_QID_QUEUE(aq->qid); - rc = ap_send(ap_dev->qid, 0x0102030405060708ULL, ap_msg.message, + rc = ap_send(aq->qid, 0x0102030405060708ULL, ap_msg.message, ap_msg.length); if (rc) goto out_free; @@ -244,7 +138,7 @@ static int zcrypt_pcixcc_rng_supported(struct ap_device *ap_dev) /* Wait for the test message to complete. */ for (i = 0; i < 2 * HZ; i++) { msleep(1000 / HZ); - rc = ap_recv(ap_dev->qid, &psmid, ap_msg.message, 4096); + rc = ap_recv(aq->qid, &psmid, ap_msg.message, 4096); if (rc == 0 && psmid == 0x0102030405060708ULL) break; } @@ -266,120 +160,168 @@ out_free: } /** - * Probe function for PCIXCC/CEX2C cards. It always accepts the AP device - * since the bus_match already checked the hardware type. The PCIXCC - * cards come in two flavours: micro code level 2 and micro code level 3. - * This is checked by sending a test message to the device. - * @ap_dev: pointer to the AP device. + * Probe function for PCIXCC/CEX2C card devices. It always accepts the + * AP device since the bus_match already checked the hardware type. The + * PCIXCC cards come in two flavours: micro code level 2 and micro code + * level 3. This is checked by sending a test message to the device. + * @ap_dev: pointer to the AP card device. */ -static int zcrypt_pcixcc_probe(struct ap_device *ap_dev) +static int zcrypt_pcixcc_card_probe(struct ap_device *ap_dev) { - struct zcrypt_device *zdev; /* * Normalized speed ratings per crypto adapter * MEX_1k, MEX_2k, MEX_4k, CRT_1k, CRT_2k, CRT_4k, RNG, SECKEY */ - int PCIXCC_MCL2_SPEED_IDX[] = {10, 10, 10, 10, 10, 10, 10, 10}; - int PCIXCC_MCL3_SPEED_IDX[] = { 8, 8, 8, 8, 8, 8, 8, 8}; - int CEX2C_SPEED_IDX[] = {1000, 1400, 2400, 1100, 1500, 2600, 100, 12}; - int CEX3C_SPEED_IDX[] = { 500, 700, 1400, 550, 800, 1500, 80, 10}; + static const int CEX2C_SPEED_IDX[] = { + 1000, 1400, 2400, 1100, 1500, 2600, 100, 12}; + static const int CEX3C_SPEED_IDX[] = { + 500, 700, 1400, 550, 800, 1500, 80, 10}; + + struct ap_card *ac = to_ap_card(&ap_dev->device); + struct zcrypt_card *zc; int rc = 0; - zdev = zcrypt_device_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); - if (!zdev) + zc = zcrypt_card_alloc(); + if (!zc) return -ENOMEM; - zdev->ap_dev = ap_dev; - zdev->online = 1; - switch (ap_dev->device_type) { - case AP_DEVICE_TYPE_PCIXCC: - rc = zcrypt_pcixcc_mcl(ap_dev); - if (rc < 0) { - zcrypt_device_free(zdev); - return rc; - } - zdev->user_space_type = rc; - if (rc == ZCRYPT_PCIXCC_MCL2) { - zdev->type_string = "PCIXCC_MCL2"; - memcpy(zdev->speed_rating, PCIXCC_MCL2_SPEED_IDX, - sizeof(PCIXCC_MCL2_SPEED_IDX)); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; - zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; - zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; - } else { - zdev->type_string = "PCIXCC_MCL3"; - memcpy(zdev->speed_rating, PCIXCC_MCL3_SPEED_IDX, - sizeof(PCIXCC_MCL3_SPEED_IDX)); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; - zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; - zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; - } - break; + zc->card = ac; + ac->private = zc; + switch (ac->ap_dev.device_type) { case AP_DEVICE_TYPE_CEX2C: - zdev->user_space_type = ZCRYPT_CEX2C; - zdev->type_string = "CEX2C"; - memcpy(zdev->speed_rating, CEX2C_SPEED_IDX, + zc->user_space_type = ZCRYPT_CEX2C; + zc->type_string = "CEX2C"; + memcpy(zc->speed_rating, CEX2C_SPEED_IDX, sizeof(CEX2C_SPEED_IDX)); - zdev->min_mod_size = PCIXCC_MIN_MOD_SIZE; - zdev->max_mod_size = PCIXCC_MAX_MOD_SIZE; - zdev->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; + zc->min_mod_size = PCIXCC_MIN_MOD_SIZE; + zc->max_mod_size = PCIXCC_MAX_MOD_SIZE; + zc->max_exp_bit_length = PCIXCC_MAX_MOD_SIZE; break; case AP_DEVICE_TYPE_CEX3C: - zdev->user_space_type = ZCRYPT_CEX3C; - zdev->type_string = "CEX3C"; - memcpy(zdev->speed_rating, CEX3C_SPEED_IDX, + zc->user_space_type = ZCRYPT_CEX3C; + zc->type_string = "CEX3C"; + memcpy(zc->speed_rating, CEX3C_SPEED_IDX, sizeof(CEX3C_SPEED_IDX)); - zdev->min_mod_size = CEX3C_MIN_MOD_SIZE; - zdev->max_mod_size = CEX3C_MAX_MOD_SIZE; - zdev->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; + zc->min_mod_size = CEX3C_MIN_MOD_SIZE; + zc->max_mod_size = CEX3C_MAX_MOD_SIZE; + zc->max_exp_bit_length = CEX3C_MAX_MOD_SIZE; break; default: - goto out_free; + zcrypt_card_free(zc); + return -ENODEV; } - zdev->load = zdev->speed_rating[0]; + zc->online = 1; - rc = zcrypt_pcixcc_rng_supported(ap_dev); + rc = zcrypt_card_register(zc); + if (rc) { + ac->private = NULL; + zcrypt_card_free(zc); + } + + return rc; +} + +/** + * This is called to remove the PCIXCC/CEX2C card driver information + * if an AP card device is removed. + */ +static void zcrypt_pcixcc_card_remove(struct ap_device *ap_dev) +{ + struct zcrypt_card *zc = to_ap_card(&ap_dev->device)->private; + + if (zc) + zcrypt_card_unregister(zc); +} + +static struct ap_driver zcrypt_pcixcc_card_driver = { + .probe = zcrypt_pcixcc_card_probe, + .remove = zcrypt_pcixcc_card_remove, + .ids = zcrypt_pcixcc_card_ids, +}; + +/** + * Probe function for PCIXCC/CEX2C queue devices. It always accepts the + * AP device since the bus_match already checked the hardware type. The + * PCIXCC cards come in two flavours: micro code level 2 and micro code + * level 3. This is checked by sending a test message to the device. + * @ap_dev: pointer to the AP card device. + */ +static int zcrypt_pcixcc_queue_probe(struct ap_device *ap_dev) +{ + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq; + int rc; + + zq = zcrypt_queue_alloc(PCIXCC_MAX_XCRB_MESSAGE_SIZE); + if (!zq) + return -ENOMEM; + zq->queue = aq; + zq->online = 1; + atomic_set(&zq->load, 0); + rc = zcrypt_pcixcc_rng_supported(aq); if (rc < 0) { - zcrypt_device_free(zdev); + zcrypt_queue_free(zq); return rc; } if (rc) - zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_DEFAULT); + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_DEFAULT); else - zdev->ops = zcrypt_msgtype(MSGTYPE06_NAME, - MSGTYPE06_VARIANT_NORNG); - ap_device_init_reply(ap_dev, &zdev->reply); - ap_dev->private = zdev; - rc = zcrypt_device_register(zdev); - if (rc) - goto out_free; - return 0; - - out_free: - ap_dev->private = NULL; - zcrypt_device_free(zdev); + zq->ops = zcrypt_msgtype(MSGTYPE06_NAME, + MSGTYPE06_VARIANT_NORNG); + ap_queue_init_reply(aq, &zq->reply); + aq->request_timeout = PCIXCC_CLEANUP_TIME, + aq->private = zq; + rc = zcrypt_queue_register(zq); + if (rc) { + aq->private = NULL; + zcrypt_queue_free(zq); + } return rc; } /** - * This is called to remove the extended PCIXCC/CEX2C driver information - * if an AP device is removed. + * This is called to remove the PCIXCC/CEX2C queue driver information + * if an AP queue device is removed. */ -static void zcrypt_pcixcc_remove(struct ap_device *ap_dev) +static void zcrypt_pcixcc_queue_remove(struct ap_device *ap_dev) { - struct zcrypt_device *zdev = ap_dev->private; + struct ap_queue *aq = to_ap_queue(&ap_dev->device); + struct zcrypt_queue *zq = aq->private; - zcrypt_device_unregister(zdev); + ap_queue_remove(aq); + if (zq) + zcrypt_queue_unregister(zq); } +static struct ap_driver zcrypt_pcixcc_queue_driver = { + .probe = zcrypt_pcixcc_queue_probe, + .remove = zcrypt_pcixcc_queue_remove, + .suspend = ap_queue_suspend, + .resume = ap_queue_resume, + .ids = zcrypt_pcixcc_queue_ids, +}; + int __init zcrypt_pcixcc_init(void) { - return ap_driver_register(&zcrypt_pcixcc_driver, THIS_MODULE, "pcixcc"); + int rc; + + rc = ap_driver_register(&zcrypt_pcixcc_card_driver, + THIS_MODULE, "pcixcccard"); + if (rc) + return rc; + + rc = ap_driver_register(&zcrypt_pcixcc_queue_driver, + THIS_MODULE, "pcixccqueue"); + if (rc) + ap_driver_unregister(&zcrypt_pcixcc_card_driver); + + return rc; } void zcrypt_pcixcc_exit(void) { - ap_driver_unregister(&zcrypt_pcixcc_driver); + ap_driver_unregister(&zcrypt_pcixcc_queue_driver); + ap_driver_unregister(&zcrypt_pcixcc_card_driver); } module_init(zcrypt_pcixcc_init); diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c new file mode 100644 index 000000000000..c70b2528d9a3 --- /dev/null +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -0,0 +1,221 @@ +/* + * zcrypt 2.1.0 + * + * Copyright IBM Corp. 2001, 2012 + * Author(s): Robert Burroughs + * Eric Rossman (edrossma@us.ibm.com) + * Cornelia Huck + * + * Hotplug & misc device support: Jochen Roehrig (roehrig@de.ibm.com) + * Major cleanup & driver split: Martin Schwidefsky + * Ralph Wuerthner + * MSGTYPE restruct: Holger Dengler + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "zcrypt_debug.h" +#include "zcrypt_api.h" + +#include "zcrypt_msgtype6.h" +#include "zcrypt_msgtype50.h" + +/* + * Device attributes common for all crypto queue devices. + */ + +static ssize_t zcrypt_queue_online_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct zcrypt_queue *zq = to_ap_queue(dev)->private; + + return snprintf(buf, PAGE_SIZE, "%d\n", zq->online); +} + +static ssize_t zcrypt_queue_online_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zcrypt_queue *zq = to_ap_queue(dev)->private; + struct zcrypt_card *zc = zq->zcard; + int online; + + if (sscanf(buf, "%d\n", &online) != 1 || online < 0 || online > 1) + return -EINVAL; + + if (online && !zc->online) + return -EINVAL; + zq->online = online; + ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dman", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), online); + if (!online) + ap_flush_queue(zq->queue); + return count; +} + +static DEVICE_ATTR(online, 0644, zcrypt_queue_online_show, + zcrypt_queue_online_store); + +static struct attribute *zcrypt_queue_attrs[] = { + &dev_attr_online.attr, + NULL, +}; + +static struct attribute_group zcrypt_queue_attr_group = { + .attrs = zcrypt_queue_attrs, +}; + +void zcrypt_queue_force_online(struct zcrypt_queue *zq, int online) +{ + zq->online = online; + if (!online) + ap_flush_queue(zq->queue); +} + +struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size) +{ + struct zcrypt_queue *zq; + + zq = kzalloc(sizeof(struct zcrypt_queue), GFP_KERNEL); + if (!zq) + return NULL; + zq->reply.message = kmalloc(max_response_size, GFP_KERNEL); + if (!zq->reply.message) + goto out_free; + zq->reply.length = max_response_size; + INIT_LIST_HEAD(&zq->list); + zq->dbf_area = zcrypt_dbf_devices; + kref_init(&zq->refcount); + return zq; + +out_free: + kfree(zq); + return NULL; +} +EXPORT_SYMBOL(zcrypt_queue_alloc); + +void zcrypt_queue_free(struct zcrypt_queue *zq) +{ + kfree(zq->reply.message); + kfree(zq); +} +EXPORT_SYMBOL(zcrypt_queue_free); + +static void zcrypt_queue_release(struct kref *kref) +{ + struct zcrypt_queue *zq = + container_of(kref, struct zcrypt_queue, refcount); + zcrypt_queue_free(zq); +} + +void zcrypt_queue_get(struct zcrypt_queue *zq) +{ + kref_get(&zq->refcount); +} +EXPORT_SYMBOL(zcrypt_queue_get); + +int zcrypt_queue_put(struct zcrypt_queue *zq) +{ + return kref_put(&zq->refcount, zcrypt_queue_release); +} +EXPORT_SYMBOL(zcrypt_queue_put); + +/** + * zcrypt_queue_register() - Register a crypto queue device. + * @zq: Pointer to a crypto queue device + * + * Register a crypto queue device. Returns 0 if successful. + */ +int zcrypt_queue_register(struct zcrypt_queue *zq) +{ + struct zcrypt_card *zc; + int rc; + + spin_lock(&zcrypt_list_lock); + zc = zq->queue->card->private; + zcrypt_card_get(zc); + zq->zcard = zc; + zq->online = 1; /* New devices are online by default. */ + ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dreg", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + zq->online); + list_add_tail(&zq->list, &zc->zqueues); + zcrypt_device_count++; + spin_unlock(&zcrypt_list_lock); + + rc = sysfs_create_group(&zq->queue->ap_dev.device.kobj, + &zcrypt_queue_attr_group); + if (rc) + goto out; + get_device(&zq->queue->ap_dev.device); + + if (zq->ops->rng) { + rc = zcrypt_rng_device_add(); + if (rc) + goto out_unregister; + } + return 0; + +out_unregister: + sysfs_remove_group(&zq->queue->ap_dev.device.kobj, + &zcrypt_queue_attr_group); + put_device(&zq->queue->ap_dev.device); +out: + spin_lock(&zcrypt_list_lock); + list_del_init(&zq->list); + spin_unlock(&zcrypt_list_lock); + zcrypt_card_put(zc); + return rc; +} +EXPORT_SYMBOL(zcrypt_queue_register); + +/** + * zcrypt_queue_unregister(): Unregister a crypto queue device. + * @zq: Pointer to crypto queue device + * + * Unregister a crypto queue device. + */ +void zcrypt_queue_unregister(struct zcrypt_queue *zq) +{ + struct zcrypt_card *zc; + + zc = zq->zcard; + spin_lock(&zcrypt_list_lock); + list_del_init(&zq->list); + zcrypt_device_count--; + spin_unlock(&zcrypt_list_lock); + zcrypt_card_put(zc); + if (zq->ops->rng) + zcrypt_rng_device_remove(); + sysfs_remove_group(&zq->queue->ap_dev.device.kobj, + &zcrypt_queue_attr_group); + put_device(&zq->queue->ap_dev.device); + zcrypt_queue_put(zq); +} +EXPORT_SYMBOL(zcrypt_queue_unregister); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index ed84c07f6a51..8a57f0b1242d 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -175,7 +175,8 @@ struct ap_device_id { kernel_ulong_t driver_info; }; -#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01 +#define AP_DEVICE_ID_MATCH_CARD_TYPE 0x01 +#define AP_DEVICE_ID_MATCH_QUEUE_TYPE 0x02 /* s390 css bus devices (subchannels) */ struct css_device_id { -- cgit v1.2.3 From b886a9d1560d6c7d5d58344b16f53ab2cba5b666 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Thu, 25 Aug 2016 11:19:58 +0200 Subject: s390/zcrypt: Introduce new zcrypt device status API Introduce new ioctl (ZDEVICESTATUS) to provide detailed information, like hardware type, domains, status and functionality of available crypto devices. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- arch/s390/include/uapi/asm/zcrypt.h | 37 ++++++++++++++++++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 42 +++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) (limited to 'drivers') diff --git a/arch/s390/include/uapi/asm/zcrypt.h b/arch/s390/include/uapi/asm/zcrypt.h index f2b18eacaca8..a777f87ef889 100644 --- a/arch/s390/include/uapi/asm/zcrypt.h +++ b/arch/s390/include/uapi/asm/zcrypt.h @@ -215,6 +215,42 @@ struct ep11_urb { uint64_t resp; } __attribute__((packed)); +/** + * struct zcrypt_device_status + * @hwtype: raw hardware type + * @qid: 6 bit device index, 8 bit domain + * @functions: AP device function bit field 'abcdef' + * a, b, c = reserved + * d = CCA coprocessor + * e = Accelerator + * f = EP11 coprocessor + * @online online status + * @reserved reserved + */ +struct zcrypt_device_status { + unsigned int hwtype:8; + unsigned int qid:14; + unsigned int online:1; + unsigned int functions:6; + unsigned int reserved:3; +}; + +#define MAX_ZDEV_CARDIDS 64 +#define MAX_ZDEV_DOMAINS 256 + +/** + * Maximum number of zcrypt devices + */ +#define MAX_ZDEV_ENTRIES (MAX_ZDEV_CARDIDS * MAX_ZDEV_DOMAINS) + +/** + * zcrypt_device_matrix + * Device matrix of all zcrypt devices + */ +struct zcrypt_device_matrix { + struct zcrypt_device_status device[MAX_ZDEV_ENTRIES]; +}; + #define AUTOSELECT ((unsigned int)0xFFFFFFFF) #define ZCRYPT_IOCTL_MAGIC 'z' @@ -321,6 +357,7 @@ struct ep11_urb { #define ICARSACRT _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x06, 0) #define ZSECSENDCPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x81, 0) #define ZSENDEP11CPRB _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x04, 0) +#define ZDEVICESTATUS _IOC(_IOC_READ|_IOC_WRITE, ZCRYPT_IOCTL_MAGIC, 0x4f, 0) /* New status calls */ #define Z90STAT_TOTALCOUNT _IOR(ZCRYPT_IOCTL_MAGIC, 0x40, int) diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index fd0ae8cd2bee..403af9d1ebde 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -539,6 +539,29 @@ static long zcrypt_rng(char *buffer) return rc; } +static void zcrypt_device_status_mask(struct zcrypt_device_matrix *matrix) +{ + struct zcrypt_card *zc; + struct zcrypt_queue *zq; + struct zcrypt_device_status *stat; + + memset(matrix, 0, sizeof(*matrix)); + spin_lock(&zcrypt_list_lock); + for_each_zcrypt_card(zc) { + for_each_zcrypt_queue(zq, zc) { + stat = matrix->device; + stat += AP_QID_CARD(zq->queue->qid) * MAX_ZDEV_DOMAINS; + stat += AP_QID_QUEUE(zq->queue->qid); + stat->hwtype = zc->card->ap_dev.device_type; + stat->functions = zc->card->functions >> 26; + stat->qid = zq->queue->qid; + stat->online = zq->online ? 0x01 : 0x00; + } + } + spin_unlock(&zcrypt_list_lock); +} +EXPORT_SYMBOL(zcrypt_device_status_mask); + static void zcrypt_status_mask(char status[AP_DEVICES]) { struct zcrypt_card *zc; @@ -764,6 +787,25 @@ static long zcrypt_unlocked_ioctl(struct file *filp, unsigned int cmd, return -EFAULT; return rc; } + case ZDEVICESTATUS: { + struct zcrypt_device_matrix *device_status; + + device_status = kzalloc(sizeof(struct zcrypt_device_matrix), + GFP_KERNEL); + if (!device_status) + return -ENOMEM; + + zcrypt_device_status_mask(device_status); + + if (copy_to_user((char __user *) arg, device_status, + sizeof(struct zcrypt_device_matrix))) { + kfree(device_status); + return -EFAULT; + } + + kfree(device_status); + return 0; + } case Z90STAT_STATUS_MASK: { char status[AP_DEVICES]; zcrypt_status_mask(status); -- cgit v1.2.3 From e47de21dd35bad6d1e71482a66699cd04e83ea40 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Fri, 14 Oct 2016 14:34:51 +0200 Subject: s390/zcrypt: Fixed attrition of AP adapters and domains Currently the first eligible AP adapter respectively domain will be selected to service requests. In case of sequential workload, the very same adapter/domain will be used. The adapter/domain selection algorithm now considers the completed transactions per adaper/domain and therefore ensures a homogeneous utilization. Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.h | 3 +- drivers/s390/crypto/ap_card.c | 4 +-- drivers/s390/crypto/ap_queue.c | 1 + drivers/s390/crypto/zcrypt_api.c | 63 +++++++++++++++++++++++++++------------- 4 files changed, 47 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h index 54b17e142792..4dc7c88fb054 100644 --- a/drivers/s390/crypto/ap_bus.h +++ b/drivers/s390/crypto/ap_bus.h @@ -195,6 +195,7 @@ struct ap_card { unsigned int functions; /* AP device function bitfield. */ int queue_depth; /* AP queue depth.*/ int id; /* AP card number. */ + atomic_t total_request_count; /* # requests ever for this AP device.*/ }; #define to_ap_card(x) container_of((x), struct ap_card, ap_dev.device) @@ -211,7 +212,7 @@ struct ap_queue { enum ap_state state; /* State of the AP device. */ int pendingq_count; /* # requests on pendingq list. */ int requestq_count; /* # requests on requestq list. */ - int total_request_count; /* # requests ever for this AP device. */ + int total_request_count; /* # requests ever for this AP device.*/ int request_timeout; /* Request timout in jiffies. */ struct timer_list timeout; /* Timer for request timeouts. */ struct list_head pendingq; /* List of message sent to AP queue. */ diff --git a/drivers/s390/crypto/ap_card.c b/drivers/s390/crypto/ap_card.c index 731dc0dbfb75..0110d44172a3 100644 --- a/drivers/s390/crypto/ap_card.c +++ b/drivers/s390/crypto/ap_card.c @@ -63,13 +63,11 @@ static ssize_t ap_request_count_show(struct device *dev, char *buf) { struct ap_card *ac = to_ap_card(dev); - struct ap_queue *aq; unsigned int req_cnt; req_cnt = 0; spin_lock_bh(&ap_list_lock); - for_each_ap_queue(aq, ac) - req_cnt += aq->total_request_count; + req_cnt = atomic_read(&ac->total_request_count); spin_unlock_bh(&ap_list_lock); return snprintf(buf, PAGE_SIZE, "%d\n", req_cnt); } diff --git a/drivers/s390/crypto/ap_queue.c b/drivers/s390/crypto/ap_queue.c index 8f95a071b670..b58a917dc510 100644 --- a/drivers/s390/crypto/ap_queue.c +++ b/drivers/s390/crypto/ap_queue.c @@ -625,6 +625,7 @@ void ap_queue_message(struct ap_queue *aq, struct ap_message *ap_msg) list_add_tail(&ap_msg->list, &aq->requestq); aq->requestq_count++; aq->total_request_count++; + atomic_inc(&aq->card->total_request_count); /* Send/receive as many request from the queue as possible. */ ap_wait(ap_sm_event_loop(aq, AP_EVENT_POLL)); spin_unlock_bh(&aq->lock); diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 403af9d1ebde..c7b5e70f2938 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -188,6 +188,34 @@ static inline void zcrypt_drop_queue(struct zcrypt_card *zc, module_put(mod); } +static inline bool zcrypt_card_compare(struct zcrypt_card *zc, + struct zcrypt_card *pref_zc, + unsigned weight, unsigned pref_weight) +{ + if (!pref_zc) + return 0; + weight += atomic_read(&zc->load); + pref_weight += atomic_read(&pref_zc->load); + if (weight == pref_weight) + return atomic_read(&zc->card->total_request_count) > + atomic_read(&pref_zc->card->total_request_count); + return weight > pref_weight; +} + +static inline bool zcrypt_queue_compare(struct zcrypt_queue *zq, + struct zcrypt_queue *pref_zq, + unsigned weight, unsigned pref_weight) +{ + if (!pref_zq) + return 0; + weight += atomic_read(&zq->load); + pref_weight += atomic_read(&pref_zq->load); + if (weight == pref_weight) + return &zq->queue->total_request_count > + &pref_zq->queue->total_request_count; + return weight > pref_weight; +} + /* * zcrypt ioctls. */ @@ -225,15 +253,14 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -289,15 +316,14 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -346,8 +372,7 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) continue; /* get weight index of the card device */ weight = speed_idx_cca(func_code) * zc->speed_rating[SECKEY]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -355,8 +380,8 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) ((*domain != (unsigned short) AUTOSELECT) && (*domain != AP_QID_QUEUE(zq->queue->qid)))) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -450,8 +475,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) continue; /* get weight index of the card device */ weight = speed_idx_ep11(func_code) * zc->speed_rating[SECKEY]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ @@ -460,8 +484,8 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; @@ -510,15 +534,14 @@ static long zcrypt_rng(char *buffer) continue; /* get weight index of the card device */ weight = zc->speed_rating[func_code]; - if (pref_zc && atomic_read(&zc->load) + weight >= - atomic_read(&pref_zc->load) + pref_weight) + if (zcrypt_card_compare(zc, pref_zc, weight, pref_weight)) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online) continue; - if (pref_zq && atomic_read(&zq->load) + weight >= - atomic_read(&pref_zq->load) + pref_weight) + if (zcrypt_queue_compare(zq, pref_zq, + weight, pref_weight)) continue; pref_zc = zc; pref_zq = zq; -- cgit v1.2.3 From 148784246ef2d85f000713cf56e1c90b405228e8 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 27 Oct 2016 08:57:39 +0200 Subject: s390/zcrypt: Correct function bits for CEX2x and CEX3x cards. For the older CEX2x and CEX3x cards the function bits returned by TAPQ do not reflect the functions of the card. Instead the functionality is implicit by the type of the card. The reworked zcrypt requires to have the function bits set correct, so this patch fixes this. The queue selection is not only based on these function bits but also on function pointers set by the individual drivers. Signed-off-by: Harald Freudenberger Signed-off-by: Ingo Tuchscherer Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 17 +++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 8 +++++--- 2 files changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index ac6c258300cf..b15013234c77 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -273,6 +273,23 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, nd = (info >> 16) & 0xff; if ((info & (1UL << 57)) && nd > 0) ap_max_domain_id = nd; + switch (*device_type) { + /* For CEX2 and CEX3 the available functions + * are not refrected by the facilities bits. + * Instead it is coded into the type. So here + * modify the function bits based on the type. + */ + case AP_DEVICE_TYPE_CEX2A: + case AP_DEVICE_TYPE_CEX3A: + *facilities |= 0x08000000; + break; + case AP_DEVICE_TYPE_CEX2C: + case AP_DEVICE_TYPE_CEX3C: + *facilities |= 0x10000000; + break; + default: + break; + } return 0; case AP_RESPONSE_Q_NOT_AVAIL: case AP_RESPONSE_DECONFIGURED: diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index c7b5e70f2938..71e298fe339f 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -257,7 +257,7 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ - if (!zq->online) + if (!zq->online || !zq->ops->rsa_modexpo) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) @@ -320,7 +320,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ - if (!zq->online) + if (!zq->online || !zq->ops->rsa_modexpo_crt) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) @@ -377,6 +377,7 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online || + !zq->ops->send_cprb || ((*domain != (unsigned short) AUTOSELECT) && (*domain != AP_QID_QUEUE(zq->queue->qid)))) continue; @@ -480,6 +481,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ if (!zq->online || + !zq->ops->send_ep11_cprb || (targets && !is_desired_ep11_queue(zq->queue->qid, target_num, targets))) @@ -538,7 +540,7 @@ static long zcrypt_rng(char *buffer) continue; for_each_zcrypt_queue(zq, zc) { /* check if device is online and eligible */ - if (!zq->online) + if (!zq->online || !zq->ops->rng) continue; if (zcrypt_queue_compare(zq, pref_zq, weight, pref_weight)) -- cgit v1.2.3 From c1c1368de497648cf532e7f37a407361c70aa638 Mon Sep 17 00:00:00 2001 From: Ingo Tuchscherer Date: Wed, 2 Nov 2016 10:23:24 +0100 Subject: s390/zcrypt: Fix ap_max_domain_id for older machine types According to the system architecture the current implementation requires the presence of the N bit in GR2 in the TAPQ response field to validate the max. number of domains (Nd). Older machine types don't have this N bit, hence the max. domain field was ignored. Before the N bit was introduced the maximum number of domain was a constant value of 15. So set this value in case of N bit absence. Signed-off-by: Ingo Tuchscherer Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index b15013234c77..78c99ae42b1f 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -271,8 +271,11 @@ static int ap_query_queue(ap_qid_t qid, int *queue_depth, int *device_type, *facilities = (unsigned int)(info >> 32); /* Update maximum domain id */ nd = (info >> 16) & 0xff; + /* if N bit is available, z13 and newer */ if ((info & (1UL << 57)) && nd > 0) ap_max_domain_id = nd; + else /* older machine types */ + ap_max_domain_id = 15; switch (*device_type) { /* For CEX2 and CEX3 the available functions * are not refrected by the facilities bits. -- cgit v1.2.3 From bf9f31190aa176c43c15cf58b60818d325e0f851 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Fri, 25 Nov 2016 11:50:16 +0100 Subject: s390/zcrypt: Improved invalid domain response handling. Add defines and switch case code to handle the two invalid domain response codes better. Until now these two response codes are handled via default resulting in -EAGAIN and switching the processed queue to offline. So this kind of malformed request bounced through all suitable queues and switched them off. Now this kind of malformed request is just rejected with EINVAL without switching off the queue. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/zcrypt_error.h | 62 ++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 09247331e9fb..865978879661 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -55,37 +55,39 @@ struct error_hdr { #define TYPE82_RSP_CODE 0x82 #define TYPE88_RSP_CODE 0x88 -#define REP82_ERROR_MACHINE_FAILURE 0x10 -#define REP82_ERROR_PREEMPT_FAILURE 0x12 -#define REP82_ERROR_CHECKPT_FAILURE 0x14 -#define REP82_ERROR_MESSAGE_TYPE 0x20 -#define REP82_ERROR_INVALID_COMM_CD 0x21 /* Type 84 */ -#define REP82_ERROR_INVALID_MSG_LEN 0x23 -#define REP82_ERROR_RESERVD_FIELD 0x24 /* was 0x50 */ -#define REP82_ERROR_FORMAT_FIELD 0x29 -#define REP82_ERROR_INVALID_COMMAND 0x30 -#define REP82_ERROR_MALFORMED_MSG 0x40 -#define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */ -#define REP82_ERROR_WORD_ALIGNMENT 0x60 -#define REP82_ERROR_MESSAGE_LENGTH 0x80 -#define REP82_ERROR_OPERAND_INVALID 0x82 -#define REP82_ERROR_OPERAND_SIZE 0x84 -#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85 -#define REP82_ERROR_RESERVED_FIELD 0x88 -#define REP82_ERROR_TRANSPORT_FAIL 0x90 -#define REP82_ERROR_PACKET_TRUNCATED 0xA0 -#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0 +#define REP82_ERROR_MACHINE_FAILURE 0x10 +#define REP82_ERROR_PREEMPT_FAILURE 0x12 +#define REP82_ERROR_CHECKPT_FAILURE 0x14 +#define REP82_ERROR_MESSAGE_TYPE 0x20 +#define REP82_ERROR_INVALID_COMM_CD 0x21 /* Type 84 */ +#define REP82_ERROR_INVALID_MSG_LEN 0x23 +#define REP82_ERROR_RESERVD_FIELD 0x24 /* was 0x50 */ +#define REP82_ERROR_FORMAT_FIELD 0x29 +#define REP82_ERROR_INVALID_COMMAND 0x30 +#define REP82_ERROR_MALFORMED_MSG 0x40 +#define REP82_ERROR_INVALID_DOMAIN_PRECHECK 0x42 +#define REP82_ERROR_RESERVED_FIELDO 0x50 /* old value */ +#define REP82_ERROR_WORD_ALIGNMENT 0x60 +#define REP82_ERROR_MESSAGE_LENGTH 0x80 +#define REP82_ERROR_OPERAND_INVALID 0x82 +#define REP82_ERROR_OPERAND_SIZE 0x84 +#define REP82_ERROR_EVEN_MOD_IN_OPND 0x85 +#define REP82_ERROR_RESERVED_FIELD 0x88 +#define REP82_ERROR_INVALID_DOMAIN_PENDING 0x8A +#define REP82_ERROR_TRANSPORT_FAIL 0x90 +#define REP82_ERROR_PACKET_TRUNCATED 0xA0 +#define REP82_ERROR_ZERO_BUFFER_LEN 0xB0 -#define REP88_ERROR_MODULE_FAILURE 0x10 +#define REP88_ERROR_MODULE_FAILURE 0x10 -#define REP88_ERROR_MESSAGE_TYPE 0x20 -#define REP88_ERROR_MESSAGE_MALFORMD 0x22 -#define REP88_ERROR_MESSAGE_LENGTH 0x23 -#define REP88_ERROR_RESERVED_FIELD 0x24 -#define REP88_ERROR_KEY_TYPE 0x34 -#define REP88_ERROR_INVALID_KEY 0x82 /* CEX2A */ -#define REP88_ERROR_OPERAND 0x84 /* CEX2A */ -#define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */ +#define REP88_ERROR_MESSAGE_TYPE 0x20 +#define REP88_ERROR_MESSAGE_MALFORMD 0x22 +#define REP88_ERROR_MESSAGE_LENGTH 0x23 +#define REP88_ERROR_RESERVED_FIELD 0x24 +#define REP88_ERROR_KEY_TYPE 0x34 +#define REP88_ERROR_INVALID_KEY 0x82 /* CEX2A */ +#define REP88_ERROR_OPERAND 0x84 /* CEX2A */ +#define REP88_ERROR_OPERAND_EVEN_MOD 0x85 /* CEX2A */ static inline int convert_error(struct zcrypt_queue *zq, struct ap_message *reply) @@ -97,6 +99,8 @@ static inline int convert_error(struct zcrypt_queue *zq, case REP82_ERROR_OPERAND_SIZE: case REP82_ERROR_EVEN_MOD_IN_OPND: case REP88_ERROR_MESSAGE_MALFORMD: + case REP82_ERROR_INVALID_DOMAIN_PRECHECK: + case REP82_ERROR_INVALID_DOMAIN_PENDING: // REP88_ERROR_INVALID_KEY // '82' CEX2A // REP88_ERROR_OPERAND // '84' CEX2A // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A -- cgit v1.2.3 From cccd85bfb7bf6787302435c669ceec23b5a5301c Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Thu, 24 Nov 2016 06:45:21 +0100 Subject: s390/zcrypt: Rework debug feature invocations. Rework the debug feature calls and initialization. There are now two debug feature entries used by the zcrypt code. The first is 'ap' with all the AP bus related stuff and the second is 'zcrypt' with all the zcrypt and devices and driver related entries. However, there isn't much traffic on both debug features. The ap bus code emits only some debug info and for zcrypt devices on appearance and disappearance there is an entry written. The new dbf invocations use the sprintf buffer layout, whereas the old implementation used the ascii dbf buffer. There are now 5*8=40 bytes used for each entry, resulting in 5 parameters per call. As the sprintf buffer needs a format string the first parameter provides this and so up to 4 more parameters can be used. Alltogehter the new layout should be much more human readable for customers and test. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_bus.c | 40 +++++++++++++++++ drivers/s390/crypto/ap_debug.h | 28 ++++++++++++ drivers/s390/crypto/zcrypt_api.c | 38 ++++++---------- drivers/s390/crypto/zcrypt_api.h | 8 ---- drivers/s390/crypto/zcrypt_card.c | 10 ++++- drivers/s390/crypto/zcrypt_debug.h | 50 ++++++--------------- drivers/s390/crypto/zcrypt_error.h | 35 ++++++++------- drivers/s390/crypto/zcrypt_msgtype50.c | 23 +++++----- drivers/s390/crypto/zcrypt_msgtype6.c | 80 +++++++++++++++++++--------------- drivers/s390/crypto/zcrypt_queue.c | 21 +++++---- 10 files changed, 190 insertions(+), 143 deletions(-) create mode 100644 drivers/s390/crypto/ap_debug.h (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c index 78c99ae42b1f..6d75984a3d85 100644 --- a/drivers/s390/crypto/ap_bus.c +++ b/drivers/s390/crypto/ap_bus.c @@ -47,9 +47,11 @@ #include #include #include +#include #include "ap_bus.h" #include "ap_asm.h" +#include "ap_debug.h" /* * Module description. @@ -81,6 +83,12 @@ LIST_HEAD(ap_card_list); static struct ap_config_info *ap_configuration; static bool initialised; +/* + * AP bus related debug feature things. + */ +static struct dentry *ap_dbf_root; +debug_info_t *ap_dbf_info; + /* * Workqueue timer for bus rescan. */ @@ -568,6 +576,8 @@ static int ap_dev_resume(struct device *dev) static void ap_bus_suspend(void) { + AP_DBF(DBF_DEBUG, "ap_bus_suspend running\n"); + ap_suspend_flag = 1; /* * Disable scanning for devices, thus we do not want to scan @@ -603,6 +613,8 @@ static void ap_bus_resume(void) { int rc; + AP_DBF(DBF_DEBUG, "ap_bus_resume running\n"); + /* remove all queue devices */ bus_for_each_dev(&ap_bus_type, NULL, NULL, __ap_queue_devices_unregister); @@ -742,6 +754,9 @@ static ssize_t ap_domain_store(struct bus_type *bus, spin_lock_bh(&ap_domain_lock); ap_domain_index = domain; spin_unlock_bh(&ap_domain_lock); + + AP_DBF(DBF_DEBUG, "store new default domain=%d\n", domain); + return count; } @@ -964,6 +979,8 @@ static void ap_scan_bus(struct work_struct *unused) unsigned int functions = 0; int rc, id, dom, borked, domains; + AP_DBF(DBF_DEBUG, "ap_scan_bus running\n"); + ap_query_configuration(); if (ap_select_domain() != 0) goto out; @@ -1129,6 +1146,23 @@ static struct reset_call ap_reset_call = { .fn = ap_reset_all, }; +int __init ap_debug_init(void) +{ + ap_dbf_root = debugfs_create_dir("ap", NULL); + ap_dbf_info = debug_register("ap", 1, 1, + DBF_MAX_SPRINTF_ARGS * sizeof(long)); + debug_register_view(ap_dbf_info, &debug_sprintf_view); + debug_set_level(ap_dbf_info, DBF_ERR); + + return 0; +} + +void ap_debug_exit(void) +{ + debugfs_remove(ap_dbf_root); + debug_unregister(ap_dbf_info); +} + /** * ap_module_init(): The module initialization code. * @@ -1139,6 +1173,10 @@ int __init ap_module_init(void) int max_domain_id; int rc, i; + rc = ap_debug_init(); + if (rc) + return rc; + if (ap_instructions_available() != 0) { pr_warn("The hardware system does not support AP instructions\n"); return -ENODEV; @@ -1266,6 +1304,8 @@ void ap_module_exit(void) unregister_reset_call(&ap_reset_call); if (ap_using_interrupts()) unregister_adapter_interrupt(&ap_airq); + + ap_debug_exit(); } module_init(ap_module_init); diff --git a/drivers/s390/crypto/ap_debug.h b/drivers/s390/crypto/ap_debug.h new file mode 100644 index 000000000000..78dbff842dae --- /dev/null +++ b/drivers/s390/crypto/ap_debug.h @@ -0,0 +1,28 @@ +/* + * Copyright IBM Corp. 2016 + * Author(s): Harald Freudenberger + */ +#ifndef AP_DEBUG_H +#define AP_DEBUG_H + +#include + +#define DBF_ERR 3 /* error conditions */ +#define DBF_WARN 4 /* warning conditions */ +#define DBF_INFO 5 /* informational */ +#define DBF_DEBUG 6 /* for debugging only */ + +#define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO) +#define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO) + +#define DBF_MAX_SPRINTF_ARGS 5 + +#define AP_DBF(...) \ + debug_sprintf_event(ap_dbf_info, ##__VA_ARGS__) + +extern debug_info_t *ap_dbf_info; + +int ap_debug_init(void); +void ap_debug_exit(void); + +#endif /* AP_DEBUG_H */ diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 71e298fe339f..7ca25e77bd6a 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -41,8 +41,8 @@ #include #include -#include "zcrypt_debug.h" #include "zcrypt_api.h" +#include "zcrypt_debug.h" #include "zcrypt_msgtype6.h" #include "zcrypt_msgtype50.h" @@ -71,10 +71,9 @@ EXPORT_SYMBOL(zcrypt_rescan_req); static LIST_HEAD(zcrypt_ops_list); -static struct dentry *debugfs_root; -debug_info_t *zcrypt_dbf_common; -debug_info_t *zcrypt_dbf_devices; -debug_info_t *zcrypt_dbf_cards; +/* Zcrypt related debug feature stuff. */ +static struct dentry *zcrypt_dbf_root; +debug_info_t *zcrypt_dbf_info; /** * Process a rescan of the transport layer. @@ -87,8 +86,8 @@ static inline int zcrypt_process_rescan(void) atomic_set(&zcrypt_rescan_req, 0); atomic_inc(&zcrypt_rescan_count); ap_bus_force_rescan(); - ZCRYPT_DBF_COMMON(DBF_INFO, "rescan%07d", - atomic_inc_return(&zcrypt_rescan_count)); + ZCRYPT_DBF(DBF_INFO, "rescan count=%07d", + atomic_inc_return(&zcrypt_rescan_count)); return 1; } return 0; @@ -1363,28 +1362,19 @@ void zcrypt_rng_device_remove(void) int __init zcrypt_debug_init(void) { - debugfs_root = debugfs_create_dir("zcrypt", NULL); - - zcrypt_dbf_common = debug_register("zcrypt_common", 1, 1, 16); - debug_register_view(zcrypt_dbf_common, &debug_hex_ascii_view); - debug_set_level(zcrypt_dbf_common, DBF_ERR); - - zcrypt_dbf_devices = debug_register("zcrypt_devices", 1, 1, 16); - debug_register_view(zcrypt_dbf_devices, &debug_hex_ascii_view); - debug_set_level(zcrypt_dbf_devices, DBF_ERR); - - zcrypt_dbf_cards = debug_register("zcrypt_cards", 1, 1, 16); - debug_register_view(zcrypt_dbf_cards, &debug_hex_ascii_view); - debug_set_level(zcrypt_dbf_cards, DBF_ERR); + zcrypt_dbf_root = debugfs_create_dir("zcrypt", NULL); + zcrypt_dbf_info = debug_register("zcrypt", 1, 1, + DBF_MAX_SPRINTF_ARGS * sizeof(long)); + debug_register_view(zcrypt_dbf_info, &debug_sprintf_view); + debug_set_level(zcrypt_dbf_info, DBF_ERR); return 0; } void zcrypt_debug_exit(void) { - debugfs_remove(debugfs_root); - debug_unregister(zcrypt_dbf_common); - debug_unregister(zcrypt_dbf_devices); + debugfs_remove(zcrypt_dbf_root); + debug_unregister(zcrypt_dbf_info); } /** @@ -1434,9 +1424,9 @@ void __exit zcrypt_api_exit(void) { remove_proc_entry("driver/z90crypt", NULL); misc_deregister(&zcrypt_misc_device); - zcrypt_debug_exit(); zcrypt_msgtype6_exit(); zcrypt_msgtype50_exit(); + zcrypt_debug_exit(); } module_init(zcrypt_api_init); diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h index 4fb892b99f41..274a59051534 100644 --- a/drivers/s390/crypto/zcrypt_api.h +++ b/drivers/s390/crypto/zcrypt_api.h @@ -132,8 +132,6 @@ struct zcrypt_card { atomic_t load; /* Utilization of the crypto device */ int request_count; /* # current requests. */ - - debug_info_t *dbf_area; /* debugging */ }; struct zcrypt_queue { @@ -149,8 +147,6 @@ struct zcrypt_queue { int request_count; /* # current requests. */ struct ap_message reply; /* Per-device reply structure. */ - - debug_info_t *dbf_area; /* debugging */ }; /* transport layer rescanning */ @@ -160,10 +156,6 @@ extern spinlock_t zcrypt_list_lock; extern int zcrypt_device_count; extern struct list_head zcrypt_card_list; -extern debug_info_t *zcrypt_dbf_common; -extern debug_info_t *zcrypt_dbf_devices; -extern debug_info_t *zcrypt_dbf_cards; - #define for_each_zcrypt_card(_zc) \ list_for_each_entry(_zc, &zcrypt_card_list, list) diff --git a/drivers/s390/crypto/zcrypt_card.c b/drivers/s390/crypto/zcrypt_card.c index 57873d775e95..53436ea52230 100644 --- a/drivers/s390/crypto/zcrypt_card.c +++ b/drivers/s390/crypto/zcrypt_card.c @@ -79,7 +79,9 @@ static ssize_t zcrypt_card_online_store(struct device *dev, zc->online = online; id = zc->card->id; - ZCRYPT_DBF_DEV(DBF_INFO, zc, "card%02xo%dman", id, online); + + ZCRYPT_DBF(DBF_INFO, "card=%02x online=%d\n", id, online); + spin_lock(&zcrypt_list_lock); list_for_each_entry(zq, &zc->zqueues, list) zcrypt_queue_force_online(zq, online); @@ -109,7 +111,6 @@ struct zcrypt_card *zcrypt_card_alloc(void) return NULL; INIT_LIST_HEAD(&zc->list); INIT_LIST_HEAD(&zc->zqueues); - zc->dbf_area = zcrypt_dbf_cards; kref_init(&zc->refcount); return zc; } @@ -160,6 +161,9 @@ int zcrypt_card_register(struct zcrypt_card *zc) spin_unlock(&zcrypt_list_lock); zc->online = 1; + + ZCRYPT_DBF(DBF_INFO, "card=%02x register online=1\n", zc->card->id); + return rc; } EXPORT_SYMBOL(zcrypt_card_register); @@ -172,6 +176,8 @@ EXPORT_SYMBOL(zcrypt_card_register); */ void zcrypt_card_unregister(struct zcrypt_card *zc) { + ZCRYPT_DBF(DBF_INFO, "card=%02x unregister\n", zc->card->id); + spin_lock(&zcrypt_list_lock); list_del_init(&zc->list); spin_unlock(&zcrypt_list_lock); diff --git a/drivers/s390/crypto/zcrypt_debug.h b/drivers/s390/crypto/zcrypt_debug.h index 28d9349de1ad..13e38defb6b8 100644 --- a/drivers/s390/crypto/zcrypt_debug.h +++ b/drivers/s390/crypto/zcrypt_debug.h @@ -1,51 +1,27 @@ /* - * Copyright IBM Corp. 2012 + * Copyright IBM Corp. 2016 * Author(s): Holger Dengler (hd@linux.vnet.ibm.com) + * Harald Freudenberger */ #ifndef ZCRYPT_DEBUG_H #define ZCRYPT_DEBUG_H #include -#include "zcrypt_api.h" -/* that gives us 15 characters in the text event views */ -#define ZCRYPT_DBF_LEN 16 - -#define DBF_ERR 3 /* error conditions */ -#define DBF_WARN 4 /* warning conditions */ -#define DBF_INFO 6 /* informational */ +#define DBF_ERR 3 /* error conditions */ +#define DBF_WARN 4 /* warning conditions */ +#define DBF_INFO 5 /* informational */ +#define DBF_DEBUG 6 /* for debugging only */ +#define RC2ERR(rc) ((rc) ? DBF_ERR : DBF_INFO) #define RC2WARN(rc) ((rc) ? DBF_WARN : DBF_INFO) -#define ZCRYPT_DBF_COMMON(level, text...) \ - do { \ - if (debug_level_enabled(zcrypt_dbf_common, level)) { \ - char debug_buffer[ZCRYPT_DBF_LEN]; \ - snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ - debug_text_event(zcrypt_dbf_common, level, \ - debug_buffer); \ - } \ - } while (0) - -#define ZCRYPT_DBF_DEVICES(level, text...) \ - do { \ - if (debug_level_enabled(zcrypt_dbf_devices, level)) { \ - char debug_buffer[ZCRYPT_DBF_LEN]; \ - snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ - debug_text_event(zcrypt_dbf_devices, level, \ - debug_buffer); \ - } \ - } while (0) - -#define ZCRYPT_DBF_DEV(level, device, text...) \ - do { \ - if (debug_level_enabled(device->dbf_area, level)) { \ - char debug_buffer[ZCRYPT_DBF_LEN]; \ - snprintf(debug_buffer, ZCRYPT_DBF_LEN, text); \ - debug_text_event(device->dbf_area, level, \ - debug_buffer); \ - } \ - } while (0) +#define DBF_MAX_SPRINTF_ARGS 5 + +#define ZCRYPT_DBF(...) \ + debug_sprintf_event(zcrypt_dbf_info, ##__VA_ARGS__) + +extern debug_info_t *zcrypt_dbf_info; int zcrypt_debug_init(void); void zcrypt_debug_exit(void); diff --git a/drivers/s390/crypto/zcrypt_error.h b/drivers/s390/crypto/zcrypt_error.h index 865978879661..13df60209ed3 100644 --- a/drivers/s390/crypto/zcrypt_error.h +++ b/drivers/s390/crypto/zcrypt_error.h @@ -93,6 +93,8 @@ static inline int convert_error(struct zcrypt_queue *zq, struct ap_message *reply) { struct error_hdr *ehdr = reply->message; + int card = AP_QID_CARD(zq->queue->qid); + int queue = AP_QID_QUEUE(zq->queue->qid); switch (ehdr->reply_code) { case REP82_ERROR_OPERAND_INVALID: @@ -105,6 +107,9 @@ static inline int convert_error(struct zcrypt_queue *zq, // REP88_ERROR_OPERAND // '84' CEX2A // REP88_ERROR_OPERAND_EVEN_MOD // '85' CEX2A /* Invalid input data. */ + ZCRYPT_DBF(DBF_WARN, + "device=%02x.%04x reply=0x%02x => rc=EINVAL\n", + card, queue, ehdr->reply_code); return -EINVAL; case REP82_ERROR_MESSAGE_TYPE: // REP88_ERROR_MESSAGE_TYPE // '20' CEX2A @@ -116,12 +121,10 @@ static inline int convert_error(struct zcrypt_queue *zq, atomic_set(&zcrypt_rescan_req, 1); zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), zq->online, - ehdr->reply_code); + card, queue); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n", + card, queue, ehdr->reply_code); return -EAGAIN; case REP82_ERROR_TRANSPORT_FAIL: case REP82_ERROR_MACHINE_FAILURE: @@ -130,22 +133,18 @@ static inline int convert_error(struct zcrypt_queue *zq, atomic_set(&zcrypt_rescan_req, 1); zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), zq->online, - ehdr->reply_code); + card, queue); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n", + card, queue, ehdr->reply_code); return -EAGAIN; default: zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), zq->online, - ehdr->reply_code); + card, queue); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x reply=0x%02x => online=0 rc=EAGAIN\n", + card, queue, ehdr->reply_code); return -EAGAIN; /* repeat the request on a different device. */ } } diff --git a/drivers/s390/crypto/zcrypt_msgtype50.c b/drivers/s390/crypto/zcrypt_msgtype50.c index a9873b436115..6dd5d7c58dd0 100644 --- a/drivers/s390/crypto/zcrypt_msgtype50.c +++ b/drivers/s390/crypto/zcrypt_msgtype50.c @@ -367,11 +367,11 @@ static int convert_type80(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online, t80h->code); - + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x code=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + t80h->code); return -EAGAIN; /* repeat the request on a different device. */ } if (zq->zcard->user_space_type == ZCRYPT_CEX2A) @@ -390,7 +390,9 @@ static int convert_response(struct zcrypt_queue *zq, unsigned int outputdatalength) { /* Response type byte is the second byte in the response. */ - switch (((unsigned char *) reply->message)[1]) { + unsigned char rtype = ((unsigned char *) reply->message)[1]; + + switch (rtype) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: return convert_error(zq, reply); @@ -402,10 +404,11 @@ static int convert_response(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (unsigned int) rtype); return -EAGAIN; /* repeat the request on a different device. */ } } diff --git a/drivers/s390/crypto/zcrypt_msgtype6.c b/drivers/s390/crypto/zcrypt_msgtype6.c index c6cfb9acec19..e5563ffeb839 100644 --- a/drivers/s390/crypto/zcrypt_msgtype6.c +++ b/drivers/s390/crypto/zcrypt_msgtype6.c @@ -638,30 +638,37 @@ static int convert_type86_ica(struct zcrypt_queue *zq, service_rc = msg->cprbx.ccp_rtcode; if (unlikely(service_rc != 0)) { service_rs = msg->cprbx.ccp_rscode; - if (service_rc == 8 && service_rs == 66) - return -EINVAL; - if (service_rc == 8 && service_rs == 65) - return -EINVAL; - if (service_rc == 8 && service_rs == 770) + if ((service_rc == 8 && service_rs == 66) || + (service_rc == 8 && service_rs == 65) || + (service_rc == 8 && service_rs == 72) || + (service_rc == 8 && service_rs == 770) || + (service_rc == 12 && service_rs == 769)) { + ZCRYPT_DBF(DBF_DEBUG, + "device=%02x.%04x rc/rs=%d/%d => rc=EINVAL\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) service_rc, (int) service_rs); return -EINVAL; + } if (service_rc == 8 && service_rs == 783) { zq->zcard->min_mod_size = PCIXCC_MIN_MOD_SIZE_OLD; + ZCRYPT_DBF(DBF_DEBUG, + "device=%02x.%04x rc/rs=%d/%d => rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) service_rc, (int) service_rs); return -EAGAIN; } - if (service_rc == 12 && service_rs == 769) - return -EINVAL; - if (service_rc == 8 && service_rs == 72) - return -EINVAL; zq->online = 0; pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%drc%d", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online, - msg->hdr.reply_code); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rc/rs=%d/%d => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) service_rc, (int) service_rs); return -EAGAIN; /* repeat the request on a different device. */ } data = msg->text; @@ -776,8 +783,7 @@ static int convert_response_ica(struct zcrypt_queue *zq, { struct type86x_reply *msg = reply->message; - /* Response type byte is the second byte in the response. */ - switch (((unsigned char *) reply->message)[1]) { + switch (msg->hdr.type) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: return convert_error(zq, reply); @@ -803,10 +809,11 @@ static int convert_response_ica(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -817,8 +824,7 @@ static int convert_response_xcrb(struct zcrypt_queue *zq, { struct type86x_reply *msg = reply->message; - /* Response type byte is the second byte in the response. */ - switch (((unsigned char *) reply->message)[1]) { + switch (msg->hdr.type) { case TYPE82_RSP_CODE: case TYPE88_RSP_CODE: xcRB->status = 0x0008044DL; /* HDD_InvalidParm */ @@ -838,10 +844,11 @@ static int convert_response_xcrb(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -851,8 +858,7 @@ static int convert_response_ep11_xcrb(struct zcrypt_queue *zq, { struct type86_ep11_reply *msg = reply->message; - /* Response type byte is the second byte in the response. */ - switch (((unsigned char *)reply->message)[1]) { + switch (msg->hdr.type) { case TYPE82_RSP_CODE: case TYPE87_RSP_CODE: return convert_error(zq, reply); @@ -867,10 +873,11 @@ static int convert_response_ep11_xcrb(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } @@ -897,10 +904,11 @@ static int convert_response_rng(struct zcrypt_queue *zq, pr_err("Cryptographic device %02x.%04x failed and was set offline\n", AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); - ZCRYPT_DBF_DEV(DBF_ERR, zq, "dev%02x%04xo%dfail", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + ZCRYPT_DBF(DBF_ERR, + "device=%02x.%04x rtype=0x%02x => online=0 rc=EAGAIN\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + (int) msg->hdr.type); return -EAGAIN; /* repeat the request on a different device. */ } } diff --git a/drivers/s390/crypto/zcrypt_queue.c b/drivers/s390/crypto/zcrypt_queue.c index c70b2528d9a3..a303f3b2c328 100644 --- a/drivers/s390/crypto/zcrypt_queue.c +++ b/drivers/s390/crypto/zcrypt_queue.c @@ -70,9 +70,12 @@ static ssize_t zcrypt_queue_online_store(struct device *dev, if (online && !zc->online) return -EINVAL; zq->online = online; - ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dman", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), online); + + ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x online=%d\n", + AP_QID_CARD(zq->queue->qid), + AP_QID_QUEUE(zq->queue->qid), + online); + if (!online) ap_flush_queue(zq->queue); return count; @@ -109,7 +112,6 @@ struct zcrypt_queue *zcrypt_queue_alloc(size_t max_response_size) goto out_free; zq->reply.length = max_response_size; INIT_LIST_HEAD(&zq->list); - zq->dbf_area = zcrypt_dbf_devices; kref_init(&zq->refcount); return zq; @@ -161,10 +163,10 @@ int zcrypt_queue_register(struct zcrypt_queue *zq) zcrypt_card_get(zc); zq->zcard = zc; zq->online = 1; /* New devices are online by default. */ - ZCRYPT_DBF_DEV(DBF_INFO, zq, "dev%02x%04xo%dreg", - AP_QID_CARD(zq->queue->qid), - AP_QID_QUEUE(zq->queue->qid), - zq->online); + + ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x register online=1\n", + AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); + list_add_tail(&zq->list, &zc->zqueues); zcrypt_device_count++; spin_unlock(&zcrypt_list_lock); @@ -205,6 +207,9 @@ void zcrypt_queue_unregister(struct zcrypt_queue *zq) { struct zcrypt_card *zc; + ZCRYPT_DBF(DBF_INFO, "queue=%02x.%04x unregister\n", + AP_QID_CARD(zq->queue->qid), AP_QID_QUEUE(zq->queue->qid)); + zc = zq->zcard; spin_lock(&zcrypt_list_lock); list_del_init(&zq->list); -- cgit v1.2.3 From 13b251bdc8b97c45cc8b1d57193ab05ec0fe97e8 Mon Sep 17 00:00:00 2001 From: Harald Freudenberger Date: Fri, 25 Nov 2016 18:04:56 +0100 Subject: s390/zcrypt: tracepoint definitions for zcrypt device driver. This patch introduces tracepoint definitions and tracepoint event invocations for the s390 zcrypt device. Currently there are just two tracepoint events defined. An s390_zcrypt_req request event occurs as soon as the request is recognized by the zcrypt ioctl function. This event may act as some kind of request-processing-starts-now indication. As late as possible within the zcrypt ioctl function there occurs the s390_zcrypt_rep event which may act as the point in time where the request has been processed by the kernel and the result is about to be transferred back to userspace. The glue which binds together request and reply event is the ptr parameter, which is the local buffer address where the request from userspace has been stored by the ioctl function. The main purpose of this zcrypt tracepoint patch is to get some data for performance measurements together with information about the kind of request and on which card and queue the request has been processed. It is not an ffdc interface as there is already code in the zcrypt device driver to serve the s390 debug feature interface. Signed-off-by: Harald Freudenberger Signed-off-by: Martin Schwidefsky --- arch/s390/include/asm/trace/zcrypt.h | 122 +++++++++++++++++++++++++++++++++++ drivers/s390/crypto/zcrypt_api.c | 105 +++++++++++++++++++++++------- 2 files changed, 203 insertions(+), 24 deletions(-) create mode 100644 arch/s390/include/asm/trace/zcrypt.h (limited to 'drivers') diff --git a/arch/s390/include/asm/trace/zcrypt.h b/arch/s390/include/asm/trace/zcrypt.h new file mode 100644 index 000000000000..adcb77fafa9d --- /dev/null +++ b/arch/s390/include/asm/trace/zcrypt.h @@ -0,0 +1,122 @@ +/* + * Tracepoint definitions for the s390 zcrypt device driver + * + * Copyright IBM Corp. 2016 + * Author(s): Harald Freudenberger + * + * Currently there are two tracepoint events defined here. + * An s390_zcrypt_req request event occurs as soon as the request is + * recognized by the zcrypt ioctl function. This event may act as some kind + * of request-processing-starts-now indication. + * As late as possible within the zcrypt ioctl function there occurs the + * s390_zcrypt_rep event which may act as the point in time where the + * request has been processed by the kernel and the result is about to be + * transferred back to userspace. + * The glue which binds together request and reply event is the ptr + * parameter, which is the local buffer address where the request from + * userspace has been stored by the ioctl function. + * + * The main purpose of this zcrypt tracepoint api is to get some data for + * performance measurements together with information about on which card + * and queue the request has been processed. It is not an ffdc interface as + * there is already code in the zcrypt device driver to serve the s390 + * debug feature interface. + */ + +#undef TRACE_SYSTEM +#define TRACE_SYSTEM s390 + +#if !defined(_TRACE_S390_ZCRYPT_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_S390_ZCRYPT_H + +#include + +#define TP_ICARSAMODEXPO 0x0001 +#define TP_ICARSACRT 0x0002 +#define TB_ZSECSENDCPRB 0x0003 +#define TP_ZSENDEP11CPRB 0x0004 +#define TP_HWRNGCPRB 0x0005 + +#define show_zcrypt_tp_type(type) \ + __print_symbolic(type, \ + { TP_ICARSAMODEXPO, "ICARSAMODEXPO" }, \ + { TP_ICARSACRT, "ICARSACRT" }, \ + { TB_ZSECSENDCPRB, "ZSECSENDCPRB" }, \ + { TP_ZSENDEP11CPRB, "ZSENDEP11CPRB" }, \ + { TP_HWRNGCPRB, "HWRNGCPRB" }) + +/** + * trace_s390_zcrypt_req - zcrypt request tracepoint function + * @ptr: Address of the local buffer where the request from userspace + * is stored. Can be used as a unique id to relate together + * request and reply. + * @type: One of the TP_ defines above. + * + * Called when a request from userspace is recognised within the ioctl + * function of the zcrypt device driver and may act as an entry + * timestamp. + */ +TRACE_EVENT(s390_zcrypt_req, + TP_PROTO(void *ptr, u32 type), + TP_ARGS(ptr, type), + TP_STRUCT__entry( + __field(void *, ptr) + __field(u32, type)), + TP_fast_assign( + __entry->ptr = ptr; + __entry->type = type;), + TP_printk("ptr=%p type=%s", + __entry->ptr, + show_zcrypt_tp_type(__entry->type)) +); + +/** + * trace_s390_zcrypt_rep - zcrypt reply tracepoint function + * @ptr: Address of the local buffer where the request from userspace + * is stored. Can be used as a unique id to match together + * request and reply. + * @fc: Function code. + * @rc: The bare returncode as returned by the device driver ioctl + * function. + * @dev: The adapter nr where this request was actually processed. + * @dom: Domain id of the device where this request was processed. + * + * Called upon recognising the reply from the crypto adapter. This + * message may act as the exit timestamp for the request but also + * carries some info about on which adapter the request was processed + * and the returncode from the device driver. + */ +TRACE_EVENT(s390_zcrypt_rep, + TP_PROTO(void *ptr, u32 fc, u32 rc, u16 dev, u16 dom), + TP_ARGS(ptr, fc, rc, dev, dom), + TP_STRUCT__entry( + __field(void *, ptr) + __field(u32, fc) + __field(u32, rc) + __field(u16, device) + __field(u16, domain)), + TP_fast_assign( + __entry->ptr = ptr; + __entry->fc = fc; + __entry->rc = rc; + __entry->device = dev; + __entry->domain = dom;), + TP_printk("ptr=%p fc=0x%04x rc=%d dev=0x%02hx domain=0x%04hx", + __entry->ptr, + (unsigned int) __entry->fc, + (int) __entry->rc, + (unsigned short) __entry->device, + (unsigned short) __entry->domain) +); + +#endif /* _TRACE_S390_ZCRYPT_H */ + +/* This part must be outside protection */ + +#undef TRACE_INCLUDE_PATH +#undef TRACE_INCLUDE_FILE + +#define TRACE_INCLUDE_PATH asm/trace +#define TRACE_INCLUDE_FILE zcrypt + +#include diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 7ca25e77bd6a..854a6e58dfea 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -41,6 +41,9 @@ #include #include +#define CREATE_TRACE_POINTS +#include + #include "zcrypt_api.h" #include "zcrypt_debug.h" @@ -55,6 +58,12 @@ MODULE_DESCRIPTION("Cryptographic Coprocessor interface, " \ "Copyright IBM Corp. 2001, 2012"); MODULE_LICENSE("GPL"); +/* + * zcrypt tracepoint functions + */ +EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_req); +EXPORT_TRACEPOINT_SYMBOL(s390_zcrypt_rep); + static int zcrypt_hwrng_seed = 1; module_param_named(hwrng_seed, zcrypt_hwrng_seed, int, S_IRUSR|S_IRGRP); MODULE_PARM_DESC(hwrng_seed, "Turn on/off hwrng auto seed, default is 1 (on)."); @@ -224,10 +233,15 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) struct zcrypt_queue *zq, *pref_zq; unsigned int weight, pref_weight; unsigned int func_code; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(mex, TP_ICARSAMODEXPO); + + if (mex->outputdatalength < mex->inputdatalength) { + rc = -EINVAL; + goto out; + } - if (mex->outputdatalength < mex->inputdatalength) - return -EINVAL; /* * As long as outputdatalength is big enough, we can set the * outputdatalength equal to the inputdatalength, since that is the @@ -237,7 +251,7 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) rc = get_rsa_modex_fc(mex, &func_code); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -269,15 +283,21 @@ static long zcrypt_rsa_modexpo(struct ica_rsa_modexpo *mex) pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); - if (!pref_zq) - return -ENODEV; + if (!pref_zq) { + rc = -ENODEV; + goto out; + } + qid = pref_zq->queue->qid; rc = pref_zq->ops->rsa_modexpo(pref_zq, mex); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); +out: + trace_s390_zcrypt_rep(mex, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -287,10 +307,15 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) struct zcrypt_queue *zq, *pref_zq; unsigned int weight, pref_weight; unsigned int func_code; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(crt, TP_ICARSACRT); + + if (crt->outputdatalength < crt->inputdatalength) { + rc = -EINVAL; + goto out; + } - if (crt->outputdatalength < crt->inputdatalength) - return -EINVAL; /* * As long as outputdatalength is big enough, we can set the * outputdatalength equal to the inputdatalength, since that is the @@ -300,7 +325,7 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) rc = get_rsa_crt_fc(crt, &func_code); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -332,15 +357,21 @@ static long zcrypt_rsa_crt(struct ica_rsa_modexpo_crt *crt) pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); - if (!pref_zq) - return -ENODEV; + if (!pref_zq) { + rc = -ENODEV; + goto out; + } + qid = pref_zq->queue->qid; rc = pref_zq->ops->rsa_modexpo_crt(pref_zq, crt); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); +out: + trace_s390_zcrypt_rep(crt, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -352,11 +383,13 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) unsigned int weight, pref_weight; unsigned int func_code; unsigned short *domain; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(xcRB, TB_ZSECSENDCPRB); rc = get_cprb_fc(xcRB, &ap_msg, &func_code, &domain); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -391,18 +424,25 @@ static long zcrypt_send_cprb(struct ica_xcRB *xcRB) pref_zq = zcrypt_pick_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); - if (!pref_zq) - return -ENODEV; + if (!pref_zq) { + rc = -ENODEV; + goto out; + } /* in case of auto select, provide the correct domain */ + qid = pref_zq->queue->qid; if (*domain == (unsigned short) AUTOSELECT) - *domain = AP_QID_QUEUE(pref_zq->queue->qid); + *domain = AP_QID_QUEUE(qid); rc = pref_zq->ops->send_cprb(pref_zq, xcRB, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); + +out: + trace_s390_zcrypt_rep(xcRB, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -439,7 +479,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) unsigned int weight, pref_weight; unsigned int func_code; struct ap_message ap_msg; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(xcrb, TP_ZSENDEP11CPRB); target_num = (unsigned short) xcrb->targets_num; @@ -449,13 +491,17 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) struct ep11_target_dev __user *uptr; targets = kcalloc(target_num, sizeof(*targets), GFP_KERNEL); - if (!targets) - return -ENOMEM; + if (!targets) { + rc = -ENOMEM; + goto out; + } uptr = (struct ep11_target_dev __force __user *) xcrb->targets; if (copy_from_user(targets, uptr, - target_num * sizeof(*targets))) - return -EFAULT; + target_num * sizeof(*targets))) { + rc = -EFAULT; + goto out; + } } rc = get_ep11cprb_fc(xcrb, &ap_msg, &func_code); @@ -501,6 +547,7 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) goto out_free; } + qid = pref_zq->queue->qid; rc = pref_zq->ops->send_ep11_cprb(pref_zq, xcrb, &ap_msg); spin_lock(&zcrypt_list_lock); @@ -509,6 +556,9 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb) out_free: kfree(targets); +out: + trace_s390_zcrypt_rep(xcrb, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } @@ -520,11 +570,13 @@ static long zcrypt_rng(char *buffer) unsigned int func_code; struct ap_message ap_msg; unsigned int domain; - int rc; + int qid = 0, rc = -ENODEV; + + trace_s390_zcrypt_req(buffer, TP_HWRNGCPRB); rc = get_rng_fc(&ap_msg, &func_code, &domain); if (rc) - return rc; + goto out; pref_zc = NULL; pref_zq = NULL; @@ -555,11 +607,16 @@ static long zcrypt_rng(char *buffer) if (!pref_zq) return -ENODEV; + qid = pref_zq->queue->qid; rc = pref_zq->ops->rng(pref_zq, buffer, &ap_msg); spin_lock(&zcrypt_list_lock); zcrypt_drop_queue(pref_zc, pref_zq, weight); spin_unlock(&zcrypt_list_lock); + +out: + trace_s390_zcrypt_rep(buffer, func_code, rc, + AP_QID_CARD(qid), AP_QID_QUEUE(qid)); return rc; } -- cgit v1.2.3 From 50cff5adcf8eb8bcdd79087a91878f298fb58dcf Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Fri, 18 Nov 2016 14:39:05 +0100 Subject: s390/dasd: fix typos in DASD error messages Signed-off-by: Martin Schwidefsky --- drivers/s390/block/dasd_3990_erp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c index 95f7645e3c37..774da20ceb58 100644 --- a/drivers/s390/block/dasd_3990_erp.c +++ b/drivers/s390/block/dasd_3990_erp.c @@ -674,7 +674,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) break; case 0x0D: dev_warn(&device->cdev->dev, - "FORMAT 4 - No syn byte in count " + "FORMAT 4 - No sync byte in count " "address area; offset active\n"); break; case 0x0E: @@ -684,7 +684,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) break; case 0x0F: dev_warn(&device->cdev->dev, - "FORMAT 4 - No syn byte in data area; " + "FORMAT 4 - No sync byte in data area; " "offset active\n"); break; default: @@ -999,7 +999,7 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense) break; default: dev_warn(&device->cdev->dev, - "FORMAT D - Reserved\n"); + "FORMAT F - Reserved\n"); } break; -- cgit v1.2.3 From d03502684b65492339d70f11aa8ed6df3961a3bf Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Tue, 13 Dec 2016 13:24:03 +0100 Subject: s390/zcrypt: add missing memory clobber to ap_qci inline assembly The ap_qci() inline assembly writes to memory (*config) but misses to tell the compiler about it. Add the missing memory clobber to fix this. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- drivers/s390/crypto/ap_asm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/s390/crypto/ap_asm.h b/drivers/s390/crypto/ap_asm.h index 12fffdd1e8e8..7a630047c372 100644 --- a/drivers/s390/crypto/ap_asm.h +++ b/drivers/s390/crypto/ap_asm.h @@ -108,7 +108,7 @@ static inline int ap_qci(void *config) EX_TABLE(0b, 1b) : "+d" (reg0), "+d" (reg1), "+d" (reg2) : - : "cc"); + : "cc", "memory"); return reg1; } -- cgit v1.2.3 From 9fa240bbfc4200b080c8fad12579659c2c2f36b5 Mon Sep 17 00:00:00 2001 From: Hal Rosenstock Date: Tue, 18 Oct 2016 13:20:29 -0400 Subject: IB/mad: Eliminate redundant SM class version defines for OPA and rename class version define to indicate SM rather than SMP or SMI Signed-off-by: Hal Rosenstock Reviewed-by: Ira Weiny Signed-off-by: Doug Ledford --- drivers/infiniband/core/mad.c | 4 ++-- drivers/infiniband/hw/hfi1/mad.c | 12 ++++++------ include/rdma/ib_mad.h | 2 +- include/rdma/opa_smi.h | 2 -- 4 files changed, 9 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 40cbd6bdb73b..bc2a9c2caa3c 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -769,7 +769,7 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv, * If we are at the start of the LID routed part, don't update the * hop_ptr or hop_cnt. See section 14.2.2, Vol 1 IB spec. */ - if (opa && smp->class_version == OPA_SMP_CLASS_VERSION) { + if (opa && smp->class_version == OPA_SM_CLASS_VERSION) { u32 opa_drslid; if ((opa_get_smp_direction(opa_smp) @@ -2167,7 +2167,7 @@ handle_smi(struct ib_mad_port_private *port_priv, struct ib_mad_hdr *mad_hdr = (struct ib_mad_hdr *)recv->mad; if (opa && mad_hdr->base_version == OPA_MGMT_BASE_VERSION && - mad_hdr->class_version == OPA_SMI_CLASS_VERSION) + mad_hdr->class_version == OPA_SM_CLASS_VERSION) return handle_opa_smi(port_priv, qp_info, wc, port_num, recv, response); diff --git a/drivers/infiniband/hw/hfi1/mad.c b/drivers/infiniband/hw/hfi1/mad.c index 9487c9bb8920..320e4daa5fc6 100644 --- a/drivers/infiniband/hw/hfi1/mad.c +++ b/drivers/infiniband/hw/hfi1/mad.c @@ -128,7 +128,7 @@ static void send_trap(struct hfi1_ibport *ibp, void *data, unsigned len) smp = send_buf->mad; smp->base_version = OPA_MGMT_BASE_VERSION; smp->mgmt_class = IB_MGMT_CLASS_SUBN_LID_ROUTED; - smp->class_version = OPA_SMI_CLASS_VERSION; + smp->class_version = OPA_SM_CLASS_VERSION; smp->method = IB_MGMT_METHOD_TRAP; ibp->rvp.tid++; smp->tid = cpu_to_be64(ibp->rvp.tid); @@ -343,7 +343,7 @@ static int __subn_get_opa_nodeinfo(struct opa_smp *smp, u32 am, u8 *data, ni->port_guid = cpu_to_be64(dd->pport[pidx].guid); ni->base_version = OPA_MGMT_BASE_VERSION; - ni->class_version = OPA_SMI_CLASS_VERSION; + ni->class_version = OPA_SM_CLASS_VERSION; ni->node_type = 1; /* channel adapter */ ni->num_ports = ibdev->phys_port_cnt; /* This is already in network order */ @@ -379,7 +379,7 @@ static int subn_get_nodeinfo(struct ib_smp *smp, struct ib_device *ibdev, nip->port_guid = cpu_to_be64(dd->pport[pidx].guid); nip->base_version = OPA_MGMT_BASE_VERSION; - nip->class_version = OPA_SMI_CLASS_VERSION; + nip->class_version = OPA_SM_CLASS_VERSION; nip->node_type = 1; /* channel adapter */ nip->num_ports = ibdev->phys_port_cnt; /* This is already in network order */ @@ -2302,7 +2302,7 @@ static int pma_get_opa_classportinfo(struct opa_pma_mad *pmp, pmp->mad_hdr.status |= IB_SMP_INVALID_FIELD; p->base_version = OPA_MGMT_BASE_VERSION; - p->class_version = OPA_SMI_CLASS_VERSION; + p->class_version = OPA_SM_CLASS_VERSION; /* * Expected response time is 4.096 usec. * 2^18 == 1.073741824 sec. */ @@ -4022,7 +4022,7 @@ static int process_subn_opa(struct ib_device *ibdev, int mad_flags, am = be32_to_cpu(smp->attr_mod); attr_id = smp->attr_id; - if (smp->class_version != OPA_SMI_CLASS_VERSION) { + if (smp->class_version != OPA_SM_CLASS_VERSION) { smp->status |= IB_SMP_UNSUP_VERSION; ret = reply((struct ib_mad_hdr *)smp); return ret; @@ -4232,7 +4232,7 @@ static int process_perf_opa(struct ib_device *ibdev, u8 port, *out_mad = *in_mad; - if (pmp->mad_hdr.class_version != OPA_SMI_CLASS_VERSION) { + if (pmp->mad_hdr.class_version != OPA_SM_CLASS_VERSION) { pmp->mad_hdr.status |= IB_SMP_UNSUP_VERSION; return reply((struct ib_mad_hdr *)pmp); } diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index c8a773ffe23b..981214b3790c 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h @@ -46,7 +46,7 @@ #define IB_MGMT_BASE_VERSION 1 #define OPA_MGMT_BASE_VERSION 0x80 -#define OPA_SMP_CLASS_VERSION 0x80 +#define OPA_SM_CLASS_VERSION 0x80 /* Management classes */ #define IB_MGMT_CLASS_SUBN_LID_ROUTED 0x01 diff --git a/include/rdma/opa_smi.h b/include/rdma/opa_smi.h index 4a529ef47995..f7896117936e 100644 --- a/include/rdma/opa_smi.h +++ b/include/rdma/opa_smi.h @@ -44,8 +44,6 @@ #define OPA_MAX_SLS 32 #define OPA_MAX_SCS 32 -#define OPA_SMI_CLASS_VERSION 0x80 - #define OPA_LID_PERMISSIVE cpu_to_be32(0xFFFFFFFF) struct opa_smp { -- cgit v1.2.3 From ea7ef2accdeaf825165cccd60b848765677bf1f2 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 18 Oct 2016 19:39:28 +0100 Subject: qedr: return -EINVAL if pd is null and avoid null ptr dereference Currently, if pd is null then we hit a null pointer derference on accessing pd->pd_id. Instead of just printing an error message we should also return -EINVAL immediately. Signed-off-by: Colin Ian King Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index a61514296767..b2a0eb8f73d2 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -511,8 +511,10 @@ int qedr_dealloc_pd(struct ib_pd *ibpd) struct qedr_dev *dev = get_qedr_dev(ibpd->device); struct qedr_pd *pd = get_qedr_pd(ibpd); - if (!pd) + if (!pd) { pr_err("Invalid PD received in dealloc_pd\n"); + return -EINVAL; + } DP_DEBUG(dev, QEDR_MSG_INIT, "Deallocating PD %d\n", pd->pd_id); dev->ops->rdma_dealloc_pd(dev->rdma_ctx, pd->pd_id); -- cgit v1.2.3 From 181d80151f9c6ff3c765c1bd2e4e200ada23c2f3 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Fri, 28 Oct 2016 16:33:47 +0000 Subject: qedr: Fix possible memory leak in qedr_create_qp() 'qp' is malloced in qedr_create_qp() and should be freed before leaving from the error handling cases, otherwise it will cause memory leak. Signed-off-by: Wei Yongjun Acked-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index b2a0eb8f73d2..8c6c5ccaf57a 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -1479,6 +1479,7 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd, struct qedr_ucontext *ctx = NULL; struct qedr_create_qp_ureq ureq; struct qedr_qp *qp; + struct ib_qp *ibqp; int rc = 0; DP_DEBUG(dev, QEDR_MSG_QP, "create qp: called from %s, pd=%p\n", @@ -1488,13 +1489,13 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd, if (rc) return ERR_PTR(rc); + if (attrs->srq) + return ERR_PTR(-EINVAL); + qp = kzalloc(sizeof(*qp), GFP_KERNEL); if (!qp) return ERR_PTR(-ENOMEM); - if (attrs->srq) - return ERR_PTR(-EINVAL); - DP_DEBUG(dev, QEDR_MSG_QP, "create qp: sq_cq=%p, sq_icid=%d, rq_cq=%p, rq_icid=%d\n", get_qedr_cq(attrs->send_cq), @@ -1510,7 +1511,10 @@ struct ib_qp *qedr_create_qp(struct ib_pd *ibpd, "create qp: unexpected udata when creating GSI QP\n"); goto err0; } - return qedr_create_gsi_qp(dev, attrs, qp); + ibqp = qedr_create_gsi_qp(dev, attrs, qp); + if (IS_ERR(ibqp)) + kfree(qp); + return ibqp; } memset(&in_params, 0, sizeof(in_params)); -- cgit v1.2.3 From aafec388a1b7fc533a81c03b4a81c6e5f3e5688f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Sat, 29 Oct 2016 16:19:53 +0000 Subject: qedr: Use list_move_tail instead of list_del/list_add_tail Using list_move_tail() instead of list_del() + list_add_tail(). Signed-off-by: Wei Yongjun Reviewed-by: Leon Romanovsky Acked-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 8c6c5ccaf57a..18e2f60a9d4f 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2419,8 +2419,7 @@ static void handle_completed_mrs(struct qedr_dev *dev, struct mr_info *info) */ pbl = list_first_entry(&info->inuse_pbl_list, struct qedr_pbl, list_entry); - list_del(&pbl->list_entry); - list_add_tail(&pbl->list_entry, &info->free_pbl_list); + list_move_tail(&pbl->list_entry, &info->free_pbl_list); info->completed_handled++; } } -- cgit v1.2.3 From aecb66b2b01a87b4b723267b9193c8f00d661c1f Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Wed, 2 Nov 2016 13:11:32 +0000 Subject: qedr: remove pointless NULL check in qedr_post_send() Remove pointless NULL check for 'wr' in qedr_post_send(). Signed-off-by: Wei Yongjun Acked-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 5 ----- 1 file changed, 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 18e2f60a9d4f..12f35150f32f 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2986,11 +2986,6 @@ int qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, return -EINVAL; } - if (!wr) { - DP_ERR(dev, "Got an empty post send.\n"); - return -EINVAL; - } - while (wr) { rc = __qedr_post_send(ibqp, wr, bad_wr); if (rc) -- cgit v1.2.3 From 77a5db13153906a7e00740b10b2730e53385c5a8 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 26 Oct 2016 12:36:40 -0700 Subject: rdma_cm: add rdma_reject_msg() helper function rdma_reject_msg() returns a pointer to a string message associated with the transport reject reason codes. Reviewed-by: Christoph Hellwig Reviewed-by: Sagi Grimberg Signed-off-by: Steve Wise Reviewed-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/core/cm.c | 48 ++++++++++++++++++++++++++++++++++++++++++ drivers/infiniband/core/cma.c | 14 ++++++++++++ drivers/infiniband/core/iwcm.c | 21 ++++++++++++++++++ include/rdma/ib_cm.h | 6 ++++++ include/rdma/iw_cm.h | 6 ++++++ include/rdma/rdma_cm.h | 8 +++++++ 6 files changed, 103 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index c99525512b34..6c64d0ce64b3 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -57,6 +57,54 @@ MODULE_AUTHOR("Sean Hefty"); MODULE_DESCRIPTION("InfiniBand CM"); MODULE_LICENSE("Dual BSD/GPL"); +static const char * const ibcm_rej_reason_strs[] = { + [IB_CM_REJ_NO_QP] = "no QP", + [IB_CM_REJ_NO_EEC] = "no EEC", + [IB_CM_REJ_NO_RESOURCES] = "no resources", + [IB_CM_REJ_TIMEOUT] = "timeout", + [IB_CM_REJ_UNSUPPORTED] = "unsupported", + [IB_CM_REJ_INVALID_COMM_ID] = "invalid comm ID", + [IB_CM_REJ_INVALID_COMM_INSTANCE] = "invalid comm instance", + [IB_CM_REJ_INVALID_SERVICE_ID] = "invalid service ID", + [IB_CM_REJ_INVALID_TRANSPORT_TYPE] = "invalid transport type", + [IB_CM_REJ_STALE_CONN] = "stale conn", + [IB_CM_REJ_RDC_NOT_EXIST] = "RDC not exist", + [IB_CM_REJ_INVALID_GID] = "invalid GID", + [IB_CM_REJ_INVALID_LID] = "invalid LID", + [IB_CM_REJ_INVALID_SL] = "invalid SL", + [IB_CM_REJ_INVALID_TRAFFIC_CLASS] = "invalid traffic class", + [IB_CM_REJ_INVALID_HOP_LIMIT] = "invalid hop limit", + [IB_CM_REJ_INVALID_PACKET_RATE] = "invalid packet rate", + [IB_CM_REJ_INVALID_ALT_GID] = "invalid alt GID", + [IB_CM_REJ_INVALID_ALT_LID] = "invalid alt LID", + [IB_CM_REJ_INVALID_ALT_SL] = "invalid alt SL", + [IB_CM_REJ_INVALID_ALT_TRAFFIC_CLASS] = "invalid alt traffic class", + [IB_CM_REJ_INVALID_ALT_HOP_LIMIT] = "invalid alt hop limit", + [IB_CM_REJ_INVALID_ALT_PACKET_RATE] = "invalid alt packet rate", + [IB_CM_REJ_PORT_CM_REDIRECT] = "port CM redirect", + [IB_CM_REJ_PORT_REDIRECT] = "port redirect", + [IB_CM_REJ_INVALID_MTU] = "invalid MTU", + [IB_CM_REJ_INSUFFICIENT_RESP_RESOURCES] = "insufficient resp resources", + [IB_CM_REJ_CONSUMER_DEFINED] = "consumer defined", + [IB_CM_REJ_INVALID_RNR_RETRY] = "invalid RNR retry", + [IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID] = "duplicate local comm ID", + [IB_CM_REJ_INVALID_CLASS_VERSION] = "invalid class version", + [IB_CM_REJ_INVALID_FLOW_LABEL] = "invalid flow label", + [IB_CM_REJ_INVALID_ALT_FLOW_LABEL] = "invalid alt flow label", +}; + +const char *__attribute_const__ ibcm_reject_msg(int reason) +{ + size_t index = reason; + + if (index < ARRAY_SIZE(ibcm_rej_reason_strs) && + ibcm_rej_reason_strs[index]) + return ibcm_rej_reason_strs[index]; + else + return "unrecognized reason"; +} +EXPORT_SYMBOL(ibcm_reject_msg); + static void cm_add_one(struct ib_device *device); static void cm_remove_one(struct ib_device *device, void *client_data); diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 36bf50ebb187..877e4dc9e382 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -101,6 +101,20 @@ const char *__attribute_const__ rdma_event_msg(enum rdma_cm_event_type event) } EXPORT_SYMBOL(rdma_event_msg); +const char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id, + int reason) +{ + if (rdma_ib_or_roce(id->device, id->port_num)) + return ibcm_reject_msg(reason); + + if (rdma_protocol_iwarp(id->device, id->port_num)) + return iwcm_reject_msg(reason); + + WARN_ON_ONCE(1); + return "unrecognized transport"; +} +EXPORT_SYMBOL(rdma_reject_msg); + static void cma_add_one(struct ib_device *device); static void cma_remove_one(struct ib_device *device, void *client_data); diff --git a/drivers/infiniband/core/iwcm.c b/drivers/infiniband/core/iwcm.c index 5495e22839a7..31661b5c1743 100644 --- a/drivers/infiniband/core/iwcm.c +++ b/drivers/infiniband/core/iwcm.c @@ -59,6 +59,27 @@ MODULE_AUTHOR("Tom Tucker"); MODULE_DESCRIPTION("iWARP CM"); MODULE_LICENSE("Dual BSD/GPL"); +static const char * const iwcm_rej_reason_strs[] = { + [ECONNRESET] = "reset by remote host", + [ECONNREFUSED] = "refused by remote application", + [ETIMEDOUT] = "setup timeout", +}; + +const char *__attribute_const__ iwcm_reject_msg(int reason) +{ + size_t index; + + /* iWARP uses negative errnos */ + index = -reason; + + if (index < ARRAY_SIZE(iwcm_rej_reason_strs) && + iwcm_rej_reason_strs[index]) + return iwcm_rej_reason_strs[index]; + else + return "unrecognized reason"; +} +EXPORT_SYMBOL(iwcm_reject_msg); + static struct ibnl_client_cbs iwcm_nl_cb_table[] = { [RDMA_NL_IWPM_REG_PID] = {.dump = iwpm_register_pid_cb}, [RDMA_NL_IWPM_ADD_MAPPING] = {.dump = iwpm_add_mapping_cb}, diff --git a/include/rdma/ib_cm.h b/include/rdma/ib_cm.h index 92a7d85917b4..b49258b16f4e 100644 --- a/include/rdma/ib_cm.h +++ b/include/rdma/ib_cm.h @@ -603,4 +603,10 @@ struct ib_cm_sidr_rep_param { int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, struct ib_cm_sidr_rep_param *param); +/** + * ibcm_reject_msg - return a pointer to a reject message string. + * @reason: Value returned in the REJECT event status field. + */ +const char *__attribute_const__ ibcm_reject_msg(int reason); + #endif /* IB_CM_H */ diff --git a/include/rdma/iw_cm.h b/include/rdma/iw_cm.h index 6d0065c322b7..5cd7701db148 100644 --- a/include/rdma/iw_cm.h +++ b/include/rdma/iw_cm.h @@ -253,4 +253,10 @@ int iw_cm_disconnect(struct iw_cm_id *cm_id, int abrupt); int iw_cm_init_qp_attr(struct iw_cm_id *cm_id, struct ib_qp_attr *qp_attr, int *qp_attr_mask); +/** + * iwcm_reject_msg - return a pointer to a reject message string. + * @reason: Value returned in the REJECT event status field. + */ +const char *__attribute_const__ iwcm_reject_msg(int reason); + #endif /* IW_CM_H */ diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 81fb1d15e8bb..f11a768be06b 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -388,4 +388,12 @@ int rdma_set_afonly(struct rdma_cm_id *id, int afonly); */ __be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr); +/** + * rdma_reject_msg - return a pointer to a reject message string. + * @id: Communication identifier that received the REJECT event. + * @reason: Value returned in the REJECT event status field. + */ +const char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id, + int reason); + #endif /* RDMA_CM_H */ -- cgit v1.2.3 From 5042a73d3e9de7bcc2a31adea08ee95bbce998dc Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 26 Oct 2016 12:36:47 -0700 Subject: rdma_cm: add rdma_is_consumer_reject() helper function Return true if the peer consumer application rejected the connection attempt. Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Steve Wise Reviewed-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 13 +++++++++++++ include/rdma/rdma_cm.h | 7 +++++++ 2 files changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 877e4dc9e382..bd1d4fe47740 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -115,6 +115,19 @@ const char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id, } EXPORT_SYMBOL(rdma_reject_msg); +bool rdma_is_consumer_reject(struct rdma_cm_id *id, int reason) +{ + if (rdma_ib_or_roce(id->device, id->port_num)) + return reason == IB_CM_REJ_CONSUMER_DEFINED; + + if (rdma_protocol_iwarp(id->device, id->port_num)) + return reason == -ECONNREFUSED; + + WARN_ON_ONCE(1); + return false; +} +EXPORT_SYMBOL(rdma_is_consumer_reject); + static void cma_add_one(struct ib_device *device); static void cma_remove_one(struct ib_device *device, void *client_data); diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index f11a768be06b..62039c2fd951 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -395,5 +395,12 @@ __be64 rdma_get_service_id(struct rdma_cm_id *id, struct sockaddr *addr); */ const char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id, int reason); +/** + * rdma_is_consumer_reject - return true if the consumer rejected the connect + * request. + * @id: Communication identifier that received the REJECT event. + * @reason: Value returned in the REJECT event status field. + */ +bool rdma_is_consumer_reject(struct rdma_cm_id *id, int reason); #endif /* RDMA_CM_H */ -- cgit v1.2.3 From 5f24410408fd093734ce758f2fe3a66fe543de22 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 26 Oct 2016 12:36:47 -0700 Subject: rdma_cm: add rdma_consumer_reject_data helper function rdma_consumer_reject_data() will return the private data pointer and length if any is available. Reviewed-by: Sagi Grimberg Reviewed-by: Christoph Hellwig Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/core/cma.c | 16 ++++++++++++++++ include/rdma/rdma_cm.h | 10 ++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index bd1d4fe47740..8c30e3dedebe 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -128,6 +128,22 @@ bool rdma_is_consumer_reject(struct rdma_cm_id *id, int reason) } EXPORT_SYMBOL(rdma_is_consumer_reject); +const void *rdma_consumer_reject_data(struct rdma_cm_id *id, + struct rdma_cm_event *ev, u8 *data_len) +{ + const void *p; + + if (rdma_is_consumer_reject(id, ev->status)) { + *data_len = ev->param.conn.private_data_len; + p = ev->param.conn.private_data; + } else { + *data_len = 0; + p = NULL; + } + return p; +} +EXPORT_SYMBOL(rdma_consumer_reject_data); + static void cma_add_one(struct ib_device *device); static void cma_remove_one(struct ib_device *device, void *client_data); diff --git a/include/rdma/rdma_cm.h b/include/rdma/rdma_cm.h index 62039c2fd951..d3968b561f86 100644 --- a/include/rdma/rdma_cm.h +++ b/include/rdma/rdma_cm.h @@ -403,4 +403,14 @@ const char *__attribute_const__ rdma_reject_msg(struct rdma_cm_id *id, */ bool rdma_is_consumer_reject(struct rdma_cm_id *id, int reason); +/** + * rdma_consumer_reject_data - return the consumer reject private data and + * length, if any. + * @id: Communication identifier that received the REJECT event. + * @ev: RDMA CM reject event. + * @data_len: Pointer to the resulting length of the consumer data. + */ +const void *rdma_consumer_reject_data(struct rdma_cm_id *id, + struct rdma_cm_event *ev, u8 *data_len); + #endif /* RDMA_CM_H */ -- cgit v1.2.3 From 7f03953c2f28cdb9c31f3f1410ba5be1f385a693 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 26 Oct 2016 12:36:47 -0700 Subject: nvme-rdma: use rdma connection reject helper functions Also add nvme cm status strings and use them. Reviewed-by: Christoph Hellwig Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/nvme/host/rdma.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/rdma.c b/drivers/nvme/host/rdma.c index 5a8388177959..accbe8edb6c4 100644 --- a/drivers/nvme/host/rdma.c +++ b/drivers/nvme/host/rdma.c @@ -43,6 +43,28 @@ #define NVME_RDMA_MAX_INLINE_SEGMENTS 1 +static const char *const nvme_rdma_cm_status_strs[] = { + [NVME_RDMA_CM_INVALID_LEN] = "invalid length", + [NVME_RDMA_CM_INVALID_RECFMT] = "invalid record format", + [NVME_RDMA_CM_INVALID_QID] = "invalid queue ID", + [NVME_RDMA_CM_INVALID_HSQSIZE] = "invalid host SQ size", + [NVME_RDMA_CM_INVALID_HRQSIZE] = "invalid host RQ size", + [NVME_RDMA_CM_NO_RSC] = "resource not found", + [NVME_RDMA_CM_INVALID_IRD] = "invalid IRD", + [NVME_RDMA_CM_INVALID_ORD] = "Invalid ORD", +}; + +static const char *nvme_rdma_cm_msg(enum nvme_rdma_cm_status status) +{ + size_t index = status; + + if (index < ARRAY_SIZE(nvme_rdma_cm_status_strs) && + nvme_rdma_cm_status_strs[index]) + return nvme_rdma_cm_status_strs[index]; + else + return "unrecognized reason"; +}; + /* * We handle AEN commands ourselves and don't even let the * block layer know about them. @@ -1207,16 +1229,24 @@ out_destroy_queue_ib: static int nvme_rdma_conn_rejected(struct nvme_rdma_queue *queue, struct rdma_cm_event *ev) { - if (ev->param.conn.private_data_len) { - struct nvme_rdma_cm_rej *rej = - (struct nvme_rdma_cm_rej *)ev->param.conn.private_data; + struct rdma_cm_id *cm_id = queue->cm_id; + int status = ev->status; + const char *rej_msg; + const struct nvme_rdma_cm_rej *rej_data; + u8 rej_data_len; + + rej_msg = rdma_reject_msg(cm_id, status); + rej_data = rdma_consumer_reject_data(cm_id, ev, &rej_data_len); + + if (rej_data && rej_data_len >= sizeof(u16)) { + u16 sts = le16_to_cpu(rej_data->sts); dev_err(queue->ctrl->ctrl.device, - "Connect rejected, status %d.", le16_to_cpu(rej->sts)); - /* XXX: Think of something clever to do here... */ + "Connect rejected: status %d (%s) nvme status %d (%s).\n", + status, rej_msg, sts, nvme_rdma_cm_msg(sts)); } else { dev_err(queue->ctrl->ctrl.device, - "Connect rejected, no private data.\n"); + "Connect rejected: status %d (%s).\n", status, rej_msg); } return -ECONNRESET; -- cgit v1.2.3 From 97540bb90acfab268b256a58c3e51cd06b2d1654 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 26 Oct 2016 12:36:47 -0700 Subject: ib_iser: log the connection reject message Acked-by: Sagi Grimberg Signed-off-by: Steve Wise Reviewed-by: Christoph Hellwig Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/iser/iser_verbs.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index a4b791dfaa1d..8ae7a3beddb7 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -890,11 +890,14 @@ static int iser_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *eve case RDMA_CM_EVENT_ESTABLISHED: iser_connected_handler(cma_id, event->param.conn.private_data); break; + case RDMA_CM_EVENT_REJECTED: + iser_info("Connection rejected: %s\n", + rdma_reject_msg(cma_id, event->status)); + /* FALLTHROUGH */ case RDMA_CM_EVENT_ADDR_ERROR: case RDMA_CM_EVENT_ROUTE_ERROR: case RDMA_CM_EVENT_CONNECT_ERROR: case RDMA_CM_EVENT_UNREACHABLE: - case RDMA_CM_EVENT_REJECTED: iser_connect_error(cma_id); break; case RDMA_CM_EVENT_DISCONNECTED: -- cgit v1.2.3 From 1e38a366ee86ac2b7a8110775cb3353649b18b70 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 26 Oct 2016 12:36:48 -0700 Subject: ib_isert: log the connection reject message Acked-by: Sagi Grimberg Signed-off-by: Steve Wise Reviewed-by: Christoph Hellwig Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/isert/ib_isert.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 6dd43f63238e..37016f01b5a5 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -795,6 +795,8 @@ isert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) */ return 1; case RDMA_CM_EVENT_REJECTED: /* FALLTHRU */ + isert_info("Connection rejected: %s\n", + rdma_reject_msg(cma_id, event->status)); case RDMA_CM_EVENT_UNREACHABLE: /* FALLTHRU */ case RDMA_CM_EVENT_CONNECT_ERROR: ret = isert_connect_error(cma_id); -- cgit v1.2.3 From 512fb1b32bac02ebec50e5060f94dc1ad23ed28f Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Wed, 26 Oct 2016 12:36:48 -0700 Subject: nvmet_rdma: log the connection reject message Acked-by: Sagi Grimberg Signed-off-by: Steve Wise Reviewed-by: Christoph Hellwig Signed-off-by: Doug Ledford --- drivers/nvme/target/rdma.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index f8d23999e0f2..50f237a46ea1 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -1358,6 +1358,9 @@ static int nvmet_rdma_cm_handler(struct rdma_cm_id *cm_id, ret = nvmet_rdma_device_removal(cm_id, queue); break; case RDMA_CM_EVENT_REJECTED: + pr_debug("Connection rejected: %s\n", + rdma_reject_msg(cm_id, event->status)); + /* FALLTHROUGH */ case RDMA_CM_EVENT_UNREACHABLE: case RDMA_CM_EVENT_CONNECT_ERROR: nvmet_rdma_queue_connect_fail(cm_id, queue); -- cgit v1.2.3 From 14ab8896f5d993c5f427504276e3c42ccb3cc354 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 24 Oct 2016 22:48:21 +0200 Subject: IB/mlx5: avoid bogus -Wmaybe-uninitialized warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We get a false-positive warning in linux-next for the mlx5 driver: infiniband/hw/mlx5/mr.c: In function ‘mlx5_ib_reg_user_mr’: infiniband/hw/mlx5/mr.c:1172:5: error: ‘order’ may be used uninitialized in this function [-Werror=maybe-uninitialized] infiniband/hw/mlx5/mr.c:1161:6: note: ‘order’ was declared here infiniband/hw/mlx5/mr.c:1173:6: error: ‘ncont’ may be used uninitialized in this function [-Werror=maybe-uninitialized] infiniband/hw/mlx5/mr.c:1160:6: note: ‘ncont’ was declared here infiniband/hw/mlx5/mr.c:1173:6: error: ‘page_shift’ may be used uninitialized in this function [-Werror=maybe-uninitialized] infiniband/hw/mlx5/mr.c:1158:6: note: ‘page_shift’ was declared here infiniband/hw/mlx5/mr.c:1143:13: error: ‘npages’ may be used uninitialized in this function [-Werror=maybe-uninitialized] infiniband/hw/mlx5/mr.c:1159:6: note: ‘npages’ was declared here I had a trivial workaround for gcc-5 or higher, but that didn't work on gcc-4.9 unfortunately. The only way I found to avoid the warnings for gcc-4.9, short of initializing each of the arguments first was to change the calling conventions to separate the error code from the umem pointer. This avoids casting the error codes from one pointer to another incompatible pointer, and lets gcc figure out when that the data is actually valid whenever we return successfully. Acked-by: Leon Romanovsky Signed-off-by: Arnd Bergmann Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/mr.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c index 5258ac870e6a..67985c69f9b9 100644 --- a/drivers/infiniband/hw/mlx5/mr.c +++ b/drivers/infiniband/hw/mlx5/mr.c @@ -844,30 +844,34 @@ static void prep_umr_unreg_wqe(struct mlx5_ib_dev *dev, umrwr->mkey = key; } -static struct ib_umem *mr_umem_get(struct ib_pd *pd, u64 start, u64 length, - int access_flags, int *npages, - int *page_shift, int *ncont, int *order) +static int mr_umem_get(struct ib_pd *pd, u64 start, u64 length, + int access_flags, struct ib_umem **umem, + int *npages, int *page_shift, int *ncont, + int *order) { struct mlx5_ib_dev *dev = to_mdev(pd->device); - struct ib_umem *umem = ib_umem_get(pd->uobject->context, start, length, - access_flags, 0); - if (IS_ERR(umem)) { + int err; + + *umem = ib_umem_get(pd->uobject->context, start, length, + access_flags, 0); + err = PTR_ERR_OR_ZERO(*umem); + if (err < 0) { mlx5_ib_err(dev, "umem get failed (%ld)\n", PTR_ERR(umem)); - return (void *)umem; + return err; } - mlx5_ib_cont_pages(umem, start, MLX5_MKEY_PAGE_SHIFT_MASK, npages, + mlx5_ib_cont_pages(*umem, start, MLX5_MKEY_PAGE_SHIFT_MASK, npages, page_shift, ncont, order); if (!*npages) { mlx5_ib_warn(dev, "avoid zero region\n"); - ib_umem_release(umem); - return ERR_PTR(-EINVAL); + ib_umem_release(*umem); + return -EINVAL; } mlx5_ib_dbg(dev, "npages %d, ncont %d, order %d, page_shift %d\n", *npages, *ncont, *order, *page_shift); - return umem; + return 0; } static void mlx5_ib_umr_done(struct ib_cq *cq, struct ib_wc *wc) @@ -1193,11 +1197,11 @@ struct ib_mr *mlx5_ib_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, mlx5_ib_dbg(dev, "start 0x%llx, virt_addr 0x%llx, length 0x%llx, access_flags 0x%x\n", start, virt_addr, length, access_flags); - umem = mr_umem_get(pd, start, length, access_flags, &npages, + err = mr_umem_get(pd, start, length, access_flags, &umem, &npages, &page_shift, &ncont, &order); - if (IS_ERR(umem)) - return (void *)umem; + if (err < 0) + return ERR_PTR(err); if (use_umr(order)) { mr = reg_umr(pd, umem, virt_addr, length, ncont, page_shift, @@ -1371,10 +1375,9 @@ int mlx5_ib_rereg_user_mr(struct ib_mr *ib_mr, int flags, u64 start, */ flags |= IB_MR_REREG_TRANS; ib_umem_release(mr->umem); - mr->umem = mr_umem_get(pd, addr, len, access_flags, &npages, - &page_shift, &ncont, &order); - if (IS_ERR(mr->umem)) { - err = PTR_ERR(mr->umem); + err = mr_umem_get(pd, addr, len, access_flags, &mr->umem, + &npages, &page_shift, &ncont, &order); + if (err < 0) { mr->umem = NULL; return err; } -- cgit v1.2.3 From e98172462f0b75ed60f3a73aa280fb29cafd450f Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 25 Oct 2016 18:16:20 +0200 Subject: IB/mlx4: avoid a -Wmaybe-uninitialize warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There is an old warning about mlx4_SW2HW_EQ_wrapper on x86: ethernet/mellanox/mlx4/resource_tracker.c: In function ‘mlx4_SW2HW_EQ_wrapper’: ethernet/mellanox/mlx4/resource_tracker.c:3071:10: error: ‘eq’ may be used uninitialized in this function [-Werror=maybe-uninitialized] The problem here is that gcc won't track the state of the variable across a spin_unlock. Moving the assignment out of the lock is safe here and avoids the warning. Signed-off-by: Arnd Bergmann Reviewed-by: Yishai Hadas Signed-off-by: Doug Ledford --- drivers/net/ethernet/mellanox/mlx4/resource_tracker.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c index 84d7857ccc27..c548beaaf910 100644 --- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c +++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c @@ -1605,13 +1605,14 @@ static int eq_res_start_move_to(struct mlx4_dev *dev, int slave, int index, r->com.from_state = r->com.state; r->com.to_state = state; r->com.state = RES_EQ_BUSY; - if (eq) - *eq = r; } } spin_unlock_irq(mlx4_tlock(dev)); + if (!err && eq) + *eq = r; + return err; } -- cgit v1.2.3 From 6efaf10f163d9a60d1d4b2a049b194a53537ba1b Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Wed, 19 Oct 2016 14:07:19 +0200 Subject: IB/rdmavt: Avoid queuing work into a destroyed cq kthread worker The memory barrier is not enough to protect queuing works into a destroyed cq kthread. Just imagine the following situation: CPU1 CPU2 rvt_cq_enter() worker = cq->rdi->worker; rvt_cq_exit() rdi->worker = NULL; smp_wmb(); kthread_flush_worker(worker); kthread_stop(worker->task); kfree(worker); // nothing queued yet => // nothing flushed and // happily stopped and freed if (likely(worker)) { // true => read before CPU2 acted cq->notify = RVT_CQ_NONE; cq->triggered++; kthread_queue_work(worker, &cq->comptask); BANG: worker has been flushed/stopped/freed in the meantime. This patch solves this by protecting the critical sections by rdi->n_cqs_lock. It seems that this lock is not much contended and looks reasonable for this purpose. One catch is that rvt_cq_enter() might be called from IRQ context. Therefore we must always take the lock with IRQs disabled to avoid a possible deadlock. Signed-off-by: Petr Mladek Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/cq.c | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c index 6d9904a4a0ab..223ec4589fc7 100644 --- a/drivers/infiniband/sw/rdmavt/cq.c +++ b/drivers/infiniband/sw/rdmavt/cq.c @@ -119,18 +119,17 @@ void rvt_cq_enter(struct rvt_cq *cq, struct ib_wc *entry, bool solicited) if (cq->notify == IB_CQ_NEXT_COMP || (cq->notify == IB_CQ_SOLICITED && (solicited || entry->status != IB_WC_SUCCESS))) { - struct kthread_worker *worker; /* * This will cause send_complete() to be called in * another thread. */ - smp_read_barrier_depends(); /* see rvt_cq_exit */ - worker = cq->rdi->worker; - if (likely(worker)) { + spin_lock(&cq->rdi->n_cqs_lock); + if (likely(cq->rdi->worker)) { cq->notify = RVT_CQ_NONE; cq->triggered++; - kthread_queue_work(worker, &cq->comptask); + kthread_queue_work(cq->rdi->worker, &cq->comptask); } + spin_unlock(&cq->rdi->n_cqs_lock); } spin_unlock_irqrestore(&cq->lock, flags); @@ -240,15 +239,15 @@ struct ib_cq *rvt_create_cq(struct ib_device *ibdev, } } - spin_lock(&rdi->n_cqs_lock); + spin_lock_irq(&rdi->n_cqs_lock); if (rdi->n_cqs_allocated == rdi->dparms.props.max_cq) { - spin_unlock(&rdi->n_cqs_lock); + spin_unlock_irq(&rdi->n_cqs_lock); ret = ERR_PTR(-ENOMEM); goto bail_ip; } rdi->n_cqs_allocated++; - spin_unlock(&rdi->n_cqs_lock); + spin_unlock_irq(&rdi->n_cqs_lock); if (cq->ip) { spin_lock_irq(&rdi->pending_lock); @@ -296,9 +295,9 @@ int rvt_destroy_cq(struct ib_cq *ibcq) struct rvt_dev_info *rdi = cq->rdi; kthread_flush_work(&cq->comptask); - spin_lock(&rdi->n_cqs_lock); + spin_lock_irq(&rdi->n_cqs_lock); rdi->n_cqs_allocated--; - spin_unlock(&rdi->n_cqs_lock); + spin_unlock_irq(&rdi->n_cqs_lock); if (cq->ip) kref_put(&cq->ip->ref, rvt_release_mmap_info); else @@ -541,12 +540,15 @@ void rvt_cq_exit(struct rvt_dev_info *rdi) { struct kthread_worker *worker; - worker = rdi->worker; - if (!worker) + /* block future queuing from send_complete() */ + spin_lock_irq(&rdi->n_cqs_lock); + if (!rdi->worker) { + spin_unlock_irq(&rdi->n_cqs_lock); return; - /* blocks future queuing from send_complete() */ + } rdi->worker = NULL; - smp_wmb(); /* See rdi_cq_enter */ + spin_unlock_irq(&rdi->n_cqs_lock); + kthread_flush_worker(worker); kthread_stop(worker->task); kfree(worker); -- cgit v1.2.3 From f5eabf5e5129e8ab5b3e7f50b24444aca1680e64 Mon Sep 17 00:00:00 2001 From: Petr Mladek Date: Wed, 19 Oct 2016 14:07:20 +0200 Subject: IB/rdmavt: Handle the kthread worker using the new API Use the new API to create and destroy the cq kthread worker. The API hides some implementation details. In particular, kthread_create_worker() allocates and initializes struct kthread_worker. It runs the kthread the right way and stores task_struct into the worker structure. In addition, the *on_cpu() variant binds the kthread to the given cpu and the related memory node. kthread_destroy_worker() flushes all pending works, stops the kthread and frees the structure. This patch does not change the existing behavior. Note that we must use the on_cpu() variant because the function starts the kthread and it must bind it to the right CPU before waking. The numa node is associated for given CPU as well. Signed-off-by: Petr Mladek Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/cq.c | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c index 223ec4589fc7..4d0b6992e847 100644 --- a/drivers/infiniband/sw/rdmavt/cq.c +++ b/drivers/infiniband/sw/rdmavt/cq.c @@ -503,33 +503,23 @@ int rvt_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *entry) */ int rvt_driver_cq_init(struct rvt_dev_info *rdi) { - int ret = 0; int cpu; - struct task_struct *task; + struct kthread_worker *worker; if (rdi->worker) return 0; + spin_lock_init(&rdi->n_cqs_lock); - rdi->worker = kzalloc(sizeof(*rdi->worker), GFP_KERNEL); - if (!rdi->worker) - return -ENOMEM; - kthread_init_worker(rdi->worker); - task = kthread_create_on_node( - kthread_worker_fn, - rdi->worker, - rdi->dparms.node, - "%s", rdi->dparms.cq_name); - if (IS_ERR(task)) { - kfree(rdi->worker); - rdi->worker = NULL; - return PTR_ERR(task); - } - set_user_nice(task, MIN_NICE); cpu = cpumask_first(cpumask_of_node(rdi->dparms.node)); - kthread_bind(task, cpu); - wake_up_process(task); - return ret; + worker = kthread_create_worker_on_cpu(cpu, 0, + "%s", rdi->dparms.cq_name); + if (IS_ERR(worker)) + return PTR_ERR(worker); + + set_user_nice(worker->task, MIN_NICE); + rdi->worker = worker; + return 0; } /** @@ -549,7 +539,5 @@ void rvt_cq_exit(struct rvt_dev_info *rdi) rdi->worker = NULL; spin_unlock_irq(&rdi->n_cqs_lock); - kthread_flush_worker(worker); - kthread_stop(worker->task); - kfree(worker); + kthread_destroy_worker(worker); } -- cgit v1.2.3 From 22dccc5454a39427de7b87a080d026b6bf66a7b9 Mon Sep 17 00:00:00 2001 From: Jim Foraker Date: Tue, 1 Nov 2016 13:44:12 -0700 Subject: IB/rdmavt: Only put mmap_info ref if it exists rvt_create_qp() creates qp->ip only when a qp creation request comes from userspace (udata is not NULL). If we exceed the number of available queue pairs however, the error path always attempts to put a kref to this structure. If the requestor is inside the kernel, this leads to a crash. We fix this by checking that qp->ip is not NULL before caling kref_put(). Signed-off-by: Jim Foraker Acked-by: Dennis Dalessandro Acked-by: Jonathan Toppins Acked-by: Alex Estrin Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rdmavt/qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/qp.c b/drivers/infiniband/sw/rdmavt/qp.c index 9e14addd690c..2a13ac660f2b 100644 --- a/drivers/infiniband/sw/rdmavt/qp.c +++ b/drivers/infiniband/sw/rdmavt/qp.c @@ -901,7 +901,8 @@ struct ib_qp *rvt_create_qp(struct ib_pd *ibpd, return ret; bail_ip: - kref_put(&qp->ip->ref, rvt_release_mmap_info); + if (qp->ip) + kref_put(&qp->ip->ref, rvt_release_mmap_info); bail_qpn: free_qpn(&rdi->qp_dev->qpn_table, qp->ibqp.qp_num); -- cgit v1.2.3 From def4a6ffc9d178d6bb14178f56873c4831fb05a7 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 22 Oct 2016 01:01:21 +0300 Subject: IB/isert: do not ignore errors in dma_map_single() There are several places, where errors in dma_map_single() are ignored. The patch fixes them. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Acked-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/isert/ib_isert.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 6dd43f63238e..f0ba5f83b02c 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -1851,6 +1851,8 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd) isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, (void *)cmd->sense_buffer, pdu_len, DMA_TO_DEVICE); + if (ib_dma_mapping_error(ib_dev, isert_cmd->pdu_buf_dma)) + return -ENOMEM; isert_cmd->pdu_buf_len = pdu_len; tx_dsg->addr = isert_cmd->pdu_buf_dma; @@ -1978,6 +1980,8 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn) isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, (void *)cmd->buf_ptr, ISCSI_HDR_LEN, DMA_TO_DEVICE); + if (ib_dma_mapping_error(ib_dev, isert_cmd->pdu_buf_dma)) + return -ENOMEM; isert_cmd->pdu_buf_len = ISCSI_HDR_LEN; tx_dsg->addr = isert_cmd->pdu_buf_dma; tx_dsg->length = ISCSI_HDR_LEN; @@ -2018,6 +2022,8 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, txt_rsp_buf, txt_rsp_len, DMA_TO_DEVICE); + if (ib_dma_mapping_error(ib_dev, isert_cmd->pdu_buf_dma)) + return -ENOMEM; isert_cmd->pdu_buf_len = txt_rsp_len; tx_dsg->addr = isert_cmd->pdu_buf_dma; -- cgit v1.2.3 From 24dc08c3c9891a79f2754f99b7bffe65745af0f3 Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Tue, 25 Oct 2016 17:29:47 +0200 Subject: IB/nes: use new api ethtool_{get|set}_link_ksettings The ethtool api {get|set}_settings is deprecated. We move this driver to new api {get|set}_link_ksettings. Signed-off-by: Philippe Reynes Signed-off-by: Doug Ledford --- drivers/infiniband/hw/nes/nes_nic.c | 76 ++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 2b27d1351cf7..311b4ba1cade 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -1465,7 +1465,8 @@ static int nes_netdev_set_pauseparam(struct net_device *netdev, /** * nes_netdev_get_settings */ -static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd) +static int nes_netdev_get_link_ksettings(struct net_device *netdev, + struct ethtool_link_ksettings *cmd) { struct nes_vnic *nesvnic = netdev_priv(netdev); struct nes_device *nesdev = nesvnic->nesdev; @@ -1474,54 +1475,59 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd u8 phy_type = nesadapter->phy_type[mac_index]; u8 phy_index = nesadapter->phy_index[mac_index]; u16 phy_data; + u32 supported, advertising; - et_cmd->duplex = DUPLEX_FULL; - et_cmd->port = PORT_MII; - et_cmd->maxtxpkt = 511; - et_cmd->maxrxpkt = 511; + cmd->base.duplex = DUPLEX_FULL; + cmd->base.port = PORT_MII; if (nesadapter->OneG_Mode) { - ethtool_cmd_speed_set(et_cmd, SPEED_1000); + cmd->base.speed = SPEED_1000; if (phy_type == NES_PHY_TYPE_PUMA_1G) { - et_cmd->supported = SUPPORTED_1000baseT_Full; - et_cmd->advertising = ADVERTISED_1000baseT_Full; - et_cmd->autoneg = AUTONEG_DISABLE; - et_cmd->transceiver = XCVR_INTERNAL; - et_cmd->phy_address = mac_index; + supported = SUPPORTED_1000baseT_Full; + advertising = ADVERTISED_1000baseT_Full; + cmd->base.autoneg = AUTONEG_DISABLE; + cmd->base.phy_address = mac_index; } else { unsigned long flags; - et_cmd->supported = SUPPORTED_1000baseT_Full - | SUPPORTED_Autoneg; - et_cmd->advertising = ADVERTISED_1000baseT_Full - | ADVERTISED_Autoneg; + + supported = SUPPORTED_1000baseT_Full + | SUPPORTED_Autoneg; + advertising = ADVERTISED_1000baseT_Full + | ADVERTISED_Autoneg; spin_lock_irqsave(&nesadapter->phy_lock, flags); nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); spin_unlock_irqrestore(&nesadapter->phy_lock, flags); if (phy_data & 0x1000) - et_cmd->autoneg = AUTONEG_ENABLE; + cmd->base.autoneg = AUTONEG_ENABLE; else - et_cmd->autoneg = AUTONEG_DISABLE; - et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->phy_address = phy_index; + cmd->base.autoneg = AUTONEG_DISABLE; + cmd->base.phy_address = phy_index; } + ethtool_convert_legacy_u32_to_link_mode( + cmd->link_modes.supported, supported); + ethtool_convert_legacy_u32_to_link_mode( + cmd->link_modes.advertising, advertising); return 0; } if ((phy_type == NES_PHY_TYPE_ARGUS) || (phy_type == NES_PHY_TYPE_SFP_D) || (phy_type == NES_PHY_TYPE_KR)) { - et_cmd->transceiver = XCVR_EXTERNAL; - et_cmd->port = PORT_FIBRE; - et_cmd->supported = SUPPORTED_FIBRE; - et_cmd->advertising = ADVERTISED_FIBRE; - et_cmd->phy_address = phy_index; + cmd->base.port = PORT_FIBRE; + supported = SUPPORTED_FIBRE; + advertising = ADVERTISED_FIBRE; + cmd->base.phy_address = phy_index; } else { - et_cmd->transceiver = XCVR_INTERNAL; - et_cmd->supported = SUPPORTED_10000baseT_Full; - et_cmd->advertising = ADVERTISED_10000baseT_Full; - et_cmd->phy_address = mac_index; + supported = SUPPORTED_10000baseT_Full; + advertising = ADVERTISED_10000baseT_Full; + cmd->base.phy_address = mac_index; } - ethtool_cmd_speed_set(et_cmd, SPEED_10000); - et_cmd->autoneg = AUTONEG_DISABLE; + cmd->base.speed = SPEED_10000; + cmd->base.autoneg = AUTONEG_DISABLE; + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); + return 0; } @@ -1529,7 +1535,9 @@ static int nes_netdev_get_settings(struct net_device *netdev, struct ethtool_cmd /** * nes_netdev_set_settings */ -static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd *et_cmd) +static int +nes_netdev_set_link_ksettings(struct net_device *netdev, + const struct ethtool_link_ksettings *cmd) { struct nes_vnic *nesvnic = netdev_priv(netdev); struct nes_device *nesdev = nesvnic->nesdev; @@ -1543,7 +1551,7 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd spin_lock_irqsave(&nesadapter->phy_lock, flags); nes_read_1G_phy_reg(nesdev, 0, phy_index, &phy_data); - if (et_cmd->autoneg) { + if (cmd->base.autoneg) { /* Turn on Full duplex, Autoneg, and restart autonegotiation */ phy_data |= 0x1300; } else { @@ -1560,8 +1568,6 @@ static int nes_netdev_set_settings(struct net_device *netdev, struct ethtool_cmd static const struct ethtool_ops nes_ethtool_ops = { .get_link = ethtool_op_get_link, - .get_settings = nes_netdev_get_settings, - .set_settings = nes_netdev_set_settings, .get_strings = nes_netdev_get_strings, .get_sset_count = nes_netdev_get_sset_count, .get_ethtool_stats = nes_netdev_get_ethtool_stats, @@ -1570,6 +1576,8 @@ static const struct ethtool_ops nes_ethtool_ops = { .set_coalesce = nes_netdev_set_coalesce, .get_pauseparam = nes_netdev_get_pauseparam, .set_pauseparam = nes_netdev_set_pauseparam, + .get_link_ksettings = nes_netdev_get_link_ksettings, + .set_link_ksettings = nes_netdev_set_link_ksettings, }; static void nes_vlan_mode(struct net_device *netdev, struct nes_device *nesdev, netdev_features_t features) -- cgit v1.2.3 From 9315bc9a133011fdb084f2626b86db3ebb64661f Mon Sep 17 00:00:00 2001 From: Hans Westgaard Ry Date: Fri, 28 Oct 2016 13:14:29 +0200 Subject: IB/core: Issue DREQ when receiving REQ/REP for stale QP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit from "InfiBand Architecture Specifications Volume 1": A QP is said to have a stale connection when only one side has connection information. A stale connection may result if the remote CM had dropped the connection and sent a DREQ but the DREQ was never received by the local CM. Alternatively the remote CM may have lost all record of past connections because its node crashed and rebooted, while the local CM did not become aware of the remote node's reboot and therefore did not clean up stale connections. and: A local CM may receive a REQ/REP for a stale connection. It shall abort the connection issuing REJ to the REQ/REP. It shall then issue DREQ with "DREQ:remote QPN” set to the remote QPN from the REQ/REP. This patch solves a problem with reuse of QPN. Current codebase, that is IPoIB, relies on a REAP-mechanism to do cleanup of the structures in CM. A problem with this is the timeconstants governing this mechanism; they are up to 768 seconds and the interface may look inresponsive in that period. Issuing a DREQ (and receiving a DREP) does the necessary cleanup and the interface comes up. Signed-off-by: Hans Westgaard Ry Reviewed-by: Håkon Bugge Reviewed-by: Sagi Grimberg Signed-off-by: Doug Ledford --- drivers/infiniband/core/cm.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index c99525512b34..c97e4d586b44 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c @@ -1519,6 +1519,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, struct cm_id_private *listen_cm_id_priv, *cur_cm_id_priv; struct cm_timewait_info *timewait_info; struct cm_req_msg *req_msg; + struct ib_cm_id *cm_id; req_msg = (struct cm_req_msg *)work->mad_recv_wc->recv_buf.mad; @@ -1540,10 +1541,18 @@ static struct cm_id_private * cm_match_req(struct cm_work *work, timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info); if (timewait_info) { cm_cleanup_timewait(cm_id_priv->timewait_info); + cur_cm_id_priv = cm_get_id(timewait_info->work.local_id, + timewait_info->work.remote_id); + spin_unlock_irq(&cm.lock); cm_issue_rej(work->port, work->mad_recv_wc, IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ, NULL, 0); + if (cur_cm_id_priv) { + cm_id = &cur_cm_id_priv->id; + ib_send_cm_dreq(cm_id, NULL, 0); + cm_deref_id(cur_cm_id_priv); + } return NULL; } @@ -1919,6 +1928,9 @@ static int cm_rep_handler(struct cm_work *work) struct cm_id_private *cm_id_priv; struct cm_rep_msg *rep_msg; int ret; + struct cm_id_private *cur_cm_id_priv; + struct ib_cm_id *cm_id; + struct cm_timewait_info *timewait_info; rep_msg = (struct cm_rep_msg *)work->mad_recv_wc->recv_buf.mad; cm_id_priv = cm_acquire_id(rep_msg->remote_comm_id, 0); @@ -1953,16 +1965,26 @@ static int cm_rep_handler(struct cm_work *work) goto error; } /* Check for a stale connection. */ - if (cm_insert_remote_qpn(cm_id_priv->timewait_info)) { + timewait_info = cm_insert_remote_qpn(cm_id_priv->timewait_info); + if (timewait_info) { rb_erase(&cm_id_priv->timewait_info->remote_id_node, &cm.remote_id_table); cm_id_priv->timewait_info->inserted_remote_id = 0; + cur_cm_id_priv = cm_get_id(timewait_info->work.local_id, + timewait_info->work.remote_id); + spin_unlock(&cm.lock); spin_unlock_irq(&cm_id_priv->lock); cm_issue_rej(work->port, work->mad_recv_wc, IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REP, NULL, 0); ret = -EINVAL; + if (cur_cm_id_priv) { + cm_id = &cur_cm_id_priv->id; + ib_send_cm_dreq(cm_id, NULL, 0); + cm_deref_id(cur_cm_id_priv); + } + goto error; } spin_unlock(&cm.lock); -- cgit v1.2.3 From 5f4c7e4eb5f36974ed46a485290f5d01ace5fdba Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Nov 2016 20:04:26 +0100 Subject: IB/usnic: simplify IS_ERR_OR_NULL to IS_ERR The function usnic_ib_qp_grp_get_chunk only returns an ERR_PTR value or a valid pointer, never NULL. The same is true of get_qp_res_chunk, which just returns the result of calling usnic_ib_qp_grp_get_chunk. Simplify IS_ERR_OR_NULL to IS_ERR in both cases. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ expression t,e; @@ t = \(usnic_ib_qp_grp_get_chunk(...)\|get_qp_res_chunk(...)\) ... when != t=e - IS_ERR_OR_NULL(t) + IS_ERR(t) @@ expression t,e,e1; @@ t = \(usnic_ib_qp_grp_get_chunk(...)\|get_qp_res_chunk(...)\) ... when != t=e ?- t ? PTR_ERR(t) : e1 + PTR_ERR(t) ... when any // Signed-off-by: Julia Lawall Reviewed-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c | 12 ++++++------ drivers/infiniband/hw/usnic/usnic_ib_verbs.c | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c index 5b0248adf4ce..2b1a3819627f 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_qp_grp.c @@ -117,10 +117,10 @@ static int enable_qp_grp(struct usnic_ib_qp_grp *qp_grp) vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic); res_chunk = get_qp_res_chunk(qp_grp); - if (IS_ERR_OR_NULL(res_chunk)) { + if (IS_ERR(res_chunk)) { usnic_err("Unable to get qp res with err %ld\n", PTR_ERR(res_chunk)); - return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM; + return PTR_ERR(res_chunk); } for (i = 0; i < res_chunk->cnt; i++) { @@ -158,10 +158,10 @@ static int disable_qp_grp(struct usnic_ib_qp_grp *qp_grp) vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic); res_chunk = get_qp_res_chunk(qp_grp); - if (IS_ERR_OR_NULL(res_chunk)) { + if (IS_ERR(res_chunk)) { usnic_err("Unable to get qp res with err %ld\n", PTR_ERR(res_chunk)); - return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM; + return PTR_ERR(res_chunk); } for (i = 0; i < res_chunk->cnt; i++) { @@ -186,11 +186,11 @@ static int init_filter_action(struct usnic_ib_qp_grp *qp_grp, struct usnic_vnic_res_chunk *res_chunk; res_chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ); - if (IS_ERR_OR_NULL(res_chunk)) { + if (IS_ERR(res_chunk)) { usnic_err("Unable to get %s with err %ld\n", usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ), PTR_ERR(res_chunk)); - return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM; + return PTR_ERR(res_chunk); } uaction->vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic); diff --git a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c index a5bfbba6bbac..79766db1dc6c 100644 --- a/drivers/infiniband/hw/usnic/usnic_ib_verbs.c +++ b/drivers/infiniband/hw/usnic/usnic_ib_verbs.c @@ -87,12 +87,12 @@ static int usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp *qp_grp, resp.bar_len = bar->len; chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ); - if (IS_ERR_OR_NULL(chunk)) { + if (IS_ERR(chunk)) { usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n", usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ), qp_grp->grp_id, PTR_ERR(chunk)); - return chunk ? PTR_ERR(chunk) : -ENOMEM; + return PTR_ERR(chunk); } WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_RQ); @@ -101,12 +101,12 @@ static int usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp *qp_grp, resp.rq_idx[i] = chunk->res[i]->vnic_idx; chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_WQ); - if (IS_ERR_OR_NULL(chunk)) { + if (IS_ERR(chunk)) { usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n", usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_WQ), qp_grp->grp_id, PTR_ERR(chunk)); - return chunk ? PTR_ERR(chunk) : -ENOMEM; + return PTR_ERR(chunk); } WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_WQ); @@ -115,12 +115,12 @@ static int usnic_ib_fill_create_qp_resp(struct usnic_ib_qp_grp *qp_grp, resp.wq_idx[i] = chunk->res[i]->vnic_idx; chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_CQ); - if (IS_ERR_OR_NULL(chunk)) { + if (IS_ERR(chunk)) { usnic_err("Failed to get chunk %s for qp_grp %d with err %ld\n", usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_CQ), qp_grp->grp_id, PTR_ERR(chunk)); - return chunk ? PTR_ERR(chunk) : -ENOMEM; + return PTR_ERR(chunk); } WARN_ON(chunk->type != USNIC_VNIC_RES_TYPE_CQ); -- cgit v1.2.3 From 0d38c240f97602d9a4553252bb710521f49bb264 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 11 Nov 2016 16:36:06 -0800 Subject: IB/srpt: Report login failures only once Report the following message only once if no ACL has been configured yet for an initiator port: "Rejected login because no ACL has been configured yet for initiator %s.\n" Signed-off-by: Bart Van Assche Cc: Nicholas Bellinger Cc: Christoph Hellwig Cc: Sagi Grimberg Reviewed-by: Max Gurtovoy Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srpt/ib_srpt.c | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 0b1f69ed2e92..d21ba9d857c3 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c @@ -1840,7 +1840,6 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, struct srpt_rdma_ch *ch, *tmp_ch; u32 it_iu_len; int i, ret = 0; - unsigned char *p; WARN_ON_ONCE(irqs_disabled()); @@ -1994,21 +1993,18 @@ static int srpt_cm_req_recv(struct ib_cm_id *cm_id, be64_to_cpu(*(__be64 *)(ch->i_port_id + 8))); pr_debug("registering session %s\n", ch->sess_name); - p = &ch->sess_name[0]; -try_again: ch->sess = target_alloc_session(&sport->port_tpg_1, 0, 0, - TARGET_PROT_NORMAL, p, ch, NULL); + TARGET_PROT_NORMAL, ch->sess_name, ch, + NULL); + /* Retry without leading "0x" */ + if (IS_ERR(ch->sess)) + ch->sess = target_alloc_session(&sport->port_tpg_1, 0, 0, + TARGET_PROT_NORMAL, + ch->sess_name + 2, ch, NULL); if (IS_ERR(ch->sess)) { - pr_info("Rejected login because no ACL has been" - " configured yet for initiator %s.\n", p); - /* - * XXX: Hack to retry of ch->i_port_id without leading '0x' - */ - if (p == &ch->sess_name[0]) { - p += 2; - goto try_again; - } + pr_info("Rejected login because no ACL has been configured yet for initiator %s.\n", + ch->sess_name); rej->reason = cpu_to_be32((PTR_ERR(ch->sess) == -ENOMEM) ? SRP_LOGIN_REJ_INSUFFICIENT_RESOURCES : SRP_LOGIN_REJ_CHANNEL_LIMIT_REACHED); -- cgit v1.2.3 From b42dde478bcaa8113b0d1cd82ad0048372c5599d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 14 Nov 2016 08:44:11 -0800 Subject: IB/mlx4: Rework special QP creation error path The special QP creation error path relies on offset_of(struct mlx4_ib_sqp, qp) == 0. Remove this assumption because that makes the QP creation code easier to understand. Signed-off-by: Bart Van Assche Cc: Yishai Hadas Reviewed-by: Laurence Oberman Reviewed-by: Yishai Hadas Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/qp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c index c22454383976..c068add8838b 100644 --- a/drivers/infiniband/hw/mlx4/qp.c +++ b/drivers/infiniband/hw/mlx4/qp.c @@ -644,7 +644,7 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd, int qpn; int err; struct ib_qp_cap backup_cap; - struct mlx4_ib_sqp *sqp; + struct mlx4_ib_sqp *sqp = NULL; struct mlx4_ib_qp *qp; enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type; struct mlx4_ib_cq *mcq; @@ -933,7 +933,9 @@ err_db: mlx4_db_free(dev->dev, &qp->db); err: - if (!*caller_qp) + if (sqp) + kfree(sqp); + else if (!*caller_qp) kfree(qp); return err; } -- cgit v1.2.3 From 2fe2f378dd45847d2643638c07a7658822087836 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 10:21:17 -0800 Subject: IB/mad: Fix an array index check The array ib_mad_mgmt_class_table.method_table has MAX_MGMT_CLASS (80) elements. Hence compare the array index with that value instead of with IB_MGMT_MAX_METHODS (128). This patch avoids that Coverity reports the following: Overrunning array class->method_table of 80 8-byte elements at element index 127 (byte offset 1016) using index convert_mgmt_class(mad_hdr->mgmt_class) (which evaluates to 127). Fixes: commit b7ab0b19a85f ("IB/mad: Verify mgmt class in received MADs") Signed-off-by: Bart Van Assche Cc: Sean Hefty Cc: Reviewed-by: Hal Rosenstock Signed-off-by: Doug Ledford --- drivers/infiniband/core/mad.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index bc2a9c2caa3c..d120f6ff1ea6 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c @@ -1746,7 +1746,7 @@ find_mad_agent(struct ib_mad_port_private *port_priv, if (!class) goto out; if (convert_mgmt_class(mad_hdr->mgmt_class) >= - IB_MGMT_MAX_METHODS) + ARRAY_SIZE(class->method_table)) goto out; method = class->method_table[convert_mgmt_class( mad_hdr->mgmt_class)]; -- cgit v1.2.3 From 11b642b84e8c43e8597de031678d15c08dd057bc Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 10:21:41 -0800 Subject: IPoIB: Avoid reading an uninitialized member variable This patch avoids that Coverity reports the following: Using uninitialized value port_attr.state when calling printk Fixes: commit 94232d9ce817 ("IPoIB: Start multicast join process only on active ports") Signed-off-by: Bart Van Assche Cc: Erez Shitrit Cc: Reviewed-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index d3394b6add24..2a3980c2c670 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -575,8 +575,11 @@ void ipoib_mcast_join_task(struct work_struct *work) if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) return; - if (ib_query_port(priv->ca, priv->port, &port_attr) || - port_attr.state != IB_PORT_ACTIVE) { + if (ib_query_port(priv->ca, priv->port, &port_attr)) { + ipoib_dbg(priv, "ib_query_port() failed\n"); + return; + } + if (port_attr.state != IB_PORT_ACTIVE) { ipoib_dbg(priv, "port state is not ACTIVE (state = %d) suspending join task\n", port_attr.state); return; -- cgit v1.2.3 From d3a2418ee36a59bc02e9d454723f3175dcf4bfd9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 10:22:17 -0800 Subject: IB/multicast: Check ib_find_pkey() return value This patch avoids that Coverity complains about not checking the ib_find_pkey() return value. Fixes: commit 547af76521b3 ("IB/multicast: Report errors on multicast groups if P_key changes") Signed-off-by: Bart Van Assche Cc: Sean Hefty Cc: Signed-off-by: Doug Ledford --- drivers/infiniband/core/multicast.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index e51b739f6ea3..322cb67b07a9 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c @@ -518,8 +518,11 @@ static void join_handler(int status, struct ib_sa_mcmember_rec *rec, process_join_error(group, status); else { int mgids_changed, is_mgid0; - ib_find_pkey(group->port->dev->device, group->port->port_num, - be16_to_cpu(rec->pkey), &pkey_index); + + if (ib_find_pkey(group->port->dev->device, + group->port->port_num, be16_to_cpu(rec->pkey), + &pkey_index)) + pkey_index = MCAST_INVALID_PKEY_INDEX; spin_lock_irq(&group->port->lock); if (group->state == MCAST_BUSY && -- cgit v1.2.3 From 1a1faf7a8a251d134d375b7783a614ee79e932f2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 13:56:46 -0800 Subject: IB/srp: Fix CONFIG_DYNAMIC_DEBUG=n build Avoid that the kernel build fails as follows if dynamic debug support is disabled: drivers/infiniband/ulp/srp/ib_srp.c:2272:3: error: implicit declaration of function 'DEFINE_DYNAMIC_DEBUG_METADATA' drivers/infiniband/ulp/srp/ib_srp.c:2272:33: error: 'ddm' undeclared (first use in this function) drivers/infiniband/ulp/srp/ib_srp.c:2275:39: error: '_DPRINTK_FLAGS_PRINT' undeclared (first use in this function) Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index d980fb458ad4..8bb720c68af0 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -64,6 +64,11 @@ MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(DRV_VERSION); MODULE_INFO(release_date, DRV_RELDATE); +#if !defined(CONFIG_DYNAMIC_DEBUG) +#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) +#define DYNAMIC_DEBUG_BRANCH(descriptor) false +#endif + static unsigned int srp_sg_tablesize; static unsigned int cmd_sg_entries; static unsigned int indirect_sg_entries; @@ -1556,7 +1561,6 @@ static int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req, return 0; } -#if defined(DYNAMIC_DATA_DEBUG) static void srp_check_mapping(struct srp_map_state *state, struct srp_rdma_ch *ch, struct srp_request *req, struct scatterlist *scat, int count) @@ -1580,7 +1584,6 @@ static void srp_check_mapping(struct srp_map_state *state, scsi_bufflen(req->scmnd), desc_len, mr_len, state->ndesc, state->nmdesc); } -#endif /** * srp_map_data() - map SCSI data buffer onto an SRP request @@ -1669,14 +1672,12 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch, if (ret < 0) goto unmap; -#if defined(DYNAMIC_DEBUG) { DEFINE_DYNAMIC_DEBUG_METADATA(ddm, "Memory mapping consistency check"); - if (unlikely(ddm.flags & _DPRINTK_FLAGS_PRINT)) + if (DYNAMIC_DEBUG_BRANCH(ddm)) srp_check_mapping(&state, ch, req, scat, count); } -#endif /* We've mapped the request, now pull as much of the indirect * descriptor table as we can into the command buffer. If this -- cgit v1.2.3 From 042dd765bdf401c0ccdeb16717b0c2a0b1405f18 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 13:57:07 -0800 Subject: IB/srp: Introduce a local variable in srp_add_one() This patch makes the srp_add_one() code more compact and does not change any functionality. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 8bb720c68af0..c216c6eaef26 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -3527,6 +3527,7 @@ free_host: static void srp_add_one(struct ib_device *device) { struct srp_device *srp_dev; + struct ib_device_attr *attr = &device->attrs; struct srp_host *host; int mr_page_shift, p; u64 max_pages_per_mr; @@ -3541,25 +3542,25 @@ static void srp_add_one(struct ib_device *device) * minimum of 4096 bytes. We're unlikely to build large sglists * out of smaller entries. */ - mr_page_shift = max(12, ffs(device->attrs.page_size_cap) - 1); + mr_page_shift = max(12, ffs(attr->page_size_cap) - 1); srp_dev->mr_page_size = 1 << mr_page_shift; srp_dev->mr_page_mask = ~((u64) srp_dev->mr_page_size - 1); - max_pages_per_mr = device->attrs.max_mr_size; + max_pages_per_mr = attr->max_mr_size; do_div(max_pages_per_mr, srp_dev->mr_page_size); pr_debug("%s: %llu / %u = %llu <> %u\n", __func__, - device->attrs.max_mr_size, srp_dev->mr_page_size, + attr->max_mr_size, srp_dev->mr_page_size, max_pages_per_mr, SRP_MAX_PAGES_PER_MR); srp_dev->max_pages_per_mr = min_t(u64, SRP_MAX_PAGES_PER_MR, max_pages_per_mr); srp_dev->has_fmr = (device->alloc_fmr && device->dealloc_fmr && device->map_phys_fmr && device->unmap_fmr); - srp_dev->has_fr = (device->attrs.device_cap_flags & + srp_dev->has_fr = (attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS); if (!never_register && !srp_dev->has_fmr && !srp_dev->has_fr) { dev_warn(&device->dev, "neither FMR nor FR is supported\n"); } else if (!never_register && - device->attrs.max_mr_size >= 2 * srp_dev->mr_page_size) { + attr->max_mr_size >= 2 * srp_dev->mr_page_size) { srp_dev->use_fast_reg = (srp_dev->has_fr && (!srp_dev->has_fmr || prefer_fr)); srp_dev->use_fmr = !srp_dev->use_fast_reg && srp_dev->has_fmr; @@ -3572,13 +3573,13 @@ static void srp_add_one(struct ib_device *device) if (srp_dev->use_fast_reg) { srp_dev->max_pages_per_mr = min_t(u32, srp_dev->max_pages_per_mr, - device->attrs.max_fast_reg_page_list_len); + attr->max_fast_reg_page_list_len); } srp_dev->mr_max_size = srp_dev->mr_page_size * srp_dev->max_pages_per_mr; pr_debug("%s: mr_page_shift = %d, device->max_mr_size = %#llx, device->max_fast_reg_page_list_len = %u, max_pages_per_mr = %d, mr_max_size = %#x\n", - device->name, mr_page_shift, device->attrs.max_mr_size, - device->attrs.max_fast_reg_page_list_len, + device->name, mr_page_shift, attr->max_mr_size, + attr->max_fast_reg_page_list_len, srp_dev->max_pages_per_mr, srp_dev->mr_max_size); INIT_LIST_HEAD(&srp_dev->dev_list); -- cgit v1.2.3 From 3787d9908c4e05af0322613fe7f8c617c1ddb1d5 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 13:57:24 -0800 Subject: IB/srp: Make login failures easier to debug If login fails because memory region allocation failed it can be hard to figure out what happened. Make it easier to figure out why login failed by logging a message if ib_alloc_mr() fails. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index c216c6eaef26..81cb27f2f0e6 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -389,6 +389,9 @@ static struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device, max_page_list_len); if (IS_ERR(mr)) { ret = PTR_ERR(mr); + if (ret == -ENOMEM) + pr_info("%s: ib_alloc_mr() failed. Try to reduce max_cmd_per_lun, max_sect or ch_count\n", + dev_name(&device->dev)); goto destroy_pool; } d->mr = mr; -- cgit v1.2.3 From 290081b45342ef902ed756f929fa9e4feb9f7dab Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 13:57:41 -0800 Subject: IB/srp: Make mapping failures easier to debug Make it easier to figure out what is going on if memory mapping fails because more memory regions than mr_per_cmd are needed. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 81cb27f2f0e6..bb9d73daadfa 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1274,8 +1274,12 @@ static int srp_map_finish_fmr(struct srp_map_state *state, struct ib_pool_fmr *fmr; u64 io_addr = 0; - if (state->fmr.next >= state->fmr.end) + if (state->fmr.next >= state->fmr.end) { + shost_printk(KERN_ERR, ch->target->scsi_host, + PFX "Out of MRs (mr_per_cmd = %d)\n", + ch->target->mr_per_cmd); return -ENOMEM; + } WARN_ON_ONCE(!dev->use_fmr); @@ -1331,8 +1335,12 @@ static int srp_map_finish_fr(struct srp_map_state *state, u32 rkey; int n, err; - if (state->fr.next >= state->fr.end) + if (state->fr.next >= state->fr.end) { + shost_printk(KERN_ERR, ch->target->scsi_host, + PFX "Out of MRs (mr_per_cmd = %d)\n", + ch->target->mr_per_cmd); return -ENOMEM; + } WARN_ON_ONCE(!dev->use_fast_reg); -- cgit v1.2.3 From 4fa354c9dbfef9226a690d8ee319b046f3067a6a Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 21 Nov 2016 13:58:18 -0800 Subject: IB/srp: Make writing the add_target sysfs attr interruptible Avoid that shutdown of srp_daemon is delayed if add_target_mutex is held by another process. Signed-off-by: Bart Van Assche Signed-off-by: Doug Ledford --- drivers/infiniband/ulp/srp/ib_srp.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index bb9d73daadfa..8ddc07123193 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -3299,7 +3299,9 @@ static ssize_t srp_create_target(struct device *dev, */ scsi_host_get(target->scsi_host); - mutex_lock(&host->add_target_mutex); + ret = mutex_lock_interruptible(&host->add_target_mutex); + if (ret < 0) + goto put; ret = srp_parse_options(buf, target); if (ret) @@ -3455,6 +3457,7 @@ connected: out: mutex_unlock(&host->add_target_mutex); +put: scsi_host_put(target->scsi_host); if (ret < 0) scsi_host_put(target->scsi_host); -- cgit v1.2.3 From 626bc02d4d33510b6ecb6f37c577f844cc6cfc57 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 5 Dec 2016 17:18:08 -0800 Subject: mlx5: Use { } instead of { 0 } to init struct Detected by sparse. Signed-off-by: Bart Van Assche Cc: Eli Cohen Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c index cda541ced141..b81736d625fc 100644 --- a/drivers/infiniband/hw/mlx5/main.c +++ b/drivers/infiniband/hw/mlx5/main.c @@ -127,7 +127,7 @@ static int mlx5_netdev_event(struct notifier_block *this, if ((upper == ndev || (!upper && ndev == ibdev->roce.netdev)) && ibdev->ib_active) { - struct ib_event ibev = {0}; + struct ib_event ibev = { }; ibev.device = &ibdev->ib_dev; ibev.event = (event == NETDEV_UP) ? -- cgit v1.2.3 From 3d6bdf1625857ba50f433bd140dada387432f051 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 5 Dec 2016 17:18:27 -0800 Subject: mlx5: Remove a set-but-not-used variable This has been detected by building the mlx5 driver with W=1. Fixes: 1a412fb1caa2 ('net/mlx5: Fixes: 1a412fb1caa2 (IB/mlx5: Modify QP commands via mlx5 ifc') Signed-off-by: Bart Van Assche Cc: Eli Cohen Acked-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/qp.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index a69524fb6032..30f6066b0560 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -2657,7 +2657,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, struct mlx5_ib_port *mibport = NULL; enum mlx5_qp_state mlx5_cur, mlx5_new; enum mlx5_qp_optpar optpar; - int sqd_event; int mlx5_st; int err; u16 op; @@ -2804,12 +2803,6 @@ static int __mlx5_ib_modify_qp(struct ib_qp *ibqp, if (qp->rq.wqe_cnt && cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) context->db_rec_addr = cpu_to_be64(qp->db.dma); - if (cur_state == IB_QPS_RTS && new_state == IB_QPS_SQD && - attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY && attr->en_sqd_async_notify) - sqd_event = 1; - else - sqd_event = 0; - if (cur_state == IB_QPS_RESET && new_state == IB_QPS_INIT) { u8 port_num = (attr_mask & IB_QP_PORT ? attr->port_num : qp->port) - 1; -- cgit v1.2.3 From 1974ab9d9d5b6eeafa629f793fdf59958646cb9d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 5 Dec 2016 17:19:52 -0800 Subject: mlx5, calc_sq_size(): Make a debug message more informative Make it clear that qp->sq.wqe_cnt is not the number of WQEs. Signed-off-by: Bart Van Assche Cc: Eli Cohen Acked-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx5/qp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx5/qp.c b/drivers/infiniband/hw/mlx5/qp.c index 30f6066b0560..cc24f2d429b9 100644 --- a/drivers/infiniband/hw/mlx5/qp.c +++ b/drivers/infiniband/hw/mlx5/qp.c @@ -407,7 +407,8 @@ static int calc_sq_size(struct mlx5_ib_dev *dev, struct ib_qp_init_attr *attr, wq_size = roundup_pow_of_two(attr->cap.max_send_wr * wqe_size); qp->sq.wqe_cnt = wq_size / MLX5_SEND_WQE_BB; if (qp->sq.wqe_cnt > (1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz))) { - mlx5_ib_dbg(dev, "wqe count(%d) exceeds limits(%d)\n", + mlx5_ib_dbg(dev, "send queue size (%d * %d / %d -> %d) exceeds limits(%d)\n", + attr->cap.max_send_wr, wqe_size, MLX5_SEND_WQE_BB, qp->sq.wqe_cnt, 1 << MLX5_CAP_GEN(dev->mdev, log_max_qp_sz)); return -ENOMEM; -- cgit v1.2.3 From 7ceb740c540dde362b3055ad92c6a38009eb7a83 Mon Sep 17 00:00:00 2001 From: Souptick Joarder Date: Fri, 2 Dec 2016 00:11:59 +0530 Subject: IB/mthca: Replace pci_pool_alloc by pci_pool_zalloc In mthca_create_ah(), pci_pool_alloc() followed by memset will be replaced by pci_pool_zalloc() Signed-off-by: Souptick joarder Reviewed-by: Yuval Shaia Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mthca/mthca_av.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c index bcac294042f5..c9f0f364f484 100644 --- a/drivers/infiniband/hw/mthca/mthca_av.c +++ b/drivers/infiniband/hw/mthca/mthca_av.c @@ -186,8 +186,8 @@ int mthca_create_ah(struct mthca_dev *dev, on_hca_fail: if (ah->type == MTHCA_AH_PCI_POOL) { - ah->av = pci_pool_alloc(dev->av_table.pool, - GFP_ATOMIC, &ah->avdma); + ah->av = pci_pool_zalloc(dev->av_table.pool, + GFP_ATOMIC, &ah->avdma); if (!ah->av) return -ENOMEM; @@ -196,8 +196,6 @@ on_hca_fail: ah->key = pd->ntmr.ibmr.lkey; - memset(av, 0, MTHCA_AV_SIZE); - av->port_pd = cpu_to_be32(pd->pd_num | (ah_attr->port_num << 24)); av->g_slid = ah_attr->src_path_bits; av->dlid = cpu_to_be16(ah_attr->dlid); -- cgit v1.2.3 From 22b1ae6169e3cb9e33ba549a0c07a0cc469143d7 Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Wed, 23 Nov 2016 08:03:04 +0000 Subject: qede: fix general protection fault may occur on probe The recent introduction of qedr driver support in qede causes a GPF when probing the driver in a server without a RoCE enabled QLogic NIC. This fix avoids using an uninitialized pointer in such a case. Caught by the kernel test robot. Signed-off-by: Ram Amrani Signed-off-by: Doug Ledford --- drivers/net/ethernet/qlogic/qede/qede_roce.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qede/qede_roce.c b/drivers/net/ethernet/qlogic/qede/qede_roce.c index 9867f960b063..49272716a7c4 100644 --- a/drivers/net/ethernet/qlogic/qede/qede_roce.c +++ b/drivers/net/ethernet/qlogic/qede/qede_roce.c @@ -191,8 +191,8 @@ int qede_roce_register_driver(struct qedr_driver *drv) } mutex_unlock(&qedr_dev_list_lock); - DP_INFO(edev, "qedr: discovered and registered %d RoCE funcs\n", - qedr_counter); + pr_notice("qedr: discovered and registered %d RoCE funcs\n", + qedr_counter); return 0; } -- cgit v1.2.3 From 17069d32a3408e69d257a3fe26f08de0336d958d Mon Sep 17 00:00:00 2001 From: Sebastian Ott Date: Fri, 2 Dec 2016 14:45:26 +0100 Subject: IB/core: fix unmap_sg argument __ib_umem_release calls dma_unmap_sg with a different number of sg_entries than ib_umem_get uses for dma_map_sg. This might cause trouble for implementations that merge sglist entries and results in the following dma debug complaint: DMA-API: device driver frees DMA sg list with different entry count [map count=2] [unmap count=1] Fix it by using the correct value. Signed-off-by: Sebastian Ott Signed-off-by: Doug Ledford --- drivers/infiniband/core/umem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c index 224ad274ea0b..0120e7ff449f 100644 --- a/drivers/infiniband/core/umem.c +++ b/drivers/infiniband/core/umem.c @@ -51,7 +51,7 @@ static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int d if (umem->nmap > 0) ib_dma_unmap_sg(dev, umem->sg_head.sgl, - umem->nmap, + umem->npages, DMA_BIDIRECTIONAL); for_each_sg(umem->sg_head.sgl, sg, umem->npages, i) { -- cgit v1.2.3 From 6a3a1056d66e6a64446930b0d9de2430d835d38f Mon Sep 17 00:00:00 2001 From: Zhouyi Zhou Date: Wed, 7 Dec 2016 15:30:05 +0800 Subject: infiniband: nes: return value of skb_linearize should be handled Return value of skb_linearize should be handled in function nes_netdev_start_xmit. Compiled in x86_64 Signed-off-by: Zhouyi Zhou Reviewed-by: Yuval Shaia Reviewed-by: Eric Dumazet Signed-off-by: Doug Ledford --- drivers/infiniband/hw/nes/nes_nic.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 311b4ba1cade..4dcfe669ebad 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -662,10 +662,14 @@ tso_sq_no_longer_full: nesnic->sq_head &= nesnic->sq_size-1; } } else { - nesvnic->linearized_skbs++; hoffset = skb_transport_header(skb) - skb->data; nhoffset = skb_network_header(skb) - skb->data; - skb_linearize(skb); + if (skb_linearize(skb)) { + nesvnic->tx_sw_dropped++; + kfree_skb(skb); + return NETDEV_TX_OK; + } + nesvnic->linearized_skbs++; skb_set_transport_header(skb, hoffset); skb_set_network_header(skb, nhoffset); if (!nes_nic_send(skb, netdev)) -- cgit v1.2.3 From 5b4c9cd7e4790f37b595aeb4bf6fcbf7e3ba9e2c Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sat, 3 Dec 2016 21:10:21 +0800 Subject: IB/ocrdma: fix bad initialization In function ocrdma_mbx_create_ah_tbl(), returns the value of status on errors. However, because status is initialized with 0, 0 will be returned even if on error paths. This patch initialize status with "-ENOMEM". Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=188831 Signed-off-by: Pan Bian Reviewed-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/ocrdma/ocrdma_hw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c index 67fc0b6857e1..6876a7129e81 100644 --- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c +++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c @@ -1642,7 +1642,7 @@ static int ocrdma_build_q_conf(u32 *num_entries, int entry_size, static int ocrdma_mbx_create_ah_tbl(struct ocrdma_dev *dev) { int i; - int status = 0; + int status = -ENOMEM; int max_ah; struct ocrdma_create_ah_tbl *cmd; struct ocrdma_create_ah_tbl_rsp *rsp; -- cgit v1.2.3 From 46d0703fac3ffa12ec36f22f386d96d0f474c9c2 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Sun, 4 Dec 2016 14:45:38 +0800 Subject: IB/mlx4: fix improper return value If uhw->inlen is non-zero, the value of variable err is 0 if the copy succeeds. Then, if kzalloc() or kmalloc() returns a NULL pointer, it will return 0 to the callers. As a result, the callers cannot detect the errors. This patch fixes the bug, assign "-ENOMEM" to err before the NULL pointer checks, and remove the initialization of err at the beginning. Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=189031 Signed-off-by: Pan Bian Reviewed-by: Leon Romanovsky Signed-off-by: Doug Ledford --- drivers/infiniband/hw/mlx4/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c index b597e8227591..a87c395e185a 100644 --- a/drivers/infiniband/hw/mlx4/main.c +++ b/drivers/infiniband/hw/mlx4/main.c @@ -430,7 +430,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, struct mlx4_ib_dev *dev = to_mdev(ibdev); struct ib_smp *in_mad = NULL; struct ib_smp *out_mad = NULL; - int err = -ENOMEM; + int err; int have_ib_ports; struct mlx4_uverbs_ex_query_device cmd; struct mlx4_uverbs_ex_query_device_resp resp = {.comp_mask = 0}; @@ -455,6 +455,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev, sizeof(resp.response_length); in_mad = kzalloc(sizeof *in_mad, GFP_KERNEL); out_mad = kmalloc(sizeof *out_mad, GFP_KERNEL); + err = -ENOMEM; if (!in_mad || !out_mad) goto out; -- cgit v1.2.3 From 29c8d9eba550c6d73d17cc1618a9f5f2a7345aa1 Mon Sep 17 00:00:00 2001 From: Adit Ranadive Date: Sun, 2 Oct 2016 19:10:22 -0700 Subject: IB: Add vmw_pvrdma driver This patch series adds a driver for a paravirtual RDMA device. The device is developed for VMware's Virtual Machines and allows existing RDMA applications to continue to use existing Verbs API when deployed in VMs on ESXi. We recently did a presentation in the OFA Workshop [1] regarding this device. Description and RDMA Support ============================ The virtual device is exposed as a dual function PCIe device. One part is a virtual network device (VMXNet3) which provides networking properties like MAC, IP addresses to the RDMA part of the device. The networking properties are used to register GIDs required by RDMA applications to communicate. These patches add support and the all required infrastructure for letting applications use such a device. We support the mandatory Verbs API as well as the base memory management extensions (Local Inv, Send with Inv and Fast Register Work Requests). We currently support both Reliable Connected and Unreliable Datagram QPs but do not support Shared Receive Queues (SRQs). Also, we support the following types of Work Requests: o Send/Receive (with or without Immediate Data) o RDMA Write (with or without Immediate Data) o RDMA Read o Local Invalidate o Send with Invalidate o Fast Register Work Requests This version only adds support for version 1 of RoCE. We will add RoCEv2 support in a future patch. We do support registration of both MAC-based and IP-based GIDs. I have also created a git tree for our user-level driver [2]. Testing ======= We have tested this internally for various types of Guest OS - Red Hat, Centos, Ubuntu 12.04/14.04/16.04, Oracle Enterprise Linux, SLES 12 using backported versions of this driver. The tests included several runs of the performance tests (included with OFED), Intel MPI PingPong benchmark on OpenMPI, krping for FRWRs. Mellanox has been kind enough to test the backported version of the driver internally on their hardware using a VMware provided ESX build. I have also applied and tested this with Doug's k.o/for-4.9 branch (commit 5603910b). Note, that this patch series should be applied all together. I split out the commits so that it may be easier to review. PVRDMA Resources ================ [1] OFA Workshop Presentation - https://openfabrics.org/images/eventpresos/2016presentations/102parardma.pdf [2] Libpvrdma User-level library - http://git.openfabrics.org/?p=~aditr/libpvrdma.git;a=summary Reviewed-by: Jorgen Hansen Reviewed-by: George Zhang Reviewed-by: Aditya Sarwade Reviewed-by: Bryan Tan Reviewed-by: Leon Romanovsky Signed-off-by: Adit Ranadive Signed-off-by: Doug Ledford --- MAINTAINERS | 7 + drivers/infiniband/Kconfig | 1 + drivers/infiniband/hw/Makefile | 1 + drivers/infiniband/hw/vmw_pvrdma/Kconfig | 7 + drivers/infiniband/hw/vmw_pvrdma/Makefile | 3 + drivers/infiniband/hw/vmw_pvrdma/pvrdma.h | 474 ++++++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_cmd.c | 119 ++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c | 425 +++++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h | 586 ++++++++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_doorbell.c | 127 ++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c | 1211 ++++++++++++++++++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_misc.c | 304 +++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c | 334 ++++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c | 972 ++++++++++++++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h | 131 +++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c | 579 ++++++++++ drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h | 436 +++++++ include/uapi/rdma/Kbuild | 1 + include/uapi/rdma/vmw_pvrdma-abi.h | 289 +++++ 19 files changed, 6007 insertions(+) create mode 100644 drivers/infiniband/hw/vmw_pvrdma/Kconfig create mode 100644 drivers/infiniband/hw/vmw_pvrdma/Makefile create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma.h create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_cmd.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_doorbell.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_misc.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c create mode 100644 drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h create mode 100644 include/uapi/rdma/vmw_pvrdma-abi.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 3d838cf49f81..75a68f079188 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12928,6 +12928,13 @@ S: Maintained F: drivers/scsi/vmw_pvscsi.c F: drivers/scsi/vmw_pvscsi.h +VMWARE PVRDMA DRIVER +M: Adit Ranadive +M: VMware PV-Drivers +L: linux-rdma@vger.kernel.org +S: Maintained +F: drivers/infiniband/hw/vmw_pvrdma/ + VOLTAGE AND CURRENT REGULATOR FRAMEWORK M: Liam Girdwood M: Mark Brown diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig index fb3fb89640e5..670917387eda 100644 --- a/drivers/infiniband/Kconfig +++ b/drivers/infiniband/Kconfig @@ -73,6 +73,7 @@ source "drivers/infiniband/hw/mlx4/Kconfig" source "drivers/infiniband/hw/mlx5/Kconfig" source "drivers/infiniband/hw/nes/Kconfig" source "drivers/infiniband/hw/ocrdma/Kconfig" +source "drivers/infiniband/hw/vmw_pvrdma/Kconfig" source "drivers/infiniband/hw/usnic/Kconfig" source "drivers/infiniband/hw/hns/Kconfig" diff --git a/drivers/infiniband/hw/Makefile b/drivers/infiniband/hw/Makefile index e7a5ed9f6f3f..ed553de2ca12 100644 --- a/drivers/infiniband/hw/Makefile +++ b/drivers/infiniband/hw/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_MLX4_INFINIBAND) += mlx4/ obj-$(CONFIG_MLX5_INFINIBAND) += mlx5/ obj-$(CONFIG_INFINIBAND_NES) += nes/ obj-$(CONFIG_INFINIBAND_OCRDMA) += ocrdma/ +obj-$(CONFIG_INFINIBAND_VMWARE_PVRDMA) += vmw_pvrdma/ obj-$(CONFIG_INFINIBAND_USNIC) += usnic/ obj-$(CONFIG_INFINIBAND_HFI1) += hfi1/ obj-$(CONFIG_INFINIBAND_HNS) += hns/ diff --git a/drivers/infiniband/hw/vmw_pvrdma/Kconfig b/drivers/infiniband/hw/vmw_pvrdma/Kconfig new file mode 100644 index 000000000000..5a9790ac0ede --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/Kconfig @@ -0,0 +1,7 @@ +config INFINIBAND_VMWARE_PVRDMA + tristate "VMware Paravirtualized RDMA Driver" + depends on NETDEVICES && ETHERNET && PCI && INET && VMXNET3 + ---help--- + This driver provides low-level support for VMware Paravirtual + RDMA adapter. It interacts with the VMXNet3 driver to provide + Ethernet capabilities. diff --git a/drivers/infiniband/hw/vmw_pvrdma/Makefile b/drivers/infiniband/hw/vmw_pvrdma/Makefile new file mode 100644 index 000000000000..0194ed19f542 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_INFINIBAND_VMWARE_PVRDMA) += vmw_pvrdma.o + +vmw_pvrdma-y := pvrdma_cmd.o pvrdma_cq.o pvrdma_doorbell.o pvrdma_main.o pvrdma_misc.o pvrdma_mr.o pvrdma_qp.o pvrdma_verbs.o diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h new file mode 100644 index 000000000000..71e1d55d69d6 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma.h @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PVRDMA_H__ +#define __PVRDMA_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pvrdma_ring.h" +#include "pvrdma_dev_api.h" +#include "pvrdma_verbs.h" + +/* NOT the same as BIT_MASK(). */ +#define PVRDMA_MASK(n) ((n << 1) - 1) + +/* + * VMware PVRDMA PCI device id. + */ +#define PCI_DEVICE_ID_VMWARE_PVRDMA 0x0820 + +struct pvrdma_dev; + +struct pvrdma_page_dir { + dma_addr_t dir_dma; + u64 *dir; + int ntables; + u64 **tables; + u64 npages; + void **pages; +}; + +struct pvrdma_cq { + struct ib_cq ibcq; + int offset; + spinlock_t cq_lock; /* Poll lock. */ + struct pvrdma_uar_map *uar; + struct ib_umem *umem; + struct pvrdma_ring_state *ring_state; + struct pvrdma_page_dir pdir; + u32 cq_handle; + bool is_kernel; + atomic_t refcnt; + wait_queue_head_t wait; +}; + +struct pvrdma_id_table { + u32 last; + u32 top; + u32 max; + u32 mask; + spinlock_t lock; /* Table lock. */ + unsigned long *table; +}; + +struct pvrdma_uar_map { + unsigned long pfn; + void __iomem *map; + int index; +}; + +struct pvrdma_uar_table { + struct pvrdma_id_table tbl; + int size; +}; + +struct pvrdma_ucontext { + struct ib_ucontext ibucontext; + struct pvrdma_dev *dev; + struct pvrdma_uar_map uar; + u64 ctx_handle; +}; + +struct pvrdma_pd { + struct ib_pd ibpd; + u32 pdn; + u32 pd_handle; + int privileged; +}; + +struct pvrdma_mr { + u32 mr_handle; + u64 iova; + u64 size; +}; + +struct pvrdma_user_mr { + struct ib_mr ibmr; + struct ib_umem *umem; + struct pvrdma_mr mmr; + struct pvrdma_page_dir pdir; + u64 *pages; + u32 npages; + u32 max_pages; + u32 page_shift; +}; + +struct pvrdma_wq { + struct pvrdma_ring *ring; + spinlock_t lock; /* Work queue lock. */ + int wqe_cnt; + int wqe_size; + int max_sg; + int offset; +}; + +struct pvrdma_ah { + struct ib_ah ibah; + struct pvrdma_av av; +}; + +struct pvrdma_qp { + struct ib_qp ibqp; + u32 qp_handle; + u32 qkey; + struct pvrdma_wq sq; + struct pvrdma_wq rq; + struct ib_umem *rumem; + struct ib_umem *sumem; + struct pvrdma_page_dir pdir; + int npages; + int npages_send; + int npages_recv; + u32 flags; + u8 port; + u8 state; + bool is_kernel; + struct mutex mutex; /* QP state mutex. */ + atomic_t refcnt; + wait_queue_head_t wait; +}; + +struct pvrdma_dev { + /* PCI device-related information. */ + struct ib_device ib_dev; + struct pci_dev *pdev; + void __iomem *regs; + struct pvrdma_device_shared_region *dsr; /* Shared region pointer */ + dma_addr_t dsrbase; /* Shared region base address */ + void *cmd_slot; + void *resp_slot; + unsigned long flags; + struct list_head device_link; + + /* Locking and interrupt information. */ + spinlock_t cmd_lock; /* Command lock. */ + struct semaphore cmd_sema; + struct completion cmd_done; + struct { + enum pvrdma_intr_type type; /* Intr type */ + struct msix_entry msix_entry[PVRDMA_MAX_INTERRUPTS]; + irq_handler_t handler[PVRDMA_MAX_INTERRUPTS]; + u8 enabled[PVRDMA_MAX_INTERRUPTS]; + u8 size; + } intr; + + /* RDMA-related device information. */ + union ib_gid *sgid_tbl; + struct pvrdma_ring_state *async_ring_state; + struct pvrdma_page_dir async_pdir; + struct pvrdma_ring_state *cq_ring_state; + struct pvrdma_page_dir cq_pdir; + struct pvrdma_cq **cq_tbl; + spinlock_t cq_tbl_lock; + struct pvrdma_qp **qp_tbl; + spinlock_t qp_tbl_lock; + struct pvrdma_uar_table uar_table; + struct pvrdma_uar_map driver_uar; + __be64 sys_image_guid; + spinlock_t desc_lock; /* Device modification lock. */ + u32 port_cap_mask; + struct mutex port_mutex; /* Port modification mutex. */ + bool ib_active; + atomic_t num_qps; + atomic_t num_cqs; + atomic_t num_pds; + atomic_t num_ahs; + + /* Network device information. */ + struct net_device *netdev; + struct notifier_block nb_netdev; +}; + +struct pvrdma_netdevice_work { + struct work_struct work; + struct net_device *event_netdev; + unsigned long event; +}; + +static inline struct pvrdma_dev *to_vdev(struct ib_device *ibdev) +{ + return container_of(ibdev, struct pvrdma_dev, ib_dev); +} + +static inline struct +pvrdma_ucontext *to_vucontext(struct ib_ucontext *ibucontext) +{ + return container_of(ibucontext, struct pvrdma_ucontext, ibucontext); +} + +static inline struct pvrdma_pd *to_vpd(struct ib_pd *ibpd) +{ + return container_of(ibpd, struct pvrdma_pd, ibpd); +} + +static inline struct pvrdma_cq *to_vcq(struct ib_cq *ibcq) +{ + return container_of(ibcq, struct pvrdma_cq, ibcq); +} + +static inline struct pvrdma_user_mr *to_vmr(struct ib_mr *ibmr) +{ + return container_of(ibmr, struct pvrdma_user_mr, ibmr); +} + +static inline struct pvrdma_qp *to_vqp(struct ib_qp *ibqp) +{ + return container_of(ibqp, struct pvrdma_qp, ibqp); +} + +static inline struct pvrdma_ah *to_vah(struct ib_ah *ibah) +{ + return container_of(ibah, struct pvrdma_ah, ibah); +} + +static inline void pvrdma_write_reg(struct pvrdma_dev *dev, u32 reg, u32 val) +{ + writel(cpu_to_le32(val), dev->regs + reg); +} + +static inline u32 pvrdma_read_reg(struct pvrdma_dev *dev, u32 reg) +{ + return le32_to_cpu(readl(dev->regs + reg)); +} + +static inline void pvrdma_write_uar_cq(struct pvrdma_dev *dev, u32 val) +{ + writel(cpu_to_le32(val), dev->driver_uar.map + PVRDMA_UAR_CQ_OFFSET); +} + +static inline void pvrdma_write_uar_qp(struct pvrdma_dev *dev, u32 val) +{ + writel(cpu_to_le32(val), dev->driver_uar.map + PVRDMA_UAR_QP_OFFSET); +} + +static inline void *pvrdma_page_dir_get_ptr(struct pvrdma_page_dir *pdir, + u64 offset) +{ + return pdir->pages[offset / PAGE_SIZE] + (offset % PAGE_SIZE); +} + +static inline enum pvrdma_mtu ib_mtu_to_pvrdma(enum ib_mtu mtu) +{ + return (enum pvrdma_mtu)mtu; +} + +static inline enum ib_mtu pvrdma_mtu_to_ib(enum pvrdma_mtu mtu) +{ + return (enum ib_mtu)mtu; +} + +static inline enum pvrdma_port_state ib_port_state_to_pvrdma( + enum ib_port_state state) +{ + return (enum pvrdma_port_state)state; +} + +static inline enum ib_port_state pvrdma_port_state_to_ib( + enum pvrdma_port_state state) +{ + return (enum ib_port_state)state; +} + +static inline int ib_port_cap_flags_to_pvrdma(int flags) +{ + return flags & PVRDMA_MASK(PVRDMA_PORT_CAP_FLAGS_MAX); +} + +static inline int pvrdma_port_cap_flags_to_ib(int flags) +{ + return flags; +} + +static inline enum pvrdma_port_width ib_port_width_to_pvrdma( + enum ib_port_width width) +{ + return (enum pvrdma_port_width)width; +} + +static inline enum ib_port_width pvrdma_port_width_to_ib( + enum pvrdma_port_width width) +{ + return (enum ib_port_width)width; +} + +static inline enum pvrdma_port_speed ib_port_speed_to_pvrdma( + enum ib_port_speed speed) +{ + return (enum pvrdma_port_speed)speed; +} + +static inline enum ib_port_speed pvrdma_port_speed_to_ib( + enum pvrdma_port_speed speed) +{ + return (enum ib_port_speed)speed; +} + +static inline int pvrdma_qp_attr_mask_to_ib(int attr_mask) +{ + return attr_mask; +} + +static inline int ib_qp_attr_mask_to_pvrdma(int attr_mask) +{ + return attr_mask & PVRDMA_MASK(PVRDMA_QP_ATTR_MASK_MAX); +} + +static inline enum pvrdma_mig_state ib_mig_state_to_pvrdma( + enum ib_mig_state state) +{ + return (enum pvrdma_mig_state)state; +} + +static inline enum ib_mig_state pvrdma_mig_state_to_ib( + enum pvrdma_mig_state state) +{ + return (enum ib_mig_state)state; +} + +static inline int ib_access_flags_to_pvrdma(int flags) +{ + return flags; +} + +static inline int pvrdma_access_flags_to_ib(int flags) +{ + return flags & PVRDMA_MASK(PVRDMA_ACCESS_FLAGS_MAX); +} + +static inline enum pvrdma_qp_type ib_qp_type_to_pvrdma(enum ib_qp_type type) +{ + return (enum pvrdma_qp_type)type; +} + +static inline enum ib_qp_type pvrdma_qp_type_to_ib(enum pvrdma_qp_type type) +{ + return (enum ib_qp_type)type; +} + +static inline enum pvrdma_qp_state ib_qp_state_to_pvrdma(enum ib_qp_state state) +{ + return (enum pvrdma_qp_state)state; +} + +static inline enum ib_qp_state pvrdma_qp_state_to_ib(enum pvrdma_qp_state state) +{ + return (enum ib_qp_state)state; +} + +static inline enum pvrdma_wr_opcode ib_wr_opcode_to_pvrdma(enum ib_wr_opcode op) +{ + return (enum pvrdma_wr_opcode)op; +} + +static inline enum ib_wc_status pvrdma_wc_status_to_ib( + enum pvrdma_wc_status status) +{ + return (enum ib_wc_status)status; +} + +static inline int pvrdma_wc_opcode_to_ib(int opcode) +{ + return opcode; +} + +static inline int pvrdma_wc_flags_to_ib(int flags) +{ + return flags; +} + +static inline int ib_send_flags_to_pvrdma(int flags) +{ + return flags & PVRDMA_MASK(PVRDMA_SEND_FLAGS_MAX); +} + +void pvrdma_qp_cap_to_ib(struct ib_qp_cap *dst, + const struct pvrdma_qp_cap *src); +void ib_qp_cap_to_pvrdma(struct pvrdma_qp_cap *dst, + const struct ib_qp_cap *src); +void pvrdma_gid_to_ib(union ib_gid *dst, const union pvrdma_gid *src); +void ib_gid_to_pvrdma(union pvrdma_gid *dst, const union ib_gid *src); +void pvrdma_global_route_to_ib(struct ib_global_route *dst, + const struct pvrdma_global_route *src); +void ib_global_route_to_pvrdma(struct pvrdma_global_route *dst, + const struct ib_global_route *src); +void pvrdma_ah_attr_to_ib(struct ib_ah_attr *dst, + const struct pvrdma_ah_attr *src); +void ib_ah_attr_to_pvrdma(struct pvrdma_ah_attr *dst, + const struct ib_ah_attr *src); + +int pvrdma_uar_table_init(struct pvrdma_dev *dev); +void pvrdma_uar_table_cleanup(struct pvrdma_dev *dev); + +int pvrdma_uar_alloc(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar); +void pvrdma_uar_free(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar); + +void _pvrdma_flush_cqe(struct pvrdma_qp *qp, struct pvrdma_cq *cq); + +int pvrdma_page_dir_init(struct pvrdma_dev *dev, struct pvrdma_page_dir *pdir, + u64 npages, bool alloc_pages); +void pvrdma_page_dir_cleanup(struct pvrdma_dev *dev, + struct pvrdma_page_dir *pdir); +int pvrdma_page_dir_insert_dma(struct pvrdma_page_dir *pdir, u64 idx, + dma_addr_t daddr); +int pvrdma_page_dir_insert_umem(struct pvrdma_page_dir *pdir, + struct ib_umem *umem, u64 offset); +dma_addr_t pvrdma_page_dir_get_dma(struct pvrdma_page_dir *pdir, u64 idx); +int pvrdma_page_dir_insert_page_list(struct pvrdma_page_dir *pdir, + u64 *page_list, int num_pages); + +int pvrdma_cmd_post(struct pvrdma_dev *dev, union pvrdma_cmd_req *req, + union pvrdma_cmd_resp *rsp, unsigned resp_code); + +#endif /* __PVRDMA_H__ */ diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cmd.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cmd.c new file mode 100644 index 000000000000..4a78c537d8a1 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cmd.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "pvrdma.h" + +#define PVRDMA_CMD_TIMEOUT 10000 /* ms */ + +static inline int pvrdma_cmd_recv(struct pvrdma_dev *dev, + union pvrdma_cmd_resp *resp, + unsigned resp_code) +{ + int err; + + dev_dbg(&dev->pdev->dev, "receive response from device\n"); + + err = wait_for_completion_interruptible_timeout(&dev->cmd_done, + msecs_to_jiffies(PVRDMA_CMD_TIMEOUT)); + if (err == 0 || err == -ERESTARTSYS) { + dev_warn(&dev->pdev->dev, + "completion timeout or interrupted\n"); + return -ETIMEDOUT; + } + + spin_lock(&dev->cmd_lock); + memcpy(resp, dev->resp_slot, sizeof(*resp)); + spin_unlock(&dev->cmd_lock); + + if (resp->hdr.ack != resp_code) { + dev_warn(&dev->pdev->dev, + "unknown response %#x expected %#x\n", + resp->hdr.ack, resp_code); + return -EFAULT; + } + + return 0; +} + +int +pvrdma_cmd_post(struct pvrdma_dev *dev, union pvrdma_cmd_req *req, + union pvrdma_cmd_resp *resp, unsigned resp_code) +{ + int err; + + dev_dbg(&dev->pdev->dev, "post request to device\n"); + + /* Serializiation */ + down(&dev->cmd_sema); + + BUILD_BUG_ON(sizeof(union pvrdma_cmd_req) != + sizeof(struct pvrdma_cmd_modify_qp)); + + spin_lock(&dev->cmd_lock); + memcpy(dev->cmd_slot, req, sizeof(*req)); + spin_unlock(&dev->cmd_lock); + + init_completion(&dev->cmd_done); + pvrdma_write_reg(dev, PVRDMA_REG_REQUEST, 0); + + /* Make sure the request is written before reading status. */ + mb(); + + err = pvrdma_read_reg(dev, PVRDMA_REG_ERR); + if (err == 0) { + if (resp != NULL) + err = pvrdma_cmd_recv(dev, resp, resp_code); + } else { + dev_warn(&dev->pdev->dev, + "failed to write request error reg: %d\n", err); + err = -EFAULT; + } + + up(&dev->cmd_sema); + + return err; +} diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c new file mode 100644 index 000000000000..e429ca5b16aa --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_cq.c @@ -0,0 +1,425 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "pvrdma.h" + +/** + * pvrdma_req_notify_cq - request notification for a completion queue + * @ibcq: the completion queue + * @notify_flags: notification flags + * + * @return: 0 for success. + */ +int pvrdma_req_notify_cq(struct ib_cq *ibcq, + enum ib_cq_notify_flags notify_flags) +{ + struct pvrdma_dev *dev = to_vdev(ibcq->device); + struct pvrdma_cq *cq = to_vcq(ibcq); + u32 val = cq->cq_handle; + + val |= (notify_flags & IB_CQ_SOLICITED_MASK) == IB_CQ_SOLICITED ? + PVRDMA_UAR_CQ_ARM_SOL : PVRDMA_UAR_CQ_ARM; + + pvrdma_write_uar_cq(dev, val); + + return 0; +} + +/** + * pvrdma_create_cq - create completion queue + * @ibdev: the device + * @attr: completion queue attributes + * @context: user context + * @udata: user data + * + * @return: ib_cq completion queue pointer on success, + * otherwise returns negative errno. + */ +struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, + const struct ib_cq_init_attr *attr, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + int entries = attr->cqe; + struct pvrdma_dev *dev = to_vdev(ibdev); + struct pvrdma_cq *cq; + int ret; + int npages; + unsigned long flags; + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_cq *cmd = &req.create_cq; + struct pvrdma_cmd_create_cq_resp *resp = &rsp.create_cq_resp; + struct pvrdma_create_cq ucmd; + + BUILD_BUG_ON(sizeof(struct pvrdma_cqe) != 64); + + entries = roundup_pow_of_two(entries); + if (entries < 1 || entries > dev->dsr->caps.max_cqe) + return ERR_PTR(-EINVAL); + + if (!atomic_add_unless(&dev->num_cqs, 1, dev->dsr->caps.max_cq)) + return ERR_PTR(-ENOMEM); + + cq = kzalloc(sizeof(*cq), GFP_KERNEL); + if (!cq) { + atomic_dec(&dev->num_cqs); + return ERR_PTR(-ENOMEM); + } + + cq->ibcq.cqe = entries; + + if (context) { + if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { + ret = -EFAULT; + goto err_cq; + } + + cq->umem = ib_umem_get(context, ucmd.buf_addr, ucmd.buf_size, + IB_ACCESS_LOCAL_WRITE, 1); + if (IS_ERR(cq->umem)) { + ret = PTR_ERR(cq->umem); + goto err_cq; + } + + npages = ib_umem_page_count(cq->umem); + } else { + cq->is_kernel = true; + + /* One extra page for shared ring state */ + npages = 1 + (entries * sizeof(struct pvrdma_cqe) + + PAGE_SIZE - 1) / PAGE_SIZE; + + /* Skip header page. */ + cq->offset = PAGE_SIZE; + } + + if (npages < 0 || npages > PVRDMA_PAGE_DIR_MAX_PAGES) { + dev_warn(&dev->pdev->dev, + "overflow pages in completion queue\n"); + ret = -EINVAL; + goto err_umem; + } + + ret = pvrdma_page_dir_init(dev, &cq->pdir, npages, cq->is_kernel); + if (ret) { + dev_warn(&dev->pdev->dev, + "could not allocate page directory\n"); + goto err_umem; + } + + /* Ring state is always the first page. Set in library for user cq. */ + if (cq->is_kernel) + cq->ring_state = cq->pdir.pages[0]; + else + pvrdma_page_dir_insert_umem(&cq->pdir, cq->umem, 0); + + atomic_set(&cq->refcnt, 1); + init_waitqueue_head(&cq->wait); + spin_lock_init(&cq->cq_lock); + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_CREATE_CQ; + cmd->nchunks = npages; + cmd->ctx_handle = (context) ? + (u64)to_vucontext(context)->ctx_handle : 0; + cmd->cqe = entries; + cmd->pdir_dma = cq->pdir.dir_dma; + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_CQ_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not create completion queue, error: %d\n", ret); + goto err_page_dir; + } + + cq->ibcq.cqe = resp->cqe; + cq->cq_handle = resp->cq_handle; + spin_lock_irqsave(&dev->cq_tbl_lock, flags); + dev->cq_tbl[cq->cq_handle % dev->dsr->caps.max_cq] = cq; + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); + + if (context) { + cq->uar = &(to_vucontext(context)->uar); + + /* Copy udata back. */ + if (ib_copy_to_udata(udata, &cq->cq_handle, sizeof(__u32))) { + dev_warn(&dev->pdev->dev, + "failed to copy back udata\n"); + pvrdma_destroy_cq(&cq->ibcq); + return ERR_PTR(-EINVAL); + } + } + + return &cq->ibcq; + +err_page_dir: + pvrdma_page_dir_cleanup(dev, &cq->pdir); +err_umem: + if (context) + ib_umem_release(cq->umem); +err_cq: + atomic_dec(&dev->num_cqs); + kfree(cq); + + return ERR_PTR(ret); +} + +static void pvrdma_free_cq(struct pvrdma_dev *dev, struct pvrdma_cq *cq) +{ + atomic_dec(&cq->refcnt); + wait_event(cq->wait, !atomic_read(&cq->refcnt)); + + if (!cq->is_kernel) + ib_umem_release(cq->umem); + + pvrdma_page_dir_cleanup(dev, &cq->pdir); + kfree(cq); +} + +/** + * pvrdma_destroy_cq - destroy completion queue + * @cq: the completion queue to destroy. + * + * @return: 0 for success. + */ +int pvrdma_destroy_cq(struct ib_cq *cq) +{ + struct pvrdma_cq *vcq = to_vcq(cq); + union pvrdma_cmd_req req; + struct pvrdma_cmd_destroy_cq *cmd = &req.destroy_cq; + struct pvrdma_dev *dev = to_vdev(cq->device); + unsigned long flags; + int ret; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_CQ; + cmd->cq_handle = vcq->cq_handle; + + ret = pvrdma_cmd_post(dev, &req, NULL, 0); + if (ret < 0) + dev_warn(&dev->pdev->dev, + "could not destroy completion queue, error: %d\n", + ret); + + /* free cq's resources */ + spin_lock_irqsave(&dev->cq_tbl_lock, flags); + dev->cq_tbl[vcq->cq_handle] = NULL; + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); + + pvrdma_free_cq(dev, vcq); + atomic_dec(&dev->num_cqs); + + return ret; +} + +/** + * pvrdma_modify_cq - modify the CQ moderation parameters + * @ibcq: the CQ to modify + * @cq_count: number of CQEs that will trigger an event + * @cq_period: max period of time in usec before triggering an event + * + * @return: -EOPNOTSUPP as CQ resize is not supported. + */ +int pvrdma_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period) +{ + return -EOPNOTSUPP; +} + +static inline struct pvrdma_cqe *get_cqe(struct pvrdma_cq *cq, int i) +{ + return (struct pvrdma_cqe *)pvrdma_page_dir_get_ptr( + &cq->pdir, + cq->offset + + sizeof(struct pvrdma_cqe) * i); +} + +void _pvrdma_flush_cqe(struct pvrdma_qp *qp, struct pvrdma_cq *cq) +{ + int head; + int has_data; + + if (!cq->is_kernel) + return; + + /* Lock held */ + has_data = pvrdma_idx_ring_has_data(&cq->ring_state->rx, + cq->ibcq.cqe, &head); + if (unlikely(has_data > 0)) { + int items; + int curr; + int tail = pvrdma_idx(&cq->ring_state->rx.prod_tail, + cq->ibcq.cqe); + struct pvrdma_cqe *cqe; + struct pvrdma_cqe *curr_cqe; + + items = (tail > head) ? (tail - head) : + (cq->ibcq.cqe - head + tail); + curr = --tail; + while (items-- > 0) { + if (curr < 0) + curr = cq->ibcq.cqe - 1; + if (tail < 0) + tail = cq->ibcq.cqe - 1; + curr_cqe = get_cqe(cq, curr); + if ((curr_cqe->qp & 0xFFFF) != qp->qp_handle) { + if (curr != tail) { + cqe = get_cqe(cq, tail); + *cqe = *curr_cqe; + } + tail--; + } else { + pvrdma_idx_ring_inc( + &cq->ring_state->rx.cons_head, + cq->ibcq.cqe); + } + curr--; + } + } +} + +static int pvrdma_poll_one(struct pvrdma_cq *cq, struct pvrdma_qp **cur_qp, + struct ib_wc *wc) +{ + struct pvrdma_dev *dev = to_vdev(cq->ibcq.device); + int has_data; + unsigned int head; + bool tried = false; + struct pvrdma_cqe *cqe; + +retry: + has_data = pvrdma_idx_ring_has_data(&cq->ring_state->rx, + cq->ibcq.cqe, &head); + if (has_data == 0) { + if (tried) + return -EAGAIN; + + pvrdma_write_uar_cq(dev, cq->cq_handle | PVRDMA_UAR_CQ_POLL); + + tried = true; + goto retry; + } else if (has_data == PVRDMA_INVALID_IDX) { + dev_err(&dev->pdev->dev, "CQ ring state invalid\n"); + return -EAGAIN; + } + + cqe = get_cqe(cq, head); + + /* Ensure cqe is valid. */ + rmb(); + if (dev->qp_tbl[cqe->qp & 0xffff]) + *cur_qp = (struct pvrdma_qp *)dev->qp_tbl[cqe->qp & 0xffff]; + else + return -EAGAIN; + + wc->opcode = pvrdma_wc_opcode_to_ib(cqe->opcode); + wc->status = pvrdma_wc_status_to_ib(cqe->status); + wc->wr_id = cqe->wr_id; + wc->qp = &(*cur_qp)->ibqp; + wc->byte_len = cqe->byte_len; + wc->ex.imm_data = cqe->imm_data; + wc->src_qp = cqe->src_qp; + wc->wc_flags = pvrdma_wc_flags_to_ib(cqe->wc_flags); + wc->pkey_index = cqe->pkey_index; + wc->slid = cqe->slid; + wc->sl = cqe->sl; + wc->dlid_path_bits = cqe->dlid_path_bits; + wc->port_num = cqe->port_num; + wc->vendor_err = 0; + + /* Update shared ring state */ + pvrdma_idx_ring_inc(&cq->ring_state->rx.cons_head, cq->ibcq.cqe); + + return 0; +} + +/** + * pvrdma_poll_cq - poll for work completion queue entries + * @ibcq: completion queue + * @num_entries: the maximum number of entries + * @entry: pointer to work completion array + * + * @return: number of polled completion entries + */ +int pvrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc) +{ + struct pvrdma_cq *cq = to_vcq(ibcq); + struct pvrdma_qp *cur_qp = NULL; + unsigned long flags; + int npolled; + + if (num_entries < 1 || wc == NULL) + return 0; + + spin_lock_irqsave(&cq->cq_lock, flags); + for (npolled = 0; npolled < num_entries; ++npolled) { + if (pvrdma_poll_one(cq, &cur_qp, wc + npolled)) + break; + } + + spin_unlock_irqrestore(&cq->cq_lock, flags); + + /* Ensure we do not return errors from poll_cq */ + return npolled; +} + +/** + * pvrdma_resize_cq - resize CQ + * @ibcq: the completion queue + * @entries: CQ entries + * @udata: user data + * + * @return: -EOPNOTSUPP as CQ resize is not supported. + */ +int pvrdma_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata) +{ + return -EOPNOTSUPP; +} diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h new file mode 100644 index 000000000000..c06768635d65 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_dev_api.h @@ -0,0 +1,586 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PVRDMA_DEV_API_H__ +#define __PVRDMA_DEV_API_H__ + +#include + +#include "pvrdma_verbs.h" + +#define PVRDMA_VERSION 17 +#define PVRDMA_BOARD_ID 1 +#define PVRDMA_REV_ID 1 + +/* + * Masks and accessors for page directory, which is a two-level lookup: + * page directory -> page table -> page. Only one directory for now, but we + * could expand that easily. 9 bits for tables, 9 bits for pages, gives one + * gigabyte for memory regions and so forth. + */ + +#define PVRDMA_PDIR_SHIFT 18 +#define PVRDMA_PTABLE_SHIFT 9 +#define PVRDMA_PAGE_DIR_DIR(x) (((x) >> PVRDMA_PDIR_SHIFT) & 0x1) +#define PVRDMA_PAGE_DIR_TABLE(x) (((x) >> PVRDMA_PTABLE_SHIFT) & 0x1ff) +#define PVRDMA_PAGE_DIR_PAGE(x) ((x) & 0x1ff) +#define PVRDMA_PAGE_DIR_MAX_PAGES (1 * 512 * 512) +#define PVRDMA_MAX_FAST_REG_PAGES 128 + +/* + * Max MSI-X vectors. + */ + +#define PVRDMA_MAX_INTERRUPTS 3 + +/* Register offsets within PCI resource on BAR1. */ +#define PVRDMA_REG_VERSION 0x00 /* R: Version of device. */ +#define PVRDMA_REG_DSRLOW 0x04 /* W: Device shared region low PA. */ +#define PVRDMA_REG_DSRHIGH 0x08 /* W: Device shared region high PA. */ +#define PVRDMA_REG_CTL 0x0c /* W: PVRDMA_DEVICE_CTL */ +#define PVRDMA_REG_REQUEST 0x10 /* W: Indicate device request. */ +#define PVRDMA_REG_ERR 0x14 /* R: Device error. */ +#define PVRDMA_REG_ICR 0x18 /* R: Interrupt cause. */ +#define PVRDMA_REG_IMR 0x1c /* R/W: Interrupt mask. */ +#define PVRDMA_REG_MACL 0x20 /* R/W: MAC address low. */ +#define PVRDMA_REG_MACH 0x24 /* R/W: MAC address high. */ + +/* Object flags. */ +#define PVRDMA_CQ_FLAG_ARMED_SOL BIT(0) /* Armed for solicited-only. */ +#define PVRDMA_CQ_FLAG_ARMED BIT(1) /* Armed. */ +#define PVRDMA_MR_FLAG_DMA BIT(0) /* DMA region. */ +#define PVRDMA_MR_FLAG_FRMR BIT(1) /* Fast reg memory region. */ + +/* + * Atomic operation capability (masked versions are extended atomic + * operations. + */ + +#define PVRDMA_ATOMIC_OP_COMP_SWAP BIT(0) /* Compare and swap. */ +#define PVRDMA_ATOMIC_OP_FETCH_ADD BIT(1) /* Fetch and add. */ +#define PVRDMA_ATOMIC_OP_MASK_COMP_SWAP BIT(2) /* Masked compare and swap. */ +#define PVRDMA_ATOMIC_OP_MASK_FETCH_ADD BIT(3) /* Masked fetch and add. */ + +/* + * Base Memory Management Extension flags to support Fast Reg Memory Regions + * and Fast Reg Work Requests. Each flag represents a verb operation and we + * must support all of them to qualify for the BMME device cap. + */ + +#define PVRDMA_BMME_FLAG_LOCAL_INV BIT(0) /* Local Invalidate. */ +#define PVRDMA_BMME_FLAG_REMOTE_INV BIT(1) /* Remote Invalidate. */ +#define PVRDMA_BMME_FLAG_FAST_REG_WR BIT(2) /* Fast Reg Work Request. */ + +/* + * GID types. The interpretation of the gid_types bit field in the device + * capabilities will depend on the device mode. For now, the device only + * supports RoCE as mode, so only the different GID types for RoCE are + * defined. + */ + +#define PVRDMA_GID_TYPE_FLAG_ROCE_V1 BIT(0) +#define PVRDMA_GID_TYPE_FLAG_ROCE_V2 BIT(1) + +enum pvrdma_pci_resource { + PVRDMA_PCI_RESOURCE_MSIX, /* BAR0: MSI-X, MMIO. */ + PVRDMA_PCI_RESOURCE_REG, /* BAR1: Registers, MMIO. */ + PVRDMA_PCI_RESOURCE_UAR, /* BAR2: UAR pages, MMIO, 64-bit. */ + PVRDMA_PCI_RESOURCE_LAST, /* Last. */ +}; + +enum pvrdma_device_ctl { + PVRDMA_DEVICE_CTL_ACTIVATE, /* Activate device. */ + PVRDMA_DEVICE_CTL_QUIESCE, /* Quiesce device. */ + PVRDMA_DEVICE_CTL_RESET, /* Reset device. */ +}; + +enum pvrdma_intr_vector { + PVRDMA_INTR_VECTOR_RESPONSE, /* Command response. */ + PVRDMA_INTR_VECTOR_ASYNC, /* Async events. */ + PVRDMA_INTR_VECTOR_CQ, /* CQ notification. */ + /* Additional CQ notification vectors. */ +}; + +enum pvrdma_intr_cause { + PVRDMA_INTR_CAUSE_RESPONSE = (1 << PVRDMA_INTR_VECTOR_RESPONSE), + PVRDMA_INTR_CAUSE_ASYNC = (1 << PVRDMA_INTR_VECTOR_ASYNC), + PVRDMA_INTR_CAUSE_CQ = (1 << PVRDMA_INTR_VECTOR_CQ), +}; + +enum pvrdma_intr_type { + PVRDMA_INTR_TYPE_INTX, /* Legacy. */ + PVRDMA_INTR_TYPE_MSI, /* MSI. */ + PVRDMA_INTR_TYPE_MSIX, /* MSI-X. */ +}; + +enum pvrdma_gos_bits { + PVRDMA_GOS_BITS_UNK, /* Unknown. */ + PVRDMA_GOS_BITS_32, /* 32-bit. */ + PVRDMA_GOS_BITS_64, /* 64-bit. */ +}; + +enum pvrdma_gos_type { + PVRDMA_GOS_TYPE_UNK, /* Unknown. */ + PVRDMA_GOS_TYPE_LINUX, /* Linux. */ +}; + +enum pvrdma_device_mode { + PVRDMA_DEVICE_MODE_ROCE, /* RoCE. */ + PVRDMA_DEVICE_MODE_IWARP, /* iWarp. */ + PVRDMA_DEVICE_MODE_IB, /* InfiniBand. */ +}; + +struct pvrdma_gos_info { + u32 gos_bits:2; /* W: PVRDMA_GOS_BITS_ */ + u32 gos_type:4; /* W: PVRDMA_GOS_TYPE_ */ + u32 gos_ver:16; /* W: Guest OS version. */ + u32 gos_misc:10; /* W: Other. */ + u32 pad; /* Pad to 8-byte alignment. */ +}; + +struct pvrdma_device_caps { + u64 fw_ver; /* R: Query device. */ + __be64 node_guid; + __be64 sys_image_guid; + u64 max_mr_size; + u64 page_size_cap; + u64 atomic_arg_sizes; /* EX verbs. */ + u32 ex_comp_mask; /* EX verbs. */ + u32 device_cap_flags2; /* EX verbs. */ + u32 max_fa_bit_boundary; /* EX verbs. */ + u32 log_max_atomic_inline_arg; /* EX verbs. */ + u32 vendor_id; + u32 vendor_part_id; + u32 hw_ver; + u32 max_qp; + u32 max_qp_wr; + u32 device_cap_flags; + u32 max_sge; + u32 max_sge_rd; + u32 max_cq; + u32 max_cqe; + u32 max_mr; + u32 max_pd; + u32 max_qp_rd_atom; + u32 max_ee_rd_atom; + u32 max_res_rd_atom; + u32 max_qp_init_rd_atom; + u32 max_ee_init_rd_atom; + u32 max_ee; + u32 max_rdd; + u32 max_mw; + u32 max_raw_ipv6_qp; + u32 max_raw_ethy_qp; + u32 max_mcast_grp; + u32 max_mcast_qp_attach; + u32 max_total_mcast_qp_attach; + u32 max_ah; + u32 max_fmr; + u32 max_map_per_fmr; + u32 max_srq; + u32 max_srq_wr; + u32 max_srq_sge; + u32 max_uar; + u32 gid_tbl_len; + u16 max_pkeys; + u8 local_ca_ack_delay; + u8 phys_port_cnt; + u8 mode; /* PVRDMA_DEVICE_MODE_ */ + u8 atomic_ops; /* PVRDMA_ATOMIC_OP_* bits */ + u8 bmme_flags; /* FRWR Mem Mgmt Extensions */ + u8 gid_types; /* PVRDMA_GID_TYPE_FLAG_ */ + u8 reserved[4]; +}; + +struct pvrdma_ring_page_info { + u32 num_pages; /* Num pages incl. header. */ + u32 reserved; /* Reserved. */ + u64 pdir_dma; /* Page directory PA. */ +}; + +#pragma pack(push, 1) + +struct pvrdma_device_shared_region { + u32 driver_version; /* W: Driver version. */ + u32 pad; /* Pad to 8-byte align. */ + struct pvrdma_gos_info gos_info; /* W: Guest OS information. */ + u64 cmd_slot_dma; /* W: Command slot address. */ + u64 resp_slot_dma; /* W: Response slot address. */ + struct pvrdma_ring_page_info async_ring_pages; + /* W: Async ring page info. */ + struct pvrdma_ring_page_info cq_ring_pages; + /* W: CQ ring page info. */ + u32 uar_pfn; /* W: UAR pageframe. */ + u32 pad2; /* Pad to 8-byte align. */ + struct pvrdma_device_caps caps; /* R: Device capabilities. */ +}; + +#pragma pack(pop) + +/* Event types. Currently a 1:1 mapping with enum ib_event. */ +enum pvrdma_eqe_type { + PVRDMA_EVENT_CQ_ERR, + PVRDMA_EVENT_QP_FATAL, + PVRDMA_EVENT_QP_REQ_ERR, + PVRDMA_EVENT_QP_ACCESS_ERR, + PVRDMA_EVENT_COMM_EST, + PVRDMA_EVENT_SQ_DRAINED, + PVRDMA_EVENT_PATH_MIG, + PVRDMA_EVENT_PATH_MIG_ERR, + PVRDMA_EVENT_DEVICE_FATAL, + PVRDMA_EVENT_PORT_ACTIVE, + PVRDMA_EVENT_PORT_ERR, + PVRDMA_EVENT_LID_CHANGE, + PVRDMA_EVENT_PKEY_CHANGE, + PVRDMA_EVENT_SM_CHANGE, + PVRDMA_EVENT_SRQ_ERR, + PVRDMA_EVENT_SRQ_LIMIT_REACHED, + PVRDMA_EVENT_QP_LAST_WQE_REACHED, + PVRDMA_EVENT_CLIENT_REREGISTER, + PVRDMA_EVENT_GID_CHANGE, +}; + +/* Event queue element. */ +struct pvrdma_eqe { + u32 type; /* Event type. */ + u32 info; /* Handle, other. */ +}; + +/* CQ notification queue element. */ +struct pvrdma_cqne { + u32 info; /* Handle */ +}; + +enum { + PVRDMA_CMD_FIRST, + PVRDMA_CMD_QUERY_PORT = PVRDMA_CMD_FIRST, + PVRDMA_CMD_QUERY_PKEY, + PVRDMA_CMD_CREATE_PD, + PVRDMA_CMD_DESTROY_PD, + PVRDMA_CMD_CREATE_MR, + PVRDMA_CMD_DESTROY_MR, + PVRDMA_CMD_CREATE_CQ, + PVRDMA_CMD_RESIZE_CQ, + PVRDMA_CMD_DESTROY_CQ, + PVRDMA_CMD_CREATE_QP, + PVRDMA_CMD_MODIFY_QP, + PVRDMA_CMD_QUERY_QP, + PVRDMA_CMD_DESTROY_QP, + PVRDMA_CMD_CREATE_UC, + PVRDMA_CMD_DESTROY_UC, + PVRDMA_CMD_CREATE_BIND, + PVRDMA_CMD_DESTROY_BIND, + PVRDMA_CMD_MAX, +}; + +enum { + PVRDMA_CMD_FIRST_RESP = (1 << 31), + PVRDMA_CMD_QUERY_PORT_RESP = PVRDMA_CMD_FIRST_RESP, + PVRDMA_CMD_QUERY_PKEY_RESP, + PVRDMA_CMD_CREATE_PD_RESP, + PVRDMA_CMD_DESTROY_PD_RESP_NOOP, + PVRDMA_CMD_CREATE_MR_RESP, + PVRDMA_CMD_DESTROY_MR_RESP_NOOP, + PVRDMA_CMD_CREATE_CQ_RESP, + PVRDMA_CMD_RESIZE_CQ_RESP, + PVRDMA_CMD_DESTROY_CQ_RESP_NOOP, + PVRDMA_CMD_CREATE_QP_RESP, + PVRDMA_CMD_MODIFY_QP_RESP, + PVRDMA_CMD_QUERY_QP_RESP, + PVRDMA_CMD_DESTROY_QP_RESP, + PVRDMA_CMD_CREATE_UC_RESP, + PVRDMA_CMD_DESTROY_UC_RESP_NOOP, + PVRDMA_CMD_CREATE_BIND_RESP_NOOP, + PVRDMA_CMD_DESTROY_BIND_RESP_NOOP, + PVRDMA_CMD_MAX_RESP, +}; + +struct pvrdma_cmd_hdr { + u64 response; /* Key for response lookup. */ + u32 cmd; /* PVRDMA_CMD_ */ + u32 reserved; /* Reserved. */ +}; + +struct pvrdma_cmd_resp_hdr { + u64 response; /* From cmd hdr. */ + u32 ack; /* PVRDMA_CMD_XXX_RESP */ + u8 err; /* Error. */ + u8 reserved[3]; /* Reserved. */ +}; + +struct pvrdma_cmd_query_port { + struct pvrdma_cmd_hdr hdr; + u8 port_num; + u8 reserved[7]; +}; + +struct pvrdma_cmd_query_port_resp { + struct pvrdma_cmd_resp_hdr hdr; + struct pvrdma_port_attr attrs; +}; + +struct pvrdma_cmd_query_pkey { + struct pvrdma_cmd_hdr hdr; + u8 port_num; + u8 index; + u8 reserved[6]; +}; + +struct pvrdma_cmd_query_pkey_resp { + struct pvrdma_cmd_resp_hdr hdr; + u16 pkey; + u8 reserved[6]; +}; + +struct pvrdma_cmd_create_uc { + struct pvrdma_cmd_hdr hdr; + u32 pfn; /* UAR page frame number */ + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_uc_resp { + struct pvrdma_cmd_resp_hdr hdr; + u32 ctx_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_destroy_uc { + struct pvrdma_cmd_hdr hdr; + u32 ctx_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_pd { + struct pvrdma_cmd_hdr hdr; + u32 ctx_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_pd_resp { + struct pvrdma_cmd_resp_hdr hdr; + u32 pd_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_destroy_pd { + struct pvrdma_cmd_hdr hdr; + u32 pd_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_mr { + struct pvrdma_cmd_hdr hdr; + u64 start; + u64 length; + u64 pdir_dma; + u32 pd_handle; + u32 access_flags; + u32 flags; + u32 nchunks; +}; + +struct pvrdma_cmd_create_mr_resp { + struct pvrdma_cmd_resp_hdr hdr; + u32 mr_handle; + u32 lkey; + u32 rkey; + u8 reserved[4]; +}; + +struct pvrdma_cmd_destroy_mr { + struct pvrdma_cmd_hdr hdr; + u32 mr_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_cq { + struct pvrdma_cmd_hdr hdr; + u64 pdir_dma; + u32 ctx_handle; + u32 cqe; + u32 nchunks; + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_cq_resp { + struct pvrdma_cmd_resp_hdr hdr; + u32 cq_handle; + u32 cqe; +}; + +struct pvrdma_cmd_resize_cq { + struct pvrdma_cmd_hdr hdr; + u32 cq_handle; + u32 cqe; +}; + +struct pvrdma_cmd_resize_cq_resp { + struct pvrdma_cmd_resp_hdr hdr; + u32 cqe; + u8 reserved[4]; +}; + +struct pvrdma_cmd_destroy_cq { + struct pvrdma_cmd_hdr hdr; + u32 cq_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_qp { + struct pvrdma_cmd_hdr hdr; + u64 pdir_dma; + u32 pd_handle; + u32 send_cq_handle; + u32 recv_cq_handle; + u32 srq_handle; + u32 max_send_wr; + u32 max_recv_wr; + u32 max_send_sge; + u32 max_recv_sge; + u32 max_inline_data; + u32 lkey; + u32 access_flags; + u16 total_chunks; + u16 send_chunks; + u16 max_atomic_arg; + u8 sq_sig_all; + u8 qp_type; + u8 is_srq; + u8 reserved[3]; +}; + +struct pvrdma_cmd_create_qp_resp { + struct pvrdma_cmd_resp_hdr hdr; + u32 qpn; + u32 max_send_wr; + u32 max_recv_wr; + u32 max_send_sge; + u32 max_recv_sge; + u32 max_inline_data; +}; + +struct pvrdma_cmd_modify_qp { + struct pvrdma_cmd_hdr hdr; + u32 qp_handle; + u32 attr_mask; + struct pvrdma_qp_attr attrs; +}; + +struct pvrdma_cmd_query_qp { + struct pvrdma_cmd_hdr hdr; + u32 qp_handle; + u32 attr_mask; +}; + +struct pvrdma_cmd_query_qp_resp { + struct pvrdma_cmd_resp_hdr hdr; + struct pvrdma_qp_attr attrs; +}; + +struct pvrdma_cmd_destroy_qp { + struct pvrdma_cmd_hdr hdr; + u32 qp_handle; + u8 reserved[4]; +}; + +struct pvrdma_cmd_destroy_qp_resp { + struct pvrdma_cmd_resp_hdr hdr; + u32 events_reported; + u8 reserved[4]; +}; + +struct pvrdma_cmd_create_bind { + struct pvrdma_cmd_hdr hdr; + u32 mtu; + u32 vlan; + u32 index; + u8 new_gid[16]; + u8 gid_type; + u8 reserved[3]; +}; + +struct pvrdma_cmd_destroy_bind { + struct pvrdma_cmd_hdr hdr; + u32 index; + u8 dest_gid[16]; + u8 reserved[4]; +}; + +union pvrdma_cmd_req { + struct pvrdma_cmd_hdr hdr; + struct pvrdma_cmd_query_port query_port; + struct pvrdma_cmd_query_pkey query_pkey; + struct pvrdma_cmd_create_uc create_uc; + struct pvrdma_cmd_destroy_uc destroy_uc; + struct pvrdma_cmd_create_pd create_pd; + struct pvrdma_cmd_destroy_pd destroy_pd; + struct pvrdma_cmd_create_mr create_mr; + struct pvrdma_cmd_destroy_mr destroy_mr; + struct pvrdma_cmd_create_cq create_cq; + struct pvrdma_cmd_resize_cq resize_cq; + struct pvrdma_cmd_destroy_cq destroy_cq; + struct pvrdma_cmd_create_qp create_qp; + struct pvrdma_cmd_modify_qp modify_qp; + struct pvrdma_cmd_query_qp query_qp; + struct pvrdma_cmd_destroy_qp destroy_qp; + struct pvrdma_cmd_create_bind create_bind; + struct pvrdma_cmd_destroy_bind destroy_bind; +}; + +union pvrdma_cmd_resp { + struct pvrdma_cmd_resp_hdr hdr; + struct pvrdma_cmd_query_port_resp query_port_resp; + struct pvrdma_cmd_query_pkey_resp query_pkey_resp; + struct pvrdma_cmd_create_uc_resp create_uc_resp; + struct pvrdma_cmd_create_pd_resp create_pd_resp; + struct pvrdma_cmd_create_mr_resp create_mr_resp; + struct pvrdma_cmd_create_cq_resp create_cq_resp; + struct pvrdma_cmd_resize_cq_resp resize_cq_resp; + struct pvrdma_cmd_create_qp_resp create_qp_resp; + struct pvrdma_cmd_query_qp_resp query_qp_resp; + struct pvrdma_cmd_destroy_qp_resp destroy_qp_resp; +}; + +#endif /* __PVRDMA_DEV_API_H__ */ diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_doorbell.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_doorbell.c new file mode 100644 index 000000000000..bf51357ea3aa --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_doorbell.c @@ -0,0 +1,127 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "pvrdma.h" + +int pvrdma_uar_table_init(struct pvrdma_dev *dev) +{ + u32 num = dev->dsr->caps.max_uar; + u32 mask = num - 1; + struct pvrdma_id_table *tbl = &dev->uar_table.tbl; + + if (!is_power_of_2(num)) + return -EINVAL; + + tbl->last = 0; + tbl->top = 0; + tbl->max = num; + tbl->mask = mask; + spin_lock_init(&tbl->lock); + tbl->table = kcalloc(BITS_TO_LONGS(num), sizeof(long), GFP_KERNEL); + if (!tbl->table) + return -ENOMEM; + + /* 0th UAR is taken by the device. */ + set_bit(0, tbl->table); + + return 0; +} + +void pvrdma_uar_table_cleanup(struct pvrdma_dev *dev) +{ + struct pvrdma_id_table *tbl = &dev->uar_table.tbl; + + kfree(tbl->table); +} + +int pvrdma_uar_alloc(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar) +{ + struct pvrdma_id_table *tbl; + unsigned long flags; + u32 obj; + + tbl = &dev->uar_table.tbl; + + spin_lock_irqsave(&tbl->lock, flags); + obj = find_next_zero_bit(tbl->table, tbl->max, tbl->last); + if (obj >= tbl->max) { + tbl->top = (tbl->top + tbl->max) & tbl->mask; + obj = find_first_zero_bit(tbl->table, tbl->max); + } + + if (obj >= tbl->max) { + spin_unlock_irqrestore(&tbl->lock, flags); + return -ENOMEM; + } + + set_bit(obj, tbl->table); + obj |= tbl->top; + + spin_unlock_irqrestore(&tbl->lock, flags); + + uar->index = obj; + uar->pfn = (pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_UAR) >> + PAGE_SHIFT) + uar->index; + + return 0; +} + +void pvrdma_uar_free(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar) +{ + struct pvrdma_id_table *tbl = &dev->uar_table.tbl; + unsigned long flags; + u32 obj; + + obj = uar->index & (tbl->max - 1); + spin_lock_irqsave(&tbl->lock, flags); + clear_bit(obj, tbl->table); + tbl->last = min(tbl->last, obj); + tbl->top = (tbl->top + tbl->max) & tbl->mask; + spin_unlock_irqrestore(&tbl->lock, flags); +} diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c new file mode 100644 index 000000000000..231a1ce1f4be --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_main.c @@ -0,0 +1,1211 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pvrdma.h" + +#define DRV_NAME "vmw_pvrdma" +#define DRV_VERSION "1.0.0.0-k" + +static DEFINE_MUTEX(pvrdma_device_list_lock); +static LIST_HEAD(pvrdma_device_list); +static struct workqueue_struct *event_wq; + +static int pvrdma_add_gid(struct ib_device *ibdev, + u8 port_num, + unsigned int index, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + void **context); +static int pvrdma_del_gid(struct ib_device *ibdev, + u8 port_num, + unsigned int index, + void **context); + + +static ssize_t show_hca(struct device *device, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "VMW_PVRDMA-%s\n", DRV_VERSION); +} + +static ssize_t show_rev(struct device *device, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", PVRDMA_REV_ID); +} + +static ssize_t show_board(struct device *device, struct device_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", PVRDMA_BOARD_ID); +} + +static DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); +static DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); +static DEVICE_ATTR(board_id, S_IRUGO, show_board, NULL); + +static struct device_attribute *pvrdma_class_attributes[] = { + &dev_attr_hw_rev, + &dev_attr_hca_type, + &dev_attr_board_id +}; + +static void pvrdma_get_fw_ver_str(struct ib_device *device, char *str, + size_t str_len) +{ + struct pvrdma_dev *dev = + container_of(device, struct pvrdma_dev, ib_dev); + snprintf(str, str_len, "%d.%d.%d\n", + (int) (dev->dsr->caps.fw_ver >> 32), + (int) (dev->dsr->caps.fw_ver >> 16) & 0xffff, + (int) dev->dsr->caps.fw_ver & 0xffff); +} + +static int pvrdma_init_device(struct pvrdma_dev *dev) +{ + /* Initialize some device related stuff */ + spin_lock_init(&dev->cmd_lock); + sema_init(&dev->cmd_sema, 1); + atomic_set(&dev->num_qps, 0); + atomic_set(&dev->num_cqs, 0); + atomic_set(&dev->num_pds, 0); + atomic_set(&dev->num_ahs, 0); + + return 0; +} + +static int pvrdma_port_immutable(struct ib_device *ibdev, u8 port_num, + struct ib_port_immutable *immutable) +{ + struct ib_port_attr attr; + int err; + + err = pvrdma_query_port(ibdev, port_num, &attr); + if (err) + return err; + + immutable->pkey_tbl_len = attr.pkey_tbl_len; + immutable->gid_tbl_len = attr.gid_tbl_len; + immutable->core_cap_flags = RDMA_CORE_PORT_IBA_ROCE; + immutable->max_mad_size = IB_MGMT_MAD_SIZE; + return 0; +} + +static struct net_device *pvrdma_get_netdev(struct ib_device *ibdev, + u8 port_num) +{ + struct net_device *netdev; + struct pvrdma_dev *dev = to_vdev(ibdev); + + if (port_num != 1) + return NULL; + + rcu_read_lock(); + netdev = dev->netdev; + if (netdev) + dev_hold(netdev); + rcu_read_unlock(); + + return netdev; +} + +static int pvrdma_register_device(struct pvrdma_dev *dev) +{ + int ret = -1; + int i = 0; + + strlcpy(dev->ib_dev.name, "vmw_pvrdma%d", IB_DEVICE_NAME_MAX); + dev->ib_dev.node_guid = dev->dsr->caps.node_guid; + dev->sys_image_guid = dev->dsr->caps.sys_image_guid; + dev->flags = 0; + dev->ib_dev.owner = THIS_MODULE; + dev->ib_dev.num_comp_vectors = 1; + dev->ib_dev.dma_device = &dev->pdev->dev; + dev->ib_dev.uverbs_abi_ver = PVRDMA_UVERBS_ABI_VERSION; + dev->ib_dev.uverbs_cmd_mask = + (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | + (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | + (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | + (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | + (1ull << IB_USER_VERBS_CMD_REG_MR) | + (1ull << IB_USER_VERBS_CMD_DEREG_MR) | + (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | + (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | + (1ull << IB_USER_VERBS_CMD_POLL_CQ) | + (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) | + (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | + (1ull << IB_USER_VERBS_CMD_CREATE_QP) | + (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | + (1ull << IB_USER_VERBS_CMD_QUERY_QP) | + (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | + (1ull << IB_USER_VERBS_CMD_POST_SEND) | + (1ull << IB_USER_VERBS_CMD_POST_RECV) | + (1ull << IB_USER_VERBS_CMD_CREATE_AH) | + (1ull << IB_USER_VERBS_CMD_DESTROY_AH); + + dev->ib_dev.node_type = RDMA_NODE_IB_CA; + dev->ib_dev.phys_port_cnt = dev->dsr->caps.phys_port_cnt; + + dev->ib_dev.query_device = pvrdma_query_device; + dev->ib_dev.query_port = pvrdma_query_port; + dev->ib_dev.query_gid = pvrdma_query_gid; + dev->ib_dev.query_pkey = pvrdma_query_pkey; + dev->ib_dev.modify_port = pvrdma_modify_port; + dev->ib_dev.alloc_ucontext = pvrdma_alloc_ucontext; + dev->ib_dev.dealloc_ucontext = pvrdma_dealloc_ucontext; + dev->ib_dev.mmap = pvrdma_mmap; + dev->ib_dev.alloc_pd = pvrdma_alloc_pd; + dev->ib_dev.dealloc_pd = pvrdma_dealloc_pd; + dev->ib_dev.create_ah = pvrdma_create_ah; + dev->ib_dev.destroy_ah = pvrdma_destroy_ah; + dev->ib_dev.create_qp = pvrdma_create_qp; + dev->ib_dev.modify_qp = pvrdma_modify_qp; + dev->ib_dev.query_qp = pvrdma_query_qp; + dev->ib_dev.destroy_qp = pvrdma_destroy_qp; + dev->ib_dev.post_send = pvrdma_post_send; + dev->ib_dev.post_recv = pvrdma_post_recv; + dev->ib_dev.create_cq = pvrdma_create_cq; + dev->ib_dev.modify_cq = pvrdma_modify_cq; + dev->ib_dev.resize_cq = pvrdma_resize_cq; + dev->ib_dev.destroy_cq = pvrdma_destroy_cq; + dev->ib_dev.poll_cq = pvrdma_poll_cq; + dev->ib_dev.req_notify_cq = pvrdma_req_notify_cq; + dev->ib_dev.get_dma_mr = pvrdma_get_dma_mr; + dev->ib_dev.reg_user_mr = pvrdma_reg_user_mr; + dev->ib_dev.dereg_mr = pvrdma_dereg_mr; + dev->ib_dev.alloc_mr = pvrdma_alloc_mr; + dev->ib_dev.map_mr_sg = pvrdma_map_mr_sg; + dev->ib_dev.add_gid = pvrdma_add_gid; + dev->ib_dev.del_gid = pvrdma_del_gid; + dev->ib_dev.get_netdev = pvrdma_get_netdev; + dev->ib_dev.get_port_immutable = pvrdma_port_immutable; + dev->ib_dev.get_link_layer = pvrdma_port_link_layer; + dev->ib_dev.get_dev_fw_str = pvrdma_get_fw_ver_str; + + mutex_init(&dev->port_mutex); + spin_lock_init(&dev->desc_lock); + + dev->cq_tbl = kcalloc(dev->dsr->caps.max_cq, sizeof(void *), + GFP_KERNEL); + if (!dev->cq_tbl) + return ret; + spin_lock_init(&dev->cq_tbl_lock); + + dev->qp_tbl = kcalloc(dev->dsr->caps.max_qp, sizeof(void *), + GFP_KERNEL); + if (!dev->qp_tbl) + goto err_cq_free; + spin_lock_init(&dev->qp_tbl_lock); + + ret = ib_register_device(&dev->ib_dev, NULL); + if (ret) + goto err_qp_free; + + for (i = 0; i < ARRAY_SIZE(pvrdma_class_attributes); ++i) { + ret = device_create_file(&dev->ib_dev.dev, + pvrdma_class_attributes[i]); + if (ret) + goto err_class; + } + + dev->ib_active = true; + + return 0; + +err_class: + ib_unregister_device(&dev->ib_dev); +err_qp_free: + kfree(dev->qp_tbl); +err_cq_free: + kfree(dev->cq_tbl); + + return ret; +} + +static irqreturn_t pvrdma_intr0_handler(int irq, void *dev_id) +{ + u32 icr = PVRDMA_INTR_CAUSE_RESPONSE; + struct pvrdma_dev *dev = dev_id; + + dev_dbg(&dev->pdev->dev, "interrupt 0 (response) handler\n"); + + if (dev->intr.type != PVRDMA_INTR_TYPE_MSIX) { + /* Legacy intr */ + icr = pvrdma_read_reg(dev, PVRDMA_REG_ICR); + if (icr == 0) + return IRQ_NONE; + } + + if (icr == PVRDMA_INTR_CAUSE_RESPONSE) + complete(&dev->cmd_done); + + return IRQ_HANDLED; +} + +static void pvrdma_qp_event(struct pvrdma_dev *dev, u32 qpn, int type) +{ + struct pvrdma_qp *qp; + unsigned long flags; + + spin_lock_irqsave(&dev->qp_tbl_lock, flags); + qp = dev->qp_tbl[qpn % dev->dsr->caps.max_qp]; + if (qp) + atomic_inc(&qp->refcnt); + spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); + + if (qp && qp->ibqp.event_handler) { + struct ib_qp *ibqp = &qp->ibqp; + struct ib_event e; + + e.device = ibqp->device; + e.element.qp = ibqp; + e.event = type; /* 1:1 mapping for now. */ + ibqp->event_handler(&e, ibqp->qp_context); + } + if (qp) { + atomic_dec(&qp->refcnt); + if (atomic_read(&qp->refcnt) == 0) + wake_up(&qp->wait); + } +} + +static void pvrdma_cq_event(struct pvrdma_dev *dev, u32 cqn, int type) +{ + struct pvrdma_cq *cq; + unsigned long flags; + + spin_lock_irqsave(&dev->cq_tbl_lock, flags); + cq = dev->cq_tbl[cqn % dev->dsr->caps.max_cq]; + if (cq) + atomic_inc(&cq->refcnt); + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); + + if (cq && cq->ibcq.event_handler) { + struct ib_cq *ibcq = &cq->ibcq; + struct ib_event e; + + e.device = ibcq->device; + e.element.cq = ibcq; + e.event = type; /* 1:1 mapping for now. */ + ibcq->event_handler(&e, ibcq->cq_context); + } + if (cq) { + atomic_dec(&cq->refcnt); + if (atomic_read(&cq->refcnt) == 0) + wake_up(&cq->wait); + } +} + +static void pvrdma_dispatch_event(struct pvrdma_dev *dev, int port, + enum ib_event_type event) +{ + struct ib_event ib_event; + + memset(&ib_event, 0, sizeof(ib_event)); + ib_event.device = &dev->ib_dev; + ib_event.element.port_num = port; + ib_event.event = event; + ib_dispatch_event(&ib_event); +} + +static void pvrdma_dev_event(struct pvrdma_dev *dev, u8 port, int type) +{ + if (port < 1 || port > dev->dsr->caps.phys_port_cnt) { + dev_warn(&dev->pdev->dev, "event on port %d\n", port); + return; + } + + pvrdma_dispatch_event(dev, port, type); +} + +static inline struct pvrdma_eqe *get_eqe(struct pvrdma_dev *dev, unsigned int i) +{ + return (struct pvrdma_eqe *)pvrdma_page_dir_get_ptr( + &dev->async_pdir, + PAGE_SIZE + + sizeof(struct pvrdma_eqe) * i); +} + +static irqreturn_t pvrdma_intr1_handler(int irq, void *dev_id) +{ + struct pvrdma_dev *dev = dev_id; + struct pvrdma_ring *ring = &dev->async_ring_state->rx; + int ring_slots = (dev->dsr->async_ring_pages.num_pages - 1) * + PAGE_SIZE / sizeof(struct pvrdma_eqe); + unsigned int head; + + dev_dbg(&dev->pdev->dev, "interrupt 1 (async event) handler\n"); + + /* + * Don't process events until the IB device is registered. Otherwise + * we'll try to ib_dispatch_event() on an invalid device. + */ + if (!dev->ib_active) + return IRQ_HANDLED; + + while (pvrdma_idx_ring_has_data(ring, ring_slots, &head) > 0) { + struct pvrdma_eqe *eqe; + + eqe = get_eqe(dev, head); + + switch (eqe->type) { + case PVRDMA_EVENT_QP_FATAL: + case PVRDMA_EVENT_QP_REQ_ERR: + case PVRDMA_EVENT_QP_ACCESS_ERR: + case PVRDMA_EVENT_COMM_EST: + case PVRDMA_EVENT_SQ_DRAINED: + case PVRDMA_EVENT_PATH_MIG: + case PVRDMA_EVENT_PATH_MIG_ERR: + case PVRDMA_EVENT_QP_LAST_WQE_REACHED: + pvrdma_qp_event(dev, eqe->info, eqe->type); + break; + + case PVRDMA_EVENT_CQ_ERR: + pvrdma_cq_event(dev, eqe->info, eqe->type); + break; + + case PVRDMA_EVENT_SRQ_ERR: + case PVRDMA_EVENT_SRQ_LIMIT_REACHED: + break; + + case PVRDMA_EVENT_PORT_ACTIVE: + case PVRDMA_EVENT_PORT_ERR: + case PVRDMA_EVENT_LID_CHANGE: + case PVRDMA_EVENT_PKEY_CHANGE: + case PVRDMA_EVENT_SM_CHANGE: + case PVRDMA_EVENT_CLIENT_REREGISTER: + case PVRDMA_EVENT_GID_CHANGE: + pvrdma_dev_event(dev, eqe->info, eqe->type); + break; + + case PVRDMA_EVENT_DEVICE_FATAL: + pvrdma_dev_event(dev, 1, eqe->type); + break; + + default: + break; + } + + pvrdma_idx_ring_inc(&ring->cons_head, ring_slots); + } + + return IRQ_HANDLED; +} + +static inline struct pvrdma_cqne *get_cqne(struct pvrdma_dev *dev, + unsigned int i) +{ + return (struct pvrdma_cqne *)pvrdma_page_dir_get_ptr( + &dev->cq_pdir, + PAGE_SIZE + + sizeof(struct pvrdma_cqne) * i); +} + +static irqreturn_t pvrdma_intrx_handler(int irq, void *dev_id) +{ + struct pvrdma_dev *dev = dev_id; + struct pvrdma_ring *ring = &dev->cq_ring_state->rx; + int ring_slots = (dev->dsr->cq_ring_pages.num_pages - 1) * PAGE_SIZE / + sizeof(struct pvrdma_cqne); + unsigned int head; + unsigned long flags; + + dev_dbg(&dev->pdev->dev, "interrupt x (completion) handler\n"); + + while (pvrdma_idx_ring_has_data(ring, ring_slots, &head) > 0) { + struct pvrdma_cqne *cqne; + struct pvrdma_cq *cq; + + cqne = get_cqne(dev, head); + spin_lock_irqsave(&dev->cq_tbl_lock, flags); + cq = dev->cq_tbl[cqne->info % dev->dsr->caps.max_cq]; + if (cq) + atomic_inc(&cq->refcnt); + spin_unlock_irqrestore(&dev->cq_tbl_lock, flags); + + if (cq && cq->ibcq.comp_handler) + cq->ibcq.comp_handler(&cq->ibcq, cq->ibcq.cq_context); + if (cq) { + atomic_dec(&cq->refcnt); + if (atomic_read(&cq->refcnt)) + wake_up(&cq->wait); + } + pvrdma_idx_ring_inc(&ring->cons_head, ring_slots); + } + + return IRQ_HANDLED; +} + +static void pvrdma_disable_msi_all(struct pvrdma_dev *dev) +{ + if (dev->intr.type == PVRDMA_INTR_TYPE_MSIX) + pci_disable_msix(dev->pdev); + else if (dev->intr.type == PVRDMA_INTR_TYPE_MSI) + pci_disable_msi(dev->pdev); +} + +static void pvrdma_free_irq(struct pvrdma_dev *dev) +{ + int i; + + dev_dbg(&dev->pdev->dev, "freeing interrupts\n"); + + if (dev->intr.type == PVRDMA_INTR_TYPE_MSIX) { + for (i = 0; i < dev->intr.size; i++) { + if (dev->intr.enabled[i]) { + free_irq(dev->intr.msix_entry[i].vector, dev); + dev->intr.enabled[i] = 0; + } + } + } else if (dev->intr.type == PVRDMA_INTR_TYPE_INTX || + dev->intr.type == PVRDMA_INTR_TYPE_MSI) { + free_irq(dev->pdev->irq, dev); + } +} + +static void pvrdma_enable_intrs(struct pvrdma_dev *dev) +{ + dev_dbg(&dev->pdev->dev, "enable interrupts\n"); + pvrdma_write_reg(dev, PVRDMA_REG_IMR, 0); +} + +static void pvrdma_disable_intrs(struct pvrdma_dev *dev) +{ + dev_dbg(&dev->pdev->dev, "disable interrupts\n"); + pvrdma_write_reg(dev, PVRDMA_REG_IMR, ~0); +} + +static int pvrdma_enable_msix(struct pci_dev *pdev, struct pvrdma_dev *dev) +{ + int i; + int ret; + + for (i = 0; i < PVRDMA_MAX_INTERRUPTS; i++) { + dev->intr.msix_entry[i].entry = i; + dev->intr.msix_entry[i].vector = i; + + switch (i) { + case 0: + /* CMD ring handler */ + dev->intr.handler[i] = pvrdma_intr0_handler; + break; + case 1: + /* Async event ring handler */ + dev->intr.handler[i] = pvrdma_intr1_handler; + break; + default: + /* Completion queue handler */ + dev->intr.handler[i] = pvrdma_intrx_handler; + break; + } + } + + ret = pci_enable_msix(pdev, dev->intr.msix_entry, + PVRDMA_MAX_INTERRUPTS); + if (!ret) { + dev->intr.type = PVRDMA_INTR_TYPE_MSIX; + dev->intr.size = PVRDMA_MAX_INTERRUPTS; + } else if (ret > 0) { + ret = pci_enable_msix(pdev, dev->intr.msix_entry, ret); + if (!ret) { + dev->intr.type = PVRDMA_INTR_TYPE_MSIX; + dev->intr.size = ret; + } else { + dev->intr.size = 0; + } + } + + dev_dbg(&pdev->dev, "using interrupt type %d, size %d\n", + dev->intr.type, dev->intr.size); + + return ret; +} + +static int pvrdma_alloc_intrs(struct pvrdma_dev *dev) +{ + int ret = 0; + int i; + + if (pci_find_capability(dev->pdev, PCI_CAP_ID_MSIX) && + pvrdma_enable_msix(dev->pdev, dev)) { + /* Try MSI */ + ret = pci_enable_msi(dev->pdev); + if (!ret) { + dev->intr.type = PVRDMA_INTR_TYPE_MSI; + } else { + /* Legacy INTR */ + dev->intr.type = PVRDMA_INTR_TYPE_INTX; + } + } + + /* Request First IRQ */ + switch (dev->intr.type) { + case PVRDMA_INTR_TYPE_INTX: + case PVRDMA_INTR_TYPE_MSI: + ret = request_irq(dev->pdev->irq, pvrdma_intr0_handler, + IRQF_SHARED, DRV_NAME, dev); + if (ret) { + dev_err(&dev->pdev->dev, + "failed to request interrupt\n"); + goto disable_msi; + } + break; + case PVRDMA_INTR_TYPE_MSIX: + ret = request_irq(dev->intr.msix_entry[0].vector, + pvrdma_intr0_handler, 0, DRV_NAME, dev); + if (ret) { + dev_err(&dev->pdev->dev, + "failed to request interrupt 0\n"); + goto disable_msi; + } + dev->intr.enabled[0] = 1; + break; + default: + /* Not reached */ + break; + } + + /* For MSIX: request intr for each vector */ + if (dev->intr.size > 1) { + ret = request_irq(dev->intr.msix_entry[1].vector, + pvrdma_intr1_handler, 0, DRV_NAME, dev); + if (ret) { + dev_err(&dev->pdev->dev, + "failed to request interrupt 1\n"); + goto free_irq; + } + dev->intr.enabled[1] = 1; + + for (i = 2; i < dev->intr.size; i++) { + ret = request_irq(dev->intr.msix_entry[i].vector, + pvrdma_intrx_handler, 0, + DRV_NAME, dev); + if (ret) { + dev_err(&dev->pdev->dev, + "failed to request interrupt %d\n", i); + goto free_irq; + } + dev->intr.enabled[i] = 1; + } + } + + return 0; + +free_irq: + pvrdma_free_irq(dev); +disable_msi: + pvrdma_disable_msi_all(dev); + return ret; +} + +static void pvrdma_free_slots(struct pvrdma_dev *dev) +{ + struct pci_dev *pdev = dev->pdev; + + if (dev->resp_slot) + dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->resp_slot, + dev->dsr->resp_slot_dma); + if (dev->cmd_slot) + dma_free_coherent(&pdev->dev, PAGE_SIZE, dev->cmd_slot, + dev->dsr->cmd_slot_dma); +} + +static int pvrdma_add_gid_at_index(struct pvrdma_dev *dev, + const union ib_gid *gid, + int index) +{ + int ret; + union pvrdma_cmd_req req; + struct pvrdma_cmd_create_bind *cmd_bind = &req.create_bind; + + if (!dev->sgid_tbl) { + dev_warn(&dev->pdev->dev, "sgid table not initialized\n"); + return -EINVAL; + } + + memset(cmd_bind, 0, sizeof(*cmd_bind)); + cmd_bind->hdr.cmd = PVRDMA_CMD_CREATE_BIND; + memcpy(cmd_bind->new_gid, gid->raw, 16); + cmd_bind->mtu = ib_mtu_enum_to_int(IB_MTU_1024); + cmd_bind->vlan = 0xfff; + cmd_bind->index = index; + cmd_bind->gid_type = PVRDMA_GID_TYPE_FLAG_ROCE_V1; + + ret = pvrdma_cmd_post(dev, &req, NULL, 0); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not create binding, error: %d\n", ret); + return -EFAULT; + } + memcpy(&dev->sgid_tbl[index], gid, sizeof(*gid)); + return 0; +} + +static int pvrdma_add_gid(struct ib_device *ibdev, + u8 port_num, + unsigned int index, + const union ib_gid *gid, + const struct ib_gid_attr *attr, + void **context) +{ + struct pvrdma_dev *dev = to_vdev(ibdev); + + return pvrdma_add_gid_at_index(dev, gid, index); +} + +static int pvrdma_del_gid_at_index(struct pvrdma_dev *dev, int index) +{ + int ret; + union pvrdma_cmd_req req; + struct pvrdma_cmd_destroy_bind *cmd_dest = &req.destroy_bind; + + /* Update sgid table. */ + if (!dev->sgid_tbl) { + dev_warn(&dev->pdev->dev, "sgid table not initialized\n"); + return -EINVAL; + } + + memset(cmd_dest, 0, sizeof(*cmd_dest)); + cmd_dest->hdr.cmd = PVRDMA_CMD_DESTROY_BIND; + memcpy(cmd_dest->dest_gid, &dev->sgid_tbl[index], 16); + cmd_dest->index = index; + + ret = pvrdma_cmd_post(dev, &req, NULL, 0); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not destroy binding, error: %d\n", ret); + return ret; + } + memset(&dev->sgid_tbl[index], 0, 16); + return 0; +} + +static int pvrdma_del_gid(struct ib_device *ibdev, + u8 port_num, + unsigned int index, + void **context) +{ + struct pvrdma_dev *dev = to_vdev(ibdev); + + dev_dbg(&dev->pdev->dev, "removing gid at index %u from %s", + index, dev->netdev->name); + + return pvrdma_del_gid_at_index(dev, index); +} + +static void pvrdma_netdevice_event_handle(struct pvrdma_dev *dev, + unsigned long event) +{ + switch (event) { + case NETDEV_REBOOT: + case NETDEV_DOWN: + pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ERR); + break; + case NETDEV_UP: + pvrdma_dispatch_event(dev, 1, IB_EVENT_PORT_ACTIVE); + break; + default: + dev_dbg(&dev->pdev->dev, "ignore netdevice event %ld on %s\n", + event, dev->ib_dev.name); + break; + } +} + +static void pvrdma_netdevice_event_work(struct work_struct *work) +{ + struct pvrdma_netdevice_work *netdev_work; + struct pvrdma_dev *dev; + + netdev_work = container_of(work, struct pvrdma_netdevice_work, work); + + mutex_lock(&pvrdma_device_list_lock); + list_for_each_entry(dev, &pvrdma_device_list, device_link) { + if (dev->netdev == netdev_work->event_netdev) { + pvrdma_netdevice_event_handle(dev, netdev_work->event); + break; + } + } + mutex_unlock(&pvrdma_device_list_lock); + + kfree(netdev_work); +} + +static int pvrdma_netdevice_event(struct notifier_block *this, + unsigned long event, void *ptr) +{ + struct net_device *event_netdev = netdev_notifier_info_to_dev(ptr); + struct pvrdma_netdevice_work *netdev_work; + + netdev_work = kmalloc(sizeof(*netdev_work), GFP_ATOMIC); + if (!netdev_work) + return NOTIFY_BAD; + + INIT_WORK(&netdev_work->work, pvrdma_netdevice_event_work); + netdev_work->event_netdev = event_netdev; + netdev_work->event = event; + queue_work(event_wq, &netdev_work->work); + + return NOTIFY_DONE; +} + +static int pvrdma_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + struct pci_dev *pdev_net; + struct pvrdma_dev *dev; + int ret; + unsigned long start; + unsigned long len; + unsigned int version; + dma_addr_t slot_dma = 0; + + dev_dbg(&pdev->dev, "initializing driver %s\n", pci_name(pdev)); + + /* Allocate zero-out device */ + dev = (struct pvrdma_dev *)ib_alloc_device(sizeof(*dev)); + if (!dev) { + dev_err(&pdev->dev, "failed to allocate IB device\n"); + return -ENOMEM; + } + + mutex_lock(&pvrdma_device_list_lock); + list_add(&dev->device_link, &pvrdma_device_list); + mutex_unlock(&pvrdma_device_list_lock); + + ret = pvrdma_init_device(dev); + if (ret) + goto err_free_device; + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); + + ret = pci_enable_device(pdev); + if (ret) { + dev_err(&pdev->dev, "cannot enable PCI device\n"); + goto err_free_device; + } + + dev_dbg(&pdev->dev, "PCI resource flags BAR0 %#lx\n", + pci_resource_flags(pdev, 0)); + dev_dbg(&pdev->dev, "PCI resource len %#llx\n", + (unsigned long long)pci_resource_len(pdev, 0)); + dev_dbg(&pdev->dev, "PCI resource start %#llx\n", + (unsigned long long)pci_resource_start(pdev, 0)); + dev_dbg(&pdev->dev, "PCI resource flags BAR1 %#lx\n", + pci_resource_flags(pdev, 1)); + dev_dbg(&pdev->dev, "PCI resource len %#llx\n", + (unsigned long long)pci_resource_len(pdev, 1)); + dev_dbg(&pdev->dev, "PCI resource start %#llx\n", + (unsigned long long)pci_resource_start(pdev, 1)); + + if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) || + !(pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { + dev_err(&pdev->dev, "PCI BAR region not MMIO\n"); + ret = -ENOMEM; + goto err_free_device; + } + + ret = pci_request_regions(pdev, DRV_NAME); + if (ret) { + dev_err(&pdev->dev, "cannot request PCI resources\n"); + goto err_disable_pdev; + } + + /* Enable 64-Bit DMA */ + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { + ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + if (ret != 0) { + dev_err(&pdev->dev, + "pci_set_consistent_dma_mask failed\n"); + goto err_free_resource; + } + } else { + ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (ret != 0) { + dev_err(&pdev->dev, + "pci_set_dma_mask failed\n"); + goto err_free_resource; + } + } + + pci_set_master(pdev); + + /* Map register space */ + start = pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_REG); + len = pci_resource_len(dev->pdev, PVRDMA_PCI_RESOURCE_REG); + dev->regs = ioremap(start, len); + if (!dev->regs) { + dev_err(&pdev->dev, "register mapping failed\n"); + ret = -ENOMEM; + goto err_free_resource; + } + + /* Setup per-device UAR. */ + dev->driver_uar.index = 0; + dev->driver_uar.pfn = + pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_UAR) >> + PAGE_SHIFT; + dev->driver_uar.map = + ioremap(dev->driver_uar.pfn << PAGE_SHIFT, PAGE_SIZE); + if (!dev->driver_uar.map) { + dev_err(&pdev->dev, "failed to remap UAR pages\n"); + ret = -ENOMEM; + goto err_unmap_regs; + } + + version = pvrdma_read_reg(dev, PVRDMA_REG_VERSION); + dev_info(&pdev->dev, "device version %d, driver version %d\n", + version, PVRDMA_VERSION); + if (version < PVRDMA_VERSION) { + dev_err(&pdev->dev, "incompatible device version\n"); + goto err_uar_unmap; + } + + dev->dsr = dma_alloc_coherent(&pdev->dev, sizeof(*dev->dsr), + &dev->dsrbase, GFP_KERNEL); + if (!dev->dsr) { + dev_err(&pdev->dev, "failed to allocate shared region\n"); + ret = -ENOMEM; + goto err_uar_unmap; + } + + /* Setup the shared region */ + memset(dev->dsr, 0, sizeof(*dev->dsr)); + dev->dsr->driver_version = PVRDMA_VERSION; + dev->dsr->gos_info.gos_bits = sizeof(void *) == 4 ? + PVRDMA_GOS_BITS_32 : + PVRDMA_GOS_BITS_64; + dev->dsr->gos_info.gos_type = PVRDMA_GOS_TYPE_LINUX; + dev->dsr->gos_info.gos_ver = 1; + dev->dsr->uar_pfn = dev->driver_uar.pfn; + + /* Command slot. */ + dev->cmd_slot = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, + &slot_dma, GFP_KERNEL); + if (!dev->cmd_slot) { + ret = -ENOMEM; + goto err_free_dsr; + } + + dev->dsr->cmd_slot_dma = (u64)slot_dma; + + /* Response slot. */ + dev->resp_slot = dma_alloc_coherent(&pdev->dev, PAGE_SIZE, + &slot_dma, GFP_KERNEL); + if (!dev->resp_slot) { + ret = -ENOMEM; + goto err_free_slots; + } + + dev->dsr->resp_slot_dma = (u64)slot_dma; + + /* Async event ring */ + dev->dsr->async_ring_pages.num_pages = 4; + ret = pvrdma_page_dir_init(dev, &dev->async_pdir, + dev->dsr->async_ring_pages.num_pages, true); + if (ret) + goto err_free_slots; + dev->async_ring_state = dev->async_pdir.pages[0]; + dev->dsr->async_ring_pages.pdir_dma = dev->async_pdir.dir_dma; + + /* CQ notification ring */ + dev->dsr->cq_ring_pages.num_pages = 4; + ret = pvrdma_page_dir_init(dev, &dev->cq_pdir, + dev->dsr->cq_ring_pages.num_pages, true); + if (ret) + goto err_free_async_ring; + dev->cq_ring_state = dev->cq_pdir.pages[0]; + dev->dsr->cq_ring_pages.pdir_dma = dev->cq_pdir.dir_dma; + + /* + * Write the PA of the shared region to the device. The writes must be + * ordered such that the high bits are written last. When the writes + * complete, the device will have filled out the capabilities. + */ + + pvrdma_write_reg(dev, PVRDMA_REG_DSRLOW, (u32)dev->dsrbase); + pvrdma_write_reg(dev, PVRDMA_REG_DSRHIGH, + (u32)((u64)(dev->dsrbase) >> 32)); + + /* Make sure the write is complete before reading status. */ + mb(); + + /* Currently, the driver only supports RoCE mode. */ + if (dev->dsr->caps.mode != PVRDMA_DEVICE_MODE_ROCE) { + dev_err(&pdev->dev, "unsupported transport %d\n", + dev->dsr->caps.mode); + ret = -EFAULT; + goto err_free_cq_ring; + } + + /* Currently, the driver only supports RoCE V1. */ + if (!(dev->dsr->caps.gid_types & PVRDMA_GID_TYPE_FLAG_ROCE_V1)) { + dev_err(&pdev->dev, "driver needs RoCE v1 support\n"); + ret = -EFAULT; + goto err_free_cq_ring; + } + + /* Paired vmxnet3 will have same bus, slot. But func will be 0 */ + pdev_net = pci_get_slot(pdev->bus, PCI_DEVFN(PCI_SLOT(pdev->devfn), 0)); + if (!pdev_net) { + dev_err(&pdev->dev, "failed to find paired net device\n"); + ret = -ENODEV; + goto err_free_cq_ring; + } + + if (pdev_net->vendor != PCI_VENDOR_ID_VMWARE || + pdev_net->device != PCI_DEVICE_ID_VMWARE_VMXNET3) { + dev_err(&pdev->dev, "failed to find paired vmxnet3 device\n"); + pci_dev_put(pdev_net); + ret = -ENODEV; + goto err_free_cq_ring; + } + + dev->netdev = pci_get_drvdata(pdev_net); + pci_dev_put(pdev_net); + if (!dev->netdev) { + dev_err(&pdev->dev, "failed to get vmxnet3 device\n"); + ret = -ENODEV; + goto err_free_cq_ring; + } + + dev_info(&pdev->dev, "paired device to %s\n", dev->netdev->name); + + /* Interrupt setup */ + ret = pvrdma_alloc_intrs(dev); + if (ret) { + dev_err(&pdev->dev, "failed to allocate interrupts\n"); + ret = -ENOMEM; + goto err_netdevice; + } + + /* Allocate UAR table. */ + ret = pvrdma_uar_table_init(dev); + if (ret) { + dev_err(&pdev->dev, "failed to allocate UAR table\n"); + ret = -ENOMEM; + goto err_free_intrs; + } + + /* Allocate GID table */ + dev->sgid_tbl = kcalloc(dev->dsr->caps.gid_tbl_len, + sizeof(union ib_gid), GFP_KERNEL); + if (!dev->sgid_tbl) { + ret = -ENOMEM; + goto err_free_uar_table; + } + dev_dbg(&pdev->dev, "gid table len %d\n", dev->dsr->caps.gid_tbl_len); + + pvrdma_enable_intrs(dev); + + /* Activate pvrdma device */ + pvrdma_write_reg(dev, PVRDMA_REG_CTL, PVRDMA_DEVICE_CTL_ACTIVATE); + + /* Make sure the write is complete before reading status. */ + mb(); + + /* Check if device was successfully activated */ + ret = pvrdma_read_reg(dev, PVRDMA_REG_ERR); + if (ret != 0) { + dev_err(&pdev->dev, "failed to activate device\n"); + ret = -EFAULT; + goto err_disable_intr; + } + + /* Register IB device */ + ret = pvrdma_register_device(dev); + if (ret) { + dev_err(&pdev->dev, "failed to register IB device\n"); + goto err_disable_intr; + } + + dev->nb_netdev.notifier_call = pvrdma_netdevice_event; + ret = register_netdevice_notifier(&dev->nb_netdev); + if (ret) { + dev_err(&pdev->dev, "failed to register netdevice events\n"); + goto err_unreg_ibdev; + } + + dev_info(&pdev->dev, "attached to device\n"); + return 0; + +err_unreg_ibdev: + ib_unregister_device(&dev->ib_dev); +err_disable_intr: + pvrdma_disable_intrs(dev); + kfree(dev->sgid_tbl); +err_free_uar_table: + pvrdma_uar_table_cleanup(dev); +err_free_intrs: + pvrdma_free_irq(dev); + pvrdma_disable_msi_all(dev); +err_netdevice: + unregister_netdevice_notifier(&dev->nb_netdev); +err_free_cq_ring: + pvrdma_page_dir_cleanup(dev, &dev->cq_pdir); +err_free_async_ring: + pvrdma_page_dir_cleanup(dev, &dev->async_pdir); +err_free_slots: + pvrdma_free_slots(dev); +err_free_dsr: + dma_free_coherent(&pdev->dev, sizeof(*dev->dsr), dev->dsr, + dev->dsrbase); +err_uar_unmap: + iounmap(dev->driver_uar.map); +err_unmap_regs: + iounmap(dev->regs); +err_free_resource: + pci_release_regions(pdev); +err_disable_pdev: + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +err_free_device: + mutex_lock(&pvrdma_device_list_lock); + list_del(&dev->device_link); + mutex_unlock(&pvrdma_device_list_lock); + ib_dealloc_device(&dev->ib_dev); + return ret; +} + +static void pvrdma_pci_remove(struct pci_dev *pdev) +{ + struct pvrdma_dev *dev = pci_get_drvdata(pdev); + + if (!dev) + return; + + dev_info(&pdev->dev, "detaching from device\n"); + + unregister_netdevice_notifier(&dev->nb_netdev); + dev->nb_netdev.notifier_call = NULL; + + flush_workqueue(event_wq); + + /* Unregister ib device */ + ib_unregister_device(&dev->ib_dev); + + mutex_lock(&pvrdma_device_list_lock); + list_del(&dev->device_link); + mutex_unlock(&pvrdma_device_list_lock); + + pvrdma_disable_intrs(dev); + pvrdma_free_irq(dev); + pvrdma_disable_msi_all(dev); + + /* Deactivate pvrdma device */ + pvrdma_write_reg(dev, PVRDMA_REG_CTL, PVRDMA_DEVICE_CTL_RESET); + pvrdma_page_dir_cleanup(dev, &dev->cq_pdir); + pvrdma_page_dir_cleanup(dev, &dev->async_pdir); + pvrdma_free_slots(dev); + + iounmap(dev->regs); + kfree(dev->sgid_tbl); + kfree(dev->cq_tbl); + kfree(dev->qp_tbl); + pvrdma_uar_table_cleanup(dev); + iounmap(dev->driver_uar.map); + + ib_dealloc_device(&dev->ib_dev); + + /* Free pci resources */ + pci_release_regions(pdev); + pci_disable_device(pdev); + pci_set_drvdata(pdev, NULL); +} + +static struct pci_device_id pvrdma_pci_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_VMWARE, PCI_DEVICE_ID_VMWARE_PVRDMA), }, + { 0 }, +}; + +MODULE_DEVICE_TABLE(pci, pvrdma_pci_table); + +static struct pci_driver pvrdma_driver = { + .name = DRV_NAME, + .id_table = pvrdma_pci_table, + .probe = pvrdma_pci_probe, + .remove = pvrdma_pci_remove, +}; + +static int __init pvrdma_init(void) +{ + int err; + + event_wq = alloc_ordered_workqueue("pvrdma_event_wq", WQ_MEM_RECLAIM); + if (!event_wq) + return -ENOMEM; + + err = pci_register_driver(&pvrdma_driver); + if (err) + destroy_workqueue(event_wq); + + return err; +} + +static void __exit pvrdma_cleanup(void) +{ + pci_unregister_driver(&pvrdma_driver); + + destroy_workqueue(event_wq); +} + +module_init(pvrdma_init); +module_exit(pvrdma_cleanup); + +MODULE_AUTHOR("VMware, Inc"); +MODULE_DESCRIPTION("VMware Paravirtual RDMA driver"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_misc.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_misc.c new file mode 100644 index 000000000000..948b5ccd2a70 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_misc.c @@ -0,0 +1,304 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +#include "pvrdma.h" + +int pvrdma_page_dir_init(struct pvrdma_dev *dev, struct pvrdma_page_dir *pdir, + u64 npages, bool alloc_pages) +{ + u64 i; + + if (npages > PVRDMA_PAGE_DIR_MAX_PAGES) + return -EINVAL; + + memset(pdir, 0, sizeof(*pdir)); + + pdir->dir = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + &pdir->dir_dma, GFP_KERNEL); + if (!pdir->dir) + goto err; + + pdir->ntables = PVRDMA_PAGE_DIR_TABLE(npages - 1) + 1; + pdir->tables = kcalloc(pdir->ntables, sizeof(*pdir->tables), + GFP_KERNEL); + if (!pdir->tables) + goto err; + + for (i = 0; i < pdir->ntables; i++) { + pdir->tables[i] = dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE, + (dma_addr_t *)&pdir->dir[i], + GFP_KERNEL); + if (!pdir->tables[i]) + goto err; + } + + pdir->npages = npages; + + if (alloc_pages) { + pdir->pages = kcalloc(npages, sizeof(*pdir->pages), + GFP_KERNEL); + if (!pdir->pages) + goto err; + + for (i = 0; i < pdir->npages; i++) { + dma_addr_t page_dma; + + pdir->pages[i] = dma_alloc_coherent(&dev->pdev->dev, + PAGE_SIZE, + &page_dma, + GFP_KERNEL); + if (!pdir->pages[i]) + goto err; + + pvrdma_page_dir_insert_dma(pdir, i, page_dma); + } + } + + return 0; + +err: + pvrdma_page_dir_cleanup(dev, pdir); + + return -ENOMEM; +} + +static u64 *pvrdma_page_dir_table(struct pvrdma_page_dir *pdir, u64 idx) +{ + return pdir->tables[PVRDMA_PAGE_DIR_TABLE(idx)]; +} + +dma_addr_t pvrdma_page_dir_get_dma(struct pvrdma_page_dir *pdir, u64 idx) +{ + return pvrdma_page_dir_table(pdir, idx)[PVRDMA_PAGE_DIR_PAGE(idx)]; +} + +static void pvrdma_page_dir_cleanup_pages(struct pvrdma_dev *dev, + struct pvrdma_page_dir *pdir) +{ + if (pdir->pages) { + u64 i; + + for (i = 0; i < pdir->npages && pdir->pages[i]; i++) { + dma_addr_t page_dma = pvrdma_page_dir_get_dma(pdir, i); + + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + pdir->pages[i], page_dma); + } + + kfree(pdir->pages); + } +} + +static void pvrdma_page_dir_cleanup_tables(struct pvrdma_dev *dev, + struct pvrdma_page_dir *pdir) +{ + if (pdir->tables) { + int i; + + pvrdma_page_dir_cleanup_pages(dev, pdir); + + for (i = 0; i < pdir->ntables; i++) { + u64 *table = pdir->tables[i]; + + if (table) + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + table, pdir->dir[i]); + } + + kfree(pdir->tables); + } +} + +void pvrdma_page_dir_cleanup(struct pvrdma_dev *dev, + struct pvrdma_page_dir *pdir) +{ + if (pdir->dir) { + pvrdma_page_dir_cleanup_tables(dev, pdir); + dma_free_coherent(&dev->pdev->dev, PAGE_SIZE, + pdir->dir, pdir->dir_dma); + } +} + +int pvrdma_page_dir_insert_dma(struct pvrdma_page_dir *pdir, u64 idx, + dma_addr_t daddr) +{ + u64 *table; + + if (idx >= pdir->npages) + return -EINVAL; + + table = pvrdma_page_dir_table(pdir, idx); + table[PVRDMA_PAGE_DIR_PAGE(idx)] = daddr; + + return 0; +} + +int pvrdma_page_dir_insert_umem(struct pvrdma_page_dir *pdir, + struct ib_umem *umem, u64 offset) +{ + u64 i = offset; + int j, entry; + int ret = 0, len = 0; + struct scatterlist *sg; + + if (offset >= pdir->npages) + return -EINVAL; + + for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) { + len = sg_dma_len(sg) >> PAGE_SHIFT; + for (j = 0; j < len; j++) { + dma_addr_t addr = sg_dma_address(sg) + + umem->page_size * j; + + ret = pvrdma_page_dir_insert_dma(pdir, i, addr); + if (ret) + goto exit; + + i++; + } + } + +exit: + return ret; +} + +int pvrdma_page_dir_insert_page_list(struct pvrdma_page_dir *pdir, + u64 *page_list, + int num_pages) +{ + int i; + int ret; + + if (num_pages > pdir->npages) + return -EINVAL; + + for (i = 0; i < num_pages; i++) { + ret = pvrdma_page_dir_insert_dma(pdir, i, page_list[i]); + if (ret) + return ret; + } + + return 0; +} + +void pvrdma_qp_cap_to_ib(struct ib_qp_cap *dst, const struct pvrdma_qp_cap *src) +{ + dst->max_send_wr = src->max_send_wr; + dst->max_recv_wr = src->max_recv_wr; + dst->max_send_sge = src->max_send_sge; + dst->max_recv_sge = src->max_recv_sge; + dst->max_inline_data = src->max_inline_data; +} + +void ib_qp_cap_to_pvrdma(struct pvrdma_qp_cap *dst, const struct ib_qp_cap *src) +{ + dst->max_send_wr = src->max_send_wr; + dst->max_recv_wr = src->max_recv_wr; + dst->max_send_sge = src->max_send_sge; + dst->max_recv_sge = src->max_recv_sge; + dst->max_inline_data = src->max_inline_data; +} + +void pvrdma_gid_to_ib(union ib_gid *dst, const union pvrdma_gid *src) +{ + BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); + memcpy(dst, src, sizeof(*src)); +} + +void ib_gid_to_pvrdma(union pvrdma_gid *dst, const union ib_gid *src) +{ + BUILD_BUG_ON(sizeof(union pvrdma_gid) != sizeof(union ib_gid)); + memcpy(dst, src, sizeof(*src)); +} + +void pvrdma_global_route_to_ib(struct ib_global_route *dst, + const struct pvrdma_global_route *src) +{ + pvrdma_gid_to_ib(&dst->dgid, &src->dgid); + dst->flow_label = src->flow_label; + dst->sgid_index = src->sgid_index; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; +} + +void ib_global_route_to_pvrdma(struct pvrdma_global_route *dst, + const struct ib_global_route *src) +{ + ib_gid_to_pvrdma(&dst->dgid, &src->dgid); + dst->flow_label = src->flow_label; + dst->sgid_index = src->sgid_index; + dst->hop_limit = src->hop_limit; + dst->traffic_class = src->traffic_class; +} + +void pvrdma_ah_attr_to_ib(struct ib_ah_attr *dst, + const struct pvrdma_ah_attr *src) +{ + pvrdma_global_route_to_ib(&dst->grh, &src->grh); + dst->dlid = src->dlid; + dst->sl = src->sl; + dst->src_path_bits = src->src_path_bits; + dst->static_rate = src->static_rate; + dst->ah_flags = src->ah_flags; + dst->port_num = src->port_num; + memcpy(&dst->dmac, &src->dmac, sizeof(dst->dmac)); +} + +void ib_ah_attr_to_pvrdma(struct pvrdma_ah_attr *dst, + const struct ib_ah_attr *src) +{ + ib_global_route_to_pvrdma(&dst->grh, &src->grh); + dst->dlid = src->dlid; + dst->sl = src->sl; + dst->src_path_bits = src->src_path_bits; + dst->static_rate = src->static_rate; + dst->ah_flags = src->ah_flags; + dst->port_num = src->port_num; + memcpy(&dst->dmac, &src->dmac, sizeof(dst->dmac)); +} diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c new file mode 100644 index 000000000000..8519f3212e52 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_mr.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include "pvrdma.h" + +/** + * pvrdma_get_dma_mr - get a DMA memory region + * @pd: protection domain + * @acc: access flags + * + * @return: ib_mr pointer on success, otherwise returns an errno. + */ +struct ib_mr *pvrdma_get_dma_mr(struct ib_pd *pd, int acc) +{ + struct pvrdma_dev *dev = to_vdev(pd->device); + struct pvrdma_user_mr *mr; + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_mr *cmd = &req.create_mr; + struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp; + int ret; + + /* Support only LOCAL_WRITE flag for DMA MRs */ + if (acc & ~IB_ACCESS_LOCAL_WRITE) { + dev_warn(&dev->pdev->dev, + "unsupported dma mr access flags %#x\n", acc); + return ERR_PTR(-EOPNOTSUPP); + } + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR; + cmd->pd_handle = to_vpd(pd)->pd_handle; + cmd->access_flags = acc; + cmd->flags = PVRDMA_MR_FLAG_DMA; + + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not get DMA mem region, error: %d\n", ret); + kfree(mr); + return ERR_PTR(ret); + } + + mr->mmr.mr_handle = resp->mr_handle; + mr->ibmr.lkey = resp->lkey; + mr->ibmr.rkey = resp->rkey; + + return &mr->ibmr; +} + +/** + * pvrdma_reg_user_mr - register a userspace memory region + * @pd: protection domain + * @start: starting address + * @length: length of region + * @virt_addr: I/O virtual address + * @access_flags: access flags for memory region + * @udata: user data + * + * @return: ib_mr pointer on success, otherwise returns an errno. + */ +struct ib_mr *pvrdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int access_flags, + struct ib_udata *udata) +{ + struct pvrdma_dev *dev = to_vdev(pd->device); + struct pvrdma_user_mr *mr = NULL; + struct ib_umem *umem; + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_mr *cmd = &req.create_mr; + struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp; + int nchunks; + int ret; + int entry; + struct scatterlist *sg; + + if (length == 0 || length > dev->dsr->caps.max_mr_size) { + dev_warn(&dev->pdev->dev, "invalid mem region length\n"); + return ERR_PTR(-EINVAL); + } + + umem = ib_umem_get(pd->uobject->context, start, + length, access_flags, 0); + if (IS_ERR(umem)) { + dev_warn(&dev->pdev->dev, + "could not get umem for mem region\n"); + return ERR_CAST(umem); + } + + nchunks = 0; + for_each_sg(umem->sg_head.sgl, sg, umem->nmap, entry) + nchunks += sg_dma_len(sg) >> PAGE_SHIFT; + + if (nchunks < 0 || nchunks > PVRDMA_PAGE_DIR_MAX_PAGES) { + dev_warn(&dev->pdev->dev, "overflow %d pages in mem region\n", + nchunks); + ret = -EINVAL; + goto err_umem; + } + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) { + ret = -ENOMEM; + goto err_umem; + } + + mr->mmr.iova = virt_addr; + mr->mmr.size = length; + mr->umem = umem; + + ret = pvrdma_page_dir_init(dev, &mr->pdir, nchunks, false); + if (ret) { + dev_warn(&dev->pdev->dev, + "could not allocate page directory\n"); + goto err_umem; + } + + ret = pvrdma_page_dir_insert_umem(&mr->pdir, mr->umem, 0); + if (ret) + goto err_pdir; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR; + cmd->start = start; + cmd->length = length; + cmd->pd_handle = to_vpd(pd)->pd_handle; + cmd->access_flags = access_flags; + cmd->nchunks = nchunks; + cmd->pdir_dma = mr->pdir.dir_dma; + + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not register mem region, error: %d\n", ret); + goto err_pdir; + } + + mr->mmr.mr_handle = resp->mr_handle; + mr->ibmr.lkey = resp->lkey; + mr->ibmr.rkey = resp->rkey; + + return &mr->ibmr; + +err_pdir: + pvrdma_page_dir_cleanup(dev, &mr->pdir); +err_umem: + ib_umem_release(umem); + kfree(mr); + + return ERR_PTR(ret); +} + +/** + * pvrdma_alloc_mr - allocate a memory region + * @pd: protection domain + * @mr_type: type of memory region + * @max_num_sg: maximum number of pages + * + * @return: ib_mr pointer on success, otherwise returns an errno. + */ +struct ib_mr *pvrdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, + u32 max_num_sg) +{ + struct pvrdma_dev *dev = to_vdev(pd->device); + struct pvrdma_user_mr *mr; + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_mr *cmd = &req.create_mr; + struct pvrdma_cmd_create_mr_resp *resp = &rsp.create_mr_resp; + int size = max_num_sg * sizeof(u64); + int ret; + + if (mr_type != IB_MR_TYPE_MEM_REG || + max_num_sg > PVRDMA_MAX_FAST_REG_PAGES) + return ERR_PTR(-EINVAL); + + mr = kzalloc(sizeof(*mr), GFP_KERNEL); + if (!mr) + return ERR_PTR(-ENOMEM); + + mr->pages = kzalloc(size, GFP_KERNEL); + if (!mr->pages) { + ret = -ENOMEM; + goto freemr; + } + + ret = pvrdma_page_dir_init(dev, &mr->pdir, max_num_sg, false); + if (ret) { + dev_warn(&dev->pdev->dev, + "failed to allocate page dir for mr\n"); + ret = -ENOMEM; + goto freepages; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_CREATE_MR; + cmd->pd_handle = to_vpd(pd)->pd_handle; + cmd->access_flags = 0; + cmd->flags = PVRDMA_MR_FLAG_FRMR; + cmd->nchunks = max_num_sg; + + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_MR_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not create FR mem region, error: %d\n", ret); + goto freepdir; + } + + mr->max_pages = max_num_sg; + mr->mmr.mr_handle = resp->mr_handle; + mr->ibmr.lkey = resp->lkey; + mr->ibmr.rkey = resp->rkey; + mr->page_shift = PAGE_SHIFT; + mr->umem = NULL; + + return &mr->ibmr; + +freepdir: + pvrdma_page_dir_cleanup(dev, &mr->pdir); +freepages: + kfree(mr->pages); +freemr: + kfree(mr); + return ERR_PTR(ret); +} + +/** + * pvrdma_dereg_mr - deregister a memory region + * @ibmr: memory region + * + * @return: 0 on success. + */ +int pvrdma_dereg_mr(struct ib_mr *ibmr) +{ + struct pvrdma_user_mr *mr = to_vmr(ibmr); + struct pvrdma_dev *dev = to_vdev(ibmr->device); + union pvrdma_cmd_req req; + struct pvrdma_cmd_destroy_mr *cmd = &req.destroy_mr; + int ret; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_MR; + cmd->mr_handle = mr->mmr.mr_handle; + ret = pvrdma_cmd_post(dev, &req, NULL, 0); + if (ret < 0) + dev_warn(&dev->pdev->dev, + "could not deregister mem region, error: %d\n", ret); + + pvrdma_page_dir_cleanup(dev, &mr->pdir); + if (mr->umem) + ib_umem_release(mr->umem); + + kfree(mr->pages); + kfree(mr); + + return 0; +} + +static int pvrdma_set_page(struct ib_mr *ibmr, u64 addr) +{ + struct pvrdma_user_mr *mr = to_vmr(ibmr); + + if (mr->npages == mr->max_pages) + return -ENOMEM; + + mr->pages[mr->npages++] = addr; + return 0; +} + +int pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, int sg_nents, + unsigned int *sg_offset) +{ + struct pvrdma_user_mr *mr = to_vmr(ibmr); + struct pvrdma_dev *dev = to_vdev(ibmr->device); + int ret; + + mr->npages = 0; + + ret = ib_sg_to_pages(ibmr, sg, sg_nents, sg_offset, pvrdma_set_page); + if (ret < 0) + dev_warn(&dev->pdev->dev, "could not map sg to pages\n"); + + return ret; +} diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c new file mode 100644 index 000000000000..c8c01e558125 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_qp.c @@ -0,0 +1,972 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "pvrdma.h" + +static inline void get_cqs(struct pvrdma_qp *qp, struct pvrdma_cq **send_cq, + struct pvrdma_cq **recv_cq) +{ + *send_cq = to_vcq(qp->ibqp.send_cq); + *recv_cq = to_vcq(qp->ibqp.recv_cq); +} + +static void pvrdma_lock_cqs(struct pvrdma_cq *scq, struct pvrdma_cq *rcq, + unsigned long *scq_flags, + unsigned long *rcq_flags) + __acquires(scq->cq_lock) __acquires(rcq->cq_lock) +{ + if (scq == rcq) { + spin_lock_irqsave(&scq->cq_lock, *scq_flags); + __acquire(rcq->cq_lock); + } else if (scq->cq_handle < rcq->cq_handle) { + spin_lock_irqsave(&scq->cq_lock, *scq_flags); + spin_lock_irqsave_nested(&rcq->cq_lock, *rcq_flags, + SINGLE_DEPTH_NESTING); + } else { + spin_lock_irqsave(&rcq->cq_lock, *rcq_flags); + spin_lock_irqsave_nested(&scq->cq_lock, *scq_flags, + SINGLE_DEPTH_NESTING); + } +} + +static void pvrdma_unlock_cqs(struct pvrdma_cq *scq, struct pvrdma_cq *rcq, + unsigned long *scq_flags, + unsigned long *rcq_flags) + __releases(scq->cq_lock) __releases(rcq->cq_lock) +{ + if (scq == rcq) { + __release(rcq->cq_lock); + spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); + } else if (scq->cq_handle < rcq->cq_handle) { + spin_unlock_irqrestore(&rcq->cq_lock, *rcq_flags); + spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); + } else { + spin_unlock_irqrestore(&scq->cq_lock, *scq_flags); + spin_unlock_irqrestore(&rcq->cq_lock, *rcq_flags); + } +} + +static void pvrdma_reset_qp(struct pvrdma_qp *qp) +{ + struct pvrdma_cq *scq, *rcq; + unsigned long scq_flags, rcq_flags; + + /* Clean up cqes */ + get_cqs(qp, &scq, &rcq); + pvrdma_lock_cqs(scq, rcq, &scq_flags, &rcq_flags); + + _pvrdma_flush_cqe(qp, scq); + if (scq != rcq) + _pvrdma_flush_cqe(qp, rcq); + + pvrdma_unlock_cqs(scq, rcq, &scq_flags, &rcq_flags); + + /* + * Reset queuepair. The checks are because usermode queuepairs won't + * have kernel ringstates. + */ + if (qp->rq.ring) { + atomic_set(&qp->rq.ring->cons_head, 0); + atomic_set(&qp->rq.ring->prod_tail, 0); + } + if (qp->sq.ring) { + atomic_set(&qp->sq.ring->cons_head, 0); + atomic_set(&qp->sq.ring->prod_tail, 0); + } +} + +static int pvrdma_set_rq_size(struct pvrdma_dev *dev, + struct ib_qp_cap *req_cap, + struct pvrdma_qp *qp) +{ + if (req_cap->max_recv_wr > dev->dsr->caps.max_qp_wr || + req_cap->max_recv_sge > dev->dsr->caps.max_sge) { + dev_warn(&dev->pdev->dev, "recv queue size invalid\n"); + return -EINVAL; + } + + qp->rq.wqe_cnt = roundup_pow_of_two(max(1U, req_cap->max_recv_wr)); + qp->rq.max_sg = roundup_pow_of_two(max(1U, req_cap->max_recv_sge)); + + /* Write back */ + req_cap->max_recv_wr = qp->rq.wqe_cnt; + req_cap->max_recv_sge = qp->rq.max_sg; + + qp->rq.wqe_size = roundup_pow_of_two(sizeof(struct pvrdma_rq_wqe_hdr) + + sizeof(struct pvrdma_sge) * + qp->rq.max_sg); + qp->npages_recv = (qp->rq.wqe_cnt * qp->rq.wqe_size + PAGE_SIZE - 1) / + PAGE_SIZE; + + return 0; +} + +static int pvrdma_set_sq_size(struct pvrdma_dev *dev, struct ib_qp_cap *req_cap, + enum ib_qp_type type, struct pvrdma_qp *qp) +{ + if (req_cap->max_send_wr > dev->dsr->caps.max_qp_wr || + req_cap->max_send_sge > dev->dsr->caps.max_sge) { + dev_warn(&dev->pdev->dev, "send queue size invalid\n"); + return -EINVAL; + } + + qp->sq.wqe_cnt = roundup_pow_of_two(max(1U, req_cap->max_send_wr)); + qp->sq.max_sg = roundup_pow_of_two(max(1U, req_cap->max_send_sge)); + + /* Write back */ + req_cap->max_send_wr = qp->sq.wqe_cnt; + req_cap->max_send_sge = qp->sq.max_sg; + + qp->sq.wqe_size = roundup_pow_of_two(sizeof(struct pvrdma_sq_wqe_hdr) + + sizeof(struct pvrdma_sge) * + qp->sq.max_sg); + /* Note: one extra page for the header. */ + qp->npages_send = 1 + (qp->sq.wqe_cnt * qp->sq.wqe_size + + PAGE_SIZE - 1) / PAGE_SIZE; + + return 0; +} + +/** + * pvrdma_create_qp - create queue pair + * @pd: protection domain + * @init_attr: queue pair attributes + * @udata: user data + * + * @return: the ib_qp pointer on success, otherwise returns an errno. + */ +struct ib_qp *pvrdma_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata) +{ + struct pvrdma_qp *qp = NULL; + struct pvrdma_dev *dev = to_vdev(pd->device); + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_qp *cmd = &req.create_qp; + struct pvrdma_cmd_create_qp_resp *resp = &rsp.create_qp_resp; + struct pvrdma_create_qp ucmd; + unsigned long flags; + int ret; + + if (init_attr->create_flags) { + dev_warn(&dev->pdev->dev, + "invalid create queuepair flags %#x\n", + init_attr->create_flags); + return ERR_PTR(-EINVAL); + } + + if (init_attr->qp_type != IB_QPT_RC && + init_attr->qp_type != IB_QPT_UD && + init_attr->qp_type != IB_QPT_GSI) { + dev_warn(&dev->pdev->dev, "queuepair type %d not supported\n", + init_attr->qp_type); + return ERR_PTR(-EINVAL); + } + + if (!atomic_add_unless(&dev->num_qps, 1, dev->dsr->caps.max_qp)) + return ERR_PTR(-ENOMEM); + + switch (init_attr->qp_type) { + case IB_QPT_GSI: + if (init_attr->port_num == 0 || + init_attr->port_num > pd->device->phys_port_cnt || + udata) { + dev_warn(&dev->pdev->dev, "invalid queuepair attrs\n"); + ret = -EINVAL; + goto err_qp; + } + /* fall through */ + case IB_QPT_RC: + case IB_QPT_UD: + qp = kzalloc(sizeof(*qp), GFP_KERNEL); + if (!qp) { + ret = -ENOMEM; + goto err_qp; + } + + spin_lock_init(&qp->sq.lock); + spin_lock_init(&qp->rq.lock); + mutex_init(&qp->mutex); + atomic_set(&qp->refcnt, 1); + init_waitqueue_head(&qp->wait); + + qp->state = IB_QPS_RESET; + + if (pd->uobject && udata) { + dev_dbg(&dev->pdev->dev, + "create queuepair from user space\n"); + + if (ib_copy_from_udata(&ucmd, udata, sizeof(ucmd))) { + ret = -EFAULT; + goto err_qp; + } + + /* set qp->sq.wqe_cnt, shift, buf_size.. */ + qp->rumem = ib_umem_get(pd->uobject->context, + ucmd.rbuf_addr, + ucmd.rbuf_size, 0, 0); + if (IS_ERR(qp->rumem)) { + ret = PTR_ERR(qp->rumem); + goto err_qp; + } + + qp->sumem = ib_umem_get(pd->uobject->context, + ucmd.sbuf_addr, + ucmd.sbuf_size, 0, 0); + if (IS_ERR(qp->sumem)) { + ib_umem_release(qp->rumem); + ret = PTR_ERR(qp->sumem); + goto err_qp; + } + + qp->npages_send = ib_umem_page_count(qp->sumem); + qp->npages_recv = ib_umem_page_count(qp->rumem); + qp->npages = qp->npages_send + qp->npages_recv; + } else { + qp->is_kernel = true; + + ret = pvrdma_set_sq_size(to_vdev(pd->device), + &init_attr->cap, + init_attr->qp_type, qp); + if (ret) + goto err_qp; + + ret = pvrdma_set_rq_size(to_vdev(pd->device), + &init_attr->cap, qp); + if (ret) + goto err_qp; + + qp->npages = qp->npages_send + qp->npages_recv; + + /* Skip header page. */ + qp->sq.offset = PAGE_SIZE; + + /* Recv queue pages are after send pages. */ + qp->rq.offset = qp->npages_send * PAGE_SIZE; + } + + if (qp->npages < 0 || qp->npages > PVRDMA_PAGE_DIR_MAX_PAGES) { + dev_warn(&dev->pdev->dev, + "overflow pages in queuepair\n"); + ret = -EINVAL; + goto err_umem; + } + + ret = pvrdma_page_dir_init(dev, &qp->pdir, qp->npages, + qp->is_kernel); + if (ret) { + dev_warn(&dev->pdev->dev, + "could not allocate page directory\n"); + goto err_umem; + } + + if (!qp->is_kernel) { + pvrdma_page_dir_insert_umem(&qp->pdir, qp->sumem, 0); + pvrdma_page_dir_insert_umem(&qp->pdir, qp->rumem, + qp->npages_send); + } else { + /* Ring state is always the first page. */ + qp->sq.ring = qp->pdir.pages[0]; + qp->rq.ring = &qp->sq.ring[1]; + } + break; + default: + ret = -EINVAL; + goto err_qp; + } + + /* Not supported */ + init_attr->cap.max_inline_data = 0; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_CREATE_QP; + cmd->pd_handle = to_vpd(pd)->pd_handle; + cmd->send_cq_handle = to_vcq(init_attr->send_cq)->cq_handle; + cmd->recv_cq_handle = to_vcq(init_attr->recv_cq)->cq_handle; + cmd->max_send_wr = init_attr->cap.max_send_wr; + cmd->max_recv_wr = init_attr->cap.max_recv_wr; + cmd->max_send_sge = init_attr->cap.max_send_sge; + cmd->max_recv_sge = init_attr->cap.max_recv_sge; + cmd->max_inline_data = init_attr->cap.max_inline_data; + cmd->sq_sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR) ? 1 : 0; + cmd->qp_type = ib_qp_type_to_pvrdma(init_attr->qp_type); + cmd->access_flags = IB_ACCESS_LOCAL_WRITE; + cmd->total_chunks = qp->npages; + cmd->send_chunks = qp->npages_send - 1; + cmd->pdir_dma = qp->pdir.dir_dma; + + dev_dbg(&dev->pdev->dev, "create queuepair with %d, %d, %d, %d\n", + cmd->max_send_wr, cmd->max_recv_wr, cmd->max_send_sge, + cmd->max_recv_sge); + + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_QP_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not create queuepair, error: %d\n", ret); + goto err_pdir; + } + + /* max_send_wr/_recv_wr/_send_sge/_recv_sge/_inline_data */ + qp->qp_handle = resp->qpn; + qp->port = init_attr->port_num; + qp->ibqp.qp_num = resp->qpn; + spin_lock_irqsave(&dev->qp_tbl_lock, flags); + dev->qp_tbl[qp->qp_handle % dev->dsr->caps.max_qp] = qp; + spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); + + return &qp->ibqp; + +err_pdir: + pvrdma_page_dir_cleanup(dev, &qp->pdir); +err_umem: + if (pd->uobject && udata) { + if (qp->rumem) + ib_umem_release(qp->rumem); + if (qp->sumem) + ib_umem_release(qp->sumem); + } +err_qp: + kfree(qp); + atomic_dec(&dev->num_qps); + + return ERR_PTR(ret); +} + +static void pvrdma_free_qp(struct pvrdma_qp *qp) +{ + struct pvrdma_dev *dev = to_vdev(qp->ibqp.device); + struct pvrdma_cq *scq; + struct pvrdma_cq *rcq; + unsigned long flags, scq_flags, rcq_flags; + + /* In case cq is polling */ + get_cqs(qp, &scq, &rcq); + pvrdma_lock_cqs(scq, rcq, &scq_flags, &rcq_flags); + + _pvrdma_flush_cqe(qp, scq); + if (scq != rcq) + _pvrdma_flush_cqe(qp, rcq); + + spin_lock_irqsave(&dev->qp_tbl_lock, flags); + dev->qp_tbl[qp->qp_handle] = NULL; + spin_unlock_irqrestore(&dev->qp_tbl_lock, flags); + + pvrdma_unlock_cqs(scq, rcq, &scq_flags, &rcq_flags); + + atomic_dec(&qp->refcnt); + wait_event(qp->wait, !atomic_read(&qp->refcnt)); + + pvrdma_page_dir_cleanup(dev, &qp->pdir); + + kfree(qp); + + atomic_dec(&dev->num_qps); +} + +/** + * pvrdma_destroy_qp - destroy a queue pair + * @qp: the queue pair to destroy + * + * @return: 0 on success. + */ +int pvrdma_destroy_qp(struct ib_qp *qp) +{ + struct pvrdma_qp *vqp = to_vqp(qp); + union pvrdma_cmd_req req; + struct pvrdma_cmd_destroy_qp *cmd = &req.destroy_qp; + int ret; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_QP; + cmd->qp_handle = vqp->qp_handle; + + ret = pvrdma_cmd_post(to_vdev(qp->device), &req, NULL, 0); + if (ret < 0) + dev_warn(&to_vdev(qp->device)->pdev->dev, + "destroy queuepair failed, error: %d\n", ret); + + pvrdma_free_qp(vqp); + + return 0; +} + +/** + * pvrdma_modify_qp - modify queue pair attributes + * @ibqp: the queue pair + * @attr: the new queue pair's attributes + * @attr_mask: attributes mask + * @udata: user data + * + * @returns 0 on success, otherwise returns an errno. + */ +int pvrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata) +{ + struct pvrdma_dev *dev = to_vdev(ibqp->device); + struct pvrdma_qp *qp = to_vqp(ibqp); + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_modify_qp *cmd = &req.modify_qp; + int cur_state, next_state; + int ret; + + /* Sanity checking. Should need lock here */ + mutex_lock(&qp->mutex); + cur_state = (attr_mask & IB_QP_CUR_STATE) ? attr->cur_qp_state : + qp->state; + next_state = (attr_mask & IB_QP_STATE) ? attr->qp_state : cur_state; + + if (!ib_modify_qp_is_ok(cur_state, next_state, ibqp->qp_type, + attr_mask, IB_LINK_LAYER_ETHERNET)) { + ret = -EINVAL; + goto out; + } + + if (attr_mask & IB_QP_PORT) { + if (attr->port_num == 0 || + attr->port_num > ibqp->device->phys_port_cnt) { + ret = -EINVAL; + goto out; + } + } + + if (attr_mask & IB_QP_MIN_RNR_TIMER) { + if (attr->min_rnr_timer > 31) { + ret = -EINVAL; + goto out; + } + } + + if (attr_mask & IB_QP_PKEY_INDEX) { + if (attr->pkey_index >= dev->dsr->caps.max_pkeys) { + ret = -EINVAL; + goto out; + } + } + + if (attr_mask & IB_QP_QKEY) + qp->qkey = attr->qkey; + + if (cur_state == next_state && cur_state == IB_QPS_RESET) { + ret = 0; + goto out; + } + + qp->state = next_state; + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_MODIFY_QP; + cmd->qp_handle = qp->qp_handle; + cmd->attr_mask = ib_qp_attr_mask_to_pvrdma(attr_mask); + cmd->attrs.qp_state = ib_qp_state_to_pvrdma(attr->qp_state); + cmd->attrs.cur_qp_state = + ib_qp_state_to_pvrdma(attr->cur_qp_state); + cmd->attrs.path_mtu = ib_mtu_to_pvrdma(attr->path_mtu); + cmd->attrs.path_mig_state = + ib_mig_state_to_pvrdma(attr->path_mig_state); + cmd->attrs.qkey = attr->qkey; + cmd->attrs.rq_psn = attr->rq_psn; + cmd->attrs.sq_psn = attr->sq_psn; + cmd->attrs.dest_qp_num = attr->dest_qp_num; + cmd->attrs.qp_access_flags = + ib_access_flags_to_pvrdma(attr->qp_access_flags); + cmd->attrs.pkey_index = attr->pkey_index; + cmd->attrs.alt_pkey_index = attr->alt_pkey_index; + cmd->attrs.en_sqd_async_notify = attr->en_sqd_async_notify; + cmd->attrs.sq_draining = attr->sq_draining; + cmd->attrs.max_rd_atomic = attr->max_rd_atomic; + cmd->attrs.max_dest_rd_atomic = attr->max_dest_rd_atomic; + cmd->attrs.min_rnr_timer = attr->min_rnr_timer; + cmd->attrs.port_num = attr->port_num; + cmd->attrs.timeout = attr->timeout; + cmd->attrs.retry_cnt = attr->retry_cnt; + cmd->attrs.rnr_retry = attr->rnr_retry; + cmd->attrs.alt_port_num = attr->alt_port_num; + cmd->attrs.alt_timeout = attr->alt_timeout; + ib_qp_cap_to_pvrdma(&cmd->attrs.cap, &attr->cap); + ib_ah_attr_to_pvrdma(&cmd->attrs.ah_attr, &attr->ah_attr); + ib_ah_attr_to_pvrdma(&cmd->attrs.alt_ah_attr, &attr->alt_ah_attr); + + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_MODIFY_QP_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not modify queuepair, error: %d\n", ret); + } else if (rsp.hdr.err > 0) { + dev_warn(&dev->pdev->dev, + "cannot modify queuepair, error: %d\n", rsp.hdr.err); + ret = -EINVAL; + } + + if (ret == 0 && next_state == IB_QPS_RESET) + pvrdma_reset_qp(qp); + +out: + mutex_unlock(&qp->mutex); + + return ret; +} + +static inline void *get_sq_wqe(struct pvrdma_qp *qp, int n) +{ + return pvrdma_page_dir_get_ptr(&qp->pdir, + qp->sq.offset + n * qp->sq.wqe_size); +} + +static inline void *get_rq_wqe(struct pvrdma_qp *qp, int n) +{ + return pvrdma_page_dir_get_ptr(&qp->pdir, + qp->rq.offset + n * qp->rq.wqe_size); +} + +static int set_reg_seg(struct pvrdma_sq_wqe_hdr *wqe_hdr, struct ib_reg_wr *wr) +{ + struct pvrdma_user_mr *mr = to_vmr(wr->mr); + + wqe_hdr->wr.fast_reg.iova_start = mr->ibmr.iova; + wqe_hdr->wr.fast_reg.pl_pdir_dma = mr->pdir.dir_dma; + wqe_hdr->wr.fast_reg.page_shift = mr->page_shift; + wqe_hdr->wr.fast_reg.page_list_len = mr->npages; + wqe_hdr->wr.fast_reg.length = mr->ibmr.length; + wqe_hdr->wr.fast_reg.access_flags = wr->access; + wqe_hdr->wr.fast_reg.rkey = wr->key; + + return pvrdma_page_dir_insert_page_list(&mr->pdir, mr->pages, + mr->npages); +} + +/** + * pvrdma_post_send - post send work request entries on a QP + * @ibqp: the QP + * @wr: work request list to post + * @bad_wr: the first bad WR returned + * + * @return: 0 on success, otherwise errno returned. + */ +int pvrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr) +{ + struct pvrdma_qp *qp = to_vqp(ibqp); + struct pvrdma_dev *dev = to_vdev(ibqp->device); + unsigned long flags; + struct pvrdma_sq_wqe_hdr *wqe_hdr; + struct pvrdma_sge *sge; + int i, index; + int nreq; + int ret; + + /* + * In states lower than RTS, we can fail immediately. In other states, + * just post and let the device figure it out. + */ + if (qp->state < IB_QPS_RTS) { + *bad_wr = wr; + return -EINVAL; + } + + spin_lock_irqsave(&qp->sq.lock, flags); + + index = pvrdma_idx(&qp->sq.ring->prod_tail, qp->sq.wqe_cnt); + for (nreq = 0; wr; nreq++, wr = wr->next) { + unsigned int tail; + + if (unlikely(!pvrdma_idx_ring_has_space( + qp->sq.ring, qp->sq.wqe_cnt, &tail))) { + dev_warn_ratelimited(&dev->pdev->dev, + "send queue is full\n"); + *bad_wr = wr; + ret = -ENOMEM; + goto out; + } + + if (unlikely(wr->num_sge > qp->sq.max_sg || wr->num_sge < 0)) { + dev_warn_ratelimited(&dev->pdev->dev, + "send SGE overflow\n"); + *bad_wr = wr; + ret = -EINVAL; + goto out; + } + + if (unlikely(wr->opcode < 0)) { + dev_warn_ratelimited(&dev->pdev->dev, + "invalid send opcode\n"); + *bad_wr = wr; + ret = -EINVAL; + goto out; + } + + /* + * Only support UD, RC. + * Need to check opcode table for thorough checking. + * opcode _UD _UC _RC + * _SEND x x x + * _SEND_WITH_IMM x x x + * _RDMA_WRITE x x + * _RDMA_WRITE_WITH_IMM x x + * _LOCAL_INV x x + * _SEND_WITH_INV x x + * _RDMA_READ x + * _ATOMIC_CMP_AND_SWP x + * _ATOMIC_FETCH_AND_ADD x + * _MASK_ATOMIC_CMP_AND_SWP x + * _MASK_ATOMIC_FETCH_AND_ADD x + * _REG_MR x + * + */ + if (qp->ibqp.qp_type != IB_QPT_UD && + qp->ibqp.qp_type != IB_QPT_RC && + wr->opcode != IB_WR_SEND) { + dev_warn_ratelimited(&dev->pdev->dev, + "unsupported queuepair type\n"); + *bad_wr = wr; + ret = -EINVAL; + goto out; + } else if (qp->ibqp.qp_type == IB_QPT_UD || + qp->ibqp.qp_type == IB_QPT_GSI) { + if (wr->opcode != IB_WR_SEND && + wr->opcode != IB_WR_SEND_WITH_IMM) { + dev_warn_ratelimited(&dev->pdev->dev, + "invalid send opcode\n"); + *bad_wr = wr; + ret = -EINVAL; + goto out; + } + } + + wqe_hdr = (struct pvrdma_sq_wqe_hdr *)get_sq_wqe(qp, index); + memset(wqe_hdr, 0, sizeof(*wqe_hdr)); + wqe_hdr->wr_id = wr->wr_id; + wqe_hdr->num_sge = wr->num_sge; + wqe_hdr->opcode = ib_wr_opcode_to_pvrdma(wr->opcode); + wqe_hdr->send_flags = ib_send_flags_to_pvrdma(wr->send_flags); + if (wr->opcode == IB_WR_SEND_WITH_IMM || + wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM) + wqe_hdr->ex.imm_data = wr->ex.imm_data; + + switch (qp->ibqp.qp_type) { + case IB_QPT_GSI: + case IB_QPT_UD: + if (unlikely(!ud_wr(wr)->ah)) { + dev_warn_ratelimited(&dev->pdev->dev, + "invalid address handle\n"); + *bad_wr = wr; + ret = -EINVAL; + goto out; + } + + /* + * Use qkey from qp context if high order bit set, + * otherwise from work request. + */ + wqe_hdr->wr.ud.remote_qpn = ud_wr(wr)->remote_qpn; + wqe_hdr->wr.ud.remote_qkey = + ud_wr(wr)->remote_qkey & 0x80000000 ? + qp->qkey : ud_wr(wr)->remote_qkey; + wqe_hdr->wr.ud.av = to_vah(ud_wr(wr)->ah)->av; + + break; + case IB_QPT_RC: + switch (wr->opcode) { + case IB_WR_RDMA_READ: + case IB_WR_RDMA_WRITE: + case IB_WR_RDMA_WRITE_WITH_IMM: + wqe_hdr->wr.rdma.remote_addr = + rdma_wr(wr)->remote_addr; + wqe_hdr->wr.rdma.rkey = rdma_wr(wr)->rkey; + break; + case IB_WR_LOCAL_INV: + case IB_WR_SEND_WITH_INV: + wqe_hdr->ex.invalidate_rkey = + wr->ex.invalidate_rkey; + break; + case IB_WR_ATOMIC_CMP_AND_SWP: + case IB_WR_ATOMIC_FETCH_AND_ADD: + wqe_hdr->wr.atomic.remote_addr = + atomic_wr(wr)->remote_addr; + wqe_hdr->wr.atomic.rkey = atomic_wr(wr)->rkey; + wqe_hdr->wr.atomic.compare_add = + atomic_wr(wr)->compare_add; + if (wr->opcode == IB_WR_ATOMIC_CMP_AND_SWP) + wqe_hdr->wr.atomic.swap = + atomic_wr(wr)->swap; + break; + case IB_WR_REG_MR: + ret = set_reg_seg(wqe_hdr, reg_wr(wr)); + if (ret < 0) { + dev_warn_ratelimited(&dev->pdev->dev, + "Failed to set fast register work request\n"); + *bad_wr = wr; + goto out; + } + break; + default: + break; + } + + break; + default: + dev_warn_ratelimited(&dev->pdev->dev, + "invalid queuepair type\n"); + ret = -EINVAL; + *bad_wr = wr; + goto out; + } + + sge = (struct pvrdma_sge *)(wqe_hdr + 1); + for (i = 0; i < wr->num_sge; i++) { + /* Need to check wqe_size 0 or max size */ + sge->addr = wr->sg_list[i].addr; + sge->length = wr->sg_list[i].length; + sge->lkey = wr->sg_list[i].lkey; + sge++; + } + + /* Make sure wqe is written before index update */ + smp_wmb(); + + index++; + if (unlikely(index >= qp->sq.wqe_cnt)) + index = 0; + /* Update shared sq ring */ + pvrdma_idx_ring_inc(&qp->sq.ring->prod_tail, + qp->sq.wqe_cnt); + } + + ret = 0; + +out: + spin_unlock_irqrestore(&qp->sq.lock, flags); + + if (!ret) + pvrdma_write_uar_qp(dev, PVRDMA_UAR_QP_SEND | qp->qp_handle); + + return ret; +} + +/** + * pvrdma_post_receive - post receive work request entries on a QP + * @ibqp: the QP + * @wr: the work request list to post + * @bad_wr: the first bad WR returned + * + * @return: 0 on success, otherwise errno returned. + */ +int pvrdma_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr) +{ + struct pvrdma_dev *dev = to_vdev(ibqp->device); + unsigned long flags; + struct pvrdma_qp *qp = to_vqp(ibqp); + struct pvrdma_rq_wqe_hdr *wqe_hdr; + struct pvrdma_sge *sge; + int index, nreq; + int ret = 0; + int i; + + /* + * In the RESET state, we can fail immediately. For other states, + * just post and let the device figure it out. + */ + if (qp->state == IB_QPS_RESET) { + *bad_wr = wr; + return -EINVAL; + } + + spin_lock_irqsave(&qp->rq.lock, flags); + + index = pvrdma_idx(&qp->rq.ring->prod_tail, qp->rq.wqe_cnt); + for (nreq = 0; wr; nreq++, wr = wr->next) { + unsigned int tail; + + if (unlikely(wr->num_sge > qp->rq.max_sg || + wr->num_sge < 0)) { + ret = -EINVAL; + *bad_wr = wr; + dev_warn_ratelimited(&dev->pdev->dev, + "recv SGE overflow\n"); + goto out; + } + + if (unlikely(!pvrdma_idx_ring_has_space( + qp->rq.ring, qp->rq.wqe_cnt, &tail))) { + ret = -ENOMEM; + *bad_wr = wr; + dev_warn_ratelimited(&dev->pdev->dev, + "recv queue full\n"); + goto out; + } + + wqe_hdr = (struct pvrdma_rq_wqe_hdr *)get_rq_wqe(qp, index); + wqe_hdr->wr_id = wr->wr_id; + wqe_hdr->num_sge = wr->num_sge; + wqe_hdr->total_len = 0; + + sge = (struct pvrdma_sge *)(wqe_hdr + 1); + for (i = 0; i < wr->num_sge; i++) { + sge->addr = wr->sg_list[i].addr; + sge->length = wr->sg_list[i].length; + sge->lkey = wr->sg_list[i].lkey; + sge++; + } + + /* Make sure wqe is written before index update */ + smp_wmb(); + + index++; + if (unlikely(index >= qp->rq.wqe_cnt)) + index = 0; + /* Update shared rq ring */ + pvrdma_idx_ring_inc(&qp->rq.ring->prod_tail, + qp->rq.wqe_cnt); + } + + spin_unlock_irqrestore(&qp->rq.lock, flags); + + pvrdma_write_uar_qp(dev, PVRDMA_UAR_QP_RECV | qp->qp_handle); + + return ret; + +out: + spin_unlock_irqrestore(&qp->rq.lock, flags); + + return ret; +} + +/** + * pvrdma_query_qp - query a queue pair's attributes + * @ibqp: the queue pair to query + * @attr: the queue pair's attributes + * @attr_mask: attributes mask + * @init_attr: initial queue pair attributes + * + * @returns 0 on success, otherwise returns an errno. + */ +int pvrdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_qp_init_attr *init_attr) +{ + struct pvrdma_dev *dev = to_vdev(ibqp->device); + struct pvrdma_qp *qp = to_vqp(ibqp); + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_query_qp *cmd = &req.query_qp; + struct pvrdma_cmd_query_qp_resp *resp = &rsp.query_qp_resp; + int ret = 0; + + mutex_lock(&qp->mutex); + + if (qp->state == IB_QPS_RESET) { + attr->qp_state = IB_QPS_RESET; + goto out; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_QUERY_QP; + cmd->qp_handle = qp->qp_handle; + cmd->attr_mask = ib_qp_attr_mask_to_pvrdma(attr_mask); + + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_QUERY_QP_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "could not query queuepair, error: %d\n", ret); + goto out; + } + + attr->qp_state = pvrdma_qp_state_to_ib(resp->attrs.qp_state); + attr->cur_qp_state = + pvrdma_qp_state_to_ib(resp->attrs.cur_qp_state); + attr->path_mtu = pvrdma_mtu_to_ib(resp->attrs.path_mtu); + attr->path_mig_state = + pvrdma_mig_state_to_ib(resp->attrs.path_mig_state); + attr->qkey = resp->attrs.qkey; + attr->rq_psn = resp->attrs.rq_psn; + attr->sq_psn = resp->attrs.sq_psn; + attr->dest_qp_num = resp->attrs.dest_qp_num; + attr->qp_access_flags = + pvrdma_access_flags_to_ib(resp->attrs.qp_access_flags); + attr->pkey_index = resp->attrs.pkey_index; + attr->alt_pkey_index = resp->attrs.alt_pkey_index; + attr->en_sqd_async_notify = resp->attrs.en_sqd_async_notify; + attr->sq_draining = resp->attrs.sq_draining; + attr->max_rd_atomic = resp->attrs.max_rd_atomic; + attr->max_dest_rd_atomic = resp->attrs.max_dest_rd_atomic; + attr->min_rnr_timer = resp->attrs.min_rnr_timer; + attr->port_num = resp->attrs.port_num; + attr->timeout = resp->attrs.timeout; + attr->retry_cnt = resp->attrs.retry_cnt; + attr->rnr_retry = resp->attrs.rnr_retry; + attr->alt_port_num = resp->attrs.alt_port_num; + attr->alt_timeout = resp->attrs.alt_timeout; + pvrdma_qp_cap_to_ib(&attr->cap, &resp->attrs.cap); + pvrdma_ah_attr_to_ib(&attr->ah_attr, &resp->attrs.ah_attr); + pvrdma_ah_attr_to_ib(&attr->alt_ah_attr, &resp->attrs.alt_ah_attr); + + qp->state = attr->qp_state; + + ret = 0; + +out: + attr->cur_qp_state = attr->qp_state; + + init_attr->event_handler = qp->ibqp.event_handler; + init_attr->qp_context = qp->ibqp.qp_context; + init_attr->send_cq = qp->ibqp.send_cq; + init_attr->recv_cq = qp->ibqp.recv_cq; + init_attr->srq = qp->ibqp.srq; + init_attr->xrcd = NULL; + init_attr->cap = attr->cap; + init_attr->sq_sig_type = 0; + init_attr->qp_type = qp->ibqp.qp_type; + init_attr->create_flags = 0; + init_attr->port_num = qp->port; + + mutex_unlock(&qp->mutex); + return ret; +} diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h new file mode 100644 index 000000000000..ed9022a91a1d --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_ring.h @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PVRDMA_RING_H__ +#define __PVRDMA_RING_H__ + +#include + +#define PVRDMA_INVALID_IDX -1 /* Invalid index. */ + +struct pvrdma_ring { + atomic_t prod_tail; /* Producer tail. */ + atomic_t cons_head; /* Consumer head. */ +}; + +struct pvrdma_ring_state { + struct pvrdma_ring tx; /* Tx ring. */ + struct pvrdma_ring rx; /* Rx ring. */ +}; + +static inline int pvrdma_idx_valid(__u32 idx, __u32 max_elems) +{ + /* Generates fewer instructions than a less-than. */ + return (idx & ~((max_elems << 1) - 1)) == 0; +} + +static inline __s32 pvrdma_idx(atomic_t *var, __u32 max_elems) +{ + const unsigned int idx = atomic_read(var); + + if (pvrdma_idx_valid(idx, max_elems)) + return idx & (max_elems - 1); + return PVRDMA_INVALID_IDX; +} + +static inline void pvrdma_idx_ring_inc(atomic_t *var, __u32 max_elems) +{ + __u32 idx = atomic_read(var) + 1; /* Increment. */ + + idx &= (max_elems << 1) - 1; /* Modulo size, flip gen. */ + atomic_set(var, idx); +} + +static inline __s32 pvrdma_idx_ring_has_space(const struct pvrdma_ring *r, + __u32 max_elems, __u32 *out_tail) +{ + const __u32 tail = atomic_read(&r->prod_tail); + const __u32 head = atomic_read(&r->cons_head); + + if (pvrdma_idx_valid(tail, max_elems) && + pvrdma_idx_valid(head, max_elems)) { + *out_tail = tail & (max_elems - 1); + return tail != (head ^ max_elems); + } + return PVRDMA_INVALID_IDX; +} + +static inline __s32 pvrdma_idx_ring_has_data(const struct pvrdma_ring *r, + __u32 max_elems, __u32 *out_head) +{ + const __u32 tail = atomic_read(&r->prod_tail); + const __u32 head = atomic_read(&r->cons_head); + + if (pvrdma_idx_valid(tail, max_elems) && + pvrdma_idx_valid(head, max_elems)) { + *out_head = head & (max_elems - 1); + return tail != head; + } + return PVRDMA_INVALID_IDX; +} + +static inline bool pvrdma_idx_ring_is_valid_idx(const struct pvrdma_ring *r, + __u32 max_elems, __u32 *idx) +{ + const __u32 tail = atomic_read(&r->prod_tail); + const __u32 head = atomic_read(&r->cons_head); + + if (pvrdma_idx_valid(tail, max_elems) && + pvrdma_idx_valid(head, max_elems) && + pvrdma_idx_valid(*idx, max_elems)) { + if (tail > head && (*idx < tail && *idx >= head)) + return true; + else if (head > tail && (*idx >= head || *idx < tail)) + return true; + } + return false; +} + +#endif /* __PVRDMA_RING_H__ */ diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c new file mode 100644 index 000000000000..54891370d18a --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.c @@ -0,0 +1,579 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "pvrdma.h" + +/** + * pvrdma_query_device - query device + * @ibdev: the device to query + * @props: the device properties + * @uhw: user data + * + * @return: 0 on success, otherwise negative errno + */ +int pvrdma_query_device(struct ib_device *ibdev, + struct ib_device_attr *props, + struct ib_udata *uhw) +{ + struct pvrdma_dev *dev = to_vdev(ibdev); + + if (uhw->inlen || uhw->outlen) + return -EINVAL; + + memset(props, 0, sizeof(*props)); + + props->fw_ver = dev->dsr->caps.fw_ver; + props->sys_image_guid = dev->dsr->caps.sys_image_guid; + props->max_mr_size = dev->dsr->caps.max_mr_size; + props->page_size_cap = dev->dsr->caps.page_size_cap; + props->vendor_id = dev->dsr->caps.vendor_id; + props->vendor_part_id = dev->pdev->device; + props->hw_ver = dev->dsr->caps.hw_ver; + props->max_qp = dev->dsr->caps.max_qp; + props->max_qp_wr = dev->dsr->caps.max_qp_wr; + props->device_cap_flags = dev->dsr->caps.device_cap_flags; + props->max_sge = dev->dsr->caps.max_sge; + props->max_cq = dev->dsr->caps.max_cq; + props->max_cqe = dev->dsr->caps.max_cqe; + props->max_mr = dev->dsr->caps.max_mr; + props->max_pd = dev->dsr->caps.max_pd; + props->max_qp_rd_atom = dev->dsr->caps.max_qp_rd_atom; + props->max_qp_init_rd_atom = dev->dsr->caps.max_qp_init_rd_atom; + props->atomic_cap = + dev->dsr->caps.atomic_ops & + (PVRDMA_ATOMIC_OP_COMP_SWAP | PVRDMA_ATOMIC_OP_FETCH_ADD) ? + IB_ATOMIC_HCA : IB_ATOMIC_NONE; + props->masked_atomic_cap = props->atomic_cap; + props->max_ah = dev->dsr->caps.max_ah; + props->max_pkeys = dev->dsr->caps.max_pkeys; + props->local_ca_ack_delay = dev->dsr->caps.local_ca_ack_delay; + if ((dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_LOCAL_INV) && + (dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_REMOTE_INV) && + (dev->dsr->caps.bmme_flags & PVRDMA_BMME_FLAG_FAST_REG_WR)) { + props->device_cap_flags |= IB_DEVICE_MEM_MGT_EXTENSIONS; + } + + return 0; +} + +/** + * pvrdma_query_port - query device port attributes + * @ibdev: the device to query + * @port: the port number + * @props: the device properties + * + * @return: 0 on success, otherwise negative errno + */ +int pvrdma_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props) +{ + struct pvrdma_dev *dev = to_vdev(ibdev); + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_query_port *cmd = &req.query_port; + struct pvrdma_cmd_query_port_resp *resp = &rsp.query_port_resp; + int err; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_QUERY_PORT; + cmd->port_num = port; + + err = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_QUERY_PORT_RESP); + if (err < 0) { + dev_warn(&dev->pdev->dev, + "could not query port, error: %d\n", err); + return err; + } + + memset(props, 0, sizeof(*props)); + + props->state = pvrdma_port_state_to_ib(resp->attrs.state); + props->max_mtu = pvrdma_mtu_to_ib(resp->attrs.max_mtu); + props->active_mtu = pvrdma_mtu_to_ib(resp->attrs.active_mtu); + props->gid_tbl_len = resp->attrs.gid_tbl_len; + props->port_cap_flags = + pvrdma_port_cap_flags_to_ib(resp->attrs.port_cap_flags); + props->max_msg_sz = resp->attrs.max_msg_sz; + props->bad_pkey_cntr = resp->attrs.bad_pkey_cntr; + props->qkey_viol_cntr = resp->attrs.qkey_viol_cntr; + props->pkey_tbl_len = resp->attrs.pkey_tbl_len; + props->lid = resp->attrs.lid; + props->sm_lid = resp->attrs.sm_lid; + props->lmc = resp->attrs.lmc; + props->max_vl_num = resp->attrs.max_vl_num; + props->sm_sl = resp->attrs.sm_sl; + props->subnet_timeout = resp->attrs.subnet_timeout; + props->init_type_reply = resp->attrs.init_type_reply; + props->active_width = pvrdma_port_width_to_ib(resp->attrs.active_width); + props->active_speed = pvrdma_port_speed_to_ib(resp->attrs.active_speed); + props->phys_state = resp->attrs.phys_state; + + return 0; +} + +/** + * pvrdma_query_gid - query device gid + * @ibdev: the device to query + * @port: the port number + * @index: the index + * @gid: the device gid value + * + * @return: 0 on success, otherwise negative errno + */ +int pvrdma_query_gid(struct ib_device *ibdev, u8 port, int index, + union ib_gid *gid) +{ + struct pvrdma_dev *dev = to_vdev(ibdev); + + if (index >= dev->dsr->caps.gid_tbl_len) + return -EINVAL; + + memcpy(gid, &dev->sgid_tbl[index], sizeof(union ib_gid)); + + return 0; +} + +/** + * pvrdma_query_pkey - query device port's P_Key table + * @ibdev: the device to query + * @port: the port number + * @index: the index + * @pkey: the device P_Key value + * + * @return: 0 on success, otherwise negative errno + */ +int pvrdma_query_pkey(struct ib_device *ibdev, u8 port, u16 index, + u16 *pkey) +{ + int err = 0; + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_query_pkey *cmd = &req.query_pkey; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_QUERY_PKEY; + cmd->port_num = port; + cmd->index = index; + + err = pvrdma_cmd_post(to_vdev(ibdev), &req, &rsp, + PVRDMA_CMD_QUERY_PKEY_RESP); + if (err < 0) { + dev_warn(&to_vdev(ibdev)->pdev->dev, + "could not query pkey, error: %d\n", err); + return err; + } + + *pkey = rsp.query_pkey_resp.pkey; + + return 0; +} + +enum rdma_link_layer pvrdma_port_link_layer(struct ib_device *ibdev, + u8 port) +{ + return IB_LINK_LAYER_ETHERNET; +} + +int pvrdma_modify_device(struct ib_device *ibdev, int mask, + struct ib_device_modify *props) +{ + unsigned long flags; + + if (mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | + IB_DEVICE_MODIFY_NODE_DESC)) { + dev_warn(&to_vdev(ibdev)->pdev->dev, + "unsupported device modify mask %#x\n", mask); + return -EOPNOTSUPP; + } + + if (mask & IB_DEVICE_MODIFY_NODE_DESC) { + spin_lock_irqsave(&to_vdev(ibdev)->desc_lock, flags); + memcpy(ibdev->node_desc, props->node_desc, 64); + spin_unlock_irqrestore(&to_vdev(ibdev)->desc_lock, flags); + } + + if (mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) { + mutex_lock(&to_vdev(ibdev)->port_mutex); + to_vdev(ibdev)->sys_image_guid = + cpu_to_be64(props->sys_image_guid); + mutex_unlock(&to_vdev(ibdev)->port_mutex); + } + + return 0; +} + +/** + * pvrdma_modify_port - modify device port attributes + * @ibdev: the device to modify + * @port: the port number + * @mask: attributes to modify + * @props: the device properties + * + * @return: 0 on success, otherwise negative errno + */ +int pvrdma_modify_port(struct ib_device *ibdev, u8 port, int mask, + struct ib_port_modify *props) +{ + struct ib_port_attr attr; + struct pvrdma_dev *vdev = to_vdev(ibdev); + int ret; + + if (mask & ~IB_PORT_SHUTDOWN) { + dev_warn(&vdev->pdev->dev, + "unsupported port modify mask %#x\n", mask); + return -EOPNOTSUPP; + } + + mutex_lock(&vdev->port_mutex); + ret = pvrdma_query_port(ibdev, port, &attr); + if (ret) + goto out; + + vdev->port_cap_mask |= props->set_port_cap_mask; + vdev->port_cap_mask &= ~props->clr_port_cap_mask; + + if (mask & IB_PORT_SHUTDOWN) + vdev->ib_active = false; + +out: + mutex_unlock(&vdev->port_mutex); + return ret; +} + +/** + * pvrdma_alloc_ucontext - allocate ucontext + * @ibdev: the IB device + * @udata: user data + * + * @return: the ib_ucontext pointer on success, otherwise errno. + */ +struct ib_ucontext *pvrdma_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata) +{ + struct pvrdma_dev *vdev = to_vdev(ibdev); + struct pvrdma_ucontext *context; + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_uc *cmd = &req.create_uc; + struct pvrdma_cmd_create_uc_resp *resp = &rsp.create_uc_resp; + struct pvrdma_alloc_ucontext_resp uresp; + int ret; + void *ptr; + + if (!vdev->ib_active) + return ERR_PTR(-EAGAIN); + + context = kmalloc(sizeof(*context), GFP_KERNEL); + if (!context) + return ERR_PTR(-ENOMEM); + + context->dev = vdev; + ret = pvrdma_uar_alloc(vdev, &context->uar); + if (ret) { + kfree(context); + return ERR_PTR(-ENOMEM); + } + + /* get ctx_handle from host */ + memset(cmd, 0, sizeof(*cmd)); + cmd->pfn = context->uar.pfn; + cmd->hdr.cmd = PVRDMA_CMD_CREATE_UC; + ret = pvrdma_cmd_post(vdev, &req, &rsp, PVRDMA_CMD_CREATE_UC_RESP); + if (ret < 0) { + dev_warn(&vdev->pdev->dev, + "could not create ucontext, error: %d\n", ret); + ptr = ERR_PTR(ret); + goto err; + } + + context->ctx_handle = resp->ctx_handle; + + /* copy back to user */ + uresp.qp_tab_size = vdev->dsr->caps.max_qp; + ret = ib_copy_to_udata(udata, &uresp, sizeof(uresp)); + if (ret) { + pvrdma_uar_free(vdev, &context->uar); + context->ibucontext.device = ibdev; + pvrdma_dealloc_ucontext(&context->ibucontext); + return ERR_PTR(-EFAULT); + } + + return &context->ibucontext; + +err: + pvrdma_uar_free(vdev, &context->uar); + kfree(context); + return ptr; +} + +/** + * pvrdma_dealloc_ucontext - deallocate ucontext + * @ibcontext: the ucontext + * + * @return: 0 on success, otherwise errno. + */ +int pvrdma_dealloc_ucontext(struct ib_ucontext *ibcontext) +{ + struct pvrdma_ucontext *context = to_vucontext(ibcontext); + union pvrdma_cmd_req req; + struct pvrdma_cmd_destroy_uc *cmd = &req.destroy_uc; + int ret; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_UC; + cmd->ctx_handle = context->ctx_handle; + + ret = pvrdma_cmd_post(context->dev, &req, NULL, 0); + if (ret < 0) + dev_warn(&context->dev->pdev->dev, + "destroy ucontext failed, error: %d\n", ret); + + /* Free the UAR even if the device command failed */ + pvrdma_uar_free(to_vdev(ibcontext->device), &context->uar); + kfree(context); + + return ret; +} + +/** + * pvrdma_mmap - create mmap region + * @ibcontext: the user context + * @vma: the VMA + * + * @return: 0 on success, otherwise errno. + */ +int pvrdma_mmap(struct ib_ucontext *ibcontext, struct vm_area_struct *vma) +{ + struct pvrdma_ucontext *context = to_vucontext(ibcontext); + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end - vma->vm_start; + unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; + + dev_dbg(&context->dev->pdev->dev, "create mmap region\n"); + + if ((size != PAGE_SIZE) || (offset & ~PAGE_MASK)) { + dev_warn(&context->dev->pdev->dev, + "invalid params for mmap region\n"); + return -EINVAL; + } + + /* Map UAR to kernel space, VM_LOCKED? */ + vma->vm_flags |= VM_DONTCOPY | VM_DONTEXPAND; + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (io_remap_pfn_range(vma, start, context->uar.pfn, size, + vma->vm_page_prot)) + return -EAGAIN; + + return 0; +} + +/** + * pvrdma_alloc_pd - allocate protection domain + * @ibdev: the IB device + * @context: user context + * @udata: user data + * + * @return: the ib_pd protection domain pointer on success, otherwise errno. + */ +struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata) +{ + struct pvrdma_pd *pd; + struct pvrdma_dev *dev = to_vdev(ibdev); + union pvrdma_cmd_req req; + union pvrdma_cmd_resp rsp; + struct pvrdma_cmd_create_pd *cmd = &req.create_pd; + struct pvrdma_cmd_create_pd_resp *resp = &rsp.create_pd_resp; + int ret; + void *ptr; + + /* Check allowed max pds */ + if (!atomic_add_unless(&dev->num_pds, 1, dev->dsr->caps.max_pd)) + return ERR_PTR(-ENOMEM); + + pd = kmalloc(sizeof(*pd), GFP_KERNEL); + if (!pd) { + ptr = ERR_PTR(-ENOMEM); + goto err; + } + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_CREATE_PD; + cmd->ctx_handle = (context) ? to_vucontext(context)->ctx_handle : 0; + ret = pvrdma_cmd_post(dev, &req, &rsp, PVRDMA_CMD_CREATE_PD_RESP); + if (ret < 0) { + dev_warn(&dev->pdev->dev, + "failed to allocate protection domain, error: %d\n", + ret); + ptr = ERR_PTR(ret); + goto freepd; + } + + pd->privileged = !context; + pd->pd_handle = resp->pd_handle; + pd->pdn = resp->pd_handle; + + if (context) { + if (ib_copy_to_udata(udata, &pd->pdn, sizeof(__u32))) { + dev_warn(&dev->pdev->dev, + "failed to copy back protection domain\n"); + pvrdma_dealloc_pd(&pd->ibpd); + return ERR_PTR(-EFAULT); + } + } + + /* u32 pd handle */ + return &pd->ibpd; + +freepd: + kfree(pd); +err: + atomic_dec(&dev->num_pds); + return ptr; +} + +/** + * pvrdma_dealloc_pd - deallocate protection domain + * @pd: the protection domain to be released + * + * @return: 0 on success, otherwise errno. + */ +int pvrdma_dealloc_pd(struct ib_pd *pd) +{ + struct pvrdma_dev *dev = to_vdev(pd->device); + union pvrdma_cmd_req req; + struct pvrdma_cmd_destroy_pd *cmd = &req.destroy_pd; + int ret; + + memset(cmd, 0, sizeof(*cmd)); + cmd->hdr.cmd = PVRDMA_CMD_DESTROY_PD; + cmd->pd_handle = to_vpd(pd)->pd_handle; + + ret = pvrdma_cmd_post(dev, &req, NULL, 0); + if (ret) + dev_warn(&dev->pdev->dev, + "could not dealloc protection domain, error: %d\n", + ret); + + kfree(to_vpd(pd)); + atomic_dec(&dev->num_pds); + + return 0; +} + +/** + * pvrdma_create_ah - create an address handle + * @pd: the protection domain + * @ah_attr: the attributes of the AH + * @udata: user data blob + * + * @return: the ib_ah pointer on success, otherwise errno. + */ +struct ib_ah *pvrdma_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata) +{ + struct pvrdma_dev *dev = to_vdev(pd->device); + struct pvrdma_ah *ah; + enum rdma_link_layer ll; + + if (!(ah_attr->ah_flags & IB_AH_GRH)) + return ERR_PTR(-EINVAL); + + ll = rdma_port_get_link_layer(pd->device, ah_attr->port_num); + + if (ll != IB_LINK_LAYER_ETHERNET || + rdma_is_multicast_addr((struct in6_addr *)ah_attr->grh.dgid.raw)) + return ERR_PTR(-EINVAL); + + if (!atomic_add_unless(&dev->num_ahs, 1, dev->dsr->caps.max_ah)) + return ERR_PTR(-ENOMEM); + + ah = kzalloc(sizeof(*ah), GFP_KERNEL); + if (!ah) { + atomic_dec(&dev->num_ahs); + return ERR_PTR(-ENOMEM); + } + + ah->av.port_pd = to_vpd(pd)->pd_handle | (ah_attr->port_num << 24); + ah->av.src_path_bits = ah_attr->src_path_bits; + ah->av.src_path_bits |= 0x80; + ah->av.gid_index = ah_attr->grh.sgid_index; + ah->av.hop_limit = ah_attr->grh.hop_limit; + ah->av.sl_tclass_flowlabel = (ah_attr->grh.traffic_class << 20) | + ah_attr->grh.flow_label; + memcpy(ah->av.dgid, ah_attr->grh.dgid.raw, 16); + memcpy(ah->av.dmac, ah_attr->dmac, 6); + + ah->ibah.device = pd->device; + ah->ibah.pd = pd; + ah->ibah.uobject = NULL; + + return &ah->ibah; +} + +/** + * pvrdma_destroy_ah - destroy an address handle + * @ah: the address handle to destroyed + * + * @return: 0 on success. + */ +int pvrdma_destroy_ah(struct ib_ah *ah) +{ + struct pvrdma_dev *dev = to_vdev(ah->device); + + kfree(to_vah(ah)); + atomic_dec(&dev->num_ahs); + + return 0; +} diff --git a/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h new file mode 100644 index 000000000000..bfbe96b56255 --- /dev/null +++ b/drivers/infiniband/hw/vmw_pvrdma/pvrdma_verbs.h @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __PVRDMA_VERBS_H__ +#define __PVRDMA_VERBS_H__ + +#include + +union pvrdma_gid { + u8 raw[16]; + struct { + __be64 subnet_prefix; + __be64 interface_id; + } global; +}; + +enum pvrdma_link_layer { + PVRDMA_LINK_LAYER_UNSPECIFIED, + PVRDMA_LINK_LAYER_INFINIBAND, + PVRDMA_LINK_LAYER_ETHERNET, +}; + +enum pvrdma_mtu { + PVRDMA_MTU_256 = 1, + PVRDMA_MTU_512 = 2, + PVRDMA_MTU_1024 = 3, + PVRDMA_MTU_2048 = 4, + PVRDMA_MTU_4096 = 5, +}; + +static inline int pvrdma_mtu_enum_to_int(enum pvrdma_mtu mtu) +{ + switch (mtu) { + case PVRDMA_MTU_256: return 256; + case PVRDMA_MTU_512: return 512; + case PVRDMA_MTU_1024: return 1024; + case PVRDMA_MTU_2048: return 2048; + case PVRDMA_MTU_4096: return 4096; + default: return -1; + } +} + +static inline enum pvrdma_mtu pvrdma_mtu_int_to_enum(int mtu) +{ + switch (mtu) { + case 256: return PVRDMA_MTU_256; + case 512: return PVRDMA_MTU_512; + case 1024: return PVRDMA_MTU_1024; + case 2048: return PVRDMA_MTU_2048; + case 4096: + default: return PVRDMA_MTU_4096; + } +} + +enum pvrdma_port_state { + PVRDMA_PORT_NOP = 0, + PVRDMA_PORT_DOWN = 1, + PVRDMA_PORT_INIT = 2, + PVRDMA_PORT_ARMED = 3, + PVRDMA_PORT_ACTIVE = 4, + PVRDMA_PORT_ACTIVE_DEFER = 5, +}; + +enum pvrdma_port_cap_flags { + PVRDMA_PORT_SM = 1 << 1, + PVRDMA_PORT_NOTICE_SUP = 1 << 2, + PVRDMA_PORT_TRAP_SUP = 1 << 3, + PVRDMA_PORT_OPT_IPD_SUP = 1 << 4, + PVRDMA_PORT_AUTO_MIGR_SUP = 1 << 5, + PVRDMA_PORT_SL_MAP_SUP = 1 << 6, + PVRDMA_PORT_MKEY_NVRAM = 1 << 7, + PVRDMA_PORT_PKEY_NVRAM = 1 << 8, + PVRDMA_PORT_LED_INFO_SUP = 1 << 9, + PVRDMA_PORT_SM_DISABLED = 1 << 10, + PVRDMA_PORT_SYS_IMAGE_GUID_SUP = 1 << 11, + PVRDMA_PORT_PKEY_SW_EXT_PORT_TRAP_SUP = 1 << 12, + PVRDMA_PORT_EXTENDED_SPEEDS_SUP = 1 << 14, + PVRDMA_PORT_CM_SUP = 1 << 16, + PVRDMA_PORT_SNMP_TUNNEL_SUP = 1 << 17, + PVRDMA_PORT_REINIT_SUP = 1 << 18, + PVRDMA_PORT_DEVICE_MGMT_SUP = 1 << 19, + PVRDMA_PORT_VENDOR_CLASS_SUP = 1 << 20, + PVRDMA_PORT_DR_NOTICE_SUP = 1 << 21, + PVRDMA_PORT_CAP_MASK_NOTICE_SUP = 1 << 22, + PVRDMA_PORT_BOOT_MGMT_SUP = 1 << 23, + PVRDMA_PORT_LINK_LATENCY_SUP = 1 << 24, + PVRDMA_PORT_CLIENT_REG_SUP = 1 << 25, + PVRDMA_PORT_IP_BASED_GIDS = 1 << 26, + PVRDMA_PORT_CAP_FLAGS_MAX = PVRDMA_PORT_IP_BASED_GIDS, +}; + +enum pvrdma_port_width { + PVRDMA_WIDTH_1X = 1, + PVRDMA_WIDTH_4X = 2, + PVRDMA_WIDTH_8X = 4, + PVRDMA_WIDTH_12X = 8, +}; + +static inline int pvrdma_width_enum_to_int(enum pvrdma_port_width width) +{ + switch (width) { + case PVRDMA_WIDTH_1X: return 1; + case PVRDMA_WIDTH_4X: return 4; + case PVRDMA_WIDTH_8X: return 8; + case PVRDMA_WIDTH_12X: return 12; + default: return -1; + } +} + +enum pvrdma_port_speed { + PVRDMA_SPEED_SDR = 1, + PVRDMA_SPEED_DDR = 2, + PVRDMA_SPEED_QDR = 4, + PVRDMA_SPEED_FDR10 = 8, + PVRDMA_SPEED_FDR = 16, + PVRDMA_SPEED_EDR = 32, +}; + +struct pvrdma_port_attr { + enum pvrdma_port_state state; + enum pvrdma_mtu max_mtu; + enum pvrdma_mtu active_mtu; + u32 gid_tbl_len; + u32 port_cap_flags; + u32 max_msg_sz; + u32 bad_pkey_cntr; + u32 qkey_viol_cntr; + u16 pkey_tbl_len; + u16 lid; + u16 sm_lid; + u8 lmc; + u8 max_vl_num; + u8 sm_sl; + u8 subnet_timeout; + u8 init_type_reply; + u8 active_width; + u8 active_speed; + u8 phys_state; + u8 reserved[2]; +}; + +struct pvrdma_global_route { + union pvrdma_gid dgid; + u32 flow_label; + u8 sgid_index; + u8 hop_limit; + u8 traffic_class; + u8 reserved; +}; + +struct pvrdma_grh { + __be32 version_tclass_flow; + __be16 paylen; + u8 next_hdr; + u8 hop_limit; + union pvrdma_gid sgid; + union pvrdma_gid dgid; +}; + +enum pvrdma_ah_flags { + PVRDMA_AH_GRH = 1, +}; + +enum pvrdma_rate { + PVRDMA_RATE_PORT_CURRENT = 0, + PVRDMA_RATE_2_5_GBPS = 2, + PVRDMA_RATE_5_GBPS = 5, + PVRDMA_RATE_10_GBPS = 3, + PVRDMA_RATE_20_GBPS = 6, + PVRDMA_RATE_30_GBPS = 4, + PVRDMA_RATE_40_GBPS = 7, + PVRDMA_RATE_60_GBPS = 8, + PVRDMA_RATE_80_GBPS = 9, + PVRDMA_RATE_120_GBPS = 10, + PVRDMA_RATE_14_GBPS = 11, + PVRDMA_RATE_56_GBPS = 12, + PVRDMA_RATE_112_GBPS = 13, + PVRDMA_RATE_168_GBPS = 14, + PVRDMA_RATE_25_GBPS = 15, + PVRDMA_RATE_100_GBPS = 16, + PVRDMA_RATE_200_GBPS = 17, + PVRDMA_RATE_300_GBPS = 18, +}; + +struct pvrdma_ah_attr { + struct pvrdma_global_route grh; + u16 dlid; + u16 vlan_id; + u8 sl; + u8 src_path_bits; + u8 static_rate; + u8 ah_flags; + u8 port_num; + u8 dmac[6]; + u8 reserved; +}; + +enum pvrdma_cq_notify_flags { + PVRDMA_CQ_SOLICITED = 1 << 0, + PVRDMA_CQ_NEXT_COMP = 1 << 1, + PVRDMA_CQ_SOLICITED_MASK = PVRDMA_CQ_SOLICITED | + PVRDMA_CQ_NEXT_COMP, + PVRDMA_CQ_REPORT_MISSED_EVENTS = 1 << 2, +}; + +struct pvrdma_qp_cap { + u32 max_send_wr; + u32 max_recv_wr; + u32 max_send_sge; + u32 max_recv_sge; + u32 max_inline_data; + u32 reserved; +}; + +enum pvrdma_sig_type { + PVRDMA_SIGNAL_ALL_WR, + PVRDMA_SIGNAL_REQ_WR, +}; + +enum pvrdma_qp_type { + PVRDMA_QPT_SMI, + PVRDMA_QPT_GSI, + PVRDMA_QPT_RC, + PVRDMA_QPT_UC, + PVRDMA_QPT_UD, + PVRDMA_QPT_RAW_IPV6, + PVRDMA_QPT_RAW_ETHERTYPE, + PVRDMA_QPT_RAW_PACKET = 8, + PVRDMA_QPT_XRC_INI = 9, + PVRDMA_QPT_XRC_TGT, + PVRDMA_QPT_MAX, +}; + +enum pvrdma_qp_create_flags { + PVRDMA_QP_CREATE_IPOPVRDMA_UD_LSO = 1 << 0, + PVRDMA_QP_CREATE_BLOCK_MULTICAST_LOOPBACK = 1 << 1, +}; + +enum pvrdma_qp_attr_mask { + PVRDMA_QP_STATE = 1 << 0, + PVRDMA_QP_CUR_STATE = 1 << 1, + PVRDMA_QP_EN_SQD_ASYNC_NOTIFY = 1 << 2, + PVRDMA_QP_ACCESS_FLAGS = 1 << 3, + PVRDMA_QP_PKEY_INDEX = 1 << 4, + PVRDMA_QP_PORT = 1 << 5, + PVRDMA_QP_QKEY = 1 << 6, + PVRDMA_QP_AV = 1 << 7, + PVRDMA_QP_PATH_MTU = 1 << 8, + PVRDMA_QP_TIMEOUT = 1 << 9, + PVRDMA_QP_RETRY_CNT = 1 << 10, + PVRDMA_QP_RNR_RETRY = 1 << 11, + PVRDMA_QP_RQ_PSN = 1 << 12, + PVRDMA_QP_MAX_QP_RD_ATOMIC = 1 << 13, + PVRDMA_QP_ALT_PATH = 1 << 14, + PVRDMA_QP_MIN_RNR_TIMER = 1 << 15, + PVRDMA_QP_SQ_PSN = 1 << 16, + PVRDMA_QP_MAX_DEST_RD_ATOMIC = 1 << 17, + PVRDMA_QP_PATH_MIG_STATE = 1 << 18, + PVRDMA_QP_CAP = 1 << 19, + PVRDMA_QP_DEST_QPN = 1 << 20, + PVRDMA_QP_ATTR_MASK_MAX = PVRDMA_QP_DEST_QPN, +}; + +enum pvrdma_qp_state { + PVRDMA_QPS_RESET, + PVRDMA_QPS_INIT, + PVRDMA_QPS_RTR, + PVRDMA_QPS_RTS, + PVRDMA_QPS_SQD, + PVRDMA_QPS_SQE, + PVRDMA_QPS_ERR, +}; + +enum pvrdma_mig_state { + PVRDMA_MIG_MIGRATED, + PVRDMA_MIG_REARM, + PVRDMA_MIG_ARMED, +}; + +enum pvrdma_mw_type { + PVRDMA_MW_TYPE_1 = 1, + PVRDMA_MW_TYPE_2 = 2, +}; + +struct pvrdma_qp_attr { + enum pvrdma_qp_state qp_state; + enum pvrdma_qp_state cur_qp_state; + enum pvrdma_mtu path_mtu; + enum pvrdma_mig_state path_mig_state; + u32 qkey; + u32 rq_psn; + u32 sq_psn; + u32 dest_qp_num; + u32 qp_access_flags; + u16 pkey_index; + u16 alt_pkey_index; + u8 en_sqd_async_notify; + u8 sq_draining; + u8 max_rd_atomic; + u8 max_dest_rd_atomic; + u8 min_rnr_timer; + u8 port_num; + u8 timeout; + u8 retry_cnt; + u8 rnr_retry; + u8 alt_port_num; + u8 alt_timeout; + u8 reserved[5]; + struct pvrdma_qp_cap cap; + struct pvrdma_ah_attr ah_attr; + struct pvrdma_ah_attr alt_ah_attr; +}; + +enum pvrdma_send_flags { + PVRDMA_SEND_FENCE = 1 << 0, + PVRDMA_SEND_SIGNALED = 1 << 1, + PVRDMA_SEND_SOLICITED = 1 << 2, + PVRDMA_SEND_INLINE = 1 << 3, + PVRDMA_SEND_IP_CSUM = 1 << 4, + PVRDMA_SEND_FLAGS_MAX = PVRDMA_SEND_IP_CSUM, +}; + +enum pvrdma_access_flags { + PVRDMA_ACCESS_LOCAL_WRITE = 1 << 0, + PVRDMA_ACCESS_REMOTE_WRITE = 1 << 1, + PVRDMA_ACCESS_REMOTE_READ = 1 << 2, + PVRDMA_ACCESS_REMOTE_ATOMIC = 1 << 3, + PVRDMA_ACCESS_MW_BIND = 1 << 4, + PVRDMA_ZERO_BASED = 1 << 5, + PVRDMA_ACCESS_ON_DEMAND = 1 << 6, + PVRDMA_ACCESS_FLAGS_MAX = PVRDMA_ACCESS_ON_DEMAND, +}; + +int pvrdma_query_device(struct ib_device *ibdev, + struct ib_device_attr *props, + struct ib_udata *udata); +int pvrdma_query_port(struct ib_device *ibdev, u8 port, + struct ib_port_attr *props); +int pvrdma_query_gid(struct ib_device *ibdev, u8 port, + int index, union ib_gid *gid); +int pvrdma_query_pkey(struct ib_device *ibdev, u8 port, + u16 index, u16 *pkey); +enum rdma_link_layer pvrdma_port_link_layer(struct ib_device *ibdev, + u8 port); +int pvrdma_modify_device(struct ib_device *ibdev, int mask, + struct ib_device_modify *props); +int pvrdma_modify_port(struct ib_device *ibdev, u8 port, + int mask, struct ib_port_modify *props); +int pvrdma_mmap(struct ib_ucontext *context, struct vm_area_struct *vma); +struct ib_ucontext *pvrdma_alloc_ucontext(struct ib_device *ibdev, + struct ib_udata *udata); +int pvrdma_dealloc_ucontext(struct ib_ucontext *context); +struct ib_pd *pvrdma_alloc_pd(struct ib_device *ibdev, + struct ib_ucontext *context, + struct ib_udata *udata); +int pvrdma_dealloc_pd(struct ib_pd *ibpd); +struct ib_mr *pvrdma_get_dma_mr(struct ib_pd *pd, int acc); +struct ib_mr *pvrdma_reg_user_mr(struct ib_pd *pd, u64 start, u64 length, + u64 virt_addr, int access_flags, + struct ib_udata *udata); +int pvrdma_dereg_mr(struct ib_mr *mr); +struct ib_mr *pvrdma_alloc_mr(struct ib_pd *pd, enum ib_mr_type mr_type, + u32 max_num_sg); +int pvrdma_map_mr_sg(struct ib_mr *ibmr, struct scatterlist *sg, + int sg_nents, unsigned int *sg_offset); +int pvrdma_modify_cq(struct ib_cq *cq, u16 cq_count, u16 cq_period); +int pvrdma_resize_cq(struct ib_cq *ibcq, int entries, + struct ib_udata *udata); +struct ib_cq *pvrdma_create_cq(struct ib_device *ibdev, + const struct ib_cq_init_attr *attr, + struct ib_ucontext *context, + struct ib_udata *udata); +int pvrdma_resize_cq(struct ib_cq *ibcq, int entries, + struct ib_udata *udata); +int pvrdma_destroy_cq(struct ib_cq *cq); +int pvrdma_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc); +int pvrdma_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags); +struct ib_ah *pvrdma_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr, + struct ib_udata *udata); +int pvrdma_destroy_ah(struct ib_ah *ah); +struct ib_qp *pvrdma_create_qp(struct ib_pd *pd, + struct ib_qp_init_attr *init_attr, + struct ib_udata *udata); +int pvrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, + int attr_mask, struct ib_udata *udata); +int pvrdma_query_qp(struct ib_qp *ibqp, struct ib_qp_attr *qp_attr, + int qp_attr_mask, struct ib_qp_init_attr *qp_init_attr); +int pvrdma_destroy_qp(struct ib_qp *qp); +int pvrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, + struct ib_send_wr **bad_wr); +int pvrdma_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, + struct ib_recv_wr **bad_wr); + +#endif /* __PVRDMA_VERBS_H__ */ diff --git a/include/uapi/rdma/Kbuild b/include/uapi/rdma/Kbuild index f14ab7ff5fee..6a8a934c540c 100644 --- a/include/uapi/rdma/Kbuild +++ b/include/uapi/rdma/Kbuild @@ -14,3 +14,4 @@ header-y += mlx5-abi.h header-y += mthca-abi.h header-y += nes-abi.h header-y += ocrdma-abi.h +header-y += vmw_pvrdma-abi.h diff --git a/include/uapi/rdma/vmw_pvrdma-abi.h b/include/uapi/rdma/vmw_pvrdma-abi.h new file mode 100644 index 000000000000..5016abc9ee97 --- /dev/null +++ b/include/uapi/rdma/vmw_pvrdma-abi.h @@ -0,0 +1,289 @@ +/* + * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of EITHER the GNU General Public License + * version 2 as published by the Free Software Foundation or the BSD + * 2-Clause 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 version 2 for more details at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. + * + * You should have received a copy of the GNU General Public License + * along with this program available in the file COPYING in the main + * directory of this source tree. + * + * The BSD 2-Clause License + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef __VMW_PVRDMA_ABI_H__ +#define __VMW_PVRDMA_ABI_H__ + +#include + +#define PVRDMA_UVERBS_ABI_VERSION 3 /* ABI Version. */ +#define PVRDMA_UAR_HANDLE_MASK 0x00FFFFFF /* Bottom 24 bits. */ +#define PVRDMA_UAR_QP_OFFSET 0 /* QP doorbell. */ +#define PVRDMA_UAR_QP_SEND BIT(30) /* Send bit. */ +#define PVRDMA_UAR_QP_RECV BIT(31) /* Recv bit. */ +#define PVRDMA_UAR_CQ_OFFSET 4 /* CQ doorbell. */ +#define PVRDMA_UAR_CQ_ARM_SOL BIT(29) /* Arm solicited bit. */ +#define PVRDMA_UAR_CQ_ARM BIT(30) /* Arm bit. */ +#define PVRDMA_UAR_CQ_POLL BIT(31) /* Poll bit. */ + +enum pvrdma_wr_opcode { + PVRDMA_WR_RDMA_WRITE, + PVRDMA_WR_RDMA_WRITE_WITH_IMM, + PVRDMA_WR_SEND, + PVRDMA_WR_SEND_WITH_IMM, + PVRDMA_WR_RDMA_READ, + PVRDMA_WR_ATOMIC_CMP_AND_SWP, + PVRDMA_WR_ATOMIC_FETCH_AND_ADD, + PVRDMA_WR_LSO, + PVRDMA_WR_SEND_WITH_INV, + PVRDMA_WR_RDMA_READ_WITH_INV, + PVRDMA_WR_LOCAL_INV, + PVRDMA_WR_FAST_REG_MR, + PVRDMA_WR_MASKED_ATOMIC_CMP_AND_SWP, + PVRDMA_WR_MASKED_ATOMIC_FETCH_AND_ADD, + PVRDMA_WR_BIND_MW, + PVRDMA_WR_REG_SIG_MR, +}; + +enum pvrdma_wc_status { + PVRDMA_WC_SUCCESS, + PVRDMA_WC_LOC_LEN_ERR, + PVRDMA_WC_LOC_QP_OP_ERR, + PVRDMA_WC_LOC_EEC_OP_ERR, + PVRDMA_WC_LOC_PROT_ERR, + PVRDMA_WC_WR_FLUSH_ERR, + PVRDMA_WC_MW_BIND_ERR, + PVRDMA_WC_BAD_RESP_ERR, + PVRDMA_WC_LOC_ACCESS_ERR, + PVRDMA_WC_REM_INV_REQ_ERR, + PVRDMA_WC_REM_ACCESS_ERR, + PVRDMA_WC_REM_OP_ERR, + PVRDMA_WC_RETRY_EXC_ERR, + PVRDMA_WC_RNR_RETRY_EXC_ERR, + PVRDMA_WC_LOC_RDD_VIOL_ERR, + PVRDMA_WC_REM_INV_RD_REQ_ERR, + PVRDMA_WC_REM_ABORT_ERR, + PVRDMA_WC_INV_EECN_ERR, + PVRDMA_WC_INV_EEC_STATE_ERR, + PVRDMA_WC_FATAL_ERR, + PVRDMA_WC_RESP_TIMEOUT_ERR, + PVRDMA_WC_GENERAL_ERR, +}; + +enum pvrdma_wc_opcode { + PVRDMA_WC_SEND, + PVRDMA_WC_RDMA_WRITE, + PVRDMA_WC_RDMA_READ, + PVRDMA_WC_COMP_SWAP, + PVRDMA_WC_FETCH_ADD, + PVRDMA_WC_BIND_MW, + PVRDMA_WC_LSO, + PVRDMA_WC_LOCAL_INV, + PVRDMA_WC_FAST_REG_MR, + PVRDMA_WC_MASKED_COMP_SWAP, + PVRDMA_WC_MASKED_FETCH_ADD, + PVRDMA_WC_RECV = 1 << 7, + PVRDMA_WC_RECV_RDMA_WITH_IMM, +}; + +enum pvrdma_wc_flags { + PVRDMA_WC_GRH = 1 << 0, + PVRDMA_WC_WITH_IMM = 1 << 1, + PVRDMA_WC_WITH_INVALIDATE = 1 << 2, + PVRDMA_WC_IP_CSUM_OK = 1 << 3, + PVRDMA_WC_WITH_SMAC = 1 << 4, + PVRDMA_WC_WITH_VLAN = 1 << 5, + PVRDMA_WC_FLAGS_MAX = PVRDMA_WC_WITH_VLAN, +}; + +struct pvrdma_alloc_ucontext_resp { + __u32 qp_tab_size; + __u32 reserved; +}; + +struct pvrdma_alloc_pd_resp { + __u32 pdn; + __u32 reserved; +}; + +struct pvrdma_create_cq { + __u64 buf_addr; + __u32 buf_size; + __u32 reserved; +}; + +struct pvrdma_create_cq_resp { + __u32 cqn; + __u32 reserved; +}; + +struct pvrdma_resize_cq { + __u64 buf_addr; + __u32 buf_size; + __u32 reserved; +}; + +struct pvrdma_create_srq { + __u64 buf_addr; +}; + +struct pvrdma_create_srq_resp { + __u32 srqn; + __u32 reserved; +}; + +struct pvrdma_create_qp { + __u64 rbuf_addr; + __u64 sbuf_addr; + __u32 rbuf_size; + __u32 sbuf_size; + __u64 qp_addr; +}; + +/* PVRDMA masked atomic compare and swap */ +struct pvrdma_ex_cmp_swap { + __u64 swap_val; + __u64 compare_val; + __u64 swap_mask; + __u64 compare_mask; +}; + +/* PVRDMA masked atomic fetch and add */ +struct pvrdma_ex_fetch_add { + __u64 add_val; + __u64 field_boundary; +}; + +/* PVRDMA address vector. */ +struct pvrdma_av { + __u32 port_pd; + __u32 sl_tclass_flowlabel; + __u8 dgid[16]; + __u8 src_path_bits; + __u8 gid_index; + __u8 stat_rate; + __u8 hop_limit; + __u8 dmac[6]; + __u8 reserved[6]; +}; + +/* PVRDMA scatter/gather entry */ +struct pvrdma_sge { + __u64 addr; + __u32 length; + __u32 lkey; +}; + +/* PVRDMA receive queue work request */ +struct pvrdma_rq_wqe_hdr { + __u64 wr_id; /* wr id */ + __u32 num_sge; /* size of s/g array */ + __u32 total_len; /* reserved */ +}; +/* Use pvrdma_sge (ib_sge) for receive queue s/g array elements. */ + +/* PVRDMA send queue work request */ +struct pvrdma_sq_wqe_hdr { + __u64 wr_id; /* wr id */ + __u32 num_sge; /* size of s/g array */ + __u32 total_len; /* reserved */ + __u32 opcode; /* operation type */ + __u32 send_flags; /* wr flags */ + union { + __u32 imm_data; + __u32 invalidate_rkey; + } ex; + __u32 reserved; + union { + struct { + __u64 remote_addr; + __u32 rkey; + __u8 reserved[4]; + } rdma; + struct { + __u64 remote_addr; + __u64 compare_add; + __u64 swap; + __u32 rkey; + __u32 reserved; + } atomic; + struct { + __u64 remote_addr; + __u32 log_arg_sz; + __u32 rkey; + union { + struct pvrdma_ex_cmp_swap cmp_swap; + struct pvrdma_ex_fetch_add fetch_add; + } wr_data; + } masked_atomics; + struct { + __u64 iova_start; + __u64 pl_pdir_dma; + __u32 page_shift; + __u32 page_list_len; + __u32 length; + __u32 access_flags; + __u32 rkey; + } fast_reg; + struct { + __u32 remote_qpn; + __u32 remote_qkey; + struct pvrdma_av av; + } ud; + } wr; +}; +/* Use pvrdma_sge (ib_sge) for send queue s/g array elements. */ + +/* Completion queue element. */ +struct pvrdma_cqe { + __u64 wr_id; + __u64 qp; + __u32 opcode; + __u32 status; + __u32 byte_len; + __u32 imm_data; + __u32 src_qp; + __u32 wc_flags; + __u32 vendor_err; + __u16 pkey_index; + __u16 slid; + __u8 sl; + __u8 dlid_path_bits; + __u8 port_num; + __u8 smac[6]; + __u8 reserved2[7]; /* Pad to next power of 2 (64). */ +}; + +#endif /* __VMW_PVRDMA_ABI_H__ */ -- cgit v1.2.3 From ace7f46ba5fde7273207c7122b0650ceb72510e0 Mon Sep 17 00:00:00 2001 From: Manish Rangankar Date: Thu, 1 Dec 2016 00:21:08 -0800 Subject: scsi: qedi: Add QLogic FastLinQ offload iSCSI driver framework. The QLogic FastLinQ Driver for iSCSI (qedi) is the iSCSI specific module for 41000 Series Converged Network Adapters by QLogic. This patch consists of following changes: - MAINTAINERS Makefile and Kconfig changes for qedi, - PCI driver registration, - iSCSI host level initialization, - Debugfs and log level infrastructure. The following indiviual changes are merged into this commit: qedi: Add LL2 iSCSI interface for offload iSCSI. qedi: Add support for iSCSI session management. qedi: Add support for data path. Signed-off-by: Nilesh Javali Signed-off-by: Adheer Chandravanshi Signed-off-by: Chad Dupuis Signed-off-by: Saurav Kashyap Signed-off-by: Arun Easi Signed-off-by: Manish Rangankar Reviewed-by: Johannes Thumshirn Reviewed-by: Hannes Reinecke Reviewed-by: Martin K. Petersen Signed-off-by: Martin K. Petersen --- MAINTAINERS | 6 + drivers/scsi/Kconfig | 1 + drivers/scsi/Makefile | 1 + drivers/scsi/qedi/Kconfig | 10 + drivers/scsi/qedi/Makefile | 5 + drivers/scsi/qedi/qedi.h | 364 ++++++ drivers/scsi/qedi/qedi_dbg.c | 143 +++ drivers/scsi/qedi/qedi_dbg.h | 144 +++ drivers/scsi/qedi/qedi_debugfs.c | 244 ++++ drivers/scsi/qedi/qedi_fw.c | 2378 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/qedi/qedi_gbl.h | 73 ++ drivers/scsi/qedi/qedi_hsi.h | 52 + drivers/scsi/qedi/qedi_iscsi.c | 1624 ++++++++++++++++++++++++++ drivers/scsi/qedi/qedi_iscsi.h | 232 ++++ drivers/scsi/qedi/qedi_main.c | 2127 ++++++++++++++++++++++++++++++++++ drivers/scsi/qedi/qedi_sysfs.c | 52 + drivers/scsi/qedi/qedi_version.h | 14 + 17 files changed, 7470 insertions(+) create mode 100644 drivers/scsi/qedi/Kconfig create mode 100644 drivers/scsi/qedi/Makefile create mode 100644 drivers/scsi/qedi/qedi.h create mode 100644 drivers/scsi/qedi/qedi_dbg.c create mode 100644 drivers/scsi/qedi/qedi_dbg.h create mode 100644 drivers/scsi/qedi/qedi_debugfs.c create mode 100644 drivers/scsi/qedi/qedi_fw.c create mode 100644 drivers/scsi/qedi/qedi_gbl.h create mode 100644 drivers/scsi/qedi/qedi_hsi.h create mode 100644 drivers/scsi/qedi/qedi_iscsi.c create mode 100644 drivers/scsi/qedi/qedi_iscsi.h create mode 100644 drivers/scsi/qedi/qedi_main.c create mode 100644 drivers/scsi/qedi/qedi_sysfs.c create mode 100644 drivers/scsi/qedi/qedi_version.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index e376bbd1c555..c117bcf51d34 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -10079,6 +10079,12 @@ F: drivers/net/ethernet/qlogic/qed/ F: include/linux/qed/ F: drivers/net/ethernet/qlogic/qede/ +QLOGIC QL41xxx ISCSI DRIVER +M: QLogic-Storage-Upstream@cavium.com +L: linux-scsi@vger.kernel.org +S: Supported +F: drivers/scsi/qedi/ + QNX4 FILESYSTEM M: Anders Larsen W: http://www.alarsen.net/linux/qnx4fs/ diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index dfa93347c752..a4f6b0d95515 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1233,6 +1233,7 @@ config SCSI_QLOGICPTI source "drivers/scsi/qla2xxx/Kconfig" source "drivers/scsi/qla4xxx/Kconfig" +source "drivers/scsi/qedi/Kconfig" config SCSI_LPFC tristate "Emulex LightPulse Fibre Channel Support" diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index a2d03957cbe2..736b77414a4b 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -131,6 +131,7 @@ obj-$(CONFIG_PS3_ROM) += ps3rom.o obj-$(CONFIG_SCSI_CXGB3_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ obj-$(CONFIG_SCSI_CXGB4_ISCSI) += libiscsi.o libiscsi_tcp.o cxgbi/ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/ +obj-$(CONFIG_QEDI) += libiscsi.o qedi/ obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/ obj-$(CONFIG_SCSI_ESAS2R) += esas2r/ obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o diff --git a/drivers/scsi/qedi/Kconfig b/drivers/scsi/qedi/Kconfig new file mode 100644 index 000000000000..23ca8a274586 --- /dev/null +++ b/drivers/scsi/qedi/Kconfig @@ -0,0 +1,10 @@ +config QEDI + tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support" + depends on PCI && SCSI + depends on QED + select SCSI_ISCSI_ATTRS + select QED_LL2 + select QED_ISCSI + ---help--- + This driver supports iSCSI offload for the QLogic FastLinQ + 41000 Series Converged Network Adapters. diff --git a/drivers/scsi/qedi/Makefile b/drivers/scsi/qedi/Makefile new file mode 100644 index 000000000000..2b3e16b24299 --- /dev/null +++ b/drivers/scsi/qedi/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_QEDI) := qedi.o +qedi-y := qedi_main.o qedi_iscsi.o qedi_fw.o qedi_sysfs.o \ + qedi_dbg.o + +qedi-$(CONFIG_DEBUG_FS) += qedi_debugfs.o diff --git a/drivers/scsi/qedi/qedi.h b/drivers/scsi/qedi/qedi.h new file mode 100644 index 000000000000..5ca3e8c28a3f --- /dev/null +++ b/drivers/scsi/qedi/qedi.h @@ -0,0 +1,364 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QEDI_H_ +#define _QEDI_H_ + +#define __PREVENT_QED_HSI__ + +#include +#include +#include +#include + +#include "qedi_hsi.h" +#include +#include "qedi_dbg.h" +#include +#include +#include "qedi_version.h" + +#define QEDI_MODULE_NAME "qedi" + +struct qedi_endpoint; + +/* + * PCI function probe defines + */ +#define QEDI_MODE_NORMAL 0 +#define QEDI_MODE_RECOVERY 1 + +#define ISCSI_WQE_SET_PTU_INVALIDATE 1 +#define QEDI_MAX_ISCSI_TASK 4096 +#define QEDI_MAX_TASK_NUM 0x0FFF +#define QEDI_MAX_ISCSI_CONNS_PER_HBA 1024 +#define QEDI_ISCSI_MAX_BDS_PER_CMD 256 /* Firmware max BDs is 256 */ +#define MAX_OUSTANDING_TASKS_PER_CON 1024 + +#define QEDI_MAX_BD_LEN 0xffff +#define QEDI_BD_SPLIT_SZ 0x1000 +#define QEDI_PAGE_SIZE 4096 +#define QEDI_FAST_SGE_COUNT 4 +/* MAX Length for cached SGL */ +#define MAX_SGLEN_FOR_CACHESGL ((1U << 16) - 1) + +#define MAX_NUM_MSIX_PF 8 +#define MIN_NUM_CPUS_MSIX(x) min((x)->msix_count, num_online_cpus()) + +#define QEDI_LOCAL_PORT_MIN 60000 +#define QEDI_LOCAL_PORT_MAX 61024 +#define QEDI_LOCAL_PORT_RANGE (QEDI_LOCAL_PORT_MAX - QEDI_LOCAL_PORT_MIN) +#define QEDI_LOCAL_PORT_INVALID 0xffff +#define TX_RX_RING 16 +#define RX_RING (TX_RX_RING - 1) +#define LL2_SINGLE_BUF_SIZE 0x400 +#define QEDI_PAGE_SIZE 4096 +#define QEDI_PAGE_ALIGN(addr) ALIGN(addr, QEDI_PAGE_SIZE) +#define QEDI_PAGE_MASK (~((QEDI_PAGE_SIZE) - 1)) + +#define QEDI_PAGE_SIZE 4096 +#define QEDI_PATH_HANDLE 0xFE0000000UL + +struct qedi_uio_ctrl { + /* meta data */ + u32 uio_hsi_version; + + /* user writes */ + u32 host_tx_prod; + u32 host_rx_cons; + u32 host_rx_bd_cons; + u32 host_tx_pkt_len; + u32 host_rx_cons_cnt; + + /* driver writes */ + u32 hw_tx_cons; + u32 hw_rx_prod; + u32 hw_rx_bd_prod; + u32 hw_rx_prod_cnt; + + /* other */ + u8 mac_addr[6]; + u8 reserve[2]; +}; + +struct qedi_rx_bd { + u32 rx_pkt_index; + u32 rx_pkt_len; + u16 vlan_id; +}; + +#define QEDI_RX_DESC_CNT (QEDI_PAGE_SIZE / sizeof(struct qedi_rx_bd)) +#define QEDI_MAX_RX_DESC_CNT (QEDI_RX_DESC_CNT - 1) +#define QEDI_NUM_RX_BD (QEDI_RX_DESC_CNT * 1) +#define QEDI_MAX_RX_BD (QEDI_NUM_RX_BD - 1) + +#define QEDI_NEXT_RX_IDX(x) ((((x) & (QEDI_MAX_RX_DESC_CNT)) == \ + (QEDI_MAX_RX_DESC_CNT - 1)) ? \ + (x) + 2 : (x) + 1) + +struct qedi_uio_dev { + struct uio_info qedi_uinfo; + u32 uio_dev; + struct list_head list; + + u32 ll2_ring_size; + void *ll2_ring; + + u32 ll2_buf_size; + void *ll2_buf; + + void *rx_pkt; + void *tx_pkt; + + struct qedi_ctx *qedi; + struct pci_dev *pdev; + void *uctrl; +}; + +/* List to maintain the skb pointers */ +struct skb_work_list { + struct list_head list; + struct sk_buff *skb; + u16 vlan_id; +}; + +/* Queue sizes in number of elements */ +#define QEDI_SQ_SIZE MAX_OUSTANDING_TASKS_PER_CON +#define QEDI_CQ_SIZE 2048 +#define QEDI_CMDQ_SIZE QEDI_MAX_ISCSI_TASK +#define QEDI_PROTO_CQ_PROD_IDX 0 + +struct qedi_glbl_q_params { + u64 hw_p_cq; /* Completion queue PBL */ + u64 hw_p_rq; /* Request queue PBL */ + u64 hw_p_cmdq; /* Command queue PBL */ +}; + +struct global_queue { + union iscsi_cqe *cq; + dma_addr_t cq_dma; + u32 cq_mem_size; + u32 cq_cons_idx; /* Completion queue consumer index */ + + void *cq_pbl; + dma_addr_t cq_pbl_dma; + u32 cq_pbl_size; + +}; + +struct qedi_fastpath { + struct qed_sb_info *sb_info; + u16 sb_id; +#define QEDI_NAME_SIZE 16 + char name[QEDI_NAME_SIZE]; + struct qedi_ctx *qedi; +}; + +/* Used to pass fastpath information needed to process CQEs */ +struct qedi_io_work { + struct list_head list; + struct iscsi_cqe_solicited cqe; + u16 que_idx; +}; + +/** + * struct iscsi_cid_queue - Per adapter iscsi cid queue + * + * @cid_que_base: queue base memory + * @cid_que: queue memory pointer + * @cid_q_prod_idx: produce index + * @cid_q_cons_idx: consumer index + * @cid_q_max_idx: max index. used to detect wrap around condition + * @cid_free_cnt: queue size + * @conn_cid_tbl: iscsi cid to conn structure mapping table + * + * Per adapter iSCSI CID Queue + */ +struct iscsi_cid_queue { + void *cid_que_base; + u32 *cid_que; + u32 cid_q_prod_idx; + u32 cid_q_cons_idx; + u32 cid_q_max_idx; + u32 cid_free_cnt; + struct qedi_conn **conn_cid_tbl; +}; + +struct qedi_portid_tbl { + spinlock_t lock; /* Port id lock */ + u16 start; + u16 max; + u16 next; + unsigned long *table; +}; + +struct qedi_itt_map { + __le32 itt; + struct qedi_cmd *p_cmd; +}; + +/* I/O tracing entry */ +#define QEDI_IO_TRACE_SIZE 2048 +struct qedi_io_log { +#define QEDI_IO_TRACE_REQ 0 +#define QEDI_IO_TRACE_RSP 1 + u8 direction; + u16 task_id; + u32 cid; + u32 port_id; /* Remote port fabric ID */ + int lun; + u8 op; /* SCSI CDB */ + u8 lba[4]; + unsigned int bufflen; /* SCSI buffer length */ + unsigned int sg_count; /* Number of SG elements */ + u8 fast_sgs; /* number of fast sgls */ + u8 slow_sgs; /* number of slow sgls */ + u8 cached_sgs; /* number of cached sgls */ + int result; /* Result passed back to mid-layer */ + unsigned long jiffies; /* Time stamp when I/O logged */ + int refcount; /* Reference count for task id */ + unsigned int blk_req_cpu; /* CPU that the task is queued on by + * blk layer + */ + unsigned int req_cpu; /* CPU that the task is queued on */ + unsigned int intr_cpu; /* Interrupt CPU that the task is received on */ + unsigned int blk_rsp_cpu;/* CPU that task is actually processed and + * returned to blk layer + */ + bool cached_sge; + bool slow_sge; + bool fast_sge; +}; + +/* Number of entries in BDQ */ +#define QEDI_BDQ_NUM 256 +#define QEDI_BDQ_BUF_SIZE 256 + +/* DMA coherent buffers for BDQ */ +struct qedi_bdq_buf { + void *buf_addr; + dma_addr_t buf_dma; +}; + +/* Main port level struct */ +struct qedi_ctx { + struct qedi_dbg_ctx dbg_ctx; + struct Scsi_Host *shost; + struct pci_dev *pdev; + struct qed_dev *cdev; + struct qed_dev_iscsi_info dev_info; + struct qed_int_info int_info; + struct qedi_glbl_q_params *p_cpuq; + struct global_queue **global_queues; + /* uio declaration */ + struct qedi_uio_dev *udev; + struct list_head ll2_skb_list; + spinlock_t ll2_lock; /* Light L2 lock */ + spinlock_t hba_lock; /* per port lock */ + struct task_struct *ll2_recv_thread; + unsigned long flags; +#define UIO_DEV_OPENED 1 +#define QEDI_IOTHREAD_WAKE 2 +#define QEDI_IN_RECOVERY 5 +#define QEDI_IN_OFFLINE 6 + + u8 mac[ETH_ALEN]; + u32 src_ip[4]; + u8 ip_type; + + /* Physical address of above array */ + dma_addr_t hw_p_cpuq; + + struct qedi_bdq_buf bdq[QEDI_BDQ_NUM]; + void *bdq_pbl; + dma_addr_t bdq_pbl_dma; + size_t bdq_pbl_mem_size; + void *bdq_pbl_list; + dma_addr_t bdq_pbl_list_dma; + u8 bdq_pbl_list_num_entries; + void __iomem *bdq_primary_prod; + void __iomem *bdq_secondary_prod; + u16 bdq_prod_idx; + u16 rq_num_entries; + + u32 msix_count; + u32 max_sqes; + u8 num_queues; + u32 max_active_conns; + + struct iscsi_cid_queue cid_que; + struct qedi_endpoint **ep_tbl; + struct qedi_portid_tbl lcl_port_tbl; + + /* Rx fast path intr context */ + struct qed_sb_info *sb_array; + struct qedi_fastpath *fp_array; + struct qed_iscsi_tid tasks; + +#define QEDI_LINK_DOWN 0 +#define QEDI_LINK_UP 1 + atomic_t link_state; + +#define QEDI_RESERVE_TASK_ID 0 +#define MAX_ISCSI_TASK_ENTRIES 4096 +#define QEDI_INVALID_TASK_ID (MAX_ISCSI_TASK_ENTRIES + 1) + unsigned long task_idx_map[MAX_ISCSI_TASK_ENTRIES / BITS_PER_LONG]; + struct qedi_itt_map *itt_map; + u16 tid_reuse_count[QEDI_MAX_ISCSI_TASK]; + struct qed_pf_params pf_params; + + struct workqueue_struct *tmf_thread; + struct workqueue_struct *offload_thread; + + u16 ll2_mtu; + + struct workqueue_struct *dpc_wq; + + spinlock_t task_idx_lock; /* To protect gbl context */ + s32 last_tidx_alloc; + s32 last_tidx_clear; + + struct qedi_io_log io_trace_buf[QEDI_IO_TRACE_SIZE]; + spinlock_t io_trace_lock; /* prtect trace Log buf */ + u16 io_trace_idx; + unsigned int intr_cpu; + u32 cached_sgls; + bool use_cached_sge; + u32 slow_sgls; + bool use_slow_sge; + u32 fast_sgls; + bool use_fast_sge; + + atomic_t num_offloads; +}; + +struct qedi_work { + struct list_head list; + struct qedi_ctx *qedi; + union iscsi_cqe cqe; + u16 que_idx; + bool is_solicited; +}; + +struct qedi_percpu_s { + struct task_struct *iothread; + struct list_head work_list; + spinlock_t p_work_lock; /* Per cpu worker lock */ +}; + +static inline void *qedi_get_task_mem(struct qed_iscsi_tid *info, u32 tid) +{ + return (info->blocks[tid / info->num_tids_per_block] + + (tid % info->num_tids_per_block) * info->size); +} + +#define QEDI_U64_HI(val) ((u32)(((u64)(val)) >> 32)) +#define QEDI_U64_LO(val) ((u32)(((u64)(val)) & 0xffffffff)) + +#endif /* _QEDI_H_ */ diff --git a/drivers/scsi/qedi/qedi_dbg.c b/drivers/scsi/qedi/qedi_dbg.c new file mode 100644 index 000000000000..2bdedb9c39bc --- /dev/null +++ b/drivers/scsi/qedi/qedi_dbg.c @@ -0,0 +1,143 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include "qedi_dbg.h" +#include + +void +qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + char nfunc[32]; + + memset(nfunc, 0, sizeof(nfunc)); + memcpy(nfunc, func, sizeof(nfunc) - 1); + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + if (likely(qedi) && likely(qedi->pdev)) + pr_err("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), + nfunc, line, qedi->host_no, &vaf); + else + pr_err("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + + va_end(va); +} + +void +qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + char nfunc[32]; + + memset(nfunc, 0, sizeof(nfunc)); + memcpy(nfunc, func, sizeof(nfunc) - 1); + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + if (!(qedi_dbg_log & QEDI_LOG_WARN)) + return; + + if (likely(qedi) && likely(qedi->pdev)) + pr_warn("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), + nfunc, line, qedi->host_no, &vaf); + else + pr_warn("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + + va_end(va); +} + +void +qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + char nfunc[32]; + + memset(nfunc, 0, sizeof(nfunc)); + memcpy(nfunc, func, sizeof(nfunc) - 1); + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + if (!(qedi_dbg_log & QEDI_LOG_NOTICE)) + return; + + if (likely(qedi) && likely(qedi->pdev)) + pr_notice("[%s]:[%s:%d]:%d: %pV", + dev_name(&qedi->pdev->dev), nfunc, line, + qedi->host_no, &vaf); + else + pr_notice("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + + va_end(va); +} + +void +qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + u32 level, const char *fmt, ...) +{ + va_list va; + struct va_format vaf; + char nfunc[32]; + + memset(nfunc, 0, sizeof(nfunc)); + memcpy(nfunc, func, sizeof(nfunc) - 1); + + va_start(va, fmt); + + vaf.fmt = fmt; + vaf.va = &va; + + if (!(qedi_dbg_log & level)) + return; + + if (likely(qedi) && likely(qedi->pdev)) + pr_info("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev), + nfunc, line, qedi->host_no, &vaf); + else + pr_info("[0000:00:00.0]:[%s:%d]: %pV", nfunc, line, &vaf); + + va_end(va); +} + +int +qedi_create_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter) +{ + int ret = 0; + + for (; iter->name; iter++) { + ret = sysfs_create_bin_file(&shost->shost_gendev.kobj, + iter->attr); + if (ret) + pr_err("Unable to create sysfs %s attr, err(%d).\n", + iter->name, ret); + } + return ret; +} + +void +qedi_remove_sysfs_attr(struct Scsi_Host *shost, struct sysfs_bin_attrs *iter) +{ + for (; iter->name; iter++) + sysfs_remove_bin_file(&shost->shost_gendev.kobj, iter->attr); +} diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h new file mode 100644 index 000000000000..c55572badfb0 --- /dev/null +++ b/drivers/scsi/qedi/qedi_dbg.h @@ -0,0 +1,144 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QEDI_DBG_H_ +#define _QEDI_DBG_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define __PREVENT_QED_HSI__ +#include +#include + +extern uint qedi_dbg_log; + +/* Debug print level definitions */ +#define QEDI_LOG_DEFAULT 0x1 /* Set default logging mask */ +#define QEDI_LOG_INFO 0x2 /* Informational logs, + * MAC address, WWPN, WWNN + */ +#define QEDI_LOG_DISC 0x4 /* Init, discovery, rport */ +#define QEDI_LOG_LL2 0x8 /* LL2, VLAN logs */ +#define QEDI_LOG_CONN 0x10 /* Connection setup, cleanup */ +#define QEDI_LOG_EVT 0x20 /* Events, link, mtu */ +#define QEDI_LOG_TIMER 0x40 /* Timer events */ +#define QEDI_LOG_MP_REQ 0x80 /* Middle Path (MP) logs */ +#define QEDI_LOG_SCSI_TM 0x100 /* SCSI Aborts, Task Mgmt */ +#define QEDI_LOG_UNSOL 0x200 /* unsolicited event logs */ +#define QEDI_LOG_IO 0x400 /* scsi cmd, completion */ +#define QEDI_LOG_MQ 0x800 /* Multi Queue logs */ +#define QEDI_LOG_BSG 0x1000 /* BSG logs */ +#define QEDI_LOG_DEBUGFS 0x2000 /* debugFS logs */ +#define QEDI_LOG_LPORT 0x4000 /* lport logs */ +#define QEDI_LOG_ELS 0x8000 /* ELS logs */ +#define QEDI_LOG_NPIV 0x10000 /* NPIV logs */ +#define QEDI_LOG_SESS 0x20000 /* Conection setup, cleanup */ +#define QEDI_LOG_UIO 0x40000 /* iSCSI UIO logs */ +#define QEDI_LOG_TID 0x80000 /* FW TID context acquire, + * free + */ +#define QEDI_TRACK_TID 0x100000 /* Track TID state. To be + * enabled only at module load + * and not run-time. + */ +#define QEDI_TRACK_CMD_LIST 0x300000 /* Track active cmd list nodes, + * done with reference to TID, + * hence TRACK_TID also enabled. + */ +#define QEDI_LOG_NOTICE 0x40000000 /* Notice logs */ +#define QEDI_LOG_WARN 0x80000000 /* Warning logs */ + +/* Debug context structure */ +struct qedi_dbg_ctx { + unsigned int host_no; + struct pci_dev *pdev; +#ifdef CONFIG_DEBUG_FS + struct dentry *bdf_dentry; +#endif +}; + +#define QEDI_ERR(pdev, fmt, ...) \ + qedi_dbg_err(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__) +#define QEDI_WARN(pdev, fmt, ...) \ + qedi_dbg_warn(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__) +#define QEDI_NOTICE(pdev, fmt, ...) \ + qedi_dbg_notice(pdev, __func__, __LINE__, fmt, ## __VA_ARGS__) +#define QEDI_INFO(pdev, level, fmt, ...) \ + qedi_dbg_info(pdev, __func__, __LINE__, level, fmt, \ + ## __VA_ARGS__) + +void qedi_dbg_err(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + const char *fmt, ...); +void qedi_dbg_warn(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + const char *fmt, ...); +void qedi_dbg_notice(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + const char *fmt, ...); +void qedi_dbg_info(struct qedi_dbg_ctx *qedi, const char *func, u32 line, + u32 info, const char *fmt, ...); + +struct Scsi_Host; + +struct sysfs_bin_attrs { + char *name; + struct bin_attribute *attr; +}; + +int qedi_create_sysfs_attr(struct Scsi_Host *shost, + struct sysfs_bin_attrs *iter); +void qedi_remove_sysfs_attr(struct Scsi_Host *shost, + struct sysfs_bin_attrs *iter); + +#ifdef CONFIG_DEBUG_FS +/* DebugFS related code */ +struct qedi_list_of_funcs { + char *oper_str; + ssize_t (*oper_func)(struct qedi_dbg_ctx *qedi); +}; + +struct qedi_debugfs_ops { + char *name; + struct qedi_list_of_funcs *qedi_funcs; +}; + +#define qedi_dbg_fileops(drv, ops) \ +{ \ + .owner = THIS_MODULE, \ + .open = simple_open, \ + .read = drv##_dbg_##ops##_cmd_read, \ + .write = drv##_dbg_##ops##_cmd_write \ +} + +/* Used for debugfs sequential files */ +#define qedi_dbg_fileops_seq(drv, ops) \ +{ \ + .owner = THIS_MODULE, \ + .open = drv##_dbg_##ops##_open, \ + .read = seq_read, \ + .llseek = seq_lseek, \ + .release = single_release, \ +} + +void qedi_dbg_host_init(struct qedi_dbg_ctx *qedi, + struct qedi_debugfs_ops *dops, + const struct file_operations *fops); +void qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi); +void qedi_dbg_init(char *drv_name); +void qedi_dbg_exit(void); +#endif /* CONFIG_DEBUG_FS */ + +#endif /* _QEDI_DBG_H_ */ diff --git a/drivers/scsi/qedi/qedi_debugfs.c b/drivers/scsi/qedi/qedi_debugfs.c new file mode 100644 index 000000000000..955936274241 --- /dev/null +++ b/drivers/scsi/qedi/qedi_debugfs.c @@ -0,0 +1,244 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include "qedi.h" +#include "qedi_dbg.h" + +#include +#include +#include + +int do_not_recover; +static struct dentry *qedi_dbg_root; + +void +qedi_dbg_host_init(struct qedi_dbg_ctx *qedi, + struct qedi_debugfs_ops *dops, + const struct file_operations *fops) +{ + char host_dirname[32]; + struct dentry *file_dentry = NULL; + + sprintf(host_dirname, "host%u", qedi->host_no); + qedi->bdf_dentry = debugfs_create_dir(host_dirname, qedi_dbg_root); + if (!qedi->bdf_dentry) + return; + + while (dops) { + if (!(dops->name)) + break; + + file_dentry = debugfs_create_file(dops->name, 0600, + qedi->bdf_dentry, qedi, + fops); + if (!file_dentry) { + QEDI_INFO(qedi, QEDI_LOG_DEBUGFS, + "Debugfs entry %s creation failed\n", + dops->name); + debugfs_remove_recursive(qedi->bdf_dentry); + return; + } + dops++; + fops++; + } +} + +void +qedi_dbg_host_exit(struct qedi_dbg_ctx *qedi) +{ + debugfs_remove_recursive(qedi->bdf_dentry); + qedi->bdf_dentry = NULL; +} + +void +qedi_dbg_init(char *drv_name) +{ + qedi_dbg_root = debugfs_create_dir(drv_name, NULL); + if (!qedi_dbg_root) + QEDI_INFO(NULL, QEDI_LOG_DEBUGFS, "Init of debugfs failed\n"); +} + +void +qedi_dbg_exit(void) +{ + debugfs_remove_recursive(qedi_dbg_root); + qedi_dbg_root = NULL; +} + +static ssize_t +qedi_dbg_do_not_recover_enable(struct qedi_dbg_ctx *qedi_dbg) +{ + if (!do_not_recover) + do_not_recover = 1; + + QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n", + do_not_recover); + return 0; +} + +static ssize_t +qedi_dbg_do_not_recover_disable(struct qedi_dbg_ctx *qedi_dbg) +{ + if (do_not_recover) + do_not_recover = 0; + + QEDI_INFO(qedi_dbg, QEDI_LOG_DEBUGFS, "do_not_recover=%d\n", + do_not_recover); + return 0; +} + +static struct qedi_list_of_funcs qedi_dbg_do_not_recover_ops[] = { + { "enable", qedi_dbg_do_not_recover_enable }, + { "disable", qedi_dbg_do_not_recover_disable }, + { NULL, NULL } +}; + +struct qedi_debugfs_ops qedi_debugfs_ops[] = { + { "gbl_ctx", NULL }, + { "do_not_recover", qedi_dbg_do_not_recover_ops}, + { "io_trace", NULL }, + { NULL, NULL } +}; + +static ssize_t +qedi_dbg_do_not_recover_cmd_write(struct file *filp, const char __user *buffer, + size_t count, loff_t *ppos) +{ + size_t cnt = 0; + struct qedi_dbg_ctx *qedi_dbg = + (struct qedi_dbg_ctx *)filp->private_data; + struct qedi_list_of_funcs *lof = qedi_dbg_do_not_recover_ops; + + if (*ppos) + return 0; + + while (lof) { + if (!(lof->oper_str)) + break; + + if (!strncmp(lof->oper_str, buffer, strlen(lof->oper_str))) { + cnt = lof->oper_func(qedi_dbg); + break; + } + + lof++; + } + return (count - cnt); +} + +static ssize_t +qedi_dbg_do_not_recover_cmd_read(struct file *filp, char __user *buffer, + size_t count, loff_t *ppos) +{ + size_t cnt = 0; + + if (*ppos) + return 0; + + cnt = sprintf(buffer, "do_not_recover=%d\n", do_not_recover); + cnt = min_t(int, count, cnt - *ppos); + *ppos += cnt; + return cnt; +} + +static int +qedi_gbl_ctx_show(struct seq_file *s, void *unused) +{ + struct qedi_fastpath *fp = NULL; + struct qed_sb_info *sb_info = NULL; + struct status_block *sb = NULL; + struct global_queue *que = NULL; + int id; + u16 prod_idx; + struct qedi_ctx *qedi = s->private; + unsigned long flags; + + seq_puts(s, " DUMP CQ CONTEXT:\n"); + + for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { + spin_lock_irqsave(&qedi->hba_lock, flags); + seq_printf(s, "=========FAST CQ PATH [%d] ==========\n", id); + fp = &qedi->fp_array[id]; + sb_info = fp->sb_info; + sb = sb_info->sb_virt; + prod_idx = (sb->pi_array[QEDI_PROTO_CQ_PROD_IDX] & + STATUS_BLOCK_PROD_INDEX_MASK); + seq_printf(s, "SB PROD IDX: %d\n", prod_idx); + que = qedi->global_queues[fp->sb_id]; + seq_printf(s, "DRV CONS IDX: %d\n", que->cq_cons_idx); + seq_printf(s, "CQ complete host memory: %d\n", fp->sb_id); + seq_puts(s, "=========== END ==================\n\n\n"); + spin_unlock_irqrestore(&qedi->hba_lock, flags); + } + return 0; +} + +static int +qedi_dbg_gbl_ctx_open(struct inode *inode, struct file *file) +{ + struct qedi_dbg_ctx *qedi_dbg = inode->i_private; + struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx, + dbg_ctx); + + return single_open(file, qedi_gbl_ctx_show, qedi); +} + +static int +qedi_io_trace_show(struct seq_file *s, void *unused) +{ + int id, idx = 0; + struct qedi_ctx *qedi = s->private; + struct qedi_io_log *io_log; + unsigned long flags; + + seq_puts(s, " DUMP IO LOGS:\n"); + spin_lock_irqsave(&qedi->io_trace_lock, flags); + idx = qedi->io_trace_idx; + for (id = 0; id < QEDI_IO_TRACE_SIZE; id++) { + io_log = &qedi->io_trace_buf[idx]; + seq_printf(s, "iodir-%d:", io_log->direction); + seq_printf(s, "tid-0x%x:", io_log->task_id); + seq_printf(s, "cid-0x%x:", io_log->cid); + seq_printf(s, "lun-%d:", io_log->lun); + seq_printf(s, "op-0x%02x:", io_log->op); + seq_printf(s, "0x%02x%02x%02x%02x:", io_log->lba[0], + io_log->lba[1], io_log->lba[2], io_log->lba[3]); + seq_printf(s, "buflen-%d:", io_log->bufflen); + seq_printf(s, "sgcnt-%d:", io_log->sg_count); + seq_printf(s, "res-0x%08x:", io_log->result); + seq_printf(s, "jif-%lu:", io_log->jiffies); + seq_printf(s, "blk_req_cpu-%d:", io_log->blk_req_cpu); + seq_printf(s, "req_cpu-%d:", io_log->req_cpu); + seq_printf(s, "intr_cpu-%d:", io_log->intr_cpu); + seq_printf(s, "blk_rsp_cpu-%d\n", io_log->blk_rsp_cpu); + + idx++; + if (idx == QEDI_IO_TRACE_SIZE) + idx = 0; + } + spin_unlock_irqrestore(&qedi->io_trace_lock, flags); + return 0; +} + +static int +qedi_dbg_io_trace_open(struct inode *inode, struct file *file) +{ + struct qedi_dbg_ctx *qedi_dbg = inode->i_private; + struct qedi_ctx *qedi = container_of(qedi_dbg, struct qedi_ctx, + dbg_ctx); + + return single_open(file, qedi_io_trace_show, qedi); +} + +const struct file_operations qedi_dbg_fops[] = { + qedi_dbg_fileops_seq(qedi, gbl_ctx), + qedi_dbg_fileops(qedi, do_not_recover), + qedi_dbg_fileops_seq(qedi, io_trace), + { NULL, NULL }, +}; diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c new file mode 100644 index 000000000000..b1d3904ae8fd --- /dev/null +++ b/drivers/scsi/qedi/qedi_fw.c @@ -0,0 +1,2378 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include + +#include "qedi.h" +#include "qedi_iscsi.h" +#include "qedi_gbl.h" + +static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, + struct iscsi_task *mtask); + +void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd) +{ + struct scsi_cmnd *sc = cmd->scsi_cmd; + + if (cmd->io_tbl.sge_valid && sc) { + cmd->io_tbl.sge_valid = 0; + scsi_dma_unmap(sc); + } +} + +static void qedi_process_logout_resp(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_logout_rsp *resp_hdr; + struct iscsi_session *session = conn->session; + struct iscsi_logout_response_hdr *cqe_logout_response; + struct qedi_cmd *cmd; + + cmd = (struct qedi_cmd *)task->dd_data; + cqe_logout_response = &cqe->cqe_common.iscsi_hdr.logout_response; + spin_lock(&session->back_lock); + resp_hdr = (struct iscsi_logout_rsp *)&qedi_conn->gen_pdu.resp_hdr; + memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); + resp_hdr->opcode = cqe_logout_response->opcode; + resp_hdr->flags = cqe_logout_response->flags; + resp_hdr->hlength = 0; + + resp_hdr->itt = build_itt(cqe->cqe_solicited.itid, conn->session->age); + resp_hdr->statsn = cpu_to_be32(cqe_logout_response->stat_sn); + resp_hdr->exp_cmdsn = cpu_to_be32(cqe_logout_response->exp_cmd_sn); + resp_hdr->max_cmdsn = cpu_to_be32(cqe_logout_response->max_cmd_sn); + + resp_hdr->t2wait = cpu_to_be32(cqe_logout_response->time2wait); + resp_hdr->t2retain = cpu_to_be32(cqe_logout_response->time2retain); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID, + "Freeing tid=0x%x for cid=0x%x\n", + cmd->task_id, qedi_conn->iscsi_conn_id); + + if (likely(cmd->io_cmd_in_list)) { + cmd->io_cmd_in_list = false; + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + } else { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Active cmd list node already deleted, tid=0x%x, cid=0x%x, io_cmd_node=%p\n", + cmd->task_id, qedi_conn->iscsi_conn_id, + &cmd->io_cmd); + } + + cmd->state = RESPONSE_RECEIVED; + qedi_clear_task_idx(qedi, cmd->task_id); + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0); + + spin_unlock(&session->back_lock); +} + +static void qedi_process_text_resp(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_task_context *task_ctx; + struct iscsi_text_rsp *resp_hdr_ptr; + struct iscsi_text_response_hdr *cqe_text_response; + struct qedi_cmd *cmd; + int pld_len; + u32 *tmp; + + cmd = (struct qedi_cmd *)task->dd_data; + task_ctx = qedi_get_task_mem(&qedi->tasks, cmd->task_id); + + cqe_text_response = &cqe->cqe_common.iscsi_hdr.text_response; + spin_lock(&session->back_lock); + resp_hdr_ptr = (struct iscsi_text_rsp *)&qedi_conn->gen_pdu.resp_hdr; + memset(resp_hdr_ptr, 0, sizeof(struct iscsi_hdr)); + resp_hdr_ptr->opcode = cqe_text_response->opcode; + resp_hdr_ptr->flags = cqe_text_response->flags; + resp_hdr_ptr->hlength = 0; + + hton24(resp_hdr_ptr->dlength, + (cqe_text_response->hdr_second_dword & + ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK)); + tmp = (u32 *)resp_hdr_ptr->dlength; + + resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid, + conn->session->age); + resp_hdr_ptr->ttt = cqe_text_response->ttt; + resp_hdr_ptr->statsn = cpu_to_be32(cqe_text_response->stat_sn); + resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_text_response->exp_cmd_sn); + resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_text_response->max_cmd_sn); + + pld_len = cqe_text_response->hdr_second_dword & + ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK; + qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len; + + memset(task_ctx, '\0', sizeof(*task_ctx)); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID, + "Freeing tid=0x%x for cid=0x%x\n", + cmd->task_id, qedi_conn->iscsi_conn_id); + + if (likely(cmd->io_cmd_in_list)) { + cmd->io_cmd_in_list = false; + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + } else { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Active cmd list node already deleted, tid=0x%x, cid=0x%x, io_cmd_node=%p\n", + cmd->task_id, qedi_conn->iscsi_conn_id, + &cmd->io_cmd); + } + + cmd->state = RESPONSE_RECEIVED; + qedi_clear_task_idx(qedi, cmd->task_id); + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, + qedi_conn->gen_pdu.resp_buf, + (qedi_conn->gen_pdu.resp_wr_ptr - + qedi_conn->gen_pdu.resp_buf)); + spin_unlock(&session->back_lock); +} + +static void qedi_tmf_resp_work(struct work_struct *work) +{ + struct qedi_cmd *qedi_cmd = + container_of(work, struct qedi_cmd, tmf_work); + struct qedi_conn *qedi_conn = qedi_cmd->conn; + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_tm_rsp *resp_hdr_ptr; + struct iscsi_cls_session *cls_sess; + int rval = 0; + + set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + resp_hdr_ptr = (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf; + cls_sess = iscsi_conn_to_session(qedi_conn->cls_conn); + + iscsi_block_session(session->cls_session); + rval = qedi_cleanup_all_io(qedi, qedi_conn, qedi_cmd->task, true); + if (rval) { + clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + qedi_clear_task_idx(qedi, qedi_cmd->task_id); + iscsi_unblock_session(session->cls_session); + return; + } + + iscsi_unblock_session(session->cls_session); + qedi_clear_task_idx(qedi, qedi_cmd->task_id); + + spin_lock(&session->back_lock); + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0); + spin_unlock(&session->back_lock); + kfree(resp_hdr_ptr); + clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); +} + +static void qedi_process_tmf_resp(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn) + +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_tmf_response_hdr *cqe_tmp_response; + struct iscsi_tm_rsp *resp_hdr_ptr; + struct iscsi_tm *tmf_hdr; + struct qedi_cmd *qedi_cmd = NULL; + u32 *tmp; + + cqe_tmp_response = &cqe->cqe_common.iscsi_hdr.tmf_response; + + qedi_cmd = task->dd_data; + qedi_cmd->tmf_resp_buf = kzalloc(sizeof(*resp_hdr_ptr), GFP_KERNEL); + if (!qedi_cmd->tmf_resp_buf) { + QEDI_ERR(&qedi->dbg_ctx, + "Failed to allocate resp buf, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + return; + } + + spin_lock(&session->back_lock); + resp_hdr_ptr = (struct iscsi_tm_rsp *)qedi_cmd->tmf_resp_buf; + memset(resp_hdr_ptr, 0, sizeof(struct iscsi_tm_rsp)); + + /* Fill up the header */ + resp_hdr_ptr->opcode = cqe_tmp_response->opcode; + resp_hdr_ptr->flags = cqe_tmp_response->hdr_flags; + resp_hdr_ptr->response = cqe_tmp_response->hdr_response; + resp_hdr_ptr->hlength = 0; + + hton24(resp_hdr_ptr->dlength, + (cqe_tmp_response->hdr_second_dword & + ISCSI_TMF_RESPONSE_HDR_DATA_SEG_LEN_MASK)); + tmp = (u32 *)resp_hdr_ptr->dlength; + resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid, + conn->session->age); + resp_hdr_ptr->statsn = cpu_to_be32(cqe_tmp_response->stat_sn); + resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_tmp_response->exp_cmd_sn); + resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_tmp_response->max_cmd_sn); + + tmf_hdr = (struct iscsi_tm *)qedi_cmd->task->hdr; + + if (likely(qedi_cmd->io_cmd_in_list)) { + qedi_cmd->io_cmd_in_list = false; + list_del_init(&qedi_cmd->io_cmd); + qedi_conn->active_cmd_count--; + } + + if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) || + ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_TARGET_WARM_RESET) || + ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_TARGET_COLD_RESET)) { + INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_resp_work); + queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work); + goto unblock_sess; + } + + qedi_clear_task_idx(qedi, qedi_cmd->task_id); + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, NULL, 0); + kfree(resp_hdr_ptr); + +unblock_sess: + spin_unlock(&session->back_lock); +} + +static void qedi_process_login_resp(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_task_context *task_ctx; + struct iscsi_login_rsp *resp_hdr_ptr; + struct iscsi_login_response_hdr *cqe_login_response; + struct qedi_cmd *cmd; + int pld_len; + u32 *tmp; + + cmd = (struct qedi_cmd *)task->dd_data; + + cqe_login_response = &cqe->cqe_common.iscsi_hdr.login_response; + task_ctx = qedi_get_task_mem(&qedi->tasks, cmd->task_id); + + spin_lock(&session->back_lock); + resp_hdr_ptr = (struct iscsi_login_rsp *)&qedi_conn->gen_pdu.resp_hdr; + memset(resp_hdr_ptr, 0, sizeof(struct iscsi_login_rsp)); + resp_hdr_ptr->opcode = cqe_login_response->opcode; + resp_hdr_ptr->flags = cqe_login_response->flags_attr; + resp_hdr_ptr->hlength = 0; + + hton24(resp_hdr_ptr->dlength, + (cqe_login_response->hdr_second_dword & + ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK)); + tmp = (u32 *)resp_hdr_ptr->dlength; + resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid, + conn->session->age); + resp_hdr_ptr->tsih = cqe_login_response->tsih; + resp_hdr_ptr->statsn = cpu_to_be32(cqe_login_response->stat_sn); + resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_login_response->exp_cmd_sn); + resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_login_response->max_cmd_sn); + resp_hdr_ptr->status_class = cqe_login_response->status_class; + resp_hdr_ptr->status_detail = cqe_login_response->status_detail; + pld_len = cqe_login_response->hdr_second_dword & + ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK; + qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len; + + if (likely(cmd->io_cmd_in_list)) { + cmd->io_cmd_in_list = false; + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + } + + memset(task_ctx, '\0', sizeof(*task_ctx)); + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr, + qedi_conn->gen_pdu.resp_buf, + (qedi_conn->gen_pdu.resp_wr_ptr - + qedi_conn->gen_pdu.resp_buf)); + + spin_unlock(&session->back_lock); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID, + "Freeing tid=0x%x for cid=0x%x\n", + cmd->task_id, qedi_conn->iscsi_conn_id); + cmd->state = RESPONSE_RECEIVED; + qedi_clear_task_idx(qedi, cmd->task_id); +} + +static void qedi_get_rq_bdq_buf(struct qedi_ctx *qedi, + struct iscsi_cqe_unsolicited *cqe, + char *ptr, int len) +{ + u16 idx = 0; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "pld_len [%d], bdq_prod_idx [%d], idx [%d]\n", + len, qedi->bdq_prod_idx, + (qedi->bdq_prod_idx % qedi->rq_num_entries)); + + /* Obtain buffer address from rqe_opaque */ + idx = cqe->rqe_opaque.lo; + if ((idx < 0) || (idx > (QEDI_BDQ_NUM - 1))) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "wrong idx %d returned by FW, dropping the unsolicited pkt\n", + idx); + return; + } + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "rqe_opaque.lo [0x%p], rqe_opaque.hi [0x%p], idx [%d]\n", + cqe->rqe_opaque.lo, cqe->rqe_opaque.hi, idx); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "unsol_cqe_type = %d\n", cqe->unsol_cqe_type); + switch (cqe->unsol_cqe_type) { + case ISCSI_CQE_UNSOLICITED_SINGLE: + case ISCSI_CQE_UNSOLICITED_FIRST: + if (len) + memcpy(ptr, (void *)qedi->bdq[idx].buf_addr, len); + break; + case ISCSI_CQE_UNSOLICITED_MIDDLE: + case ISCSI_CQE_UNSOLICITED_LAST: + break; + default: + break; + } +} + +static void qedi_put_rq_bdq_buf(struct qedi_ctx *qedi, + struct iscsi_cqe_unsolicited *cqe, + int count) +{ + u16 tmp; + u16 idx = 0; + struct scsi_bd *pbl; + + /* Obtain buffer address from rqe_opaque */ + idx = cqe->rqe_opaque.lo; + if ((idx < 0) || (idx > (QEDI_BDQ_NUM - 1))) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "wrong idx %d returned by FW, dropping the unsolicited pkt\n", + idx); + return; + } + + pbl = (struct scsi_bd *)qedi->bdq_pbl; + pbl += (qedi->bdq_prod_idx % qedi->rq_num_entries); + pbl->address.hi = cpu_to_le32(QEDI_U64_HI(qedi->bdq[idx].buf_dma)); + pbl->address.lo = cpu_to_le32(QEDI_U64_LO(qedi->bdq[idx].buf_dma)); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx] idx [%d]\n", + pbl, pbl->address.hi, pbl->address.lo, idx); + pbl->opaque.hi = 0; + pbl->opaque.lo = cpu_to_le32(QEDI_U64_LO(idx)); + + /* Increment producer to let f/w know we've handled the frame */ + qedi->bdq_prod_idx += count; + + writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod); + tmp = readw(qedi->bdq_primary_prod); + + writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod); + tmp = readw(qedi->bdq_secondary_prod); +} + +static void qedi_unsol_pdu_adjust_bdq(struct qedi_ctx *qedi, + struct iscsi_cqe_unsolicited *cqe, + u32 pdu_len, u32 num_bdqs, + char *bdq_data) +{ + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "num_bdqs [%d]\n", num_bdqs); + + qedi_get_rq_bdq_buf(qedi, cqe, bdq_data, pdu_len); + qedi_put_rq_bdq_buf(qedi, cqe, (num_bdqs + 1)); +} + +static int qedi_process_nopin_mesg(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn, u16 que_idx) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_nop_in_hdr *cqe_nop_in; + struct iscsi_nopin *hdr; + struct qedi_cmd *cmd; + int tgt_async_nop = 0; + u32 lun[2]; + u32 pdu_len, num_bdqs; + char bdq_data[QEDI_BDQ_BUF_SIZE]; + unsigned long flags; + + spin_lock_bh(&session->back_lock); + cqe_nop_in = &cqe->cqe_common.iscsi_hdr.nop_in; + + pdu_len = cqe_nop_in->hdr_second_dword & + ISCSI_NOP_IN_HDR_DATA_SEG_LEN_MASK; + num_bdqs = pdu_len / QEDI_BDQ_BUF_SIZE; + + hdr = (struct iscsi_nopin *)&qedi_conn->gen_pdu.resp_hdr; + memset(hdr, 0, sizeof(struct iscsi_hdr)); + hdr->opcode = cqe_nop_in->opcode; + hdr->max_cmdsn = cpu_to_be32(cqe_nop_in->max_cmd_sn); + hdr->exp_cmdsn = cpu_to_be32(cqe_nop_in->exp_cmd_sn); + hdr->statsn = cpu_to_be32(cqe_nop_in->stat_sn); + hdr->ttt = cpu_to_be32(cqe_nop_in->ttt); + + if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) { + spin_lock_irqsave(&qedi->hba_lock, flags); + qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited, + pdu_len, num_bdqs, bdq_data); + hdr->itt = RESERVED_ITT; + tgt_async_nop = 1; + spin_unlock_irqrestore(&qedi->hba_lock, flags); + goto done; + } + + /* Response to one of our nop-outs */ + if (task) { + cmd = task->dd_data; + hdr->flags = ISCSI_FLAG_CMD_FINAL; + hdr->itt = build_itt(cqe->cqe_solicited.itid, + conn->session->age); + lun[0] = 0xffffffff; + lun[1] = 0xffffffff; + memcpy(&hdr->lun, lun, sizeof(struct scsi_lun)); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID, + "Freeing tid=0x%x for cid=0x%x\n", + cmd->task_id, qedi_conn->iscsi_conn_id); + cmd->state = RESPONSE_RECEIVED; + spin_lock(&qedi_conn->list_lock); + if (likely(cmd->io_cmd_in_list)) { + cmd->io_cmd_in_list = false; + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + } + + spin_unlock(&qedi_conn->list_lock); + qedi_clear_task_idx(qedi, cmd->task_id); + } + +done: + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, bdq_data, pdu_len); + + spin_unlock_bh(&session->back_lock); + return tgt_async_nop; +} + +static void qedi_process_async_mesg(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn, + u16 que_idx) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_async_msg_hdr *cqe_async_msg; + struct iscsi_async *resp_hdr; + u32 lun[2]; + u32 pdu_len, num_bdqs; + char bdq_data[QEDI_BDQ_BUF_SIZE]; + unsigned long flags; + + spin_lock_bh(&session->back_lock); + + cqe_async_msg = &cqe->cqe_common.iscsi_hdr.async_msg; + pdu_len = cqe_async_msg->hdr_second_dword & + ISCSI_ASYNC_MSG_HDR_DATA_SEG_LEN_MASK; + num_bdqs = pdu_len / QEDI_BDQ_BUF_SIZE; + + if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) { + spin_lock_irqsave(&qedi->hba_lock, flags); + qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited, + pdu_len, num_bdqs, bdq_data); + spin_unlock_irqrestore(&qedi->hba_lock, flags); + } + + resp_hdr = (struct iscsi_async *)&qedi_conn->gen_pdu.resp_hdr; + memset(resp_hdr, 0, sizeof(struct iscsi_hdr)); + resp_hdr->opcode = cqe_async_msg->opcode; + resp_hdr->flags = 0x80; + + lun[0] = cpu_to_be32(cqe_async_msg->lun.lo); + lun[1] = cpu_to_be32(cqe_async_msg->lun.hi); + memcpy(&resp_hdr->lun, lun, sizeof(struct scsi_lun)); + resp_hdr->exp_cmdsn = cpu_to_be32(cqe_async_msg->exp_cmd_sn); + resp_hdr->max_cmdsn = cpu_to_be32(cqe_async_msg->max_cmd_sn); + resp_hdr->statsn = cpu_to_be32(cqe_async_msg->stat_sn); + + resp_hdr->async_event = cqe_async_msg->async_event; + resp_hdr->async_vcode = cqe_async_msg->async_vcode; + + resp_hdr->param1 = cpu_to_be16(cqe_async_msg->param1_rsrv); + resp_hdr->param2 = cpu_to_be16(cqe_async_msg->param2_rsrv); + resp_hdr->param3 = cpu_to_be16(cqe_async_msg->param3_rsrv); + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, bdq_data, + pdu_len); + + spin_unlock_bh(&session->back_lock); +} + +static void qedi_process_reject_mesg(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn, + uint16_t que_idx) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_reject_hdr *cqe_reject; + struct iscsi_reject *hdr; + u32 pld_len, num_bdqs; + unsigned long flags; + + spin_lock_bh(&session->back_lock); + cqe_reject = &cqe->cqe_common.iscsi_hdr.reject; + pld_len = cqe_reject->hdr_second_dword & + ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK; + num_bdqs = pld_len / QEDI_BDQ_BUF_SIZE; + + if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) { + spin_lock_irqsave(&qedi->hba_lock, flags); + qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited, + pld_len, num_bdqs, conn->data); + spin_unlock_irqrestore(&qedi->hba_lock, flags); + } + hdr = (struct iscsi_reject *)&qedi_conn->gen_pdu.resp_hdr; + memset(hdr, 0, sizeof(struct iscsi_hdr)); + hdr->opcode = cqe_reject->opcode; + hdr->reason = cqe_reject->hdr_reason; + hdr->flags = cqe_reject->hdr_flags; + hton24(hdr->dlength, (cqe_reject->hdr_second_dword & + ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK)); + hdr->max_cmdsn = cpu_to_be32(cqe_reject->max_cmd_sn); + hdr->exp_cmdsn = cpu_to_be32(cqe_reject->exp_cmd_sn); + hdr->statsn = cpu_to_be32(cqe_reject->stat_sn); + hdr->ffffffff = cpu_to_be32(0xffffffff); + + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, + conn->data, pld_len); + spin_unlock_bh(&session->back_lock); +} + +static void qedi_scsi_completion(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct iscsi_conn *conn) +{ + struct scsi_cmnd *sc_cmd; + struct qedi_cmd *cmd = task->dd_data; + struct iscsi_session *session = conn->session; + struct iscsi_scsi_rsp *hdr; + struct iscsi_data_in_hdr *cqe_data_in; + int datalen = 0; + struct qedi_conn *qedi_conn; + u32 iscsi_cid; + bool mark_cmd_node_deleted = false; + u8 cqe_err_bits = 0; + + iscsi_cid = cqe->cqe_common.conn_id; + qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; + + cqe_data_in = &cqe->cqe_common.iscsi_hdr.data_in; + cqe_err_bits = + cqe->cqe_common.error_bitmap.error_bits.cqe_error_status_bits; + + spin_lock_bh(&session->back_lock); + /* get the scsi command */ + sc_cmd = cmd->scsi_cmd; + + if (!sc_cmd) { + QEDI_WARN(&qedi->dbg_ctx, "sc_cmd is NULL!\n"); + goto error; + } + + if (!sc_cmd->SCp.ptr) { + QEDI_WARN(&qedi->dbg_ctx, + "SCp.ptr is NULL, returned in another context.\n"); + goto error; + } + + if (!sc_cmd->request) { + QEDI_WARN(&qedi->dbg_ctx, + "sc_cmd->request is NULL, sc_cmd=%p.\n", + sc_cmd); + goto error; + } + + if (!sc_cmd->request->special) { + QEDI_WARN(&qedi->dbg_ctx, + "request->special is NULL so request not valid, sc_cmd=%p.\n", + sc_cmd); + goto error; + } + + if (!sc_cmd->request->q) { + QEDI_WARN(&qedi->dbg_ctx, + "request->q is NULL so request is not valid, sc_cmd=%p.\n", + sc_cmd); + goto error; + } + + qedi_iscsi_unmap_sg_list(cmd); + + hdr = (struct iscsi_scsi_rsp *)task->hdr; + hdr->opcode = cqe_data_in->opcode; + hdr->max_cmdsn = cpu_to_be32(cqe_data_in->max_cmd_sn); + hdr->exp_cmdsn = cpu_to_be32(cqe_data_in->exp_cmd_sn); + hdr->itt = build_itt(cqe->cqe_solicited.itid, conn->session->age); + hdr->response = cqe_data_in->reserved1; + hdr->cmd_status = cqe_data_in->status_rsvd; + hdr->flags = cqe_data_in->flags; + hdr->residual_count = cpu_to_be32(cqe_data_in->residual_count); + + if (hdr->cmd_status == SAM_STAT_CHECK_CONDITION) { + datalen = cqe_data_in->reserved2 & + ISCSI_COMMON_HDR_DATA_SEG_LEN_MASK; + memcpy((char *)conn->data, (char *)cmd->sense_buffer, datalen); + } + + /* If f/w reports data underrun err then set residual to IO transfer + * length, set Underrun flag and clear Overrun flag explicitly + */ + if (unlikely(cqe_err_bits && + GET_FIELD(cqe_err_bits, CQE_ERROR_BITMAP_UNDER_RUN_ERR))) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Under flow itt=0x%x proto flags=0x%x tid=0x%x cid 0x%x fw resid 0x%x sc dlen 0x%x\n", + hdr->itt, cqe_data_in->flags, cmd->task_id, + qedi_conn->iscsi_conn_id, hdr->residual_count, + scsi_bufflen(sc_cmd)); + hdr->residual_count = cpu_to_be32(scsi_bufflen(sc_cmd)); + hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW; + hdr->flags &= (~ISCSI_FLAG_CMD_OVERFLOW); + } + + spin_lock(&qedi_conn->list_lock); + if (likely(cmd->io_cmd_in_list)) { + cmd->io_cmd_in_list = false; + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + mark_cmd_node_deleted = true; + } + spin_unlock(&qedi_conn->list_lock); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID, + "Freeing tid=0x%x for cid=0x%x\n", + cmd->task_id, qedi_conn->iscsi_conn_id); + cmd->state = RESPONSE_RECEIVED; + if (qedi_io_tracing) + qedi_trace_io(qedi, task, cmd->task_id, QEDI_IO_TRACE_RSP); + + qedi_clear_task_idx(qedi, cmd->task_id); + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, + conn->data, datalen); +error: + spin_unlock_bh(&session->back_lock); +} + +static void qedi_mtask_completion(struct qedi_ctx *qedi, + union iscsi_cqe *cqe, + struct iscsi_task *task, + struct qedi_conn *conn, uint16_t que_idx) +{ + struct iscsi_conn *iscsi_conn; + u32 hdr_opcode; + + hdr_opcode = cqe->cqe_common.iscsi_hdr.common.hdr_first_byte; + iscsi_conn = conn->cls_conn->dd_data; + + switch (hdr_opcode) { + case ISCSI_OPCODE_SCSI_RESPONSE: + case ISCSI_OPCODE_DATA_IN: + qedi_scsi_completion(qedi, cqe, task, iscsi_conn); + break; + case ISCSI_OPCODE_LOGIN_RESPONSE: + qedi_process_login_resp(qedi, cqe, task, conn); + break; + case ISCSI_OPCODE_TMF_RESPONSE: + qedi_process_tmf_resp(qedi, cqe, task, conn); + break; + case ISCSI_OPCODE_TEXT_RESPONSE: + qedi_process_text_resp(qedi, cqe, task, conn); + break; + case ISCSI_OPCODE_LOGOUT_RESPONSE: + qedi_process_logout_resp(qedi, cqe, task, conn); + break; + case ISCSI_OPCODE_NOP_IN: + qedi_process_nopin_mesg(qedi, cqe, task, conn, que_idx); + break; + default: + QEDI_ERR(&qedi->dbg_ctx, "unknown opcode\n"); + } +} + +static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi, + struct iscsi_cqe_solicited *cqe, + struct iscsi_task *task, + struct qedi_conn *qedi_conn) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + struct qedi_cmd *cmd = task->dd_data; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UNSOL, + "itid=0x%x, cmd task id=0x%x\n", + cqe->itid, cmd->task_id); + + cmd->state = RESPONSE_RECEIVED; + qedi_clear_task_idx(qedi, cmd->task_id); + + spin_lock_bh(&session->back_lock); + __iscsi_put_task(task); + spin_unlock_bh(&session->back_lock); +} + +static void qedi_process_cmd_cleanup_resp(struct qedi_ctx *qedi, + struct iscsi_cqe_solicited *cqe, + struct iscsi_task *task, + struct iscsi_conn *conn) +{ + struct qedi_work_map *work, *work_tmp; + u32 proto_itt = cqe->itid; + u32 ptmp_itt = 0; + itt_t protoitt = 0; + int found = 0; + struct qedi_cmd *qedi_cmd = NULL; + u32 rtid = 0; + u32 iscsi_cid; + struct qedi_conn *qedi_conn; + struct qedi_cmd *cmd_new, *dbg_cmd; + struct iscsi_task *mtask; + struct iscsi_tm *tmf_hdr = NULL; + + iscsi_cid = cqe->conn_id; + qedi_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; + + /* Based on this itt get the corresponding qedi_cmd */ + spin_lock_bh(&qedi_conn->tmf_work_lock); + list_for_each_entry_safe(work, work_tmp, &qedi_conn->tmf_work_list, + list) { + if (work->rtid == proto_itt) { + /* We found the command */ + qedi_cmd = work->qedi_cmd; + if (!qedi_cmd->list_tmf_work) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "TMF work not found, cqe->tid=0x%x, cid=0x%x\n", + proto_itt, qedi_conn->iscsi_conn_id); + WARN_ON(1); + } + found = 1; + mtask = qedi_cmd->task; + tmf_hdr = (struct iscsi_tm *)mtask->hdr; + rtid = work->rtid; + + list_del_init(&work->list); + kfree(work); + qedi_cmd->list_tmf_work = NULL; + } + } + spin_unlock_bh(&qedi_conn->tmf_work_lock); + + if (found) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "TMF work, cqe->tid=0x%x, tmf flags=0x%x, cid=0x%x\n", + proto_itt, tmf_hdr->flags, qedi_conn->iscsi_conn_id); + + if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_ABORT_TASK) { + spin_lock_bh(&conn->session->back_lock); + + protoitt = build_itt(get_itt(tmf_hdr->rtt), + conn->session->age); + task = iscsi_itt_to_task(conn, protoitt); + + spin_unlock_bh(&conn->session->back_lock); + + if (!task) { + QEDI_NOTICE(&qedi->dbg_ctx, + "IO task completed, tmf rtt=0x%x, cid=0x%x\n", + get_itt(tmf_hdr->rtt), + qedi_conn->iscsi_conn_id); + return; + } + + dbg_cmd = task->dd_data; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "Abort tmf rtt=0x%x, i/o itt=0x%x, i/o tid=0x%x, cid=0x%x\n", + get_itt(tmf_hdr->rtt), get_itt(task->itt), + dbg_cmd->task_id, qedi_conn->iscsi_conn_id); + + if (qedi_cmd->state == CLEANUP_WAIT_FAILED) + qedi_cmd->state = CLEANUP_RECV; + + qedi_clear_task_idx(qedi_conn->qedi, rtid); + + spin_lock(&qedi_conn->list_lock); + list_del_init(&dbg_cmd->io_cmd); + qedi_conn->active_cmd_count--; + spin_unlock(&qedi_conn->list_lock); + qedi_cmd->state = CLEANUP_RECV; + wake_up_interruptible(&qedi_conn->wait_queue); + } + } else if (qedi_conn->cmd_cleanup_req > 0) { + spin_lock_bh(&conn->session->back_lock); + qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt); + protoitt = build_itt(ptmp_itt, conn->session->age); + task = iscsi_itt_to_task(conn, protoitt); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "cleanup io itid=0x%x, protoitt=0x%x, cmd_cleanup_cmpl=%d, cid=0x%x\n", + cqe->itid, protoitt, qedi_conn->cmd_cleanup_cmpl, + qedi_conn->iscsi_conn_id); + + spin_unlock_bh(&conn->session->back_lock); + if (!task) { + QEDI_NOTICE(&qedi->dbg_ctx, + "task is null, itid=0x%x, cid=0x%x\n", + cqe->itid, qedi_conn->iscsi_conn_id); + return; + } + qedi_conn->cmd_cleanup_cmpl++; + wake_up(&qedi_conn->wait_queue); + cmd_new = task->dd_data; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID, + "Freeing tid=0x%x for cid=0x%x\n", + cqe->itid, qedi_conn->iscsi_conn_id); + qedi_clear_task_idx(qedi_conn->qedi, cqe->itid); + + } else { + qedi_get_proto_itt(qedi, cqe->itid, &ptmp_itt); + protoitt = build_itt(ptmp_itt, conn->session->age); + task = iscsi_itt_to_task(conn, protoitt); + QEDI_ERR(&qedi->dbg_ctx, + "Delayed or untracked cleanup response, itt=0x%x, tid=0x%x, cid=0x%x, task=%p\n", + protoitt, cqe->itid, qedi_conn->iscsi_conn_id, task); + WARN_ON(1); + } +} + +void qedi_fp_process_cqes(struct qedi_work *work) +{ + struct qedi_ctx *qedi = work->qedi; + union iscsi_cqe *cqe = &work->cqe; + struct iscsi_task *task = NULL; + struct iscsi_nopout *nopout_hdr; + struct qedi_conn *q_conn; + struct iscsi_conn *conn; + struct qedi_cmd *qedi_cmd; + u32 comp_type; + u32 iscsi_cid; + u32 hdr_opcode; + u16 que_idx = work->que_idx; + u8 cqe_err_bits = 0; + + comp_type = cqe->cqe_common.cqe_type; + hdr_opcode = cqe->cqe_common.iscsi_hdr.common.hdr_first_byte; + cqe_err_bits = + cqe->cqe_common.error_bitmap.error_bits.cqe_error_status_bits; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "fw_cid=0x%x, cqe type=0x%x, opcode=0x%x\n", + cqe->cqe_common.conn_id, comp_type, hdr_opcode); + + if (comp_type >= MAX_ISCSI_CQES_TYPE) { + QEDI_WARN(&qedi->dbg_ctx, "Invalid CqE type\n"); + return; + } + + iscsi_cid = cqe->cqe_common.conn_id; + q_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; + if (!q_conn) { + QEDI_WARN(&qedi->dbg_ctx, + "Session no longer exists for cid=0x%x!!\n", + iscsi_cid); + return; + } + + conn = q_conn->cls_conn->dd_data; + + if (unlikely(cqe_err_bits && + GET_FIELD(cqe_err_bits, + CQE_ERROR_BITMAP_DATA_DIGEST_ERR))) { + iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST); + return; + } + + switch (comp_type) { + case ISCSI_CQE_TYPE_SOLICITED: + case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE: + qedi_cmd = container_of(work, struct qedi_cmd, cqe_work); + task = qedi_cmd->task; + if (!task) { + QEDI_WARN(&qedi->dbg_ctx, "task is NULL\n"); + return; + } + + /* Process NOPIN local completion */ + nopout_hdr = (struct iscsi_nopout *)task->hdr; + if ((nopout_hdr->itt == RESERVED_ITT) && + (cqe->cqe_solicited.itid != (u16)RESERVED_ITT)) { + qedi_process_nopin_local_cmpl(qedi, &cqe->cqe_solicited, + task, q_conn); + } else { + cqe->cqe_solicited.itid = + qedi_get_itt(cqe->cqe_solicited); + /* Process other solicited responses */ + qedi_mtask_completion(qedi, cqe, task, q_conn, que_idx); + } + break; + case ISCSI_CQE_TYPE_UNSOLICITED: + switch (hdr_opcode) { + case ISCSI_OPCODE_NOP_IN: + qedi_process_nopin_mesg(qedi, cqe, task, q_conn, + que_idx); + break; + case ISCSI_OPCODE_ASYNC_MSG: + qedi_process_async_mesg(qedi, cqe, task, q_conn, + que_idx); + break; + case ISCSI_OPCODE_REJECT: + qedi_process_reject_mesg(qedi, cqe, task, q_conn, + que_idx); + break; + } + goto exit_fp_process; + case ISCSI_CQE_TYPE_DUMMY: + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "Dummy CqE\n"); + goto exit_fp_process; + case ISCSI_CQE_TYPE_TASK_CLEANUP: + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, "CleanUp CqE\n"); + qedi_process_cmd_cleanup_resp(qedi, &cqe->cqe_solicited, task, + conn); + goto exit_fp_process; + default: + QEDI_ERR(&qedi->dbg_ctx, "Error cqe.\n"); + break; + } + +exit_fp_process: + return; +} + +static void qedi_add_to_sq(struct qedi_conn *qedi_conn, struct iscsi_task *task, + u16 tid, uint16_t ptu_invalidate, int is_cleanup) +{ + struct iscsi_wqe *wqe; + struct iscsi_wqe_field *cont_field; + struct qedi_endpoint *ep; + struct scsi_cmnd *sc = task->sc; + struct iscsi_login_req *login_hdr; + struct qedi_cmd *cmd = task->dd_data; + + login_hdr = (struct iscsi_login_req *)task->hdr; + ep = qedi_conn->ep; + wqe = &ep->sq[ep->sq_prod_idx]; + + memset(wqe, 0, sizeof(*wqe)); + + ep->sq_prod_idx++; + ep->fw_sq_prod_idx++; + if (ep->sq_prod_idx == QEDI_SQ_SIZE) + ep->sq_prod_idx = 0; + + if (is_cleanup) { + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE, + ISCSI_WQE_TYPE_TASK_CLEANUP); + wqe->task_id = tid; + return; + } + + if (ptu_invalidate) { + SET_FIELD(wqe->flags, ISCSI_WQE_PTU_INVALIDATE, + ISCSI_WQE_SET_PTU_INVALIDATE); + } + + cont_field = &wqe->cont_prevtid_union.cont_field; + + switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { + case ISCSI_OP_LOGIN: + case ISCSI_OP_TEXT: + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE, + ISCSI_WQE_TYPE_MIDDLE_PATH); + SET_FIELD(wqe->flags, ISCSI_WQE_NUM_FAST_SGES, + 1); + cont_field->contlen_cdbsize_field = ntoh24(login_hdr->dlength); + break; + case ISCSI_OP_LOGOUT: + case ISCSI_OP_NOOP_OUT: + case ISCSI_OP_SCSI_TMFUNC: + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE, + ISCSI_WQE_TYPE_NORMAL); + break; + default: + if (!sc) + break; + + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE, + ISCSI_WQE_TYPE_NORMAL); + cont_field->contlen_cdbsize_field = + (sc->sc_data_direction == DMA_TO_DEVICE) ? + scsi_bufflen(sc) : 0; + if (cmd->use_slowpath) + SET_FIELD(wqe->flags, ISCSI_WQE_NUM_FAST_SGES, 0); + else + SET_FIELD(wqe->flags, ISCSI_WQE_NUM_FAST_SGES, + (sc->sc_data_direction == + DMA_TO_DEVICE) ? + min((u16)QEDI_FAST_SGE_COUNT, + (u16)cmd->io_tbl.sge_valid) : 0); + break; + } + + wqe->task_id = tid; + /* Make sure SQ data is coherent */ + wmb(); +} + +static void qedi_ring_doorbell(struct qedi_conn *qedi_conn) +{ + struct iscsi_db_data dbell = { 0 }; + + dbell.agg_flags = 0; + + dbell.params |= DB_DEST_XCM << ISCSI_DB_DATA_DEST_SHIFT; + dbell.params |= DB_AGG_CMD_SET << ISCSI_DB_DATA_AGG_CMD_SHIFT; + dbell.params |= + DQ_XCM_ISCSI_SQ_PROD_CMD << ISCSI_DB_DATA_AGG_VAL_SEL_SHIFT; + + dbell.sq_prod = qedi_conn->ep->fw_sq_prod_idx; + writel(*(u32 *)&dbell, qedi_conn->ep->p_doorbell); + + /* Make sure fw write idx is coherent, and include both memory barriers + * as a failsafe as for some architectures the call is the same but on + * others they are two different assembly operations. + */ + wmb(); + mmiowb(); + QEDI_INFO(&qedi_conn->qedi->dbg_ctx, QEDI_LOG_MP_REQ, + "prod_idx=0x%x, fw_prod_idx=0x%x, cid=0x%x\n", + qedi_conn->ep->sq_prod_idx, qedi_conn->ep->fw_sq_prod_idx, + qedi_conn->iscsi_conn_id); +} + +int qedi_send_iscsi_login(struct qedi_conn *qedi_conn, + struct iscsi_task *task) +{ + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_task_context *fw_task_ctx; + struct iscsi_login_req *login_hdr; + struct iscsi_login_req_hdr *fw_login_req = NULL; + struct iscsi_cached_sge_ctx *cached_sge = NULL; + struct iscsi_sge *single_sge = NULL; + struct iscsi_sge *req_sge = NULL; + struct iscsi_sge *resp_sge = NULL; + struct qedi_cmd *qedi_cmd; + s16 ptu_invalidate = 0; + s16 tid = 0; + + req_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl; + resp_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl; + qedi_cmd = (struct qedi_cmd *)task->dd_data; + login_hdr = (struct iscsi_login_req *)task->hdr; + + tid = qedi_get_task_idx(qedi); + if (tid == -1) + return -ENOMEM; + + fw_task_ctx = qedi_get_task_mem(&qedi->tasks, tid); + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context)); + + qedi_cmd->task_id = tid; + + /* Ystorm context */ + fw_login_req = &fw_task_ctx->ystorm_st_context.pdu_hdr.login_req; + fw_login_req->opcode = login_hdr->opcode; + fw_login_req->version_min = login_hdr->min_version; + fw_login_req->version_max = login_hdr->max_version; + fw_login_req->flags_attr = login_hdr->flags; + fw_login_req->isid_tabc = *((u16 *)login_hdr->isid + 2); + fw_login_req->isid_d = *((u32 *)login_hdr->isid); + fw_login_req->tsih = login_hdr->tsih; + qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd); + fw_login_req->itt = qedi_set_itt(tid, get_itt(task->itt)); + fw_login_req->cid = qedi_conn->iscsi_conn_id; + fw_login_req->cmd_sn = be32_to_cpu(login_hdr->cmdsn); + fw_login_req->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn); + fw_login_req->exp_stat_sn = 0; + + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) { + ptu_invalidate = 1; + qedi->tid_reuse_count[tid] = 0; + } + + fw_task_ctx->ystorm_st_context.state.reuse_count = + qedi->tid_reuse_count[tid]; + fw_task_ctx->mstorm_st_context.reuse_count = + qedi->tid_reuse_count[tid]++; + cached_sge = + &fw_task_ctx->ystorm_st_context.state.sgl_ctx_union.cached_sge; + cached_sge->sge.sge_len = req_sge->sge_len; + cached_sge->sge.sge_addr.lo = (u32)(qedi_conn->gen_pdu.req_dma_addr); + cached_sge->sge.sge_addr.hi = + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32); + + /* Mstorm context */ + single_sge = &fw_task_ctx->mstorm_st_context.sgl_union.single_sge; + fw_task_ctx->mstorm_st_context.task_type = 0x2; + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id; + single_sge->sge_addr.lo = resp_sge->sge_addr.lo; + single_sge->sge_addr.hi = resp_sge->sge_addr.hi; + single_sge->sge_len = resp_sge->sge_len; + + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SINGLE_SGE, 1); + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 0); + fw_task_ctx->mstorm_st_context.sgl_size = 1; + fw_task_ctx->mstorm_st_context.rem_task_size = resp_sge->sge_len; + + /* Ustorm context */ + fw_task_ctx->ustorm_st_context.rem_rcv_len = resp_sge->sge_len; + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = + ntoh24(login_hdr->dlength); + fw_task_ctx->ustorm_st_context.exp_data_sn = 0; + fw_task_ctx->ustorm_st_context.cq_rss_number = 0; + fw_task_ctx->ustorm_st_context.task_type = 0x2; + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id; + fw_task_ctx->ustorm_ag_context.exp_data_acked = + ntoh24(login_hdr->dlength); + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1, + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1); + SET_FIELD(fw_task_ctx->ustorm_st_context.flags, + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 0); + + spin_lock(&qedi_conn->list_lock); + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list); + qedi_cmd->io_cmd_in_list = true; + qedi_conn->active_cmd_count++; + spin_unlock(&qedi_conn->list_lock); + + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false); + qedi_ring_doorbell(qedi_conn); + return 0; +} + +int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn, + struct iscsi_task *task) +{ + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_logout_req_hdr *fw_logout_req = NULL; + struct iscsi_task_context *fw_task_ctx = NULL; + struct iscsi_logout *logout_hdr = NULL; + struct qedi_cmd *qedi_cmd = NULL; + s16 tid = 0; + s16 ptu_invalidate = 0; + + qedi_cmd = (struct qedi_cmd *)task->dd_data; + logout_hdr = (struct iscsi_logout *)task->hdr; + + tid = qedi_get_task_idx(qedi); + if (tid == -1) + return -ENOMEM; + + fw_task_ctx = qedi_get_task_mem(&qedi->tasks, tid); + + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context)); + qedi_cmd->task_id = tid; + + /* Ystorm context */ + fw_logout_req = &fw_task_ctx->ystorm_st_context.pdu_hdr.logout_req; + fw_logout_req->opcode = ISCSI_OPCODE_LOGOUT_REQUEST; + fw_logout_req->reason_code = 0x80 | logout_hdr->flags; + qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd); + fw_logout_req->itt = qedi_set_itt(tid, get_itt(task->itt)); + fw_logout_req->exp_stat_sn = be32_to_cpu(logout_hdr->exp_statsn); + fw_logout_req->cmd_sn = be32_to_cpu(logout_hdr->cmdsn); + + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) { + ptu_invalidate = 1; + qedi->tid_reuse_count[tid] = 0; + } + fw_task_ctx->ystorm_st_context.state.reuse_count = + qedi->tid_reuse_count[tid]; + fw_task_ctx->mstorm_st_context.reuse_count = + qedi->tid_reuse_count[tid]++; + fw_logout_req->cid = qedi_conn->iscsi_conn_id; + fw_task_ctx->ystorm_st_context.state.buffer_offset[0] = 0; + + /* Mstorm context */ + fw_task_ctx->mstorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH; + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id; + + /* Ustorm context */ + fw_task_ctx->ustorm_st_context.rem_rcv_len = 0; + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = 0; + fw_task_ctx->ustorm_st_context.exp_data_sn = 0; + fw_task_ctx->ustorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH; + fw_task_ctx->ustorm_st_context.cq_rss_number = 0; + + SET_FIELD(fw_task_ctx->ustorm_st_context.flags, + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 0); + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, 0); + + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id; + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1, + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1); + + spin_lock(&qedi_conn->list_lock); + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list); + qedi_cmd->io_cmd_in_list = true; + qedi_conn->active_cmd_count++; + spin_unlock(&qedi_conn->list_lock); + + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false); + qedi_ring_doorbell(qedi_conn); + + return 0; +} + +int qedi_cleanup_all_io(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn, + struct iscsi_task *task, bool in_recovery) +{ + int rval; + struct iscsi_task *ctask; + struct qedi_cmd *cmd, *cmd_tmp; + struct iscsi_tm *tmf_hdr; + unsigned int lun = 0; + bool lun_reset = false; + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_session *session = conn->session; + + /* From recovery, task is NULL or from tmf resp valid task */ + if (task) { + tmf_hdr = (struct iscsi_tm *)task->hdr; + + if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) { + lun_reset = true; + lun = scsilun_to_int(&tmf_hdr->lun); + } + } + + qedi_conn->cmd_cleanup_req = 0; + qedi_conn->cmd_cleanup_cmpl = 0; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "active_cmd_count=%d, cid=0x%x, in_recovery=%d, lun_reset=%d\n", + qedi_conn->active_cmd_count, qedi_conn->iscsi_conn_id, + in_recovery, lun_reset); + + if (lun_reset) + spin_lock_bh(&session->back_lock); + + spin_lock(&qedi_conn->list_lock); + + list_for_each_entry_safe(cmd, cmd_tmp, &qedi_conn->active_cmd_list, + io_cmd) { + ctask = cmd->task; + if (ctask == task) + continue; + + if (lun_reset) { + if (cmd->scsi_cmd && cmd->scsi_cmd->device) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "tid=0x%x itt=0x%x scsi_cmd_ptr=%p device=%p task_state=%d cmd_state=0%x cid=0x%x\n", + cmd->task_id, get_itt(ctask->itt), + cmd->scsi_cmd, cmd->scsi_cmd->device, + ctask->state, cmd->state, + qedi_conn->iscsi_conn_id); + if (cmd->scsi_cmd->device->lun != lun) + continue; + } + } + qedi_conn->cmd_cleanup_req++; + qedi_iscsi_cleanup_task(ctask, true); + + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + QEDI_WARN(&qedi->dbg_ctx, + "Deleted active cmd list node io_cmd=%p, cid=0x%x\n", + &cmd->io_cmd, qedi_conn->iscsi_conn_id); + } + + spin_unlock(&qedi_conn->list_lock); + + if (lun_reset) + spin_unlock_bh(&session->back_lock); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "cmd_cleanup_req=%d, cid=0x%x\n", + qedi_conn->cmd_cleanup_req, + qedi_conn->iscsi_conn_id); + + rval = wait_event_interruptible_timeout(qedi_conn->wait_queue, + ((qedi_conn->cmd_cleanup_req == + qedi_conn->cmd_cleanup_cmpl) || + qedi_conn->ep), + 5 * HZ); + if (rval) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "i/o cmd_cleanup_req=%d, equal to cmd_cleanup_cmpl=%d, cid=0x%x\n", + qedi_conn->cmd_cleanup_req, + qedi_conn->cmd_cleanup_cmpl, + qedi_conn->iscsi_conn_id); + + return 0; + } + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "i/o cmd_cleanup_req=%d, not equal to cmd_cleanup_cmpl=%d, cid=0x%x\n", + qedi_conn->cmd_cleanup_req, + qedi_conn->cmd_cleanup_cmpl, + qedi_conn->iscsi_conn_id); + + iscsi_host_for_each_session(qedi->shost, + qedi_mark_device_missing); + qedi_ops->common->drain(qedi->cdev); + + /* Enable IOs for all other sessions except current.*/ + if (!wait_event_interruptible_timeout(qedi_conn->wait_queue, + (qedi_conn->cmd_cleanup_req == + qedi_conn->cmd_cleanup_cmpl), + 5 * HZ)) { + iscsi_host_for_each_session(qedi->shost, + qedi_mark_device_available); + return -1; + } + + iscsi_host_for_each_session(qedi->shost, + qedi_mark_device_available); + + return 0; +} + +void qedi_clearsq(struct qedi_ctx *qedi, struct qedi_conn *qedi_conn, + struct iscsi_task *task) +{ + struct qedi_endpoint *qedi_ep; + int rval; + + qedi_ep = qedi_conn->ep; + qedi_conn->cmd_cleanup_req = 0; + qedi_conn->cmd_cleanup_cmpl = 0; + + if (!qedi_ep) { + QEDI_WARN(&qedi->dbg_ctx, + "Cannot proceed, ep already disconnected, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + return; + } + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Clearing SQ for cid=0x%x, conn=%p, ep=%p\n", + qedi_conn->iscsi_conn_id, qedi_conn, qedi_ep); + + qedi_ops->clear_sq(qedi->cdev, qedi_ep->handle); + + rval = qedi_cleanup_all_io(qedi, qedi_conn, task, true); + if (rval) { + QEDI_ERR(&qedi->dbg_ctx, + "fatal error, need hard reset, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + WARN_ON(1); + } +} + +static int qedi_wait_for_cleanup_request(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn, + struct iscsi_task *task, + struct qedi_cmd *qedi_cmd, + struct qedi_work_map *list_work) +{ + struct qedi_cmd *cmd = (struct qedi_cmd *)task->dd_data; + int wait; + + wait = wait_event_interruptible_timeout(qedi_conn->wait_queue, + ((qedi_cmd->state == + CLEANUP_RECV) || + ((qedi_cmd->type == TYPEIO) && + (cmd->state == + RESPONSE_RECEIVED))), + 5 * HZ); + if (!wait) { + qedi_cmd->state = CLEANUP_WAIT_FAILED; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "Cleanup timedout tid=0x%x, issue connection recovery, cid=0x%x\n", + cmd->task_id, qedi_conn->iscsi_conn_id); + + return -1; + } + return 0; +} + +static void qedi_tmf_work(struct work_struct *work) +{ + struct qedi_cmd *qedi_cmd = + container_of(work, struct qedi_cmd, tmf_work); + struct qedi_conn *qedi_conn = qedi_cmd->conn; + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct iscsi_cls_session *cls_sess; + struct qedi_work_map *list_work = NULL; + struct iscsi_task *mtask; + struct qedi_cmd *cmd; + struct iscsi_task *ctask; + struct iscsi_tm *tmf_hdr; + s16 rval = 0; + s16 tid = 0; + + mtask = qedi_cmd->task; + tmf_hdr = (struct iscsi_tm *)mtask->hdr; + cls_sess = iscsi_conn_to_session(qedi_conn->cls_conn); + set_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + + ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt); + if (!ctask || !ctask->sc) { + QEDI_ERR(&qedi->dbg_ctx, "Task already completed\n"); + goto abort_ret; + } + + cmd = (struct qedi_cmd *)ctask->dd_data; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Abort tmf rtt=0x%x, cmd itt=0x%x, cmd tid=0x%x, cid=0x%x\n", + get_itt(tmf_hdr->rtt), get_itt(ctask->itt), cmd->task_id, + qedi_conn->iscsi_conn_id); + + if (do_not_recover) { + QEDI_ERR(&qedi->dbg_ctx, "DONT SEND CLEANUP/ABORT %d\n", + do_not_recover); + goto abort_ret; + } + + list_work = kzalloc(sizeof(*list_work), GFP_ATOMIC); + if (!list_work) { + QEDI_ERR(&qedi->dbg_ctx, "Memory alloction failed\n"); + goto abort_ret; + } + + qedi_cmd->type = TYPEIO; + list_work->qedi_cmd = qedi_cmd; + list_work->rtid = cmd->task_id; + list_work->state = QEDI_WORK_SCHEDULED; + qedi_cmd->list_tmf_work = list_work; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "Queue tmf work=%p, list node=%p, cid=0x%x, tmf flags=0x%x\n", + list_work->ptr_tmf_work, list_work, qedi_conn->iscsi_conn_id, + tmf_hdr->flags); + + spin_lock_bh(&qedi_conn->tmf_work_lock); + list_add_tail(&list_work->list, &qedi_conn->tmf_work_list); + spin_unlock_bh(&qedi_conn->tmf_work_lock); + + qedi_iscsi_cleanup_task(ctask, false); + + rval = qedi_wait_for_cleanup_request(qedi, qedi_conn, ctask, qedi_cmd, + list_work); + if (rval == -1) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "FW cleanup got escalated, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + goto ldel_exit; + } + + tid = qedi_get_task_idx(qedi); + if (tid == -1) { + QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + goto ldel_exit; + } + + qedi_cmd->task_id = tid; + qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task); + +abort_ret: + clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + return; + +ldel_exit: + spin_lock_bh(&qedi_conn->tmf_work_lock); + if (!qedi_cmd->list_tmf_work) { + list_del_init(&list_work->list); + qedi_cmd->list_tmf_work = NULL; + kfree(list_work); + } + spin_unlock_bh(&qedi_conn->tmf_work_lock); + + spin_lock(&qedi_conn->list_lock); + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + spin_unlock(&qedi_conn->list_lock); + + clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); +} + +static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn, + struct iscsi_task *mtask) +{ + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data; + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_task_context *fw_task_ctx; + struct iscsi_tmf_request_hdr *fw_tmf_request; + struct iscsi_sge *single_sge; + struct qedi_cmd *qedi_cmd; + struct qedi_cmd *cmd; + struct iscsi_task *ctask; + struct iscsi_tm *tmf_hdr; + struct iscsi_sge *req_sge; + struct iscsi_sge *resp_sge; + u32 lun[2]; + s16 tid = 0, ptu_invalidate = 0; + + req_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl; + resp_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl; + qedi_cmd = (struct qedi_cmd *)mtask->dd_data; + tmf_hdr = (struct iscsi_tm *)mtask->hdr; + + tid = qedi_cmd->task_id; + qedi_update_itt_map(qedi, tid, mtask->itt, qedi_cmd); + + fw_task_ctx = qedi_get_task_mem(&qedi->tasks, tid); + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context)); + + fw_tmf_request = &fw_task_ctx->ystorm_st_context.pdu_hdr.tmf_request; + fw_tmf_request->itt = qedi_set_itt(tid, get_itt(mtask->itt)); + fw_tmf_request->cmd_sn = be32_to_cpu(tmf_hdr->cmdsn); + + memcpy(lun, &tmf_hdr->lun, sizeof(struct scsi_lun)); + fw_tmf_request->lun.lo = be32_to_cpu(lun[0]); + fw_tmf_request->lun.hi = be32_to_cpu(lun[1]); + + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) { + ptu_invalidate = 1; + qedi->tid_reuse_count[tid] = 0; + } + fw_task_ctx->ystorm_st_context.state.reuse_count = + qedi->tid_reuse_count[tid]; + fw_task_ctx->mstorm_st_context.reuse_count = + qedi->tid_reuse_count[tid]++; + + if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_ABORT_TASK) { + ctask = iscsi_itt_to_task(conn, tmf_hdr->rtt); + if (!ctask || !ctask->sc) { + QEDI_ERR(&qedi->dbg_ctx, + "Could not get reference task\n"); + return 0; + } + cmd = (struct qedi_cmd *)ctask->dd_data; + fw_tmf_request->rtt = + qedi_set_itt(cmd->task_id, + get_itt(tmf_hdr->rtt)); + } else { + fw_tmf_request->rtt = ISCSI_RESERVED_TAG; + } + + fw_tmf_request->opcode = tmf_hdr->opcode; + fw_tmf_request->function = tmf_hdr->flags; + fw_tmf_request->hdr_second_dword = ntoh24(tmf_hdr->dlength); + fw_tmf_request->ref_cmd_sn = be32_to_cpu(tmf_hdr->refcmdsn); + + single_sge = &fw_task_ctx->mstorm_st_context.sgl_union.single_sge; + fw_task_ctx->mstorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH; + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id; + single_sge->sge_addr.lo = resp_sge->sge_addr.lo; + single_sge->sge_addr.hi = resp_sge->sge_addr.hi; + single_sge->sge_len = resp_sge->sge_len; + + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SINGLE_SGE, 1); + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 0); + fw_task_ctx->mstorm_st_context.sgl_size = 1; + fw_task_ctx->mstorm_st_context.rem_task_size = resp_sge->sge_len; + + /* Ustorm context */ + fw_task_ctx->ustorm_st_context.rem_rcv_len = 0; + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = 0; + fw_task_ctx->ustorm_st_context.exp_data_sn = 0; + fw_task_ctx->ustorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH; + fw_task_ctx->ustorm_st_context.cq_rss_number = 0; + + SET_FIELD(fw_task_ctx->ustorm_st_context.flags, + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 0); + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, 0); + + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id; + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1, + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1); + fw_task_ctx->ustorm_st_context.lun.lo = be32_to_cpu(lun[0]); + fw_task_ctx->ustorm_st_context.lun.hi = be32_to_cpu(lun[1]); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "Add TMF to SQ, tmf tid=0x%x, itt=0x%x, cid=0x%x\n", + tid, mtask->itt, qedi_conn->iscsi_conn_id); + + spin_lock(&qedi_conn->list_lock); + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list); + qedi_cmd->io_cmd_in_list = true; + qedi_conn->active_cmd_count++; + spin_unlock(&qedi_conn->list_lock); + + qedi_add_to_sq(qedi_conn, mtask, tid, ptu_invalidate, false); + qedi_ring_doorbell(qedi_conn); + return 0; +} + +int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn, + struct iscsi_task *mtask) +{ + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_tm *tmf_hdr; + struct qedi_cmd *qedi_cmd = (struct qedi_cmd *)mtask->dd_data; + s16 tid = 0; + + tmf_hdr = (struct iscsi_tm *)mtask->hdr; + qedi_cmd->task = mtask; + + /* If abort task then schedule the work and return */ + if ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_ABORT_TASK) { + qedi_cmd->state = CLEANUP_WAIT; + INIT_WORK(&qedi_cmd->tmf_work, qedi_tmf_work); + queue_work(qedi->tmf_thread, &qedi_cmd->tmf_work); + + } else if (((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_LOGICAL_UNIT_RESET) || + ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_TARGET_WARM_RESET) || + ((tmf_hdr->flags & ISCSI_FLAG_TM_FUNC_MASK) == + ISCSI_TM_FUNC_TARGET_COLD_RESET)) { + tid = qedi_get_task_idx(qedi); + if (tid == -1) { + QEDI_ERR(&qedi->dbg_ctx, "Invalid tid, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + return -1; + } + qedi_cmd->task_id = tid; + + qedi_send_iscsi_tmf(qedi_conn, qedi_cmd->task); + + } else { + QEDI_ERR(&qedi->dbg_ctx, "Invalid tmf, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + return -1; + } + + return 0; +} + +int qedi_send_iscsi_text(struct qedi_conn *qedi_conn, + struct iscsi_task *task) +{ + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_task_context *fw_task_ctx; + struct iscsi_text_request_hdr *fw_text_request; + struct iscsi_cached_sge_ctx *cached_sge; + struct iscsi_sge *single_sge; + struct qedi_cmd *qedi_cmd; + /* For 6.5 hdr iscsi_hdr */ + struct iscsi_text *text_hdr; + struct iscsi_sge *req_sge; + struct iscsi_sge *resp_sge; + s16 ptu_invalidate = 0; + s16 tid = 0; + + req_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl; + resp_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl; + qedi_cmd = (struct qedi_cmd *)task->dd_data; + text_hdr = (struct iscsi_text *)task->hdr; + + tid = qedi_get_task_idx(qedi); + if (tid == -1) + return -ENOMEM; + + fw_task_ctx = qedi_get_task_mem(&qedi->tasks, tid); + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context)); + + qedi_cmd->task_id = tid; + + /* Ystorm context */ + fw_text_request = + &fw_task_ctx->ystorm_st_context.pdu_hdr.text_request; + fw_text_request->opcode = text_hdr->opcode; + fw_text_request->flags_attr = text_hdr->flags; + + qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd); + fw_text_request->itt = qedi_set_itt(tid, get_itt(task->itt)); + fw_text_request->ttt = text_hdr->ttt; + fw_text_request->cmd_sn = be32_to_cpu(text_hdr->cmdsn); + fw_text_request->exp_stat_sn = be32_to_cpu(text_hdr->exp_statsn); + fw_text_request->hdr_second_dword = ntoh24(text_hdr->dlength); + + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) { + ptu_invalidate = 1; + qedi->tid_reuse_count[tid] = 0; + } + fw_task_ctx->ystorm_st_context.state.reuse_count = + qedi->tid_reuse_count[tid]; + fw_task_ctx->mstorm_st_context.reuse_count = + qedi->tid_reuse_count[tid]++; + + cached_sge = + &fw_task_ctx->ystorm_st_context.state.sgl_ctx_union.cached_sge; + cached_sge->sge.sge_len = req_sge->sge_len; + cached_sge->sge.sge_addr.lo = (u32)(qedi_conn->gen_pdu.req_dma_addr); + cached_sge->sge.sge_addr.hi = + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32); + + /* Mstorm context */ + single_sge = &fw_task_ctx->mstorm_st_context.sgl_union.single_sge; + fw_task_ctx->mstorm_st_context.task_type = 0x2; + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id; + single_sge->sge_addr.lo = resp_sge->sge_addr.lo; + single_sge->sge_addr.hi = resp_sge->sge_addr.hi; + single_sge->sge_len = resp_sge->sge_len; + + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SINGLE_SGE, 1); + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 0); + fw_task_ctx->mstorm_st_context.sgl_size = 1; + fw_task_ctx->mstorm_st_context.rem_task_size = resp_sge->sge_len; + + /* Ustorm context */ + fw_task_ctx->ustorm_ag_context.exp_data_acked = + ntoh24(text_hdr->dlength); + fw_task_ctx->ustorm_st_context.rem_rcv_len = resp_sge->sge_len; + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = + ntoh24(text_hdr->dlength); + fw_task_ctx->ustorm_st_context.exp_data_sn = + be32_to_cpu(text_hdr->exp_statsn); + fw_task_ctx->ustorm_st_context.cq_rss_number = 0; + fw_task_ctx->ustorm_st_context.task_type = 0x2; + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id; + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1, + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1); + + /* Add command in active command list */ + spin_lock(&qedi_conn->list_lock); + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list); + qedi_cmd->io_cmd_in_list = true; + qedi_conn->active_cmd_count++; + spin_unlock(&qedi_conn->list_lock); + + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false); + qedi_ring_doorbell(qedi_conn); + + return 0; +} + +int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn, + struct iscsi_task *task, + char *datap, int data_len, int unsol) +{ + struct qedi_ctx *qedi = qedi_conn->qedi; + struct iscsi_task_context *fw_task_ctx; + struct iscsi_nop_out_hdr *fw_nop_out; + struct qedi_cmd *qedi_cmd; + /* For 6.5 hdr iscsi_hdr */ + struct iscsi_nopout *nopout_hdr; + struct iscsi_cached_sge_ctx *cached_sge; + struct iscsi_sge *single_sge; + struct iscsi_sge *req_sge; + struct iscsi_sge *resp_sge; + u32 lun[2]; + s16 ptu_invalidate = 0; + s16 tid = 0; + + req_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl; + resp_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl; + qedi_cmd = (struct qedi_cmd *)task->dd_data; + nopout_hdr = (struct iscsi_nopout *)task->hdr; + + tid = qedi_get_task_idx(qedi); + if (tid == -1) { + QEDI_WARN(&qedi->dbg_ctx, "Invalid tid\n"); + return -ENOMEM; + } + + fw_task_ctx = qedi_get_task_mem(&qedi->tasks, tid); + + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context)); + qedi_cmd->task_id = tid; + + /* Ystorm context */ + fw_nop_out = &fw_task_ctx->ystorm_st_context.pdu_hdr.nop_out; + SET_FIELD(fw_nop_out->flags_attr, ISCSI_NOP_OUT_HDR_CONST1, 1); + SET_FIELD(fw_nop_out->flags_attr, ISCSI_NOP_OUT_HDR_RSRV, 0); + + memcpy(lun, &nopout_hdr->lun, sizeof(struct scsi_lun)); + fw_nop_out->lun.lo = be32_to_cpu(lun[0]); + fw_nop_out->lun.hi = be32_to_cpu(lun[1]); + + qedi_update_itt_map(qedi, tid, task->itt, qedi_cmd); + + if (nopout_hdr->ttt != ISCSI_TTT_ALL_ONES) { + fw_nop_out->itt = be32_to_cpu(nopout_hdr->itt); + fw_nop_out->ttt = be32_to_cpu(nopout_hdr->ttt); + fw_task_ctx->ystorm_st_context.state.buffer_offset[0] = 0; + fw_task_ctx->ystorm_st_context.state.local_comp = 1; + SET_FIELD(fw_task_ctx->ustorm_st_context.flags, + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 1); + } else { + fw_nop_out->itt = qedi_set_itt(tid, get_itt(task->itt)); + fw_nop_out->ttt = ISCSI_TTT_ALL_ONES; + fw_task_ctx->ystorm_st_context.state.buffer_offset[0] = 0; + + spin_lock(&qedi_conn->list_lock); + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list); + qedi_cmd->io_cmd_in_list = true; + qedi_conn->active_cmd_count++; + spin_unlock(&qedi_conn->list_lock); + } + + fw_nop_out->opcode = ISCSI_OPCODE_NOP_OUT; + fw_nop_out->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn); + fw_nop_out->exp_stat_sn = be32_to_cpu(nopout_hdr->exp_statsn); + + cached_sge = + &fw_task_ctx->ystorm_st_context.state.sgl_ctx_union.cached_sge; + cached_sge->sge.sge_len = req_sge->sge_len; + cached_sge->sge.sge_addr.lo = (u32)(qedi_conn->gen_pdu.req_dma_addr); + cached_sge->sge.sge_addr.hi = + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32); + + /* Mstorm context */ + fw_task_ctx->mstorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH; + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id; + + single_sge = &fw_task_ctx->mstorm_st_context.sgl_union.single_sge; + single_sge->sge_addr.lo = resp_sge->sge_addr.lo; + single_sge->sge_addr.hi = resp_sge->sge_addr.hi; + single_sge->sge_len = resp_sge->sge_len; + fw_task_ctx->mstorm_st_context.rem_task_size = resp_sge->sge_len; + + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) { + ptu_invalidate = 1; + qedi->tid_reuse_count[tid] = 0; + } + fw_task_ctx->ystorm_st_context.state.reuse_count = + qedi->tid_reuse_count[tid]; + fw_task_ctx->mstorm_st_context.reuse_count = + qedi->tid_reuse_count[tid]++; + /* Ustorm context */ + fw_task_ctx->ustorm_st_context.rem_rcv_len = resp_sge->sge_len; + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = data_len; + fw_task_ctx->ustorm_st_context.exp_data_sn = 0; + fw_task_ctx->ustorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH; + fw_task_ctx->ustorm_st_context.cq_rss_number = 0; + + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, 0); + + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id; + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1, + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1); + + fw_task_ctx->ustorm_st_context.lun.lo = be32_to_cpu(lun[0]); + fw_task_ctx->ustorm_st_context.lun.hi = be32_to_cpu(lun[1]); + + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false); + qedi_ring_doorbell(qedi_conn); + return 0; +} + +static int qedi_split_bd(struct qedi_cmd *cmd, u64 addr, int sg_len, + int bd_index) +{ + struct iscsi_sge *bd = cmd->io_tbl.sge_tbl; + int frag_size, sg_frags; + + sg_frags = 0; + + while (sg_len) { + if (addr % QEDI_PAGE_SIZE) + frag_size = + (QEDI_PAGE_SIZE - (addr % QEDI_PAGE_SIZE)); + else + frag_size = (sg_len > QEDI_BD_SPLIT_SZ) ? 0 : + (sg_len % QEDI_BD_SPLIT_SZ); + + if (frag_size == 0) + frag_size = QEDI_BD_SPLIT_SZ; + + bd[bd_index + sg_frags].sge_addr.lo = (addr & 0xffffffff); + bd[bd_index + sg_frags].sge_addr.hi = (addr >> 32); + bd[bd_index + sg_frags].sge_len = (u16)frag_size; + QEDI_INFO(&cmd->conn->qedi->dbg_ctx, QEDI_LOG_IO, + "split sge %d: addr=%llx, len=%x", + (bd_index + sg_frags), addr, frag_size); + + addr += (u64)frag_size; + sg_frags++; + sg_len -= frag_size; + } + return sg_frags; +} + +static int qedi_map_scsi_sg(struct qedi_ctx *qedi, struct qedi_cmd *cmd) +{ + struct scsi_cmnd *sc = cmd->scsi_cmd; + struct iscsi_sge *bd = cmd->io_tbl.sge_tbl; + struct scatterlist *sg; + int byte_count = 0; + int bd_count = 0; + int sg_count; + int sg_len; + int sg_frags; + u64 addr, end_addr; + int i; + + WARN_ON(scsi_sg_count(sc) > QEDI_ISCSI_MAX_BDS_PER_CMD); + + sg_count = dma_map_sg(&qedi->pdev->dev, scsi_sglist(sc), + scsi_sg_count(sc), sc->sc_data_direction); + + /* + * New condition to send single SGE as cached-SGL. + * Single SGE with length less than 64K. + */ + sg = scsi_sglist(sc); + if ((sg_count == 1) && (sg_dma_len(sg) <= MAX_SGLEN_FOR_CACHESGL)) { + sg_len = sg_dma_len(sg); + addr = (u64)sg_dma_address(sg); + + bd[bd_count].sge_addr.lo = (addr & 0xffffffff); + bd[bd_count].sge_addr.hi = (addr >> 32); + bd[bd_count].sge_len = (u16)sg_len; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, + "single-cashed-sgl: bd_count:%d addr=%llx, len=%x", + sg_count, addr, sg_len); + + return ++bd_count; + } + + scsi_for_each_sg(sc, sg, sg_count, i) { + sg_len = sg_dma_len(sg); + addr = (u64)sg_dma_address(sg); + end_addr = (addr + sg_len); + + /* + * first sg elem in the 'list', + * check if end addr is page-aligned. + */ + if ((i == 0) && (sg_count > 1) && (end_addr % QEDI_PAGE_SIZE)) + cmd->use_slowpath = true; + + /* + * last sg elem in the 'list', + * check if start addr is page-aligned. + */ + else if ((i == (sg_count - 1)) && + (sg_count > 1) && (addr % QEDI_PAGE_SIZE)) + cmd->use_slowpath = true; + + /* + * middle sg elements in list, + * check if start and end addr is page-aligned + */ + else if ((i != 0) && (i != (sg_count - 1)) && + ((addr % QEDI_PAGE_SIZE) || + (end_addr % QEDI_PAGE_SIZE))) + cmd->use_slowpath = true; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, "sg[%d] size=0x%x", + i, sg_len); + + if (sg_len > QEDI_BD_SPLIT_SZ) { + sg_frags = qedi_split_bd(cmd, addr, sg_len, bd_count); + } else { + sg_frags = 1; + bd[bd_count].sge_addr.lo = addr & 0xffffffff; + bd[bd_count].sge_addr.hi = addr >> 32; + bd[bd_count].sge_len = sg_len; + } + byte_count += sg_len; + bd_count += sg_frags; + } + + if (byte_count != scsi_bufflen(sc)) + QEDI_ERR(&qedi->dbg_ctx, + "byte_count = %d != scsi_bufflen = %d\n", byte_count, + scsi_bufflen(sc)); + else + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, "byte_count = %d\n", + byte_count); + + WARN_ON(byte_count != scsi_bufflen(sc)); + + return bd_count; +} + +static void qedi_iscsi_map_sg_list(struct qedi_cmd *cmd) +{ + int bd_count; + struct scsi_cmnd *sc = cmd->scsi_cmd; + + if (scsi_sg_count(sc)) { + bd_count = qedi_map_scsi_sg(cmd->conn->qedi, cmd); + if (bd_count == 0) + return; + } else { + struct iscsi_sge *bd = cmd->io_tbl.sge_tbl; + + bd[0].sge_addr.lo = 0; + bd[0].sge_addr.hi = 0; + bd[0].sge_len = 0; + bd_count = 0; + } + cmd->io_tbl.sge_valid = bd_count; +} + +static void qedi_cpy_scsi_cdb(struct scsi_cmnd *sc, u32 *dstp) +{ + u32 dword; + int lpcnt; + u8 *srcp; + + lpcnt = sc->cmd_len / sizeof(dword); + srcp = (u8 *)sc->cmnd; + while (lpcnt--) { + memcpy(&dword, (const void *)srcp, 4); + *dstp = cpu_to_be32(dword); + srcp += 4; + dstp++; + } + if (sc->cmd_len & 0x3) { + dword = (u32)srcp[0] | ((u32)srcp[1] << 8); + *dstp = cpu_to_be32(dword); + } +} + +void qedi_trace_io(struct qedi_ctx *qedi, struct iscsi_task *task, + u16 tid, int8_t direction) +{ + struct qedi_io_log *io_log; + struct iscsi_conn *conn = task->conn; + struct qedi_conn *qedi_conn = conn->dd_data; + struct scsi_cmnd *sc_cmd = task->sc; + unsigned long flags; + u8 op; + + spin_lock_irqsave(&qedi->io_trace_lock, flags); + + io_log = &qedi->io_trace_buf[qedi->io_trace_idx]; + io_log->direction = direction; + io_log->task_id = tid; + io_log->cid = qedi_conn->iscsi_conn_id; + io_log->lun = sc_cmd->device->lun; + io_log->op = sc_cmd->cmnd[0]; + op = sc_cmd->cmnd[0]; + io_log->lba[0] = sc_cmd->cmnd[2]; + io_log->lba[1] = sc_cmd->cmnd[3]; + io_log->lba[2] = sc_cmd->cmnd[4]; + io_log->lba[3] = sc_cmd->cmnd[5]; + io_log->bufflen = scsi_bufflen(sc_cmd); + io_log->sg_count = scsi_sg_count(sc_cmd); + io_log->fast_sgs = qedi->fast_sgls; + io_log->cached_sgs = qedi->cached_sgls; + io_log->slow_sgs = qedi->slow_sgls; + io_log->cached_sge = qedi->use_cached_sge; + io_log->slow_sge = qedi->use_slow_sge; + io_log->fast_sge = qedi->use_fast_sge; + io_log->result = sc_cmd->result; + io_log->jiffies = jiffies; + io_log->blk_req_cpu = smp_processor_id(); + + if (direction == QEDI_IO_TRACE_REQ) { + /* For requests we only care about the submission CPU */ + io_log->req_cpu = smp_processor_id() % qedi->num_queues; + io_log->intr_cpu = 0; + io_log->blk_rsp_cpu = 0; + } else if (direction == QEDI_IO_TRACE_RSP) { + io_log->req_cpu = smp_processor_id() % qedi->num_queues; + io_log->intr_cpu = qedi->intr_cpu; + io_log->blk_rsp_cpu = smp_processor_id(); + } + + qedi->io_trace_idx++; + if (qedi->io_trace_idx == QEDI_IO_TRACE_SIZE) + qedi->io_trace_idx = 0; + + qedi->use_cached_sge = false; + qedi->use_slow_sge = false; + qedi->use_fast_sge = false; + + spin_unlock_irqrestore(&qedi->io_trace_lock, flags); +} + +int qedi_iscsi_send_ioreq(struct iscsi_task *task) +{ + struct iscsi_conn *conn = task->conn; + struct iscsi_session *session = conn->session; + struct Scsi_Host *shost = iscsi_session_to_shost(session->cls_session); + struct qedi_ctx *qedi = iscsi_host_priv(shost); + struct qedi_conn *qedi_conn = conn->dd_data; + struct qedi_cmd *cmd = task->dd_data; + struct scsi_cmnd *sc = task->sc; + struct iscsi_task_context *fw_task_ctx; + struct iscsi_cached_sge_ctx *cached_sge; + struct iscsi_phys_sgl_ctx *phys_sgl; + struct iscsi_virt_sgl_ctx *virt_sgl; + struct ystorm_iscsi_task_st_ctx *yst_cxt; + struct mstorm_iscsi_task_st_ctx *mst_cxt; + struct iscsi_sgl *sgl_struct; + struct iscsi_sge *single_sge; + struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr; + struct iscsi_sge *bd = cmd->io_tbl.sge_tbl; + enum iscsi_task_type task_type; + struct iscsi_cmd_hdr *fw_cmd; + u32 lun[2]; + u32 exp_data; + u16 cq_idx = smp_processor_id() % qedi->num_queues; + s16 ptu_invalidate = 0; + s16 tid = 0; + u8 num_fast_sgs; + + tid = qedi_get_task_idx(qedi); + if (tid == -1) + return -ENOMEM; + + qedi_iscsi_map_sg_list(cmd); + + int_to_scsilun(sc->device->lun, (struct scsi_lun *)lun); + fw_task_ctx = qedi_get_task_mem(&qedi->tasks, tid); + + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context)); + cmd->task_id = tid; + + /* Ystorm context */ + fw_cmd = &fw_task_ctx->ystorm_st_context.pdu_hdr.cmd; + SET_FIELD(fw_cmd->flags_attr, ISCSI_CMD_HDR_ATTR, ISCSI_ATTR_SIMPLE); + + if (sc->sc_data_direction == DMA_TO_DEVICE) { + if (conn->session->initial_r2t_en) { + exp_data = min((conn->session->imm_data_en * + conn->max_xmit_dlength), + conn->session->first_burst); + exp_data = min(exp_data, scsi_bufflen(sc)); + fw_task_ctx->ustorm_ag_context.exp_data_acked = + cpu_to_le32(exp_data); + } else { + fw_task_ctx->ustorm_ag_context.exp_data_acked = + min(conn->session->first_burst, scsi_bufflen(sc)); + } + + SET_FIELD(fw_cmd->flags_attr, ISCSI_CMD_HDR_WRITE, 1); + task_type = ISCSI_TASK_TYPE_INITIATOR_WRITE; + } else { + if (scsi_bufflen(sc)) + SET_FIELD(fw_cmd->flags_attr, ISCSI_CMD_HDR_READ, 1); + task_type = ISCSI_TASK_TYPE_INITIATOR_READ; + } + + fw_cmd->lun.lo = be32_to_cpu(lun[0]); + fw_cmd->lun.hi = be32_to_cpu(lun[1]); + + qedi_update_itt_map(qedi, tid, task->itt, cmd); + fw_cmd->itt = qedi_set_itt(tid, get_itt(task->itt)); + fw_cmd->expected_transfer_length = scsi_bufflen(sc); + fw_cmd->cmd_sn = be32_to_cpu(hdr->cmdsn); + fw_cmd->opcode = hdr->opcode; + qedi_cpy_scsi_cdb(sc, (u32 *)fw_cmd->cdb); + + /* Mstorm context */ + fw_task_ctx->mstorm_st_context.sense_db.lo = (u32)cmd->sense_buffer_dma; + fw_task_ctx->mstorm_st_context.sense_db.hi = + (u32)((u64)cmd->sense_buffer_dma >> 32); + fw_task_ctx->mstorm_ag_context.task_cid = qedi_conn->iscsi_conn_id; + fw_task_ctx->mstorm_st_context.task_type = task_type; + + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) { + ptu_invalidate = 1; + qedi->tid_reuse_count[tid] = 0; + } + fw_task_ctx->ystorm_st_context.state.reuse_count = + qedi->tid_reuse_count[tid]; + fw_task_ctx->mstorm_st_context.reuse_count = + qedi->tid_reuse_count[tid]++; + + /* Ustorm context */ + fw_task_ctx->ustorm_st_context.rem_rcv_len = scsi_bufflen(sc); + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = scsi_bufflen(sc); + fw_task_ctx->ustorm_st_context.exp_data_sn = + be32_to_cpu(hdr->exp_statsn); + fw_task_ctx->ustorm_st_context.task_type = task_type; + fw_task_ctx->ustorm_st_context.cq_rss_number = cq_idx; + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id; + + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1, + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1); + SET_FIELD(fw_task_ctx->ustorm_st_context.flags, + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 0); + + num_fast_sgs = (cmd->io_tbl.sge_valid ? + min((u16)QEDI_FAST_SGE_COUNT, + (u16)cmd->io_tbl.sge_valid) : 0); + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, num_fast_sgs); + + fw_task_ctx->ustorm_st_context.lun.lo = be32_to_cpu(lun[0]); + fw_task_ctx->ustorm_st_context.lun.hi = be32_to_cpu(lun[1]); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, "Total sge count [%d]\n", + cmd->io_tbl.sge_valid); + + yst_cxt = &fw_task_ctx->ystorm_st_context; + mst_cxt = &fw_task_ctx->mstorm_st_context; + /* Tx path */ + if (task_type == ISCSI_TASK_TYPE_INITIATOR_WRITE) { + /* not considering superIO or FastIO */ + if (cmd->io_tbl.sge_valid == 1) { + cached_sge = &yst_cxt->state.sgl_ctx_union.cached_sge; + cached_sge->sge.sge_addr.lo = bd[0].sge_addr.lo; + cached_sge->sge.sge_addr.hi = bd[0].sge_addr.hi; + cached_sge->sge.sge_len = bd[0].sge_len; + qedi->cached_sgls++; + } else if ((cmd->io_tbl.sge_valid != 1) && cmd->use_slowpath) { + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 1); + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, 0); + phys_sgl = &yst_cxt->state.sgl_ctx_union.phys_sgl; + phys_sgl->sgl_base.lo = (u32)(cmd->io_tbl.sge_tbl_dma); + phys_sgl->sgl_base.hi = + (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32); + phys_sgl->sgl_size = cmd->io_tbl.sge_valid; + qedi->slow_sgls++; + } else if ((cmd->io_tbl.sge_valid != 1) && !cmd->use_slowpath) { + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 0); + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, + min((u16)QEDI_FAST_SGE_COUNT, + (u16)cmd->io_tbl.sge_valid)); + virt_sgl = &yst_cxt->state.sgl_ctx_union.virt_sgl; + virt_sgl->sgl_base.lo = (u32)(cmd->io_tbl.sge_tbl_dma); + virt_sgl->sgl_base.hi = + (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32); + virt_sgl->sgl_initial_offset = + (u32)bd[0].sge_addr.lo & (QEDI_PAGE_SIZE - 1); + qedi->fast_sgls++; + } + fw_task_ctx->mstorm_st_context.sgl_size = cmd->io_tbl.sge_valid; + fw_task_ctx->mstorm_st_context.rem_task_size = scsi_bufflen(sc); + } else { + /* Rx path */ + if (cmd->io_tbl.sge_valid == 1) { + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 0); + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SINGLE_SGE, 1); + single_sge = &mst_cxt->sgl_union.single_sge; + single_sge->sge_addr.lo = bd[0].sge_addr.lo; + single_sge->sge_addr.hi = bd[0].sge_addr.hi; + single_sge->sge_len = bd[0].sge_len; + qedi->cached_sgls++; + } else if ((cmd->io_tbl.sge_valid != 1) && cmd->use_slowpath) { + sgl_struct = &mst_cxt->sgl_union.sgl_struct; + sgl_struct->sgl_addr.lo = + (u32)(cmd->io_tbl.sge_tbl_dma); + sgl_struct->sgl_addr.hi = + (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32); + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 1); + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, 0); + sgl_struct->updated_sge_size = 0; + sgl_struct->updated_sge_offset = 0; + qedi->slow_sgls++; + } else if ((cmd->io_tbl.sge_valid != 1) && !cmd->use_slowpath) { + sgl_struct = &mst_cxt->sgl_union.sgl_struct; + sgl_struct->sgl_addr.lo = + (u32)(cmd->io_tbl.sge_tbl_dma); + sgl_struct->sgl_addr.hi = + (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32); + sgl_struct->byte_offset = + (u32)bd[0].sge_addr.lo & (QEDI_PAGE_SIZE - 1); + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags, + ISCSI_MFLAGS_SLOW_IO, 0); + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map, + ISCSI_REG1_NUM_FAST_SGES, 0); + sgl_struct->updated_sge_size = 0; + sgl_struct->updated_sge_offset = 0; + qedi->fast_sgls++; + } + fw_task_ctx->mstorm_st_context.sgl_size = cmd->io_tbl.sge_valid; + fw_task_ctx->mstorm_st_context.rem_task_size = scsi_bufflen(sc); + } + + if (cmd->io_tbl.sge_valid == 1) + /* Singel-SGL */ + qedi->use_cached_sge = true; + else { + if (cmd->use_slowpath) + qedi->use_slow_sge = true; + else + qedi->use_fast_sge = true; + } + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, + "%s: %s-SGL: num_sges=0x%x first-sge-lo=0x%x first-sge-hi=0x%x", + (task_type == ISCSI_TASK_TYPE_INITIATOR_WRITE) ? + "Write " : "Read ", (cmd->io_tbl.sge_valid == 1) ? + "Single" : (cmd->use_slowpath ? "SLOW" : "FAST"), + (u16)cmd->io_tbl.sge_valid, (u32)(cmd->io_tbl.sge_tbl_dma), + (u32)((u64)cmd->io_tbl.sge_tbl_dma >> 32)); + + /* Add command in active command list */ + spin_lock(&qedi_conn->list_lock); + list_add_tail(&cmd->io_cmd, &qedi_conn->active_cmd_list); + cmd->io_cmd_in_list = true; + qedi_conn->active_cmd_count++; + spin_unlock(&qedi_conn->list_lock); + + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false); + qedi_ring_doorbell(qedi_conn); + if (qedi_io_tracing) + qedi_trace_io(qedi, task, tid, QEDI_IO_TRACE_REQ); + + return 0; +} + +int qedi_iscsi_cleanup_task(struct iscsi_task *task, bool mark_cmd_node_deleted) +{ + struct iscsi_conn *conn = task->conn; + struct qedi_conn *qedi_conn = conn->dd_data; + struct qedi_cmd *cmd = task->dd_data; + s16 ptu_invalidate = 0; + + QEDI_INFO(&qedi_conn->qedi->dbg_ctx, QEDI_LOG_SCSI_TM, + "issue cleanup tid=0x%x itt=0x%x task_state=%d cmd_state=0%x cid=0x%x\n", + cmd->task_id, get_itt(task->itt), task->state, + cmd->state, qedi_conn->iscsi_conn_id); + + qedi_add_to_sq(qedi_conn, task, cmd->task_id, ptu_invalidate, true); + qedi_ring_doorbell(qedi_conn); + + return 0; +} diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h new file mode 100644 index 000000000000..8e488de88ece --- /dev/null +++ b/drivers/scsi/qedi/qedi_gbl.h @@ -0,0 +1,73 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QEDI_GBL_H_ +#define _QEDI_GBL_H_ + +#include "qedi_iscsi.h" + +extern uint qedi_io_tracing; +extern int do_not_recover; +extern struct scsi_host_template qedi_host_template; +extern struct iscsi_transport qedi_iscsi_transport; +extern const struct qed_iscsi_ops *qedi_ops; +extern struct qedi_debugfs_ops qedi_debugfs_ops; +extern const struct file_operations qedi_dbg_fops; +extern struct device_attribute *qedi_shost_attrs[]; + +int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep); +void qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep); + +int qedi_send_iscsi_login(struct qedi_conn *qedi_conn, + struct iscsi_task *task); +int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn, + struct iscsi_task *task); +int qedi_iscsi_abort_work(struct qedi_conn *qedi_conn, + struct iscsi_task *mtask); +int qedi_send_iscsi_text(struct qedi_conn *qedi_conn, + struct iscsi_task *task); +int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn, + struct iscsi_task *task, + char *datap, int data_len, int unsol); +int qedi_iscsi_send_ioreq(struct iscsi_task *task); +int qedi_get_task_idx(struct qedi_ctx *qedi); +void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx); +int qedi_iscsi_cleanup_task(struct iscsi_task *task, + bool mark_cmd_node_deleted); +void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd); +void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, + struct qedi_cmd *qedi_cmd); +void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt); +void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, int16_t *tid); +void qedi_process_iscsi_error(struct qedi_endpoint *ep, + struct async_data *data); +void qedi_start_conn_recovery(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn); +struct qedi_conn *qedi_get_conn_from_id(struct qedi_ctx *qedi, u32 iscsi_cid); +void qedi_process_tcp_error(struct qedi_endpoint *ep, struct async_data *data); +void qedi_mark_device_missing(struct iscsi_cls_session *cls_session); +void qedi_mark_device_available(struct iscsi_cls_session *cls_session); +void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu); +int qedi_recover_all_conns(struct qedi_ctx *qedi); +void qedi_fp_process_cqes(struct qedi_work *work); +int qedi_cleanup_all_io(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn, + struct iscsi_task *task, bool in_recovery); +void qedi_trace_io(struct qedi_ctx *qedi, struct iscsi_task *task, + u16 tid, int8_t direction); +int qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id); +u16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl); +void qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id); +int qedi_create_sysfs_ctx_attr(struct qedi_ctx *qedi); +void qedi_remove_sysfs_ctx_attr(struct qedi_ctx *qedi); +void qedi_clearsq(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn, + struct iscsi_task *task); + +#endif diff --git a/drivers/scsi/qedi/qedi_hsi.h b/drivers/scsi/qedi/qedi_hsi.h new file mode 100644 index 000000000000..8ca44c78f093 --- /dev/null +++ b/drivers/scsi/qedi/qedi_hsi.h @@ -0,0 +1,52 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ +#ifndef __QEDI_HSI__ +#define __QEDI_HSI__ +/* + * Add include to common target + */ +#include + +/* + * Add include to common storage target + */ +#include + +/* + * Add include to common TCP target + */ +#include + +/* + * Add include to common iSCSI target for both eCore and protocol driver + */ +#include + +/* + * iSCSI CMDQ element + */ +struct iscsi_cmdqe { + __le16 conn_id; + u8 invalid_command; + u8 cmd_hdr_type; + __le32 reserved1[2]; + __le32 cmd_payload[13]; +}; + +/* + * iSCSI CMD header type + */ +enum iscsi_cmd_hdr_type { + ISCSI_CMD_HDR_TYPE_BHS_ONLY /* iSCSI BHS with no expected AHS */, + ISCSI_CMD_HDR_TYPE_BHS_W_AHS /* iSCSI BHS with expected AHS */, + ISCSI_CMD_HDR_TYPE_AHS /* iSCSI AHS */, + MAX_ISCSI_CMD_HDR_TYPE +}; + +#endif /* __QEDI_HSI__ */ diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c new file mode 100644 index 000000000000..d6a205433b66 --- /dev/null +++ b/drivers/scsi/qedi/qedi_iscsi.c @@ -0,0 +1,1624 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include + +#include "qedi.h" +#include "qedi_iscsi.h" +#include "qedi_gbl.h" + +int qedi_recover_all_conns(struct qedi_ctx *qedi) +{ + struct qedi_conn *qedi_conn; + int i; + + for (i = 0; i < qedi->max_active_conns; i++) { + qedi_conn = qedi_get_conn_from_id(qedi, i); + if (!qedi_conn) + continue; + + qedi_start_conn_recovery(qedi, qedi_conn); + } + + return SUCCESS; +} + +static int qedi_eh_host_reset(struct scsi_cmnd *cmd) +{ + struct Scsi_Host *shost = cmd->device->host; + struct qedi_ctx *qedi; + + qedi = iscsi_host_priv(shost); + + return qedi_recover_all_conns(qedi); +} + +struct scsi_host_template qedi_host_template = { + .module = THIS_MODULE, + .name = "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver", + .proc_name = QEDI_MODULE_NAME, + .queuecommand = iscsi_queuecommand, + .eh_abort_handler = iscsi_eh_abort, + .eh_device_reset_handler = iscsi_eh_device_reset, + .eh_target_reset_handler = iscsi_eh_recover_target, + .eh_host_reset_handler = qedi_eh_host_reset, + .target_alloc = iscsi_target_alloc, + .change_queue_depth = scsi_change_queue_depth, + .can_queue = QEDI_MAX_ISCSI_TASK, + .this_id = -1, + .sg_tablesize = QEDI_ISCSI_MAX_BDS_PER_CMD, + .max_sectors = 0xffff, + .cmd_per_lun = 128, + .use_clustering = ENABLE_CLUSTERING, + .shost_attrs = qedi_shost_attrs, +}; + +static void qedi_conn_free_login_resources(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn) +{ + if (qedi_conn->gen_pdu.resp_bd_tbl) { + dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, + qedi_conn->gen_pdu.resp_bd_tbl, + qedi_conn->gen_pdu.resp_bd_dma); + qedi_conn->gen_pdu.resp_bd_tbl = NULL; + } + + if (qedi_conn->gen_pdu.req_bd_tbl) { + dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, + qedi_conn->gen_pdu.req_bd_tbl, + qedi_conn->gen_pdu.req_bd_dma); + qedi_conn->gen_pdu.req_bd_tbl = NULL; + } + + if (qedi_conn->gen_pdu.resp_buf) { + dma_free_coherent(&qedi->pdev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + qedi_conn->gen_pdu.resp_buf, + qedi_conn->gen_pdu.resp_dma_addr); + qedi_conn->gen_pdu.resp_buf = NULL; + } + + if (qedi_conn->gen_pdu.req_buf) { + dma_free_coherent(&qedi->pdev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + qedi_conn->gen_pdu.req_buf, + qedi_conn->gen_pdu.req_dma_addr); + qedi_conn->gen_pdu.req_buf = NULL; + } +} + +static int qedi_conn_alloc_login_resources(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn) +{ + qedi_conn->gen_pdu.req_buf = + dma_alloc_coherent(&qedi->pdev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + &qedi_conn->gen_pdu.req_dma_addr, + GFP_KERNEL); + if (!qedi_conn->gen_pdu.req_buf) + goto login_req_buf_failure; + + qedi_conn->gen_pdu.req_buf_size = 0; + qedi_conn->gen_pdu.req_wr_ptr = qedi_conn->gen_pdu.req_buf; + + qedi_conn->gen_pdu.resp_buf = + dma_alloc_coherent(&qedi->pdev->dev, + ISCSI_DEF_MAX_RECV_SEG_LEN, + &qedi_conn->gen_pdu.resp_dma_addr, + GFP_KERNEL); + if (!qedi_conn->gen_pdu.resp_buf) + goto login_resp_buf_failure; + + qedi_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN; + qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf; + + qedi_conn->gen_pdu.req_bd_tbl = + dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, + &qedi_conn->gen_pdu.req_bd_dma, GFP_KERNEL); + if (!qedi_conn->gen_pdu.req_bd_tbl) + goto login_req_bd_tbl_failure; + + qedi_conn->gen_pdu.resp_bd_tbl = + dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, + &qedi_conn->gen_pdu.resp_bd_dma, + GFP_KERNEL); + if (!qedi_conn->gen_pdu.resp_bd_tbl) + goto login_resp_bd_tbl_failure; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SESS, + "Allocation successful, cid=0x%x\n", + qedi_conn->iscsi_conn_id); + return 0; + +login_resp_bd_tbl_failure: + dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE, + qedi_conn->gen_pdu.req_bd_tbl, + qedi_conn->gen_pdu.req_bd_dma); + qedi_conn->gen_pdu.req_bd_tbl = NULL; + +login_req_bd_tbl_failure: + dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, + qedi_conn->gen_pdu.resp_buf, + qedi_conn->gen_pdu.resp_dma_addr); + qedi_conn->gen_pdu.resp_buf = NULL; +login_resp_buf_failure: + dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN, + qedi_conn->gen_pdu.req_buf, + qedi_conn->gen_pdu.req_dma_addr); + qedi_conn->gen_pdu.req_buf = NULL; +login_req_buf_failure: + iscsi_conn_printk(KERN_ERR, qedi_conn->cls_conn->dd_data, + "login resource alloc failed!!\n"); + return -ENOMEM; +} + +static void qedi_destroy_cmd_pool(struct qedi_ctx *qedi, + struct iscsi_session *session) +{ + int i; + + for (i = 0; i < session->cmds_max; i++) { + struct iscsi_task *task = session->cmds[i]; + struct qedi_cmd *cmd = task->dd_data; + + if (cmd->io_tbl.sge_tbl) + dma_free_coherent(&qedi->pdev->dev, + QEDI_ISCSI_MAX_BDS_PER_CMD * + sizeof(struct iscsi_sge), + cmd->io_tbl.sge_tbl, + cmd->io_tbl.sge_tbl_dma); + + if (cmd->sense_buffer) + dma_free_coherent(&qedi->pdev->dev, + SCSI_SENSE_BUFFERSIZE, + cmd->sense_buffer, + cmd->sense_buffer_dma); + } +} + +static int qedi_alloc_sget(struct qedi_ctx *qedi, struct iscsi_session *session, + struct qedi_cmd *cmd) +{ + struct qedi_io_bdt *io = &cmd->io_tbl; + struct iscsi_sge *sge; + + io->sge_tbl = dma_alloc_coherent(&qedi->pdev->dev, + QEDI_ISCSI_MAX_BDS_PER_CMD * + sizeof(*sge), + &io->sge_tbl_dma, GFP_KERNEL); + if (!io->sge_tbl) { + iscsi_session_printk(KERN_ERR, session, + "Could not allocate BD table.\n"); + return -ENOMEM; + } + + io->sge_valid = 0; + return 0; +} + +static int qedi_setup_cmd_pool(struct qedi_ctx *qedi, + struct iscsi_session *session) +{ + int i; + + for (i = 0; i < session->cmds_max; i++) { + struct iscsi_task *task = session->cmds[i]; + struct qedi_cmd *cmd = task->dd_data; + + task->hdr = &cmd->hdr; + task->hdr_max = sizeof(struct iscsi_hdr); + + if (qedi_alloc_sget(qedi, session, cmd)) + goto free_sgets; + + cmd->sense_buffer = dma_alloc_coherent(&qedi->pdev->dev, + SCSI_SENSE_BUFFERSIZE, + &cmd->sense_buffer_dma, + GFP_KERNEL); + if (!cmd->sense_buffer) + goto free_sgets; + } + + return 0; + +free_sgets: + qedi_destroy_cmd_pool(qedi, session); + return -ENOMEM; +} + +static struct iscsi_cls_session * +qedi_session_create(struct iscsi_endpoint *ep, u16 cmds_max, + u16 qdepth, uint32_t initial_cmdsn) +{ + struct Scsi_Host *shost; + struct iscsi_cls_session *cls_session; + struct qedi_ctx *qedi; + struct qedi_endpoint *qedi_ep; + + if (!ep) + return NULL; + + qedi_ep = ep->dd_data; + shost = qedi_ep->qedi->shost; + qedi = iscsi_host_priv(shost); + + if (cmds_max > qedi->max_sqes) + cmds_max = qedi->max_sqes; + else if (cmds_max < QEDI_SQ_WQES_MIN) + cmds_max = QEDI_SQ_WQES_MIN; + + cls_session = iscsi_session_setup(&qedi_iscsi_transport, shost, + cmds_max, 0, sizeof(struct qedi_cmd), + initial_cmdsn, ISCSI_MAX_TARGET); + if (!cls_session) { + QEDI_ERR(&qedi->dbg_ctx, + "Failed to setup session for ep=%p\n", qedi_ep); + return NULL; + } + + if (qedi_setup_cmd_pool(qedi, cls_session->dd_data)) { + QEDI_ERR(&qedi->dbg_ctx, + "Failed to setup cmd pool for ep=%p\n", qedi_ep); + goto session_teardown; + } + + return cls_session; + +session_teardown: + iscsi_session_teardown(cls_session); + return NULL; +} + +static void qedi_session_destroy(struct iscsi_cls_session *cls_session) +{ + struct iscsi_session *session = cls_session->dd_data; + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct qedi_ctx *qedi = iscsi_host_priv(shost); + + qedi_destroy_cmd_pool(qedi, session); + iscsi_session_teardown(cls_session); +} + +static struct iscsi_cls_conn * +qedi_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid) +{ + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct qedi_ctx *qedi = iscsi_host_priv(shost); + struct iscsi_cls_conn *cls_conn; + struct qedi_conn *qedi_conn; + struct iscsi_conn *conn; + + cls_conn = iscsi_conn_setup(cls_session, sizeof(*qedi_conn), + cid); + if (!cls_conn) { + QEDI_ERR(&qedi->dbg_ctx, + "conn_new: iscsi conn setup failed, cid=0x%x, cls_sess=%p!\n", + cid, cls_session); + return NULL; + } + + conn = cls_conn->dd_data; + qedi_conn = conn->dd_data; + qedi_conn->cls_conn = cls_conn; + qedi_conn->qedi = qedi; + qedi_conn->ep = NULL; + qedi_conn->active_cmd_count = 0; + INIT_LIST_HEAD(&qedi_conn->active_cmd_list); + spin_lock_init(&qedi_conn->list_lock); + + if (qedi_conn_alloc_login_resources(qedi, qedi_conn)) { + iscsi_conn_printk(KERN_ALERT, conn, + "conn_new: login resc alloc failed, cid=0x%x, cls_sess=%p!!\n", + cid, cls_session); + goto free_conn; + } + + return cls_conn; + +free_conn: + iscsi_conn_teardown(cls_conn); + return NULL; +} + +void qedi_mark_device_missing(struct iscsi_cls_session *cls_session) +{ + iscsi_block_session(cls_session); +} + +void qedi_mark_device_available(struct iscsi_cls_session *cls_session) +{ + iscsi_unblock_session(cls_session); +} + +static int qedi_bind_conn_to_iscsi_cid(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn) +{ + u32 iscsi_cid = qedi_conn->iscsi_conn_id; + + if (qedi->cid_que.conn_cid_tbl[iscsi_cid]) { + iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data, + "conn bind - entry #%d not free\n", + iscsi_cid); + return -EBUSY; + } + + qedi->cid_que.conn_cid_tbl[iscsi_cid] = qedi_conn; + return 0; +} + +struct qedi_conn *qedi_get_conn_from_id(struct qedi_ctx *qedi, u32 iscsi_cid) +{ + if (!qedi->cid_que.conn_cid_tbl) { + QEDI_ERR(&qedi->dbg_ctx, "missing conn<->cid table\n"); + return NULL; + + } else if (iscsi_cid >= qedi->max_active_conns) { + QEDI_ERR(&qedi->dbg_ctx, "wrong cid #%d\n", iscsi_cid); + return NULL; + } + return qedi->cid_que.conn_cid_tbl[iscsi_cid]; +} + +static int qedi_conn_bind(struct iscsi_cls_session *cls_session, + struct iscsi_cls_conn *cls_conn, + u64 transport_fd, int is_leading) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct qedi_conn *qedi_conn = conn->dd_data; + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session); + struct qedi_ctx *qedi = iscsi_host_priv(shost); + struct qedi_endpoint *qedi_ep; + struct iscsi_endpoint *ep; + + ep = iscsi_lookup_endpoint(transport_fd); + if (!ep) + return -EINVAL; + + qedi_ep = ep->dd_data; + if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) || + (qedi_ep->state == EP_STATE_TCP_RST_RCVD)) + return -EINVAL; + + if (iscsi_conn_bind(cls_session, cls_conn, is_leading)) + return -EINVAL; + + qedi_ep->conn = qedi_conn; + qedi_conn->ep = qedi_ep; + qedi_conn->iscsi_conn_id = qedi_ep->iscsi_cid; + qedi_conn->fw_cid = qedi_ep->fw_cid; + qedi_conn->cmd_cleanup_req = 0; + qedi_conn->cmd_cleanup_cmpl = 0; + + if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn)) + return -EINVAL; + + spin_lock_init(&qedi_conn->tmf_work_lock); + INIT_LIST_HEAD(&qedi_conn->tmf_work_list); + init_waitqueue_head(&qedi_conn->wait_queue); + return 0; +} + +static int qedi_iscsi_update_conn(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn) +{ + struct qed_iscsi_params_update *conn_info; + struct iscsi_cls_conn *cls_conn = qedi_conn->cls_conn; + struct iscsi_conn *conn = cls_conn->dd_data; + struct qedi_endpoint *qedi_ep; + int rval; + + qedi_ep = qedi_conn->ep; + + conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL); + if (!conn_info) { + QEDI_ERR(&qedi->dbg_ctx, "memory alloc failed\n"); + return -ENOMEM; + } + + conn_info->update_flag = 0; + + if (conn->hdrdgst_en) + SET_FIELD(conn_info->update_flag, + ISCSI_CONN_UPDATE_RAMROD_PARAMS_HD_EN, true); + if (conn->datadgst_en) + SET_FIELD(conn_info->update_flag, + ISCSI_CONN_UPDATE_RAMROD_PARAMS_DD_EN, true); + if (conn->session->initial_r2t_en) + SET_FIELD(conn_info->update_flag, + ISCSI_CONN_UPDATE_RAMROD_PARAMS_INITIAL_R2T, + true); + if (conn->session->imm_data_en) + SET_FIELD(conn_info->update_flag, + ISCSI_CONN_UPDATE_RAMROD_PARAMS_IMMEDIATE_DATA, + true); + + conn_info->max_seq_size = conn->session->max_burst; + conn_info->max_recv_pdu_length = conn->max_recv_dlength; + conn_info->max_send_pdu_length = conn->max_xmit_dlength; + conn_info->first_seq_length = conn->session->first_burst; + conn_info->exp_stat_sn = conn->exp_statsn; + + rval = qedi_ops->update_conn(qedi->cdev, qedi_ep->handle, + conn_info); + if (rval) { + rval = -ENXIO; + QEDI_ERR(&qedi->dbg_ctx, "Could not update connection\n"); + goto update_conn_err; + } + + kfree(conn_info); + rval = 0; + +update_conn_err: + return rval; +} + +static u16 qedi_calc_mss(u16 pmtu, u8 is_ipv6, u8 tcp_ts_en, u8 vlan_en) +{ + u16 mss = 0; + u16 hdrs = TCP_HDR_LEN; + + if (is_ipv6) + hdrs += IPV6_HDR_LEN; + else + hdrs += IPV4_HDR_LEN; + + if (vlan_en) + hdrs += VLAN_LEN; + + mss = pmtu - hdrs; + + if (tcp_ts_en) + mss -= TCP_OPTION_LEN; + + if (!mss) + mss = DEF_MSS; + + return mss; +} + +static int qedi_iscsi_offload_conn(struct qedi_endpoint *qedi_ep) +{ + struct qedi_ctx *qedi = qedi_ep->qedi; + struct qed_iscsi_params_offload *conn_info; + int rval; + int i; + + conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL); + if (!conn_info) { + QEDI_ERR(&qedi->dbg_ctx, + "Failed to allocate memory ep=%p\n", qedi_ep); + return -ENOMEM; + } + + ether_addr_copy(conn_info->src.mac, qedi_ep->src_mac); + ether_addr_copy(conn_info->dst.mac, qedi_ep->dst_mac); + + conn_info->src.ip[0] = ntohl(qedi_ep->src_addr[0]); + conn_info->dst.ip[0] = ntohl(qedi_ep->dst_addr[0]); + + if (qedi_ep->ip_type == TCP_IPV4) { + conn_info->ip_version = 0; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "After ntohl: src_addr=%pI4, dst_addr=%pI4\n", + qedi_ep->src_addr, qedi_ep->dst_addr); + } else { + for (i = 1; i < 4; i++) { + conn_info->src.ip[i] = ntohl(qedi_ep->src_addr[i]); + conn_info->dst.ip[i] = ntohl(qedi_ep->dst_addr[i]); + } + + conn_info->ip_version = 1; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "After ntohl: src_addr=%pI6, dst_addr=%pI6\n", + qedi_ep->src_addr, qedi_ep->dst_addr); + } + + conn_info->src.port = qedi_ep->src_port; + conn_info->dst.port = qedi_ep->dst_port; + + conn_info->layer_code = ISCSI_SLOW_PATH_LAYER_CODE; + conn_info->sq_pbl_addr = qedi_ep->sq_pbl_dma; + conn_info->vlan_id = qedi_ep->vlan_id; + + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_TS_EN, 1); + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_EN, 1); + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_CNT_EN, 1); + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_KA_EN, 1); + + conn_info->default_cq = (qedi_ep->fw_cid % 8); + + conn_info->ka_max_probe_cnt = DEF_KA_MAX_PROBE_COUNT; + conn_info->dup_ack_theshold = 3; + conn_info->rcv_wnd = 65535; + conn_info->cwnd = DEF_MAX_CWND; + + conn_info->ss_thresh = 65535; + conn_info->srtt = 300; + conn_info->rtt_var = 150; + conn_info->flow_label = 0; + conn_info->ka_timeout = DEF_KA_TIMEOUT; + conn_info->ka_interval = DEF_KA_INTERVAL; + conn_info->max_rt_time = DEF_MAX_RT_TIME; + conn_info->ttl = DEF_TTL; + conn_info->tos_or_tc = DEF_TOS; + conn_info->remote_port = qedi_ep->dst_port; + conn_info->local_port = qedi_ep->src_port; + + conn_info->mss = qedi_calc_mss(qedi_ep->pmtu, + (qedi_ep->ip_type == TCP_IPV6), + 1, (qedi_ep->vlan_id != 0)); + + conn_info->rcv_wnd_scale = 4; + conn_info->ts_ticks_per_second = 1000; + conn_info->da_timeout_value = 200; + conn_info->ack_frequency = 2; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Default cq index [%d], mss [%d]\n", + conn_info->default_cq, conn_info->mss); + + rval = qedi_ops->offload_conn(qedi->cdev, qedi_ep->handle, conn_info); + if (rval) + QEDI_ERR(&qedi->dbg_ctx, "offload_conn returned %d, ep=%p\n", + rval, qedi_ep); + + kfree(conn_info); + return rval; +} + +static int qedi_conn_start(struct iscsi_cls_conn *cls_conn) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct qedi_conn *qedi_conn = conn->dd_data; + struct qedi_ctx *qedi; + int rval; + + qedi = qedi_conn->qedi; + + rval = qedi_iscsi_update_conn(qedi, qedi_conn); + if (rval) { + iscsi_conn_printk(KERN_ALERT, conn, + "conn_start: FW oflload conn failed.\n"); + rval = -EINVAL; + goto start_err; + } + + clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags); + qedi_conn->abrt_conn = 0; + + rval = iscsi_conn_start(cls_conn); + if (rval) { + iscsi_conn_printk(KERN_ALERT, conn, + "iscsi_conn_start: FW oflload conn failed!!\n"); + } + +start_err: + return rval; +} + +static void qedi_conn_destroy(struct iscsi_cls_conn *cls_conn) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct qedi_conn *qedi_conn = conn->dd_data; + struct Scsi_Host *shost; + struct qedi_ctx *qedi; + + shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); + qedi = iscsi_host_priv(shost); + + qedi_conn_free_login_resources(qedi, qedi_conn); + iscsi_conn_teardown(cls_conn); +} + +static int qedi_ep_get_param(struct iscsi_endpoint *ep, + enum iscsi_param param, char *buf) +{ + struct qedi_endpoint *qedi_ep = ep->dd_data; + int len; + + if (!qedi_ep) + return -ENOTCONN; + + switch (param) { + case ISCSI_PARAM_CONN_PORT: + len = sprintf(buf, "%hu\n", qedi_ep->dst_port); + break; + case ISCSI_PARAM_CONN_ADDRESS: + if (qedi_ep->ip_type == TCP_IPV4) + len = sprintf(buf, "%pI4\n", qedi_ep->dst_addr); + else + len = sprintf(buf, "%pI6\n", qedi_ep->dst_addr); + break; + default: + return -ENOTCONN; + } + + return len; +} + +static int qedi_host_get_param(struct Scsi_Host *shost, + enum iscsi_host_param param, char *buf) +{ + struct qedi_ctx *qedi; + int len; + + qedi = iscsi_host_priv(shost); + + switch (param) { + case ISCSI_HOST_PARAM_HWADDRESS: + len = sysfs_format_mac(buf, qedi->mac, 6); + break; + case ISCSI_HOST_PARAM_NETDEV_NAME: + len = sprintf(buf, "host%d\n", shost->host_no); + break; + case ISCSI_HOST_PARAM_IPADDRESS: + if (qedi->ip_type == TCP_IPV4) + len = sprintf(buf, "%pI4\n", qedi->src_ip); + else + len = sprintf(buf, "%pI6\n", qedi->src_ip); + break; + default: + return iscsi_host_get_param(shost, param, buf); + } + + return len; +} + +static void qedi_conn_get_stats(struct iscsi_cls_conn *cls_conn, + struct iscsi_stats *stats) +{ + struct iscsi_conn *conn = cls_conn->dd_data; + struct qed_iscsi_stats iscsi_stats; + struct Scsi_Host *shost; + struct qedi_ctx *qedi; + + shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn)); + qedi = iscsi_host_priv(shost); + qedi_ops->get_stats(qedi->cdev, &iscsi_stats); + + conn->txdata_octets = iscsi_stats.iscsi_tx_bytes_cnt; + conn->rxdata_octets = iscsi_stats.iscsi_rx_bytes_cnt; + conn->dataout_pdus_cnt = (uint32_t)iscsi_stats.iscsi_tx_data_pdu_cnt; + conn->datain_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_data_pdu_cnt; + conn->r2t_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_r2t_pdu_cnt; + + stats->txdata_octets = conn->txdata_octets; + stats->rxdata_octets = conn->rxdata_octets; + stats->scsicmd_pdus = conn->scsicmd_pdus_cnt; + stats->dataout_pdus = conn->dataout_pdus_cnt; + stats->scsirsp_pdus = conn->scsirsp_pdus_cnt; + stats->datain_pdus = conn->datain_pdus_cnt; + stats->r2t_pdus = conn->r2t_pdus_cnt; + stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt; + stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt; + stats->digest_err = 0; + stats->timeout_err = 0; + strcpy(stats->custom[0].desc, "eh_abort_cnt"); + stats->custom[0].value = conn->eh_abort_cnt; + stats->custom_length = 1; +} + +static void qedi_iscsi_prep_generic_pdu_bd(struct qedi_conn *qedi_conn) +{ + struct iscsi_sge *bd_tbl; + + bd_tbl = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl; + + bd_tbl->sge_addr.hi = + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32); + bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.req_dma_addr; + bd_tbl->sge_len = qedi_conn->gen_pdu.req_wr_ptr - + qedi_conn->gen_pdu.req_buf; + bd_tbl->reserved0 = 0; + bd_tbl = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl; + bd_tbl->sge_addr.hi = + (u32)((u64)qedi_conn->gen_pdu.resp_dma_addr >> 32); + bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.resp_dma_addr; + bd_tbl->sge_len = ISCSI_DEF_MAX_RECV_SEG_LEN; + bd_tbl->reserved0 = 0; +} + +static int qedi_iscsi_send_generic_request(struct iscsi_task *task) +{ + struct qedi_cmd *cmd = task->dd_data; + struct qedi_conn *qedi_conn = cmd->conn; + char *buf; + int data_len; + int rc = 0; + + qedi_iscsi_prep_generic_pdu_bd(qedi_conn); + switch (task->hdr->opcode & ISCSI_OPCODE_MASK) { + case ISCSI_OP_LOGIN: + qedi_send_iscsi_login(qedi_conn, task); + break; + case ISCSI_OP_NOOP_OUT: + data_len = qedi_conn->gen_pdu.req_buf_size; + buf = qedi_conn->gen_pdu.req_buf; + if (data_len) + rc = qedi_send_iscsi_nopout(qedi_conn, task, + buf, data_len, 1); + else + rc = qedi_send_iscsi_nopout(qedi_conn, task, + NULL, 0, 1); + break; + case ISCSI_OP_LOGOUT: + rc = qedi_send_iscsi_logout(qedi_conn, task); + break; + case ISCSI_OP_SCSI_TMFUNC: + rc = qedi_iscsi_abort_work(qedi_conn, task); + break; + case ISCSI_OP_TEXT: + rc = qedi_send_iscsi_text(qedi_conn, task); + break; + default: + iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data, + "unsupported op 0x%x\n", task->hdr->opcode); + } + + return rc; +} + +static int qedi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task) +{ + struct qedi_conn *qedi_conn = conn->dd_data; + struct qedi_cmd *cmd = task->dd_data; + + memset(qedi_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN); + + qedi_conn->gen_pdu.req_buf_size = task->data_count; + + if (task->data_count) { + memcpy(qedi_conn->gen_pdu.req_buf, task->data, + task->data_count); + qedi_conn->gen_pdu.req_wr_ptr = + qedi_conn->gen_pdu.req_buf + task->data_count; + } + + cmd->conn = conn->dd_data; + cmd->scsi_cmd = NULL; + return qedi_iscsi_send_generic_request(task); +} + +static int qedi_task_xmit(struct iscsi_task *task) +{ + struct iscsi_conn *conn = task->conn; + struct qedi_conn *qedi_conn = conn->dd_data; + struct qedi_cmd *cmd = task->dd_data; + struct scsi_cmnd *sc = task->sc; + + cmd->state = 0; + cmd->task = NULL; + cmd->use_slowpath = false; + cmd->conn = qedi_conn; + cmd->task = task; + cmd->io_cmd_in_list = false; + INIT_LIST_HEAD(&cmd->io_cmd); + + if (!sc) + return qedi_mtask_xmit(conn, task); + + cmd->scsi_cmd = sc; + return qedi_iscsi_send_ioreq(task); +} + +static struct iscsi_endpoint * +qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr, + int non_blocking) +{ + struct qedi_ctx *qedi; + struct iscsi_endpoint *ep; + struct qedi_endpoint *qedi_ep; + struct sockaddr_in *addr; + struct sockaddr_in6 *addr6; + struct qed_dev *cdev = NULL; + struct qedi_uio_dev *udev = NULL; + struct iscsi_path path_req; + u32 msg_type = ISCSI_KEVENT_IF_DOWN; + u32 iscsi_cid = QEDI_CID_RESERVED; + u16 len = 0; + char *buf = NULL; + int ret; + + if (!shost) { + ret = -ENXIO; + QEDI_ERR(NULL, "shost is NULL\n"); + return ERR_PTR(ret); + } + + if (do_not_recover) { + ret = -ENOMEM; + return ERR_PTR(ret); + } + + qedi = iscsi_host_priv(shost); + cdev = qedi->cdev; + udev = qedi->udev; + + if (test_bit(QEDI_IN_OFFLINE, &qedi->flags) || + test_bit(QEDI_IN_RECOVERY, &qedi->flags)) { + ret = -ENOMEM; + return ERR_PTR(ret); + } + + ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint)); + if (!ep) { + QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n"); + ret = -ENOMEM; + return ERR_PTR(ret); + } + qedi_ep = ep->dd_data; + memset(qedi_ep, 0, sizeof(struct qedi_endpoint)); + qedi_ep->state = EP_STATE_IDLE; + qedi_ep->iscsi_cid = (u32)-1; + qedi_ep->qedi = qedi; + + if (dst_addr->sa_family == AF_INET) { + addr = (struct sockaddr_in *)dst_addr; + memcpy(qedi_ep->dst_addr, &addr->sin_addr.s_addr, + sizeof(struct in_addr)); + qedi_ep->dst_port = ntohs(addr->sin_port); + qedi_ep->ip_type = TCP_IPV4; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "dst_addr=%pI4, dst_port=%u\n", + qedi_ep->dst_addr, qedi_ep->dst_port); + } else if (dst_addr->sa_family == AF_INET6) { + addr6 = (struct sockaddr_in6 *)dst_addr; + memcpy(qedi_ep->dst_addr, &addr6->sin6_addr, + sizeof(struct in6_addr)); + qedi_ep->dst_port = ntohs(addr6->sin6_port); + qedi_ep->ip_type = TCP_IPV6; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "dst_addr=%pI6, dst_port=%u\n", + qedi_ep->dst_addr, qedi_ep->dst_port); + } else { + QEDI_ERR(&qedi->dbg_ctx, "Invalid endpoint\n"); + } + + if (atomic_read(&qedi->link_state) != QEDI_LINK_UP) { + QEDI_WARN(&qedi->dbg_ctx, "qedi link down\n"); + ret = -ENXIO; + goto ep_conn_exit; + } + + ret = qedi_alloc_sq(qedi, qedi_ep); + if (ret) + goto ep_conn_exit; + + ret = qedi_ops->acquire_conn(qedi->cdev, &qedi_ep->handle, + &qedi_ep->fw_cid, &qedi_ep->p_doorbell); + + if (ret) { + QEDI_ERR(&qedi->dbg_ctx, "Could not acquire connection\n"); + ret = -ENXIO; + goto ep_free_sq; + } + + iscsi_cid = qedi_ep->handle; + qedi_ep->iscsi_cid = iscsi_cid; + + init_waitqueue_head(&qedi_ep->ofld_wait); + init_waitqueue_head(&qedi_ep->tcp_ofld_wait); + qedi_ep->state = EP_STATE_OFLDCONN_START; + qedi->ep_tbl[iscsi_cid] = qedi_ep; + + buf = (char *)&path_req; + len = sizeof(path_req); + memset(&path_req, 0, len); + + msg_type = ISCSI_KEVENT_PATH_REQ; + path_req.handle = (u64)qedi_ep->iscsi_cid; + path_req.pmtu = qedi->ll2_mtu; + qedi_ep->pmtu = qedi->ll2_mtu; + if (qedi_ep->ip_type == TCP_IPV4) { + memcpy(&path_req.dst.v4_addr, &qedi_ep->dst_addr, + sizeof(struct in_addr)); + path_req.ip_addr_len = 4; + } else { + memcpy(&path_req.dst.v6_addr, &qedi_ep->dst_addr, + sizeof(struct in6_addr)); + path_req.ip_addr_len = 16; + } + + ret = iscsi_offload_mesg(shost, &qedi_iscsi_transport, msg_type, buf, + len); + if (ret) { + QEDI_ERR(&qedi->dbg_ctx, + "iscsi_offload_mesg() failed for cid=0x%x ret=%d\n", + iscsi_cid, ret); + goto ep_rel_conn; + } + + atomic_inc(&qedi->num_offloads); + return ep; + +ep_rel_conn: + qedi->ep_tbl[iscsi_cid] = NULL; + ret = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle); + if (ret) + QEDI_WARN(&qedi->dbg_ctx, "release_conn returned %d\n", + ret); +ep_free_sq: + qedi_free_sq(qedi, qedi_ep); +ep_conn_exit: + iscsi_destroy_endpoint(ep); + return ERR_PTR(ret); +} + +static int qedi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms) +{ + struct qedi_endpoint *qedi_ep; + int ret = 0; + + if (do_not_recover) + return 1; + + qedi_ep = ep->dd_data; + if (qedi_ep->state == EP_STATE_IDLE || + qedi_ep->state == EP_STATE_OFLDCONN_FAILED) + return -1; + + if (qedi_ep->state == EP_STATE_OFLDCONN_COMPL) + ret = 1; + + ret = wait_event_interruptible_timeout(qedi_ep->ofld_wait, + QEDI_OFLD_WAIT_STATE(qedi_ep), + msecs_to_jiffies(timeout_ms)); + + if (qedi_ep->state == EP_STATE_OFLDCONN_FAILED) + ret = -1; + + if (ret > 0) + return 1; + else if (!ret) + return 0; + else + return ret; +} + +static void qedi_cleanup_active_cmd_list(struct qedi_conn *qedi_conn) +{ + struct qedi_cmd *cmd, *cmd_tmp; + + list_for_each_entry_safe(cmd, cmd_tmp, &qedi_conn->active_cmd_list, + io_cmd) { + list_del_init(&cmd->io_cmd); + qedi_conn->active_cmd_count--; + } +} + +static void qedi_ep_disconnect(struct iscsi_endpoint *ep) +{ + struct qedi_endpoint *qedi_ep; + struct qedi_conn *qedi_conn = NULL; + struct iscsi_conn *conn = NULL; + struct qedi_ctx *qedi; + int ret = 0; + int wait_delay = 20 * HZ; + int abrt_conn = 0; + int count = 10; + + qedi_ep = ep->dd_data; + qedi = qedi_ep->qedi; + + flush_work(&qedi_ep->offload_work); + + if (qedi_ep->conn) { + qedi_conn = qedi_ep->conn; + conn = qedi_conn->cls_conn->dd_data; + iscsi_suspend_queue(conn); + abrt_conn = qedi_conn->abrt_conn; + + while (count--) { + if (!test_bit(QEDI_CONN_FW_CLEANUP, + &qedi_conn->flags)) { + break; + } + msleep(1000); + } + + if (test_bit(QEDI_IN_RECOVERY, &qedi->flags)) { + if (do_not_recover) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Do not recover cid=0x%x\n", + qedi_ep->iscsi_cid); + goto ep_exit_recover; + } + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Reset recovery cid=0x%x, qedi_ep=%p, state=0x%x\n", + qedi_ep->iscsi_cid, qedi_ep, qedi_ep->state); + qedi_cleanup_active_cmd_list(qedi_conn); + goto ep_release_conn; + } + } + + if (do_not_recover) + goto ep_exit_recover; + + switch (qedi_ep->state) { + case EP_STATE_OFLDCONN_START: + goto ep_release_conn; + case EP_STATE_OFLDCONN_FAILED: + break; + case EP_STATE_OFLDCONN_COMPL: + if (unlikely(!qedi_conn)) + break; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Active cmd count=%d, abrt_conn=%d, ep state=0x%x, cid=0x%x, qedi_conn=%p\n", + qedi_conn->active_cmd_count, abrt_conn, + qedi_ep->state, + qedi_ep->iscsi_cid, + qedi_ep->conn + ); + + if (!qedi_conn->active_cmd_count) + abrt_conn = 0; + else + abrt_conn = 1; + + if (abrt_conn) + qedi_clearsq(qedi, qedi_conn, NULL); + break; + default: + break; + } + + qedi_ep->state = EP_STATE_DISCONN_START; + ret = qedi_ops->destroy_conn(qedi->cdev, qedi_ep->handle, abrt_conn); + if (ret) { + QEDI_WARN(&qedi->dbg_ctx, + "destroy_conn failed returned %d\n", ret); + } else { + ret = wait_event_interruptible_timeout( + qedi_ep->tcp_ofld_wait, + (qedi_ep->state != + EP_STATE_DISCONN_START), + wait_delay); + if ((ret <= 0) || (qedi_ep->state == EP_STATE_DISCONN_START)) { + QEDI_WARN(&qedi->dbg_ctx, + "Destroy conn timedout or interrupted, ret=%d, delay=%d, cid=0x%x\n", + ret, wait_delay, qedi_ep->iscsi_cid); + } + } + +ep_release_conn: + ret = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle); + if (ret) + QEDI_WARN(&qedi->dbg_ctx, + "release_conn returned %d, cid=0x%x\n", + ret, qedi_ep->iscsi_cid); +ep_exit_recover: + qedi_ep->state = EP_STATE_IDLE; + qedi->ep_tbl[qedi_ep->iscsi_cid] = NULL; + qedi->cid_que.conn_cid_tbl[qedi_ep->iscsi_cid] = NULL; + qedi_free_id(&qedi->lcl_port_tbl, qedi_ep->src_port); + qedi_free_sq(qedi, qedi_ep); + + if (qedi_conn) + qedi_conn->ep = NULL; + + qedi_ep->conn = NULL; + qedi_ep->qedi = NULL; + atomic_dec(&qedi->num_offloads); + + iscsi_destroy_endpoint(ep); +} + +static int qedi_data_avail(struct qedi_ctx *qedi, u16 vlanid) +{ + struct qed_dev *cdev = qedi->cdev; + struct qedi_uio_dev *udev; + struct qedi_uio_ctrl *uctrl; + struct sk_buff *skb; + u32 len; + int rc = 0; + + udev = qedi->udev; + if (!udev) { + QEDI_ERR(&qedi->dbg_ctx, "udev is NULL.\n"); + return -EINVAL; + } + + uctrl = (struct qedi_uio_ctrl *)udev->uctrl; + if (!uctrl) { + QEDI_ERR(&qedi->dbg_ctx, "uctlr is NULL.\n"); + return -EINVAL; + } + + len = uctrl->host_tx_pkt_len; + if (!len) { + QEDI_ERR(&qedi->dbg_ctx, "Invalid len %u\n", len); + return -EINVAL; + } + + skb = alloc_skb(len, GFP_ATOMIC); + if (!skb) { + QEDI_ERR(&qedi->dbg_ctx, "alloc_skb failed\n"); + return -EINVAL; + } + + skb_put(skb, len); + memcpy(skb->data, udev->tx_pkt, len); + skb->ip_summed = CHECKSUM_NONE; + + if (vlanid) + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid); + + rc = qedi_ops->ll2->start_xmit(cdev, skb); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, "ll2 start_xmit returned %d\n", + rc); + kfree_skb(skb); + } + + uctrl->host_tx_pkt_len = 0; + uctrl->hw_tx_cons++; + + return rc; +} + +static void qedi_offload_work(struct work_struct *work) +{ + struct qedi_endpoint *qedi_ep = + container_of(work, struct qedi_endpoint, offload_work); + struct qedi_ctx *qedi; + int wait_delay = 20 * HZ; + int ret; + + qedi = qedi_ep->qedi; + + ret = qedi_iscsi_offload_conn(qedi_ep); + if (ret) { + QEDI_ERR(&qedi->dbg_ctx, + "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n", + qedi_ep->iscsi_cid, qedi_ep, ret); + qedi_ep->state = EP_STATE_OFLDCONN_FAILED; + return; + } + + ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait, + (qedi_ep->state == + EP_STATE_OFLDCONN_COMPL), + wait_delay); + if ((ret <= 0) || (qedi_ep->state != EP_STATE_OFLDCONN_COMPL)) { + qedi_ep->state = EP_STATE_OFLDCONN_FAILED; + QEDI_ERR(&qedi->dbg_ctx, + "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n", + qedi_ep->iscsi_cid, qedi_ep); + } +} + +static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data) +{ + struct qedi_ctx *qedi; + struct qedi_endpoint *qedi_ep; + int ret = 0; + u32 iscsi_cid; + u16 port_id = 0; + + if (!shost) { + ret = -ENXIO; + QEDI_ERR(NULL, "shost is NULL\n"); + return ret; + } + + if (strcmp(shost->hostt->proc_name, "qedi")) { + ret = -ENXIO; + QEDI_ERR(NULL, "shost %s is invalid\n", + shost->hostt->proc_name); + return ret; + } + + qedi = iscsi_host_priv(shost); + if (path_data->handle == QEDI_PATH_HANDLE) { + ret = qedi_data_avail(qedi, path_data->vlan_id); + goto set_path_exit; + } + + iscsi_cid = (u32)path_data->handle; + qedi_ep = qedi->ep_tbl[iscsi_cid]; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "iscsi_cid=0x%x, qedi_ep=%p\n", iscsi_cid, qedi_ep); + + if (!is_valid_ether_addr(&path_data->mac_addr[0])) { + QEDI_NOTICE(&qedi->dbg_ctx, "dst mac NOT VALID\n"); + ret = -EIO; + goto set_path_exit; + } + + ether_addr_copy(&qedi_ep->src_mac[0], &qedi->mac[0]); + ether_addr_copy(&qedi_ep->dst_mac[0], &path_data->mac_addr[0]); + + qedi_ep->vlan_id = path_data->vlan_id; + if (path_data->pmtu < DEF_PATH_MTU) { + qedi_ep->pmtu = qedi->ll2_mtu; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "MTU cannot be %u, using default MTU %u\n", + path_data->pmtu, qedi_ep->pmtu); + } + + if (path_data->pmtu != qedi->ll2_mtu) { + if (path_data->pmtu > JUMBO_MTU) { + ret = -EINVAL; + QEDI_ERR(NULL, "Invalid MTU %u\n", path_data->pmtu); + goto set_path_exit; + } + + qedi_reset_host_mtu(qedi, path_data->pmtu); + qedi_ep->pmtu = qedi->ll2_mtu; + } + + port_id = qedi_ep->src_port; + if (port_id >= QEDI_LOCAL_PORT_MIN && + port_id < QEDI_LOCAL_PORT_MAX) { + if (qedi_alloc_id(&qedi->lcl_port_tbl, port_id)) + port_id = 0; + } else { + port_id = 0; + } + + if (!port_id) { + port_id = qedi_alloc_new_id(&qedi->lcl_port_tbl); + if (port_id == QEDI_LOCAL_PORT_INVALID) { + QEDI_ERR(&qedi->dbg_ctx, + "Failed to allocate port id for iscsi_cid=0x%x\n", + iscsi_cid); + ret = -ENOMEM; + goto set_path_exit; + } + } + + qedi_ep->src_port = port_id; + + if (qedi_ep->ip_type == TCP_IPV4) { + memcpy(&qedi_ep->src_addr[0], &path_data->src.v4_addr, + sizeof(struct in_addr)); + memcpy(&qedi->src_ip[0], &path_data->src.v4_addr, + sizeof(struct in_addr)); + qedi->ip_type = TCP_IPV4; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "src addr:port=%pI4:%u, dst addr:port=%pI4:%u\n", + qedi_ep->src_addr, qedi_ep->src_port, + qedi_ep->dst_addr, qedi_ep->dst_port); + } else { + memcpy(&qedi_ep->src_addr[0], &path_data->src.v6_addr, + sizeof(struct in6_addr)); + memcpy(&qedi->src_ip[0], &path_data->src.v6_addr, + sizeof(struct in6_addr)); + qedi->ip_type = TCP_IPV6; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "src addr:port=%pI6:%u, dst addr:port=%pI6:%u\n", + qedi_ep->src_addr, qedi_ep->src_port, + qedi_ep->dst_addr, qedi_ep->dst_port); + } + + INIT_WORK(&qedi_ep->offload_work, qedi_offload_work); + queue_work(qedi->offload_thread, &qedi_ep->offload_work); + + ret = 0; + +set_path_exit: + return ret; +} + +static umode_t qedi_attr_is_visible(int param_type, int param) +{ + switch (param_type) { + case ISCSI_HOST_PARAM: + switch (param) { + case ISCSI_HOST_PARAM_NETDEV_NAME: + case ISCSI_HOST_PARAM_HWADDRESS: + case ISCSI_HOST_PARAM_IPADDRESS: + return 0444; + default: + return 0; + } + case ISCSI_PARAM: + switch (param) { + case ISCSI_PARAM_MAX_RECV_DLENGTH: + case ISCSI_PARAM_MAX_XMIT_DLENGTH: + case ISCSI_PARAM_HDRDGST_EN: + case ISCSI_PARAM_DATADGST_EN: + case ISCSI_PARAM_CONN_ADDRESS: + case ISCSI_PARAM_CONN_PORT: + case ISCSI_PARAM_EXP_STATSN: + case ISCSI_PARAM_PERSISTENT_ADDRESS: + case ISCSI_PARAM_PERSISTENT_PORT: + case ISCSI_PARAM_PING_TMO: + case ISCSI_PARAM_RECV_TMO: + case ISCSI_PARAM_INITIAL_R2T_EN: + case ISCSI_PARAM_MAX_R2T: + case ISCSI_PARAM_IMM_DATA_EN: + case ISCSI_PARAM_FIRST_BURST: + case ISCSI_PARAM_MAX_BURST: + case ISCSI_PARAM_PDU_INORDER_EN: + case ISCSI_PARAM_DATASEQ_INORDER_EN: + case ISCSI_PARAM_ERL: + case ISCSI_PARAM_TARGET_NAME: + case ISCSI_PARAM_TPGT: + case ISCSI_PARAM_USERNAME: + case ISCSI_PARAM_PASSWORD: + case ISCSI_PARAM_USERNAME_IN: + case ISCSI_PARAM_PASSWORD_IN: + case ISCSI_PARAM_FAST_ABORT: + case ISCSI_PARAM_ABORT_TMO: + case ISCSI_PARAM_LU_RESET_TMO: + case ISCSI_PARAM_TGT_RESET_TMO: + case ISCSI_PARAM_IFACE_NAME: + case ISCSI_PARAM_INITIATOR_NAME: + case ISCSI_PARAM_BOOT_ROOT: + case ISCSI_PARAM_BOOT_NIC: + case ISCSI_PARAM_BOOT_TARGET: + return 0444; + default: + return 0; + } + } + + return 0; +} + +static void qedi_cleanup_task(struct iscsi_task *task) +{ + if (!task->sc || task->state == ISCSI_TASK_PENDING) { + QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n", + atomic_read(&task->refcount)); + return; + } + + qedi_iscsi_unmap_sg_list(task->dd_data); +} + +struct iscsi_transport qedi_iscsi_transport = { + .owner = THIS_MODULE, + .name = QEDI_MODULE_NAME, + .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_MULTI_R2T | CAP_DATADGST | + CAP_DATA_PATH_OFFLOAD | CAP_TEXT_NEGO, + .create_session = qedi_session_create, + .destroy_session = qedi_session_destroy, + .create_conn = qedi_conn_create, + .bind_conn = qedi_conn_bind, + .start_conn = qedi_conn_start, + .stop_conn = iscsi_conn_stop, + .destroy_conn = qedi_conn_destroy, + .set_param = iscsi_set_param, + .get_ep_param = qedi_ep_get_param, + .get_conn_param = iscsi_conn_get_param, + .get_session_param = iscsi_session_get_param, + .get_host_param = qedi_host_get_param, + .send_pdu = iscsi_conn_send_pdu, + .get_stats = qedi_conn_get_stats, + .xmit_task = qedi_task_xmit, + .cleanup_task = qedi_cleanup_task, + .session_recovery_timedout = iscsi_session_recovery_timedout, + .ep_connect = qedi_ep_connect, + .ep_poll = qedi_ep_poll, + .ep_disconnect = qedi_ep_disconnect, + .set_path = qedi_set_path, + .attr_is_visible = qedi_attr_is_visible, +}; + +void qedi_start_conn_recovery(struct qedi_ctx *qedi, + struct qedi_conn *qedi_conn) +{ + struct iscsi_cls_session *cls_sess; + struct iscsi_cls_conn *cls_conn; + struct iscsi_conn *conn; + + cls_conn = qedi_conn->cls_conn; + conn = cls_conn->dd_data; + cls_sess = iscsi_conn_to_session(cls_conn); + + if (iscsi_is_session_online(cls_sess)) { + qedi_conn->abrt_conn = 1; + QEDI_ERR(&qedi->dbg_ctx, + "Failing connection, state=0x%x, cid=0x%x\n", + conn->session->state, qedi_conn->iscsi_conn_id); + iscsi_conn_failure(qedi_conn->cls_conn->dd_data, + ISCSI_ERR_CONN_FAILED); + } +} + +static const struct { + enum iscsi_error_types error_code; + char *err_string; +} qedi_iscsi_error[] = { + { ISCSI_STATUS_NONE, + "tcp_error none" + }, + { ISCSI_CONN_ERROR_TASK_CID_MISMATCH, + "task cid mismatch" + }, + { ISCSI_CONN_ERROR_TASK_NOT_VALID, + "invalid task" + }, + { ISCSI_CONN_ERROR_RQ_RING_IS_FULL, + "rq ring full" + }, + { ISCSI_CONN_ERROR_CMDQ_RING_IS_FULL, + "cmdq ring full" + }, + { ISCSI_CONN_ERROR_HQE_CACHING_FAILED, + "sge caching failed" + }, + { ISCSI_CONN_ERROR_HEADER_DIGEST_ERROR, + "hdr digest error" + }, + { ISCSI_CONN_ERROR_LOCAL_COMPLETION_ERROR, + "local cmpl error" + }, + { ISCSI_CONN_ERROR_DATA_OVERRUN, + "invalid task" + }, + { ISCSI_CONN_ERROR_OUT_OF_SGES_ERROR, + "out of sge error" + }, + { ISCSI_CONN_ERROR_TCP_SEG_PROC_IP_OPTIONS_ERROR, + "tcp seg ip options error" + }, + { ISCSI_CONN_ERROR_TCP_IP_FRAGMENT_ERROR, + "tcp ip fragment error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_AHS_LEN, + "AHS len protocol error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_ITT_OUT_OF_RANGE, + "itt out of range error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_EXCEEDS_PDU_SIZE, + "data seg more than pdu size" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE, + "invalid opcode" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE_BEFORE_UPDATE, + "invalid opcode before update" + }, + { ISCSI_CONN_ERROR_UNVALID_NOPIN_DSL, + "unexpected opcode" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_CARRIES_NO_DATA, + "r2t carries no data" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SN, + "data sn error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_IN_TTT, + "data TTT error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_TTT, + "r2t TTT error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_BUFFER_OFFSET, + "buffer offset error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_BUFFER_OFFSET_OOO, + "buffer offset ooo" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_SN, + "data seg len 0" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0, + "data xer len error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1, + "data xer len1 error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_2, + "data xer len2 error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_LUN, + "protocol lun error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_F_BIT_ZERO, + "f bit zero error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_EXP_STAT_SN, + "exp stat sn error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DSL_NOT_ZERO, + "dsl not zero error" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_DSL, + "invalid dsl" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG, + "data seg len too big" + }, + { ISCSI_CONN_ERROR_PROTOCOL_ERR_OUTSTANDING_R2T_COUNT, + "outstanding r2t count error" + }, + { ISCSI_CONN_ERROR_SENSE_DATA_LENGTH, + "sense datalen error" + }, +}; + +char *qedi_get_iscsi_error(enum iscsi_error_types err_code) +{ + int i; + char *msg = NULL; + + for (i = 0; i < ARRAY_SIZE(qedi_iscsi_error); i++) { + if (qedi_iscsi_error[i].error_code == err_code) { + msg = qedi_iscsi_error[i].err_string; + break; + } + } + return msg; +} + +void qedi_process_iscsi_error(struct qedi_endpoint *ep, struct async_data *data) +{ + struct qedi_conn *qedi_conn; + struct qedi_ctx *qedi; + char warn_notice[] = "iscsi_warning"; + char error_notice[] = "iscsi_error"; + char unknown_msg[] = "Unknown error"; + char *message; + int need_recovery = 0; + u32 err_mask = 0; + char *msg; + + if (!ep) + return; + + qedi_conn = ep->conn; + if (!qedi_conn) + return; + + qedi = ep->qedi; + + QEDI_ERR(&qedi->dbg_ctx, "async event iscsi error:0x%x\n", + data->error_code); + + if (err_mask) { + need_recovery = 0; + message = warn_notice; + } else { + need_recovery = 1; + message = error_notice; + } + + msg = qedi_get_iscsi_error(data->error_code); + if (!msg) { + need_recovery = 0; + msg = unknown_msg; + } + + iscsi_conn_printk(KERN_ALERT, + qedi_conn->cls_conn->dd_data, + "qedi: %s - %s\n", message, msg); + + if (need_recovery) + qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); +} + +void qedi_process_tcp_error(struct qedi_endpoint *ep, struct async_data *data) +{ + struct qedi_conn *qedi_conn; + + if (!ep) + return; + + qedi_conn = ep->conn; + if (!qedi_conn) + return; + + QEDI_ERR(&ep->qedi->dbg_ctx, "async event TCP error:0x%x\n", + data->error_code); + + qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn); +} diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h new file mode 100644 index 000000000000..d3c06bbddb4e --- /dev/null +++ b/drivers/scsi/qedi/qedi_iscsi.h @@ -0,0 +1,232 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#ifndef _QEDI_ISCSI_H_ +#define _QEDI_ISCSI_H_ + +#include +#include +#include "qedi.h" + +#define ISCSI_MAX_SESS_PER_HBA 4096 + +#define DEF_KA_TIMEOUT 7200000 +#define DEF_KA_INTERVAL 10000 +#define DEF_KA_MAX_PROBE_COUNT 10 +#define DEF_TOS 0 +#define DEF_TTL 0xfe +#define DEF_SND_SEQ_SCALE 0 +#define DEF_RCV_BUF 0xffff +#define DEF_SND_BUF 0xffff +#define DEF_SEED 0 +#define DEF_MAX_RT_TIME 8000 +#define DEF_MAX_DA_COUNT 2 +#define DEF_SWS_TIMER 1000 +#define DEF_MAX_CWND 2 +#define DEF_PATH_MTU 1500 +#define DEF_MSS 1460 +#define DEF_LL2_MTU 1560 +#define JUMBO_MTU 9000 + +#define MIN_MTU 576 /* rfc 793 */ +#define IPV4_HDR_LEN 20 +#define IPV6_HDR_LEN 40 +#define TCP_HDR_LEN 20 +#define TCP_OPTION_LEN 12 +#define VLAN_LEN 4 + +enum { + EP_STATE_IDLE = 0x0, + EP_STATE_ACQRCONN_START = 0x1, + EP_STATE_ACQRCONN_COMPL = 0x2, + EP_STATE_OFLDCONN_START = 0x4, + EP_STATE_OFLDCONN_COMPL = 0x8, + EP_STATE_DISCONN_START = 0x10, + EP_STATE_DISCONN_COMPL = 0x20, + EP_STATE_CLEANUP_START = 0x40, + EP_STATE_CLEANUP_CMPL = 0x80, + EP_STATE_TCP_FIN_RCVD = 0x100, + EP_STATE_TCP_RST_RCVD = 0x200, + EP_STATE_LOGOUT_SENT = 0x400, + EP_STATE_LOGOUT_RESP_RCVD = 0x800, + EP_STATE_CLEANUP_FAILED = 0x1000, + EP_STATE_OFLDCONN_FAILED = 0x2000, + EP_STATE_CONNECT_FAILED = 0x4000, + EP_STATE_DISCONN_TIMEDOUT = 0x8000, +}; + +struct qedi_conn; + +struct qedi_endpoint { + struct qedi_ctx *qedi; + u32 dst_addr[4]; + u32 src_addr[4]; + u16 src_port; + u16 dst_port; + u16 vlan_id; + u16 pmtu; + u8 src_mac[ETH_ALEN]; + u8 dst_mac[ETH_ALEN]; + u8 ip_type; + int state; + wait_queue_head_t ofld_wait; + wait_queue_head_t tcp_ofld_wait; + u32 iscsi_cid; + /* identifier of the connection from qed */ + u32 handle; + u32 fw_cid; + void __iomem *p_doorbell; + + /* Send queue management */ + struct iscsi_wqe *sq; + dma_addr_t sq_dma; + + u16 sq_prod_idx; + u16 fw_sq_prod_idx; + u16 sq_con_idx; + u32 sq_mem_size; + + void *sq_pbl; + dma_addr_t sq_pbl_dma; + u32 sq_pbl_size; + struct qedi_conn *conn; + struct work_struct offload_work; +}; + +#define QEDI_SQ_WQES_MIN 16 + +struct qedi_io_bdt { + struct iscsi_sge *sge_tbl; + dma_addr_t sge_tbl_dma; + u16 sge_valid; +}; + +/** + * struct generic_pdu_resc - login pdu resource structure + * + * @req_buf: driver buffer used to stage payload associated with + * the login request + * @req_dma_addr: dma address for iscsi login request payload buffer + * @req_buf_size: actual login request payload length + * @req_wr_ptr: pointer into login request buffer when next data is + * to be written + * @resp_hdr: iscsi header where iscsi login response header is to + * be recreated + * @resp_buf: buffer to stage login response payload + * @resp_dma_addr: login response payload buffer dma address + * @resp_buf_size: login response paylod length + * @resp_wr_ptr: pointer into login response buffer when next data is + * to be written + * @req_bd_tbl: iscsi login request payload BD table + * @req_bd_dma: login request BD table dma address + * @resp_bd_tbl: iscsi login response payload BD table + * @resp_bd_dma: login request BD table dma address + * + * following structure defines buffer info for generic pdus such as iSCSI Login, + * Logout and NOP + */ +struct generic_pdu_resc { + char *req_buf; + dma_addr_t req_dma_addr; + u32 req_buf_size; + char *req_wr_ptr; + struct iscsi_hdr resp_hdr; + char *resp_buf; + dma_addr_t resp_dma_addr; + u32 resp_buf_size; + char *resp_wr_ptr; + char *req_bd_tbl; + dma_addr_t req_bd_dma; + char *resp_bd_tbl; + dma_addr_t resp_bd_dma; +}; + +struct qedi_conn { + struct iscsi_cls_conn *cls_conn; + struct qedi_ctx *qedi; + struct qedi_endpoint *ep; + struct list_head active_cmd_list; + spinlock_t list_lock; /* internal conn lock */ + u32 active_cmd_count; + u32 cmd_cleanup_req; + u32 cmd_cleanup_cmpl; + + u32 iscsi_conn_id; + int itt; + int abrt_conn; +#define QEDI_CID_RESERVED 0x5AFF + u32 fw_cid; + /* + * Buffer for login negotiation process + */ + struct generic_pdu_resc gen_pdu; + + struct list_head tmf_work_list; + wait_queue_head_t wait_queue; + spinlock_t tmf_work_lock; /* tmf work lock */ + unsigned long flags; +#define QEDI_CONN_FW_CLEANUP 1 +}; + +struct qedi_cmd { + struct list_head io_cmd; + bool io_cmd_in_list; + struct iscsi_hdr hdr; + struct qedi_conn *conn; + struct scsi_cmnd *scsi_cmd; + struct scatterlist *sg; + struct qedi_io_bdt io_tbl; + struct iscsi_task_context request; + unsigned char *sense_buffer; + dma_addr_t sense_buffer_dma; + u16 task_id; + + /* field populated for tmf work queue */ + struct iscsi_task *task; + struct work_struct tmf_work; + int state; +#define CLEANUP_WAIT 1 +#define CLEANUP_RECV 2 +#define CLEANUP_WAIT_FAILED 3 +#define CLEANUP_NOT_REQUIRED 4 +#define LUN_RESET_RESPONSE_RECEIVED 5 +#define RESPONSE_RECEIVED 6 + + int type; +#define TYPEIO 1 +#define TYPERESET 2 + + struct qedi_work_map *list_tmf_work; + /* slowpath management */ + bool use_slowpath; + + struct iscsi_tm_rsp *tmf_resp_buf; + struct qedi_work cqe_work; +}; + +struct qedi_work_map { + struct list_head list; + struct qedi_cmd *qedi_cmd; + int rtid; + + int state; +#define QEDI_WORK_QUEUED 1 +#define QEDI_WORK_SCHEDULED 2 +#define QEDI_WORK_EXIT 3 + + struct work_struct *ptr_tmf_work; +}; + +#define qedi_set_itt(task_id, itt) ((u32)(((task_id) & 0xffff) | ((itt) << 16))) +#define qedi_get_itt(cqe) (cqe.iscsi_hdr.cmd.itt >> 16) + +#define QEDI_OFLD_WAIT_STATE(q) ((q)->state == EP_STATE_OFLDCONN_FAILED || \ + (q)->state == EP_STATE_OFLDCONN_COMPL) + +#endif /* _QEDI_ISCSI_H_ */ diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c new file mode 100644 index 000000000000..19ead8d17e55 --- /dev/null +++ b/drivers/scsi/qedi/qedi_main.c @@ -0,0 +1,2127 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "qedi.h" +#include "qedi_gbl.h" +#include "qedi_iscsi.h" + +static uint qedi_fw_debug; +module_param(qedi_fw_debug, uint, 0644); +MODULE_PARM_DESC(qedi_fw_debug, " Firmware debug level 0(default) to 3"); + +uint qedi_dbg_log = QEDI_LOG_WARN | QEDI_LOG_SCSI_TM; +module_param(qedi_dbg_log, uint, 0644); +MODULE_PARM_DESC(qedi_dbg_log, " Default debug level"); + +uint qedi_io_tracing; +module_param(qedi_io_tracing, uint, 0644); +MODULE_PARM_DESC(qedi_io_tracing, + " Enable logging of SCSI requests/completions into trace buffer. (default off)."); + +const struct qed_iscsi_ops *qedi_ops; +static struct scsi_transport_template *qedi_scsi_transport; +static struct pci_driver qedi_pci_driver; +static DEFINE_PER_CPU(struct qedi_percpu_s, qedi_percpu); +static LIST_HEAD(qedi_udev_list); +/* Static function declaration */ +static int qedi_alloc_global_queues(struct qedi_ctx *qedi); +static void qedi_free_global_queues(struct qedi_ctx *qedi); +static struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid); +static void qedi_reset_uio_rings(struct qedi_uio_dev *udev); +static void qedi_ll2_free_skbs(struct qedi_ctx *qedi); + +static int qedi_iscsi_event_cb(void *context, u8 fw_event_code, void *fw_handle) +{ + struct qedi_ctx *qedi; + struct qedi_endpoint *qedi_ep; + struct async_data *data; + int rval = 0; + + if (!context || !fw_handle) { + QEDI_ERR(NULL, "Recv event with ctx NULL\n"); + return -EINVAL; + } + + qedi = (struct qedi_ctx *)context; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Recv Event %d fw_handle %p\n", fw_event_code, fw_handle); + + data = (struct async_data *)fw_handle; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "cid=0x%x tid=0x%x err-code=0x%x fw-dbg-param=0x%x\n", + data->cid, data->itid, data->error_code, + data->fw_debug_param); + + qedi_ep = qedi->ep_tbl[data->cid]; + + if (!qedi_ep) { + QEDI_WARN(&qedi->dbg_ctx, + "Cannot process event, ep already disconnected, cid=0x%x\n", + data->cid); + WARN_ON(1); + return -ENODEV; + } + + switch (fw_event_code) { + case ISCSI_EVENT_TYPE_ASYN_CONNECT_COMPLETE: + if (qedi_ep->state == EP_STATE_OFLDCONN_START) + qedi_ep->state = EP_STATE_OFLDCONN_COMPL; + + wake_up_interruptible(&qedi_ep->tcp_ofld_wait); + break; + case ISCSI_EVENT_TYPE_ASYN_TERMINATE_DONE: + qedi_ep->state = EP_STATE_DISCONN_COMPL; + wake_up_interruptible(&qedi_ep->tcp_ofld_wait); + break; + case ISCSI_EVENT_TYPE_ISCSI_CONN_ERROR: + qedi_process_iscsi_error(qedi_ep, data); + break; + case ISCSI_EVENT_TYPE_ASYN_ABORT_RCVD: + case ISCSI_EVENT_TYPE_ASYN_SYN_RCVD: + case ISCSI_EVENT_TYPE_ASYN_MAX_RT_TIME: + case ISCSI_EVENT_TYPE_ASYN_MAX_RT_CNT: + case ISCSI_EVENT_TYPE_ASYN_MAX_KA_PROBES_CNT: + case ISCSI_EVENT_TYPE_ASYN_FIN_WAIT2: + case ISCSI_EVENT_TYPE_TCP_CONN_ERROR: + qedi_process_tcp_error(qedi_ep, data); + break; + default: + QEDI_ERR(&qedi->dbg_ctx, "Recv Unknown Event %u\n", + fw_event_code); + } + + return rval; +} + +static int qedi_uio_open(struct uio_info *uinfo, struct inode *inode) +{ + struct qedi_uio_dev *udev = uinfo->priv; + struct qedi_ctx *qedi = udev->qedi; + + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + + if (udev->uio_dev != -1) + return -EBUSY; + + rtnl_lock(); + udev->uio_dev = iminor(inode); + qedi_reset_uio_rings(udev); + set_bit(UIO_DEV_OPENED, &qedi->flags); + rtnl_unlock(); + + return 0; +} + +static int qedi_uio_close(struct uio_info *uinfo, struct inode *inode) +{ + struct qedi_uio_dev *udev = uinfo->priv; + struct qedi_ctx *qedi = udev->qedi; + + udev->uio_dev = -1; + clear_bit(UIO_DEV_OPENED, &qedi->flags); + qedi_ll2_free_skbs(qedi); + return 0; +} + +static void __qedi_free_uio_rings(struct qedi_uio_dev *udev) +{ + if (udev->ll2_ring) { + free_page((unsigned long)udev->ll2_ring); + udev->ll2_ring = NULL; + } + + if (udev->ll2_buf) { + free_pages((unsigned long)udev->ll2_buf, 2); + udev->ll2_buf = NULL; + } +} + +static void __qedi_free_uio(struct qedi_uio_dev *udev) +{ + uio_unregister_device(&udev->qedi_uinfo); + + __qedi_free_uio_rings(udev); + + pci_dev_put(udev->pdev); + kfree(udev->uctrl); + kfree(udev); +} + +static void qedi_free_uio(struct qedi_uio_dev *udev) +{ + if (!udev) + return; + + list_del_init(&udev->list); + __qedi_free_uio(udev); +} + +static void qedi_reset_uio_rings(struct qedi_uio_dev *udev) +{ + struct qedi_ctx *qedi = NULL; + struct qedi_uio_ctrl *uctrl = NULL; + + qedi = udev->qedi; + uctrl = udev->uctrl; + + spin_lock_bh(&qedi->ll2_lock); + uctrl->host_rx_cons = 0; + uctrl->hw_rx_prod = 0; + uctrl->hw_rx_bd_prod = 0; + uctrl->host_rx_bd_cons = 0; + + memset(udev->ll2_ring, 0, udev->ll2_ring_size); + memset(udev->ll2_buf, 0, udev->ll2_buf_size); + spin_unlock_bh(&qedi->ll2_lock); +} + +static int __qedi_alloc_uio_rings(struct qedi_uio_dev *udev) +{ + int rc = 0; + + if (udev->ll2_ring || udev->ll2_buf) + return rc; + + /* Allocating memory for LL2 ring */ + udev->ll2_ring_size = QEDI_PAGE_SIZE; + udev->ll2_ring = (void *)get_zeroed_page(GFP_KERNEL | __GFP_COMP); + if (!udev->ll2_ring) { + rc = -ENOMEM; + goto exit_alloc_ring; + } + + /* Allocating memory for Tx/Rx pkt buffer */ + udev->ll2_buf_size = TX_RX_RING * LL2_SINGLE_BUF_SIZE; + udev->ll2_buf_size = QEDI_PAGE_ALIGN(udev->ll2_buf_size); + udev->ll2_buf = (void *)__get_free_pages(GFP_KERNEL | __GFP_COMP | + __GFP_ZERO, 2); + if (!udev->ll2_buf) { + rc = -ENOMEM; + goto exit_alloc_buf; + } + return rc; + +exit_alloc_buf: + free_page((unsigned long)udev->ll2_ring); + udev->ll2_ring = NULL; +exit_alloc_ring: + return rc; +} + +static int qedi_alloc_uio_rings(struct qedi_ctx *qedi) +{ + struct qedi_uio_dev *udev = NULL; + struct qedi_uio_ctrl *uctrl = NULL; + int rc = 0; + + list_for_each_entry(udev, &qedi_udev_list, list) { + if (udev->pdev == qedi->pdev) { + udev->qedi = qedi; + if (__qedi_alloc_uio_rings(udev)) { + udev->qedi = NULL; + return -ENOMEM; + } + qedi->udev = udev; + return 0; + } + } + + udev = kzalloc(sizeof(*udev), GFP_KERNEL); + if (!udev) { + rc = -ENOMEM; + goto err_udev; + } + + uctrl = kzalloc(sizeof(*uctrl), GFP_KERNEL); + if (!uctrl) { + rc = -ENOMEM; + goto err_uctrl; + } + + udev->uio_dev = -1; + + udev->qedi = qedi; + udev->pdev = qedi->pdev; + udev->uctrl = uctrl; + + rc = __qedi_alloc_uio_rings(udev); + if (rc) + goto err_uio_rings; + + list_add(&udev->list, &qedi_udev_list); + + pci_dev_get(udev->pdev); + qedi->udev = udev; + + udev->tx_pkt = udev->ll2_buf; + udev->rx_pkt = udev->ll2_buf + LL2_SINGLE_BUF_SIZE; + return 0; + + err_uio_rings: + kfree(uctrl); + err_uctrl: + kfree(udev); + err_udev: + return -ENOMEM; +} + +static int qedi_init_uio(struct qedi_ctx *qedi) +{ + struct qedi_uio_dev *udev = qedi->udev; + struct uio_info *uinfo; + int ret = 0; + + if (!udev) + return -ENOMEM; + + uinfo = &udev->qedi_uinfo; + + uinfo->mem[0].addr = (unsigned long)udev->uctrl; + uinfo->mem[0].size = sizeof(struct qedi_uio_ctrl); + uinfo->mem[0].memtype = UIO_MEM_LOGICAL; + + uinfo->mem[1].addr = (unsigned long)udev->ll2_ring; + uinfo->mem[1].size = udev->ll2_ring_size; + uinfo->mem[1].memtype = UIO_MEM_LOGICAL; + + uinfo->mem[2].addr = (unsigned long)udev->ll2_buf; + uinfo->mem[2].size = udev->ll2_buf_size; + uinfo->mem[2].memtype = UIO_MEM_LOGICAL; + + uinfo->name = "qedi_uio"; + uinfo->version = QEDI_MODULE_VERSION; + uinfo->irq = UIO_IRQ_CUSTOM; + + uinfo->open = qedi_uio_open; + uinfo->release = qedi_uio_close; + + if (udev->uio_dev == -1) { + if (!uinfo->priv) { + uinfo->priv = udev; + + ret = uio_register_device(&udev->pdev->dev, uinfo); + if (ret) { + QEDI_ERR(&qedi->dbg_ctx, + "UIO registration failed\n"); + } + } + } + + return ret; +} + +static int qedi_alloc_and_init_sb(struct qedi_ctx *qedi, + struct qed_sb_info *sb_info, u16 sb_id) +{ + struct status_block *sb_virt; + dma_addr_t sb_phys; + int ret; + + sb_virt = dma_alloc_coherent(&qedi->pdev->dev, + sizeof(struct status_block), &sb_phys, + GFP_KERNEL); + if (!sb_virt) { + QEDI_ERR(&qedi->dbg_ctx, + "Status block allocation failed for id = %d.\n", + sb_id); + return -ENOMEM; + } + + ret = qedi_ops->common->sb_init(qedi->cdev, sb_info, sb_virt, sb_phys, + sb_id, QED_SB_TYPE_STORAGE); + if (ret) { + QEDI_ERR(&qedi->dbg_ctx, + "Status block initialization failed for id = %d.\n", + sb_id); + return ret; + } + + return 0; +} + +static void qedi_free_sb(struct qedi_ctx *qedi) +{ + struct qed_sb_info *sb_info; + int id; + + for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { + sb_info = &qedi->sb_array[id]; + if (sb_info->sb_virt) + dma_free_coherent(&qedi->pdev->dev, + sizeof(*sb_info->sb_virt), + (void *)sb_info->sb_virt, + sb_info->sb_phys); + } +} + +static void qedi_free_fp(struct qedi_ctx *qedi) +{ + kfree(qedi->fp_array); + kfree(qedi->sb_array); +} + +static void qedi_destroy_fp(struct qedi_ctx *qedi) +{ + qedi_free_sb(qedi); + qedi_free_fp(qedi); +} + +static int qedi_alloc_fp(struct qedi_ctx *qedi) +{ + int ret = 0; + + qedi->fp_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), + sizeof(struct qedi_fastpath), GFP_KERNEL); + if (!qedi->fp_array) { + QEDI_ERR(&qedi->dbg_ctx, + "fastpath fp array allocation failed.\n"); + return -ENOMEM; + } + + qedi->sb_array = kcalloc(MIN_NUM_CPUS_MSIX(qedi), + sizeof(struct qed_sb_info), GFP_KERNEL); + if (!qedi->sb_array) { + QEDI_ERR(&qedi->dbg_ctx, + "fastpath sb array allocation failed.\n"); + ret = -ENOMEM; + goto free_fp; + } + + return ret; + +free_fp: + qedi_free_fp(qedi); + return ret; +} + +static void qedi_int_fp(struct qedi_ctx *qedi) +{ + struct qedi_fastpath *fp; + int id; + + memset(qedi->fp_array, 0, MIN_NUM_CPUS_MSIX(qedi) * + sizeof(*qedi->fp_array)); + memset(qedi->sb_array, 0, MIN_NUM_CPUS_MSIX(qedi) * + sizeof(*qedi->sb_array)); + + for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { + fp = &qedi->fp_array[id]; + fp->sb_info = &qedi->sb_array[id]; + fp->sb_id = id; + fp->qedi = qedi; + snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", + "qedi", id); + + /* fp_array[i] ---- irq cookie + * So init data which is needed in int ctx + */ + } +} + +static int qedi_prepare_fp(struct qedi_ctx *qedi) +{ + struct qedi_fastpath *fp; + int id, ret = 0; + + ret = qedi_alloc_fp(qedi); + if (ret) + goto err; + + qedi_int_fp(qedi); + + for (id = 0; id < MIN_NUM_CPUS_MSIX(qedi); id++) { + fp = &qedi->fp_array[id]; + ret = qedi_alloc_and_init_sb(qedi, fp->sb_info, fp->sb_id); + if (ret) { + QEDI_ERR(&qedi->dbg_ctx, + "SB allocation and initialization failed.\n"); + ret = -EIO; + goto err_init; + } + } + + return 0; + +err_init: + qedi_free_sb(qedi); + qedi_free_fp(qedi); +err: + return ret; +} + +static int qedi_setup_cid_que(struct qedi_ctx *qedi) +{ + int i; + + qedi->cid_que.cid_que_base = kmalloc_array(qedi->max_active_conns, + sizeof(u32), GFP_KERNEL); + if (!qedi->cid_que.cid_que_base) + return -ENOMEM; + + qedi->cid_que.conn_cid_tbl = kmalloc_array(qedi->max_active_conns, + sizeof(struct qedi_conn *), + GFP_KERNEL); + if (!qedi->cid_que.conn_cid_tbl) { + kfree(qedi->cid_que.cid_que_base); + qedi->cid_que.cid_que_base = NULL; + return -ENOMEM; + } + + qedi->cid_que.cid_que = (u32 *)qedi->cid_que.cid_que_base; + qedi->cid_que.cid_q_prod_idx = 0; + qedi->cid_que.cid_q_cons_idx = 0; + qedi->cid_que.cid_q_max_idx = qedi->max_active_conns; + qedi->cid_que.cid_free_cnt = qedi->max_active_conns; + + for (i = 0; i < qedi->max_active_conns; i++) { + qedi->cid_que.cid_que[i] = i; + qedi->cid_que.conn_cid_tbl[i] = NULL; + } + + return 0; +} + +static void qedi_release_cid_que(struct qedi_ctx *qedi) +{ + kfree(qedi->cid_que.cid_que_base); + qedi->cid_que.cid_que_base = NULL; + + kfree(qedi->cid_que.conn_cid_tbl); + qedi->cid_que.conn_cid_tbl = NULL; +} + +static int qedi_init_id_tbl(struct qedi_portid_tbl *id_tbl, u16 size, + u16 start_id, u16 next) +{ + id_tbl->start = start_id; + id_tbl->max = size; + id_tbl->next = next; + spin_lock_init(&id_tbl->lock); + id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL); + if (!id_tbl->table) + return -ENOMEM; + + return 0; +} + +static void qedi_free_id_tbl(struct qedi_portid_tbl *id_tbl) +{ + kfree(id_tbl->table); + id_tbl->table = NULL; +} + +int qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id) +{ + int ret = -1; + + id -= id_tbl->start; + if (id >= id_tbl->max) + return ret; + + spin_lock(&id_tbl->lock); + if (!test_bit(id, id_tbl->table)) { + set_bit(id, id_tbl->table); + ret = 0; + } + spin_unlock(&id_tbl->lock); + return ret; +} + +u16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl) +{ + u16 id; + + spin_lock(&id_tbl->lock); + id = find_next_zero_bit(id_tbl->table, id_tbl->max, id_tbl->next); + if (id >= id_tbl->max) { + id = QEDI_LOCAL_PORT_INVALID; + if (id_tbl->next != 0) { + id = find_first_zero_bit(id_tbl->table, id_tbl->next); + if (id >= id_tbl->next) + id = QEDI_LOCAL_PORT_INVALID; + } + } + + if (id < id_tbl->max) { + set_bit(id, id_tbl->table); + id_tbl->next = (id + 1) & (id_tbl->max - 1); + id += id_tbl->start; + } + + spin_unlock(&id_tbl->lock); + + return id; +} + +void qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id) +{ + if (id == QEDI_LOCAL_PORT_INVALID) + return; + + id -= id_tbl->start; + if (id >= id_tbl->max) + return; + + clear_bit(id, id_tbl->table); +} + +static void qedi_cm_free_mem(struct qedi_ctx *qedi) +{ + kfree(qedi->ep_tbl); + qedi->ep_tbl = NULL; + qedi_free_id_tbl(&qedi->lcl_port_tbl); +} + +static int qedi_cm_alloc_mem(struct qedi_ctx *qedi) +{ + u16 port_id; + + qedi->ep_tbl = kzalloc((qedi->max_active_conns * + sizeof(struct qedi_endpoint *)), GFP_KERNEL); + if (!qedi->ep_tbl) + return -ENOMEM; + port_id = prandom_u32() % QEDI_LOCAL_PORT_RANGE; + if (qedi_init_id_tbl(&qedi->lcl_port_tbl, QEDI_LOCAL_PORT_RANGE, + QEDI_LOCAL_PORT_MIN, port_id)) { + qedi_cm_free_mem(qedi); + return -ENOMEM; + } + + return 0; +} + +static struct qedi_ctx *qedi_host_alloc(struct pci_dev *pdev) +{ + struct Scsi_Host *shost; + struct qedi_ctx *qedi = NULL; + + shost = iscsi_host_alloc(&qedi_host_template, + sizeof(struct qedi_ctx), 0); + if (!shost) { + QEDI_ERR(NULL, "Could not allocate shost\n"); + goto exit_setup_shost; + } + + shost->max_id = QEDI_MAX_ISCSI_CONNS_PER_HBA; + shost->max_channel = 0; + shost->max_lun = ~0; + shost->max_cmd_len = 16; + shost->transportt = qedi_scsi_transport; + + qedi = iscsi_host_priv(shost); + memset(qedi, 0, sizeof(*qedi)); + qedi->shost = shost; + qedi->dbg_ctx.host_no = shost->host_no; + qedi->pdev = pdev; + qedi->dbg_ctx.pdev = pdev; + qedi->max_active_conns = ISCSI_MAX_SESS_PER_HBA; + qedi->max_sqes = QEDI_SQ_SIZE; + + if (shost_use_blk_mq(shost)) + shost->nr_hw_queues = MIN_NUM_CPUS_MSIX(qedi); + + pci_set_drvdata(pdev, qedi); + +exit_setup_shost: + return qedi; +} + +static int qedi_ll2_rx(void *cookie, struct sk_buff *skb, u32 arg1, u32 arg2) +{ + struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; + struct qedi_uio_dev *udev; + struct qedi_uio_ctrl *uctrl; + struct skb_work_list *work; + u32 prod; + + if (!qedi) { + QEDI_ERR(NULL, "qedi is NULL\n"); + return -1; + } + + if (!test_bit(UIO_DEV_OPENED, &qedi->flags)) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UIO, + "UIO DEV is not opened\n"); + kfree_skb(skb); + return 0; + } + + udev = qedi->udev; + uctrl = udev->uctrl; + + work = kzalloc(sizeof(*work), GFP_ATOMIC); + if (!work) { + QEDI_WARN(&qedi->dbg_ctx, + "Could not allocate work so dropping frame.\n"); + kfree_skb(skb); + return 0; + } + + INIT_LIST_HEAD(&work->list); + work->skb = skb; + + if (skb_vlan_tag_present(skb)) + work->vlan_id = skb_vlan_tag_get(skb); + + if (work->vlan_id) + __vlan_insert_tag(work->skb, htons(ETH_P_8021Q), work->vlan_id); + + spin_lock_bh(&qedi->ll2_lock); + list_add_tail(&work->list, &qedi->ll2_skb_list); + + ++uctrl->hw_rx_prod_cnt; + prod = (uctrl->hw_rx_prod + 1) % RX_RING; + if (prod != uctrl->host_rx_cons) { + uctrl->hw_rx_prod = prod; + spin_unlock_bh(&qedi->ll2_lock); + wake_up_process(qedi->ll2_recv_thread); + return 0; + } + + spin_unlock_bh(&qedi->ll2_lock); + return 0; +} + +/* map this skb to iscsiuio mmaped region */ +static int qedi_ll2_process_skb(struct qedi_ctx *qedi, struct sk_buff *skb, + u16 vlan_id) +{ + struct qedi_uio_dev *udev = NULL; + struct qedi_uio_ctrl *uctrl = NULL; + struct qedi_rx_bd rxbd; + struct qedi_rx_bd *p_rxbd; + u32 rx_bd_prod; + void *pkt; + int len = 0; + + if (!qedi) { + QEDI_ERR(NULL, "qedi is NULL\n"); + return -1; + } + + udev = qedi->udev; + uctrl = udev->uctrl; + pkt = udev->rx_pkt + (uctrl->hw_rx_prod * LL2_SINGLE_BUF_SIZE); + len = min_t(u32, skb->len, (u32)LL2_SINGLE_BUF_SIZE); + memcpy(pkt, skb->data, len); + + memset(&rxbd, 0, sizeof(rxbd)); + rxbd.rx_pkt_index = uctrl->hw_rx_prod; + rxbd.rx_pkt_len = len; + rxbd.vlan_id = vlan_id; + + uctrl->hw_rx_bd_prod = (uctrl->hw_rx_bd_prod + 1) % QEDI_NUM_RX_BD; + rx_bd_prod = uctrl->hw_rx_bd_prod; + p_rxbd = (struct qedi_rx_bd *)udev->ll2_ring; + p_rxbd += rx_bd_prod; + + memcpy(p_rxbd, &rxbd, sizeof(rxbd)); + + /* notify the iscsiuio about new packet */ + uio_event_notify(&udev->qedi_uinfo); + + return 0; +} + +static void qedi_ll2_free_skbs(struct qedi_ctx *qedi) +{ + struct skb_work_list *work, *work_tmp; + + spin_lock_bh(&qedi->ll2_lock); + list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, list) { + list_del(&work->list); + if (work->skb) + kfree_skb(work->skb); + kfree(work); + } + spin_unlock_bh(&qedi->ll2_lock); +} + +static int qedi_ll2_recv_thread(void *arg) +{ + struct qedi_ctx *qedi = (struct qedi_ctx *)arg; + struct skb_work_list *work, *work_tmp; + + set_user_nice(current, -20); + + while (!kthread_should_stop()) { + spin_lock_bh(&qedi->ll2_lock); + list_for_each_entry_safe(work, work_tmp, &qedi->ll2_skb_list, + list) { + list_del(&work->list); + qedi_ll2_process_skb(qedi, work->skb, work->vlan_id); + kfree_skb(work->skb); + kfree(work); + } + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_bh(&qedi->ll2_lock); + schedule(); + } + + __set_current_state(TASK_RUNNING); + return 0; +} + +static int qedi_set_iscsi_pf_param(struct qedi_ctx *qedi) +{ + u8 num_sq_pages; + u32 log_page_size; + int rval = 0; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "Min number of MSIX %d\n", + MIN_NUM_CPUS_MSIX(qedi)); + + num_sq_pages = (MAX_OUSTANDING_TASKS_PER_CON * 8) / PAGE_SIZE; + + qedi->num_queues = MIN_NUM_CPUS_MSIX(qedi); + + memset(&qedi->pf_params.iscsi_pf_params, 0, + sizeof(qedi->pf_params.iscsi_pf_params)); + + qedi->p_cpuq = pci_alloc_consistent(qedi->pdev, + qedi->num_queues * sizeof(struct qedi_glbl_q_params), + &qedi->hw_p_cpuq); + if (!qedi->p_cpuq) { + QEDI_ERR(&qedi->dbg_ctx, "pci_alloc_consistent fail\n"); + rval = -1; + goto err_alloc_mem; + } + + rval = qedi_alloc_global_queues(qedi); + if (rval) { + QEDI_ERR(&qedi->dbg_ctx, "Global queue allocation failed.\n"); + rval = -1; + goto err_alloc_mem; + } + + qedi->pf_params.iscsi_pf_params.num_cons = QEDI_MAX_ISCSI_CONNS_PER_HBA; + qedi->pf_params.iscsi_pf_params.num_tasks = QEDI_MAX_ISCSI_TASK; + qedi->pf_params.iscsi_pf_params.half_way_close_timeout = 10; + qedi->pf_params.iscsi_pf_params.num_sq_pages_in_ring = num_sq_pages; + qedi->pf_params.iscsi_pf_params.num_r2tq_pages_in_ring = num_sq_pages; + qedi->pf_params.iscsi_pf_params.num_uhq_pages_in_ring = num_sq_pages; + qedi->pf_params.iscsi_pf_params.num_queues = qedi->num_queues; + qedi->pf_params.iscsi_pf_params.debug_mode = qedi_fw_debug; + + for (log_page_size = 0 ; log_page_size < 32 ; log_page_size++) { + if ((1 << log_page_size) == PAGE_SIZE) + break; + } + qedi->pf_params.iscsi_pf_params.log_page_size = log_page_size; + + qedi->pf_params.iscsi_pf_params.glbl_q_params_addr = + (u64)qedi->hw_p_cpuq; + + /* RQ BDQ initializations. + * rq_num_entries: suggested value for Initiator is 16 (4KB RQ) + * rqe_log_size: 8 for 256B RQE + */ + qedi->pf_params.iscsi_pf_params.rqe_log_size = 8; + /* BDQ address and size */ + qedi->pf_params.iscsi_pf_params.bdq_pbl_base_addr[BDQ_ID_RQ] = + qedi->bdq_pbl_list_dma; + qedi->pf_params.iscsi_pf_params.bdq_pbl_num_entries[BDQ_ID_RQ] = + qedi->bdq_pbl_list_num_entries; + qedi->pf_params.iscsi_pf_params.rq_buffer_size = QEDI_BDQ_BUF_SIZE; + + /* cq_num_entries: num_tasks + rq_num_entries */ + qedi->pf_params.iscsi_pf_params.cq_num_entries = 2048; + + qedi->pf_params.iscsi_pf_params.gl_rq_pi = QEDI_PROTO_CQ_PROD_IDX; + qedi->pf_params.iscsi_pf_params.gl_cmd_pi = 1; + qedi->pf_params.iscsi_pf_params.ooo_enable = 1; + +err_alloc_mem: + return rval; +} + +/* Free DMA coherent memory for array of queue pointers we pass to qed */ +static void qedi_free_iscsi_pf_param(struct qedi_ctx *qedi) +{ + size_t size = 0; + + if (qedi->p_cpuq) { + size = qedi->num_queues * sizeof(struct qedi_glbl_q_params); + pci_free_consistent(qedi->pdev, size, qedi->p_cpuq, + qedi->hw_p_cpuq); + } + + qedi_free_global_queues(qedi); + + kfree(qedi->global_queues); +} + +static void qedi_link_update(void *dev, struct qed_link_output *link) +{ + struct qedi_ctx *qedi = (struct qedi_ctx *)dev; + + if (link->link_up) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "Link Up event.\n"); + atomic_set(&qedi->link_state, QEDI_LINK_UP); + } else { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "Link Down event.\n"); + atomic_set(&qedi->link_state, QEDI_LINK_DOWN); + } +} + +static struct qed_iscsi_cb_ops qedi_cb_ops = { + { + .link_update = qedi_link_update, + } +}; + +static int qedi_queue_cqe(struct qedi_ctx *qedi, union iscsi_cqe *cqe, + u16 que_idx, struct qedi_percpu_s *p) +{ + struct qedi_work *qedi_work; + struct qedi_conn *q_conn; + struct iscsi_conn *conn; + struct qedi_cmd *qedi_cmd; + u32 iscsi_cid; + int rc = 0; + + iscsi_cid = cqe->cqe_common.conn_id; + q_conn = qedi->cid_que.conn_cid_tbl[iscsi_cid]; + if (!q_conn) { + QEDI_WARN(&qedi->dbg_ctx, + "Session no longer exists for cid=0x%x!!\n", + iscsi_cid); + return -1; + } + conn = q_conn->cls_conn->dd_data; + + switch (cqe->cqe_common.cqe_type) { + case ISCSI_CQE_TYPE_SOLICITED: + case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE: + qedi_cmd = qedi_get_cmd_from_tid(qedi, cqe->cqe_solicited.itid); + if (!qedi_cmd) { + rc = -1; + break; + } + INIT_LIST_HEAD(&qedi_cmd->cqe_work.list); + qedi_cmd->cqe_work.qedi = qedi; + memcpy(&qedi_cmd->cqe_work.cqe, cqe, sizeof(union iscsi_cqe)); + qedi_cmd->cqe_work.que_idx = que_idx; + qedi_cmd->cqe_work.is_solicited = true; + list_add_tail(&qedi_cmd->cqe_work.list, &p->work_list); + break; + case ISCSI_CQE_TYPE_UNSOLICITED: + case ISCSI_CQE_TYPE_DUMMY: + case ISCSI_CQE_TYPE_TASK_CLEANUP: + qedi_work = kzalloc(sizeof(*qedi_work), GFP_ATOMIC); + if (!qedi_work) { + rc = -1; + break; + } + INIT_LIST_HEAD(&qedi_work->list); + qedi_work->qedi = qedi; + memcpy(&qedi_work->cqe, cqe, sizeof(union iscsi_cqe)); + qedi_work->que_idx = que_idx; + qedi_work->is_solicited = false; + list_add_tail(&qedi_work->list, &p->work_list); + break; + default: + rc = -1; + QEDI_ERR(&qedi->dbg_ctx, "FW Error cqe.\n"); + } + return rc; +} + +static bool qedi_process_completions(struct qedi_fastpath *fp) +{ + struct qedi_ctx *qedi = fp->qedi; + struct qed_sb_info *sb_info = fp->sb_info; + struct status_block *sb = sb_info->sb_virt; + struct qedi_percpu_s *p = NULL; + struct global_queue *que; + u16 prod_idx; + unsigned long flags; + union iscsi_cqe *cqe; + int cpu; + int ret; + + /* Get the current firmware producer index */ + prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; + + if (prod_idx >= QEDI_CQ_SIZE) + prod_idx = prod_idx % QEDI_CQ_SIZE; + + que = qedi->global_queues[fp->sb_id]; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, + "Before: global queue=%p prod_idx=%d cons_idx=%d, sb_id=%d\n", + que, prod_idx, que->cq_cons_idx, fp->sb_id); + + qedi->intr_cpu = fp->sb_id; + cpu = smp_processor_id(); + p = &per_cpu(qedi_percpu, cpu); + + if (unlikely(!p->iothread)) + WARN_ON(1); + + spin_lock_irqsave(&p->p_work_lock, flags); + while (que->cq_cons_idx != prod_idx) { + cqe = &que->cq[que->cq_cons_idx]; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_IO, + "cqe=%p prod_idx=%d cons_idx=%d.\n", + cqe, prod_idx, que->cq_cons_idx); + + ret = qedi_queue_cqe(qedi, cqe, fp->sb_id, p); + if (ret) + continue; + + que->cq_cons_idx++; + if (que->cq_cons_idx == QEDI_CQ_SIZE) + que->cq_cons_idx = 0; + } + wake_up_process(p->iothread); + spin_unlock_irqrestore(&p->p_work_lock, flags); + + return true; +} + +static bool qedi_fp_has_work(struct qedi_fastpath *fp) +{ + struct qedi_ctx *qedi = fp->qedi; + struct global_queue *que; + struct qed_sb_info *sb_info = fp->sb_info; + struct status_block *sb = sb_info->sb_virt; + u16 prod_idx; + + barrier(); + + /* Get the current firmware producer index */ + prod_idx = sb->pi_array[QEDI_PROTO_CQ_PROD_IDX]; + + /* Get the pointer to the global CQ this completion is on */ + que = qedi->global_queues[fp->sb_id]; + + /* prod idx wrap around uint16 */ + if (prod_idx >= QEDI_CQ_SIZE) + prod_idx = prod_idx % QEDI_CQ_SIZE; + + return (que->cq_cons_idx != prod_idx); +} + +/* MSI-X fastpath handler code */ +static irqreturn_t qedi_msix_handler(int irq, void *dev_id) +{ + struct qedi_fastpath *fp = dev_id; + struct qedi_ctx *qedi = fp->qedi; + bool wake_io_thread = true; + + qed_sb_ack(fp->sb_info, IGU_INT_DISABLE, 0); + +process_again: + wake_io_thread = qedi_process_completions(fp); + if (wake_io_thread) { + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, + "process already running\n"); + } + + if (qedi_fp_has_work(fp) == 0) + qed_sb_update_sb_idx(fp->sb_info); + + /* Check for more work */ + rmb(); + + if (qedi_fp_has_work(fp) == 0) + qed_sb_ack(fp->sb_info, IGU_INT_ENABLE, 1); + else + goto process_again; + + return IRQ_HANDLED; +} + +/* simd handler for MSI/INTa */ +static void qedi_simd_int_handler(void *cookie) +{ + /* Cookie is qedi_ctx struct */ + struct qedi_ctx *qedi = (struct qedi_ctx *)cookie; + + QEDI_WARN(&qedi->dbg_ctx, "qedi=%p.\n", qedi); +} + +#define QEDI_SIMD_HANDLER_NUM 0 +static void qedi_sync_free_irqs(struct qedi_ctx *qedi) +{ + int i; + + if (qedi->int_info.msix_cnt) { + for (i = 0; i < qedi->int_info.used_cnt; i++) { + synchronize_irq(qedi->int_info.msix[i].vector); + irq_set_affinity_hint(qedi->int_info.msix[i].vector, + NULL); + free_irq(qedi->int_info.msix[i].vector, + &qedi->fp_array[i]); + } + } else { + qedi_ops->common->simd_handler_clean(qedi->cdev, + QEDI_SIMD_HANDLER_NUM); + } + + qedi->int_info.used_cnt = 0; + qedi_ops->common->set_fp_int(qedi->cdev, 0); +} + +static int qedi_request_msix_irq(struct qedi_ctx *qedi) +{ + int i, rc, cpu; + + cpu = cpumask_first(cpu_online_mask); + for (i = 0; i < MIN_NUM_CPUS_MSIX(qedi); i++) { + rc = request_irq(qedi->int_info.msix[i].vector, + qedi_msix_handler, 0, "qedi", + &qedi->fp_array[i]); + + if (rc) { + QEDI_WARN(&qedi->dbg_ctx, "request_irq failed.\n"); + qedi_sync_free_irqs(qedi); + return rc; + } + qedi->int_info.used_cnt++; + rc = irq_set_affinity_hint(qedi->int_info.msix[i].vector, + get_cpu_mask(cpu)); + cpu = cpumask_next(cpu, cpu_online_mask); + } + + return 0; +} + +static int qedi_setup_int(struct qedi_ctx *qedi) +{ + int rc = 0; + + rc = qedi_ops->common->set_fp_int(qedi->cdev, num_online_cpus()); + rc = qedi_ops->common->get_fp_int(qedi->cdev, &qedi->int_info); + if (rc) + goto exit_setup_int; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, + "Number of msix_cnt = 0x%x num of cpus = 0x%x\n", + qedi->int_info.msix_cnt, num_online_cpus()); + + if (qedi->int_info.msix_cnt) { + rc = qedi_request_msix_irq(qedi); + goto exit_setup_int; + } else { + qedi_ops->common->simd_handler_config(qedi->cdev, &qedi, + QEDI_SIMD_HANDLER_NUM, + qedi_simd_int_handler); + qedi->int_info.used_cnt = 1; + } + +exit_setup_int: + return rc; +} + +static void qedi_free_bdq(struct qedi_ctx *qedi) +{ + int i; + + if (qedi->bdq_pbl_list) + dma_free_coherent(&qedi->pdev->dev, PAGE_SIZE, + qedi->bdq_pbl_list, qedi->bdq_pbl_list_dma); + + if (qedi->bdq_pbl) + dma_free_coherent(&qedi->pdev->dev, qedi->bdq_pbl_mem_size, + qedi->bdq_pbl, qedi->bdq_pbl_dma); + + for (i = 0; i < QEDI_BDQ_NUM; i++) { + if (qedi->bdq[i].buf_addr) { + dma_free_coherent(&qedi->pdev->dev, QEDI_BDQ_BUF_SIZE, + qedi->bdq[i].buf_addr, + qedi->bdq[i].buf_dma); + } + } +} + +static void qedi_free_global_queues(struct qedi_ctx *qedi) +{ + int i; + struct global_queue **gl = qedi->global_queues; + + for (i = 0; i < qedi->num_queues; i++) { + if (!gl[i]) + continue; + + if (gl[i]->cq) + dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_mem_size, + gl[i]->cq, gl[i]->cq_dma); + if (gl[i]->cq_pbl) + dma_free_coherent(&qedi->pdev->dev, gl[i]->cq_pbl_size, + gl[i]->cq_pbl, gl[i]->cq_pbl_dma); + + kfree(gl[i]); + } + qedi_free_bdq(qedi); +} + +static int qedi_alloc_bdq(struct qedi_ctx *qedi) +{ + int i; + struct scsi_bd *pbl; + u64 *list; + dma_addr_t page; + + /* Alloc dma memory for BDQ buffers */ + for (i = 0; i < QEDI_BDQ_NUM; i++) { + qedi->bdq[i].buf_addr = + dma_alloc_coherent(&qedi->pdev->dev, + QEDI_BDQ_BUF_SIZE, + &qedi->bdq[i].buf_dma, + GFP_KERNEL); + if (!qedi->bdq[i].buf_addr) { + QEDI_ERR(&qedi->dbg_ctx, + "Could not allocate BDQ buffer %d.\n", i); + return -ENOMEM; + } + } + + /* Alloc dma memory for BDQ page buffer list */ + qedi->bdq_pbl_mem_size = QEDI_BDQ_NUM * sizeof(struct scsi_bd); + qedi->bdq_pbl_mem_size = ALIGN(qedi->bdq_pbl_mem_size, PAGE_SIZE); + qedi->rq_num_entries = qedi->bdq_pbl_mem_size / sizeof(struct scsi_bd); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, "rq_num_entries = %d.\n", + qedi->rq_num_entries); + + qedi->bdq_pbl = dma_alloc_coherent(&qedi->pdev->dev, + qedi->bdq_pbl_mem_size, + &qedi->bdq_pbl_dma, GFP_KERNEL); + if (!qedi->bdq_pbl) { + QEDI_ERR(&qedi->dbg_ctx, "Could not allocate BDQ PBL.\n"); + return -ENOMEM; + } + + /* + * Populate BDQ PBL with physical and virtual address of individual + * BDQ buffers + */ + pbl = (struct scsi_bd *)qedi->bdq_pbl; + for (i = 0; i < QEDI_BDQ_NUM; i++) { + pbl->address.hi = + cpu_to_le32(QEDI_U64_HI(qedi->bdq[i].buf_dma)); + pbl->address.lo = + cpu_to_le32(QEDI_U64_LO(qedi->bdq[i].buf_dma)); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "pbl [0x%p] pbl->address hi [0x%llx] lo [0x%llx], idx [%d]\n", + pbl, pbl->address.hi, pbl->address.lo, i); + pbl->opaque.hi = 0; + pbl->opaque.lo = cpu_to_le32(QEDI_U64_LO(i)); + pbl++; + } + + /* Allocate list of PBL pages */ + qedi->bdq_pbl_list = dma_alloc_coherent(&qedi->pdev->dev, + PAGE_SIZE, + &qedi->bdq_pbl_list_dma, + GFP_KERNEL); + if (!qedi->bdq_pbl_list) { + QEDI_ERR(&qedi->dbg_ctx, + "Could not allocate list of PBL pages.\n"); + return -ENOMEM; + } + memset(qedi->bdq_pbl_list, 0, PAGE_SIZE); + + /* + * Now populate PBL list with pages that contain pointers to the + * individual buffers. + */ + qedi->bdq_pbl_list_num_entries = qedi->bdq_pbl_mem_size / PAGE_SIZE; + list = (u64 *)qedi->bdq_pbl_list; + page = qedi->bdq_pbl_list_dma; + for (i = 0; i < qedi->bdq_pbl_list_num_entries; i++) { + *list = qedi->bdq_pbl_dma; + list++; + page += PAGE_SIZE; + } + + return 0; +} + +static int qedi_alloc_global_queues(struct qedi_ctx *qedi) +{ + u32 *list; + int i; + int status = 0, rc; + u32 *pbl; + dma_addr_t page; + int num_pages; + + /* + * Number of global queues (CQ / RQ). This should + * be <= number of available MSIX vectors for the PF + */ + if (!qedi->num_queues) { + QEDI_ERR(&qedi->dbg_ctx, "No MSI-X vectors available!\n"); + return 1; + } + + /* Make sure we allocated the PBL that will contain the physical + * addresses of our queues + */ + if (!qedi->p_cpuq) { + status = 1; + goto mem_alloc_failure; + } + + qedi->global_queues = kzalloc((sizeof(struct global_queue *) * + qedi->num_queues), GFP_KERNEL); + if (!qedi->global_queues) { + QEDI_ERR(&qedi->dbg_ctx, + "Unable to allocate global queues array ptr memory\n"); + return -ENOMEM; + } + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, + "qedi->global_queues=%p.\n", qedi->global_queues); + + /* Allocate DMA coherent buffers for BDQ */ + rc = qedi_alloc_bdq(qedi); + if (rc) + goto mem_alloc_failure; + + /* Allocate a CQ and an associated PBL for each MSI-X + * vector. + */ + for (i = 0; i < qedi->num_queues; i++) { + qedi->global_queues[i] = + kzalloc(sizeof(*qedi->global_queues[0]), + GFP_KERNEL); + if (!qedi->global_queues[i]) { + QEDI_ERR(&qedi->dbg_ctx, + "Unable to allocation global queue %d.\n", i); + goto mem_alloc_failure; + } + + qedi->global_queues[i]->cq_mem_size = + (QEDI_CQ_SIZE + 8) * sizeof(union iscsi_cqe); + qedi->global_queues[i]->cq_mem_size = + (qedi->global_queues[i]->cq_mem_size + + (QEDI_PAGE_SIZE - 1)); + + qedi->global_queues[i]->cq_pbl_size = + (qedi->global_queues[i]->cq_mem_size / + QEDI_PAGE_SIZE) * sizeof(void *); + qedi->global_queues[i]->cq_pbl_size = + (qedi->global_queues[i]->cq_pbl_size + + (QEDI_PAGE_SIZE - 1)); + + qedi->global_queues[i]->cq = + dma_alloc_coherent(&qedi->pdev->dev, + qedi->global_queues[i]->cq_mem_size, + &qedi->global_queues[i]->cq_dma, + GFP_KERNEL); + + if (!qedi->global_queues[i]->cq) { + QEDI_WARN(&qedi->dbg_ctx, + "Could not allocate cq.\n"); + status = -ENOMEM; + goto mem_alloc_failure; + } + memset(qedi->global_queues[i]->cq, 0, + qedi->global_queues[i]->cq_mem_size); + + qedi->global_queues[i]->cq_pbl = + dma_alloc_coherent(&qedi->pdev->dev, + qedi->global_queues[i]->cq_pbl_size, + &qedi->global_queues[i]->cq_pbl_dma, + GFP_KERNEL); + + if (!qedi->global_queues[i]->cq_pbl) { + QEDI_WARN(&qedi->dbg_ctx, + "Could not allocate cq PBL.\n"); + status = -ENOMEM; + goto mem_alloc_failure; + } + memset(qedi->global_queues[i]->cq_pbl, 0, + qedi->global_queues[i]->cq_pbl_size); + + /* Create PBL */ + num_pages = qedi->global_queues[i]->cq_mem_size / + QEDI_PAGE_SIZE; + page = qedi->global_queues[i]->cq_dma; + pbl = (u32 *)qedi->global_queues[i]->cq_pbl; + + while (num_pages--) { + *pbl = (u32)page; + pbl++; + *pbl = (u32)((u64)page >> 32); + pbl++; + page += QEDI_PAGE_SIZE; + } + } + + list = (u32 *)qedi->p_cpuq; + + /* + * The list is built as follows: CQ#0 PBL pointer, RQ#0 PBL pointer, + * CQ#1 PBL pointer, RQ#1 PBL pointer, etc. Each PBL pointer points + * to the physical address which contains an array of pointers to the + * physical addresses of the specific queue pages. + */ + for (i = 0; i < qedi->num_queues; i++) { + *list = (u32)qedi->global_queues[i]->cq_pbl_dma; + list++; + *list = (u32)((u64)qedi->global_queues[i]->cq_pbl_dma >> 32); + list++; + + *list = (u32)0; + list++; + *list = (u32)((u64)0 >> 32); + list++; + } + + return 0; + +mem_alloc_failure: + qedi_free_global_queues(qedi); + return status; +} + +int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) +{ + int rval = 0; + u32 *pbl; + dma_addr_t page; + int num_pages; + + if (!ep) + return -EIO; + + /* Calculate appropriate queue and PBL sizes */ + ep->sq_mem_size = QEDI_SQ_SIZE * sizeof(struct iscsi_wqe); + ep->sq_mem_size += QEDI_PAGE_SIZE - 1; + + ep->sq_pbl_size = (ep->sq_mem_size / QEDI_PAGE_SIZE) * sizeof(void *); + ep->sq_pbl_size = ep->sq_pbl_size + QEDI_PAGE_SIZE; + + ep->sq = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_mem_size, + &ep->sq_dma, GFP_KERNEL); + if (!ep->sq) { + QEDI_WARN(&qedi->dbg_ctx, + "Could not allocate send queue.\n"); + rval = -ENOMEM; + goto out; + } + memset(ep->sq, 0, ep->sq_mem_size); + + ep->sq_pbl = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size, + &ep->sq_pbl_dma, GFP_KERNEL); + if (!ep->sq_pbl) { + QEDI_WARN(&qedi->dbg_ctx, + "Could not allocate send queue PBL.\n"); + rval = -ENOMEM; + goto out_free_sq; + } + memset(ep->sq_pbl, 0, ep->sq_pbl_size); + + /* Create PBL */ + num_pages = ep->sq_mem_size / QEDI_PAGE_SIZE; + page = ep->sq_dma; + pbl = (u32 *)ep->sq_pbl; + + while (num_pages--) { + *pbl = (u32)page; + pbl++; + *pbl = (u32)((u64)page >> 32); + pbl++; + page += QEDI_PAGE_SIZE; + } + + return rval; + +out_free_sq: + dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, + ep->sq_dma); +out: + return rval; +} + +void qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep) +{ + if (ep->sq_pbl) + dma_free_coherent(&qedi->pdev->dev, ep->sq_pbl_size, ep->sq_pbl, + ep->sq_pbl_dma); + if (ep->sq) + dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq, + ep->sq_dma); +} + +int qedi_get_task_idx(struct qedi_ctx *qedi) +{ + s16 tmp_idx; + +again: + tmp_idx = find_first_zero_bit(qedi->task_idx_map, + MAX_ISCSI_TASK_ENTRIES); + + if (tmp_idx >= MAX_ISCSI_TASK_ENTRIES) { + QEDI_ERR(&qedi->dbg_ctx, "FW task context pool is full.\n"); + tmp_idx = -1; + goto err_idx; + } + + if (test_and_set_bit(tmp_idx, qedi->task_idx_map)) + goto again; + +err_idx: + return tmp_idx; +} + +void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx) +{ + if (!test_and_clear_bit(idx, qedi->task_idx_map)) { + QEDI_ERR(&qedi->dbg_ctx, + "FW task context, already cleared, tid=0x%x\n", idx); + WARN_ON(1); + } +} + +void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt, + struct qedi_cmd *cmd) +{ + qedi->itt_map[tid].itt = proto_itt; + qedi->itt_map[tid].p_cmd = cmd; + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "update itt map tid=0x%x, with proto itt=0x%x\n", tid, + qedi->itt_map[tid].itt); +} + +void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid) +{ + u16 i; + + for (i = 0; i < MAX_ISCSI_TASK_ENTRIES; i++) { + if (qedi->itt_map[i].itt == itt) { + *tid = i; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "Ref itt=0x%x, found at tid=0x%x\n", + itt, *tid); + return; + } + } + + WARN_ON(1); +} + +void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt) +{ + *proto_itt = qedi->itt_map[tid].itt; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN, + "Get itt map tid [0x%x with proto itt[0x%x]", + tid, *proto_itt); +} + +struct qedi_cmd *qedi_get_cmd_from_tid(struct qedi_ctx *qedi, u32 tid) +{ + struct qedi_cmd *cmd = NULL; + + if (tid > MAX_ISCSI_TASK_ENTRIES) + return NULL; + + cmd = qedi->itt_map[tid].p_cmd; + if (cmd->task_id != tid) + return NULL; + + qedi->itt_map[tid].p_cmd = NULL; + + return cmd; +} + +static int qedi_alloc_itt(struct qedi_ctx *qedi) +{ + qedi->itt_map = kcalloc(MAX_ISCSI_TASK_ENTRIES, + sizeof(struct qedi_itt_map), GFP_KERNEL); + if (!qedi->itt_map) { + QEDI_ERR(&qedi->dbg_ctx, + "Unable to allocate itt map array memory\n"); + return -ENOMEM; + } + return 0; +} + +static void qedi_free_itt(struct qedi_ctx *qedi) +{ + kfree(qedi->itt_map); +} + +static struct qed_ll2_cb_ops qedi_ll2_cb_ops = { + .rx_cb = qedi_ll2_rx, + .tx_cb = NULL, +}; + +static int qedi_percpu_io_thread(void *arg) +{ + struct qedi_percpu_s *p = arg; + struct qedi_work *work, *tmp; + unsigned long flags; + LIST_HEAD(work_list); + + set_user_nice(current, -20); + + while (!kthread_should_stop()) { + spin_lock_irqsave(&p->p_work_lock, flags); + while (!list_empty(&p->work_list)) { + list_splice_init(&p->work_list, &work_list); + spin_unlock_irqrestore(&p->p_work_lock, flags); + + list_for_each_entry_safe(work, tmp, &work_list, list) { + list_del_init(&work->list); + qedi_fp_process_cqes(work); + if (!work->is_solicited) + kfree(work); + } + cond_resched(); + spin_lock_irqsave(&p->p_work_lock, flags); + } + set_current_state(TASK_INTERRUPTIBLE); + spin_unlock_irqrestore(&p->p_work_lock, flags); + schedule(); + } + __set_current_state(TASK_RUNNING); + + return 0; +} + +static void qedi_percpu_thread_create(unsigned int cpu) +{ + struct qedi_percpu_s *p; + struct task_struct *thread; + + p = &per_cpu(qedi_percpu, cpu); + + thread = kthread_create_on_node(qedi_percpu_io_thread, (void *)p, + cpu_to_node(cpu), + "qedi_thread/%d", cpu); + if (likely(!IS_ERR(thread))) { + kthread_bind(thread, cpu); + p->iothread = thread; + wake_up_process(thread); + } +} + +static void qedi_percpu_thread_destroy(unsigned int cpu) +{ + struct qedi_percpu_s *p; + struct task_struct *thread; + struct qedi_work *work, *tmp; + + p = &per_cpu(qedi_percpu, cpu); + spin_lock_bh(&p->p_work_lock); + thread = p->iothread; + p->iothread = NULL; + + list_for_each_entry_safe(work, tmp, &p->work_list, list) { + list_del_init(&work->list); + qedi_fp_process_cqes(work); + if (!work->is_solicited) + kfree(work); + } + + spin_unlock_bh(&p->p_work_lock); + if (thread) + kthread_stop(thread); +} + +static int qedi_cpu_callback(struct notifier_block *nfb, + unsigned long action, void *hcpu) +{ + unsigned int cpu = (unsigned long)hcpu; + + switch (action) { + case CPU_ONLINE: + case CPU_ONLINE_FROZEN: + QEDI_ERR(NULL, "CPU %d online.\n", cpu); + qedi_percpu_thread_create(cpu); + break; + case CPU_DEAD: + case CPU_DEAD_FROZEN: + QEDI_ERR(NULL, "CPU %d offline.\n", cpu); + qedi_percpu_thread_destroy(cpu); + break; + default: + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block qedi_cpu_notifier = { + .notifier_call = qedi_cpu_callback, +}; + +void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu) +{ + struct qed_ll2_params params; + + qedi_recover_all_conns(qedi); + + qedi_ops->ll2->stop(qedi->cdev); + qedi_ll2_free_skbs(qedi); + + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "old MTU %u, new MTU %u\n", + qedi->ll2_mtu, mtu); + memset(¶ms, 0, sizeof(params)); + qedi->ll2_mtu = mtu; + params.mtu = qedi->ll2_mtu + IPV6_HDR_LEN + TCP_HDR_LEN; + params.drop_ttl0_packets = 0; + params.rx_vlan_stripping = 1; + ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); + qedi_ops->ll2->start(qedi->cdev, ¶ms); +} + +static void __qedi_remove(struct pci_dev *pdev, int mode) +{ + struct qedi_ctx *qedi = pci_get_drvdata(pdev); + + if (qedi->tmf_thread) { + flush_workqueue(qedi->tmf_thread); + destroy_workqueue(qedi->tmf_thread); + qedi->tmf_thread = NULL; + } + + if (qedi->offload_thread) { + flush_workqueue(qedi->offload_thread); + destroy_workqueue(qedi->offload_thread); + qedi->offload_thread = NULL; + } + +#ifdef CONFIG_DEBUG_FS + qedi_dbg_host_exit(&qedi->dbg_ctx); +#endif + if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) + qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); + + qedi_sync_free_irqs(qedi); + + if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { + qedi_ops->stop(qedi->cdev); + qedi_ops->ll2->stop(qedi->cdev); + } + + if (mode == QEDI_MODE_NORMAL) + qedi_free_iscsi_pf_param(qedi); + + if (!test_bit(QEDI_IN_OFFLINE, &qedi->flags)) { + qedi_ops->common->slowpath_stop(qedi->cdev); + qedi_ops->common->remove(qedi->cdev); + } + + qedi_destroy_fp(qedi); + + if (mode == QEDI_MODE_NORMAL) { + qedi_release_cid_que(qedi); + qedi_cm_free_mem(qedi); + qedi_free_uio(qedi->udev); + qedi_free_itt(qedi); + + iscsi_host_remove(qedi->shost); + iscsi_host_free(qedi->shost); + + if (qedi->ll2_recv_thread) { + kthread_stop(qedi->ll2_recv_thread); + qedi->ll2_recv_thread = NULL; + } + qedi_ll2_free_skbs(qedi); + } +} + +static int __qedi_probe(struct pci_dev *pdev, int mode) +{ + struct qedi_ctx *qedi; + struct qed_ll2_params params; + u32 dp_module = 0; + u8 dp_level = 0; + bool is_vf = false; + char host_buf[16]; + struct qed_link_params link_params; + struct qed_slowpath_params sp_params; + struct qed_probe_params qed_params; + void *task_start, *task_end; + int rc; + u16 tmp; + + if (mode != QEDI_MODE_RECOVERY) { + qedi = qedi_host_alloc(pdev); + if (!qedi) { + rc = -ENOMEM; + goto exit_probe; + } + } else { + qedi = pci_get_drvdata(pdev); + } + + memset(&qed_params, 0, sizeof(qed_params)); + qed_params.protocol = QED_PROTOCOL_ISCSI; + qed_params.dp_module = dp_module; + qed_params.dp_level = dp_level; + qed_params.is_vf = is_vf; + qedi->cdev = qedi_ops->common->probe(pdev, &qed_params); + if (!qedi->cdev) { + rc = -ENODEV; + QEDI_ERR(&qedi->dbg_ctx, "Cannot initialize hardware\n"); + goto free_host; + } + + qedi->msix_count = MAX_NUM_MSIX_PF; + atomic_set(&qedi->link_state, QEDI_LINK_DOWN); + + if (mode != QEDI_MODE_RECOVERY) { + rc = qedi_set_iscsi_pf_param(qedi); + if (rc) { + rc = -ENOMEM; + QEDI_ERR(&qedi->dbg_ctx, + "Set iSCSI pf param fail\n"); + goto free_host; + } + } + + qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); + + rc = qedi_prepare_fp(qedi); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath.\n"); + goto free_pf_params; + } + + /* Start the Slowpath-process */ + memset(&sp_params, 0, sizeof(struct qed_slowpath_params)); + sp_params.int_mode = QED_INT_MODE_MSIX; + sp_params.drv_major = QEDI_DRIVER_MAJOR_VER; + sp_params.drv_minor = QEDI_DRIVER_MINOR_VER; + sp_params.drv_rev = QEDI_DRIVER_REV_VER; + sp_params.drv_eng = QEDI_DRIVER_ENG_VER; + strlcpy(sp_params.name, "qedi iSCSI", QED_DRV_VER_STR_SIZE); + rc = qedi_ops->common->slowpath_start(qedi->cdev, &sp_params); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, "Cannot start slowpath\n"); + goto stop_hw; + } + + /* update_pf_params needs to be called before and after slowpath + * start + */ + qedi_ops->common->update_pf_params(qedi->cdev, &qedi->pf_params); + + qedi_setup_int(qedi); + if (rc) + goto stop_iscsi_func; + + qedi_ops->common->set_power_state(qedi->cdev, PCI_D0); + + /* Learn information crucial for qedi to progress */ + rc = qedi_ops->fill_dev_info(qedi->cdev, &qedi->dev_info); + if (rc) + goto stop_iscsi_func; + + /* Record BDQ producer doorbell addresses */ + qedi->bdq_primary_prod = qedi->dev_info.primary_dbq_rq_addr; + qedi->bdq_secondary_prod = qedi->dev_info.secondary_bdq_rq_addr; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, + "BDQ primary_prod=%p secondary_prod=%p.\n", + qedi->bdq_primary_prod, + qedi->bdq_secondary_prod); + + /* + * We need to write the number of BDs in the BDQ we've preallocated so + * the f/w will do a prefetch and we'll get an unsolicited CQE when a + * packet arrives. + */ + qedi->bdq_prod_idx = QEDI_BDQ_NUM; + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, + "Writing %d to primary and secondary BDQ doorbell registers.\n", + qedi->bdq_prod_idx); + writew(qedi->bdq_prod_idx, qedi->bdq_primary_prod); + tmp = readw(qedi->bdq_primary_prod); + writew(qedi->bdq_prod_idx, qedi->bdq_secondary_prod); + tmp = readw(qedi->bdq_secondary_prod); + + ether_addr_copy(qedi->mac, qedi->dev_info.common.hw_mac); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, "MAC address is %pM.\n", + qedi->mac); + + sprintf(host_buf, "host_%d", qedi->shost->host_no); + qedi_ops->common->set_id(qedi->cdev, host_buf, QEDI_MODULE_VERSION); + + qedi_ops->register_ops(qedi->cdev, &qedi_cb_ops, qedi); + + memset(¶ms, 0, sizeof(params)); + params.mtu = DEF_PATH_MTU + IPV6_HDR_LEN + TCP_HDR_LEN; + qedi->ll2_mtu = DEF_PATH_MTU; + params.drop_ttl0_packets = 0; + params.rx_vlan_stripping = 1; + ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac); + + if (mode != QEDI_MODE_RECOVERY) { + /* set up rx path */ + INIT_LIST_HEAD(&qedi->ll2_skb_list); + spin_lock_init(&qedi->ll2_lock); + /* start qedi context */ + spin_lock_init(&qedi->hba_lock); + spin_lock_init(&qedi->task_idx_lock); + } + qedi_ops->ll2->register_cb_ops(qedi->cdev, &qedi_ll2_cb_ops, qedi); + qedi_ops->ll2->start(qedi->cdev, ¶ms); + + if (mode != QEDI_MODE_RECOVERY) { + qedi->ll2_recv_thread = kthread_run(qedi_ll2_recv_thread, + (void *)qedi, + "qedi_ll2_thread"); + } + + rc = qedi_ops->start(qedi->cdev, &qedi->tasks, + qedi, qedi_iscsi_event_cb); + if (rc) { + rc = -ENODEV; + QEDI_ERR(&qedi->dbg_ctx, "Cannot start iSCSI function\n"); + goto stop_slowpath; + } + + task_start = qedi_get_task_mem(&qedi->tasks, 0); + task_end = qedi_get_task_mem(&qedi->tasks, MAX_TID_BLOCKS_ISCSI - 1); + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_DISC, + "Task context start=%p, end=%p block_size=%u.\n", + task_start, task_end, qedi->tasks.size); + + memset(&link_params, 0, sizeof(link_params)); + link_params.link_up = true; + rc = qedi_ops->common->set_link(qedi->cdev, &link_params); + if (rc) { + QEDI_WARN(&qedi->dbg_ctx, "Link set up failed.\n"); + atomic_set(&qedi->link_state, QEDI_LINK_DOWN); + } + +#ifdef CONFIG_DEBUG_FS + qedi_dbg_host_init(&qedi->dbg_ctx, &qedi_debugfs_ops, + &qedi_dbg_fops); +#endif + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, + "QLogic FastLinQ iSCSI Module qedi %s, FW %d.%d.%d.%d\n", + QEDI_MODULE_VERSION, FW_MAJOR_VERSION, FW_MINOR_VERSION, + FW_REVISION_VERSION, FW_ENGINEERING_VERSION); + + if (mode == QEDI_MODE_NORMAL) { + if (iscsi_host_add(qedi->shost, &pdev->dev)) { + QEDI_ERR(&qedi->dbg_ctx, + "Could not add iscsi host\n"); + rc = -ENOMEM; + goto remove_host; + } + + /* Allocate uio buffers */ + rc = qedi_alloc_uio_rings(qedi); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, + "UIO alloc ring failed err=%d\n", rc); + goto remove_host; + } + + rc = qedi_init_uio(qedi); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, + "UIO init failed, err=%d\n", rc); + goto free_uio; + } + + /* host the array on iscsi_conn */ + rc = qedi_setup_cid_que(qedi); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, + "Could not setup cid que\n"); + goto free_uio; + } + + rc = qedi_cm_alloc_mem(qedi); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, + "Could not alloc cm memory\n"); + goto free_cid_que; + } + + rc = qedi_alloc_itt(qedi); + if (rc) { + QEDI_ERR(&qedi->dbg_ctx, + "Could not alloc itt memory\n"); + goto free_cid_que; + } + + sprintf(host_buf, "host_%d", qedi->shost->host_no); + qedi->tmf_thread = create_singlethread_workqueue(host_buf); + if (!qedi->tmf_thread) { + QEDI_ERR(&qedi->dbg_ctx, + "Unable to start tmf thread!\n"); + rc = -ENODEV; + goto free_cid_que; + } + + sprintf(host_buf, "qedi_ofld%d", qedi->shost->host_no); + qedi->offload_thread = create_workqueue(host_buf); + if (!qedi->offload_thread) { + QEDI_ERR(&qedi->dbg_ctx, + "Unable to start offload thread!\n"); + rc = -ENODEV; + goto free_cid_que; + } + + /* F/w needs 1st task context memory entry for performance */ + set_bit(QEDI_RESERVE_TASK_ID, qedi->task_idx_map); + atomic_set(&qedi->num_offloads, 0); + } + + return 0; + +free_cid_que: + qedi_release_cid_que(qedi); +free_uio: + qedi_free_uio(qedi->udev); +remove_host: +#ifdef CONFIG_DEBUG_FS + qedi_dbg_host_exit(&qedi->dbg_ctx); +#endif + iscsi_host_remove(qedi->shost); +stop_iscsi_func: + qedi_ops->stop(qedi->cdev); +stop_slowpath: + qedi_ops->common->slowpath_stop(qedi->cdev); +stop_hw: + qedi_ops->common->remove(qedi->cdev); +free_pf_params: + qedi_free_iscsi_pf_param(qedi); +free_host: + iscsi_host_free(qedi->shost); +exit_probe: + return rc; +} + +static int qedi_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + return __qedi_probe(pdev, QEDI_MODE_NORMAL); +} + +static void qedi_remove(struct pci_dev *pdev) +{ + __qedi_remove(pdev, QEDI_MODE_NORMAL); +} + +static struct pci_device_id qedi_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, 0x165E) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(pci, qedi_pci_tbl); + +static struct pci_driver qedi_pci_driver = { + .name = QEDI_MODULE_NAME, + .id_table = qedi_pci_tbl, + .probe = qedi_probe, + .remove = qedi_remove, +}; + +static int __init qedi_init(void) +{ + int rc = 0; + int ret; + struct qedi_percpu_s *p; + unsigned int cpu = 0; + + qedi_ops = qed_get_iscsi_ops(); + if (!qedi_ops) { + QEDI_ERR(NULL, "Failed to get qed iSCSI operations\n"); + rc = -EINVAL; + goto exit_qedi_init_0; + } + +#ifdef CONFIG_DEBUG_FS + qedi_dbg_init("qedi"); +#endif + + qedi_scsi_transport = iscsi_register_transport(&qedi_iscsi_transport); + if (!qedi_scsi_transport) { + QEDI_ERR(NULL, "Could not register qedi transport"); + rc = -ENOMEM; + goto exit_qedi_init_1; + } + + register_hotcpu_notifier(&qedi_cpu_notifier); + + ret = pci_register_driver(&qedi_pci_driver); + if (ret) { + QEDI_ERR(NULL, "Failed to register driver\n"); + rc = -EINVAL; + goto exit_qedi_init_2; + } + + for_each_possible_cpu(cpu) { + p = &per_cpu(qedi_percpu, cpu); + INIT_LIST_HEAD(&p->work_list); + spin_lock_init(&p->p_work_lock); + p->iothread = NULL; + } + + for_each_online_cpu(cpu) + qedi_percpu_thread_create(cpu); + + return rc; + +exit_qedi_init_2: + iscsi_unregister_transport(&qedi_iscsi_transport); +exit_qedi_init_1: +#ifdef CONFIG_DEBUG_FS + qedi_dbg_exit(); +#endif + qed_put_iscsi_ops(); +exit_qedi_init_0: + return rc; +} + +static void __exit qedi_cleanup(void) +{ + unsigned int cpu = 0; + + for_each_online_cpu(cpu) + qedi_percpu_thread_destroy(cpu); + + pci_unregister_driver(&qedi_pci_driver); + unregister_hotcpu_notifier(&qedi_cpu_notifier); + iscsi_unregister_transport(&qedi_iscsi_transport); + +#ifdef CONFIG_DEBUG_FS + qedi_dbg_exit(); +#endif + qed_put_iscsi_ops(); +} + +MODULE_DESCRIPTION("QLogic FastLinQ 4xxxx iSCSI Module"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("QLogic Corporation"); +MODULE_VERSION(QEDI_MODULE_VERSION); +module_init(qedi_init); +module_exit(qedi_cleanup); diff --git a/drivers/scsi/qedi/qedi_sysfs.c b/drivers/scsi/qedi/qedi_sysfs.c new file mode 100644 index 000000000000..b10c48bd1428 --- /dev/null +++ b/drivers/scsi/qedi/qedi_sysfs.c @@ -0,0 +1,52 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#include "qedi.h" +#include "qedi_gbl.h" +#include "qedi_iscsi.h" +#include "qedi_dbg.h" + +static inline struct qedi_ctx *qedi_dev_to_hba(struct device *dev) +{ + struct Scsi_Host *shost = class_to_shost(dev); + + return iscsi_host_priv(shost); +} + +static ssize_t qedi_show_port_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct qedi_ctx *qedi = qedi_dev_to_hba(dev); + + if (atomic_read(&qedi->link_state) == QEDI_LINK_UP) + return sprintf(buf, "Online\n"); + else + return sprintf(buf, "Linkdown\n"); +} + +static ssize_t qedi_show_speed(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct qedi_ctx *qedi = qedi_dev_to_hba(dev); + struct qed_link_output if_link; + + qedi_ops->common->get_link(qedi->cdev, &if_link); + + return sprintf(buf, "%d Gbit\n", if_link.speed / 1000); +} + +static DEVICE_ATTR(port_state, 0444, qedi_show_port_state, NULL); +static DEVICE_ATTR(speed, 0444, qedi_show_speed, NULL); + +struct device_attribute *qedi_shost_attrs[] = { + &dev_attr_port_state, + &dev_attr_speed, + NULL +}; diff --git a/drivers/scsi/qedi/qedi_version.h b/drivers/scsi/qedi/qedi_version.h new file mode 100644 index 000000000000..9543a1b139d4 --- /dev/null +++ b/drivers/scsi/qedi/qedi_version.h @@ -0,0 +1,14 @@ +/* + * QLogic iSCSI Offload Driver + * Copyright (c) 2016 Cavium Inc. + * + * This software is available under the terms of the GNU General Public License + * (GPL) Version 2, available from the file COPYING in the main directory of + * this source tree. + */ + +#define QEDI_MODULE_VERSION "8.10.3.0" +#define QEDI_DRIVER_MAJOR_VER 8 +#define QEDI_DRIVER_MINOR_VER 10 +#define QEDI_DRIVER_REV_VER 3 +#define QEDI_DRIVER_ENG_VER 0 -- cgit v1.2.3 From e0eed8ab7379faba26f9d85a5904b8292dc4d8b9 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Thu, 1 Dec 2016 20:28:27 +0530 Subject: scsi: cxgb4i: use cxgb4_tp_smt_idx() to get smt_idx cxgb4_tp_smt_idx() is defined in cxgb4 driver, it returns smt_idx for T4,T5,T6 adapters. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 9e6f647ff1c1..ffcae8519881 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1452,8 +1452,8 @@ static int init_act_open(struct cxgbi_sock *csk) csk->mtu = dst_mtu(csk->dst); cxgb4_best_mtu(lldi->mtus, csk->mtu, &csk->mss_idx); csk->tx_chan = cxgb4_port_chan(ndev); - /* SMT two entries per row */ - csk->smac_idx = ((cxgb4_port_viid(ndev) & 0x7F)) << 1; + csk->smac_idx = cxgb4_tp_smt_idx(lldi->adapter_type, + cxgb4_port_viid(ndev)); step = lldi->ntxq / lldi->nchan; csk->txq_idx = cxgb4_port_idx(ndev) * step; step = lldi->nrxq / lldi->nchan; -- cgit v1.2.3 From 586be7cb694fdbb3a35cc35c03387ce0fc534572 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Thu, 1 Dec 2016 20:28:28 +0530 Subject: scsi: cxgb4i: libcxgbi: add active open cmd for T6 adapters Add T6 active open cmd to open active connections on T6 adapters. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 86 ++++++++++++++++++++++++++++++++------ drivers/scsi/cxgbi/libcxgbi.c | 6 +-- 2 files changed, 77 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index ffcae8519881..01a2f2f315f8 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -189,7 +189,6 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, struct l2t_entry *e) { struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); - int t4 = is_t4(lldi->adapter_type); int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); unsigned long long opt0; unsigned int opt2; @@ -232,7 +231,7 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, csk, &req->local_ip, ntohs(req->local_port), &req->peer_ip, ntohs(req->peer_port), csk->atid, csk->rss_qid); - } else { + } else if (is_t5(lldi->adapter_type)) { struct cpl_t5_act_open_req *req = (struct cpl_t5_act_open_req *)skb->head; u32 isn = (prandom_u32() & ~7UL) - 1; @@ -260,12 +259,45 @@ static void send_act_open_req(struct cxgbi_sock *csk, struct sk_buff *skb, csk, &req->local_ip, ntohs(req->local_port), &req->peer_ip, ntohs(req->peer_port), csk->atid, csk->rss_qid); + } else { + struct cpl_t6_act_open_req *req = + (struct cpl_t6_act_open_req *)skb->head; + u32 isn = (prandom_u32() & ~7UL) - 1; + + INIT_TP_WR(req, 0); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ, + qid_atid)); + req->local_port = csk->saddr.sin_port; + req->peer_port = csk->daddr.sin_port; + req->local_ip = csk->saddr.sin_addr.s_addr; + req->peer_ip = csk->daddr.sin_addr.s_addr; + req->opt0 = cpu_to_be64(opt0); + req->params = cpu_to_be64(FILTER_TUPLE_V( + cxgb4_select_ntuple( + csk->cdev->ports[csk->port_id], + csk->l2t))); + req->rsvd = cpu_to_be32(isn); + + opt2 |= T5_ISS_VALID; + opt2 |= RX_FC_DISABLE_F; + opt2 |= T5_OPT_2_VALID_F; + + req->opt2 = cpu_to_be32(opt2); + req->rsvd2 = cpu_to_be32(0); + req->opt3 = cpu_to_be32(0); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk t6 0x%p, %pI4:%u-%pI4:%u, atid %d, qid %u.\n", + csk, &req->local_ip, ntohs(req->local_port), + &req->peer_ip, ntohs(req->peer_port), + csk->atid, csk->rss_qid); } set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); pr_info_ipaddr("t%d csk 0x%p,%u,0x%lx,%u, rss_qid %u.\n", - (&csk->saddr), (&csk->daddr), t4 ? 4 : 5, csk, + (&csk->saddr), (&csk->daddr), + CHELSIO_CHIP_VERSION(lldi->adapter_type), csk, csk->state, csk->flags, csk->atid, csk->rss_qid); cxgb4_l2t_send(csk->cdev->ports[csk->port_id], skb, csk->l2t); @@ -276,7 +308,6 @@ static void send_act_open_req6(struct cxgbi_sock *csk, struct sk_buff *skb, struct l2t_entry *e) { struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(csk->cdev); - int t4 = is_t4(lldi->adapter_type); int wscale = cxgbi_sock_compute_wscale(csk->mss_idx); unsigned long long opt0; unsigned int opt2; @@ -294,10 +325,9 @@ static void send_act_open_req6(struct cxgbi_sock *csk, struct sk_buff *skb, opt2 = RX_CHANNEL_V(0) | RSS_QUEUE_VALID_F | - RX_FC_DISABLE_F | RSS_QUEUE_V(csk->rss_qid); - if (t4) { + if (is_t4(lldi->adapter_type)) { struct cpl_act_open_req6 *req = (struct cpl_act_open_req6 *)skb->head; @@ -322,7 +352,7 @@ static void send_act_open_req6(struct cxgbi_sock *csk, struct sk_buff *skb, req->params = cpu_to_be32(cxgb4_select_ntuple( csk->cdev->ports[csk->port_id], csk->l2t)); - } else { + } else if (is_t5(lldi->adapter_type)) { struct cpl_t5_act_open_req6 *req = (struct cpl_t5_act_open_req6 *)skb->head; @@ -345,12 +375,41 @@ static void send_act_open_req6(struct cxgbi_sock *csk, struct sk_buff *skb, req->params = cpu_to_be64(FILTER_TUPLE_V(cxgb4_select_ntuple( csk->cdev->ports[csk->port_id], csk->l2t))); + } else { + struct cpl_t6_act_open_req6 *req = + (struct cpl_t6_act_open_req6 *)skb->head; + + INIT_TP_WR(req, 0); + OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_ACT_OPEN_REQ6, + qid_atid)); + req->local_port = csk->saddr6.sin6_port; + req->peer_port = csk->daddr6.sin6_port; + req->local_ip_hi = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr); + req->local_ip_lo = *(__be64 *)(csk->saddr6.sin6_addr.s6_addr + + 8); + req->peer_ip_hi = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr); + req->peer_ip_lo = *(__be64 *)(csk->daddr6.sin6_addr.s6_addr + + 8); + req->opt0 = cpu_to_be64(opt0); + + opt2 |= RX_FC_DISABLE_F; + opt2 |= T5_OPT_2_VALID_F; + + req->opt2 = cpu_to_be32(opt2); + + req->params = cpu_to_be64(FILTER_TUPLE_V(cxgb4_select_ntuple( + csk->cdev->ports[csk->port_id], + csk->l2t))); + + req->rsvd2 = cpu_to_be32(0); + req->opt3 = cpu_to_be32(0); } set_wr_txq(skb, CPL_PRIORITY_SETUP, csk->port_id); pr_info("t%d csk 0x%p,%u,0x%lx,%u, [%pI6]:%u-[%pI6]:%u, rss_qid %u.\n", - t4 ? 4 : 5, csk, csk->state, csk->flags, csk->atid, + CHELSIO_CHIP_VERSION(lldi->adapter_type), csk, csk->state, + csk->flags, csk->atid, &csk->saddr6.sin6_addr, ntohs(csk->saddr.sin_port), &csk->daddr6.sin6_addr, ntohs(csk->daddr.sin_port), csk->rss_qid); @@ -1382,7 +1441,6 @@ static int init_act_open(struct cxgbi_sock *csk) void *daddr; unsigned int step; unsigned int size, size6; - int t4 = is_t4(lldi->adapter_type); unsigned int linkspeed; unsigned int rcv_winf, snd_winf; @@ -1428,12 +1486,15 @@ static int init_act_open(struct cxgbi_sock *csk) cxgb4_clip_get(ndev, (const u32 *)&csk->saddr6.sin6_addr, 1); #endif - if (t4) { + if (is_t4(lldi->adapter_type)) { size = sizeof(struct cpl_act_open_req); size6 = sizeof(struct cpl_act_open_req6); - } else { + } else if (is_t5(lldi->adapter_type)) { size = sizeof(struct cpl_t5_act_open_req); size6 = sizeof(struct cpl_t5_act_open_req6); + } else { + size = sizeof(struct cpl_t6_act_open_req); + size6 = sizeof(struct cpl_t6_act_open_req6); } if (csk->csk_family == AF_INET) @@ -1794,7 +1855,8 @@ static void *t4_uld_add(const struct cxgb4_lld_info *lldi) cdev->nports = lldi->nports; cdev->mtus = lldi->mtus; cdev->nmtus = NMTUS; - cdev->rx_credit_thres = cxgb4i_rx_credit_thres; + cdev->rx_credit_thres = (CHELSIO_CHIP_VERSION(lldi->adapter_type) <= + CHELSIO_T5) ? cxgb4i_rx_credit_thres : 0; cdev->skb_tx_rsvd = CXGB4I_TX_HEADER_LEN; cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr); cdev->itp = &cxgb4i_iscsi_transport; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 2ffe029ff2b6..542337889224 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -1627,15 +1627,15 @@ static void csk_return_rx_credits(struct cxgbi_sock *csk, int copied) csk->rcv_wup, cdev->rx_credit_thres, csk->rcv_win); + if (!cdev->rx_credit_thres) + return; + if (csk->state != CTP_ESTABLISHED) return; credits = csk->copied_seq - csk->rcv_wup; if (unlikely(!credits)) return; - if (unlikely(cdev->rx_credit_thres == 0)) - return; - must_send = credits + 16384 >= csk->rcv_win; if (must_send || credits >= cdev->rx_credit_thres) csk->rcv_wup += cdev->csk_send_rx_credits(csk, credits); -- cgit v1.2.3 From 44830d8fd28a729729d14bb160341a6170631eb7 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Thu, 1 Dec 2016 20:28:29 +0530 Subject: scsi: cxgb4i: libcxgbi: cxgb4: add T6 iSCSI completion feature T6 adapters reduce number of completions to host by generating single completion for all the directly placed(DDP) iSCSI pdus in a sequence. This patch adds new structure for completion hw cmd (struct cpl_rx_iscsi_cmp) and implements T6 completion feature. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/net/ethernet/chelsio/cxgb4/t4_msg.h | 13 ++ drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 219 ++++++++++++++++++++++++---- drivers/scsi/cxgbi/libcxgbi.c | 19 +++ drivers/scsi/cxgbi/libcxgbi.h | 1 + 4 files changed, 226 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h index fba3b2ad382d..a267173f5997 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h +++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h @@ -76,6 +76,7 @@ enum { CPL_PASS_ESTABLISH = 0x41, CPL_RX_DATA_DDP = 0x42, CPL_PASS_ACCEPT_REQ = 0x44, + CPL_RX_ISCSI_CMP = 0x45, CPL_TRACE_PKT_T5 = 0x48, CPL_RX_ISCSI_DDP = 0x49, @@ -934,6 +935,18 @@ struct cpl_iscsi_data { __u8 status; }; +struct cpl_rx_iscsi_cmp { + union opcode_tid ot; + __be16 pdu_len_ddp; + __be16 len; + __be32 seq; + __be16 urg; + __u8 rsvd; + __u8 status; + __be32 ulp_crc; + __be32 ddpvld; +}; + struct cpl_tx_data_iso { __be32 op_to_scsi; __u8 reserved1; diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 01a2f2f315f8..57401b58efce 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -1232,6 +1232,101 @@ rel_skb: __kfree_skb(skb); } +static void do_rx_iscsi_data(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_iscsi_hdr *cpl = (struct cpl_iscsi_hdr *)skb->data; + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + struct sk_buff *lskb; + u32 tid = GET_TID(cpl); + u16 pdu_len_ddp = be16_to_cpu(cpl->pdu_len_ddp); + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) { + pr_err("can't find conn. for tid %u.\n", tid); + goto rel_skb; + } + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx, tid %u, skb 0x%p,%u, 0x%x.\n", + csk, csk->state, csk->flags, csk->tid, skb, + skb->len, pdu_len_ddp); + + spin_lock_bh(&csk->lock); + + if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, bad state.\n", + csk, csk->state, csk->flags, csk->tid); + + if (csk->state != CTP_ABORTING) + goto abort_conn; + else + goto discard; + } + + cxgbi_skcb_tcp_seq(skb) = be32_to_cpu(cpl->seq); + cxgbi_skcb_flags(skb) = 0; + + skb_reset_transport_header(skb); + __skb_pull(skb, sizeof(*cpl)); + __pskb_trim(skb, ntohs(cpl->len)); + + if (!csk->skb_ulp_lhdr) + csk->skb_ulp_lhdr = skb; + + lskb = csk->skb_ulp_lhdr; + cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA); + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx, skb 0x%p data, 0x%p.\n", + csk, csk->state, csk->flags, skb, lskb); + + __skb_queue_tail(&csk->receive_queue, skb); + spin_unlock_bh(&csk->lock); + return; + +abort_conn: + send_abort_req(csk); +discard: + spin_unlock_bh(&csk->lock); +rel_skb: + __kfree_skb(skb); +} + +static void +cxgb4i_process_ddpvld(struct cxgbi_sock *csk, + struct sk_buff *skb, u32 ddpvld) +{ + if (ddpvld & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) { + pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, hcrc bad 0x%lx.\n", + csk, skb, ddpvld, cxgbi_skcb_flags(skb)); + cxgbi_skcb_set_flag(skb, SKCBF_RX_HCRC_ERR); + } + + if (ddpvld & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) { + pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, dcrc bad 0x%lx.\n", + csk, skb, ddpvld, cxgbi_skcb_flags(skb)); + cxgbi_skcb_set_flag(skb, SKCBF_RX_DCRC_ERR); + } + + if (ddpvld & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) { + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, lhdr 0x%p, status 0x%x, pad bad.\n", + csk, skb, ddpvld); + cxgbi_skcb_set_flag(skb, SKCBF_RX_PAD_ERR); + } + + if ((ddpvld & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) && + !cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA)) { + log_debug(1 << CXGBI_DBG_PDU_RX, + "csk 0x%p, lhdr 0x%p, 0x%x, data ddp'ed.\n", + csk, skb, ddpvld); + cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA_DDPD); + } +} + static void do_rx_data_ddp(struct cxgbi_device *cdev, struct sk_buff *skb) { @@ -1241,7 +1336,7 @@ static void do_rx_data_ddp(struct cxgbi_device *cdev, unsigned int tid = GET_TID(rpl); struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); struct tid_info *t = lldi->tids; - unsigned int status = ntohl(rpl->ddpvld); + u32 ddpvld = be32_to_cpu(rpl->ddpvld); csk = lookup_tid(t, tid); if (unlikely(!csk)) { @@ -1251,7 +1346,7 @@ static void do_rx_data_ddp(struct cxgbi_device *cdev, log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p.\n", - csk, csk->state, csk->flags, skb, status, csk->skb_ulp_lhdr); + csk, csk->state, csk->flags, skb, ddpvld, csk->skb_ulp_lhdr); spin_lock_bh(&csk->lock); @@ -1279,29 +1374,8 @@ static void do_rx_data_ddp(struct cxgbi_device *cdev, pr_info("tid 0x%x, RX_DATA_DDP pdulen %u != %u.\n", csk->tid, ntohs(rpl->len), cxgbi_skcb_rx_pdulen(lskb)); - if (status & (1 << CPL_RX_DDP_STATUS_HCRC_SHIFT)) { - pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, hcrc bad 0x%lx.\n", - csk, lskb, status, cxgbi_skcb_flags(lskb)); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_HCRC_ERR); - } - if (status & (1 << CPL_RX_DDP_STATUS_DCRC_SHIFT)) { - pr_info("csk 0x%p, lhdr 0x%p, status 0x%x, dcrc bad 0x%lx.\n", - csk, lskb, status, cxgbi_skcb_flags(lskb)); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_DCRC_ERR); - } - if (status & (1 << CPL_RX_DDP_STATUS_PAD_SHIFT)) { - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, lhdr 0x%p, status 0x%x, pad bad.\n", - csk, lskb, status); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_PAD_ERR); - } - if ((status & (1 << CPL_RX_DDP_STATUS_DDP_SHIFT)) && - !cxgbi_skcb_test_flag(lskb, SKCBF_RX_DATA)) { - log_debug(1 << CXGBI_DBG_PDU_RX, - "csk 0x%p, lhdr 0x%p, 0x%x, data ddp'ed.\n", - csk, lskb, status); - cxgbi_skcb_set_flag(lskb, SKCBF_RX_DATA_DDPD); - } + cxgb4i_process_ddpvld(csk, lskb, ddpvld); + log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, lskb 0x%p, f 0x%lx.\n", csk, lskb, cxgbi_skcb_flags(lskb)); @@ -1319,6 +1393,98 @@ rel_skb: __kfree_skb(skb); } +static void +do_rx_iscsi_cmp(struct cxgbi_device *cdev, struct sk_buff *skb) +{ + struct cxgbi_sock *csk; + struct cpl_rx_iscsi_cmp *rpl = (struct cpl_rx_iscsi_cmp *)skb->data; + struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); + struct tid_info *t = lldi->tids; + struct sk_buff *data_skb = NULL; + u32 tid = GET_TID(rpl); + u32 ddpvld = be32_to_cpu(rpl->ddpvld); + u32 seq = be32_to_cpu(rpl->seq); + u16 pdu_len_ddp = be16_to_cpu(rpl->pdu_len_ddp); + + csk = lookup_tid(t, tid); + if (unlikely(!csk)) { + pr_err("can't find connection for tid %u.\n", tid); + goto rel_skb; + } + + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_PDU_RX, + "csk 0x%p,%u,0x%lx, skb 0x%p,0x%x, lhdr 0x%p, len %u, " + "pdu_len_ddp %u, status %u.\n", + csk, csk->state, csk->flags, skb, ddpvld, csk->skb_ulp_lhdr, + ntohs(rpl->len), pdu_len_ddp, rpl->status); + + spin_lock_bh(&csk->lock); + + if (unlikely(csk->state >= CTP_PASSIVE_CLOSE)) { + log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK, + "csk 0x%p,%u,0x%lx,%u, bad state.\n", + csk, csk->state, csk->flags, csk->tid); + + if (csk->state != CTP_ABORTING) + goto abort_conn; + else + goto discard; + } + + cxgbi_skcb_tcp_seq(skb) = seq; + cxgbi_skcb_flags(skb) = 0; + cxgbi_skcb_rx_pdulen(skb) = 0; + + skb_reset_transport_header(skb); + __skb_pull(skb, sizeof(*rpl)); + __pskb_trim(skb, be16_to_cpu(rpl->len)); + + csk->rcv_nxt = seq + pdu_len_ddp; + + if (csk->skb_ulp_lhdr) { + data_skb = skb_peek(&csk->receive_queue); + if (!data_skb || + !cxgbi_skcb_test_flag(data_skb, SKCBF_RX_DATA)) { + pr_err("Error! freelist data not found 0x%p, tid %u\n", + data_skb, tid); + + goto abort_conn; + } + __skb_unlink(data_skb, &csk->receive_queue); + + cxgbi_skcb_set_flag(skb, SKCBF_RX_DATA); + + __skb_queue_tail(&csk->receive_queue, skb); + __skb_queue_tail(&csk->receive_queue, data_skb); + } else { + __skb_queue_tail(&csk->receive_queue, skb); + } + + csk->skb_ulp_lhdr = NULL; + + cxgbi_skcb_set_flag(skb, SKCBF_RX_HDR); + cxgbi_skcb_set_flag(skb, SKCBF_RX_STATUS); + cxgbi_skcb_set_flag(skb, SKCBF_RX_ISCSI_COMPL); + cxgbi_skcb_rx_ddigest(skb) = be32_to_cpu(rpl->ulp_crc); + + cxgb4i_process_ddpvld(csk, skb, ddpvld); + + log_debug(1 << CXGBI_DBG_PDU_RX, "csk 0x%p, skb 0x%p, f 0x%lx.\n", + csk, skb, cxgbi_skcb_flags(skb)); + + cxgbi_conn_pdu_ready(csk); + spin_unlock_bh(&csk->lock); + + return; + +abort_conn: + send_abort_req(csk); +discard: + spin_unlock_bh(&csk->lock); +rel_skb: + __kfree_skb(skb); +} + static void do_fw4_ack(struct cxgbi_device *cdev, struct sk_buff *skb) { struct cxgbi_sock *csk; @@ -1582,10 +1748,11 @@ static cxgb4i_cplhandler_func cxgb4i_cplhandlers[NUM_CPL_CMDS] = { [CPL_CLOSE_CON_RPL] = do_close_con_rpl, [CPL_FW4_ACK] = do_fw4_ack, [CPL_ISCSI_HDR] = do_rx_iscsi_hdr, - [CPL_ISCSI_DATA] = do_rx_iscsi_hdr, + [CPL_ISCSI_DATA] = do_rx_iscsi_data, [CPL_SET_TCB_RPL] = do_set_tcb_rpl, [CPL_RX_DATA_DDP] = do_rx_data_ddp, [CPL_RX_ISCSI_DDP] = do_rx_data_ddp, + [CPL_RX_ISCSI_CMP] = do_rx_iscsi_cmp, [CPL_RX_DATA] = do_rx_data, }; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 542337889224..eb4af124d5cd 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -1574,6 +1574,25 @@ static int skb_read_pdu_bhs(struct iscsi_conn *conn, struct sk_buff *skb) return -EIO; } + if (cxgbi_skcb_test_flag(skb, SKCBF_RX_ISCSI_COMPL) && + cxgbi_skcb_test_flag(skb, SKCBF_RX_DATA_DDPD)) { + /* If completion flag is set and data is directly + * placed in to the host memory then update + * task->exp_datasn to the datasn in completion + * iSCSI hdr as T6 adapter generates completion only + * for the last pdu of a sequence. + */ + itt_t itt = ((struct iscsi_data *)skb->data)->itt; + struct iscsi_task *task = iscsi_itt_to_ctask(conn, itt); + u32 data_sn = be32_to_cpu(((struct iscsi_data *) + skb->data)->datasn); + if (task && task->sc) { + struct iscsi_tcp_task *tcp_task = task->dd_data; + + tcp_task->exp_datasn = data_sn; + } + } + return read_pdu_skb(conn, skb, 0, 0); } diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index e7802738f5d2..85bae613d860 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -207,6 +207,7 @@ enum cxgbi_skcb_flags { SKCBF_RX_HDR, /* received pdu header */ SKCBF_RX_DATA, /* received pdu payload */ SKCBF_RX_STATUS, /* received ddp status */ + SKCBF_RX_ISCSI_COMPL, /* received iscsi completion */ SKCBF_RX_DATA_DDPD, /* pdu payload ddp'd */ SKCBF_RX_HCRC_ERR, /* header digest error */ SKCBF_RX_DCRC_ERR, /* data digest error */ -- cgit v1.2.3 From 1fe1fdb04b92f54b58eb8b71d2f28cf73fd9801c Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Wed, 7 Dec 2016 21:06:45 +0530 Subject: scsi: cxgb4i: libcxgbi: add missing module_put() Add module_put() in cxgbi_sock_act_open_req_arp_failure() to release module reference in case of arp failure, also check return value of try_module_get() before posting active open hw cmd. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 11 ++++++++--- drivers/scsi/cxgbi/libcxgbi.c | 3 +++ drivers/scsi/cxgbi/libcxgbi.h | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index 57401b58efce..9a2fdc305cf2 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -801,7 +801,7 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb) (&csk->saddr), (&csk->daddr), atid, tid, csk, csk->state, csk->flags, rcv_isn); - module_put(THIS_MODULE); + module_put(cdev->owner); cxgbi_sock_get(csk); csk->tid = tid; @@ -950,7 +950,7 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb) if (is_neg_adv(status)) goto rel_skb; - module_put(THIS_MODULE); + module_put(cdev->owner); if (status && status != CPL_ERR_TCAM_FULL && status != CPL_ERR_CONN_EXIST && @@ -1713,7 +1713,11 @@ static int init_act_open(struct cxgbi_sock *csk) csk->mtu, csk->mss_idx, csk->smac_idx); /* must wait for either a act_open_rpl or act_open_establish */ - try_module_get(THIS_MODULE); + if (!try_module_get(cdev->owner)) { + pr_err("%s, try_module_get failed.\n", ndev->name); + goto rel_resource; + } + cxgbi_sock_set_state(csk, CTP_ACTIVE_OPEN); if (csk->csk_family == AF_INET) send_act_open_req(csk, skb, csk->l2t); @@ -2027,6 +2031,7 @@ static void *t4_uld_add(const struct cxgb4_lld_info *lldi) cdev->skb_tx_rsvd = CXGB4I_TX_HEADER_LEN; cdev->skb_rx_extra = sizeof(struct cpl_iscsi_hdr); cdev->itp = &cxgb4i_iscsi_transport; + cdev->owner = THIS_MODULE; cdev->pfvf = FW_VIID_PFN_G(cxgb4_port_viid(lldi->ports[0])) << FW_VIID_PFN_S; diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index eb4af124d5cd..9f4fde9b12e3 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -896,6 +896,7 @@ EXPORT_SYMBOL_GPL(cxgbi_sock_fail_act_open); void cxgbi_sock_act_open_req_arp_failure(void *handle, struct sk_buff *skb) { struct cxgbi_sock *csk = (struct cxgbi_sock *)skb->sk; + struct module *owner = csk->cdev->owner; log_debug(1 << CXGBI_DBG_SOCK, "csk 0x%p,%u,0x%lx,%u.\n", csk, (csk)->state, (csk)->flags, (csk)->tid); @@ -906,6 +907,8 @@ void cxgbi_sock_act_open_req_arp_failure(void *handle, struct sk_buff *skb) spin_unlock_bh(&csk->lock); cxgbi_sock_put(csk); __kfree_skb(skb); + + module_put(owner); } EXPORT_SYMBOL_GPL(cxgbi_sock_act_open_req_arp_failure); diff --git a/drivers/scsi/cxgbi/libcxgbi.h b/drivers/scsi/cxgbi/libcxgbi.h index 85bae613d860..95ba99044c3e 100644 --- a/drivers/scsi/cxgbi/libcxgbi.h +++ b/drivers/scsi/cxgbi/libcxgbi.h @@ -468,6 +468,7 @@ struct cxgbi_device { struct pci_dev *pdev; struct dentry *debugfs_root; struct iscsi_transport *itp; + struct module *owner; unsigned int pfvf; unsigned int rx_credit_thres; -- cgit v1.2.3 From 165ae50e450bc7de6c741bf2c27ed0920a40a9af Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Fri, 9 Dec 2016 14:40:07 +0530 Subject: scsi: libcxgbi: return error if interface is not up Do not post hw active open cmd if IFF_UP is not set or link is down on the interface, return -ENETDOWN in this case. Signed-off-by: Varun Prakash Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/libcxgbi.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 9f4fde9b12e3..9167bcd9fffe 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -642,6 +642,12 @@ static struct cxgbi_sock *cxgbi_check_route(struct sockaddr *dst_addr) n->dev->name, ndev->name, mtu); } + if (!(ndev->flags & IFF_UP) || !netif_carrier_ok(ndev)) { + pr_info("%s interface not up.\n", ndev->name); + err = -ENETDOWN; + goto rel_neigh; + } + cdev = cxgbi_device_find_by_netdev(ndev, &port); if (!cdev) { pr_info("dst %pI4, %s, NOT cxgbi device.\n", @@ -736,6 +742,12 @@ static struct cxgbi_sock *cxgbi_check_route6(struct sockaddr *dst_addr) } ndev = n->dev; + if (!(ndev->flags & IFF_UP) || !netif_carrier_ok(ndev)) { + pr_info("%s interface not up.\n", ndev->name); + err = -ENETDOWN; + goto rel_rt; + } + if (ipv6_addr_is_multicast(&daddr6->sin6_addr)) { pr_info("multi-cast route %pI6 port %u, dev %s.\n", daddr6->sin6_addr.s6_addr, -- cgit v1.2.3 From dac37e15b7d511e026a9313c8c46794c144103cd Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 9 Dec 2016 17:16:31 +0100 Subject: scsi: zfcp: fix use-after-"free" in FC ingress path after TMF When SCSI EH invokes zFCP's callbacks for eh_device_reset_handler() and eh_target_reset_handler(), it expects us to relent the ownership over the given scsi_cmnd and all other scsi_cmnds within the same scope - LUN or target - when returning with SUCCESS from the callback ('release' them). SCSI EH can then reuse those commands. We did not follow this rule to release commands upon SUCCESS; and if later a reply arrived for one of those supposed to be released commands, we would still make use of the scsi_cmnd in our ingress tasklet. This will at least result in undefined behavior or a kernel panic because of a wrong kernel pointer dereference. To fix this, we NULLify all pointers to scsi_cmnds (struct zfcp_fsf_req *)->data in the matching scope if a TMF was successful. This is done under the locks (struct zfcp_adapter *)->abort_lock and (struct zfcp_reqlist *)->lock to prevent the requests from being removed from the request-hashtable, and the ingress tasklet from making use of the scsi_cmnd-pointer in zfcp_fsf_fcp_cmnd_handler(). For cases where a reply arrives during SCSI EH, but before we get a chance to NULLify the pointer - but before we return from the callback -, we assume that the code is protected from races via the CAS operation in blk_complete_request() that is called in scsi_done(). The following stacktrace shows an example for a crash resulting from the previous behavior: Unable to handle kernel pointer dereference at virtual kernel address fffffee17a672000 Oops: 0038 [#1] SMP CPU: 2 PID: 0 Comm: swapper/2 Not tainted task: 00000003f7ff5be0 ti: 00000003f3d38000 task.ti: 00000003f3d38000 Krnl PSW : 0404d00180000000 00000000001156b0 (smp_vcpu_scheduled+0x18/0x40) R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:3 CC:1 PM:0 EA:3 Krnl GPRS: 000000200000007e 0000000000000000 fffffee17a671fd8 0000000300000015 ffffffff80000000 00000000005dfde8 07000003f7f80e00 000000004fa4e800 000000036ce8d8f8 000000036ce8d9c0 00000003ece8fe00 ffffffff969c9e93 00000003fffffffd 000000036ce8da10 00000000003bf134 00000003f3b07918 Krnl Code: 00000000001156a2: a7190000 lghi %r1,0 00000000001156a6: a7380015 lhi %r3,21 #00000000001156aa: e32050000008 ag %r2,0(%r5) >00000000001156b0: 482022b0 lh %r2,688(%r2) 00000000001156b4: ae123000 sigp %r1,%r2,0(%r3) 00000000001156b8: b2220020 ipm %r2 00000000001156bc: 8820001c srl %r2,28 00000000001156c0: c02700000001 xilf %r2,1 Call Trace: ([<0000000000000000>] 0x0) [<000003ff807bdb8e>] zfcp_fsf_fcp_cmnd_handler+0x3de/0x490 [zfcp] [<000003ff807be30a>] zfcp_fsf_req_complete+0x252/0x800 [zfcp] [<000003ff807c0a48>] zfcp_fsf_reqid_check+0xe8/0x190 [zfcp] [<000003ff807c194e>] zfcp_qdio_int_resp+0x66/0x188 [zfcp] [<000003ff80440c64>] qdio_kick_handler+0xdc/0x310 [qdio] [<000003ff804463d0>] __tiqdio_inbound_processing+0xf8/0xcd8 [qdio] [<0000000000141fd4>] tasklet_action+0x9c/0x170 [<0000000000141550>] __do_softirq+0xe8/0x258 [<000000000010ce0a>] do_softirq+0xba/0xc0 [<000000000014187c>] irq_exit+0xc4/0xe8 [<000000000046b526>] do_IRQ+0x146/0x1d8 [<00000000005d6a3c>] io_return+0x0/0x8 [<00000000005d6422>] vtime_stop_cpu+0x4a/0xa0 ([<0000000000000000>] 0x0) [<0000000000103d8a>] arch_cpu_idle+0xa2/0xb0 [<0000000000197f94>] cpu_startup_entry+0x13c/0x1f8 [<0000000000114782>] smp_start_secondary+0xda/0xe8 [<00000000005d6efe>] restart_int_handler+0x56/0x6c [<0000000000000000>] 0x0 Last Breaking-Event-Address: [<00000000003bf12e>] arch_spin_lock_wait+0x56/0xb0 Suggested-by: Steffen Maier Signed-off-by: Benjamin Block Fixes: ea127f9754 ("[PATCH] s390 (7/7): zfcp host adapter.") (tglx/history.git) Cc: #2.6.32+ Signed-off-by: Steffen Maier Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_dbf.h | 11 ++++++++ drivers/s390/scsi/zfcp_reqlist.h | 30 ++++++++++++++++++++- drivers/s390/scsi/zfcp_scsi.c | 57 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 95 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 36d07584271d..2d06b5d2c05b 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -388,4 +388,15 @@ void zfcp_dbf_scsi_devreset(char *tag, struct scsi_cmnd *scmnd, u8 flag) _zfcp_dbf_scsi(tmp_tag, 1, scmnd, NULL); } +/** + * zfcp_dbf_scsi_nullcmnd() - trace NULLify of SCSI command in dev/tgt-reset. + * @scmnd: SCSI command that was NULLified. + * @fsf_req: request that owned @scmnd. + */ +static inline void zfcp_dbf_scsi_nullcmnd(struct scsi_cmnd *scmnd, + struct zfcp_fsf_req *fsf_req) +{ + _zfcp_dbf_scsi("scfc__1", 3, scmnd, fsf_req); +} + #endif /* ZFCP_DBF_H */ diff --git a/drivers/s390/scsi/zfcp_reqlist.h b/drivers/s390/scsi/zfcp_reqlist.h index 7c2c6194dfca..703fce59befe 100644 --- a/drivers/s390/scsi/zfcp_reqlist.h +++ b/drivers/s390/scsi/zfcp_reqlist.h @@ -4,7 +4,7 @@ * Data structure and helper functions for tracking pending FSF * requests. * - * Copyright IBM Corp. 2009 + * Copyright IBM Corp. 2009, 2016 */ #ifndef ZFCP_REQLIST_H @@ -180,4 +180,32 @@ static inline void zfcp_reqlist_move(struct zfcp_reqlist *rl, spin_unlock_irqrestore(&rl->lock, flags); } +/** + * zfcp_reqlist_apply_for_all() - apply a function to every request. + * @rl: the requestlist that contains the target requests. + * @f: the function to apply to each request; the first parameter of the + * function will be the target-request; the second parameter is the same + * pointer as given with the argument @data. + * @data: freely chosen argument; passed through to @f as second parameter. + * + * Uses :c:macro:`list_for_each_entry` to iterate over the lists in the hash- + * table (not a 'safe' variant, so don't modify the list). + * + * Holds @rl->lock over the entire request-iteration. + */ +static inline void +zfcp_reqlist_apply_for_all(struct zfcp_reqlist *rl, + void (*f)(struct zfcp_fsf_req *, void *), void *data) +{ + struct zfcp_fsf_req *req; + unsigned long flags; + unsigned int i; + + spin_lock_irqsave(&rl->lock, flags); + for (i = 0; i < ZFCP_REQ_LIST_BUCKETS; i++) + list_for_each_entry(req, &rl->buckets[i], list) + f(req, data); + spin_unlock_irqrestore(&rl->lock, flags); +} + #endif /* ZFCP_REQLIST_H */ diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 9069f98a1817..11cd18c134c1 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -3,7 +3,7 @@ * * Interface to Linux SCSI midlayer. * - * Copyright IBM Corp. 2002, 2015 + * Copyright IBM Corp. 2002, 2016 */ #define KMSG_COMPONENT "zfcp" @@ -209,6 +209,57 @@ static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt) return retval; } +struct zfcp_scsi_req_filter { + u8 tmf_scope; + u32 lun_handle; + u32 port_handle; +}; + +static void zfcp_scsi_forget_cmnd(struct zfcp_fsf_req *old_req, void *data) +{ + struct zfcp_scsi_req_filter *filter = + (struct zfcp_scsi_req_filter *)data; + + /* already aborted - prevent side-effects - or not a SCSI command */ + if (old_req->data == NULL || old_req->fsf_command != FSF_QTCB_FCP_CMND) + return; + + /* (tmf_scope == FCP_TMF_TGT_RESET || tmf_scope == FCP_TMF_LUN_RESET) */ + if (old_req->qtcb->header.port_handle != filter->port_handle) + return; + + if (filter->tmf_scope == FCP_TMF_LUN_RESET && + old_req->qtcb->header.lun_handle != filter->lun_handle) + return; + + zfcp_dbf_scsi_nullcmnd((struct scsi_cmnd *)old_req->data, old_req); + old_req->data = NULL; +} + +static void zfcp_scsi_forget_cmnds(struct zfcp_scsi_dev *zsdev, u8 tm_flags) +{ + struct zfcp_adapter *adapter = zsdev->port->adapter; + struct zfcp_scsi_req_filter filter = { + .tmf_scope = FCP_TMF_TGT_RESET, + .port_handle = zsdev->port->handle, + }; + unsigned long flags; + + if (tm_flags == FCP_TMF_LUN_RESET) { + filter.tmf_scope = FCP_TMF_LUN_RESET; + filter.lun_handle = zsdev->lun_handle; + } + + /* + * abort_lock secures against other processings - in the abort-function + * and normal cmnd-handler - of (struct zfcp_fsf_req *)->data + */ + write_lock_irqsave(&adapter->abort_lock, flags); + zfcp_reqlist_apply_for_all(adapter->req_list, zfcp_scsi_forget_cmnd, + &filter); + write_unlock_irqrestore(&adapter->abort_lock, flags); +} + static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) { struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(scpnt->device); @@ -241,8 +292,10 @@ static int zfcp_task_mgmt_function(struct scsi_cmnd *scpnt, u8 tm_flags) if (fsf_req->status & ZFCP_STATUS_FSFREQ_TMFUNCFAILED) { zfcp_dbf_scsi_devreset("fail", scpnt, tm_flags); retval = FAILED; - } else + } else { zfcp_dbf_scsi_devreset("okay", scpnt, tm_flags); + zfcp_scsi_forget_cmnds(zfcp_sdev, tm_flags); + } zfcp_fsf_req_free(fsf_req); return retval; -- cgit v1.2.3 From 56d23ed7adf3974f10e91b643bd230e9c65b5f79 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Fri, 9 Dec 2016 17:16:32 +0100 Subject: scsi: zfcp: do not trace pure benign residual HBA responses at default level Since quite a while, Linux issues enough SCSI commands per scsi_device which successfully return with FCP_RESID_UNDER, FSF_FCP_RSP_AVAILABLE, and SAM_STAT_GOOD. This floods the HBA trace area and we cannot see other and important HBA trace records long enough. Therefore, do not trace HBA response errors for pure benign residual under counts at the default trace level. This excludes benign residual under count combined with other validity bits set in FCP_RSP_IU, such as FCP_SNS_LEN_VAL. For all those other cases, we still do want to see both the HBA record and the corresponding SCSI record by default. Signed-off-by: Steffen Maier Fixes: a54ca0f62f95 ("[SCSI] zfcp: Redesign of the debug tracing for HBA records.") Cc: #2.6.37+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_dbf.h | 30 ++++++++++++++++++++++++++++-- drivers/s390/scsi/zfcp_fsf.h | 3 ++- 2 files changed, 30 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_dbf.h b/drivers/s390/scsi/zfcp_dbf.h index 2d06b5d2c05b..db186d44cfaf 100644 --- a/drivers/s390/scsi/zfcp_dbf.h +++ b/drivers/s390/scsi/zfcp_dbf.h @@ -2,7 +2,7 @@ * zfcp device driver * debug feature declarations * - * Copyright IBM Corp. 2008, 2015 + * Copyright IBM Corp. 2008, 2016 */ #ifndef ZFCP_DBF_H @@ -283,6 +283,30 @@ struct zfcp_dbf { struct zfcp_dbf_scsi scsi_buf; }; +/** + * zfcp_dbf_hba_fsf_resp_suppress - true if we should not trace by default + * @req: request that has been completed + * + * Returns true if FCP response with only benign residual under count. + */ +static inline +bool zfcp_dbf_hba_fsf_resp_suppress(struct zfcp_fsf_req *req) +{ + struct fsf_qtcb *qtcb = req->qtcb; + u32 fsf_stat = qtcb->header.fsf_status; + struct fcp_resp *fcp_rsp; + u8 rsp_flags, fr_status; + + if (qtcb->prefix.qtcb_type != FSF_IO_COMMAND) + return false; /* not an FCP response */ + fcp_rsp = (struct fcp_resp *)&qtcb->bottom.io.fcp_rsp; + rsp_flags = fcp_rsp->fr_flags; + fr_status = fcp_rsp->fr_status; + return (fsf_stat == FSF_FCP_RSP_AVAILABLE) && + (rsp_flags == FCP_RESID_UNDER) && + (fr_status == SAM_STAT_GOOD); +} + static inline void zfcp_dbf_hba_fsf_resp(char *tag, int level, struct zfcp_fsf_req *req) { @@ -304,7 +328,9 @@ void zfcp_dbf_hba_fsf_response(struct zfcp_fsf_req *req) zfcp_dbf_hba_fsf_resp("fs_perr", 1, req); } else if (qtcb->header.fsf_status != FSF_GOOD) { - zfcp_dbf_hba_fsf_resp("fs_ferr", 1, req); + zfcp_dbf_hba_fsf_resp("fs_ferr", + zfcp_dbf_hba_fsf_resp_suppress(req) + ? 5 : 1, req); } else if ((req->fsf_command == FSF_QTCB_OPEN_PORT_WITH_DID) || (req->fsf_command == FSF_QTCB_OPEN_LUN)) { diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index be1c04b334c5..ea3c76ac0de1 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -3,7 +3,7 @@ * * Interface to the FSF support functions. * - * Copyright IBM Corp. 2002, 2015 + * Copyright IBM Corp. 2002, 2016 */ #ifndef FSF_H @@ -78,6 +78,7 @@ #define FSF_APP_TAG_CHECK_FAILURE 0x00000082 #define FSF_REF_TAG_CHECK_FAILURE 0x00000083 #define FSF_ADAPTER_STATUS_AVAILABLE 0x000000AD +#define FSF_FCP_RSP_AVAILABLE 0x000000AF #define FSF_UNKNOWN_COMMAND 0x000000E2 #define FSF_UNKNOWN_OP_SUBTYPE 0x000000E3 #define FSF_INVALID_COMMAND_OPTION 0x000000E5 -- cgit v1.2.3 From 6f2ce1c6af37191640ee3ff6e8fc39ea10352f4c Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Fri, 9 Dec 2016 17:16:33 +0100 Subject: scsi: zfcp: fix rport unblock race with LUN recovery It is unavoidable that zfcp_scsi_queuecommand() has to finish requests with DID_IMM_RETRY (like fc_remote_port_chkready()) during the time window when zfcp detected an unavailable rport but fc_remote_port_delete(), which is asynchronous via zfcp_scsi_schedule_rport_block(), has not yet blocked the rport. However, for the case when the rport becomes available again, we should prevent unblocking the rport too early. In contrast to other FCP LLDDs, zfcp has to open each LUN with the FCP channel hardware before it can send I/O to a LUN. So if a port already has LUNs attached and we unblock the rport just after port recovery, recoveries of LUNs behind this port can still be pending which in turn force zfcp_scsi_queuecommand() to unnecessarily finish requests with DID_IMM_RETRY. This also opens a time window with unblocked rport (until the followup LUN reopen recovery has finished). If a scsi_cmnd timeout occurs during this time window fc_timed_out() cannot work as desired and such command would indeed time out and trigger scsi_eh. This prevents a clean and timely path failover. This should not happen if the path issue can be recovered on FC transport layer such as path issues involving RSCNs. Fix this by only calling zfcp_scsi_schedule_rport_register(), to asynchronously trigger fc_remote_port_add(), after all LUN recoveries as children of the rport have finished and no new recoveries of equal or higher order were triggered meanwhile. Finished intentionally includes any recovery result no matter if successful or failed (still unblock rport so other successful LUNs work). For simplicity, we check after each finished LUN recovery if there is another LUN recovery pending on the same port and then do nothing. We handle the special case of a successful recovery of a port without LUN children the same way without changing this case's semantics. For debugging we introduce 2 new trace records written if the rport unblock attempt was aborted due to still unfinished or freshly triggered recovery. The records are only written above the default trace level. Benjamin noticed the important special case of new recovery that can be triggered between having given up the erp_lock and before calling zfcp_erp_action_cleanup() within zfcp_erp_strategy(). We must avoid the following sequence: ERP thread rport_work other context ------------------------- -------------- -------------------------------- port is unblocked, rport still blocked, due to pending/running ERP action, so ((port->status & ...UNBLOCK) != 0) and (port->rport == NULL) unlock ERP zfcp_erp_action_cleanup() case ZFCP_ERP_ACTION_REOPEN_LUN: zfcp_erp_try_rport_unblock() ((status & ...UNBLOCK) != 0) [OLD!] zfcp_erp_port_reopen() lock ERP zfcp_erp_port_block() port->status clear ...UNBLOCK unlock ERP zfcp_scsi_schedule_rport_block() port->rport_task = RPORT_DEL queue_work(rport_work) zfcp_scsi_rport_work() (port->rport_task != RPORT_ADD) port->rport_task = RPORT_NONE zfcp_scsi_rport_block() if (!port->rport) return zfcp_scsi_schedule_rport_register() port->rport_task = RPORT_ADD queue_work(rport_work) zfcp_scsi_rport_work() (port->rport_task == RPORT_ADD) port->rport_task = RPORT_NONE zfcp_scsi_rport_register() (port->rport == NULL) rport = fc_remote_port_add() port->rport = rport; Now the rport was erroneously unblocked while the zfcp_port is blocked. This is another situation we want to avoid due to scsi_eh potential. This state would at least remain until the new recovery from the other context finished successfully, or potentially forever if it failed. In order to close this race, we take the erp_lock inside zfcp_erp_try_rport_unblock() when checking the status of zfcp_port or LUN. With that, the possible corresponding rport state sequences would be: (unblock[ERP thread],block[other context]) if the ERP thread gets erp_lock first and still sees ((port->status & ...UNBLOCK) != 0), (block[other context],NOP[ERP thread]) if the ERP thread gets erp_lock after the other context has already cleard ...UNBLOCK from port->status. Since checking fields of struct erp_action is unsafe because they could have been overwritten (re-used for new recovery) meanwhile, we only check status of zfcp_port and LUN since these are only changed under erp_lock elsewhere. Regarding the check of the proper status flags (port or port_forced are similar to the shown adapter recovery): [zfcp_erp_adapter_shutdown()] zfcp_erp_adapter_reopen() zfcp_erp_adapter_block() * clear UNBLOCK ---------------------------------------+ zfcp_scsi_schedule_rports_block() | write_lock_irqsave(&adapter->erp_lock, flags);-------+ | zfcp_erp_action_enqueue() | | zfcp_erp_setup_act() | | * set ERP_INUSE -----------------------------------|--|--+ write_unlock_irqrestore(&adapter->erp_lock, flags);--+ | | .context-switch. | | zfcp_erp_thread() | | zfcp_erp_strategy() | | write_lock_irqsave(&adapter->erp_lock, flags);------+ | | ... | | | zfcp_erp_strategy_check_target() | | | zfcp_erp_strategy_check_adapter() | | | zfcp_erp_adapter_unblock() | | | * set UNBLOCK -----------------------------------|--+ | zfcp_erp_action_dequeue() | | * clear ERP_INUSE ---------------------------------|-----+ ... | write_unlock_irqrestore(&adapter->erp_lock, flags);-+ Hence, we should check for both UNBLOCK and ERP_INUSE because they are interleaved. Also we need to explicitly check ERP_FAILED for the link down case which currently does not clear the UNBLOCK flag in zfcp_fsf_link_down_info_eval(). Signed-off-by: Steffen Maier Fixes: 8830271c4819 ("[SCSI] zfcp: Dont fail SCSI commands when transitioning to blocked fc_rport") Fixes: a2fa0aede07c ("[SCSI] zfcp: Block FC transport rports early on errors") Fixes: 5f852be9e11d ("[SCSI] zfcp: Fix deadlock between zfcp ERP and SCSI") Fixes: 338151e06608 ("[SCSI] zfcp: make use of fc_remote_port_delete when target port is unavailable") Fixes: 3859f6a248cb ("[PATCH] zfcp: add rports to enable scsi_add_device to work again") Cc: #2.6.32+ Reviewed-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_dbf.c | 17 +++++++++--- drivers/s390/scsi/zfcp_erp.c | 61 +++++++++++++++++++++++++++++++++++++++++-- drivers/s390/scsi/zfcp_ext.h | 4 ++- drivers/s390/scsi/zfcp_scsi.c | 4 +-- 4 files changed, 77 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index 581001989937..d5bf36ec8a75 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -289,11 +289,12 @@ void zfcp_dbf_rec_trig(char *tag, struct zfcp_adapter *adapter, /** - * zfcp_dbf_rec_run - trace event related to running recovery + * zfcp_dbf_rec_run_lvl - trace event related to running recovery + * @level: trace level to be used for event * @tag: identifier for event * @erp: erp_action running */ -void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp) +void zfcp_dbf_rec_run_lvl(int level, char *tag, struct zfcp_erp_action *erp) { struct zfcp_dbf *dbf = erp->adapter->dbf; struct zfcp_dbf_rec *rec = &dbf->rec_buf; @@ -319,10 +320,20 @@ void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp) else rec->u.run.rec_count = atomic_read(&erp->adapter->erp_counter); - debug_event(dbf->rec, 1, rec, sizeof(*rec)); + debug_event(dbf->rec, level, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->rec_lock, flags); } +/** + * zfcp_dbf_rec_run - trace event related to running recovery + * @tag: identifier for event + * @erp: erp_action running + */ +void zfcp_dbf_rec_run(char *tag, struct zfcp_erp_action *erp) +{ + zfcp_dbf_rec_run_lvl(1, tag, erp); +} + /** * zfcp_dbf_rec_run_wka - trace wka port event with info like running recovery * @tag: identifier for event diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index a59d678125bd..7ccfce559034 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -3,7 +3,7 @@ * * Error Recovery Procedures (ERP). * - * Copyright IBM Corp. 2002, 2015 + * Copyright IBM Corp. 2002, 2016 */ #define KMSG_COMPONENT "zfcp" @@ -1204,6 +1204,62 @@ static void zfcp_erp_action_dequeue(struct zfcp_erp_action *erp_action) } } +/** + * zfcp_erp_try_rport_unblock - unblock rport if no more/new recovery + * @port: zfcp_port whose fc_rport we should try to unblock + */ +static void zfcp_erp_try_rport_unblock(struct zfcp_port *port) +{ + unsigned long flags; + struct zfcp_adapter *adapter = port->adapter; + int port_status; + struct Scsi_Host *shost = adapter->scsi_host; + struct scsi_device *sdev; + + write_lock_irqsave(&adapter->erp_lock, flags); + port_status = atomic_read(&port->status); + if ((port_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 || + (port_status & (ZFCP_STATUS_COMMON_ERP_INUSE | + ZFCP_STATUS_COMMON_ERP_FAILED)) != 0) { + /* new ERP of severity >= port triggered elsewhere meanwhile or + * local link down (adapter erp_failed but not clear unblock) + */ + zfcp_dbf_rec_run_lvl(4, "ertru_p", &port->erp_action); + write_unlock_irqrestore(&adapter->erp_lock, flags); + return; + } + spin_lock(shost->host_lock); + __shost_for_each_device(sdev, shost) { + struct zfcp_scsi_dev *zsdev = sdev_to_zfcp(sdev); + int lun_status; + + if (zsdev->port != port) + continue; + /* LUN under port of interest */ + lun_status = atomic_read(&zsdev->status); + if ((lun_status & ZFCP_STATUS_COMMON_ERP_FAILED) != 0) + continue; /* unblock rport despite failed LUNs */ + /* LUN recovery not given up yet [maybe follow-up pending] */ + if ((lun_status & ZFCP_STATUS_COMMON_UNBLOCKED) == 0 || + (lun_status & ZFCP_STATUS_COMMON_ERP_INUSE) != 0) { + /* LUN blocked: + * not yet unblocked [LUN recovery pending] + * or meanwhile blocked [new LUN recovery triggered] + */ + zfcp_dbf_rec_run_lvl(4, "ertru_l", &zsdev->erp_action); + spin_unlock(shost->host_lock); + write_unlock_irqrestore(&adapter->erp_lock, flags); + return; + } + } + /* now port has no child or all children have completed recovery, + * and no ERP of severity >= port was meanwhile triggered elsewhere + */ + zfcp_scsi_schedule_rport_register(port); + spin_unlock(shost->host_lock); + write_unlock_irqrestore(&adapter->erp_lock, flags); +} + static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) { struct zfcp_adapter *adapter = act->adapter; @@ -1214,6 +1270,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) case ZFCP_ERP_ACTION_REOPEN_LUN: if (!(act->status & ZFCP_STATUS_ERP_NO_REF)) scsi_device_put(sdev); + zfcp_erp_try_rport_unblock(port); break; case ZFCP_ERP_ACTION_REOPEN_PORT: @@ -1224,7 +1281,7 @@ static void zfcp_erp_action_cleanup(struct zfcp_erp_action *act, int result) */ if (act->step != ZFCP_ERP_STEP_UNINITIALIZED) if (result == ZFCP_ERP_SUCCEEDED) - zfcp_scsi_schedule_rport_register(port); + zfcp_erp_try_rport_unblock(port); /* fall through */ case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: put_device(&port->dev); diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 968a0ab4b398..9afdbc32b23f 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -3,7 +3,7 @@ * * External function declarations. * - * Copyright IBM Corp. 2002, 2015 + * Copyright IBM Corp. 2002, 2016 */ #ifndef ZFCP_EXT_H @@ -35,6 +35,8 @@ extern void zfcp_dbf_adapter_unregister(struct zfcp_adapter *); extern void zfcp_dbf_rec_trig(char *, struct zfcp_adapter *, struct zfcp_port *, struct scsi_device *, u8, u8); extern void zfcp_dbf_rec_run(char *, struct zfcp_erp_action *); +extern void zfcp_dbf_rec_run_lvl(int level, char *tag, + struct zfcp_erp_action *erp); extern void zfcp_dbf_rec_run_wka(char *, struct zfcp_fc_wka_port *, u64); extern void zfcp_dbf_hba_fsf_uss(char *, struct zfcp_fsf_req *); extern void zfcp_dbf_hba_fsf_res(char *, int, struct zfcp_fsf_req *); diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index 11cd18c134c1..07ffdbb5107f 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -88,9 +88,7 @@ int zfcp_scsi_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scpnt) } if (unlikely(!(status & ZFCP_STATUS_COMMON_UNBLOCKED))) { - /* This could be either - * open LUN pending: this is temporary, will result in - * open LUN or ERP_FAILED, so retry command + /* This could be * call to rport_delete pending: mimic retry from * fc_remote_port_chkready until rport is BLOCKED */ -- cgit v1.2.3 From 2c9bce5b49713acba3e90ce994d60996adcd4b30 Mon Sep 17 00:00:00 2001 From: adam radford Date: Fri, 9 Dec 2016 11:08:05 -0800 Subject: scsi: Update 3ware driver email addresses This change updates the 3ware drivers (3w-xxxx, 3w-9xxx, 3w-sas) email addresses from linuxraid@lsi.com to aradford@gmail.com, since the old email address doesn't exist. This patch was updated to remove www.lsi.com text. [mkp: applied by hand] Signed-off-by: Adam Radford Acked-by: Sumit Saxena Signed-off-by: Martin K. Petersen --- MAINTAINERS | 2 +- drivers/scsi/3w-9xxx.c | 9 +++------ drivers/scsi/3w-9xxx.h | 9 +++------ drivers/scsi/3w-sas.c | 7 ++----- drivers/scsi/3w-sas.h | 7 ++----- drivers/scsi/3w-xxxx.c | 7 +++---- drivers/scsi/3w-xxxx.h | 5 +++-- 7 files changed, 17 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index c117bcf51d34..830879cb65d1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -143,7 +143,7 @@ S: Maintained F: drivers/net/ethernet/3com/typhoon* 3WARE SAS/SATA-RAID SCSI DRIVERS (3W-XXXX, 3W-9XXX, 3W-SAS) -M: Adam Radford +M: Adam Radford L: linux-scsi@vger.kernel.org W: http://www.lsi.com S: Supported diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index a56a7b243e91..316f87fe3299 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -1,8 +1,8 @@ /* 3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux. - Written By: Adam Radford - Modifications By: Tom Couch + Written By: Adam Radford + Modifications By: Tom Couch Copyright (C) 2004-2009 Applied Micro Circuits Corporation. Copyright (C) 2010 LSI Corporation. @@ -41,10 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com + aradford@gmail.com Note: This version of the driver does not contain a bundled firmware image. diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h index 0fdc83cfa0e1..b6c208cc474f 100644 --- a/drivers/scsi/3w-9xxx.h +++ b/drivers/scsi/3w-9xxx.h @@ -1,8 +1,8 @@ /* 3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux. - Written By: Adam Radford - Modifications By: Tom Couch + Written By: Adam Radford + Modifications By: Tom Couch Copyright (C) 2004-2009 Applied Micro Circuits Corporation. Copyright (C) 2010 LSI Corporation. @@ -41,10 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com + aradford@gmail.com */ #ifndef _3W_9XXX_H diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index f8374850f714..970d8fa6bd53 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1,7 +1,7 @@ /* 3w-sas.c -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. - Written By: Adam Radford + Written By: Adam Radford Copyright (C) 2009 LSI Corporation. @@ -43,10 +43,7 @@ LSI 3ware 9750 6Gb/s SAS/SATA-RAID Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com + aradford@gmail.com History ------- diff --git a/drivers/scsi/3w-sas.h b/drivers/scsi/3w-sas.h index fec6449c7595..05e77d84c16d 100644 --- a/drivers/scsi/3w-sas.h +++ b/drivers/scsi/3w-sas.h @@ -1,7 +1,7 @@ /* 3w-sas.h -- LSI 3ware SAS/SATA-RAID Controller device driver for Linux. - Written By: Adam Radford + Written By: Adam Radford Copyright (C) 2009 LSI Corporation. @@ -39,10 +39,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - - For more information, goto: - http://www.lsi.com + aradford@gmail.com */ #ifndef _3W_SAS_H diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 25aba1613e21..aa412ab02765 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1,7 +1,7 @@ /* 3w-xxxx.c -- 3ware Storage Controller device driver for Linux. - Written By: Adam Radford + Written By: Adam Radford Modifications By: Joel Jacobson Arnaldo Carvalho de Melo Brad Strand @@ -47,10 +47,9 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com - For more information, goto: - http://www.lsi.com + aradford@gmail.com + History ------- diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 6f65e663d393..69e80c1ed1ca 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -1,7 +1,7 @@ /* 3w-xxxx.h -- 3ware Storage Controller device driver for Linux. - Written By: Adam Radford + Written By: Adam Radford Modifications By: Joel Jacobson Arnaldo Carvalho de Melo Brad Strand @@ -45,7 +45,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Bugs/Comments/Suggestions should be mailed to: - linuxraid@lsi.com + + aradford@gmail.com For more information, goto: http://www.lsi.com -- cgit v1.2.3 From 7e8a9486786d5ede1d2405fab140c6a0d8b2c1fe Mon Sep 17 00:00:00 2001 From: Amit Kushwaha Date: Mon, 12 Dec 2016 16:34:21 +0530 Subject: scsi: hpsa: remove memory allocate failure message This patch cleanup warning reported by checkpatch.pl WARNING: Possible unnecessary 'out of memory' message With no available memory, a warn on message already gets printed by page alloc apis and modified goto use if memory unallocated. Signed-off-by: Amit Kushwaha Acked-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/hpsa.c | 37 ++++++++++++------------------------- 1 file changed, 12 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 691a09316952..cbc0c5fe5a60 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -1557,10 +1557,9 @@ static void hpsa_monitor_offline_device(struct ctlr_info *h, /* Device is not on the list, add it. */ device = kmalloc(sizeof(*device), GFP_KERNEL); - if (!device) { - dev_warn(&h->pdev->dev, "out of memory in %s\n", __func__); + if (!device) return; - } + memcpy(device->scsi3addr, scsi3addr, sizeof(device->scsi3addr)); spin_lock_irqsave(&h->offline_device_lock, flags); list_add_tail(&device->offline_list, &h->offline_device_list); @@ -2142,17 +2141,15 @@ static int hpsa_alloc_sg_chain_blocks(struct ctlr_info *h) h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds, GFP_KERNEL); - if (!h->cmd_sg_list) { - dev_err(&h->pdev->dev, "Failed to allocate SG list\n"); + if (!h->cmd_sg_list) return -ENOMEM; - } + for (i = 0; i < h->nr_cmds; i++) { h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) * h->chainsize, GFP_KERNEL); - if (!h->cmd_sg_list[i]) { - dev_err(&h->pdev->dev, "Failed to allocate cmd SG\n"); + if (!h->cmd_sg_list[i]) goto clean; - } + } return 0; @@ -3454,11 +3451,8 @@ static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, struct bmic_sense_subsystem_info *ssi; ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); - if (ssi == NULL) { - dev_warn(&h->pdev->dev, - "%s: out of memory\n", __func__); + if (!ssi) return; - } rc = hpsa_bmic_sense_subsystem_information(h, scsi3addr, 0, ssi, sizeof(*ssi)); @@ -4335,8 +4329,6 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h) currentsd[i] = kzalloc(sizeof(*currentsd[i]), GFP_KERNEL); if (!currentsd[i]) { - dev_warn(&h->pdev->dev, "out of memory at %s:%d\n", - __FILE__, __LINE__); h->drv_req_rescan = 1; goto out; } @@ -8597,14 +8589,12 @@ static int hpsa_luns_changed(struct ctlr_info *h) */ if (!h->lastlogicals) - goto out; + return rc; logdev = kzalloc(sizeof(*logdev), GFP_KERNEL); - if (!logdev) { - dev_warn(&h->pdev->dev, - "Out of memory, can't track lun changes.\n"); - goto out; - } + if (!logdev) + return rc; + if (hpsa_scsi_do_report_luns(h, 1, logdev, sizeof(*logdev), 0)) { dev_warn(&h->pdev->dev, "report luns failed, can't track lun changes.\n"); @@ -8998,11 +8988,8 @@ static void hpsa_disable_rld_caching(struct ctlr_info *h) return; options = kzalloc(sizeof(*options), GFP_KERNEL); - if (!options) { - dev_err(&h->pdev->dev, - "Error: failed to disable rld caching, during alloc.\n"); + if (!options) return; - } c = cmd_alloc(h); -- cgit v1.2.3 From 77ddb94a4853204dc680121d59221b1be7c2297e Mon Sep 17 00:00:00 2001 From: "himanshu.madhani@cavium.com" Date: Mon, 12 Dec 2016 14:40:05 -0800 Subject: scsi: qla2xxx: Only allow operational MBX to proceed during RESET. This patch is allowing only ROM mailbox command which are necessary to initialize chip after a reset has been issued. In a target environment, there could be a user space daemon which can issue statistics and other management mailbox command which are non-critical. This patch will timeout non critical mailbox commands immediately rather than waiting for timeout, if driver detects that chip reset has been issued or chip reset is in progress. Reviewed-by: Hannes Reinecke Reviewed-by: Christoph Hellwig Signed-off-by: Himanshu Madhani Signed-off-by: Giridhar Malavali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_mbx.c | 52 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 23698c998699..b31c36b251a6 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -10,6 +10,43 @@ #include #include +struct rom_cmd { + uint16_t cmd; +} rom_cmds[] = { + { MBC_LOAD_RAM }, + { MBC_EXECUTE_FIRMWARE }, + { MBC_READ_RAM_WORD }, + { MBC_MAILBOX_REGISTER_TEST }, + { MBC_VERIFY_CHECKSUM }, + { MBC_GET_FIRMWARE_VERSION }, + { MBC_LOAD_RISC_RAM }, + { MBC_DUMP_RISC_RAM }, + { MBC_LOAD_RISC_RAM_EXTENDED }, + { MBC_DUMP_RISC_RAM_EXTENDED }, + { MBC_WRITE_RAM_WORD_EXTENDED }, + { MBC_READ_RAM_EXTENDED }, + { MBC_GET_RESOURCE_COUNTS }, + { MBC_SET_FIRMWARE_OPTION }, + { MBC_MID_INITIALIZE_FIRMWARE }, + { MBC_GET_FIRMWARE_STATE }, + { MBC_GET_MEM_OFFLOAD_CNTRL_STAT }, + { MBC_GET_RETRY_COUNT }, + { MBC_TRACE_CONTROL }, +}; + +static int is_rom_cmd(uint16_t cmd) +{ + int i; + struct rom_cmd *wc; + + for (i = 0; i < ARRAY_SIZE(rom_cmds); i++) { + wc = rom_cmds + i; + if (wc->cmd == cmd) + return 1; + } + + return 0; +} /* * qla2x00_mailbox_command @@ -92,6 +129,17 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) return QLA_FUNCTION_TIMEOUT; } + /* check if ISP abort is active and return cmd with timeout */ + if ((test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || + test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags)) && + !is_rom_cmd(mcp->mb[0])) { + ql_log(ql_log_info, vha, 0x1005, + "Cmd 0x%x aborted with timeout since ISP Abort is pending\n", + mcp->mb[0]); + return QLA_FUNCTION_TIMEOUT; + } + /* * Wait for active mailbox commands to finish by waiting at most tov * seconds. This is to serialize actual issuing of mailbox cmds during @@ -178,6 +226,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) WRT_REG_WORD(®->isp.hccr, HCCR_SET_HOST_INT); spin_unlock_irqrestore(&ha->hardware_lock, flags); + wait_time = jiffies; if (!wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ)) { ql_dbg(ql_dbg_mbx, vha, 0x117a, @@ -186,6 +235,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); spin_unlock_irqrestore(&ha->hardware_lock, flags); } + if (time_after(jiffies, wait_time + 5 * HZ)) + ql_log(ql_log_warn, vha, 0x1015, "cmd=0x%x, waited %d msecs\n", + command, jiffies_to_msecs(jiffies - wait_time)); } else { ql_dbg(ql_dbg_mbx, vha, 0x1011, "Cmd=%x Polling Mode.\n", command); -- cgit v1.2.3 From 4fa183455988adaa7f6565ca06bceecafb527820 Mon Sep 17 00:00:00 2001 From: Michael Hernandez Date: Mon, 12 Dec 2016 14:40:06 -0800 Subject: scsi: qla2xxx: Utilize pci_alloc_irq_vectors/pci_free_irq_vectors calls. Replaces the old pci_enable_msi[x]* and pci_disable_msi[x] calls. Signed-off-by: Michael Hernandez Signed-off-by: Himanshu Madhani Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 89 ++++++++++++++++-------------------------- drivers/scsi/qla2xxx/qla_mid.c | 2 +- 3 files changed, 36 insertions(+), 57 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 5236e3f2a06a..d38c205ae22c 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2747,7 +2747,7 @@ struct qla_msix_entry { int have_irq; uint32_t vector; uint16_t entry; - struct rsp_que *rsp; + void *handle; struct irq_affinity_notify irq_notify; int cpuid; }; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 19f18485a854..ad5304caf1ff 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3025,52 +3025,17 @@ static struct qla_init_msix_entry qla83xx_msix_entries[3] = { { "qla2xxx (atio_q)", qla83xx_msix_atio_q }, }; -static void -qla24xx_disable_msix(struct qla_hw_data *ha) -{ - int i; - struct qla_msix_entry *qentry; - scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - - for (i = 0; i < ha->msix_count; i++) { - qentry = &ha->msix_entries[i]; - if (qentry->have_irq) { - /* un-register irq cpu affinity notification */ - irq_set_affinity_notifier(qentry->vector, NULL); - free_irq(qentry->vector, qentry->rsp); - } - } - pci_disable_msix(ha->pdev); - kfree(ha->msix_entries); - ha->msix_entries = NULL; - ha->flags.msix_enabled = 0; - ql_dbg(ql_dbg_init, vha, 0x0042, - "Disabled the MSI.\n"); -} - static int qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) { #define MIN_MSIX_COUNT 2 #define ATIO_VECTOR 2 int i, ret; - struct msix_entry *entries; struct qla_msix_entry *qentry; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); - entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count, - GFP_KERNEL); - if (!entries) { - ql_log(ql_log_warn, vha, 0x00bc, - "Failed to allocate memory for msix_entry.\n"); - return -ENOMEM; - } - - for (i = 0; i < ha->msix_count; i++) - entries[i].entry = i; - - ret = pci_enable_msix_range(ha->pdev, - entries, MIN_MSIX_COUNT, ha->msix_count); + ret = pci_alloc_irq_vectors(ha->pdev, MIN_MSIX_COUNT, ha->msix_count, + PCI_IRQ_MSIX); if (ret < 0) { ql_log(ql_log_fatal, vha, 0x00c7, "MSI-X: Failed to enable support, " @@ -3097,10 +3062,10 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) for (i = 0; i < ha->msix_count; i++) { qentry = &ha->msix_entries[i]; - qentry->vector = entries[i].vector; - qentry->entry = entries[i].entry; + qentry->vector = pci_irq_vector(ha->pdev, i); + qentry->entry = i; qentry->have_irq = 0; - qentry->rsp = NULL; + qentry->handle = NULL; qentry->irq_notify.notify = qla_irq_affinity_notify; qentry->irq_notify.release = qla_irq_affinity_release; qentry->cpuid = -1; @@ -3109,7 +3074,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) /* Enable MSI-X vectors for the base queue */ for (i = 0; i < 2; i++) { qentry = &ha->msix_entries[i]; - qentry->rsp = rsp; + qentry->handle = rsp; rsp->msix = qentry; if (IS_P3P_TYPE(ha)) ret = request_irq(qentry->vector, @@ -3142,7 +3107,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) */ if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) { qentry = &ha->msix_entries[ATIO_VECTOR]; - qentry->rsp = rsp; + qentry->handle = rsp; rsp->msix = qentry; ret = request_irq(qentry->vector, qla83xx_msix_entries[ATIO_VECTOR].handler, @@ -3155,7 +3120,7 @@ msix_register_fail: ql_log(ql_log_fatal, vha, 0x00cb, "MSI-X: unable to register handler -- %x/%d.\n", qentry->vector, ret); - qla24xx_disable_msix(ha); + qla2x00_free_irqs(vha); ha->mqenable = 0; goto msix_out; } @@ -3177,7 +3142,6 @@ msix_register_fail: ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues); msix_out: - kfree(entries); return ret; } @@ -3230,7 +3194,7 @@ skip_msix: !IS_QLA27XX(ha)) goto skip_msi; - ret = pci_enable_msi(ha->pdev); + ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI); if (!ret) { ql_dbg(ql_dbg_init, vha, 0x0038, "MSI: Enabled.\n"); @@ -3275,6 +3239,8 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) { struct qla_hw_data *ha = vha->hw; struct rsp_que *rsp; + struct qla_msix_entry *qentry; + int i; /* * We need to check that ha->rsp_q_map is valid in case we are called @@ -3284,13 +3250,24 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) return; rsp = ha->rsp_q_map[0]; - if (ha->flags.msix_enabled) - qla24xx_disable_msix(ha); - else if (ha->flags.msi_enabled) { - free_irq(ha->pdev->irq, rsp); - pci_disable_msi(ha->pdev); - } else - free_irq(ha->pdev->irq, rsp); + if (ha->flags.msix_enabled) { + for (i = 0; i < ha->msix_count; i++) { + qentry = &ha->msix_entries[i]; + if (qentry->have_irq) { + irq_set_affinity_notifier(qentry->vector, NULL); + free_irq(pci_irq_vector(ha->pdev, i), qentry->handle); + } + } + kfree(ha->msix_entries); + ha->msix_entries = NULL; + ha->flags.msix_enabled = 0; + ql_dbg(ql_dbg_init, vha, 0x0042, + "Disabled MSI-X.\n"); + } else { + free_irq(pci_irq_vector(ha->pdev, 0), rsp); + } + + pci_free_irq_vectors(ha->pdev); } @@ -3310,7 +3287,7 @@ int qla25xx_request_irq(struct rsp_que *rsp) return ret; } msix->have_irq = 1; - msix->rsp = rsp; + msix->handle = rsp; return ret; } @@ -3323,11 +3300,12 @@ static void qla_irq_affinity_notify(struct irq_affinity_notify *notify, container_of(notify, struct qla_msix_entry, irq_notify); struct qla_hw_data *ha; struct scsi_qla_host *base_vha; + struct rsp_que *rsp = e->handle; /* user is recommended to set mask to just 1 cpu */ e->cpuid = cpumask_first(mask); - ha = e->rsp->hw; + ha = rsp->hw; base_vha = pci_get_drvdata(ha->pdev); ql_dbg(ql_dbg_init, base_vha, 0xffff, @@ -3351,7 +3329,8 @@ static void qla_irq_affinity_release(struct kref *ref) container_of(ref, struct irq_affinity_notify, kref); struct qla_msix_entry *e = container_of(notify, struct qla_msix_entry, irq_notify); - struct scsi_qla_host *base_vha = pci_get_drvdata(e->rsp->hw->pdev); + struct rsp_que *rsp = e->handle; + struct scsi_qla_host *base_vha = pci_get_drvdata(rsp->hw->pdev); ql_dbg(ql_dbg_init, base_vha, 0xffff, "%s: host%ld: vector %d cpu %d \n", __func__, diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index cf7ba52bae66..8e406fc35db4 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -542,7 +542,7 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) if (rsp->msix && rsp->msix->have_irq) { free_irq(rsp->msix->vector, rsp); rsp->msix->have_irq = 0; - rsp->msix->rsp = NULL; + rsp->msix->handle = NULL; } dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) * sizeof(response_t), rsp->ring, rsp->dma); -- cgit v1.2.3 From d74595278f4ab192af66d9e60a9087464638beee Mon Sep 17 00:00:00 2001 From: Michael Hernandez Date: Mon, 12 Dec 2016 14:40:07 -0800 Subject: scsi: qla2xxx: Add multiple queue pair functionality. Replaced existing multiple queue functionality with framework that allows for the creation of pairs of request and response queues, either at start of day or dynamically. Queue pair creation depend on module parameter "ql2xmqsupport", which need to be enabled to create queue pair. Signed-off-by: Sawan Chandak Signed-off-by: Michael Hernandez Signed-off-by: Himanshu Madhani Acked-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 36 ++-- drivers/scsi/qla2xxx/qla_dbg.c | 4 +- drivers/scsi/qla2xxx/qla_def.h | 105 ++++++++-- drivers/scsi/qla2xxx/qla_gbl.h | 28 ++- drivers/scsi/qla2xxx/qla_init.c | 173 +++++++++++++++- drivers/scsi/qla2xxx/qla_inline.h | 30 +++ drivers/scsi/qla2xxx/qla_iocb.c | 407 ++++++++++++++++++++++++++++++++++---- drivers/scsi/qla2xxx/qla_isr.c | 124 ++++++------ drivers/scsi/qla2xxx/qla_mbx.c | 33 ++-- drivers/scsi/qla2xxx/qla_mid.c | 114 ++++++----- drivers/scsi/qla2xxx/qla_os.c | 395 ++++++++++++++++++++++++------------ 11 files changed, 1114 insertions(+), 335 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index fe7469c901f7..47eb4d545d13 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -1988,9 +1988,9 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost); scsi_qla_host_t *vha = NULL; struct qla_hw_data *ha = base_vha->hw; - uint16_t options = 0; int cnt; struct req_que *req = ha->req_q_map[0]; + struct qla_qpair *qpair; ret = qla24xx_vport_create_req_sanity_check(fc_vport); if (ret) { @@ -2075,15 +2075,9 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) qlt_vport_create(vha, ha); qla24xx_vport_disable(fc_vport, disable); - if (ha->flags.cpu_affinity_enabled) { - req = ha->req_q_map[1]; - ql_dbg(ql_dbg_multiq, vha, 0xc000, - "Request queue %p attached with " - "VP[%d], cpu affinity =%d\n", - req, vha->vp_idx, ha->flags.cpu_affinity_enabled); - goto vport_queue; - } else if (ql2xmaxqueues == 1 || !ha->npiv_info) + if (!ql2xmqsupport || !ha->npiv_info) goto vport_queue; + /* Create a request queue in QoS mode for the vport */ for (cnt = 0; cnt < ha->nvram_npiv_size; cnt++) { if (memcmp(ha->npiv_info[cnt].port_name, vha->port_name, 8) == 0 @@ -2095,20 +2089,20 @@ qla24xx_vport_create(struct fc_vport *fc_vport, bool disable) } if (qos) { - ret = qla25xx_create_req_que(ha, options, vha->vp_idx, 0, 0, - qos); - if (!ret) + qpair = qla2xxx_create_qpair(vha, qos, vha->vp_idx); + if (!qpair) ql_log(ql_log_warn, vha, 0x7084, - "Can't create request queue for VP[%d]\n", + "Can't create qpair for VP[%d]\n", vha->vp_idx); else { ql_dbg(ql_dbg_multiq, vha, 0xc001, - "Request Que:%d Q0s: %d) created for VP[%d]\n", - ret, qos, vha->vp_idx); + "Queue pair: %d Qos: %d) created for VP[%d]\n", + qpair->id, qos, vha->vp_idx); ql_dbg(ql_dbg_user, vha, 0x7085, - "Request Que:%d Q0s: %d) created for VP[%d]\n", - ret, qos, vha->vp_idx); - req = ha->req_q_map[ret]; + "Queue Pair: %d Qos: %d) created for VP[%d]\n", + qpair->id, qos, vha->vp_idx); + req = qpair->req; + vha->qpair = qpair; } } @@ -2162,10 +2156,10 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) clear_bit(vha->vp_idx, ha->vp_idx_map); mutex_unlock(&ha->vport_lock); - if (vha->req->id && !ha->flags.cpu_affinity_enabled) { - if (qla25xx_delete_req_que(vha, vha->req) != QLA_SUCCESS) + if (vha->qpair->vp_idx == vha->vp_idx) { + if (qla2xxx_delete_qpair(vha, vha->qpair) != QLA_SUCCESS) ql_log(ql_log_warn, vha, 0x7087, - "Queue delete failed.\n"); + "Queue Pair delete failed.\n"); } ql_log(ql_log_info, vha, 0x7088, "VP[%d] deleted.\n", id); diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c index 45af34ddc432..21d9fb7fc887 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.c +++ b/drivers/scsi/qla2xxx/qla_dbg.c @@ -11,7 +11,7 @@ * ---------------------------------------------------------------------- * | Level | Last Value Used | Holes | * ---------------------------------------------------------------------- - * | Module Init and Probe | 0x0191 | 0x0146 | + * | Module Init and Probe | 0x0193 | 0x0146 | * | | | 0x015b-0x0160 | * | | | 0x016e | * | Mailbox commands | 0x1199 | 0x1193 | @@ -58,7 +58,7 @@ * | | | 0xb13a,0xb142 | * | | | 0xb13c-0xb140 | * | | | 0xb149 | - * | MultiQ | 0xc00c | | + * | MultiQ | 0xc010 | | * | Misc | 0xd301 | 0xd031-0xd0ff | * | | | 0xd101-0xd1fe | * | | | 0xd214-0xd2fe | diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index d38c205ae22c..d60cd1737ee6 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -401,6 +401,7 @@ typedef struct srb { uint16_t type; char *name; int iocbs; + struct qla_qpair *qpair; union { struct srb_iocb iocb_cmd; struct bsg_job *bsg_job; @@ -2719,6 +2720,7 @@ struct isp_operations { int (*get_flash_version) (struct scsi_qla_host *, void *); int (*start_scsi) (srb_t *); + int (*start_scsi_mq) (srb_t *); int (*abort_isp) (struct scsi_qla_host *); int (*iospace_config)(struct qla_hw_data*); int (*initialize_adapter)(struct scsi_qla_host *); @@ -2730,8 +2732,9 @@ struct isp_operations { #define QLA_MSIX_FW_MODE(m) (((m) & (BIT_7|BIT_8|BIT_9)) >> 7) #define QLA_MSIX_FW_MODE_1(m) (QLA_MSIX_FW_MODE(m) == 1) -#define QLA_MSIX_DEFAULT 0x00 -#define QLA_MSIX_RSP_Q 0x01 +#define QLA_MSIX_DEFAULT 0x00 +#define QLA_MSIX_RSP_Q 0x01 +#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x02 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 @@ -2745,8 +2748,10 @@ struct scsi_qla_host; struct qla_msix_entry { int have_irq; + int in_use; uint32_t vector; uint16_t entry; + char name[30]; void *handle; struct irq_affinity_notify irq_notify; int cpuid; @@ -2872,7 +2877,6 @@ struct rsp_que { struct qla_msix_entry *msix; struct req_que *req; srb_t *status_srb; /* status continuation entry */ - struct work_struct q_work; dma_addr_t dma_fx00; response_t *ring_fx00; @@ -2909,6 +2913,37 @@ struct req_que { uint8_t req_pkt[REQUEST_ENTRY_SIZE]; }; +/*Queue pair data structure */ +struct qla_qpair { + spinlock_t qp_lock; + atomic_t ref_count; + /* distill these fields down to 'online=0/1' + * ha->flags.eeh_busy + * ha->flags.pci_channel_io_perm_failure + * base_vha->loop_state + */ + uint32_t online:1; + /* move vha->flags.difdix_supported here */ + uint32_t difdix_supported:1; + uint32_t delete_in_progress:1; + + uint16_t id; /* qp number used with FW */ + uint16_t num_active_cmd; /* cmds down at firmware */ + cpumask_t cpu_mask; /* CPU mask for cpu affinity operation */ + uint16_t vp_idx; /* vport ID */ + + mempool_t *srb_mempool; + + /* to do: New driver: move queues to here instead of pointers */ + struct req_que *req; + struct rsp_que *rsp; + struct atio_que *atio; + struct qla_msix_entry *msix; /* point to &ha->msix_entries[x] */ + struct qla_hw_data *hw; + struct work_struct q_work; + struct list_head qp_list_elem; /* vha->qp_list */ +}; + /* Place holder for FW buffer parameters */ struct qlfc_fw { void *fw_buf; @@ -3004,7 +3039,6 @@ struct qla_hw_data { uint32_t chip_reset_done :1; uint32_t running_gold_fw :1; uint32_t eeh_busy :1; - uint32_t cpu_affinity_enabled :1; uint32_t disable_msix_handshake :1; uint32_t fcp_prio_enabled :1; uint32_t isp82xx_fw_hung:1; @@ -3061,10 +3095,15 @@ struct qla_hw_data { uint8_t mqenable; struct req_que **req_q_map; struct rsp_que **rsp_q_map; + struct qla_qpair **queue_pair_map; unsigned long req_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; unsigned long rsp_qid_map[(QLA_MAX_QUEUES / 8) / sizeof(unsigned long)]; + unsigned long qpair_qid_map[(QLA_MAX_QUEUES / 8) + / sizeof(unsigned long)]; uint8_t max_req_queues; uint8_t max_rsp_queues; + uint8_t max_qpairs; + struct qla_qpair *base_qpair; struct qla_npiv_entry *npiv_info; uint16_t nvram_npiv_size; @@ -3328,6 +3367,7 @@ struct qla_hw_data { struct mutex vport_lock; /* Virtual port synchronization */ spinlock_t vport_slock; /* order is hardware_lock, then vport_slock */ + struct mutex mq_lock; /* multi-queue synchronization */ struct completion mbx_cmd_comp; /* Serialize mbx access */ struct completion mbx_intr_comp; /* Used for completion notification */ struct completion dcbx_comp; /* For set port config notification */ @@ -3608,6 +3648,7 @@ typedef struct scsi_qla_host { uint32_t fw_tgt_reported:1; uint32_t bbcr_enable:1; + uint32_t qpairs_available:1; } flags; atomic_t loop_state; @@ -3646,6 +3687,7 @@ typedef struct scsi_qla_host { #define FX00_TARGET_SCAN 24 #define FX00_CRITEMP_RECOVERY 25 #define FX00_HOST_INFO_RESEND 26 +#define QPAIR_ONLINE_CHECK_NEEDED 27 unsigned long pci_flags; #define PFLG_DISCONNECTED 0 /* PCI device removed */ @@ -3704,10 +3746,13 @@ typedef struct scsi_qla_host { /* List of pending PLOGI acks, protected by hw lock */ struct list_head plogi_ack_list; + struct list_head qp_list; + uint32_t vp_abort_cnt; struct fc_vport *fc_vport; /* holds fc_vport * for each vport */ uint16_t vp_idx; /* vport ID */ + struct qla_qpair *qpair; /* base qpair */ unsigned long vp_flags; #define VP_IDX_ACQUIRED 0 /* bit no 0 */ @@ -3763,6 +3808,23 @@ struct qla_tgt_vp_map { scsi_qla_host_t *vha; }; +struct qla2_sgx { + dma_addr_t dma_addr; /* OUT */ + uint32_t dma_len; /* OUT */ + + uint32_t tot_bytes; /* IN */ + struct scatterlist *cur_sg; /* IN */ + + /* for book keeping, bzero on initial invocation */ + uint32_t bytes_consumed; + uint32_t num_bytes; + uint32_t tot_partial; + + /* for debugging */ + uint32_t num_sg; + srb_t *sp; +}; + /* * Macros to help code, maintain, etc. */ @@ -3775,21 +3837,34 @@ struct qla_tgt_vp_map { (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \ test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) -#define QLA_VHA_MARK_BUSY(__vha, __bail) do { \ - atomic_inc(&__vha->vref_count); \ - mb(); \ - if (__vha->flags.delete_progress) { \ - atomic_dec(&__vha->vref_count); \ - __bail = 1; \ - } else { \ - __bail = 0; \ - } \ +#define QLA_VHA_MARK_BUSY(__vha, __bail) do { \ + atomic_inc(&__vha->vref_count); \ + mb(); \ + if (__vha->flags.delete_progress) { \ + atomic_dec(&__vha->vref_count); \ + __bail = 1; \ + } else { \ + __bail = 0; \ + } \ } while (0) -#define QLA_VHA_MARK_NOT_BUSY(__vha) do { \ - atomic_dec(&__vha->vref_count); \ +#define QLA_VHA_MARK_NOT_BUSY(__vha) \ + atomic_dec(&__vha->vref_count); \ + +#define QLA_QPAIR_MARK_BUSY(__qpair, __bail) do { \ + atomic_inc(&__qpair->ref_count); \ + mb(); \ + if (__qpair->delete_in_progress) { \ + atomic_dec(&__qpair->ref_count); \ + __bail = 1; \ + } else { \ + __bail = 0; \ + } \ } while (0) +#define QLA_QPAIR_MARK_NOT_BUSY(__qpair) \ + atomic_dec(&__qpair->ref_count); \ + /* * qla2x00 local function return status codes */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index c51d9f3359e3..afa0116a163b 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -91,12 +91,17 @@ extern int qla2x00_alloc_outstanding_cmds(struct qla_hw_data *, struct req_que *); extern int qla2x00_init_rings(scsi_qla_host_t *); extern uint8_t qla27xx_find_valid_image(struct scsi_qla_host *); +extern struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *, + int, int); +extern int qla2xxx_delete_qpair(struct scsi_qla_host *, struct qla_qpair *); /* * Global Data in qla_os.c source file. */ extern char qla2x00_version_str[]; +extern struct kmem_cache *srb_cachep; + extern int ql2xlogintimeout; extern int qlport_down_retry; extern int ql2xplogiabsentdevice; @@ -105,8 +110,7 @@ extern int ql2xfdmienable; extern int ql2xallocfwdump; extern int ql2xextended_error_logging; extern int ql2xiidmaenable; -extern int ql2xmaxqueues; -extern int ql2xmultique_tag; +extern int ql2xmqsupport; extern int ql2xfwloadbin; extern int ql2xetsenable; extern int ql2xshiftctondsd; @@ -172,6 +176,9 @@ extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); extern int qla2x00_post_uevent_work(struct scsi_qla_host *, u32); extern void qla2x00_disable_board_on_pci_error(struct work_struct *); +extern void qla2x00_sp_compl(void *, void *, int); +extern void qla2xxx_qpair_sp_free_dma(void *, void *); +extern void qla2xxx_qpair_sp_compl(void *, void *, int); /* * Global Functions in qla_mid.c source file. @@ -220,6 +227,8 @@ extern uint16_t qla2x00_calc_iocbs_32(uint16_t); extern uint16_t qla2x00_calc_iocbs_64(uint16_t); extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t); extern void qla2x00_build_scsi_iocbs_64(srb_t *, cmd_entry_t *, uint16_t); +extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, + uint16_t, struct req_que *); extern int qla2x00_start_scsi(srb_t *sp); extern int qla24xx_start_scsi(srb_t *sp); int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, @@ -227,6 +236,7 @@ int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, extern int qla2x00_start_sp(srb_t *); extern int qla24xx_dif_start_scsi(srb_t *); extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t); +extern int qla2xxx_dif_start_scsi_mq(srb_t *); extern unsigned long qla2x00_get_async_timeout(struct scsi_qla_host *); extern void *qla2x00_alloc_iocbs(scsi_qla_host_t *, srb_t *); @@ -237,7 +247,10 @@ extern int qla24xx_walk_and_build_sglist(struct qla_hw_data *, srb_t *, uint32_t *, uint16_t, struct qla_tgt_cmd *); extern int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *, srb_t *, uint32_t *, uint16_t, struct qla_tgt_cmd *); - +extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *); +extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *); +extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *, + struct cmd_type_crc_2 *, uint16_t, uint16_t, uint16_t); /* * Global Function Prototypes in qla_mbx.c source file. @@ -468,6 +481,8 @@ qla2x00_get_sp_from_handle(scsi_qla_host_t *, const char *, struct req_que *, extern void qla2x00_process_completed_request(struct scsi_qla_host *, struct req_que *, uint32_t); +extern irqreturn_t +qla2xxx_msix_rsp_q(int irq, void *dev_id); /* * Global Function Prototypes in qla_sup.c source file. @@ -603,15 +618,18 @@ extern int qla2x00_dfs_setup(scsi_qla_host_t *); extern int qla2x00_dfs_remove(scsi_qla_host_t *); /* Globa function prototypes for multi-q */ -extern int qla25xx_request_irq(struct rsp_que *); +extern int qla25xx_request_irq(struct qla_hw_data *, struct qla_qpair *, + struct qla_msix_entry *, int); extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *); extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t, uint16_t, int, uint8_t); extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t, - uint16_t, int); + uint16_t, struct qla_qpair *); + extern void qla2x00_init_response_q_entries(struct rsp_que *); extern int qla25xx_delete_req_que(struct scsi_qla_host *, struct req_que *); +extern int qla25xx_delete_rsp_que(struct scsi_qla_host *, struct rsp_que *); extern int qla25xx_delete_queues(struct scsi_qla_host *); extern uint16_t qla24xx_rd_req_reg(struct qla_hw_data *, uint16_t); extern uint16_t qla25xx_rd_req_reg(struct qla_hw_data *, uint16_t); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5b09296b46a3..400ffd1894ee 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1769,8 +1769,7 @@ qla2x00_alloc_outstanding_cmds(struct qla_hw_data *ha, struct req_que *req) if (req->outstanding_cmds) return QLA_SUCCESS; - if (!IS_FWI2_CAPABLE(ha) || (ha->mqiobase && - (ql2xmultique_tag || ql2xmaxqueues > 1))) + if (!IS_FWI2_CAPABLE(ha)) req->num_outstanding_cmds = DEFAULT_OUTSTANDING_COMMANDS; else { if (ha->cur_fw_xcb_count <= ha->cur_fw_iocb_count) @@ -4248,10 +4247,7 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) struct req_que *req; struct rsp_que *rsp; - if (vha->hw->flags.cpu_affinity_enabled) - req = vha->hw->req_q_map[0]; - else - req = vha->req; + req = vha->req; rsp = req->rsp; clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); @@ -6040,10 +6036,10 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha) return -EINVAL; rval = qla2x00_fw_ready(base_vha); - if (ha->flags.cpu_affinity_enabled) - req = ha->req_q_map[0]; + if (vha->qpair) + req = vha->qpair->req; else - req = vha->req; + req = ha->req_q_map[0]; rsp = req->rsp; if (rval == QLA_SUCCESS) { @@ -6725,3 +6721,162 @@ qla24xx_update_all_fcp_prio(scsi_qla_host_t *vha) return ret; } + +struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int vp_idx) +{ + int rsp_id = 0; + int req_id = 0; + int i; + struct qla_hw_data *ha = vha->hw; + uint16_t qpair_id = 0; + struct qla_qpair *qpair = NULL; + struct qla_msix_entry *msix; + + if (!(ha->fw_attributes & BIT_6) || !ha->flags.msix_enabled) { + ql_log(ql_log_warn, vha, 0x00181, + "FW/Driver is not multi-queue capable.\n"); + return NULL; + } + + if (ql2xmqsupport) { + qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL); + if (qpair == NULL) { + ql_log(ql_log_warn, vha, 0x0182, + "Failed to allocate memory for queue pair.\n"); + return NULL; + } + memset(qpair, 0, sizeof(struct qla_qpair)); + + qpair->hw = vha->hw; + + /* Assign available que pair id */ + mutex_lock(&ha->mq_lock); + qpair_id = find_first_zero_bit(ha->qpair_qid_map, ha->max_qpairs); + if (qpair_id >= ha->max_qpairs) { + mutex_unlock(&ha->mq_lock); + ql_log(ql_log_warn, vha, 0x0183, + "No resources to create additional q pair.\n"); + goto fail_qid_map; + } + set_bit(qpair_id, ha->qpair_qid_map); + ha->queue_pair_map[qpair_id] = qpair; + qpair->id = qpair_id; + qpair->vp_idx = vp_idx; + + for (i = 0; i < ha->msix_count; i++) { + msix = &ha->msix_entries[i + 2]; + if (msix->in_use) + continue; + qpair->msix = msix; + ql_log(ql_dbg_multiq, vha, 0xc00f, + "Vector %x selected for qpair\n", msix->vector); + break; + } + if (!qpair->msix) { + ql_log(ql_log_warn, vha, 0x0184, + "Out of MSI-X vectors!.\n"); + goto fail_msix; + } + + qpair->msix->in_use = 1; + list_add_tail(&qpair->qp_list_elem, &vha->qp_list); + + mutex_unlock(&ha->mq_lock); + + /* Create response queue first */ + rsp_id = qla25xx_create_rsp_que(ha, 0, 0, 0, qpair); + if (!rsp_id) { + ql_log(ql_log_warn, vha, 0x0185, + "Failed to create response queue.\n"); + goto fail_rsp; + } + + qpair->rsp = ha->rsp_q_map[rsp_id]; + + /* Create request queue */ + req_id = qla25xx_create_req_que(ha, 0, vp_idx, 0, rsp_id, qos); + if (!req_id) { + ql_log(ql_log_warn, vha, 0x0186, + "Failed to create request queue.\n"); + goto fail_req; + } + + qpair->req = ha->req_q_map[req_id]; + qpair->rsp->req = qpair->req; + + if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) { + if (ha->fw_attributes & BIT_4) + qpair->difdix_supported = 1; + } + + qpair->srb_mempool = mempool_create_slab_pool(SRB_MIN_REQ, srb_cachep); + if (!qpair->srb_mempool) { + ql_log(ql_log_warn, vha, 0x0191, + "Failed to create srb mempool for qpair %d\n", + qpair->id); + goto fail_mempool; + } + + /* Mark as online */ + qpair->online = 1; + + if (!vha->flags.qpairs_available) + vha->flags.qpairs_available = 1; + + ql_dbg(ql_dbg_multiq, vha, 0xc00d, + "Request/Response queue pair created, id %d\n", + qpair->id); + ql_dbg(ql_dbg_init, vha, 0x0187, + "Request/Response queue pair created, id %d\n", + qpair->id); + } + return qpair; + +fail_mempool: +fail_req: + qla25xx_delete_rsp_que(vha, qpair->rsp); +fail_rsp: + mutex_lock(&ha->mq_lock); + qpair->msix->in_use = 0; + list_del(&qpair->qp_list_elem); + if (list_empty(&vha->qp_list)) + vha->flags.qpairs_available = 0; +fail_msix: + ha->queue_pair_map[qpair_id] = NULL; + clear_bit(qpair_id, ha->qpair_qid_map); + mutex_unlock(&ha->mq_lock); +fail_qid_map: + kfree(qpair); + return NULL; +} + +int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair) +{ + int ret; + struct qla_hw_data *ha = qpair->hw; + + qpair->delete_in_progress = 1; + while (atomic_read(&qpair->ref_count)) + msleep(500); + + ret = qla25xx_delete_req_que(vha, qpair->req); + if (ret != QLA_SUCCESS) + goto fail; + ret = qla25xx_delete_rsp_que(vha, qpair->rsp); + if (ret != QLA_SUCCESS) + goto fail; + + mutex_lock(&ha->mq_lock); + ha->queue_pair_map[qpair->id] = NULL; + clear_bit(qpair->id, ha->qpair_qid_map); + list_del(&qpair->qp_list_elem); + if (list_empty(&vha->qp_list)) + vha->flags.qpairs_available = 0; + mempool_destroy(qpair->srb_mempool); + kfree(qpair); + mutex_unlock(&ha->mq_lock); + + return QLA_SUCCESS; +fail: + return ret; +} diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index edc48f3b8230..44e404583c86 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -215,6 +215,36 @@ qla2x00_reset_active(scsi_qla_host_t *vha) test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); } +static inline srb_t * +qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) +{ + srb_t *sp = NULL; + uint8_t bail; + + QLA_QPAIR_MARK_BUSY(qpair, bail); + if (unlikely(bail)) + return NULL; + + sp = mempool_alloc(qpair->srb_mempool, flag); + if (!sp) + goto done; + + memset(sp, 0, sizeof(*sp)); + sp->fcport = fcport; + sp->iocbs = 1; +done: + if (!sp) + QLA_QPAIR_MARK_NOT_BUSY(qpair); + return sp; +} + +static inline void +qla2xxx_rel_qpair_sp(struct qla_qpair *qpair, srb_t *sp) +{ + mempool_free(sp, qpair->srb_mempool); + QLA_QPAIR_MARK_NOT_BUSY(qpair); +} + static inline srb_t * qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag) { diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 221ad8907893..58e49a3e1de8 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -12,7 +12,6 @@ #include -static void qla25xx_set_que(srb_t *, struct rsp_que **); /** * qla2x00_get_cmd_direction() - Determine control_flag data direction. * @cmd: SCSI command @@ -143,7 +142,7 @@ qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *vha, struct req_que *req) return (cont_pkt); } -static inline int +inline int qla24xx_configure_prot_mode(srb_t *sp, uint16_t *fw_prot_opts) { struct scsi_cmnd *cmd = GET_CMD_SP(sp); @@ -693,10 +692,11 @@ qla24xx_calc_dsd_lists(uint16_t dsds) * @sp: SRB command to process * @cmd_pkt: Command type 3 IOCB * @tot_dsds: Total number of segments to transfer + * @req: pointer to request queue */ -static inline void +inline void qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, - uint16_t tot_dsds) + uint16_t tot_dsds, struct req_que *req) { uint16_t avail_dsds; uint32_t *cur_dsd; @@ -745,7 +745,7 @@ qla24xx_build_scsi_iocbs(srb_t *sp, struct cmd_type_7 *cmd_pkt, * Five DSDs are available in the Continuation * Type 1 IOCB. */ - cont_pkt = qla2x00_prep_cont_type1_iocb(vha, vha->req); + cont_pkt = qla2x00_prep_cont_type1_iocb(vha, req); cur_dsd = (uint32_t *)cont_pkt->dseg_0_address; avail_dsds = 5; } @@ -845,24 +845,7 @@ qla24xx_set_t10dif_tags(srb_t *sp, struct fw_dif_context *pkt, } } -struct qla2_sgx { - dma_addr_t dma_addr; /* OUT */ - uint32_t dma_len; /* OUT */ - - uint32_t tot_bytes; /* IN */ - struct scatterlist *cur_sg; /* IN */ - - /* for book keeping, bzero on initial invocation */ - uint32_t bytes_consumed; - uint32_t num_bytes; - uint32_t tot_partial; - - /* for debugging */ - uint32_t num_sg; - srb_t *sp; -}; - -static int +int qla24xx_get_one_block_sg(uint32_t blk_sz, struct qla2_sgx *sgx, uint32_t *partial) { @@ -1207,7 +1190,7 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, * @cmd_pkt: Command type 3 IOCB * @tot_dsds: Total number of segments to transfer */ -static inline int +inline int qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, uint16_t tot_dsds, uint16_t tot_prot_dsds, uint16_t fw_prot_opts) { @@ -1436,8 +1419,8 @@ qla24xx_start_scsi(srb_t *sp) struct qla_hw_data *ha = vha->hw; /* Setup device pointers. */ - qla25xx_set_que(sp, &rsp); req = vha->req; + rsp = req->rsp; /* So we know we haven't pci_map'ed anything yet */ tot_dsds = 0; @@ -1523,12 +1506,10 @@ qla24xx_start_scsi(srb_t *sp) cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); /* Build IOCB segments */ - qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds); + qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); /* Set total data segment count. */ cmd_pkt->entry_count = (uint8_t)req_cnt; - /* Specify response queue number where completion should happen */ - cmd_pkt->entry_status = (uint8_t) rsp->id; wmb(); /* Adjust ring index. */ req->ring_index++; @@ -1597,9 +1578,8 @@ qla24xx_dif_start_scsi(srb_t *sp) } /* Setup device pointers. */ - - qla25xx_set_que(sp, &rsp); req = vha->req; + rsp = req->rsp; /* So we know we haven't pci_map'ed anything yet */ tot_dsds = 0; @@ -1764,18 +1744,365 @@ queuing_error: return QLA_FUNCTION_FAILED; } - -static void qla25xx_set_que(srb_t *sp, struct rsp_que **rsp) +/** + * qla2xxx_start_scsi_mq() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occurred, else zero. + */ +static int +qla2xxx_start_scsi_mq(srb_t *sp) { + int nseg; + unsigned long flags; + uint32_t *clr_ptr; + uint32_t index; + uint32_t handle; + struct cmd_type_7 *cmd_pkt; + uint16_t cnt; + uint16_t req_cnt; + uint16_t tot_dsds; + struct req_que *req = NULL; + struct rsp_que *rsp = NULL; struct scsi_cmnd *cmd = GET_CMD_SP(sp); - struct qla_hw_data *ha = sp->fcport->vha->hw; - int affinity = cmd->request->cpu; + struct scsi_qla_host *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair = sp->qpair; + + /* Setup qpair pointers */ + rsp = qpair->rsp; + req = qpair->req; + + /* So we know we haven't pci_map'ed anything yet */ + tot_dsds = 0; + + /* Send marker if required */ + if (vha->marker_needed != 0) { + if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + QLA_SUCCESS) + return QLA_FUNCTION_FAILED; + vha->marker_needed = 0; + } + + /* Acquire qpair specific lock */ + spin_lock_irqsave(&qpair->qp_lock, flags); + + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < req->num_outstanding_cmds; index++) { + handle++; + if (handle == req->num_outstanding_cmds) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + if (index == req->num_outstanding_cmds) + goto queuing_error; + + /* Map the sg table so we have an accurate count of sg entries needed */ + if (scsi_sg_count(cmd)) { + nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), + scsi_sg_count(cmd), cmd->sc_data_direction); + if (unlikely(!nseg)) + goto queuing_error; + } else + nseg = 0; + + tot_dsds = nseg; + req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); + if (req->cnt < (req_cnt + 2)) { + cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr : + RD_REG_DWORD_RELAXED(req->req_q_out); + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + } + + /* Build command packet. */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->handle = handle; + cmd->host_scribble = (unsigned char *)(unsigned long)handle; + req->cnt -= req_cnt; + + cmd_pkt = (struct cmd_type_7 *)req->ring_ptr; + cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + + /* Zero out remaining portion of packet. */ + /* tagged queuing modifier -- default is TSK_SIMPLE (0). */ + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + + /* Set NPORT-ID and LUN number*/ + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; + cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; + cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; + cmd_pkt->vp_index = sp->fcport->vha->vp_idx; + + int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); + host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); + + cmd_pkt->task = TSK_SIMPLE; + + /* Load SCSI command packet. */ + memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len); + host_to_fcp_swap(cmd_pkt->fcp_cdb, sizeof(cmd_pkt->fcp_cdb)); + + cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); + + /* Build IOCB segments */ + qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); + + /* Set total data segment count. */ + cmd_pkt->entry_count = (uint8_t)req_cnt; + wmb(); + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else + req->ring_ptr++; + + sp->flags |= SRB_DMA_VALID; + + /* Set chip new ring index. */ + WRT_REG_DWORD(req->req_q_in, req->ring_index); + + /* Manage unprocessed RIO/ZIO commands in response queue. */ + if (vha->flags.process_response_queue && + rsp->ring_ptr->signature != RESPONSE_PROCESSED) + qla24xx_process_response_queue(vha, rsp); + + spin_unlock_irqrestore(&qpair->qp_lock, flags); + return QLA_SUCCESS; + +queuing_error: + if (tot_dsds) + scsi_dma_unmap(cmd); + + spin_unlock_irqrestore(&qpair->qp_lock, flags); + + return QLA_FUNCTION_FAILED; +} + + +/** + * qla2xxx_dif_start_scsi_mq() - Send a SCSI command to the ISP + * @sp: command to send to the ISP + * + * Returns non-zero if a failure occurred, else zero. + */ +int +qla2xxx_dif_start_scsi_mq(srb_t *sp) +{ + int nseg; + unsigned long flags; + uint32_t *clr_ptr; + uint32_t index; + uint32_t handle; + uint16_t cnt; + uint16_t req_cnt = 0; + uint16_t tot_dsds; + uint16_t tot_prot_dsds; + uint16_t fw_prot_opts = 0; + struct req_que *req = NULL; + struct rsp_que *rsp = NULL; + struct scsi_cmnd *cmd = GET_CMD_SP(sp); + struct scsi_qla_host *vha = sp->fcport->vha; + struct qla_hw_data *ha = vha->hw; + struct cmd_type_crc_2 *cmd_pkt; + uint32_t status = 0; + struct qla_qpair *qpair = sp->qpair; + +#define QDSS_GOT_Q_SPACE BIT_0 + + /* Check for host side state */ + if (!qpair->online) { + cmd->result = DID_NO_CONNECT << 16; + return QLA_INTERFACE_ERROR; + } + + if (!qpair->difdix_supported && + scsi_get_prot_op(cmd) != SCSI_PROT_NORMAL) { + cmd->result = DID_NO_CONNECT << 16; + return QLA_INTERFACE_ERROR; + } + + /* Only process protection or >16 cdb in this routine */ + if (scsi_get_prot_op(cmd) == SCSI_PROT_NORMAL) { + if (cmd->cmd_len <= 16) + return qla2xxx_start_scsi_mq(sp); + } + + /* Setup qpair pointers */ + rsp = qpair->rsp; + req = qpair->req; + + /* So we know we haven't pci_map'ed anything yet */ + tot_dsds = 0; + + /* Send marker if required */ + if (vha->marker_needed != 0) { + if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + QLA_SUCCESS) + return QLA_FUNCTION_FAILED; + vha->marker_needed = 0; + } + + /* Acquire ring specific lock */ + spin_lock_irqsave(&qpair->qp_lock, flags); + + /* Check for room in outstanding command list. */ + handle = req->current_outstanding_cmd; + for (index = 1; index < req->num_outstanding_cmds; index++) { + handle++; + if (handle == req->num_outstanding_cmds) + handle = 1; + if (!req->outstanding_cmds[handle]) + break; + } + + if (index == req->num_outstanding_cmds) + goto queuing_error; + + /* Compute number of required data segments */ + /* Map the sg table so we have an accurate count of sg entries needed */ + if (scsi_sg_count(cmd)) { + nseg = dma_map_sg(&ha->pdev->dev, scsi_sglist(cmd), + scsi_sg_count(cmd), cmd->sc_data_direction); + if (unlikely(!nseg)) + goto queuing_error; + else + sp->flags |= SRB_DMA_VALID; + + if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || + (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { + struct qla2_sgx sgx; + uint32_t partial; + + memset(&sgx, 0, sizeof(struct qla2_sgx)); + sgx.tot_bytes = scsi_bufflen(cmd); + sgx.cur_sg = scsi_sglist(cmd); + sgx.sp = sp; + + nseg = 0; + while (qla24xx_get_one_block_sg( + cmd->device->sector_size, &sgx, &partial)) + nseg++; + } + } else + nseg = 0; + + /* number of required data segments */ + tot_dsds = nseg; + + /* Compute number of required protection segments */ + if (qla24xx_configure_prot_mode(sp, &fw_prot_opts)) { + nseg = dma_map_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), + scsi_prot_sg_count(cmd), cmd->sc_data_direction); + if (unlikely(!nseg)) + goto queuing_error; + else + sp->flags |= SRB_CRC_PROT_DMA_VALID; + + if ((scsi_get_prot_op(cmd) == SCSI_PROT_READ_INSERT) || + (scsi_get_prot_op(cmd) == SCSI_PROT_WRITE_STRIP)) { + nseg = scsi_bufflen(cmd) / cmd->device->sector_size; + } + } else { + nseg = 0; + } + + req_cnt = 1; + /* Total Data and protection sg segment(s) */ + tot_prot_dsds = nseg; + tot_dsds += nseg; + if (req->cnt < (req_cnt + 2)) { + cnt = IS_SHADOW_REG_CAPABLE(ha) ? *req->out_ptr : + RD_REG_DWORD_RELAXED(req->req_q_out); + if (req->ring_index < cnt) + req->cnt = cnt - req->ring_index; + else + req->cnt = req->length - + (req->ring_index - cnt); + if (req->cnt < (req_cnt + 2)) + goto queuing_error; + } + + status |= QDSS_GOT_Q_SPACE; + + /* Build header part of command packet (excluding the OPCODE). */ + req->current_outstanding_cmd = handle; + req->outstanding_cmds[handle] = sp; + sp->handle = handle; + cmd->host_scribble = (unsigned char *)(unsigned long)handle; + req->cnt -= req_cnt; + + /* Fill-in common area */ + cmd_pkt = (struct cmd_type_crc_2 *)req->ring_ptr; + cmd_pkt->handle = MAKE_HANDLE(req->id, handle); + + clr_ptr = (uint32_t *)cmd_pkt + 2; + memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8); + + /* Set NPORT-ID and LUN number*/ + cmd_pkt->nport_handle = cpu_to_le16(sp->fcport->loop_id); + cmd_pkt->port_id[0] = sp->fcport->d_id.b.al_pa; + cmd_pkt->port_id[1] = sp->fcport->d_id.b.area; + cmd_pkt->port_id[2] = sp->fcport->d_id.b.domain; - if (ha->flags.cpu_affinity_enabled && affinity >= 0 && - affinity < ha->max_rsp_queues - 1) - *rsp = ha->rsp_q_map[affinity + 1]; - else - *rsp = ha->rsp_q_map[0]; + int_to_scsilun(cmd->device->lun, &cmd_pkt->lun); + host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun)); + + /* Total Data and protection segment(s) */ + cmd_pkt->dseg_count = cpu_to_le16(tot_dsds); + + /* Build IOCB segments and adjust for data protection segments */ + if (qla24xx_build_scsi_crc_2_iocbs(sp, (struct cmd_type_crc_2 *) + req->ring_ptr, tot_dsds, tot_prot_dsds, fw_prot_opts) != + QLA_SUCCESS) + goto queuing_error; + + cmd_pkt->entry_count = (uint8_t)req_cnt; + cmd_pkt->timeout = cpu_to_le16(0); + wmb(); + + /* Adjust ring index. */ + req->ring_index++; + if (req->ring_index == req->length) { + req->ring_index = 0; + req->ring_ptr = req->ring; + } else + req->ring_ptr++; + + /* Set chip new ring index. */ + WRT_REG_DWORD(req->req_q_in, req->ring_index); + + /* Manage unprocessed RIO/ZIO commands in response queue. */ + if (vha->flags.process_response_queue && + rsp->ring_ptr->signature != RESPONSE_PROCESSED) + qla24xx_process_response_queue(vha, rsp); + + spin_unlock_irqrestore(&qpair->qp_lock, flags); + + return QLA_SUCCESS; + +queuing_error: + if (status & QDSS_GOT_Q_SPACE) { + req->outstanding_cmds[handle] = NULL; + req->cnt += req_cnt; + } + /* Cleanup will be performed by the caller (queuecommand) */ + + spin_unlock_irqrestore(&qpair->qp_lock, flags); + return QLA_FUNCTION_FAILED; } /* Generic Control-SRB manipulation functions. */ @@ -2664,7 +2991,7 @@ sufficient_dsds: cmd_pkt->byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd)); /* Build IOCB segments */ - qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds); + qla24xx_build_scsi_iocbs(sp, cmd_pkt, tot_dsds, req); /* Set total data segment count. */ cmd_pkt->entry_count = (uint8_t)req_cnt; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ad5304caf1ff..d27019b3ed74 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2870,41 +2870,6 @@ out: return IRQ_HANDLED; } -static irqreturn_t -qla25xx_msix_rsp_q(int irq, void *dev_id) -{ - struct qla_hw_data *ha; - scsi_qla_host_t *vha; - struct rsp_que *rsp; - struct device_reg_24xx __iomem *reg; - unsigned long flags; - uint32_t hccr = 0; - - rsp = (struct rsp_que *) dev_id; - if (!rsp) { - ql_log(ql_log_info, NULL, 0x505b, - "%s: NULL response queue pointer.\n", __func__); - return IRQ_NONE; - } - ha = rsp->hw; - vha = pci_get_drvdata(ha->pdev); - - /* Clear the interrupt, if enabled, for this response queue */ - if (!ha->flags.disable_msix_handshake) { - reg = &ha->iobase->isp24; - spin_lock_irqsave(&ha->hardware_lock, flags); - WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); - hccr = RD_REG_DWORD_RELAXED(®->hccr); - spin_unlock_irqrestore(&ha->hardware_lock, flags); - } - if (qla2x00_check_reg32_for_disconnect(vha, hccr)) - goto out; - queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work); - -out: - return IRQ_HANDLED; -} - static irqreturn_t qla24xx_msix_default(int irq, void *dev_id) { @@ -3001,6 +2966,35 @@ qla24xx_msix_default(int irq, void *dev_id) return IRQ_HANDLED; } +irqreturn_t +qla2xxx_msix_rsp_q(int irq, void *dev_id) +{ + struct qla_hw_data *ha; + struct qla_qpair *qpair; + struct device_reg_24xx __iomem *reg; + unsigned long flags; + + qpair = dev_id; + if (!qpair) { + ql_log(ql_log_info, NULL, 0x505b, + "%s: NULL response queue pointer.\n", __func__); + return IRQ_NONE; + } + ha = qpair->hw; + + /* Clear the interrupt, if enabled, for this response queue */ + if (unlikely(!ha->flags.disable_msix_handshake)) { + reg = &ha->iobase->isp24; + spin_lock_irqsave(&ha->hardware_lock, flags); + WRT_REG_DWORD(®->hccr, HCCRX_CLR_RISC_INT); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + } + + queue_work(ha->wq, &qpair->q_work); + + return IRQ_HANDLED; +} + /* Interrupt handling helpers. */ struct qla_init_msix_entry { @@ -3008,18 +3002,18 @@ struct qla_init_msix_entry { irq_handler_t handler; }; -static struct qla_init_msix_entry msix_entries[3] = { +static struct qla_init_msix_entry msix_entries[] = { { "qla2xxx (default)", qla24xx_msix_default }, { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, - { "qla2xxx (multiq)", qla25xx_msix_rsp_q }, + { "qla2xxx (qpair_multiq)", qla2xxx_msix_rsp_q }, }; -static struct qla_init_msix_entry qla82xx_msix_entries[2] = { +static struct qla_init_msix_entry qla82xx_msix_entries[] = { { "qla2xxx (default)", qla82xx_msix_default }, { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, }; -static struct qla_init_msix_entry qla83xx_msix_entries[3] = { +static struct qla_init_msix_entry qla83xx_msix_entries[] = { { "qla2xxx (default)", qla24xx_msix_default }, { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, { "qla2xxx (atio_q)", qla83xx_msix_atio_q }, @@ -3035,7 +3029,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); ret = pci_alloc_irq_vectors(ha->pdev, MIN_MSIX_COUNT, ha->msix_count, - PCI_IRQ_MSIX); + PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); if (ret < 0) { ql_log(ql_log_fatal, vha, 0x00c7, "MSI-X: Failed to enable support, " @@ -3045,10 +3039,23 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) } else if (ret < ha->msix_count) { ql_log(ql_log_warn, vha, 0x00c6, "MSI-X: Failed to enable support " - "-- %d/%d\n Retry with %d vectors.\n", - ha->msix_count, ret, ret); + "with %d vectors, using %d vectors.\n", + ha->msix_count, ret); ha->msix_count = ret; - ha->max_rsp_queues = ha->msix_count - 1; + /* Recalculate queue values */ + if (ha->mqiobase && ql2xmqsupport) { + ha->max_req_queues = ha->msix_count - 1; + + /* ATIOQ needs 1 vector. That's 1 less QPair */ + if (QLA_TGT_MODE_ENABLED()) + ha->max_req_queues--; + + ha->max_rsp_queues = ha->max_req_queues; + + ha->max_qpairs = ha->max_req_queues - 1; + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190, + "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs); + } } ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) * ha->msix_count, GFP_KERNEL); @@ -3065,6 +3072,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) qentry->vector = pci_irq_vector(ha->pdev, i); qentry->entry = i; qentry->have_irq = 0; + qentry->in_use = 0; qentry->handle = NULL; qentry->irq_notify.notify = qla_irq_affinity_notify; qentry->irq_notify.release = qla_irq_affinity_release; @@ -3076,6 +3084,8 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) qentry = &ha->msix_entries[i]; qentry->handle = rsp; rsp->msix = qentry; + scnprintf(qentry->name, sizeof(qentry->name), + msix_entries[i].name); if (IS_P3P_TYPE(ha)) ret = request_irq(qentry->vector, qla82xx_msix_entries[i].handler, @@ -3107,8 +3117,10 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) */ if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) { qentry = &ha->msix_entries[ATIO_VECTOR]; - qentry->handle = rsp; rsp->msix = qentry; + qentry->handle = rsp; + scnprintf(qentry->name, sizeof(qentry->name), + qla83xx_msix_entries[ATIO_VECTOR].name); ret = request_irq(qentry->vector, qla83xx_msix_entries[ATIO_VECTOR].handler, 0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp); @@ -3128,11 +3140,13 @@ msix_register_fail: /* Enable MSI-X vector for response queue update for queue 0 */ if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) { if (ha->msixbase && ha->mqiobase && - (ha->max_rsp_queues > 1 || ha->max_req_queues > 1)) + (ha->max_rsp_queues > 1 || ha->max_req_queues > 1 || + ql2xmqsupport)) ha->mqenable = 1; } else - if (ha->mqiobase - && (ha->max_rsp_queues > 1 || ha->max_req_queues > 1)) + if (ha->mqiobase && + (ha->max_rsp_queues > 1 || ha->max_req_queues > 1 || + ql2xmqsupport)) ha->mqenable = 1; ql_dbg(ql_dbg_multiq, vha, 0xc005, "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n", @@ -3270,16 +3284,16 @@ qla2x00_free_irqs(scsi_qla_host_t *vha) pci_free_irq_vectors(ha->pdev); } - -int qla25xx_request_irq(struct rsp_que *rsp) +int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair, + struct qla_msix_entry *msix, int vector_type) { - struct qla_hw_data *ha = rsp->hw; - struct qla_init_msix_entry *intr = &msix_entries[2]; - struct qla_msix_entry *msix = rsp->msix; + struct qla_init_msix_entry *intr = &msix_entries[vector_type]; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); int ret; - ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp); + scnprintf(msix->name, sizeof(msix->name), + "qla2xxx%lu_qpair%d", vha->host_no, qpair->id); + ret = request_irq(msix->vector, intr->handler, 0, msix->name, qpair); if (ret) { ql_log(ql_log_fatal, vha, 0x00e6, "MSI-X: Unable to register handler -- %x/%d.\n", @@ -3287,7 +3301,7 @@ int qla25xx_request_irq(struct rsp_que *rsp) return ret; } msix->have_irq = 1; - msix->handle = rsp; + msix->handle = qpair; return ret; } @@ -3333,6 +3347,6 @@ static void qla_irq_affinity_release(struct kref *ref) struct scsi_qla_host *base_vha = pci_get_drvdata(rsp->hw->pdev); ql_dbg(ql_dbg_init, base_vha, 0xffff, - "%s: host%ld: vector %d cpu %d \n", __func__, + "%s: host%ld: vector %d cpu %d\n", __func__, base_vha->host_no, e->vector, e->cpuid); } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index b31c36b251a6..2819ceb96041 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1246,12 +1246,17 @@ qla2x00_abort_command(srb_t *sp) fc_port_t *fcport = sp->fcport; scsi_qla_host_t *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; - struct req_que *req = vha->req; + struct req_que *req; struct scsi_cmnd *cmd = GET_CMD_SP(sp); ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103b, "Entered %s.\n", __func__); + if (vha->flags.qpairs_available && sp->qpair) + req = sp->qpair->req; + else + req = vha->req; + spin_lock_irqsave(&ha->hardware_lock, flags); for (handle = 1; handle < req->num_outstanding_cmds; handle++) { if (req->outstanding_cmds[handle] == sp) @@ -2204,10 +2209,10 @@ qla24xx_login_fabric(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1061, "Entered %s.\n", __func__); - if (ha->flags.cpu_affinity_enabled) - req = ha->req_q_map[0]; + if (vha->vp_idx && vha->qpair) + req = vha->qpair->req; else - req = vha->req; + req = ha->req_q_map[0]; lg = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &lg_dma); if (lg == NULL) { @@ -2487,10 +2492,7 @@ qla24xx_fabric_logout(scsi_qla_host_t *vha, uint16_t loop_id, uint8_t domain, } memset(lg, 0, sizeof(struct logio_entry_24xx)); - if (ql2xmaxqueues > 1) - req = ha->req_q_map[0]; - else - req = vha->req; + req = vha->req; lg->entry_type = LOGINOUT_PORT_IOCB_TYPE; lg->entry_count = 1; lg->handle = MAKE_HANDLE(req->id, lg->handle); @@ -2956,6 +2958,9 @@ qla24xx_abort_command(srb_t *sp) ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c, "Entered %s.\n", __func__); + if (vha->flags.qpairs_available && sp->qpair) + req = sp->qpair->req; + if (ql2xasynctmfenable) return qla24xx_async_abort_command(sp); @@ -3036,6 +3041,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, struct qla_hw_data *ha; struct req_que *req; struct rsp_que *rsp; + struct qla_qpair *qpair; vha = fcport->vha; ha = vha->hw; @@ -3044,10 +3050,15 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1092, "Entered %s.\n", __func__); - if (ha->flags.cpu_affinity_enabled) - rsp = ha->rsp_q_map[tag + 1]; - else + if (vha->vp_idx && vha->qpair) { + /* NPIV port */ + qpair = vha->qpair; + rsp = qpair->rsp; + req = qpair->req; + } else { rsp = req->rsp; + } + tsk = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); if (tsk == NULL) { ql_log(ql_log_warn, vha, 0x1093, diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 8e406fc35db4..c6d6f0d912ff 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -540,8 +540,9 @@ qla25xx_free_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) uint16_t que_id = rsp->id; if (rsp->msix && rsp->msix->have_irq) { - free_irq(rsp->msix->vector, rsp); + free_irq(rsp->msix->vector, rsp->msix->handle); rsp->msix->have_irq = 0; + rsp->msix->in_use = 0; rsp->msix->handle = NULL; } dma_free_coherent(&ha->pdev->dev, (rsp->length + 1) * @@ -573,7 +574,7 @@ qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req) return ret; } -static int +int qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp) { int ret = -1; @@ -596,34 +597,42 @@ qla25xx_delete_queues(struct scsi_qla_host *vha) struct req_que *req = NULL; struct rsp_que *rsp = NULL; struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair, *tqpair; - /* Delete request queues */ - for (cnt = 1; cnt < ha->max_req_queues; cnt++) { - req = ha->req_q_map[cnt]; - if (req && test_bit(cnt, ha->req_qid_map)) { - ret = qla25xx_delete_req_que(vha, req); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x00ea, - "Couldn't delete req que %d.\n", - req->id); - return ret; + if (ql2xmqsupport) { + list_for_each_entry_safe(qpair, tqpair, &vha->qp_list, + qp_list_elem) + qla2xxx_delete_qpair(vha, qpair); + } else { + /* Delete request queues */ + for (cnt = 1; cnt < ha->max_req_queues; cnt++) { + req = ha->req_q_map[cnt]; + if (req && test_bit(cnt, ha->req_qid_map)) { + ret = qla25xx_delete_req_que(vha, req); + if (ret != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x00ea, + "Couldn't delete req que %d.\n", + req->id); + return ret; + } } } - } - /* Delete response queues */ - for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) { - rsp = ha->rsp_q_map[cnt]; - if (rsp && test_bit(cnt, ha->rsp_qid_map)) { - ret = qla25xx_delete_rsp_que(vha, rsp); - if (ret != QLA_SUCCESS) { - ql_log(ql_log_warn, vha, 0x00eb, - "Couldn't delete rsp que %d.\n", - rsp->id); - return ret; + /* Delete response queues */ + for (cnt = 1; cnt < ha->max_rsp_queues; cnt++) { + rsp = ha->rsp_q_map[cnt]; + if (rsp && test_bit(cnt, ha->rsp_qid_map)) { + ret = qla25xx_delete_rsp_que(vha, rsp); + if (ret != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x00eb, + "Couldn't delete rsp que %d.\n", + rsp->id); + return ret; + } } } } + return ret; } @@ -659,10 +668,10 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, if (ret != QLA_SUCCESS) goto que_failed; - mutex_lock(&ha->vport_lock); + mutex_lock(&ha->mq_lock); que_id = find_first_zero_bit(ha->req_qid_map, ha->max_req_queues); if (que_id >= ha->max_req_queues) { - mutex_unlock(&ha->vport_lock); + mutex_unlock(&ha->mq_lock); ql_log(ql_log_warn, base_vha, 0x00db, "No resources to create additional request queue.\n"); goto que_failed; @@ -708,7 +717,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, req->req_q_out = ®->isp25mq.req_q_out; req->max_q_depth = ha->req_q_map[0]->max_q_depth; req->out_ptr = (void *)(req->ring + req->length); - mutex_unlock(&ha->vport_lock); + mutex_unlock(&ha->mq_lock); ql_dbg(ql_dbg_multiq, base_vha, 0xc004, "ring_ptr=%p ring_index=%d, " "cnt=%d id=%d max_q_depth=%d.\n", @@ -724,9 +733,9 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options, if (ret != QLA_SUCCESS) { ql_log(ql_log_fatal, base_vha, 0x00df, "%s failed.\n", __func__); - mutex_lock(&ha->vport_lock); + mutex_lock(&ha->mq_lock); clear_bit(que_id, ha->req_qid_map); - mutex_unlock(&ha->vport_lock); + mutex_unlock(&ha->mq_lock); goto que_failed; } @@ -741,20 +750,20 @@ failed: static void qla_do_work(struct work_struct *work) { unsigned long flags; - struct rsp_que *rsp = container_of(work, struct rsp_que, q_work); + struct qla_qpair *qpair = container_of(work, struct qla_qpair, q_work); struct scsi_qla_host *vha; - struct qla_hw_data *ha = rsp->hw; + struct qla_hw_data *ha = qpair->hw; - spin_lock_irqsave(&rsp->hw->hardware_lock, flags); + spin_lock_irqsave(&qpair->qp_lock, flags); vha = pci_get_drvdata(ha->pdev); - qla24xx_process_response_queue(vha, rsp); - spin_unlock_irqrestore(&rsp->hw->hardware_lock, flags); + qla24xx_process_response_queue(vha, qpair->rsp); + spin_unlock_irqrestore(&qpair->qp_lock, flags); } /* create response queue */ int qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, - uint8_t vp_idx, uint16_t rid, int req) + uint8_t vp_idx, uint16_t rid, struct qla_qpair *qpair) { int ret = 0; struct rsp_que *rsp = NULL; @@ -779,28 +788,24 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, goto que_failed; } - mutex_lock(&ha->vport_lock); + mutex_lock(&ha->mq_lock); que_id = find_first_zero_bit(ha->rsp_qid_map, ha->max_rsp_queues); if (que_id >= ha->max_rsp_queues) { - mutex_unlock(&ha->vport_lock); + mutex_unlock(&ha->mq_lock); ql_log(ql_log_warn, base_vha, 0x00e2, "No resources to create additional request queue.\n"); goto que_failed; } set_bit(que_id, ha->rsp_qid_map); - if (ha->flags.msix_enabled) - rsp->msix = &ha->msix_entries[que_id + 1]; - else - ql_log(ql_log_warn, base_vha, 0x00e3, - "MSIX not enabled.\n"); + rsp->msix = qpair->msix; ha->rsp_q_map[que_id] = rsp; rsp->rid = rid; rsp->vp_idx = vp_idx; rsp->hw = ha; ql_dbg(ql_dbg_init, base_vha, 0x00e4, - "queue_id=%d rid=%d vp_idx=%d hw=%p.\n", + "rsp queue_id=%d rid=%d vp_idx=%d hw=%p.\n", que_id, rsp->rid, rsp->vp_idx, rsp->hw); /* Use alternate PCI bus number */ if (MSB(rsp->rid)) @@ -812,23 +817,27 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, if (!IS_MSIX_NACK_CAPABLE(ha)) options |= BIT_6; + /* Set option to indicate response queue creation */ + options |= BIT_1; + rsp->options = options; rsp->id = que_id; reg = ISP_QUE_REG(ha, que_id); rsp->rsp_q_in = ®->isp25mq.rsp_q_in; rsp->rsp_q_out = ®->isp25mq.rsp_q_out; rsp->in_ptr = (void *)(rsp->ring + rsp->length); - mutex_unlock(&ha->vport_lock); + mutex_unlock(&ha->mq_lock); ql_dbg(ql_dbg_multiq, base_vha, 0xc00b, - "options=%x id=%d rsp_q_in=%p rsp_q_out=%p", + "options=%x id=%d rsp_q_in=%p rsp_q_out=%p\n", rsp->options, rsp->id, rsp->rsp_q_in, rsp->rsp_q_out); ql_dbg(ql_dbg_init, base_vha, 0x00e5, - "options=%x id=%d rsp_q_in=%p rsp_q_out=%p", + "options=%x id=%d rsp_q_in=%p rsp_q_out=%p\n", rsp->options, rsp->id, rsp->rsp_q_in, rsp->rsp_q_out); - ret = qla25xx_request_irq(rsp); + ret = qla25xx_request_irq(ha, qpair, qpair->msix, + QLA_MSIX_QPAIR_MULTIQ_RSP_Q); if (ret) goto que_failed; @@ -836,19 +845,16 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options, if (ret != QLA_SUCCESS) { ql_log(ql_log_fatal, base_vha, 0x00e7, "%s failed.\n", __func__); - mutex_lock(&ha->vport_lock); + mutex_lock(&ha->mq_lock); clear_bit(que_id, ha->rsp_qid_map); - mutex_unlock(&ha->vport_lock); + mutex_unlock(&ha->mq_lock); goto que_failed; } - if (req >= 0) - rsp->req = ha->req_q_map[req]; - else - rsp->req = NULL; + rsp->req = NULL; qla2x00_init_response_q_entries(rsp); - if (rsp->hw->wq) - INIT_WORK(&rsp->q_work, qla_do_work); + if (qpair->hw->wq) + INIT_WORK(&qpair->q_work, qla_do_work); return rsp->id; que_failed: diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 56d6142852a5..6ef32c932826 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -30,7 +30,7 @@ static int apidev_major; /* * SRB allocation cache */ -static struct kmem_cache *srb_cachep; +struct kmem_cache *srb_cachep; /* * CT6 CTX allocation cache @@ -143,19 +143,12 @@ MODULE_PARM_DESC(ql2xiidmaenable, "Enables iIDMA settings " "Default is 1 - perform iIDMA. 0 - no iIDMA."); -int ql2xmaxqueues = 1; -module_param(ql2xmaxqueues, int, S_IRUGO); -MODULE_PARM_DESC(ql2xmaxqueues, - "Enables MQ settings " - "Default is 1 for single queue. Set it to number " - "of queues in MQ mode."); - -int ql2xmultique_tag; -module_param(ql2xmultique_tag, int, S_IRUGO); -MODULE_PARM_DESC(ql2xmultique_tag, - "Enables CPU affinity settings for the driver " - "Default is 0 for no affinity of request and response IO. " - "Set it to 1 to turn on the cpu affinity."); +int ql2xmqsupport = 1; +module_param(ql2xmqsupport, int, S_IRUGO); +MODULE_PARM_DESC(ql2xmqsupport, + "Enable on demand multiple queue pairs support " + "Default is 1 for supported. " + "Set it to 0 to turn off mq qpair support."); int ql2xfwloadbin; module_param(ql2xfwloadbin, int, S_IRUGO|S_IWUSR); @@ -339,6 +332,8 @@ static int qla2x00_mem_alloc(struct qla_hw_data *, uint16_t, uint16_t, struct req_que **, struct rsp_que **); static void qla2x00_free_fw_dump(struct qla_hw_data *); static void qla2x00_mem_free(struct qla_hw_data *); +int qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, + struct qla_qpair *qpair); /* -------------------------------------------------------------------------- */ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, @@ -360,6 +355,25 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, "Unable to allocate memory for response queue ptrs.\n"); goto fail_rsp_map; } + + if (ql2xmqsupport && ha->max_qpairs) { + ha->queue_pair_map = kcalloc(ha->max_qpairs, sizeof(struct qla_qpair *), + GFP_KERNEL); + if (!ha->queue_pair_map) { + ql_log(ql_log_fatal, vha, 0x0180, + "Unable to allocate memory for queue pair ptrs.\n"); + goto fail_qpair_map; + } + ha->base_qpair = kzalloc(sizeof(struct qla_qpair), GFP_KERNEL); + if (ha->base_qpair == NULL) { + ql_log(ql_log_warn, vha, 0x0182, + "Failed to allocate base queue pair memory.\n"); + goto fail_base_qpair; + } + ha->base_qpair->req = req; + ha->base_qpair->rsp = rsp; + } + /* * Make sure we record at least the request and response queue zero in * case we need to free them if part of the probe fails. @@ -370,6 +384,11 @@ static int qla2x00_alloc_queues(struct qla_hw_data *ha, struct req_que *req, set_bit(0, ha->req_qid_map); return 1; +fail_base_qpair: + kfree(ha->queue_pair_map); +fail_qpair_map: + kfree(ha->rsp_q_map); + ha->rsp_q_map = NULL; fail_rsp_map: kfree(ha->req_q_map); ha->req_q_map = NULL; @@ -439,62 +458,6 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) ha->rsp_q_map = NULL; } -static int qla25xx_setup_mode(struct scsi_qla_host *vha) -{ - uint16_t options = 0; - int ques, req, ret; - struct qla_hw_data *ha = vha->hw; - - if (!(ha->fw_attributes & BIT_6)) { - ql_log(ql_log_warn, vha, 0x00d8, - "Firmware is not multi-queue capable.\n"); - goto fail; - } - if (ql2xmultique_tag) { - /* create a request queue for IO */ - options |= BIT_7; - req = qla25xx_create_req_que(ha, options, 0, 0, -1, - QLA_DEFAULT_QUE_QOS); - if (!req) { - ql_log(ql_log_warn, vha, 0x00e0, - "Failed to create request queue.\n"); - goto fail; - } - ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); - vha->req = ha->req_q_map[req]; - options |= BIT_1; - for (ques = 1; ques < ha->max_rsp_queues; ques++) { - ret = qla25xx_create_rsp_que(ha, options, 0, 0, req); - if (!ret) { - ql_log(ql_log_warn, vha, 0x00e8, - "Failed to create response queue.\n"); - goto fail2; - } - } - ha->flags.cpu_affinity_enabled = 1; - ql_dbg(ql_dbg_multiq, vha, 0xc007, - "CPU affinity mode enabled, " - "no. of response queues:%d no. of request queues:%d.\n", - ha->max_rsp_queues, ha->max_req_queues); - ql_dbg(ql_dbg_init, vha, 0x00e9, - "CPU affinity mode enabled, " - "no. of response queues:%d no. of request queues:%d.\n", - ha->max_rsp_queues, ha->max_req_queues); - } - return 0; -fail2: - qla25xx_delete_queues(vha); - destroy_workqueue(ha->wq); - ha->wq = NULL; - vha->req = ha->req_q_map[0]; -fail: - ha->mqenable = 0; - kfree(ha->req_q_map); - kfree(ha->rsp_q_map); - ha->max_req_queues = ha->max_rsp_queues = 1; - return 1; -} - static char * qla2x00_pci_info_str(struct scsi_qla_host *vha, char *str) { @@ -669,7 +632,7 @@ qla2x00_sp_free_dma(void *vha, void *ptr) qla2x00_rel_sp(sp->fcport->vha, sp); } -static void +void qla2x00_sp_compl(void *data, void *ptr, int res) { struct qla_hw_data *ha = (struct qla_hw_data *)data; @@ -693,6 +656,75 @@ qla2x00_sp_compl(void *data, void *ptr, int res) cmd->scsi_done(cmd); } +void +qla2xxx_qpair_sp_free_dma(void *vha, void *ptr) +{ + srb_t *sp = (srb_t *)ptr; + struct scsi_cmnd *cmd = GET_CMD_SP(sp); + struct qla_hw_data *ha = sp->fcport->vha->hw; + void *ctx = GET_CMD_CTX_SP(sp); + + if (sp->flags & SRB_DMA_VALID) { + scsi_dma_unmap(cmd); + sp->flags &= ~SRB_DMA_VALID; + } + + if (sp->flags & SRB_CRC_PROT_DMA_VALID) { + dma_unmap_sg(&ha->pdev->dev, scsi_prot_sglist(cmd), + scsi_prot_sg_count(cmd), cmd->sc_data_direction); + sp->flags &= ~SRB_CRC_PROT_DMA_VALID; + } + + if (sp->flags & SRB_CRC_CTX_DSD_VALID) { + /* List assured to be having elements */ + qla2x00_clean_dsd_pool(ha, sp, NULL); + sp->flags &= ~SRB_CRC_CTX_DSD_VALID; + } + + if (sp->flags & SRB_CRC_CTX_DMA_VALID) { + dma_pool_free(ha->dl_dma_pool, ctx, + ((struct crc_context *)ctx)->crc_ctx_dma); + sp->flags &= ~SRB_CRC_CTX_DMA_VALID; + } + + if (sp->flags & SRB_FCP_CMND_DMA_VALID) { + struct ct6_dsd *ctx1 = (struct ct6_dsd *)ctx; + + dma_pool_free(ha->fcp_cmnd_dma_pool, ctx1->fcp_cmnd, + ctx1->fcp_cmnd_dma); + list_splice(&ctx1->dsd_list, &ha->gbl_dsd_list); + ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; + ha->gbl_dsd_avail += ctx1->dsd_use_cnt; + mempool_free(ctx1, ha->ctx_mempool); + } + + CMD_SP(cmd) = NULL; + qla2xxx_rel_qpair_sp(sp->qpair, sp); +} + +void +qla2xxx_qpair_sp_compl(void *data, void *ptr, int res) +{ + srb_t *sp = (srb_t *)ptr; + struct scsi_cmnd *cmd = GET_CMD_SP(sp); + + cmd->result = res; + + if (atomic_read(&sp->ref_count) == 0) { + ql_dbg(ql_dbg_io, sp->fcport->vha, 0x3079, + "SP reference-count to ZERO -- sp=%p cmd=%p.\n", + sp, GET_CMD_SP(sp)); + if (ql2xextended_error_logging & ql_dbg_io) + WARN_ON(atomic_read(&sp->ref_count) == 0); + return; + } + if (!atomic_dec_and_test(&sp->ref_count)) + return; + + qla2xxx_qpair_sp_free_dma(sp->fcport->vha, sp); + cmd->scsi_done(cmd); +} + /* If we are SP1 here, we need to still take and release the host_lock as SP1 * does not have the changes necessary to avoid taking host->host_lock. */ @@ -706,12 +738,18 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); srb_t *sp; int rval; + struct qla_qpair *qpair; if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) { cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; } + if (vha->vp_idx && vha->qpair) { + qpair = vha->qpair; + return qla2xxx_mqueuecommand(host, cmd, qpair); + } + if (ha->flags.eeh_busy) { if (ha->flags.pci_channel_io_perm_failure) { ql_dbg(ql_dbg_aer, vha, 0x9010, @@ -808,6 +846,95 @@ qc24_fail_command: return 0; } +/* For MQ supported I/O */ +int +qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, + struct qla_qpair *qpair) +{ + scsi_qla_host_t *vha = shost_priv(host); + fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata; + struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device)); + struct qla_hw_data *ha = vha->hw; + struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); + srb_t *sp; + int rval; + + rval = fc_remote_port_chkready(rport); + if (rval) { + cmd->result = rval; + ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3076, + "fc_remote_port_chkready failed for cmd=%p, rval=0x%x.\n", + cmd, rval); + goto qc24_fail_command; + } + + if (!fcport) { + cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } + + if (atomic_read(&fcport->state) != FCS_ONLINE) { + if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD || + atomic_read(&base_vha->loop_state) == LOOP_DEAD) { + ql_dbg(ql_dbg_io, vha, 0x3077, + "Returning DNC, fcport_state=%d loop_state=%d.\n", + atomic_read(&fcport->state), + atomic_read(&base_vha->loop_state)); + cmd->result = DID_NO_CONNECT << 16; + goto qc24_fail_command; + } + goto qc24_target_busy; + } + + /* + * Return target busy if we've received a non-zero retry_delay_timer + * in a FCP_RSP. + */ + if (fcport->retry_delay_timestamp == 0) { + /* retry delay not set */ + } else if (time_after(jiffies, fcport->retry_delay_timestamp)) + fcport->retry_delay_timestamp = 0; + else + goto qc24_target_busy; + + sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC); + if (!sp) + goto qc24_host_busy; + + sp->u.scmd.cmd = cmd; + sp->type = SRB_SCSI_CMD; + atomic_set(&sp->ref_count, 1); + CMD_SP(cmd) = (void *)sp; + sp->free = qla2xxx_qpair_sp_free_dma; + sp->done = qla2xxx_qpair_sp_compl; + sp->qpair = qpair; + + rval = ha->isp_ops->start_scsi_mq(sp); + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3078, + "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd); + if (rval == QLA_INTERFACE_ERROR) + goto qc24_fail_command; + goto qc24_host_busy_free_sp; + } + + return 0; + +qc24_host_busy_free_sp: + qla2xxx_qpair_sp_free_dma(vha, sp); + +qc24_host_busy: + return SCSI_MLQUEUE_HOST_BUSY; + +qc24_target_busy: + return SCSI_MLQUEUE_TARGET_BUSY; + +qc24_fail_command: + cmd->scsi_done(cmd); + + return 0; +} + /* * qla2x00_eh_wait_on_command * Waits for the command to be returned by the Firmware for some @@ -1601,7 +1728,6 @@ qla2x00_iospace_config(struct qla_hw_data *ha) { resource_size_t pio; uint16_t msix; - int cpus; if (pci_request_selected_regions(ha->pdev, ha->bars, QLA2XXX_DRIVER_NAME)) { @@ -1658,9 +1784,7 @@ skip_pio: /* Determine queue resources */ ha->max_req_queues = ha->max_rsp_queues = 1; - if ((ql2xmaxqueues <= 1 && !ql2xmultique_tag) || - (ql2xmaxqueues > 1 && ql2xmultique_tag) || - (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) + if (!ql2xmqsupport || (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))) goto mqiobase_exit; ha->mqiobase = ioremap(pci_resource_start(ha->pdev, 3), @@ -1670,26 +1794,18 @@ skip_pio: "MQIO Base=%p.\n", ha->mqiobase); /* Read MSIX vector size of the board */ pci_read_config_word(ha->pdev, QLA_PCI_MSIX_CONTROL, &msix); - ha->msix_count = msix; + ha->msix_count = msix + 1; /* Max queues are bounded by available msix vectors */ - /* queue 0 uses two msix vectors */ - if (ql2xmultique_tag) { - cpus = num_online_cpus(); - ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ? - (cpus + 1) : (ha->msix_count - 1); - ha->max_req_queues = 2; - } else if (ql2xmaxqueues > 1) { - ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? - QLA_MQ_SIZE : ql2xmaxqueues; - ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc008, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0019, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - } + /* MB interrupt uses 1 vector */ + ha->max_req_queues = ha->msix_count - 1; + ha->max_rsp_queues = ha->max_req_queues; + /* Queue pairs is the max value minus the base queue pair */ + ha->max_qpairs = ha->max_rsp_queues - 1; + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0188, + "Max no of queues pairs: %d.\n", ha->max_qpairs); + ql_log_pci(ql_log_info, ha->pdev, 0x001a, - "MSI-X vector count: %d.\n", msix); + "MSI-X vector count: %d.\n", ha->msix_count); } else ql_log_pci(ql_log_info, ha->pdev, 0x001b, "BAR 3 not enabled.\n"); @@ -1709,7 +1825,6 @@ static int qla83xx_iospace_config(struct qla_hw_data *ha) { uint16_t msix; - int cpus; if (pci_request_selected_regions(ha->pdev, ha->bars, QLA2XXX_DRIVER_NAME)) { @@ -1761,26 +1876,23 @@ qla83xx_iospace_config(struct qla_hw_data *ha) /* Read MSIX vector size of the board */ pci_read_config_word(ha->pdev, QLA_83XX_PCI_MSIX_CONTROL, &msix); - ha->msix_count = msix; + ha->msix_count = msix + 1; /* Max queues are bounded by available msix vectors */ /* queue 0 uses two msix vectors */ - if (ql2xmultique_tag) { - cpus = num_online_cpus(); - ha->max_rsp_queues = (ha->msix_count - 1 > cpus) ? - (cpus + 1) : (ha->msix_count - 1); - ha->max_req_queues = 2; - } else if (ql2xmaxqueues > 1) { - ha->max_req_queues = ql2xmaxqueues > QLA_MQ_SIZE ? - QLA_MQ_SIZE : ql2xmaxqueues; - ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc00c, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); - ql_dbg_pci(ql_dbg_init, ha->pdev, 0x011b, - "QoS mode set, max no of request queues:%d.\n", - ha->max_req_queues); + if (ql2xmqsupport) { + /* MB interrupt uses 1 vector */ + ha->max_req_queues = ha->msix_count - 1; + ha->max_rsp_queues = ha->max_req_queues; + /* Queue pairs is the max value minus + * the base queue pair */ + ha->max_qpairs = ha->max_req_queues - 1; + ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc010, + "Max no of queues pairs: %d.\n", ha->max_qpairs); + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190, + "Max no of queues pairs: %d.\n", ha->max_qpairs); } ql_log_pci(ql_log_info, ha->pdev, 0x011c, - "MSI-X vector count: %d.\n", msix); + "MSI-X vector count: %d.\n", ha->msix_count); } else ql_log_pci(ql_log_info, ha->pdev, 0x011e, "BAR 1 not enabled.\n"); @@ -1831,6 +1943,7 @@ static struct isp_operations qla2100_isp_ops = { .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, + .start_scsi_mq = NULL, .abort_isp = qla2x00_abort_isp, .iospace_config = qla2x00_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -1869,6 +1982,7 @@ static struct isp_operations qla2300_isp_ops = { .write_optrom = qla2x00_write_optrom_data, .get_flash_version = qla2x00_get_flash_version, .start_scsi = qla2x00_start_scsi, + .start_scsi_mq = NULL, .abort_isp = qla2x00_abort_isp, .iospace_config = qla2x00_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -1907,6 +2021,7 @@ static struct isp_operations qla24xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_start_scsi, + .start_scsi_mq = NULL, .abort_isp = qla2x00_abort_isp, .iospace_config = qla2x00_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -1945,6 +2060,7 @@ static struct isp_operations qla25xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_dif_start_scsi, + .start_scsi_mq = qla2xxx_dif_start_scsi_mq, .abort_isp = qla2x00_abort_isp, .iospace_config = qla2x00_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -1983,6 +2099,7 @@ static struct isp_operations qla81xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_dif_start_scsi, + .start_scsi_mq = qla2xxx_dif_start_scsi_mq, .abort_isp = qla2x00_abort_isp, .iospace_config = qla2x00_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -2021,6 +2138,7 @@ static struct isp_operations qla82xx_isp_ops = { .write_optrom = qla82xx_write_optrom_data, .get_flash_version = qla82xx_get_flash_version, .start_scsi = qla82xx_start_scsi, + .start_scsi_mq = NULL, .abort_isp = qla82xx_abort_isp, .iospace_config = qla82xx_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -2059,6 +2177,7 @@ static struct isp_operations qla8044_isp_ops = { .write_optrom = qla8044_write_optrom_data, .get_flash_version = qla82xx_get_flash_version, .start_scsi = qla82xx_start_scsi, + .start_scsi_mq = NULL, .abort_isp = qla8044_abort_isp, .iospace_config = qla82xx_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -2097,6 +2216,7 @@ static struct isp_operations qla83xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_dif_start_scsi, + .start_scsi_mq = qla2xxx_dif_start_scsi_mq, .abort_isp = qla2x00_abort_isp, .iospace_config = qla83xx_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -2135,6 +2255,7 @@ static struct isp_operations qlafx00_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qlafx00_start_scsi, + .start_scsi_mq = NULL, .abort_isp = qlafx00_abort_isp, .iospace_config = qlafx00_iospace_config, .initialize_adapter = qlafx00_initialize_adapter, @@ -2173,6 +2294,7 @@ static struct isp_operations qla27xx_isp_ops = { .write_optrom = qla24xx_write_optrom_data, .get_flash_version = qla24xx_get_flash_version, .start_scsi = qla24xx_dif_start_scsi, + .start_scsi_mq = qla2xxx_dif_start_scsi_mq, .abort_isp = qla2x00_abort_isp, .iospace_config = qla83xx_iospace_config, .initialize_adapter = qla2x00_initialize_adapter, @@ -2387,6 +2509,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) uint16_t req_length = 0, rsp_length = 0; struct req_que *req = NULL; struct rsp_que *rsp = NULL; + bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); sht = &qla2xxx_driver_template; if (pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2422 || @@ -2650,6 +2773,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) "Found an ISP%04X irq %d iobase 0x%p.\n", pdev->device, pdev->irq, ha->iobase); mutex_init(&ha->vport_lock); + mutex_init(&ha->mq_lock); init_completion(&ha->mbx_cmd_comp); complete(&ha->mbx_cmd_comp); init_completion(&ha->mbx_intr_comp); @@ -2737,7 +2861,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->max_cmd_len, host->max_channel, host->max_lun, host->transportt, sht->vendor_id); -que_init: + /* Set up the irqs */ + ret = qla2x00_request_irqs(ha, rsp); + if (ret) + goto probe_init_failed; + /* Alloc arrays of request and response ring ptrs */ if (!qla2x00_alloc_queues(ha, req, rsp)) { ql_log(ql_log_fatal, base_vha, 0x003d, @@ -2748,11 +2876,6 @@ que_init: qlt_probe_one_stage1(base_vha, ha); - /* Set up the irqs */ - ret = qla2x00_request_irqs(ha, rsp); - if (ret) - goto probe_init_failed; - pci_save_state(pdev); /* Assign back pointers */ @@ -2842,13 +2965,8 @@ que_init: host->can_queue, base_vha->req, base_vha->mgmt_svr_loop_id, host->sg_tablesize); - if (ha->mqenable) { - if (qla25xx_setup_mode(base_vha)) { - ql_log(ql_log_warn, base_vha, 0x00ec, - "Failed to create queues, falling back to single queue mode.\n"); - goto que_init; - } - } + if (ha->mqenable) + ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); if (ha->flags.running_gold_fw) goto skip_dpc; @@ -4034,6 +4152,7 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, INIT_LIST_HEAD(&vha->qla_sess_op_cmd_list); INIT_LIST_HEAD(&vha->logo_list); INIT_LIST_HEAD(&vha->plogi_ack_list); + INIT_LIST_HEAD(&vha->qp_list); spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); @@ -5073,6 +5192,8 @@ qla2x00_do_dpc(void *data) { scsi_qla_host_t *base_vha; struct qla_hw_data *ha; + uint32_t online; + struct qla_qpair *qpair; ha = (struct qla_hw_data *)data; base_vha = pci_get_drvdata(ha->pdev); @@ -5334,6 +5455,22 @@ intr_on_check: ha->isp_ops->beacon_blink(base_vha); } + /* qpair online check */ + if (test_and_clear_bit(QPAIR_ONLINE_CHECK_NEEDED, + &base_vha->dpc_flags)) { + if (ha->flags.eeh_busy || + ha->flags.pci_channel_io_perm_failure) + online = 0; + else + online = 1; + + mutex_lock(&ha->mq_lock); + list_for_each_entry(qpair, &base_vha->qp_list, + qp_list_elem) + qpair->online = online; + mutex_unlock(&ha->mq_lock); + } + if (!IS_QLAFX00(ha)) qla2x00_do_dpc_all_vps(base_vha); @@ -5676,6 +5813,10 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) switch (state) { case pci_channel_io_normal: ha->flags.eeh_busy = 0; + if (ql2xmqsupport) { + set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_frozen: ha->flags.eeh_busy = 1; @@ -5689,10 +5830,18 @@ qla2xxx_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) pci_disable_device(pdev); /* Return back all IOs */ qla2x00_abort_all_cmds(vha, DID_RESET << 16); + if (ql2xmqsupport) { + set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } return PCI_ERS_RESULT_NEED_RESET; case pci_channel_io_perm_failure: ha->flags.pci_channel_io_perm_failure = 1; qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16); + if (ql2xmqsupport) { + set_bit(QPAIR_ONLINE_CHECK_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } return PCI_ERS_RESULT_DISCONNECT; } return PCI_ERS_RESULT_NEED_RESET; -- cgit v1.2.3 From 5601236b6f7948cd1783298f6d4cacce02e22fde Mon Sep 17 00:00:00 2001 From: Michael Hernandez Date: Mon, 12 Dec 2016 14:40:08 -0800 Subject: scsi: qla2xxx: Add Block Multi Queue functionality. Tell the SCSI layer how many hardware queues we have based on the number of max queue pairs created. The number of max queue pairs created will depend on number of MSI-X vector count. This feature can be turned on via CONFIG_SCSI_MQ_DEFAULT or passing scsi_mod.use_blk_mq=Y as a parameter to the kernel Reviewed-by: Hannes Reinecke Signed-off-by: Sawan Chandak Signed-off-by: Michael Hernandez Signed-off-by: Himanshu Madhani Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 47 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 6ef32c932826..d10a8763caaf 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -254,6 +255,7 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *); static void qla2x00_clear_drv_active(struct qla_hw_data *); static void qla2x00_free_device(scsi_qla_host_t *); static void qla83xx_disable_laser(scsi_qla_host_t *vha); +static int qla2xxx_map_queues(struct Scsi_Host *shost); struct scsi_host_template qla2xxx_driver_template = { .module = THIS_MODULE, @@ -273,6 +275,7 @@ struct scsi_host_template qla2xxx_driver_template = { .scan_finished = qla2xxx_scan_finished, .scan_start = qla2xxx_scan_start, .change_queue_depth = scsi_change_queue_depth, + .map_queues = qla2xxx_map_queues, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -738,16 +741,26 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); srb_t *sp; int rval; - struct qla_qpair *qpair; + struct qla_qpair *qpair = NULL; + uint32_t tag; + uint16_t hwq; if (unlikely(test_bit(UNLOADING, &base_vha->dpc_flags))) { cmd->result = DID_NO_CONNECT << 16; goto qc24_fail_command; } - if (vha->vp_idx && vha->qpair) { - qpair = vha->qpair; - return qla2xxx_mqueuecommand(host, cmd, qpair); + if (ha->mqenable) { + if (shost_use_blk_mq(vha->host)) { + tag = blk_mq_unique_tag(cmd->request); + hwq = blk_mq_unique_tag_to_hwq(tag); + qpair = ha->queue_pair_map[hwq]; + } else if (vha->vp_idx && vha->qpair) { + qpair = vha->qpair; + } + + if (qpair) + return qla2xxx_mqueuecommand(host, cmd, qpair); } if (ha->flags.eeh_busy) { @@ -2509,6 +2522,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) uint16_t req_length = 0, rsp_length = 0; struct req_que *req = NULL; struct rsp_que *rsp = NULL; + int i; bars = pci_select_bars(pdev, IORESOURCE_MEM | IORESOURCE_IO); sht = &qla2xxx_driver_template; @@ -2874,6 +2888,16 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_init_failed; } + if (ha->mqenable && shost_use_blk_mq(host)) { + /* number of hardware queues supported by blk/scsi-mq*/ + host->nr_hw_queues = ha->max_qpairs; + + ql_dbg(ql_dbg_init, base_vha, 0x0192, + "blk/scsi-mq enabled, HW queues = %d.\n", host->nr_hw_queues); + } else + ql_dbg(ql_dbg_init, base_vha, 0x0193, + "blk/scsi-mq disabled.\n"); + qlt_probe_one_stage1(base_vha, ha); pci_save_state(pdev); @@ -2965,8 +2989,14 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->can_queue, base_vha->req, base_vha->mgmt_svr_loop_id, host->sg_tablesize); - if (ha->mqenable) + if (ha->mqenable) { ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); + /* Create start of day qpairs for Block MQ */ + if (shost_use_blk_mq(host)) { + for (i = 0; i < ha->max_qpairs; i++) + qla2xxx_create_qpair(base_vha, 5, 0); + } + } if (ha->flags.running_gold_fw) goto skip_dpc; @@ -6109,6 +6139,13 @@ qla83xx_disable_laser(scsi_qla_host_t *vha) qla83xx_wr_reg(vha, reg, data); } +static int qla2xxx_map_queues(struct Scsi_Host *shost) +{ + scsi_qla_host_t *vha = (scsi_qla_host_t *)shost->hostdata; + + return blk_mq_pci_map_queues(&shost->tag_set, vha->hw->pdev); +} + static const struct pci_error_handlers qla2xxx_err_handler = { .error_detected = qla2xxx_pci_error_detected, .mmio_enabled = qla2xxx_pci_mmio_enabled, -- cgit v1.2.3 From 093df73771bac8a37d607c0e705d157a8cef4c5c Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 12 Dec 2016 14:40:09 -0800 Subject: scsi: qla2xxx: Fix Target mode handling with Multiqueue changes. - Fix race condition between dpc_thread accessing Multiqueue resources and qla2x00_remove_one thread trying to free resource. - Fix out of order free for Multiqueue resources. Also, Multiqueue interrupts needs a workqueue. Interrupt needed to stop before the wq can be destroyed. Reviewed-by: Hannes Reinecke Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Reviewed-by: Christoph Hellwig Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 3 ++- drivers/scsi/qla2xxx/qla_init.c | 2 +- drivers/scsi/qla2xxx/qla_isr.c | 20 +++++++--------- drivers/scsi/qla2xxx/qla_os.c | 53 ++++++++++++++++++++++++++++++----------- 4 files changed, 50 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index d60cd1737ee6..f7df01b76714 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2734,7 +2734,8 @@ struct isp_operations { #define QLA_MSIX_DEFAULT 0x00 #define QLA_MSIX_RSP_Q 0x01 -#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x02 +#define QLA_ATIO_VECTOR 0x02 +#define QLA_MSIX_QPAIR_MULTIQ_RSP_Q 0x03 #define QLA_MIDX_DEFAULT 0 #define QLA_MIDX_RSP_Q 1 diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 400ffd1894ee..632d5f30386a 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -6764,7 +6764,7 @@ struct qla_qpair *qla2xxx_create_qpair(struct scsi_qla_host *vha, int qos, int v qpair->vp_idx = vp_idx; for (i = 0; i < ha->msix_count; i++) { - msix = &ha->msix_entries[i + 2]; + msix = &ha->msix_entries[i]; if (msix->in_use) continue; qpair->msix = msix; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index d27019b3ed74..af840bf587d5 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3005,6 +3005,7 @@ struct qla_init_msix_entry { static struct qla_init_msix_entry msix_entries[] = { { "qla2xxx (default)", qla24xx_msix_default }, { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, + { "qla2xxx (atio_q)", qla83xx_msix_atio_q }, { "qla2xxx (qpair_multiq)", qla2xxx_msix_rsp_q }, }; @@ -3013,17 +3014,10 @@ static struct qla_init_msix_entry qla82xx_msix_entries[] = { { "qla2xxx (rsp_q)", qla82xx_msix_rsp_q }, }; -static struct qla_init_msix_entry qla83xx_msix_entries[] = { - { "qla2xxx (default)", qla24xx_msix_default }, - { "qla2xxx (rsp_q)", qla24xx_msix_rsp_q }, - { "qla2xxx (atio_q)", qla83xx_msix_atio_q }, -}; - static int qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) { #define MIN_MSIX_COUNT 2 -#define ATIO_VECTOR 2 int i, ret; struct qla_msix_entry *qentry; scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev); @@ -3080,7 +3074,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) } /* Enable MSI-X vectors for the base queue */ - for (i = 0; i < 2; i++) { + for (i = 0; i < (QLA_MSIX_RSP_Q + 1); i++) { qentry = &ha->msix_entries[i]; qentry->handle = rsp; rsp->msix = qentry; @@ -3097,6 +3091,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) if (ret) goto msix_register_fail; qentry->have_irq = 1; + qentry->in_use = 1; /* Register for CPU affinity notification. */ irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify); @@ -3116,14 +3111,15 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) * queue. */ if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) { - qentry = &ha->msix_entries[ATIO_VECTOR]; + qentry = &ha->msix_entries[QLA_ATIO_VECTOR]; rsp->msix = qentry; qentry->handle = rsp; scnprintf(qentry->name, sizeof(qentry->name), - qla83xx_msix_entries[ATIO_VECTOR].name); + msix_entries[QLA_ATIO_VECTOR].name); + qentry->in_use = 1; ret = request_irq(qentry->vector, - qla83xx_msix_entries[ATIO_VECTOR].handler, - 0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp); + msix_entries[QLA_ATIO_VECTOR].handler, + 0, msix_entries[QLA_ATIO_VECTOR].name, rsp); qentry->have_irq = 1; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index d10a8763caaf..8521cfe302e9 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -439,24 +439,41 @@ static void qla2x00_free_queues(struct qla_hw_data *ha) struct req_que *req; struct rsp_que *rsp; int cnt; + unsigned long flags; + spin_lock_irqsave(&ha->hardware_lock, flags); for (cnt = 0; cnt < ha->max_req_queues; cnt++) { if (!test_bit(cnt, ha->req_qid_map)) continue; req = ha->req_q_map[cnt]; + clear_bit(cnt, ha->req_qid_map); + ha->req_q_map[cnt] = NULL; + + spin_unlock_irqrestore(&ha->hardware_lock, flags); qla2x00_free_req_que(ha, req); + spin_lock_irqsave(&ha->hardware_lock, flags); } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + kfree(ha->req_q_map); ha->req_q_map = NULL; + + spin_lock_irqsave(&ha->hardware_lock, flags); for (cnt = 0; cnt < ha->max_rsp_queues; cnt++) { if (!test_bit(cnt, ha->rsp_qid_map)) continue; rsp = ha->rsp_q_map[cnt]; + clear_bit(cnt, ha->req_qid_map); + ha->rsp_q_map[cnt] = NULL; + spin_unlock_irqrestore(&ha->hardware_lock, flags); qla2x00_free_rsp_que(ha, rsp); + spin_lock_irqsave(&ha->hardware_lock, flags); } + spin_unlock_irqrestore(&ha->hardware_lock, flags); + kfree(ha->rsp_q_map); ha->rsp_q_map = NULL; } @@ -1890,17 +1907,22 @@ qla83xx_iospace_config(struct qla_hw_data *ha) pci_read_config_word(ha->pdev, QLA_83XX_PCI_MSIX_CONTROL, &msix); ha->msix_count = msix + 1; - /* Max queues are bounded by available msix vectors */ - /* queue 0 uses two msix vectors */ + /* + * By default, driver uses at least two msix vectors + * (default & rspq) + */ if (ql2xmqsupport) { /* MB interrupt uses 1 vector */ ha->max_req_queues = ha->msix_count - 1; ha->max_rsp_queues = ha->max_req_queues; + + /* ATIOQ needs 1 vector. That's 1 less QPair */ + if (QLA_TGT_MODE_ENABLED()) + ha->max_req_queues--; + /* Queue pairs is the max value minus * the base queue pair */ ha->max_qpairs = ha->max_req_queues - 1; - ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc010, - "Max no of queues pairs: %d.\n", ha->max_qpairs); ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190, "Max no of queues pairs: %d.\n", ha->max_qpairs); } @@ -1912,6 +1934,8 @@ qla83xx_iospace_config(struct qla_hw_data *ha) mqiobase_exit: ha->msix_count = ha->max_rsp_queues + 1; + if (QLA_TGT_MODE_ENABLED()) + ha->msix_count++; qlt_83xx_iospace_config(ha); @@ -2989,7 +3013,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host->can_queue, base_vha->req, base_vha->mgmt_svr_loop_id, host->sg_tablesize); - if (ha->mqenable) { + if (ha->mqenable && qla_ini_mode_enabled(base_vha)) { ha->wq = alloc_workqueue("qla2xxx_wq", WQ_MEM_RECLAIM, 1); /* Create start of day qpairs for Block MQ */ if (shost_use_blk_mq(host)) { @@ -3263,13 +3287,6 @@ qla2x00_delete_all_vps(struct qla_hw_data *ha, scsi_qla_host_t *base_vha) static void qla2x00_destroy_deferred_work(struct qla_hw_data *ha) { - /* Flush the work queue and remove it */ - if (ha->wq) { - flush_workqueue(ha->wq); - destroy_workqueue(ha->wq); - ha->wq = NULL; - } - /* Cancel all work and destroy DPC workqueues */ if (ha->dpc_lp_wq) { cancel_work_sync(&ha->idc_aen); @@ -3465,9 +3482,17 @@ qla2x00_free_device(scsi_qla_host_t *vha) ha->isp_ops->disable_intrs(ha); } + qla2x00_free_fcports(vha); + qla2x00_free_irqs(vha); - qla2x00_free_fcports(vha); + /* Flush the work queue and remove it */ + if (ha->wq) { + flush_workqueue(ha->wq); + destroy_workqueue(ha->wq); + ha->wq = NULL; + } + qla2x00_mem_free(ha); @@ -5187,8 +5212,8 @@ qla2x00_disable_board_on_pci_error(struct work_struct *work) base_vha->flags.init_done = 0; qla25xx_delete_queues(base_vha); - qla2x00_free_irqs(base_vha); qla2x00_free_fcports(base_vha); + qla2x00_free_irqs(base_vha); qla2x00_mem_free(ha); qla82xx_md_free(base_vha); qla2x00_free_queues(ha); -- cgit v1.2.3 From 307d9075a02b696e817b775c565e45c4fa3c32f2 Mon Sep 17 00:00:00 2001 From: Adam Manzanares Date: Mon, 12 Dec 2016 16:31:40 -0800 Subject: scsi: mpt3sas: Recognize and act on iopriority info This patch adds support for request iopriority handling in the mpt3sas layer. This works only when a ATA device is behind the SATL. The ATA device also has to indicate that it supports command priorities in the identify information that is pulled from the SATL. Signed-off-by: Adam Manzanares Acked-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 6 +++++ drivers/scsi/mpt3sas/mpt3sas_ctl.c | 43 ++++++++++++++++++++++++++++++++++-- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 34 +++++++++++++++++++++++++++- 3 files changed, 80 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 8de0eda8cd00..394fe1338d09 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -402,6 +402,9 @@ struct MPT3SAS_DEVICE { u8 block; u8 tlr_snoop_check; u8 ignore_delay_remove; + /* Iopriority Command Handling */ + u8 ncq_prio_enable; + }; #define MPT3_CMD_NOT_USED 0x8000 /* free */ @@ -1458,4 +1461,7 @@ mpt3sas_setup_direct_io(struct MPT3SAS_ADAPTER *ioc, struct scsi_cmnd *scmd, struct _raid_device *raid_device, Mpi2SCSIIORequest_t *mpi_request, u16 smid); +/* NCQ Prio Handling Check */ +bool scsih_ncq_prio_supp(struct scsi_device *sdev); + #endif /* MPT3SAS_BASE_H_INCLUDED */ diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 050bd788ad02..95f0f24bac05 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -3325,8 +3325,6 @@ static DEVICE_ATTR(diag_trigger_mpi, S_IRUGO | S_IWUSR, /*********** diagnostic trigger suppport *** END ****************************/ - - /*****************************************/ struct device_attribute *mpt3sas_host_attrs[] = { @@ -3402,9 +3400,50 @@ _ctl_device_handle_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR(sas_device_handle, S_IRUGO, _ctl_device_handle_show, NULL); +/** + * _ctl_device_ncq_io_prio_show - send prioritized io commands to device + * @dev - pointer to embedded device + * @buf - the buffer returned + * + * A sysfs 'read/write' sdev attribute, only works with SATA + */ +static ssize_t +_ctl_device_ncq_prio_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; + + return snprintf(buf, PAGE_SIZE, "%d\n", + sas_device_priv_data->ncq_prio_enable); +} + +static ssize_t +_ctl_device_ncq_prio_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct MPT3SAS_DEVICE *sas_device_priv_data = sdev->hostdata; + bool ncq_prio_enable = 0; + + if (kstrtobool(buf, &ncq_prio_enable)) + return -EINVAL; + + if (!scsih_ncq_prio_supp(sdev)) + return -EINVAL; + + sas_device_priv_data->ncq_prio_enable = ncq_prio_enable; + return strlen(buf); +} +static DEVICE_ATTR(sas_ncq_prio_enable, S_IRUGO | S_IWUSR, + _ctl_device_ncq_prio_enable_show, + _ctl_device_ncq_prio_enable_store); + struct device_attribute *mpt3sas_dev_attrs[] = { &dev_attr_sas_address, &dev_attr_sas_device_handle, + &dev_attr_sas_ncq_prio_enable, NULL, }; diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 5c8f75247d73..b5c966e319d3 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -4053,6 +4053,8 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) struct MPT3SAS_DEVICE *sas_device_priv_data; struct MPT3SAS_TARGET *sas_target_priv_data; struct _raid_device *raid_device; + struct request *rq = scmd->request; + int class; Mpi2SCSIIORequest_t *mpi_request; u32 mpi_control; u16 smid; @@ -4115,7 +4117,12 @@ scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd) /* set tags */ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ; - + /* NCQ Prio supported, make sure control indicated high priority */ + if (sas_device_priv_data->ncq_prio_enable) { + class = IOPRIO_PRIO_CLASS(req_get_ioprio(rq)); + if (class == IOPRIO_CLASS_RT) + mpi_control |= 1 << MPI2_SCSIIO_CONTROL_CMDPRI_SHIFT; + } /* Make sure Device is not raid volume. * We do not expose raid functionality to upper layer for warpdrive. */ @@ -9099,6 +9106,31 @@ scsih_pci_mmio_enabled(struct pci_dev *pdev) return PCI_ERS_RESULT_RECOVERED; } +/** + * scsih__ncq_prio_supp - Check for NCQ command priority support + * @sdev: scsi device struct + * + * This is called when a user indicates they would like to enable + * ncq command priorities. This works only on SATA devices. + */ +bool scsih_ncq_prio_supp(struct scsi_device *sdev) +{ + unsigned char *buf; + bool ncq_prio_supp = false; + + if (!scsi_device_supports_vpd(sdev)) + return ncq_prio_supp; + + buf = kmalloc(SCSI_VPD_PG_LEN, GFP_KERNEL); + if (!buf) + return ncq_prio_supp; + + if (!scsi_get_vpd_page(sdev, 0x89, buf, SCSI_VPD_PG_LEN)) + ncq_prio_supp = (buf[213] >> 4) & 1; + + kfree(buf); + return ncq_prio_supp; +} /* * The pci device ids are defined in mpi/mpi2_cnfg.h. */ -- cgit v1.2.3 From d2a145252c52792bc59e4767b486b26c430af4bb Mon Sep 17 00:00:00 2001 From: Wei Fang Date: Tue, 13 Dec 2016 09:25:21 +0800 Subject: scsi: avoid a permanent stop of the scsi device's request queue A race between scanning and fc_remote_port_delete() may result in a permanent stop if the device gets blocked before scsi_sysfs_add_sdev() and unblocked after. The reason is that blocking a device sets both the SDEV_BLOCKED state and the QUEUE_FLAG_STOPPED. However, scsi_sysfs_add_sdev() unconditionally sets SDEV_RUNNING which causes the device to be ignored by scsi_target_unblock() and thus never have its QUEUE_FLAG_STOPPED cleared leading to a device which is apparently running but has a stopped queue. We actually have two places where SDEV_RUNNING is set: once in scsi_add_lun() which respects the blocked flag and once in scsi_sysfs_add_sdev() which doesn't. Since the second set is entirely spurious, simply remove it to fix the problem. Cc: Reported-by: Zengxi Chen Signed-off-by: Wei Fang Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_sysfs.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 07349270535d..82dfe07b1d47 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1204,10 +1204,6 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) struct request_queue *rq = sdev->request_queue; struct scsi_target *starget = sdev->sdev_target; - error = scsi_device_set_state(sdev, SDEV_RUNNING); - if (error) - return error; - error = scsi_target_add(starget); if (error) return error; -- cgit v1.2.3 From 5be5955425c22df5e25ee0628b57f523437af6dc Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 14 Dec 2016 15:05:30 -0800 Subject: igb: update driver to make use of DMA_ATTR_SKIP_CPU_SYNC The ARM architecture provides a mechanism for deferring cache line invalidation in the case of map/unmap. This patch makes use of this mechanism to avoid unnecessary synchronization. A secondary effect of this change is that the portion of the page that has been synchronized for use by the CPU should be writable and could be passed up the stack (at least on ARM). The last bit that occurred to me is that on architectures where the sync_for_cpu call invalidates cache lines we were prefetching and then invalidating the first 128 bytes of the packet. To avoid that I have moved the sync up to before we perform the prefetch and allocate the skbuff so that we can actually make use of it. Link: http://lkml.kernel.org/r/20161110113611.76501.98897.stgit@ahduyck-blue-test.jf.intel.com Signed-off-by: Alexander Duyck Acked-by: Jeff Kirsher Cc: "David S. Miller" Cc: "James E.J. Bottomley" Cc: Chris Metcalf Cc: David Howells Cc: Geert Uytterhoeven Cc: Hans-Christian Noren Egtvedt Cc: Helge Deller Cc: James Hogan Cc: Jonas Bonn Cc: Keguang Zhang Cc: Ley Foon Tan Cc: Mark Salter Cc: Max Filippov Cc: Michael Ellerman Cc: Michal Simek Cc: Ralf Baechle Cc: Rich Felker Cc: Richard Kuo Cc: Russell King Cc: Steven Miao Cc: Tobias Klauser Cc: Vineet Gupta Cc: Yoshinori Sato Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/ethernet/intel/igb/igb_main.c | 53 +++++++++++++++++++------------ 1 file changed, 33 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index cae24a8ccf47..60f122531e29 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3947,10 +3947,21 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring) if (!buffer_info->page) continue; - dma_unmap_page(rx_ring->dev, - buffer_info->dma, - PAGE_SIZE, - DMA_FROM_DEVICE); + /* Invalidate cache lines that may have been written to by + * device so that we avoid corrupting memory. + */ + dma_sync_single_range_for_cpu(rx_ring->dev, + buffer_info->dma, + buffer_info->page_offset, + IGB_RX_BUFSZ, + DMA_FROM_DEVICE); + + /* free resources associated with mapping */ + dma_unmap_page_attrs(rx_ring->dev, + buffer_info->dma, + PAGE_SIZE, + DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); __free_page(buffer_info->page); buffer_info->page = NULL; @@ -6812,12 +6823,6 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring, /* transfer page from old buffer to new buffer */ *new_buff = *old_buff; - - /* sync the buffer for use by the device */ - dma_sync_single_range_for_device(rx_ring->dev, old_buff->dma, - old_buff->page_offset, - IGB_RX_BUFSZ, - DMA_FROM_DEVICE); } static inline bool igb_page_is_reserved(struct page *page) @@ -6938,6 +6943,13 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring, page = rx_buffer->page; prefetchw(page); + /* we are reusing so sync this buffer for CPU use */ + dma_sync_single_range_for_cpu(rx_ring->dev, + rx_buffer->dma, + rx_buffer->page_offset, + size, + DMA_FROM_DEVICE); + if (likely(!skb)) { void *page_addr = page_address(page) + rx_buffer->page_offset; @@ -6962,21 +6974,15 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring, prefetchw(skb->data); } - /* we are reusing so sync this buffer for CPU use */ - dma_sync_single_range_for_cpu(rx_ring->dev, - rx_buffer->dma, - rx_buffer->page_offset, - size, - DMA_FROM_DEVICE); - /* pull page into skb */ if (igb_add_rx_frag(rx_ring, rx_buffer, size, rx_desc, skb)) { /* hand second half of page back to the ring */ igb_reuse_rx_page(rx_ring, rx_buffer); } else { /* we are not reusing the buffer so unmap it */ - dma_unmap_page(rx_ring->dev, rx_buffer->dma, - PAGE_SIZE, DMA_FROM_DEVICE); + dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, + PAGE_SIZE, DMA_FROM_DEVICE, + DMA_ATTR_SKIP_CPU_SYNC); } /* clear contents of rx_buffer */ @@ -7234,7 +7240,8 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring, } /* map page for use */ - dma = dma_map_page(rx_ring->dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE); + dma = dma_map_page_attrs(rx_ring->dev, page, 0, PAGE_SIZE, + DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); /* if mapping failed free memory back to system since * there isn't much point in holding memory we can't use @@ -7275,6 +7282,12 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count) if (!igb_alloc_mapped_page(rx_ring, bi)) break; + /* sync the buffer for use by the device */ + dma_sync_single_range_for_device(rx_ring->dev, bi->dma, + bi->page_offset, + IGB_RX_BUFSZ, + DMA_FROM_DEVICE); + /* Refresh the desc even if buffer_addrs didn't change * because each write-back erases this info. */ -- cgit v1.2.3 From bd4171a5d4c2827f4ae7a235389648d7c149a41b Mon Sep 17 00:00:00 2001 From: Alexander Duyck Date: Wed, 14 Dec 2016 15:05:34 -0800 Subject: igb: update code to better handle incrementing page count Update the driver code so that we do bulk updates of the page reference count instead of just incrementing it by one reference at a time. The advantage to doing this is that we cut down on atomic operations and this in turn should give us a slight improvement in cycles per packet. In addition if we eventually move this over to using build_skb the gains will be more noticeable. Link: http://lkml.kernel.org/r/20161110113616.76501.17072.stgit@ahduyck-blue-test.jf.intel.com Signed-off-by: Alexander Duyck Acked-by: Jeff Kirsher Cc: "David S. Miller" Cc: "James E.J. Bottomley" Cc: Chris Metcalf Cc: David Howells Cc: Geert Uytterhoeven Cc: Hans-Christian Noren Egtvedt Cc: Helge Deller Cc: James Hogan Cc: Jonas Bonn Cc: Keguang Zhang Cc: Ley Foon Tan Cc: Mark Salter Cc: Max Filippov Cc: Michael Ellerman Cc: Michal Simek Cc: Ralf Baechle Cc: Rich Felker Cc: Richard Kuo Cc: Russell King Cc: Steven Miao Cc: Tobias Klauser Cc: Vineet Gupta Cc: Yoshinori Sato Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/ethernet/intel/igb/igb.h | 7 ++++++- drivers/net/ethernet/intel/igb/igb_main.c | 24 +++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h index d11093dce1b9..acbc3abe2ddd 100644 --- a/drivers/net/ethernet/intel/igb/igb.h +++ b/drivers/net/ethernet/intel/igb/igb.h @@ -210,7 +210,12 @@ struct igb_tx_buffer { struct igb_rx_buffer { dma_addr_t dma; struct page *page; - unsigned int page_offset; +#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) + __u32 page_offset; +#else + __u16 page_offset; +#endif + __u16 pagecnt_bias; }; struct igb_tx_queue_stats { diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c index 60f122531e29..a761001308dc 100644 --- a/drivers/net/ethernet/intel/igb/igb_main.c +++ b/drivers/net/ethernet/intel/igb/igb_main.c @@ -3962,7 +3962,8 @@ static void igb_clean_rx_ring(struct igb_ring *rx_ring) PAGE_SIZE, DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); - __free_page(buffer_info->page); + __page_frag_drain(buffer_info->page, 0, + buffer_info->pagecnt_bias); buffer_info->page = NULL; } @@ -6834,13 +6835,15 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, struct page *page, unsigned int truesize) { + unsigned int pagecnt_bias = rx_buffer->pagecnt_bias--; + /* avoid re-using remote pages */ if (unlikely(igb_page_is_reserved(page))) return false; #if (PAGE_SIZE < 8192) /* if we are only owner of page we can reuse it */ - if (unlikely(page_count(page) != 1)) + if (unlikely(page_ref_count(page) != pagecnt_bias)) return false; /* flip page offset to other buffer */ @@ -6853,10 +6856,14 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer, return false; #endif - /* Even if we own the page, we are not allowed to use atomic_set() - * This would break get_page_unless_zero() users. + /* If we have drained the page fragment pool we need to update + * the pagecnt_bias and page count so that we fully restock the + * number of references the driver holds. */ - page_ref_inc(page); + if (unlikely(pagecnt_bias == 1)) { + page_ref_add(page, USHRT_MAX); + rx_buffer->pagecnt_bias = USHRT_MAX; + } return true; } @@ -6908,7 +6915,6 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring, return true; /* this page cannot be reused so discard it */ - __free_page(page); return false; } @@ -6979,10 +6985,13 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring, /* hand second half of page back to the ring */ igb_reuse_rx_page(rx_ring, rx_buffer); } else { - /* we are not reusing the buffer so unmap it */ + /* We are not reusing the buffer so unmap it and free + * any references we are holding to it + */ dma_unmap_page_attrs(rx_ring->dev, rx_buffer->dma, PAGE_SIZE, DMA_FROM_DEVICE, DMA_ATTR_SKIP_CPU_SYNC); + __page_frag_drain(page, 0, rx_buffer->pagecnt_bias); } /* clear contents of rx_buffer */ @@ -7256,6 +7265,7 @@ static bool igb_alloc_mapped_page(struct igb_ring *rx_ring, bi->dma = dma; bi->page = page; bi->page_offset = 0; + bi->pagecnt_bias = 1; return true; } -- cgit v1.2.3 From b5fc8c6c000aa083a671cd8f1736d04081bf65aa Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Wed, 14 Dec 2016 15:06:15 -0800 Subject: drivers/net/wireless/intel/iwlwifi/dvm/calib.c: simplfy min() expression This cast is no longer needed. Cc: Johannes Berg Cc: Emmanuel Grumbach Cc: Intel Linux Wireless Cc: Kalle Valo Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/net/wireless/intel/iwlwifi/dvm/calib.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c index e9cef9de9ed8..c96f9b1d948a 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/calib.c +++ b/drivers/net/wireless/intel/iwlwifi/dvm/calib.c @@ -900,8 +900,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv, /* bound gain by 2 bits value max, 3rd bit is sign */ data->delta_gain_code[i] = - min(abs(delta_g), - (s32) CHAIN_NOISE_MAX_DELTA_GAIN_CODE); + min(abs(delta_g), CHAIN_NOISE_MAX_DELTA_GAIN_CODE); if (delta_g < 0) /* -- cgit v1.2.3 From 5b56d49fc31dbb0487e14ead790fc81ca9fb2c99 Mon Sep 17 00:00:00 2001 From: Lorenzo Stoakes Date: Wed, 14 Dec 2016 15:06:52 -0800 Subject: mm: add locked parameter to get_user_pages_remote() Patch series "mm: unexport __get_user_pages_unlocked()". This patch series continues the cleanup of get_user_pages*() functions taking advantage of the fact we can now pass gup_flags as we please. It firstly adds an additional 'locked' parameter to get_user_pages_remote() to allow for its callers to utilise VM_FAULT_RETRY functionality. This is necessary as the invocation of __get_user_pages_unlocked() in process_vm_rw_single_vec() makes use of this and no other existing higher level function would allow it to do so. Secondly existing callers of __get_user_pages_unlocked() are replaced with the appropriate higher-level replacement - get_user_pages_unlocked() if the current task and memory descriptor are referenced, or get_user_pages_remote() if other task/memory descriptors are referenced (having acquiring mmap_sem.) This patch (of 2): Add a int *locked parameter to get_user_pages_remote() to allow VM_FAULT_RETRY faulting behaviour similar to get_user_pages_[un]locked(). Taking into account the previous adjustments to get_user_pages*() functions allowing for the passing of gup_flags, we are now in a position where __get_user_pages_unlocked() need only be exported for his ability to allow VM_FAULT_RETRY behaviour, this adjustment allows us to subsequently unexport __get_user_pages_unlocked() as well as allowing for future flexibility in the use of get_user_pages_remote(). [sfr@canb.auug.org.au: merge fix for get_user_pages_remote API change] Link: http://lkml.kernel.org/r/20161122210511.024ec341@canb.auug.org.au Link: http://lkml.kernel.org/r/20161027095141.2569-2-lstoakes@gmail.com Signed-off-by: Lorenzo Stoakes Acked-by: Michal Hocko Cc: Jan Kara Cc: Hugh Dickins Cc: Dave Hansen Cc: Rik van Riel Cc: Mel Gorman Cc: Paolo Bonzini Cc: Radim Krcmar Signed-off-by: Stephen Rothwell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 2 +- drivers/gpu/drm/i915/i915_gem_userptr.c | 2 +- drivers/infiniband/core/umem_odp.c | 2 +- drivers/vfio/vfio_iommu_type1.c | 2 +- fs/exec.c | 2 +- include/linux/mm.h | 2 +- kernel/events/uprobes.c | 4 ++-- mm/gup.c | 12 ++++++++---- mm/memory.c | 2 +- security/tomoyo/domain.c | 2 +- 10 files changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 7d066a91d778..6f5dfabb3096 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -759,7 +759,7 @@ static struct page **etnaviv_gem_userptr_do_get_pages( down_read(&mm->mmap_sem); while (pinned < npages) { ret = get_user_pages_remote(task, mm, ptr, npages - pinned, - flags, pvec + pinned, NULL); + flags, pvec + pinned, NULL, NULL); if (ret < 0) break; diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index 107ddf51065e..d068af2ec3a3 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c @@ -515,7 +515,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work) obj->userptr.ptr + pinned * PAGE_SIZE, npages - pinned, flags, - pvec + pinned, NULL); + pvec + pinned, NULL, NULL); if (ret < 0) break; diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c index 1f0fe3217f23..6b079a31dced 100644 --- a/drivers/infiniband/core/umem_odp.c +++ b/drivers/infiniband/core/umem_odp.c @@ -578,7 +578,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt, */ npages = get_user_pages_remote(owning_process, owning_mm, user_virt, gup_num_pages, - flags, local_page_list, NULL); + flags, local_page_list, NULL, NULL); up_read(&owning_mm->mmap_sem); if (npages < 0) diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c index 9815e45c23c4..f3726ba12aa6 100644 --- a/drivers/vfio/vfio_iommu_type1.c +++ b/drivers/vfio/vfio_iommu_type1.c @@ -362,7 +362,7 @@ static int vaddr_get_pfn(struct mm_struct *mm, unsigned long vaddr, down_read(&mm->mmap_sem); ret = get_user_pages_remote(NULL, mm, vaddr, 1, flags, page, - NULL); + NULL, NULL); up_read(&mm->mmap_sem); } diff --git a/fs/exec.c b/fs/exec.c index 923c57d96899..eac60886b0ab 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -209,7 +209,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, * doing the exec and bprm->mm is the new process's mm. */ ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags, - &page, NULL); + &page, NULL, NULL); if (ret <= 0) return NULL; diff --git a/include/linux/mm.h b/include/linux/mm.h index a92c8d73aeaf..cc154454675a 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -1274,7 +1274,7 @@ extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, - struct vm_area_struct **vmas); + struct vm_area_struct **vmas, int *locked); long get_user_pages(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, struct vm_area_struct **vmas); diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index f9ec9add2164..215871bda3a2 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c @@ -301,7 +301,7 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, retry: /* Read the page with vaddr into memory */ ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page, - &vma); + &vma, NULL); if (ret <= 0) return ret; @@ -1712,7 +1712,7 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr) * essentially a kernel access to the memory. */ result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page, - NULL); + NULL, NULL); if (result < 0) return result; diff --git a/mm/gup.c b/mm/gup.c index e50178c58b97..b64c907aa4f0 100644 --- a/mm/gup.c +++ b/mm/gup.c @@ -917,6 +917,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked); * only intends to ensure the pages are faulted in. * @vmas: array of pointers to vmas corresponding to each page. * Or NULL if the caller does not require them. + * @locked: pointer to lock flag indicating whether lock is held and + * subsequently whether VM_FAULT_RETRY functionality can be + * utilised. Lock must initially be held. * * Returns number of pages pinned. This may be fewer than the number * requested. If nr_pages is 0 or negative, returns 0. If no pages @@ -960,10 +963,10 @@ EXPORT_SYMBOL(get_user_pages_unlocked); long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, - struct vm_area_struct **vmas) + struct vm_area_struct **vmas, int *locked) { return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas, - NULL, false, + locked, true, gup_flags | FOLL_TOUCH | FOLL_REMOTE); } EXPORT_SYMBOL(get_user_pages_remote); @@ -971,8 +974,9 @@ EXPORT_SYMBOL(get_user_pages_remote); /* * This is the same as get_user_pages_remote(), just with a * less-flexible calling convention where we assume that the task - * and mm being operated on are the current task's. We also - * obviously don't pass FOLL_REMOTE in here. + * and mm being operated on are the current task's and don't allow + * passing of a locked parameter. We also obviously don't pass + * FOLL_REMOTE in here. */ long get_user_pages(unsigned long start, unsigned long nr_pages, unsigned int gup_flags, struct page **pages, diff --git a/mm/memory.c b/mm/memory.c index c264f7cd3e47..3a6a1239c42b 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -3919,7 +3919,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, struct page *page = NULL; ret = get_user_pages_remote(tsk, mm, addr, 1, - gup_flags, &page, &vma); + gup_flags, &page, &vma, NULL); if (ret <= 0) { #ifndef CONFIG_HAVE_IOREMAP_PROT break; diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c index 682b73af7766..838ffa78cfda 100644 --- a/security/tomoyo/domain.c +++ b/security/tomoyo/domain.c @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos, * the execve(). */ if (get_user_pages_remote(current, bprm->mm, pos, 1, - FOLL_FORCE, &page, NULL) <= 0) + FOLL_FORCE, &page, NULL, NULL) <= 0) return false; #else page = bprm->page[pos / PAGE_SIZE]; -- cgit v1.2.3 From 1a29d85eb0f19b7d8271923d8917d7b4f5540b3e Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Wed, 14 Dec 2016 15:07:01 -0800 Subject: mm: use vmf->address instead of of vmf->virtual_address Every single user of vmf->virtual_address typed that entry to unsigned long before doing anything with it so the type of virtual_address does not really provide us any additional safety. Just use masked vmf->address which already has the appropriate type. Link: http://lkml.kernel.org/r/1479460644-25076-3-git-send-email-jack@suse.cz Signed-off-by: Jan Kara Acked-by: Kirill A. Shutemov Cc: Dan Williams Cc: Ross Zwisler Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/powerpc/platforms/cell/spufs/file.c | 8 +++----- arch/x86/entry/vdso/vma.c | 4 ++-- drivers/char/agp/alpha-agp.c | 3 +-- drivers/char/mspec.c | 2 +- drivers/dax/dax.c | 3 +-- drivers/gpu/drm/armada/armada_gem.c | 5 ++--- drivers/gpu/drm/drm_vm.c | 10 +++++----- drivers/gpu/drm/etnaviv/etnaviv_gem.c | 7 +++---- drivers/gpu/drm/exynos/exynos_drm_gem.c | 6 ++---- drivers/gpu/drm/gma500/framebuffer.c | 2 +- drivers/gpu/drm/gma500/gem.c | 5 ++--- drivers/gpu/drm/i915/i915_gem.c | 3 +-- drivers/gpu/drm/msm/msm_gem.c | 8 +++----- drivers/gpu/drm/omapdrm/omap_gem.c | 20 ++++++++------------ drivers/gpu/drm/tegra/gem.c | 4 ++-- drivers/gpu/drm/ttm/ttm_bo_vm.c | 2 +- drivers/gpu/drm/udl/udl_gem.c | 5 ++--- drivers/gpu/drm/vgem/vgem_drv.c | 2 +- drivers/media/v4l2-core/videobuf-dma-sg.c | 5 ++--- drivers/misc/cxl/context.c | 5 ++--- drivers/misc/sgi-gru/grumain.c | 2 +- drivers/staging/android/ion/ion.c | 2 +- drivers/staging/lustre/lustre/llite/vvp_io.c | 6 +++--- drivers/xen/privcmd.c | 2 +- fs/dax.c | 4 ++-- include/linux/mm.h | 2 -- mm/memory.c | 9 ++++----- 27 files changed, 57 insertions(+), 79 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 06254467e4dd..3a147122bc98 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -236,7 +236,6 @@ static int spufs_mem_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct spu_context *ctx = vma->vm_file->private_data; - unsigned long address = (unsigned long)vmf->virtual_address; unsigned long pfn, offset; offset = vmf->pgoff << PAGE_SHIFT; @@ -244,7 +243,7 @@ spufs_mem_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; pr_debug("spufs_mem_mmap_fault address=0x%lx, offset=0x%lx\n", - address, offset); + vmf->address, offset); if (spu_acquire(ctx)) return VM_FAULT_NOPAGE; @@ -256,7 +255,7 @@ spufs_mem_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) vma->vm_page_prot = pgprot_noncached_wc(vma->vm_page_prot); pfn = (ctx->spu->local_store_phys + offset) >> PAGE_SHIFT; } - vm_insert_pfn(vma, address, pfn); + vm_insert_pfn(vma, vmf->address, pfn); spu_release(ctx); @@ -355,8 +354,7 @@ static int spufs_ps_fault(struct vm_area_struct *vma, down_read(¤t->mm->mmap_sem); } else { area = ctx->spu->problem_phys + ps_offs; - vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, - (area + offset) >> PAGE_SHIFT); + vm_insert_pfn(vma, vmf->address, (area + offset) >> PAGE_SHIFT); spu_context_trace(spufs_ps_fault__insert, ctx, ctx->spu); } diff --git a/arch/x86/entry/vdso/vma.c b/arch/x86/entry/vdso/vma.c index e739002427ed..40121d14d34d 100644 --- a/arch/x86/entry/vdso/vma.c +++ b/arch/x86/entry/vdso/vma.c @@ -109,7 +109,7 @@ static int vvar_fault(const struct vm_special_mapping *sm, return VM_FAULT_SIGBUS; if (sym_offset == image->sym_vvar_page) { - ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, + ret = vm_insert_pfn(vma, vmf->address, __pa_symbol(&__vvar_page) >> PAGE_SHIFT); } else if (sym_offset == image->sym_pvclock_page) { struct pvclock_vsyscall_time_info *pvti = @@ -117,7 +117,7 @@ static int vvar_fault(const struct vm_special_mapping *sm, if (pvti && vclock_was_used(VCLOCK_PVCLOCK)) { ret = vm_insert_pfn( vma, - (unsigned long)vmf->virtual_address, + vmf->address, __pa(pvti) >> PAGE_SHIFT); } } diff --git a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c index 199b8e99f7d7..737187865269 100644 --- a/drivers/char/agp/alpha-agp.c +++ b/drivers/char/agp/alpha-agp.c @@ -19,8 +19,7 @@ static int alpha_core_agp_vm_fault(struct vm_area_struct *vma, unsigned long pa; struct page *page; - dma_addr = (unsigned long)vmf->virtual_address - vma->vm_start - + agp->aperture.bus_base; + dma_addr = vmf->address - vma->vm_start + agp->aperture.bus_base; pa = agp->ops->translate(agp, dma_addr); if (pa == (unsigned long)-EINVAL) diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index f3f92d5fcda0..a697ca0cab1e 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -227,7 +227,7 @@ mspec_fault(struct vm_area_struct *vma, struct vm_fault *vmf) * be because another thread has installed the pte first, so it * is no problem. */ - vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); + vm_insert_pfn(vma, vmf->address, pfn); return VM_FAULT_NOPAGE; } diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 286447a83dab..26ec39ddf21f 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -328,7 +328,6 @@ static phys_addr_t pgoff_to_phys(struct dax_dev *dax_dev, pgoff_t pgoff, static int __dax_dev_fault(struct dax_dev *dax_dev, struct vm_area_struct *vma, struct vm_fault *vmf) { - unsigned long vaddr = (unsigned long) vmf->virtual_address; struct device *dev = &dax_dev->dev; struct dax_region *dax_region; int rc = VM_FAULT_SIGBUS; @@ -353,7 +352,7 @@ static int __dax_dev_fault(struct dax_dev *dax_dev, struct vm_area_struct *vma, pfn = phys_to_pfn_t(phys, dax_region->pfn_flags); - rc = vm_insert_mixed(vma, vaddr, pfn); + rc = vm_insert_mixed(vma, vmf->address, pfn); if (rc == -ENOMEM) return VM_FAULT_OOM; diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c index 768087ddb046..a293c8be232c 100644 --- a/drivers/gpu/drm/armada/armada_gem.c +++ b/drivers/gpu/drm/armada/armada_gem.c @@ -17,12 +17,11 @@ static int armada_gem_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct armada_gem_object *obj = drm_to_armada_gem(vma->vm_private_data); - unsigned long addr = (unsigned long)vmf->virtual_address; unsigned long pfn = obj->phys_addr >> PAGE_SHIFT; int ret; - pfn += (addr - vma->vm_start) >> PAGE_SHIFT; - ret = vm_insert_pfn(vma, addr, pfn); + pfn += (vmf->address - vma->vm_start) >> PAGE_SHIFT; + ret = vm_insert_pfn(vma, vmf->address, pfn); switch (ret) { case 0: diff --git a/drivers/gpu/drm/drm_vm.c b/drivers/gpu/drm/drm_vm.c index caa4e4ca616d..bd311c77c254 100644 --- a/drivers/gpu/drm/drm_vm.c +++ b/drivers/gpu/drm/drm_vm.c @@ -124,8 +124,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) * Using vm_pgoff as a selector forces us to use this unusual * addressing scheme. */ - resource_size_t offset = (unsigned long)vmf->virtual_address - - vma->vm_start; + resource_size_t offset = vmf->address - vma->vm_start; resource_size_t baddr = map->offset + offset; struct drm_agp_mem *agpmem; struct page *page; @@ -195,7 +194,7 @@ static int drm_do_vm_shm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!map) return VM_FAULT_SIGBUS; /* Nothing allocated */ - offset = (unsigned long)vmf->virtual_address - vma->vm_start; + offset = vmf->address - vma->vm_start; i = (unsigned long)map->handle + offset; page = vmalloc_to_page((void *)i); if (!page) @@ -301,7 +300,8 @@ static int drm_do_vm_dma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!dma->pagelist) return VM_FAULT_SIGBUS; /* Nothing allocated */ - offset = (unsigned long)vmf->virtual_address - vma->vm_start; /* vm_[pg]off[set] should be 0 */ + offset = vmf->address - vma->vm_start; + /* vm_[pg]off[set] should be 0 */ page_nr = offset >> PAGE_SHIFT; /* page_nr could just be vmf->pgoff */ page = virt_to_page((void *)dma->pagelist[page_nr]); @@ -337,7 +337,7 @@ static int drm_do_vm_sg_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!entry->pagelist) return VM_FAULT_SIGBUS; /* Nothing allocated */ - offset = (unsigned long)vmf->virtual_address - vma->vm_start; + offset = vmf->address - vma->vm_start; map_offset = map->offset - (unsigned long)dev->sg->virtual; page_offset = (offset >> PAGE_SHIFT) + (map_offset >> PAGE_SHIFT); page = entry->pagelist[page_offset]; diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c index 6f5dfabb3096..114dddbd297b 100644 --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c @@ -202,15 +202,14 @@ int etnaviv_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } /* We don't use vmf->pgoff since that has the fake offset: */ - pgoff = ((unsigned long)vmf->virtual_address - - vma->vm_start) >> PAGE_SHIFT; + pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; page = pages[pgoff]; - VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, page_to_pfn(page), page_to_pfn(page) << PAGE_SHIFT); - ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page); + ret = vm_insert_page(vma, vmf->address, page); out: switch (ret) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.c b/drivers/gpu/drm/exynos/exynos_drm_gem.c index ea7a18230888..57b81460fec8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gem.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gem.c @@ -455,8 +455,7 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) pgoff_t page_offset; int ret; - page_offset = ((unsigned long)vmf->virtual_address - - vma->vm_start) >> PAGE_SHIFT; + page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; if (page_offset >= (exynos_gem->size >> PAGE_SHIFT)) { DRM_ERROR("invalid page offset\n"); @@ -465,8 +464,7 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } pfn = page_to_pfn(exynos_gem->pages[page_offset]); - ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, - __pfn_to_pfn_t(pfn, PFN_DEV)); + ret = vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); out: switch (ret) { diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c index 4071b2d1e8cf..8b44fa542562 100644 --- a/drivers/gpu/drm/gma500/framebuffer.c +++ b/drivers/gpu/drm/gma500/framebuffer.c @@ -125,7 +125,7 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) psbfb->gtt->offset; page_num = vma_pages(vma); - address = (unsigned long)vmf->virtual_address - (vmf->pgoff << PAGE_SHIFT); + address = vmf->address - (vmf->pgoff << PAGE_SHIFT); vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); diff --git a/drivers/gpu/drm/gma500/gem.c b/drivers/gpu/drm/gma500/gem.c index 6d1cb6b370b1..527c62917660 100644 --- a/drivers/gpu/drm/gma500/gem.c +++ b/drivers/gpu/drm/gma500/gem.c @@ -197,15 +197,14 @@ int psb_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) /* Page relative to the VMA start - we must calculate this ourselves because vmf->pgoff is the fake GEM offset */ - page_offset = ((unsigned long) vmf->virtual_address - vma->vm_start) - >> PAGE_SHIFT; + page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; /* CPU view of the page, don't go via the GART for CPU writes */ if (r->stolen) pfn = (dev_priv->stolen_base + r->offset) >> PAGE_SHIFT; else pfn = page_to_pfn(r->pages[page_offset]); - ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); + ret = vm_insert_pfn(vma, vmf->address, pfn); fail: mutex_unlock(&dev_priv->mmap_mutex); diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d0dcaf35b429..412f3513f269 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -1796,8 +1796,7 @@ int i915_gem_fault(struct vm_area_struct *area, struct vm_fault *vmf) int ret; /* We don't use vmf->pgoff since that has the fake offset */ - page_offset = ((unsigned long)vmf->virtual_address - area->vm_start) >> - PAGE_SHIFT; + page_offset = (vmf->address - area->vm_start) >> PAGE_SHIFT; trace_i915_gem_object_fault(obj, page_offset, true, write); diff --git a/drivers/gpu/drm/msm/msm_gem.c b/drivers/gpu/drm/msm/msm_gem.c index cd06cfd94687..d8bc59c7e261 100644 --- a/drivers/gpu/drm/msm/msm_gem.c +++ b/drivers/gpu/drm/msm/msm_gem.c @@ -225,16 +225,14 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) } /* We don't use vmf->pgoff since that has the fake offset: */ - pgoff = ((unsigned long)vmf->virtual_address - - vma->vm_start) >> PAGE_SHIFT; + pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; pfn = page_to_pfn(pages[pgoff]); - VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, pfn, pfn << PAGE_SHIFT); - ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, - __pfn_to_pfn_t(pfn, PFN_DEV)); + ret = vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); out_unlock: mutex_unlock(&dev->struct_mutex); diff --git a/drivers/gpu/drm/omapdrm/omap_gem.c b/drivers/gpu/drm/omapdrm/omap_gem.c index d4e1e11466f8..4a90c690f09e 100644 --- a/drivers/gpu/drm/omapdrm/omap_gem.c +++ b/drivers/gpu/drm/omapdrm/omap_gem.c @@ -398,8 +398,7 @@ static int fault_1d(struct drm_gem_object *obj, pgoff_t pgoff; /* We don't use vmf->pgoff since that has the fake offset: */ - pgoff = ((unsigned long)vmf->virtual_address - - vma->vm_start) >> PAGE_SHIFT; + pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; if (omap_obj->pages) { omap_gem_cpu_sync(obj, pgoff); @@ -409,11 +408,10 @@ static int fault_1d(struct drm_gem_object *obj, pfn = (omap_obj->paddr >> PAGE_SHIFT) + pgoff; } - VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, pfn, pfn << PAGE_SHIFT); - return vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, - __pfn_to_pfn_t(pfn, PFN_DEV)); + return vm_insert_mixed(vma, vmf->address, __pfn_to_pfn_t(pfn, PFN_DEV)); } /* Special handling for the case of faulting in 2d tiled buffers */ @@ -427,7 +425,7 @@ static int fault_2d(struct drm_gem_object *obj, struct page *pages[64]; /* XXX is this too much to have on stack? */ unsigned long pfn; pgoff_t pgoff, base_pgoff; - void __user *vaddr; + unsigned long vaddr; int i, ret, slots; /* @@ -447,8 +445,7 @@ static int fault_2d(struct drm_gem_object *obj, const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE); /* We don't use vmf->pgoff since that has the fake offset: */ - pgoff = ((unsigned long)vmf->virtual_address - - vma->vm_start) >> PAGE_SHIFT; + pgoff = (vmf->address - vma->vm_start) >> PAGE_SHIFT; /* * Actual address we start mapping at is rounded down to previous slot @@ -459,7 +456,7 @@ static int fault_2d(struct drm_gem_object *obj, /* figure out buffer width in slots */ slots = omap_obj->width >> priv->usergart[fmt].slot_shift; - vaddr = vmf->virtual_address - ((pgoff - base_pgoff) << PAGE_SHIFT); + vaddr = vmf->address - ((pgoff - base_pgoff) << PAGE_SHIFT); entry = &priv->usergart[fmt].entry[priv->usergart[fmt].last]; @@ -503,12 +500,11 @@ static int fault_2d(struct drm_gem_object *obj, pfn = entry->paddr >> PAGE_SHIFT; - VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address, + VERB("Inserting %p pfn %lx, pa %lx", (void *)vmf->address, pfn, pfn << PAGE_SHIFT); for (i = n; i > 0; i--) { - vm_insert_mixed(vma, (unsigned long)vaddr, - __pfn_to_pfn_t(pfn, PFN_DEV)); + vm_insert_mixed(vma, vaddr, __pfn_to_pfn_t(pfn, PFN_DEV)); pfn += priv->usergart[fmt].stride_pfn; vaddr += PAGE_SIZE * m; } diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c index c08e5279eeac..7d853e6b5ff0 100644 --- a/drivers/gpu/drm/tegra/gem.c +++ b/drivers/gpu/drm/tegra/gem.c @@ -452,10 +452,10 @@ static int tegra_bo_fault(struct vm_area_struct *vma, struct vm_fault *vmf) if (!bo->pages) return VM_FAULT_SIGBUS; - offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> PAGE_SHIFT; + offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; page = bo->pages[offset]; - err = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page); + err = vm_insert_page(vma, vmf->address, page); switch (err) { case -EAGAIN: case 0: diff --git a/drivers/gpu/drm/ttm/ttm_bo_vm.c b/drivers/gpu/drm/ttm/ttm_bo_vm.c index 4748aedc933a..68ef993ab431 100644 --- a/drivers/gpu/drm/ttm/ttm_bo_vm.c +++ b/drivers/gpu/drm/ttm/ttm_bo_vm.c @@ -101,7 +101,7 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) struct page *page; int ret; int i; - unsigned long address = (unsigned long)vmf->virtual_address; + unsigned long address = vmf->address; int retval = VM_FAULT_NOPAGE; struct ttm_mem_type_manager *man = &bdev->man[bo->mem.mem_type]; diff --git a/drivers/gpu/drm/udl/udl_gem.c b/drivers/gpu/drm/udl/udl_gem.c index 818e70712b18..3c0c4bd3f750 100644 --- a/drivers/gpu/drm/udl/udl_gem.c +++ b/drivers/gpu/drm/udl/udl_gem.c @@ -107,14 +107,13 @@ int udl_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) unsigned int page_offset; int ret = 0; - page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >> - PAGE_SHIFT; + page_offset = (vmf->address - vma->vm_start) >> PAGE_SHIFT; if (!obj->pages) return VM_FAULT_SIGBUS; page = obj->pages[page_offset]; - ret = vm_insert_page(vma, (unsigned long)vmf->virtual_address, page); + ret = vm_insert_page(vma, vmf->address, page); switch (ret) { case -EAGAIN: case 0: diff --git a/drivers/gpu/drm/vgem/vgem_drv.c b/drivers/gpu/drm/vgem/vgem_drv.c index f36c14729b55..477e07f0ecb6 100644 --- a/drivers/gpu/drm/vgem/vgem_drv.c +++ b/drivers/gpu/drm/vgem/vgem_drv.c @@ -54,7 +54,7 @@ static int vgem_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct drm_vgem_gem_object *obj = vma->vm_private_data; /* We don't use vmf->pgoff since that has the fake offset */ - unsigned long vaddr = (unsigned long)vmf->virtual_address; + unsigned long vaddr = vmf->address; struct page *page; page = shmem_read_mapping_page(file_inode(obj->base.filp)->i_mapping, diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c index 1db0af6c7f94..ba63ca57ed7e 100644 --- a/drivers/media/v4l2-core/videobuf-dma-sg.c +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c @@ -439,13 +439,12 @@ static int videobuf_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) struct page *page; dprintk(3, "fault: fault @ %08lx [vma %08lx-%08lx]\n", - (unsigned long)vmf->virtual_address, - vma->vm_start, vma->vm_end); + vmf->address, vma->vm_start, vma->vm_end); page = alloc_page(GFP_USER | __GFP_DMA32); if (!page) return VM_FAULT_OOM; - clear_user_highpage(page, (unsigned long)vmf->virtual_address); + clear_user_highpage(page, vmf->address); vmf->page = page; return 0; diff --git a/drivers/misc/cxl/context.c b/drivers/misc/cxl/context.c index 5e506c19108a..5d36dcc7f47e 100644 --- a/drivers/misc/cxl/context.c +++ b/drivers/misc/cxl/context.c @@ -117,13 +117,12 @@ int cxl_context_init(struct cxl_context *ctx, struct cxl_afu *afu, bool master, static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { struct cxl_context *ctx = vma->vm_file->private_data; - unsigned long address = (unsigned long)vmf->virtual_address; u64 area, offset; offset = vmf->pgoff << PAGE_SHIFT; pr_devel("%s: pe: %i address: 0x%lx offset: 0x%llx\n", - __func__, ctx->pe, address, offset); + __func__, ctx->pe, vmf->address, offset); if (ctx->afu->current_mode == CXL_MODE_DEDICATED) { area = ctx->afu->psn_phys; @@ -155,7 +154,7 @@ static int cxl_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) return VM_FAULT_SIGBUS; } - vm_insert_pfn(vma, address, (area + offset) >> PAGE_SHIFT); + vm_insert_pfn(vma, vmf->address, (area + offset) >> PAGE_SHIFT); mutex_unlock(&ctx->status_mutex); diff --git a/drivers/misc/sgi-gru/grumain.c b/drivers/misc/sgi-gru/grumain.c index 33741ad4a74a..af2e077da4b8 100644 --- a/drivers/misc/sgi-gru/grumain.c +++ b/drivers/misc/sgi-gru/grumain.c @@ -932,7 +932,7 @@ int gru_fault(struct vm_area_struct *vma, struct vm_fault *vmf) unsigned long paddr, vaddr; unsigned long expires; - vaddr = (unsigned long)vmf->virtual_address; + vaddr = vmf->address; gru_dbg(grudev, "vma %p, vaddr 0x%lx (0x%lx)\n", vma, vaddr, GSEG_BASE(vaddr)); STAT(nopfn); diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index d5cc3070e83f..b653451843c8 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -882,7 +882,7 @@ static int ion_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf) BUG_ON(!buffer->pages || !buffer->pages[vmf->pgoff]); pfn = page_to_pfn(ion_buffer_page(buffer->pages[vmf->pgoff])); - ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn); + ret = vm_insert_pfn(vma, vmf->address, pfn); mutex_unlock(&buffer->lock); if (ret) return VM_FAULT_ERROR; diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c index 0b6d388d8aa4..697cbfbe9374 100644 --- a/drivers/staging/lustre/lustre/llite/vvp_io.c +++ b/drivers/staging/lustre/lustre/llite/vvp_io.c @@ -1014,7 +1014,7 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio) "page %p map %p index %lu flags %lx count %u priv %0lx: got addr %p type NOPAGE\n", vmf->page, vmf->page->mapping, vmf->page->index, (long)vmf->page->flags, page_count(vmf->page), - page_private(vmf->page), vmf->virtual_address); + page_private(vmf->page), (void *)vmf->address); if (unlikely(!(cfio->ft_flags & VM_FAULT_LOCKED))) { lock_page(vmf->page); cfio->ft_flags |= VM_FAULT_LOCKED; @@ -1025,12 +1025,12 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio) } if (cfio->ft_flags & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) { - CDEBUG(D_PAGE, "got addr %p - SIGBUS\n", vmf->virtual_address); + CDEBUG(D_PAGE, "got addr %p - SIGBUS\n", (void *)vmf->address); return -EFAULT; } if (cfio->ft_flags & VM_FAULT_OOM) { - CDEBUG(D_PAGE, "got addr %p - OOM\n", vmf->virtual_address); + CDEBUG(D_PAGE, "got addr %p - OOM\n", (void *)vmf->address); return -ENOMEM; } diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c index 702040fe2001..6e3306f4a525 100644 --- a/drivers/xen/privcmd.c +++ b/drivers/xen/privcmd.c @@ -602,7 +602,7 @@ static int privcmd_fault(struct vm_area_struct *vma, struct vm_fault *vmf) { printk(KERN_DEBUG "privcmd_fault: vma=%p %lx-%lx, pgoff=%lx, uv=%p\n", vma, vma->vm_start, vma->vm_end, - vmf->pgoff, vmf->virtual_address); + vmf->pgoff, (void *)vmf->address); return VM_FAULT_SIGBUS; } diff --git a/fs/dax.c b/fs/dax.c index 5ae8e11ad786..f1dfae64b11a 100644 --- a/fs/dax.c +++ b/fs/dax.c @@ -738,7 +738,7 @@ static int dax_insert_mapping(struct address_space *mapping, struct block_device *bdev, sector_t sector, size_t size, void **entryp, struct vm_area_struct *vma, struct vm_fault *vmf) { - unsigned long vaddr = (unsigned long)vmf->virtual_address; + unsigned long vaddr = vmf->address; struct blk_dax_ctl dax = { .sector = sector, .size = size, @@ -948,7 +948,7 @@ int dax_iomap_fault(struct vm_area_struct *vma, struct vm_fault *vmf, { struct address_space *mapping = vma->vm_file->f_mapping; struct inode *inode = mapping->host; - unsigned long vaddr = (unsigned long)vmf->virtual_address; + unsigned long vaddr = vmf->address; loff_t pos = (loff_t)vmf->pgoff << PAGE_SHIFT; sector_t sector; struct iomap iomap = { 0 }; diff --git a/include/linux/mm.h b/include/linux/mm.h index de5bcead2511..75fda0de64bf 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -297,8 +297,6 @@ struct vm_fault { gfp_t gfp_mask; /* gfp mask to be used for allocations */ pgoff_t pgoff; /* Logical page offset based on vma */ unsigned long address; /* Faulting virtual address */ - void __user *virtual_address; /* Faulting virtual address masked by - * PAGE_MASK */ pmd_t *pmd; /* Pointer to pmd entry matching * the 'address' */ diff --git a/mm/memory.c b/mm/memory.c index 512e1c359193..379836261d4a 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -2040,7 +2040,7 @@ static int do_page_mkwrite(struct vm_area_struct *vma, struct page *page, struct vm_fault vmf; int ret; - vmf.virtual_address = (void __user *)(address & PAGE_MASK); + vmf.address = address & PAGE_MASK; vmf.pgoff = page->index; vmf.flags = FAULT_FLAG_WRITE|FAULT_FLAG_MKWRITE; vmf.gfp_mask = __get_fault_gfp_mask(vma); @@ -2276,8 +2276,7 @@ static int wp_pfn_shared(struct vm_fault *vmf, pte_t orig_pte) struct vm_fault vmf2 = { .page = NULL, .pgoff = linear_page_index(vma, vmf->address), - .virtual_address = - (void __user *)(vmf->address & PAGE_MASK), + .address = vmf->address, .flags = FAULT_FLAG_WRITE | FAULT_FLAG_MKWRITE, }; int ret; @@ -2852,7 +2851,7 @@ static int __do_fault(struct vm_fault *vmf, pgoff_t pgoff, struct vm_fault vmf2; int ret; - vmf2.virtual_address = (void __user *)(vmf->address & PAGE_MASK); + vmf2.address = vmf->address; vmf2.pgoff = pgoff; vmf2.flags = vmf->flags; vmf2.page = NULL; @@ -3612,7 +3611,7 @@ static int __handle_mm_fault(struct vm_area_struct *vma, unsigned long address, { struct vm_fault vmf = { .vma = vma, - .address = address, + .address = address & PAGE_MASK, .flags = flags, }; struct mm_struct *mm = vma->vm_mm; -- cgit v1.2.3 From 99c494077e2d4282a17120a772eecc00ec3004cc Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 14 Dec 2016 15:09:13 -0800 Subject: idr: add ida_is_empty Two of the USB Gadgets were poking around in the internals of struct ida in order to determine if it is empty. Add the appropriate abstraction. Link: http://lkml.kernel.org/r/1480369871-5271-63-git-send-email-mawilcox@linuxonhyperv.com Signed-off-by: Matthew Wilcox Acked-by: Konstantin Khlebnikov Tested-by: Kirill A. Shutemov Cc: Ross Zwisler Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: Michal Nazarewicz Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/usb/gadget/function/f_hid.c | 6 +++--- drivers/usb/gadget/function/f_printer.c | 6 +++--- include/linux/idr.h | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c index 7abd70b2a588..3151d2a0fe59 100644 --- a/drivers/usb/gadget/function/f_hid.c +++ b/drivers/usb/gadget/function/f_hid.c @@ -905,7 +905,7 @@ static void hidg_free_inst(struct usb_function_instance *f) mutex_lock(&hidg_ida_lock); hidg_put_minor(opts->minor); - if (idr_is_empty(&hidg_ida.idr)) + if (ida_is_empty(&hidg_ida)) ghid_cleanup(); mutex_unlock(&hidg_ida_lock); @@ -931,7 +931,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) mutex_lock(&hidg_ida_lock); - if (idr_is_empty(&hidg_ida.idr)) { + if (ida_is_empty(&hidg_ida)) { status = ghid_setup(NULL, HIDG_MINORS); if (status) { ret = ERR_PTR(status); @@ -944,7 +944,7 @@ static struct usb_function_instance *hidg_alloc_inst(void) if (opts->minor < 0) { ret = ERR_PTR(opts->minor); kfree(opts); - if (idr_is_empty(&hidg_ida.idr)) + if (ida_is_empty(&hidg_ida)) ghid_cleanup(); goto unlock; } diff --git a/drivers/usb/gadget/function/f_printer.c b/drivers/usb/gadget/function/f_printer.c index 0de36cda6e41..8054da9276dd 100644 --- a/drivers/usb/gadget/function/f_printer.c +++ b/drivers/usb/gadget/function/f_printer.c @@ -1265,7 +1265,7 @@ static void gprinter_free_inst(struct usb_function_instance *f) mutex_lock(&printer_ida_lock); gprinter_put_minor(opts->minor); - if (idr_is_empty(&printer_ida.idr)) + if (ida_is_empty(&printer_ida)) gprinter_cleanup(); mutex_unlock(&printer_ida_lock); @@ -1289,7 +1289,7 @@ static struct usb_function_instance *gprinter_alloc_inst(void) mutex_lock(&printer_ida_lock); - if (idr_is_empty(&printer_ida.idr)) { + if (ida_is_empty(&printer_ida)) { status = gprinter_setup(PRINTER_MINORS); if (status) { ret = ERR_PTR(status); @@ -1302,7 +1302,7 @@ static struct usb_function_instance *gprinter_alloc_inst(void) if (opts->minor < 0) { ret = ERR_PTR(opts->minor); kfree(opts); - if (idr_is_empty(&printer_ida.idr)) + if (ida_is_empty(&printer_ida)) gprinter_cleanup(); goto unlock; } diff --git a/include/linux/idr.h b/include/linux/idr.h index 083d61e92706..3639a28188c9 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h @@ -195,6 +195,11 @@ static inline int ida_get_new(struct ida *ida, int *p_id) return ida_get_new_above(ida, 0, p_id); } +static inline bool ida_is_empty(struct ida *ida) +{ + return idr_is_empty(&ida->idr); +} + void __init idr_init_cache(void); #endif /* __IDR_H__ */ -- cgit v1.2.3 From 37f4915fef0572e41ab91b7d3f7feb237cddbd92 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 14 Dec 2016 15:09:16 -0800 Subject: tpm: use idr_find(), not idr_find_slowpath() idr_find_slowpath() is not intended to be part of the public API, it's an implementation detail. There's no reason to skip straight to the slowpath here. Link: http://lkml.kernel.org/r/1480369871-5271-64-git-send-email-mawilcox@linuxonhyperv.com Signed-off-by: Matthew Wilcox Tested-by: Kirill A. Shutemov Cc: Konstantin Khlebnikov Cc: Ross Zwisler Cc: Peter Huewe Cc: Marcel Selhorst Cc: Jarkko Sakkinen Cc: Jason Gunthorpe Cc: Matthew Wilcox Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/char/tpm/tpm-chip.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c index e5950131bd90..447b6ca09826 100644 --- a/drivers/char/tpm/tpm-chip.c +++ b/drivers/char/tpm/tpm-chip.c @@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(tpm_put_ops); * * The return'd chip has been tpm_try_get_ops'd and must be released via * tpm_put_ops - */ + */ struct tpm_chip *tpm_chip_find_get(int chip_num) { struct tpm_chip *chip, *res = NULL; @@ -103,7 +103,7 @@ struct tpm_chip *tpm_chip_find_get(int chip_num) } } while (chip_prev != chip_num); } else { - chip = idr_find_slowpath(&dev_nums_idr, chip_num); + chip = idr_find(&dev_nums_idr, chip_num); if (chip && !tpm_try_get_ops(chip)) res = chip; } -- cgit v1.2.3 From 61bd405f4edcf7396cc7853e48212342feead06d Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 22 Nov 2016 13:51:49 +0800 Subject: virtio_pci_modern: fix complaint by sparse drivers/virtio/virtio_pci_modern.c:66:40: warning: incorrect type in argument 2 (different base types) drivers/virtio/virtio_pci_modern.c:66:40: expected unsigned int [noderef] [usertype] *addr drivers/virtio/virtio_pci_modern.c:66:40: got restricted __le32 [noderef] [usertype] *lo drivers/virtio/virtio_pci_modern.c:67:33: warning: incorrect type in argument 2 (different base types) drivers/virtio/virtio_pci_modern.c:67:33: expected unsigned int [noderef] [usertype] *addr drivers/virtio/virtio_pci_modern.c:67:33: got restricted __le32 [noderef] [usertype] *hi drivers/virtio/virtio_pci_modern.c:150:32: warning: incorrect type in argument 2 (different base types) drivers/virtio/virtio_pci_modern.c:150:32: expected unsigned int [noderef] [usertype] *addr drivers/virtio/virtio_pci_modern.c:150:32: got restricted __le32 [noderef] * drivers/virtio/virtio_pci_modern.c:151:39: warning: incorrect type in argument 1 (different base types) drivers/virtio/virtio_pci_modern.c:151:39: expected unsigned int [noderef] [usertype] *addr drivers/virtio/virtio_pci_modern.c:151:39: got restricted __le32 [noderef] * drivers/virtio/virtio_pci_modern.c:152:32: warning: incorrect type in argument 2 (different base types) drivers/virtio/virtio_pci_modern.c:152:32: expected unsigned int [noderef] [usertype] *addr Signed-off-by: Gonglei Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_modern.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c index e76bd91a29da..4bf7ab375894 100644 --- a/drivers/virtio/virtio_pci_modern.c +++ b/drivers/virtio/virtio_pci_modern.c @@ -33,12 +33,12 @@ static inline u8 vp_ioread8(u8 __iomem *addr) { return ioread8(addr); } -static inline u16 vp_ioread16 (u16 __iomem *addr) +static inline u16 vp_ioread16 (__le16 __iomem *addr) { return ioread16(addr); } -static inline u32 vp_ioread32(u32 __iomem *addr) +static inline u32 vp_ioread32(__le32 __iomem *addr) { return ioread32(addr); } @@ -48,12 +48,12 @@ static inline void vp_iowrite8(u8 value, u8 __iomem *addr) iowrite8(value, addr); } -static inline void vp_iowrite16(u16 value, u16 __iomem *addr) +static inline void vp_iowrite16(u16 value, __le16 __iomem *addr) { iowrite16(value, addr); } -static inline void vp_iowrite32(u32 value, u32 __iomem *addr) +static inline void vp_iowrite32(u32 value, __le32 __iomem *addr) { iowrite32(value, addr); } -- cgit v1.2.3 From c60923cb9cb5e042790839d553ed77e68ef45adf Mon Sep 17 00:00:00 2001 From: Gonglei Date: Tue, 22 Nov 2016 13:51:50 +0800 Subject: virtio_ring: fix complaint by sparse # make C=2 CF="-D__CHECK_ENDIAN__" ./drivers/virtio/ drivers/virtio/virtio_ring.c:423:19: warning: incorrect type in assignment (different base types) drivers/virtio/virtio_ring.c:423:19: expected unsigned int [unsigned] [assigned] i drivers/virtio/virtio_ring.c:423:19: got restricted __virtio16 [usertype] next drivers/virtio/virtio_ring.c:423:19: warning: incorrect type in assignment (different base types) drivers/virtio/virtio_ring.c:423:19: expected unsigned int [unsigned] [assigned] i drivers/virtio/virtio_ring.c:423:19: got restricted __virtio16 [usertype] next drivers/virtio/virtio_ring.c:423:19: warning: incorrect type in assignment (different base types) drivers/virtio/virtio_ring.c:423:19: expected unsigned int [unsigned] [assigned] i drivers/virtio/virtio_ring.c:423:19: got restricted __virtio16 [usertype] next drivers/virtio/virtio_ring.c:604:39: warning: incorrect type in initializer (different base types) drivers/virtio/virtio_ring.c:604:39: expected unsigned short [unsigned] [usertype] nextflag drivers/virtio/virtio_ring.c:604:39: got restricted __virtio16 drivers/virtio/virtio_ring.c:612:33: warning: restricted __virtio16 degrades to integer Signed-off-by: Gonglei Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_ring.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index 489bfc61cf30..d2863c321e93 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -420,7 +420,7 @@ unmap_release: if (i == err_idx) break; vring_unmap_one(vq, &desc[i]); - i = vq->vring.desc[i].next; + i = virtio16_to_cpu(_vq->vdev, vq->vring.desc[i].next); } vq->vq.num_free += total_sg; @@ -601,7 +601,7 @@ EXPORT_SYMBOL_GPL(virtqueue_kick); static void detach_buf(struct vring_virtqueue *vq, unsigned int head) { unsigned int i, j; - u16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT); + __virtio16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT); /* Clear data ptr. */ vq->desc_state[head].data = NULL; -- cgit v1.2.3 From 7328fa64aa30405c2d6abd44bb6866e914dba35d Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 5 Dec 2016 21:39:42 +0200 Subject: virtio_console: drop unused config fields struct ports_device includes a config field including the whole virtio_console_config, but only max_nr_ports in there is ever updated or used. The rest is unused and in fact does not even mirror the device config. Drop everything except max_nr_ports, saving some memory. Signed-off-by: Michael S. Tsirkin Reviewed-by: Jason Wang --- drivers/char/virtio_console.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c index 5649234b7316..8b00e79c2683 100644 --- a/drivers/char/virtio_console.c +++ b/drivers/char/virtio_console.c @@ -152,8 +152,8 @@ struct ports_device { spinlock_t c_ivq_lock; spinlock_t c_ovq_lock; - /* The current config space is stored here */ - struct virtio_console_config config; + /* max. number of ports this device can hold */ + u32 max_nr_ports; /* The virtio device we're associated with */ struct virtio_device *vdev; @@ -1649,11 +1649,11 @@ static void handle_control_message(struct virtio_device *vdev, break; } if (virtio32_to_cpu(vdev, cpkt->id) >= - portdev->config.max_nr_ports) { + portdev->max_nr_ports) { dev_warn(&portdev->vdev->dev, "Request for adding port with " "out-of-bound id %u, max. supported id: %u\n", - cpkt->id, portdev->config.max_nr_ports - 1); + cpkt->id, portdev->max_nr_ports - 1); break; } add_port(portdev, virtio32_to_cpu(vdev, cpkt->id)); @@ -1894,7 +1894,7 @@ static int init_vqs(struct ports_device *portdev) u32 i, j, nr_ports, nr_queues; int err; - nr_ports = portdev->config.max_nr_ports; + nr_ports = portdev->max_nr_ports; nr_queues = use_multiport(portdev) ? (nr_ports + 1) * 2 : 2; vqs = kmalloc(nr_queues * sizeof(struct virtqueue *), GFP_KERNEL); @@ -2047,13 +2047,13 @@ static int virtcons_probe(struct virtio_device *vdev) } multiport = false; - portdev->config.max_nr_ports = 1; + portdev->max_nr_ports = 1; /* Don't test MULTIPORT at all if we're rproc: not a valid feature! */ if (!is_rproc_serial(vdev) && virtio_cread_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT, struct virtio_console_config, max_nr_ports, - &portdev->config.max_nr_ports) == 0) { + &portdev->max_nr_ports) == 0) { multiport = true; } -- cgit v1.2.3 From 8854a56f3e71703e0253697e4cc82b20acf732dc Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 5 Dec 2016 21:44:39 +0200 Subject: drm/virtio: fix endianness in primary_plane_update virtio_gpu_cmd_transfer_to_host_2d expects x and y parameters in LE, but virtio_gpu_primary_plane_update passes in the CPU format instead. Signed-off-by: Michael S. Tsirkin --- drivers/gpu/drm/virtio/virtgpu_plane.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_plane.c b/drivers/gpu/drm/virtio/virtgpu_plane.c index cb75f0663ba0..11288ffa4af6 100644 --- a/drivers/gpu/drm/virtio/virtgpu_plane.c +++ b/drivers/gpu/drm/virtio/virtgpu_plane.c @@ -88,8 +88,8 @@ static void virtio_gpu_primary_plane_update(struct drm_plane *plane, (vgdev, handle, 0, cpu_to_le32(plane->state->src_w >> 16), cpu_to_le32(plane->state->src_h >> 16), - plane->state->src_x >> 16, - plane->state->src_y >> 16, NULL); + cpu_to_le32(plane->state->src_x >> 16), + cpu_to_le32(plane->state->src_y >> 16), NULL); } } else { handle = 0; -- cgit v1.2.3 From f862e60f8d52dae33c9f72afc20fab691a89f0bd Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 5 Dec 2016 22:36:56 +0200 Subject: drm/virtio: fix lock context imbalance When virtio_gpu_free_vbufs exits due to list empty, it does not drop the free_vbufs lock that it took. list empty is not expected to happen anyway, but it can't hurt to fix this and drop the lock. Signed-off-by: Michael S. Tsirkin --- drivers/gpu/drm/virtio/virtgpu_vq.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index 974f9410474b..abfc54a18f1a 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -109,8 +109,10 @@ void virtio_gpu_free_vbufs(struct virtio_gpu_device *vgdev) spin_lock(&vgdev->free_vbufs_lock); for (i = 0; i < count; i++) { - if (WARN_ON(list_empty(&vgdev->free_vbufs))) + if (WARN_ON(list_empty(&vgdev->free_vbufs))) { + spin_unlock(&vgdev->free_vbufs_lock); return; + } vbuf = list_first_entry(&vgdev->free_vbufs, struct virtio_gpu_vbuffer, list); list_del(&vbuf->list); -- cgit v1.2.3 From 3373755a415c9c8024d26cf32fd812a8cdb82541 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 5 Dec 2016 22:39:30 +0200 Subject: drm/virtio: annotate virtio_gpu_queue_ctrl_buffer_locked virtio_gpu_queue_ctrl_buffer_locked is called with ctrlq.qlock taken, it releases and acquires this lock. This causes a sparse warning. Add appropriate annotations for sparse context checking. Signed-off-by: Michael S. Tsirkin --- drivers/gpu/drm/virtio/virtgpu_vq.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c index abfc54a18f1a..43ea0dc957d2 100644 --- a/drivers/gpu/drm/virtio/virtgpu_vq.c +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c @@ -297,6 +297,8 @@ void virtio_gpu_dequeue_cursor_func(struct work_struct *work) static int virtio_gpu_queue_ctrl_buffer_locked(struct virtio_gpu_device *vgdev, struct virtio_gpu_vbuffer *vbuf) + __releases(&vgdev->ctrlq.qlock) + __acquires(&vgdev->ctrlq.qlock) { struct virtqueue *vq = vgdev->ctrlq.vq; struct scatterlist *sgs[3], vcmd, vout, vresp; -- cgit v1.2.3 From 2f952c0105d14bd46bb6d6a3cc03ad789a381228 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 6 Dec 2016 05:57:54 +0200 Subject: vhost: make interval tree static inline vhost_umem_interval_tree is only used locally within vhost.c, mark it static. As some functions generated go unused, this triggers warnings unless we also mark it inline. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 266354390c8f..e4825222eb06 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -49,7 +49,7 @@ enum { INTERVAL_TREE_DEFINE(struct vhost_umem_node, rb, __u64, __subtree_last, - START, LAST, , vhost_umem_interval_tree); + START, LAST, static inline, vhost_umem_interval_tree); #ifdef CONFIG_VHOST_CROSS_ENDIAN_LEGACY static void vhost_disable_cross_endian(struct vhost_virtqueue *vq) -- cgit v1.2.3 From 72952cc0614b61650b2b13f57752a6dd82cbeae5 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Tue, 6 Dec 2016 06:01:41 +0200 Subject: vhost: add missing __user annotations Several vhost functions were missing __user annotations on pointers, causing sparse warnings. Fix this up. sparse also warns about vhost_process_iotlb_msg which is local and should be static. Fix that up as well. Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index e4825222eb06..2f58181b918d 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -719,7 +719,7 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_umem *umem, static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len, struct iovec iov[], int iov_size, int access); -static int vhost_copy_to_user(struct vhost_virtqueue *vq, void *to, +static int vhost_copy_to_user(struct vhost_virtqueue *vq, void __user *to, const void *from, unsigned size) { int ret; @@ -749,7 +749,7 @@ out: } static int vhost_copy_from_user(struct vhost_virtqueue *vq, void *to, - void *from, unsigned size) + void __user *from, unsigned size) { int ret; @@ -783,7 +783,7 @@ out: } static void __user *__vhost_get_user(struct vhost_virtqueue *vq, - void *addr, unsigned size) + void __user *addr, unsigned size) { int ret; @@ -934,8 +934,8 @@ static int umem_access_ok(u64 uaddr, u64 size, int access) return 0; } -int vhost_process_iotlb_msg(struct vhost_dev *dev, - struct vhost_iotlb_msg *msg) +static int vhost_process_iotlb_msg(struct vhost_dev *dev, + struct vhost_iotlb_msg *msg) { int ret = 0; -- cgit v1.2.3 From aec03f89e905dca9ce4b061e03ee1da3a3eb3432 Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Mon, 12 Dec 2016 23:18:29 -0500 Subject: ACPI/NUMA: Do not map pxm to node when NUMA is turned off acpi_map_pxm_to_node() unconditially maps nodes even when NUMA is turned off. So acpi_get_node() might return a node > 0, which is fatal when NUMA is disabled as the rest of the kernel assumes that only node 0 exists. Expose numa_off to the acpi code and return NUMA_NO_NODE when it's set. Signed-off-by: Boris Ostrovsky Cc: fenghua.yu@intel.com Cc: tony.luck@intel.com Cc: linux-ia64@vger.kernel.org Cc: catalin.marinas@arm.com Cc: rjw@rjwysocki.net Cc: will.deacon@arm.com Cc: linux-acpi@vger.kernel.org Cc: linux-arm-kernel@lists.infradead.org Cc: lenb@kernel.org Link: http://lkml.kernel.org/r/1481602709-18260-1-git-send-email-boris.ostrovsky@oracle.com Signed-off-by: Thomas Gleixner --- arch/arm64/include/asm/numa.h | 2 ++ arch/arm64/mm/numa.c | 2 +- arch/ia64/include/asm/numa.h | 2 ++ arch/x86/mm/numa.c | 2 +- drivers/acpi/numa.c | 2 +- 5 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/arch/arm64/include/asm/numa.h b/arch/arm64/include/asm/numa.h index 600887e491fd..bf466d1876e3 100644 --- a/arch/arm64/include/asm/numa.h +++ b/arch/arm64/include/asm/numa.h @@ -15,6 +15,8 @@ int __node_distance(int from, int to); extern nodemask_t numa_nodes_parsed __initdata; +extern bool numa_off; + /* Mappings between node number and cpus on that node. */ extern cpumask_var_t node_to_cpumask_map[MAX_NUMNODES]; void numa_clear_node(unsigned int cpu); diff --git a/arch/arm64/mm/numa.c b/arch/arm64/mm/numa.c index 4b32168cf91a..b388a99fea7b 100644 --- a/arch/arm64/mm/numa.c +++ b/arch/arm64/mm/numa.c @@ -35,7 +35,7 @@ static int cpu_to_node_map[NR_CPUS] = { [0 ... NR_CPUS-1] = NUMA_NO_NODE }; static int numa_distance_cnt; static u8 *numa_distance; -static bool numa_off; +bool numa_off; static __init int numa_parse_early_param(char *opt) { diff --git a/arch/ia64/include/asm/numa.h b/arch/ia64/include/asm/numa.h index 2db0a6c6daa5..ebef7f40aabb 100644 --- a/arch/ia64/include/asm/numa.h +++ b/arch/ia64/include/asm/numa.h @@ -65,6 +65,8 @@ extern int paddr_to_nid(unsigned long paddr); #define local_nodeid (cpu_to_node_map[smp_processor_id()]) +#define numa_off 0 + extern void map_cpu_to_node(int cpu, int nid); extern void unmap_cpu_from_node(int cpu, int nid); extern void numa_clear_node(int cpu); diff --git a/arch/x86/mm/numa.c b/arch/x86/mm/numa.c index 3f35b48d1d9d..12dcad7297a5 100644 --- a/arch/x86/mm/numa.c +++ b/arch/x86/mm/numa.c @@ -19,7 +19,7 @@ #include "numa_internal.h" -int __initdata numa_off; +int numa_off; nodemask_t numa_nodes_parsed __initdata; struct pglist_data *node_data[MAX_NUMNODES] __read_mostly; diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c index ce3a7a16f03f..edb0c79f7c64 100644 --- a/drivers/acpi/numa.c +++ b/drivers/acpi/numa.c @@ -70,7 +70,7 @@ int acpi_map_pxm_to_node(int pxm) { int node; - if (pxm < 0 || pxm >= MAX_PXM_DOMAINS) + if (pxm < 0 || pxm >= MAX_PXM_DOMAINS || numa_off) return NUMA_NO_NODE; node = pxm_to_node_map[pxm]; -- cgit v1.2.3 From a2c223b5ed64d7a0266cf1a3e0b2726647a98ed8 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 26 Oct 2016 15:25:23 -0200 Subject: edac: edac_core.h: get rid of unused kobj_complete This element of struct edac_pci_ctl_info is never used. So, get rid of it. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 4861542163d7..58d66da56486 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -380,7 +380,6 @@ struct edac_pci_ctl_info { * device this structure controls */ struct kobject kobj; - struct completion kobj_complete; }; #define to_edac_pci_ctl_work(w) \ -- cgit v1.2.3 From 723061753724009a6e3cbec9deba7860dba2df99 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 26 Oct 2016 16:15:02 -0200 Subject: edac: edac_core.h: remove prototype for edac_pci_reset_delay_period() This function doesn't exist. So, remove its prototype. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 58d66da56486..1723f3643e75 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -493,9 +493,6 @@ extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci); -extern void edac_pci_reset_delay_period(struct edac_pci_ctl_info *pci, - unsigned long value); - extern int edac_pci_alloc_index(void); extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx); extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev); -- cgit v1.2.3 From 0b892c717714334890ea179a2dc1941a223e446f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 29 Oct 2016 09:56:00 -0200 Subject: edac: move EDAC PCI definitions to drivers/edac/edac_pci.h The edac_core.h header contain data structures and function definitions for the 3 parts of EDAC: MC, PCI and device. Let's move the PCI ones to a separate header file, as part of a header reorganization. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 145 +---------------------------------- drivers/edac/edac_pci.c | 19 ++--- drivers/edac/edac_pci.h | 173 ++++++++++++++++++++++++++++++++++++++++++ drivers/edac/edac_pci_sysfs.c | 2 +- include/linux/edac.h | 2 + 5 files changed, 185 insertions(+), 156 deletions(-) create mode 100644 drivers/edac/edac_pci.h (limited to 'drivers') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 1723f3643e75..8c7cca2d6e40 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -35,8 +35,7 @@ #include #include -#define EDAC_DEVICE_NAME_LEN 31 -#define EDAC_ATTRIB_VALUE_LEN 15 +#include "edac_pci.h" #if PAGE_SHIFT < 20 #define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) @@ -321,128 +320,6 @@ extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info); -#ifdef CONFIG_PCI - -struct edac_pci_counter { - atomic_t pe_count; - atomic_t npe_count; -}; - -/* - * Abstract edac_pci control info structure - * - */ -struct edac_pci_ctl_info { - /* for global list of edac_pci_ctl_info structs */ - struct list_head link; - - int pci_idx; - - struct bus_type *edac_subsys; /* pointer to subsystem */ - - /* the internal state of this controller instance */ - int op_state; - /* work struct for this instance */ - struct delayed_work work; - - /* pointer to edac polling checking routine: - * If NOT NULL: points to polling check routine - * If NULL: Then assumes INTERRUPT operation, where - * MC driver will receive events - */ - void (*edac_check) (struct edac_pci_ctl_info * edac_dev); - - struct device *dev; /* pointer to device structure */ - - const char *mod_name; /* module name */ - const char *ctl_name; /* edac controller name */ - const char *dev_name; /* pci/platform/etc... name */ - - void *pvt_info; /* pointer to 'private driver' info */ - - unsigned long start_time; /* edac_pci load start time (jiffies) */ - - struct completion complete; - - /* sysfs top name under 'edac' directory - * and instance name: - * cpu/cpu0/... - * cpu/cpu1/... - * cpu/cpu2/... - * ... - */ - char name[EDAC_DEVICE_NAME_LEN + 1]; - - /* Event counters for the this whole EDAC Device */ - struct edac_pci_counter counters; - - /* edac sysfs device control for the 'name' - * device this structure controls - */ - struct kobject kobj; -}; - -#define to_edac_pci_ctl_work(w) \ - container_of(w, struct edac_pci_ctl_info,work) - -/* write all or some bits in a byte-register*/ -static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, - u8 mask) -{ - if (mask != 0xff) { - u8 buf; - - pci_read_config_byte(pdev, offset, &buf); - value &= mask; - buf &= ~mask; - value |= buf; - } - - pci_write_config_byte(pdev, offset, value); -} - -/* write all or some bits in a word-register*/ -static inline void pci_write_bits16(struct pci_dev *pdev, int offset, - u16 value, u16 mask) -{ - if (mask != 0xffff) { - u16 buf; - - pci_read_config_word(pdev, offset, &buf); - value &= mask; - buf &= ~mask; - value |= buf; - } - - pci_write_config_word(pdev, offset, value); -} - -/* - * pci_write_bits32 - * - * edac local routine to do pci_write_config_dword, but adds - * a mask parameter. If mask is all ones, ignore the mask. - * Otherwise utilize the mask to isolate specified bits - * - * write all or some bits in a dword-register - */ -static inline void pci_write_bits32(struct pci_dev *pdev, int offset, - u32 value, u32 mask) -{ - if (mask != 0xffffffff) { - u32 buf; - - pci_read_config_dword(pdev, offset, &buf); - value &= mask; - buf &= ~mask; - value |= buf; - } - - pci_write_config_dword(pdev, offset, value); -} - -#endif /* CONFIG_PCI */ - struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, unsigned n_layers, struct edac_mc_layer *layers, @@ -485,26 +362,6 @@ extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, extern int edac_device_alloc_index(void); extern const char *edac_layer_name[]; -/* - * edac_pci APIs - */ -extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, - const char *edac_pci_name); - -extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci); - -extern int edac_pci_alloc_index(void); -extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx); -extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev); - -extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl( - struct device *dev, - const char *mod_name); - -extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci); -extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci); -extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci); - /* * edac misc APIs */ diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 8f2f2899a7a2..02a0af4f53b3 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -9,22 +9,19 @@ * or implied. * */ +#include +#include +#include +#include +#include #include -#include +#include #include -#include +#include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include "edac_core.h" +#include "edac_pci.h" #include "edac_module.h" static DEFINE_MUTEX(edac_pci_ctls_mutex); diff --git a/drivers/edac/edac_pci.h b/drivers/edac/edac_pci.h new file mode 100644 index 000000000000..9da0c6fb0634 --- /dev/null +++ b/drivers/edac/edac_pci.h @@ -0,0 +1,173 @@ +/* + * Defines, structures, APIs for edac_pci and edac_pci_sysfs + * + * (C) 2007 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Thayne Harbaugh + * Based on work by Dan Hollis and others. + * http://www.anime.net/~goemon/linux-ecc/ + * + * NMI handling support added by + * Dave Peterson + * + * Refactored for multi-source files: + * Doug Thompson + * + * Please look at Documentation/driver-api/edac.rst for more info about + * EDAC core structs and functions. + */ + +#ifndef _EDAC_PCI_H_ +#define _EDAC_PCI_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PCI + +struct edac_pci_counter { + atomic_t pe_count; + atomic_t npe_count; +}; + +/* + * Abstract edac_pci control info structure + * + */ +struct edac_pci_ctl_info { + /* for global list of edac_pci_ctl_info structs */ + struct list_head link; + + int pci_idx; + + struct bus_type *edac_subsys; /* pointer to subsystem */ + + /* the internal state of this controller instance */ + int op_state; + /* work struct for this instance */ + struct delayed_work work; + + /* pointer to edac polling checking routine: + * If NOT NULL: points to polling check routine + * If NULL: Then assumes INTERRUPT operation, where + * MC driver will receive events + */ + void (*edac_check) (struct edac_pci_ctl_info * edac_dev); + + struct device *dev; /* pointer to device structure */ + + const char *mod_name; /* module name */ + const char *ctl_name; /* edac controller name */ + const char *dev_name; /* pci/platform/etc... name */ + + void *pvt_info; /* pointer to 'private driver' info */ + + unsigned long start_time; /* edac_pci load start time (jiffies) */ + + struct completion complete; + + /* sysfs top name under 'edac' directory + * and instance name: + * cpu/cpu0/... + * cpu/cpu1/... + * cpu/cpu2/... + * ... + */ + char name[EDAC_DEVICE_NAME_LEN + 1]; + + /* Event counters for the this whole EDAC Device */ + struct edac_pci_counter counters; + + /* edac sysfs device control for the 'name' + * device this structure controls + */ + struct kobject kobj; +}; + +#define to_edac_pci_ctl_work(w) \ + container_of(w, struct edac_pci_ctl_info,work) + +/* write all or some bits in a byte-register*/ +static inline void pci_write_bits8(struct pci_dev *pdev, int offset, u8 value, + u8 mask) +{ + if (mask != 0xff) { + u8 buf; + + pci_read_config_byte(pdev, offset, &buf); + value &= mask; + buf &= ~mask; + value |= buf; + } + + pci_write_config_byte(pdev, offset, value); +} + +/* write all or some bits in a word-register*/ +static inline void pci_write_bits16(struct pci_dev *pdev, int offset, + u16 value, u16 mask) +{ + if (mask != 0xffff) { + u16 buf; + + pci_read_config_word(pdev, offset, &buf); + value &= mask; + buf &= ~mask; + value |= buf; + } + + pci_write_config_word(pdev, offset, value); +} + +/* + * pci_write_bits32 + * + * edac local routine to do pci_write_config_dword, but adds + * a mask parameter. If mask is all ones, ignore the mask. + * Otherwise utilize the mask to isolate specified bits + * + * write all or some bits in a dword-register + */ +static inline void pci_write_bits32(struct pci_dev *pdev, int offset, + u32 value, u32 mask) +{ + if (mask != 0xffffffff) { + u32 buf; + + pci_read_config_dword(pdev, offset, &buf); + value &= mask; + buf &= ~mask; + value |= buf; + } + + pci_write_config_dword(pdev, offset, value); +} + +#endif /* CONFIG_PCI */ + +extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, + const char *edac_pci_name); + +extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci); + +extern int edac_pci_alloc_index(void); +extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx); +extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev); + +extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl( + struct device *dev, + const char *mod_name); + +extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci); +extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci); +extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci); + +#endif diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index 6e3428ba400f..dbeb048d8efb 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -11,7 +11,7 @@ #include #include -#include "edac_core.h" +#include "edac_pci.h" #include "edac_module.h" #define EDAC_PCI_SYMLINK "device" diff --git a/include/linux/edac.h b/include/linux/edac.h index cb56dcba68c6..0fec0f26469b 100644 --- a/include/linux/edac.h +++ b/include/linux/edac.h @@ -18,6 +18,8 @@ #include #include +#define EDAC_DEVICE_NAME_LEN 31 + struct device; #define EDAC_OPSTATE_INVAL -1 -- cgit v1.2.3 From 6d8ef2472410c8ab004729a71ec829a224699a08 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 29 Oct 2016 10:01:41 -0200 Subject: edac: move EDAC device definitions to drivers/edac/edac_device.h The edac_core.h header contain data structures and function definitions for both EDAC MC and EDAC device. Let's move the devices ones to a separate header file, as part of a header reorganization. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 238 +--------------------------------- drivers/edac/edac_device.c | 21 ++- drivers/edac/edac_device.h | 269 +++++++++++++++++++++++++++++++++++++++ drivers/edac/edac_device_sysfs.c | 4 +- 4 files changed, 281 insertions(+), 251 deletions(-) create mode 100644 drivers/edac/edac_device.h (limited to 'drivers') diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 8c7cca2d6e40..3e11d9d85462 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -36,6 +36,7 @@ #include #include "edac_pci.h" +#include "edac_device.h" #if PAGE_SHIFT < 20 #define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) @@ -95,231 +96,6 @@ do { \ #define to_mci(k) container_of(k, struct mem_ctl_info, dev) -/* - * The following are the structures to provide for a generic - * or abstract 'edac_device'. This set of structures and the - * code that implements the APIs for the same, provide for - * registering EDAC type devices which are NOT standard memory. - * - * CPU caches (L1 and L2) - * DMA engines - * Core CPU switches - * Fabric switch units - * PCIe interface controllers - * other EDAC/ECC type devices that can be monitored for - * errors, etc. - * - * It allows for a 2 level set of hierarchy. For example: - * - * cache could be composed of L1, L2 and L3 levels of cache. - * Each CPU core would have its own L1 cache, while sharing - * L2 and maybe L3 caches. - * - * View them arranged, via the sysfs presentation: - * /sys/devices/system/edac/.. - * - * mc/ - * cpu/cpu0/.. - * /L1-cache/ce_count - * /ue_count - * /L2-cache/ce_count - * /ue_count - * cpu/cpu1/.. - * /L1-cache/ce_count - * /ue_count - * /L2-cache/ce_count - * /ue_count - * ... - * - * the L1 and L2 directories would be "edac_device_block's" - */ - -struct edac_device_counter { - u32 ue_count; - u32 ce_count; -}; - -/* forward reference */ -struct edac_device_ctl_info; -struct edac_device_block; - -/* edac_dev_sysfs_attribute structure - * used for driver sysfs attributes in mem_ctl_info - * for extra controls and attributes: - * like high level error Injection controls - */ -struct edac_dev_sysfs_attribute { - struct attribute attr; - ssize_t (*show)(struct edac_device_ctl_info *, char *); - ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t); -}; - -/* edac_dev_sysfs_block_attribute structure - * - * used in leaf 'block' nodes for adding controls/attributes - * - * each block in each instance of the containing control structure - * can have an array of the following. The show and store functions - * will be filled in with the show/store function in the - * low level driver. - * - * The 'value' field will be the actual value field used for - * counting - */ -struct edac_dev_sysfs_block_attribute { - struct attribute attr; - ssize_t (*show)(struct kobject *, struct attribute *, char *); - ssize_t (*store)(struct kobject *, struct attribute *, - const char *, size_t); - struct edac_device_block *block; - - unsigned int value; -}; - -/* device block control structure */ -struct edac_device_block { - struct edac_device_instance *instance; /* Up Pointer */ - char name[EDAC_DEVICE_NAME_LEN + 1]; - - struct edac_device_counter counters; /* basic UE and CE counters */ - - int nr_attribs; /* how many attributes */ - - /* this block's attributes, could be NULL */ - struct edac_dev_sysfs_block_attribute *block_attributes; - - /* edac sysfs device control */ - struct kobject kobj; -}; - -/* device instance control structure */ -struct edac_device_instance { - struct edac_device_ctl_info *ctl; /* Up pointer */ - char name[EDAC_DEVICE_NAME_LEN + 4]; - - struct edac_device_counter counters; /* instance counters */ - - u32 nr_blocks; /* how many blocks */ - struct edac_device_block *blocks; /* block array */ - - /* edac sysfs device control */ - struct kobject kobj; -}; - - -/* - * Abstract edac_device control info structure - * - */ -struct edac_device_ctl_info { - /* for global list of edac_device_ctl_info structs */ - struct list_head link; - - struct module *owner; /* Module owner of this control struct */ - - int dev_idx; - - /* Per instance controls for this edac_device */ - int log_ue; /* boolean for logging UEs */ - int log_ce; /* boolean for logging CEs */ - int panic_on_ue; /* boolean for panic'ing on an UE */ - unsigned poll_msec; /* number of milliseconds to poll interval */ - unsigned long delay; /* number of jiffies for poll_msec */ - - /* Additional top controller level attributes, but specified - * by the low level driver. - * - * Set by the low level driver to provide attributes at the - * controller level, same level as 'ue_count' and 'ce_count' above. - * An array of structures, NULL terminated - * - * If attributes are desired, then set to array of attributes - * If no attributes are desired, leave NULL - */ - struct edac_dev_sysfs_attribute *sysfs_attributes; - - /* pointer to main 'edac' subsys in sysfs */ - struct bus_type *edac_subsys; - - /* the internal state of this controller instance */ - int op_state; - /* work struct for this instance */ - struct delayed_work work; - - /* pointer to edac polling checking routine: - * If NOT NULL: points to polling check routine - * If NULL: Then assumes INTERRUPT operation, where - * MC driver will receive events - */ - void (*edac_check) (struct edac_device_ctl_info * edac_dev); - - struct device *dev; /* pointer to device structure */ - - const char *mod_name; /* module name */ - const char *ctl_name; /* edac controller name */ - const char *dev_name; /* pci/platform/etc... name */ - - void *pvt_info; /* pointer to 'private driver' info */ - - unsigned long start_time; /* edac_device load start time (jiffies) */ - - struct completion removal_complete; - - /* sysfs top name under 'edac' directory - * and instance name: - * cpu/cpu0/... - * cpu/cpu1/... - * cpu/cpu2/... - * ... - */ - char name[EDAC_DEVICE_NAME_LEN + 1]; - - /* Number of instances supported on this control structure - * and the array of those instances - */ - u32 nr_instances; - struct edac_device_instance *instances; - - /* Event counters for the this whole EDAC Device */ - struct edac_device_counter counters; - - /* edac sysfs device control for the 'name' - * device this structure controls - */ - struct kobject kobj; -}; - -/* To get from the instance's wq to the beginning of the ctl structure */ -#define to_edac_mem_ctl_work(w) \ - container_of(w, struct mem_ctl_info, work) - -#define to_edac_device_ctl_work(w) \ - container_of(w,struct edac_device_ctl_info,work) - -/* - * The alloc() and free() functions for the 'edac_device' control info - * structure. A MC driver will allocate one of these for each edac_device - * it is going to control/register with the EDAC CORE. - */ -extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( - unsigned sizeof_private, - char *edac_device_name, unsigned nr_instances, - char *edac_block_name, unsigned nr_blocks, - unsigned offset_value, - struct edac_dev_sysfs_block_attribute *block_attributes, - unsigned nr_attribs, - int device_index); - -/* The offset value can be: - * -1 indicating no offset value - * 0 for zero-based block numbers - * 1 for 1-based block number - * other for other-based block number - */ -#define BLOCK_OFFSET_VALUE_OFF ((unsigned) -1) - -extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info); - struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, unsigned n_layers, struct edac_mc_layer *layers, @@ -350,18 +126,6 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, const char *msg, const char *other_detail); -/* - * edac_device APIs - */ -extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev); -extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev); -extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, - int inst_nr, int block_nr, const char *msg); -extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, - int inst_nr, int block_nr, const char *msg); -extern int edac_device_alloc_index(void); -extern const char *edac_layer_name[]; - /* * edac misc APIs */ diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index a97900333e2d..046ab7794fc2 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -12,23 +12,20 @@ * 19 Jan 2007 */ +#include +#include +#include +#include +#include +#include #include -#include +#include #include -#include +#include #include -#include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include "edac_core.h" +#include "edac_device.h" #include "edac_module.h" /* lock for the list: 'edac_device_list', manipulation of this list diff --git a/drivers/edac/edac_device.h b/drivers/edac/edac_device.h new file mode 100644 index 000000000000..eb1204408529 --- /dev/null +++ b/drivers/edac/edac_device.h @@ -0,0 +1,269 @@ +/* + * Defines, structures, APIs for edac_device + * + * (C) 2007 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Thayne Harbaugh + * Based on work by Dan Hollis and others. + * http://www.anime.net/~goemon/linux-ecc/ + * + * NMI handling support added by + * Dave Peterson + * + * Refactored for multi-source files: + * Doug Thompson + * + * Please look at Documentation/driver-api/edac.rst for more info about + * EDAC core structs and functions. + */ + +#ifndef _EDAC_DEVICE_H_ +#define _EDAC_DEVICE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + + +/* + * The following are the structures to provide for a generic + * or abstract 'edac_device'. This set of structures and the + * code that implements the APIs for the same, provide for + * registering EDAC type devices which are NOT standard memory. + * + * CPU caches (L1 and L2) + * DMA engines + * Core CPU switches + * Fabric switch units + * PCIe interface controllers + * other EDAC/ECC type devices that can be monitored for + * errors, etc. + * + * It allows for a 2 level set of hierarchy. For example: + * + * cache could be composed of L1, L2 and L3 levels of cache. + * Each CPU core would have its own L1 cache, while sharing + * L2 and maybe L3 caches. + * + * View them arranged, via the sysfs presentation: + * /sys/devices/system/edac/.. + * + * mc/ + * cpu/cpu0/.. + * /L1-cache/ce_count + * /ue_count + * /L2-cache/ce_count + * /ue_count + * cpu/cpu1/.. + * /L1-cache/ce_count + * /ue_count + * /L2-cache/ce_count + * /ue_count + * ... + * + * the L1 and L2 directories would be "edac_device_block's" + */ + +struct edac_device_counter { + u32 ue_count; + u32 ce_count; +}; + +/* forward reference */ +struct edac_device_ctl_info; +struct edac_device_block; + +/* edac_dev_sysfs_attribute structure + * used for driver sysfs attributes in mem_ctl_info + * for extra controls and attributes: + * like high level error Injection controls + */ +struct edac_dev_sysfs_attribute { + struct attribute attr; + ssize_t (*show)(struct edac_device_ctl_info *, char *); + ssize_t (*store)(struct edac_device_ctl_info *, const char *, size_t); +}; + +/* edac_dev_sysfs_block_attribute structure + * + * used in leaf 'block' nodes for adding controls/attributes + * + * each block in each instance of the containing control structure + * can have an array of the following. The show and store functions + * will be filled in with the show/store function in the + * low level driver. + * + * The 'value' field will be the actual value field used for + * counting + */ +struct edac_dev_sysfs_block_attribute { + struct attribute attr; + ssize_t (*show)(struct kobject *, struct attribute *, char *); + ssize_t (*store)(struct kobject *, struct attribute *, + const char *, size_t); + struct edac_device_block *block; + + unsigned int value; +}; + +/* device block control structure */ +struct edac_device_block { + struct edac_device_instance *instance; /* Up Pointer */ + char name[EDAC_DEVICE_NAME_LEN + 1]; + + struct edac_device_counter counters; /* basic UE and CE counters */ + + int nr_attribs; /* how many attributes */ + + /* this block's attributes, could be NULL */ + struct edac_dev_sysfs_block_attribute *block_attributes; + + /* edac sysfs device control */ + struct kobject kobj; +}; + +/* device instance control structure */ +struct edac_device_instance { + struct edac_device_ctl_info *ctl; /* Up pointer */ + char name[EDAC_DEVICE_NAME_LEN + 4]; + + struct edac_device_counter counters; /* instance counters */ + + u32 nr_blocks; /* how many blocks */ + struct edac_device_block *blocks; /* block array */ + + /* edac sysfs device control */ + struct kobject kobj; +}; + + +/* + * Abstract edac_device control info structure + * + */ +struct edac_device_ctl_info { + /* for global list of edac_device_ctl_info structs */ + struct list_head link; + + struct module *owner; /* Module owner of this control struct */ + + int dev_idx; + + /* Per instance controls for this edac_device */ + int log_ue; /* boolean for logging UEs */ + int log_ce; /* boolean for logging CEs */ + int panic_on_ue; /* boolean for panic'ing on an UE */ + unsigned poll_msec; /* number of milliseconds to poll interval */ + unsigned long delay; /* number of jiffies for poll_msec */ + + /* Additional top controller level attributes, but specified + * by the low level driver. + * + * Set by the low level driver to provide attributes at the + * controller level, same level as 'ue_count' and 'ce_count' above. + * An array of structures, NULL terminated + * + * If attributes are desired, then set to array of attributes + * If no attributes are desired, leave NULL + */ + struct edac_dev_sysfs_attribute *sysfs_attributes; + + /* pointer to main 'edac' subsys in sysfs */ + struct bus_type *edac_subsys; + + /* the internal state of this controller instance */ + int op_state; + /* work struct for this instance */ + struct delayed_work work; + + /* pointer to edac polling checking routine: + * If NOT NULL: points to polling check routine + * If NULL: Then assumes INTERRUPT operation, where + * MC driver will receive events + */ + void (*edac_check) (struct edac_device_ctl_info * edac_dev); + + struct device *dev; /* pointer to device structure */ + + const char *mod_name; /* module name */ + const char *ctl_name; /* edac controller name */ + const char *dev_name; /* pci/platform/etc... name */ + + void *pvt_info; /* pointer to 'private driver' info */ + + unsigned long start_time; /* edac_device load start time (jiffies) */ + + struct completion removal_complete; + + /* sysfs top name under 'edac' directory + * and instance name: + * cpu/cpu0/... + * cpu/cpu1/... + * cpu/cpu2/... + * ... + */ + char name[EDAC_DEVICE_NAME_LEN + 1]; + + /* Number of instances supported on this control structure + * and the array of those instances + */ + u32 nr_instances; + struct edac_device_instance *instances; + + /* Event counters for the this whole EDAC Device */ + struct edac_device_counter counters; + + /* edac sysfs device control for the 'name' + * device this structure controls + */ + struct kobject kobj; +}; + +/* To get from the instance's wq to the beginning of the ctl structure */ +#define to_edac_mem_ctl_work(w) \ + container_of(w, struct mem_ctl_info, work) + +#define to_edac_device_ctl_work(w) \ + container_of(w,struct edac_device_ctl_info,work) + +/* + * The alloc() and free() functions for the 'edac_device' control info + * structure. A MC driver will allocate one of these for each edac_device + * it is going to control/register with the EDAC CORE. + */ +extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( + unsigned sizeof_private, + char *edac_device_name, unsigned nr_instances, + char *edac_block_name, unsigned nr_blocks, + unsigned offset_value, + struct edac_dev_sysfs_block_attribute *block_attributes, + unsigned nr_attribs, + int device_index); + +/* The offset value can be: + * -1 indicating no offset value + * 0 for zero-based block numbers + * 1 for 1-based block number + * other for other-based block number + */ +#define BLOCK_OFFSET_VALUE_OFF ((unsigned) -1) + +extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info); + +extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev); +extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev); +extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, + int inst_nr, int block_nr, const char *msg); +extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, + int inst_nr, int block_nr, const char *msg); +extern int edac_device_alloc_index(void); +extern const char *edac_layer_name[]; + +#endif diff --git a/drivers/edac/edac_device_sysfs.c b/drivers/edac/edac_device_sysfs.c index 93da1a45c716..0e7ea3591b78 100644 --- a/drivers/edac/edac_device_sysfs.c +++ b/drivers/edac/edac_device_sysfs.c @@ -1,7 +1,7 @@ /* * file for managing the edac_device subsystem of devices for EDAC * - * (C) 2007 SoftwareBitMaker + * (C) 2007 SoftwareBitMaker * * This file may be distributed under the terms of the * GNU General Public License. @@ -15,7 +15,7 @@ #include #include -#include "edac_core.h" +#include "edac_device.h" #include "edac_module.h" #define EDAC_DEVICE_SYMLINK "device" -- cgit v1.2.3 From 78d88e8a3d738f1ce508cd24b525d2e6cdfda1c1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 29 Oct 2016 15:16:34 -0200 Subject: edac: rename edac_core.h to edac_mc.h Now, all left at edac_core.h are at drivers/edac/edac_mc.c, so rename it to edac_mc.h. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/altera_edac.c | 1 - drivers/edac/amd64_edac.h | 2 +- drivers/edac/amd76x_edac.c | 2 +- drivers/edac/amd8111_edac.c | 1 - drivers/edac/amd8131_edac.c | 1 - drivers/edac/cell_edac.c | 2 +- drivers/edac/cpc925_edac.c | 1 - drivers/edac/e752x_edac.c | 2 +- drivers/edac/e7xxx_edac.c | 2 +- drivers/edac/edac_core.h | 134 ---------------------------------------- drivers/edac/edac_mc.c | 2 +- drivers/edac/edac_mc.h | 131 +++++++++++++++++++++++++++++++++++++++ drivers/edac/edac_mc_sysfs.c | 2 +- drivers/edac/edac_module.c | 2 +- drivers/edac/edac_module.h | 4 +- drivers/edac/fsl_ddr_edac.c | 1 - drivers/edac/ghes_edac.c | 2 +- drivers/edac/highbank_l2_edac.c | 1 - drivers/edac/highbank_mc_edac.c | 1 - drivers/edac/i3000_edac.c | 2 +- drivers/edac/i3200_edac.c | 2 +- drivers/edac/i5000_edac.c | 2 +- drivers/edac/i5100_edac.c | 1 - drivers/edac/i5400_edac.c | 2 +- drivers/edac/i7300_edac.c | 2 +- drivers/edac/i7core_edac.c | 2 +- drivers/edac/i82443bxgx_edac.c | 2 +- drivers/edac/i82860_edac.c | 2 +- drivers/edac/i82875p_edac.c | 2 +- drivers/edac/i82975x_edac.c | 2 +- drivers/edac/ie31200_edac.c | 2 +- drivers/edac/layerscape_edac.c | 2 +- drivers/edac/mpc85xx_edac.c | 1 - drivers/edac/mv64x60_edac.c | 1 - drivers/edac/octeon_edac-l2c.c | 1 - drivers/edac/octeon_edac-lmc.c | 1 - drivers/edac/octeon_edac-pc.c | 1 - drivers/edac/octeon_edac-pci.c | 1 - drivers/edac/pasemi_edac.c | 2 +- drivers/edac/ppc4xx_edac.c | 2 +- drivers/edac/r82600_edac.c | 2 +- drivers/edac/sb_edac.c | 2 +- drivers/edac/skx_edac.c | 2 +- drivers/edac/synopsys_edac.c | 2 +- drivers/edac/tile_edac.c | 2 +- drivers/edac/x38_edac.c | 2 +- drivers/edac/xgene_edac.c | 1 - 47 files changed, 163 insertions(+), 179 deletions(-) delete mode 100644 drivers/edac/edac_core.h create mode 100644 drivers/edac/edac_mc.h (limited to 'drivers') diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 6421cc3c7dc1..c5a5b91f37f0 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -35,7 +35,6 @@ #include #include "altera_edac.h" -#include "edac_core.h" #include "edac_module.h" #define EDAC_MOD_STR "altera_edac" diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index f14c24d5b140..496603d8f3d2 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -17,7 +17,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #include "mce_amd.h" #define amd64_debug(fmt, arg...) \ diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c index 3a501b530e11..a7450275ad28 100644 --- a/drivers/edac/amd76x_edac.c +++ b/drivers/edac/amd76x_edac.c @@ -17,7 +17,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define AMD76X_REVISION " Ver: 2.0.2" #define EDAC_MOD_STR "amd76x_edac" diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c index 2b63f7c2d6d2..b5786cfded3a 100644 --- a/drivers/edac/amd8111_edac.c +++ b/drivers/edac/amd8111_edac.c @@ -29,7 +29,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #include "amd8111_edac.h" diff --git a/drivers/edac/amd8131_edac.c b/drivers/edac/amd8131_edac.c index a5c680561c73..8851c33d7d24 100644 --- a/drivers/edac/amd8131_edac.c +++ b/drivers/edac/amd8131_edac.c @@ -29,7 +29,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #include "amd8131_edac.h" diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c index a9259b069dcd..bc1f3416400e 100644 --- a/drivers/edac/cell_edac.c +++ b/drivers/edac/cell_edac.c @@ -19,7 +19,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" struct cell_edac_priv { diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c index 682288ced4ac..837b62c4993d 100644 --- a/drivers/edac/cpc925_edac.c +++ b/drivers/edac/cpc925_edac.c @@ -27,7 +27,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #define CPC925_EDAC_REVISION " Ver: 1.0.0" diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index b2d71388172b..1a352cae1f52 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c @@ -24,7 +24,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define E752X_REVISION " Ver: 2.0.2" #define EDAC_MOD_STR "e752x_edac" diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c index ece3aef16bb1..67ef07aed923 100644 --- a/drivers/edac/e7xxx_edac.c +++ b/drivers/edac/e7xxx_edac.c @@ -30,7 +30,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define E7XXX_REVISION " Ver: 2.0.2" #define EDAC_MOD_STR "e7xxx_edac" diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h deleted file mode 100644 index 3e11d9d85462..000000000000 --- a/drivers/edac/edac_core.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Defines, structures, APIs for edac_core module - * - * (C) 2007 Linux Networx (http://lnxi.com) - * This file may be distributed under the terms of the - * GNU General Public License. - * - * Written by Thayne Harbaugh - * Based on work by Dan Hollis and others. - * http://www.anime.net/~goemon/linux-ecc/ - * - * NMI handling support added by - * Dave Peterson - * - * Refactored for multi-source files: - * Doug Thompson - * - */ - -#ifndef _EDAC_CORE_H_ -#define _EDAC_CORE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "edac_pci.h" -#include "edac_device.h" - -#if PAGE_SHIFT < 20 -#define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) -#define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) -#else /* PAGE_SHIFT > 20 */ -#define PAGES_TO_MiB(pages) ((pages) << (PAGE_SHIFT - 20)) -#define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20)) -#endif - -#define edac_printk(level, prefix, fmt, arg...) \ - printk(level "EDAC " prefix ": " fmt, ##arg) - -#define edac_mc_printk(mci, level, fmt, arg...) \ - printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg) - -#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \ - printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg) - -#define edac_device_printk(ctl, level, fmt, arg...) \ - printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg) - -#define edac_pci_printk(ctl, level, fmt, arg...) \ - printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg) - -/* prefixes for edac_printk() and edac_mc_printk() */ -#define EDAC_MC "MC" -#define EDAC_PCI "PCI" -#define EDAC_DEBUG "DEBUG" - -extern const char * const edac_mem_types[]; - -#ifdef CONFIG_EDAC_DEBUG -extern int edac_debug_level; - -#define edac_dbg(level, fmt, ...) \ -do { \ - if (level <= edac_debug_level) \ - edac_printk(KERN_DEBUG, EDAC_DEBUG, \ - "%s: " fmt, __func__, ##__VA_ARGS__); \ -} while (0) - -#else /* !CONFIG_EDAC_DEBUG */ - -#define edac_dbg(level, fmt, ...) \ -do { \ - if (0) \ - edac_printk(KERN_DEBUG, EDAC_DEBUG, \ - "%s: " fmt, __func__, ##__VA_ARGS__); \ -} while (0) - -#endif /* !CONFIG_EDAC_DEBUG */ - -#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ - PCI_DEVICE_ID_ ## vend ## _ ## dev - -#define edac_dev_name(dev) (dev)->dev_name - -#define to_mci(k) container_of(k, struct mem_ctl_info, dev) - -struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, - unsigned n_layers, - struct edac_mc_layer *layers, - unsigned sz_pvt); -extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, - const struct attribute_group **groups); -#define edac_mc_add_mc(mci) edac_mc_add_mc_with_groups(mci, NULL) -extern void edac_mc_free(struct mem_ctl_info *mci); -extern struct mem_ctl_info *edac_mc_find(int idx); -extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); -extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); -extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, - unsigned long page); - -void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type, - struct mem_ctl_info *mci, - struct edac_raw_error_desc *e); - -void edac_mc_handle_error(const enum hw_event_mc_err_type type, - struct mem_ctl_info *mci, - const u16 error_count, - const unsigned long page_frame_number, - const unsigned long offset_in_page, - const unsigned long syndrome, - const int top_layer, - const int mid_layer, - const int low_layer, - const char *msg, - const char *other_detail); - -/* - * edac misc APIs - */ -extern char *edac_op_state_to_string(int op_state); - -#endif /* _EDAC_CORE_H_ */ diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index d2ea9c4f1824..4ff5116a90a5 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -30,7 +30,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_mc.h" #include "edac_module.h" #include diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h new file mode 100644 index 000000000000..b62d9bad9859 --- /dev/null +++ b/drivers/edac/edac_mc.h @@ -0,0 +1,131 @@ +/* + * Defines, structures, APIs for edac_mc module + * + * (C) 2007 Linux Networx (http://lnxi.com) + * This file may be distributed under the terms of the + * GNU General Public License. + * + * Written by Thayne Harbaugh + * Based on work by Dan Hollis and others. + * http://www.anime.net/~goemon/linux-ecc/ + * + * NMI handling support added by + * Dave Peterson + * + * Refactored for multi-source files: + * Doug Thompson + * + */ + +#ifndef _EDAC_MC_H_ +#define _EDAC_MC_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if PAGE_SHIFT < 20 +#define PAGES_TO_MiB(pages) ((pages) >> (20 - PAGE_SHIFT)) +#define MiB_TO_PAGES(mb) ((mb) << (20 - PAGE_SHIFT)) +#else /* PAGE_SHIFT > 20 */ +#define PAGES_TO_MiB(pages) ((pages) << (PAGE_SHIFT - 20)) +#define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20)) +#endif + +#define edac_printk(level, prefix, fmt, arg...) \ + printk(level "EDAC " prefix ": " fmt, ##arg) + +#define edac_mc_printk(mci, level, fmt, arg...) \ + printk(level "EDAC MC%d: " fmt, mci->mc_idx, ##arg) + +#define edac_mc_chipset_printk(mci, level, prefix, fmt, arg...) \ + printk(level "EDAC " prefix " MC%d: " fmt, mci->mc_idx, ##arg) + +#define edac_device_printk(ctl, level, fmt, arg...) \ + printk(level "EDAC DEVICE%d: " fmt, ctl->dev_idx, ##arg) + +#define edac_pci_printk(ctl, level, fmt, arg...) \ + printk(level "EDAC PCI%d: " fmt, ctl->pci_idx, ##arg) + +/* prefixes for edac_printk() and edac_mc_printk() */ +#define EDAC_MC "MC" +#define EDAC_PCI "PCI" +#define EDAC_DEBUG "DEBUG" + +extern const char * const edac_mem_types[]; + +#ifdef CONFIG_EDAC_DEBUG +extern int edac_debug_level; + +#define edac_dbg(level, fmt, ...) \ +do { \ + if (level <= edac_debug_level) \ + edac_printk(KERN_DEBUG, EDAC_DEBUG, \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ +} while (0) + +#else /* !CONFIG_EDAC_DEBUG */ + +#define edac_dbg(level, fmt, ...) \ +do { \ + if (0) \ + edac_printk(KERN_DEBUG, EDAC_DEBUG, \ + "%s: " fmt, __func__, ##__VA_ARGS__); \ +} while (0) + +#endif /* !CONFIG_EDAC_DEBUG */ + +#define PCI_VEND_DEV(vend, dev) PCI_VENDOR_ID_ ## vend, \ + PCI_DEVICE_ID_ ## vend ## _ ## dev + +#define edac_dev_name(dev) (dev)->dev_name + +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + +struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, + unsigned n_layers, + struct edac_mc_layer *layers, + unsigned sz_pvt); +extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, + const struct attribute_group **groups); +#define edac_mc_add_mc(mci) edac_mc_add_mc_with_groups(mci, NULL) +extern void edac_mc_free(struct mem_ctl_info *mci); +extern struct mem_ctl_info *edac_mc_find(int idx); +extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); +extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); +extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, + unsigned long page); + +void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type, + struct mem_ctl_info *mci, + struct edac_raw_error_desc *e); + +void edac_mc_handle_error(const enum hw_event_mc_err_type type, + struct mem_ctl_info *mci, + const u16 error_count, + const unsigned long page_frame_number, + const unsigned long offset_in_page, + const unsigned long syndrome, + const int top_layer, + const int mid_layer, + const int low_layer, + const char *msg, + const char *other_detail); + +/* + * edac misc APIs + */ +extern char *edac_op_state_to_string(int op_state); + +#endif /* _EDAC_MC_H_ */ diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 4e0f8e720ad9..39dbab7d62f1 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -19,7 +19,7 @@ #include #include -#include "edac_core.h" +#include "edac_mc.h" #include "edac_module.h" /* MC EDAC Controls, setable by module parameter, and sysfs */ diff --git a/drivers/edac/edac_module.c b/drivers/edac/edac_module.c index 5f8543be995a..172598a27d7d 100644 --- a/drivers/edac/edac_module.c +++ b/drivers/edac/edac_module.c @@ -12,7 +12,7 @@ */ #include -#include "edac_core.h" +#include "edac_mc.h" #include "edac_module.h" #define EDAC_VERSION "Ver: 3.0.0" diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index cfaacb99c973..014871e169cc 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -10,7 +10,9 @@ #ifndef __EDAC_MODULE_H__ #define __EDAC_MODULE_H__ -#include "edac_core.h" +#include "edac_mc.h" +#include "edac_pci.h" +#include "edac_device.h" /* * INTERNAL EDAC MODULE: diff --git a/drivers/edac/fsl_ddr_edac.c b/drivers/edac/fsl_ddr_edac.c index 9774f52f0c3e..4e9608a958e7 100644 --- a/drivers/edac/fsl_ddr_edac.c +++ b/drivers/edac/fsl_ddr_edac.c @@ -28,7 +28,6 @@ #include #include #include "edac_module.h" -#include "edac_core.h" #include "fsl_ddr_edac.h" #define EDAC_MOD_STR "fsl_ddr_edac" diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index e3fa4390f846..4e61a6229dd2 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -14,7 +14,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #include #define GHES_EDAC_REVISION " Ver: 1.0.0" diff --git a/drivers/edac/highbank_l2_edac.c b/drivers/edac/highbank_l2_edac.c index 2f193668ebc7..cd9a2bb7c548 100644 --- a/drivers/edac/highbank_l2_edac.c +++ b/drivers/edac/highbank_l2_edac.c @@ -21,7 +21,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #define SR_CLR_SB_ECC_INTR 0x0 diff --git a/drivers/edac/highbank_mc_edac.c b/drivers/edac/highbank_mc_edac.c index 11260cc3360e..0e7e0a404d89 100644 --- a/drivers/edac/highbank_mc_edac.c +++ b/drivers/edac/highbank_mc_edac.c @@ -22,7 +22,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" /* DDR Ctrlr Error Registers */ diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index 5cb36a6022cc..5306240570d7 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c @@ -14,7 +14,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define I3000_REVISION "1.1" diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index 1f453382258a..77c58d201a30 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c @@ -13,7 +13,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #include diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c index 72e07e3cf718..1670d27bcac8 100644 --- a/drivers/edac/i5000_edac.c +++ b/drivers/edac/i5000_edac.c @@ -22,7 +22,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" /* * Alter this version for the I5000 module when modifications are made diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index c655162caf08..a8334c4acea7 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -29,7 +29,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" /* register addresses */ diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c index 6ef6ad1ba16e..abf6ef22e220 100644 --- a/drivers/edac/i5400_edac.c +++ b/drivers/edac/i5400_edac.c @@ -32,7 +32,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" /* * Alter this version for the I5400 module when modifications are made diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index dcac982fdc7a..0a912bf6de00 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c @@ -26,7 +26,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" /* * Alter this version for the I7300 module when modifications are made diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8a68a5e943ea..69b5adead0ad 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -39,7 +39,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" /* Static vars */ static LIST_HEAD(i7core_edac_list); diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index 4d4110364f02..cb61a5b7d080 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c @@ -29,7 +29,7 @@ #include -#include "edac_core.h" +#include "edac_module.h" #define I82443_REVISION "0.1" diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c index ee1078cd3b96..236c813227fc 100644 --- a/drivers/edac/i82860_edac.c +++ b/drivers/edac/i82860_edac.c @@ -14,7 +14,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define I82860_REVISION " Ver: 2.0.2" #define EDAC_MOD_STR "i82860_edac" diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c index c26a513f8869..e286b7e74c7a 100644 --- a/drivers/edac/i82875p_edac.c +++ b/drivers/edac/i82875p_edac.c @@ -18,7 +18,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define I82875P_REVISION " Ver: 2.0.2" #define EDAC_MOD_STR "i82875p_edac" diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c index 35ab66c623a3..7baa8ace267b 100644 --- a/drivers/edac/i82975x_edac.c +++ b/drivers/edac/i82975x_edac.c @@ -14,7 +14,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define I82975X_REVISION " Ver: 1.0.0" #define EDAC_MOD_STR "i82975x_edac" diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c index 1c88d9707495..2733fb5938a4 100644 --- a/drivers/edac/ie31200_edac.c +++ b/drivers/edac/ie31200_edac.c @@ -41,7 +41,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" #define IE31200_REVISION "1.0" #define EDAC_MOD_STR "ie31200_edac" diff --git a/drivers/edac/layerscape_edac.c b/drivers/edac/layerscape_edac.c index 6c59d897ad12..94cac7686a56 100644 --- a/drivers/edac/layerscape_edac.c +++ b/drivers/edac/layerscape_edac.c @@ -16,7 +16,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include "edac_core.h" +#include "edac_module.h" #include "fsl_ddr_edac.h" static const struct of_device_id fsl_ddr_mc_err_of_match[] = { diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c index c62602141f95..8f66cbed70b7 100644 --- a/drivers/edac/mpc85xx_edac.c +++ b/drivers/edac/mpc85xx_edac.c @@ -25,7 +25,6 @@ #include #include #include "edac_module.h" -#include "edac_core.h" #include "mpc85xx_edac.h" #include "fsl_ddr_edac.h" diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index cb9b8577acbc..14b7e7b71eaa 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c @@ -17,7 +17,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #include "mv64x60_edac.h" diff --git a/drivers/edac/octeon_edac-l2c.c b/drivers/edac/octeon_edac-l2c.c index afea7fc625cc..c33059e9b0be 100644 --- a/drivers/edac/octeon_edac-l2c.c +++ b/drivers/edac/octeon_edac-l2c.c @@ -16,7 +16,6 @@ #include -#include "edac_core.h" #include "edac_module.h" #define EDAC_MOD_STR "octeon-l2c" diff --git a/drivers/edac/octeon_edac-lmc.c b/drivers/edac/octeon_edac-lmc.c index cda6dab5067a..9c1ffe3e912b 100644 --- a/drivers/edac/octeon_edac-lmc.c +++ b/drivers/edac/octeon_edac-lmc.c @@ -19,7 +19,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #define OCTEON_MAX_MC 4 diff --git a/drivers/edac/octeon_edac-pc.c b/drivers/edac/octeon_edac-pc.c index 2ab6cf24c959..754eced59c32 100644 --- a/drivers/edac/octeon_edac-pc.c +++ b/drivers/edac/octeon_edac-pc.c @@ -15,7 +15,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #include diff --git a/drivers/edac/octeon_edac-pci.c b/drivers/edac/octeon_edac-pci.c index 9ca73cec74e7..28b238eecefc 100644 --- a/drivers/edac/octeon_edac-pci.c +++ b/drivers/edac/octeon_edac-pci.c @@ -18,7 +18,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" static void octeon_pci_poll(struct edac_pci_ctl_info *pci) diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c index 9c971b575530..199f2c80480d 100644 --- a/drivers/edac/pasemi_edac.c +++ b/drivers/edac/pasemi_edac.c @@ -26,7 +26,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define MODULE_NAME "pasemi_edac" diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 691ce25e9010..e55e92590106 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -21,7 +21,7 @@ #include -#include "edac_core.h" +#include "edac_module.h" #include "ppc4xx_edac.h" /* diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c index 8f936bc7a010..978916625ced 100644 --- a/drivers/edac/r82600_edac.c +++ b/drivers/edac/r82600_edac.c @@ -20,7 +20,7 @@ #include #include #include -#include "edac_core.h" +#include "edac_module.h" #define R82600_REVISION " Ver: 2.0.2" #define EDAC_MOD_STR "r82600_edac" diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index c1ad0eb7d5dd..54ae6dc45ab2 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -27,7 +27,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" /* Static vars */ static LIST_HEAD(sbridge_edac_list); diff --git a/drivers/edac/skx_edac.c b/drivers/edac/skx_edac.c index 9edcb29b3001..79ef675e4d6f 100644 --- a/drivers/edac/skx_edac.c +++ b/drivers/edac/skx_edac.c @@ -29,7 +29,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" #define SKX_REVISION " Ver: 1.0 " diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c index fc153aea2f6c..1c01dec78ec3 100644 --- a/drivers/edac/synopsys_edac.c +++ b/drivers/edac/synopsys_edac.c @@ -23,7 +23,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" /* Number of cs_rows needed per memory controller */ #define SYNPS_EDAC_NR_CSROWS 1 diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c index 71381642ce2a..8a33a87e67f1 100644 --- a/drivers/edac/tile_edac.c +++ b/drivers/edac/tile_edac.c @@ -30,7 +30,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" #define DRV_NAME "tile-edac" diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index 314cf5cf268c..03c97a4bf590 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c @@ -16,7 +16,7 @@ #include #include -#include "edac_core.h" +#include "edac_module.h" #define X38_REVISION "1.1" diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c index 5569391ea800..6c270d9d304a 100644 --- a/drivers/edac/xgene_edac.c +++ b/drivers/edac/xgene_edac.c @@ -28,7 +28,6 @@ #include #include -#include "edac_core.h" #include "edac_module.h" #define EDAC_MOD_STR "xgene_edac" -- cgit v1.2.3 From 5336f75499bbb293910b3502b3c4a4f9ab9ff078 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 26 Oct 2016 16:01:47 -0200 Subject: edac: move documentation from edac_device to edac_core.h Several functions are documented at edac_device.c. As we'll be including edac_core.h at drivers-api book, move those, in order for the kernel-doc markups be part of the API documentation book. As several of those kernel-doc macros are not in the right format, fix them. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_device.c | 58 ---------------------------------------------- drivers/edac/edac_device.h | 51 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 58 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index 046ab7794fc2..de4d5d08af9e 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -47,21 +47,6 @@ static void edac_device_dump_device(struct edac_device_ctl_info *edac_dev) } #endif /* CONFIG_EDAC_DEBUG */ - -/* - * edac_device_alloc_ctl_info() - * Allocate a new edac device control info structure - * - * The control structure is allocated in complete chunk - * from the OS. It is in turn sub allocated to the - * various objects that compose the structure - * - * The structure has a 'nr_instance' array within itself. - * Each instance represents a major component - * Example: L1 cache and L2 cache are 2 instance components - * - * Within each instance is an array of 'nr_blocks' blockoffsets - */ struct edac_device_ctl_info *edac_device_alloc_ctl_info( unsigned sz_private, char *edac_device_name, unsigned nr_instances, @@ -241,11 +226,6 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info( } EXPORT_SYMBOL_GPL(edac_device_alloc_ctl_info); -/* - * edac_device_free_ctl_info() - * frees the memory allocated by the edac_device_alloc_ctl_info() - * function - */ void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info) { edac_device_unregister_sysfs_main_kobj(ctl_info); @@ -457,12 +437,6 @@ void edac_device_reset_delay_period(struct edac_device_ctl_info *edac_dev, edac_mod_work(&edac_dev->work, jiffs); } -/* - * edac_device_alloc_index: Allocate a unique device index number - * - * Return: - * allocated index number - */ int edac_device_alloc_index(void) { static atomic_t device_indexes = ATOMIC_INIT(0); @@ -471,17 +445,6 @@ int edac_device_alloc_index(void) } EXPORT_SYMBOL_GPL(edac_device_alloc_index); -/** - * edac_device_add_device: Insert the 'edac_dev' structure into the - * edac_device global list and create sysfs entries associated with - * edac_device structure. - * @edac_device: pointer to the edac_device structure to be added to the list - * 'edac_device' structure. - * - * Return: - * 0 Success - * !0 Failure - */ int edac_device_add_device(struct edac_device_ctl_info *edac_dev) { edac_dbg(0, "\n"); @@ -538,19 +501,6 @@ fail0: } EXPORT_SYMBOL_GPL(edac_device_add_device); -/** - * edac_device_del_device: - * Remove sysfs entries for specified edac_device structure and - * then remove edac_device structure from global list - * - * @dev: - * Pointer to 'struct device' representing edac_device - * structure to remove. - * - * Return: - * Pointer to removed edac_device structure, - * OR NULL if device not found. - */ struct edac_device_ctl_info *edac_device_del_device(struct device *dev) { struct edac_device_ctl_info *edac_dev; @@ -605,10 +555,6 @@ static inline int edac_device_get_panic_on_ue(struct edac_device_ctl_info return edac_dev->panic_on_ue; } -/* - * edac_device_handle_ce - * perform a common output and handling of an 'edac_dev' CE event - */ void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg) { @@ -651,10 +597,6 @@ void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, } EXPORT_SYMBOL_GPL(edac_device_handle_ce); -/* - * edac_device_handle_ue - * perform a common output and handling of an 'edac_dev' UE event - */ void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg) { diff --git a/drivers/edac/edac_device.h b/drivers/edac/edac_device.h index eb1204408529..1aaba74ae411 100644 --- a/drivers/edac/edac_device.h +++ b/drivers/edac/edac_device.h @@ -257,12 +257,63 @@ extern struct edac_device_ctl_info *edac_device_alloc_ctl_info( extern void edac_device_free_ctl_info(struct edac_device_ctl_info *ctl_info); +/** + * edac_device_add_device: Insert the 'edac_dev' structure into the + * edac_device global list and create sysfs entries associated with + * edac_device structure. + * + * @edac_dev: pointer to edac_device structure to be added to the list + * 'edac_device' structure. + * + * Returns: + * 0 on Success, or an error code on failure + */ extern int edac_device_add_device(struct edac_device_ctl_info *edac_dev); + +/** + * edac_device_del_device: + * Remove sysfs entries for specified edac_device structure and + * then remove edac_device structure from global list + * + * @dev: + * Pointer to struct &device representing the edac device + * structure to remove. + * + * Returns: + * Pointer to removed edac_device structure, + * or %NULL if device not found. + */ extern struct edac_device_ctl_info *edac_device_del_device(struct device *dev); + +/** + * edac_device_handle_ue(): + * perform a common output and handling of an 'edac_dev' UE event + * + * @edac_dev: pointer to struct &edac_device_ctl_info + * @inst_nr: number of the instance where the UE error happened + * @block_nr: number of the block where the UE error happened + * @msg: message to be printed + */ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg); +/** + * edac_device_handle_ce(): + * perform a common output and handling of an 'edac_dev' CE event + * + * @edac_dev: pointer to struct &edac_device_ctl_info + * @inst_nr: number of the instance where the CE error happened + * @block_nr: number of the block where the CE error happened + * @msg: message to be printed + */ extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev, int inst_nr, int block_nr, const char *msg); + +/** + * edac_device_alloc_index: Allocate a unique device index number + * + * Returns: + * allocated index number + */ extern int edac_device_alloc_index(void); extern const char *edac_layer_name[]; -- cgit v1.2.3 From fdaf0b3505f330b8a56ddec4e904049be998d6d1 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 26 Oct 2016 16:13:43 -0200 Subject: edac: move documentation from edac_pci*.c to edac_pci.h Several functions are documented at edac_pci.c and edac_pci_sysfs.c. As we'll be including edac_pci.h at drivers-api book, move those, in order for the kernel-doc markups be part of the API documentation book. As several of those kernel-doc macros are not in the right format, fix them. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_pci.c | 65 ---------------------------- drivers/edac/edac_pci.h | 98 +++++++++++++++++++++++++++++++++++++++++++ drivers/edac/edac_pci_sysfs.c | 11 ----- 3 files changed, 98 insertions(+), 76 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 02a0af4f53b3..4e9d5632041a 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -28,13 +28,6 @@ static DEFINE_MUTEX(edac_pci_ctls_mutex); static LIST_HEAD(edac_pci_list); static atomic_t pci_indexes = ATOMIC_INIT(0); -/* - * edac_pci_alloc_ctl_info - * - * The alloc() function for the 'edac_pci' control info - * structure. The chip driver will allocate one of these for each - * edac_pci it is going to control/register with the EDAC CORE. - */ struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, const char *edac_pci_name) { @@ -65,16 +58,6 @@ struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, } EXPORT_SYMBOL_GPL(edac_pci_alloc_ctl_info); -/* - * edac_pci_free_ctl_info() - * - * Last action on the pci control structure. - * - * call the remove sysfs information, which will unregister - * this control struct's kobj. When that kobj's ref count - * goes to zero, its release function will be call and then - * kfree() the memory. - */ void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci) { edac_dbg(1, "\n"); @@ -212,31 +195,12 @@ static void edac_pci_workq_function(struct work_struct *work_req) mutex_unlock(&edac_pci_ctls_mutex); } -/* - * edac_pci_alloc_index: Allocate a unique PCI index number - * - * Return: - * allocated index number - * - */ int edac_pci_alloc_index(void) { return atomic_inc_return(&pci_indexes) - 1; } EXPORT_SYMBOL_GPL(edac_pci_alloc_index); -/* - * edac_pci_add_device: Insert the 'edac_dev' structure into the - * edac_pci global list and create sysfs entries associated with - * edac_pci structure. - * @pci: pointer to the edac_device structure to be added to the list - * @edac_idx: A unique numeric identifier to be assigned to the - * 'edac_pci' structure. - * - * Return: - * 0 Success - * !0 Failure - */ int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx) { edac_dbg(0, "\n"); @@ -282,19 +246,6 @@ fail0: } EXPORT_SYMBOL_GPL(edac_pci_add_device); -/* - * edac_pci_del_device() - * Remove sysfs entries for specified edac_pci structure and - * then remove edac_pci structure from global list - * - * @dev: - * Pointer to 'struct device' representing edac_pci structure - * to remove - * - * Return: - * Pointer to removed edac_pci structure, - * or NULL if device not found - */ struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev) { struct edac_pci_ctl_info *pci; @@ -348,17 +299,6 @@ struct edac_pci_gen_data { int edac_idx; }; -/* - * edac_pci_create_generic_ctl - * - * A generic constructor for a PCI parity polling device - * Some systems have more than one domain of PCI busses. - * For systems with one domain, then this API will - * provide for a generic poller. - * - * This routine calls the edac_pci_alloc_ctl_info() for - * the generic device, with default values - */ struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev, const char *mod_name) { @@ -391,11 +331,6 @@ struct edac_pci_ctl_info *edac_pci_create_generic_ctl(struct device *dev, } EXPORT_SYMBOL_GPL(edac_pci_create_generic_ctl); -/* - * edac_pci_release_generic_ctl - * - * The release function of a generic EDAC PCI polling device - */ void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci) { edac_dbg(0, "pci mod=%s\n", pci->mod_name); diff --git a/drivers/edac/edac_pci.h b/drivers/edac/edac_pci.h index 9da0c6fb0634..5175f5724cfa 100644 --- a/drivers/edac/edac_pci.h +++ b/drivers/edac/edac_pci.h @@ -153,21 +153,119 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset, #endif /* CONFIG_PCI */ +/* + * edac_pci APIs + */ + +/** + * edac_pci_alloc_ctl_info: + * The alloc() function for the 'edac_pci' control info + * structure. + * + * @sz_pvt: size of the private info at struct &edac_pci_ctl_info + * @edac_pci_name: name of the PCI device + * + * The chip driver will allocate one of these for each + * edac_pci it is going to control/register with the EDAC CORE. + * + * Returns: a pointer to struct &edac_pci_ctl_info on success; %NULL otherwise. + */ extern struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt, const char *edac_pci_name); +/** + * edac_pci_free_ctl_info(): + * Last action on the pci control structure. + * + * @pci: pointer to struct &edac_pci_ctl_info + * + * Calls the remove sysfs information, which will unregister + * this control struct's kobj. When that kobj's ref count + * goes to zero, its release function will be call and then + * kfree() the memory. + */ extern void edac_pci_free_ctl_info(struct edac_pci_ctl_info *pci); +/** + * edac_pci_alloc_index: Allocate a unique PCI index number + * + * Returns: + * allocated index number + * + */ extern int edac_pci_alloc_index(void); + +/** + * edac_pci_add_device(): Insert the 'edac_dev' structure into the + * edac_pci global list and create sysfs entries associated with + * edac_pci structure. + * + * @pci: pointer to the edac_device structure to be added to the list + * @edac_idx: A unique numeric identifier to be assigned to the + * 'edac_pci' structure. + * + * Returns: + * 0 on Success, or an error code on failure + */ extern int edac_pci_add_device(struct edac_pci_ctl_info *pci, int edac_idx); + +/** + * edac_pci_del_device() + * Remove sysfs entries for specified edac_pci structure and + * then remove edac_pci structure from global list + * + * @dev: + * Pointer to 'struct device' representing edac_pci structure + * to remove + * + * Returns: + * Pointer to removed edac_pci structure, + * or %NULL if device not found + */ extern struct edac_pci_ctl_info *edac_pci_del_device(struct device *dev); +/** + * edac_pci_create_generic_ctl() + * A generic constructor for a PCI parity polling device + * Some systems have more than one domain of PCI busses. + * For systems with one domain, then this API will + * provide for a generic poller. + * + * @dev: pointer to struct &device; + * @mod_name: name of the PCI device + * + * This routine calls the edac_pci_alloc_ctl_info() for + * the generic device, with default values + * + * Returns: Pointer to struct &edac_pci_ctl_info on success, %NULL on + * failure. + */ extern struct edac_pci_ctl_info *edac_pci_create_generic_ctl( struct device *dev, const char *mod_name); +/** + * edac_pci_release_generic_ctl + * The release function of a generic EDAC PCI polling device + * + * @pci: pointer to struct &edac_pci_ctl_info + */ extern void edac_pci_release_generic_ctl(struct edac_pci_ctl_info *pci); + +/** + * edac_pci_create_sysfs + * Create the controls/attributes for the specified EDAC PCI device + * + * @pci: pointer to struct &edac_pci_ctl_info + */ extern int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci); + +/** + * edac_pci_remove_sysfs() + * remove the controls and attributes for this EDAC PCI device + * + * @pci: pointer to struct &edac_pci_ctl_info + */ extern void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci); #endif diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index dbeb048d8efb..72c9eb9fdffb 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c @@ -418,12 +418,6 @@ static void edac_pci_main_kobj_teardown(void) } } -/* - * - * edac_pci_create_sysfs - * - * Create the controls/attributes for the specified EDAC PCI device - */ int edac_pci_create_sysfs(struct edac_pci_ctl_info *pci) { int err; @@ -459,11 +453,6 @@ unregister_cleanup: return err; } -/* - * edac_pci_remove_sysfs - * - * remove the controls and attributes for this EDAC PCI device - */ void edac_pci_remove_sysfs(struct edac_pci_ctl_info *pci) { edac_dbg(0, "index=%d\n", pci->pci_idx); -- cgit v1.2.3 From e01aa14cf2e7ff6d39614f8087800d08ba1629b2 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 26 Oct 2016 15:47:55 -0200 Subject: edac: move documentation from edac_mc.c to edac_core.h Several functions are documented at edac_mc.c. As we'll be including edac_core.h at drivers-api book, move those, in order for the kernel-doc markups be part of the API documentation book. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_mc.c | 82 --------------------------------------- drivers/edac/edac_mc.h | 101 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 82 deletions(-) (limited to 'drivers') diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 4ff5116a90a5..5f2c717f8053 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -239,30 +239,6 @@ static void _edac_mc_free(struct mem_ctl_info *mci) kfree(mci); } -/** - * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure - * @mc_num: Memory controller number - * @n_layers: Number of MC hierarchy layers - * layers: Describes each layer as seen by the Memory Controller - * @size_pvt: size of private storage needed - * - * - * Everything is kmalloc'ed as one big chunk - more efficient. - * Only can be used if all structures have the same lifetime - otherwise - * you have to allocate and initialize your own structures. - * - * Use edac_mc_free() to free mc structures allocated by this function. - * - * NOTE: drivers handle multi-rank memories in different ways: in some - * drivers, one multi-rank memory stick is mapped as one entry, while, in - * others, a single multi-rank memory stick would be mapped into several - * entries. Currently, this function will allocate multiple struct dimm_info - * on such scenarios, as grouping the multiple ranks require drivers change. - * - * Returns: - * On failure: NULL - * On success: struct mem_ctl_info pointer - */ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, unsigned n_layers, struct edac_mc_layer *layers, @@ -460,11 +436,6 @@ error: } EXPORT_SYMBOL_GPL(edac_mc_alloc); -/** - * edac_mc_free - * 'Free' a previously allocated 'mci' structure - * @mci: pointer to a struct mem_ctl_info structure - */ void edac_mc_free(struct mem_ctl_info *mci) { edac_dbg(1, "\n"); @@ -646,12 +617,6 @@ static int del_mc_from_global_list(struct mem_ctl_info *mci) return handlers; } -/** - * edac_mc_find: Search for a mem_ctl_info structure whose index is 'idx'. - * - * If found, return a pointer to the structure. - * Else return NULL. - */ struct mem_ctl_info *edac_mc_find(int idx) { struct mem_ctl_info *mci = NULL; @@ -676,16 +641,6 @@ unlock: } EXPORT_SYMBOL(edac_mc_find); -/** - * edac_mc_add_mc_with_groups: Insert the 'mci' structure into the mci - * global list and create sysfs entries associated with mci structure - * @mci: pointer to the mci structure to be added to the list - * @groups: optional attribute groups for the driver-specific sysfs entries - * - * Return: - * 0 Success - * !0 Failure - */ /* FIXME - should a warning be printed if no error detection? correction? */ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, @@ -776,13 +731,6 @@ fail0: } EXPORT_SYMBOL_GPL(edac_mc_add_mc_with_groups); -/** - * edac_mc_del_mc: Remove sysfs entries for specified mci structure and - * remove mci structure from global list - * @pdev: Pointer to 'struct device' representing mci structure to remove. - * - * Return pointer to removed mci structure, or NULL if device not found. - */ struct mem_ctl_info *edac_mc_del_mc(struct device *dev) { struct mem_ctl_info *mci; @@ -1046,18 +994,6 @@ static void edac_ue_error(struct mem_ctl_info *mci, edac_inc_ue_error(mci, enable_per_layer_report, pos, error_count); } -/** - * edac_raw_mc_handle_error - reports a memory event to userspace without doing - * anything to discover the error location - * - * @type: severity of the error (CE/UE/Fatal) - * @mci: a struct mem_ctl_info pointer - * @e: error description - * - * This raw function is used internally by edac_mc_handle_error(). It should - * only be called directly when the hardware error come directly from BIOS, - * like in the case of APEI GHES driver. - */ void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type, struct mem_ctl_info *mci, struct edac_raw_error_desc *e) @@ -1087,24 +1023,6 @@ void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type, } EXPORT_SYMBOL_GPL(edac_raw_mc_handle_error); -/** - * edac_mc_handle_error - reports a memory event to userspace - * - * @type: severity of the error (CE/UE/Fatal) - * @mci: a struct mem_ctl_info pointer - * @error_count: Number of errors of the same type - * @page_frame_number: mem page where the error occurred - * @offset_in_page: offset of the error inside the page - * @syndrome: ECC syndrome - * @top_layer: Memory layer[0] position - * @mid_layer: Memory layer[1] position - * @low_layer: Memory layer[2] position - * @msg: Message meaningful to the end users that - * explains the event - * @other_detail: Technical details about the event that - * may help hardware manufacturers and - * EDAC developers to analyse the event - */ void edac_mc_handle_error(const enum hw_event_mc_err_type type, struct mem_ctl_info *mci, const u16 error_count, diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index b62d9bad9859..97ee6a91f633 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -93,24 +93,125 @@ do { \ #define to_mci(k) container_of(k, struct mem_ctl_info, dev) +/** + * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure + * @mc_num: Memory controller number + * @n_layers: Number of MC hierarchy layers + * @layers: Describes each layer as seen by the Memory Controller + * @sz_pvt: size of private storage needed + * + * + * Everything is kmalloc'ed as one big chunk - more efficient. + * Only can be used if all structures have the same lifetime - otherwise + * you have to allocate and initialize your own structures. + * + * Use edac_mc_free() to free mc structures allocated by this function. + * + * .. note:: + * + * drivers handle multi-rank memories in different ways: in some + * drivers, one multi-rank memory stick is mapped as one entry, while, in + * others, a single multi-rank memory stick would be mapped into several + * entries. Currently, this function will allocate multiple struct dimm_info + * on such scenarios, as grouping the multiple ranks require drivers change. + * + * Returns: + * On failure: NULL + * On success: struct mem_ctl_info pointer + */ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, unsigned n_layers, struct edac_mc_layer *layers, unsigned sz_pvt); + +/** + * edac_mc_add_mc_with_groups: Insert the 'mci' structure into the mci + * global list and create sysfs entries associated with mci structure + * @mci: pointer to the mci structure to be added to the list + * @groups: optional attribute groups for the driver-specific sysfs entries + * + * Return: + * 0 Success + * !0 Failure + */ extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, const struct attribute_group **groups); #define edac_mc_add_mc(mci) edac_mc_add_mc_with_groups(mci, NULL) + +/** + * edac_mc_free + * 'Free' a previously allocated 'mci' structure + * @mci: pointer to a struct mem_ctl_info structure + */ extern void edac_mc_free(struct mem_ctl_info *mci); + +/** + * edac_mc_find: Search for a mem_ctl_info structure whose index is @idx. + * + * @idx: index to be seek + * + * If found, return a pointer to the structure. + * Else return NULL. + * + * Caller must hold mem_ctls_mutex. + */ extern struct mem_ctl_info *edac_mc_find(int idx); + +/** + * find_mci_by_dev + * + * scan list of controllers looking for the one that manages + * the 'dev' device + * @dev: pointer to a struct device related with the MCI + */ extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); + +/** + * edac_mc_del_mc: Remove sysfs entries for specified mci structure and + * remove mci structure from global list + * + * @dev: Pointer to struct &device representing mci structure to remove. + * + * Returns: pointer to removed mci structure, or NULL if device not found. + */ extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page); +/** + * edac_raw_mc_handle_error - reports a memory event to userspace without doing + * anything to discover the error location + * + * @type: severity of the error (CE/UE/Fatal) + * @mci: a struct mem_ctl_info pointer + * @e: error description + * + * This raw function is used internally by edac_mc_handle_error(). It should + * only be called directly when the hardware error come directly from BIOS, + * like in the case of APEI GHES driver. + */ void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type, struct mem_ctl_info *mci, struct edac_raw_error_desc *e); +/** + * edac_mc_handle_error - reports a memory event to userspace + * + * @type: severity of the error (CE/UE/Fatal) + * @mci: a struct mem_ctl_info pointer + * @error_count: Number of errors of the same type + * @page_frame_number: mem page where the error occurred + * @offset_in_page: offset of the error inside the page + * @syndrome: ECC syndrome + * @top_layer: Memory layer[0] position + * @mid_layer: Memory layer[1] position + * @low_layer: Memory layer[2] position + * @msg: Message meaningful to the end users that + * explains the event + * @other_detail: Technical details about the event that + * may help hardware manufacturers and + * EDAC developers to analyse the event + */ void edac_mc_handle_error(const enum hw_event_mc_err_type type, struct mem_ctl_info *mci, const u16 error_count, -- cgit v1.2.3 From 6634fbb6b6356e6f5b428a349952b368b25d514d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 26 Oct 2016 14:14:45 -0200 Subject: driver-api: create an edac.rst file with EDAC documentation Currently, there's no device driver documentation for the EDAC subsystem at the driver-api book. Fill in the blanks for the structures and functions that misses documentation, uniform the word on the existing ones, and add a new edac.rst file at driver-api, in order to document the EDAC subsystem. Signed-off-by: Mauro Carvalho Chehab --- Documentation/driver-api/edac.rst | 72 ++++++++++++++++++++++++++++++++++++++ Documentation/driver-api/index.rst | 1 + drivers/edac/edac_mc.h | 2 -- 3 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 Documentation/driver-api/edac.rst (limited to 'drivers') diff --git a/Documentation/driver-api/edac.rst b/Documentation/driver-api/edac.rst new file mode 100644 index 000000000000..3771e768fda1 --- /dev/null +++ b/Documentation/driver-api/edac.rst @@ -0,0 +1,72 @@ +Error Detection And Correction (EDAC) Devices +============================================= + +Memory Controllers +------------------ + +Most of the EDAC core is focused on doing Memory Controller error detection. +The :c:func:`edac_mc_alloc`. It uses internally the struct ``mem_ctl_info`` +to describe the memory controllers, with is an opaque struct for the EDAC +drivers. Only the EDAC core is allowed to touch it. + +.. kernel-doc:: include/linux/edac.h + +.. kernel-doc:: drivers/edac/edac_mc.h + +PCI Controllers +--------------- + +The EDAC subsystem provides a mechanism to handle PCI controllers by calling +the :c:func:`edac_pci_alloc_ctl_info`. It will use the struct +:c:type:`edac_pci_ctl_info` to describe the PCI controllers. + +.. kernel-doc:: drivers/edac/edac_pci.h + +EDAC Blocks +----------- + +The EDAC subsystem also provides a generic mechanism to report errors on +other parts of the hardware via :c:func:`edac_device_alloc_ctl_info` function. + +The structures :c:type:`edac_dev_sysfs_block_attribute`, +:c:type:`edac_device_block`, :c:type:`edac_device_instance` and +:c:type:`edac_device_ctl_info` provide a generic or abstract 'edac_device' +representation at sysfs. + +This set of structures and the code that implements the APIs for the same, provide for registering EDAC type devices which are NOT standard memory or +PCI, like: + +- CPU caches (L1 and L2) +- DMA engines +- Core CPU switches +- Fabric switch units +- PCIe interface controllers +- other EDAC/ECC type devices that can be monitored for + errors, etc. + +It allows for a 2 level set of hierarchy. + +For example, a cache could be composed of L1, L2 and L3 levels of cache. +Each CPU core would have its own L1 cache, while sharing L2 and maybe L3 +caches. On such case, those can be represented via the following sysfs +nodes:: + + /sys/devices/system/edac/.. + + pci/ + mc/ + cpu/cpu0/.. + /L1-cache/ce_count + /ue_count + /L2-cache/ce_count + /ue_count + cpu/cpu1/.. + /L1-cache/ce_count + /ue_count + /L2-cache/ce_count + /ue_count + ... + + the L1 and L2 directories would be "edac_device_block's" + +.. kernel-doc:: drivers/edac/edac_device.h diff --git a/Documentation/driver-api/index.rst b/Documentation/driver-api/index.rst index a528178a54a5..5475a2807e7a 100644 --- a/Documentation/driver-api/index.rst +++ b/Documentation/driver-api/index.rst @@ -26,6 +26,7 @@ available subsections can be seen below. spi i2c hsi + edac miscellaneous vme 80211/index diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index 97ee6a91f633..dcc2c7e3b8bc 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -152,8 +152,6 @@ extern void edac_mc_free(struct mem_ctl_info *mci); * * If found, return a pointer to the structure. * Else return NULL. - * - * Caller must hold mem_ctls_mutex. */ extern struct mem_ctl_info *edac_mc_find(int idx); -- cgit v1.2.3 From 66c222a02fadfd7cc62c754c12379d6bb08eaf77 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 29 Oct 2016 10:35:23 -0200 Subject: edac: fix kernel-doc tags at the drivers/edac_*.h Some kernel-doc tags don't provide good descriptions or use a different style. Adjust them. Signed-off-by: Mauro Carvalho Chehab --- Documentation/admin-guide/ras.rst | 2 +- drivers/edac/edac_mc.h | 55 +++++++++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/Documentation/admin-guide/ras.rst b/Documentation/admin-guide/ras.rst index 2f8706bae5a4..d71340e86c27 100644 --- a/Documentation/admin-guide/ras.rst +++ b/Documentation/admin-guide/ras.rst @@ -843,7 +843,7 @@ Module parameters EDAC device type ---------------- -In the header file, edac_core.h, there is a series of edac_device structures +In the header file, edac_pci.h, there is a series of edac_device structures and APIs for the EDAC_DEVICE. User space access to an edac_device is through the sysfs interface. diff --git a/drivers/edac/edac_mc.h b/drivers/edac/edac_mc.h index dcc2c7e3b8bc..50fc1dc9c0d8 100644 --- a/drivers/edac/edac_mc.h +++ b/drivers/edac/edac_mc.h @@ -15,6 +15,8 @@ * Refactored for multi-source files: * Doug Thompson * + * Please look at Documentation/driver-api/edac.rst for more info about + * EDAC core structs and functions. */ #ifndef _EDAC_MC_H_ @@ -94,7 +96,8 @@ do { \ #define to_mci(k) container_of(k, struct mem_ctl_info, dev) /** - * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure + * edac_mc_alloc() - Allocate and partially fill a struct &mem_ctl_info. + * * @mc_num: Memory controller number * @n_layers: Number of MC hierarchy layers * @layers: Describes each layer as seen by the Memory Controller @@ -116,8 +119,8 @@ do { \ * on such scenarios, as grouping the multiple ranks require drivers change. * * Returns: - * On failure: NULL - * On success: struct mem_ctl_info pointer + * On success, return a pointer to struct mem_ctl_info pointer; + * %NULL otherwise */ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, unsigned n_layers, @@ -125,28 +128,28 @@ struct mem_ctl_info *edac_mc_alloc(unsigned mc_num, unsigned sz_pvt); /** - * edac_mc_add_mc_with_groups: Insert the 'mci' structure into the mci - * global list and create sysfs entries associated with mci structure + * edac_mc_add_mc_with_groups() - Insert the @mci structure into the mci + * global list and create sysfs entries associated with @mci structure. + * * @mci: pointer to the mci structure to be added to the list * @groups: optional attribute groups for the driver-specific sysfs entries * - * Return: - * 0 Success - * !0 Failure + * Returns: + * 0 on Success, or an error code on failure */ extern int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, const struct attribute_group **groups); #define edac_mc_add_mc(mci) edac_mc_add_mc_with_groups(mci, NULL) /** - * edac_mc_free - * 'Free' a previously allocated 'mci' structure + * edac_mc_free() - Frees a previously allocated @mci structure + * * @mci: pointer to a struct mem_ctl_info structure */ extern void edac_mc_free(struct mem_ctl_info *mci); /** - * edac_mc_find: Search for a mem_ctl_info structure whose index is @idx. + * edac_mc_find() - Search for a mem_ctl_info structure whose index is @idx. * * @idx: index to be seek * @@ -156,29 +159,41 @@ extern void edac_mc_free(struct mem_ctl_info *mci); extern struct mem_ctl_info *edac_mc_find(int idx); /** - * find_mci_by_dev + * find_mci_by_dev() - Scan list of controllers looking for the one that + * manages the @dev device. * - * scan list of controllers looking for the one that manages - * the 'dev' device * @dev: pointer to a struct device related with the MCI + * + * Returns: on success, returns a pointer to struct &mem_ctl_info; + * %NULL otherwise. */ extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); /** - * edac_mc_del_mc: Remove sysfs entries for specified mci structure and - * remove mci structure from global list + * edac_mc_del_mc() - Remove sysfs entries for mci structure associated with + * @dev and remove mci structure from global list. * * @dev: Pointer to struct &device representing mci structure to remove. * - * Returns: pointer to removed mci structure, or NULL if device not found. + * Returns: pointer to removed mci structure, or %NULL if device not found. */ extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); + +/** + * edac_mc_find_csrow_by_page() - Ancillary routine to identify what csrow + * contains a memory page. + * + * @mci: pointer to a struct mem_ctl_info structure + * @page: memory page to find + * + * Returns: on success, returns the csrow. -1 if not found. + */ extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page); /** - * edac_raw_mc_handle_error - reports a memory event to userspace without doing - * anything to discover the error location + * edac_raw_mc_handle_error() - Reports a memory event to userspace without + * doing anything to discover the error location. * * @type: severity of the error (CE/UE/Fatal) * @mci: a struct mem_ctl_info pointer @@ -193,7 +208,7 @@ void edac_raw_mc_handle_error(const enum hw_event_mc_err_type type, struct edac_raw_error_desc *e); /** - * edac_mc_handle_error - reports a memory event to userspace + * edac_mc_handle_error() - Reports a memory event to userspace. * * @type: severity of the error (CE/UE/Fatal) * @mci: a struct mem_ctl_info pointer -- cgit v1.2.3 From d0905ca757bc40bd1ebc261a448a521b064777d7 Mon Sep 17 00:00:00 2001 From: Andy Grover Date: Mon, 21 Nov 2016 16:35:30 -0800 Subject: target/user: Fix use-after-free of tcmu_cmds if they are expired Don't free the cmd in tcmu_check_expired_cmd, it's still referenced by an entry in our cmd_id->cmd idr. If userspace ever resumes processing, tcmu_handle_completions() will use the now-invalid cmd pointer. Instead, don't free cmd. It will be freed by tcmu_handle_completion() if userspace ever recovers, or tcmu_free_device if not. Cc: stable@vger.kernel.org Reported-by: Bryant G Ly Tested-by: Bryant G Ly Signed-off-by: Andy Grover Signed-off-by: Bart Van Assche --- drivers/target/target_core_user.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 1bf1d37aa2e3..2e331008d30b 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -686,8 +686,6 @@ static int tcmu_check_expired_cmd(int id, void *p, void *data) target_complete_cmd(cmd->se_cmd, SAM_STAT_CHECK_CONDITION); cmd->se_cmd = NULL; - kmem_cache_free(tcmu_cmd_cache, cmd); - return 0; } -- cgit v1.2.3 From 54971406b7731efd5dbe0b1ccc42dfbd8af1f3b2 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 16:06:38 +0800 Subject: drm/amdgpu: disable uvd pg on Tonga. it does not work with GPU pass through if the VM is not cleanly shutdown leading to a hang when the modules is reloaded. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/vi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 9f771f4ffcb7..6d49254636b8 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -933,7 +933,7 @@ static int vi_common_early_init(void *handle) break; case CHIP_TONGA: adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG; - adev->pg_flags = AMD_PG_SUPPORT_UVD; + adev->pg_flags = 0; adev->external_rev_id = adev->rev_id + 0x14; break; case CHIP_POLARIS11: -- cgit v1.2.3 From eb584241226958d45aa1f07f4f6a6ea9da98b29e Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 17:22:25 +0800 Subject: drm/amdgpu: fix enable_cp_power_gating in gfx_v8.0. the CP_PG_DISABLE bit was reversed. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 6324f67bdb1f..2dbe6a1d8973 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3996,7 +3996,7 @@ static void cz_enable_sck_slow_down_on_power_down(struct amdgpu_device *adev, static void cz_enable_cp_power_gating(struct amdgpu_device *adev, bool enable) { - WREG32_FIELD(RLC_PG_CNTL, CP_PG_DISABLE, enable ? 1 : 0); + WREG32_FIELD(RLC_PG_CNTL, CP_PG_DISABLE, enable ? 0 : 1); } static void gfx_v8_0_init_pg(struct amdgpu_device *adev) -- cgit v1.2.3 From 202e0b227b906cb80a2791f21216a55d9468d61b Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 17:44:20 +0800 Subject: drm/amdgpu: fix init save/restore list in gfx_v8.0 set valid data to mmRLC_SRM_INDEX_CNTL_ADDRx/DATAx. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 2dbe6a1d8973..2e65ccbb91be 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3949,8 +3949,12 @@ static int gfx_v8_0_init_save_restore_list(struct amdgpu_device *adev) temp = mmRLC_SRM_INDEX_CNTL_ADDR_0; data = mmRLC_SRM_INDEX_CNTL_DATA_0; for (i = 0; i < sizeof(unique_indices) / sizeof(int); i++) { - amdgpu_mm_wreg(adev, temp + i, unique_indices[i] & 0x3FFFF, false); - amdgpu_mm_wreg(adev, data + i, unique_indices[i] >> 20, false); + if (unique_indices[i] != 0) { + amdgpu_mm_wreg(adev, temp + i, + unique_indices[i] & 0x3FFFF, false); + amdgpu_mm_wreg(adev, data + i, + unique_indices[i] >> 20, false); + } } kfree(register_list_format); -- cgit v1.2.3 From 98fccc78bc29e35f7204f5f6cf7f0a923e335222 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 17:48:48 +0800 Subject: drm/amdgpu: enable AMD_PG_SUPPORT_CP in Carrizo/Stoney. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 6d49254636b8..16342195bb8e 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -971,6 +971,7 @@ static int vi_common_early_init(void *handle) adev->pg_flags |= AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_GFX_SMG | AMD_PG_SUPPORT_GFX_PIPELINE | + AMD_PG_SUPPORT_CP | AMD_PG_SUPPORT_UVD | AMD_PG_SUPPORT_VCE; } @@ -996,6 +997,7 @@ static int vi_common_early_init(void *handle) adev->pg_flags = AMD_PG_SUPPORT_GFX_PG | AMD_PG_SUPPORT_GFX_SMG | AMD_PG_SUPPORT_GFX_PIPELINE | + AMD_PG_SUPPORT_CP | AMD_PG_SUPPORT_UVD | AMD_PG_SUPPORT_VCE; adev->external_rev_id = adev->rev_id + 0x61; -- cgit v1.2.3 From c4d17b81244d23e7727f0bf68f0f63905e871a73 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 17:54:57 +0800 Subject: drm/amdgpu: always initialize gfx pg for gfx_v8.0. v2: always init gfx pg for asics that can support. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 71 ++++++++++++++++------------------- 1 file changed, 32 insertions(+), 39 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 2e65ccbb91be..48ee40dce60e 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -3970,20 +3970,17 @@ static void gfx_v8_0_init_power_gating(struct amdgpu_device *adev) { uint32_t data; - if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG | - AMD_PG_SUPPORT_GFX_SMG | - AMD_PG_SUPPORT_GFX_DMG)) { - WREG32_FIELD(CP_RB_WPTR_POLL_CNTL, IDLE_POLL_COUNT, 0x60); - - data = REG_SET_FIELD(0, RLC_PG_DELAY, POWER_UP_DELAY, 0x10); - data = REG_SET_FIELD(data, RLC_PG_DELAY, POWER_DOWN_DELAY, 0x10); - data = REG_SET_FIELD(data, RLC_PG_DELAY, CMD_PROPAGATE_DELAY, 0x10); - data = REG_SET_FIELD(data, RLC_PG_DELAY, MEM_SLEEP_DELAY, 0x10); - WREG32(mmRLC_PG_DELAY, data); - - WREG32_FIELD(RLC_PG_DELAY_2, SERDES_CMD_DELAY, 0x3); - WREG32_FIELD(RLC_AUTO_PG_CTRL, GRBM_REG_SAVE_GFX_IDLE_THRESHOLD, 0x55f0); - } + WREG32_FIELD(CP_RB_WPTR_POLL_CNTL, IDLE_POLL_COUNT, 0x60); + + data = REG_SET_FIELD(0, RLC_PG_DELAY, POWER_UP_DELAY, 0x10); + data = REG_SET_FIELD(data, RLC_PG_DELAY, POWER_DOWN_DELAY, 0x10); + data = REG_SET_FIELD(data, RLC_PG_DELAY, CMD_PROPAGATE_DELAY, 0x10); + data = REG_SET_FIELD(data, RLC_PG_DELAY, MEM_SLEEP_DELAY, 0x10); + WREG32(mmRLC_PG_DELAY, data); + + WREG32_FIELD(RLC_PG_DELAY_2, SERDES_CMD_DELAY, 0x3); + WREG32_FIELD(RLC_AUTO_PG_CTRL, GRBM_REG_SAVE_GFX_IDLE_THRESHOLD, 0x55f0); + } static void cz_enable_sck_slow_down_on_power_up(struct amdgpu_device *adev, @@ -4005,36 +4002,32 @@ static void cz_enable_cp_power_gating(struct amdgpu_device *adev, bool enable) static void gfx_v8_0_init_pg(struct amdgpu_device *adev) { - if (adev->pg_flags & (AMD_PG_SUPPORT_GFX_PG | - AMD_PG_SUPPORT_GFX_SMG | - AMD_PG_SUPPORT_GFX_DMG | - AMD_PG_SUPPORT_CP | - AMD_PG_SUPPORT_GDS | - AMD_PG_SUPPORT_RLC_SMU_HS)) { + if ((adev->asic_type == CHIP_CARRIZO) || + (adev->asic_type == CHIP_STONEY)) { gfx_v8_0_init_csb(adev); gfx_v8_0_init_save_restore_list(adev); gfx_v8_0_enable_save_restore_machine(adev); - - if ((adev->asic_type == CHIP_CARRIZO) || - (adev->asic_type == CHIP_STONEY)) { - WREG32(mmRLC_JUMP_TABLE_RESTORE, adev->gfx.rlc.cp_table_gpu_addr >> 8); - gfx_v8_0_init_power_gating(adev); - WREG32(mmRLC_PG_ALWAYS_ON_CU_MASK, adev->gfx.cu_info.ao_cu_mask); - if (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS) { - cz_enable_sck_slow_down_on_power_up(adev, true); - cz_enable_sck_slow_down_on_power_down(adev, true); - } else { - cz_enable_sck_slow_down_on_power_up(adev, false); - cz_enable_sck_slow_down_on_power_down(adev, false); - } - if (adev->pg_flags & AMD_PG_SUPPORT_CP) - cz_enable_cp_power_gating(adev, true); - else - cz_enable_cp_power_gating(adev, false); - } else if (adev->asic_type == CHIP_POLARIS11) { - gfx_v8_0_init_power_gating(adev); + WREG32(mmRLC_JUMP_TABLE_RESTORE, adev->gfx.rlc.cp_table_gpu_addr >> 8); + gfx_v8_0_init_power_gating(adev); + WREG32(mmRLC_PG_ALWAYS_ON_CU_MASK, adev->gfx.cu_info.ao_cu_mask); + if (adev->pg_flags & AMD_PG_SUPPORT_RLC_SMU_HS) { + cz_enable_sck_slow_down_on_power_up(adev, true); + cz_enable_sck_slow_down_on_power_down(adev, true); + } else { + cz_enable_sck_slow_down_on_power_up(adev, false); + cz_enable_sck_slow_down_on_power_down(adev, false); } + if (adev->pg_flags & AMD_PG_SUPPORT_CP) + cz_enable_cp_power_gating(adev, true); + else + cz_enable_cp_power_gating(adev, false); + } else if (adev->asic_type == CHIP_POLARIS11) { + gfx_v8_0_init_csb(adev); + gfx_v8_0_init_save_restore_list(adev); + gfx_v8_0_enable_save_restore_machine(adev); + gfx_v8_0_init_power_gating(adev); } + } static void gfx_v8_0_rlc_stop(struct amdgpu_device *adev) -- cgit v1.2.3 From ad1830d504d85233392215c9966e5876b99c481e Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 17:55:50 +0800 Subject: drm/amdgpu: fix pg can't be disabled by PG mask. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 48ee40dce60e..9bf6b6218f32 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -5336,14 +5336,11 @@ static int gfx_v8_0_set_powergating_state(void *handle, struct amdgpu_device *adev = (struct amdgpu_device *)handle; bool enable = (state == AMD_PG_STATE_GATE) ? true : false; - if (!(adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) - return 0; - switch (adev->asic_type) { case CHIP_CARRIZO: case CHIP_STONEY: - if (adev->pg_flags & AMD_PG_SUPPORT_GFX_PG) - cz_update_gfx_cg_power_gating(adev, enable); + + cz_update_gfx_cg_power_gating(adev, enable); if ((adev->pg_flags & AMD_PG_SUPPORT_GFX_SMG) && enable) gfx_v8_0_enable_gfx_static_mg_power_gating(adev, true); -- cgit v1.2.3 From 398d82ccbd8b97e67d2503f09345de5d63a80c56 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Fri, 9 Dec 2016 13:27:27 +0800 Subject: drm/amdgpu: add new gfx cg flags. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/include/amd_shared.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/include/amd_shared.h b/drivers/gpu/drm/amd/include/amd_shared.h index d1986276dbbd..c02469ada9f1 100644 --- a/drivers/gpu/drm/amd/include/amd_shared.h +++ b/drivers/gpu/drm/amd/include/amd_shared.h @@ -126,6 +126,10 @@ enum amd_vce_level { #define AMD_CG_SUPPORT_HDP_LS (1 << 15) #define AMD_CG_SUPPORT_HDP_MGCG (1 << 16) #define AMD_CG_SUPPORT_ROM_MGCG (1 << 17) +#define AMD_CG_SUPPORT_DRM_LS (1 << 18) +#define AMD_CG_SUPPORT_BIF_MGCG (1 << 19) +#define AMD_CG_SUPPORT_GFX_3D_CGCG (1 << 20) +#define AMD_CG_SUPPORT_GFX_3D_CGLS (1 << 21) /* PG flags */ #define AMD_PG_SUPPORT_GFX_PG (1 << 0) -- cgit v1.2.3 From ca18b84986ccde80fe3ba6c2aed4408b25c0da8c Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 18:22:38 +0800 Subject: drm/amdgpu: initialize cg flags for tonga/polaris10/polaris11. Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/vi.c | 52 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 16342195bb8e..33a2badf586a 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -932,18 +932,64 @@ static int vi_common_early_init(void *handle) adev->external_rev_id = adev->rev_id + 0x3c; break; case CHIP_TONGA: - adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG; + adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG | + AMD_CG_SUPPORT_GFX_CGCG | + AMD_CG_SUPPORT_GFX_CGLS | + AMD_CG_SUPPORT_SDMA_MGCG | + AMD_CG_SUPPORT_SDMA_LS | + AMD_CG_SUPPORT_BIF_LS | + AMD_CG_SUPPORT_HDP_MGCG | + AMD_CG_SUPPORT_HDP_LS | + AMD_CG_SUPPORT_ROM_MGCG | + AMD_CG_SUPPORT_MC_MGCG | + AMD_CG_SUPPORT_MC_LS | + AMD_CG_SUPPORT_DRM_LS | + AMD_CG_SUPPORT_UVD_MGCG; adev->pg_flags = 0; adev->external_rev_id = adev->rev_id + 0x14; break; case CHIP_POLARIS11: - adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG | + adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG | + AMD_CG_SUPPORT_GFX_RLC_LS | + AMD_CG_SUPPORT_GFX_CP_LS | + AMD_CG_SUPPORT_GFX_CGCG | + AMD_CG_SUPPORT_GFX_CGLS | + AMD_CG_SUPPORT_GFX_3D_CGCG | + AMD_CG_SUPPORT_GFX_3D_CGLS | + AMD_CG_SUPPORT_SDMA_MGCG | + AMD_CG_SUPPORT_SDMA_LS | + AMD_CG_SUPPORT_BIF_MGCG | + AMD_CG_SUPPORT_BIF_LS | + AMD_CG_SUPPORT_HDP_MGCG | + AMD_CG_SUPPORT_HDP_LS | + AMD_CG_SUPPORT_ROM_MGCG | + AMD_CG_SUPPORT_MC_MGCG | + AMD_CG_SUPPORT_MC_LS | + AMD_CG_SUPPORT_DRM_LS | + AMD_CG_SUPPORT_UVD_MGCG | AMD_CG_SUPPORT_VCE_MGCG; adev->pg_flags = 0; adev->external_rev_id = adev->rev_id + 0x5A; break; case CHIP_POLARIS10: - adev->cg_flags = AMD_CG_SUPPORT_UVD_MGCG | + adev->cg_flags = AMD_CG_SUPPORT_GFX_MGCG | + AMD_CG_SUPPORT_GFX_RLC_LS | + AMD_CG_SUPPORT_GFX_CP_LS | + AMD_CG_SUPPORT_GFX_CGCG | + AMD_CG_SUPPORT_GFX_CGLS | + AMD_CG_SUPPORT_GFX_3D_CGCG | + AMD_CG_SUPPORT_GFX_3D_CGLS | + AMD_CG_SUPPORT_SDMA_MGCG | + AMD_CG_SUPPORT_SDMA_LS | + AMD_CG_SUPPORT_BIF_MGCG | + AMD_CG_SUPPORT_BIF_LS | + AMD_CG_SUPPORT_HDP_MGCG | + AMD_CG_SUPPORT_HDP_LS | + AMD_CG_SUPPORT_ROM_MGCG | + AMD_CG_SUPPORT_MC_MGCG | + AMD_CG_SUPPORT_MC_LS | + AMD_CG_SUPPORT_DRM_LS | + AMD_CG_SUPPORT_UVD_MGCG | AMD_CG_SUPPORT_VCE_MGCG; adev->pg_flags = 0; adev->external_rev_id = adev->rev_id + 0x50; -- cgit v1.2.3 From 8a19e7fa085e22519f2b069406f82ae24d3f3c93 Mon Sep 17 00:00:00 2001 From: Rex Zhu Date: Wed, 7 Dec 2016 19:11:49 +0800 Subject: drm/amdgpu: refine set clock gating for tonga/polaris Signed-off-by: Rex Zhu Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c | 165 +++++++++++++++++++++++++--------- drivers/gpu/drm/amd/amdgpu/vi.c | 155 ++++++++++++++++++++++---------- 2 files changed, 230 insertions(+), 90 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c index 9bf6b6218f32..d0ec00986f38 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v8_0.c @@ -5785,25 +5785,49 @@ static int gfx_v8_0_update_gfx_clock_gating(struct amdgpu_device *adev, static int gfx_v8_0_tonga_update_gfx_clock_gating(struct amdgpu_device *adev, enum amd_clockgating_state state) { - uint32_t msg_id, pp_state; + uint32_t msg_id, pp_state = 0; + uint32_t pp_support_state = 0; void *pp_handle = adev->powerplay.pp_handle; - if (state == AMD_CG_STATE_UNGATE) - pp_state = 0; - else - pp_state = PP_STATE_CG | PP_STATE_LS; + if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_CGLS)) { + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) { + pp_support_state = PP_STATE_SUPPORT_LS; + pp_state = PP_STATE_LS; + } + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG) { + pp_support_state |= PP_STATE_SUPPORT_CG; + pp_state |= PP_STATE_CG; + } + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_CG, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } - msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, - PP_BLOCK_GFX_CG, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS)) { + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) { + pp_support_state = PP_STATE_SUPPORT_LS; + pp_state = PP_STATE_LS; + } - msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, - PP_BLOCK_GFX_MG, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG) { + pp_support_state |= PP_STATE_SUPPORT_CG; + pp_state |= PP_STATE_CG; + } + + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_MG, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } return 0; } @@ -5811,43 +5835,98 @@ static int gfx_v8_0_tonga_update_gfx_clock_gating(struct amdgpu_device *adev, static int gfx_v8_0_polaris_update_gfx_clock_gating(struct amdgpu_device *adev, enum amd_clockgating_state state) { - uint32_t msg_id, pp_state; + + uint32_t msg_id, pp_state = 0; + uint32_t pp_support_state = 0; void *pp_handle = adev->powerplay.pp_handle; - if (state == AMD_CG_STATE_UNGATE) - pp_state = 0; - else - pp_state = PP_STATE_CG | PP_STATE_LS; + if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_CGCG | AMD_CG_SUPPORT_GFX_CGLS)) { + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGLS) { + pp_support_state = PP_STATE_SUPPORT_LS; + pp_state = PP_STATE_LS; + } + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CGCG) { + pp_support_state |= PP_STATE_SUPPORT_CG; + pp_state |= PP_STATE_CG; + } + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_CG, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } - msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, - PP_BLOCK_GFX_CG, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_3D_CGCG | AMD_CG_SUPPORT_GFX_3D_CGLS)) { + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGLS) { + pp_support_state = PP_STATE_SUPPORT_LS; + pp_state = PP_STATE_LS; + } + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_3D_CGCG) { + pp_support_state |= PP_STATE_SUPPORT_CG; + pp_state |= PP_STATE_CG; + } + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_3D, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } - msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, - PP_BLOCK_GFX_3D, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + if (adev->cg_flags & (AMD_CG_SUPPORT_GFX_MGCG | AMD_CG_SUPPORT_GFX_MGLS)) { + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGLS) { + pp_support_state = PP_STATE_SUPPORT_LS; + pp_state = PP_STATE_LS; + } - msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, - PP_BLOCK_GFX_MG, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_MGCG) { + pp_support_state |= PP_STATE_SUPPORT_CG; + pp_state |= PP_STATE_CG; + } - msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, - PP_BLOCK_GFX_RLC, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; - msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_MG, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_RLC_LS) { + pp_support_state = PP_STATE_SUPPORT_LS; + + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + else + pp_state = PP_STATE_LS; + + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, + PP_BLOCK_GFX_RLC, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + + if (adev->cg_flags & AMD_CG_SUPPORT_GFX_CP_LS) { + pp_support_state = PP_STATE_SUPPORT_LS; + + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + else + pp_state = PP_STATE_LS; + msg_id = PP_CG_MSG_ID(PP_GROUP_GFX, PP_BLOCK_GFX_CP, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, + pp_support_state, pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } return 0; } diff --git a/drivers/gpu/drm/amd/amdgpu/vi.c b/drivers/gpu/drm/amd/amdgpu/vi.c index 33a2badf586a..bf088d6d9bf1 100644 --- a/drivers/gpu/drm/amd/amdgpu/vi.c +++ b/drivers/gpu/drm/amd/amdgpu/vi.c @@ -1203,57 +1203,118 @@ static void vi_update_rom_medium_grain_clock_gating(struct amdgpu_device *adev, static int vi_common_set_clockgating_state_by_smu(void *handle, enum amd_clockgating_state state) { - uint32_t msg_id, pp_state; + uint32_t msg_id, pp_state = 0; + uint32_t pp_support_state = 0; struct amdgpu_device *adev = (struct amdgpu_device *)handle; void *pp_handle = adev->powerplay.pp_handle; - if (state == AMD_CG_STATE_UNGATE) - pp_state = 0; - else - pp_state = PP_STATE_CG | PP_STATE_LS; - - msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, - PP_BLOCK_SYS_MC, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); - - msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, - PP_BLOCK_SYS_SDMA, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); - - msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, - PP_BLOCK_SYS_HDP, - PP_STATE_SUPPORT_CG | PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); - - msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, - PP_BLOCK_SYS_BIF, - PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); - - msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, - PP_BLOCK_SYS_BIF, - PP_STATE_SUPPORT_CG, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); - - msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, - PP_BLOCK_SYS_DRM, - PP_STATE_SUPPORT_LS, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); - - msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, - PP_BLOCK_SYS_ROM, - PP_STATE_SUPPORT_CG, - pp_state); - amd_set_clockgating_by_smu(pp_handle, msg_id); + if (adev->cg_flags & (AMD_CG_SUPPORT_MC_LS | AMD_CG_SUPPORT_MC_MGCG)) { + if (adev->cg_flags & AMD_CG_SUPPORT_MC_LS) { + pp_support_state = AMD_CG_SUPPORT_MC_LS; + pp_state = PP_STATE_LS; + } + if (adev->cg_flags & AMD_CG_SUPPORT_MC_MGCG) { + pp_support_state |= AMD_CG_SUPPORT_MC_MGCG; + pp_state |= PP_STATE_CG; + } + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_MC, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + + if (adev->cg_flags & (AMD_CG_SUPPORT_SDMA_LS | AMD_CG_SUPPORT_SDMA_MGCG)) { + if (adev->cg_flags & AMD_CG_SUPPORT_SDMA_LS) { + pp_support_state = AMD_CG_SUPPORT_SDMA_LS; + pp_state = PP_STATE_LS; + } + if (adev->cg_flags & AMD_CG_SUPPORT_SDMA_MGCG) { + pp_support_state |= AMD_CG_SUPPORT_SDMA_MGCG; + pp_state |= PP_STATE_CG; + } + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_SDMA, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + + if (adev->cg_flags & (AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_MGCG)) { + if (adev->cg_flags & AMD_CG_SUPPORT_HDP_LS) { + pp_support_state = AMD_CG_SUPPORT_HDP_LS; + pp_state = PP_STATE_LS; + } + if (adev->cg_flags & AMD_CG_SUPPORT_HDP_MGCG) { + pp_support_state |= AMD_CG_SUPPORT_HDP_MGCG; + pp_state |= PP_STATE_CG; + } + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_HDP, + pp_support_state, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + + + if (adev->cg_flags & AMD_CG_SUPPORT_BIF_LS) { + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + else + pp_state = PP_STATE_LS; + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_BIF, + PP_STATE_SUPPORT_LS, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + if (adev->cg_flags & AMD_CG_SUPPORT_BIF_MGCG) { + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + else + pp_state = PP_STATE_CG; + + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_BIF, + PP_STATE_SUPPORT_CG, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + + if (adev->cg_flags & AMD_CG_SUPPORT_DRM_LS) { + + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + else + pp_state = PP_STATE_LS; + + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_DRM, + PP_STATE_SUPPORT_LS, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } + + if (adev->cg_flags & AMD_CG_SUPPORT_ROM_MGCG) { + + if (state == AMD_CG_STATE_UNGATE) + pp_state = 0; + else + pp_state = PP_STATE_CG; + + msg_id = PP_CG_MSG_ID(PP_GROUP_SYS, + PP_BLOCK_SYS_ROM, + PP_STATE_SUPPORT_CG, + pp_state); + amd_set_clockgating_by_smu(pp_handle, msg_id); + } return 0; } -- cgit v1.2.3 From d3ea547853852481dc5eba6d4cb13adab1564d0b Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Thu, 15 Dec 2016 12:18:42 -0800 Subject: rdma: fix buggy code that the compiler warns about MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Get rid of this warning: drivers/infiniband/sw/rdmavt/cq.c: In function ‘rvt_cq_exit’: drivers/infiniband/sw/rdmavt/cq.c:542:2: warning: ‘worker’ may be used uninitialized in this function [-Wmaybe-uninitialized] kthread_destroy_worker(worker); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ by fixing the function to actually work. Fixes: 6efaf10f163d ("IB/rdmavt: Avoid queuing work into a destroyed cq kthread worker") Cc: Petr Mladek Cc: Doug Ledford Signed-off-by: Linus Torvalds --- drivers/infiniband/sw/rdmavt/cq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rdmavt/cq.c b/drivers/infiniband/sw/rdmavt/cq.c index 4d0b6992e847..7aa7a4e312f1 100644 --- a/drivers/infiniband/sw/rdmavt/cq.c +++ b/drivers/infiniband/sw/rdmavt/cq.c @@ -532,7 +532,8 @@ void rvt_cq_exit(struct rvt_dev_info *rdi) /* block future queuing from send_complete() */ spin_lock_irq(&rdi->n_cqs_lock); - if (!rdi->worker) { + worker = rdi->worker; + if (!worker) { spin_unlock_irq(&rdi->n_cqs_lock); return; } -- cgit v1.2.3 From cb2bf25145e0d2abef20f47dd2ae55bff97fd9cb Mon Sep 17 00:00:00 2001 From: Darren Hart Date: Wed, 14 Dec 2016 14:45:48 -0800 Subject: platform/x86: thinkpad_acpi: Initialize local in_tablet_mode and type linux-next reported in_tablet_mode and type may be used uninitialized after: b31800283868 ("platform/x86: thinkpad_acpi: Move tablet detection into separate function") This turns out to be a false positive as the pr_info call cannot be reached if tp_features.hotkey_tablet (global scope) is 0, and in_tablet_mode and type are assigned in both places tp_features.hotkey_tablet is assigned. Regardless, to make it explicit and avoid further reports, initialize in_tablet_mode to 0 and type to NULL. Signed-off-by: Darren Hart Acked-by: Henrique de Moraes Holschuh Cc: Lyude --- drivers/platform/x86/thinkpad_acpi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index 69cb0da95be9..aa65a857a6b1 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -3143,8 +3143,8 @@ typedef tpacpi_keymap_entry_t tpacpi_keymap_t[TPACPI_HOTKEY_MAP_LEN]; static int hotkey_init_tablet_mode(void) { - int in_tablet_mode, res; - char *type; + int in_tablet_mode = 0, res; + char *type = NULL; if (acpi_evalf(hkey_handle, &res, "MHKG", "qd")) { /* For X41t, X60t, X61t Tablets... */ -- cgit v1.2.3 From d41795978c47fa87b6514a0f2238958b7e8319a0 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 15 Dec 2016 23:58:13 +0200 Subject: virtio: clean up handling of request_irq failure We call del_vqs twice when request_irq fails, this makes no sense. Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_common.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index d9a905827967..423f3d9c1548 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -360,10 +360,8 @@ static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs, vring_interrupt, 0, vp_dev->msix_names[msix_vec], vqs[i]); - if (err) { - vp_del_vq(vqs[i]); + if (err) goto error_find; - } } return 0; -- cgit v1.2.3 From fa3a3279354e5f7a13ec16f2c9f5e39124745332 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 17 Nov 2016 11:43:13 +0100 Subject: virtio_pci: use pci_alloc_irq_vectors This avoids the separate allocation for the msix_entries structures, and instead allows us to use pci_irq_vector to find a given IRQ vector. Signed-off-by: Christoph Hellwig Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_common.c | 42 +++++++++++++++----------------------- drivers/virtio/virtio_pci_common.h | 1 - 2 files changed, 17 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 423f3d9c1548..2846872d5728 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -37,7 +37,7 @@ void vp_synchronize_vectors(struct virtio_device *vdev) synchronize_irq(vp_dev->pci_dev->irq); for (i = 0; i < vp_dev->msix_vectors; ++i) - synchronize_irq(vp_dev->msix_entries[i].vector); + synchronize_irq(pci_irq_vector(vp_dev->pci_dev, i)); } /* the notify function used when creating a virt queue */ @@ -113,7 +113,7 @@ static void vp_free_vectors(struct virtio_device *vdev) } for (i = 0; i < vp_dev->msix_used_vectors; ++i) - free_irq(vp_dev->msix_entries[i].vector, vp_dev); + free_irq(pci_irq_vector(vp_dev->pci_dev, i), vp_dev); for (i = 0; i < vp_dev->msix_vectors; i++) if (vp_dev->msix_affinity_masks[i]) @@ -123,7 +123,7 @@ static void vp_free_vectors(struct virtio_device *vdev) /* Disable the vector used for configuration */ vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR); - pci_disable_msix(vp_dev->pci_dev); + pci_free_irq_vectors(vp_dev->pci_dev); vp_dev->msix_enabled = 0; } @@ -131,8 +131,6 @@ static void vp_free_vectors(struct virtio_device *vdev) vp_dev->msix_used_vectors = 0; kfree(vp_dev->msix_names); vp_dev->msix_names = NULL; - kfree(vp_dev->msix_entries); - vp_dev->msix_entries = NULL; kfree(vp_dev->msix_affinity_masks); vp_dev->msix_affinity_masks = NULL; } @@ -147,10 +145,6 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, vp_dev->msix_vectors = nvectors; - vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries, - GFP_KERNEL); - if (!vp_dev->msix_entries) - goto error; vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names, GFP_KERNEL); if (!vp_dev->msix_names) @@ -165,12 +159,9 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, GFP_KERNEL)) goto error; - for (i = 0; i < nvectors; ++i) - vp_dev->msix_entries[i].entry = i; - - err = pci_enable_msix_exact(vp_dev->pci_dev, - vp_dev->msix_entries, nvectors); - if (err) + err = pci_alloc_irq_vectors(vp_dev->pci_dev, nvectors, nvectors, + PCI_IRQ_MSIX); + if (err < 0) goto error; vp_dev->msix_enabled = 1; @@ -178,7 +169,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, v = vp_dev->msix_used_vectors; snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-config", name); - err = request_irq(vp_dev->msix_entries[v].vector, + err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), vp_config_changed, 0, vp_dev->msix_names[v], vp_dev); if (err) @@ -197,7 +188,7 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, v = vp_dev->msix_used_vectors; snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names, "%s-virtqueues", name); - err = request_irq(vp_dev->msix_entries[v].vector, + err = request_irq(pci_irq_vector(vp_dev->pci_dev, v), vp_vring_interrupt, 0, vp_dev->msix_names[v], vp_dev); if (err) @@ -276,14 +267,15 @@ void vp_del_vqs(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtqueue *vq, *n; - struct virtio_pci_vq_info *info; list_for_each_entry_safe(vq, n, &vdev->vqs, list) { - info = vp_dev->vqs[vq->index]; - if (vp_dev->per_vq_vectors && - info->msix_vector != VIRTIO_MSI_NO_VECTOR) - free_irq(vp_dev->msix_entries[info->msix_vector].vector, - vq); + if (vp_dev->per_vq_vectors) { + int v = vp_dev->vqs[vq->index]->msix_vector; + + if (v != VIRTIO_MSI_NO_VECTOR) + free_irq(pci_irq_vector(vp_dev->pci_dev, v), + vq); + } vp_del_vq(vq); } vp_dev->per_vq_vectors = false; @@ -356,7 +348,7 @@ static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs, sizeof *vp_dev->msix_names, "%s-%s", dev_name(&vp_dev->vdev.dev), names[i]); - err = request_irq(vp_dev->msix_entries[msix_vec].vector, + err = request_irq(pci_irq_vector(vp_dev->pci_dev, msix_vec), vring_interrupt, 0, vp_dev->msix_names[msix_vec], vqs[i]); @@ -417,7 +409,7 @@ int vp_set_vq_affinity(struct virtqueue *vq, int cpu) if (vp_dev->msix_enabled) { mask = vp_dev->msix_affinity_masks[info->msix_vector]; - irq = vp_dev->msix_entries[info->msix_vector].vector; + irq = pci_irq_vector(vp_dev->pci_dev, info->msix_vector); if (cpu == -1) irq_set_affinity_hint(irq, NULL); else { diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h index 28263200ed42..b2f666250ae0 100644 --- a/drivers/virtio/virtio_pci_common.h +++ b/drivers/virtio/virtio_pci_common.h @@ -85,7 +85,6 @@ struct virtio_pci_device { /* MSI-X support */ int msix_enabled; int intx_enabled; - struct msix_entry *msix_entries; cpumask_var_t *msix_affinity_masks; /* Name strings for interrupts. This size should be enough, * and I'm too lazy to allocate each name separately. */ -- cgit v1.2.3 From 9f8196cc05caa9aba19f38f29c5f9a12722986c4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 17 Nov 2016 11:43:14 +0100 Subject: virtio_pci: remove the call to vp_free_vectors in vp_request_msix_vectors vp_request_msix_vectors is only called by vp_try_to_find_vqs, which already calls vp_free_vectors through vp_del_vqs in the failure case. Signed-off-by: Christoph Hellwig Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_common.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 2846872d5728..5fc9d283a954 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -197,7 +197,6 @@ static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, } return 0; error: - vp_free_vectors(vdev); return err; } -- cgit v1.2.3 From 66f2f55542270c44d67f05533594f75404c1481a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 17 Nov 2016 11:43:15 +0100 Subject: virtio_pci: merge vp_free_vectors into vp_del_vqs Signed-off-by: Christoph Hellwig Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_common.c | 61 +++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index 5fc9d283a954..c93739eaeea0 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -102,39 +102,6 @@ static irqreturn_t vp_interrupt(int irq, void *opaque) return vp_vring_interrupt(irq, opaque); } -static void vp_free_vectors(struct virtio_device *vdev) -{ - struct virtio_pci_device *vp_dev = to_vp_device(vdev); - int i; - - if (vp_dev->intx_enabled) { - free_irq(vp_dev->pci_dev->irq, vp_dev); - vp_dev->intx_enabled = 0; - } - - for (i = 0; i < vp_dev->msix_used_vectors; ++i) - free_irq(pci_irq_vector(vp_dev->pci_dev, i), vp_dev); - - for (i = 0; i < vp_dev->msix_vectors; i++) - if (vp_dev->msix_affinity_masks[i]) - free_cpumask_var(vp_dev->msix_affinity_masks[i]); - - if (vp_dev->msix_enabled) { - /* Disable the vector used for configuration */ - vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR); - - pci_free_irq_vectors(vp_dev->pci_dev); - vp_dev->msix_enabled = 0; - } - - vp_dev->msix_vectors = 0; - vp_dev->msix_used_vectors = 0; - kfree(vp_dev->msix_names); - vp_dev->msix_names = NULL; - kfree(vp_dev->msix_affinity_masks); - vp_dev->msix_affinity_masks = NULL; -} - static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors, bool per_vq_vectors) { @@ -266,6 +233,7 @@ void vp_del_vqs(struct virtio_device *vdev) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtqueue *vq, *n; + int i; list_for_each_entry_safe(vq, n, &vdev->vqs, list) { if (vp_dev->per_vq_vectors) { @@ -279,7 +247,32 @@ void vp_del_vqs(struct virtio_device *vdev) } vp_dev->per_vq_vectors = false; - vp_free_vectors(vdev); + if (vp_dev->intx_enabled) { + free_irq(vp_dev->pci_dev->irq, vp_dev); + vp_dev->intx_enabled = 0; + } + + for (i = 0; i < vp_dev->msix_used_vectors; ++i) + free_irq(pci_irq_vector(vp_dev->pci_dev, i), vp_dev); + + for (i = 0; i < vp_dev->msix_vectors; i++) + if (vp_dev->msix_affinity_masks[i]) + free_cpumask_var(vp_dev->msix_affinity_masks[i]); + + if (vp_dev->msix_enabled) { + /* Disable the vector used for configuration */ + vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR); + + pci_free_irq_vectors(vp_dev->pci_dev); + vp_dev->msix_enabled = 0; + } + + vp_dev->msix_vectors = 0; + vp_dev->msix_used_vectors = 0; + kfree(vp_dev->msix_names); + vp_dev->msix_names = NULL; + kfree(vp_dev->msix_affinity_masks); + vp_dev->msix_affinity_masks = NULL; kfree(vp_dev->vqs); vp_dev->vqs = NULL; } -- cgit v1.2.3 From a3cbec69727c8c149ee2b3652e184818cc269fe6 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 17 Nov 2016 11:43:16 +0100 Subject: virtio_pci: split vp_try_to_find_vqs into INTx and MSI-X variants There is basically no shared logic between the INTx and MSI-X case in vp_try_to_find_vqs, so split the function into two and clean them up a little bit. Also remove the fairly pointless vp_request_intx wrapper while we're at it. Signed-off-by: Christoph Hellwig Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_pci_common.c | 97 ++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c index c93739eaeea0..186cbab327b8 100644 --- a/drivers/virtio/virtio_pci_common.c +++ b/drivers/virtio/virtio_pci_common.c @@ -167,18 +167,6 @@ error: return err; } -static int vp_request_intx(struct virtio_device *vdev) -{ - int err; - struct virtio_pci_device *vp_dev = to_vp_device(vdev); - - err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, - IRQF_SHARED, dev_name(&vdev->dev), vp_dev); - if (!err) - vp_dev->intx_enabled = 1; - return err; -} - static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index, void (*callback)(struct virtqueue *vq), const char *name, @@ -277,50 +265,44 @@ void vp_del_vqs(struct virtio_device *vdev) vp_dev->vqs = NULL; } -static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs, +static int vp_find_vqs_msix(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], vq_callback_t *callbacks[], const char * const names[], - bool use_msix, bool per_vq_vectors) { struct virtio_pci_device *vp_dev = to_vp_device(vdev); u16 msix_vec; int i, err, nvectors, allocated_vectors; - vp_dev->vqs = kmalloc(nvqs * sizeof *vp_dev->vqs, GFP_KERNEL); + vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); if (!vp_dev->vqs) return -ENOMEM; - if (!use_msix) { - /* Old style: one normal interrupt for change and all vqs. */ - err = vp_request_intx(vdev); - if (err) - goto error_find; + if (per_vq_vectors) { + /* Best option: one for change interrupt, one per vq. */ + nvectors = 1; + for (i = 0; i < nvqs; ++i) + if (callbacks[i]) + ++nvectors; } else { - if (per_vq_vectors) { - /* Best option: one for change interrupt, one per vq. */ - nvectors = 1; - for (i = 0; i < nvqs; ++i) - if (callbacks[i]) - ++nvectors; - } else { - /* Second best: one for change, shared for all vqs. */ - nvectors = 2; - } - - err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors); - if (err) - goto error_find; + /* Second best: one for change, shared for all vqs. */ + nvectors = 2; } + err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors); + if (err) + goto error_find; + vp_dev->per_vq_vectors = per_vq_vectors; allocated_vectors = vp_dev->msix_used_vectors; for (i = 0; i < nvqs; ++i) { if (!names[i]) { vqs[i] = NULL; continue; - } else if (!callbacks[i] || !vp_dev->msix_enabled) + } + + if (!callbacks[i]) msix_vec = VIRTIO_MSI_NO_VECTOR; else if (vp_dev->per_vq_vectors) msix_vec = allocated_vectors++; @@ -354,6 +336,43 @@ error_find: return err; } +static int vp_find_vqs_intx(struct virtio_device *vdev, unsigned nvqs, + struct virtqueue *vqs[], vq_callback_t *callbacks[], + const char * const names[]) +{ + struct virtio_pci_device *vp_dev = to_vp_device(vdev); + int i, err; + + vp_dev->vqs = kcalloc(nvqs, sizeof(*vp_dev->vqs), GFP_KERNEL); + if (!vp_dev->vqs) + return -ENOMEM; + + err = request_irq(vp_dev->pci_dev->irq, vp_interrupt, IRQF_SHARED, + dev_name(&vdev->dev), vp_dev); + if (err) + goto out_del_vqs; + + vp_dev->intx_enabled = 1; + vp_dev->per_vq_vectors = false; + for (i = 0; i < nvqs; ++i) { + if (!names[i]) { + vqs[i] = NULL; + continue; + } + vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], + VIRTIO_MSI_NO_VECTOR); + if (IS_ERR(vqs[i])) { + err = PTR_ERR(vqs[i]); + goto out_del_vqs; + } + } + + return 0; +out_del_vqs: + vp_del_vqs(vdev); + return err; +} + /* the config->find_vqs() implementation */ int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, struct virtqueue *vqs[], @@ -363,17 +382,15 @@ int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs, int err; /* Try MSI-X with one vector per queue. */ - err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names, true, true); + err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, true); if (!err) return 0; /* Fallback: MSI-X with one vector for config, one shared for queues. */ - err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names, - true, false); + err = vp_find_vqs_msix(vdev, nvqs, vqs, callbacks, names, false); if (!err) return 0; /* Finally fall back to regular interrupts. */ - return vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names, - false, false); + return vp_find_vqs_intx(vdev, nvqs, vqs, callbacks, names); } const char *vp_bus_name(struct virtio_device *vdev) -- cgit v1.2.3 From 6c083c2b8a0a110cad936bc0a2c089f0d8115175 Mon Sep 17 00:00:00 2001 From: Gao feng Date: Wed, 14 Dec 2016 19:24:36 +0800 Subject: vsock: lookup and setup guest_cid inside vhost_vsock_lock Multi vsocks may setup the same cid at the same time. Signed-off-by: Gao feng Signed-off-by: Michael S. Tsirkin Reviewed-by: Stefan Hajnoczi --- drivers/vhost/vsock.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vsock.c b/drivers/vhost/vsock.c index e6b70966c19d..bbbf588540ed 100644 --- a/drivers/vhost/vsock.c +++ b/drivers/vhost/vsock.c @@ -50,11 +50,10 @@ static u32 vhost_transport_get_local_cid(void) return VHOST_VSOCK_DEFAULT_HOST_CID; } -static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) +static struct vhost_vsock *__vhost_vsock_get(u32 guest_cid) { struct vhost_vsock *vsock; - spin_lock_bh(&vhost_vsock_lock); list_for_each_entry(vsock, &vhost_vsock_list, list) { u32 other_cid = vsock->guest_cid; @@ -63,15 +62,24 @@ static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) continue; if (other_cid == guest_cid) { - spin_unlock_bh(&vhost_vsock_lock); return vsock; } } - spin_unlock_bh(&vhost_vsock_lock); return NULL; } +static struct vhost_vsock *vhost_vsock_get(u32 guest_cid) +{ + struct vhost_vsock *vsock; + + spin_lock_bh(&vhost_vsock_lock); + vsock = __vhost_vsock_get(guest_cid); + spin_unlock_bh(&vhost_vsock_lock); + + return vsock; +} + static void vhost_transport_do_send_pkt(struct vhost_vsock *vsock, struct vhost_virtqueue *vq) @@ -559,11 +567,12 @@ static int vhost_vsock_set_cid(struct vhost_vsock *vsock, u64 guest_cid) return -EINVAL; /* Refuse if CID is already in use */ - other = vhost_vsock_get(guest_cid); - if (other && other != vsock) - return -EADDRINUSE; - spin_lock_bh(&vhost_vsock_lock); + other = __vhost_vsock_get(guest_cid); + if (other && other != vsock) { + spin_unlock_bh(&vhost_vsock_lock); + return -EADDRINUSE; + } vsock->guest_cid = guest_cid; spin_unlock_bh(&vhost_vsock_lock); -- cgit v1.2.3 From 809ecb9bca6a9424ccd392d67e368160f8b76c92 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Mon, 12 Dec 2016 14:46:49 +0800 Subject: vhost: cache used event for better performance When event index was enabled, we need to fetch used event from userspace memory each time. This userspace fetch (with memory barrier) could be saved sometime when 1) caching used event and 2) if used event is ahead of new and old to new updating does not cross it, we're sure there's no need to notify guest. This will be useful for heavy tx load e.g guest pktgen test with Linux driver shows ~3.5% improvement. Signed-off-by: Jason Wang Signed-off-by: Michael S. Tsirkin --- drivers/vhost/vhost.c | 28 ++++++++++++++++++++++------ drivers/vhost/vhost.h | 3 +++ 2 files changed, 25 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c index 2f58181b918d..c0f81e8cb50c 100644 --- a/drivers/vhost/vhost.c +++ b/drivers/vhost/vhost.c @@ -290,6 +290,7 @@ static void vhost_vq_reset(struct vhost_dev *dev, vq->avail = NULL; vq->used = NULL; vq->last_avail_idx = 0; + vq->last_used_event = 0; vq->avail_idx = 0; vq->last_used_idx = 0; vq->signalled_used = 0; @@ -1324,7 +1325,7 @@ long vhost_vring_ioctl(struct vhost_dev *d, int ioctl, void __user *argp) r = -EINVAL; break; } - vq->last_avail_idx = s.num; + vq->last_avail_idx = vq->last_used_event = s.num; /* Forget the cached index value. */ vq->avail_idx = vq->last_avail_idx; break; @@ -2159,10 +2160,6 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) __u16 old, new; __virtio16 event; bool v; - /* Flush out used index updates. This is paired - * with the barrier that the Guest executes when enabling - * interrupts. */ - smp_mb(); if (vhost_has_feature(vq, VIRTIO_F_NOTIFY_ON_EMPTY) && unlikely(vq->avail_idx == vq->last_avail_idx)) @@ -2170,6 +2167,10 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) { __virtio16 flags; + /* Flush out used index updates. This is paired + * with the barrier that the Guest executes when enabling + * interrupts. */ + smp_mb(); if (vhost_get_user(vq, flags, &vq->avail->flags)) { vq_err(vq, "Failed to get flags"); return true; @@ -2184,11 +2185,26 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq) if (unlikely(!v)) return true; + /* We're sure if the following conditions are met, there's no + * need to notify guest: + * 1) cached used event is ahead of new + * 2) old to new updating does not cross cached used event. */ + if (vring_need_event(vq->last_used_event, new + vq->num, new) && + !vring_need_event(vq->last_used_event, new, old)) + return false; + + /* Flush out used index updates. This is paired + * with the barrier that the Guest executes when enabling + * interrupts. */ + smp_mb(); + if (vhost_get_user(vq, event, vhost_used_event(vq))) { vq_err(vq, "Failed to get used event idx"); return true; } - return vring_need_event(vhost16_to_cpu(vq, event), new, old); + vq->last_used_event = vhost16_to_cpu(vq, event); + + return vring_need_event(vq->last_used_event, new, old); } /* This actually signals the guest, using eventfd. */ diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h index 78f3c5fc02e4..a9cbbb148f46 100644 --- a/drivers/vhost/vhost.h +++ b/drivers/vhost/vhost.h @@ -107,6 +107,9 @@ struct vhost_virtqueue { /* Last index we used. */ u16 last_used_idx; + /* Last used evet we've seen */ + u16 last_used_event; + /* Used flags */ u16 used_flags; -- cgit v1.2.3 From dbaf0624ffa57ae6e7d87a823185ccd9a7852d3c Mon Sep 17 00:00:00 2001 From: Gonglei Date: Thu, 15 Dec 2016 10:03:16 +0800 Subject: crypto: add virtio-crypto driver This patch introduces virtio-crypto driver for Linux Kernel. The virtio crypto device is a virtual cryptography device as well as a kind of virtual hardware accelerator for virtual machines. The encryption anddecryption requests are placed in the data queue and are ultimately handled by thebackend crypto accelerators. The second queue is the control queue used to create or destroy sessions for symmetric algorithms and will control some advanced features in the future. The virtio crypto device provides the following cryptoservices: CIPHER, MAC, HASH, and AEAD. For more information about virtio-crypto device, please see: http://qemu-project.org/Features/VirtioCrypto CC: Michael S. Tsirkin CC: Cornelia Huck CC: Stefan Hajnoczi CC: Herbert Xu CC: Halil Pasic CC: David S. Miller CC: Zeng Xin Signed-off-by: Gonglei Signed-off-by: Michael S. Tsirkin --- MAINTAINERS | 9 + drivers/crypto/Kconfig | 2 + drivers/crypto/Makefile | 1 + drivers/crypto/virtio/Kconfig | 10 + drivers/crypto/virtio/Makefile | 5 + drivers/crypto/virtio/virtio_crypto_algs.c | 540 +++++++++++++++++++++++++++ drivers/crypto/virtio/virtio_crypto_common.h | 128 +++++++ drivers/crypto/virtio/virtio_crypto_core.c | 476 +++++++++++++++++++++++ drivers/crypto/virtio/virtio_crypto_mgr.c | 264 +++++++++++++ include/uapi/linux/Kbuild | 1 + include/uapi/linux/virtio_crypto.h | 450 ++++++++++++++++++++++ include/uapi/linux/virtio_ids.h | 1 + 12 files changed, 1887 insertions(+) create mode 100644 drivers/crypto/virtio/Kconfig create mode 100644 drivers/crypto/virtio/Makefile create mode 100644 drivers/crypto/virtio/virtio_crypto_algs.c create mode 100644 drivers/crypto/virtio/virtio_crypto_common.h create mode 100644 drivers/crypto/virtio/virtio_crypto_core.c create mode 100644 drivers/crypto/virtio/virtio_crypto_mgr.c create mode 100644 include/uapi/linux/virtio_crypto.h (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 59c9895d73d5..650ad4f6b608 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12988,6 +12988,7 @@ F: drivers/net/virtio_net.c F: drivers/block/virtio_blk.c F: include/linux/virtio_*.h F: include/uapi/linux/virtio_*.h +F: drivers/crypto/virtio/ VIRTIO DRIVERS FOR S390 M: Christian Borntraeger @@ -13024,6 +13025,14 @@ S: Maintained F: drivers/virtio/virtio_input.c F: include/uapi/linux/virtio_input.h +VIRTIO CRYPTO DRIVER +M: Gonglei +L: virtualization@lists.linux-foundation.org +L: linux-crypto@vger.kernel.org +S: Maintained +F: drivers/crypto/virtio/ +F: include/uapi/linux/virtio_crypto.h + VIA RHINE NETWORK DRIVER S: Orphan F: drivers/net/ethernet/via/via-rhine.c diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index 4d2b81f2b223..79564785ae30 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -555,4 +555,6 @@ config CRYPTO_DEV_ROCKCHIP source "drivers/crypto/chelsio/Kconfig" +source "drivers/crypto/virtio/Kconfig" + endif # CRYPTO_HW diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile index ad7250fa1348..bc53cb833a06 100644 --- a/drivers/crypto/Makefile +++ b/drivers/crypto/Makefile @@ -32,3 +32,4 @@ obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/ obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/ obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/ +obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio/ diff --git a/drivers/crypto/virtio/Kconfig b/drivers/crypto/virtio/Kconfig new file mode 100644 index 000000000000..d80f73366ae2 --- /dev/null +++ b/drivers/crypto/virtio/Kconfig @@ -0,0 +1,10 @@ +config CRYPTO_DEV_VIRTIO + tristate "VirtIO crypto driver" + depends on VIRTIO + select CRYPTO_AEAD + select CRYPTO_AUTHENC + select CRYPTO_BLKCIPHER + default m + help + This driver provides support for virtio crypto device. If you + choose 'M' here, this module will be called virtio_crypto. diff --git a/drivers/crypto/virtio/Makefile b/drivers/crypto/virtio/Makefile new file mode 100644 index 000000000000..dd342c947ff9 --- /dev/null +++ b/drivers/crypto/virtio/Makefile @@ -0,0 +1,5 @@ +obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio_crypto.o +virtio_crypto-objs := \ + virtio_crypto_algs.o \ + virtio_crypto_mgr.o \ + virtio_crypto_core.o diff --git a/drivers/crypto/virtio/virtio_crypto_algs.c b/drivers/crypto/virtio/virtio_crypto_algs.c new file mode 100644 index 000000000000..c2374df9abae --- /dev/null +++ b/drivers/crypto/virtio/virtio_crypto_algs.c @@ -0,0 +1,540 @@ + /* Algorithms supported by virtio crypto device + * + * Authors: Gonglei + * + * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 "virtio_crypto_common.h" + +/* + * The algs_lock protects the below global virtio_crypto_active_devs + * and crypto algorithms registion. + */ +static DEFINE_MUTEX(algs_lock); +static unsigned int virtio_crypto_active_devs; + +static u64 virtio_crypto_alg_sg_nents_length(struct scatterlist *sg) +{ + u64 total = 0; + + for (total = 0; sg; sg = sg_next(sg)) + total += sg->length; + + return total; +} + +static int +virtio_crypto_alg_validate_key(int key_len, uint32_t *alg) +{ + switch (key_len) { + case AES_KEYSIZE_128: + case AES_KEYSIZE_192: + case AES_KEYSIZE_256: + *alg = VIRTIO_CRYPTO_CIPHER_AES_CBC; + break; + default: + pr_err("virtio_crypto: Unsupported key length: %d\n", + key_len); + return -EINVAL; + } + return 0; +} + +static int virtio_crypto_alg_ablkcipher_init_session( + struct virtio_crypto_ablkcipher_ctx *ctx, + uint32_t alg, const uint8_t *key, + unsigned int keylen, + int encrypt) +{ + struct scatterlist outhdr, key_sg, inhdr, *sgs[3]; + unsigned int tmp; + struct virtio_crypto *vcrypto = ctx->vcrypto; + int op = encrypt ? VIRTIO_CRYPTO_OP_ENCRYPT : VIRTIO_CRYPTO_OP_DECRYPT; + int err; + unsigned int num_out = 0, num_in = 0; + + /* + * Avoid to do DMA from the stack, switch to using + * dynamically-allocated for the key + */ + uint8_t *cipher_key = kmalloc(keylen, GFP_ATOMIC); + + if (!cipher_key) + return -ENOMEM; + + memcpy(cipher_key, key, keylen); + + spin_lock(&vcrypto->ctrl_lock); + /* Pad ctrl header */ + vcrypto->ctrl.header.opcode = + cpu_to_le32(VIRTIO_CRYPTO_CIPHER_CREATE_SESSION); + vcrypto->ctrl.header.algo = cpu_to_le32(alg); + /* Set the default dataqueue id to 0 */ + vcrypto->ctrl.header.queue_id = 0; + + vcrypto->input.status = cpu_to_le32(VIRTIO_CRYPTO_ERR); + /* Pad cipher's parameters */ + vcrypto->ctrl.u.sym_create_session.op_type = + cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); + vcrypto->ctrl.u.sym_create_session.u.cipher.para.algo = + vcrypto->ctrl.header.algo; + vcrypto->ctrl.u.sym_create_session.u.cipher.para.keylen = + cpu_to_le32(keylen); + vcrypto->ctrl.u.sym_create_session.u.cipher.para.op = + cpu_to_le32(op); + + sg_init_one(&outhdr, &vcrypto->ctrl, sizeof(vcrypto->ctrl)); + sgs[num_out++] = &outhdr; + + /* Set key */ + sg_init_one(&key_sg, cipher_key, keylen); + sgs[num_out++] = &key_sg; + + /* Return status and session id back */ + sg_init_one(&inhdr, &vcrypto->input, sizeof(vcrypto->input)); + sgs[num_out + num_in++] = &inhdr; + + err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out, + num_in, vcrypto, GFP_ATOMIC); + if (err < 0) { + spin_unlock(&vcrypto->ctrl_lock); + kzfree(cipher_key); + return err; + } + virtqueue_kick(vcrypto->ctrl_vq); + + /* + * Trapping into the hypervisor, so the request should be + * handled immediately. + */ + while (!virtqueue_get_buf(vcrypto->ctrl_vq, &tmp) && + !virtqueue_is_broken(vcrypto->ctrl_vq)) + cpu_relax(); + + if (le32_to_cpu(vcrypto->input.status) != VIRTIO_CRYPTO_OK) { + spin_unlock(&vcrypto->ctrl_lock); + pr_err("virtio_crypto: Create session failed status: %u\n", + le32_to_cpu(vcrypto->input.status)); + kzfree(cipher_key); + return -EINVAL; + } + + if (encrypt) + ctx->enc_sess_info.session_id = + le64_to_cpu(vcrypto->input.session_id); + else + ctx->dec_sess_info.session_id = + le64_to_cpu(vcrypto->input.session_id); + + spin_unlock(&vcrypto->ctrl_lock); + + kzfree(cipher_key); + return 0; +} + +static int virtio_crypto_alg_ablkcipher_close_session( + struct virtio_crypto_ablkcipher_ctx *ctx, + int encrypt) +{ + struct scatterlist outhdr, status_sg, *sgs[2]; + unsigned int tmp; + struct virtio_crypto_destroy_session_req *destroy_session; + struct virtio_crypto *vcrypto = ctx->vcrypto; + int err; + unsigned int num_out = 0, num_in = 0; + + spin_lock(&vcrypto->ctrl_lock); + vcrypto->ctrl_status.status = VIRTIO_CRYPTO_ERR; + /* Pad ctrl header */ + vcrypto->ctrl.header.opcode = + cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION); + /* Set the default virtqueue id to 0 */ + vcrypto->ctrl.header.queue_id = 0; + + destroy_session = &vcrypto->ctrl.u.destroy_session; + + if (encrypt) + destroy_session->session_id = + cpu_to_le64(ctx->enc_sess_info.session_id); + else + destroy_session->session_id = + cpu_to_le64(ctx->dec_sess_info.session_id); + + sg_init_one(&outhdr, &vcrypto->ctrl, sizeof(vcrypto->ctrl)); + sgs[num_out++] = &outhdr; + + /* Return status and session id back */ + sg_init_one(&status_sg, &vcrypto->ctrl_status.status, + sizeof(vcrypto->ctrl_status.status)); + sgs[num_out + num_in++] = &status_sg; + + err = virtqueue_add_sgs(vcrypto->ctrl_vq, sgs, num_out, + num_in, vcrypto, GFP_ATOMIC); + if (err < 0) { + spin_unlock(&vcrypto->ctrl_lock); + return err; + } + virtqueue_kick(vcrypto->ctrl_vq); + + while (!virtqueue_get_buf(vcrypto->ctrl_vq, &tmp) && + !virtqueue_is_broken(vcrypto->ctrl_vq)) + cpu_relax(); + + if (vcrypto->ctrl_status.status != VIRTIO_CRYPTO_OK) { + spin_unlock(&vcrypto->ctrl_lock); + pr_err("virtio_crypto: Close session failed status: %u, session_id: 0x%llx\n", + vcrypto->ctrl_status.status, + destroy_session->session_id); + + return -EINVAL; + } + spin_unlock(&vcrypto->ctrl_lock); + + return 0; +} + +static int virtio_crypto_alg_ablkcipher_init_sessions( + struct virtio_crypto_ablkcipher_ctx *ctx, + const uint8_t *key, unsigned int keylen) +{ + uint32_t alg; + int ret; + struct virtio_crypto *vcrypto = ctx->vcrypto; + + if (keylen > vcrypto->max_cipher_key_len) { + pr_err("virtio_crypto: the key is too long\n"); + goto bad_key; + } + + if (virtio_crypto_alg_validate_key(keylen, &alg)) + goto bad_key; + + /* Create encryption session */ + ret = virtio_crypto_alg_ablkcipher_init_session(ctx, + alg, key, keylen, 1); + if (ret) + return ret; + /* Create decryption session */ + ret = virtio_crypto_alg_ablkcipher_init_session(ctx, + alg, key, keylen, 0); + if (ret) { + virtio_crypto_alg_ablkcipher_close_session(ctx, 1); + return ret; + } + return 0; + +bad_key: + crypto_tfm_set_flags(ctx->tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); + return -EINVAL; +} + +/* Note: kernel crypto API realization */ +static int virtio_crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm, + const uint8_t *key, + unsigned int keylen) +{ + struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm); + int ret; + + if (!ctx->vcrypto) { + /* New key */ + int node = virtio_crypto_get_current_node(); + struct virtio_crypto *vcrypto = + virtcrypto_get_dev_node(node); + if (!vcrypto) { + pr_err("virtio_crypto: Could not find a virtio device in the system"); + return -ENODEV; + } + + ctx->vcrypto = vcrypto; + } else { + /* Rekeying, we should close the created sessions previously */ + virtio_crypto_alg_ablkcipher_close_session(ctx, 1); + virtio_crypto_alg_ablkcipher_close_session(ctx, 0); + } + + ret = virtio_crypto_alg_ablkcipher_init_sessions(ctx, key, keylen); + if (ret) { + virtcrypto_dev_put(ctx->vcrypto); + ctx->vcrypto = NULL; + + return ret; + } + + return 0; +} + +static int +__virtio_crypto_ablkcipher_do_req(struct virtio_crypto_request *vc_req, + struct ablkcipher_request *req, + struct data_queue *data_vq, + __u8 op) +{ + struct crypto_ablkcipher *tfm = crypto_ablkcipher_reqtfm(req); + unsigned int ivsize = crypto_ablkcipher_ivsize(tfm); + struct virtio_crypto_ablkcipher_ctx *ctx = vc_req->ablkcipher_ctx; + struct virtio_crypto *vcrypto = ctx->vcrypto; + struct virtio_crypto_op_data_req *req_data; + int src_nents, dst_nents; + int err; + unsigned long flags; + struct scatterlist outhdr, iv_sg, status_sg, **sgs; + int i; + u64 dst_len; + unsigned int num_out = 0, num_in = 0; + int sg_total; + uint8_t *iv; + + src_nents = sg_nents_for_len(req->src, req->nbytes); + dst_nents = sg_nents(req->dst); + + pr_debug("virtio_crypto: Number of sgs (src_nents: %d, dst_nents: %d)\n", + src_nents, dst_nents); + + /* Why 3? outhdr + iv + inhdr */ + sg_total = src_nents + dst_nents + 3; + sgs = kzalloc_node(sg_total * sizeof(*sgs), GFP_ATOMIC, + dev_to_node(&vcrypto->vdev->dev)); + if (!sgs) + return -ENOMEM; + + req_data = kzalloc_node(sizeof(*req_data), GFP_ATOMIC, + dev_to_node(&vcrypto->vdev->dev)); + if (!req_data) { + kfree(sgs); + return -ENOMEM; + } + + vc_req->req_data = req_data; + vc_req->type = VIRTIO_CRYPTO_SYM_OP_CIPHER; + /* Head of operation */ + if (op) { + req_data->header.session_id = + cpu_to_le64(ctx->enc_sess_info.session_id); + req_data->header.opcode = + cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ENCRYPT); + } else { + req_data->header.session_id = + cpu_to_le64(ctx->dec_sess_info.session_id); + req_data->header.opcode = + cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DECRYPT); + } + req_data->u.sym_req.op_type = cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER); + req_data->u.sym_req.u.cipher.para.iv_len = cpu_to_le32(ivsize); + req_data->u.sym_req.u.cipher.para.src_data_len = + cpu_to_le32(req->nbytes); + + dst_len = virtio_crypto_alg_sg_nents_length(req->dst); + if (unlikely(dst_len > U32_MAX)) { + pr_err("virtio_crypto: The dst_len is beyond U32_MAX\n"); + err = -EINVAL; + goto free; + } + + pr_debug("virtio_crypto: src_len: %u, dst_len: %llu\n", + req->nbytes, dst_len); + + if (unlikely(req->nbytes + dst_len + ivsize + + sizeof(vc_req->status) > vcrypto->max_size)) { + pr_err("virtio_crypto: The length is too big\n"); + err = -EINVAL; + goto free; + } + + req_data->u.sym_req.u.cipher.para.dst_data_len = + cpu_to_le32((uint32_t)dst_len); + + /* Outhdr */ + sg_init_one(&outhdr, req_data, sizeof(*req_data)); + sgs[num_out++] = &outhdr; + + /* IV */ + + /* + * Avoid to do DMA from the stack, switch to using + * dynamically-allocated for the IV + */ + iv = kzalloc_node(ivsize, GFP_ATOMIC, + dev_to_node(&vcrypto->vdev->dev)); + if (!iv) { + err = -ENOMEM; + goto free; + } + memcpy(iv, req->info, ivsize); + sg_init_one(&iv_sg, iv, ivsize); + sgs[num_out++] = &iv_sg; + vc_req->iv = iv; + + /* Source data */ + for (i = 0; i < src_nents; i++) + sgs[num_out++] = &req->src[i]; + + /* Destination data */ + for (i = 0; i < dst_nents; i++) + sgs[num_out + num_in++] = &req->dst[i]; + + /* Status */ + sg_init_one(&status_sg, &vc_req->status, sizeof(vc_req->status)); + sgs[num_out + num_in++] = &status_sg; + + vc_req->sgs = sgs; + + spin_lock_irqsave(&data_vq->lock, flags); + err = virtqueue_add_sgs(data_vq->vq, sgs, num_out, + num_in, vc_req, GFP_ATOMIC); + virtqueue_kick(data_vq->vq); + spin_unlock_irqrestore(&data_vq->lock, flags); + if (unlikely(err < 0)) + goto free_iv; + + return 0; + +free_iv: + kzfree(iv); +free: + kzfree(req_data); + kfree(sgs); + return err; +} + +static int virtio_crypto_ablkcipher_encrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req); + struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(atfm); + struct virtio_crypto_request *vc_req = ablkcipher_request_ctx(req); + struct virtio_crypto *vcrypto = ctx->vcrypto; + int ret; + /* Use the first data virtqueue as default */ + struct data_queue *data_vq = &vcrypto->data_vq[0]; + + vc_req->ablkcipher_ctx = ctx; + vc_req->ablkcipher_req = req; + ret = __virtio_crypto_ablkcipher_do_req(vc_req, req, data_vq, 1); + if (ret < 0) { + pr_err("virtio_crypto: Encryption failed!\n"); + return ret; + } + + return -EINPROGRESS; +} + +static int virtio_crypto_ablkcipher_decrypt(struct ablkcipher_request *req) +{ + struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req); + struct virtio_crypto_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(atfm); + struct virtio_crypto_request *vc_req = ablkcipher_request_ctx(req); + struct virtio_crypto *vcrypto = ctx->vcrypto; + int ret; + /* Use the first data virtqueue as default */ + struct data_queue *data_vq = &vcrypto->data_vq[0]; + + vc_req->ablkcipher_ctx = ctx; + vc_req->ablkcipher_req = req; + + ret = __virtio_crypto_ablkcipher_do_req(vc_req, req, data_vq, 0); + if (ret < 0) { + pr_err("virtio_crypto: Decryption failed!\n"); + return ret; + } + + return -EINPROGRESS; +} + +static int virtio_crypto_ablkcipher_init(struct crypto_tfm *tfm) +{ + struct virtio_crypto_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm); + + tfm->crt_ablkcipher.reqsize = sizeof(struct virtio_crypto_request); + ctx->tfm = tfm; + + return 0; +} + +static void virtio_crypto_ablkcipher_exit(struct crypto_tfm *tfm) +{ + struct virtio_crypto_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm); + + if (!ctx->vcrypto) + return; + + virtio_crypto_alg_ablkcipher_close_session(ctx, 1); + virtio_crypto_alg_ablkcipher_close_session(ctx, 0); + virtcrypto_dev_put(ctx->vcrypto); + ctx->vcrypto = NULL; +} + +static struct crypto_alg virtio_crypto_algs[] = { { + .cra_name = "cbc(aes)", + .cra_driver_name = "virtio_crypto_aes_cbc", + .cra_priority = 501, + .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC, + .cra_blocksize = AES_BLOCK_SIZE, + .cra_ctxsize = sizeof(struct virtio_crypto_ablkcipher_ctx), + .cra_alignmask = 0, + .cra_module = THIS_MODULE, + .cra_type = &crypto_ablkcipher_type, + .cra_init = virtio_crypto_ablkcipher_init, + .cra_exit = virtio_crypto_ablkcipher_exit, + .cra_u = { + .ablkcipher = { + .setkey = virtio_crypto_ablkcipher_setkey, + .decrypt = virtio_crypto_ablkcipher_decrypt, + .encrypt = virtio_crypto_ablkcipher_encrypt, + .min_keysize = AES_MIN_KEY_SIZE, + .max_keysize = AES_MAX_KEY_SIZE, + .ivsize = AES_BLOCK_SIZE, + }, + }, +} }; + +int virtio_crypto_algs_register(void) +{ + int ret = 0; + + mutex_lock(&algs_lock); + if (++virtio_crypto_active_devs != 1) + goto unlock; + + ret = crypto_register_algs(virtio_crypto_algs, + ARRAY_SIZE(virtio_crypto_algs)); + if (ret) + virtio_crypto_active_devs--; + +unlock: + mutex_unlock(&algs_lock); + return ret; +} + +void virtio_crypto_algs_unregister(void) +{ + mutex_lock(&algs_lock); + if (--virtio_crypto_active_devs != 0) + goto unlock; + + crypto_unregister_algs(virtio_crypto_algs, + ARRAY_SIZE(virtio_crypto_algs)); + +unlock: + mutex_unlock(&algs_lock); +} diff --git a/drivers/crypto/virtio/virtio_crypto_common.h b/drivers/crypto/virtio/virtio_crypto_common.h new file mode 100644 index 000000000000..3d6566b02876 --- /dev/null +++ b/drivers/crypto/virtio/virtio_crypto_common.h @@ -0,0 +1,128 @@ +/* Common header for Virtio crypto device. + * + * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef _VIRTIO_CRYPTO_COMMON_H +#define _VIRTIO_CRYPTO_COMMON_H + +#include +#include +#include +#include +#include +#include + + +/* Internal representation of a data virtqueue */ +struct data_queue { + /* Virtqueue associated with this send _queue */ + struct virtqueue *vq; + + /* To protect the vq operations for the dataq */ + spinlock_t lock; + + /* Name of the tx queue: dataq.$index */ + char name[32]; +}; + +struct virtio_crypto { + struct virtio_device *vdev; + struct virtqueue *ctrl_vq; + struct data_queue *data_vq; + + /* To protect the vq operations for the controlq */ + spinlock_t ctrl_lock; + + /* Maximum of data queues supported by the device */ + u32 max_data_queues; + + /* Number of queue currently used by the driver */ + u32 curr_queue; + + /* Maximum length of cipher key */ + u32 max_cipher_key_len; + /* Maximum length of authenticated key */ + u32 max_auth_key_len; + /* Maximum size of per request */ + u64 max_size; + + /* Control VQ buffers: protected by the ctrl_lock */ + struct virtio_crypto_op_ctrl_req ctrl; + struct virtio_crypto_session_input input; + struct virtio_crypto_inhdr ctrl_status; + + unsigned long status; + atomic_t ref_count; + struct list_head list; + struct module *owner; + uint8_t dev_id; + + /* Does the affinity hint is set for virtqueues? */ + bool affinity_hint_set; +}; + +struct virtio_crypto_sym_session_info { + /* Backend session id, which come from the host side */ + __u64 session_id; +}; + +struct virtio_crypto_ablkcipher_ctx { + struct virtio_crypto *vcrypto; + struct crypto_tfm *tfm; + + struct virtio_crypto_sym_session_info enc_sess_info; + struct virtio_crypto_sym_session_info dec_sess_info; +}; + +struct virtio_crypto_request { + /* Cipher or aead */ + uint32_t type; + uint8_t status; + struct virtio_crypto_ablkcipher_ctx *ablkcipher_ctx; + struct ablkcipher_request *ablkcipher_req; + struct virtio_crypto_op_data_req *req_data; + struct scatterlist **sgs; + uint8_t *iv; +}; + +int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev); +struct list_head *virtcrypto_devmgr_get_head(void); +void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev); +struct virtio_crypto *virtcrypto_devmgr_get_first(void); +int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev); +int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev); +void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev); +int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev); +struct virtio_crypto *virtcrypto_get_dev_node(int node); +int virtcrypto_dev_start(struct virtio_crypto *vcrypto); +void virtcrypto_dev_stop(struct virtio_crypto *vcrypto); + +static inline int virtio_crypto_get_current_node(void) +{ + int cpu, node; + + cpu = get_cpu(); + node = topology_physical_package_id(cpu); + put_cpu(); + + return node; +} + +int virtio_crypto_algs_register(void); +void virtio_crypto_algs_unregister(void); + +#endif /* _VIRTIO_CRYPTO_COMMON_H */ diff --git a/drivers/crypto/virtio/virtio_crypto_core.c b/drivers/crypto/virtio/virtio_crypto_core.c new file mode 100644 index 000000000000..fe70ec823b27 --- /dev/null +++ b/drivers/crypto/virtio/virtio_crypto_core.c @@ -0,0 +1,476 @@ + /* Driver for Virtio crypto device. + * + * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 "virtio_crypto_common.h" + + +static void +virtcrypto_clear_request(struct virtio_crypto_request *vc_req) +{ + if (vc_req) { + kzfree(vc_req->iv); + kzfree(vc_req->req_data); + kfree(vc_req->sgs); + } +} + +static void virtcrypto_dataq_callback(struct virtqueue *vq) +{ + struct virtio_crypto *vcrypto = vq->vdev->priv; + struct virtio_crypto_request *vc_req; + unsigned long flags; + unsigned int len; + struct ablkcipher_request *ablk_req; + int error; + unsigned int qid = vq->index; + + spin_lock_irqsave(&vcrypto->data_vq[qid].lock, flags); + do { + virtqueue_disable_cb(vq); + while ((vc_req = virtqueue_get_buf(vq, &len)) != NULL) { + if (vc_req->type == VIRTIO_CRYPTO_SYM_OP_CIPHER) { + switch (vc_req->status) { + case VIRTIO_CRYPTO_OK: + error = 0; + break; + case VIRTIO_CRYPTO_INVSESS: + case VIRTIO_CRYPTO_ERR: + error = -EINVAL; + break; + case VIRTIO_CRYPTO_BADMSG: + error = -EBADMSG; + break; + default: + error = -EIO; + break; + } + ablk_req = vc_req->ablkcipher_req; + virtcrypto_clear_request(vc_req); + + spin_unlock_irqrestore( + &vcrypto->data_vq[qid].lock, flags); + /* Finish the encrypt or decrypt process */ + ablk_req->base.complete(&ablk_req->base, error); + spin_lock_irqsave( + &vcrypto->data_vq[qid].lock, flags); + } + } + } while (!virtqueue_enable_cb(vq)); + spin_unlock_irqrestore(&vcrypto->data_vq[qid].lock, flags); +} + +static int virtcrypto_find_vqs(struct virtio_crypto *vi) +{ + vq_callback_t **callbacks; + struct virtqueue **vqs; + int ret = -ENOMEM; + int i, total_vqs; + const char **names; + + /* + * We expect 1 data virtqueue, followed by + * possible N-1 data queues used in multiqueue mode, + * followed by control vq. + */ + total_vqs = vi->max_data_queues + 1; + + /* Allocate space for find_vqs parameters */ + vqs = kcalloc(total_vqs, sizeof(*vqs), GFP_KERNEL); + if (!vqs) + goto err_vq; + callbacks = kcalloc(total_vqs, sizeof(*callbacks), GFP_KERNEL); + if (!callbacks) + goto err_callback; + names = kcalloc(total_vqs, sizeof(*names), GFP_KERNEL); + if (!names) + goto err_names; + + /* Parameters for control virtqueue */ + callbacks[total_vqs - 1] = NULL; + names[total_vqs - 1] = "controlq"; + + /* Allocate/initialize parameters for data virtqueues */ + for (i = 0; i < vi->max_data_queues; i++) { + callbacks[i] = virtcrypto_dataq_callback; + snprintf(vi->data_vq[i].name, sizeof(vi->data_vq[i].name), + "dataq.%d", i); + names[i] = vi->data_vq[i].name; + } + + ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks, + names); + if (ret) + goto err_find; + + vi->ctrl_vq = vqs[total_vqs - 1]; + + for (i = 0; i < vi->max_data_queues; i++) { + spin_lock_init(&vi->data_vq[i].lock); + vi->data_vq[i].vq = vqs[i]; + } + + kfree(names); + kfree(callbacks); + kfree(vqs); + + return 0; + +err_find: + kfree(names); +err_names: + kfree(callbacks); +err_callback: + kfree(vqs); +err_vq: + return ret; +} + +static int virtcrypto_alloc_queues(struct virtio_crypto *vi) +{ + vi->data_vq = kcalloc(vi->max_data_queues, sizeof(*vi->data_vq), + GFP_KERNEL); + if (!vi->data_vq) + return -ENOMEM; + + return 0; +} + +static void virtcrypto_clean_affinity(struct virtio_crypto *vi, long hcpu) +{ + int i; + + if (vi->affinity_hint_set) { + for (i = 0; i < vi->max_data_queues; i++) + virtqueue_set_affinity(vi->data_vq[i].vq, -1); + + vi->affinity_hint_set = false; + } +} + +static void virtcrypto_set_affinity(struct virtio_crypto *vcrypto) +{ + int i = 0; + int cpu; + + /* + * In single queue mode, we don't set the cpu affinity. + */ + if (vcrypto->curr_queue == 1 || vcrypto->max_data_queues == 1) { + virtcrypto_clean_affinity(vcrypto, -1); + return; + } + + /* + * In multiqueue mode, we let the queue to be private to one cpu + * by setting the affinity hint to eliminate the contention. + * + * TODO: adds cpu hotplug support by register cpu notifier. + * + */ + for_each_online_cpu(cpu) { + virtqueue_set_affinity(vcrypto->data_vq[i].vq, cpu); + if (++i >= vcrypto->max_data_queues) + break; + } + + vcrypto->affinity_hint_set = true; +} + +static void virtcrypto_free_queues(struct virtio_crypto *vi) +{ + kfree(vi->data_vq); +} + +static int virtcrypto_init_vqs(struct virtio_crypto *vi) +{ + int ret; + + /* Allocate send & receive queues */ + ret = virtcrypto_alloc_queues(vi); + if (ret) + goto err; + + ret = virtcrypto_find_vqs(vi); + if (ret) + goto err_free; + + get_online_cpus(); + virtcrypto_set_affinity(vi); + put_online_cpus(); + + return 0; + +err_free: + virtcrypto_free_queues(vi); +err: + return ret; +} + +static int virtcrypto_update_status(struct virtio_crypto *vcrypto) +{ + u32 status; + int err; + + virtio_cread(vcrypto->vdev, + struct virtio_crypto_config, status, &status); + + /* + * Unknown status bits would be a host error and the driver + * should consider the device to be broken. + */ + if (status & (~VIRTIO_CRYPTO_S_HW_READY)) { + dev_warn(&vcrypto->vdev->dev, + "Unknown status bits: 0x%x\n", status); + + virtio_break_device(vcrypto->vdev); + return -EPERM; + } + + if (vcrypto->status == status) + return 0; + + vcrypto->status = status; + + if (vcrypto->status & VIRTIO_CRYPTO_S_HW_READY) { + err = virtcrypto_dev_start(vcrypto); + if (err) { + dev_err(&vcrypto->vdev->dev, + "Failed to start virtio crypto device.\n"); + + return -EPERM; + } + dev_info(&vcrypto->vdev->dev, "Accelerator is ready\n"); + } else { + virtcrypto_dev_stop(vcrypto); + dev_info(&vcrypto->vdev->dev, "Accelerator is not ready\n"); + } + + return 0; +} + +static void virtcrypto_del_vqs(struct virtio_crypto *vcrypto) +{ + struct virtio_device *vdev = vcrypto->vdev; + + virtcrypto_clean_affinity(vcrypto, -1); + + vdev->config->del_vqs(vdev); + + virtcrypto_free_queues(vcrypto); +} + +static int virtcrypto_probe(struct virtio_device *vdev) +{ + int err = -EFAULT; + struct virtio_crypto *vcrypto; + u32 max_data_queues = 0, max_cipher_key_len = 0; + u32 max_auth_key_len = 0; + u64 max_size = 0; + + if (!virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) + return -ENODEV; + + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config access disabled\n", + __func__); + return -EINVAL; + } + + if (num_possible_nodes() > 1 && dev_to_node(&vdev->dev) < 0) { + /* + * If the accelerator is connected to a node with no memory + * there is no point in using the accelerator since the remote + * memory transaction will be very slow. + */ + dev_err(&vdev->dev, "Invalid NUMA configuration.\n"); + return -EINVAL; + } + + vcrypto = kzalloc_node(sizeof(*vcrypto), GFP_KERNEL, + dev_to_node(&vdev->dev)); + if (!vcrypto) + return -ENOMEM; + + virtio_cread(vdev, struct virtio_crypto_config, + max_dataqueues, &max_data_queues); + if (max_data_queues < 1) + max_data_queues = 1; + + virtio_cread(vdev, struct virtio_crypto_config, + max_cipher_key_len, &max_cipher_key_len); + virtio_cread(vdev, struct virtio_crypto_config, + max_auth_key_len, &max_auth_key_len); + virtio_cread(vdev, struct virtio_crypto_config, + max_size, &max_size); + + /* Add virtio crypto device to global table */ + err = virtcrypto_devmgr_add_dev(vcrypto); + if (err) { + dev_err(&vdev->dev, "Failed to add new virtio crypto device.\n"); + goto free; + } + vcrypto->owner = THIS_MODULE; + vcrypto = vdev->priv = vcrypto; + vcrypto->vdev = vdev; + + spin_lock_init(&vcrypto->ctrl_lock); + + /* Use single data queue as default */ + vcrypto->curr_queue = 1; + vcrypto->max_data_queues = max_data_queues; + vcrypto->max_cipher_key_len = max_cipher_key_len; + vcrypto->max_auth_key_len = max_auth_key_len; + vcrypto->max_size = max_size; + + dev_info(&vdev->dev, + "max_queues: %u, max_cipher_key_len: %u, max_auth_key_len: %u, max_size 0x%llx\n", + vcrypto->max_data_queues, + vcrypto->max_cipher_key_len, + vcrypto->max_auth_key_len, + vcrypto->max_size); + + err = virtcrypto_init_vqs(vcrypto); + if (err) { + dev_err(&vdev->dev, "Failed to initialize vqs.\n"); + goto free_dev; + } + virtio_device_ready(vdev); + + err = virtcrypto_update_status(vcrypto); + if (err) + goto free_vqs; + + return 0; + +free_vqs: + vcrypto->vdev->config->reset(vdev); + virtcrypto_del_vqs(vcrypto); +free_dev: + virtcrypto_devmgr_rm_dev(vcrypto); +free: + kfree(vcrypto); + return err; +} + +static void virtcrypto_free_unused_reqs(struct virtio_crypto *vcrypto) +{ + struct virtio_crypto_request *vc_req; + int i; + struct virtqueue *vq; + + for (i = 0; i < vcrypto->max_data_queues; i++) { + vq = vcrypto->data_vq[i].vq; + while ((vc_req = virtqueue_detach_unused_buf(vq)) != NULL) { + kfree(vc_req->req_data); + kfree(vc_req->sgs); + } + } +} + +static void virtcrypto_remove(struct virtio_device *vdev) +{ + struct virtio_crypto *vcrypto = vdev->priv; + + dev_info(&vdev->dev, "Start virtcrypto_remove.\n"); + + if (virtcrypto_dev_started(vcrypto)) + virtcrypto_dev_stop(vcrypto); + vdev->config->reset(vdev); + virtcrypto_free_unused_reqs(vcrypto); + virtcrypto_del_vqs(vcrypto); + virtcrypto_devmgr_rm_dev(vcrypto); + kfree(vcrypto); +} + +static void virtcrypto_config_changed(struct virtio_device *vdev) +{ + struct virtio_crypto *vcrypto = vdev->priv; + + virtcrypto_update_status(vcrypto); +} + +#ifdef CONFIG_PM_SLEEP +static int virtcrypto_freeze(struct virtio_device *vdev) +{ + struct virtio_crypto *vcrypto = vdev->priv; + + vdev->config->reset(vdev); + virtcrypto_free_unused_reqs(vcrypto); + if (virtcrypto_dev_started(vcrypto)) + virtcrypto_dev_stop(vcrypto); + + virtcrypto_del_vqs(vcrypto); + return 0; +} + +static int virtcrypto_restore(struct virtio_device *vdev) +{ + struct virtio_crypto *vcrypto = vdev->priv; + int err; + + err = virtcrypto_init_vqs(vcrypto); + if (err) + return err; + + virtio_device_ready(vdev); + err = virtcrypto_dev_start(vcrypto); + if (err) { + dev_err(&vdev->dev, "Failed to start virtio crypto device.\n"); + return -EFAULT; + } + + return 0; +} +#endif + +static unsigned int features[] = { + /* none */ +}; + +static struct virtio_device_id id_table[] = { + { VIRTIO_ID_CRYPTO, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + +static struct virtio_driver virtio_crypto_driver = { + .driver.name = KBUILD_MODNAME, + .driver.owner = THIS_MODULE, + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .id_table = id_table, + .probe = virtcrypto_probe, + .remove = virtcrypto_remove, + .config_changed = virtcrypto_config_changed, +#ifdef CONFIG_PM_SLEEP + .freeze = virtcrypto_freeze, + .restore = virtcrypto_restore, +#endif +}; + +module_virtio_driver(virtio_crypto_driver); + +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("virtio crypto device driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Gonglei "); diff --git a/drivers/crypto/virtio/virtio_crypto_mgr.c b/drivers/crypto/virtio/virtio_crypto_mgr.c new file mode 100644 index 000000000000..a69ff71de2c4 --- /dev/null +++ b/drivers/crypto/virtio/virtio_crypto_mgr.c @@ -0,0 +1,264 @@ + /* Management for virtio crypto devices (refer to adf_dev_mgr.c) + * + * Copyright 2016 HUAWEI TECHNOLOGIES CO., LTD. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 "virtio_crypto_common.h" + +static LIST_HEAD(virtio_crypto_table); +static uint32_t num_devices; + +/* The table_lock protects the above global list and num_devices */ +static DEFINE_MUTEX(table_lock); + +#define VIRTIO_CRYPTO_MAX_DEVICES 32 + + +/* + * virtcrypto_devmgr_add_dev() - Add vcrypto_dev to the acceleration + * framework. + * @vcrypto_dev: Pointer to virtio crypto device. + * + * Function adds virtio crypto device to the global list. + * To be used by virtio crypto device specific drivers. + * + * Return: 0 on success, error code othewise. + */ +int virtcrypto_devmgr_add_dev(struct virtio_crypto *vcrypto_dev) +{ + struct list_head *itr; + + mutex_lock(&table_lock); + if (num_devices == VIRTIO_CRYPTO_MAX_DEVICES) { + pr_info("virtio_crypto: only support up to %d devices\n", + VIRTIO_CRYPTO_MAX_DEVICES); + mutex_unlock(&table_lock); + return -EFAULT; + } + + list_for_each(itr, &virtio_crypto_table) { + struct virtio_crypto *ptr = + list_entry(itr, struct virtio_crypto, list); + + if (ptr == vcrypto_dev) { + mutex_unlock(&table_lock); + return -EEXIST; + } + } + atomic_set(&vcrypto_dev->ref_count, 0); + list_add_tail(&vcrypto_dev->list, &virtio_crypto_table); + vcrypto_dev->dev_id = num_devices++; + mutex_unlock(&table_lock); + return 0; +} + +struct list_head *virtcrypto_devmgr_get_head(void) +{ + return &virtio_crypto_table; +} + +/* + * virtcrypto_devmgr_rm_dev() - Remove vcrypto_dev from the acceleration + * framework. + * @vcrypto_dev: Pointer to virtio crypto device. + * + * Function removes virtio crypto device from the acceleration framework. + * To be used by virtio crypto device specific drivers. + * + * Return: void + */ +void virtcrypto_devmgr_rm_dev(struct virtio_crypto *vcrypto_dev) +{ + mutex_lock(&table_lock); + list_del(&vcrypto_dev->list); + num_devices--; + mutex_unlock(&table_lock); +} + +/* + * virtcrypto_devmgr_get_first() + * + * Function returns the first virtio crypto device from the acceleration + * framework. + * + * To be used by virtio crypto device specific drivers. + * + * Return: pointer to vcrypto_dev or NULL if not found. + */ +struct virtio_crypto *virtcrypto_devmgr_get_first(void) +{ + struct virtio_crypto *dev = NULL; + + mutex_lock(&table_lock); + if (!list_empty(&virtio_crypto_table)) + dev = list_first_entry(&virtio_crypto_table, + struct virtio_crypto, + list); + mutex_unlock(&table_lock); + return dev; +} + +/* + * virtcrypto_dev_in_use() - Check whether vcrypto_dev is currently in use + * @vcrypto_dev: Pointer to virtio crypto device. + * + * To be used by virtio crypto device specific drivers. + * + * Return: 1 when device is in use, 0 otherwise. + */ +int virtcrypto_dev_in_use(struct virtio_crypto *vcrypto_dev) +{ + return atomic_read(&vcrypto_dev->ref_count) != 0; +} + +/* + * virtcrypto_dev_get() - Increment vcrypto_dev reference count + * @vcrypto_dev: Pointer to virtio crypto device. + * + * Increment the vcrypto_dev refcount and if this is the first time + * incrementing it during this period the vcrypto_dev is in use, + * increment the module refcount too. + * To be used by virtio crypto device specific drivers. + * + * Return: 0 when successful, EFAULT when fail to bump module refcount + */ +int virtcrypto_dev_get(struct virtio_crypto *vcrypto_dev) +{ + if (atomic_add_return(1, &vcrypto_dev->ref_count) == 1) + if (!try_module_get(vcrypto_dev->owner)) + return -EFAULT; + return 0; +} + +/* + * virtcrypto_dev_put() - Decrement vcrypto_dev reference count + * @vcrypto_dev: Pointer to virtio crypto device. + * + * Decrement the vcrypto_dev refcount and if this is the last time + * decrementing it during this period the vcrypto_dev is in use, + * decrement the module refcount too. + * To be used by virtio crypto device specific drivers. + * + * Return: void + */ +void virtcrypto_dev_put(struct virtio_crypto *vcrypto_dev) +{ + if (atomic_sub_return(1, &vcrypto_dev->ref_count) == 0) + module_put(vcrypto_dev->owner); +} + +/* + * virtcrypto_dev_started() - Check whether device has started + * @vcrypto_dev: Pointer to virtio crypto device. + * + * To be used by virtio crypto device specific drivers. + * + * Return: 1 when the device has started, 0 otherwise + */ +int virtcrypto_dev_started(struct virtio_crypto *vcrypto_dev) +{ + return (vcrypto_dev->status & VIRTIO_CRYPTO_S_HW_READY); +} + +/* + * virtcrypto_get_dev_node() - Get vcrypto_dev on the node. + * @node: Node id the driver works. + * + * Function returns the virtio crypto device used fewest on the node. + * + * To be used by virtio crypto device specific drivers. + * + * Return: pointer to vcrypto_dev or NULL if not found. + */ +struct virtio_crypto *virtcrypto_get_dev_node(int node) +{ + struct virtio_crypto *vcrypto_dev = NULL, *tmp_dev; + unsigned long best = ~0; + unsigned long ctr; + + mutex_lock(&table_lock); + list_for_each_entry(tmp_dev, virtcrypto_devmgr_get_head(), list) { + + if ((node == dev_to_node(&tmp_dev->vdev->dev) || + dev_to_node(&tmp_dev->vdev->dev) < 0) && + virtcrypto_dev_started(tmp_dev)) { + ctr = atomic_read(&tmp_dev->ref_count); + if (best > ctr) { + vcrypto_dev = tmp_dev; + best = ctr; + } + } + } + + if (!vcrypto_dev) { + pr_info("virtio_crypto: Could not find a device on node %d\n", + node); + /* Get any started device */ + list_for_each_entry(tmp_dev, + virtcrypto_devmgr_get_head(), list) { + if (virtcrypto_dev_started(tmp_dev)) { + vcrypto_dev = tmp_dev; + break; + } + } + } + mutex_unlock(&table_lock); + if (!vcrypto_dev) + return NULL; + + virtcrypto_dev_get(vcrypto_dev); + return vcrypto_dev; +} + +/* + * virtcrypto_dev_start() - Start virtio crypto device + * @vcrypto: Pointer to virtio crypto device. + * + * Function notifies all the registered services that the virtio crypto device + * is ready to be used. + * To be used by virtio crypto device specific drivers. + * + * Return: 0 on success, EFAULT when fail to register algorithms + */ +int virtcrypto_dev_start(struct virtio_crypto *vcrypto) +{ + if (virtio_crypto_algs_register()) { + pr_err("virtio_crypto: Failed to register crypto algs\n"); + return -EFAULT; + } + + return 0; +} + +/* + * virtcrypto_dev_stop() - Stop virtio crypto device + * @vcrypto: Pointer to virtio crypto device. + * + * Function notifies all the registered services that the virtio crypto device + * is ready to be used. + * To be used by virtio crypto device specific drivers. + * + * Return: void + */ +void virtcrypto_dev_stop(struct virtio_crypto *vcrypto) +{ + virtio_crypto_algs_unregister(); +} diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild index bc2ef9fef7c8..a26c5c76ab62 100644 --- a/include/uapi/linux/Kbuild +++ b/include/uapi/linux/Kbuild @@ -462,6 +462,7 @@ header-y += virtio_rng.h header-y += virtio_scsi.h header-y += virtio_types.h header-y += virtio_vsock.h +header-y += virtio_crypto.h header-y += vm_sockets.h header-y += vt.h header-y += vtpm_proxy.h diff --git a/include/uapi/linux/virtio_crypto.h b/include/uapi/linux/virtio_crypto.h new file mode 100644 index 000000000000..50cdc8aebfcf --- /dev/null +++ b/include/uapi/linux/virtio_crypto.h @@ -0,0 +1,450 @@ +#ifndef _VIRTIO_CRYPTO_H +#define _VIRTIO_CRYPTO_H +/* This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include +#include +#include +#include + + +#define VIRTIO_CRYPTO_SERVICE_CIPHER 0 +#define VIRTIO_CRYPTO_SERVICE_HASH 1 +#define VIRTIO_CRYPTO_SERVICE_MAC 2 +#define VIRTIO_CRYPTO_SERVICE_AEAD 3 + +#define VIRTIO_CRYPTO_OPCODE(service, op) (((service) << 8) | (op)) + +struct virtio_crypto_ctrl_header { +#define VIRTIO_CRYPTO_CIPHER_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x02) +#define VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x03) +#define VIRTIO_CRYPTO_HASH_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x02) +#define VIRTIO_CRYPTO_HASH_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x03) +#define VIRTIO_CRYPTO_MAC_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x02) +#define VIRTIO_CRYPTO_MAC_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x03) +#define VIRTIO_CRYPTO_AEAD_CREATE_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x02) +#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x03) + __le32 opcode; + __le32 algo; + __le32 flag; + /* data virtqueue id */ + __le32 queue_id; +}; + +struct virtio_crypto_cipher_session_para { +#define VIRTIO_CRYPTO_NO_CIPHER 0 +#define VIRTIO_CRYPTO_CIPHER_ARC4 1 +#define VIRTIO_CRYPTO_CIPHER_AES_ECB 2 +#define VIRTIO_CRYPTO_CIPHER_AES_CBC 3 +#define VIRTIO_CRYPTO_CIPHER_AES_CTR 4 +#define VIRTIO_CRYPTO_CIPHER_DES_ECB 5 +#define VIRTIO_CRYPTO_CIPHER_DES_CBC 6 +#define VIRTIO_CRYPTO_CIPHER_3DES_ECB 7 +#define VIRTIO_CRYPTO_CIPHER_3DES_CBC 8 +#define VIRTIO_CRYPTO_CIPHER_3DES_CTR 9 +#define VIRTIO_CRYPTO_CIPHER_KASUMI_F8 10 +#define VIRTIO_CRYPTO_CIPHER_SNOW3G_UEA2 11 +#define VIRTIO_CRYPTO_CIPHER_AES_F8 12 +#define VIRTIO_CRYPTO_CIPHER_AES_XTS 13 +#define VIRTIO_CRYPTO_CIPHER_ZUC_EEA3 14 + __le32 algo; + /* length of key */ + __le32 keylen; + +#define VIRTIO_CRYPTO_OP_ENCRYPT 1 +#define VIRTIO_CRYPTO_OP_DECRYPT 2 + /* encrypt or decrypt */ + __le32 op; + __le32 padding; +}; + +struct virtio_crypto_session_input { + /* Device-writable part */ + __le64 session_id; + __le32 status; + __le32 padding; +}; + +struct virtio_crypto_cipher_session_req { + struct virtio_crypto_cipher_session_para para; + __u8 padding[32]; +}; + +struct virtio_crypto_hash_session_para { +#define VIRTIO_CRYPTO_NO_HASH 0 +#define VIRTIO_CRYPTO_HASH_MD5 1 +#define VIRTIO_CRYPTO_HASH_SHA1 2 +#define VIRTIO_CRYPTO_HASH_SHA_224 3 +#define VIRTIO_CRYPTO_HASH_SHA_256 4 +#define VIRTIO_CRYPTO_HASH_SHA_384 5 +#define VIRTIO_CRYPTO_HASH_SHA_512 6 +#define VIRTIO_CRYPTO_HASH_SHA3_224 7 +#define VIRTIO_CRYPTO_HASH_SHA3_256 8 +#define VIRTIO_CRYPTO_HASH_SHA3_384 9 +#define VIRTIO_CRYPTO_HASH_SHA3_512 10 +#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE128 11 +#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE256 12 + __le32 algo; + /* hash result length */ + __le32 hash_result_len; + __u8 padding[8]; +}; + +struct virtio_crypto_hash_create_session_req { + struct virtio_crypto_hash_session_para para; + __u8 padding[40]; +}; + +struct virtio_crypto_mac_session_para { +#define VIRTIO_CRYPTO_NO_MAC 0 +#define VIRTIO_CRYPTO_MAC_HMAC_MD5 1 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA1 2 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_224 3 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_256 4 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_384 5 +#define VIRTIO_CRYPTO_MAC_HMAC_SHA_512 6 +#define VIRTIO_CRYPTO_MAC_CMAC_3DES 25 +#define VIRTIO_CRYPTO_MAC_CMAC_AES 26 +#define VIRTIO_CRYPTO_MAC_KASUMI_F9 27 +#define VIRTIO_CRYPTO_MAC_SNOW3G_UIA2 28 +#define VIRTIO_CRYPTO_MAC_GMAC_AES 41 +#define VIRTIO_CRYPTO_MAC_GMAC_TWOFISH 42 +#define VIRTIO_CRYPTO_MAC_CBCMAC_AES 49 +#define VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9 50 +#define VIRTIO_CRYPTO_MAC_XCBC_AES 53 + __le32 algo; + /* hash result length */ + __le32 hash_result_len; + /* length of authenticated key */ + __le32 auth_key_len; + __le32 padding; +}; + +struct virtio_crypto_mac_create_session_req { + struct virtio_crypto_mac_session_para para; + __u8 padding[40]; +}; + +struct virtio_crypto_aead_session_para { +#define VIRTIO_CRYPTO_NO_AEAD 0 +#define VIRTIO_CRYPTO_AEAD_GCM 1 +#define VIRTIO_CRYPTO_AEAD_CCM 2 +#define VIRTIO_CRYPTO_AEAD_CHACHA20_POLY1305 3 + __le32 algo; + /* length of key */ + __le32 key_len; + /* hash result length */ + __le32 hash_result_len; + /* length of the additional authenticated data (AAD) in bytes */ + __le32 aad_len; + /* encrypt or decrypt, See above VIRTIO_CRYPTO_OP_* */ + __le32 op; + __le32 padding; +}; + +struct virtio_crypto_aead_create_session_req { + struct virtio_crypto_aead_session_para para; + __u8 padding[32]; +}; + +struct virtio_crypto_alg_chain_session_para { +#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1 +#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2 + __le32 alg_chain_order; +/* Plain hash */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN 1 +/* Authenticated hash (mac) */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH 2 +/* Nested hash */ +#define VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED 3 + __le32 hash_mode; + struct virtio_crypto_cipher_session_para cipher_param; + union { + struct virtio_crypto_hash_session_para hash_param; + struct virtio_crypto_mac_session_para mac_param; + __u8 padding[16]; + } u; + /* length of the additional authenticated data (AAD) in bytes */ + __le32 aad_len; + __le32 padding; +}; + +struct virtio_crypto_alg_chain_session_req { + struct virtio_crypto_alg_chain_session_para para; +}; + +struct virtio_crypto_sym_create_session_req { + union { + struct virtio_crypto_cipher_session_req cipher; + struct virtio_crypto_alg_chain_session_req chain; + __u8 padding[48]; + } u; + + /* Device-readable part */ + +/* No operation */ +#define VIRTIO_CRYPTO_SYM_OP_NONE 0 +/* Cipher only operation on the data */ +#define VIRTIO_CRYPTO_SYM_OP_CIPHER 1 +/* + * Chain any cipher with any hash or mac operation. The order + * depends on the value of alg_chain_order param + */ +#define VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING 2 + __le32 op_type; + __le32 padding; +}; + +struct virtio_crypto_destroy_session_req { + /* Device-readable part */ + __le64 session_id; + __u8 padding[48]; +}; + +/* The request of the control virtqueue's packet */ +struct virtio_crypto_op_ctrl_req { + struct virtio_crypto_ctrl_header header; + + union { + struct virtio_crypto_sym_create_session_req + sym_create_session; + struct virtio_crypto_hash_create_session_req + hash_create_session; + struct virtio_crypto_mac_create_session_req + mac_create_session; + struct virtio_crypto_aead_create_session_req + aead_create_session; + struct virtio_crypto_destroy_session_req + destroy_session; + __u8 padding[56]; + } u; +}; + +struct virtio_crypto_op_header { +#define VIRTIO_CRYPTO_CIPHER_ENCRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x00) +#define VIRTIO_CRYPTO_CIPHER_DECRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_CIPHER, 0x01) +#define VIRTIO_CRYPTO_HASH \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_HASH, 0x00) +#define VIRTIO_CRYPTO_MAC \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_MAC, 0x00) +#define VIRTIO_CRYPTO_AEAD_ENCRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x00) +#define VIRTIO_CRYPTO_AEAD_DECRYPT \ + VIRTIO_CRYPTO_OPCODE(VIRTIO_CRYPTO_SERVICE_AEAD, 0x01) + __le32 opcode; + /* algo should be service-specific algorithms */ + __le32 algo; + /* session_id should be service-specific algorithms */ + __le64 session_id; + /* control flag to control the request */ + __le32 flag; + __le32 padding; +}; + +struct virtio_crypto_cipher_para { + /* + * Byte Length of valid IV/Counter + * + * For block ciphers in CBC or F8 mode, or for Kasumi in F8 mode, or for + * SNOW3G in UEA2 mode, this is the length of the IV (which + * must be the same as the block length of the cipher). + * For block ciphers in CTR mode, this is the length of the counter + * (which must be the same as the block length of the cipher). + * For AES-XTS, this is the 128bit tweak, i, from IEEE Std 1619-2007. + * + * The IV/Counter will be updated after every partial cryptographic + * operation. + */ + __le32 iv_len; + /* length of source data */ + __le32 src_data_len; + /* length of dst data */ + __le32 dst_data_len; + __le32 padding; +}; + +struct virtio_crypto_hash_para { + /* length of source data */ + __le32 src_data_len; + /* hash result length */ + __le32 hash_result_len; +}; + +struct virtio_crypto_mac_para { + struct virtio_crypto_hash_para hash; +}; + +struct virtio_crypto_aead_para { + /* + * Byte Length of valid IV data pointed to by the below iv_addr + * parameter. + * + * For GCM mode, this is either 12 (for 96-bit IVs) or 16, in which + * case iv_addr points to J0. + * For CCM mode, this is the length of the nonce, which can be in the + * range 7 to 13 inclusive. + */ + __le32 iv_len; + /* length of additional auth data */ + __le32 aad_len; + /* length of source data */ + __le32 src_data_len; + /* length of dst data */ + __le32 dst_data_len; +}; + +struct virtio_crypto_cipher_data_req { + /* Device-readable part */ + struct virtio_crypto_cipher_para para; + __u8 padding[24]; +}; + +struct virtio_crypto_hash_data_req { + /* Device-readable part */ + struct virtio_crypto_hash_para para; + __u8 padding[40]; +}; + +struct virtio_crypto_mac_data_req { + /* Device-readable part */ + struct virtio_crypto_mac_para para; + __u8 padding[40]; +}; + +struct virtio_crypto_alg_chain_data_para { + __le32 iv_len; + /* Length of source data */ + __le32 src_data_len; + /* Length of destination data */ + __le32 dst_data_len; + /* Starting point for cipher processing in source data */ + __le32 cipher_start_src_offset; + /* Length of the source data that the cipher will be computed on */ + __le32 len_to_cipher; + /* Starting point for hash processing in source data */ + __le32 hash_start_src_offset; + /* Length of the source data that the hash will be computed on */ + __le32 len_to_hash; + /* Length of the additional auth data */ + __le32 aad_len; + /* Length of the hash result */ + __le32 hash_result_len; + __le32 reserved; +}; + +struct virtio_crypto_alg_chain_data_req { + /* Device-readable part */ + struct virtio_crypto_alg_chain_data_para para; +}; + +struct virtio_crypto_sym_data_req { + union { + struct virtio_crypto_cipher_data_req cipher; + struct virtio_crypto_alg_chain_data_req chain; + __u8 padding[40]; + } u; + + /* See above VIRTIO_CRYPTO_SYM_OP_* */ + __le32 op_type; + __le32 padding; +}; + +struct virtio_crypto_aead_data_req { + /* Device-readable part */ + struct virtio_crypto_aead_para para; + __u8 padding[32]; +}; + +/* The request of the data virtqueue's packet */ +struct virtio_crypto_op_data_req { + struct virtio_crypto_op_header header; + + union { + struct virtio_crypto_sym_data_req sym_req; + struct virtio_crypto_hash_data_req hash_req; + struct virtio_crypto_mac_data_req mac_req; + struct virtio_crypto_aead_data_req aead_req; + __u8 padding[48]; + } u; +}; + +#define VIRTIO_CRYPTO_OK 0 +#define VIRTIO_CRYPTO_ERR 1 +#define VIRTIO_CRYPTO_BADMSG 2 +#define VIRTIO_CRYPTO_NOTSUPP 3 +#define VIRTIO_CRYPTO_INVSESS 4 /* Invalid session id */ + +/* The accelerator hardware is ready */ +#define VIRTIO_CRYPTO_S_HW_READY (1 << 0) + +struct virtio_crypto_config { + /* See VIRTIO_CRYPTO_OP_* above */ + __u32 status; + + /* + * Maximum number of data queue + */ + __u32 max_dataqueues; + + /* + * Specifies the services mask which the device support, + * see VIRTIO_CRYPTO_SERVICE_* above + */ + __u32 crypto_services; + + /* Detailed algorithms mask */ + __u32 cipher_algo_l; + __u32 cipher_algo_h; + __u32 hash_algo; + __u32 mac_algo_l; + __u32 mac_algo_h; + __u32 aead_algo; + /* Maximum length of cipher key */ + __u32 max_cipher_key_len; + /* Maximum length of authenticated key */ + __u32 max_auth_key_len; + __u32 reserve; + /* Maximum size of each crypto request's content */ + __u64 max_size; +}; + +struct virtio_crypto_inhdr { + /* See VIRTIO_CRYPTO_* above */ + __u8 status; +}; +#endif diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_ids.h index 3228d582234a..6d5c3b2d4f4d 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -42,5 +42,6 @@ #define VIRTIO_ID_GPU 16 /* virtio GPU */ #define VIRTIO_ID_INPUT 18 /* virtio input */ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ +#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ #endif /* _LINUX_VIRTIO_IDS_H */ -- cgit v1.2.3 From 9d1b972f8a25bba01ecfc1d90d7a2fbf1923d052 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Thu, 24 Nov 2016 10:25:13 +0000 Subject: vringh: kill off ACCESS_ONCE() Despite living under drivers/ vringh.c is also used as part of the userspace virtio tools. Before we can kill off the ACCESS_ONCE()definition in the tools, we must convert vringh.c to use {READ,WRITE}_ONCE(). This patch does so, along with the required include of for the relevant definitions. The userspace tools provide their own definitions in their own . Signed-off-by: Mark Rutland Cc: Jason Wang Cc: Michael S. Tsirkin Cc: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Cc: netdev@vger.kernel.org Cc: virtualization@lists.linux-foundation.org Signed-off-by: Michael S. Tsirkin Reviewed-by: Christian Borntraeger Reviewed-by: Cornelia Huck Reviewed-by: Jason Wang --- drivers/vhost/vringh.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/vringh.c b/drivers/vhost/vringh.c index 3bb02c60a2f5..bb8971f2a634 100644 --- a/drivers/vhost/vringh.c +++ b/drivers/vhost/vringh.c @@ -3,6 +3,7 @@ * * Since these may be in userspace, we use (inline) accessors. */ +#include #include #include #include @@ -820,13 +821,13 @@ EXPORT_SYMBOL(vringh_need_notify_user); static inline int getu16_kern(const struct vringh *vrh, u16 *val, const __virtio16 *p) { - *val = vringh16_to_cpu(vrh, ACCESS_ONCE(*p)); + *val = vringh16_to_cpu(vrh, READ_ONCE(*p)); return 0; } static inline int putu16_kern(const struct vringh *vrh, __virtio16 *p, u16 val) { - ACCESS_ONCE(*p) = cpu_to_vringh16(vrh, val); + WRITE_ONCE(*p, cpu_to_vringh16(vrh, val)); return 0; } -- cgit v1.2.3 From b9fd06d0dae38a88efa4b770dfa9db7dcbe3cda9 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Fri, 11 Nov 2016 14:27:10 +0100 Subject: vhost/scsi: Remove unused but set variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove the unused but set variable se_tpg in vhost_scsi_nexus_cb() to fix the following GCC warning when building with 'W=1': drivers/vhost/scsi.c:1752:26: warning: variable ‘se_tpg’ set but not used Signed-off-by: Tobias Klauser Signed-off-by: Michael S. Tsirkin --- drivers/vhost/scsi.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index 6e29d053843d..e2be447752c2 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c @@ -1749,7 +1749,6 @@ out: static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, const char *name) { - struct se_portal_group *se_tpg; struct vhost_scsi_nexus *tv_nexus; mutex_lock(&tpg->tv_tpg_mutex); @@ -1758,7 +1757,6 @@ static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg, pr_debug("tpg->tpg_nexus already exists\n"); return -EEXIST; } - se_tpg = &tpg->se_tpg; tv_nexus = kzalloc(sizeof(struct vhost_scsi_nexus), GFP_KERNEL); if (!tv_nexus) { -- cgit v1.2.3 From 0c7eaf5930e145b9f1a0121bd5813a05b0fc77f2 Mon Sep 17 00:00:00 2001 From: Felipe Franciosi Date: Mon, 14 Nov 2016 06:16:15 -0800 Subject: virtio_ring: fix description of virtqueue_get_buf The device (not the driver) populates the used ring and includes the len of how much data was written. Signed-off-by: Felipe Franciosi Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_ring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c index d2863c321e93..409aeaa49246 100644 --- a/drivers/virtio/virtio_ring.c +++ b/drivers/virtio/virtio_ring.c @@ -649,7 +649,7 @@ static inline bool more_used(const struct vring_virtqueue *vq) * @vq: the struct virtqueue we're talking about. * @len: the length written into the buffer * - * If the driver wrote data into the buffer, @len will be set to the + * If the device wrote data into the buffer, @len will be set to the * amount written. This means you don't need to clear the buffer * beforehand to ensure there's no data leakage in the case of short * writes. -- cgit v1.2.3 From cecdbdc3771e5b8583a9b43b03335b4223a9a6c9 Mon Sep 17 00:00:00 2001 From: Yuan Liu Date: Wed, 23 Nov 2016 16:31:00 -0800 Subject: virtio_mmio: Set dev.release() to avoid warning Fix a warning thrown from virtio_mmio_remove(): Device 'virtio0' does not have a release() function The fix is according to virtio_pci_probe() of drivers/virtio/virtio_pci_common.c Signed-off-by: Yuan Liu Signed-off-by: Michael S. Tsirkin --- drivers/virtio/virtio_mmio.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c index 48bfea91dbca..d47a2fcef818 100644 --- a/drivers/virtio/virtio_mmio.c +++ b/drivers/virtio/virtio_mmio.c @@ -489,6 +489,7 @@ static const struct virtio_config_ops virtio_mmio_config_ops = { }; +static void virtio_mmio_release_dev_empty(struct device *_d) {} /* Platform device */ @@ -511,6 +512,7 @@ static int virtio_mmio_probe(struct platform_device *pdev) return -ENOMEM; vm_dev->vdev.dev.parent = &pdev->dev; + vm_dev->vdev.dev.release = virtio_mmio_release_dev_empty; vm_dev->vdev.config = &virtio_mmio_config_ops; vm_dev->pdev = pdev; INIT_LIST_HEAD(&vm_dev->virtqueues); -- cgit v1.2.3 From 9efeccacd3a486128d3add611dd4cefb5b60a58c Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Sun, 11 Dec 2016 06:34:53 +0200 Subject: linux: drop __bitwise__ everywhere __bitwise__ used to mean "yes, please enable sparse checks unconditionally", but now that we dropped __CHECK_ENDIAN__ __bitwise is exactly the same. There aren't many users, replace it by __bitwise everywhere. Signed-off-by: Michael S. Tsirkin Acked-by: Greg Kroah-Hartman Acked-by: Stefan Schmidt Acked-by: Krzysztof Kozlowski Akced-by: Lee Duncan --- arch/arm/plat-samsung/include/plat/gpio-cfg.h | 2 +- drivers/md/dm-cache-block-types.h | 6 +++--- drivers/net/ethernet/sun/sunhme.h | 2 +- drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h | 4 ++-- include/linux/mmzone.h | 2 +- include/linux/serial_core.h | 4 ++-- include/linux/types.h | 4 ++-- include/scsi/iscsi_proto.h | 2 +- include/target/target_core_base.h | 2 +- include/uapi/linux/virtio_types.h | 6 +++--- net/ieee802154/6lowpan/6lowpan_i.h | 2 +- net/mac80211/ieee80211_i.h | 4 ++-- 12 files changed, 20 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/arch/arm/plat-samsung/include/plat/gpio-cfg.h b/arch/arm/plat-samsung/include/plat/gpio-cfg.h index 21391faab068..e55d1f597db8 100644 --- a/arch/arm/plat-samsung/include/plat/gpio-cfg.h +++ b/arch/arm/plat-samsung/include/plat/gpio-cfg.h @@ -26,7 +26,7 @@ #include -typedef unsigned int __bitwise__ samsung_gpio_pull_t; +typedef unsigned int __bitwise samsung_gpio_pull_t; /* forward declaration if gpio-core.h hasn't been included */ struct samsung_gpio_chip; diff --git a/drivers/md/dm-cache-block-types.h b/drivers/md/dm-cache-block-types.h index bed4ad4e1b7c..389c9e8ac785 100644 --- a/drivers/md/dm-cache-block-types.h +++ b/drivers/md/dm-cache-block-types.h @@ -17,9 +17,9 @@ * discard bitset. */ -typedef dm_block_t __bitwise__ dm_oblock_t; -typedef uint32_t __bitwise__ dm_cblock_t; -typedef dm_block_t __bitwise__ dm_dblock_t; +typedef dm_block_t __bitwise dm_oblock_t; +typedef uint32_t __bitwise dm_cblock_t; +typedef dm_block_t __bitwise dm_dblock_t; static inline dm_oblock_t to_oblock(dm_block_t b) { diff --git a/drivers/net/ethernet/sun/sunhme.h b/drivers/net/ethernet/sun/sunhme.h index f4307654e4ae..4a8d5b18dfd5 100644 --- a/drivers/net/ethernet/sun/sunhme.h +++ b/drivers/net/ethernet/sun/sunhme.h @@ -302,7 +302,7 @@ * Always write the address first before setting the ownership * bits to avoid races with the hardware scanning the ring. */ -typedef u32 __bitwise__ hme32; +typedef u32 __bitwise hme32; struct happy_meal_rxd { hme32 rx_flags; diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h index 1ad0ec180d5d..84813b550ef1 100644 --- a/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h +++ b/drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h @@ -228,7 +228,7 @@ enum iwl_ucode_tlv_flag { IWL_UCODE_TLV_FLAGS_BCAST_FILTERING = BIT(29), }; -typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t; +typedef unsigned int __bitwise iwl_ucode_tlv_api_t; /** * enum iwl_ucode_tlv_api - ucode api @@ -258,7 +258,7 @@ enum iwl_ucode_tlv_api { #endif }; -typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t; +typedef unsigned int __bitwise iwl_ucode_tlv_capa_t; /** * enum iwl_ucode_tlv_capa - ucode capabilities diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h index 0f088f3a2fed..36d9896fbc1e 100644 --- a/include/linux/mmzone.h +++ b/include/linux/mmzone.h @@ -246,7 +246,7 @@ struct lruvec { #define ISOLATE_UNEVICTABLE ((__force isolate_mode_t)0x8) /* LRU Isolation modes. */ -typedef unsigned __bitwise__ isolate_mode_t; +typedef unsigned __bitwise isolate_mode_t; enum zone_watermarks { WMARK_MIN, diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 5d494888a612..5def8e830fb0 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -111,8 +111,8 @@ struct uart_icount { __u32 buf_overrun; }; -typedef unsigned int __bitwise__ upf_t; -typedef unsigned int __bitwise__ upstat_t; +typedef unsigned int __bitwise upf_t; +typedef unsigned int __bitwise upstat_t; struct uart_port { spinlock_t lock; /* port lock */ diff --git a/include/linux/types.h b/include/linux/types.h index baf718324f4a..d501ad3ba247 100644 --- a/include/linux/types.h +++ b/include/linux/types.h @@ -154,8 +154,8 @@ typedef u64 dma_addr_t; typedef u32 dma_addr_t; #endif -typedef unsigned __bitwise__ gfp_t; -typedef unsigned __bitwise__ fmode_t; +typedef unsigned __bitwise gfp_t; +typedef unsigned __bitwise fmode_t; #ifdef CONFIG_PHYS_ADDR_T_64BIT typedef u64 phys_addr_t; diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index c1260d80ef30..df156f1d50b2 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h @@ -74,7 +74,7 @@ static inline int iscsi_sna_gte(u32 n1, u32 n2) #define zero_data(p) {p[0]=0;p[1]=0;p[2]=0;} /* initiator tags; opaque for target */ -typedef uint32_t __bitwise__ itt_t; +typedef uint32_t __bitwise itt_t; /* below makes sense only for initiator that created this tag */ #define build_itt(itt, age) ((__force itt_t)\ ((itt) | ((age) << ISCSI_AGE_SHIFT))) diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index c2119008990a..00558287936d 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -149,7 +149,7 @@ enum se_cmd_flags_table { * Used by transport_send_check_condition_and_sense() * to signal which ASC/ASCQ sense payload should be built. */ -typedef unsigned __bitwise__ sense_reason_t; +typedef unsigned __bitwise sense_reason_t; enum tcm_sense_reason_table { #define R(x) (__force sense_reason_t )(x) diff --git a/include/uapi/linux/virtio_types.h b/include/uapi/linux/virtio_types.h index e845e8c4cbee..55c3b738722c 100644 --- a/include/uapi/linux/virtio_types.h +++ b/include/uapi/linux/virtio_types.h @@ -39,8 +39,8 @@ * - __le{16,32,64} for standard-compliant virtio devices */ -typedef __u16 __bitwise__ __virtio16; -typedef __u32 __bitwise__ __virtio32; -typedef __u64 __bitwise__ __virtio64; +typedef __u16 __bitwise __virtio16; +typedef __u32 __bitwise __virtio32; +typedef __u64 __bitwise __virtio64; #endif /* _UAPI_LINUX_VIRTIO_TYPES_H */ diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h index 5ac778962e4e..ac7c96b73ad5 100644 --- a/net/ieee802154/6lowpan/6lowpan_i.h +++ b/net/ieee802154/6lowpan/6lowpan_i.h @@ -7,7 +7,7 @@ #include #include -typedef unsigned __bitwise__ lowpan_rx_result; +typedef unsigned __bitwise lowpan_rx_result; #define RX_CONTINUE ((__force lowpan_rx_result) 0u) #define RX_DROP_UNUSABLE ((__force lowpan_rx_result) 1u) #define RX_DROP ((__force lowpan_rx_result) 2u) diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index d37a577f63a1..b2069fbd60f9 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -159,7 +159,7 @@ enum ieee80211_bss_valid_data_flags { IEEE80211_BSS_VALID_ERP = BIT(3) }; -typedef unsigned __bitwise__ ieee80211_tx_result; +typedef unsigned __bitwise ieee80211_tx_result; #define TX_CONTINUE ((__force ieee80211_tx_result) 0u) #define TX_DROP ((__force ieee80211_tx_result) 1u) #define TX_QUEUED ((__force ieee80211_tx_result) 2u) @@ -180,7 +180,7 @@ struct ieee80211_tx_data { }; -typedef unsigned __bitwise__ ieee80211_rx_result; +typedef unsigned __bitwise ieee80211_rx_result; #define RX_CONTINUE ((__force ieee80211_rx_result) 0u) #define RX_DROP_UNUSABLE ((__force ieee80211_rx_result) 1u) #define RX_DROP_MONITOR ((__force ieee80211_rx_result) 2u) -- cgit v1.2.3 From 6bdf1e0efb04a1716373646cb6f35b73addca492 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Thu, 15 Dec 2016 04:07:46 +0200 Subject: Makefile: drop -D__CHECK_ENDIAN__ from cflags That's the default now, no need for makefiles to set it. Signed-off-by: Michael S. Tsirkin Acked-by: Kalle Valo Acked-by: Marcel Holtmann Acked-by: Marc Kleine-Budde Acked-by: Greg Kroah-Hartman Acked-by: Arend van Spriel --- drivers/bluetooth/Makefile | 2 -- drivers/net/can/Makefile | 1 - drivers/net/ethernet/altera/Makefile | 1 - drivers/net/ethernet/atheros/alx/Makefile | 1 - drivers/net/ethernet/freescale/Makefile | 2 -- drivers/net/wireless/ath/Makefile | 2 -- drivers/net/wireless/ath/wil6210/Makefile | 2 -- drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile | 2 -- drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile | 1 - drivers/net/wireless/intel/iwlegacy/Makefile | 2 -- drivers/net/wireless/intel/iwlwifi/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/dvm/Makefile | 2 +- drivers/net/wireless/intel/iwlwifi/mvm/Makefile | 2 +- drivers/net/wireless/intersil/orinoco/Makefile | 3 --- drivers/net/wireless/mediatek/mt7601u/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/btcoexist/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8192c/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8192ce/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8192cu/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8192de/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8192ee/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8192se/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8723ae/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8723be/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8723com/Makefile | 2 -- drivers/net/wireless/realtek/rtlwifi/rtl8821ae/Makefile | 2 -- drivers/net/wireless/ti/wl1251/Makefile | 2 -- drivers/net/wireless/ti/wlcore/Makefile | 2 -- drivers/staging/rtl8188eu/Makefile | 2 +- drivers/staging/rtl8192e/Makefile | 2 -- drivers/staging/rtl8192e/rtl8192e/Makefile | 2 -- net/bluetooth/Makefile | 2 -- net/ieee802154/Makefile | 2 -- net/mac80211/Makefile | 2 +- net/mac802154/Makefile | 2 -- net/wireless/Makefile | 2 -- 38 files changed, 5 insertions(+), 68 deletions(-) (limited to 'drivers') diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index b1fc29a697b7..80627187c8b6 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -40,5 +40,3 @@ hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o hci_uart-$(CONFIG_BT_HCIUART_AG6XX) += hci_ag6xx.o hci_uart-$(CONFIG_BT_HCIUART_MRVL) += hci_mrvl.o hci_uart-objs := $(hci_uart-y) - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/can/Makefile b/drivers/net/can/Makefile index 26ba4b794a0b..7a85495dbb0c 100644 --- a/drivers/net/can/Makefile +++ b/drivers/net/can/Makefile @@ -31,5 +31,4 @@ obj-$(CONFIG_CAN_TI_HECC) += ti_hecc.o obj-$(CONFIG_CAN_XILINXCAN) += xilinx_can.o obj-$(CONFIG_PCH_CAN) += pch_can.o -subdir-ccflags-y += -D__CHECK_ENDIAN__ subdir-ccflags-$(CONFIG_CAN_DEBUG_DEVICES) += -DDEBUG diff --git a/drivers/net/ethernet/altera/Makefile b/drivers/net/ethernet/altera/Makefile index 3eff2fd3997e..d4a187e45369 100644 --- a/drivers/net/ethernet/altera/Makefile +++ b/drivers/net/ethernet/altera/Makefile @@ -5,4 +5,3 @@ obj-$(CONFIG_ALTERA_TSE) += altera_tse.o altera_tse-objs := altera_tse_main.o altera_tse_ethtool.o \ altera_msgdma.o altera_sgdma.o altera_utils.o -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/ethernet/atheros/alx/Makefile b/drivers/net/ethernet/atheros/alx/Makefile index 5901fa407d52..ed4a605874a3 100644 --- a/drivers/net/ethernet/atheros/alx/Makefile +++ b/drivers/net/ethernet/atheros/alx/Makefile @@ -1,3 +1,2 @@ obj-$(CONFIG_ALX) += alx.o alx-objs := main.o ethtool.o hw.o -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/ethernet/freescale/Makefile b/drivers/net/ethernet/freescale/Makefile index 4a13115155c9..c46df5c82af5 100644 --- a/drivers/net/ethernet/freescale/Makefile +++ b/drivers/net/ethernet/freescale/Makefile @@ -4,8 +4,6 @@ obj-$(CONFIG_FEC) += fec.o fec-objs :=fec_main.o fec_ptp.o -CFLAGS_fec_main.o := -D__CHECK_ENDIAN__ -CFLAGS_fec_ptp.o := -D__CHECK_ENDIAN__ obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile index 89f8d5979402..4cdebc7659dd 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile @@ -19,6 +19,4 @@ ath-objs := main.o \ ath-$(CONFIG_ATH_DEBUG) += debug.o ath-$(CONFIG_ATH_TRACEPOINTS) += trace.o -ccflags-y += -D__CHECK_ENDIAN__ - CFLAGS_trace.o := -I$(src) diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile index 11b544b26c74..89bf2f9eca1d 100644 --- a/drivers/net/wireless/ath/wil6210/Makefile +++ b/drivers/net/wireless/ath/wil6210/Makefile @@ -22,5 +22,3 @@ wil6210-y += p2p.o # for tracing framework to find trace.h CFLAGS_trace.o := -I$(src) - -subdir-ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile index d1568bed1ad1..0383ba559edc 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/Makefile @@ -19,8 +19,6 @@ ccflags-y += \ -Idrivers/net/wireless/broadcom/brcm80211/brcmfmac \ -Idrivers/net/wireless/broadcom/brcm80211/include -ccflags-y += -D__CHECK_ENDIAN__ - obj-$(CONFIG_BRCMFMAC) += brcmfmac.o brcmfmac-objs += \ cfg80211.o \ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile index 960e6b86bbcb..ed83f33aceb7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile @@ -16,7 +16,6 @@ # CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ccflags-y := \ - -D__CHECK_ENDIAN__ \ -Idrivers/net/wireless/broadcom/brcm80211/brcmsmac \ -Idrivers/net/wireless/broadcom/brcm80211/brcmsmac/phy \ -Idrivers/net/wireless/broadcom/brcm80211/include diff --git a/drivers/net/wireless/intel/iwlegacy/Makefile b/drivers/net/wireless/intel/iwlegacy/Makefile index c985a01a0731..c826a6b985bb 100644 --- a/drivers/net/wireless/intel/iwlegacy/Makefile +++ b/drivers/net/wireless/intel/iwlegacy/Makefile @@ -13,5 +13,3 @@ iwl4965-$(CONFIG_IWLEGACY_DEBUGFS) += 4965-debug.o obj-$(CONFIG_IWL3945) += iwl3945.o iwl3945-objs := 3945-mac.o 3945.o 3945-rs.o iwl3945-$(CONFIG_IWLEGACY_DEBUGFS) += 3945-debug.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile index 6e7ed908de0c..92e611841200 100644 --- a/drivers/net/wireless/intel/iwlwifi/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/Makefile @@ -15,7 +15,7 @@ iwlwifi-objs += $(iwlwifi-m) iwlwifi-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o -ccflags-y += -D__CHECK_ENDIAN__ -I$(src) +ccflags-y += -I$(src) obj-$(CONFIG_IWLDVM) += dvm/ obj-$(CONFIG_IWLMVM) += mvm/ diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/Makefile b/drivers/net/wireless/intel/iwlwifi/dvm/Makefile index 4d19685f31c3..b256a354953a 100644 --- a/drivers/net/wireless/intel/iwlwifi/dvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/dvm/Makefile @@ -10,4 +10,4 @@ iwldvm-objs += rxon.o devices.o iwldvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwldvm-$(CONFIG_IWLWIFI_DEBUGFS) += debugfs.o -ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ +ccflags-y += -I$(src)/../ diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile index 2e06dfc1c477..83ac807e547d 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/Makefile +++ b/drivers/net/wireless/intel/iwlwifi/mvm/Makefile @@ -9,4 +9,4 @@ iwlmvm-$(CONFIG_IWLWIFI_LEDS) += led.o iwlmvm-y += tof.o fw-dbg.o iwlmvm-$(CONFIG_PM) += d3.o -ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/../ +ccflags-y += -I$(src)/../ diff --git a/drivers/net/wireless/intersil/orinoco/Makefile b/drivers/net/wireless/intersil/orinoco/Makefile index bfdefb85abcd..b7ecef820f76 100644 --- a/drivers/net/wireless/intersil/orinoco/Makefile +++ b/drivers/net/wireless/intersil/orinoco/Makefile @@ -12,6 +12,3 @@ obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o obj-$(CONFIG_ORINOCO_USB) += orinoco_usb.o - -# Orinoco should be endian clean. -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/mediatek/mt7601u/Makefile b/drivers/net/wireless/mediatek/mt7601u/Makefile index ea9ed8a5db4d..08fc802ead4b 100644 --- a/drivers/net/wireless/mediatek/mt7601u/Makefile +++ b/drivers/net/wireless/mediatek/mt7601u/Makefile @@ -1,5 +1,3 @@ -ccflags-y += -D__CHECK_ENDIAN__ - obj-$(CONFIG_MT7601U) += mt7601u.o mt7601u-objs = \ diff --git a/drivers/net/wireless/realtek/rtlwifi/Makefile b/drivers/net/wireless/realtek/rtlwifi/Makefile index ad6d3c52ec57..84c2e826fa1d 100644 --- a/drivers/net/wireless/realtek/rtlwifi/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/Makefile @@ -30,5 +30,3 @@ obj-$(CONFIG_RTLBTCOEXIST) += btcoexist/ obj-$(CONFIG_RTL8723_COMMON) += rtl8723com/ obj-$(CONFIG_RTL8821AE) += rtl8821ae/ obj-$(CONFIG_RTL8192EE) += rtl8192ee/ - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/btcoexist/Makefile b/drivers/net/wireless/realtek/rtlwifi/btcoexist/Makefile index 47ceecfcb7dc..d1454d4f08a5 100644 --- a/drivers/net/wireless/realtek/rtlwifi/btcoexist/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/btcoexist/Makefile @@ -3,5 +3,3 @@ btcoexist-objs := halbtc8723b2ant.o \ rtl_btc.o obj-$(CONFIG_RTLBTCOEXIST) += btcoexist.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile index 676e7de27f27..dae4f0f19cd3 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8188ee/Makefile @@ -11,5 +11,3 @@ rtl8188ee-objs := \ trx.o obj-$(CONFIG_RTL8188EE) += rtl8188ee.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/Makefile index aee42d7ae8a2..0546b7556259 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192c/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192c/Makefile @@ -5,5 +5,3 @@ rtl8192c-common-objs := \ phy_common.o obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c-common.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/Makefile index c0cb0cfe7d37..577c7adbc322 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ce/Makefile @@ -9,5 +9,3 @@ rtl8192ce-objs := \ trx.o obj-$(CONFIG_RTL8192CE) += rtl8192ce.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/Makefile index ad2de6b839ef..97437dadc287 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192cu/Makefile @@ -10,5 +10,3 @@ rtl8192cu-objs := \ trx.o obj-$(CONFIG_RTL8192CU) += rtl8192cu.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/Makefile index e3213c8264b6..d0703f20d30c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192de/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192de/Makefile @@ -10,5 +10,3 @@ rtl8192de-objs := \ trx.o obj-$(CONFIG_RTL8192DE) += rtl8192de.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/Makefile index 0315eeda9b60..f254b9f64326 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192ee/Makefile @@ -12,5 +12,3 @@ rtl8192ee-objs := \ obj-$(CONFIG_RTL8192EE) += rtl8192ee.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/Makefile index b7eb13819cbc..dfa9dbbe2cdf 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8192se/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8192se/Makefile @@ -11,5 +11,3 @@ rtl8192se-objs := \ obj-$(CONFIG_RTL8192SE) += rtl8192se.o -ccflags-y += -D__CHECK_ENDIAN__ - diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/Makefile index 6220672a96f4..e7607d2cb2ef 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723ae/Makefile @@ -14,5 +14,3 @@ rtl8723ae-objs := \ obj-$(CONFIG_RTL8723AE) += rtl8723ae.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/Makefile index a77c34102792..a841cbd55d8e 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723be/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723be/Makefile @@ -12,5 +12,3 @@ rtl8723be-objs := \ obj-$(CONFIG_RTL8723BE) += rtl8723be.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/Makefile index 345a68adcf38..73da75526e2a 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8723com/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8723com/Makefile @@ -5,5 +5,3 @@ rtl8723-common-objs := \ phy_common.o obj-$(CONFIG_RTL8723_COMMON) += rtl8723-common.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/Makefile b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/Makefile index f7a26f71197e..8ca406b95f02 100644 --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/Makefile +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/Makefile @@ -12,5 +12,3 @@ rtl8821ae-objs := \ obj-$(CONFIG_RTL8821AE) += rtl8821ae.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/ti/wl1251/Makefile b/drivers/net/wireless/ti/wl1251/Makefile index a5c6328b5f72..58b4f935a3f6 100644 --- a/drivers/net/wireless/ti/wl1251/Makefile +++ b/drivers/net/wireless/ti/wl1251/Makefile @@ -6,5 +6,3 @@ wl1251_sdio-objs += sdio.o obj-$(CONFIG_WL1251) += wl1251.o obj-$(CONFIG_WL1251_SPI) += wl1251_spi.o obj-$(CONFIG_WL1251_SDIO) += wl1251_sdio.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/ti/wlcore/Makefile b/drivers/net/wireless/ti/wlcore/Makefile index 0a69c1373643..e286713b3c18 100644 --- a/drivers/net/wireless/ti/wlcore/Makefile +++ b/drivers/net/wireless/ti/wlcore/Makefile @@ -8,5 +8,3 @@ wlcore-$(CONFIG_NL80211_TESTMODE) += testmode.o obj-$(CONFIG_WLCORE) += wlcore.o obj-$(CONFIG_WLCORE_SPI) += wlcore_spi.o obj-$(CONFIG_WLCORE_SDIO) += wlcore_sdio.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/staging/rtl8188eu/Makefile b/drivers/staging/rtl8188eu/Makefile index 29b9834870fd..27af86e05098 100644 --- a/drivers/staging/rtl8188eu/Makefile +++ b/drivers/staging/rtl8188eu/Makefile @@ -53,4 +53,4 @@ r8188eu-y := \ obj-$(CONFIG_R8188EU) := r8188eu.o -ccflags-y += -D__CHECK_ENDIAN__ -I$(srctree)/$(src)/include +ccflags-y += -I$(srctree)/$(src)/include diff --git a/drivers/staging/rtl8192e/Makefile b/drivers/staging/rtl8192e/Makefile index cb18db74d78c..7101fcc8871b 100644 --- a/drivers/staging/rtl8192e/Makefile +++ b/drivers/staging/rtl8192e/Makefile @@ -17,5 +17,3 @@ obj-$(CONFIG_RTLLIB_CRYPTO_TKIP) += rtllib_crypt_tkip.o obj-$(CONFIG_RTLLIB_CRYPTO_WEP) += rtllib_crypt_wep.o obj-$(CONFIG_RTL8192E) += rtl8192e/ - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/staging/rtl8192e/rtl8192e/Makefile b/drivers/staging/rtl8192e/rtl8192e/Makefile index a2c4fb4ba1af..176a4a2b8b20 100644 --- a/drivers/staging/rtl8192e/rtl8192e/Makefile +++ b/drivers/staging/rtl8192e/rtl8192e/Makefile @@ -16,5 +16,3 @@ r8192e_pci-objs := \ rtl_wx.o \ obj-$(CONFIG_RTL8192E) += r8192e_pci.o - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index b3ff12eb9b6d..4bfaa19a5573 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -20,5 +20,3 @@ bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o bluetooth-$(CONFIG_BT_LEDS) += leds.o bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o - -subdir-ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/ieee802154/Makefile b/net/ieee802154/Makefile index 4adfd4d5471b..9b92ade687a3 100644 --- a/net/ieee802154/Makefile +++ b/net/ieee802154/Makefile @@ -7,5 +7,3 @@ ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o core.o \ ieee802154_socket-y := socket.o CFLAGS_trace.o := -I$(src) - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 0b202b343fd4..282912245938 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -61,4 +61,4 @@ rc80211_minstrel_ht-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_ht_debugfs.o mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) -ccflags-y += -D__CHECK_ENDIAN__ -DDEBUG +ccflags-y += -DDEBUG diff --git a/net/mac802154/Makefile b/net/mac802154/Makefile index 17a51e8389e2..5857bb1e1695 100644 --- a/net/mac802154/Makefile +++ b/net/mac802154/Makefile @@ -3,5 +3,3 @@ mac802154-objs := main.o rx.o tx.o mac_cmd.o mib.o \ iface.o llsec.o util.o cfg.o trace.o CFLAGS_trace.o := -I$(src) - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 4c9e39f04ef8..816c9331c8d2 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -17,8 +17,6 @@ cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o CFLAGS_trace.o := -I$(src) -ccflags-y += -D__CHECK_ENDIAN__ - $(obj)/regdb.c: $(src)/db.txt $(src)/genregdb.awk @$(AWK) -f $(srctree)/$(src)/genregdb.awk < $< > $@ -- cgit v1.2.3 From 9cf8bd529c6ba81402ebf6b7a56307b0787e4f93 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 15 Dec 2016 20:04:31 -0800 Subject: libnvdimm: replace mutex_is_locked() warnings with lockdep_assert_held For warnings that should only ever trigger during development and testing replace WARN statements with lockdep_assert_held. The lockdep pattern is prevalent, and these paths are are well covered by libnvdimm unit tests. Reported-by: Johannes Thumshirn Reviewed-by: Johannes Thumshirn Signed-off-by: Dan Williams --- drivers/nvdimm/claim.c | 10 ++++------ drivers/nvdimm/namespace_devs.c | 2 +- drivers/nvdimm/region_devs.c | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 3376da1fb263..97d1772774a8 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -22,9 +22,8 @@ void __nd_detach_ndns(struct device *dev, struct nd_namespace_common **_ndns) { struct nd_namespace_common *ndns = *_ndns; - dev_WARN_ONCE(dev, !mutex_is_locked(&ndns->dev.mutex) - || ndns->claim != dev, - "%s: invalid claim\n", __func__); + lockdep_assert_held(&ndns->dev.mutex); + dev_WARN_ONCE(dev, ndns->claim != dev, "%s: invalid claim\n", __func__); ndns->claim = NULL; *_ndns = NULL; put_device(&ndns->dev); @@ -49,9 +48,8 @@ bool __nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach, { if (attach->claim) return false; - dev_WARN_ONCE(dev, !mutex_is_locked(&attach->dev.mutex) - || *_ndns, - "%s: invalid claim\n", __func__); + lockdep_assert_held(&attach->dev.mutex); + dev_WARN_ONCE(dev, *_ndns, "%s: invalid claim\n", __func__); attach->claim = dev; *_ndns = attach; get_device(&attach->dev); diff --git a/drivers/nvdimm/namespace_devs.c b/drivers/nvdimm/namespace_devs.c index 8817f8a0cf38..de5809a88512 100644 --- a/drivers/nvdimm/namespace_devs.c +++ b/drivers/nvdimm/namespace_devs.c @@ -1653,7 +1653,7 @@ static int select_pmem_id(struct nd_region *nd_region, u8 *pmem_id) u64 hw_start, hw_end, pmem_start, pmem_end; struct nd_label_ent *label_ent; - WARN_ON(!mutex_is_locked(&nd_mapping->lock)); + lockdep_assert_held(&nd_mapping->lock); list_for_each_entry(label_ent, &nd_mapping->labels, list) { nd_label = label_ent->label; if (!nd_label) diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index 6af5e629140c..7cd705f3247c 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -509,7 +509,7 @@ void nd_mapping_free_labels(struct nd_mapping *nd_mapping) { struct nd_label_ent *label_ent, *e; - WARN_ON(!mutex_is_locked(&nd_mapping->lock)); + lockdep_assert_held(&nd_mapping->lock); list_for_each_entry_safe(label_ent, e, &nd_mapping->labels, list) { list_del(&label_ent->list); kfree(label_ent); -- cgit v1.2.3 From f43d3ec3a889c7f6a196f3b6d6b13345ee46af8a Mon Sep 17 00:00:00 2001 From: Guy Shapiro Date: Thu, 15 Dec 2016 21:23:02 -0800 Subject: Input: imx6ul_tsc - generalize the averaging property Make the avarage-samples property a general touchscreen property rather than imx6ul device specific. Signed-off-by: Guy Shapiro Acked-by: Rob Herring Signed-off-by: Dmitry Torokhov --- .../bindings/input/touchscreen/imx6ul_tsc.txt | 11 ++----- .../bindings/input/touchscreen/touchscreen.txt | 3 ++ drivers/input/touchscreen/imx6ul_tsc.c | 38 +++++++++++++++------- 3 files changed, 33 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt index a66069f6db66..d4927c202aef 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt @@ -17,13 +17,8 @@ Optional properties: This value depends on the touch screen. - pre-charge-time: the touch screen need some time to precharge. This value depends on the touch screen. -- average-samples: Number of data samples which are averaged for each read. - Valid values 0-4 - 0 = 1 sample - 1 = 4 samples - 2 = 8 samples - 3 = 16 samples - 4 = 32 samples +- touchscreen-average-samples: Number of data samples which are averaged for + each read. Valid values are 1, 4, 8, 16 and 32. Example: tsc: tsc@02040000 { @@ -39,6 +34,6 @@ Example: xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>; measure-delay-time = <0xfff>; pre-charge-time = <0xffff>; - average-samples = <4>; + touchscreen-average-samples = <32>; status = "okay"; }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt index bccaa4e73045..537643e86f61 100644 --- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt +++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt @@ -14,6 +14,9 @@ Optional properties for Touchscreens: - touchscreen-fuzz-pressure : pressure noise value of the absolute input device (arbitrary range dependent on the controller) + - touchscreen-average-samples : Number of data samples which are averaged + for each read (valid values dependent on the + controller) - touchscreen-inverted-x : X axis is inverted (boolean) - touchscreen-inverted-y : Y axis is inverted (boolean) - touchscreen-swapped-x-y : X and Y axis are swapped (boolean) diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c index d2a39120f37f..7098e0a47019 100644 --- a/drivers/input/touchscreen/imx6ul_tsc.c +++ b/drivers/input/touchscreen/imx6ul_tsc.c @@ -21,6 +21,7 @@ #include #include #include +#include /* ADC configuration registers field define */ #define ADC_AIEN (0x1 << 7) @@ -93,7 +94,8 @@ struct imx6ul_tsc { u32 measure_delay_time; u32 pre_charge_time; - u32 average_samples; + bool average_enable; + u32 average_select; struct completion completion; }; @@ -117,9 +119,9 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK; adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK); adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE; - if (tsc->average_samples) { + if (tsc->average_enable) { adc_cfg &= ~ADC_AVGS_MASK; - adc_cfg |= (tsc->average_samples - 1) << ADC_AVGS_SHIFT; + adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT; } adc_cfg &= ~ADC_HARDWARE_TRIGGER; writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG); @@ -132,7 +134,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc) /* start ADC calibration */ adc_gc = readl(tsc->adc_regs + REG_ADC_GC); adc_gc |= ADC_CAL; - if (tsc->average_samples) + if (tsc->average_enable) adc_gc |= ADC_AVGE; writel(adc_gc, tsc->adc_regs + REG_ADC_GC); @@ -362,6 +364,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) int err; int tsc_irq; int adc_irq; + u32 average_samples; tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL); if (!tsc) @@ -466,14 +469,27 @@ static int imx6ul_tsc_probe(struct platform_device *pdev) if (err) tsc->pre_charge_time = 0xfff; - err = of_property_read_u32(np, "average-samples", - &tsc->average_samples); + err = of_property_read_u32(np, "touchscreen-average-samples", + &average_samples); if (err) - tsc->average_samples = 0; - - if (tsc->average_samples > 4) { - dev_err(&pdev->dev, "average-samples (%u) must be [0-4]\n", - tsc->average_samples); + average_samples = 1; + + switch (average_samples) { + case 1: + tsc->average_enable = false; + tsc->average_select = 0; /* value unused; initialize anyway */ + break; + case 4: + case 8: + case 16: + case 32: + tsc->average_enable = true; + tsc->average_select = ilog2(average_samples) - 2; + break; + default: + dev_err(&pdev->dev, + "touchscreen-average-samples (%u) must be 1, 4, 8, 16 or 32\n", + average_samples); return -EINVAL; } -- cgit v1.2.3 From c55b1de02d68e4343045391c0f4978c0bc5a9447 Mon Sep 17 00:00:00 2001 From: Jike Song Date: Thu, 8 Dec 2016 11:00:34 +0800 Subject: drm/i915/gvt/kvmgt: replace kmalloc() by kzalloc() Signed-off-by: Jike Song Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/kvmgt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index dc0365033157..aecb657d8b99 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -322,7 +322,7 @@ static void kvmgt_protect_table_add(struct kvmgt_guest_info *info, gfn_t gfn) if (kvmgt_gfn_is_write_protected(info, gfn)) return; - p = kmalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC); + p = kzalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC); if (WARN(!p, "gfn: 0x%llx\n", gfn)) return; -- cgit v1.2.3 From f440c8a572d7e0002d5c2c8dbd740130ad8ffa5b Mon Sep 17 00:00:00 2001 From: Jike Song Date: Thu, 8 Dec 2016 11:00:35 +0800 Subject: drm/i915/gvt/kvmgt: read/write GPA via KVM API Previously to read/write a GPA, we at first try to pin the GFN it belongs to, then translate the pinned PFN to a kernel HVA, then read/write it. This is however not necessary. A GFN should be pinned IFF it would be accessed by peripheral devices (DMA), not by CPU. This patch changes the read/write method to KVM API, which will leverage userspace HVA and copy_{from|to}_usr instead. Signed-off-by: Jike Song Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/gvt/kvmgt.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index aecb657d8b99..24496ad6a942 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -519,33 +520,27 @@ static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) return pfn; } -static void *kvmgt_gpa_to_hva(unsigned long handle, unsigned long gpa) -{ - unsigned long pfn; - gfn_t gfn = gpa_to_gfn(gpa); - - pfn = kvmgt_gfn_to_pfn(handle, gfn); - if (!pfn) - return NULL; - - return (char *)pfn_to_kaddr(pfn) + offset_in_page(gpa); -} - static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa, void *buf, unsigned long len, bool write) { - void *hva = NULL; + struct kvmgt_guest_info *info; + struct kvm *kvm; + int ret; + bool kthread = current->mm == NULL; - hva = kvmgt_gpa_to_hva(handle, gpa); - if (!hva) - return -EFAULT; + info = (struct kvmgt_guest_info *)handle; + kvm = info->kvm; - if (write) - memcpy(hva, buf, len); - else - memcpy(buf, hva, len); + if (kthread) + use_mm(kvm->mm); - return 0; + ret = write ? kvm_write_guest(kvm, gpa, buf, len) : + kvm_read_guest(kvm, gpa, buf, len); + + if (kthread) + unuse_mm(kvm->mm); + + return ret; } static int kvmgt_read_gpa(unsigned long handle, unsigned long gpa, -- cgit v1.2.3 From 659643f7d81432189c2c87230e2feee4c75c14c1 Mon Sep 17 00:00:00 2001 From: Jike Song Date: Thu, 8 Dec 2016 11:00:36 +0800 Subject: drm/i915/gvt/kvmgt: add vfio/mdev support to KVMGT KVMGT leverages vfio/mdev to mediate device accesses from guest, this patch adds the vfio/mdev support, thereby completes the functionality. An intel_vgpu is presented as a mdev device, and full userspace API compatibility with vfio-pci is kept. An intel_vgpu_ops is provided to mdev framework, methods get called to create/remove a vgpu, to open/close it, and to access it. Signed-off-by: Kevin Tian Signed-off-by: Xiaoguang Chen Signed-off-by: Jike Song Signed-off-by: Zhenyu Wang --- drivers/gpu/drm/i915/Kconfig | 1 + drivers/gpu/drm/i915/gvt/Makefile | 2 - drivers/gpu/drm/i915/gvt/gvt.h | 6 +- drivers/gpu/drm/i915/gvt/kvmgt.c | 938 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 907 insertions(+), 40 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index 5ddde7349fbd..183f5dc1c3f2 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -116,6 +116,7 @@ config DRM_I915_GVT_KVMGT tristate "Enable KVM/VFIO support for Intel GVT-g" depends on DRM_I915_GVT depends on KVM + depends on VFIO_MDEV && VFIO_MDEV_DEVICE default n help Choose this option if you want to enable KVMGT support for diff --git a/drivers/gpu/drm/i915/gvt/Makefile b/drivers/gpu/drm/i915/gvt/Makefile index 8a46a7f31d53..b123c20e2097 100644 --- a/drivers/gpu/drm/i915/gvt/Makefile +++ b/drivers/gpu/drm/i915/gvt/Makefile @@ -5,6 +5,4 @@ GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \ ccflags-y += -I$(src) -I$(src)/$(GVT_DIR) -Wall i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE)) - -CFLAGS_kvmgt.o := -Wno-unused-function obj-$(CONFIG_DRM_I915_GVT_KVMGT) += $(GVT_DIR)/kvmgt.o diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h index b1a7c8dd4b5f..ad0e9364ee70 100644 --- a/drivers/gpu/drm/i915/gvt/gvt.h +++ b/drivers/gpu/drm/i915/gvt/gvt.h @@ -164,15 +164,17 @@ struct intel_vgpu { #if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT) struct { - struct device *mdev; + struct mdev_device *mdev; struct vfio_region *region; int num_regions; struct eventfd_ctx *intx_trigger; struct eventfd_ctx *msi_trigger; struct rb_root cache; struct mutex cache_lock; - void *vfio_group; struct notifier_block iommu_notifier; + struct notifier_block group_notifier; + struct kvm *kvm; + struct work_struct release_work; } vdev; #endif }; diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c index 24496ad6a942..4dd6722a7339 100644 --- a/drivers/gpu/drm/i915/gvt/kvmgt.c +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c @@ -40,24 +40,13 @@ #include #include #include +#include #include "i915_drv.h" #include "gvt.h" -static inline long kvmgt_pin_pages(struct device *dev, unsigned long *user_pfn, - long npage, int prot, unsigned long *phys_pfn) -{ - return 0; -} -static inline long kvmgt_unpin_pages(struct device *dev, unsigned long *pfn, - long npage) -{ - return 0; -} - static const struct intel_gvt_ops *intel_gvt_ops; - /* helper macros copied from vfio-pci */ #define VFIO_PCI_OFFSET_SHIFT 40 #define VFIO_PCI_OFFSET_TO_INDEX(off) (off >> VFIO_PCI_OFFSET_SHIFT) @@ -91,6 +80,15 @@ struct gvt_dma { kvm_pfn_t pfn; }; +static inline bool handle_valid(unsigned long handle) +{ + return !!(handle & ~0xff); +} + +static int kvmgt_guest_init(struct mdev_device *mdev); +static void intel_vgpu_release_work(struct work_struct *work); +static bool kvmgt_guest_exit(struct kvmgt_guest_info *info); + static struct gvt_dma *__gvt_cache_find(struct intel_vgpu *vgpu, gfn_t gfn) { struct rb_node *node = vgpu->vdev.cache.rb_node; @@ -168,9 +166,10 @@ static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu, static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) { - struct device *dev = vgpu->vdev.mdev; + struct device *dev = &vgpu->vdev.mdev->dev; struct gvt_dma *this; - unsigned long pfn; + unsigned long g1; + int rc; mutex_lock(&vgpu->vdev.cache_lock); this = __gvt_cache_find(vgpu, gfn); @@ -179,8 +178,9 @@ static void gvt_cache_remove(struct intel_vgpu *vgpu, gfn_t gfn) return; } - pfn = this->pfn; - WARN_ON((kvmgt_unpin_pages(dev, &pfn, 1) != 1)); + g1 = gfn; + rc = vfio_unpin_pages(dev, &g1, 1); + WARN_ON(rc != 1); __gvt_cache_remove_entry(vgpu, this); mutex_unlock(&vgpu->vdev.cache_lock); } @@ -195,15 +195,15 @@ static void gvt_cache_destroy(struct intel_vgpu *vgpu) { struct gvt_dma *dma; struct rb_node *node = NULL; - struct device *dev = vgpu->vdev.mdev; - unsigned long pfn; + struct device *dev = &vgpu->vdev.mdev->dev; + unsigned long gfn; mutex_lock(&vgpu->vdev.cache_lock); while ((node = rb_first(&vgpu->vdev.cache))) { dma = rb_entry(node, struct gvt_dma, node); - pfn = dma->pfn; + gfn = dma->gfn; - kvmgt_unpin_pages(dev, &pfn, 1); + vfio_unpin_pages(dev, &gfn, 1); __gvt_cache_remove_entry(vgpu, dma); } mutex_unlock(&vgpu->vdev.cache_lock); @@ -227,7 +227,53 @@ static struct intel_vgpu_type *intel_gvt_find_vgpu_type(struct intel_gvt *gvt, return NULL; } +static ssize_t available_instance_show(struct kobject *kobj, struct device *dev, + char *buf) +{ + struct intel_vgpu_type *type; + unsigned int num = 0; + void *gvt = kdev_to_i915(dev)->gvt; + + type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); + if (!type) + num = 0; + else + num = type->avail_instance; + + return sprintf(buf, "%u\n", num); +} + +static ssize_t device_api_show(struct kobject *kobj, struct device *dev, + char *buf) +{ + return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING); +} + +static ssize_t description_show(struct kobject *kobj, struct device *dev, + char *buf) +{ + struct intel_vgpu_type *type; + void *gvt = kdev_to_i915(dev)->gvt; + + type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); + if (!type) + return 0; + + return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n" + "fence: %d\n", + BYTES_TO_MB(type->low_gm_size), + BYTES_TO_MB(type->high_gm_size), + type->fence); +} + +static MDEV_TYPE_ATTR_RO(available_instance); +static MDEV_TYPE_ATTR_RO(device_api); +static MDEV_TYPE_ATTR_RO(description); + static struct attribute *type_attrs[] = { + &mdev_type_attr_available_instance.attr, + &mdev_type_attr_device_api.attr, + &mdev_type_attr_description.attr, NULL, }; @@ -343,6 +389,720 @@ static void kvmgt_protect_table_del(struct kvmgt_guest_info *info, } } +static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev) +{ + struct intel_vgpu *vgpu; + struct intel_vgpu_type *type; + struct device *pdev; + void *gvt; + + pdev = mdev->parent->dev; + gvt = kdev_to_i915(pdev)->gvt; + + type = intel_gvt_find_vgpu_type(gvt, kobject_name(kobj)); + if (!type) { + gvt_err("failed to find type %s to create\n", + kobject_name(kobj)); + return -EINVAL; + } + + vgpu = intel_gvt_ops->vgpu_create(gvt, type); + if (IS_ERR_OR_NULL(vgpu)) { + gvt_err("create intel vgpu failed\n"); + return -EINVAL; + } + + INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work); + + vgpu->vdev.mdev = mdev; + mdev_set_drvdata(mdev, vgpu); + + gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n", + dev_name(&mdev->dev)); + return 0; +} + +static int intel_vgpu_remove(struct mdev_device *mdev) +{ + struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); + + if (handle_valid(vgpu->handle)) + return -EBUSY; + + intel_gvt_ops->vgpu_destroy(vgpu); + return 0; +} + +static int intel_vgpu_iommu_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct intel_vgpu *vgpu = container_of(nb, + struct intel_vgpu, + vdev.iommu_notifier); + + if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) { + struct vfio_iommu_type1_dma_unmap *unmap = data; + unsigned long gfn, end_gfn; + + gfn = unmap->iova >> PAGE_SHIFT; + end_gfn = gfn + unmap->size / PAGE_SIZE; + + while (gfn < end_gfn) + gvt_cache_remove(vgpu, gfn++); + } + + return NOTIFY_OK; +} + +static int intel_vgpu_group_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct intel_vgpu *vgpu = container_of(nb, + struct intel_vgpu, + vdev.group_notifier); + + /* the only action we care about */ + if (action == VFIO_GROUP_NOTIFY_SET_KVM) { + vgpu->vdev.kvm = data; + + if (!data) + schedule_work(&vgpu->vdev.release_work); + } + + return NOTIFY_OK; +} + +static int intel_vgpu_open(struct mdev_device *mdev) +{ + struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); + unsigned long events; + int ret; + + vgpu->vdev.iommu_notifier.notifier_call = intel_vgpu_iommu_notifier; + vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier; + + events = VFIO_IOMMU_NOTIFY_DMA_UNMAP; + ret = vfio_register_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, &events, + &vgpu->vdev.iommu_notifier); + if (ret != 0) { + gvt_err("vfio_register_notifier for iommu failed: %d\n", ret); + goto out; + } + + events = VFIO_GROUP_NOTIFY_SET_KVM; + ret = vfio_register_notifier(&mdev->dev, VFIO_GROUP_NOTIFY, &events, + &vgpu->vdev.group_notifier); + if (ret != 0) { + gvt_err("vfio_register_notifier for group failed: %d\n", ret); + goto undo_iommu; + } + + return kvmgt_guest_init(mdev); + +undo_iommu: + vfio_unregister_notifier(&mdev->dev, VFIO_IOMMU_NOTIFY, + &vgpu->vdev.iommu_notifier); +out: + return ret; +} + +static void __intel_vgpu_release(struct intel_vgpu *vgpu) +{ + struct kvmgt_guest_info *info; + + if (!handle_valid(vgpu->handle)) + return; + + vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_IOMMU_NOTIFY, + &vgpu->vdev.iommu_notifier); + vfio_unregister_notifier(&vgpu->vdev.mdev->dev, VFIO_GROUP_NOTIFY, + &vgpu->vdev.group_notifier); + + info = (struct kvmgt_guest_info *)vgpu->handle; + kvmgt_guest_exit(info); + vgpu->handle = 0; +} + +static void intel_vgpu_release(struct mdev_device *mdev) +{ + struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); + + __intel_vgpu_release(vgpu); +} + +static void intel_vgpu_release_work(struct work_struct *work) +{ + struct intel_vgpu *vgpu = container_of(work, struct intel_vgpu, + vdev.release_work); + __intel_vgpu_release(vgpu); +} + +static uint64_t intel_vgpu_get_bar0_addr(struct intel_vgpu *vgpu) +{ + u32 start_lo, start_hi; + u32 mem_type; + int pos = PCI_BASE_ADDRESS_0; + + start_lo = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) & + PCI_BASE_ADDRESS_MEM_MASK; + mem_type = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + pos)) & + PCI_BASE_ADDRESS_MEM_TYPE_MASK; + + switch (mem_type) { + case PCI_BASE_ADDRESS_MEM_TYPE_64: + start_hi = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + + pos + 4)); + break; + case PCI_BASE_ADDRESS_MEM_TYPE_32: + case PCI_BASE_ADDRESS_MEM_TYPE_1M: + /* 1M mem BAR treated as 32-bit BAR */ + default: + /* mem unknown type treated as 32-bit BAR */ + start_hi = 0; + break; + } + + return ((u64)start_hi << 32) | start_lo; +} + +static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf, + size_t count, loff_t *ppos, bool is_write) +{ + struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); + unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos); + uint64_t pos = *ppos & VFIO_PCI_OFFSET_MASK; + int ret = -EINVAL; + + + if (index >= VFIO_PCI_NUM_REGIONS) { + gvt_err("invalid index: %u\n", index); + return -EINVAL; + } + + switch (index) { + case VFIO_PCI_CONFIG_REGION_INDEX: + if (is_write) + ret = intel_gvt_ops->emulate_cfg_write(vgpu, pos, + buf, count); + else + ret = intel_gvt_ops->emulate_cfg_read(vgpu, pos, + buf, count); + break; + case VFIO_PCI_BAR0_REGION_INDEX: + case VFIO_PCI_BAR1_REGION_INDEX: + if (is_write) { + uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu); + + ret = intel_gvt_ops->emulate_mmio_write(vgpu, + bar0_start + pos, buf, count); + } else { + uint64_t bar0_start = intel_vgpu_get_bar0_addr(vgpu); + + ret = intel_gvt_ops->emulate_mmio_read(vgpu, + bar0_start + pos, buf, count); + } + break; + case VFIO_PCI_BAR2_REGION_INDEX: + case VFIO_PCI_BAR3_REGION_INDEX: + case VFIO_PCI_BAR4_REGION_INDEX: + case VFIO_PCI_BAR5_REGION_INDEX: + case VFIO_PCI_VGA_REGION_INDEX: + case VFIO_PCI_ROM_REGION_INDEX: + default: + gvt_err("unsupported region: %u\n", index); + } + + return ret == 0 ? count : ret; +} + +static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned int done = 0; + int ret; + + while (count) { + size_t filled; + + if (count >= 4 && !(*ppos % 4)) { + u32 val; + + ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), + ppos, false); + if (ret <= 0) + goto read_err; + + if (copy_to_user(buf, &val, sizeof(val))) + goto read_err; + + filled = 4; + } else if (count >= 2 && !(*ppos % 2)) { + u16 val; + + ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), + ppos, false); + if (ret <= 0) + goto read_err; + + if (copy_to_user(buf, &val, sizeof(val))) + goto read_err; + + filled = 2; + } else { + u8 val; + + ret = intel_vgpu_rw(mdev, &val, sizeof(val), ppos, + false); + if (ret <= 0) + goto read_err; + + if (copy_to_user(buf, &val, sizeof(val))) + goto read_err; + + filled = 1; + } + + count -= filled; + done += filled; + *ppos += filled; + buf += filled; + } + + return done; + +read_err: + return -EFAULT; +} + +static ssize_t intel_vgpu_write(struct mdev_device *mdev, + const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned int done = 0; + int ret; + + while (count) { + size_t filled; + + if (count >= 4 && !(*ppos % 4)) { + u32 val; + + if (copy_from_user(&val, buf, sizeof(val))) + goto write_err; + + ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val), + ppos, true); + if (ret <= 0) + goto write_err; + + filled = 4; + } else if (count >= 2 && !(*ppos % 2)) { + u16 val; + + if (copy_from_user(&val, buf, sizeof(val))) + goto write_err; + + ret = intel_vgpu_rw(mdev, (char *)&val, + sizeof(val), ppos, true); + if (ret <= 0) + goto write_err; + + filled = 2; + } else { + u8 val; + + if (copy_from_user(&val, buf, sizeof(val))) + goto write_err; + + ret = intel_vgpu_rw(mdev, &val, sizeof(val), + ppos, true); + if (ret <= 0) + goto write_err; + + filled = 1; + } + + count -= filled; + done += filled; + *ppos += filled; + buf += filled; + } + + return done; +write_err: + return -EFAULT; +} + +static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma) +{ + unsigned int index; + u64 virtaddr; + unsigned long req_size, pgoff = 0; + pgprot_t pg_prot; + struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); + + index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT); + if (index >= VFIO_PCI_ROM_REGION_INDEX) + return -EINVAL; + + if (vma->vm_end < vma->vm_start) + return -EINVAL; + if ((vma->vm_flags & VM_SHARED) == 0) + return -EINVAL; + if (index != VFIO_PCI_BAR2_REGION_INDEX) + return -EINVAL; + + pg_prot = vma->vm_page_prot; + virtaddr = vma->vm_start; + req_size = vma->vm_end - vma->vm_start; + pgoff = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT; + + return remap_pfn_range(vma, virtaddr, pgoff, req_size, pg_prot); +} + +static int intel_vgpu_get_irq_count(struct intel_vgpu *vgpu, int type) +{ + if (type == VFIO_PCI_INTX_IRQ_INDEX || type == VFIO_PCI_MSI_IRQ_INDEX) + return 1; + + return 0; +} + +static int intel_vgpu_set_intx_mask(struct intel_vgpu *vgpu, + unsigned int index, unsigned int start, + unsigned int count, uint32_t flags, + void *data) +{ + return 0; +} + +static int intel_vgpu_set_intx_unmask(struct intel_vgpu *vgpu, + unsigned int index, unsigned int start, + unsigned int count, uint32_t flags, void *data) +{ + return 0; +} + +static int intel_vgpu_set_intx_trigger(struct intel_vgpu *vgpu, + unsigned int index, unsigned int start, unsigned int count, + uint32_t flags, void *data) +{ + return 0; +} + +static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu, + unsigned int index, unsigned int start, unsigned int count, + uint32_t flags, void *data) +{ + struct eventfd_ctx *trigger; + + if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { + int fd = *(int *)data; + + trigger = eventfd_ctx_fdget(fd); + if (IS_ERR(trigger)) { + gvt_err("eventfd_ctx_fdget failed\n"); + return PTR_ERR(trigger); + } + vgpu->vdev.msi_trigger = trigger; + } + + return 0; +} + +static int intel_vgpu_set_irqs(struct intel_vgpu *vgpu, uint32_t flags, + unsigned int index, unsigned int start, unsigned int count, + void *data) +{ + int (*func)(struct intel_vgpu *vgpu, unsigned int index, + unsigned int start, unsigned int count, uint32_t flags, + void *data) = NULL; + + switch (index) { + case VFIO_PCI_INTX_IRQ_INDEX: + switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { + case VFIO_IRQ_SET_ACTION_MASK: + func = intel_vgpu_set_intx_mask; + break; + case VFIO_IRQ_SET_ACTION_UNMASK: + func = intel_vgpu_set_intx_unmask; + break; + case VFIO_IRQ_SET_ACTION_TRIGGER: + func = intel_vgpu_set_intx_trigger; + break; + } + break; + case VFIO_PCI_MSI_IRQ_INDEX: + switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) { + case VFIO_IRQ_SET_ACTION_MASK: + case VFIO_IRQ_SET_ACTION_UNMASK: + /* XXX Need masking support exported */ + break; + case VFIO_IRQ_SET_ACTION_TRIGGER: + func = intel_vgpu_set_msi_trigger; + break; + } + break; + } + + if (!func) + return -ENOTTY; + + return func(vgpu, index, start, count, flags, data); +} + +static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd, + unsigned long arg) +{ + struct intel_vgpu *vgpu = mdev_get_drvdata(mdev); + unsigned long minsz; + + gvt_dbg_core("vgpu%d ioctl, cmd: %d\n", vgpu->id, cmd); + + if (cmd == VFIO_DEVICE_GET_INFO) { + struct vfio_device_info info; + + minsz = offsetofend(struct vfio_device_info, num_irqs); + + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz) + return -EINVAL; + + info.flags = VFIO_DEVICE_FLAGS_PCI; + info.flags |= VFIO_DEVICE_FLAGS_RESET; + info.num_regions = VFIO_PCI_NUM_REGIONS; + info.num_irqs = VFIO_PCI_NUM_IRQS; + + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; + + } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) { + struct vfio_region_info info; + struct vfio_info_cap caps = { .buf = NULL, .size = 0 }; + int i, ret; + struct vfio_region_info_cap_sparse_mmap *sparse = NULL; + size_t size; + int nr_areas = 1; + int cap_type_id; + + minsz = offsetofend(struct vfio_region_info, offset); + + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz) + return -EINVAL; + + switch (info.index) { + case VFIO_PCI_CONFIG_REGION_INDEX: + info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); + info.size = INTEL_GVT_MAX_CFG_SPACE_SZ; + info.flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + break; + case VFIO_PCI_BAR0_REGION_INDEX: + info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); + info.size = vgpu->cfg_space.bar[info.index].size; + if (!info.size) { + info.flags = 0; + break; + } + + info.flags = VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + break; + case VFIO_PCI_BAR1_REGION_INDEX: + info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); + info.size = 0; + info.flags = 0; + break; + case VFIO_PCI_BAR2_REGION_INDEX: + info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); + info.flags = VFIO_REGION_INFO_FLAG_CAPS | + VFIO_REGION_INFO_FLAG_MMAP | + VFIO_REGION_INFO_FLAG_READ | + VFIO_REGION_INFO_FLAG_WRITE; + info.size = gvt_aperture_sz(vgpu->gvt); + + size = sizeof(*sparse) + + (nr_areas * sizeof(*sparse->areas)); + sparse = kzalloc(size, GFP_KERNEL); + if (!sparse) + return -ENOMEM; + + sparse->nr_areas = nr_areas; + cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP; + sparse->areas[0].offset = + PAGE_ALIGN(vgpu_aperture_offset(vgpu)); + sparse->areas[0].size = vgpu_aperture_sz(vgpu); + if (!caps.buf) { + kfree(caps.buf); + caps.buf = NULL; + caps.size = 0; + } + break; + + case VFIO_PCI_BAR3_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX: + info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index); + info.size = 0; + + info.flags = 0; + gvt_dbg_core("get region info bar:%d\n", info.index); + break; + + case VFIO_PCI_ROM_REGION_INDEX: + case VFIO_PCI_VGA_REGION_INDEX: + gvt_dbg_core("get region info index:%d\n", info.index); + break; + default: + { + struct vfio_region_info_cap_type cap_type; + + if (info.index >= VFIO_PCI_NUM_REGIONS + + vgpu->vdev.num_regions) + return -EINVAL; + + i = info.index - VFIO_PCI_NUM_REGIONS; + + info.offset = + VFIO_PCI_INDEX_TO_OFFSET(info.index); + info.size = vgpu->vdev.region[i].size; + info.flags = vgpu->vdev.region[i].flags; + + cap_type.type = vgpu->vdev.region[i].type; + cap_type.subtype = vgpu->vdev.region[i].subtype; + + ret = vfio_info_add_capability(&caps, + VFIO_REGION_INFO_CAP_TYPE, + &cap_type); + if (ret) + return ret; + } + } + + if ((info.flags & VFIO_REGION_INFO_FLAG_CAPS) && sparse) { + switch (cap_type_id) { + case VFIO_REGION_INFO_CAP_SPARSE_MMAP: + ret = vfio_info_add_capability(&caps, + VFIO_REGION_INFO_CAP_SPARSE_MMAP, + sparse); + kfree(sparse); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + } + + if (caps.size) { + if (info.argsz < sizeof(info) + caps.size) { + info.argsz = sizeof(info) + caps.size; + info.cap_offset = 0; + } else { + vfio_info_cap_shift(&caps, sizeof(info)); + if (copy_to_user((void __user *)arg + + sizeof(info), caps.buf, + caps.size)) { + kfree(caps.buf); + return -EFAULT; + } + info.cap_offset = sizeof(info); + } + + kfree(caps.buf); + } + + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; + } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) { + struct vfio_irq_info info; + + minsz = offsetofend(struct vfio_irq_info, count); + + if (copy_from_user(&info, (void __user *)arg, minsz)) + return -EFAULT; + + if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS) + return -EINVAL; + + switch (info.index) { + case VFIO_PCI_INTX_IRQ_INDEX: + case VFIO_PCI_MSI_IRQ_INDEX: + break; + default: + return -EINVAL; + } + + info.flags = VFIO_IRQ_INFO_EVENTFD; + + info.count = intel_vgpu_get_irq_count(vgpu, info.index); + + if (info.index == VFIO_PCI_INTX_IRQ_INDEX) + info.flags |= (VFIO_IRQ_INFO_MASKABLE | + VFIO_IRQ_INFO_AUTOMASKED); + else + info.flags |= VFIO_IRQ_INFO_NORESIZE; + + return copy_to_user((void __user *)arg, &info, minsz) ? + -EFAULT : 0; + } else if (cmd == VFIO_DEVICE_SET_IRQS) { + struct vfio_irq_set hdr; + u8 *data = NULL; + int ret = 0; + size_t data_size = 0; + + minsz = offsetofend(struct vfio_irq_set, count); + + if (copy_from_user(&hdr, (void __user *)arg, minsz)) + return -EFAULT; + + if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) { + int max = intel_vgpu_get_irq_count(vgpu, hdr.index); + + ret = vfio_set_irqs_validate_and_prepare(&hdr, max, + VFIO_PCI_NUM_IRQS, &data_size); + if (ret) { + gvt_err("intel:vfio_set_irqs_validate_and_prepare failed\n"); + return -EINVAL; + } + if (data_size) { + data = memdup_user((void __user *)(arg + minsz), + data_size); + if (IS_ERR(data)) + return PTR_ERR(data); + } + } + + ret = intel_vgpu_set_irqs(vgpu, hdr.flags, hdr.index, + hdr.start, hdr.count, data); + kfree(data); + + return ret; + } else if (cmd == VFIO_DEVICE_RESET) { + intel_gvt_ops->vgpu_reset(vgpu); + return 0; + } + + return 0; +} + +static const struct parent_ops intel_vgpu_ops = { + .supported_type_groups = intel_vgpu_type_groups, + .create = intel_vgpu_create, + .remove = intel_vgpu_remove, + + .open = intel_vgpu_open, + .release = intel_vgpu_release, + + .read = intel_vgpu_read, + .write = intel_vgpu_write, + .mmap = intel_vgpu_mmap, + .ioctl = intel_vgpu_ioctl, +}; + static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops) { if (!intel_gvt_init_vgpu_type_groups(gvt)) @@ -350,22 +1110,28 @@ static int kvmgt_host_init(struct device *dev, void *gvt, const void *ops) intel_gvt_ops = ops; - /* MDEV is not yet available */ - return -ENODEV; + return mdev_register_device(dev, &intel_vgpu_ops); } static void kvmgt_host_exit(struct device *dev, void *gvt) { intel_gvt_cleanup_vgpu_type_groups(gvt); + mdev_unregister_device(dev); } static int kvmgt_write_protect_add(unsigned long handle, u64 gfn) { - struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; - struct kvm *kvm = info->kvm; + struct kvmgt_guest_info *info; + struct kvm *kvm; struct kvm_memory_slot *slot; int idx; + if (!handle_valid(handle)) + return -ESRCH; + + info = (struct kvmgt_guest_info *)handle; + kvm = info->kvm; + idx = srcu_read_lock(&kvm->srcu); slot = gfn_to_memslot(kvm, gfn); @@ -385,11 +1151,17 @@ out: static int kvmgt_write_protect_remove(unsigned long handle, u64 gfn) { - struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; - struct kvm *kvm = info->kvm; + struct kvmgt_guest_info *info; + struct kvm *kvm; struct kvm_memory_slot *slot; int idx; + if (!handle_valid(handle)) + return 0; + + info = (struct kvmgt_guest_info *)handle; + kvm = info->kvm; + idx = srcu_read_lock(&kvm->srcu); slot = gfn_to_memslot(kvm, gfn); @@ -477,6 +1249,85 @@ static int kvmgt_detect_host(void) return kvmgt_check_guest() ? -ENODEV : 0; } +static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu, struct kvm *kvm) +{ + struct intel_vgpu *itr; + struct kvmgt_guest_info *info; + int id; + bool ret = false; + + mutex_lock(&vgpu->gvt->lock); + for_each_active_vgpu(vgpu->gvt, itr, id) { + if (!handle_valid(itr->handle)) + continue; + + info = (struct kvmgt_guest_info *)itr->handle; + if (kvm && kvm == info->kvm) { + ret = true; + goto out; + } + } +out: + mutex_unlock(&vgpu->gvt->lock); + return ret; +} + +static int kvmgt_guest_init(struct mdev_device *mdev) +{ + struct kvmgt_guest_info *info; + struct intel_vgpu *vgpu; + struct kvm *kvm; + + vgpu = mdev_get_drvdata(mdev); + if (handle_valid(vgpu->handle)) + return -EEXIST; + + kvm = vgpu->vdev.kvm; + if (!kvm || kvm->mm != current->mm) { + gvt_err("KVM is required to use Intel vGPU\n"); + return -ESRCH; + } + + if (__kvmgt_vgpu_exist(vgpu, kvm)) + return -EEXIST; + + info = vzalloc(sizeof(struct kvmgt_guest_info)); + if (!info) + return -ENOMEM; + + vgpu->handle = (unsigned long)info; + info->vgpu = vgpu; + info->kvm = kvm; + + kvmgt_protect_table_init(info); + gvt_cache_init(vgpu); + + info->track_node.track_write = kvmgt_page_track_write; + info->track_node.track_flush_slot = kvmgt_page_track_flush_slot; + kvm_page_track_register_notifier(kvm, &info->track_node); + + return 0; +} + +static bool kvmgt_guest_exit(struct kvmgt_guest_info *info) +{ + struct intel_vgpu *vgpu; + + if (!info) { + gvt_err("kvmgt_guest_info invalid\n"); + return false; + } + + vgpu = info->vgpu; + + kvm_page_track_unregister_notifier(info->kvm, &info->track_node); + kvmgt_protect_table_destroy(info); + gvt_cache_destroy(vgpu); + vfree(info); + + return true; +} + static int kvmgt_attach_vgpu(void *vgpu, unsigned long *handle) { /* nothing to do here */ @@ -490,30 +1341,42 @@ static void kvmgt_detach_vgpu(unsigned long handle) static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data) { - struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; - struct intel_vgpu *vgpu = info->vgpu; + struct kvmgt_guest_info *info; + struct intel_vgpu *vgpu; - if (vgpu->vdev.msi_trigger) - return eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1; + if (!handle_valid(handle)) + return -ESRCH; - return false; + info = (struct kvmgt_guest_info *)handle; + vgpu = info->vgpu; + + if (eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1) + return 0; + + return -EFAULT; } static unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn) { unsigned long pfn; - struct kvmgt_guest_info *info = (struct kvmgt_guest_info *)handle; + struct kvmgt_guest_info *info; + struct device *dev; int rc; + if (!handle_valid(handle)) + return INTEL_GVT_INVALID_ADDR; + + info = (struct kvmgt_guest_info *)handle; pfn = gvt_cache_find(info->vgpu, gfn); if (pfn != 0) return pfn; - rc = kvmgt_pin_pages(info->vgpu->vdev.mdev, &gfn, 1, - IOMMU_READ | IOMMU_WRITE, &pfn); + pfn = INTEL_GVT_INVALID_ADDR; + dev = &info->vgpu->vdev.mdev->dev; + rc = vfio_pin_pages(dev, &gfn, 1, IOMMU_READ | IOMMU_WRITE, &pfn); if (rc != 1) { - gvt_err("vfio_pin_pages failed for gfn: 0x%lx\n", gfn); - return 0; + gvt_err("vfio_pin_pages failed for gfn 0x%lx: %d\n", gfn, rc); + return INTEL_GVT_INVALID_ADDR; } gvt_cache_add(info->vgpu, gfn, pfn); @@ -528,6 +1391,9 @@ static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa, int ret; bool kthread = current->mm == NULL; + if (!handle_valid(handle)) + return -ESRCH; + info = (struct kvmgt_guest_info *)handle; kvm = info->kvm; -- cgit v1.2.3 From a91918cd3ea11f91c68e08e1e8ce1b560447a80e Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 13 Dec 2016 15:27:04 +0300 Subject: target/iscsi: Fix double free in lio_target_tiqn_addtpg() This iscsit_tpg_add_portal_group() function is only called from lio_target_tiqn_addtpg(). Both functions free the "tpg" pointer on error so it's a double free bug. The memory is allocated in the caller so it should be freed in the caller and not here. Fixes: e48354ce078c ("iscsi-target: Add iSCSI fabric support for target v4.1") Signed-off-by: Dan Carpenter Reviewed-by: David Disseldorp [ bvanassche: Added "Fix" at start of patch title ] Signed-off-by: Bart Van Assche --- drivers/target/iscsi/iscsi_target_tpg.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 552151579a28..2e7e08dbda48 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c @@ -260,7 +260,6 @@ err_out: iscsi_release_param_list(tpg->param_list); tpg->param_list = NULL; } - kfree(tpg); return -ENOMEM; } -- cgit v1.2.3 From a3960ced84b8049783de678abf8cd680ee14175f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 7 Nov 2016 16:31:21 +0000 Subject: target: Fix spelling mistake and unwrap multi-line text Trivial fix to spelling mistake "Obselete" to "Obsolete" in error message and also turn multi-line text into one line. Signed-off-by: Colin Ian King Signed-off-by: Bart Van Assche --- drivers/target/target_core_pr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index d7fe569eece5..d761025144f9 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -255,8 +255,7 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd) if ((cmd->t_task_cdb[1] & 0x01) && (cmd->t_task_cdb[1] & 0x02)) { - pr_err("LongIO and Obselete Bits set, returning" - " ILLEGAL_REQUEST\n"); + pr_err("LongIO and Obsolete Bits set, returning ILLEGAL_REQUEST\n"); return TCM_UNSUPPORTED_SCSI_OPCODE; } /* -- cgit v1.2.3 From 83337e544323a8bd7492994d64af339175ac7107 Mon Sep 17 00:00:00 2001 From: Varun Prakash Date: Sun, 11 Dec 2016 22:05:56 +0530 Subject: iscsi-target: Return error if unable to add network portal If iscsit_tpg_add_network_portal() fails then return error code instead of 0 to user space. If iscsi-target returns 0 then user space keeps on retrying same command infinitely, targetcli or echo hangs till command completes with non zero return value. In some cases it is possible that add network portal command never completes with success even after retrying multiple times, for example - cxgbit_setup_np() always returns -EINVAL if portal IP does not belong to Chelsio adapter interface. Signed-off-by: Varun Prakash Signed-off-by: Bart Van Assche [ bvanassche: Added "Fixes:" and "Cc: stable" tags ] Fixes: commit d4b3fa4b0881 ("iscsi-target: Make iscsi_tpg_np driver show/store use generic code") Cc: --- drivers/target/iscsi/iscsi_target_configfs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 7bfb16d407b9..bf40f03755dd 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c @@ -101,8 +101,10 @@ static ssize_t lio_target_np_driver_store(struct config_item *item, tpg_np_new = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr, tpg_np, type); - if (IS_ERR(tpg_np_new)) + if (IS_ERR(tpg_np_new)) { + rc = PTR_ERR(tpg_np_new); goto out; + } } else { tpg_np_new = iscsit_tpg_locate_child_np(tpg_np, type); if (tpg_np_new) { -- cgit v1.2.3 From 8759fec4af222f338d08f8f1a7ad6a77ca6cb301 Mon Sep 17 00:00:00 2001 From: Romain Perier Date: Wed, 14 Dec 2016 15:15:07 +0100 Subject: crypto: marvell - Copy IVDIG before launching partial DMA ahash requests Currently, inner IV/DIGEST data are only copied once into the hash engines and not set explicitly before launching a request that is not a first frag. This is an issue especially when multiple ahash reqs are computed in parallel or chained with cipher request, as the state of the request being computed is not updated into the hash engine. It leads to non-deterministic corrupted digest results. Fixes: commit 2786cee8e50b ("crypto: marvell - Move SRAM I/O operations to step functions") Signed-off-by: Romain Perier Acked-by: Boris Brezillon Cc: Signed-off-by: Herbert Xu --- drivers/crypto/marvell/cesa.h | 3 ++- drivers/crypto/marvell/hash.c | 34 +++++++++++++++++++++++++++++++++- drivers/crypto/marvell/tdma.c | 9 ++++++++- 3 files changed, 43 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/crypto/marvell/cesa.h b/drivers/crypto/marvell/cesa.h index a768da7138a1..b7872f62f674 100644 --- a/drivers/crypto/marvell/cesa.h +++ b/drivers/crypto/marvell/cesa.h @@ -273,7 +273,8 @@ struct mv_cesa_op_ctx { #define CESA_TDMA_SRC_IN_SRAM BIT(30) #define CESA_TDMA_END_OF_REQ BIT(29) #define CESA_TDMA_BREAK_CHAIN BIT(28) -#define CESA_TDMA_TYPE_MSK GENMASK(27, 0) +#define CESA_TDMA_SET_STATE BIT(27) +#define CESA_TDMA_TYPE_MSK GENMASK(26, 0) #define CESA_TDMA_DUMMY 0 #define CESA_TDMA_DATA 1 #define CESA_TDMA_OP 2 diff --git a/drivers/crypto/marvell/hash.c b/drivers/crypto/marvell/hash.c index 2a9260559654..585c90f9f606 100644 --- a/drivers/crypto/marvell/hash.c +++ b/drivers/crypto/marvell/hash.c @@ -281,13 +281,32 @@ static void mv_cesa_ahash_std_prepare(struct ahash_request *req) sreq->offset = 0; } +static void mv_cesa_ahash_dma_step(struct ahash_request *req) +{ + struct mv_cesa_ahash_req *creq = ahash_request_ctx(req); + struct mv_cesa_req *base = &creq->base; + + /* We must explicitly set the digest state. */ + if (base->chain.first->flags & CESA_TDMA_SET_STATE) { + struct mv_cesa_engine *engine = base->engine; + int i; + + /* Set the hash state in the IVDIG regs. */ + for (i = 0; i < ARRAY_SIZE(creq->state); i++) + writel_relaxed(creq->state[i], engine->regs + + CESA_IVDIG(i)); + } + + mv_cesa_dma_step(base); +} + static void mv_cesa_ahash_step(struct crypto_async_request *req) { struct ahash_request *ahashreq = ahash_request_cast(req); struct mv_cesa_ahash_req *creq = ahash_request_ctx(ahashreq); if (mv_cesa_req_get_type(&creq->base) == CESA_DMA_REQ) - mv_cesa_dma_step(&creq->base); + mv_cesa_ahash_dma_step(ahashreq); else mv_cesa_ahash_std_step(ahashreq); } @@ -585,12 +604,16 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) struct mv_cesa_ahash_dma_iter iter; struct mv_cesa_op_ctx *op = NULL; unsigned int frag_len; + bool set_state = false; int ret; u32 type; basereq->chain.first = NULL; basereq->chain.last = NULL; + if (!mv_cesa_mac_op_is_first_frag(&creq->op_tmpl)) + set_state = true; + if (creq->src_nents) { ret = dma_map_sg(cesa_dev->dev, req->src, creq->src_nents, DMA_TO_DEVICE); @@ -684,6 +707,15 @@ static int mv_cesa_ahash_dma_req_init(struct ahash_request *req) if (type != CESA_TDMA_RESULT) basereq->chain.last->flags |= CESA_TDMA_BREAK_CHAIN; + if (set_state) { + /* + * Put the CESA_TDMA_SET_STATE flag on the first tdma desc to + * let the step logic know that the IVDIG registers should be + * explicitly set before launching a TDMA chain. + */ + basereq->chain.first->flags |= CESA_TDMA_SET_STATE; + } + return 0; err_free_tdma: diff --git a/drivers/crypto/marvell/tdma.c b/drivers/crypto/marvell/tdma.c index 4416b88eca70..c76375ff376d 100644 --- a/drivers/crypto/marvell/tdma.c +++ b/drivers/crypto/marvell/tdma.c @@ -109,7 +109,14 @@ void mv_cesa_tdma_chain(struct mv_cesa_engine *engine, last->next = dreq->chain.first; engine->chain.last = dreq->chain.last; - if (!(last->flags & CESA_TDMA_BREAK_CHAIN)) + /* + * Break the DMA chain if the CESA_TDMA_BREAK_CHAIN is set on + * the last element of the current chain, or if the request + * being queued needs the IV regs to be set before lauching + * the request. + */ + if (!(last->flags & CESA_TDMA_BREAK_CHAIN) && + !(dreq->chain.first->flags & CESA_TDMA_SET_STATE)) last->next_dma = dreq->chain.first->cur_dma; } } -- cgit v1.2.3 From 57d77c62536ea0f388c840c8ac7e94be54425308 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 14 Oct 2016 12:23:50 -0300 Subject: watchdog: bcm7038_wdt: fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/watchdog/bcm7038_wdt.ko | grep alias $ After this patch: $ modinfo drivers/watchdog/bcm7038_wdt.ko | grep alias alias: of:N*T*Cbrcm,bcm7038-wdtC* alias: of:N*T*Cbrcm,bcm7038-wdt Signed-off-by: Javier Martinez Canillas Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/bcm7038_wdt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/bcm7038_wdt.c b/drivers/watchdog/bcm7038_wdt.c index e238df4d75a2..4814c00b32f6 100644 --- a/drivers/watchdog/bcm7038_wdt.c +++ b/drivers/watchdog/bcm7038_wdt.c @@ -216,6 +216,7 @@ static const struct of_device_id bcm7038_wdt_match[] = { { .compatible = "brcm,bcm7038-wdt" }, {}, }; +MODULE_DEVICE_TABLE(of, bcm7038_wdt_match); static struct platform_driver bcm7038_wdt_driver = { .probe = bcm7038_wdt_probe, -- cgit v1.2.3 From f99524dced4c89af52a82a369cb61a111b9169b3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Fri, 14 Oct 2016 12:23:51 -0300 Subject: watchdog: max77620_wdt: fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ $ modinfo drivers/watchdog/max77620_wdt.ko | grep alias $ After this patch: modinfo drivers/watchdog/max77620_wdt.ko | grep alias alias: platform:max77620-watchdog Signed-off-by: Javier Martinez Canillas Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/max77620_wdt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/max77620_wdt.c b/drivers/watchdog/max77620_wdt.c index 48b84df2afda..68c41fa2be27 100644 --- a/drivers/watchdog/max77620_wdt.c +++ b/drivers/watchdog/max77620_wdt.c @@ -205,6 +205,7 @@ static struct platform_device_id max77620_wdt_devtype[] = { { .name = "max77620-watchdog", }, { }, }; +MODULE_DEVICE_TABLE(platform, max77620_wdt_devtype); static struct platform_driver max77620_wdt_driver = { .driver = { -- cgit v1.2.3 From 0f3871f8a535d7e79512fe56f4a5a161b3a03422 Mon Sep 17 00:00:00 2001 From: "Robert P. J. Day" Date: Sun, 16 Oct 2016 08:10:37 -0400 Subject: watchdog: Standardize leading tabs and spaces in Kconfig file Replace small number of lines using leading spaces with proper leading tabs and spaces -- purely an aesthetic fix. Signed-off-by: Robert P. J. Day Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 3eb58cb51e56..ee55dd5f4968 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -72,16 +72,16 @@ config SOFT_WATCHDOG module will be called softdog. config DA9052_WATCHDOG - tristate "Dialog DA9052 Watchdog" - depends on PMIC_DA9052 - select WATCHDOG_CORE - help - Support for the watchdog in the DA9052 PMIC. Watchdog trigger - cause system reset. + tristate "Dialog DA9052 Watchdog" + depends on PMIC_DA9052 + select WATCHDOG_CORE + help + Support for the watchdog in the DA9052 PMIC. Watchdog trigger + cause system reset. - Say Y here to include support for the DA9052 watchdog. - Alternatively say M to compile the driver as a module, - which will be called da9052_wdt. + Say Y here to include support for the DA9052 watchdog. + Alternatively say M to compile the driver as a module, + which will be called da9052_wdt. config DA9055_WATCHDOG tristate "Dialog Semiconductor DA9055 Watchdog" @@ -1624,16 +1624,16 @@ config BOOKE_WDT_DEFAULT_TIMEOUT The value can be overridden by the wdt_period command-line parameter. config MEN_A21_WDT - tristate "MEN A21 VME CPU Carrier Board Watchdog Timer" - select WATCHDOG_CORE - depends on GPIOLIB || COMPILE_TEST - help - Watchdog driver for MEN A21 VMEbus CPU Carrier Boards. + tristate "MEN A21 VME CPU Carrier Board Watchdog Timer" + select WATCHDOG_CORE + depends on GPIOLIB || COMPILE_TEST + help + Watchdog driver for MEN A21 VMEbus CPU Carrier Boards. - The driver can also be built as a module. If so, the module will be - called mena21_wdt. + The driver can also be built as a module. If so, the module will be + called mena21_wdt. - If unsure select N here. + If unsure select N here. # PPC64 Architecture -- cgit v1.2.3 From 807f0b2d22b0934fc1c67df8a4961044bd76b081 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Wed, 19 Oct 2016 16:49:42 -0300 Subject: watchdog: meson: Remove unneeded platform MODULE_ALIAS The Amlogic Meson is a DT-only platform, which means the devices are registered via OF and not using the legacy platform devices support. So there's no need to have a MODULE_ALIAS("platform:meson-gxbb-wdt") since the reported uevent MODALIAS to user-space will be the OF one. Signed-off-by: Javier Martinez Canillas Acked-by: Kevin Hilman Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/meson_gxbb_wdt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/meson_gxbb_wdt.c b/drivers/watchdog/meson_gxbb_wdt.c index 44d180a2c5e5..45d47664a00a 100644 --- a/drivers/watchdog/meson_gxbb_wdt.c +++ b/drivers/watchdog/meson_gxbb_wdt.c @@ -264,7 +264,6 @@ static struct platform_driver meson_gxbb_wdt_driver = { module_platform_driver(meson_gxbb_wdt_driver); -MODULE_ALIAS("platform:meson-gxbb-wdt"); MODULE_AUTHOR("Neil Armstrong "); MODULE_DESCRIPTION("Amlogic Meson GXBB Watchdog timer driver"); MODULE_LICENSE("Dual BSD/GPL"); -- cgit v1.2.3 From 9b3865749589d67f612d71b447847223b2321408 Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Thu, 24 Nov 2016 14:58:28 +0200 Subject: watchdog: davinci: add support for deferred probing devm_clk_get can fail with EPROBE_DEFER in case the clock provider is not ready yet. Handle this case gracefully, rather than dumping out a huge warning. Signed-off-by: Tero Kristo Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/davinci_wdt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c index 17454ca653f4..0e731d797a2a 100644 --- a/drivers/watchdog/davinci_wdt.c +++ b/drivers/watchdog/davinci_wdt.c @@ -166,8 +166,12 @@ static int davinci_wdt_probe(struct platform_device *pdev) return -ENOMEM; davinci_wdt->clk = devm_clk_get(dev, NULL); - if (WARN_ON(IS_ERR(davinci_wdt->clk))) + + if (IS_ERR(davinci_wdt->clk)) { + if (PTR_ERR(davinci_wdt->clk) != -EPROBE_DEFER) + dev_err(&pdev->dev, "failed to get clock node\n"); return PTR_ERR(davinci_wdt->clk); + } clk_prepare_enable(davinci_wdt->clk); -- cgit v1.2.3 From f06f35c66fdbd5ac38901a3305ce763a0cd59375 Mon Sep 17 00:00:00 2001 From: Christian Lamparter Date: Mon, 14 Nov 2016 02:11:16 +0100 Subject: watchdog: qcom: fix kernel panic due to external abort on non-linefetch This patch fixes a off-by-one in the "watchdog: qcom: add option for standalone watchdog not in timer block" patch that causes the following panic on boot: > Unhandled fault: external abort on non-linefetch (0x1008) at 0xc8874002 > pgd = c0204000 > [c8874002] *pgd=87806811, *pte=0b017653, *ppte=0b017453 > Internal error: : 1008 [#1] SMP ARM > CPU: 2 PID: 1 Comm: swapper/0 Not tainted 4.8.6 #0 > Hardware name: Generic DT based system > PC is at 0xc02222f4 > LR is at 0x1 > pc : [] lr : [<00000001>] psr: 00000113 > sp : c782fc98 ip : 00000003 fp : 00000000 > r10: 00000004 r9 : c782e000 r8 : c04ab98c > r7 : 00000001 r6 : c8874002 r5 : c782fe00 r4 : 00000002 > r3 : 00000000 r2 : c782fe00 r1 : 00100000 r0 : c8874002 > Flags: nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none > Control: 10c5387d Table: 8020406a DAC: 00000051 > Process swapper/0 (pid: 1, stack limit = 0xc782e210) > Stack: (0xc782fc98 to 0xc7830000) > [...] The WDT_STS (status) needs to be translated via wdt_addr as well. fixes: f0d9d0f4b44a ("watchdog: qcom: add option for standalone watchdog not in timer block") Cc: stable@vger.kernel.org # 4.8 Signed-off-by: Christian Lamparter Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/qcom-wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c index 5796b5d1b3f2..4f47b5e90956 100644 --- a/drivers/watchdog/qcom-wdt.c +++ b/drivers/watchdog/qcom-wdt.c @@ -209,7 +209,7 @@ static int qcom_wdt_probe(struct platform_device *pdev) wdt->wdd.parent = &pdev->dev; wdt->layout = regs; - if (readl(wdt->base + WDT_STS) & 1) + if (readl(wdt_addr(wdt, WDT_STS)) & 1) wdt->wdd.bootstatus = WDIOF_CARDRESET; /* -- cgit v1.2.3 From 35ffa961df7ed13b3701bdb546f08849921e50dc Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 10 Nov 2016 16:02:20 -0800 Subject: watchdog: jz4740: Fix modular build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Compiling this driver as a module causes a build error because a semicolon is missing after MODULE_DEVICE_TABLE. Add it. CC [M] drivers/watchdog/jz4740_wdt.o drivers/watchdog/jz4740_wdt.c:154:1: error: expected ‘,’ or ‘;’ before ‘static’ drivers/watchdog/jz4740_wdt.c:218:11: error: ‘jz4740_wdt_probe’ undeclared here (not in a function) Cc: Zubair Lutfullah Kakakhel Cc: Guenter Roeck Signed-off-by: Stephen Boyd Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/jz4740_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c index c8d51ddb26d5..20627f22baf6 100644 --- a/drivers/watchdog/jz4740_wdt.c +++ b/drivers/watchdog/jz4740_wdt.c @@ -148,7 +148,7 @@ static const struct of_device_id jz4740_wdt_of_matches[] = { { .compatible = "ingenic,jz4740-watchdog", }, { /* sentinel */ } }; -MODULE_DEVICE_TABLE(of, jz4740_wdt_of_matches) +MODULE_DEVICE_TABLE(of, jz4740_wdt_of_matches); #endif static int jz4740_wdt_probe(struct platform_device *pdev) -- cgit v1.2.3 From 9eff1140a82db8c5520f76e51c21827b4af670b3 Mon Sep 17 00:00:00 2001 From: Alexander Usyskin Date: Tue, 8 Nov 2016 17:55:52 +0200 Subject: watchdog: mei_wdt: request stop on reboot to prevent false positive event Systemd on reboot enables shutdown watchdog that leaves the watchdog device open to ensure that even if power down process get stuck the platform reboots nonetheless. The iamt_wdt is an alarm-only watchdog and can't reboot system, but the FW will generate an alarm event reboot was completed in time, as the watchdog is not automatically disabled during power cycle. So we should request stop watchdog on reboot to eliminate wrong alarm from the FW. Cc: Signed-off-by: Alexander Usyskin Signed-off-by: Tomas Winkler Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/mei_wdt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/watchdog/mei_wdt.c b/drivers/watchdog/mei_wdt.c index 630bd189f167..2a9d5cdedea2 100644 --- a/drivers/watchdog/mei_wdt.c +++ b/drivers/watchdog/mei_wdt.c @@ -389,6 +389,8 @@ static int mei_wdt_register(struct mei_wdt *wdt) wdt->wdd.max_timeout = MEI_WDT_MAX_TIMEOUT; watchdog_set_drvdata(&wdt->wdd, wdt); + watchdog_stop_on_reboot(&wdt->wdd); + ret = watchdog_register_device(&wdt->wdd); if (ret) { dev_err(dev, "unable to register watchdog device = %d.\n", ret); -- cgit v1.2.3 From 31ecad65b011d64dfc80cab7c968078171aa2642 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Nov 2016 16:50:02 +0200 Subject: intel-mid_wdt: make sure watchdog is not running at startup Make sure that the watchdog is not running after loading and before it is started by opening /dev/watchdog. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/intel-mid_wdt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index db36d12e2b52..ff099a36d0c8 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -151,6 +151,9 @@ static int mid_wdt_probe(struct platform_device *pdev) return ret; } + /* Make sure the watchdog is not running */ + wdt_stop(wdt_dev); + ret = watchdog_register_device(wdt_dev); if (ret) { dev_err(&pdev->dev, "error registering watchdog device\n"); -- cgit v1.2.3 From bb79036215e2ca9d7ef5bd1461981396989c40da Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 18 Nov 2016 17:24:41 +0200 Subject: intel-mid_wdt: Error code is just an integer Error code when printed is more readable if it's represented as plain decimal integer. Otherwise user will see something like intel_mid_wdt: Error stopping watchdog: 0xffffffed which is not quite understandable ("Should I interpret it as a bitfield?"). Make it clear to use plaint integer specifier. While here, move struct device *dev local variable definition to the top of functions. Signed-off-by: Andy Shevchenko Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/intel-mid_wdt.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/intel-mid_wdt.c b/drivers/watchdog/intel-mid_wdt.c index ff099a36d0c8..a4b729259b12 100644 --- a/drivers/watchdog/intel-mid_wdt.c +++ b/drivers/watchdog/intel-mid_wdt.c @@ -43,6 +43,7 @@ static inline int wdt_command(int sub, u32 *in, int inlen) static int wdt_start(struct watchdog_device *wd) { + struct device *dev = watchdog_get_drvdata(wd); int ret, in_size; int timeout = wd->timeout; struct ipc_wd_start { @@ -57,36 +58,32 @@ static int wdt_start(struct watchdog_device *wd) in_size = DIV_ROUND_UP(sizeof(ipc_wd_start), 4); ret = wdt_command(SCU_WATCHDOG_START, (u32 *)&ipc_wd_start, in_size); - if (ret) { - struct device *dev = watchdog_get_drvdata(wd); + if (ret) dev_crit(dev, "error starting watchdog: %d\n", ret); - } return ret; } static int wdt_ping(struct watchdog_device *wd) { + struct device *dev = watchdog_get_drvdata(wd); int ret; ret = wdt_command(SCU_WATCHDOG_KEEPALIVE, NULL, 0); - if (ret) { - struct device *dev = watchdog_get_drvdata(wd); - dev_crit(dev, "Error executing keepalive: 0x%x\n", ret); - } + if (ret) + dev_crit(dev, "Error executing keepalive: %d\n", ret); return ret; } static int wdt_stop(struct watchdog_device *wd) { + struct device *dev = watchdog_get_drvdata(wd); int ret; ret = wdt_command(SCU_WATCHDOG_STOP, NULL, 0); - if (ret) { - struct device *dev = watchdog_get_drvdata(wd); - dev_crit(dev, "Error stopping watchdog: 0x%x\n", ret); - } + if (ret) + dev_crit(dev, "Error stopping watchdog: %d\n", ret); return ret; } -- cgit v1.2.3 From 72106c1894aa4e26ab403282cc7617fcb07d3d4d Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Mon, 14 Nov 2016 08:22:45 +0000 Subject: watchdog: da9062/61: watchdog driver The of_device_id match array is added to support "dlg,da9062-watchdog" as a valid .compatible string. A MODULE_DEVICE_TABLE() macro is added. This patch assumes the use of a DA9062 fallback compatible string for the DTS to pick up the DA9062 device driver for use with the DA9061 watchdog hardware Copyright header is updated to add DA9061 in its description and the module description macro is extended to include DA9061. Kconfig is updated to reflect support for DA9061/62. Reviewed-by: Guenter Roeck Signed-off-by: Steve Twiss Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 4 ++-- drivers/watchdog/da9062_wdt.c | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index ee55dd5f4968..a05afcbec778 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -104,11 +104,11 @@ config DA9063_WATCHDOG This driver can be built as a module. The module name is da9063_wdt. config DA9062_WATCHDOG - tristate "Dialog DA9062 Watchdog" + tristate "Dialog DA9062/61 Watchdog" depends on MFD_DA9062 select WATCHDOG_CORE help - Support for the watchdog in the DA9062 PMIC. + Support for the watchdog in the DA9062 and DA9061 PMICs. This driver can be built as a module. The module name is da9062_wdt. diff --git a/drivers/watchdog/da9062_wdt.c b/drivers/watchdog/da9062_wdt.c index 7386111220d5..a02cee6820a1 100644 --- a/drivers/watchdog/da9062_wdt.c +++ b/drivers/watchdog/da9062_wdt.c @@ -1,5 +1,5 @@ /* - * da9062_wdt.c - WDT device driver for DA9062 + * Watchdog device driver for DA9062 and DA9061 PMICs * Copyright (C) 2015 Dialog Semiconductor Ltd. * * This program is free software; you can redistribute it and/or @@ -188,6 +188,13 @@ static const struct watchdog_ops da9062_watchdog_ops = { .set_timeout = da9062_wdt_set_timeout, }; +static const struct of_device_id da9062_compatible_id_table[] = { + { .compatible = "dlg,da9062-watchdog", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, da9062_compatible_id_table); + static int da9062_wdt_probe(struct platform_device *pdev) { int ret; @@ -244,11 +251,12 @@ static struct platform_driver da9062_wdt_driver = { .remove = da9062_wdt_remove, .driver = { .name = "da9062-watchdog", + .of_match_table = da9062_compatible_id_table, }, }; module_platform_driver(da9062_wdt_driver); MODULE_AUTHOR("S Twiss "); -MODULE_DESCRIPTION("WDT device driver for Dialog DA9062"); +MODULE_DESCRIPTION("WDT device driver for Dialog DA9062 and DA9061"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:da9062-watchdog"); -- cgit v1.2.3 From b6621df5c87603310c3f94903bb30adbfeb9aa69 Mon Sep 17 00:00:00 2001 From: Amit Kushwaha Date: Tue, 6 Dec 2016 10:19:48 -0800 Subject: watchdog: cpwd: remove memory allocate failure message Replaced goto with a return statement and dropped the kfree() calls because memory allocated with devm_kzalloc() is automatically freed on driver detach Signed-off-by: Amit Kushwaha Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/cpwd.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 71ee07950e63..3d43775548e5 100644 --- a/drivers/watchdog/cpwd.c +++ b/drivers/watchdog/cpwd.c @@ -538,12 +538,9 @@ static int cpwd_probe(struct platform_device *op) if (cpwd_device) return -EINVAL; - p = kzalloc(sizeof(*p), GFP_KERNEL); - err = -ENOMEM; - if (!p) { - pr_err("Unable to allocate struct cpwd\n"); - goto out; - } + p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; p->irq = op->archdata.irqs[0]; @@ -553,12 +550,12 @@ static int cpwd_probe(struct platform_device *op) 4 * WD_TIMER_REGSZ, DRIVER_NAME); if (!p->regs) { pr_err("Unable to map registers\n"); - goto out_free; + return -ENOMEM; } options = of_find_node_by_path("/options"); - err = -ENODEV; if (!options) { + err = -ENODEV; pr_err("Unable to find /options node\n"); goto out_iounmap; } @@ -620,10 +617,7 @@ static int cpwd_probe(struct platform_device *op) platform_set_drvdata(op, p); cpwd_device = p; - err = 0; - -out: - return err; + return 0; out_unregister: for (i--; i >= 0; i--) @@ -632,9 +626,7 @@ out_unregister: out_iounmap: of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); -out_free: - kfree(p); - goto out; + return err; } static int cpwd_remove(struct platform_device *op) @@ -659,7 +651,6 @@ static int cpwd_remove(struct platform_device *op) free_irq(p->irq, p); of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ); - kfree(p); cpwd_device = NULL; -- cgit v1.2.3 From 1d8565ee4f5bd9fccb738e53d6b9fc7a559f7d2b Mon Sep 17 00:00:00 2001 From: Yang Ling Date: Thu, 8 Dec 2016 00:10:58 +0800 Subject: watchdog: loongson1: Add Loongson1 SoC watchdog driver Add watchdog timer specific driver for Loongson1 SoC. Signed-off-by: Yang Ling Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 7 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/loongson1_wdt.c | 170 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 drivers/watchdog/loongson1_wdt.c (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index a05afcbec778..f1de1214f10f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1514,6 +1514,13 @@ config LANTIQ_WDT help Hardware driver for the Lantiq SoC Watchdog Timer. +config LOONGSON1_WDT + tristate "Loongson1 SoC hardware watchdog" + depends on MACH_LOONGSON32 + select WATCHDOG_CORE + help + Hardware driver for the Loongson1 SoC Watchdog Timer. + config RALINK_WDT tristate "Ralink SoC watchdog" select WATCHDOG_CORE diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index caa9f4aa492a..0c3d35e3c334 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -163,6 +163,7 @@ obj-$(CONFIG_TXX9_WDT) += txx9wdt.o obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o +obj-$(CONFIG_LOONGSON1_WDT) += loongson1_wdt.o obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o obj-$(CONFIG_MT7621_WDT) += mt7621_wdt.o diff --git a/drivers/watchdog/loongson1_wdt.c b/drivers/watchdog/loongson1_wdt.c new file mode 100644 index 000000000000..3aee50c64a36 --- /dev/null +++ b/drivers/watchdog/loongson1_wdt.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2016 Yang Ling + * + * 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 + +#define DEFAULT_HEARTBEAT 30 + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0444); + +static unsigned int heartbeat; +module_param(heartbeat, uint, 0444); + +struct ls1x_wdt_drvdata { + void __iomem *base; + struct clk *clk; + unsigned long clk_rate; + struct watchdog_device wdt; +}; + +static int ls1x_wdt_ping(struct watchdog_device *wdt_dev) +{ + struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); + + writel(0x1, drvdata->base + WDT_SET); + + return 0; +} + +static int ls1x_wdt_set_timeout(struct watchdog_device *wdt_dev, + unsigned int timeout) +{ + struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); + unsigned int max_hw_heartbeat = wdt_dev->max_hw_heartbeat_ms / 1000; + unsigned int counts; + + wdt_dev->timeout = timeout; + + counts = drvdata->clk_rate * min(timeout, max_hw_heartbeat); + writel(counts, drvdata->base + WDT_TIMER); + + return 0; +} + +static int ls1x_wdt_start(struct watchdog_device *wdt_dev) +{ + struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); + + writel(0x1, drvdata->base + WDT_EN); + + return 0; +} + +static int ls1x_wdt_stop(struct watchdog_device *wdt_dev) +{ + struct ls1x_wdt_drvdata *drvdata = watchdog_get_drvdata(wdt_dev); + + writel(0x0, drvdata->base + WDT_EN); + + return 0; +} + +static const struct watchdog_info ls1x_wdt_info = { + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, + .identity = "Loongson1 Watchdog", +}; + +static const struct watchdog_ops ls1x_wdt_ops = { + .owner = THIS_MODULE, + .start = ls1x_wdt_start, + .stop = ls1x_wdt_stop, + .ping = ls1x_wdt_ping, + .set_timeout = ls1x_wdt_set_timeout, +}; + +static int ls1x_wdt_probe(struct platform_device *pdev) +{ + struct ls1x_wdt_drvdata *drvdata; + struct watchdog_device *ls1x_wdt; + unsigned long clk_rate; + struct resource *res; + int err; + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + drvdata->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(drvdata->base)) + return PTR_ERR(drvdata->base); + + drvdata->clk = devm_clk_get(&pdev->dev, pdev->name); + if (IS_ERR(drvdata->clk)) + return PTR_ERR(drvdata->clk); + + err = clk_prepare_enable(drvdata->clk); + if (err) { + dev_err(&pdev->dev, "clk enable failed\n"); + return err; + } + + clk_rate = clk_get_rate(drvdata->clk); + if (!clk_rate) { + err = -EINVAL; + goto err0; + } + drvdata->clk_rate = clk_rate; + + ls1x_wdt = &drvdata->wdt; + ls1x_wdt->info = &ls1x_wdt_info; + ls1x_wdt->ops = &ls1x_wdt_ops; + ls1x_wdt->timeout = DEFAULT_HEARTBEAT; + ls1x_wdt->min_timeout = 1; + ls1x_wdt->max_hw_heartbeat_ms = U32_MAX / clk_rate * 1000; + ls1x_wdt->parent = &pdev->dev; + + watchdog_init_timeout(ls1x_wdt, heartbeat, &pdev->dev); + watchdog_set_nowayout(ls1x_wdt, nowayout); + watchdog_set_drvdata(ls1x_wdt, drvdata); + + err = watchdog_register_device(&drvdata->wdt); + if (err) { + dev_err(&pdev->dev, "failed to register watchdog device\n"); + goto err0; + } + + platform_set_drvdata(pdev, drvdata); + + dev_info(&pdev->dev, "Loongson1 Watchdog driver registered\n"); + + return 0; +err0: + clk_disable_unprepare(drvdata->clk); + return err; +} + +static int ls1x_wdt_remove(struct platform_device *pdev) +{ + struct ls1x_wdt_drvdata *drvdata = platform_get_drvdata(pdev); + + watchdog_unregister_device(&drvdata->wdt); + clk_disable_unprepare(drvdata->clk); + + return 0; +} + +static struct platform_driver ls1x_wdt_driver = { + .probe = ls1x_wdt_probe, + .remove = ls1x_wdt_remove, + .driver = { + .name = "ls1x-wdt", + }, +}; + +module_platform_driver(ls1x_wdt_driver); + +MODULE_AUTHOR("Yang Ling "); +MODULE_DESCRIPTION("Loongson1 Watchdog Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 054ae19422859c394d5f26a8756ed57d332f6284 Mon Sep 17 00:00:00 2001 From: Rasmus Villemoes Date: Mon, 12 Dec 2016 10:48:43 +0100 Subject: watchdog: bcm2835_wdt: set WDOG_HW_RUNNING bit when appropriate A bootloader may start the watchdog device before handing control to the kernel - in that case, we should tell the kernel about it so the watchdog framework can keep it alive until userspace opens /dev/watchdog0. Signed-off-by: Rasmus Villemoes Reviewed-by: Guenter Roeck Acked-by: Eric Anholt Signed-off-by: Guenter Roeck --- drivers/watchdog/bcm2835_wdt.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c index 4dddd8298a22..c32c45bd8b09 100644 --- a/drivers/watchdog/bcm2835_wdt.c +++ b/drivers/watchdog/bcm2835_wdt.c @@ -55,6 +55,15 @@ struct bcm2835_wdt { static unsigned int heartbeat; static bool nowayout = WATCHDOG_NOWAYOUT; +static bool bcm2835_wdt_is_running(struct bcm2835_wdt *wdt) +{ + uint32_t cur; + + cur = readl(wdt->base + PM_RSTC); + + return !!(cur & PM_RSTC_WRCFG_FULL_RESET); +} + static int bcm2835_wdt_start(struct watchdog_device *wdog) { struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); @@ -181,6 +190,17 @@ static int bcm2835_wdt_probe(struct platform_device *pdev) watchdog_init_timeout(&bcm2835_wdt_wdd, heartbeat, dev); watchdog_set_nowayout(&bcm2835_wdt_wdd, nowayout); bcm2835_wdt_wdd.parent = &pdev->dev; + if (bcm2835_wdt_is_running(wdt)) { + /* + * The currently active timeout value (set by the + * bootloader) may be different from the module + * heartbeat parameter or the value in device + * tree. But we just need to set WDOG_HW_RUNNING, + * because then the framework will "immediately" ping + * the device, updating the timeout. + */ + set_bit(WDOG_HW_RUNNING, &bcm2835_wdt_wdd.status); + } err = watchdog_register_device(&bcm2835_wdt_wdd); if (err) { dev_err(dev, "Failed to register watchdog device"); -- cgit v1.2.3 From 724284a323c4cdea6c1bb1448247ffc858f2bd1d Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 15 Dec 2016 18:49:29 +0100 Subject: watchdog: octeon: Remove unneeded linux/miscdevice.h include watchdog/octeon-wdt-main.c does not use any miscdevice so this patch remove this unnecessary inclusion. Signed-off-by: Corentin Labbe Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/octeon-wdt-main.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/octeon-wdt-main.c b/drivers/watchdog/octeon-wdt-main.c index b55981f88a08..8b4fa4df3fc1 100644 --- a/drivers/watchdog/octeon-wdt-main.c +++ b/drivers/watchdog/octeon-wdt-main.c @@ -56,7 +56,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include #include #include #include -- cgit v1.2.3 From f01d74cc5a2aefa0ba16e2821086a1f2d0a2c899 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 15 Dec 2016 19:03:44 +0100 Subject: watchdog: mpc8xxx: Remove unneeded linux/miscdevice.h include watchdog/mpc8xxx_wdt.c does not use any miscdevice so this patch remove this unnecessary inclusion. Signed-off-by: Corentin Labbe Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/mpc8xxx_wdt.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 5f2273aac37d..366e5c7e650b 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 067161281f428aa7c6e153e06aab7b5fe1ed1e98 Mon Sep 17 00:00:00 2001 From: "Maciej S. Szmigiero" Date: Thu, 15 Dec 2016 23:52:36 +0100 Subject: watchdog: it87_wdt: add IT8620E ID This adds IT8620E chip ID to it87_wdt driver. Such chip is often found on current Gigabyte motherboards, it is allegedly custom made for this manufacturer. Upon testing it looks like it has a 16-bit timer and cannot be reset via game port (only via CIR), so it is similar to IT87{18,20,21,28,83} chips. Tested on GA-F2A88XM-HD3P board. Signed-off-by: Maciej S. Szmigiero Reviewed-by: Guenter Roeck Signed-off-by: Guenter Roeck --- drivers/watchdog/Kconfig | 4 ++-- drivers/watchdog/it87_wdt.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f1de1214f10f..acb00b53a520 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -1008,8 +1008,8 @@ config IT87_WDT tristate "IT87 Watchdog Timer" depends on X86 ---help--- - This is the driver for the hardware watchdog on the ITE IT8702, - IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728 + This is the driver for the hardware watchdog on the ITE IT8620, + IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728 Super I/O chips. If the driver does not work, then make sure that the game port in diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c index e54839b12650..b9878c41598f 100644 --- a/drivers/watchdog/it87_wdt.c +++ b/drivers/watchdog/it87_wdt.c @@ -12,7 +12,7 @@ * http://www.ite.com.tw/ * * Support of the watchdog timers, which are available on - * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, + * IT8620, IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, * IT8728 and IT8783. * * This program is free software; you can redistribute it and/or @@ -78,6 +78,7 @@ /* Chip Id numbers */ #define NO_DEV_ID 0xffff +#define IT8620_ID 0x8620 #define IT8702_ID 0x8702 #define IT8705_ID 0x8705 #define IT8712_ID 0x8712 @@ -630,6 +631,7 @@ static int __init it87_wdt_init(void) case IT8726_ID: max_units = 65535; break; + case IT8620_ID: case IT8718_ID: case IT8720_ID: case IT8721_ID: -- cgit v1.2.3 From 868f036fee4b1f934117197fb93461d2c968ffec Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 16 Dec 2016 08:10:31 -0800 Subject: libnvdimm: fix mishandled nvdimm_clear_poison() return value Colin, via static analysis, reports that the length could be negative from nvdimm_clear_poison() in the error case. There was a similar problem with commit 0a3f27b9a6a8 "libnvdimm, namespace: avoid multiple sector calculations" that I noticed when merging the for-4.10/libnvdimm topic branch into libnvdimm-for-next, but I missed this one. Fix both of them to the following procedure: * if we clear a block's worth of media, clear that many blocks in badblocks * if we clear less than the requested size of the transfer return an error * always invalidate cache after any non-error / non-zero nvdimm_clear_poison result Fixes: 82bf1037f2ca ("libnvdimm: check and clear poison before writing to pmem") Fixes: 0a3f27b9a6a8 ("libnvdimm, namespace: avoid multiple sector calculations") Cc: Fabian Frederick Cc: Dave Jiang Reported-by: Colin Ian King Signed-off-by: Dan Williams --- drivers/nvdimm/claim.c | 9 +++++---- drivers/nvdimm/pmem.c | 21 ++++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index 97d1772774a8..b3323c0697f6 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -247,12 +247,13 @@ static int nsio_rw_bytes(struct nd_namespace_common *ndns, long cleared; cleared = nvdimm_clear_poison(&ndns->dev, offset, size); - if (cleared != size) { - size = cleared; + if (cleared < size) rc = -EIO; + if (cleared > 0 && cleared / 512) { + cleared /= 512; + badblocks_clear(&nsio->bb, sector, cleared); } - - badblocks_clear(&nsio->bb, sector, cleared >> 9); + invalidate_pmem(nsio->addr + offset, size); } else rc = -EIO; } diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index bcc359a4e64d..ecf79fd64517 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -47,22 +47,29 @@ static struct nd_region *to_region(struct pmem_device *pmem) return to_nd_region(to_dev(pmem)->parent); } -static void pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, +static int pmem_clear_poison(struct pmem_device *pmem, phys_addr_t offset, unsigned int len) { struct device *dev = to_dev(pmem); - sector_t sector, cleared; + sector_t sector; + long cleared; + int rc = 0; sector = (offset - pmem->data_offset) / 512; - cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len) / 512; - if (cleared) { - dev_dbg(dev, "%s: %#llx clear %ld sector%s\n", - __func__, (unsigned long long) sector, - cleared, cleared > 1 ? "s" : ""); + cleared = nvdimm_clear_poison(dev, pmem->phys_addr + offset, len); + if (cleared < len) + rc = -EIO; + if (cleared > 0 && cleared / 512) { + cleared /= 512; + dev_dbg(dev, "%s: %#llx clear %ld sector%s\n", __func__, + (unsigned long long) sector, cleared, + cleared > 1 ? "s" : ""); badblocks_clear(&pmem->bb, sector, cleared); } invalidate_pmem(pmem->virt_addr + offset, len); + + return rc; } static void write_pmem(void *pmem_addr, struct page *page, -- cgit v1.2.3 From e28ceeb10cd1883a4b6528c17a2b1f2024e35cad Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Sun, 11 Dec 2016 18:31:22 +0100 Subject: net/3com/3c515: Fix timer handling, prevent leaks and crashes The timer handling in this driver is broken in several ways: - corkscrew_open() initializes and arms a timer before requesting the device interrupt. If the request fails the timer stays armed. A second call to corkscrew_open will unconditionally reinitialize the quued timer and arm it again. Also a immediate device removal will leave the timer queued because close() is not called (open() failed) and therefore nothing issues del_timer(). The reinitialization corrupts the link chain in the timer wheel hash bucket and causes a NULL pointer dereference when the timer wheel tries to operate on that hash bucket. Immediate device removal lets the link chain poke into freed and possibly reused memory. Solution: Arm the timer after the successful irq request. - corkscrew_close() uses del_timer() On close the timer is disarmed with del_timer() which lets the following code race against a concurrent timer expiry function. Solution: Use del_timer_sync() instead - corkscrew_close() calls del_timer() unconditionally del_timer() is invoked even if the timer was never initialized. This works by chance because the struct containing the timer is zeroed at allocation time. Solution: Move the setup of the timer into corkscrew_setup(). Reported-by: Matthew Whitehead Signed-off-by: Thomas Gleixner Cc: Andy Lutomirski Cc: netdev@vger.kernel.org Signed-off-by: David S. Miller --- drivers/net/ethernet/3com/3c515.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c index b9f4c463e516..be5b80103bec 100644 --- a/drivers/net/ethernet/3com/3c515.c +++ b/drivers/net/ethernet/3com/3c515.c @@ -627,6 +627,8 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, spin_lock_init(&vp->lock); + setup_timer(&vp->timer, corkscrew_timer, (unsigned long) dev); + /* Read the station address from the EEPROM. */ EL3WINDOW(0); for (i = 0; i < 0x18; i++) { @@ -707,6 +709,7 @@ static int corkscrew_open(struct net_device *dev) { int ioaddr = dev->base_addr; struct corkscrew_private *vp = netdev_priv(dev); + bool armtimer = false; __u32 config; int i; @@ -731,12 +734,7 @@ static int corkscrew_open(struct net_device *dev) if (corkscrew_debug > 1) pr_debug("%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); - - init_timer(&vp->timer); - vp->timer.expires = jiffies + media_tbl[dev->if_port].wait; - vp->timer.data = (unsigned long) dev; - vp->timer.function = corkscrew_timer; /* timer handler */ - add_timer(&vp->timer); + armtimer = true; } else dev->if_port = vp->default_media; @@ -776,6 +774,9 @@ static int corkscrew_open(struct net_device *dev) return -EAGAIN; } + if (armtimer) + mod_timer(&vp->timer, jiffies + media_tbl[dev->if_port].wait); + if (corkscrew_debug > 1) { EL3WINDOW(4); pr_debug("%s: corkscrew_open() irq %d media status %4.4x.\n", @@ -1426,7 +1427,7 @@ static int corkscrew_close(struct net_device *dev) dev->name, rx_nocopy, rx_copy, queued_packet); } - del_timer(&vp->timer); + del_timer_sync(&vp->timer); /* Turn off statistics ASAP. We update lp->stats below. */ outw(StatsDisable, ioaddr + EL3_CMD); -- cgit v1.2.3 From 66e2809dd324f0ab5e1f9d997b40d4d31a2e42b1 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sun, 11 Dec 2016 21:07:19 +0100 Subject: net: dsa: mv88e6xxx: Fix opps when adding vlan bridge A port is not necessarily assigned to a netdev. And a port does not need to be a member of a bridge. So when iterating over all ports, check before using the netdev and bridge_dev for a port. Otherwise we dereference a NULL pointer. Fixes: da9c359e19f0 ("net: dsa: mv88e6xxx: check hardware VLAN in use") Signed-off-by: Andrew Lunn Reviewed-by: Vivien Didelot Signed-off-by: David S. Miller --- drivers/net/dsa/mv88e6xxx/chip.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 4da379f28d5d..f7222dc6581d 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -1775,6 +1775,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, if (dsa_is_dsa_port(ds, i) || dsa_is_cpu_port(ds, i)) continue; + if (!ds->ports[port].netdev) + continue; + if (vlan.data[i] == GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) continue; @@ -1783,6 +1786,9 @@ static int mv88e6xxx_port_check_hw_vlan(struct dsa_switch *ds, int port, chip->ports[port].bridge_dev) break; /* same bridge, check next VLAN */ + if (!chip->ports[i].bridge_dev) + continue; + netdev_warn(ds->ports[port].netdev, "hardware VLAN %d already used by %s\n", vlan.vid, -- cgit v1.2.3 From 2087d421a5a1af4883e3cf0afb93823b7e12132a Mon Sep 17 00:00:00 2001 From: Dongpo Li Date: Mon, 12 Dec 2016 20:03:42 +0800 Subject: net: ethernet: hisi_femac: Call SET_NETDEV_DEV() The hisi_femac driver calls into PHYLIB which now checks for net_device->dev.parent, so make sure we do set it before calling into any MDIO/PHYLIB related function. Fixes: ec988ad78ed6 ("phy: Don't increment MDIO bus refcount unless it's a different owner") Signed-off-by: Dongpo Li Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hisi_femac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/hisilicon/hisi_femac.c b/drivers/net/ethernet/hisilicon/hisi_femac.c index 49863068c59e..979852d56f31 100644 --- a/drivers/net/ethernet/hisilicon/hisi_femac.c +++ b/drivers/net/ethernet/hisilicon/hisi_femac.c @@ -805,6 +805,7 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) return -ENOMEM; platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); priv = netdev_priv(ndev); priv->dev = dev; @@ -882,7 +883,6 @@ static int hisi_femac_drv_probe(struct platform_device *pdev) ndev->netdev_ops = &hisi_femac_netdev_ops; ndev->ethtool_ops = &hisi_femac_ethtools_ops; netif_napi_add(ndev, &priv->napi, hisi_femac_poll, FEMAC_POLL_WEIGHT); - SET_NETDEV_DEV(ndev, &pdev->dev); hisi_femac_port_init(priv); -- cgit v1.2.3 From 8cd1f70f205a1c684037f06906566ddb3066d659 Mon Sep 17 00:00:00 2001 From: Dongpo Li Date: Mon, 12 Dec 2016 20:03:43 +0800 Subject: net: ethernet: hip04: Call SET_NETDEV_DEV() The hip04 driver calls into PHYLIB which now checks for net_device->dev.parent, so make sure we do set it before calling into any MDIO/PHYLIB related function. Fixes: ec988ad78ed6 ("phy: Don't increment MDIO bus refcount unless it's a different owner") Signed-off-by: Dongpo Li Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/hisilicon/hip04_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c index 854befde0a08..97b184774784 100644 --- a/drivers/net/ethernet/hisilicon/hip04_eth.c +++ b/drivers/net/ethernet/hisilicon/hip04_eth.c @@ -828,6 +828,7 @@ static int hip04_mac_probe(struct platform_device *pdev) priv = netdev_priv(ndev); priv->ndev = ndev; platform_set_drvdata(pdev, ndev); + SET_NETDEV_DEV(ndev, &pdev->dev); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->base = devm_ioremap_resource(d, res); @@ -903,7 +904,6 @@ static int hip04_mac_probe(struct platform_device *pdev) ndev->priv_flags |= IFF_UNICAST_FLT; ndev->irq = irq; netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT); - SET_NETDEV_DEV(ndev, &pdev->dev); hip04_reset_ppe(priv); if (priv->phy_mode == PHY_INTERFACE_MODE_MII) -- cgit v1.2.3 From ebe5236d06abcdb1beb93ffbab73557d5b496824 Mon Sep 17 00:00:00 2001 From: Jeroen De Wachter Date: Mon, 12 Dec 2016 14:29:08 +0100 Subject: encx24j600: bugfix - always move ERXTAIL to next packet in encx24j600_rx_packets Before, encx24j600_rx_packets did not update encx24j600_priv's next_packet member when an error occurred during packet handling (either because the packet's RSV header indicates an error or because the encx24j600_receive_packet method can't allocate an sk_buff). If the next_packet member is not updated, the ERXTAIL register will be set to the same value it had before, which means the bad packet remains in the component's memory and its RSV header will be read again when a new packet arrives. If the RSV header indicates a bad packet or if sk_buff allocation continues to fail, new packets will be stored in the component's memory until that memory is full, after which packets will be dropped. The SETPKTDEC command is always executed though, so the encx24j600 hardware has an incorrect count of the packets in its memory. To prevent this, the next_packet member should always be updated, allowing the packet to be skipped (either because it's bad, as indicated in its RSV header, or because allocating an sk_buff failed). In the allocation failure case, this does mean dropping a valid packet, but dropping the oldest packet to keep as much memory as possible available for new packets seems preferable to keeping old (but valid) packets around while dropping new ones. Signed-off-by: Jeroen De Wachter Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/encx24j600.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/microchip/encx24j600.c b/drivers/net/ethernet/microchip/encx24j600.c index b14f0305aa31..5251aa3cf4d7 100644 --- a/drivers/net/ethernet/microchip/encx24j600.c +++ b/drivers/net/ethernet/microchip/encx24j600.c @@ -346,7 +346,6 @@ static int encx24j600_receive_packet(struct encx24j600_priv *priv, /* Maintain stats */ dev->stats.rx_packets++; dev->stats.rx_bytes += rsv->len; - priv->next_packet = rsv->next_packet; netif_rx(skb); @@ -383,6 +382,8 @@ static void encx24j600_rx_packets(struct encx24j600_priv *priv, u8 packet_count) encx24j600_receive_packet(priv, &rsv); } + priv->next_packet = rsv.next_packet; + newrxtail = priv->next_packet - 2; if (newrxtail == ENC_RX_BUF_START) newrxtail = SRAM_SIZE - 2; -- cgit v1.2.3 From b822ee6c5e5ba1f695fc514a65849cdd87618bd3 Mon Sep 17 00:00:00 2001 From: Jeroen De Wachter Date: Mon, 12 Dec 2016 14:29:09 +0100 Subject: encx24j600: Fix some checkstyle warnings Signed-off-by: Jeroen De Wachter Signed-off-by: David S. Miller --- drivers/net/ethernet/microchip/encx24j600-regmap.c | 17 +++++++++++------ drivers/net/ethernet/microchip/encx24j600.c | 16 ++++++++++++++-- 2 files changed, 25 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/microchip/encx24j600-regmap.c b/drivers/net/ethernet/microchip/encx24j600-regmap.c index f3bb9055a292..44bb04d4d21b 100644 --- a/drivers/net/ethernet/microchip/encx24j600-regmap.c +++ b/drivers/net/ethernet/microchip/encx24j600-regmap.c @@ -26,11 +26,11 @@ static inline bool is_bits_set(int value, int mask) } static int encx24j600_switch_bank(struct encx24j600_context *ctx, - int bank) + int bank) { int ret = 0; - int bank_opcode = BANK_SELECT(bank); + ret = spi_write(ctx->spi, &bank_opcode, 1); if (ret == 0) ctx->bank = bank; @@ -39,7 +39,7 @@ static int encx24j600_switch_bank(struct encx24j600_context *ctx, } static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode, - const void *buf, size_t len) + const void *buf, size_t len) { struct spi_message m; struct spi_transfer t[2] = { { .tx_buf = &opcode, .len = 1, }, @@ -54,12 +54,14 @@ static int encx24j600_cmdn(struct encx24j600_context *ctx, u8 opcode, static void regmap_lock_mutex(void *context) { struct encx24j600_context *ctx = context; + mutex_lock(&ctx->mutex); } static void regmap_unlock_mutex(void *context) { struct encx24j600_context *ctx = context; + mutex_unlock(&ctx->mutex); } @@ -128,6 +130,7 @@ static int regmap_encx24j600_sfr_update(struct encx24j600_context *ctx, if (reg < 0x80) { int ret = 0; + cmd = banked_code | banked_reg; if ((banked_reg < 0x16) && (ctx->bank != bank)) ret = encx24j600_switch_bank(ctx, bank); @@ -174,6 +177,7 @@ static int regmap_encx24j600_sfr_write(void *context, u8 reg, u8 *val, size_t len) { struct encx24j600_context *ctx = context; + return regmap_encx24j600_sfr_update(ctx, reg, val, len, WCRU, WCRCODE); } @@ -228,9 +232,9 @@ int regmap_encx24j600_spi_write(void *context, u8 reg, const u8 *data, if (reg < 0xc0) return encx24j600_cmdn(ctx, reg, data, count); - else - /* SPI 1-byte command. Ignore data */ - return spi_write(ctx->spi, ®, 1); + + /* SPI 1-byte command. Ignore data */ + return spi_write(ctx->spi, ®, 1); } EXPORT_SYMBOL_GPL(regmap_encx24j600_spi_write); @@ -495,6 +499,7 @@ static struct regmap_config phycfg = { .writeable_reg = encx24j600_phymap_writeable, .volatile_reg = encx24j600_phymap_volatile, }; + static struct regmap_bus phymap_encx24j600 = { .reg_write = regmap_encx24j600_phy_reg_write, .reg_read = regmap_encx24j600_phy_reg_read, diff --git a/drivers/net/ethernet/microchip/encx24j600.c b/drivers/net/ethernet/microchip/encx24j600.c index 5251aa3cf4d7..fbce6166504e 100644 --- a/drivers/net/ethernet/microchip/encx24j600.c +++ b/drivers/net/ethernet/microchip/encx24j600.c @@ -30,7 +30,7 @@ #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) static int debug = -1; -module_param(debug, int, 0); +module_param(debug, int, 0000); MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); /* SRAM memory layout: @@ -105,6 +105,7 @@ static u16 encx24j600_read_reg(struct encx24j600_priv *priv, u8 reg) struct net_device *dev = priv->ndev; unsigned int val = 0; int ret = regmap_read(priv->ctx.regmap, reg, &val); + if (unlikely(ret)) netif_err(priv, drv, dev, "%s: error %d reading reg %02x\n", __func__, ret, reg); @@ -115,6 +116,7 @@ static void encx24j600_write_reg(struct encx24j600_priv *priv, u8 reg, u16 val) { struct net_device *dev = priv->ndev; int ret = regmap_write(priv->ctx.regmap, reg, val); + if (unlikely(ret)) netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n", __func__, ret, reg, val); @@ -125,6 +127,7 @@ static void encx24j600_update_reg(struct encx24j600_priv *priv, u8 reg, { struct net_device *dev = priv->ndev; int ret = regmap_update_bits(priv->ctx.regmap, reg, mask, val); + if (unlikely(ret)) netif_err(priv, drv, dev, "%s: error %d updating reg %02x=%04x~%04x\n", __func__, ret, reg, val, mask); @@ -135,6 +138,7 @@ static u16 encx24j600_read_phy(struct encx24j600_priv *priv, u8 reg) struct net_device *dev = priv->ndev; unsigned int val = 0; int ret = regmap_read(priv->ctx.phymap, reg, &val); + if (unlikely(ret)) netif_err(priv, drv, dev, "%s: error %d reading %02x\n", __func__, ret, reg); @@ -145,6 +149,7 @@ static void encx24j600_write_phy(struct encx24j600_priv *priv, u8 reg, u16 val) { struct net_device *dev = priv->ndev; int ret = regmap_write(priv->ctx.phymap, reg, val); + if (unlikely(ret)) netif_err(priv, drv, dev, "%s: error %d writing reg %02x=%04x\n", __func__, ret, reg, val); @@ -164,6 +169,7 @@ static void encx24j600_cmd(struct encx24j600_priv *priv, u8 cmd) { struct net_device *dev = priv->ndev; int ret = regmap_write(priv->ctx.regmap, cmd, 0); + if (unlikely(ret)) netif_err(priv, drv, dev, "%s: error %d with cmd %02x\n", __func__, ret, cmd); @@ -173,6 +179,7 @@ static int encx24j600_raw_read(struct encx24j600_priv *priv, u8 reg, u8 *data, size_t count) { int ret; + mutex_lock(&priv->ctx.mutex); ret = regmap_encx24j600_spi_read(&priv->ctx, reg, data, count); mutex_unlock(&priv->ctx.mutex); @@ -184,6 +191,7 @@ static int encx24j600_raw_write(struct encx24j600_priv *priv, u8 reg, const u8 *data, size_t count) { int ret; + mutex_lock(&priv->ctx.mutex); ret = regmap_encx24j600_spi_write(&priv->ctx, reg, data, count); mutex_unlock(&priv->ctx.mutex); @@ -194,6 +202,7 @@ static int encx24j600_raw_write(struct encx24j600_priv *priv, u8 reg, static void encx24j600_update_phcon1(struct encx24j600_priv *priv) { u16 phcon1 = encx24j600_read_phy(priv, PHCON1); + if (priv->autoneg == AUTONEG_ENABLE) { phcon1 |= ANEN | RENEG; } else { @@ -328,6 +337,7 @@ static int encx24j600_receive_packet(struct encx24j600_priv *priv, { struct net_device *dev = priv->ndev; struct sk_buff *skb = netdev_alloc_skb(dev, rsv->len + NET_IP_ALIGN); + if (!skb) { pr_err_ratelimited("RX: OOM: packet dropped\n"); dev->stats.rx_dropped++; @@ -828,6 +838,7 @@ static void encx24j600_set_multicast_list(struct net_device *dev) static void encx24j600_hw_tx(struct encx24j600_priv *priv) { struct net_device *dev = priv->ndev; + netif_info(priv, tx_queued, dev, "TX Packet Len:%d\n", priv->tx_skb->len); @@ -895,7 +906,6 @@ static void encx24j600_tx_timeout(struct net_device *dev) dev->stats.tx_errors++; netif_wake_queue(dev); - return; } static int encx24j600_get_regs_len(struct net_device *dev) @@ -958,12 +968,14 @@ static int encx24j600_set_settings(struct net_device *dev, static u32 encx24j600_get_msglevel(struct net_device *dev) { struct encx24j600_priv *priv = netdev_priv(dev); + return priv->msg_enable; } static void encx24j600_set_msglevel(struct net_device *dev, u32 val) { struct encx24j600_priv *priv = netdev_priv(dev); + priv->msg_enable = val; } -- cgit v1.2.3 From 6613d18e90385db5cdbe32fe47567a3c11575b2d Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Mon, 31 Oct 2016 07:22:33 +0000 Subject: platform/x86: mlx-platform: Move module from arch/x86 Since mlx-platform is not an architectural driver, it is moved out of arch/x86/platform to drivers/platform/x86. Relevant Makefile and Kconfig are updated. Signed-off-by: Vadim Pasternak Acked-by: Thomas Gleixner Signed-off-by: Andy Shevchenko --- MAINTAINERS | 2 +- arch/x86/Kconfig | 12 -- arch/x86/platform/Makefile | 1 - arch/x86/platform/mellanox/Makefile | 1 - arch/x86/platform/mellanox/mlx-platform.c | 266 ------------------------------ drivers/platform/x86/Kconfig | 13 +- drivers/platform/x86/Makefile | 1 + drivers/platform/x86/mlx-platform.c | 265 +++++++++++++++++++++++++++++ 8 files changed, 279 insertions(+), 282 deletions(-) delete mode 100644 arch/x86/platform/mellanox/Makefile delete mode 100644 arch/x86/platform/mellanox/mlx-platform.c create mode 100644 drivers/platform/x86/mlx-platform.c (limited to 'drivers') diff --git a/MAINTAINERS b/MAINTAINERS index 3e30399e715f..960f364f1c94 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7879,7 +7879,7 @@ MELLANOX PLATFORM DRIVER M: Vadim Pasternak L: platform-driver-x86@vger.kernel.org S: Supported -F: arch/x86/platform/mellanox/mlx-platform.c +F: drivers/platform/x86/mlx-platform.c MELLANOX MLX CPLD HOTPLUG DRIVER M: Vadim Pasternak diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index bada636d1065..ccd5ff7d1879 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -550,18 +550,6 @@ config X86_INTEL_QUARK Say Y here if you have a Quark based system such as the Arduino compatible Intel Galileo. -config MLX_PLATFORM - tristate "Mellanox Technologies platform support" - depends on X86_64 - depends on X86_EXTENDED_PLATFORM - ---help--- - This option enables system support for the Mellanox Technologies - platform. - - Say Y here if you are building a kernel for Mellanox system. - - Otherwise, say N. - config X86_INTEL_LPSS bool "Intel Low Power Subsystem Support" depends on X86 && ACPI diff --git a/arch/x86/platform/Makefile b/arch/x86/platform/Makefile index 3c3c19ea94df..184842ef332e 100644 --- a/arch/x86/platform/Makefile +++ b/arch/x86/platform/Makefile @@ -8,7 +8,6 @@ obj-y += iris/ obj-y += intel/ obj-y += intel-mid/ obj-y += intel-quark/ -obj-y += mellanox/ obj-y += olpc/ obj-y += scx200/ obj-y += sfi/ diff --git a/arch/x86/platform/mellanox/Makefile b/arch/x86/platform/mellanox/Makefile deleted file mode 100644 index f43c93188a1d..000000000000 --- a/arch/x86/platform/mellanox/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o diff --git a/arch/x86/platform/mellanox/mlx-platform.c b/arch/x86/platform/mellanox/mlx-platform.c deleted file mode 100644 index 7dcfcca97399..000000000000 --- a/arch/x86/platform/mellanox/mlx-platform.c +++ /dev/null @@ -1,266 +0,0 @@ -/* - * arch/x86/platform/mellanox/mlx-platform.c - * Copyright (c) 2016 Mellanox Technologies. All rights reserved. - * Copyright (c) 2016 Vadim Pasternak - * - * 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. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the names of the copyright holders nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -#define MLX_PLAT_DEVICE_NAME "mlxplat" - -/* LPC bus IO offsets */ -#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 -#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 -#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 -#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb -#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda -#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL -#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ - MLXPLAT_CPLD_LPC_PIO_OFFSET) -#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ - MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ - MLXPLAT_CPLD_LPC_PIO_OFFSET) - -/* Start channel numbers */ -#define MLXPLAT_CPLD_CH1 2 -#define MLXPLAT_CPLD_CH2 10 - -/* Number of LPC attached MUX platform devices */ -#define MLXPLAT_CPLD_LPC_MUX_DEVS 2 - -/* mlxplat_priv - platform private data - * @pdev_i2c - i2c controller platform device - * @pdev_mux - array of mux platform devices - */ -struct mlxplat_priv { - struct platform_device *pdev_i2c; - struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; -}; - -/* Regions for LPC I2C controller and LPC base register space */ -static const struct resource mlxplat_lpc_resources[] = { - [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR, - MLXPLAT_CPLD_LPC_IO_RANGE, - "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), - [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR, - MLXPLAT_CPLD_LPC_IO_RANGE, - "mlxplat_cpld_lpc_regs", - IORESOURCE_IO), -}; - -/* Platform default channels */ -static const int mlxplat_default_channels[][8] = { - { - MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, - MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + - 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7 - }, - { - MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2, - MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 + - 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7 - }, -}; - -/* Platform channels for MSN21xx system family */ -static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; - -/* Platform mux data */ -static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { - { - .parent = 1, - .base_nr = MLXPLAT_CPLD_CH1, - .write_only = 1, - .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, - .reg_size = 1, - .idle_in_use = 1, - }, - { - .parent = 1, - .base_nr = MLXPLAT_CPLD_CH2, - .write_only = 1, - .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, - .reg_size = 1, - .idle_in_use = 1, - }, - -}; - -static struct platform_device *mlxplat_dev; - -static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { - mlxplat_mux_data[i].values = mlxplat_default_channels[i]; - mlxplat_mux_data[i].n_values = - ARRAY_SIZE(mlxplat_default_channels[i]); - } - - return 1; -}; - -static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { - mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; - mlxplat_mux_data[i].n_values = - ARRAY_SIZE(mlxplat_msn21xx_channels); - } - - return 1; -}; - -static struct dmi_system_id mlxplat_dmi_table[] __initdata = { - { - .callback = mlxplat_dmi_default_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), - DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), - }, - }, - { - .callback = mlxplat_dmi_default_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), - DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), - }, - }, - { - .callback = mlxplat_dmi_default_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), - DMI_MATCH(DMI_PRODUCT_NAME, "MSB"), - }, - }, - { - .callback = mlxplat_dmi_default_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), - DMI_MATCH(DMI_PRODUCT_NAME, "MSX"), - }, - }, - { - .callback = mlxplat_dmi_msn21xx_matched, - .matches = { - DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), - DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"), - }, - }, - { } -}; - -static int __init mlxplat_init(void) -{ - struct mlxplat_priv *priv; - int i, err; - - if (!dmi_check_system(mlxplat_dmi_table)) - return -ENODEV; - - mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1, - mlxplat_lpc_resources, - ARRAY_SIZE(mlxplat_lpc_resources)); - - if (IS_ERR(mlxplat_dev)) - return PTR_ERR(mlxplat_dev); - - priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), - GFP_KERNEL); - if (!priv) { - err = -ENOMEM; - goto fail_alloc; - } - platform_set_drvdata(mlxplat_dev, priv); - - priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, - NULL, 0); - if (IS_ERR(priv->pdev_i2c)) { - err = PTR_ERR(priv->pdev_i2c); - goto fail_alloc; - }; - - for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { - priv->pdev_mux[i] = platform_device_register_resndata( - &mlxplat_dev->dev, - "i2c-mux-reg", i, NULL, - 0, &mlxplat_mux_data[i], - sizeof(mlxplat_mux_data[i])); - if (IS_ERR(priv->pdev_mux[i])) { - err = PTR_ERR(priv->pdev_mux[i]); - goto fail_platform_mux_register; - } - } - - return 0; - -fail_platform_mux_register: - for (i--; i > 0 ; i--) - platform_device_unregister(priv->pdev_mux[i]); - platform_device_unregister(priv->pdev_i2c); -fail_alloc: - platform_device_unregister(mlxplat_dev); - - return err; -} -module_init(mlxplat_init); - -static void __exit mlxplat_exit(void) -{ - struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); - int i; - - for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) - platform_device_unregister(priv->pdev_mux[i]); - - platform_device_unregister(priv->pdev_i2c); - platform_device_unregister(mlxplat_dev); -} -module_exit(mlxplat_exit); - -MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); -MODULE_DESCRIPTION("Mellanox platform driver"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); -MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:"); diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 185376901d9c..4639d970f8cb 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1028,10 +1028,21 @@ config INTEL_TELEMETRY directly via debugfs files. Various tools may use this interface for SoC state monitoring. +config MLX_PLATFORM + tristate "Mellanox Technologies platform support" + depends on X86_64 + ---help--- + This option enables system support for the Mellanox Technologies + platform. The Mellanox systems provide data center networking + solutions based on Virtual Protocol Interconnect (VPI) technology + enable seamless connectivity to 56/100Gb/s InfiniBand or 10/40/56GbE + connection. + + If you have a Mellanox system, say Y or M here. + config MLX_CPLD_PLATFORM tristate "Mellanox platform hotplug driver support" default n - depends on MLX_PLATFORM select HWMON select I2C ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 1f06b6339cf7..2d6a587bded5 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -71,4 +71,5 @@ obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ intel_telemetry_debugfs.o obj-$(CONFIG_INTEL_PMC_CORE) += intel_pmc_core.o +obj-$(CONFIG_MLX_PLATFORM) += mlx-platform.o obj-$(CONFIG_MLX_CPLD_PLATFORM) += mlxcpld-hotplug.o diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c new file mode 100644 index 000000000000..bbf60d16faa6 --- /dev/null +++ b/drivers/platform/x86/mlx-platform.c @@ -0,0 +1,265 @@ +/* + * Copyright (c) 2016 Mellanox Technologies. All rights reserved. + * Copyright (c) 2016 Vadim Pasternak + * + * 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. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the names of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * Alternatively, this software may be distributed under the terms of the + * GNU General Public License ("GPL") version 2 as published by the Free + * Software Foundation. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define MLX_PLAT_DEVICE_NAME "mlxplat" + +/* LPC bus IO offsets */ +#define MLXPLAT_CPLD_LPC_I2C_BASE_ADRR 0x2000 +#define MLXPLAT_CPLD_LPC_REG_BASE_ADRR 0x2500 +#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100 +#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb +#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda +#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL +#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ + MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \ + MLXPLAT_CPLD_LPC_PIO_OFFSET) +#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \ + MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \ + MLXPLAT_CPLD_LPC_PIO_OFFSET) + +/* Start channel numbers */ +#define MLXPLAT_CPLD_CH1 2 +#define MLXPLAT_CPLD_CH2 10 + +/* Number of LPC attached MUX platform devices */ +#define MLXPLAT_CPLD_LPC_MUX_DEVS 2 + +/* mlxplat_priv - platform private data + * @pdev_i2c - i2c controller platform device + * @pdev_mux - array of mux platform devices + */ +struct mlxplat_priv { + struct platform_device *pdev_i2c; + struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; +}; + +/* Regions for LPC I2C controller and LPC base register space */ +static const struct resource mlxplat_lpc_resources[] = { + [0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR, + MLXPLAT_CPLD_LPC_IO_RANGE, + "mlxplat_cpld_lpc_i2c_ctrl", IORESOURCE_IO), + [1] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_REG_BASE_ADRR, + MLXPLAT_CPLD_LPC_IO_RANGE, + "mlxplat_cpld_lpc_regs", + IORESOURCE_IO), +}; + +/* Platform default channels */ +static const int mlxplat_default_channels[][8] = { + { + MLXPLAT_CPLD_CH1, MLXPLAT_CPLD_CH1 + 1, MLXPLAT_CPLD_CH1 + 2, + MLXPLAT_CPLD_CH1 + 3, MLXPLAT_CPLD_CH1 + 4, MLXPLAT_CPLD_CH1 + + 5, MLXPLAT_CPLD_CH1 + 6, MLXPLAT_CPLD_CH1 + 7 + }, + { + MLXPLAT_CPLD_CH2, MLXPLAT_CPLD_CH2 + 1, MLXPLAT_CPLD_CH2 + 2, + MLXPLAT_CPLD_CH2 + 3, MLXPLAT_CPLD_CH2 + 4, MLXPLAT_CPLD_CH2 + + 5, MLXPLAT_CPLD_CH2 + 6, MLXPLAT_CPLD_CH2 + 7 + }, +}; + +/* Platform channels for MSN21xx system family */ +static const int mlxplat_msn21xx_channels[] = { 1, 2, 3, 4, 5, 6, 7, 8 }; + +/* Platform mux data */ +static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH1, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1, + .reg_size = 1, + .idle_in_use = 1, + }, + { + .parent = 1, + .base_nr = MLXPLAT_CPLD_CH2, + .write_only = 1, + .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2, + .reg_size = 1, + .idle_in_use = 1, + }, + +}; + +static struct platform_device *mlxplat_dev; + +static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { + mlxplat_mux_data[i].values = mlxplat_default_channels[i]; + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_default_channels[i]); + } + + return 1; +}; + +static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { + mlxplat_mux_data[i].values = mlxplat_msn21xx_channels; + mlxplat_mux_data[i].n_values = + ARRAY_SIZE(mlxplat_msn21xx_channels); + } + + return 1; +}; + +static struct dmi_system_id mlxplat_dmi_table[] __initdata = { + { + .callback = mlxplat_dmi_default_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), + DMI_MATCH(DMI_PRODUCT_NAME, "MSN24"), + }, + }, + { + .callback = mlxplat_dmi_default_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), + DMI_MATCH(DMI_PRODUCT_NAME, "MSN27"), + }, + }, + { + .callback = mlxplat_dmi_default_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), + DMI_MATCH(DMI_PRODUCT_NAME, "MSB"), + }, + }, + { + .callback = mlxplat_dmi_default_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), + DMI_MATCH(DMI_PRODUCT_NAME, "MSX"), + }, + }, + { + .callback = mlxplat_dmi_msn21xx_matched, + .matches = { + DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"), + DMI_MATCH(DMI_PRODUCT_NAME, "MSN21"), + }, + }, + { } +}; + +static int __init mlxplat_init(void) +{ + struct mlxplat_priv *priv; + int i, err; + + if (!dmi_check_system(mlxplat_dmi_table)) + return -ENODEV; + + mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, -1, + mlxplat_lpc_resources, + ARRAY_SIZE(mlxplat_lpc_resources)); + + if (IS_ERR(mlxplat_dev)) + return PTR_ERR(mlxplat_dev); + + priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv), + GFP_KERNEL); + if (!priv) { + err = -ENOMEM; + goto fail_alloc; + } + platform_set_drvdata(mlxplat_dev, priv); + + priv->pdev_i2c = platform_device_register_simple("i2c_mlxcpld", -1, + NULL, 0); + if (IS_ERR(priv->pdev_i2c)) { + err = PTR_ERR(priv->pdev_i2c); + goto fail_alloc; + }; + + for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { + priv->pdev_mux[i] = platform_device_register_resndata( + &mlxplat_dev->dev, + "i2c-mux-reg", i, NULL, + 0, &mlxplat_mux_data[i], + sizeof(mlxplat_mux_data[i])); + if (IS_ERR(priv->pdev_mux[i])) { + err = PTR_ERR(priv->pdev_mux[i]); + goto fail_platform_mux_register; + } + } + + return 0; + +fail_platform_mux_register: + for (i--; i > 0 ; i--) + platform_device_unregister(priv->pdev_mux[i]); + platform_device_unregister(priv->pdev_i2c); +fail_alloc: + platform_device_unregister(mlxplat_dev); + + return err; +} +module_init(mlxplat_init); + +static void __exit mlxplat_exit(void) +{ + struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); + int i; + + for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) + platform_device_unregister(priv->pdev_mux[i]); + + platform_device_unregister(priv->pdev_i2c); + platform_device_unregister(mlxplat_dev); +} +module_exit(mlxplat_exit); + +MODULE_AUTHOR("Vadim Pasternak (vadimp@mellanox.com)"); +MODULE_DESCRIPTION("Mellanox platform driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_ALIAS("dmi:*:*Mellanox*:MSN24*:"); +MODULE_ALIAS("dmi:*:*Mellanox*:MSN27*:"); +MODULE_ALIAS("dmi:*:*Mellanox*:MSB*:"); +MODULE_ALIAS("dmi:*:*Mellanox*:MSX*:"); +MODULE_ALIAS("dmi:*:*Mellanox*:MSN21*:"); -- cgit v1.2.3 From c3886c9d6076555697551da9b921cf6a6e9cc2b5 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 28 Oct 2016 01:26:50 +0800 Subject: platform/x86: mlx-platform: Fix semicolon.cocci warnings drivers/platform/x86/mlx-platform.c:219:2-3: Unneeded semicolon Remove unneeded semicolon. Generated by: scripts/coccinelle/misc/semicolon.cocci CC: Vadim Pasternak Signed-off-by: Fengguang Wu Acked-by: Vadim Pasternak Signed-off-by: Andy Shevchenko --- drivers/platform/x86/mlx-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index bbf60d16faa6..cb6199e6ade0 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -215,7 +215,7 @@ static int __init mlxplat_init(void) if (IS_ERR(priv->pdev_i2c)) { err = PTR_ERR(priv->pdev_i2c); goto fail_alloc; - }; + } for (i = 0; i < ARRAY_SIZE(mlxplat_mux_data); i++) { priv->pdev_mux[i] = platform_device_register_resndata( -- cgit v1.2.3 From afc4715901f0dce3206837a7051af05abf5a1e06 Mon Sep 17 00:00:00 2001 From: Vadim Pasternak Date: Thu, 27 Oct 2016 19:55:54 +0000 Subject: platform/x86: mlx-platform: Add mlxcpld-hotplug driver registration Add calls for mlxcpld-hotplug platform driver registration/unregistration and add platform hotplug data configurations. This driver, when registered within system will handle system hot-plug events for the power suppliers, power cables and fans (insertion and removing). These events are controlled through CPLD Lattice device. Signed-off-by: Vadim Pasternak Signed-off-by: Andy Shevchenko --- drivers/platform/x86/mlx-platform.c | 98 ++++++++++++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c index cb6199e6ade0..97b4c3a219c0 100644 --- a/drivers/platform/x86/mlx-platform.c +++ b/drivers/platform/x86/mlx-platform.c @@ -38,6 +38,7 @@ #include #include #include +#include #define MLX_PLAT_DEVICE_NAME "mlxplat" @@ -69,6 +70,7 @@ struct mlxplat_priv { struct platform_device *pdev_i2c; struct platform_device *pdev_mux[MLXPLAT_CPLD_LPC_MUX_DEVS]; + struct platform_device *pdev_hotplug; }; /* Regions for LPC I2C controller and LPC base register space */ @@ -120,7 +122,87 @@ static struct i2c_mux_reg_platform_data mlxplat_mux_data[] = { }; -static struct platform_device *mlxplat_dev; +/* Platform hotplug devices */ +static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_psu[] = { + { + .brdinfo = { I2C_BOARD_INFO("24c02", 0x51) }, + .bus = 10, + }, + { + .brdinfo = { I2C_BOARD_INFO("24c02", 0x50) }, + .bus = 10, + }, +}; + +static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_pwr[] = { + { + .brdinfo = { I2C_BOARD_INFO("dps460", 0x59) }, + .bus = 10, + }, + { + .brdinfo = { I2C_BOARD_INFO("dps460", 0x58) }, + .bus = 10, + }, +}; + +static struct mlxcpld_hotplug_device mlxplat_mlxcpld_hotplug_fan[] = { + { + .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, + .bus = 11, + }, + { + .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, + .bus = 12, + }, + { + .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, + .bus = 13, + }, + { + .brdinfo = { I2C_BOARD_INFO("24c32", 0x50) }, + .bus = 14, + }, +}; + +/* Platform hotplug default data */ +static +struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_default_data = { + .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a), + .top_aggr_mask = 0x48, + .top_aggr_psu_mask = 0x08, + .psu_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x58), + .psu_mask = 0x03, + .psu_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_psu), + .psu = mlxplat_mlxcpld_hotplug_psu, + .top_aggr_pwr_mask = 0x08, + .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64), + .pwr_mask = 0x03, + .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr), + .pwr = mlxplat_mlxcpld_hotplug_pwr, + .top_aggr_fan_mask = 0x40, + .fan_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x88), + .fan_mask = 0x0f, + .fan_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_fan), + .fan = mlxplat_mlxcpld_hotplug_fan, +}; + +/* Platform hotplug MSN21xx system family data */ +static +struct mlxcpld_hotplug_platform_data mlxplat_mlxcpld_hotplug_msn21xx_data = { + .top_aggr_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x3a), + .top_aggr_mask = 0x04, + .top_aggr_pwr_mask = 0x04, + .pwr_reg_offset = (MLXPLAT_CPLD_LPC_REG_BASE_ADRR | 0x64), + .pwr_mask = 0x03, + .pwr_count = ARRAY_SIZE(mlxplat_mlxcpld_hotplug_pwr), +}; + +static struct resource mlxplat_mlxcpld_hotplug_resources[] = { + [0] = DEFINE_RES_IRQ_NAMED(17, "mlxcpld-hotplug"), +}; + +struct platform_device *mlxplat_dev; +struct mlxcpld_hotplug_platform_data *mlxplat_hotplug; static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) { @@ -131,6 +213,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi) mlxplat_mux_data[i].n_values = ARRAY_SIZE(mlxplat_default_channels[i]); } + mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_default_data; return 1; }; @@ -144,6 +227,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi) mlxplat_mux_data[i].n_values = ARRAY_SIZE(mlxplat_msn21xx_channels); } + mlxplat_hotplug = &mlxplat_mlxcpld_hotplug_msn21xx_data; return 1; }; @@ -229,6 +313,16 @@ static int __init mlxplat_init(void) } } + priv->pdev_hotplug = platform_device_register_resndata( + &mlxplat_dev->dev, "mlxcpld-hotplug", -1, + mlxplat_mlxcpld_hotplug_resources, + ARRAY_SIZE(mlxplat_mlxcpld_hotplug_resources), + mlxplat_hotplug, sizeof(*mlxplat_hotplug)); + if (IS_ERR(priv->pdev_hotplug)) { + err = PTR_ERR(priv->pdev_hotplug); + goto fail_platform_mux_register; + } + return 0; fail_platform_mux_register: @@ -247,6 +341,8 @@ static void __exit mlxplat_exit(void) struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev); int i; + platform_device_unregister(priv->pdev_hotplug); + for (i = ARRAY_SIZE(mlxplat_mux_data) - 1; i >= 0 ; i--) platform_device_unregister(priv->pdev_mux[i]); -- cgit v1.2.3 From 3dda3b3798f96d2974b5f60811142d3e25547807 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 25 Nov 2016 17:11:41 +0100 Subject: platform/x86: Add custom surface3 platform device for controlling LID The LID state provided by ACPI on the Surface 3 is not accurate. The ACPI node doesn't get notified on LID open, which means the LID input switch stays close most of the time. Fortunatelly, there is a WMI method which directly queries the GPIO underneath the LID state, so it's far more reliable than ACPI. To get the notifications that the LID was opened/closed, we can rely on the ACPI notification of the touchscreen: the DSDT shows that the touchscreen will get notified on close/open as it also controls its _STA method. Note that we need to set the tag "power-switch" to the LID input node through a udev rule for logind to accept it: SUBSYSTEM=="input", KERNEL=="event*", KERNELS=="surface3-wmi", \ TAG+="power-switch" Signed-off-by: Benjamin Tissoires Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 12 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/surface3-wmi.c | 296 ++++++++++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+) create mode 100644 drivers/platform/x86/surface3-wmi.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 4639d970f8cb..0414d76dc15c 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -363,6 +363,18 @@ config IDEAPAD_LAPTOP This is a driver for Lenovo IdeaPad netbooks contains drivers for rfkill switch, hotkey, fan control and backlight control. +config SURFACE3_WMI + tristate "Surface 3 WMI Driver" + depends on ACPI_WMI + depends on DMI + depends on INPUT + depends on SPI + ---help--- + Say Y here if you have a Surface 3. + + To compile this driver as a module, choose M here: the module will + be called surface3-wmi. + config THINKPAD_ACPI tristate "ThinkPad ACPI Laptop Extras" depends on ACPI diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2d6a587bded5..6cd3d909b759 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o obj-$(CONFIG_ACPI_WMI) += wmi.o obj-$(CONFIG_MSI_WMI) += msi-wmi.o +obj-$(CONFIG_SURFACE3_WMI) += surface3-wmi.o obj-$(CONFIG_TOPSTAR_LAPTOP) += topstar-laptop.o # toshiba_acpi must link after wmi to ensure that wmi devices are found diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c new file mode 100644 index 000000000000..5553b2b85e0a --- /dev/null +++ b/drivers/platform/x86/surface3-wmi.c @@ -0,0 +1,296 @@ +/* + * Driver for the LID cover switch of the Surface 3 + * + * Copyright (c) 2016 Red Hat 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; version 2 of the License. + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Benjamin Tissoires "); +MODULE_DESCRIPTION("Surface 3 platform driver"); +MODULE_LICENSE("GPL"); + +#define ACPI_BUTTON_HID_LID "PNP0C0D" +#define SPI_CTL_OBJ_NAME "SPI" +#define SPI_TS_OBJ_NAME "NTRG" + +#define SURFACE3_LID_GUID "F7CC25EC-D20B-404C-8903-0ED4359C18AE" + +MODULE_ALIAS("wmi:" SURFACE3_LID_GUID); + +static const struct dmi_system_id surface3_dmi_table[] = { +#if defined(CONFIG_X86) + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Microsoft Corporation"), + DMI_MATCH(DMI_PRODUCT_NAME, "Surface 3"), + }, + }, +#endif + { } +}; + +struct surface3_wmi { + struct acpi_device *touchscreen_adev; + struct acpi_device *pnp0c0d_adev; + struct acpi_hotplug_context hp; + struct input_dev *input; +}; + +static struct platform_device *s3_wmi_pdev; + +static struct surface3_wmi s3_wmi; + +static DEFINE_MUTEX(s3_wmi_lock); + +static int s3_wmi_query_block(const char *guid, int instance, int *ret) +{ + acpi_status status; + union acpi_object *obj; + + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + + mutex_lock(&s3_wmi_lock); + status = wmi_query_block(guid, instance, &output); + + obj = output.pointer; + + if (!obj || obj->type != ACPI_TYPE_INTEGER) { + if (obj) { + pr_err("query block returned object type: %d - buffer length:%d\n", + obj->type, + obj->type == ACPI_TYPE_BUFFER ? + obj->buffer.length : 0); + } + kfree(obj); + return -EINVAL; + } + *ret = obj->integer.value; + kfree(obj); + mutex_unlock(&s3_wmi_lock); + return 0; +} + +static inline int s3_wmi_query_lid(int *ret) +{ + return s3_wmi_query_block(SURFACE3_LID_GUID, 0, ret); +} + +static int s3_wmi_send_lid_state(void) +{ + int ret, lid_sw; + + ret = s3_wmi_query_lid(&lid_sw); + if (ret) + return ret; + + input_report_switch(s3_wmi.input, SW_LID, lid_sw); + input_sync(s3_wmi.input); + + return 0; +} + +static int s3_wmi_hp_notify(struct acpi_device *adev, u32 value) +{ + return s3_wmi_send_lid_state(); +} + +static acpi_status s3_wmi_attach_spi_device(acpi_handle handle, + u32 level, + void *data, + void **return_value) +{ + struct acpi_device *adev, **ts_adev; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + + ts_adev = data; + + if (strncmp(acpi_device_bid(adev), SPI_TS_OBJ_NAME, + strlen(SPI_TS_OBJ_NAME))) + return AE_OK; + + if (*ts_adev) { + pr_err("duplicate entry %s\n", SPI_TS_OBJ_NAME); + return AE_OK; + } + + *ts_adev = adev; + + return AE_OK; +} + +static int s3_wmi_check_platform_device(struct device *dev, void *data) +{ + struct acpi_device *adev, *ts_adev; + acpi_handle handle; + acpi_status status; + + /* ignore non ACPI devices */ + handle = ACPI_HANDLE(dev); + if (!handle || acpi_bus_get_device(handle, &adev)) + return 0; + + /* check for LID ACPI switch */ + if (!strcmp(ACPI_BUTTON_HID_LID, acpi_device_hid(adev))) { + s3_wmi.pnp0c0d_adev = adev; + return 0; + } + + /* ignore non SPI controllers */ + if (strncmp(acpi_device_bid(adev), SPI_CTL_OBJ_NAME, + strlen(SPI_CTL_OBJ_NAME))) + return 0; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + s3_wmi_attach_spi_device, NULL, + &ts_adev, NULL); + if (ACPI_FAILURE(status)) + dev_warn(dev, "failed to enumerate SPI slaves\n"); + + if (!ts_adev) + return 0; + + s3_wmi.touchscreen_adev = ts_adev; + + return 0; +} + +static int s3_wmi_create_and_register_input(struct platform_device *pdev) +{ + struct input_dev *input; + int error; + + input = devm_input_allocate_device(&pdev->dev); + if (!input) + return -ENOMEM; + + input->name = "Lid Switch"; + input->phys = "button/input0"; + input->id.bustype = BUS_HOST; + input->id.product = 0x0005; + + input_set_capability(input, EV_SW, SW_LID); + + error = input_register_device(input); + if (error) + goto out_err; + + s3_wmi.input = input; + + return 0; + out_err: + input_free_device(s3_wmi.input); + return error; +} + +static int __init s3_wmi_probe(struct platform_device *pdev) +{ + int error; + + if (!dmi_check_system(surface3_dmi_table)) + return -ENODEV; + + memset(&s3_wmi, 0, sizeof(s3_wmi)); + + bus_for_each_dev(&platform_bus_type, NULL, NULL, + s3_wmi_check_platform_device); + + if (!s3_wmi.touchscreen_adev) + return -ENODEV; + + acpi_bus_trim(s3_wmi.pnp0c0d_adev); + + error = s3_wmi_create_and_register_input(pdev); + if (error) + goto restore_acpi_lid; + + acpi_initialize_hp_context(s3_wmi.touchscreen_adev, &s3_wmi.hp, + s3_wmi_hp_notify, NULL); + + s3_wmi_send_lid_state(); + + return 0; + + restore_acpi_lid: + acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle); + return error; +} + +static int s3_wmi_remove(struct platform_device *device) +{ + /* remove the hotplug context from the acpi device */ + s3_wmi.touchscreen_adev->hp = NULL; + + /* reinstall the actual PNPC0C0D LID default handle */ + acpi_bus_scan(s3_wmi.pnp0c0d_adev->handle); + return 0; +} + +#ifdef CONFIG_PM +static int s3_wmi_resume(struct device *dev) +{ + s3_wmi_send_lid_state(); + return 0; +} +#endif +static SIMPLE_DEV_PM_OPS(s3_wmi_pm, NULL, s3_wmi_resume); + +static struct platform_driver s3_wmi_driver = { + .driver = { + .name = "surface3-wmi", + .pm = &s3_wmi_pm, + }, + .remove = s3_wmi_remove, +}; + +static int __init s3_wmi_init(void) +{ + int error; + + s3_wmi_pdev = platform_device_alloc("surface3-wmi", -1); + if (!s3_wmi_pdev) + return -ENOMEM; + + error = platform_device_add(s3_wmi_pdev); + if (error) + goto err_device_put; + + error = platform_driver_probe(&s3_wmi_driver, s3_wmi_probe); + if (error) + goto err_device_del; + + pr_info("Surface 3 WMI Extras loaded\n"); + return 0; + + err_device_del: + platform_device_del(s3_wmi_pdev); + err_device_put: + platform_device_put(s3_wmi_pdev); + return error; +} + +static void __exit s3_wmi_exit(void) +{ + platform_device_unregister(s3_wmi_pdev); + platform_driver_unregister(&s3_wmi_driver); +} + +module_init(s3_wmi_init); +module_exit(s3_wmi_exit); -- cgit v1.2.3 From 1a64b719d3ae0e4fb939d9a9e31abb60b4ce4eb1 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Mon, 5 Dec 2016 16:10:33 +0100 Subject: platform/x86: Introduce button support for the Surface 3 The Surface 3 is not following the ACPI spec for PNP0C40, but nearly. The device is connected to a I2C device that might have some magic but we don't know about. Just create the device after the enumeration and use the declared GPIOs to provide button support. This driver is just an adaptation of drivers/input/misc/soc_button_array.c The Surface Pro 3 is using an ACPI driver and matches against the bid of the device ("VGBI"). To prevent this incompatible driver to be used on the Surface Pro, we add a match on the Surface 3 bid "TEV2". link: https://bugzilla.kernel.org/show_bug.cgi?id=102761 Signed-off-by: Benjamin Tissoires Acked-by: Dmitry Torokhov Signed-off-by: Andy Shevchenko --- drivers/platform/x86/Kconfig | 6 + drivers/platform/x86/Makefile | 1 + drivers/platform/x86/surface3_button.c | 250 +++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 drivers/platform/x86/surface3_button.c (limited to 'drivers') diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 0414d76dc15c..493e3386fbf6 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1023,6 +1023,12 @@ config SURFACE_PRO3_BUTTON ---help--- This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet. +config SURFACE_3_BUTTON + tristate "Power/home/volume buttons driver for Microsoft Surface 3 tablet" + depends on ACPI && KEYBOARD_GPIO + ---help--- + This driver handles the power/home/volume buttons on the Microsoft Surface 3 tablet. + config INTEL_PUNIT_IPC tristate "Intel P-Unit IPC Driver" ---help--- diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 6cd3d909b759..e9290290f026 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI) += alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o +obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ diff --git a/drivers/platform/x86/surface3_button.c b/drivers/platform/x86/surface3_button.c new file mode 100644 index 000000000000..8bfd7f613d36 --- /dev/null +++ b/drivers/platform/x86/surface3_button.c @@ -0,0 +1,250 @@ +/* + * Supports for the button array on the Surface tablets. + * + * (C) Copyright 2016 Red Hat, Inc + * + * Based on soc_button_array.c: + * + * {C} Copyright 2014 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; version 2 + * of the License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SURFACE_BUTTON_OBJ_NAME "TEV2" +#define MAX_NBUTTONS 4 + +/* + * Some of the buttons like volume up/down are auto repeat, while others + * are not. To support both, we register two platform devices, and put + * buttons into them based on whether the key should be auto repeat. + */ +#define BUTTON_TYPES 2 + +/* + * Power button, Home button, Volume buttons support is supposed to + * be covered by drivers/input/misc/soc_button_array.c, which is implemented + * according to "Windows ACPI Design Guide for SoC Platforms". + * However surface 3 seems not to obey the specs, instead it uses + * device TEV2(MSHW0028) for declaring the GPIOs. The gpios are also slightly + * different in which the Home button is active high. + * Compared to surfacepro3_button.c which also handles MSHW0028, the Surface 3 + * is a reduce platform and thus uses GPIOs, not ACPI events. + * We choose an I2C driver here because we need to access the resources + * declared under the device node, while surfacepro3_button.c only needs + * the ACPI companion node. + */ +static const struct acpi_device_id surface3_acpi_match[] = { + { "MSHW0028", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, surface3_acpi_match); + +struct surface3_button_info { + const char *name; + int acpi_index; + unsigned int event_type; + unsigned int event_code; + bool autorepeat; + bool wakeup; + bool active_low; +}; + +struct surface3_button_data { + struct platform_device *children[BUTTON_TYPES]; +}; + +/* + * Get the Nth GPIO number from the ACPI object. + */ +static int surface3_button_lookup_gpio(struct device *dev, int acpi_index) +{ + struct gpio_desc *desc; + int gpio; + + desc = gpiod_get_index(dev, NULL, acpi_index, GPIOD_ASIS); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + gpio = desc_to_gpio(desc); + + gpiod_put(desc); + + return gpio; +} + +static struct platform_device * +surface3_button_device_create(struct i2c_client *client, + const struct surface3_button_info *button_info, + bool autorepeat) +{ + const struct surface3_button_info *info; + struct platform_device *pd; + struct gpio_keys_button *gpio_keys; + struct gpio_keys_platform_data *gpio_keys_pdata; + int n_buttons = 0; + int gpio; + int error; + + gpio_keys_pdata = devm_kzalloc(&client->dev, + sizeof(*gpio_keys_pdata) + + sizeof(*gpio_keys) * MAX_NBUTTONS, + GFP_KERNEL); + if (!gpio_keys_pdata) + return ERR_PTR(-ENOMEM); + + gpio_keys = (void *)(gpio_keys_pdata + 1); + + for (info = button_info; info->name; info++) { + if (info->autorepeat != autorepeat) + continue; + + gpio = surface3_button_lookup_gpio(&client->dev, + info->acpi_index); + if (!gpio_is_valid(gpio)) + continue; + + gpio_keys[n_buttons].type = info->event_type; + gpio_keys[n_buttons].code = info->event_code; + gpio_keys[n_buttons].gpio = gpio; + gpio_keys[n_buttons].active_low = info->active_low; + gpio_keys[n_buttons].desc = info->name; + gpio_keys[n_buttons].wakeup = info->wakeup; + n_buttons++; + } + + if (n_buttons == 0) { + error = -ENODEV; + goto err_free_mem; + } + + gpio_keys_pdata->buttons = gpio_keys; + gpio_keys_pdata->nbuttons = n_buttons; + gpio_keys_pdata->rep = autorepeat; + + pd = platform_device_alloc("gpio-keys", PLATFORM_DEVID_AUTO); + if (!pd) { + error = -ENOMEM; + goto err_free_mem; + } + + error = platform_device_add_data(pd, gpio_keys_pdata, + sizeof(*gpio_keys_pdata)); + if (error) + goto err_free_pdev; + + error = platform_device_add(pd); + if (error) + goto err_free_pdev; + + return pd; + +err_free_pdev: + platform_device_put(pd); +err_free_mem: + devm_kfree(&client->dev, gpio_keys_pdata); + return ERR_PTR(error); +} + +static int surface3_button_remove(struct i2c_client *client) +{ + struct surface3_button_data *priv = i2c_get_clientdata(client); + + int i; + + for (i = 0; i < BUTTON_TYPES; i++) + if (priv->children[i]) + platform_device_unregister(priv->children[i]); + + return 0; +} + +static struct surface3_button_info surface3_button_surface3[] = { + { "power", 0, EV_KEY, KEY_POWER, false, true, true }, + { "home", 1, EV_KEY, KEY_LEFTMETA, false, true, false }, + { "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false, true }, + { "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false, true }, + { } +}; + +static int surface3_button_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct device *dev = &client->dev; + struct surface3_button_data *priv; + struct platform_device *pd; + int i; + int error; + + if (strncmp(acpi_device_bid(ACPI_COMPANION(&client->dev)), + SURFACE_BUTTON_OBJ_NAME, + strlen(SURFACE_BUTTON_OBJ_NAME))) + return -ENODEV; + + if (gpiod_count(dev, KBUILD_MODNAME) <= 0) { + dev_dbg(dev, "no GPIO attached, ignoring...\n"); + return -ENODEV; + } + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + i2c_set_clientdata(client, priv); + + for (i = 0; i < BUTTON_TYPES; i++) { + pd = surface3_button_device_create(client, + surface3_button_surface3, + i == 0); + if (IS_ERR(pd)) { + error = PTR_ERR(pd); + if (error != -ENODEV) { + surface3_button_remove(client); + return error; + } + continue; + } + + priv->children[i] = pd; + } + + if (!priv->children[0] && !priv->children[1]) + return -ENODEV; + + return 0; +} + +static const struct i2c_device_id surface3_id[] = { + { } +}; +MODULE_DEVICE_TABLE(i2c, surface3_id); + +static struct i2c_driver surface3_driver = { + .probe = surface3_button_probe, + .remove = surface3_button_remove, + .id_table = surface3_id, + .driver = { + .name = "surface3", + .acpi_match_table = ACPI_PTR(surface3_acpi_match), + }, +}; +module_i2c_driver(surface3_driver); + +MODULE_AUTHOR("Benjamin Tissoires "); +MODULE_DESCRIPTION("surface3 button array driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From e297046875f2c5a43684f54f0fd098249b4f293a Mon Sep 17 00:00:00 2001 From: velemas Date: Tue, 6 Dec 2016 22:17:43 +0300 Subject: platform/x86: ideapad-laptop: Add Y700 15-ACZ to no_hw_rfkill DMI list Like other Y700 models Lenovo Y700 15-ACZ does not have a physical rfkill switch. ideapad-laptop wrongly reports all radios as blocked by hardware which causes wireless network connections to fail. Add this model without an rfkill switch to the no_hw_rfkill list. Signed-off-by: Artiom Vaskov Signed-off-by: Andy Shevchenko --- drivers/platform/x86/ideapad-laptop.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c index a2323941e677..dc5561973047 100644 --- a/drivers/platform/x86/ideapad-laptop.c +++ b/drivers/platform/x86/ideapad-laptop.c @@ -870,6 +870,13 @@ static const struct dmi_system_id no_hw_rfkill_list[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo G50-30"), }, }, + { + .ident = "Lenovo ideapad Y700-15ACZ", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"), + DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo ideapad Y700-15ACZ"), + }, + }, { .ident = "Lenovo ideapad Y700-15ISK", .matches = { -- cgit v1.2.3 From 026acd5f47340382844f0af73516cf7ae6cdc876 Mon Sep 17 00:00:00 2001 From: Timur Tabi Date: Tue, 13 Dec 2016 17:49:02 -0600 Subject: net: qcom/emac: don't try to claim clocks on ACPI systems On ACPI systems, clocks are not available to drivers directly. They are handled exclusively by ACPI and/or firmware, so there is no clock driver. Calls to clk_get() always fail, so we should not even attempt to claim any clocks on ACPI systems. Signed-off-by: Timur Tabi Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/ethernet/qualcomm/emac/emac.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/qualcomm/emac/emac.c b/drivers/net/ethernet/qualcomm/emac/emac.c index ae32f855e31b..422289c232bc 100644 --- a/drivers/net/ethernet/qualcomm/emac/emac.c +++ b/drivers/net/ethernet/qualcomm/emac/emac.c @@ -460,6 +460,12 @@ static int emac_clks_phase1_init(struct platform_device *pdev, { int ret; + /* On ACPI platforms, clocks are controlled by firmware and/or + * ACPI, not by drivers. + */ + if (has_acpi_companion(&pdev->dev)) + return 0; + ret = emac_clks_get(pdev, adpt); if (ret) return ret; @@ -485,6 +491,9 @@ static int emac_clks_phase2_init(struct platform_device *pdev, { int ret; + if (has_acpi_companion(&pdev->dev)) + return 0; + ret = clk_set_rate(adpt->clk[EMAC_CLK_TX], 125000000); if (ret) return ret; -- cgit v1.2.3 From 94acf164dc8f1184e8d0737be7125134c2701dbe Mon Sep 17 00:00:00 2001 From: Thomas Falcon Date: Tue, 13 Dec 2016 18:15:09 -0600 Subject: ibmveth: calculate gso_segs for large packets Include calculations to compute the number of segments that comprise an aggregated large packet. Signed-off-by: Thomas Falcon Reviewed-by: Marcelo Ricardo Leitner Reviewed-by: Jonathan Maxwell Signed-off-by: David S. Miller --- drivers/net/ethernet/ibm/ibmveth.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ibm/ibmveth.c b/drivers/net/ethernet/ibm/ibmveth.c index fbece63395a8..a831f947ca8c 100644 --- a/drivers/net/ethernet/ibm/ibmveth.c +++ b/drivers/net/ethernet/ibm/ibmveth.c @@ -1181,7 +1181,9 @@ map_failed: static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt) { + struct tcphdr *tcph; int offset = 0; + int hdr_len; /* only TCP packets will be aggregated */ if (skb->protocol == htons(ETH_P_IP)) { @@ -1208,14 +1210,20 @@ static void ibmveth_rx_mss_helper(struct sk_buff *skb, u16 mss, int lrg_pkt) /* if mss is not set through Large Packet bit/mss in rx buffer, * expect that the mss will be written to the tcp header checksum. */ + tcph = (struct tcphdr *)(skb->data + offset); if (lrg_pkt) { skb_shinfo(skb)->gso_size = mss; } else if (offset) { - struct tcphdr *tcph = (struct tcphdr *)(skb->data + offset); - skb_shinfo(skb)->gso_size = ntohs(tcph->check); tcph->check = 0; } + + if (skb_shinfo(skb)->gso_size) { + hdr_len = offset + tcph->doff * 4; + skb_shinfo(skb)->gso_segs = + DIV_ROUND_UP(skb->len - hdr_len, + skb_shinfo(skb)->gso_size); + } } static int ibmveth_poll(struct napi_struct *napi, int budget) -- cgit v1.2.3 From 83a77e9ec4150ee4acc635638f7dedd9da523a26 Mon Sep 17 00:00:00 2001 From: Bartosz Folta Date: Wed, 14 Dec 2016 06:39:15 +0000 Subject: net: macb: Added PCI wrapper for Platform Driver. There are hardware PCI implementations of Cadence GEM network controller. This patch will allow to use such hardware with reuse of existing Platform Driver. Signed-off-by: Bartosz Folta Signed-off-by: David S. Miller --- drivers/net/ethernet/cadence/Kconfig | 9 ++ drivers/net/ethernet/cadence/Makefile | 1 + drivers/net/ethernet/cadence/macb.c | 31 +++++-- drivers/net/ethernet/cadence/macb_pci.c | 153 ++++++++++++++++++++++++++++++++ include/linux/platform_data/macb.h | 6 ++ 5 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 drivers/net/ethernet/cadence/macb_pci.c (limited to 'drivers') diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig index f0bcb15d3fec..608bea171956 100644 --- a/drivers/net/ethernet/cadence/Kconfig +++ b/drivers/net/ethernet/cadence/Kconfig @@ -31,4 +31,13 @@ config MACB To compile this driver as a module, choose M here: the module will be called macb. +config MACB_PCI + tristate "Cadence PCI MACB/GEM support" + depends on MACB && PCI && COMMON_CLK + ---help--- + This is PCI wrapper for MACB driver. + + To compile this driver as a module, choose M here: the module + will be called macb_pci. + endif # NET_CADENCE diff --git a/drivers/net/ethernet/cadence/Makefile b/drivers/net/ethernet/cadence/Makefile index 91f79b1f0505..4ba75594d5c5 100644 --- a/drivers/net/ethernet/cadence/Makefile +++ b/drivers/net/ethernet/cadence/Makefile @@ -3,3 +3,4 @@ # obj-$(CONFIG_MACB) += macb.o +obj-$(CONFIG_MACB_PCI) += macb_pci.o diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c index 538544a7c642..c0fb80acc2da 100644 --- a/drivers/net/ethernet/cadence/macb.c +++ b/drivers/net/ethernet/cadence/macb.c @@ -404,6 +404,8 @@ static int macb_mii_probe(struct net_device *dev) phy_irq = gpio_to_irq(pdata->phy_irq_pin); phydev->irq = (phy_irq < 0) ? PHY_POLL : phy_irq; } + } else { + phydev->irq = PHY_POLL; } /* attach the mac to the phy */ @@ -482,6 +484,9 @@ static int macb_mii_init(struct macb *bp) goto err_out_unregister_bus; } } else { + for (i = 0; i < PHY_MAX_ADDR; i++) + bp->mii_bus->irq[i] = PHY_POLL; + if (pdata) bp->mii_bus->phy_mask = pdata->phy_mask; @@ -2523,16 +2528,24 @@ static int macb_clk_init(struct platform_device *pdev, struct clk **pclk, struct clk **hclk, struct clk **tx_clk, struct clk **rx_clk) { + struct macb_platform_data *pdata; int err; - *pclk = devm_clk_get(&pdev->dev, "pclk"); + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + *pclk = pdata->pclk; + *hclk = pdata->hclk; + } else { + *pclk = devm_clk_get(&pdev->dev, "pclk"); + *hclk = devm_clk_get(&pdev->dev, "hclk"); + } + if (IS_ERR(*pclk)) { err = PTR_ERR(*pclk); dev_err(&pdev->dev, "failed to get macb_clk (%u)\n", err); return err; } - *hclk = devm_clk_get(&pdev->dev, "hclk"); if (IS_ERR(*hclk)) { err = PTR_ERR(*hclk); dev_err(&pdev->dev, "failed to get hclk (%u)\n", err); @@ -3107,15 +3120,23 @@ static const struct of_device_id macb_dt_ids[] = { MODULE_DEVICE_TABLE(of, macb_dt_ids); #endif /* CONFIG_OF */ +static const struct macb_config default_gem_config = { + .caps = MACB_CAPS_GIGABIT_MODE_AVAILABLE | MACB_CAPS_JUMBO, + .dma_burst_length = 16, + .clk_init = macb_clk_init, + .init = macb_init, + .jumbo_max_len = 10240, +}; + static int macb_probe(struct platform_device *pdev) { + const struct macb_config *macb_config = &default_gem_config; int (*clk_init)(struct platform_device *, struct clk **, struct clk **, struct clk **, struct clk **) - = macb_clk_init; - int (*init)(struct platform_device *) = macb_init; + = macb_config->clk_init; + int (*init)(struct platform_device *) = macb_config->init; struct device_node *np = pdev->dev.of_node; struct device_node *phy_node; - const struct macb_config *macb_config = NULL; struct clk *pclk, *hclk = NULL, *tx_clk = NULL, *rx_clk = NULL; unsigned int queue_mask, num_queues; struct macb_platform_data *pdata; diff --git a/drivers/net/ethernet/cadence/macb_pci.c b/drivers/net/ethernet/cadence/macb_pci.c new file mode 100644 index 000000000000..92be2cd8f817 --- /dev/null +++ b/drivers/net/ethernet/cadence/macb_pci.c @@ -0,0 +1,153 @@ +/** + * macb_pci.c - Cadence GEM PCI wrapper. + * + * Copyright (C) 2016 Cadence Design Systems - http://www.cadence.com + * + * Authors: Rafal Ozieblo + * Bartosz Folta + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 of + * the License as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include "macb.h" + +#define PCI_DRIVER_NAME "macb_pci" +#define PLAT_DRIVER_NAME "macb" + +#define CDNS_VENDOR_ID 0x17cd +#define CDNS_DEVICE_ID 0xe007 + +#define GEM_PCLK_RATE 50000000 +#define GEM_HCLK_RATE 50000000 + +static int macb_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + int err; + struct platform_device *plat_dev; + struct platform_device_info plat_info; + struct macb_platform_data plat_data; + struct resource res[2]; + + /* sanity check */ + if (!id) + return -EINVAL; + + /* enable pci device */ + err = pci_enable_device(pdev); + if (err < 0) { + dev_err(&pdev->dev, "Enabling PCI device has failed: 0x%04X", + err); + return -EACCES; + } + + pci_set_master(pdev); + + /* set up resources */ + memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); + res[0].start = pdev->resource[0].start; + res[0].end = pdev->resource[0].end; + res[0].name = PCI_DRIVER_NAME; + res[0].flags = IORESOURCE_MEM; + res[1].start = pdev->irq; + res[1].name = PCI_DRIVER_NAME; + res[1].flags = IORESOURCE_IRQ; + + dev_info(&pdev->dev, "EMAC physical base addr = 0x%p\n", + (void *)(uintptr_t)pci_resource_start(pdev, 0)); + + /* set up macb platform data */ + memset(&plat_data, 0, sizeof(plat_data)); + + /* initialize clocks */ + plat_data.pclk = clk_register_fixed_rate(&pdev->dev, "pclk", NULL, 0, + GEM_PCLK_RATE); + if (IS_ERR(plat_data.pclk)) { + err = PTR_ERR(plat_data.pclk); + goto err_pclk_register; + } + + plat_data.hclk = clk_register_fixed_rate(&pdev->dev, "hclk", NULL, 0, + GEM_HCLK_RATE); + if (IS_ERR(plat_data.hclk)) { + err = PTR_ERR(plat_data.hclk); + goto err_hclk_register; + } + + /* set up platform device info */ + memset(&plat_info, 0, sizeof(plat_info)); + plat_info.parent = &pdev->dev; + plat_info.fwnode = pdev->dev.fwnode; + plat_info.name = PLAT_DRIVER_NAME; + plat_info.id = pdev->devfn; + plat_info.res = res; + plat_info.num_res = ARRAY_SIZE(res); + plat_info.data = &plat_data; + plat_info.size_data = sizeof(plat_data); + plat_info.dma_mask = DMA_BIT_MASK(32); + + /* register platform device */ + plat_dev = platform_device_register_full(&plat_info); + if (IS_ERR(plat_dev)) { + err = PTR_ERR(plat_dev); + goto err_plat_dev_register; + } + + pci_set_drvdata(pdev, plat_dev); + + return 0; + +err_plat_dev_register: + clk_unregister(plat_data.hclk); + +err_hclk_register: + clk_unregister(plat_data.pclk); + +err_pclk_register: + pci_disable_device(pdev); + return err; +} + +static void macb_remove(struct pci_dev *pdev) +{ + struct platform_device *plat_dev = pci_get_drvdata(pdev); + struct macb_platform_data *plat_data = dev_get_platdata(&plat_dev->dev); + + platform_device_unregister(plat_dev); + pci_disable_device(pdev); + clk_unregister(plat_data->pclk); + clk_unregister(plat_data->hclk); +} + +static struct pci_device_id dev_id_table[] = { + { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), }, + { 0, } +}; + +static struct pci_driver macb_pci_driver = { + .name = PCI_DRIVER_NAME, + .id_table = dev_id_table, + .probe = macb_probe, + .remove = macb_remove, +}; + +module_pci_driver(macb_pci_driver); +MODULE_DEVICE_TABLE(pci, dev_id_table); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Cadence NIC PCI wrapper"); diff --git a/include/linux/platform_data/macb.h b/include/linux/platform_data/macb.h index 21b15f6fee25..7815d50c26ff 100644 --- a/include/linux/platform_data/macb.h +++ b/include/linux/platform_data/macb.h @@ -8,6 +8,8 @@ #ifndef __MACB_PDATA_H__ #define __MACB_PDATA_H__ +#include + /** * struct macb_platform_data - platform data for MACB Ethernet * @phy_mask: phy mask passed when register the MDIO bus @@ -15,12 +17,16 @@ * @phy_irq_pin: PHY IRQ * @is_rmii: using RMII interface? * @rev_eth_addr: reverse Ethernet address byte order + * @pclk: platform clock + * @hclk: AHB clock */ struct macb_platform_data { u32 phy_mask; int phy_irq_pin; u8 is_rmii; u8 rev_eth_addr; + struct clk *pclk; + struct clk *hclk; }; #endif /* __MACB_PDATA_H__ */ -- cgit v1.2.3 From a0f37efa82253994b99623dbf41eea8dd0ba169b Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 14 Dec 2016 11:06:18 -0800 Subject: net: vrf: Fix NAT within a VRF Connection tracking with VRF is broken because the pass through the VRF device drops the connection tracking info. Removing the call to nf_reset allows DNAT and MASQUERADE to work across interfaces within a VRF. Fixes: 73e20b761acf ("net: vrf: Add support for PREROUTING rules on vrf device") Signed-off-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/vrf.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 3bca24651dc0..015a1321c7dd 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -849,8 +849,6 @@ static struct sk_buff *vrf_rcv_nfhook(u8 pf, unsigned int hook, { struct net *net = dev_net(dev); - nf_reset(skb); - if (NF_HOOK(pf, hook, net, NULL, skb, dev, NULL, vrf_rcv_finish) < 0) skb = NULL; /* kfree_skb(skb) handled by nf code */ -- cgit v1.2.3 From eb63ecc1706b3e094d0f57438b6c2067cfc299f2 Mon Sep 17 00:00:00 2001 From: David Ahern Date: Wed, 14 Dec 2016 14:31:11 -0800 Subject: net: vrf: Drop conntrack data after pass through VRF device on Tx Locally originated traffic in a VRF fails in the presence of a POSTROUTING rule. For example, $ iptables -t nat -A POSTROUTING -s 11.1.1.0/24 -j MASQUERADE $ ping -I red -c1 11.1.1.3 ping: Warning: source address might be selected on device other than red. PING 11.1.1.3 (11.1.1.3) from 11.1.1.2 red: 56(84) bytes of data. ping: sendmsg: Operation not permitted Worse, the above causes random corruption resulting in a panic in random places (I have not seen a consistent backtrace). Call nf_reset to drop the conntrack info following the pass through the VRF device. The nf_reset is needed on Tx but not Rx because of the order in which NF_HOOK's are hit: on Rx the VRF device is after the real ingress device and on Tx it is is before the real egress device. Connection tracking should be tied to the real egress device and not the VRF device. Fixes: 8f58336d3f78a ("net: Add ethernet header for pass through VRF device") Fixes: 35402e3136634 ("net: Add IPv6 support to VRF device") Signed-off-by: David Ahern Signed-off-by: David S. Miller --- drivers/net/vrf.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/net/vrf.c b/drivers/net/vrf.c index 015a1321c7dd..7532646c3b7b 100644 --- a/drivers/net/vrf.c +++ b/drivers/net/vrf.c @@ -366,6 +366,8 @@ static int vrf_finish_output6(struct net *net, struct sock *sk, struct in6_addr *nexthop; int ret; + nf_reset(skb); + skb->protocol = htons(ETH_P_IPV6); skb->dev = dev; @@ -547,6 +549,8 @@ static int vrf_finish_output(struct net *net, struct sock *sk, struct sk_buff *s u32 nexthop; int ret = -EINVAL; + nf_reset(skb); + /* Be paranoid, rather than too clever. */ if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { struct sk_buff *skb2; -- cgit v1.2.3 From 7d6f8dc0b2180ed60aea65660b35d7618ff6e4ee Mon Sep 17 00:00:00 2001 From: Claudiu Manoil Date: Thu, 15 Dec 2016 15:13:04 +0200 Subject: dpaa_eth: use big endian accessors Ensure correct access to the big endian QMan HW through proper accessors. Signed-off-by: Claudiu Manoil Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/dpaa_eth.c | 71 ++++++++++++++------------ 1 file changed, 37 insertions(+), 34 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c index 3c48a84dec86..624ba9058dc4 100644 --- a/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c +++ b/drivers/net/ethernet/freescale/dpaa/dpaa_eth.c @@ -733,7 +733,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv) priv->cgr_data.cgr.cb = dpaa_eth_cgscn; /* Enable Congestion State Change Notifications and CS taildrop */ - initcgr.we_mask = QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES; + initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CSCN_EN | QM_CGR_WE_CS_THRES); initcgr.cgr.cscn_en = QM_CGR_EN; /* Set different thresholds based on the MAC speed. @@ -747,7 +747,7 @@ static int dpaa_eth_cgr_init(struct dpaa_priv *priv) cs_th = DPAA_CS_THRESHOLD_1G; qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1); - initcgr.we_mask |= QM_CGR_WE_CSTD_EN; + initcgr.we_mask |= cpu_to_be16(QM_CGR_WE_CSTD_EN); initcgr.cgr.cstd_en = QM_CGR_EN; err = qman_create_cgr(&priv->cgr_data.cgr, QMAN_CGR_FLAG_USE_INIT, @@ -896,18 +896,18 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) if (dpaa_fq->init) { memset(&initfq, 0, sizeof(initfq)); - initfq.we_mask = QM_INITFQ_WE_FQCTRL; + initfq.we_mask = cpu_to_be16(QM_INITFQ_WE_FQCTRL); /* Note: we may get to keep an empty FQ in cache */ - initfq.fqd.fq_ctrl = QM_FQCTRL_PREFERINCACHE; + initfq.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_PREFERINCACHE); /* Try to reduce the number of portal interrupts for * Tx Confirmation FQs. */ if (dpaa_fq->fq_type == FQ_TYPE_TX_CONFIRM) - initfq.fqd.fq_ctrl |= QM_FQCTRL_HOLDACTIVE; + initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE); /* FQ placement */ - initfq.we_mask |= QM_INITFQ_WE_DESTWQ; + initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_DESTWQ); qm_fqd_set_destwq(&initfq.fqd, dpaa_fq->channel, dpaa_fq->wq); @@ -920,8 +920,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) if (dpaa_fq->fq_type == FQ_TYPE_TX || dpaa_fq->fq_type == FQ_TYPE_TX_CONFIRM || dpaa_fq->fq_type == FQ_TYPE_TX_CONF_MQ) { - initfq.we_mask |= QM_INITFQ_WE_CGID; - initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE; + initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CGID); + initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_CGE); initfq.fqd.cgid = (u8)priv->cgr_data.cgr.cgrid; /* Set a fixed overhead accounting, in an attempt to * reduce the impact of fixed-size skb shells and the @@ -932,7 +932,7 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) * insufficient value, but even that is better than * no overhead accounting at all. */ - initfq.we_mask |= QM_INITFQ_WE_OAC; + initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_OAC); qm_fqd_set_oac(&initfq.fqd, QM_OAC_CG); qm_fqd_set_oal(&initfq.fqd, min(sizeof(struct sk_buff) + @@ -941,9 +941,9 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) } if (td_enable) { - initfq.we_mask |= QM_INITFQ_WE_TDTHRESH; + initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_TDTHRESH); qm_fqd_set_taildrop(&initfq.fqd, DPAA_FQ_TD, 1); - initfq.fqd.fq_ctrl = QM_FQCTRL_TDE; + initfq.fqd.fq_ctrl = cpu_to_be16(QM_FQCTRL_TDE); } if (dpaa_fq->fq_type == FQ_TYPE_TX) { @@ -951,7 +951,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) if (queue_id >= 0) confq = priv->conf_fqs[queue_id]; if (confq) { - initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; + initfq.we_mask |= + cpu_to_be16(QM_INITFQ_WE_CONTEXTA); /* ContextA: OVOM=1(use contextA2 bits instead of ICAD) * A2V=1 (contextA A2 field is valid) * A0V=1 (contextA A0 field is valid) @@ -959,8 +960,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) * ContextA A2: EBD=1 (deallocate buffers inside FMan) * ContextB B0(ASPID): 0 (absolute Virtual Storage ID) */ - initfq.fqd.context_a.hi = 0x1e000000; - initfq.fqd.context_a.lo = 0x80000000; + qm_fqd_context_a_set64(&initfq.fqd, + 0x1e00000080000000ULL); } } @@ -968,13 +969,13 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) if (priv->use_ingress_cgr && (dpaa_fq->fq_type == FQ_TYPE_RX_DEFAULT || dpaa_fq->fq_type == FQ_TYPE_RX_ERROR)) { - initfq.we_mask |= QM_INITFQ_WE_CGID; - initfq.fqd.fq_ctrl |= QM_FQCTRL_CGE; + initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CGID); + initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_CGE); initfq.fqd.cgid = (u8)priv->ingress_cgr.cgrid; /* Set a fixed overhead accounting, just like for the * egress CGR. */ - initfq.we_mask |= QM_INITFQ_WE_OAC; + initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_OAC); qm_fqd_set_oac(&initfq.fqd, QM_OAC_CG); qm_fqd_set_oal(&initfq.fqd, min(sizeof(struct sk_buff) + @@ -984,9 +985,8 @@ static int dpaa_fq_init(struct dpaa_fq *dpaa_fq, bool td_enable) /* Initialization common to all ingress queues */ if (dpaa_fq->flags & QMAN_FQ_FLAG_NO_ENQUEUE) { - initfq.we_mask |= QM_INITFQ_WE_CONTEXTA; - initfq.fqd.fq_ctrl |= - QM_FQCTRL_HOLDACTIVE; + initfq.we_mask |= cpu_to_be16(QM_INITFQ_WE_CONTEXTA); + initfq.fqd.fq_ctrl |= cpu_to_be16(QM_FQCTRL_HOLDACTIVE); initfq.fqd.context_a.stashing.exclusive = QM_STASHING_EXCL_DATA | QM_STASHING_EXCL_CTX | QM_STASHING_EXCL_ANNOTATION; @@ -1350,7 +1350,7 @@ static int dpaa_enable_tx_csum(struct dpaa_priv *priv, parse_result->l4_off = (u8)skb_transport_offset(skb); /* Enable L3 (and L4, if TCP or UDP) HW checksum. */ - fd->cmd |= FM_FD_CMD_RPD | FM_FD_CMD_DTC; + fd->cmd |= cpu_to_be32(FM_FD_CMD_RPD | FM_FD_CMD_DTC); /* On P1023 and similar platforms fd->cmd interpretation could * be disabled by setting CONTEXT_A bit ICMD; currently this bit @@ -1732,7 +1732,7 @@ static int skb_to_contig_fd(struct dpaa_priv *priv, /* Fill in the rest of the FD fields */ qm_fd_set_contig(fd, priv->tx_headroom, skb->len); - fd->cmd |= FM_FD_CMD_FCO; + fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO); /* Map the entire buffer size that may be seen by FMan, but no more */ addr = dma_map_single(dev, skbh, @@ -1840,7 +1840,7 @@ static int skb_to_sg_fd(struct dpaa_priv *priv, } fd->bpid = FSL_DPAA_BPID_INV; - fd->cmd |= FM_FD_CMD_FCO; + fd->cmd |= cpu_to_be32(FM_FD_CMD_FCO); qm_fd_addr_set64(fd, addr); return 0; @@ -1867,7 +1867,7 @@ static inline int dpaa_xmit(struct dpaa_priv *priv, egress_fq = priv->egress_fqs[queue]; if (fd->bpid == FSL_DPAA_BPID_INV) - fd->cmd |= qman_fq_fqid(priv->conf_fqs[queue]); + fd->cmd |= cpu_to_be32(qman_fq_fqid(priv->conf_fqs[queue])); /* Trace this Tx fd */ trace_dpaa_tx_fd(priv->net_dev, egress_fq, fd); @@ -1960,17 +1960,17 @@ static void dpaa_rx_error(struct net_device *net_dev, { if (net_ratelimit()) netif_err(priv, hw, net_dev, "Err FD status = 0x%08x\n", - fd->status & FM_FD_STAT_RX_ERRORS); + be32_to_cpu(fd->status) & FM_FD_STAT_RX_ERRORS); percpu_priv->stats.rx_errors++; - if (fd->status & FM_FD_ERR_DMA) + if (be32_to_cpu(fd->status) & FM_FD_ERR_DMA) percpu_priv->rx_errors.dme++; - if (fd->status & FM_FD_ERR_PHYSICAL) + if (be32_to_cpu(fd->status) & FM_FD_ERR_PHYSICAL) percpu_priv->rx_errors.fpe++; - if (fd->status & FM_FD_ERR_SIZE) + if (be32_to_cpu(fd->status) & FM_FD_ERR_SIZE) percpu_priv->rx_errors.fse++; - if (fd->status & FM_FD_ERR_PRS_HDR_ERR) + if (be32_to_cpu(fd->status) & FM_FD_ERR_PRS_HDR_ERR) percpu_priv->rx_errors.phe++; dpaa_fd_release(net_dev, fd); @@ -1986,7 +1986,7 @@ static void dpaa_tx_error(struct net_device *net_dev, if (net_ratelimit()) netif_warn(priv, hw, net_dev, "FD status = 0x%08x\n", - fd->status & FM_FD_STAT_TX_ERRORS); + be32_to_cpu(fd->status) & FM_FD_STAT_TX_ERRORS); percpu_priv->stats.tx_errors++; @@ -2020,10 +2020,11 @@ static void dpaa_tx_conf(struct net_device *net_dev, { struct sk_buff *skb; - if (unlikely(fd->status & FM_FD_STAT_TX_ERRORS) != 0) { + if (unlikely(be32_to_cpu(fd->status) & FM_FD_STAT_TX_ERRORS)) { if (net_ratelimit()) netif_warn(priv, hw, net_dev, "FD status = 0x%08x\n", - fd->status & FM_FD_STAT_TX_ERRORS); + be32_to_cpu(fd->status) & + FM_FD_STAT_TX_ERRORS); percpu_priv->stats.tx_errors++; } @@ -2100,6 +2101,8 @@ static enum qman_cb_dqrr_result rx_default_dqrr(struct qman_portal *portal, struct sk_buff *skb; int *count_ptr; + fd_status = be32_to_cpu(fd->status); + fd_format = qm_fd_get_format(fd); net_dev = ((struct dpaa_fq *)fq)->net_dev; priv = netdev_priv(net_dev); dpaa_bp = dpaa_bpid2pool(dq->fd.bpid); @@ -2417,12 +2420,12 @@ static int dpaa_ingress_cgr_init(struct dpaa_priv *priv) } /* Enable CS TD, but disable Congestion State Change Notifications. */ - initcgr.we_mask = QM_CGR_WE_CS_THRES; + initcgr.we_mask = cpu_to_be16(QM_CGR_WE_CS_THRES); initcgr.cgr.cscn_en = QM_CGR_EN; cs_th = DPAA_INGRESS_CS_THRESHOLD; qm_cgr_cs_thres_set64(&initcgr.cgr.cs_thres, cs_th, 1); - initcgr.we_mask |= QM_CGR_WE_CSTD_EN; + initcgr.we_mask |= cpu_to_be16(QM_CGR_WE_CSTD_EN); initcgr.cgr.cstd_en = QM_CGR_EN; /* This CGR will be associated with the SWP affined to the current CPU. -- cgit v1.2.3 From 708f0f4f9cec143403f8575493bea62a692b4ca2 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Thu, 15 Dec 2016 15:13:05 +0200 Subject: dpaa_eth: remove redundant dependency on FSL_SOC Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/dpaa/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/dpaa/Kconfig b/drivers/net/ethernet/freescale/dpaa/Kconfig index f3a3454805f9..a654736237a9 100644 --- a/drivers/net/ethernet/freescale/dpaa/Kconfig +++ b/drivers/net/ethernet/freescale/dpaa/Kconfig @@ -1,6 +1,6 @@ menuconfig FSL_DPAA_ETH tristate "DPAA Ethernet" - depends on FSL_SOC && FSL_DPAA && FSL_FMAN + depends on FSL_DPAA && FSL_FMAN select PHYLIB select FSL_FMAN_MAC ---help--- -- cgit v1.2.3 From f600b690501550b94e83e07295d9c8b9c4c39f4e Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Thu, 15 Dec 2016 12:13:24 -0800 Subject: virtio_net: Add XDP support This adds XDP support to virtio_net. Some requirements must be met for XDP to be enabled depending on the mode. First it will only be supported with LRO disabled so that data is not pushed across multiple buffers. Second the MTU must be less than a page size to avoid having to handle XDP across multiple pages. If mergeable receive is enabled this patch only supports the case where header and data are in the same buf which we can check when a packet is received by looking at num_buf. If the num_buf is greater than 1 and a XDP program is loaded the packet is dropped and a warning is thrown. When any_header_sg is set this does not happen and both header and data is put in a single buffer as expected so we check this when XDP programs are loaded. Subsequent patches will process the packet in a degraded mode to ensure connectivity and correctness is not lost even if backend pushes packets into multiple buffers. If big packets mode is enabled and MTU/LRO conditions above are met then XDP is allowed. This patch was tested with qemu with vhost=on and vhost=off where mergeable and big_packet modes were forced via hard coding feature negotiation. Multiple buffers per packet was forced via a small test patch to vhost.c in the vhost=on qemu mode. Suggested-by: Shrijeet Mukherjee Signed-off-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 176 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 171 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index fe9f7726e990..6fdb6065b940 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -81,6 +82,8 @@ struct receive_queue { struct napi_struct napi; + struct bpf_prog __rcu *xdp_prog; + /* Chain pages by the private ptr. */ struct page *pages; @@ -324,6 +327,38 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi, return skb; } +static u32 do_xdp_prog(struct virtnet_info *vi, + struct bpf_prog *xdp_prog, + struct page *page, int offset, int len) +{ + int hdr_padded_len; + struct xdp_buff xdp; + u32 act; + u8 *buf; + + buf = page_address(page) + offset; + + if (vi->mergeable_rx_bufs) + hdr_padded_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); + else + hdr_padded_len = sizeof(struct padded_vnet_hdr); + + xdp.data = buf + hdr_padded_len; + xdp.data_end = xdp.data + (len - vi->hdr_len); + + act = bpf_prog_run_xdp(xdp_prog, &xdp); + switch (act) { + case XDP_PASS: + return XDP_PASS; + default: + bpf_warn_invalid_xdp_action(act); + case XDP_TX: + case XDP_ABORTED: + case XDP_DROP: + return XDP_DROP; + } +} + static struct sk_buff *receive_small(struct virtnet_info *vi, void *buf, unsigned int len) { struct sk_buff * skb = buf; @@ -340,14 +375,32 @@ static struct sk_buff *receive_big(struct net_device *dev, void *buf, unsigned int len) { + struct bpf_prog *xdp_prog; struct page *page = buf; - struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE); + struct sk_buff *skb; + rcu_read_lock(); + xdp_prog = rcu_dereference(rq->xdp_prog); + if (xdp_prog) { + struct virtio_net_hdr_mrg_rxbuf *hdr = buf; + u32 act; + + if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) + goto err_xdp; + act = do_xdp_prog(vi, xdp_prog, page, 0, len); + if (act == XDP_DROP) + goto err_xdp; + } + rcu_read_unlock(); + + skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE); if (unlikely(!skb)) goto err; return skb; +err_xdp: + rcu_read_unlock(); err: dev->stats.rx_dropped++; give_pages(rq, page); @@ -365,11 +418,42 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers); struct page *page = virt_to_head_page(buf); int offset = buf - page_address(page); - unsigned int truesize = max(len, mergeable_ctx_to_buf_truesize(ctx)); + struct sk_buff *head_skb, *curr_skb; + struct bpf_prog *xdp_prog; + unsigned int truesize; + + rcu_read_lock(); + xdp_prog = rcu_dereference(rq->xdp_prog); + if (xdp_prog) { + u32 act; + + /* No known backend devices should send packets with + * more than a single buffer when XDP conditions are + * met. However it is not strictly illegal so the case + * is handled as an exception and a warning is thrown. + */ + if (unlikely(num_buf > 1)) { + bpf_warn_invalid_xdp_buffer(); + goto err_xdp; + } + + /* Transient failure which in theory could occur if + * in-flight packets from before XDP was enabled reach + * the receive path after XDP is loaded. In practice I + * was not able to create this condition. + */ + if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) + goto err_xdp; + + act = do_xdp_prog(vi, xdp_prog, page, offset, len); + if (act == XDP_DROP) + goto err_xdp; + } + rcu_read_unlock(); - struct sk_buff *head_skb = page_to_skb(vi, rq, page, offset, len, - truesize); - struct sk_buff *curr_skb = head_skb; + truesize = max(len, mergeable_ctx_to_buf_truesize(ctx)); + head_skb = page_to_skb(vi, rq, page, offset, len, truesize); + curr_skb = head_skb; if (unlikely(!curr_skb)) goto err_skb; @@ -423,6 +507,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, ewma_pkt_len_add(&rq->mrg_avg_pkt_len, head_skb->len); return head_skb; +err_xdp: + rcu_read_unlock(); err_skb: put_page(page); while (--num_buf) { @@ -1337,6 +1423,13 @@ static int virtnet_set_channels(struct net_device *dev, if (queue_pairs > vi->max_queue_pairs || queue_pairs == 0) return -EINVAL; + /* For now we don't support modifying channels while XDP is loaded + * also when XDP is loaded all RX queues have XDP programs so we only + * need to check a single RX queue. + */ + if (vi->rq[0].xdp_prog) + return -EINVAL; + get_online_cpus(); err = virtnet_set_queues(vi, queue_pairs); if (!err) { @@ -1428,6 +1521,70 @@ static const struct ethtool_ops virtnet_ethtool_ops = { .set_settings = virtnet_set_settings, }; +static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog) +{ + unsigned long int max_sz = PAGE_SIZE - sizeof(struct padded_vnet_hdr); + struct virtnet_info *vi = netdev_priv(dev); + struct bpf_prog *old_prog; + int i; + + if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) || + virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6)) { + netdev_warn(dev, "can't set XDP while host is implementing LRO, disable LRO first\n"); + return -EOPNOTSUPP; + } + + if (vi->mergeable_rx_bufs && !vi->any_header_sg) { + netdev_warn(dev, "XDP expects header/data in single page, any_header_sg required\n"); + return -EINVAL; + } + + if (dev->mtu > max_sz) { + netdev_warn(dev, "XDP requires MTU less than %lu\n", max_sz); + return -EINVAL; + } + + if (prog) { + prog = bpf_prog_add(prog, vi->max_queue_pairs - 1); + if (IS_ERR(prog)) + return PTR_ERR(prog); + } + + for (i = 0; i < vi->max_queue_pairs; i++) { + old_prog = rtnl_dereference(vi->rq[i].xdp_prog); + rcu_assign_pointer(vi->rq[i].xdp_prog, prog); + if (old_prog) + bpf_prog_put(old_prog); + } + + return 0; +} + +static bool virtnet_xdp_query(struct net_device *dev) +{ + struct virtnet_info *vi = netdev_priv(dev); + int i; + + for (i = 0; i < vi->max_queue_pairs; i++) { + if (vi->rq[i].xdp_prog) + return true; + } + return false; +} + +static int virtnet_xdp(struct net_device *dev, struct netdev_xdp *xdp) +{ + switch (xdp->command) { + case XDP_SETUP_PROG: + return virtnet_xdp_set(dev, xdp->prog); + case XDP_QUERY_PROG: + xdp->prog_attached = virtnet_xdp_query(dev); + return 0; + default: + return -EINVAL; + } +} + static const struct net_device_ops virtnet_netdev = { .ndo_open = virtnet_open, .ndo_stop = virtnet_close, @@ -1444,6 +1601,7 @@ static const struct net_device_ops virtnet_netdev = { #ifdef CONFIG_NET_RX_BUSY_POLL .ndo_busy_poll = virtnet_busy_poll, #endif + .ndo_xdp = virtnet_xdp, }; static void virtnet_config_changed_work(struct work_struct *work) @@ -1505,12 +1663,20 @@ static void virtnet_free_queues(struct virtnet_info *vi) static void free_receive_bufs(struct virtnet_info *vi) { + struct bpf_prog *old_prog; int i; + rtnl_lock(); for (i = 0; i < vi->max_queue_pairs; i++) { while (vi->rq[i].pages) __free_pages(get_a_page(&vi->rq[i], GFP_KERNEL), 0); + + old_prog = rtnl_dereference(vi->rq[i].xdp_prog); + RCU_INIT_POINTER(vi->rq[i].xdp_prog, NULL); + if (old_prog) + bpf_prog_put(old_prog); } + rtnl_unlock(); } static void free_receive_page_frags(struct virtnet_info *vi) -- cgit v1.2.3 From 672aafd5d88a951f394334802b938b502010d9eb Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Thu, 15 Dec 2016 12:13:49 -0800 Subject: virtio_net: add dedicated XDP transmit queues XDP requires using isolated transmit queues to avoid interference with normal networking stack (BQL, NETDEV_TX_BUSY, etc). This patch adds a XDP queue per cpu when a XDP program is loaded and does not expose the queues to the OS via the normal API call to netif_set_real_num_tx_queues(). This way the stack will never push an skb to these queues. However virtio/vhost/qemu implementation only allows for creating TX/RX queue pairs at this time so creating only TX queues was not possible. And because the associated RX queues are being created I went ahead and exposed these to the stack and let the backend use them. This creates more RX queues visible to the network stack than TX queues which is worth mentioning but does not cause any issues as far as I can tell. Signed-off-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 6fdb6065b940..1d16862c5710 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -114,6 +114,9 @@ struct virtnet_info { /* # of queue pairs currently used by the driver */ u16 curr_queue_pairs; + /* # of XDP queue pairs currently used by the driver */ + u16 xdp_queue_pairs; + /* I like... big packets and I cannot lie! */ bool big_packets; @@ -1526,7 +1529,8 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog) unsigned long int max_sz = PAGE_SIZE - sizeof(struct padded_vnet_hdr); struct virtnet_info *vi = netdev_priv(dev); struct bpf_prog *old_prog; - int i; + u16 xdp_qp = 0, curr_qp; + int i, err; if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) || virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6)) { @@ -1544,12 +1548,34 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog) return -EINVAL; } + curr_qp = vi->curr_queue_pairs - vi->xdp_queue_pairs; + if (prog) + xdp_qp = nr_cpu_ids; + + /* XDP requires extra queues for XDP_TX */ + if (curr_qp + xdp_qp > vi->max_queue_pairs) { + netdev_warn(dev, "request %i queues but max is %i\n", + curr_qp + xdp_qp, vi->max_queue_pairs); + return -ENOMEM; + } + + err = virtnet_set_queues(vi, curr_qp + xdp_qp); + if (err) { + dev_warn(&dev->dev, "XDP Device queue allocation failure.\n"); + return err; + } + if (prog) { prog = bpf_prog_add(prog, vi->max_queue_pairs - 1); - if (IS_ERR(prog)) + if (IS_ERR(prog)) { + virtnet_set_queues(vi, curr_qp); return PTR_ERR(prog); + } } + vi->xdp_queue_pairs = xdp_qp; + netif_set_real_num_rx_queues(dev, curr_qp + xdp_qp); + for (i = 0; i < vi->max_queue_pairs; i++) { old_prog = rtnl_dereference(vi->rq[i].xdp_prog); rcu_assign_pointer(vi->rq[i].xdp_prog, prog); -- cgit v1.2.3 From 56434a01b12e99eb60908f5f2b27b90726d0a183 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Thu, 15 Dec 2016 12:14:13 -0800 Subject: virtio_net: add XDP_TX support This adds support for the XDP_TX action to virtio_net. When an XDP program is run and returns the XDP_TX action the virtio_net XDP implementation will transmit the packet on a TX queue that aligns with the current CPU that the XDP packet was processed on. Before sending the packet the header is zeroed. Also XDP is expected to handle checksum correctly so no checksum offload support is provided. Signed-off-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 100 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1d16862c5710..ca3d2e2350c6 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -330,12 +330,58 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi, return skb; } +static void virtnet_xdp_xmit(struct virtnet_info *vi, + struct receive_queue *rq, + struct send_queue *sq, + struct xdp_buff *xdp) +{ + struct page *page = virt_to_head_page(xdp->data); + struct virtio_net_hdr_mrg_rxbuf *hdr; + unsigned int num_sg, len; + void *xdp_sent; + int err; + + /* Free up any pending old buffers before queueing new ones. */ + while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) { + struct page *sent_page = virt_to_head_page(xdp_sent); + + if (vi->mergeable_rx_bufs) + put_page(sent_page); + else + give_pages(rq, sent_page); + } + + /* Zero header and leave csum up to XDP layers */ + hdr = xdp->data; + memset(hdr, 0, vi->hdr_len); + + num_sg = 1; + sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data); + err = virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, + xdp->data, GFP_ATOMIC); + if (unlikely(err)) { + if (vi->mergeable_rx_bufs) + put_page(page); + else + give_pages(rq, page); + return; // On error abort to avoid unnecessary kick + } else if (!vi->mergeable_rx_bufs) { + /* If not mergeable bufs must be big packets so cleanup pages */ + give_pages(rq, (struct page *)page->private); + page->private = 0; + } + + virtqueue_kick(sq->vq); +} + static u32 do_xdp_prog(struct virtnet_info *vi, + struct receive_queue *rq, struct bpf_prog *xdp_prog, struct page *page, int offset, int len) { int hdr_padded_len; struct xdp_buff xdp; + unsigned int qp; u32 act; u8 *buf; @@ -353,9 +399,15 @@ static u32 do_xdp_prog(struct virtnet_info *vi, switch (act) { case XDP_PASS: return XDP_PASS; + case XDP_TX: + qp = vi->curr_queue_pairs - + vi->xdp_queue_pairs + + smp_processor_id(); + xdp.data = buf + (vi->mergeable_rx_bufs ? 0 : 4); + virtnet_xdp_xmit(vi, rq, &vi->sq[qp], &xdp); + return XDP_TX; default: bpf_warn_invalid_xdp_action(act); - case XDP_TX: case XDP_ABORTED: case XDP_DROP: return XDP_DROP; @@ -390,9 +442,17 @@ static struct sk_buff *receive_big(struct net_device *dev, if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) goto err_xdp; - act = do_xdp_prog(vi, xdp_prog, page, 0, len); - if (act == XDP_DROP) + act = do_xdp_prog(vi, rq, xdp_prog, page, 0, len); + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + rcu_read_unlock(); + goto xdp_xmit; + case XDP_DROP: + default: goto err_xdp; + } } rcu_read_unlock(); @@ -407,6 +467,7 @@ err_xdp: err: dev->stats.rx_dropped++; give_pages(rq, page); +xdp_xmit: return NULL; } @@ -425,6 +486,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, struct bpf_prog *xdp_prog; unsigned int truesize; + head_skb = NULL; + rcu_read_lock(); xdp_prog = rcu_dereference(rq->xdp_prog); if (xdp_prog) { @@ -448,9 +511,17 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) goto err_xdp; - act = do_xdp_prog(vi, xdp_prog, page, offset, len); - if (act == XDP_DROP) + act = do_xdp_prog(vi, rq, xdp_prog, page, offset, len); + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + rcu_read_unlock(); + goto xdp_xmit; + case XDP_DROP: + default: goto err_xdp; + } } rcu_read_unlock(); @@ -528,6 +599,7 @@ err_skb: err_buf: dev->stats.rx_dropped++; dev_kfree_skb(head_skb); +xdp_xmit: return NULL; } @@ -1713,6 +1785,16 @@ static void free_receive_page_frags(struct virtnet_info *vi) put_page(vi->rq[i].alloc_frag.page); } +static bool is_xdp_queue(struct virtnet_info *vi, int q) +{ + if (q < (vi->curr_queue_pairs - vi->xdp_queue_pairs)) + return false; + else if (q < vi->curr_queue_pairs) + return true; + else + return false; +} + static void free_unused_bufs(struct virtnet_info *vi) { void *buf; @@ -1720,8 +1802,12 @@ static void free_unused_bufs(struct virtnet_info *vi) for (i = 0; i < vi->max_queue_pairs; i++) { struct virtqueue *vq = vi->sq[i].vq; - while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) - dev_kfree_skb(buf); + while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) { + if (!is_xdp_queue(vi, i)) + dev_kfree_skb(buf); + else + put_page(virt_to_head_page(buf)); + } } for (i = 0; i < vi->max_queue_pairs; i++) { -- cgit v1.2.3 From 72979a6c35907b6a7ab85e7bc60e0d52dba68f9d Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Thu, 15 Dec 2016 12:14:36 -0800 Subject: virtio_net: xdp, add slowpath case for non contiguous buffers virtio_net XDP support expects receive buffers to be contiguous. If this is not the case we enable a slowpath to allow connectivity to continue but at a significan performance overhead associated with linearizing data. To make it painfully aware to users that XDP is running in a degraded mode we throw an xdp buffer error. To linearize packets we allocate a page and copy the segments of the data, including the header, into it. After this the page can be handled by XDP code flow as normal. Then depending on the return code the page is either freed or sent to the XDP xmit path. There is no attempt to optimize this path. This case is being handled simple as a precaution in case some unknown backend were to generate packets in this form. To test this I had to hack qemu and force it to generate these packets. I do not expect this case to be generated by "real" backends. Signed-off-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index ca3d2e2350c6..08327e005ccc 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -471,6 +471,64 @@ xdp_xmit: return NULL; } +/* The conditions to enable XDP should preclude the underlying device from + * sending packets across multiple buffers (num_buf > 1). However per spec + * it does not appear to be illegal to do so but rather just against convention. + * So in order to avoid making a system unresponsive the packets are pushed + * into a page and the XDP program is run. This will be extremely slow and we + * push a warning to the user to fix this as soon as possible. Fixing this may + * require resolving the underlying hardware to determine why multiple buffers + * are being received or simply loading the XDP program in the ingress stack + * after the skb is built because there is no advantage to running it here + * anymore. + */ +static struct page *xdp_linearize_page(struct receive_queue *rq, + u16 num_buf, + struct page *p, + int offset, + unsigned int *len) +{ + struct page *page = alloc_page(GFP_ATOMIC); + unsigned int page_off = 0; + + if (!page) + return NULL; + + memcpy(page_address(page) + page_off, page_address(p) + offset, *len); + page_off += *len; + + while (--num_buf) { + unsigned int buflen; + unsigned long ctx; + void *buf; + int off; + + ctx = (unsigned long)virtqueue_get_buf(rq->vq, &buflen); + if (unlikely(!ctx)) + goto err_buf; + + /* guard against a misconfigured or uncooperative backend that + * is sending packet larger than the MTU. + */ + if ((page_off + buflen) > PAGE_SIZE) + goto err_buf; + + buf = mergeable_ctx_to_buf_address(ctx); + p = virt_to_head_page(buf); + off = buf - page_address(p); + + memcpy(page_address(page) + page_off, + page_address(p) + off, buflen); + page_off += buflen; + } + + *len = page_off; + return page; +err_buf: + __free_pages(page, 0); + return NULL; +} + static struct sk_buff *receive_mergeable(struct net_device *dev, struct virtnet_info *vi, struct receive_queue *rq, @@ -491,6 +549,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, rcu_read_lock(); xdp_prog = rcu_dereference(rq->xdp_prog); if (xdp_prog) { + struct page *xdp_page; u32 act; /* No known backend devices should send packets with @@ -500,7 +559,15 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, */ if (unlikely(num_buf > 1)) { bpf_warn_invalid_xdp_buffer(); - goto err_xdp; + + /* linearize data for XDP */ + xdp_page = xdp_linearize_page(rq, num_buf, + page, offset, &len); + if (!xdp_page) + goto err_xdp; + offset = 0; + } else { + xdp_page = page; } /* Transient failure which in theory could occur if @@ -514,12 +581,18 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, act = do_xdp_prog(vi, rq, xdp_prog, page, offset, len); switch (act) { case XDP_PASS: + if (unlikely(xdp_page != page)) + __free_pages(xdp_page, 0); break; case XDP_TX: + if (unlikely(xdp_page != page)) + goto err_xdp; rcu_read_unlock(); goto xdp_xmit; case XDP_DROP: default: + if (unlikely(xdp_page != page)) + __free_pages(xdp_page, 0); goto err_xdp; } } -- cgit v1.2.3 From 4794195058b916cabcfaf9f4dfc699e6f48784f7 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 16:58:06 -0800 Subject: isdn/gigaset: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/isdn/gigaset/bas-gigaset.c | 32 ++++++++++++++++---------------- drivers/isdn/gigaset/ser-gigaset.c | 32 ++++++++++++++++---------------- drivers/isdn/gigaset/usb-gigaset.c | 32 ++++++++++++++++---------------- 3 files changed, 48 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index aecec6d32463..11e13c56126f 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -2565,22 +2565,22 @@ static int gigaset_post_reset(struct usb_interface *intf) static const struct gigaset_ops gigops = { - gigaset_write_cmd, - gigaset_write_room, - gigaset_chars_in_buffer, - gigaset_brkchars, - gigaset_init_bchannel, - gigaset_close_bchannel, - gigaset_initbcshw, - gigaset_freebcshw, - gigaset_reinitbcshw, - gigaset_initcshw, - gigaset_freecshw, - gigaset_set_modem_ctrl, - gigaset_baud_rate, - gigaset_set_line_ctrl, - gigaset_isoc_send_skb, - gigaset_isoc_input, + .write_cmd = gigaset_write_cmd, + .write_room = gigaset_write_room, + .chars_in_buffer = gigaset_chars_in_buffer, + .brkchars = gigaset_brkchars, + .init_bchannel = gigaset_init_bchannel, + .close_bchannel = gigaset_close_bchannel, + .initbcshw = gigaset_initbcshw, + .freebcshw = gigaset_freebcshw, + .reinitbcshw = gigaset_reinitbcshw, + .initcshw = gigaset_initcshw, + .freecshw = gigaset_freecshw, + .set_modem_ctrl = gigaset_set_modem_ctrl, + .baud_rate = gigaset_baud_rate, + .set_line_ctrl = gigaset_set_line_ctrl, + .send_skb = gigaset_isoc_send_skb, + .handle_input = gigaset_isoc_input, }; /* bas_gigaset_init diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index b90776ef56ec..ab0b63a4d045 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -445,22 +445,22 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag) } static const struct gigaset_ops ops = { - gigaset_write_cmd, - gigaset_write_room, - gigaset_chars_in_buffer, - gigaset_brkchars, - gigaset_init_bchannel, - gigaset_close_bchannel, - gigaset_initbcshw, - gigaset_freebcshw, - gigaset_reinitbcshw, - gigaset_initcshw, - gigaset_freecshw, - gigaset_set_modem_ctrl, - gigaset_baud_rate, - gigaset_set_line_ctrl, - gigaset_m10x_send_skb, /* asyncdata.c */ - gigaset_m10x_input, /* asyncdata.c */ + .write_cmd = gigaset_write_cmd, + .write_room = gigaset_write_room, + .chars_in_buffer = gigaset_chars_in_buffer, + .brkchars = gigaset_brkchars, + .init_bchannel = gigaset_init_bchannel, + .close_bchannel = gigaset_close_bchannel, + .initbcshw = gigaset_initbcshw, + .freebcshw = gigaset_freebcshw, + .reinitbcshw = gigaset_reinitbcshw, + .initcshw = gigaset_initcshw, + .freecshw = gigaset_freecshw, + .set_modem_ctrl = gigaset_set_modem_ctrl, + .baud_rate = gigaset_baud_rate, + .set_line_ctrl = gigaset_set_line_ctrl, + .send_skb = gigaset_m10x_send_skb, /* asyncdata.c */ + .handle_input = gigaset_m10x_input, /* asyncdata.c */ }; diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 5f306e2eece5..eade36dafa34 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -862,22 +862,22 @@ static int gigaset_pre_reset(struct usb_interface *intf) } static const struct gigaset_ops ops = { - gigaset_write_cmd, - gigaset_write_room, - gigaset_chars_in_buffer, - gigaset_brkchars, - gigaset_init_bchannel, - gigaset_close_bchannel, - gigaset_initbcshw, - gigaset_freebcshw, - gigaset_reinitbcshw, - gigaset_initcshw, - gigaset_freecshw, - gigaset_set_modem_ctrl, - gigaset_baud_rate, - gigaset_set_line_ctrl, - gigaset_m10x_send_skb, - gigaset_m10x_input, + .write_cmd = gigaset_write_cmd, + .write_room = gigaset_write_room, + .chars_in_buffer = gigaset_chars_in_buffer, + .brkchars = gigaset_brkchars, + .init_bchannel = gigaset_init_bchannel, + .close_bchannel = gigaset_close_bchannel, + .initbcshw = gigaset_initbcshw, + .freebcshw = gigaset_freebcshw, + .reinitbcshw = gigaset_reinitbcshw, + .initcshw = gigaset_initcshw, + .freecshw = gigaset_freecshw, + .set_modem_ctrl = gigaset_set_modem_ctrl, + .baud_rate = gigaset_baud_rate, + .set_line_ctrl = gigaset_set_line_ctrl, + .send_skb = gigaset_m10x_send_skb, + .handle_input = gigaset_m10x_input, }; /* -- cgit v1.2.3 From aabd7ad949247ef315fa5086d2caad7885567434 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 16:59:18 -0800 Subject: WAN: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/wan/lmc/lmc_media.c | 97 +++++++++++++++++++++-------------------- 1 file changed, 49 insertions(+), 48 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index 5920c996fcdf..ff2e4a5654c7 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -95,62 +95,63 @@ static inline void write_av9110_bit (lmc_softc_t *, int); static void write_av9110(lmc_softc_t *, u32, u32, u32, u32, u32); lmc_media_t lmc_ds3_media = { - lmc_ds3_init, /* special media init stuff */ - lmc_ds3_default, /* reset to default state */ - lmc_ds3_set_status, /* reset status to state provided */ - lmc_dummy_set_1, /* set clock source */ - lmc_dummy_set2_1, /* set line speed */ - lmc_ds3_set_100ft, /* set cable length */ - lmc_ds3_set_scram, /* set scrambler */ - lmc_ds3_get_link_status, /* get link status */ - lmc_dummy_set_1, /* set link status */ - lmc_ds3_set_crc_length, /* set CRC length */ - lmc_dummy_set_1, /* set T1 or E1 circuit type */ - lmc_ds3_watchdog + .init = lmc_ds3_init, /* special media init stuff */ + .defaults = lmc_ds3_default, /* reset to default state */ + .set_status = lmc_ds3_set_status, /* reset status to state provided */ + .set_clock_source = lmc_dummy_set_1, /* set clock source */ + .set_speed = lmc_dummy_set2_1, /* set line speed */ + .set_cable_length = lmc_ds3_set_100ft, /* set cable length */ + .set_scrambler = lmc_ds3_set_scram, /* set scrambler */ + .get_link_status = lmc_ds3_get_link_status, /* get link status */ + .set_link_status = lmc_dummy_set_1, /* set link status */ + .set_crc_length = lmc_ds3_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */ + .watchdog = lmc_ds3_watchdog }; lmc_media_t lmc_hssi_media = { - lmc_hssi_init, /* special media init stuff */ - lmc_hssi_default, /* reset to default state */ - lmc_hssi_set_status, /* reset status to state provided */ - lmc_hssi_set_clock, /* set clock source */ - lmc_dummy_set2_1, /* set line speed */ - lmc_dummy_set_1, /* set cable length */ - lmc_dummy_set_1, /* set scrambler */ - lmc_hssi_get_link_status, /* get link status */ - lmc_hssi_set_link_status, /* set link status */ - lmc_hssi_set_crc_length, /* set CRC length */ - lmc_dummy_set_1, /* set T1 or E1 circuit type */ - lmc_hssi_watchdog + .init = lmc_hssi_init, /* special media init stuff */ + .defaults = lmc_hssi_default, /* reset to default state */ + .set_status = lmc_hssi_set_status, /* reset status to state provided */ + .set_clock_source = lmc_hssi_set_clock, /* set clock source */ + .set_speed = lmc_dummy_set2_1, /* set line speed */ + .set_cable_length = lmc_dummy_set_1, /* set cable length */ + .set_scrambler = lmc_dummy_set_1, /* set scrambler */ + .get_link_status = lmc_hssi_get_link_status, /* get link status */ + .set_link_status = lmc_hssi_set_link_status, /* set link status */ + .set_crc_length = lmc_hssi_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */ + .watchdog = lmc_hssi_watchdog }; -lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */ - lmc_ssi_default, /* reset to default state */ - lmc_ssi_set_status, /* reset status to state provided */ - lmc_ssi_set_clock, /* set clock source */ - lmc_ssi_set_speed, /* set line speed */ - lmc_dummy_set_1, /* set cable length */ - lmc_dummy_set_1, /* set scrambler */ - lmc_ssi_get_link_status, /* get link status */ - lmc_ssi_set_link_status, /* set link status */ - lmc_ssi_set_crc_length, /* set CRC length */ - lmc_dummy_set_1, /* set T1 or E1 circuit type */ - lmc_ssi_watchdog +lmc_media_t lmc_ssi_media = { + .init = lmc_ssi_init, /* special media init stuff */ + .defaults = lmc_ssi_default, /* reset to default state */ + .set_status = lmc_ssi_set_status, /* reset status to state provided */ + .set_clock_source = lmc_ssi_set_clock, /* set clock source */ + .set_speed = lmc_ssi_set_speed, /* set line speed */ + .set_cable_length = lmc_dummy_set_1, /* set cable length */ + .set_scrambler = lmc_dummy_set_1, /* set scrambler */ + .get_link_status = lmc_ssi_get_link_status, /* get link status */ + .set_link_status = lmc_ssi_set_link_status, /* set link status */ + .set_crc_length = lmc_ssi_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_dummy_set_1, /* set T1 or E1 circuit type */ + .watchdog = lmc_ssi_watchdog }; lmc_media_t lmc_t1_media = { - lmc_t1_init, /* special media init stuff */ - lmc_t1_default, /* reset to default state */ - lmc_t1_set_status, /* reset status to state provided */ - lmc_t1_set_clock, /* set clock source */ - lmc_dummy_set2_1, /* set line speed */ - lmc_dummy_set_1, /* set cable length */ - lmc_dummy_set_1, /* set scrambler */ - lmc_t1_get_link_status, /* get link status */ - lmc_dummy_set_1, /* set link status */ - lmc_t1_set_crc_length, /* set CRC length */ - lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ - lmc_t1_watchdog + .init = lmc_t1_init, /* special media init stuff */ + .defaults = lmc_t1_default, /* reset to default state */ + .set_status = lmc_t1_set_status, /* reset status to state provided */ + .set_clock_source = lmc_t1_set_clock, /* set clock source */ + .set_speed = lmc_dummy_set2_1, /* set line speed */ + .set_cable_length = lmc_dummy_set_1, /* set cable length */ + .set_scrambler = lmc_dummy_set_1, /* set scrambler */ + .get_link_status = lmc_t1_get_link_status, /* get link status */ + .set_link_status = lmc_dummy_set_1, /* set link status */ + .set_crc_length = lmc_t1_set_crc_length, /* set CRC length */ + .set_circuit_type = lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */ + .watchdog = lmc_t1_watchdog }; static void -- cgit v1.2.3 From 9751362a4fe7ad37115d20344ce6d914a088268d Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 17:00:54 -0800 Subject: bna: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/net/ethernet/brocade/bna/bna_enet.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/brocade/bna/bna_enet.c b/drivers/net/ethernet/brocade/bna/bna_enet.c index 4e5c3874a50f..bba81735ce87 100644 --- a/drivers/net/ethernet/brocade/bna/bna_enet.c +++ b/drivers/net/ethernet/brocade/bna/bna_enet.c @@ -1676,10 +1676,10 @@ bna_cb_ioceth_reset(void *arg) } static struct bfa_ioc_cbfn bna_ioceth_cbfn = { - bna_cb_ioceth_enable, - bna_cb_ioceth_disable, - bna_cb_ioceth_hbfail, - bna_cb_ioceth_reset + .enable_cbfn = bna_cb_ioceth_enable, + .disable_cbfn = bna_cb_ioceth_disable, + .hbfail_cbfn = bna_cb_ioceth_hbfail, + .reset_cbfn = bna_cb_ioceth_reset }; static void bna_attr_init(struct bna_ioceth *ioceth) -- cgit v1.2.3 From ebf12f1320c70c3eaeb5b7d108444fafd54d352c Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 16 Dec 2016 17:01:42 -0800 Subject: isdn: use designated initializers Prepare to mark sensitive kernel structures for randomization by making sure they're using designated initializers. These were identified during allyesconfig builds of x86, arm, and arm64, with most initializer fixes extracted from grsecurity. Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/isdn/i4l/isdn_concap.c | 6 +++--- drivers/isdn/i4l/isdn_x25iface.c | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c index 91d57304d4d3..336523ec077c 100644 --- a/drivers/isdn/i4l/isdn_concap.c +++ b/drivers/isdn/i4l/isdn_concap.c @@ -80,9 +80,9 @@ static int isdn_concap_dl_disconn_req(struct concap_proto *concap) } struct concap_device_ops isdn_concap_reliable_dl_dops = { - &isdn_concap_dl_data_req, - &isdn_concap_dl_connect_req, - &isdn_concap_dl_disconn_req + .data_req = &isdn_concap_dl_data_req, + .connect_req = &isdn_concap_dl_connect_req, + .disconn_req = &isdn_concap_dl_disconn_req }; /* The following should better go into a dedicated source file such that diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c index 0c5d8de41b23..ba60076e0b95 100644 --- a/drivers/isdn/i4l/isdn_x25iface.c +++ b/drivers/isdn/i4l/isdn_x25iface.c @@ -53,14 +53,14 @@ static int isdn_x25iface_disconn_ind(struct concap_proto *); static struct concap_proto_ops ix25_pops = { - &isdn_x25iface_proto_new, - &isdn_x25iface_proto_del, - &isdn_x25iface_proto_restart, - &isdn_x25iface_proto_close, - &isdn_x25iface_xmit, - &isdn_x25iface_receive, - &isdn_x25iface_connect_ind, - &isdn_x25iface_disconn_ind + .proto_new = &isdn_x25iface_proto_new, + .proto_del = &isdn_x25iface_proto_del, + .restart = &isdn_x25iface_proto_restart, + .close = &isdn_x25iface_proto_close, + .encap_and_xmit = &isdn_x25iface_xmit, + .data_ind = &isdn_x25iface_receive, + .connect_ind = &isdn_x25iface_connect_ind, + .disconn_ind = &isdn_x25iface_disconn_ind }; /* error message helper function */ -- cgit v1.2.3 From 88edf10315c8d72db70d39f3851cf2c91abdb634 Mon Sep 17 00:00:00 2001 From: Lionel Gauthier Date: Thu, 15 Dec 2016 22:35:52 +0100 Subject: gtp: gtp_check_src_ms_ipv4() always return success gtp_check_src_ms_ipv4() did not find the PDP context matching with the UE IP address because the memory location is not right, but the result is inverted by the Boolean "not" operator. So whatever is the PDP context, any call to this function is successful. Signed-off-by: Lionel Gauthier Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- drivers/net/gtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 98f10c216521..6031d499f2be 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -158,9 +158,9 @@ static bool gtp_check_src_ms_ipv4(struct sk_buff *skb, struct pdp_ctx *pctx, if (!pskb_may_pull(skb, hdrlen + sizeof(struct iphdr))) return false; - iph = (struct iphdr *)(skb->data + hdrlen + sizeof(struct iphdr)); + iph = (struct iphdr *)(skb->data + hdrlen); - return iph->saddr != pctx->ms_addr_ip4.s_addr; + return iph->saddr == pctx->ms_addr_ip4.s_addr; } /* Check if the inner IP source address in this packet is assigned to any -- cgit v1.2.3 From d928be81b44dc3cad75d7a9f9fcbe99725dc7e56 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Thu, 15 Dec 2016 22:35:53 +0100 Subject: gtp: Fix initialization of Flags octet in GTPv1 header When generating a GTPv1 header in gtp1_push_header(), initialize the 'reserved' bit to zero. All 3GPP specifications for GTPv1 from Release 99 through Release 13 agree that a transmitter shall set this bit to zero, see e.g. Note 0 of Figure 2 in Section 6 of 3GPP TS 29.060 v13.5.0 Release 13, available from http://www.etsi.org/deliver/etsi_ts/129000_129099/129060/13.05.00_60/ts_129060v130500p.pdf Signed-off-by: Harald Welte Signed-off-by: Pablo Neira Ayuso Signed-off-by: David S. Miller --- drivers/net/gtp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/gtp.c b/drivers/net/gtp.c index 6031d499f2be..8b6810bad54b 100644 --- a/drivers/net/gtp.c +++ b/drivers/net/gtp.c @@ -423,11 +423,11 @@ static inline void gtp1_push_header(struct sk_buff *skb, struct pdp_ctx *pctx) /* Bits 8 7 6 5 4 3 2 1 * +--+--+--+--+--+--+--+--+ - * |version |PT| 1| E| S|PN| + * |version |PT| 0| E| S|PN| * +--+--+--+--+--+--+--+--+ * 0 0 1 1 1 0 0 0 */ - gtp1->flags = 0x38; /* v1, GTP-non-prime. */ + gtp1->flags = 0x30; /* v1, GTP-non-prime. */ gtp1->type = GTP_TPDU; gtp1->length = htons(payload_len); gtp1->tid = htonl(pctx->u.v1.o_tei); -- cgit v1.2.3 From 493ff7e2cdda9182fb709d3681315180d9165bd8 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Fri, 9 Dec 2016 10:31:57 +0100 Subject: i2c: octeon: thunderx: Limit register access retries Do not infinitely retry register readq and writeq operations in order to not lock up the CPU in case the TWSI gets stuck. Return -EIO in case of a failed data read. For all other cases just return so subsequent operations will fail and trigger the recovery. Signed-off-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-octeon-core.c | 4 +++- drivers/i2c/busses/i2c-octeon-core.h | 21 ++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 3d10f1a802be..1d8775799056 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -342,7 +342,9 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, if (result) return result; - data[i] = octeon_i2c_data_read(i2c); + data[i] = octeon_i2c_data_read(i2c, &result); + if (result) + return result; if (recv_len && i == 0) { if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) return -EPROTO; diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index 87151ea74acd..e160f838c254 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -141,11 +141,14 @@ static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr) */ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data) { + int tries = 1000; u64 tmp; __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c)); do { tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + if (--tries < 0) + return; } while ((tmp & SW_TWSI_V) != 0); } @@ -163,24 +166,32 @@ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 * * The I2C core registers are accessed indirectly via the SW_TWSI CSR. */ -static inline u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg) +static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg, + int *error) { + int tries = 1000; u64 tmp; __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c)); do { tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + if (--tries < 0) { + /* signal that the returned data is invalid */ + if (error) + *error = -EIO; + return 0; + } } while ((tmp & SW_TWSI_V) != 0); return tmp & 0xFF; } #define octeon_i2c_ctl_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL) -#define octeon_i2c_data_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA) + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL) +#define octeon_i2c_data_read(i2c, error) \ + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error) #define octeon_i2c_stat_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT) + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL) /** * octeon_i2c_read_int - read the TWSI_INT register -- cgit v1.2.3 From 7f638c1cb0a1112dbe0b682a42db30521646686b Mon Sep 17 00:00:00 2001 From: Russell King Date: Sat, 17 Dec 2016 12:10:56 +0000 Subject: i2c: mux: pca954x: fix i2c mux selection caching smbus functions return -ve on error, 0 on success. However, __i2c_transfer() have a different return signature - -ve on error, or number of buffers transferred (which may be zero or greater.) The upshot of this is that the sense of the test is reversed when using the mux on a bus supporting the master_xfer method: we cache the value and never retry if we fail to transfer any buffers, but if we succeed, we clear the cached value. Fix this by making pca954x_reg_write() return a negative error code for all failure cases. Fixes: 463e8f845cbf ("i2c: mux: pca954x: retry updating the mux selection on failure") Acked-by: Peter Rosin Signed-off-by: Russell King Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 9a348ee4dc14..dd18b9ccb1f4 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -167,6 +167,9 @@ static int pca954x_reg_write(struct i2c_adapter *adap, buf[0] = val; msg.buf = buf; ret = __i2c_transfer(adap, &msg, 1); + + if (ret >= 0 && ret != 1) + ret = -EREMOTEIO; } else { union i2c_smbus_data data; ret = adap->algo->smbus_xfer(adap, client->addr, @@ -195,7 +198,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) /* Only select the channel if its different from the last channel */ if (data->last_chan != regval) { ret = pca954x_reg_write(muxc->parent, client, regval); - data->last_chan = ret ? 0 : regval; + data->last_chan = ret < 0 ? 0 : regval; } return ret; -- cgit v1.2.3 From 1635c5d04ea9343f0e3c74709c29995a23801ecd Mon Sep 17 00:00:00 2001 From: Tin Huynh Date: Wed, 14 Dec 2016 14:17:26 +0700 Subject: i2c: xgene: Fix missing code of DTB support In DTB case, i2c-core doesn't create slave device which is installed on i2c-xgene bus because of missing code in this driver. This patch fixes this issue. Signed-off-by: Tin Huynh Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-xgene-slimpro.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 05cf192ef1ac..0ab1e55558bc 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -415,6 +415,7 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) adapter->algo = &xgene_slimpro_i2c_algorithm; adapter->class = I2C_CLASS_HWMON; adapter->dev.parent = &pdev->dev; + adapter->dev.of_node = pdev->dev.of_node; i2c_set_adapdata(adapter, ctx); rc = i2c_add_adapter(adapter); if (rc) { -- cgit v1.2.3 From 8e598769c55dd6c442a1c6cbd21e7abda2a52215 Mon Sep 17 00:00:00 2001 From: Tin Huynh Date: Wed, 14 Dec 2016 16:23:58 +0700 Subject: i2c: designware: fix wrong Tx/Rx FIFO for ACPI ACPI always sets Tx/Rx FIFO to 32. This configuration will cause problem if the IP core supports a FIFO size of less than 32. The driver should read the FIFO size from the IP and select the smaller one of the two. Signed-off-by: Tin Huynh Acked-by: Jarkko Nikula Reviewed-by: Mika Westerberg Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 31 ++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 08153ea4d848..6ce431323125 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -150,6 +150,29 @@ static int i2c_dw_plat_prepare_clk(struct dw_i2c_dev *i_dev, bool prepare) return 0; } +static void dw_i2c_set_fifo_size(struct dw_i2c_dev *dev, int id) +{ + u32 param, tx_fifo_depth, rx_fifo_depth; + + /* + * Try to detect the FIFO depth if not set by interface driver, + * the depth could be from 2 to 256 from HW spec. + */ + param = i2c_dw_read_comp_param(dev); + tx_fifo_depth = ((param >> 16) & 0xff) + 1; + rx_fifo_depth = ((param >> 8) & 0xff) + 1; + if (!dev->tx_fifo_depth) { + dev->tx_fifo_depth = tx_fifo_depth; + dev->rx_fifo_depth = rx_fifo_depth; + dev->adapter.nr = id; + } else if (tx_fifo_depth >= 2) { + dev->tx_fifo_depth = min_t(u32, dev->tx_fifo_depth, + tx_fifo_depth); + dev->rx_fifo_depth = min_t(u32, dev->rx_fifo_depth, + rx_fifo_depth); + } +} + static int dw_i2c_plat_probe(struct platform_device *pdev) { struct dw_i2c_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -245,13 +268,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) 1000000); } - if (!dev->tx_fifo_depth) { - u32 param1 = i2c_dw_read_comp_param(dev); - - dev->tx_fifo_depth = ((param1 >> 16) & 0xff) + 1; - dev->rx_fifo_depth = ((param1 >> 8) & 0xff) + 1; - dev->adapter.nr = pdev->id; - } + dw_i2c_set_fifo_size(dev, pdev->id); adap = &dev->adapter; adap->owner = THIS_MODULE; -- cgit v1.2.3 From be628be09563f8f6e81929efbd7cf3f45c344416 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Wed, 26 Oct 2016 20:31:17 -0700 Subject: bcache: Make gc wakeup sane, remove set_task_state() Signed-off-by: Kent Overstreet --- drivers/md/bcache/bcache.h | 4 ++-- drivers/md/bcache/btree.c | 39 ++++++++++++++++++++------------------- drivers/md/bcache/btree.h | 3 +-- drivers/md/bcache/request.c | 4 +--- drivers/md/bcache/super.c | 2 ++ 5 files changed, 26 insertions(+), 26 deletions(-) (limited to 'drivers') diff --git a/drivers/md/bcache/bcache.h b/drivers/md/bcache/bcache.h index 6b420a55c745..c3ea03c9a1a8 100644 --- a/drivers/md/bcache/bcache.h +++ b/drivers/md/bcache/bcache.h @@ -425,7 +425,7 @@ struct cache { * until a gc finishes - otherwise we could pointlessly burn a ton of * cpu */ - unsigned invalidate_needs_gc:1; + unsigned invalidate_needs_gc; bool discard; /* Get rid of? */ @@ -593,8 +593,8 @@ struct cache_set { /* Counts how many sectors bio_insert has added to the cache */ atomic_t sectors_to_gc; + wait_queue_head_t gc_wait; - wait_queue_head_t moving_gc_wait; struct keybuf moving_gc_keys; /* Number of moving GC bios in flight */ struct semaphore moving_in_flight; diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 6fdd8e252760..a43eedd5804d 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -1757,32 +1757,34 @@ static void bch_btree_gc(struct cache_set *c) bch_moving_gc(c); } -static int bch_gc_thread(void *arg) +static bool gc_should_run(struct cache_set *c) { - struct cache_set *c = arg; struct cache *ca; unsigned i; - while (1) { -again: - bch_btree_gc(c); + for_each_cache(ca, c, i) + if (ca->invalidate_needs_gc) + return true; - set_current_state(TASK_INTERRUPTIBLE); - if (kthread_should_stop()) - break; + if (atomic_read(&c->sectors_to_gc) < 0) + return true; - mutex_lock(&c->bucket_lock); + return false; +} - for_each_cache(ca, c, i) - if (ca->invalidate_needs_gc) { - mutex_unlock(&c->bucket_lock); - set_current_state(TASK_RUNNING); - goto again; - } +static int bch_gc_thread(void *arg) +{ + struct cache_set *c = arg; - mutex_unlock(&c->bucket_lock); + while (1) { + wait_event_interruptible(c->gc_wait, + kthread_should_stop() || gc_should_run(c)); - schedule(); + if (kthread_should_stop()) + break; + + set_gc_sectors(c); + bch_btree_gc(c); } return 0; @@ -1790,11 +1792,10 @@ again: int bch_gc_thread_start(struct cache_set *c) { - c->gc_thread = kthread_create(bch_gc_thread, c, "bcache_gc"); + c->gc_thread = kthread_run(bch_gc_thread, c, "bcache_gc"); if (IS_ERR(c->gc_thread)) return PTR_ERR(c->gc_thread); - set_task_state(c->gc_thread, TASK_INTERRUPTIBLE); return 0; } diff --git a/drivers/md/bcache/btree.h b/drivers/md/bcache/btree.h index 5c391fa01bed..9b80417cd547 100644 --- a/drivers/md/bcache/btree.h +++ b/drivers/md/bcache/btree.h @@ -260,8 +260,7 @@ void bch_initial_mark_key(struct cache_set *, int, struct bkey *); static inline void wake_up_gc(struct cache_set *c) { - if (c->gc_thread) - wake_up_process(c->gc_thread); + wake_up(&c->gc_wait); } #define MAP_DONE 0 diff --git a/drivers/md/bcache/request.c b/drivers/md/bcache/request.c index f49c5417527d..76d20875503c 100644 --- a/drivers/md/bcache/request.c +++ b/drivers/md/bcache/request.c @@ -196,10 +196,8 @@ static void bch_data_insert_start(struct closure *cl) struct data_insert_op *op = container_of(cl, struct data_insert_op, cl); struct bio *bio = op->bio, *n; - if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) { - set_gc_sectors(op->c); + if (atomic_sub_return(bio_sectors(bio), &op->c->sectors_to_gc) < 0) wake_up_gc(op->c); - } if (op->bypass) return bch_data_invalidate(cl); diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index 2fb5bfeb43e2..b33dd3bd104f 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -1489,6 +1489,7 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb) mutex_init(&c->bucket_lock); init_waitqueue_head(&c->btree_cache_wait); init_waitqueue_head(&c->bucket_wait); + init_waitqueue_head(&c->gc_wait); sema_init(&c->uuid_write_mutex, 1); spin_lock_init(&c->btree_gc_time.lock); @@ -1548,6 +1549,7 @@ static void run_cache_set(struct cache_set *c) for_each_cache(ca, c, i) c->nbuckets += ca->sb.nbuckets; + set_gc_sectors(c); if (CACHE_SYNC(&c->sb)) { LIST_HEAD(journal); -- cgit v1.2.3 From b8c0d911ac5285e6be8967713271a51bdc5a936a Mon Sep 17 00:00:00 2001 From: Eric Wheeler Date: Sun, 23 Oct 2016 18:19:20 -0700 Subject: bcache: partition support: add 16 minors per bcacheN device Signed-off-by: Eric Wheeler Tested-by: Wido den Hollander --- drivers/md/bcache/super.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/md/bcache/super.c b/drivers/md/bcache/super.c index b33dd3bd104f..3a19cbc8b230 100644 --- a/drivers/md/bcache/super.c +++ b/drivers/md/bcache/super.c @@ -58,6 +58,7 @@ static wait_queue_head_t unregister_wait; struct workqueue_struct *bcache_wq; #define BTREE_MAX_PAGES (256 * 1024 / PAGE_SIZE) +#define BCACHE_MINORS 16 /* partition support */ /* Superblock */ @@ -783,8 +784,10 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size, if (minor < 0) return minor; + minor *= BCACHE_MINORS; + if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) || - !(d->disk = alloc_disk(1))) { + !(d->disk = alloc_disk(BCACHE_MINORS))) { ida_simple_remove(&bcache_minor, minor); return -ENOMEM; } -- cgit v1.2.3 From d7fe1a67f658b50ec98ee1afb86df7b35c2b2593 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Sat, 17 Dec 2016 14:50:04 -0800 Subject: dax: add region 'id', 'size', and 'align' attributes While this information is available by looking at the nvdimm parent device that may not always be the case when/if we add support for other memory regions. Tooling should not depend on walking a given ancestor topology that is not guaranteed by the device's class. For example, a device-dax instance will always have a dax_region parent, but it may not always have a libnvdimm "dax" device as a grandparent. Reported-by: Johannes Thumshirn Signed-off-by: Dan Williams --- drivers/dax/dax.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) (limited to 'drivers') diff --git a/drivers/dax/dax.c b/drivers/dax/dax.c index 0e499bfca41c..369fccda3b1b 100644 --- a/drivers/dax/dax.c +++ b/drivers/dax/dax.c @@ -75,6 +75,73 @@ struct dax_dev { struct resource res[0]; }; +static ssize_t id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dax_region *dax_region; + ssize_t rc = -ENXIO; + + device_lock(dev); + dax_region = dev_get_drvdata(dev); + if (dax_region) + rc = sprintf(buf, "%d\n", dax_region->id); + device_unlock(dev); + + return rc; +} +static DEVICE_ATTR_RO(id); + +static ssize_t region_size_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dax_region *dax_region; + ssize_t rc = -ENXIO; + + device_lock(dev); + dax_region = dev_get_drvdata(dev); + if (dax_region) + rc = sprintf(buf, "%llu\n", (unsigned long long) + resource_size(&dax_region->res)); + device_unlock(dev); + + return rc; +} +static struct device_attribute dev_attr_region_size = __ATTR(size, 0444, + region_size_show, NULL); + +static ssize_t align_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dax_region *dax_region; + ssize_t rc = -ENXIO; + + device_lock(dev); + dax_region = dev_get_drvdata(dev); + if (dax_region) + rc = sprintf(buf, "%u\n", dax_region->align); + device_unlock(dev); + + return rc; +} +static DEVICE_ATTR_RO(align); + +static struct attribute *dax_region_attributes[] = { + &dev_attr_region_size.attr, + &dev_attr_align.attr, + &dev_attr_id.attr, + NULL, +}; + +static const struct attribute_group dax_region_attribute_group = { + .name = "dax_region", + .attrs = dax_region_attributes, +}; + +static const struct attribute_group *dax_region_attribute_groups[] = { + &dax_region_attribute_group, + NULL, +}; + static struct inode *dax_alloc_inode(struct super_block *sb) { return kmem_cache_alloc(dax_cache, GFP_KERNEL); @@ -200,12 +267,31 @@ void dax_region_put(struct dax_region *dax_region) } EXPORT_SYMBOL_GPL(dax_region_put); +static void dax_region_unregister(void *region) +{ + struct dax_region *dax_region = region; + + sysfs_remove_groups(&dax_region->dev->kobj, + dax_region_attribute_groups); + dax_region_put(dax_region); +} + struct dax_region *alloc_dax_region(struct device *parent, int region_id, struct resource *res, unsigned int align, void *addr, unsigned long pfn_flags) { struct dax_region *dax_region; + /* + * The DAX core assumes that it can store its private data in + * parent->driver_data. This WARN is a reminder / safeguard for + * developers of device-dax drivers. + */ + if (dev_get_drvdata(parent)) { + dev_WARN(parent, "dax core failed to setup private data\n"); + return NULL; + } + if (!IS_ALIGNED(res->start, align) || !IS_ALIGNED(resource_size(res), align)) return NULL; @@ -214,6 +300,7 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, if (!dax_region) return NULL; + dev_set_drvdata(parent, dax_region); memcpy(&dax_region->res, res, sizeof(*res)); dax_region->pfn_flags = pfn_flags; kref_init(&dax_region->kref); @@ -222,7 +309,14 @@ struct dax_region *alloc_dax_region(struct device *parent, int region_id, dax_region->align = align; dax_region->dev = parent; dax_region->base = addr; + if (sysfs_create_groups(&parent->kobj, dax_region_attribute_groups)) { + kfree(dax_region); + return NULL;; + } + kref_get(&dax_region->kref); + if (devm_add_action_or_reset(parent, dax_region_unregister, dax_region)) + return NULL; return dax_region; } EXPORT_SYMBOL_GPL(alloc_dax_region); -- cgit v1.2.3 From 49cad93909b18acf942b70356e65eeeaa9ca9d23 Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Sun, 11 Dec 2016 22:47:50 +0100 Subject: net: chelsio: cxgb2: use new api ethtool_{get|set}_link_ksettings The ethtool api {get|set}_settings is deprecated. We move this driver to new api {get|set}_link_ksettings. Signed-off-by: Philippe Reynes Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 64 ++++++++++++++++++------------- 1 file changed, 37 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c index 81d1d0bc7553..3a05f9098e75 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c @@ -568,28 +568,33 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs, reg_block_dump(ap, buf, A_MC5_CONFIG, A_MC5_MASK_WRITE_CMD); } -static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; + u32 supported, advertising; - cmd->supported = p->link_config.supported; - cmd->advertising = p->link_config.advertising; + supported = p->link_config.supported; + advertising = p->link_config.advertising; if (netif_carrier_ok(dev)) { - ethtool_cmd_speed_set(cmd, p->link_config.speed); - cmd->duplex = p->link_config.duplex; + cmd->base.speed = p->link_config.speed; + cmd->base.duplex = p->link_config.duplex; } else { - ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); - cmd->duplex = DUPLEX_UNKNOWN; + cmd->base.speed = SPEED_UNKNOWN; + cmd->base.duplex = DUPLEX_UNKNOWN; } - cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy->mdio.prtad; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = p->link_config.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; + cmd->base.port = (supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; + cmd->base.phy_address = p->phy->mdio.prtad; + cmd->base.autoneg = p->link_config.autoneg; + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); + return 0; } @@ -628,36 +633,41 @@ static int speed_duplex_to_caps(int speed, int duplex) ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ ADVERTISED_10000baseT_Full) -static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct link_config *lc = &p->link_config; + u32 advertising; + + ethtool_convert_link_mode_to_legacy_u32(&advertising, + cmd->link_modes.advertising); if (!(lc->supported & SUPPORTED_Autoneg)) return -EOPNOTSUPP; /* can't change speed/duplex */ - if (cmd->autoneg == AUTONEG_DISABLE) { - u32 speed = ethtool_cmd_speed(cmd); - int cap = speed_duplex_to_caps(speed, cmd->duplex); + if (cmd->base.autoneg == AUTONEG_DISABLE) { + u32 speed = cmd->base.speed; + int cap = speed_duplex_to_caps(speed, cmd->base.duplex); if (!(lc->supported & cap) || (speed == SPEED_1000)) return -EINVAL; lc->requested_speed = speed; - lc->requested_duplex = cmd->duplex; + lc->requested_duplex = cmd->base.duplex; lc->advertising = 0; } else { - cmd->advertising &= ADVERTISED_MASK; - if (cmd->advertising & (cmd->advertising - 1)) - cmd->advertising = lc->supported; - cmd->advertising &= lc->supported; - if (!cmd->advertising) + advertising &= ADVERTISED_MASK; + if (advertising & (advertising - 1)) + advertising = lc->supported; + advertising &= lc->supported; + if (!advertising) return -EINVAL; lc->requested_speed = SPEED_INVALID; lc->requested_duplex = DUPLEX_INVALID; - lc->advertising = cmd->advertising | ADVERTISED_Autoneg; + lc->advertising = advertising | ADVERTISED_Autoneg; } - lc->autoneg = cmd->autoneg; + lc->autoneg = cmd->base.autoneg; if (netif_running(dev)) t1_link_start(p->phy, p->mac, lc); return 0; @@ -788,8 +798,6 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, } static const struct ethtool_ops t1_ethtool_ops = { - .get_settings = get_settings, - .set_settings = set_settings, .get_drvinfo = get_drvinfo, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, @@ -807,6 +815,8 @@ static const struct ethtool_ops t1_ethtool_ops = { .get_ethtool_stats = get_stats, .get_regs_len = get_regs_len, .get_regs = get_regs, + .get_link_ksettings = get_link_ksettings, + .set_link_ksettings = set_link_ksettings, }; static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) -- cgit v1.2.3 From b7b44fd23e6d2a896c6efbe85b39862f14aae11a Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Mon, 12 Dec 2016 00:27:49 +0100 Subject: net: chelsio: cxgb3: use new api ethtool_{get|set}_link_ksettings The ethtool api {get|set}_settings is deprecated. We move this driver to new api {get|set}_link_ksettings. Signed-off-by: Philippe Reynes Signed-off-by: David S. Miller --- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 65 ++++++++++++++----------- 1 file changed, 37 insertions(+), 28 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 092b3c16440b..7b2224ae72f2 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -1801,27 +1801,31 @@ static int set_phys_id(struct net_device *dev, return 0; } -static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct port_info *p = netdev_priv(dev); + u32 supported; - cmd->supported = p->link_config.supported; - cmd->advertising = p->link_config.advertising; + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + p->link_config.supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + p->link_config.advertising); if (netif_carrier_ok(dev)) { - ethtool_cmd_speed_set(cmd, p->link_config.speed); - cmd->duplex = p->link_config.duplex; + cmd->base.speed = p->link_config.speed; + cmd->base.duplex = p->link_config.duplex; } else { - ethtool_cmd_speed_set(cmd, SPEED_UNKNOWN); - cmd->duplex = DUPLEX_UNKNOWN; + cmd->base.speed = SPEED_UNKNOWN; + cmd->base.duplex = DUPLEX_UNKNOWN; } - cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; - cmd->phy_address = p->phy.mdio.prtad; - cmd->transceiver = XCVR_EXTERNAL; - cmd->autoneg = p->link_config.autoneg; - cmd->maxtxpkt = 0; - cmd->maxrxpkt = 0; + ethtool_convert_link_mode_to_legacy_u32(&supported, + cmd->link_modes.supported); + + cmd->base.port = (supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE; + cmd->base.phy_address = p->phy.mdio.prtad; + cmd->base.autoneg = p->link_config.autoneg; return 0; } @@ -1860,44 +1864,49 @@ static int speed_duplex_to_caps(int speed, int duplex) ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \ ADVERTISED_10000baseT_Full) -static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct port_info *p = netdev_priv(dev); struct link_config *lc = &p->link_config; + u32 advertising; + + ethtool_convert_link_mode_to_legacy_u32(&advertising, + cmd->link_modes.advertising); if (!(lc->supported & SUPPORTED_Autoneg)) { /* * PHY offers a single speed/duplex. See if that's what's * being requested. */ - if (cmd->autoneg == AUTONEG_DISABLE) { - u32 speed = ethtool_cmd_speed(cmd); - int cap = speed_duplex_to_caps(speed, cmd->duplex); + if (cmd->base.autoneg == AUTONEG_DISABLE) { + u32 speed = cmd->base.speed; + int cap = speed_duplex_to_caps(speed, cmd->base.duplex); if (lc->supported & cap) return 0; } return -EINVAL; } - if (cmd->autoneg == AUTONEG_DISABLE) { - u32 speed = ethtool_cmd_speed(cmd); - int cap = speed_duplex_to_caps(speed, cmd->duplex); + if (cmd->base.autoneg == AUTONEG_DISABLE) { + u32 speed = cmd->base.speed; + int cap = speed_duplex_to_caps(speed, cmd->base.duplex); if (!(lc->supported & cap) || (speed == SPEED_1000)) return -EINVAL; lc->requested_speed = speed; - lc->requested_duplex = cmd->duplex; + lc->requested_duplex = cmd->base.duplex; lc->advertising = 0; } else { - cmd->advertising &= ADVERTISED_MASK; - cmd->advertising &= lc->supported; - if (!cmd->advertising) + advertising &= ADVERTISED_MASK; + advertising &= lc->supported; + if (!advertising) return -EINVAL; lc->requested_speed = SPEED_INVALID; lc->requested_duplex = DUPLEX_INVALID; - lc->advertising = cmd->advertising | ADVERTISED_Autoneg; + lc->advertising = advertising | ADVERTISED_Autoneg; } - lc->autoneg = cmd->autoneg; + lc->autoneg = cmd->base.autoneg; if (netif_running(dev)) t3_link_start(&p->phy, &p->mac, lc); return 0; @@ -2097,8 +2106,6 @@ static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) } static const struct ethtool_ops cxgb_ethtool_ops = { - .get_settings = get_settings, - .set_settings = set_settings, .get_drvinfo = get_drvinfo, .get_msglevel = get_msglevel, .set_msglevel = set_msglevel, @@ -2120,6 +2127,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_regs_len = get_regs_len, .get_regs = get_regs, .get_wol = get_wol, + .get_link_ksettings = get_link_ksettings, + .set_link_ksettings = set_link_ksettings, }; static int in_range(int val, int lo, int hi) -- cgit v1.2.3 From 93dfe6c290123f1059828001678e6f8b1a102d9a Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Mon, 12 Dec 2016 23:28:33 +0100 Subject: net: cirrus: ep93xx: use new api ethtool_{get|set}_link_ksettings The ethtool api {get|set}_settings is deprecated. We move this driver to new api {get|set}_link_ksettings. Signed-off-by: Philippe Reynes Signed-off-by: David S. Miller --- drivers/net/ethernet/cirrus/ep93xx_eth.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c index a1de0d12927d..396c88678eab 100644 --- a/drivers/net/ethernet/cirrus/ep93xx_eth.c +++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c @@ -715,16 +715,18 @@ static void ep93xx_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i strlcpy(info->version, DRV_MODULE_VERSION, sizeof(info->version)); } -static int ep93xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int ep93xx_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_gset(&ep->mii, cmd); + return mii_ethtool_get_link_ksettings(&ep->mii, cmd); } -static int ep93xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int ep93xx_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct ep93xx_priv *ep = netdev_priv(dev); - return mii_ethtool_sset(&ep->mii, cmd); + return mii_ethtool_set_link_ksettings(&ep->mii, cmd); } static int ep93xx_nway_reset(struct net_device *dev) @@ -741,10 +743,10 @@ static u32 ep93xx_get_link(struct net_device *dev) static const struct ethtool_ops ep93xx_ethtool_ops = { .get_drvinfo = ep93xx_get_drvinfo, - .get_settings = ep93xx_get_settings, - .set_settings = ep93xx_set_settings, .nway_reset = ep93xx_nway_reset, .get_link = ep93xx_get_link, + .get_link_ksettings = ep93xx_get_link_ksettings, + .set_link_ksettings = ep93xx_set_link_ksettings, }; static const struct net_device_ops ep93xx_netdev_ops = { -- cgit v1.2.3 From 99bff5ee44f32c3ca5115922e487b067d9c3dd6b Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Wed, 14 Dec 2016 10:01:58 +0100 Subject: net: davicom: dm9000: use new api ethtool_{get|set}_link_ksettings The ethtool api {get|set}_settings is deprecated. We move this driver to new api {get|set}_link_ksettings. Signed-off-by: Philippe Reynes Signed-off-by: David S. Miller --- drivers/net/ethernet/davicom/dm9000.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c index f1a81c52afe3..008dc8161775 100644 --- a/drivers/net/ethernet/davicom/dm9000.c +++ b/drivers/net/ethernet/davicom/dm9000.c @@ -570,19 +570,21 @@ static void dm9000_set_msglevel(struct net_device *dev, u32 value) dm->msg_enable = value; } -static int dm9000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int dm9000_get_link_ksettings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) { struct board_info *dm = to_dm9000_board(dev); - mii_ethtool_gset(&dm->mii, cmd); + mii_ethtool_get_link_ksettings(&dm->mii, cmd); return 0; } -static int dm9000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int dm9000_set_link_ksettings(struct net_device *dev, + const struct ethtool_link_ksettings *cmd) { struct board_info *dm = to_dm9000_board(dev); - return mii_ethtool_sset(&dm->mii, cmd); + return mii_ethtool_set_link_ksettings(&dm->mii, cmd); } static int dm9000_nway_reset(struct net_device *dev) @@ -741,8 +743,6 @@ static int dm9000_set_wol(struct net_device *dev, struct ethtool_wolinfo *w) static const struct ethtool_ops dm9000_ethtool_ops = { .get_drvinfo = dm9000_get_drvinfo, - .get_settings = dm9000_get_settings, - .set_settings = dm9000_set_settings, .get_msglevel = dm9000_get_msglevel, .set_msglevel = dm9000_set_msglevel, .nway_reset = dm9000_nway_reset, @@ -752,6 +752,8 @@ static const struct ethtool_ops dm9000_ethtool_ops = { .get_eeprom_len = dm9000_get_eeprom_len, .get_eeprom = dm9000_get_eeprom, .set_eeprom = dm9000_set_eeprom, + .get_link_ksettings = dm9000_get_link_ksettings, + .set_link_ksettings = dm9000_set_link_ksettings, }; static void dm9000_show_carrier(struct board_info *db, -- cgit v1.2.3 From 7cafe8f82438ced6de4c6f17b872a02c10f7a63a Mon Sep 17 00:00:00 2001 From: Philippe Reynes Date: Thu, 15 Dec 2016 00:12:53 +0100 Subject: net: sfc: use new api ethtool_{get|set}_link_ksettings The ethtool api {get|set}_settings is deprecated. We move this driver to new api {get|set}_link_ksettings. Signed-off-by: Philippe Reynes Tested-by: Bert Kenward Acked-by: Bert Kenward Signed-off-by: David S. Miller --- drivers/net/ethernet/sfc/ethtool.c | 35 ++++++++++++-------- drivers/net/ethernet/sfc/mcdi_port.c | 60 +++++++++++++++++++++-------------- drivers/net/ethernet/sfc/net_driver.h | 12 +++---- 3 files changed, 65 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/sfc/ethtool.c b/drivers/net/ethernet/sfc/ethtool.c index f644216eda1b..87bdc56b4e3a 100644 --- a/drivers/net/ethernet/sfc/ethtool.c +++ b/drivers/net/ethernet/sfc/ethtool.c @@ -120,44 +120,53 @@ static int efx_ethtool_phys_id(struct net_device *net_dev, } /* This must be called with rtnl_lock held. */ -static int efx_ethtool_get_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd) +static int +efx_ethtool_get_link_ksettings(struct net_device *net_dev, + struct ethtool_link_ksettings *cmd) { struct efx_nic *efx = netdev_priv(net_dev); struct efx_link_state *link_state = &efx->link_state; + u32 supported; mutex_lock(&efx->mac_lock); - efx->phy_op->get_settings(efx, ecmd); + efx->phy_op->get_link_ksettings(efx, cmd); mutex_unlock(&efx->mac_lock); /* Both MACs support pause frames (bidirectional and respond-only) */ - ecmd->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + ethtool_convert_link_mode_to_legacy_u32(&supported, + cmd->link_modes.supported); + + supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause; + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); if (LOOPBACK_INTERNAL(efx)) { - ethtool_cmd_speed_set(ecmd, link_state->speed); - ecmd->duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; + cmd->base.speed = link_state->speed; + cmd->base.duplex = link_state->fd ? DUPLEX_FULL : DUPLEX_HALF; } return 0; } /* This must be called with rtnl_lock held. */ -static int efx_ethtool_set_settings(struct net_device *net_dev, - struct ethtool_cmd *ecmd) +static int +efx_ethtool_set_link_ksettings(struct net_device *net_dev, + const struct ethtool_link_ksettings *cmd) { struct efx_nic *efx = netdev_priv(net_dev); int rc; /* GMAC does not support 1000Mbps HD */ - if ((ethtool_cmd_speed(ecmd) == SPEED_1000) && - (ecmd->duplex != DUPLEX_FULL)) { + if ((cmd->base.speed == SPEED_1000) && + (cmd->base.duplex != DUPLEX_FULL)) { netif_dbg(efx, drv, efx->net_dev, "rejecting unsupported 1000Mbps HD setting\n"); return -EINVAL; } mutex_lock(&efx->mac_lock); - rc = efx->phy_op->set_settings(efx, ecmd); + rc = efx->phy_op->set_link_ksettings(efx, cmd); mutex_unlock(&efx->mac_lock); return rc; } @@ -1342,8 +1351,6 @@ static int efx_ethtool_get_module_info(struct net_device *net_dev, } const struct ethtool_ops efx_ethtool_ops = { - .get_settings = efx_ethtool_get_settings, - .set_settings = efx_ethtool_set_settings, .get_drvinfo = efx_ethtool_get_drvinfo, .get_regs_len = efx_ethtool_get_regs_len, .get_regs = efx_ethtool_get_regs, @@ -1373,4 +1380,6 @@ const struct ethtool_ops efx_ethtool_ops = { .get_ts_info = efx_ethtool_get_ts_info, .get_module_info = efx_ethtool_get_module_info, .get_module_eeprom = efx_ethtool_get_module_eeprom, + .get_link_ksettings = efx_ethtool_get_link_ksettings, + .set_link_ksettings = efx_ethtool_set_link_ksettings, }; diff --git a/drivers/net/ethernet/sfc/mcdi_port.c b/drivers/net/ethernet/sfc/mcdi_port.c index 9dcd396784ae..c905971c5f3a 100644 --- a/drivers/net/ethernet/sfc/mcdi_port.c +++ b/drivers/net/ethernet/sfc/mcdi_port.c @@ -503,45 +503,59 @@ static void efx_mcdi_phy_remove(struct efx_nic *efx) kfree(phy_data); } -static void efx_mcdi_phy_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +static void efx_mcdi_phy_get_link_ksettings(struct efx_nic *efx, + struct ethtool_link_ksettings *cmd) { struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; MCDI_DECLARE_BUF(outbuf, MC_CMD_GET_LINK_OUT_LEN); int rc; - - ecmd->supported = - mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); - ecmd->advertising = efx->link_advertising; - ethtool_cmd_speed_set(ecmd, efx->link_state.speed); - ecmd->duplex = efx->link_state.fd; - ecmd->port = mcdi_to_ethtool_media(phy_cfg->media); - ecmd->phy_address = phy_cfg->port; - ecmd->transceiver = XCVR_INTERNAL; - ecmd->autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); - ecmd->mdio_support = (efx->mdio.mode_support & + u32 supported, advertising, lp_advertising; + + supported = mcdi_to_ethtool_cap(phy_cfg->media, phy_cfg->supported_cap); + advertising = efx->link_advertising; + cmd->base.speed = efx->link_state.speed; + cmd->base.duplex = efx->link_state.fd; + cmd->base.port = mcdi_to_ethtool_media(phy_cfg->media); + cmd->base.phy_address = phy_cfg->port; + cmd->base.autoneg = !!(efx->link_advertising & ADVERTISED_Autoneg); + cmd->base.mdio_support = (efx->mdio.mode_support & (MDIO_SUPPORTS_C45 | MDIO_SUPPORTS_C22)); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising, + advertising); + BUILD_BUG_ON(MC_CMD_GET_LINK_IN_LEN != 0); rc = efx_mcdi_rpc(efx, MC_CMD_GET_LINK, NULL, 0, outbuf, sizeof(outbuf), NULL); if (rc) return; - ecmd->lp_advertising = + lp_advertising = mcdi_to_ethtool_cap(phy_cfg->media, MCDI_DWORD(outbuf, GET_LINK_OUT_LP_CAP)); + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.lp_advertising, + lp_advertising); } -static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +static int +efx_mcdi_phy_set_link_ksettings(struct efx_nic *efx, + const struct ethtool_link_ksettings *cmd) { struct efx_mcdi_phy_data *phy_cfg = efx->phy_data; u32 caps; int rc; + u32 advertising; + + ethtool_convert_link_mode_to_legacy_u32(&advertising, + cmd->link_modes.advertising); - if (ecmd->autoneg) { - caps = (ethtool_to_mcdi_cap(ecmd->advertising) | + if (cmd->base.autoneg) { + caps = (ethtool_to_mcdi_cap(advertising) | 1 << MC_CMD_PHY_CAP_AN_LBN); - } else if (ecmd->duplex) { - switch (ethtool_cmd_speed(ecmd)) { + } else if (cmd->base.duplex) { + switch (cmd->base.speed) { case 10: caps = 1 << MC_CMD_PHY_CAP_10FDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100FDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000FDX_LBN; break; @@ -550,7 +564,7 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec default: return -EINVAL; } } else { - switch (ethtool_cmd_speed(ecmd)) { + switch (cmd->base.speed) { case 10: caps = 1 << MC_CMD_PHY_CAP_10HDX_LBN; break; case 100: caps = 1 << MC_CMD_PHY_CAP_100HDX_LBN; break; case 1000: caps = 1 << MC_CMD_PHY_CAP_1000HDX_LBN; break; @@ -563,9 +577,9 @@ static int efx_mcdi_phy_set_settings(struct efx_nic *efx, struct ethtool_cmd *ec if (rc) return rc; - if (ecmd->autoneg) { + if (cmd->base.autoneg) { efx_link_set_advertising( - efx, ecmd->advertising | ADVERTISED_Autoneg); + efx, advertising | ADVERTISED_Autoneg); phy_cfg->forced_cap = 0; } else { efx_link_set_advertising(efx, 0); @@ -812,8 +826,8 @@ static const struct efx_phy_operations efx_mcdi_phy_ops = { .poll = efx_mcdi_phy_poll, .fini = efx_port_dummy_op_void, .remove = efx_mcdi_phy_remove, - .get_settings = efx_mcdi_phy_get_settings, - .set_settings = efx_mcdi_phy_set_settings, + .get_link_ksettings = efx_mcdi_phy_get_link_ksettings, + .set_link_ksettings = efx_mcdi_phy_set_link_ksettings, .test_alive = efx_mcdi_phy_test_alive, .run_tests = efx_mcdi_phy_run_tests, .test_name = efx_mcdi_phy_test_name, diff --git a/drivers/net/ethernet/sfc/net_driver.h b/drivers/net/ethernet/sfc/net_driver.h index 8692e829b40f..1a635ced62d0 100644 --- a/drivers/net/ethernet/sfc/net_driver.h +++ b/drivers/net/ethernet/sfc/net_driver.h @@ -720,8 +720,8 @@ static inline bool efx_link_state_equal(const struct efx_link_state *left, * @reconfigure: Reconfigure PHY (e.g. for new link parameters) * @poll: Update @link_state and report whether it changed. * Serialised by the mac_lock. - * @get_settings: Get ethtool settings. Serialised by the mac_lock. - * @set_settings: Set ethtool settings. Serialised by the mac_lock. + * @get_link_ksettings: Get ethtool settings. Serialised by the mac_lock. + * @set_link_ksettings: Set ethtool settings. Serialised by the mac_lock. * @set_npage_adv: Set abilities advertised in (Extended) Next Page * (only needed where AN bit is set in mmds) * @test_alive: Test that PHY is 'alive' (online) @@ -736,10 +736,10 @@ struct efx_phy_operations { void (*remove) (struct efx_nic *efx); int (*reconfigure) (struct efx_nic *efx); bool (*poll) (struct efx_nic *efx); - void (*get_settings) (struct efx_nic *efx, - struct ethtool_cmd *ecmd); - int (*set_settings) (struct efx_nic *efx, - struct ethtool_cmd *ecmd); + void (*get_link_ksettings)(struct efx_nic *efx, + struct ethtool_link_ksettings *cmd); + int (*set_link_ksettings)(struct efx_nic *efx, + const struct ethtool_link_ksettings *cmd); void (*set_npage_adv) (struct efx_nic *efx, u32); int (*test_alive) (struct efx_nic *efx); const char *(*test_name) (struct efx_nic *efx, unsigned int index); -- cgit v1.2.3 From 3a7f0762a6b784ac9257287346e4f5f5f7f420b7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 12 Dec 2016 14:21:34 +0300 Subject: irda: w83977af_ir: cleanup an indent issue In commit 99d8d2159d7c ("irda: w83977af_ir: Neaten logging"), we accidentally added an extra tab to these lines. Signed-off-by: Dan Carpenter Signed-off-by: David S. Miller --- drivers/net/irda/w83977af_ir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index f293d33fb28f..8d5b903d1d9d 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -517,9 +517,9 @@ static netdev_tx_t w83977af_hard_xmit(struct sk_buff *skb, mtt = irda_get_mtt(skb); pr_debug("%s: %ld, mtt=%d\n", __func__, jiffies, mtt); - if (mtt > 1000) - mdelay(mtt / 1000); - else if (mtt) + if (mtt > 1000) + mdelay(mtt / 1000); + else if (mtt) udelay(mtt); /* Enable DMA interrupt */ -- cgit v1.2.3 From c762eaa777b789540e3fe33581d6d0e593dbb22e Mon Sep 17 00:00:00 2001 From: Manuel Bessler Date: Thu, 15 Dec 2016 22:55:00 -0500 Subject: r6040: move spinlock in r6040_close as SOFTIRQ-unsafe lock order detected 'ifconfig eth0 down' makes r6040_close() trigger: INFO: HARDIRQ-safe -> HARDIRQ-unsafe lock order detected Fixed by moving calls to phy_stop(), napi_disable(), netif_stop_queue() to outside of the module's private spin_lock_irq block. Found on a Versalogic Tomcat SBC with a Vortex86 SoC s1660e_5150:~# sudo ifconfig eth0 down [ 61.306415] ====================================================== [ 61.306415] [ INFO: SOFTIRQ-safe -> SOFTIRQ-unsafe lock order detected ] [ 61.306415] 4.9.0-gb898d2d-manuel #1 Not tainted [ 61.306415] ------------------------------------------------------ [ 61.306415] ifconfig/449 [HC0[0]:SC0[0]:HE0:SE1] is trying to acquire: [ 61.306415] (&dev->lock){+.+...}, at: [] phy_stop+0x16/0x80 [ 61.306415] and this task is already holding: [ 61.306415] (&(&lp->lock)->rlock){+.-...}, at: [] r6040_close+0x24/0x230 [r6040] which would create a new lock dependency: [ 61.306415] (&(&lp->lock)->rlock){+.-...} -> (&dev->lock){+.+...} [ 61.306415] but this new dependency connects a SOFTIRQ-irq-safe lock: [ 61.306415] (&(&lp->lock)->rlock){+.-...} [ 61.306415] ... which became SOFTIRQ-irq-safe at: [ 61.306415] [ 61.306415] [] __lock_acquire+0x555/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] _raw_spin_lock_irqsave+0x24/0x40 [ 61.306415] [ 61.306415] [] r6040_start_xmit+0x30/0x1d0 [r6040] [ 61.306415] [ 61.306415] [] dev_hard_start_xmit+0x9d/0x2d0 [ 61.306415] [ 61.306415] [] sch_direct_xmit+0xa8/0x140 [ 61.306415] [ 61.306415] [] __dev_queue_xmit+0x416/0x780 [ 61.306415] [ 61.306415] [] dev_queue_xmit+0xa/0x10 [ 61.306415] [ 61.306415] [] neigh_resolve_output+0x147/0x220 [ 61.306415] [ 61.306415] [] ip6_finish_output2+0x2fb/0x910 [ 61.306415] [ 61.306415] [] ip6_finish_output+0xa6/0x1a0 [ 61.306415] [ 61.306415] [] ip6_output+0x55/0x320 [ 61.306415] [ 61.306415] [] mld_sendpack+0x352/0x560 [ 61.306415] [ 61.306415] [] mld_ifc_timer_expire+0x155/0x280 [ 61.306415] [ 61.306415] [] call_timer_fn+0x81/0x270 [ 61.306415] [ 61.306415] [] expire_timers+0xc1/0x180 [ 61.306415] [ 61.306415] [] run_timer_softirq+0x77/0x150 [ 61.306415] [ 61.306415] [] __do_softirq+0xb4/0x3d0 [ 61.306415] [ 61.306415] [] do_softirq_own_stack+0x1c/0x30 [ 61.306415] [ 61.306415] [] irq_exit+0x8e/0xa0 [ 61.306415] [ 61.306415] [] do_IRQ+0x51/0x100 [ 61.306415] [ 61.306415] [] common_interrupt+0x36/0x40 [ 61.306415] [ 61.306415] [] set_root+0x68/0xf0 [ 61.306415] [ 61.306415] [] path_init+0x400/0x640 [ 61.306415] [ 61.306415] [] path_lookupat+0xf/0xe0 [ 61.306415] [ 61.306415] [] filename_lookup+0x6c/0x100 [ 61.306415] [ 61.306415] [] user_path_at_empty+0x25/0x30 [ 61.306415] [ 61.306415] [] SyS_faccessat+0x86/0x1e0 [ 61.306415] [ 61.306415] [] SyS_access+0x10/0x20 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] [ 61.306415] to a SOFTIRQ-irq-unsafe lock: [ 61.306415] (&dev->lock){+.+...} [ 61.306415] ... which became SOFTIRQ-irq-unsafe at: [ 61.306415] ...[ 61.306415] [ 61.306415] [] __lock_acquire+0x59c/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] mutex_lock_nested+0x2d/0x4a0 [ 61.306415] [ 61.306415] [] phy_probe+0x4d/0xc0 [ 61.306415] [ 61.306415] [] phy_attach_direct+0xbe/0x190 [ 61.306415] [ 61.306415] [] phy_connect_direct+0x17/0x60 [ 61.306415] [ 61.306415] [] phy_connect+0x33/0x70 [ 61.306415] [ 61.306415] [] r6040_init_one+0x3a0/0x500 [r6040] [ 61.306415] [ 61.306415] [] pci_device_probe+0x77/0xd0 [ 61.306415] [ 61.306415] [] driver_probe_device+0x145/0x280 [ 61.306415] [ 61.306415] [] __driver_attach+0x89/0x90 [ 61.306415] [ 61.306415] [] bus_for_each_dev+0x4f/0x80 [ 61.306415] [ 61.306415] [] driver_attach+0x14/0x20 [ 61.306415] [ 61.306415] [] bus_add_driver+0x197/0x210 [ 61.306415] [ 61.306415] [] driver_register+0x51/0xd0 [ 61.306415] [ 61.306415] [] __pci_register_driver+0x45/0x50 [ 61.306415] [ 61.306415] [] 0xd0938017 [ 61.306415] [ 61.306415] [] do_one_initcall+0x2f/0x140 [ 61.306415] [ 61.306415] [] do_init_module+0x4a/0x19b [ 61.306415] [ 61.306415] [] load_module+0x1b2e/0x2070 [ 61.306415] [ 61.306415] [] SyS_finit_module+0x69/0x80 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] [ 61.306415] other info that might help us debug this: [ 61.306415] [ 61.306415] Possible interrupt unsafe locking scenario: [ 61.306415] [ 61.306415] CPU0 CPU1 [ 61.306415] ---- ---- [ 61.306415] lock(&dev->lock); [ 61.306415] local_irq_disable(); [ 61.306415] lock(&(&lp->lock)->rlock); [ 61.306415] lock(&dev->lock); [ 61.306415] [ 61.306415] lock(&(&lp->lock)->rlock); [ 61.306415] [ 61.306415] *** DEADLOCK *** [ 61.306415] [ 61.306415] 2 locks held by ifconfig/449: [ 61.306415] #0: (rtnl_mutex){+.+.+.}, at: [] rtnl_lock+0xf/0x20 [ 61.306415] #1: (&(&lp->lock)->rlock){+.-...}, at: [] r6040_close+0x24/0x230 [r6040] [ 61.306415] [ 61.306415] the dependencies between SOFTIRQ-irq-safe lock and the holding lock: [ 61.306415] -> (&(&lp->lock)->rlock){+.-...} ops: 3049 { [ 61.306415] HARDIRQ-ON-W at: [ 61.306415] [ 61.306415] [] __lock_acquire+0x577/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] _raw_spin_lock+0x1b/0x30 [ 61.306415] [ 61.306415] [] r6040_poll+0x2c/0x330 [r6040] [ 61.306415] [ 61.306415] [] net_rx_action+0x197/0x340 [ 61.306415] [ 61.306415] [] __do_softirq+0xb4/0x3d0 [ 61.306415] [ 61.306415] [] run_ksoftirqd+0x17/0x40 [ 61.306415] [ 61.306415] [] smpboot_thread_fn+0x141/0x180 [ 61.306415] [ 61.306415] [] kthread+0xde/0x110 [ 61.306415] [ 61.306415] [] ret_from_fork+0x19/0x30 [ 61.306415] IN-SOFTIRQ-W at: [ 61.306415] [ 61.306415] [] __lock_acquire+0x555/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] _raw_spin_lock_irqsave+0x24/0x40 [ 61.306415] [ 61.306415] [] r6040_start_xmit+0x30/0x1d0 [r6040] [ 61.306415] [ 61.306415] [] dev_hard_start_xmit+0x9d/0x2d0 [ 61.306415] [ 61.306415] [] sch_direct_xmit+0xa8/0x140 [ 61.306415] [ 61.306415] [] __dev_queue_xmit+0x416/0x780 [ 61.306415] [ 61.306415] [] dev_queue_xmit+0xa/0x10 [ 61.306415] [ 61.306415] [] neigh_resolve_output+0x147/0x220 [ 61.306415] [ 61.306415] [] ip6_finish_output2+0x2fb/0x910 [ 61.306415] [ 61.306415] [] ip6_finish_output+0xa6/0x1a0 [ 61.306415] [ 61.306415] [] ip6_output+0x55/0x320 [ 61.306415] [ 61.306415] [] mld_sendpack+0x352/0x560 [ 61.306415] [ 61.306415] [] mld_ifc_timer_expire+0x155/0x280 [ 61.306415] [ 61.306415] [] call_timer_fn+0x81/0x270 [ 61.306415] [ 61.306415] [] expire_timers+0xc1/0x180 [ 61.306415] [ 61.306415] [] run_timer_softirq+0x77/0x150 [ 61.306415] [ 61.306415] [] __do_softirq+0xb4/0x3d0 [ 61.306415] [ 61.306415] [] do_softirq_own_stack+0x1c/0x30 [ 61.306415] [ 61.306415] [] irq_exit+0x8e/0xa0 [ 61.306415] [ 61.306415] [] do_IRQ+0x51/0x100 [ 61.306415] [ 61.306415] [] common_interrupt+0x36/0x40 [ 61.306415] [ 61.306415] [] set_root+0x68/0xf0 [ 61.306415] [ 61.306415] [] path_init+0x400/0x640 [ 61.306415] [ 61.306415] [] path_lookupat+0xf/0xe0 [ 61.306415] [ 61.306415] [] filename_lookup+0x6c/0x100 [ 61.306415] [ 61.306415] [] user_path_at_empty+0x25/0x30 [ 61.306415] [ 61.306415] [] SyS_faccessat+0x86/0x1e0 [ 61.306415] [ 61.306415] [] SyS_access+0x10/0x20 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] INITIAL USE at: [ 61.306415] [ 61.306415] [] __lock_acquire+0x1fe/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] _raw_spin_lock_irqsave+0x24/0x40 [ 61.306415] [ 61.306415] [] r6040_get_stats+0x1e/0x60 [r6040] [ 61.306415] [ 61.306415] [] dev_get_stats+0x96/0xc0 [ 61.306415] [ 61.306415] [] rtnl_fill_stats+0x36/0xfd [ 61.306415] [ 61.306415] [] rtnl_fill_ifinfo+0x47c/0xce0 [ 61.306415] [ 61.306415] [] rtmsg_ifinfo_build_skb+0x4e/0xd0 [ 61.306415] [ 61.306415] [] rtmsg_ifinfo.part.20+0x10/0x40 [ 61.306415] [ 61.306415] [] rtmsg_ifinfo+0x1b/0x20 [ 61.306415] [ 61.306415] [] register_netdevice+0x409/0x550 [ 61.306415] [ 61.306415] [] register_netdev+0x12/0x20 [ 61.306415] [ 61.306415] [] r6040_init_one+0x3e8/0x500 [r6040] [ 61.306415] [ 61.306415] [] pci_device_probe+0x77/0xd0 [ 61.306415] [ 61.306415] [] driver_probe_device+0x145/0x280 [ 61.306415] [ 61.306415] [] __driver_attach+0x89/0x90 [ 61.306415] [ 61.306415] [] bus_for_each_dev+0x4f/0x80 [ 61.306415] [ 61.306415] [] driver_attach+0x14/0x20 [ 61.306415] [ 61.306415] [] bus_add_driver+0x197/0x210 [ 61.306415] [ 61.306415] [] driver_register+0x51/0xd0 [ 61.306415] [ 61.306415] [] __pci_register_driver+0x45/0x50 [ 61.306415] [ 61.306415] [] 0xd0938017 [ 61.306415] [ 61.306415] [] do_one_initcall+0x2f/0x140 [ 61.306415] [ 61.306415] [] do_init_module+0x4a/0x19b [ 61.306415] [ 61.306415] [] load_module+0x1b2e/0x2070 [ 61.306415] [ 61.306415] [] SyS_finit_module+0x69/0x80 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] } [ 61.306415] ... key at: [] __key.45893+0x0/0xfffff739 [r6040] [ 61.306415] ... acquired at: [ 61.306415] [ 61.306415] [] check_irq_usage+0x42/0xb0 [ 61.306415] [ 61.306415] [] __lock_acquire+0x110c/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] mutex_lock_nested+0x2d/0x4a0 [ 61.306415] [ 61.306415] [] phy_stop+0x16/0x80 [ 61.306415] [ 61.306415] [] r6040_close+0x89/0x230 [r6040] [ 61.306415] [ 61.306415] [] __dev_close_many+0x61/0xa0 [ 61.306415] [ 61.306415] [] __dev_close+0x1f/0x30 [ 61.306415] [ 61.306415] [] __dev_change_flags+0x87/0x150 [ 61.306415] [ 61.306415] [] dev_change_flags+0x23/0x60 [ 61.306415] [ 61.306415] [] devinet_ioctl+0x5f8/0x6f0 [ 61.306415] [ 61.306415] [] inet_ioctl+0x65/0x90 [ 61.306415] [ 61.306415] [] sock_ioctl+0x124/0x2b0 [ 61.306415] [ 61.306415] [] do_vfs_ioctl+0x7c/0x790 [ 61.306415] [ 61.306415] [] SyS_ioctl+0x28/0x50 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] [ 61.306415] the dependencies between the lock to be acquired[ 61.306415] and SOFTIRQ-irq-unsafe lock: [ 61.306415] -> (&dev->lock){+.+...} ops: 56 { [ 61.306415] HARDIRQ-ON-W at: [ 61.306415] [ 61.306415] [] __lock_acquire+0x577/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] mutex_lock_nested+0x2d/0x4a0 [ 61.306415] [ 61.306415] [] phy_probe+0x4d/0xc0 [ 61.306415] [ 61.306415] [] phy_attach_direct+0xbe/0x190 [ 61.306415] [ 61.306415] [] phy_connect_direct+0x17/0x60 [ 61.306415] [ 61.306415] [] phy_connect+0x33/0x70 [ 61.306415] [ 61.306415] [] r6040_init_one+0x3a0/0x500 [r6040] [ 61.306415] [ 61.306415] [] pci_device_probe+0x77/0xd0 [ 61.306415] [ 61.306415] [] driver_probe_device+0x145/0x280 [ 61.306415] [ 61.306415] [] __driver_attach+0x89/0x90 [ 61.306415] [ 61.306415] [] bus_for_each_dev+0x4f/0x80 [ 61.306415] [ 61.306415] [] driver_attach+0x14/0x20 [ 61.306415] [ 61.306415] [] bus_add_driver+0x197/0x210 [ 61.306415] [ 61.306415] [] driver_register+0x51/0xd0 [ 61.306415] [ 61.306415] [] __pci_register_driver+0x45/0x50 [ 61.306415] [ 61.306415] [] 0xd0938017 [ 61.306415] [ 61.306415] [] do_one_initcall+0x2f/0x140 [ 61.306415] [ 61.306415] [] do_init_module+0x4a/0x19b [ 61.306415] [ 61.306415] [] load_module+0x1b2e/0x2070 [ 61.306415] [ 61.306415] [] SyS_finit_module+0x69/0x80 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] SOFTIRQ-ON-W at: [ 61.306415] [ 61.306415] [] __lock_acquire+0x59c/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] mutex_lock_nested+0x2d/0x4a0 [ 61.306415] [ 61.306415] [] phy_probe+0x4d/0xc0 [ 61.306415] [ 61.306415] [] phy_attach_direct+0xbe/0x190 [ 61.306415] [ 61.306415] [] phy_connect_direct+0x17/0x60 [ 61.306415] [ 61.306415] [] phy_connect+0x33/0x70 [ 61.306415] [ 61.306415] [] r6040_init_one+0x3a0/0x500 [r6040] [ 61.306415] [ 61.306415] [] pci_device_probe+0x77/0xd0 [ 61.306415] [ 61.306415] [] driver_probe_device+0x145/0x280 [ 61.306415] [ 61.306415] [] __driver_attach+0x89/0x90 [ 61.306415] [ 61.306415] [] bus_for_each_dev+0x4f/0x80 [ 61.306415] [ 61.306415] [] driver_attach+0x14/0x20 [ 61.306415] [ 61.306415] [] bus_add_driver+0x197/0x210 [ 61.306415] [ 61.306415] [] driver_register+0x51/0xd0 [ 61.306415] [ 61.306415] [] __pci_register_driver+0x45/0x50 [ 61.306415] [ 61.306415] [] 0xd0938017 [ 61.306415] [ 61.306415] [] do_one_initcall+0x2f/0x140 [ 61.306415] [ 61.306415] [] do_init_module+0x4a/0x19b [ 61.306415] [ 61.306415] [] load_module+0x1b2e/0x2070 [ 61.306415] [ 61.306415] [] SyS_finit_module+0x69/0x80 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] INITIAL USE at: [ 61.306415] [ 61.306415] [] __lock_acquire+0x1fe/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] mutex_lock_nested+0x2d/0x4a0 [ 61.306415] [ 61.306415] [] phy_probe+0x4d/0xc0 [ 61.306415] [ 61.306415] [] phy_attach_direct+0xbe/0x190 [ 61.306415] [ 61.306415] [] phy_connect_direct+0x17/0x60 [ 61.306415] [ 61.306415] [] phy_connect+0x33/0x70 [ 61.306415] [ 61.306415] [] r6040_init_one+0x3a0/0x500 [r6040] [ 61.306415] [ 61.306415] [] pci_device_probe+0x77/0xd0 [ 61.306415] [ 61.306415] [] driver_probe_device+0x145/0x280 [ 61.306415] [ 61.306415] [] __driver_attach+0x89/0x90 [ 61.306415] [ 61.306415] [] bus_for_each_dev+0x4f/0x80 [ 61.306415] [ 61.306415] [] driver_attach+0x14/0x20 [ 61.306415] [ 61.306415] [] bus_add_driver+0x197/0x210 [ 61.306415] [ 61.306415] [] driver_register+0x51/0xd0 [ 61.306415] [ 61.306415] [] __pci_register_driver+0x45/0x50 [ 61.306415] [ 61.306415] [] 0xd0938017 [ 61.306415] [ 61.306415] [] do_one_initcall+0x2f/0x140 [ 61.306415] [ 61.306415] [] do_init_module+0x4a/0x19b [ 61.306415] [ 61.306415] [] load_module+0x1b2e/0x2070 [ 61.306415] [ 61.306415] [] SyS_finit_module+0x69/0x80 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] } [ 61.306415] ... key at: [] __key.43998+0x0/0x8 [ 61.306415] ... acquired at: [ 61.306415] [ 61.306415] [] check_irq_usage+0x42/0xb0 [ 61.306415] [ 61.306415] [] __lock_acquire+0x110c/0x1770 [ 61.306415] [ 61.306415] [] lock_acquire+0x7c/0x150 [ 61.306415] [ 61.306415] [] mutex_lock_nested+0x2d/0x4a0 [ 61.306415] [ 61.306415] [] phy_stop+0x16/0x80 [ 61.306415] [ 61.306415] [] r6040_close+0x89/0x230 [r6040] [ 61.306415] [ 61.306415] [] __dev_close_many+0x61/0xa0 [ 61.306415] [ 61.306415] [] __dev_close+0x1f/0x30 [ 61.306415] [ 61.306415] [] __dev_change_flags+0x87/0x150 [ 61.306415] [ 61.306415] [] dev_change_flags+0x23/0x60 [ 61.306415] [ 61.306415] [] devinet_ioctl+0x5f8/0x6f0 [ 61.306415] [ 61.306415] [] inet_ioctl+0x65/0x90 [ 61.306415] [ 61.306415] [] sock_ioctl+0x124/0x2b0 [ 61.306415] [ 61.306415] [] do_vfs_ioctl+0x7c/0x790 [ 61.306415] [ 61.306415] [] SyS_ioctl+0x28/0x50 [ 61.306415] [ 61.306415] [] do_int80_syscall_32+0x3f/0x110 [ 61.306415] [ 61.306415] [] restore_all+0x0/0x61 [ 61.306415] [ 61.306415] [ 61.306415] stack backtrace: [ 61.306415] CPU: 0 PID: 449 Comm: ifconfig Not tainted 4.9.0-gb898d2d-manuel #1 [ 61.306415] Call Trace: [ 61.306415] dump_stack+0x16/0x19 [ 61.306415] check_usage+0x3f6/0x550 [ 61.306415] ? check_usage+0x4d/0x550 [ 61.306415] check_irq_usage+0x42/0xb0 [ 61.306415] __lock_acquire+0x110c/0x1770 [ 61.306415] lock_acquire+0x7c/0x150 [ 61.306415] ? phy_stop+0x16/0x80 [ 61.306415] mutex_lock_nested+0x2d/0x4a0 [ 61.306415] ? phy_stop+0x16/0x80 [ 61.306415] ? r6040_close+0x24/0x230 [r6040] [ 61.306415] ? __delay+0x9/0x10 [ 61.306415] phy_stop+0x16/0x80 [ 61.306415] r6040_close+0x89/0x230 [r6040] [ 61.306415] __dev_close_many+0x61/0xa0 [ 61.306415] __dev_close+0x1f/0x30 [ 61.306415] __dev_change_flags+0x87/0x150 [ 61.306415] dev_change_flags+0x23/0x60 [ 61.306415] devinet_ioctl+0x5f8/0x6f0 [ 61.306415] inet_ioctl+0x65/0x90 [ 61.306415] sock_ioctl+0x124/0x2b0 [ 61.306415] ? dlci_ioctl_set+0x30/0x30 [ 61.306415] do_vfs_ioctl+0x7c/0x790 [ 61.306415] ? trace_hardirqs_on+0xb/0x10 [ 61.306415] ? call_rcu_sched+0xd/0x10 [ 61.306415] ? __put_cred+0x32/0x50 [ 61.306415] ? SyS_faccessat+0x178/0x1e0 [ 61.306415] SyS_ioctl+0x28/0x50 [ 61.306415] do_int80_syscall_32+0x3f/0x110 [ 61.306415] entry_INT80_32+0x2f/0x2f [ 61.306415] EIP: 0xb764d364 [ 61.306415] EFLAGS: 00000286 CPU: 0 [ 61.306415] EAX: ffffffda EBX: 00000004 ECX: 00008914 EDX: bfa99d7c [ 61.306415] ESI: bfa99e4c EDI: fffffffe EBP: 00000004 ESP: bfa99d58 [ 61.306415] DS: 007b ES: 007b FS: 0000 GS: 0033 SS: 007b [ 63.836607] r6040 0000:00:08.0 eth0: Link is Down Signed-off-by: Manuel Bessler Signed-off-by: David S. Miller --- drivers/net/ethernet/rdc/r6040.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/rdc/r6040.c b/drivers/net/ethernet/rdc/r6040.c index 4ff4e0491406..aa11b70b9ca4 100644 --- a/drivers/net/ethernet/rdc/r6040.c +++ b/drivers/net/ethernet/rdc/r6040.c @@ -472,8 +472,6 @@ static void r6040_down(struct net_device *dev) iowrite16(adrp[0], ioaddr + MID_0L); iowrite16(adrp[1], ioaddr + MID_0M); iowrite16(adrp[2], ioaddr + MID_0H); - - phy_stop(dev->phydev); } static int r6040_close(struct net_device *dev) @@ -481,12 +479,12 @@ static int r6040_close(struct net_device *dev) struct r6040_private *lp = netdev_priv(dev); struct pci_dev *pdev = lp->pdev; - spin_lock_irq(&lp->lock); + phy_stop(dev->phydev); napi_disable(&lp->napi); netif_stop_queue(dev); - r6040_down(dev); - free_irq(dev->irq, dev); + spin_lock_irq(&lp->lock); + r6040_down(dev); /* Free RX buffer */ r6040_free_rxbufs(dev); @@ -496,6 +494,8 @@ static int r6040_close(struct net_device *dev) spin_unlock_irq(&lp->lock); + free_irq(dev->irq, dev); + /* Free Descriptor memory */ if (lp->rx_ring) { pci_free_consistent(pdev, -- cgit v1.2.3 From 7729bad4fd95e48bcafcb2222c63a8a5cdc42f61 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Dec 2016 09:47:41 +0100 Subject: qed: fix old-style function definition The newly added file causes a harmless warning, with "make W=1": drivers/net/ethernet/qlogic/qed/qed_iscsi.c: In function 'qed_get_iscsi_ops': drivers/net/ethernet/qlogic/qed/qed_iscsi.c:1268:29: warning: old-style function definition [-Wold-style-definition] This makes it a proper prototype. Fixes: fc831825f99e ("qed: Add support for hardware offloaded iSCSI.") Signed-off-by: Arnd Bergmann Reviewed-by: Johannes Thumshirn Signed-off-by: David S. Miller --- drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c index 00efb1c4c57e..17a70122df05 100644 --- a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c @@ -1265,7 +1265,7 @@ static const struct qed_iscsi_ops qed_iscsi_ops_pass = { .get_stats = &qed_iscsi_stats, }; -const struct qed_iscsi_ops *qed_get_iscsi_ops() +const struct qed_iscsi_ops *qed_get_iscsi_ops(void) { return &qed_iscsi_ops_pass; } -- cgit v1.2.3 From 9a60c9072295b30459284beca9aff52be8dfd64b Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 16 Dec 2016 19:29:03 +0100 Subject: mlxsw: spectrum: Mark split ports as such When a port is split we should mark it as such, as otherwise the split ports aren't renamed correctly (e.g. sw1p3 -> sw1p3s1) and the unsplit operation fails: $ devlink port split sw1p3 count 4 $ devlink port unsplit eth0 devlink answers: Invalid argument [ 598.565307] mlxsw_spectrum 0000:03:00.0 eth0: Port wasn't split Fixes: 67963a33b4fd ("mlxsw: Make devlink port instances independent of spectrum/switchx2 port instances") Signed-off-by: Ido Schimmel Reported-by: Tamir Winetroub Reviewed-by: Elad Raz Tested-by: Tamir Winetroub Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c index fece974b4edd..d768c7b6c6d6 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.c @@ -2404,7 +2404,7 @@ static int mlxsw_sp_port_create(struct mlxsw_sp *mlxsw_sp, u8 local_port, local_port); return err; } - err = __mlxsw_sp_port_create(mlxsw_sp, local_port, false, + err = __mlxsw_sp_port_create(mlxsw_sp, local_port, split, module, width, lane); if (err) goto err_port_create; -- cgit v1.2.3 From a6b3c48312f6a2c3905653c0633344f811c1dde5 Mon Sep 17 00:00:00 2001 From: Emese Revfy Date: Fri, 16 Dec 2016 13:40:47 -0800 Subject: isdn: Constify some function parameters The coming initify gcc plugin expects const pointer types, and caught some __printf arguments that weren't const yet. This fixes those. Signed-off-by: Emese Revfy [kees: expanded commit message] Signed-off-by: Kees Cook Signed-off-by: David S. Miller --- drivers/isdn/hisax/config.c | 16 ++++++++-------- drivers/isdn/hisax/hisax.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c index bf04d2a3cf4a..2d12c6ceeb89 100644 --- a/drivers/isdn/hisax/config.c +++ b/drivers/isdn/hisax/config.c @@ -659,7 +659,7 @@ int jiftime(char *s, long mark) static u_char tmpbuf[HISAX_STATUS_BUFSIZE]; -void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args) { /* if head == NULL the fmt contains the full info */ @@ -669,23 +669,24 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, u_char *p; isdn_ctrl ic; int len; + const u_char *data; if (!cs) { printk(KERN_WARNING "HiSax: No CardStatus for message"); return; } spin_lock_irqsave(&cs->statlock, flags); - p = tmpbuf; if (head) { + p = tmpbuf; p += jiftime(p, jiffies); p += sprintf(p, " %s", head); p += vsprintf(p, fmt, args); *p++ = '\n'; *p = 0; len = p - tmpbuf; - p = tmpbuf; + data = tmpbuf; } else { - p = fmt; + data = fmt; len = strlen(fmt); } if (len > HISAX_STATUS_BUFSIZE) { @@ -699,13 +700,12 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, if (i >= len) i = len; len -= i; - memcpy(cs->status_write, p, i); + memcpy(cs->status_write, data, i); cs->status_write += i; if (cs->status_write > cs->status_end) cs->status_write = cs->status_buf; - p += i; if (len) { - memcpy(cs->status_write, p, len); + memcpy(cs->status_write, data + i, len); cs->status_write += len; } #ifdef KERNELSTACK_DEBUG @@ -729,7 +729,7 @@ void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, } } -void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...) +void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...) { va_list args; diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h index 6ead6314e6d2..338d0408b377 100644 --- a/drivers/isdn/hisax/hisax.h +++ b/drivers/isdn/hisax/hisax.h @@ -1288,9 +1288,9 @@ int jiftime(char *s, long mark); int HiSax_command(isdn_ctrl *ic); int HiSax_writebuf_skb(int id, int chan, int ack, struct sk_buff *skb); __printf(3, 4) -void HiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, ...); +void HiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, ...); __printf(3, 0) -void VHiSax_putstatus(struct IsdnCardState *cs, char *head, char *fmt, va_list args); +void VHiSax_putstatus(struct IsdnCardState *cs, char *head, const char *fmt, va_list args); void HiSax_reportcard(int cardnr, int sel); int QuickHex(char *txt, u_char *p, int cnt); void LogFrame(struct IsdnCardState *cs, u_char *p, int size); -- cgit v1.2.3 From 3e3397e7b11ce1b9526975ddfbe8dd569fc1f316 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Sat, 17 Dec 2016 00:45:05 +0000 Subject: net: mv643xx_eth: fix build failure The build of sparc allmodconfig fails with the error: "of_irq_to_resource" [drivers/net/ethernet/marvell/mv643xx_eth.ko] undefined! of_irq_to_resource() is defined when CONFIG_OF_IRQ is defined. And also CONFIG_OF_IRQ can only be defined if CONFIG_IRQ is defined. So we can safely use #if defined(CONFIG_OF_IRQ) in the code. Signed-off-by: Sudip Mukherjee Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mv643xx_eth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mv643xx_eth.c b/drivers/net/ethernet/marvell/mv643xx_eth.c index 5f62c3d70df9..1fa7c03edec2 100644 --- a/drivers/net/ethernet/marvell/mv643xx_eth.c +++ b/drivers/net/ethernet/marvell/mv643xx_eth.c @@ -2713,7 +2713,7 @@ static const struct of_device_id mv643xx_eth_shared_ids[] = { MODULE_DEVICE_TABLE(of, mv643xx_eth_shared_ids); #endif -#if defined(CONFIG_OF) && !defined(CONFIG_MV64X60) +#if defined(CONFIG_OF_IRQ) && !defined(CONFIG_MV64X60) #define mv643xx_eth_property(_np, _name, _v) \ do { \ u32 tmp; \ -- cgit v1.2.3 From 649ac63a9ae5e08b7123f2fa98c2bf42f033bdb9 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Sat, 17 Dec 2016 21:29:11 +0100 Subject: i2c: mux: mlxcpld: fix i2c mux selection caching smbus functions return -ve on error, 0 on success. However, __i2c_transfer() have a different return signature - -ve on error, or number of buffers transferred (which may be zero or greater). The upshot of this is that the sense of the test is reversed when using the mux on a bus supporting the master_xfer method: we cache the value and never retry if we fail to transfer any buffers, but if we succeed, we clear the cached value. Fix this by making mlxcpld_mux_reg_write() return a -ve error code for all failure cases, just as was done in commit 7f638c1cb0a1 ("i2c: mux: pca954x: fix i2c mux selection caching"). This also aligns the implementations of these two muxes in this area. Signed-off-by: Peter Rosin Acked-by: Vadim Pasternak Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 3ab654bbfab5..b7ca249ec9c3 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -95,6 +95,7 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, struct i2c_client *client, u8 val) { struct mlxcpld_mux_plat_data *pdata = dev_get_platdata(&client->dev); + int ret = -ENODEV; if (adap->algo->master_xfer) { struct i2c_msg msg; @@ -104,17 +105,21 @@ static int mlxcpld_mux_reg_write(struct i2c_adapter *adap, msg.flags = 0; msg.len = 2; msg.buf = msgbuf; - return __i2c_transfer(adap, &msg, 1); + ret = __i2c_transfer(adap, &msg, 1); + + if (ret >= 0 && ret != 1) + ret = -EREMOTEIO; } else if (adap->algo->smbus_xfer) { union i2c_smbus_data data; data.byte = val; - return adap->algo->smbus_xfer(adap, client->addr, - client->flags, I2C_SMBUS_WRITE, - pdata->sel_reg_addr, - I2C_SMBUS_BYTE_DATA, &data); - } else - return -ENODEV; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, I2C_SMBUS_WRITE, + pdata->sel_reg_addr, + I2C_SMBUS_BYTE_DATA, &data); + } + + return ret; } static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) @@ -127,10 +132,7 @@ static int mlxcpld_mux_select_chan(struct i2c_mux_core *muxc, u32 chan) /* Only select the channel if its different from the last channel */ if (data->last_chan != regval) { err = mlxcpld_mux_reg_write(muxc->parent, client, regval); - if (err) - data->last_chan = 0; - else - data->last_chan = regval; + data->last_chan = err < 0 ? 0 : regval; } return err; -- cgit v1.2.3 From 298360af3dab45659810fdc51aba0c9f4097e4f6 Mon Sep 17 00:00:00 2001 From: Russell Currey Date: Thu, 15 Dec 2016 16:12:41 +1100 Subject: drivers/gpu/drm/ast: Fix infinite loop if read fails ast_get_dram_info() configures a window in order to access BMC memory. A BMC register can be configured to disallow this, and if so, causes an infinite loop in the ast driver which renders the system unusable. Fix this by erroring out if an error is detected. On powerpc systems with EEH, this leads to the device being fenced and the system continuing to operate. Cc: # 3.10+ Signed-off-by: Russell Currey Reviewed-by: Joel Stanley Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161215051241.20815-1-ruscur@russell.cc --- drivers/gpu/drm/ast/ast_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/ast/ast_main.c b/drivers/gpu/drm/ast/ast_main.c index 904beaa932d0..f75c6421db62 100644 --- a/drivers/gpu/drm/ast/ast_main.c +++ b/drivers/gpu/drm/ast/ast_main.c @@ -223,7 +223,8 @@ static int ast_get_dram_info(struct drm_device *dev) ast_write32(ast, 0x10000, 0xfc600309); do { - ; + if (pci_channel_offline(dev->pdev)) + return -EIO; } while (ast_read32(ast, 0x10000) != 0x01); data = ast_read32(ast, 0x10004); @@ -428,7 +429,9 @@ int ast_driver_load(struct drm_device *dev, unsigned long flags) ast_detect_chip(dev, &need_post); if (ast->chip != AST1180) { - ast_get_dram_info(dev); + ret = ast_get_dram_info(dev); + if (ret) + goto out_free; ast->vram_size = ast_get_vram_info(dev); DRM_INFO("dram %d %d %d %08x\n", ast->mclk, ast->dram_type, ast->dram_bus_width, ast->vram_size); } -- cgit v1.2.3 From b414fa01c31318383ae29d9d23cb9ca4184bbd86 Mon Sep 17 00:00:00 2001 From: Steve Wise Date: Thu, 15 Dec 2016 08:09:35 -0800 Subject: iw_cxgb4: set correct FetchBurstMax for QPs The current QP FetchBurstMax value is 256B, which is incorrect since a WR can exceed that value. The result being a partial WR fetched by hardware, and a fatal "bad WR" error posted by the SGE. So bump the FetchBurstMax to 512B. Signed-off-by: Steve Wise Signed-off-by: Doug Ledford --- drivers/infiniband/hw/cxgb4/qp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c index f57deba6717c..108c8837ba58 100644 --- a/drivers/infiniband/hw/cxgb4/qp.c +++ b/drivers/infiniband/hw/cxgb4/qp.c @@ -321,7 +321,8 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, FW_RI_RES_WR_DCAEN_V(0) | FW_RI_RES_WR_DCACPU_V(0) | FW_RI_RES_WR_FBMIN_V(2) | - FW_RI_RES_WR_FBMAX_V(2) | + (t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_FBMAX_V(2) : + FW_RI_RES_WR_FBMAX_V(3)) | FW_RI_RES_WR_CIDXFTHRESHO_V(0) | FW_RI_RES_WR_CIDXFTHRESH_V(0) | FW_RI_RES_WR_EQSIZE_V(eqsize)); @@ -345,7 +346,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq, FW_RI_RES_WR_DCAEN_V(0) | FW_RI_RES_WR_DCACPU_V(0) | FW_RI_RES_WR_FBMIN_V(2) | - FW_RI_RES_WR_FBMAX_V(2) | + FW_RI_RES_WR_FBMAX_V(3) | FW_RI_RES_WR_CIDXFTHRESHO_V(0) | FW_RI_RES_WR_CIDXFTHRESH_V(0) | FW_RI_RES_WR_EQSIZE_V(eqsize)); -- cgit v1.2.3 From e259934d4df7f99f2a5c2c4f074f6a55bd4b1722 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 15 Dec 2016 17:15:07 +0100 Subject: IB/rxe: Fix a memory leak in rxe_qp_cleanup() A socket is associated with every QP by the rxe driver but sock_release() is never called. Add a call to sock_release() in rxe_qp_cleanup(). Fixes: commit 8700e3e7c48A5 ("Add Soft RoCE driver") Signed-off-by: Bart Van Assche Cc: Moni Shoua Cc: Kamal Heib Cc: Amir Vadai Cc: Haggai Eran Cc: Reviewed-by: Moni Shoua Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_qp.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_qp.c b/drivers/infiniband/sw/rxe/rxe_qp.c index b8036cfbce04..4b6e455e72a1 100644 --- a/drivers/infiniband/sw/rxe/rxe_qp.c +++ b/drivers/infiniband/sw/rxe/rxe_qp.c @@ -853,4 +853,5 @@ void rxe_qp_cleanup(void *arg) free_rd_atomic_resources(qp); kernel_sock_shutdown(qp->sk, SHUT_RDWR); + sock_release(qp->sk); } -- cgit v1.2.3 From 957ae5098185e763b5c06be6c3b4b6e98c048712 Mon Sep 17 00:00:00 2001 From: Nilesh Bacchewar Date: Mon, 7 Nov 2016 12:11:47 -0800 Subject: platform/x86: Add Whiskey Cove PMIC TMU support This adds TMU (Time Management Unit) support for Intel BXT platform. It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove PMIC. Signed-off-by: Nilesh Bacchewar Reviewed-by: Mika Westerberg [andy: resolve merge conflict in Kconfig] Signed-off-by: Andy Shevchenko --- drivers/mfd/intel_soc_pmic_bxtwc.c | 38 ++++++++ drivers/platform/x86/Kconfig | 9 ++ drivers/platform/x86/Makefile | 1 + drivers/platform/x86/intel_bxtwc_tmu.c | 162 +++++++++++++++++++++++++++++++++ include/linux/mfd/intel_soc_pmic.h | 1 + 5 files changed, 211 insertions(+) create mode 100644 drivers/platform/x86/intel_bxtwc_tmu.c (limited to 'drivers') diff --git a/drivers/mfd/intel_soc_pmic_bxtwc.c b/drivers/mfd/intel_soc_pmic_bxtwc.c index 43e54b7e908f..92aba02042f0 100644 --- a/drivers/mfd/intel_soc_pmic_bxtwc.c +++ b/drivers/mfd/intel_soc_pmic_bxtwc.c @@ -42,6 +42,7 @@ #define BXTWC_GPIOIRQ0 0x4E0B #define BXTWC_GPIOIRQ1 0x4E0C #define BXTWC_CRITIRQ 0x4E0D +#define BXTWC_TMUIRQ 0x4FB6 /* Interrupt MASK Registers */ #define BXTWC_MIRQLVL1 0x4E0E @@ -59,6 +60,7 @@ #define BXTWC_MGPIO0IRQ 0x4E19 #define BXTWC_MGPIO1IRQ 0x4E1A #define BXTWC_MCRITIRQ 0x4E1B +#define BXTWC_MTMUIRQ 0x4FB7 /* Whiskey Cove PMIC share same ACPI ID between different platforms */ #define BROXTON_PMIC_WC_HRV 4 @@ -91,6 +93,7 @@ enum bxtwc_irqs_level2 { BXTWC_GPIO0_IRQ, BXTWC_GPIO1_IRQ, BXTWC_CRIT_IRQ, + BXTWC_TMU_IRQ, }; static const struct regmap_irq bxtwc_regmap_irqs[] = { @@ -118,6 +121,10 @@ static const struct regmap_irq bxtwc_regmap_irqs_level2[] = { REGMAP_IRQ_REG(BXTWC_CRIT_IRQ, 9, 0x03), }; +static const struct regmap_irq bxtwc_regmap_irqs_tmu[] = { + REGMAP_IRQ_REG(BXTWC_TMU_IRQ, 0, 0x06), +}; + static struct regmap_irq_chip bxtwc_regmap_irq_chip = { .name = "bxtwc_irq_chip", .status_base = BXTWC_IRQLVL1, @@ -136,6 +143,15 @@ static struct regmap_irq_chip bxtwc_regmap_irq_chip_level2 = { .num_regs = 10, }; +static struct regmap_irq_chip bxtwc_regmap_irq_chip_tmu = { + .name = "bxtwc_irq_chip_tmu", + .status_base = BXTWC_TMUIRQ, + .mask_base = BXTWC_MTMUIRQ, + .irqs = bxtwc_regmap_irqs_tmu, + .num_irqs = ARRAY_SIZE(bxtwc_regmap_irqs_tmu), + .num_regs = 1, +}; + static struct resource gpio_resources[] = { DEFINE_RES_IRQ_NAMED(BXTWC_GPIO0_IRQ, "GPIO0"), DEFINE_RES_IRQ_NAMED(BXTWC_GPIO1_IRQ, "GPIO1"), @@ -164,6 +180,10 @@ static struct resource bcu_resources[] = { DEFINE_RES_IRQ_NAMED(BXTWC_BCU_IRQ, "BCU"), }; +static struct resource tmu_resources[] = { + DEFINE_RES_IRQ_NAMED(BXTWC_TMU_IRQ, "TMU"), +}; + static struct mfd_cell bxt_wc_dev[] = { { .name = "bxt_wcove_gpadc", @@ -190,6 +210,12 @@ static struct mfd_cell bxt_wc_dev[] = { .num_resources = ARRAY_SIZE(bcu_resources), .resources = bcu_resources, }, + { + .name = "bxt_wcove_tmu", + .num_resources = ARRAY_SIZE(tmu_resources), + .resources = tmu_resources, + }, + { .name = "bxt_wcove_gpio", .num_resources = ARRAY_SIZE(gpio_resources), @@ -400,6 +426,15 @@ static int bxtwc_probe(struct platform_device *pdev) goto err_irq_chip_level2; } + ret = regmap_add_irq_chip(pmic->regmap, pmic->irq, + IRQF_ONESHOT | IRQF_SHARED, + 0, &bxtwc_regmap_irq_chip_tmu, + &pmic->irq_chip_data_tmu); + if (ret) { + dev_err(&pdev->dev, "Failed to add TMU IRQ chip\n"); + goto err_irq_chip_tmu; + } + ret = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_NONE, bxt_wc_dev, ARRAY_SIZE(bxt_wc_dev), NULL, 0, NULL); @@ -429,6 +464,8 @@ static int bxtwc_probe(struct platform_device *pdev) err_sysfs: mfd_remove_devices(&pdev->dev); err_mfd: + regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu); +err_irq_chip_tmu: regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); err_irq_chip_level2: regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); @@ -444,6 +481,7 @@ static int bxtwc_remove(struct platform_device *pdev) mfd_remove_devices(&pdev->dev); regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data); regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_level2); + regmap_del_irq_chip(pmic->irq, pmic->irq_chip_data_tmu); return 0; } diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 493e3386fbf6..5fe8be089b8b 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1017,6 +1017,15 @@ config INTEL_PMC_IPC The PMC is an ARC processor which defines IPC commands for communication with other entities in the CPU. +config INTEL_BXTWC_PMIC_TMU + tristate "Intel BXT Whiskey Cove TMU Driver" + depends on REGMAP + depends on INTEL_SOC_PMIC && INTEL_PMC_IPC + ---help--- + Select this driver to use Intel BXT Whiskey Cove PMIC TMU feature. + This driver enables the alarm wakeup functionality in the TMU unit + of Whiskey Cove PMIC. + config SURFACE_PRO3_BUTTON tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet" depends on ACPI && INPUT diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index e9290290f026..d4111f0f8a78 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -69,6 +69,7 @@ obj-$(CONFIG_INTEL_PMC_IPC) += intel_pmc_ipc.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o +obj-$(CONFIG_INTEL_BXTWC_PMIC_TMU) += intel_bxtwc_tmu.o obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \ intel_telemetry_pltdrv.o \ intel_telemetry_debugfs.o diff --git a/drivers/platform/x86/intel_bxtwc_tmu.c b/drivers/platform/x86/intel_bxtwc_tmu.c new file mode 100644 index 000000000000..e202abd5b0df --- /dev/null +++ b/drivers/platform/x86/intel_bxtwc_tmu.c @@ -0,0 +1,162 @@ +/* + * intel_bxtwc_tmu.c - Intel BXT Whiskey Cove PMIC TMU driver + * + * Copyright (C) 2016 Intel Corporation. All rights reserved. + * + * This driver adds TMU (Time Management Unit) support for Intel BXT platform. + * It enables the alarm wake-up functionality in the TMU unit of Whiskey Cove + * PMIC. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include + +#define BXTWC_TMUIRQ 0x4fb6 +#define BXTWC_MIRQLVL1 0x4e0e +#define BXTWC_MTMUIRQ_REG 0x4fb7 +#define BXTWC_MIRQLVL1_MTMU BIT(1) +#define BXTWC_TMU_WK_ALRM BIT(1) +#define BXTWC_TMU_SYS_ALRM BIT(2) +#define BXTWC_TMU_ALRM_MASK (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM) +#define BXTWC_TMU_ALRM_IRQ (BXTWC_TMU_WK_ALRM | BXTWC_TMU_SYS_ALRM) + +struct wcove_tmu { + int irq; + struct device *dev; + struct regmap *regmap; +}; + +static irqreturn_t bxt_wcove_tmu_irq_handler(int irq, void *data) +{ + struct wcove_tmu *wctmu = data; + unsigned int tmu_irq; + + /* Read TMU interrupt reg */ + regmap_read(wctmu->regmap, BXTWC_TMUIRQ, &tmu_irq); + if (tmu_irq & BXTWC_TMU_ALRM_IRQ) { + /* clear TMU irq */ + regmap_write(wctmu->regmap, BXTWC_TMUIRQ, tmu_irq); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +static int bxt_wcove_tmu_probe(struct platform_device *pdev) +{ + struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); + struct regmap_irq_chip_data *regmap_irq_chip; + struct wcove_tmu *wctmu; + int ret, virq, irq; + + wctmu = devm_kzalloc(&pdev->dev, sizeof(*wctmu), GFP_KERNEL); + if (!wctmu) + return -ENOMEM; + + wctmu->dev = &pdev->dev; + wctmu->regmap = pmic->regmap; + + irq = platform_get_irq(pdev, 0); + + if (irq < 0) { + dev_err(&pdev->dev, "invalid irq %d\n", irq); + return irq; + } + + regmap_irq_chip = pmic->irq_chip_data_tmu; + virq = regmap_irq_get_virq(regmap_irq_chip, irq); + if (virq < 0) { + dev_err(&pdev->dev, + "failed to get virtual interrupt=%d\n", irq); + return virq; + } + + ret = devm_request_threaded_irq(&pdev->dev, virq, + NULL, bxt_wcove_tmu_irq_handler, + IRQF_ONESHOT, "bxt_wcove_tmu", wctmu); + if (ret) { + dev_err(&pdev->dev, "request irq failed: %d,virq: %d\n", + ret, virq); + return ret; + } + wctmu->irq = virq; + + /* Enable TMU interrupts */ + regmap_update_bits(wctmu->regmap, BXTWC_MIRQLVL1, + BXTWC_MIRQLVL1_MTMU, 0); + + /* Unmask TMU second level Wake & System alarm */ + regmap_update_bits(wctmu->regmap, BXTWC_MTMUIRQ_REG, + BXTWC_TMU_ALRM_MASK, 0); + + platform_set_drvdata(pdev, wctmu); + return 0; +} + +static int bxt_wcove_tmu_remove(struct platform_device *pdev) +{ + struct wcove_tmu *wctmu = platform_get_drvdata(pdev); + unsigned int val; + + /* Mask TMU interrupts */ + regmap_read(wctmu->regmap, BXTWC_MIRQLVL1, &val); + regmap_write(wctmu->regmap, BXTWC_MIRQLVL1, + val | BXTWC_MIRQLVL1_MTMU); + regmap_read(wctmu->regmap, BXTWC_MTMUIRQ_REG, &val); + regmap_write(wctmu->regmap, BXTWC_MTMUIRQ_REG, + val | BXTWC_TMU_ALRM_MASK); + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int bxtwc_tmu_suspend(struct device *dev) +{ + struct wcove_tmu *wctmu = dev_get_drvdata(dev); + + enable_irq_wake(wctmu->irq); + return 0; +} + +static int bxtwc_tmu_resume(struct device *dev) +{ + struct wcove_tmu *wctmu = dev_get_drvdata(dev); + + disable_irq_wake(wctmu->irq); + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(bxtwc_tmu_pm_ops, bxtwc_tmu_suspend, bxtwc_tmu_resume); + +static const struct platform_device_id bxt_wcove_tmu_id_table[] = { + { .name = "bxt_wcove_tmu" }, + {}, +}; +MODULE_DEVICE_TABLE(platform, bxt_wcove_tmu_id_table); + +static struct platform_driver bxt_wcove_tmu_driver = { + .probe = bxt_wcove_tmu_probe, + .remove = bxt_wcove_tmu_remove, + .driver = { + .name = "bxt_wcove_tmu", + .pm = &bxtwc_tmu_pm_ops, + }, + .id_table = bxt_wcove_tmu_id_table, +}; + +module_platform_driver(bxt_wcove_tmu_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("Nilesh Bacchewar "); +MODULE_DESCRIPTION("BXT Whiskey Cove TMU Driver"); diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h index cf619dbeace2..956caa0628f5 100644 --- a/include/linux/mfd/intel_soc_pmic.h +++ b/include/linux/mfd/intel_soc_pmic.h @@ -26,6 +26,7 @@ struct intel_soc_pmic { struct regmap *regmap; struct regmap_irq_chip_data *irq_chip_data; struct regmap_irq_chip_data *irq_chip_data_level2; + struct regmap_irq_chip_data *irq_chip_data_tmu; struct device *dev; }; -- cgit v1.2.3 From 83da6b59919a71a1a97ce9863aa0267eaf6d496c Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 15 Dec 2016 03:10:02 +0200 Subject: platform/x86: surface3-wmi: Balance locking on error path There is a possibility that lock will be left acquired. Consolidate error path under out_free_unlock label. Reported-by: kbuild test robot Reviewed-by: Benjamin Tissoires Signed-off-by: Andy Shevchenko --- drivers/platform/x86/surface3-wmi.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/platform/x86/surface3-wmi.c b/drivers/platform/x86/surface3-wmi.c index 5553b2b85e0a..cbf4d83a7271 100644 --- a/drivers/platform/x86/surface3-wmi.c +++ b/drivers/platform/x86/surface3-wmi.c @@ -60,10 +60,10 @@ static DEFINE_MUTEX(s3_wmi_lock); static int s3_wmi_query_block(const char *guid, int instance, int *ret) { + struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; acpi_status status; union acpi_object *obj; - - struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL }; + int error = 0; mutex_lock(&s3_wmi_lock); status = wmi_query_block(guid, instance, &output); @@ -77,13 +77,14 @@ static int s3_wmi_query_block(const char *guid, int instance, int *ret) obj->type == ACPI_TYPE_BUFFER ? obj->buffer.length : 0); } - kfree(obj); - return -EINVAL; + error = -EINVAL; + goto out_free_unlock; } *ret = obj->integer.value; + out_free_unlock: kfree(obj); mutex_unlock(&s3_wmi_lock); - return 0; + return error; } static inline int s3_wmi_query_lid(int *ret) -- cgit v1.2.3 From 65dadffddbe44a60f8be9e95f264949ba1e547e9 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Fri, 16 Dec 2016 14:43:39 -0800 Subject: Input: joydev - remove unused linux/miscdevice.h include This patch remove the inclusion of linux/miscdevice.h for joydev since it does not use miscdevice. Signed-off-by: Corentin Labbe Signed-off-by: Dmitry Torokhov --- drivers/input/joydev.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index f3135ae22df4..abd18f31b24f 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3 From 41c567a5d7d1a986763e58c3394782813c3bcb03 Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Sun, 18 Dec 2016 15:26:12 -0800 Subject: Input: i8042 - add Pegatron touchpad to noloop table Avoid AUX loopback in Pegatron C15B touchpad, so input subsystem is able to recognize a Synaptics touchpad in the AUX port. Fixes: https://bugzilla.kernel.org/show_bug.cgi?id=93791 (Touchpad is not detected on DNS 0801480 notebook (PEGATRON C15B)) Suggested-by: Dmitry Torokhov Signed-off-by: Marcos Paulo de Souza Signed-off-by: Dmitry Torokhov --- drivers/input/serio/i8042-x86ia64io.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 73a4e68448fc..381d802fe853 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -211,6 +211,12 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = { DMI_MATCH(DMI_PRODUCT_VERSION, "Rev 1"), }, }, + { + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "PEGATRON CORPORATION"), + DMI_MATCH(DMI_PRODUCT_NAME, "C15B"), + }, + }, { } }; -- cgit v1.2.3 From 67626c9323027534496d21cf32793121662d03c0 Mon Sep 17 00:00:00 2001 From: Aniroop Mathur Date: Sun, 18 Dec 2016 15:27:16 -0800 Subject: Input: synaptics_i2c - change msleep to usleep_range for small msecs msleep(1~20) may not do what the caller intends, and will often sleep longer. (~20 ms actual sleep for any value given in the 1~20ms range) This is not the desired behaviour for many cases like device resume time, device suspend time, device enable time, retry logic, etc. Thus, change msleep to usleep_range for precise wakeups. Signed-off-by: Aniroop Mathur Acked-by: Igor Grinberg Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/synaptics_i2c.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/input/mouse/synaptics_i2c.c b/drivers/input/mouse/synaptics_i2c.c index aa7c5da60800..cb2bf203f4ca 100644 --- a/drivers/input/mouse/synaptics_i2c.c +++ b/drivers/input/mouse/synaptics_i2c.c @@ -29,7 +29,7 @@ * after soft reset, we should wait for 1 ms * before the device becomes operational */ -#define SOFT_RESET_DELAY_MS 3 +#define SOFT_RESET_DELAY_US 3000 /* and after hard reset, we should wait for max 500ms */ #define HARD_RESET_DELAY_MS 500 @@ -311,7 +311,7 @@ static int synaptics_i2c_reset_config(struct i2c_client *client) if (ret) { dev_err(&client->dev, "Unable to reset device\n"); } else { - msleep(SOFT_RESET_DELAY_MS); + usleep_range(SOFT_RESET_DELAY_US, SOFT_RESET_DELAY_US + 100); ret = synaptics_i2c_config(client); if (ret) dev_err(&client->dev, "Unable to config device\n"); -- cgit v1.2.3 From 9c19b8930d2cf95f5dc5ec11610400a7c61845d1 Mon Sep 17 00:00:00 2001 From: Tin Huynh Date: Wed, 30 Nov 2016 09:57:31 +0700 Subject: rtc: ds1307: Add ACPI support This patch enables ACPI support for rtc-ds1307 driver. Signed-off-by: Tin Huynh Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 52 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 4e31036ee259..4ad97be48043 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -11,6 +11,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -191,6 +192,26 @@ static const struct i2c_device_id ds1307_id[] = { }; MODULE_DEVICE_TABLE(i2c, ds1307_id); +#ifdef CONFIG_ACPI +static const struct acpi_device_id ds1307_acpi_ids[] = { + { .id = "DS1307", .driver_data = ds_1307 }, + { .id = "DS1337", .driver_data = ds_1337 }, + { .id = "DS1338", .driver_data = ds_1338 }, + { .id = "DS1339", .driver_data = ds_1339 }, + { .id = "DS1388", .driver_data = ds_1388 }, + { .id = "DS1340", .driver_data = ds_1340 }, + { .id = "DS3231", .driver_data = ds_3231 }, + { .id = "M41T00", .driver_data = m41t00 }, + { .id = "MCP7940X", .driver_data = mcp794xx }, + { .id = "MCP7941X", .driver_data = mcp794xx }, + { .id = "PT7C4338", .driver_data = ds_1307 }, + { .id = "RX8025", .driver_data = rx_8025 }, + { .id = "ISL12057", .driver_data = ds_1337 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids); +#endif + /*----------------------------------------------------------------------*/ #define BLOCK_DATA_MAX_TRIES 10 @@ -874,17 +895,17 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client, return setup; } -static void ds1307_trickle_of_init(struct i2c_client *client, - struct chip_desc *chip) +static void ds1307_trickle_init(struct i2c_client *client, + struct chip_desc *chip) { uint32_t ohms = 0; bool diode = true; if (!chip->do_trickle_setup) goto out; - if (of_property_read_u32(client->dev.of_node, "trickle-resistor-ohms" , &ohms)) + if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms)) goto out; - if (of_property_read_bool(client->dev.of_node, "trickle-diode-disable")) + if (device_property_read_bool(&client->dev, "trickle-diode-disable")) diode = false; chip->trickle_charger_setup = chip->do_trickle_setup(client, ohms, diode); @@ -1268,7 +1289,7 @@ static int ds1307_probe(struct i2c_client *client, struct ds1307 *ds1307; int err = -ENODEV; int tmp, wday; - struct chip_desc *chip = &chips[id->driver_data]; + struct chip_desc *chip; struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); bool want_irq = false; bool ds1307_can_wakeup_device = false; @@ -1297,11 +1318,23 @@ static int ds1307_probe(struct i2c_client *client, i2c_set_clientdata(client, ds1307); ds1307->client = client; - ds1307->type = id->driver_data; + if (id) { + chip = &chips[id->driver_data]; + ds1307->type = id->driver_data; + } else { + const struct acpi_device_id *acpi_id; + + acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids), + &client->dev); + if (!acpi_id) + return -ENODEV; + chip = &chips[acpi_id->driver_data]; + ds1307->type = acpi_id->driver_data; + } - if (!pdata && client->dev.of_node) - ds1307_trickle_of_init(client, chip); - else if (pdata && pdata->trickle_charger_setup) + if (!pdata) + ds1307_trickle_init(client, chip); + else if (pdata->trickle_charger_setup) chip->trickle_charger_setup = pdata->trickle_charger_setup; if (chip->trickle_charger_setup && chip->trickle_charger_reg) { @@ -1678,6 +1711,7 @@ static int ds1307_remove(struct i2c_client *client) static struct i2c_driver ds1307_driver = { .driver = { .name = "rtc-ds1307", + .acpi_match_table = ACPI_PTR(ds1307_acpi_ids), }, .probe = ds1307_probe, .remove = ds1307_remove, -- cgit v1.2.3 From 0b6a8f5c9bebe51b95ff23939db570e8d298a36f Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Sun, 4 Dec 2016 23:04:39 +0900 Subject: rtc: add support for EPSON TOYOCOM RTC-7301SF/DG This adds support for EPSON TOYOCOM RTC-7301SF/DG which has parallel interface compatible with SRAM. This driver supports basic clock, calendar and alarm functionality. Tested with Microblaze linux running on Artix7 FPGA board with my own custom IP for RTC-7301. Signed-off-by: Akinobu Mita Acked-by: Rob Herring Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/epson,rtc7301.txt | 16 + drivers/rtc/Kconfig | 11 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-r7301.c | 453 +++++++++++++++++++++ 4 files changed, 481 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/epson,rtc7301.txt create mode 100644 drivers/rtc/rtc-r7301.c (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt b/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt new file mode 100644 index 000000000000..5f9df3f1467c --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt @@ -0,0 +1,16 @@ +EPSON TOYOCOM RTC-7301SF/DG + +Required properties: + +- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg" +- reg: Specifies base physical address and size of the registers. +- interrupts: A single interrupt specifier. + +Example: + +rtc: rtc@44a00000 { + compatible = "epson,rtc7301dg"; + reg = <0x44a00000 0x10000>; + interrupt-parent = <&axi_intc_0>; + interrupts = <3 2>; +}; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index a44f1f27ecfa..c93c5a8fba32 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1705,6 +1705,17 @@ config RTC_DRV_PIC32 This driver can also be built as a module. If so, the module will be called rtc-pic32 +config RTC_DRV_R7301 + tristate "EPSON TOYOCOM RTC-7301SF/DG" + select REGMAP_MMIO + depends on OF && HAS_IOMEM + help + If you say yes here you get support for the EPSON TOYOCOM + RTC-7301SF/DG chips. + + This driver can also be built as a module. If so, the module + will be called rtc-r7301. + comment "HID Sensor RTC drivers" config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1ac694a330c8..f13ab1c5c222 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -120,6 +120,7 @@ obj-$(CONFIG_RTC_DRV_PM8XXX) += rtc-pm8xxx.o obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o +obj-$(CONFIG_RTC_DRV_R7301) += rtc-r7301.o obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o obj-$(CONFIG_RTC_DRV_RK808) += rtc-rk808.o diff --git a/drivers/rtc/rtc-r7301.c b/drivers/rtc/rtc-r7301.c new file mode 100644 index 000000000000..28d540885f3d --- /dev/null +++ b/drivers/rtc/rtc-r7301.c @@ -0,0 +1,453 @@ +/* + * EPSON TOYOCOM RTC-7301SF/DG Driver + * + * Copyright (c) 2016 Akinobu Mita + * + * Based on rtc-rp5c01.c + * + * Datasheet: http://www5.epsondevice.com/en/products/parallel/rtc7301sf.html + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRV_NAME "rtc-r7301" + +#define RTC7301_1_SEC 0x0 /* Bank 0 and Band 1 */ +#define RTC7301_10_SEC 0x1 /* Bank 0 and Band 1 */ +#define RTC7301_AE BIT(3) +#define RTC7301_1_MIN 0x2 /* Bank 0 and Band 1 */ +#define RTC7301_10_MIN 0x3 /* Bank 0 and Band 1 */ +#define RTC7301_1_HOUR 0x4 /* Bank 0 and Band 1 */ +#define RTC7301_10_HOUR 0x5 /* Bank 0 and Band 1 */ +#define RTC7301_DAY_OF_WEEK 0x6 /* Bank 0 and Band 1 */ +#define RTC7301_1_DAY 0x7 /* Bank 0 and Band 1 */ +#define RTC7301_10_DAY 0x8 /* Bank 0 and Band 1 */ +#define RTC7301_1_MONTH 0x9 /* Bank 0 */ +#define RTC7301_10_MONTH 0xa /* Bank 0 */ +#define RTC7301_1_YEAR 0xb /* Bank 0 */ +#define RTC7301_10_YEAR 0xc /* Bank 0 */ +#define RTC7301_100_YEAR 0xd /* Bank 0 */ +#define RTC7301_1000_YEAR 0xe /* Bank 0 */ +#define RTC7301_ALARM_CONTROL 0xe /* Bank 1 */ +#define RTC7301_ALARM_CONTROL_AIE BIT(0) +#define RTC7301_ALARM_CONTROL_AF BIT(1) +#define RTC7301_TIMER_CONTROL 0xe /* Bank 2 */ +#define RTC7301_TIMER_CONTROL_TIE BIT(0) +#define RTC7301_TIMER_CONTROL_TF BIT(1) +#define RTC7301_CONTROL 0xf /* All banks */ +#define RTC7301_CONTROL_BUSY BIT(0) +#define RTC7301_CONTROL_STOP BIT(1) +#define RTC7301_CONTROL_BANK_SEL_0 BIT(2) +#define RTC7301_CONTROL_BANK_SEL_1 BIT(3) + +struct rtc7301_priv { + struct regmap *regmap; + int irq; + spinlock_t lock; + u8 bank; +}; + +static const struct regmap_config rtc7301_regmap_config = { + .reg_bits = 32, + .val_bits = 8, + .reg_stride = 4, +}; + +static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg) +{ + int reg_stride = regmap_get_reg_stride(priv->regmap); + unsigned int val; + + regmap_read(priv->regmap, reg_stride * reg, &val); + + return val & 0xf; +} + +static void rtc7301_write(struct rtc7301_priv *priv, u8 val, unsigned int reg) +{ + int reg_stride = regmap_get_reg_stride(priv->regmap); + + regmap_write(priv->regmap, reg_stride * reg, val); +} + +static void rtc7301_update_bits(struct rtc7301_priv *priv, unsigned int reg, + u8 mask, u8 val) +{ + int reg_stride = regmap_get_reg_stride(priv->regmap); + + regmap_update_bits(priv->regmap, reg_stride * reg, mask, val); +} + +static int rtc7301_wait_while_busy(struct rtc7301_priv *priv) +{ + int retries = 100; + + while (retries-- > 0) { + u8 val; + + val = rtc7301_read(priv, RTC7301_CONTROL); + if (!(val & RTC7301_CONTROL_BUSY)) + return 0; + + usleep_range(200, 300); + } + + return -ETIMEDOUT; +} + +static void rtc7301_stop(struct rtc7301_priv *priv) +{ + rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, + RTC7301_CONTROL_STOP); +} + +static void rtc7301_start(struct rtc7301_priv *priv) +{ + rtc7301_update_bits(priv, RTC7301_CONTROL, RTC7301_CONTROL_STOP, 0); +} + +static void rtc7301_select_bank(struct rtc7301_priv *priv, u8 bank) +{ + u8 val = 0; + + if (bank == priv->bank) + return; + + if (bank & BIT(0)) + val |= RTC7301_CONTROL_BANK_SEL_0; + if (bank & BIT(1)) + val |= RTC7301_CONTROL_BANK_SEL_1; + + rtc7301_update_bits(priv, RTC7301_CONTROL, + RTC7301_CONTROL_BANK_SEL_0 | + RTC7301_CONTROL_BANK_SEL_1, val); + + priv->bank = bank; +} + +static void rtc7301_get_time(struct rtc7301_priv *priv, struct rtc_time *tm, + bool alarm) +{ + int year; + + tm->tm_sec = rtc7301_read(priv, RTC7301_1_SEC); + tm->tm_sec += (rtc7301_read(priv, RTC7301_10_SEC) & ~RTC7301_AE) * 10; + tm->tm_min = rtc7301_read(priv, RTC7301_1_MIN); + tm->tm_min += (rtc7301_read(priv, RTC7301_10_MIN) & ~RTC7301_AE) * 10; + tm->tm_hour = rtc7301_read(priv, RTC7301_1_HOUR); + tm->tm_hour += (rtc7301_read(priv, RTC7301_10_HOUR) & ~RTC7301_AE) * 10; + tm->tm_mday = rtc7301_read(priv, RTC7301_1_DAY); + tm->tm_mday += (rtc7301_read(priv, RTC7301_10_DAY) & ~RTC7301_AE) * 10; + + if (alarm) { + tm->tm_wday = -1; + tm->tm_mon = -1; + tm->tm_year = -1; + tm->tm_yday = -1; + tm->tm_isdst = -1; + return; + } + + tm->tm_wday = (rtc7301_read(priv, RTC7301_DAY_OF_WEEK) & ~RTC7301_AE); + tm->tm_mon = rtc7301_read(priv, RTC7301_10_MONTH) * 10 + + rtc7301_read(priv, RTC7301_1_MONTH) - 1; + year = rtc7301_read(priv, RTC7301_1000_YEAR) * 1000 + + rtc7301_read(priv, RTC7301_100_YEAR) * 100 + + rtc7301_read(priv, RTC7301_10_YEAR) * 10 + + rtc7301_read(priv, RTC7301_1_YEAR); + + tm->tm_year = year - 1900; +} + +static void rtc7301_write_time(struct rtc7301_priv *priv, struct rtc_time *tm, + bool alarm) +{ + int year; + + rtc7301_write(priv, tm->tm_sec % 10, RTC7301_1_SEC); + rtc7301_write(priv, tm->tm_sec / 10, RTC7301_10_SEC); + + rtc7301_write(priv, tm->tm_min % 10, RTC7301_1_MIN); + rtc7301_write(priv, tm->tm_min / 10, RTC7301_10_MIN); + + rtc7301_write(priv, tm->tm_hour % 10, RTC7301_1_HOUR); + rtc7301_write(priv, tm->tm_hour / 10, RTC7301_10_HOUR); + + rtc7301_write(priv, tm->tm_mday % 10, RTC7301_1_DAY); + rtc7301_write(priv, tm->tm_mday / 10, RTC7301_10_DAY); + + /* Don't care for alarm register */ + rtc7301_write(priv, alarm ? RTC7301_AE : tm->tm_wday, + RTC7301_DAY_OF_WEEK); + + if (alarm) + return; + + rtc7301_write(priv, (tm->tm_mon + 1) % 10, RTC7301_1_MONTH); + rtc7301_write(priv, (tm->tm_mon + 1) / 10, RTC7301_10_MONTH); + + year = tm->tm_year + 1900; + + rtc7301_write(priv, year % 10, RTC7301_1_YEAR); + rtc7301_write(priv, (year / 10) % 10, RTC7301_10_YEAR); + rtc7301_write(priv, (year / 100) % 10, RTC7301_100_YEAR); + rtc7301_write(priv, year / 1000, RTC7301_1000_YEAR); +} + +static void rtc7301_alarm_irq(struct rtc7301_priv *priv, unsigned int enabled) +{ + rtc7301_update_bits(priv, RTC7301_ALARM_CONTROL, + RTC7301_ALARM_CONTROL_AF | + RTC7301_ALARM_CONTROL_AIE, + enabled ? RTC7301_ALARM_CONTROL_AIE : 0); +} + +static int rtc7301_read_time(struct device *dev, struct rtc_time *tm) +{ + struct rtc7301_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + int err; + + spin_lock_irqsave(&priv->lock, flags); + + rtc7301_select_bank(priv, 0); + + err = rtc7301_wait_while_busy(priv); + if (!err) + rtc7301_get_time(priv, tm, false); + + spin_unlock_irqrestore(&priv->lock, flags); + + return err ? err : rtc_valid_tm(tm); +} + +static int rtc7301_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rtc7301_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + rtc7301_stop(priv); + usleep_range(200, 300); + rtc7301_select_bank(priv, 0); + rtc7301_write_time(priv, tm, false); + rtc7301_start(priv); + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int rtc7301_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct rtc7301_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + u8 alrm_ctrl; + + if (priv->irq <= 0) + return -EINVAL; + + spin_lock_irqsave(&priv->lock, flags); + + rtc7301_select_bank(priv, 1); + rtc7301_get_time(priv, &alarm->time, true); + + alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL); + + alarm->enabled = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AIE); + alarm->pending = !!(alrm_ctrl & RTC7301_ALARM_CONTROL_AF); + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int rtc7301_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct rtc7301_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + + if (priv->irq <= 0) + return -EINVAL; + + spin_lock_irqsave(&priv->lock, flags); + + rtc7301_select_bank(priv, 1); + rtc7301_write_time(priv, &alarm->time, true); + rtc7301_alarm_irq(priv, alarm->enabled); + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static int rtc7301_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct rtc7301_priv *priv = dev_get_drvdata(dev); + unsigned long flags; + + if (priv->irq <= 0) + return -EINVAL; + + spin_lock_irqsave(&priv->lock, flags); + + rtc7301_select_bank(priv, 1); + rtc7301_alarm_irq(priv, enabled); + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + +static const struct rtc_class_ops rtc7301_rtc_ops = { + .read_time = rtc7301_read_time, + .set_time = rtc7301_set_time, + .read_alarm = rtc7301_read_alarm, + .set_alarm = rtc7301_set_alarm, + .alarm_irq_enable = rtc7301_alarm_irq_enable, +}; + +static irqreturn_t rtc7301_irq_handler(int irq, void *dev_id) +{ + struct rtc_device *rtc = dev_id; + struct rtc7301_priv *priv = dev_get_drvdata(rtc->dev.parent); + unsigned long flags; + irqreturn_t ret = IRQ_NONE; + u8 alrm_ctrl; + + spin_lock_irqsave(&priv->lock, flags); + + rtc7301_select_bank(priv, 1); + + alrm_ctrl = rtc7301_read(priv, RTC7301_ALARM_CONTROL); + if (alrm_ctrl & RTC7301_ALARM_CONTROL_AF) { + ret = IRQ_HANDLED; + rtc7301_alarm_irq(priv, false); + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return ret; +} + +static void rtc7301_init(struct rtc7301_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->lock, flags); + + rtc7301_select_bank(priv, 2); + rtc7301_write(priv, 0, RTC7301_TIMER_CONTROL); + + spin_unlock_irqrestore(&priv->lock, flags); +} + +static int __init rtc7301_rtc_probe(struct platform_device *dev) +{ + struct resource *res; + void __iomem *regs; + struct rtc7301_priv *priv; + struct rtc_device *rtc; + int ret; + + res = platform_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) + return -ENODEV; + + priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + regs = devm_ioremap_resource(&dev->dev, res); + if (IS_ERR(regs)) + return PTR_ERR(regs); + + priv->regmap = devm_regmap_init_mmio(&dev->dev, regs, + &rtc7301_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + priv->irq = platform_get_irq(dev, 0); + + spin_lock_init(&priv->lock); + priv->bank = -1; + + rtc7301_init(priv); + + platform_set_drvdata(dev, priv); + + rtc = devm_rtc_device_register(&dev->dev, DRV_NAME, &rtc7301_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + if (priv->irq > 0) { + ret = devm_request_irq(&dev->dev, priv->irq, + rtc7301_irq_handler, IRQF_SHARED, + dev_name(&dev->dev), rtc); + if (ret) { + priv->irq = 0; + dev_err(&dev->dev, "unable to request IRQ\n"); + } else { + device_set_wakeup_capable(&dev->dev, true); + } + } + + return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int rtc7301_suspend(struct device *dev) +{ + struct rtc7301_priv *priv = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(priv->irq); + + return 0; +} + +static int rtc7301_resume(struct device *dev) +{ + struct rtc7301_priv *priv = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(priv->irq); + + return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(rtc7301_pm_ops, rtc7301_suspend, rtc7301_resume); + +static const struct of_device_id rtc7301_dt_match[] = { + { .compatible = "epson,rtc7301sf" }, + { .compatible = "epson,rtc7301dg" }, + {} +}; +MODULE_DEVICE_TABLE(of, rtc7301_dt_match); + +static struct platform_driver rtc7301_rtc_driver = { + .driver = { + .name = DRV_NAME, + .of_match_table = rtc7301_dt_match, + .pm = &rtc7301_pm_ops, + }, +}; + +module_platform_driver_probe(rtc7301_rtc_driver, rtc7301_rtc_probe); + +MODULE_AUTHOR("Akinobu Mita "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("EPSON TOYOCOM RTC-7301SF/DG Driver"); +MODULE_ALIAS("platform:rtc-r7301"); -- cgit v1.2.3 From bcf18d88ac16c1a86bac7e8f5f4b1de1f752865f Mon Sep 17 00:00:00 2001 From: Emil Bartczak Date: Thu, 8 Dec 2016 00:27:37 +0100 Subject: rtc: mcp795: use bcd2bin/bin2bcd. Change rtc-mcp795.c to use the bcd2bin/bin2bcd functions. This change fixes the wrong conversion of month value from binary to BCD (missing right shift operation for 10 month). Signed-off-by: Emil Bartczak Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 4021fd04cb0a..0389ee03c660 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -21,6 +21,7 @@ #include #include #include +#include /* MCP795 Instructions, see datasheet table 3-1 */ #define MCP795_EEREAD 0x03 @@ -104,16 +105,16 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim) if (ret) return ret; - data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10); - data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10); - data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10); - data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10); - data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10); + data[0] = (data[0] & 0x80) | bin2bcd(tim->tm_sec); + data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min); + data[2] = bin2bcd(tim->tm_hour); + data[4] = bin2bcd(tim->tm_mday); + data[5] = (data[5] & 0x10) | bin2bcd(tim->tm_mon); if (tim->tm_year > 100) tim->tm_year -= 100; - data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10); + data[6] = bin2bcd(tim->tm_year); ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data)); @@ -137,12 +138,12 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim) if (ret) return ret; - tim->tm_sec = ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f); - tim->tm_min = ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f); - tim->tm_hour = ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f); - tim->tm_mday = ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f); - tim->tm_mon = ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f); - tim->tm_year = ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */ + tim->tm_sec = bcd2bin(data[0] & 0x7F); + tim->tm_min = bcd2bin(data[1] & 0x7F); + tim->tm_hour = bcd2bin(data[2] & 0x3F); + tim->tm_mday = bcd2bin(data[4] & 0x3F); + tim->tm_mon = bcd2bin(data[5] & 0x1F); + tim->tm_year = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */ dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, -- cgit v1.2.3 From e72765c648a172f052486cba9688ddc28f23140b Mon Sep 17 00:00:00 2001 From: Emil Bartczak Date: Thu, 8 Dec 2016 00:27:38 +0100 Subject: rtc: mcp795: fix bitmask value for leap year (LP). According the datasheet the leap year is a fifth bit in month register. Signed-off-by: Emil Bartczak Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 0389ee03c660..5fbdb4c20a9b 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -40,6 +40,7 @@ #define MCP795_ST_BIT 0x80 #define MCP795_24_BIT 0x40 +#define MCP795_LP_BIT BIT(5) static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count) { @@ -109,7 +110,7 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim) data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min); data[2] = bin2bcd(tim->tm_hour); data[4] = bin2bcd(tim->tm_mday); - data[5] = (data[5] & 0x10) | bin2bcd(tim->tm_mon); + data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon); if (tim->tm_year > 100) tim->tm_year -= 100; -- cgit v1.2.3 From 26eeefd5956449b03c87c49b996e012ffe3e59aa Mon Sep 17 00:00:00 2001 From: Emil Bartczak Date: Thu, 8 Dec 2016 00:27:39 +0100 Subject: rtc: mcp795: fix time range difference between linux and RTC chip. In linux rtc_time struct, tm_mon range is 0~11, while in RTC HW REG, month range is 1~12. This patch adjusts difference of them. Signed-off-by: Emil Bartczak Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 5fbdb4c20a9b..4618f4fa655f 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -110,7 +110,7 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim) data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min); data[2] = bin2bcd(tim->tm_hour); data[4] = bin2bcd(tim->tm_mday); - data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon); + data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon + 1); if (tim->tm_year > 100) tim->tm_year -= 100; @@ -143,7 +143,7 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim) tim->tm_min = bcd2bin(data[1] & 0x7F); tim->tm_hour = bcd2bin(data[2] & 0x3F); tim->tm_mday = bcd2bin(data[4] & 0x3F); - tim->tm_mon = bcd2bin(data[5] & 0x1F); + tim->tm_mon = bcd2bin(data[5] & 0x1F) - 1; tim->tm_year = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */ dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", -- cgit v1.2.3 From 43d0b10f60c54667108729adb525bc1090d4238f Mon Sep 17 00:00:00 2001 From: Emil Bartczak Date: Thu, 8 Dec 2016 00:27:40 +0100 Subject: rtc: mcp795: fix month write resetting date to 1. According to Microchip errata some combinations of date and month values may result in the date being reset to 1, even if the date is also written with the month (for example 31-07 or 31-08). As a workaround avoid writing date and month values within the same Write command. Instead, terminate the Write command after loading the date and begin a new command to write the month. In addition, disable the oscillator before loading the new values. This is done by ensuring both the ST and EXTOSC bits are cleared and waiting for the OSCON bit to clear. Signed-off-by: Emil Bartczak Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 86 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 4618f4fa655f..89b0ffa83064 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -22,6 +22,7 @@ #include #include #include +#include /* MCP795 Instructions, see datasheet table 3-1 */ #define MCP795_EEREAD 0x03 @@ -38,9 +39,17 @@ #define MCP795_CLRWDT 0x44 #define MCP795_CLRRAM 0x54 +/* MCP795 RTCC registers, see datasheet table 4-1 */ +#define MCP795_REG_SECONDS 0x01 +#define MCP795_REG_DAY 0x04 +#define MCP795_REG_MONTH 0x06 +#define MCP795_REG_CONTROL 0x08 + #define MCP795_ST_BIT 0x80 #define MCP795_24_BIT 0x40 #define MCP795_LP_BIT BIT(5) +#define MCP795_EXTOSC_BIT BIT(3) +#define MCP795_OSCON_BIT BIT(5) static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count) { @@ -95,13 +104,65 @@ static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state) return ret; } +static int mcp795_stop_oscillator(struct device *dev, bool *extosc) +{ + int retries = 5; + int ret; + u8 data; + + ret = mcp795_rtcc_set_bits(dev, MCP795_REG_SECONDS, MCP795_ST_BIT, 0); + if (ret) + return ret; + ret = mcp795_rtcc_read(dev, MCP795_REG_CONTROL, &data, 1); + if (ret) + return ret; + *extosc = !!(data & MCP795_EXTOSC_BIT); + ret = mcp795_rtcc_set_bits( + dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, 0); + if (ret) + return ret; + /* wait for the OSCON bit to clear */ + do { + usleep_range(700, 800); + ret = mcp795_rtcc_read(dev, MCP795_REG_DAY, &data, 1); + if (ret) + break; + if (!(data & MCP795_OSCON_BIT)) + break; + + } while (--retries); + + return !retries ? -EIO : ret; +} + +static int mcp795_start_oscillator(struct device *dev, bool *extosc) +{ + if (extosc) { + u8 data = *extosc ? MCP795_EXTOSC_BIT : 0; + int ret; + + ret = mcp795_rtcc_set_bits( + dev, MCP795_REG_CONTROL, MCP795_EXTOSC_BIT, data); + if (ret) + return ret; + } + return mcp795_rtcc_set_bits( + dev, MCP795_REG_SECONDS, MCP795_ST_BIT, MCP795_ST_BIT); +} + static int mcp795_set_time(struct device *dev, struct rtc_time *tim) { int ret; u8 data[7]; + bool extosc; + + /* Stop RTC and store current value of EXTOSC bit */ + ret = mcp795_stop_oscillator(dev, &extosc); + if (ret) + return ret; /* Read first, so we can leave config bits untouched */ - ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data)); if (ret) return ret; @@ -117,8 +178,23 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim) data[6] = bin2bcd(tim->tm_year); - ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data)); + /* Always write the date and month using a separate Write command. + * This is a workaround for a know silicon issue that some combinations + * of date and month values may result in the date being reset to 1. + */ + ret = mcp795_rtcc_write(dev, MCP795_REG_SECONDS, data, 5); + if (ret) + return ret; + + ret = mcp795_rtcc_write(dev, MCP795_REG_MONTH, &data[5], 2); + if (ret) + return ret; + /* Start back RTC and restore previous value of EXTOSC bit. + * There is no need to clear EXTOSC bit when the previous value was 0 + * because it was already cleared when stopping the RTC oscillator. + */ + ret = mcp795_start_oscillator(dev, extosc ? &extosc : NULL); if (ret) return ret; @@ -134,7 +210,7 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim) int ret; u8 data[7]; - ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + ret = mcp795_rtcc_read(dev, MCP795_REG_SECONDS, data, sizeof(data)); if (ret) return ret; @@ -171,8 +247,8 @@ static int mcp795_probe(struct spi_device *spi) return ret; } - /* Start the oscillator */ - mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT); + /* Start the oscillator but don't set the value of EXTOSC bit */ + mcp795_start_oscillator(&spi->dev, NULL); /* Clear the 12 hour mode flag*/ mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0); -- cgit v1.2.3 From a2b42997513401903341cf96616839ad22f151b6 Mon Sep 17 00:00:00 2001 From: Emil Bartczak Date: Thu, 8 Dec 2016 00:27:41 +0100 Subject: rtc: mcp795: Prefer using the BIT() macro. This patch doesn't change the code but replaces all bitmask values with the BIT(x) macro. Signed-off-by: Emil Bartczak Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 89b0ffa83064..8ed55f6ff8ba 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -45,8 +45,8 @@ #define MCP795_REG_MONTH 0x06 #define MCP795_REG_CONTROL 0x08 -#define MCP795_ST_BIT 0x80 -#define MCP795_24_BIT 0x40 +#define MCP795_ST_BIT BIT(7) +#define MCP795_24_BIT BIT(6) #define MCP795_LP_BIT BIT(5) #define MCP795_EXTOSC_BIT BIT(3) #define MCP795_OSCON_BIT BIT(5) -- cgit v1.2.3 From d3e5925902dc0f639efc3641e07fca2bd7af5441 Mon Sep 17 00:00:00 2001 From: Emil Bartczak Date: Thu, 8 Dec 2016 00:27:42 +0100 Subject: rtc: mcp795: Fix whitespace and indentation. Fix whitespace and indentation errors and the following checkpatch warnings: - line 15: Block comments use a trailing */ on a separate line - line 256: Line over 80 characters No code change. Signed-off-by: Emil Bartczak Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mcp795.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c index 8ed55f6ff8ba..ce75e421ba00 100644 --- a/drivers/rtc/rtc-mcp795.c +++ b/drivers/rtc/rtc-mcp795.c @@ -12,7 +12,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * */ + */ #include #include @@ -31,7 +31,7 @@ #define MCP795_EEWREN 0x06 #define MCP795_SRREAD 0x05 #define MCP795_SRWRITE 0x01 -#define MCP795_READ 0x13 +#define MCP795_READ 0x13 #define MCP795_WRITE 0x12 #define MCP795_UNLOCK 0x14 #define MCP795_IDWRITE 0x32 @@ -45,9 +45,9 @@ #define MCP795_REG_MONTH 0x06 #define MCP795_REG_CONTROL 0x08 -#define MCP795_ST_BIT BIT(7) -#define MCP795_24_BIT BIT(6) -#define MCP795_LP_BIT BIT(5) +#define MCP795_ST_BIT BIT(7) +#define MCP795_24_BIT BIT(6) +#define MCP795_LP_BIT BIT(5) #define MCP795_EXTOSC_BIT BIT(3) #define MCP795_OSCON_BIT BIT(5) @@ -253,7 +253,7 @@ static int mcp795_probe(struct spi_device *spi) mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0); rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795", - &mcp795_rtc_ops, THIS_MODULE); + &mcp795_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) return PTR_ERR(rtc); -- cgit v1.2.3 From d4af49f810db8b855b043615c3b4312e5ba8aedb Mon Sep 17 00:00:00 2001 From: Kefeng Wang Date: Mon, 19 Dec 2016 10:01:47 +0100 Subject: firmware: dmi_scan: Always show system identification string Let's keep consistent when print dmi_ids_string between SMBIOS 2.x and SMBIOS 3.x, and always show the system identification string, like Vendor, Product/Board name and BIOS infos. Signed-off-by: Kefeng Wang Signed-off-by: Jean Delvare --- drivers/firmware/dmi_scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c index 88bebe1968b7..54be60ead08f 100644 --- a/drivers/firmware/dmi_scan.c +++ b/drivers/firmware/dmi_scan.c @@ -560,7 +560,7 @@ static int __init dmi_present(const u8 *buf) dmi_ver >> 16, (dmi_ver >> 8) & 0xFF); } dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string)); - printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string); + pr_info("DMI: %s\n", dmi_ids_string); return 0; } } @@ -588,7 +588,7 @@ static int __init dmi_smbios3_present(const u8 *buf) dmi_ver >> 16, (dmi_ver >> 8) & 0xFF, dmi_ver & 0xFF); dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string)); - pr_debug("DMI: %s\n", dmi_ids_string); + pr_info("DMI: %s\n", dmi_ids_string); return 0; } } -- cgit v1.2.3 From f357563f958df06cd9ea9e614cdba30578bb08b1 Mon Sep 17 00:00:00 2001 From: Jérémy Lefaure Date: Fri, 16 Dec 2016 19:29:27 -0500 Subject: irqchip/st: Mark st_irq_syscfg_resume() __maybe_unused MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When CONFIG_PM_SLEEP is disabled, the compiler raises a warning on st_irq_syscfg_resume: drivers/irqchip/irq-st.c:183:12: warning: 'st_irq_syscfg_resume' defined but not used [-Wunused-function] static int st_irq_syscfg_resume(struct device *dev) ^~~~~~~~~~~~~~~~~~~~ Annotate the function with __maybe_unused. Signed-off-by: Jérémy Lefaure Cc: Marc Zyngier Cc: Jason Cooper Link: http://lkml.kernel.org/r/20161217002927.31947-1-jeremy.lefaure@lse.epita.fr Signed-off-by: Thomas Gleixner --- drivers/irqchip/irq-st.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/irqchip/irq-st.c b/drivers/irqchip/irq-st.c index 9af48a85c16f..5e0e250db0be 100644 --- a/drivers/irqchip/irq-st.c +++ b/drivers/irqchip/irq-st.c @@ -180,7 +180,7 @@ static int st_irq_syscfg_probe(struct platform_device *pdev) return st_irq_syscfg_enable(pdev); } -static int st_irq_syscfg_resume(struct device *dev) +static int __maybe_unused st_irq_syscfg_resume(struct device *dev) { struct st_irq_syscfg *ddata = dev_get_drvdata(dev); -- cgit v1.2.3 From 938d0071573c5f83da87cc607bebea1e5b4e52b6 Mon Sep 17 00:00:00 2001 From: Corentin Labbe Date: Thu, 15 Dec 2016 16:27:11 +0100 Subject: HID: intel-ish-hid: Remove unneeded linux/miscdevice.h include hid/intel-ish-hid does not use any miscdevice so this patch remove this unnecessary inclusion. Signed-off-by: Corentin Labbe Acked-by: Srinivas Pandruvada Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ipc/pci-ish.c | 1 - drivers/hid/intel-ish-hid/ishtp/hbm.c | 1 - drivers/hid/intel-ish-hid/ishtp/init.c | 1 - 3 files changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c index 20d647d2dd2c..d20da39c696c 100644 --- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c +++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c @@ -24,7 +24,6 @@ #include #include #include -#include #define CREATE_TRACE_POINTS #include #include "ishtp-dev.h" diff --git a/drivers/hid/intel-ish-hid/ishtp/hbm.c b/drivers/hid/intel-ish-hid/ishtp/hbm.c index 59460b66e689..b7213608ce43 100644 --- a/drivers/hid/intel-ish-hid/ishtp/hbm.c +++ b/drivers/hid/intel-ish-hid/ishtp/hbm.c @@ -19,7 +19,6 @@ #include #include #include -#include #include "ishtp-dev.h" #include "hbm.h" #include "client.h" diff --git a/drivers/hid/intel-ish-hid/ishtp/init.c b/drivers/hid/intel-ish-hid/ishtp/init.c index ac364418e17c..d27e03526acd 100644 --- a/drivers/hid/intel-ish-hid/ishtp/init.c +++ b/drivers/hid/intel-ish-hid/ishtp/init.c @@ -16,7 +16,6 @@ #include #include #include -#include #include "ishtp-dev.h" #include "hbm.h" #include "client.h" -- cgit v1.2.3 From c9435f35ae64ee162555a82b6a3586b160093957 Mon Sep 17 00:00:00 2001 From: Sudip Mukherjee Date: Sun, 18 Dec 2016 22:26:36 +0000 Subject: clocksource/drivers/moxart: Plug memory and mapping leaks If of_iomap() or any other subsequent function fails moxart_timer_init() exits without freeing memory and unmapping the timer base. Add proper cleanup points. Signed-off-by: Sudip Mukherjee Cc: Daniel Lezcano Cc: Sudip Mukherjee Link: http://lkml.kernel.org/r/1482099996-1524-1-git-send-email-sudipm.mukherjee@gmail.com Signed-off-by: Thomas Gleixner --- drivers/clocksource/moxart_timer.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/clocksource/moxart_timer.c b/drivers/clocksource/moxart_timer.c index 2a8f4705c734..7f3430654fbd 100644 --- a/drivers/clocksource/moxart_timer.c +++ b/drivers/clocksource/moxart_timer.c @@ -161,19 +161,22 @@ static int __init moxart_timer_init(struct device_node *node) timer->base = of_iomap(node, 0); if (!timer->base) { pr_err("%s: of_iomap failed\n", node->full_name); - return -ENXIO; + ret = -ENXIO; + goto out_free; } irq = irq_of_parse_and_map(node, 0); if (irq <= 0) { pr_err("%s: irq_of_parse_and_map failed\n", node->full_name); - return -EINVAL; + ret = -EINVAL; + goto out_unmap; } clk = of_clk_get(node, 0); if (IS_ERR(clk)) { pr_err("%s: of_clk_get failed\n", node->full_name); - return PTR_ERR(clk); + ret = PTR_ERR(clk); + goto out_unmap; } pclk = clk_get_rate(clk); @@ -186,7 +189,8 @@ static int __init moxart_timer_init(struct device_node *node) timer->t1_disable_val = ASPEED_TIMER1_DISABLE; } else { pr_err("%s: unknown platform\n", node->full_name); - return -EINVAL; + ret = -EINVAL; + goto out_unmap; } timer->count_per_tick = DIV_ROUND_CLOSEST(pclk, HZ); @@ -208,14 +212,14 @@ static int __init moxart_timer_init(struct device_node *node) clocksource_mmio_readl_down); if (ret) { pr_err("%s: clocksource_mmio_init failed\n", node->full_name); - return ret; + goto out_unmap; } ret = request_irq(irq, moxart_timer_interrupt, IRQF_TIMER, node->name, &timer->clkevt); if (ret) { pr_err("%s: setup_irq failed\n", node->full_name); - return ret; + goto out_unmap; } /* Clear match registers */ @@ -241,6 +245,12 @@ static int __init moxart_timer_init(struct device_node *node) clockevents_config_and_register(&timer->clkevt, pclk, 0x4, 0xfffffffe); return 0; + +out_unmap: + iounmap(timer->base); +out_free: + kfree(timer); + return ret; } CLOCKSOURCE_OF_DECLARE(moxart, "moxa,moxart-timer", moxart_timer_init); CLOCKSOURCE_OF_DECLARE(aspeed, "aspeed,ast2400-timer", moxart_timer_init); -- cgit v1.2.3 From 4fed0231994b27b3896bc63885ac66d02fff625b Mon Sep 17 00:00:00 2001 From: Yuta Kobayashi Date: Mon, 19 Dec 2016 02:36:45 +0000 Subject: HID: multitouch: enable the Surface 4 Type Cover Pro (JP) to report multitouch data Since commit 8fe89ef076fa1 ("HID: multitouch: enable the Surface 3 Type Cover to report multitouch data"), the TypeCover can be properly handled by hid-multitouch and don't require any special quirk in the kernel. Remove the support of the Surface 4 Type Cover Pro (JP) from hid-microsoft so it can properly report multitouch from the touchpad. Signed-off-by: Yuta Kobayashi Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 -- drivers/hid/hid-ids.h | 1 - drivers/hid/hid-microsoft.c | 2 -- drivers/hid/usbhid/hid-quirks.c | 1 - 4 files changed, 6 deletions(-) (limited to 'drivers') diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index cff060b56da9..db87d918efca 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -729,7 +729,6 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 || hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP || hid->product == USB_DEVICE_ID_MS_POWER_COVER) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; @@ -1990,7 +1989,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ec277b96eaa1..55758f7f88fb 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -723,7 +723,6 @@ #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4 0x07e4 #define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2 0x07e8 -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9 #define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_VENDOR_ID_MOJO 0x8282 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index 74b7b84a0420..2b706b51bec3 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -284,8 +284,6 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2), .driver_data = MS_HIDINPUT }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP), - .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD), diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index b3e01c82af05..ebb8e95c46ab 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -105,7 +105,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_2, HID_QUIRK_NO_INIT_REPORTS }, - { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v1.2.3 From d79e141c1c6ea7cb70c169971d522b88c8d5b419 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Fri, 9 Dec 2016 12:57:39 -0800 Subject: Input: i8042 - Trust firmware a bit more when probing on X86 The error message "Can't read CTR while initializing i8042" appears on Cherry Trail-based devices at each boot time: i8042: PNP: No PS/2 controller found. Probing ports directly. i8042: Can't read CTR while initializing i8042 i8042: probe of i8042 failed with error -5 This happens because we historically do not trust firmware on X86 and, while noting that PNP does not show keyboard or mouse devices, we still charge ahead and try to probe the controller. Let's relax this a bit and if results of PNP probe agree with the results of platform initialization/quirks conclude that there is, in fact, no i8042. While at it, let's avoid using x86_platform.i8042_detect() and instead abort execution early if platform indicates that it can not possibly have i8042 (x86_platform.legacy.i8042 equals X86_LEGACY_I8042_PLATFORM_ABSENT). Reported-and-tested-by: Takashi Iwai Signed-off-by: Dmitry Torokhov Acked-by: Marcos Paulo de Souza Cc: linux-input@vger.kernel.org Link: http://lkml.kernel.org/r/1481317061-31486-3-git-send-email-dmitry.torokhov@gmail.com Signed-off-by: Thomas Gleixner --- drivers/input/serio/i8042-x86ia64io.h | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h index 73a4e68448fc..77551f522202 100644 --- a/drivers/input/serio/i8042-x86ia64io.h +++ b/drivers/input/serio/i8042-x86ia64io.h @@ -983,7 +983,11 @@ static int __init i8042_pnp_init(void) #if defined(__ia64__) return -ENODEV; #else - pr_info("PNP: No PS/2 controller found. Probing ports directly.\n"); + pr_info("PNP: No PS/2 controller found.\n"); + if (x86_platform.legacy.i8042 != + X86_LEGACY_I8042_EXPECTED_PRESENT) + return -ENODEV; + pr_info("Probing ports directly.\n"); return 0; #endif } @@ -1070,8 +1074,8 @@ static int __init i8042_platform_init(void) #ifdef CONFIG_X86 u8 a20_on = 0xdf; - /* Just return if pre-detection shows no i8042 controller exist */ - if (!x86_platform.i8042_detect()) + /* Just return if platform does not have i8042 controller */ + if (x86_platform.legacy.i8042 == X86_LEGACY_I8042_PLATFORM_ABSENT) return -ENODEV; #endif -- cgit v1.2.3 From ae7871be189cb41184f1e05742b4a99e2c59774d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 16 Dec 2016 14:28:41 +0100 Subject: swiotlb: Convert swiotlb_force from int to enum Convert the flag swiotlb_force from an int to an enum, to prepare for the advent of more possible values. Suggested-by: Konrad Rzeszutek Wilk Signed-off-by: Geert Uytterhoeven Signed-off-by: Konrad Rzeszutek Wilk --- arch/arm64/mm/dma-mapping.c | 3 ++- arch/arm64/mm/init.c | 3 ++- arch/x86/kernel/pci-swiotlb.c | 2 +- arch/x86/xen/pci-swiotlb-xen.c | 2 +- drivers/xen/swiotlb-xen.c | 4 ++-- include/linux/swiotlb.h | 7 ++++++- include/trace/events/swiotlb.h | 16 +++++++++------- lib/swiotlb.c | 8 ++++---- 8 files changed, 27 insertions(+), 18 deletions(-) (limited to 'drivers') diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c index 3f74d0d98de6..02265a589ef5 100644 --- a/arch/arm64/mm/dma-mapping.c +++ b/arch/arm64/mm/dma-mapping.c @@ -524,7 +524,8 @@ EXPORT_SYMBOL(dummy_dma_ops); static int __init arm64_dma_init(void) { - if (swiotlb_force || max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) + if (swiotlb_force == SWIOTLB_FORCE || + max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) swiotlb = 1; return atomic_pool_init(); diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c index 212c4d1e2f26..716d1226ba69 100644 --- a/arch/arm64/mm/init.c +++ b/arch/arm64/mm/init.c @@ -401,7 +401,8 @@ static void __init free_unused_memmap(void) */ void __init mem_init(void) { - if (swiotlb_force || max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) + if (swiotlb_force == SWIOTLB_FORCE || + max_pfn > (arm64_dma_phys_limit >> PAGE_SHIFT)) swiotlb_init(1); set_max_mapnr(pfn_to_page(max_pfn) - mem_map); diff --git a/arch/x86/kernel/pci-swiotlb.c b/arch/x86/kernel/pci-swiotlb.c index 36049af2715e..410efb2c7b80 100644 --- a/arch/x86/kernel/pci-swiotlb.c +++ b/arch/x86/kernel/pci-swiotlb.c @@ -68,7 +68,7 @@ static struct dma_map_ops swiotlb_dma_ops = { */ int __init pci_swiotlb_detect_override(void) { - if (swiotlb_force) + if (swiotlb_force == SWIOTLB_FORCE) swiotlb = 1; return swiotlb; diff --git a/arch/x86/xen/pci-swiotlb-xen.c b/arch/x86/xen/pci-swiotlb-xen.c index a9fafb5c8738..a0b36a9d5df1 100644 --- a/arch/x86/xen/pci-swiotlb-xen.c +++ b/arch/x86/xen/pci-swiotlb-xen.c @@ -48,7 +48,7 @@ int __init pci_xen_swiotlb_detect(void) * activate this IOMMU. If running as PV privileged, activate it * irregardless. */ - if ((xen_initial_domain() || swiotlb || swiotlb_force)) + if (xen_initial_domain() || swiotlb || swiotlb_force == SWIOTLB_FORCE) xen_swiotlb = 1; /* If we are running under Xen, we MUST disable the native SWIOTLB. diff --git a/drivers/xen/swiotlb-xen.c b/drivers/xen/swiotlb-xen.c index 478fb91e3df2..aba12009422e 100644 --- a/drivers/xen/swiotlb-xen.c +++ b/drivers/xen/swiotlb-xen.c @@ -392,7 +392,7 @@ dma_addr_t xen_swiotlb_map_page(struct device *dev, struct page *page, if (dma_capable(dev, dev_addr, size) && !range_straddles_page_boundary(phys, size) && !xen_arch_need_swiotlb(dev, phys, dev_addr) && - !swiotlb_force) { + (swiotlb_force != SWIOTLB_FORCE)) { /* we are not interested in the dma_addr returned by * xen_dma_map_page, only in the potential cache flushes executed * by the function. */ @@ -552,7 +552,7 @@ xen_swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, phys_addr_t paddr = sg_phys(sg); dma_addr_t dev_addr = xen_phys_to_bus(paddr); - if (swiotlb_force || + if (swiotlb_force == SWIOTLB_FORCE || xen_arch_need_swiotlb(hwdev, paddr, dev_addr) || !dma_capable(hwdev, dev_addr, sg->length) || range_straddles_page_boundary(paddr, sg->length)) { diff --git a/include/linux/swiotlb.h b/include/linux/swiotlb.h index 183f37c8a5e1..71d104e4c849 100644 --- a/include/linux/swiotlb.h +++ b/include/linux/swiotlb.h @@ -9,7 +9,12 @@ struct device; struct page; struct scatterlist; -extern int swiotlb_force; +enum swiotlb_force { + SWIOTLB_NORMAL, /* Default - depending on HW DMA mask etc. */ + SWIOTLB_FORCE, /* swiotlb=force */ +}; + +extern enum swiotlb_force swiotlb_force; /* * Maximum allowable number of contiguous slabs to map, diff --git a/include/trace/events/swiotlb.h b/include/trace/events/swiotlb.h index 7ea4c5e7c448..5e2e30a7efce 100644 --- a/include/trace/events/swiotlb.h +++ b/include/trace/events/swiotlb.h @@ -11,16 +11,16 @@ TRACE_EVENT(swiotlb_bounced, TP_PROTO(struct device *dev, dma_addr_t dev_addr, size_t size, - int swiotlb_force), + enum swiotlb_force swiotlb_force), TP_ARGS(dev, dev_addr, size, swiotlb_force), TP_STRUCT__entry( - __string( dev_name, dev_name(dev) ) - __field( u64, dma_mask ) - __field( dma_addr_t, dev_addr ) - __field( size_t, size ) - __field( int, swiotlb_force ) + __string( dev_name, dev_name(dev) ) + __field( u64, dma_mask ) + __field( dma_addr_t, dev_addr ) + __field( size_t, size ) + __field( enum swiotlb_force, swiotlb_force ) ), TP_fast_assign( @@ -37,7 +37,9 @@ TRACE_EVENT(swiotlb_bounced, __entry->dma_mask, (unsigned long long)__entry->dev_addr, __entry->size, - __entry->swiotlb_force ? "swiotlb_force" : "" ) + __print_symbolic(__entry->swiotlb_force, + { SWIOTLB_NORMAL, "NORMAL" }, + { SWIOTLB_FORCE, "FORCE" })) ); #endif /* _TRACE_SWIOTLB_H */ diff --git a/lib/swiotlb.c b/lib/swiotlb.c index cb1b54ee8527..a32dce6d5101 100644 --- a/lib/swiotlb.c +++ b/lib/swiotlb.c @@ -53,7 +53,7 @@ */ #define IO_TLB_MIN_SLABS ((1<<20) >> IO_TLB_SHIFT) -int swiotlb_force; +enum swiotlb_force swiotlb_force; /* * Used to do a quick range check in swiotlb_tbl_unmap_single and @@ -107,7 +107,7 @@ setup_io_tlb_npages(char *str) if (*str == ',') ++str; if (!strcmp(str, "force")) - swiotlb_force = 1; + swiotlb_force = SWIOTLB_FORCE; return 0; } @@ -763,7 +763,7 @@ dma_addr_t swiotlb_map_page(struct device *dev, struct page *page, * we can safely return the device addr and not worry about bounce * buffering it. */ - if (dma_capable(dev, dev_addr, size) && !swiotlb_force) + if (dma_capable(dev, dev_addr, size) && swiotlb_force != SWIOTLB_FORCE) return dev_addr; trace_swiotlb_bounced(dev, dev_addr, size, swiotlb_force); @@ -904,7 +904,7 @@ swiotlb_map_sg_attrs(struct device *hwdev, struct scatterlist *sgl, int nelems, phys_addr_t paddr = sg_phys(sg); dma_addr_t dev_addr = phys_to_dma(hwdev, paddr); - if (swiotlb_force || + if (swiotlb_force == SWIOTLB_FORCE || !dma_capable(hwdev, dev_addr, sg->length)) { phys_addr_t map = map_single(hwdev, sg_phys(sg), sg->length, dir, attrs); -- cgit v1.2.3 From f42cce3c2409960adebe8e970574b23cbbf34e7d Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 20 Oct 2016 00:34:04 -0300 Subject: mailbox: mailbox-test: Fix module autoload If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/mailbox/mailbox-test.ko | grep alias $ After this patch: $ modinfo drivers/mailbox/mailbox-test.ko | grep alias alias: of:N*T*Cmailbox-testC* alias: of:N*T*Cmailbox-test Signed-off-by: Javier Martinez Canillas Acked-by: Lee Jones Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-test.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 9ca96e9db6bf..deb9c61aebb4 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -357,6 +357,7 @@ static const struct of_device_id mbox_test_match[] = { { .compatible = "mailbox-test" }, {}, }; +MODULE_DEVICE_TABLE(of, mbox_test_match); static struct platform_driver mbox_test_driver = { .driver = { -- cgit v1.2.3 From 2f50497d71e2982584d1a11d636d43eea0f992e6 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 20 Oct 2016 00:34:05 -0300 Subject: mailbox: sti: Fix module autoload for OF registration If the driver is built as a module, autoload won't work because the module alias information is not filled. So user-space can't match the registered device with the corresponding module. Export the module alias information using the MODULE_DEVICE_TABLE() macro. Before this patch: $ modinfo drivers/mailbox/mailbox-sti.ko | grep alias alias: platform:mailbox-sti After this patch: $ modinfo drivers/mailbox/mailbox-sti.ko | grep alias alias: platform:mailbox-sti alias: of:N*T*Cst,stih407-mailboxC* alias: of:N*T*Cst,stih407-mailbox Signed-off-by: Javier Martinez Canillas Acked-by: Lee Jones Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-sti.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mailbox/mailbox-sti.c b/drivers/mailbox/mailbox-sti.c index a334db5c9f1c..41bcd339b68a 100644 --- a/drivers/mailbox/mailbox-sti.c +++ b/drivers/mailbox/mailbox-sti.c @@ -403,6 +403,7 @@ static const struct of_device_id sti_mailbox_match[] = { }, { } }; +MODULE_DEVICE_TABLE(of, sti_mailbox_match); static int sti_mbox_probe(struct platform_device *pdev) { -- cgit v1.2.3 From 9b1b2b3adb310560a31ea248fa0defc8f09129ff Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:25:55 -0500 Subject: mailbox: bcm-pdc: Use octal permissions rather than symbolic When creating the debugfs files for the PDC driver, use octal file permissions rather than symbolic file permissions. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index c19dd820ea9b..a9c804fa3fbe 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -480,7 +480,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs) if (!debugfs_dir) debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, NULL); - pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, S_IRUSR, + /* S_IRUSR == 0400 */ + pdcs->debugfs_stats = debugfs_create_file(spu_stats_name, 0400, debugfs_dir, pdcs, &pdc_debugfs_stats); } -- cgit v1.2.3 From 9fb0f9ac54b393ddfe49be7da7751f02bb133db6 Mon Sep 17 00:00:00 2001 From: Steve Lin Date: Mon, 14 Nov 2016 13:25:56 -0500 Subject: mailbox: bcm-pdc: Changes so mbox client can be removed / re-inserted Ensure that DMA is disabled, and pointers reset, when changing DMA base addresses in pdc_ring_init(). This allows a mailbox client to be re-inserted after being removed. Otherwise, the DMA doesn't restart so the client hangs while being reinserted. Signed-off-by: Steve Lin Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 54 +++++++++++++++++++++++++++++++++------ 1 file changed, 46 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index a9c804fa3fbe..3b4ebbe81964 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -117,15 +117,16 @@ /* * Sets the following bits for write to transmit control reg: - * 0 - XmtEn - enable activity on the tx channel * 11 - PtyChkDisable - parity check is disabled * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory */ -#define PDC_TX_CTL 0x000C0801 +#define PDC_TX_CTL 0x000C0800 + +/* Bit in tx control reg to enable tx channel */ +#define PDC_TX_ENABLE 0x1 /* * Sets the following bits for write to receive control reg: - * 0 - RcvEn - enable activity on the rx channel * 7:1 - RcvOffset - size in bytes of status region at start of rx frame buf * 9 - SepRxHdrDescEn - place start of new frames only in descriptors * that have StartOfFrame set @@ -135,7 +136,10 @@ * 11 - PtyChkDisable - parity check is disabled * 20:18 - BurstLen = 3 -> 2^7 = 128 byte data reads from memory */ -#define PDC_RX_CTL 0x000C0E01 +#define PDC_RX_CTL 0x000C0E00 + +/* Bit in rx control reg to enable rx channel */ +#define PDC_RX_ENABLE 0x1 #define CRYPTO_D64_RS0_CD_MASK ((PDC_RING_ENTRIES * RING_ENTRY_SIZE) - 1) @@ -1054,6 +1058,15 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) /* Tell device the base DMA address of each ring */ dma_reg = &pdcs->regs->dmaregs[ringset]; + + /* But first disable DMA and set curptr to 0 for both TX & RX */ + iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); + iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)), + (void *)&dma_reg->dmarcv.control); + iowrite32(0, (void *)&dma_reg->dmaxmt.ptr); + iowrite32(0, (void *)&dma_reg->dmarcv.ptr); + + /* Set base DMA addresses */ iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase), (void *)&dma_reg->dmaxmt.addrlow); iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase), @@ -1064,6 +1077,11 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase), (void *)&dma_reg->dmarcv.addrhigh); + /* Re-enable DMA */ + iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control); + iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)), + (void *)&dma_reg->dmarcv.control); + /* Initialize descriptors */ for (i = 0; i < PDC_RING_ENTRIES; i++) { /* Every tx descriptor can be used for start of frame. */ @@ -1235,22 +1253,40 @@ void pdc_hw_init(struct pdc_state *pdcs) pdcs->nrxd = PDC_RING_ENTRIES; pdcs->ntxpost = PDC_RING_ENTRIES - 1; pdcs->nrxpost = PDC_RING_ENTRIES - 1; - pdcs->regs->intmask = 0; + iowrite32(0, &pdcs->regs->intmask); dma_reg = &pdcs->regs->dmaregs[ringset]; - iowrite32(0, (void *)&dma_reg->dmaxmt.ptr); - iowrite32(0, (void *)&dma_reg->dmarcv.ptr); - iowrite32(PDC_TX_CTL, (void *)&dma_reg->dmaxmt.control); + /* Configure DMA but will enable later in pdc_ring_init() */ + iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1), (void *)&dma_reg->dmarcv.control); + /* Reset current index pointers after making sure DMA is disabled */ + iowrite32(0, &dma_reg->dmaxmt.ptr); + iowrite32(0, &dma_reg->dmarcv.ptr); + if (pdcs->pdc_resp_hdr_len == PDC_SPU2_RESP_HDR_LEN) iowrite32(PDC_CKSUM_CTRL, pdcs->pdc_reg_vbase + PDC_CKSUM_CTRL_OFFSET); } +/** + * pdc_hw_disable() - Disable the tx and rx control in the hw. + * @pdcs: PDC state structure + * + */ +static void pdc_hw_disable(struct pdc_state *pdcs) +{ + struct dma64 *dma_reg; + + dma_reg = &pdcs->regs->dmaregs[PDC_RINGSET]; + iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); + iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1), + &dma_reg->dmarcv.control); +} + /** * pdc_rx_buf_pool_create() - Pool of receive buffers used to catch the metadata * header returned with each response message. @@ -1505,6 +1541,8 @@ static int pdc_remove(struct platform_device *pdev) pdc_free_debugfs(); + pdc_hw_disable(pdcs); + mbox_controller_unregister(&pdcs->mbc); dma_pool_destroy(pdcs->rx_buf_pool); -- cgit v1.2.3 From 9310f1ded44067b2da61fa0471ca5b7768dd28ae Mon Sep 17 00:00:00 2001 From: Steve Lin Date: Mon, 14 Nov 2016 13:25:57 -0500 Subject: mailbox: bcm-pdc: PDC driver leaves debugfs files after removal Minor fix to ensure that debugfs stats pseudo-files are removed when driver module is unloaded. Previously, the call to debugfs_remove_recursive() was never being called since the directory was not empty, and a seg fault would occur if another process tried to access these leftover files. Signed-off-by: Steve Lin Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 3b4ebbe81964..c9434a756bf3 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -492,10 +492,8 @@ static void pdc_setup_debugfs(struct pdc_state *pdcs) static void pdc_free_debugfs(void) { - if (debugfs_dir && simple_empty(debugfs_dir)) { - debugfs_remove_recursive(debugfs_dir); - debugfs_dir = NULL; - } + debugfs_remove_recursive(debugfs_dir); + debugfs_dir = NULL; } /** -- cgit v1.2.3 From ab8d1b2d564f6649547b97e65806556c42f93a26 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:25:58 -0500 Subject: mailbox: bcm-pdc: Convert from interrupts to poll for tx done The PDC driver is a mailbox controller. A mailbox controller can report that a mailbox message has been "transmitted" either when a tx interrupt fires or by having the mailbox framework poll. This commit converts the PDC driver to the poll method. We found that the tx interrupt happens when the descriptors are read by the SPU hw. Thus, the interrupt method does not allow more than one tx message in the PDC tx DMA ring at a time. To keep the SPU hw busy, we would like to keep the tx ring full under heavy load. With the poll method, the PDC driver responds that the previous message has been transmitted if the tx ring has space for another message. SPU request messages take a variable number of descriptors. If 15 descriptors are available, there is a good chance another message will fit. Also increased the ring size from 128 to 512 descriptors. With this change, I found the PDC driver hangs on its spinlock under heavy load. The PDC spinlock is not required; so I removed it. Calls to pdc_send_data() are already synchronized because of the channel spinlock in the mailbox framework. Other references to ring indexes should not require locking because they only written on either the tx or rx side. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 207 ++++++++++++++++++++++++++------------ 1 file changed, 145 insertions(+), 62 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index c9434a756bf3..fa3f484d3771 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -60,7 +60,13 @@ #define RING_ENTRY_SIZE sizeof(struct dma64dd) /* # entries in PDC dma ring */ -#define PDC_RING_ENTRIES 128 +#define PDC_RING_ENTRIES 512 +/* + * Minimum number of ring descriptor entries that must be free to tell mailbox + * framework that it can submit another request + */ +#define PDC_RING_SPACE_MIN 15 + #define PDC_RING_SIZE (PDC_RING_ENTRIES * RING_ENTRY_SIZE) /* Rings are 8k aligned */ #define RING_ALIGN_ORDER 13 @@ -93,11 +99,9 @@ * Interrupt mask and status definitions. Enable interrupts for tx and rx on * ring 0 */ -#define PDC_XMTINT_0 (24 + PDC_RINGSET) #define PDC_RCVINT_0 (16 + PDC_RINGSET) -#define PDC_XMTINTEN_0 BIT(PDC_XMTINT_0) #define PDC_RCVINTEN_0 BIT(PDC_RCVINT_0) -#define PDC_INTMASK (PDC_XMTINTEN_0 | PDC_RCVINTEN_0) +#define PDC_INTMASK (PDC_RCVINTEN_0) #define PDC_LAZY_FRAMECOUNT 1 #define PDC_LAZY_TIMEOUT 10000 #define PDC_LAZY_INT (PDC_LAZY_TIMEOUT | (PDC_LAZY_FRAMECOUNT << 24)) @@ -258,9 +262,6 @@ struct pdc_ring_alloc { /* PDC state structure */ struct pdc_state { - /* synchronize access to this PDC state structure */ - spinlock_t pdc_lock; - /* Index of the PDC whose state is in this structure instance */ u8 pdc_idx; @@ -401,11 +402,14 @@ struct pdc_state { struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ /* counters */ - u32 pdc_requests; /* number of request messages submitted */ - u32 pdc_replies; /* number of reply messages received */ - u32 txnobuf; /* count of tx ring full */ - u32 rxnobuf; /* count of rx ring full */ - u32 rx_oflow; /* count of rx overflows */ + u32 pdc_requests; /* number of request messages submitted */ + u32 pdc_replies; /* number of reply messages received */ + u32 last_tx_not_done; /* too few tx descriptors to indicate done */ + u32 tx_ring_full; /* unable to accept msg because tx ring full */ + u32 rx_ring_full; /* unable to accept msg because rx ring full */ + u32 txnobuf; /* unable to create tx descriptor */ + u32 rxnobuf; /* unable to create rx descriptor */ + u32 rx_oflow; /* count of rx overflows */ }; /* Global variables */ @@ -438,20 +442,33 @@ static ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf, out_offset += snprintf(buf + out_offset, out_count - out_offset, "SPU %u stats:\n", pdcs->pdc_idx); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "PDC requests............%u\n", + "PDC requests....................%u\n", pdcs->pdc_requests); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "PDC responses...........%u\n", + "PDC responses...................%u\n", pdcs->pdc_replies); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "Tx err ring full........%u\n", + "Tx not done.....................%u\n", + pdcs->last_tx_not_done); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Tx ring full....................%u\n", + pdcs->tx_ring_full); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Rx ring full....................%u\n", + pdcs->rx_ring_full); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Tx desc write fail. Ring full...%u\n", pdcs->txnobuf); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "Rx err ring full........%u\n", + "Rx desc write fail. Ring full...%u\n", pdcs->rxnobuf); out_offset += snprintf(buf + out_offset, out_count - out_offset, - "Receive overflow........%u\n", + "Receive overflow................%u\n", pdcs->rx_oflow); + out_offset += snprintf(buf + out_offset, out_count - out_offset, + "Num frags in rx ring............%u\n", + NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, + pdcs->nrxpost)); if (out_offset > out_count) out_offset = out_count; @@ -582,8 +599,6 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) u32 rx_idx; /* ring index of start of receive frame */ dma_addr_t resp_hdr_daddr; - spin_lock(&pdcs->pdc_lock); - /* * return if a complete response message is not yet ready. * rxin_numd[rxin] is the number of fragments in the next msg @@ -600,7 +615,6 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) { /* No response ready */ - spin_unlock(&pdcs->pdc_lock); return -EAGAIN; } /* can't read descriptors/data until write index is read */ @@ -630,8 +644,6 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) for (i = 0; i < num_frags; i++) pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost); - spin_unlock(&pdcs->pdc_lock); - dev_dbg(dev, "PDC %u reclaimed %d rx descriptors", pdcs->pdc_idx, num_frags); @@ -920,8 +932,6 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) struct pdc_state *pdcs = cookie; u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); - if (intstatus & PDC_XMTINTEN_0) - set_bit(PDC_XMTINT_0, &pdcs->intstatus); if (intstatus & PDC_RCVINTEN_0) set_bit(PDC_RCVINT_0, &pdcs->intstatus); @@ -953,45 +963,35 @@ static irqreturn_t pdc_irq_thread(int irq, void *cookie) struct pdc_state *pdcs = cookie; struct mbox_controller *mbc; struct mbox_chan *chan; - bool tx_int; bool rx_int; int rx_status; struct brcm_message mssg; - tx_int = test_and_clear_bit(PDC_XMTINT_0, &pdcs->intstatus); rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (pdcs && (tx_int || rx_int)) { + if (pdcs && rx_int) { dev_dbg(&pdcs->pdev->dev, - "%s() got irq %d with tx_int %s, rx_int %s", - __func__, irq, - tx_int ? "set" : "clear", rx_int ? "set" : "clear"); + "%s() got irq %d with rx_int %s", + __func__, irq, rx_int ? "set" : "clear"); mbc = &pdcs->mbc; chan = &mbc->chans[0]; - if (tx_int) { - dev_dbg(&pdcs->pdev->dev, "%s(): tx done", __func__); - /* only one frame in flight at a time */ - mbox_chan_txdone(chan, PDC_SUCCESS); - } - if (rx_int) { - while (1) { - /* Could be many frames ready */ - memset(&mssg, 0, sizeof(mssg)); - mssg.type = BRCM_MESSAGE_SPU; - rx_status = pdc_receive(pdcs, &mssg); - if (rx_status >= 0) { - dev_dbg(&pdcs->pdev->dev, - "%s(): invoking client rx cb", - __func__); - mbox_chan_received_data(chan, &mssg); - } else { - dev_dbg(&pdcs->pdev->dev, - "%s(): no SPU response available", - __func__); - break; - } + while (1) { + /* Could be many frames ready */ + memset(&mssg, 0, sizeof(mssg)); + mssg.type = BRCM_MESSAGE_SPU; + rx_status = pdc_receive(pdcs, &mssg); + if (rx_status >= 0) { + dev_dbg(&pdcs->pdev->dev, + "%s(): invoking client rx cb", + __func__); + mbox_chan_received_data(chan, &mssg); + } else { + dev_dbg(&pdcs->pdev->dev, + "%s(): no SPU response available", + __func__); + break; } } return IRQ_HANDLED; @@ -1036,9 +1036,6 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) dev_dbg(dev, " - base DMA addr of rx ring %pad", &rx.dmabase); dev_dbg(dev, " - base virtual addr of rx ring %p", rx.vbase); - /* lock after ring allocation to avoid scheduling while atomic */ - spin_lock(&pdcs->pdc_lock); - memcpy(&pdcs->tx_ring_alloc, &tx, sizeof(tx)); memcpy(&pdcs->rx_ring_alloc, &rx, sizeof(rx)); @@ -1103,7 +1100,6 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) (void *)&pdcs->rxd_64[i].ctrl1); } } - spin_unlock(&pdcs->pdc_lock); return PDC_SUCCESS; fail_dealloc: @@ -1127,6 +1123,80 @@ static void pdc_ring_free(struct pdc_state *pdcs) } } +/** + * pdc_desc_count() - Count the number of DMA descriptors that will be required + * for a given scatterlist. Account for the max length of a DMA buffer. + * @sg: Scatterlist to be DMA'd + * Return: Number of descriptors required + */ +static u32 pdc_desc_count(struct scatterlist *sg) +{ + u32 cnt = 0; + + while (sg) { + cnt += ((sg->length / PDC_DMA_BUF_MAX) + 1); + sg = sg_next(sg); + } + return cnt; +} + +/** + * pdc_rings_full() - Check whether the tx ring has room for tx_cnt descriptors + * and the rx ring has room for rx_cnt descriptors. + * @pdcs: PDC state + * @tx_cnt: The number of descriptors required in the tx ring + * @rx_cnt: The number of descriptors required i the rx ring + * + * Return: true if one of the rings does not have enough space + * false if sufficient space is available in both rings + */ +static bool pdc_rings_full(struct pdc_state *pdcs, int tx_cnt, int rx_cnt) +{ + u32 rx_avail; + u32 tx_avail; + bool full = false; + + /* Check if the tx and rx rings are likely to have enough space */ + rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout, + pdcs->nrxpost); + if (unlikely(rx_cnt > rx_avail)) { + pdcs->rx_ring_full++; + full = true; + } + + if (likely(!full)) { + tx_avail = pdcs->ntxpost - NTXDACTIVE(pdcs->txin, pdcs->txout, + pdcs->ntxpost); + if (unlikely(tx_cnt > tx_avail)) { + pdcs->tx_ring_full++; + full = true; + } + } + return full; +} + +/** + * pdc_last_tx_done() - If both the tx and rx rings have at least + * PDC_RING_SPACE_MIN descriptors available, then indicate that the mailbox + * framework can submit another message. + * @chan: mailbox channel to check + * Return: true if PDC can accept another message on this channel + */ +static bool pdc_last_tx_done(struct mbox_chan *chan) +{ + struct pdc_state *pdcs = chan->con_priv; + bool ret; + + if (unlikely(pdc_rings_full(pdcs, PDC_RING_SPACE_MIN, + PDC_RING_SPACE_MIN))) { + pdcs->last_tx_not_done++; + ret = false; + } else { + ret = true; + } + return ret; +} + /** * pdc_send_data() - mailbox send_data function * @chan: The mailbox channel on which the data is sent. The channel @@ -1158,6 +1228,8 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) int src_nent; int dst_nent; int nent; + u32 tx_desc_req; + u32 rx_desc_req; if (mssg->type != BRCM_MESSAGE_SPU) return -ENOTSUPP; @@ -1180,7 +1252,19 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) } } - spin_lock(&pdcs->pdc_lock); + /* + * Check if the tx and rx rings have enough space. Do this prior to + * writing any tx or rx descriptors. Need to ensure that we do not write + * a partial set of descriptors, or write just rx descriptors but + * corresponding tx descriptors don't fit. Note that we want this check + * and the entire sequence of descriptor to happen without another + * thread getting in. The channel spin lock in the mailbox framework + * ensures this. + */ + tx_desc_req = pdc_desc_count(mssg->spu.src); + rx_desc_req = pdc_desc_count(mssg->spu.dst); + if (pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)) + return -ENOSPC; /* Create rx descriptors to SPU catch response */ err = pdc_rx_list_init(pdcs, mssg->spu.dst, mssg->ctx); @@ -1190,8 +1274,6 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src); err |= pdc_tx_list_final(pdcs); /* initiate transfer */ - spin_unlock(&pdcs->pdc_lock); - if (err) dev_err(&pdcs->pdev->dev, "%s failed with error %d", __func__, err); @@ -1359,6 +1441,7 @@ static int pdc_interrupts_init(struct pdc_state *pdcs) static const struct mbox_chan_ops pdc_mbox_chan_ops = { .send_data = pdc_send_data, + .last_tx_done = pdc_last_tx_done, .startup = pdc_startup, .shutdown = pdc_shutdown }; @@ -1391,8 +1474,9 @@ static int pdc_mb_init(struct pdc_state *pdcs) if (!mbc->chans) return -ENOMEM; - mbc->txdone_irq = true; - mbc->txdone_poll = false; + mbc->txdone_irq = false; + mbc->txdone_poll = true; + mbc->txpoll_period = 1; for (chan_index = 0; chan_index < mbc->num_chans; chan_index++) mbc->chans[chan_index].con_priv = pdcs; @@ -1462,7 +1546,6 @@ static int pdc_probe(struct platform_device *pdev) goto cleanup; } - spin_lock_init(&pdcs->pdc_lock); pdcs->pdev = pdev; platform_set_drvdata(pdev, pdcs); pdcs->pdc_idx = pdcg.num_spu; -- cgit v1.2.3 From e004c7e7d3b873a671fecf04f197982806e380eb Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:25:59 -0500 Subject: mailbox: bcm-pdc: streamline rx code Remove the unnecessary rmb() from the receive path. If the rx ring has multiple messages ready, avoid reading last_rx_curr multiple times from the register. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 108 +++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index fa3f484d3771..21957609ea91 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -570,27 +570,23 @@ pdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len, } /** - * pdc_receive() - Receive a response message from a given SPU. + * pdc_receive_one() - Receive a response message from a given SPU. * @pdcs: PDC state for the SPU to receive from - * @mssg: mailbox message to be returned to client * * When the return code indicates success, the response message is available in * the receive buffers provided prior to submission of the request. * - * Input: - * pdcs - PDC state structure for the SPU to be polled - * mssg - mailbox message to be returned to client. This function sets the - * context pointer on the message to help the client associate the - * response with a request. - * * Return: PDC_SUCCESS if one or more receive descriptors was processed * -EAGAIN indicates that no response message is available * -EIO an error occurred */ static int -pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) +pdc_receive_one(struct pdc_state *pdcs) { struct device *dev = &pdcs->pdev->dev; + struct mbox_controller *mbc; + struct mbox_chan *chan; + struct brcm_message mssg; u32 len, rx_status; u32 num_frags; int i; @@ -599,29 +595,23 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) u32 rx_idx; /* ring index of start of receive frame */ dma_addr_t resp_hdr_daddr; + mbc = &pdcs->mbc; + chan = &mbc->chans[0]; + mssg.type = BRCM_MESSAGE_SPU; + /* * return if a complete response message is not yet ready. * rxin_numd[rxin] is the number of fragments in the next msg * to read. */ frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost); - if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) { - /* See if the hw has written more fragments than we know */ - pdcs->last_rx_curr = - (ioread32((void *)&pdcs->rxregs_64->status0) & - CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE; - frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, - pdcs->nrxpost); - if ((frags_rdy == 0) || - (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) { - /* No response ready */ - return -EAGAIN; - } - /* can't read descriptors/data until write index is read */ - rmb(); - } + if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) + /* No response ready */ + return -EAGAIN; num_frags = pdcs->txin_numd[pdcs->txin]; + WARN_ON(num_frags == 0); + dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin], sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE); @@ -634,7 +624,7 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) rx_idx = pdcs->rxin; num_frags = pdcs->rxin_numd[rx_idx]; /* Return opaque context with result */ - mssg->ctx = pdcs->rxp_ctx[rx_idx]; + mssg.ctx = pdcs->rxp_ctx[rx_idx]; pdcs->rxp_ctx[rx_idx] = NULL; resp_hdr = pdcs->resp_hdr[rx_idx]; resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx]; @@ -674,12 +664,35 @@ pdc_receive(struct pdc_state *pdcs, struct brcm_message *mssg) dma_pool_free(pdcs->rx_buf_pool, resp_hdr, resp_hdr_daddr); + mbox_chan_received_data(chan, &mssg); + pdcs->pdc_replies++; - /* if we read one or more rx descriptors, claim success */ - if (num_frags > 0) - return PDC_SUCCESS; - else - return -EIO; + return PDC_SUCCESS; +} + +/** + * pdc_receive() - Process as many responses as are available in the rx ring. + * @pdcs: PDC state + * + * Called within the hard IRQ. + * Return: + */ +static int +pdc_receive(struct pdc_state *pdcs) +{ + int rx_status; + + /* read last_rx_curr from register once */ + pdcs->last_rx_curr = + (ioread32((void *)&pdcs->rxregs_64->status0) & + CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE; + + do { + /* Could be many frames ready */ + rx_status = pdc_receive_one(pdcs); + } while (rx_status == PDC_SUCCESS); + + return 0; } /** @@ -946,14 +959,13 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) } /** - * pdc_irq_thread() - Function invoked on deferred thread when a DMA tx has - * completed or data is available to receive. + * pdc_irq_thread() - Function invoked on deferred thread when data is available + * to receive. * @irq: Interrupt number * @cookie: PDC state for PDC that generated the interrupt * - * On DMA tx complete, notify the mailbox client. On DMA rx complete, process - * as many SPU response messages as are available and send each to the mailbox - * client. + * On DMA rx complete, process as many SPU response messages as are available + * and send each to the mailbox client. * * Return: IRQ_HANDLED if we recognized and handled the interrupt * IRQ_NONE otherwise @@ -961,39 +973,15 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) static irqreturn_t pdc_irq_thread(int irq, void *cookie) { struct pdc_state *pdcs = cookie; - struct mbox_controller *mbc; - struct mbox_chan *chan; bool rx_int; - int rx_status; - struct brcm_message mssg; rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (pdcs && rx_int) { dev_dbg(&pdcs->pdev->dev, "%s() got irq %d with rx_int %s", __func__, irq, rx_int ? "set" : "clear"); - mbc = &pdcs->mbc; - chan = &mbc->chans[0]; - - while (1) { - /* Could be many frames ready */ - memset(&mssg, 0, sizeof(mssg)); - mssg.type = BRCM_MESSAGE_SPU; - rx_status = pdc_receive(pdcs, &mssg); - if (rx_status >= 0) { - dev_dbg(&pdcs->pdev->dev, - "%s(): invoking client rx cb", - __func__); - mbox_chan_received_data(chan, &mssg); - } else { - dev_dbg(&pdcs->pdev->dev, - "%s(): no SPU response available", - __func__); - break; - } - } + pdc_receive(pdcs); return IRQ_HANDLED; } return IRQ_NONE; -- cgit v1.2.3 From 7493cde34efc28641c295ee0d52ab9d790853c62 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:00 -0500 Subject: mailbox: bcm-pdc: Try to improve branch prediction Use likely/unlikely directives to improve branch prediction. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 21957609ea91..7ed3f0247cb8 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -834,7 +834,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, /* allocate a buffer for the dma rx status */ vaddr = dma_pool_zalloc(pdcs->rx_buf_pool, GFP_ATOMIC, &daddr); - if (!vaddr) + if (unlikely(!vaddr)) return -ENOMEM; /* @@ -945,14 +945,14 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) struct pdc_state *pdcs = cookie; u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); - if (intstatus & PDC_RCVINTEN_0) + if (likely(intstatus & PDC_RCVINTEN_0)) set_bit(PDC_RCVINT_0, &pdcs->intstatus); /* Clear interrupt flags in device */ iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); /* Wakeup IRQ thread */ - if (pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK)) + if (likely(pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))) return IRQ_WAKE_THREAD; return IRQ_NONE; @@ -976,7 +976,7 @@ static irqreturn_t pdc_irq_thread(int irq, void *cookie) bool rx_int; rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (pdcs && rx_int) { + if (likely(pdcs && rx_int)) { dev_dbg(&pdcs->pdev->dev, "%s() got irq %d with rx_int %s", __func__, irq, rx_int ? "set" : "clear"); @@ -1007,14 +1007,14 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) /* Allocate tx ring */ tx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &tx.dmabase); - if (!tx.vbase) { + if (unlikely(!tx.vbase)) { err = -ENOMEM; goto done; } /* Allocate rx ring */ rx.vbase = dma_pool_zalloc(pdcs->ring_pool, GFP_KERNEL, &rx.dmabase); - if (!rx.vbase) { + if (unlikely(!rx.vbase)) { err = -ENOMEM; goto fail_dealloc; } @@ -1219,21 +1219,21 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) u32 tx_desc_req; u32 rx_desc_req; - if (mssg->type != BRCM_MESSAGE_SPU) + if (unlikely(mssg->type != BRCM_MESSAGE_SPU)) return -ENOTSUPP; src_nent = sg_nents(mssg->spu.src); - if (src_nent) { + if (likely(src_nent)) { nent = dma_map_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE); - if (nent == 0) + if (unlikely(nent == 0)) return -EIO; } dst_nent = sg_nents(mssg->spu.dst); - if (dst_nent) { + if (likely(dst_nent)) { nent = dma_map_sg(dev, mssg->spu.dst, dst_nent, DMA_FROM_DEVICE); - if (nent == 0) { + if (unlikely(nent == 0)) { dma_unmap_sg(dev, mssg->spu.src, src_nent, DMA_TO_DEVICE); return -EIO; @@ -1251,7 +1251,7 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) */ tx_desc_req = pdc_desc_count(mssg->spu.src); rx_desc_req = pdc_desc_count(mssg->spu.dst); - if (pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1)) + if (unlikely(pdc_rings_full(pdcs, tx_desc_req, rx_desc_req + 1))) return -ENOSPC; /* Create rx descriptors to SPU catch response */ @@ -1262,7 +1262,7 @@ static int pdc_send_data(struct mbox_chan *chan, void *data) err |= pdc_tx_list_sg_add(pdcs, mssg->spu.src); err |= pdc_tx_list_final(pdcs); /* initiate transfer */ - if (err) + if (unlikely(err)) dev_err(&pdcs->pdev->dev, "%s failed with error %d", __func__, err); -- cgit v1.2.3 From 8aef00f090bcbe5237c5a6628e7c000890267efe Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:01 -0500 Subject: mailbox: bcm-pdc: Convert from threaded IRQ to tasklet Previously used threaded IRQs in the PDC driver to defer processing the rx DMA ring after getting an rx done interrupt. Instead, use a tasklet at normal priority for deferred processing. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 57 +++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 32 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 7ed3f0247cb8..16e544018a68 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -285,6 +285,9 @@ struct pdc_state { */ unsigned long intstatus; + /* tasklet for deferred processing after DMA rx interrupt */ + struct tasklet_struct rx_tasklet; + /* Number of bytes of receive status prior to each rx frame */ u32 rx_status_len; /* Whether a BCM header is prepended to each frame */ @@ -931,7 +934,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) /** * pdc_irq_handler() - Interrupt handler called in interrupt context. * @irq: Interrupt number that has fired - * @cookie: PDC state for DMA engine that generated the interrupt + * @data: device struct for DMA engine that generated the interrupt * * We have to clear the device interrupt status flags here. So cache the * status for later use in the thread function. Other than that, just return @@ -940,9 +943,10 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) * Return: IRQ_WAKE_THREAD if interrupt is ours * IRQ_NONE otherwise */ -static irqreturn_t pdc_irq_handler(int irq, void *cookie) +static irqreturn_t pdc_irq_handler(int irq, void *data) { - struct pdc_state *pdcs = cookie; + struct device *dev = (struct device *)data; + struct pdc_state *pdcs = dev_get_drvdata(dev); u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); if (likely(intstatus & PDC_RCVINTEN_0)) @@ -952,39 +956,22 @@ static irqreturn_t pdc_irq_handler(int irq, void *cookie) iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); /* Wakeup IRQ thread */ - if (likely(pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))) - return IRQ_WAKE_THREAD; - + if (likely(pdcs && (irq == pdcs->pdc_irq) && + (intstatus & PDC_INTMASK))) { + tasklet_schedule(&pdcs->rx_tasklet); + return IRQ_HANDLED; + } return IRQ_NONE; } -/** - * pdc_irq_thread() - Function invoked on deferred thread when data is available - * to receive. - * @irq: Interrupt number - * @cookie: PDC state for PDC that generated the interrupt - * - * On DMA rx complete, process as many SPU response messages as are available - * and send each to the mailbox client. - * - * Return: IRQ_HANDLED if we recognized and handled the interrupt - * IRQ_NONE otherwise - */ -static irqreturn_t pdc_irq_thread(int irq, void *cookie) +static void pdc_tasklet_cb(unsigned long data) { - struct pdc_state *pdcs = cookie; + struct pdc_state *pdcs = (struct pdc_state *)data; bool rx_int; rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (likely(pdcs && rx_int)) { - dev_dbg(&pdcs->pdev->dev, - "%s() got irq %d with rx_int %s", - __func__, irq, rx_int ? "set" : "clear"); - + if (likely(pdcs && rx_int)) pdc_receive(pdcs); - return IRQ_HANDLED; - } - return IRQ_NONE; } /** @@ -1416,11 +1403,11 @@ static int pdc_interrupts_init(struct pdc_state *pdcs) pdcs->pdc_irq = irq_of_parse_and_map(dn, 0); dev_dbg(dev, "pdc device %s irq %u for pdcs %p", dev_name(dev), pdcs->pdc_irq, pdcs); - err = devm_request_threaded_irq(dev, pdcs->pdc_irq, - pdc_irq_handler, - pdc_irq_thread, 0, dev_name(dev), pdcs); + + err = devm_request_irq(dev, pdcs->pdc_irq, pdc_irq_handler, 0, + dev_name(dev), dev); if (err) { - dev_err(dev, "threaded tx IRQ %u request failed with err %d\n", + dev_err(dev, "IRQ %u request failed with err %d\n", pdcs->pdc_irq, err); return err; } @@ -1579,6 +1566,9 @@ static int pdc_probe(struct platform_device *pdev) pdc_hw_init(pdcs); + /* Init tasklet for deferred DMA rx processing */ + tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long) pdcs); + err = pdc_interrupts_init(pdcs); if (err) goto cleanup_buf_pool; @@ -1595,6 +1585,7 @@ static int pdc_probe(struct platform_device *pdev) return PDC_SUCCESS; cleanup_buf_pool: + tasklet_kill(&pdcs->rx_tasklet); dma_pool_destroy(pdcs->rx_buf_pool); cleanup_ring_pool: @@ -1610,6 +1601,8 @@ static int pdc_remove(struct platform_device *pdev) pdc_free_debugfs(); + tasklet_kill(&pdcs->rx_tasklet); + pdc_hw_disable(pdcs); mbox_controller_unregister(&pdcs->mbc); -- cgit v1.2.3 From 38ed49ed4a99942f1a340f4a82a5a8b492e3463b Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:02 -0500 Subject: mailbox: bcm-pdc: Don't use iowrite32 to write DMA descriptors In PDC driver, it is not necessary to use iowrite32() when writing DMA descriptors to the transmit and receive rings. The ring memory is in host memory. So convert to normal assignment statements. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 16e544018a68..e7dc1a227713 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -528,17 +528,17 @@ pdc_build_rxd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len, u32 flags) { struct device *dev = &pdcs->pdev->dev; + struct dma64dd *rxd = &pdcs->rxd_64[pdcs->rxout]; dev_dbg(dev, "Writing rx descriptor for PDC %u at index %u with length %u. flags %#x\n", pdcs->pdc_idx, pdcs->rxout, buf_len, flags); - iowrite32(lower_32_bits(dma_addr), - (void *)&pdcs->rxd_64[pdcs->rxout].addrlow); - iowrite32(upper_32_bits(dma_addr), - (void *)&pdcs->rxd_64[pdcs->rxout].addrhigh); - iowrite32(flags, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl1); - iowrite32(buf_len, (void *)&pdcs->rxd_64[pdcs->rxout].ctrl2); + rxd->addrlow = cpu_to_le32(lower_32_bits(dma_addr)); + rxd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr)); + rxd->ctrl1 = cpu_to_le32(flags); + rxd->ctrl2 = cpu_to_le32(buf_len); + /* bump ring index and return */ pdcs->rxout = NEXTRXD(pdcs->rxout, pdcs->nrxpost); } @@ -556,17 +556,16 @@ pdc_build_txd(struct pdc_state *pdcs, dma_addr_t dma_addr, u32 buf_len, u32 flags) { struct device *dev = &pdcs->pdev->dev; + struct dma64dd *txd = &pdcs->txd_64[pdcs->txout]; dev_dbg(dev, "Writing tx descriptor for PDC %u at index %u with length %u, flags %#x\n", pdcs->pdc_idx, pdcs->txout, buf_len, flags); - iowrite32(lower_32_bits(dma_addr), - (void *)&pdcs->txd_64[pdcs->txout].addrlow); - iowrite32(upper_32_bits(dma_addr), - (void *)&pdcs->txd_64[pdcs->txout].addrhigh); - iowrite32(flags, (void *)&pdcs->txd_64[pdcs->txout].ctrl1); - iowrite32(buf_len, (void *)&pdcs->txd_64[pdcs->txout].ctrl2); + txd->addrlow = cpu_to_le32(lower_32_bits(dma_addr)); + txd->addrhigh = cpu_to_le32(upper_32_bits(dma_addr)); + txd->ctrl1 = cpu_to_le32(flags); + txd->ctrl2 = cpu_to_le32(buf_len); /* bump ring index and return */ pdcs->txout = NEXTTXD(pdcs->txout, pdcs->ntxpost); -- cgit v1.2.3 From 63bb50bdb997f4bede1b5f2d56645f393f7f39fb Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:03 -0500 Subject: mailbox: bcm-pdc: Performance improvements Three changes to improve performance in the PDC driver: - disable and reenable interrupts while the interrupt handler is running - update rxin and txin descriptor indexes more efficiently - group receive descriptor context into a structure and keep context in a single array rather than five to improve locality of reference Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 85 ++++++++++++++++++++++----------------- 1 file changed, 49 insertions(+), 36 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index e7dc1a227713..8c2aa7c9c27f 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -260,6 +260,27 @@ struct pdc_ring_alloc { u32 size; /* ring allocation size in bytes */ }; +/* + * context associated with a receive descriptor. + * @rxp_ctx: opaque context associated with frame that starts at each + * rx ring index. + * @dst_sg: Scatterlist used to form reply frames beginning at a given ring + * index. Retained in order to unmap each sg after reply is processed. + * @rxin_numd: Number of rx descriptors associated with the message that starts + * at a descriptor index. Not set for every index. For example, + * if descriptor index i points to a scatterlist with 4 entries, + * then the next three descriptor indexes don't have a value set. + * @resp_hdr: Virtual address of buffer used to catch DMA rx status + * @resp_hdr_daddr: physical address of DMA rx status buffer + */ +struct pdc_rx_ctx { + void *rxp_ctx; + struct scatterlist *dst_sg; + u32 rxin_numd; + void *resp_hdr; + dma_addr_t resp_hdr_daddr; +}; + /* PDC state structure */ struct pdc_state { /* Index of the PDC whose state is in this structure instance */ @@ -377,11 +398,7 @@ struct pdc_state { /* Index of next rx descriptor to post. */ u32 rxout; - /* - * opaque context associated with frame that starts at each - * rx ring index. - */ - void *rxp_ctx[PDC_RING_ENTRIES]; + struct pdc_rx_ctx rx_ctx[PDC_RING_ENTRIES]; /* * Scatterlists used to form request and reply frames beginning at a @@ -389,18 +406,6 @@ struct pdc_state { * is processed */ struct scatterlist *src_sg[PDC_RING_ENTRIES]; - struct scatterlist *dst_sg[PDC_RING_ENTRIES]; - - /* - * Number of rx descriptors associated with the message that starts - * at this descriptor index. Not set for every index. For example, - * if descriptor index i points to a scatterlist with 4 entries, then - * the next three descriptor indexes don't have a value set. - */ - u32 rxin_numd[PDC_RING_ENTRIES]; - - void *resp_hdr[PDC_RING_ENTRIES]; - dma_addr_t resp_hdr_daddr[PDC_RING_ENTRIES]; struct dentry *debugfs_stats; /* debug FS stats file for this PDC */ @@ -591,11 +596,11 @@ pdc_receive_one(struct pdc_state *pdcs) struct brcm_message mssg; u32 len, rx_status; u32 num_frags; - int i; u8 *resp_hdr; /* virtual addr of start of resp message DMA header */ u32 frags_rdy; /* number of fragments ready to read */ u32 rx_idx; /* ring index of start of receive frame */ dma_addr_t resp_hdr_daddr; + struct pdc_rx_ctx *rx_ctx; mbc = &pdcs->mbc; chan = &mbc->chans[0]; @@ -607,7 +612,8 @@ pdc_receive_one(struct pdc_state *pdcs) * to read. */ frags_rdy = NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, pdcs->nrxpost); - if ((frags_rdy == 0) || (frags_rdy < pdcs->rxin_numd[pdcs->rxin])) + if ((frags_rdy == 0) || + (frags_rdy < pdcs->rx_ctx[pdcs->rxin].rxin_numd)) /* No response ready */ return -EAGAIN; @@ -617,24 +623,23 @@ pdc_receive_one(struct pdc_state *pdcs) dma_unmap_sg(dev, pdcs->src_sg[pdcs->txin], sg_nents(pdcs->src_sg[pdcs->txin]), DMA_TO_DEVICE); - for (i = 0; i < num_frags; i++) - pdcs->txin = NEXTTXD(pdcs->txin, pdcs->ntxpost); + pdcs->txin = (pdcs->txin + num_frags) & pdcs->ntxpost; dev_dbg(dev, "PDC %u reclaimed %d tx descriptors", pdcs->pdc_idx, num_frags); rx_idx = pdcs->rxin; - num_frags = pdcs->rxin_numd[rx_idx]; + rx_ctx = &pdcs->rx_ctx[rx_idx]; + num_frags = rx_ctx->rxin_numd; /* Return opaque context with result */ - mssg.ctx = pdcs->rxp_ctx[rx_idx]; - pdcs->rxp_ctx[rx_idx] = NULL; - resp_hdr = pdcs->resp_hdr[rx_idx]; - resp_hdr_daddr = pdcs->resp_hdr_daddr[rx_idx]; - dma_unmap_sg(dev, pdcs->dst_sg[rx_idx], - sg_nents(pdcs->dst_sg[rx_idx]), DMA_FROM_DEVICE); + mssg.ctx = rx_ctx->rxp_ctx; + rx_ctx->rxp_ctx = NULL; + resp_hdr = rx_ctx->resp_hdr; + resp_hdr_daddr = rx_ctx->resp_hdr_daddr; + dma_unmap_sg(dev, rx_ctx->dst_sg, sg_nents(rx_ctx->dst_sg), + DMA_FROM_DEVICE); - for (i = 0; i < num_frags; i++) - pdcs->rxin = NEXTRXD(pdcs->rxin, pdcs->nrxpost); + pdcs->rxin = (pdcs->rxin + num_frags) & pdcs->nrxpost; dev_dbg(dev, "PDC %u reclaimed %d rx descriptors", pdcs->pdc_idx, num_frags); @@ -826,6 +831,7 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, u32 rx_pkt_cnt = 1; /* Adding a single rx buffer */ dma_addr_t daddr; void *vaddr; + struct pdc_rx_ctx *rx_ctx; rx_avail = pdcs->nrxpost - NRXDACTIVE(pdcs->rxin, pdcs->rxout, pdcs->nrxpost); @@ -849,15 +855,16 @@ static int pdc_rx_list_init(struct pdc_state *pdcs, struct scatterlist *dst_sg, /* This is always the first descriptor in the receive sequence */ flags = D64_CTRL1_SOF; - pdcs->rxin_numd[pdcs->rx_msg_start] = 1; + pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd = 1; if (unlikely(pdcs->rxout == (pdcs->nrxd - 1))) flags |= D64_CTRL1_EOT; - pdcs->rxp_ctx[pdcs->rxout] = ctx; - pdcs->dst_sg[pdcs->rxout] = dst_sg; - pdcs->resp_hdr[pdcs->rxout] = vaddr; - pdcs->resp_hdr_daddr[pdcs->rxout] = daddr; + rx_ctx = &pdcs->rx_ctx[pdcs->rxout]; + rx_ctx->rxp_ctx = ctx; + rx_ctx->dst_sg = dst_sg; + rx_ctx->resp_hdr = vaddr; + rx_ctx->resp_hdr_daddr = daddr; pdc_build_rxd(pdcs, daddr, pdcs->pdc_resp_hdr_len, flags); return PDC_SUCCESS; } @@ -925,7 +932,7 @@ static int pdc_rx_list_sg_add(struct pdc_state *pdcs, struct scatterlist *sg) desc_w++; sg = sg_next(sg); } - pdcs->rxin_numd[pdcs->rx_msg_start] += desc_w; + pdcs->rx_ctx[pdcs->rx_msg_start].rxin_numd += desc_w; return PDC_SUCCESS; } @@ -954,6 +961,9 @@ static irqreturn_t pdc_irq_handler(int irq, void *data) /* Clear interrupt flags in device */ iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); + /* Disable interrupts until soft handler runs */ + iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); + /* Wakeup IRQ thread */ if (likely(pdcs && (irq == pdcs->pdc_irq) && (intstatus & PDC_INTMASK))) { @@ -971,6 +981,9 @@ static void pdc_tasklet_cb(unsigned long data) rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); if (likely(pdcs && rx_int)) pdc_receive(pdcs); + + /* reenable interrupts */ + iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); } /** -- cgit v1.2.3 From 30d1ef623fd1e99bc1bab5211ba1da0d97d40e64 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:04 -0500 Subject: mailbox: bcm-pdc: Simplify interrupt handler logic Earlier versions of the PDC driver registered for both transmit and receive interrupts. The hard IRQ handler had to communicate to the soft handler which interrupt(s) had occurred. The PDC driver no longer registers for tx interrupts. So there is no reason to save the intstatus. So remove the intstatus member of the PDC state. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index 8c2aa7c9c27f..c1ec17cfa03a 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -298,14 +298,6 @@ struct pdc_state { unsigned int pdc_irq; - /* - * Last interrupt status read from PDC device. Saved in interrupt - * handler so the handler can clear the interrupt in the device, - * and the interrupt thread called later can know which interrupt - * bits are active. - */ - unsigned long intstatus; - /* tasklet for deferred processing after DMA rx interrupt */ struct tasklet_struct rx_tasklet; @@ -955,32 +947,30 @@ static irqreturn_t pdc_irq_handler(int irq, void *data) struct pdc_state *pdcs = dev_get_drvdata(dev); u32 intstatus = ioread32(pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); - if (likely(intstatus & PDC_RCVINTEN_0)) - set_bit(PDC_RCVINT_0, &pdcs->intstatus); - - /* Clear interrupt flags in device */ - iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); + if (unlikely(intstatus == 0)) + return IRQ_NONE; /* Disable interrupts until soft handler runs */ iowrite32(0, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); + /* Clear interrupt flags in device */ + iowrite32(intstatus, pdcs->pdc_reg_vbase + PDC_INTSTATUS_OFFSET); + /* Wakeup IRQ thread */ - if (likely(pdcs && (irq == pdcs->pdc_irq) && - (intstatus & PDC_INTMASK))) { - tasklet_schedule(&pdcs->rx_tasklet); - return IRQ_HANDLED; - } - return IRQ_NONE; + tasklet_schedule(&pdcs->rx_tasklet); + return IRQ_HANDLED; } +/** + * pdc_tasklet_cb() - Tasklet callback that runs the deferred processing after + * a DMA receive interrupt. Reenables the receive interrupt. + * @data: PDC state structure + */ static void pdc_tasklet_cb(unsigned long data) { struct pdc_state *pdcs = (struct pdc_state *)data; - bool rx_int; - rx_int = test_and_clear_bit(PDC_RCVINT_0, &pdcs->intstatus); - if (likely(pdcs && rx_int)) - pdc_receive(pdcs); + pdc_receive(pdcs); /* reenable interrupts */ iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); @@ -1405,8 +1395,6 @@ static int pdc_interrupts_init(struct pdc_state *pdcs) struct device_node *dn = pdev->dev.of_node; int err; - pdcs->intstatus = 0; - /* interrupt configuration */ iowrite32(PDC_INTMASK, pdcs->pdc_reg_vbase + PDC_INTMASK_OFFSET); iowrite32(PDC_LAZY_INT, pdcs->pdc_reg_vbase + PDC_RCVLAZY0_OFFSET); -- cgit v1.2.3 From cf17581340d730175f1f3f4ce6e90ae434154e37 Mon Sep 17 00:00:00 2001 From: Rob Rice Date: Mon, 14 Nov 2016 13:26:05 -0500 Subject: mailbox: bcm-pdc: Remove unnecessary void* casts Remove unnecessary void* casts in register writes. Fix two other minor formatting issues. Signed-off-by: Rob Rice Reviewed-by: Andy Gospodarek Reviewed-by: Jon Mason Signed-off-by: Jassi Brar --- drivers/mailbox/bcm-pdc-mailbox.c | 41 +++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/bcm-pdc-mailbox.c b/drivers/mailbox/bcm-pdc-mailbox.c index c1ec17cfa03a..2aeb034d5fb9 100644 --- a/drivers/mailbox/bcm-pdc-mailbox.c +++ b/drivers/mailbox/bcm-pdc-mailbox.c @@ -468,7 +468,7 @@ static ssize_t pdc_debugfs_read(struct file *filp, char __user *ubuf, out_offset += snprintf(buf + out_offset, out_count - out_offset, "Num frags in rx ring............%u\n", NRXDACTIVE(pdcs->rxin, pdcs->last_rx_curr, - pdcs->nrxpost)); + pdcs->nrxpost)); if (out_offset > out_count) out_offset = out_count; @@ -683,7 +683,7 @@ pdc_receive(struct pdc_state *pdcs) /* read last_rx_curr from register once */ pdcs->last_rx_curr = - (ioread32((void *)&pdcs->rxregs_64->status0) & + (ioread32(&pdcs->rxregs_64->status0) & CRYPTO_D64_RS0_CD_MASK) / RING_ENTRY_SIZE; do { @@ -793,8 +793,8 @@ static int pdc_tx_list_final(struct pdc_state *pdcs) * before chip starts to process new request */ wmb(); - iowrite32(pdcs->rxout << 4, (void *)&pdcs->rxregs_64->ptr); - iowrite32(pdcs->txout << 4, (void *)&pdcs->txregs_64->ptr); + iowrite32(pdcs->rxout << 4, &pdcs->rxregs_64->ptr); + iowrite32(pdcs->txout << 4, &pdcs->txregs_64->ptr); pdcs->pdc_requests++; return PDC_SUCCESS; @@ -1034,47 +1034,46 @@ static int pdc_ring_init(struct pdc_state *pdcs, int ringset) /* But first disable DMA and set curptr to 0 for both TX & RX */ iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); iowrite32((PDC_RX_CTL + (pdcs->rx_status_len << 1)), - (void *)&dma_reg->dmarcv.control); - iowrite32(0, (void *)&dma_reg->dmaxmt.ptr); - iowrite32(0, (void *)&dma_reg->dmarcv.ptr); + &dma_reg->dmarcv.control); + iowrite32(0, &dma_reg->dmaxmt.ptr); + iowrite32(0, &dma_reg->dmarcv.ptr); /* Set base DMA addresses */ iowrite32(lower_32_bits(pdcs->tx_ring_alloc.dmabase), - (void *)&dma_reg->dmaxmt.addrlow); + &dma_reg->dmaxmt.addrlow); iowrite32(upper_32_bits(pdcs->tx_ring_alloc.dmabase), - (void *)&dma_reg->dmaxmt.addrhigh); + &dma_reg->dmaxmt.addrhigh); iowrite32(lower_32_bits(pdcs->rx_ring_alloc.dmabase), - (void *)&dma_reg->dmarcv.addrlow); + &dma_reg->dmarcv.addrlow); iowrite32(upper_32_bits(pdcs->rx_ring_alloc.dmabase), - (void *)&dma_reg->dmarcv.addrhigh); + &dma_reg->dmarcv.addrhigh); /* Re-enable DMA */ iowrite32(PDC_TX_CTL | PDC_TX_ENABLE, &dma_reg->dmaxmt.control); iowrite32((PDC_RX_CTL | PDC_RX_ENABLE | (pdcs->rx_status_len << 1)), - (void *)&dma_reg->dmarcv.control); + &dma_reg->dmarcv.control); /* Initialize descriptors */ for (i = 0; i < PDC_RING_ENTRIES; i++) { /* Every tx descriptor can be used for start of frame. */ if (i != pdcs->ntxpost) { iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF, - (void *)&pdcs->txd_64[i].ctrl1); + &pdcs->txd_64[i].ctrl1); } else { /* Last descriptor in ringset. Set End of Table. */ iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOF | - D64_CTRL1_EOT, - (void *)&pdcs->txd_64[i].ctrl1); + D64_CTRL1_EOT, &pdcs->txd_64[i].ctrl1); } /* Every rx descriptor can be used for start of frame */ if (i != pdcs->nrxpost) { iowrite32(D64_CTRL1_SOF, - (void *)&pdcs->rxd_64[i].ctrl1); + &pdcs->rxd_64[i].ctrl1); } else { /* Last descriptor in ringset. Set End of Table. */ iowrite32(D64_CTRL1_SOF | D64_CTRL1_EOT, - (void *)&pdcs->rxd_64[i].ctrl1); + &pdcs->rxd_64[i].ctrl1); } } return PDC_SUCCESS; @@ -1300,10 +1299,10 @@ void pdc_hw_init(struct pdc_state *pdcs) /* initialize data structures */ pdcs->regs = (struct pdc_regs *)pdcs->pdc_reg_vbase; pdcs->txregs_64 = (struct dma64_regs *) - (void *)(((u8 *)pdcs->pdc_reg_vbase) + + (((u8 *)pdcs->pdc_reg_vbase) + PDC_TXREGS_OFFSET + (sizeof(struct dma64) * ringset)); pdcs->rxregs_64 = (struct dma64_regs *) - (void *)(((u8 *)pdcs->pdc_reg_vbase) + + (((u8 *)pdcs->pdc_reg_vbase) + PDC_RXREGS_OFFSET + (sizeof(struct dma64) * ringset)); pdcs->ntxd = PDC_RING_ENTRIES; @@ -1318,7 +1317,7 @@ void pdc_hw_init(struct pdc_state *pdcs) iowrite32(PDC_TX_CTL, &dma_reg->dmaxmt.control); iowrite32(PDC_RX_CTL + (pdcs->rx_status_len << 1), - (void *)&dma_reg->dmarcv.control); + &dma_reg->dmarcv.control); /* Reset current index pointers after making sure DMA is disabled */ iowrite32(0, &dma_reg->dmaxmt.ptr); @@ -1567,7 +1566,7 @@ static int pdc_probe(struct platform_device *pdev) pdc_hw_init(pdcs); /* Init tasklet for deferred DMA rx processing */ - tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long) pdcs); + tasklet_init(&pdcs->rx_tasklet, pdc_tasklet_cb, (unsigned long)pdcs); err = pdc_interrupts_init(pdcs); if (err) -- cgit v1.2.3 From baef9a35d24626ebdc5a9074455e63eea6c7f6af Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 29 Nov 2016 14:37:04 +0000 Subject: mailbox: mailbox-test: add support for fasync/poll Currently the read operation on the message debug file returns error if there's no data ready to be read. It expects the userspace to retry if it fails. Since the mailbox response could be asynchronous, it would be good to add support to block the read until the data is available. We can also implement poll file operations so that the userspace can wait to become ready to perform any I/O. This patch implements the poll and fasync file operation callback for the test mailbox device. Cc: Lee Jones Signed-off-by: Sudeep Holla Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-test.c | 79 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 71 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index deb9c61aebb4..383a8b7600ac 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -11,12 +11,14 @@ #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -39,6 +41,8 @@ struct mbox_test_device { char *signal; char *message; spinlock_t lock; + wait_queue_head_t waitq; + struct fasync_struct *async_queue; }; static ssize_t mbox_test_signal_write(struct file *filp, @@ -81,6 +85,13 @@ static const struct file_operations mbox_test_signal_ops = { .llseek = generic_file_llseek, }; +static int mbox_test_message_fasync(int fd, struct file *filp, int on) +{ + struct mbox_test_device *tdev = filp->private_data; + + return fasync_helper(fd, filp, on, &tdev->async_queue); +} + static ssize_t mbox_test_message_write(struct file *filp, const char __user *userbuf, size_t count, loff_t *ppos) @@ -138,6 +149,20 @@ out: return ret < 0 ? ret : count; } +static bool mbox_test_message_data_ready(struct mbox_test_device *tdev) +{ + unsigned char data; + unsigned long flags; + + spin_lock_irqsave(&tdev->lock, flags); + data = tdev->rx_buffer[0]; + spin_unlock_irqrestore(&tdev->lock, flags); + + if (data != '\0') + return true; + return false; +} + static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, size_t count, loff_t *ppos) { @@ -147,6 +172,8 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, int l = 0; int ret; + DECLARE_WAITQUEUE(wait, current); + touser = kzalloc(MBOX_HEXDUMP_MAX_LEN + 1, GFP_KERNEL); if (!touser) return -ENOMEM; @@ -155,15 +182,29 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, ret = snprintf(touser, 20, "\n"); ret = simple_read_from_buffer(userbuf, count, ppos, touser, ret); - goto out; + goto kfree_err; } - if (tdev->rx_buffer[0] == '\0') { - ret = snprintf(touser, 9, "\n"); - ret = simple_read_from_buffer(userbuf, count, ppos, - touser, ret); - goto out; - } + add_wait_queue(&tdev->waitq, &wait); + + do { + __set_current_state(TASK_INTERRUPTIBLE); + + if (mbox_test_message_data_ready(tdev)) + break; + + if (filp->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + goto waitq_err; + } + + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto waitq_err; + } + schedule(); + + } while (1); spin_lock_irqsave(&tdev->lock, flags); @@ -185,14 +226,31 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, spin_unlock_irqrestore(&tdev->lock, flags); ret = simple_read_from_buffer(userbuf, count, ppos, touser, MBOX_HEXDUMP_MAX_LEN); -out: +waitq_err: + __set_current_state(TASK_RUNNING); + remove_wait_queue(&tdev->waitq, &wait); +kfree_err: kfree(touser); return ret; } +static unsigned int +mbox_test_message_poll(struct file *filp, struct poll_table_struct *wait) +{ + struct mbox_test_device *tdev = filp->private_data; + + poll_wait(filp, &tdev->waitq, wait); + + if (mbox_test_message_data_ready(tdev)) + return POLLIN | POLLRDNORM; + return 0; +} + static const struct file_operations mbox_test_message_ops = { .write = mbox_test_message_write, .read = mbox_test_message_read, + .fasync = mbox_test_message_fasync, + .poll = mbox_test_message_poll, .open = simple_open, .llseek = generic_file_llseek, }; @@ -234,6 +292,10 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN); } spin_unlock_irqrestore(&tdev->lock, flags); + + wake_up_interruptible(&tdev->waitq); + + kill_fasync(&tdev->async_queue, SIGIO, POLL_IN); } static void mbox_test_prepare_message(struct mbox_client *client, void *message) @@ -334,6 +396,7 @@ static int mbox_test_probe(struct platform_device *pdev) if (ret) return ret; + init_waitqueue_head(&tdev->waitq); dev_info(&pdev->dev, "Successfully registered\n"); return 0; -- cgit v1.2.3 From db4d22c07e3e652eeec82abcc1399e6305edd838 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Tue, 29 Nov 2016 14:37:05 +0000 Subject: mailbox: mailbox-test: allow reserved areas in SRAM When CONFIG_SRAM is enable and the SRAM region is found, the entire SRAM region resource is requested and marked as occupied by SRAM driver even if certain parts of regions is marked reserved. It's quite possible that a small region of the SRAM is reserved for all the mailbox communication and hence it may fail to request the region as it's already marked busy region. This patch tries to just do a ioremap of this mailbox memory region if it finds it busy. Cc: Lee Jones Signed-off-by: Sudeep Holla Signed-off-by: Jassi Brar --- drivers/mailbox/mailbox-test.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mailbox/mailbox-test.c b/drivers/mailbox/mailbox-test.c index 383a8b7600ac..9c79f8019d2a 100644 --- a/drivers/mailbox/mailbox-test.c +++ b/drivers/mailbox/mailbox-test.c @@ -352,6 +352,7 @@ static int mbox_test_probe(struct platform_device *pdev) { struct mbox_test_device *tdev; struct resource *res; + resource_size_t size; int ret; tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL); @@ -360,14 +361,21 @@ static int mbox_test_probe(struct platform_device *pdev) /* It's okay for MMIO to be NULL */ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + size = resource_size(res); tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(tdev->tx_mmio)) + if (PTR_ERR(tdev->tx_mmio) == -EBUSY) + /* if reserved area in SRAM, try just ioremap */ + tdev->tx_mmio = devm_ioremap(&pdev->dev, res->start, size); + else if (IS_ERR(tdev->tx_mmio)) tdev->tx_mmio = NULL; /* If specified, second reg entry is Rx MMIO */ res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + size = resource_size(res); tdev->rx_mmio = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(tdev->rx_mmio)) + if (PTR_ERR(tdev->rx_mmio) == -EBUSY) + tdev->rx_mmio = devm_ioremap(&pdev->dev, res->start, size); + else if (IS_ERR(tdev->rx_mmio)) tdev->rx_mmio = tdev->tx_mmio; tdev->tx_channel = mbox_test_request_channel(pdev, "tx"); -- cgit v1.2.3 From c965809c669da004b660e5923b8add8fac5a7dc8 Mon Sep 17 00:00:00 2001 From: Stephen Bates Date: Fri, 16 Dec 2016 11:54:50 -0700 Subject: nvme : Use correct scnprintf in cmb show Make sure we are using the correct scnprintf in the sysfs show function for the CMB. Signed-off-by: Stephen Bates Reviewed-by Jon Derrick: Signed-off-by: Jens Axboe --- drivers/nvme/host/pci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 2fd7dc2e8fc4..3d21a154dce7 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -50,7 +50,7 @@ #define NVME_AQ_DEPTH 256 #define SQ_SIZE(depth) (depth * sizeof(struct nvme_command)) #define CQ_SIZE(depth) (depth * sizeof(struct nvme_completion)) - + /* * We handle AEN commands ourselves and don't even let the * block layer know about them. @@ -1349,7 +1349,7 @@ static ssize_t nvme_cmb_show(struct device *dev, { struct nvme_dev *ndev = to_nvme_dev(dev_get_drvdata(dev)); - return snprintf(buf, PAGE_SIZE, "cmbloc : x%08x\ncmbsz : x%08x\n", + return scnprintf(buf, PAGE_SIZE, "cmbloc : x%08x\ncmbsz : x%08x\n", ndev->cmbloc, ndev->cmbsz); } static DEVICE_ATTR(cmb, S_IRUGO, nvme_cmb_show, NULL); -- cgit v1.2.3 From 162809dfc2bfb31eb54dc67733bcdab0f2d1534d Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 15 Dec 2016 00:33:30 +0530 Subject: net: ethernet: cavium: octeon: octeon_mgmt: Handle return NULL error from devm_ioremap Here, If devm_ioremap will fail. It will return NULL. Kernel can run into a NULL-pointer dereference. This error check will avoid NULL pointer dereference. Signed-off-by: Arvind Yadav Signed-off-by: David S. Miller --- drivers/net/ethernet/cavium/octeon/octeon_mgmt.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c index 16e12c45904b..21f80f5744ba 100644 --- a/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/cavium/octeon/octeon_mgmt.c @@ -1469,6 +1469,12 @@ static int octeon_mgmt_probe(struct platform_device *pdev) p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size); p->agl_prt_ctl = (u64)devm_ioremap(&pdev->dev, p->agl_prt_ctl_phys, p->agl_prt_ctl_size); + if (!p->mix || !p->agl || !p->agl_prt_ctl) { + dev_err(&pdev->dev, "failed to map I/O memory\n"); + result = -ENOMEM; + goto err; + } + spin_lock_init(&p->lock); skb_queue_head_init(&p->tx_list); -- cgit v1.2.3 From ad688cdbb076833ba17fc65591cd0fe01900a5cf Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Sun, 18 Dec 2016 21:38:12 +0100 Subject: stmmac: fix memory barriers Fix up memory barriers in stmmac driver. They are meant to protect against DMA engine, so smp_ variants are certainly wrong, and dma_ variants are preferable. Signed-off-by: Pavel Machek Tested-by: Niklas Cassel Acked-by: Giuseppe Cavallaro Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c | 4 ++-- drivers/net/ethernet/stmicro/stmmac/enh_desc.c | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c index a340fc8bd0de..8816515e1bbb 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_descs.c @@ -334,7 +334,7 @@ static void dwmac4_rd_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, * descriptors for the same frame has to be set before, to * avoid race condition. */ - wmb(); + dma_wmb(); p->des3 = cpu_to_le32(tdes3); } @@ -377,7 +377,7 @@ static void dwmac4_rd_prepare_tso_tx_desc(struct dma_desc *p, int is_fs, * descriptors for the same frame has to be set before, to * avoid race condition. */ - wmb(); + dma_wmb(); p->des3 = cpu_to_le32(tdes3); } diff --git a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c index ce97e522566a..f0d86321dfe2 100644 --- a/drivers/net/ethernet/stmicro/stmmac/enh_desc.c +++ b/drivers/net/ethernet/stmicro/stmmac/enh_desc.c @@ -350,7 +350,7 @@ static void enh_desc_prepare_tx_desc(struct dma_desc *p, int is_fs, int len, * descriptors for the same frame has to be set before, to * avoid race condition. */ - wmb(); + dma_wmb(); p->des0 = cpu_to_le32(tdes0); } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 3e405785b81c..bb40382e205d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -2125,7 +2125,7 @@ static netdev_tx_t stmmac_tso_xmit(struct sk_buff *skb, struct net_device *dev) * descriptor and then barrier is needed to make sure that * all is coherent before granting the DMA engine. */ - smp_wmb(); + dma_wmb(); if (netif_msg_pktdata(priv)) { pr_info("%s: curr=%d dirty=%d f=%d, e=%d, f_p=%p, nfrags %d\n", @@ -2338,7 +2338,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev) * descriptor and then barrier is needed to make sure that * all is coherent before granting the DMA engine. */ - smp_wmb(); + dma_wmb(); } netdev_sent_queue(dev, skb->len); @@ -2443,14 +2443,14 @@ static inline void stmmac_rx_refill(struct stmmac_priv *priv) netif_dbg(priv, rx_status, priv->dev, "refill entry #%d\n", entry); } - wmb(); + dma_wmb(); if (unlikely(priv->synopsys_id >= DWMAC_CORE_4_00)) priv->hw->desc->init_rx_desc(p, priv->use_riwt, 0, 0); else priv->hw->desc->set_rx_owner(p); - wmb(); + dma_wmb(); entry = STMMAC_GET_ENTRY(entry, DMA_RX_SIZE); } -- cgit v1.2.3 From a1f49cc179ce6b7b7758ae3ff5cdb138d0ee0f56 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Wed, 14 Dec 2016 14:36:42 +0800 Subject: drm/amdgpu: fix cursor setting of dce6/dce8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: 7c83d7abc999 ("drm/amdgpu: Only update the CUR_SIZE register when necessary") Signed-off-by: Flora Cui Reviewed-by: Michel Dänzer Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/dce_v6_0.c | 6 +----- drivers/gpu/drm/amd/amdgpu/dce_v8_0.c | 2 -- 2 files changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c index e564442b6393..b4e4ec630e8c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v6_0.c @@ -1944,9 +1944,7 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v6_0_lock_cursor(crtc, true); - if (width != amdgpu_crtc->cursor_width || - height != amdgpu_crtc->cursor_height || - hot_x != amdgpu_crtc->cursor_hot_x || + if (hot_x != amdgpu_crtc->cursor_hot_x || hot_y != amdgpu_crtc->cursor_hot_y) { int x, y; @@ -1955,8 +1953,6 @@ static int dce_v6_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v6_0_cursor_move_locked(crtc, x, y); - amdgpu_crtc->cursor_width = width; - amdgpu_crtc->cursor_height = height; amdgpu_crtc->cursor_hot_x = hot_x; amdgpu_crtc->cursor_hot_y = hot_y; } diff --git a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c index 6ce7fb42dbef..584abe834a3c 100644 --- a/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c +++ b/drivers/gpu/drm/amd/amdgpu/dce_v8_0.c @@ -2438,8 +2438,6 @@ static int dce_v8_0_crtc_cursor_set2(struct drm_crtc *crtc, dce_v8_0_cursor_move_locked(crtc, x, y); - amdgpu_crtc->cursor_width = width; - amdgpu_crtc->cursor_height = height; amdgpu_crtc->cursor_hot_x = hot_x; amdgpu_crtc->cursor_hot_y = hot_y; } -- cgit v1.2.3 From 5b311c1519c658bf06f7a08a2ddc2648e4c9cd5c Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Wed, 14 Dec 2016 11:10:46 +0900 Subject: mmc: sdhci-cadence: add Socionext UniPhier specific compatible string Add a Socionext SoC specific compatible (suggested by Rob Herring). No SoC specific data are associated with the compatible strings for now, but other SoC vendors may use this IP and want to differentiate IP variants in the future. Signed-off-by: Masahiro Yamada Acked-by: Rob Herring Signed-off-by: Ulf Hansson --- Documentation/devicetree/bindings/mmc/sdhci-cadence.txt | 6 ++++-- drivers/mmc/host/sdhci-cadence.c | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt b/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt index 750374fc9d94..c0f37cb41a9b 100644 --- a/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt +++ b/Documentation/devicetree/bindings/mmc/sdhci-cadence.txt @@ -1,7 +1,9 @@ * Cadence SD/SDIO/eMMC Host Controller Required properties: -- compatible: should be "cdns,sd4hc". +- compatible: should be one of the following: + "cdns,sd4hc" - default of the IP + "socionext,uniphier-sd4hc" - for Socionext UniPhier SoCs - reg: offset and length of the register set for the device. - interrupts: a single interrupt specifier. - clocks: phandle to the input clock. @@ -19,7 +21,7 @@ if supported. See mmc.txt for details. Example: emmc: sdhci@5a000000 { - compatible = "cdns,sd4hc"; + compatible = "socionext,uniphier-sd4hc", "cdns,sd4hc"; reg = <0x5a000000 0x400>; interrupts = <0 78 4>; clocks = <&clk 4>; diff --git a/drivers/mmc/host/sdhci-cadence.c b/drivers/mmc/host/sdhci-cadence.c index 1501cfdac473..4b0ecb981842 100644 --- a/drivers/mmc/host/sdhci-cadence.c +++ b/drivers/mmc/host/sdhci-cadence.c @@ -262,6 +262,7 @@ disable_clk: } static const struct of_device_id sdhci_cdns_match[] = { + { .compatible = "socionext,uniphier-sd4hc" }, { .compatible = "cdns,sd4hc" }, { /* sentinel */ } }; -- cgit v1.2.3 From 84ec048ba133c2a570273e90622d8fac4930553e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 19 Dec 2016 15:33:11 +0200 Subject: mmc: sdhci: Fix to handle MMC_POWER_UNDEFINED Since commit c2c24819b280 ("mmc: core: Don't power off the card when starting the host"), the power state can still be MMC_POWER_UNDEFINED after mmc_start_host() is called. That can trigger a warning in SDHCI during runtime resume as it tries to restore the I/O state. Handle MMC_POWER_UNDEFINED simply by not updating the I/O state in that case. Fixes: c2c24819b280 ("mmc: core: Don't power off the card when starting the host") Signed-off-by: Adrian Hunter Signed-off-by: Ulf Hansson --- drivers/mmc/host/sdhci.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 111991e5b9a0..23909804ffb8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1576,6 +1576,9 @@ static void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) unsigned long flags; u8 ctrl; + if (ios->power_mode == MMC_POWER_UNDEFINED) + return; + spin_lock_irqsave(&host->lock, flags); if (host->flags & SDHCI_DEVICE_DEAD) { @@ -2938,22 +2941,24 @@ int sdhci_runtime_resume_host(struct sdhci_host *host) sdhci_init(host, 0); - /* Force clock and power re-program */ - host->pwr = 0; - host->clock = 0; - mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios); - mmc->ops->set_ios(mmc, &mmc->ios); + if (mmc->ios.power_mode != MMC_POWER_UNDEFINED) { + /* Force clock and power re-program */ + host->pwr = 0; + host->clock = 0; + mmc->ops->start_signal_voltage_switch(mmc, &mmc->ios); + mmc->ops->set_ios(mmc, &mmc->ios); - if ((host_flags & SDHCI_PV_ENABLED) && - !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { - spin_lock_irqsave(&host->lock, flags); - sdhci_enable_preset_value(host, true); - spin_unlock_irqrestore(&host->lock, flags); - } + if ((host_flags & SDHCI_PV_ENABLED) && + !(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) { + spin_lock_irqsave(&host->lock, flags); + sdhci_enable_preset_value(host, true); + spin_unlock_irqrestore(&host->lock, flags); + } - if ((mmc->caps2 & MMC_CAP2_HS400_ES) && - mmc->ops->hs400_enhanced_strobe) - mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios); + if ((mmc->caps2 & MMC_CAP2_HS400_ES) && + mmc->ops->hs400_enhanced_strobe) + mmc->ops->hs400_enhanced_strobe(mmc, &mmc->ios); + } spin_lock_irqsave(&host->lock, flags); -- cgit v1.2.3 From 15520111500c33a012aeec28ece8c5f2dcbf6b5e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 19 Dec 2016 15:57:34 +0200 Subject: mmc: core: Further fix thread wake-up Commit e0097cf5f2f1 ("mmc: queue: Fix queue thread wake-up") did not go far enough. mmc_wait_for_data_req_done() still contains some problems and can be further simplified. First it should not touch context_info->is_waiting_last_req because that is a wake-up control used by the owner of the context. Secondly, it should always return when one of its wake-up conditions is met because, again, that is contolled by the owner of the context. While the current block driver does not have an issue, these problems were exposed during testing of the Software Command Queue patches. Fixes: e0097cf5f2f1 ("mmc: queue: Fix queue thread wake-up") Signed-off-by: Adrian Hunter Tested-by: Harjani Ritesh Signed-off-by: Ulf Hansson --- drivers/mmc/core/core.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 543eadd230e5..1076b9d89df3 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -496,8 +496,7 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq) * Returns enum mmc_blk_status after checking errors. */ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, - struct mmc_request *mrq, - struct mmc_async_req *next_req) + struct mmc_request *mrq) { struct mmc_command *cmd; struct mmc_context_info *context_info = &host->context_info; @@ -507,7 +506,7 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, wait_event_interruptible(context_info->wait, (context_info->is_done_rcv || context_info->is_new_req)); - context_info->is_waiting_last_req = false; + if (context_info->is_done_rcv) { context_info->is_done_rcv = false; cmd = mrq->cmd; @@ -527,10 +526,9 @@ static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host, __mmc_start_request(host, mrq); continue; /* wait for done/new event again */ } - } else if (context_info->is_new_req) { - if (!next_req) - return MMC_BLK_NEW_REQUEST; } + + return MMC_BLK_NEW_REQUEST; } mmc_retune_release(host); return status; @@ -660,7 +658,7 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host, mmc_pre_req(host, areq->mrq); if (host->areq) { - status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq); + status = mmc_wait_for_data_req_done(host, host->areq->mrq); if (status == MMC_BLK_NEW_REQUEST) { if (ret_stat) *ret_stat = status; -- cgit v1.2.3 From cb853da3a368c40300a0e940f86be582037bb082 Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Fri, 9 Dec 2016 11:34:13 +0000 Subject: brcmfmac: fix memory leak in brcmf_cfg80211_attach() In brcmf_cfg80211_attach() there was one error path not properly handled as it leaked memory allocated in brcmf_btcoex_attach(). Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index ccae3bbe7db2..7ffc4aba5bab 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -6868,7 +6868,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, err = brcmf_p2p_attach(cfg, p2pdev_forced); if (err) { - brcmf_err("P2P initilisation failed (%d)\n", err); + brcmf_err("P2P initialisation failed (%d)\n", err); goto wiphy_unreg_out; } err = brcmf_btcoex_attach(cfg); @@ -6893,7 +6893,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, err = brcmf_fweh_activate_events(ifp); if (err) { brcmf_err("FWEH activation failed (%d)\n", err); - goto wiphy_unreg_out; + goto detach; } /* Fill in some of the advertised nl80211 supported features */ @@ -6908,6 +6908,9 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr, return cfg; +detach: + brcmf_btcoex_detach(cfg); + brcmf_p2p_detach(&cfg->p2p); wiphy_unreg_out: wiphy_unregister(cfg->wiphy); priv_out: -- cgit v1.2.3 From 2b66325d5ea7c2a39ac69ed83b6979afe480d81a Mon Sep 17 00:00:00 2001 From: Arend Van Spriel Date: Fri, 9 Dec 2016 11:34:14 +0000 Subject: brcmfmac: fix uninitialized field in scheduled scan ssid configuration The scheduled scan ssid configuration in firmware has a flags field that was not initialized resulting in unexpected behaviour. Fixes: e3bdb7cc0300 ("brcmfmac: fix handling ssids in .sched_scan_start() callback") Reviewed-by: Hante Meuleman Reviewed-by: Pieter-Paul Giesberts Reviewed-by: Franky Lin Signed-off-by: Arend van Spriel Signed-off-by: Kalle Valo --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c index f273cab0da10..9a25e79a46cf 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c @@ -137,6 +137,7 @@ static int brcmf_pno_add_ssid(struct brcmf_if *ifp, struct cfg80211_ssid *ssid, pfn.wpa_auth = cpu_to_le32(BRCMF_PNO_WPA_AUTH_ANY); pfn.wsec = cpu_to_le32(0); pfn.infra = cpu_to_le32(1); + pfn.flags = 0; if (active) pfn.flags = cpu_to_le32(1 << BRCMF_PNO_HIDDEN_BIT); pfn.ssid.SSID_len = cpu_to_le32(ssid->ssid_len); -- cgit v1.2.3 From 35f6c2336b1a5007ec837623f771d2d56dfba5c2 Mon Sep 17 00:00:00 2001 From: Matthew Auld Date: Mon, 28 Nov 2016 10:36:48 +0000 Subject: drm/i915: drop the struct_mutex when wedged or trying to reset We grab the struct_mutex in intel_crtc_page_flip, but if we are wedged or a reset is in progress we bail early but never seem to actually release the lock. Fixes: 7f1847ebf48b ("drm/i915: Simplify checking of GPU reset_counter in display pageflips") Cc: Chris Wilson Signed-off-by: Matthew Auld Link: http://patchwork.freedesktop.org/patch/msgid/20161128103648.9235-1-matthew.auld@intel.com Reviewed-by: Joonas Lahtinen Reviewed-by: Chris Wilson Signed-off-by: Chris Wilson Cc: # v4.7+ (cherry picked from commit ddbb271aea87fc6004d3c8bcdb0710e980c7ec85) Signed-off-by: Jani Nikula (cherry picked from commit e411072d5740a49cdc9d0713798c30440757e451) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 03d631525336..4ef5a39acc69 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -12212,7 +12212,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc, intel_crtc->reset_count = i915_reset_count(&dev_priv->gpu_error); if (i915_reset_in_progress_or_wedged(&dev_priv->gpu_error)) { ret = -EIO; - goto cleanup; + goto unlock; } atomic_inc(&intel_crtc->unpin_work_count); @@ -12301,6 +12301,7 @@ cleanup_unpin: intel_unpin_fb_obj(fb, crtc->primary->state->rotation); cleanup_pending: atomic_dec(&intel_crtc->unpin_work_count); +unlock: mutex_unlock(&dev->struct_mutex); cleanup: crtc->primary->fb = old_fb; -- cgit v1.2.3 From bb98e72adaf9d19719aba35f802d4836f5d5176c Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Dec 2016 15:29:04 +0100 Subject: drm/i915/dsi: Do not clear DPOUNIT_CLOCK_GATE_DISABLE from vlv_init_display_clock_gating MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On my Cherrytrail CUBE iwork8 Air tablet PIPE-A would get stuck on loading i915 at boot 1 out of every 3 boots, resulting in a non functional LCD. Once the i915 driver has successfully loaded, the panel can be disabled / enabled without hitting this issue. The getting stuck is caused by vlv_init_display_clock_gating() clearing the DPOUNIT_CLOCK_GATE_DISABLE bit in DSPCLK_GATE_D when called from chv_pipe_power_well_ops.enable() on driver load, while a pipe is enabled driving the DSI LCD by the BIOS. Clearing this bit while DSI is in use is a known issue and intel_dsi_pre_enable() / intel_dsi_post_disable() already set / clear it as appropriate. This commit modifies vlv_init_display_clock_gating() to leave the DPOUNIT_CLOCK_GATE_DISABLE bit alone fixing the pipe getting stuck. Changes in v2: -Replace PIPE-A with "a pipe" or "the pipe" in the commit msg and comment Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97330 Cc: stable@vger.kernel.org Signed-off-by: Hans de Goede Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20161202142904.25613-1-hdegoede@redhat.com Signed-off-by: Ville Syrjälä (cherry picked from commit 721d484563e1a51ada760089c490cbc47e909756) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_runtime_pm.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c index 356c662ad453..87b4af092d54 100644 --- a/drivers/gpu/drm/i915/intel_runtime_pm.c +++ b/drivers/gpu/drm/i915/intel_runtime_pm.c @@ -1039,7 +1039,18 @@ static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv, static void vlv_init_display_clock_gating(struct drm_i915_private *dev_priv) { - I915_WRITE(DSPCLK_GATE_D, VRHUNIT_CLOCK_GATE_DISABLE); + u32 val; + + /* + * On driver load, a pipe may be active and driving a DSI display. + * Preserve DPOUNIT_CLOCK_GATE_DISABLE to avoid the pipe getting stuck + * (and never recovering) in this case. intel_dsi_post_disable() will + * clear it when we turn off the display. + */ + val = I915_READ(DSPCLK_GATE_D); + val &= DPOUNIT_CLOCK_GATE_DISABLE; + val |= VRHUNIT_CLOCK_GATE_DISABLE; + I915_WRITE(DSPCLK_GATE_D, val); /* * Disable trickle feed and enable pnd deadline calculation -- cgit v1.2.3 From 25e23bc57e737a0d81dc6b03c610789866858b35 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Fri, 2 Dec 2016 16:01:28 +0100 Subject: drm/i915/dsi: Fix swapping of MIPI_SEQ_DEASSERT_RESET / MIPI_SEQ_ASSERT_RESET MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Looking at the ADF code from the Android kernel sources for a cherrytrail tablet I noticed that it is calling the MIPI_SEQ_ASSERT_RESET sequence from the panel prepare hook. Until commit b1cb1bd29189 ("drm/i915/dsi: update reset and power sequences in panel prepare/unprepare hooks") the mainline i915 code was doing the same. That commits effectively swaps the calling of MIPI_SEQ_ASSERT_RESET / MIPI_SEQ_DEASSERT_RESET. Looking at the naming of the sequences that is the right thing to do, but the problem is, that the old mainline code and the ADF code was actually calling the right sequence (tested on a cube iwork8 air tablet), and the swapping of the calling breaks things. This breakage was likely not noticed in testing because on cherrytrail, currently chv_exec_gpio ends up disabling the gpio pins rather then setting them (this is fixed in the next patch in this patch-set). This commit fixes the swapping by fixing MIPI_SEQ_ASSERT/DEASSERT_RESET's places in the enum defining them, so that their (new) names match their actual use. Changes in v2: -Add a comment to the enum explaining that the assert/reassert names are swapped in the spec Fixes: b1cb1bd29189 ("drm/i915/dsi: update reset and power sequences...") Cc: Jani Nikula Cc: Ville Syrjälä Signed-off-by: Hans de Goede Acked-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/20161202150128.29871-1-hdegoede@redhat.com Signed-off-by: Ville Syrjälä (cherry picked from commit 2b8208ac93be2783edc627fc02d9ca50cc479923) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_bios.h | 12 +++++++++--- drivers/gpu/drm/i915/intel_dsi_panel_vbt.c | 4 ++-- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index 8405b5a367d7..7e3545f65257 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h @@ -46,14 +46,20 @@ struct edp_power_seq { u16 t11_t12; } __packed; -/* MIPI Sequence Block definitions */ +/* + * MIPI Sequence Block definitions + * + * Note the VBT spec has AssertReset / DeassertReset swapped from their + * usual naming, we use the proper names here to avoid confusion when + * reading the code. + */ enum mipi_seq { MIPI_SEQ_END = 0, - MIPI_SEQ_ASSERT_RESET, + MIPI_SEQ_DEASSERT_RESET, /* Spec says MipiAssertResetPin */ MIPI_SEQ_INIT_OTP, MIPI_SEQ_DISPLAY_ON, MIPI_SEQ_DISPLAY_OFF, - MIPI_SEQ_DEASSERT_RESET, + MIPI_SEQ_ASSERT_RESET, /* Spec says MipiDeassertResetPin */ MIPI_SEQ_BACKLIGHT_ON, /* sequence block v2+ */ MIPI_SEQ_BACKLIGHT_OFF, /* sequence block v2+ */ MIPI_SEQ_TEAR_ON, /* sequence block v2+ */ diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 0d8ff0034b88..579d2f570717 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -376,11 +376,11 @@ static const fn_mipi_elem_exec exec_elem[] = { */ static const char * const seq_name[] = { - [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET", + [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET", [MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP", [MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON", [MIPI_SEQ_DISPLAY_OFF] = "MIPI_SEQ_DISPLAY_OFF", - [MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET", + [MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET", [MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON", [MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF", [MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON", -- cgit v1.2.3 From 22ca0d4991169b76e753d767a45f1105c356bbb8 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 1 Dec 2016 21:29:09 +0100 Subject: drm/i915/dsi: Fix chv_exec_gpio disabling the GPIOs it is setting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Set the CHV_GPIO_GPIOEN bit when updating GPIOs from chv_exec_gpio. Fixes: a0a6d4ffd2ad ("drm/i915/dsi: add support for gpio elements on CHV") Cc: stable@vger.kernel.org Cc: Jani Nikula Cc: Ville Syrjälä Signed-off-by: Hans de Goede Reviewed-by: Ville Syrjälä Link: http://patchwork.freedesktop.org/patch/msgid/20161201202925.12220-3-hdegoede@redhat.com Signed-off-by: Ville Syrjälä (cherry picked from commit b2b45fcd921e864a5e9bbc7aa55dee96d5e11c06) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dsi_panel_vbt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c index 579d2f570717..47cd1b20fb3e 100644 --- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c +++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c @@ -300,7 +300,8 @@ static void chv_exec_gpio(struct drm_i915_private *dev_priv, mutex_lock(&dev_priv->sb_lock); vlv_iosf_sb_write(dev_priv, port, cfg1, 0); vlv_iosf_sb_write(dev_priv, port, cfg0, - CHV_GPIO_GPIOCFG_GPO | CHV_GPIO_GPIOTXSTATE(value)); + CHV_GPIO_GPIOEN | CHV_GPIO_GPIOCFG_GPO | + CHV_GPIO_GPIOTXSTATE(value)); mutex_unlock(&dev_priv->sb_lock); } -- cgit v1.2.3 From 2c7d0602c815277f7cb7c932b091288710d8aba7 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 5 Dec 2016 18:27:37 +0200 Subject: drm/i915/gen9: Fix PCODE polling during CDCLK change notification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit 848496e5902833600f7992f4faa82dc1546051ba Author: Ville Syrjälä Date: Wed Jul 13 16:32:03 2016 +0300 drm/i915: Wait up to 3ms for the pcu to ack the cdclk change request on SKL increased the timeout to match the spec, but we still see a timeout on at least one SKL. A CDCLK change request following the failed one will succeed nevertheless. I could reproduce this problem easily by running kms_pipe_crc_basic in a loop. In all failure cases _wait_for() was pre-empted for >3ms and so in the worst case - when the pre-emption happened right after calculating timeout__ in _wait_for() - we called skl_cdclk_wait_for_pcu_ready() only once which failed and so _wait_for() timed out. As opposed to this the spec says to keep retrying the request for at most a 3ms period. To fix this send the first request explicitly to guarantee that there is 3ms between the first and last request. Though this matches the spec, I noticed that in rare cases this can still time out if we sent only a few requests (in the worst case 2) _and_ PCODE is busy for some reason even after a previous request and a 3ms delay. To work around this retry the polling with pre-emption disabled to maximize the number of requests. Also increase the timeout to 10ms to account for interrupts that could reduce the number of requests. With this change I couldn't trigger the problem. v2: - Use 1ms poll period instead of 10us. (Chris) v3: - Poll with pre-emption disabled to increase the number of request attempts. (Ville, Chris) - Factor out a helper to poll, it's also needed by the next patch. v4: - Pass reply_mask, reply to skl_pcode_request(), instead of assuming the reply is generic. (Ville) v5: - List the request specific timeout values as code comment. (Ville) v6: - Try the poll first with preemption enabled. - Add code comment about first request being queued by PCODE. (Art) - Add timeout_base_ms argument. (Ville) v7: - Clarify code comment about first queued request. (Chris) Cc: Ville Syrjälä Cc: Chris Wilson Cc: Art Runyan Cc: # v4.2- : 3b2c171 : drm/i915: Wait up to 3ms Cc: # v4.2- Fixes: 5d96d8afcfbb ("drm/i915/skl: Deinit/init the display at suspend/resume") Reference: https://bugs.freedesktop.org/show_bug.cgi?id=97929 Testcase: igt/kms_pipe_crc_basic/suspend-read-crc-pipe-B Signed-off-by: Imre Deak Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1480955258-26311-1-git-send-email-imre.deak@intel.com (cherry picked from commit a0b8a1fe34430c3a82258e8cb45f5968bdf31afd) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 31 +++++---------- drivers/gpu/drm/i915/intel_pm.c | 75 ++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 56002a52936d..243224aeabf8 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -3509,6 +3509,8 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e, int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val); int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val); +int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, + u32 reply_mask, u32 reply, int timeout_base_ms); /* intel_sideband.c */ u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr); diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 4ef5a39acc69..7d234043822d 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -6244,35 +6244,24 @@ skl_dpll0_disable(struct drm_i915_private *dev_priv) dev_priv->cdclk_pll.vco = 0; } -static bool skl_cdclk_pcu_ready(struct drm_i915_private *dev_priv) -{ - int ret; - u32 val; - - /* inform PCU we want to change CDCLK */ - val = SKL_CDCLK_PREPARE_FOR_CHANGE; - mutex_lock(&dev_priv->rps.hw_lock); - ret = sandybridge_pcode_read(dev_priv, SKL_PCODE_CDCLK_CONTROL, &val); - mutex_unlock(&dev_priv->rps.hw_lock); - - return ret == 0 && (val & SKL_CDCLK_READY_FOR_CHANGE); -} - -static bool skl_cdclk_wait_for_pcu_ready(struct drm_i915_private *dev_priv) -{ - return _wait_for(skl_cdclk_pcu_ready(dev_priv), 3000, 10) == 0; -} - static void skl_set_cdclk(struct drm_i915_private *dev_priv, int cdclk, int vco) { u32 freq_select, pcu_ack; + int ret; WARN_ON((cdclk == 24000) != (vco == 0)); DRM_DEBUG_DRIVER("Changing CDCLK to %d kHz (VCO %d kHz)\n", cdclk, vco); - if (!skl_cdclk_wait_for_pcu_ready(dev_priv)) { - DRM_ERROR("failed to inform PCU about cdclk change\n"); + mutex_lock(&dev_priv->rps.hw_lock); + ret = skl_pcode_request(dev_priv, SKL_PCODE_CDCLK_CONTROL, + SKL_CDCLK_PREPARE_FOR_CHANGE, + SKL_CDCLK_READY_FOR_CHANGE, + SKL_CDCLK_READY_FOR_CHANGE, 3); + mutex_unlock(&dev_priv->rps.hw_lock); + if (ret) { + DRM_ERROR("Failed to inform PCU about cdclk change (%d)\n", + ret); return; } diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index cbd0f3269b2d..90e42e094b13 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -7890,6 +7890,81 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, return 0; } +static bool skl_pcode_try_request(struct drm_i915_private *dev_priv, u32 mbox, + u32 request, u32 reply_mask, u32 reply, + u32 *status) +{ + u32 val = request; + + *status = sandybridge_pcode_read(dev_priv, mbox, &val); + + return *status || ((val & reply_mask) == reply); +} + +/** + * skl_pcode_request - send PCODE request until acknowledgment + * @dev_priv: device private + * @mbox: PCODE mailbox ID the request is targeted for + * @request: request ID + * @reply_mask: mask used to check for request acknowledgment + * @reply: value used to check for request acknowledgment + * @timeout_base_ms: timeout for polling with preemption enabled + * + * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE + * reports an error or an overall timeout of @timeout_base_ms+10 ms expires. + * The request is acknowledged once the PCODE reply dword equals @reply after + * applying @reply_mask. Polling is first attempted with preemption enabled + * for @timeout_base_ms and if this times out for another 10 ms with + * preemption disabled. + * + * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some + * other error as reported by PCODE. + */ +int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request, + u32 reply_mask, u32 reply, int timeout_base_ms) +{ + u32 status; + int ret; + + WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock)); + +#define COND skl_pcode_try_request(dev_priv, mbox, request, reply_mask, reply, \ + &status) + + /* + * Prime the PCODE by doing a request first. Normally it guarantees + * that a subsequent request, at most @timeout_base_ms later, succeeds. + * _wait_for() doesn't guarantee when its passed condition is evaluated + * first, so send the first request explicitly. + */ + if (COND) { + ret = 0; + goto out; + } + ret = _wait_for(COND, timeout_base_ms * 1000, 10); + if (!ret) + goto out; + + /* + * The above can time out if the number of requests was low (2 in the + * worst case) _and_ PCODE was busy for some reason even after a + * (queued) request and @timeout_base_ms delay. As a workaround retry + * the poll with preemption disabled to maximize the number of + * requests. Increase the timeout from @timeout_base_ms to 10ms to + * account for interrupts that could reduce the number of these + * requests. + */ + DRM_DEBUG_KMS("PCODE timeout, retrying with preemption disabled\n"); + WARN_ON_ONCE(timeout_base_ms > 3); + preempt_disable(); + ret = wait_for_atomic(COND, 10); + preempt_enable(); + +out: + return ret ? ret : status; +#undef COND +} + static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val) { /* -- cgit v1.2.3 From dccf82ad1775f2b9c36ec85e25e39d88c7e86818 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Mon, 5 Dec 2016 18:27:38 +0200 Subject: drm/i915/gen9: Fix PCODE polling during SAGV disabling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the previous patch, it's possible atm that we call intel_do_sagv_disable() only once during the 1ms period and time out if that call fails. As opposed to this the spec says that we need to keep retrying this request for a 1ms duration, so let's do this similarly to the CDCLK change notification request. v4-5: - Rebased on the reply_mask, reply change. v6: - Remove w/s change. (Lyude) - Rebased on the timeout_base argument change. Cc: Lyude Cc: Ville Syrjälä Cc: Chris Wilson Fixes: 656d1b89e5ff ("drm/i915/skl: Add support for the SAGV, fix underrun hangs") Signed-off-by: Imre Deak Reviewed-by: Lyude (v4) Link: http://patchwork.freedesktop.org/patch/msgid/1480955258-26311-2-git-send-email-imre.deak@intel.com (cherry picked from commit b3b8e99984a4eace91bc097e8f8cec71441cae16) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_pm.c | 34 +++++++++------------------------- 1 file changed, 9 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c index 90e42e094b13..1377679ac109 100644 --- a/drivers/gpu/drm/i915/intel_pm.c +++ b/drivers/gpu/drm/i915/intel_pm.c @@ -2964,24 +2964,10 @@ intel_enable_sagv(struct drm_i915_private *dev_priv) return 0; } -static int -intel_do_sagv_disable(struct drm_i915_private *dev_priv) -{ - int ret; - uint32_t temp = GEN9_SAGV_DISABLE; - - ret = sandybridge_pcode_read(dev_priv, GEN9_PCODE_SAGV_CONTROL, - &temp); - if (ret) - return ret; - else - return temp & GEN9_SAGV_IS_DISABLED; -} - int intel_disable_sagv(struct drm_i915_private *dev_priv) { - int ret, result; + int ret; if (!intel_has_sagv(dev_priv)) return 0; @@ -2993,25 +2979,23 @@ intel_disable_sagv(struct drm_i915_private *dev_priv) mutex_lock(&dev_priv->rps.hw_lock); /* bspec says to keep retrying for at least 1 ms */ - ret = wait_for(result = intel_do_sagv_disable(dev_priv), 1); + ret = skl_pcode_request(dev_priv, GEN9_PCODE_SAGV_CONTROL, + GEN9_SAGV_DISABLE, + GEN9_SAGV_IS_DISABLED, GEN9_SAGV_IS_DISABLED, + 1); mutex_unlock(&dev_priv->rps.hw_lock); - if (ret == -ETIMEDOUT) { - DRM_ERROR("Request to disable SAGV timed out\n"); - return -ETIMEDOUT; - } - /* * Some skl systems, pre-release machines in particular, * don't actually have an SAGV. */ - if (IS_SKYLAKE(dev_priv) && result == -ENXIO) { + if (IS_SKYLAKE(dev_priv) && ret == -ENXIO) { DRM_DEBUG_DRIVER("No SAGV found on system, ignoring\n"); dev_priv->sagv_status = I915_SAGV_NOT_CONTROLLED; return 0; - } else if (result < 0) { - DRM_ERROR("Failed to disable the SAGV\n"); - return result; + } else if (ret < 0) { + DRM_ERROR("Failed to disable the SAGV (%d)\n", ret); + return ret; } dev_priv->sagv_status = I915_SAGV_DISABLED; -- cgit v1.2.3 From 057f803ff10742addd19a7c2fb6fb83940059a6c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Wed, 7 Dec 2016 13:34:11 +0000 Subject: drm/i915: Reorder phys backing storage release MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In commit a4f5ea64f0a8 ("drm/i915: Refactor object page API"), I reordered the object->pages teardown to be more friendly wrt to a separate obj->mm.lock. However, I overlooked the phys object and left it with a dangling use-after-free of its phys_handle. Move the allocation of the phys handle to get_pages and it release to put_pages to prevent the invalid access and to improve symmetry. v2: Add commentary about always aligning to page size. Testcase: igt/drv_selftest/objects Reported-by: Ville Syrjälä Fixes: a4f5ea64f0a8 ("drm/i915: Refactor object page API") Signed-off-by: Chris Wilson Cc: Ville Syrjälä Cc: Tvrtko Ursulin Cc: Joonas Lahtinen Reviewed-by: Joonas Lahtinen Link: http://patchwork.freedesktop.org/patch/msgid/20161207133411.8028-1-chris@chris-wilson.co.uk (cherry picked from commit dbb4351bab0a8440f6b02895c142bce6c30b7097) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem.c | 53 ++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index d0dcaf35b429..3b6eb651d88a 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -174,21 +174,35 @@ static struct sg_table * i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) { struct address_space *mapping = obj->base.filp->f_mapping; - char *vaddr = obj->phys_handle->vaddr; + drm_dma_handle_t *phys; struct sg_table *st; struct scatterlist *sg; + char *vaddr; int i; if (WARN_ON(i915_gem_object_needs_bit17_swizzle(obj))) return ERR_PTR(-EINVAL); + /* Always aligning to the object size, allows a single allocation + * to handle all possible callers, and given typical object sizes, + * the alignment of the buddy allocation will naturally match. + */ + phys = drm_pci_alloc(obj->base.dev, + obj->base.size, + roundup_pow_of_two(obj->base.size)); + if (!phys) + return ERR_PTR(-ENOMEM); + + vaddr = phys->vaddr; for (i = 0; i < obj->base.size / PAGE_SIZE; i++) { struct page *page; char *src; page = shmem_read_mapping_page(mapping, i); - if (IS_ERR(page)) - return ERR_CAST(page); + if (IS_ERR(page)) { + st = ERR_CAST(page); + goto err_phys; + } src = kmap_atomic(page); memcpy(vaddr, src, PAGE_SIZE); @@ -202,21 +216,29 @@ i915_gem_object_get_pages_phys(struct drm_i915_gem_object *obj) i915_gem_chipset_flush(to_i915(obj->base.dev)); st = kmalloc(sizeof(*st), GFP_KERNEL); - if (st == NULL) - return ERR_PTR(-ENOMEM); + if (!st) { + st = ERR_PTR(-ENOMEM); + goto err_phys; + } if (sg_alloc_table(st, 1, GFP_KERNEL)) { kfree(st); - return ERR_PTR(-ENOMEM); + st = ERR_PTR(-ENOMEM); + goto err_phys; } sg = st->sgl; sg->offset = 0; sg->length = obj->base.size; - sg_dma_address(sg) = obj->phys_handle->busaddr; + sg_dma_address(sg) = phys->busaddr; sg_dma_len(sg) = obj->base.size; + obj->phys_handle = phys; + return st; + +err_phys: + drm_pci_free(obj->base.dev, phys); return st; } @@ -272,12 +294,13 @@ i915_gem_object_put_pages_phys(struct drm_i915_gem_object *obj, sg_free_table(pages); kfree(pages); + + drm_pci_free(obj->base.dev, obj->phys_handle); } static void i915_gem_object_release_phys(struct drm_i915_gem_object *obj) { - drm_pci_free(obj->base.dev, obj->phys_handle); i915_gem_object_unpin_pages(obj); } @@ -538,15 +561,13 @@ int i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, int align) { - drm_dma_handle_t *phys; int ret; - if (obj->phys_handle) { - if ((unsigned long)obj->phys_handle->vaddr & (align -1)) - return -EBUSY; + if (align > obj->base.size) + return -EINVAL; + if (obj->ops == &i915_gem_phys_ops) return 0; - } if (obj->mm.madv != I915_MADV_WILLNEED) return -EFAULT; @@ -562,12 +583,6 @@ i915_gem_object_attach_phys(struct drm_i915_gem_object *obj, if (obj->mm.pages) return -EBUSY; - /* create a new object */ - phys = drm_pci_alloc(obj->base.dev, obj->base.size, align); - if (!phys) - return -ENOMEM; - - obj->phys_handle = phys; obj->ops = &i915_gem_phys_ops; return i915_gem_object_pin_pages(obj); -- cgit v1.2.3 From 2c57b18adb93fc070039538f1ce375d3d3e99bbb Mon Sep 17 00:00:00 2001 From: Daniel Vetter Date: Tue, 13 Dec 2016 20:54:14 +0100 Subject: drm/i915: tune down the fast link training vs boot fail MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It's been unfixed since a while and no one is immediately working on this. And we have the FIXME already. And now also a task in the DP team's backlog. Cc: Linus Torvalds Cc: stable@vger.kernel.org Cc: Ville Syrjälä References: https://lists.freedesktop.org/archives/intel-gfx/2016-July/101951.html Acked-by: Ville Syrjälä [danvet: Adjust comment per Ville's feedback.] Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/20161213195414.28923-1-daniel.vetter@ffwll.ch (cherry picked from commit 2dd85aeb5bc99e3763dd192cdb95ff405a102c8a) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_dp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 90283edcafba..d9bc19be855e 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4014,8 +4014,8 @@ intel_dp_check_link_status(struct intel_dp *intel_dp) return; /* FIXME: we need to synchronize this sort of stuff with hardware - * readout */ - if (WARN_ON_ONCE(!intel_dp->lane_count)) + * readout. Currently fast link training doesn't work on boot-up. */ + if (!intel_dp->lane_count) return; /* if link training is requested we should perform it always */ -- cgit v1.2.3 From b1b7ec985805e005055d1d471ca586a715ffc10a Mon Sep 17 00:00:00 2001 From: Mika Kuoppala Date: Wed, 14 Dec 2016 14:26:20 +0200 Subject: drm/i915: Fix setting of boost freq tunable For limiting the max frequency of gpu, the max freq tunable is not enough to hard limit the max gap. We now have also per client boost max freq. When this tunable was introduced, it was mistakenly made read only. Allow user to gain control by setting it writable. Fixes: 29ecd78d3b79 ("drm/i915: Define a separate variable and control for RPS waitboost frequency") Cc: # v4.9+ Cc: Chris Wilson Cc: Mika Kuoppala Cc: Daniel Vetter Cc: Jani Nikula Reviewed-by: Chris Wilson Signed-off-by: Mika Kuoppala Link: http://patchwork.freedesktop.org/patch/msgid/1481718380-9170-1-git-send-email-mika.kuoppala@intel.com (cherry picked from commit 73a798711314b54cbd4fe224e24db92c306a8d8c) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_sysfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c index 47590ab08d7e..3df8d3dd31cd 100644 --- a/drivers/gpu/drm/i915/i915_sysfs.c +++ b/drivers/gpu/drm/i915/i915_sysfs.c @@ -460,7 +460,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev, static DEVICE_ATTR(gt_act_freq_mhz, S_IRUGO, gt_act_freq_mhz_show, NULL); static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL); -static DEVICE_ATTR(gt_boost_freq_mhz, S_IRUGO, gt_boost_freq_mhz_show, gt_boost_freq_mhz_store); +static DEVICE_ATTR(gt_boost_freq_mhz, S_IRUGO | S_IWUSR, gt_boost_freq_mhz_show, gt_boost_freq_mhz_store); static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store); static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store); -- cgit v1.2.3 From 1c4672ce4eeaeaadeea8adabaad21262b7172607 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Tue, 13 Dec 2016 18:57:44 -0200 Subject: drm/i915: disable PSR by default on HSW/BDW We've been ignoring the poor bugzilla reporters that say PSR causes system lockups and all other sorts of problems. The earliest bug report is from April, so I think we can use the "revert the offending commit if no fixes are presented within 8 months" rule here. Fixes: 9b58e352b463 ("drm/i915: Enable PSR by default on Haswell and Broadwell.") Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97602 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=97515 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96736 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96704 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=96569 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=95176 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94985 Cc: # v4.6+ Cc: Rodrigo Vivi Cc: Jim Bride Signed-off-by: Paulo Zanoni Acked-by: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Acked-by: Jani Nikula Link: http://patchwork.freedesktop.org/patch/msgid/1481662664-18986-1-git-send-email-paulo.r.zanoni@intel.com (cherry picked from commit 2ee7dc497e348eecbb82adbb1ea9e9a7e29fe921) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_psr.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 7b488e2793d9..c6be70686b4a 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -825,13 +825,9 @@ void intel_psr_init(struct drm_device *dev) dev_priv->psr_mmio_base = IS_HASWELL(dev_priv) ? HSW_EDP_PSR_BASE : BDW_EDP_PSR_BASE; - /* Per platform default */ - if (i915.enable_psr == -1) { - if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) - i915.enable_psr = 1; - else - i915.enable_psr = 0; - } + /* Per platform default: all disabled. */ + if (i915.enable_psr == -1) + i915.enable_psr = 0; /* Set link_standby x link_off defaults */ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv)) -- cgit v1.2.3 From d8953c8326d87a337763ca547ad7db034a94ddb1 Mon Sep 17 00:00:00 2001 From: Tvrtko Ursulin Date: Fri, 16 Dec 2016 13:18:42 +0000 Subject: drm/i915: Fix use after free in logical_render_ring_init Commit 3b3f1650b1ca ("drm/i915: Allocate intel_engine_cs structure only for the enabled engines") introduced the dynanically allocated engine instances and created an potential use after free scenario in logical_render_ring_init where lrc_destroy_wa_ctx_obj could be called after the engine instance has been freed. This can only happen during engine setup/init error handling which luckily does not happen ever in practice. Fix is to not call lrc_destroy_wa_ctx_obj since it would have already been executed from the preceding engine cleanup. Signed-off-by: Tvrtko Ursulin Reported-by: Dan Carpenter Fixes: 3b3f1650b1ca ("drm/i915: Allocate intel_engine_cs structure only for the enabled engines") Cc: Chris Wilson Cc: Joonas Lahtinen Cc: Tvrtko Ursulin Cc: Daniel Vetter Cc: Jani Nikula Reviewed-by: Chris Wilson Link: http://patchwork.freedesktop.org/patch/msgid/1481894322-2145-1-git-send-email-tvrtko.ursulin@linux.intel.com (cherry picked from commit d038fc7e4fff14d6b026130007faef35cbf5e956) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/intel_lrc.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 0a09024d6ca3..d4961fa20c73 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -1968,12 +1968,7 @@ int logical_render_ring_init(struct intel_engine_cs *engine) ret); } - ret = logical_ring_init(engine); - if (ret) { - lrc_destroy_wa_ctx_obj(engine); - } - - return ret; + return logical_ring_init(engine); } int logical_xcs_ring_init(struct intel_engine_cs *engine) -- cgit v1.2.3 From abb0deacb5a6713b918ac6395182cb27bb88be69 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 19 Dec 2016 12:43:45 +0000 Subject: drm/i915: Fallback to single PAGE_SIZE segments for DMA remapping If we at first do not succeed with attempting to remap our physical pages using a coalesced scattergather list, try again with one scattergather entry per page. This should help with swiotlb as it uses a limited buffer size and only searches for contiguous chunks within its buffer aligned up to the next boundary - i.e. we may prematurely cause a failure as we are unable to utilize the unused space between large chunks and trigger an error such as: i915 0000:00:02.0: swiotlb buffer is full (sz: 1630208 bytes) Reported-by: Juergen Gross Tested-by: Juergen Gross Fixes: 871dfbd67d4e ("drm/i915: Allow compaction upto SWIOTLB max segment size") Signed-off-by: Chris Wilson Cc: Tvrtko Ursulin Cc: Imre Deak Cc: Link: http://patchwork.freedesktop.org/patch/msgid/20161219124346.550-1-chris@chris-wilson.co.uk Reviewed-by: Daniel Vetter (cherry picked from commit d766ef53006c2c38a7fe2bef0904105a793383f2) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 3b6eb651d88a..c6f80bc3b7bc 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -2342,7 +2342,8 @@ static struct sg_table * i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) { struct drm_i915_private *dev_priv = to_i915(obj->base.dev); - int page_count, i; + const unsigned long page_count = obj->base.size / PAGE_SIZE; + unsigned long i; struct address_space *mapping; struct sg_table *st; struct scatterlist *sg; @@ -2368,7 +2369,7 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) if (st == NULL) return ERR_PTR(-ENOMEM); - page_count = obj->base.size / PAGE_SIZE; +rebuild_st: if (sg_alloc_table(st, page_count, GFP_KERNEL)) { kfree(st); return ERR_PTR(-ENOMEM); @@ -2427,8 +2428,25 @@ i915_gem_object_get_pages_gtt(struct drm_i915_gem_object *obj) i915_sg_trim(st); ret = i915_gem_gtt_prepare_pages(obj, st); - if (ret) - goto err_pages; + if (ret) { + /* DMA remapping failed? One possible cause is that + * it could not reserve enough large entries, asking + * for PAGE_SIZE chunks instead may be helpful. + */ + if (max_segment > PAGE_SIZE) { + for_each_sgt_page(page, sgt_iter, st) + put_page(page); + sg_free_table(st); + + max_segment = PAGE_SIZE; + goto rebuild_st; + } else { + dev_warn(&dev_priv->drm.pdev->dev, + "Failed to DMA remap %lu pages\n", + page_count); + goto err_pages; + } + } if (i915_gem_object_needs_bit17_swizzle(obj)) i915_gem_object_do_bit_17_swizzle(obj, st); -- cgit v1.2.3 From 6ba0566cf2afcdb17bff882e3a95cbbcb22c4a83 Mon Sep 17 00:00:00 2001 From: Paulo Zanoni Date: Wed, 14 Dec 2016 12:55:37 -0200 Subject: drm/i915: skip the first 4k of stolen memory on everything >= gen8 BSpec got updated and this workaround is now listed as standard required programming for all subsequent projects. This is confirmed to fix Skylake screen flickering issues (probably caused by the fact that we initialized a ring in the first page of stolen, but I didn't 100% confirm this theory). v2: this is the patch that fixes the screen flickering, document it. Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=94605 Cc: stable@vger.kernel.org Tested-by: Dominik Klementowski Signed-off-by: Paulo Zanoni Acked-by: Chris Wilson Reviewed-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1481727338-9901-1-git-send-email-paulo.r.zanoni@intel.com (cherry picked from commit d43537610470d8829ebd17cd7842f47176e35ebd) Signed-off-by: Jani Nikula --- drivers/gpu/drm/i915/i915_gem_stolen.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c index ebaa941c83af..abc78bbfc1dc 100644 --- a/drivers/gpu/drm/i915/i915_gem_stolen.c +++ b/drivers/gpu/drm/i915/i915_gem_stolen.c @@ -55,10 +55,9 @@ int i915_gem_stolen_insert_node_in_range(struct drm_i915_private *dev_priv, return -ENODEV; /* See the comment at the drm_mm_init() call for more about this check. - * WaSkipStolenMemoryFirstPage:bdw,chv,kbl (incomplete) + * WaSkipStolenMemoryFirstPage:bdw+ (incomplete) */ - if (start < 4096 && (IS_GEN8(dev_priv) || - IS_KBL_REVID(dev_priv, 0, KBL_REVID_A0))) + if (start < 4096 && INTEL_GEN(dev_priv) >= 8) start = 4096; mutex_lock(&dev_priv->mm.stolen_lock); -- cgit v1.2.3 From d4166b8b33650d9dc89715c9540ba0f261490d4d Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Thu, 15 Dec 2016 11:23:19 +0200 Subject: ath10k: free host-mem with DMA_BIRECTIONAL flag Hopefully this fixes the problem reported by Kalle: Noticed this in my log, but I don't have time to investigate this in detail right now: [ 413.795346] IPv6: ADDRCONF(NETDEV_UP): wlan0: link is not ready [ 414.158755] IPv6: ADDRCONF(NETDEV_CHANGE): wlan0: link becomes ready [ 477.439659] ath10k_pci 0000:02:00.0: could not get mac80211 beacon [ 481.666630] ------------[ cut here ]------------ [ 481.666669] WARNING: CPU: 0 PID: 1978 at lib/dma-debug.c:1155 check_unmap+0x320/0x8e0 [ 481.666688] ath10k_pci 0000:02:00.0: DMA-API: device driver frees DMA memory with different direction [device address=0x000000002d130000] [size=63800 bytes] [mapped with DMA_BIDIRECTIONAL] [unmapped with DMA_TO_DEVICE] [ 481.666703] Modules linked in: ctr ccm ath10k_pci(E-) ath10k_core(E) ath(E) mac80211(E) cfg80211(E) snd_hda_codec_hdmi snd_hda_codec_idt snd_hda_codec_generic snd_hda_intel snd_hda_codec snd_hda_core snd_hwdep snd_pcm snd_seq_midi arc4 snd_rawmidi snd_seq_midi_event snd_seq btusb btintel snd_seq_device joydev coret [ 481.671468] CPU: 0 PID: 1978 Comm: rmmod Tainted: G E 4.9.0-rc7-wt+ #54 [ 481.671478] Hardware name: Hewlett-Packard HP ProBook 6540b/1722, BIOS 68CDD Ver. F.04 01/27/2010 [ 481.671489] ef49dcec c842ee92 c8b5830e ef49dd34 ef49dd20 c80850f5 c8b5a13c ef49dd50 [ 481.671560] 000007ba c8b5830e 00000483 c8461830 c8461830 00000483 ef49ddcc f34e64b8 [ 481.671641] c8b58360 ef49dd3c c80851bb 00000009 00000000 ef49dd34 c8b5a13c ef49dd50 [ 481.671716] Call Trace: [ 481.671731] [] dump_stack+0x76/0xb4 [ 481.671745] [] __warn+0xe5/0x100 [ 481.671757] [] ? check_unmap+0x320/0x8e0 [ 481.671769] [] ? check_unmap+0x320/0x8e0 [ 481.671780] [] warn_slowpath_fmt+0x3b/0x40 [ 481.671791] [] check_unmap+0x320/0x8e0 [ 481.671804] [] debug_dma_unmap_page+0x84/0xa0 [ 481.671835] [] ath10k_wmi_free_host_mem+0x9a/0xe0 [ath10k_core] [ 481.671861] [] ath10k_core_destroy+0x50/0x60 [ath10k_core] [ 481.671875] [] ath10k_pci_remove+0x79/0xa0 [ath10k_pci] [ 481.671889] [] pci_device_remove+0x38/0xb0 [ 481.671901] [] __device_release_driver+0x7b/0x110 [ 481.671913] [] driver_detach+0x97/0xa0 [ 481.671923] [] bus_remove_driver+0x4b/0xb0 [ 481.671934] [] driver_unregister+0x2a/0x60 [ 481.671949] [] pci_unregister_driver+0x18/0x70 [ 481.671965] [] ath10k_pci_exit+0xd/0x25f [ath10k_pci] [ 481.671979] [] SyS_delete_module+0xf4/0x180 [ 481.671995] [] ? __might_fault+0x8b/0xa0 [ 481.672009] [] do_fast_syscall_32+0xa0/0x1e0 [ 481.672025] [] sysenter_past_esp+0x45/0x74 [ 481.672037] ---[ end trace 3fd23759e17e1622 ]--- [ 481.672049] Mapped at: [ 481.672060] [ 481.672072] [] debug_dma_map_page.part.25+0x1c/0xf0 [ 481.672083] [ 481.672095] [] debug_dma_map_page+0x99/0xc0 [ 481.672106] [ 481.672132] [] ath10k_wmi_alloc_chunk+0x12c/0x1f0 [ath10k_core] [ 481.672142] [ 481.672168] [] ath10k_wmi_event_service_ready_work+0x304/0x540 [ath10k_core] [ 481.672178] [ 481.672190] [] process_one_work+0x1c3/0x670 [ 482.137134] ath10k_pci 0000:02:00.0: pci irq msi oper_irq_mode 2 irq_mode 0 reset_mode 0 [ 482.313144] ath10k_pci 0000:02:00.0: Direct firmware load for ath10k/pre-cal-pci-0000:02:00.0.bin failed with error -2 [ 482.313274] ath10k_pci 0000:02:00.0: Direct firmware load for ath10k/cal-pci-0000:02:00.0.bin failed with error -2 [ 482.313768] ath10k_pci 0000:02:00.0: qca988x hw2.0 target 0x4100016c chip_id 0x043202ff sub 0000:0000 [ 482.313777] ath10k_pci 0000:02:00.0: kconfig debug 1 debugfs 1 tracing 1 dfs 0 testmode 1 [ 482.313974] ath10k_pci 0000:02:00.0: firmware ver 10.2.4.70.59-2 api 5 features no-p2p,raw-mode,mfp,allows-mesh-bcast crc32 4159f498 [ 482.369858] ath10k_pci 0000:02:00.0: Direct firmware load for ath10k/QCA988X/hw2.0/board-2.bin failed with error -2 [ 482.370011] ath10k_pci 0000:02:00.0: board_file api 1 bmi_id N/A crc32 bebc7c08 [ 483.596770] ath10k_pci 0000:02:00.0: htt-ver 2.1 wmi-op 5 htt-op 2 cal otp max-sta 128 raw 0 hwcrypto 1 [ 483.701686] ath: EEPROM regdomain: 0x0 [ 483.701706] ath: EEPROM indicates default country code should be used [ 483.701713] ath: doing EEPROM country->regdmn map search [ 483.701721] ath: country maps to regdmn code: 0x3a [ 483.701730] ath: Country alpha2 being used: US [ 483.701737] ath: Regpair used: 0x3a Reported-by: Kalle Valo Signed-off-by: Ben Greear Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath10k/wmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c index c893314a191f..50d6ee6afe26 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c @@ -8271,7 +8271,7 @@ void ath10k_wmi_free_host_mem(struct ath10k *ar) dma_unmap_single(ar->dev, ar->wmi.mem_chunks[i].paddr, ar->wmi.mem_chunks[i].len, - DMA_TO_DEVICE); + DMA_BIDIRECTIONAL); kfree(ar->wmi.mem_chunks[i].vaddr); } -- cgit v1.2.3 From 3bb9ab63276696988d8224f52db20e87194deb4b Mon Sep 17 00:00:00 2001 From: jbrunet Date: Mon, 19 Dec 2016 16:05:36 +0100 Subject: net: phy: fix sign type error in genphy_config_eee_advert In genphy_config_eee_advert, the return value of phy_read_mmd_indirect is checked to know if the register could be accessed but the result is assigned to a 'u32'. Changing to 'int' to correctly get errors from phy_read_mmd_indirect. Fixes: d853d145ea3e ("net: phy: add an option to disable EEE advertisement") Reported-by: Julia Lawall Signed-off-by: Jerome Brunet Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 9c06f8028f0c..ee5ebadb1463 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1187,8 +1187,8 @@ static int genphy_config_advert(struct phy_device *phydev) */ static int genphy_config_eee_advert(struct phy_device *phydev) { - u32 broken = phydev->eee_broken_modes; - u32 old_adv, adv; + int broken = phydev->eee_broken_modes; + int old_adv, adv; /* Nothing to disable */ if (!broken) -- cgit v1.2.3 From 57f3986231bb2c69a55ccab1d2b30a00818027ac Mon Sep 17 00:00:00 2001 From: jbrunet Date: Mon, 19 Dec 2016 16:05:37 +0100 Subject: net: phy: use boolean dt properties for eee broken modes The patches regarding eee-broken-modes was merged before all people involved could find an agreement on the best way to move forward. While we agreed on having a DT property to mark particular modes as broken, the value used for eee-broken-modes mapped the phy register in very direct way. Because of this, the concern is that it could be used to implement configuration policies instead of describing a broken HW. In the end, having a boolean property for each mode seems to be preferred over one bit field value mapping the register (too) directly. Cc: Florian Fainelli Signed-off-by: Jerome Brunet Signed-off-by: David S. Miller --- drivers/net/phy/phy_device.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index ee5ebadb1463..92b08383cafa 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -1665,7 +1665,7 @@ static void of_set_phy_supported(struct phy_device *phydev) static void of_set_phy_eee_broken(struct phy_device *phydev) { struct device_node *node = phydev->mdio.dev.of_node; - u32 broken; + u32 broken = 0; if (!IS_ENABLED(CONFIG_OF_MDIO)) return; @@ -1673,8 +1673,20 @@ static void of_set_phy_eee_broken(struct phy_device *phydev) if (!node) return; - if (!of_property_read_u32(node, "eee-broken-modes", &broken)) - phydev->eee_broken_modes = broken; + if (of_property_read_bool(node, "eee-broken-100tx")) + broken |= MDIO_EEE_100TX; + if (of_property_read_bool(node, "eee-broken-1000t")) + broken |= MDIO_EEE_1000T; + if (of_property_read_bool(node, "eee-broken-10gt")) + broken |= MDIO_EEE_10GT; + if (of_property_read_bool(node, "eee-broken-1000kx")) + broken |= MDIO_EEE_1000KX; + if (of_property_read_bool(node, "eee-broken-10gkx4")) + broken |= MDIO_EEE_10GKX4; + if (of_property_read_bool(node, "eee-broken-10gkr")) + broken |= MDIO_EEE_10GKR; + + phydev->eee_broken_modes = broken; } /** -- cgit v1.2.3 From 606987b04e6c0dd8027ea331f2eeae35a5f4413c Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Mon, 19 Dec 2016 22:42:43 +0200 Subject: fsl/fman: fix 1G support for QSGMII interfaces QSGMII ports were not advertising 1G speed. Signed-off-by: Madalin Bucur Reviewed-by: Camelia Groza Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/mac.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fman/mac.c b/drivers/net/ethernet/freescale/fman/mac.c index 69ca42ce5dd5..0b31f8502ada 100644 --- a/drivers/net/ethernet/freescale/fman/mac.c +++ b/drivers/net/ethernet/freescale/fman/mac.c @@ -594,6 +594,7 @@ static const u16 phy2speed[] = { [PHY_INTERFACE_MODE_RGMII_RXID] = SPEED_1000, [PHY_INTERFACE_MODE_RGMII_TXID] = SPEED_1000, [PHY_INTERFACE_MODE_RTBI] = SPEED_1000, + [PHY_INTERFACE_MODE_QSGMII] = SPEED_1000, [PHY_INTERFACE_MODE_XGMII] = SPEED_10000 }; -- cgit v1.2.3 From ae6021d4fc2bcc9e3193a007b2c9d31392ac641b Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Mon, 19 Dec 2016 22:42:44 +0200 Subject: powerpc: fsl/fman: remove fsl,fman from of_device_ids[] The fsl/fman drivers will use of_platform_populate() on all supported platforms. Call of_platform_populate() to probe the FMan sub-nodes. Signed-off-by: Igal Liberman Signed-off-by: Madalin Bucur Acked-by: Scott Wood Signed-off-by: David S. Miller --- arch/powerpc/platforms/85xx/corenet_generic.c | 3 --- drivers/net/ethernet/freescale/fman/fman.c | 7 +++++++ 2 files changed, 7 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/arch/powerpc/platforms/85xx/corenet_generic.c b/arch/powerpc/platforms/85xx/corenet_generic.c index 3803b0addf65..6c0ba75fb256 100644 --- a/arch/powerpc/platforms/85xx/corenet_generic.c +++ b/arch/powerpc/platforms/85xx/corenet_generic.c @@ -117,9 +117,6 @@ static const struct of_device_id of_device_ids[] = { { .compatible = "fsl,qe", }, - { - .compatible = "fsl,fman", - }, /* The following two are for the Freescale hypervisor */ { .name = "hypervisor", diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index dafd9e1baba2..4b832633a1c0 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -2868,6 +2868,13 @@ static struct fman *read_dts_node(struct platform_device *of_dev) fman->dev = &of_dev->dev; + err = of_platform_populate(fm_node, NULL, NULL, &of_dev->dev); + if (err) { + dev_err(&of_dev->dev, "%s: of_platform_populate() failed\n", + __func__); + goto fman_free; + } + return fman; fman_node_put: -- cgit v1.2.3 From 1e33099540b1e13d0e9674bc97c15d3fac050f6f Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Mon, 19 Dec 2016 22:42:45 +0200 Subject: fsl/fman: A007273 only applies to PPC SoCs Signed-off-by: Madalin Bucur Reviewed-by: Camelia Groza Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/fman.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fman/fman.c b/drivers/net/ethernet/freescale/fman/fman.c index 4b832633a1c0..f60845f0c6ca 100644 --- a/drivers/net/ethernet/freescale/fman/fman.c +++ b/drivers/net/ethernet/freescale/fman/fman.c @@ -1890,6 +1890,7 @@ static int fman_reset(struct fman *fman) goto _return; } else { +#ifdef CONFIG_PPC struct device_node *guts_node; struct ccsr_guts __iomem *guts_regs; u32 devdisr2, reg; @@ -1921,6 +1922,7 @@ static int fman_reset(struct fman *fman) /* Enable all MACs */ iowrite32be(reg, &guts_regs->devdisr2); +#endif /* Perform FMan reset */ iowrite32be(FPM_RSTC_FM_RESET, &fman->fpm_regs->fm_rstc); @@ -1932,25 +1934,31 @@ static int fman_reset(struct fman *fman) } while (((ioread32be(&fman->fpm_regs->fm_rstc)) & FPM_RSTC_FM_RESET) && --count); if (count == 0) { +#ifdef CONFIG_PPC iounmap(guts_regs); of_node_put(guts_node); +#endif err = -EBUSY; goto _return; } +#ifdef CONFIG_PPC /* Restore devdisr2 value */ iowrite32be(devdisr2, &guts_regs->devdisr2); iounmap(guts_regs); of_node_put(guts_node); +#endif goto _return; +#ifdef CONFIG_PPC guts_regs: of_node_put(guts_node); guts_node: dev_dbg(fman->dev, "%s: Didn't perform FManV3 reset due to Errata A007273!\n", __func__); +#endif } _return: return err; -- cgit v1.2.3 From 2e3db5a4b9ee704f841d6356a32428830c7079e6 Mon Sep 17 00:00:00 2001 From: Madalin Bucur Date: Mon, 19 Dec 2016 22:42:46 +0200 Subject: fsl/fman: enable compilation on ARM64 Signed-off-by: Madalin Bucur Signed-off-by: David S. Miller --- drivers/net/ethernet/freescale/fman/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/freescale/fman/Kconfig b/drivers/net/ethernet/freescale/fman/Kconfig index 79b7c84b7869..dc0850b3b517 100644 --- a/drivers/net/ethernet/freescale/fman/Kconfig +++ b/drivers/net/ethernet/freescale/fman/Kconfig @@ -1,6 +1,6 @@ config FSL_FMAN tristate "FMan support" - depends on FSL_SOC || COMPILE_TEST + depends on FSL_SOC || ARCH_LAYERSCAPE || COMPILE_TEST select GENERIC_ALLOCATOR select PHYLIB default n -- cgit v1.2.3 From e9838ef2d6f3f3ccb058514d4ac03a6f6155ecc2 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Mon, 19 Dec 2016 17:55:56 -0500 Subject: net: netcp: ethss: fix errors in ethtool ops In ethtool ops, it needs to retrieve the corresponding ethss module (gbe or xgbe) from the net_device structure. Prior to this patch, the retrieving procedure only checks for the gbe module. This patch fixes the issue by checking the xgbe module if the net_device structure does not correspond to the gbe module. Signed-off-by: WingMan Kwok Signed-off-by: Murali Karicheri Signed-off-by: Sekhar Nori Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index c7e547e4f2b1..a31931cdac53 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -1746,6 +1746,17 @@ static void keystone_set_msglevel(struct net_device *ndev, u32 value) netcp->msg_enable = value; } +static struct gbe_intf *keystone_get_intf_data(struct netcp_intf *netcp) +{ + struct gbe_intf *gbe_intf; + + gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + if (!gbe_intf) + gbe_intf = netcp_module_get_intf_data(&xgbe_module, netcp); + + return gbe_intf; +} + static void keystone_get_stat_strings(struct net_device *ndev, uint32_t stringset, uint8_t *data) { @@ -1754,7 +1765,7 @@ static void keystone_get_stat_strings(struct net_device *ndev, struct gbe_priv *gbe_dev; int i; - gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + gbe_intf = keystone_get_intf_data(netcp); if (!gbe_intf) return; gbe_dev = gbe_intf->gbe_dev; @@ -1778,7 +1789,7 @@ static int keystone_get_sset_count(struct net_device *ndev, int stringset) struct gbe_intf *gbe_intf; struct gbe_priv *gbe_dev; - gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + gbe_intf = keystone_get_intf_data(netcp); if (!gbe_intf) return -EINVAL; gbe_dev = gbe_intf->gbe_dev; @@ -1896,7 +1907,7 @@ static void keystone_get_ethtool_stats(struct net_device *ndev, struct gbe_intf *gbe_intf; struct gbe_priv *gbe_dev; - gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + gbe_intf = keystone_get_intf_data(netcp); if (!gbe_intf) return; @@ -1920,7 +1931,7 @@ static int keystone_get_link_ksettings(struct net_device *ndev, if (!phy) return -EINVAL; - gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + gbe_intf = keystone_get_intf_data(netcp); if (!gbe_intf) return -EINVAL; @@ -1953,7 +1964,7 @@ static int keystone_set_link_ksettings(struct net_device *ndev, if (!phy) return -EINVAL; - gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp); + gbe_intf = keystone_get_intf_data(netcp); if (!gbe_intf) return -EINVAL; -- cgit v1.2.3 From 4c0ef2319a6cc3506db2a546b9e6294ec635eb90 Mon Sep 17 00:00:00 2001 From: WingMan Kwok Date: Mon, 19 Dec 2016 17:55:57 -0500 Subject: net: netcp: ethss: fix 10gbe host port tx pri map configuration This patch adds the missing 10gbe host port tx priority map configurations. Signed-off-by: WingMan Kwok Signed-off-by: Murali Karicheri Signed-off-by: Sekhar Nori Signed-off-by: David S. Miller --- drivers/net/ethernet/ti/netcp_ethss.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c index a31931cdac53..7d9e36f66735 100644 --- a/drivers/net/ethernet/ti/netcp_ethss.c +++ b/drivers/net/ethernet/ti/netcp_ethss.c @@ -94,6 +94,7 @@ /* offset relative to base of XGBE_SS_REG_INDEX */ #define XGBE10_SGMII_MODULE_OFFSET 0x100 +#define IS_SS_ID_XGBE(d) ((d)->ss_version == XGBE_SS_VERSION_10) /* offset relative to base of XGBE_SM_REG_INDEX */ #define XGBE10_HOST_PORT_OFFSET 0x34 #define XGBE10_SLAVE_PORT_OFFSET 0x64 @@ -2322,7 +2323,7 @@ static void gbe_init_host_port(struct gbe_priv *priv) int bypass_en = 1; /* Host Tx Pri */ - if (IS_SS_ID_NU(priv)) + if (IS_SS_ID_NU(priv) || IS_SS_ID_XGBE(priv)) writel(HOST_TX_PRI_MAP_DEFAULT, GBE_REG_ADDR(priv, host_port_regs, tx_pri_map)); -- cgit v1.2.3 From f7ca8e3b945366259e82ed50961809ad4262933f Mon Sep 17 00:00:00 2001 From: Dongpo Li Date: Tue, 20 Dec 2016 10:09:28 +0800 Subject: net: hix5hd2_gmac: fix compatible strings name The SoC hix5hd2 compatible string has the suffix "-gmac" and we should not change its compatible string. So we should name all the compatible string with the suffix "-gmac". Creating a new name suffix "-gemac" is unnecessary. We also add another SoC compatible string in dt binding documentation and describe which generic version the SoC belongs to. Fixes: d0fb6ba75dc0 ("net: hix5hd2_gmac: add generic compatible string") Signed-off-by: Dongpo Li Signed-off-by: David S. Miller --- .../devicetree/bindings/net/hisilicon-hix5hd2-gmac.txt | 13 ++++++++----- drivers/net/ethernet/hisilicon/hix5hd2_gmac.c | 13 +++++++------ 2 files changed, 15 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/Documentation/devicetree/bindings/net/hisilicon-hix5hd2-gmac.txt b/Documentation/devicetree/bindings/net/hisilicon-hix5hd2-gmac.txt index 063c02da018a..eea73adc678f 100644 --- a/Documentation/devicetree/bindings/net/hisilicon-hix5hd2-gmac.txt +++ b/Documentation/devicetree/bindings/net/hisilicon-hix5hd2-gmac.txt @@ -2,11 +2,14 @@ Hisilicon hix5hd2 gmac controller Required properties: - compatible: should contain one of the following SoC strings: - * "hisilicon,hix5hd2-gemac" - * "hisilicon,hi3798cv200-gemac" + * "hisilicon,hix5hd2-gmac" + * "hisilicon,hi3798cv200-gmac" + * "hisilicon,hi3516a-gmac" and one of the following version string: - * "hisilicon,hisi-gemac-v1" - * "hisilicon,hisi-gemac-v2" + * "hisilicon,hisi-gmac-v1" + * "hisilicon,hisi-gmac-v2" + The version v1 includes SoCs hix5hd2. + The version v2 includes SoCs hi3798cv200, hi3516a. - reg: specifies base physical address(s) and size of the device registers. The first region is the MAC register base and size. The second region is external interface control register. @@ -35,7 +38,7 @@ Required properties: Example: gmac0: ethernet@f9840000 { - compatible = "hisilicon,hi3798cv200-gemac", "hisilicon,hisi-gemac-v2"; + compatible = "hisilicon,hi3798cv200-gmac", "hisilicon,hisi-gmac-v2"; reg = <0xf9840000 0x1000>,<0xf984300c 0x4>; interrupts = <0 71 4>; #address-cells = <1>; diff --git a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c index ee7e9ce2f5b3..418ca1f3774a 100644 --- a/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c +++ b/drivers/net/ethernet/hisilicon/hix5hd2_gmac.c @@ -1316,10 +1316,11 @@ static int hix5hd2_dev_remove(struct platform_device *pdev) } static const struct of_device_id hix5hd2_of_match[] = { - { .compatible = "hisilicon,hisi-gemac-v1", .data = (void *)GEMAC_V1 }, - { .compatible = "hisilicon,hisi-gemac-v2", .data = (void *)GEMAC_V2 }, - { .compatible = "hisilicon,hix5hd2-gemac", .data = (void *)GEMAC_V1 }, - { .compatible = "hisilicon,hi3798cv200-gemac", .data = (void *)GEMAC_V2 }, + { .compatible = "hisilicon,hisi-gmac-v1", .data = (void *)GEMAC_V1 }, + { .compatible = "hisilicon,hisi-gmac-v2", .data = (void *)GEMAC_V2 }, + { .compatible = "hisilicon,hix5hd2-gmac", .data = (void *)GEMAC_V1 }, + { .compatible = "hisilicon,hi3798cv200-gmac", .data = (void *)GEMAC_V2 }, + { .compatible = "hisilicon,hi3516a-gmac", .data = (void *)GEMAC_V2 }, {}, }; @@ -1327,7 +1328,7 @@ MODULE_DEVICE_TABLE(of, hix5hd2_of_match); static struct platform_driver hix5hd2_dev_driver = { .driver = { - .name = "hisi-gemac", + .name = "hisi-gmac", .of_match_table = hix5hd2_of_match, }, .probe = hix5hd2_dev_probe, @@ -1338,4 +1339,4 @@ module_platform_driver(hix5hd2_dev_driver); MODULE_DESCRIPTION("HISILICON Gigabit Ethernet MAC driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:hisi-gemac"); +MODULE_ALIAS("platform:hisi-gmac"); -- cgit v1.2.3 From ae99b639ce79f73fe4d1c44da8aa2d96b0f13253 Mon Sep 17 00:00:00 2001 From: Tobias Klauser Date: Tue, 20 Dec 2016 14:38:26 +0100 Subject: ethernet: sfc: Add Kconfig entry for vendor Solarflare Since commit 5a6681e22c14 ("sfc: separate out SFC4000 ("Falcon") support into new sfc-falcon driver") there are two drivers for Solarflare devices, but both still show up directly beneath "Ethernet driver support" in the Kconfig. Follow the pattern of other vendors and group them beneath an own vendor Kconfig entry for Solarflare. Cc: Edward Cree Signed-off-by: Tobias Klauser Acked-by: Edward Cree Signed-off-by: David S. Miller --- drivers/net/ethernet/Kconfig | 1 - drivers/net/ethernet/sfc/Kconfig | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 6e16e441f85e..e4c28fed61d5 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -166,7 +166,6 @@ source "drivers/net/ethernet/seeq/Kconfig" source "drivers/net/ethernet/silan/Kconfig" source "drivers/net/ethernet/sis/Kconfig" source "drivers/net/ethernet/sfc/Kconfig" -source "drivers/net/ethernet/sfc/falcon/Kconfig" source "drivers/net/ethernet/sgi/Kconfig" source "drivers/net/ethernet/smsc/Kconfig" source "drivers/net/ethernet/stmicro/Kconfig" diff --git a/drivers/net/ethernet/sfc/Kconfig b/drivers/net/ethernet/sfc/Kconfig index 46f7be85f5a3..2c032629c369 100644 --- a/drivers/net/ethernet/sfc/Kconfig +++ b/drivers/net/ethernet/sfc/Kconfig @@ -1,3 +1,20 @@ +# +# Solarflare device configuration +# + +config NET_VENDOR_SOLARFLARE + bool "Solarflare devices" + default y + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y. + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Solarflare devices. If you say Y, you will be asked + for your specific card in the following questions. + +if NET_VENDOR_SOLARFLARE + config SFC tristate "Solarflare SFC9000/SFC9100-family support" depends on PCI @@ -44,3 +61,7 @@ config SFC_MCDI_LOGGING Driver-Interface) commands and responses, allowing debugging of driver/firmware interaction. The tracing is actually enabled by a sysfs file 'mcdi_logging' under the PCI device. + +source "drivers/net/ethernet/sfc/falcon/Kconfig" + +endif # NET_VENDOR_SOLARFLARE -- cgit v1.2.3 From f7fb138389aac97fe165c9b8fe4dcfeb97a78d06 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 20 Dec 2016 22:02:14 +0800 Subject: net/mlx5: use rb_entry() To make the code clearer, use rb_entry() instead of container_of() to deal with rbtree. Signed-off-by: Geliang Tang Acked-by: Leon Romanovsky Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c index 3b026c151cf2..7431f633de31 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c @@ -75,7 +75,7 @@ static void mlx5_fc_stats_insert(struct rb_root *root, struct mlx5_fc *counter) struct rb_node *parent = NULL; while (*new) { - struct mlx5_fc *this = container_of(*new, struct mlx5_fc, node); + struct mlx5_fc *this = rb_entry(*new, struct mlx5_fc, node); int result = counter->id - this->id; parent = *new; -- cgit v1.2.3 From 7dbbf0fa1bf14c17900bb8057986b06db3822239 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 22 Nov 2016 16:17:50 -0800 Subject: scsi: scsi-mq: Wait for .queue_rq() if necessary Ensure that if scsi-mq is enabled that scsi_internal_device_block() waits until ongoing shost->hostt->queuecommand() calls have finished. Signed-off-by: Bart Van Assche Reviewed-by: Sagi Grimberg Reviewed-by: Martin K. Petersen Cc: James Bottomley Cc: Christoph Hellwig Cc: Doug Ledford Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index c35b6de4ca64..9fd9a977c695 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -2893,7 +2893,7 @@ scsi_internal_device_block(struct scsi_device *sdev) * request queue. */ if (q->mq_ops) { - blk_mq_stop_hw_queues(q); + blk_mq_quiesce_queue(q); } else { spin_lock_irqsave(q->queue_lock, flags); blk_stop_queue(q); -- cgit v1.2.3 From 7961d53d22375bb9e8ae8063533b9059102ed39d Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 20 Dec 2016 08:43:30 -0800 Subject: scsi: qedi: fix build, depends on UIO Fix build of SCSI qedi driver. It uses uio interfaces so it should depend on UIO. ERROR: "uio_unregister_device" [drivers/scsi/qedi/qedi.ko] undefined! ERROR: "uio_event_notify" [drivers/scsi/qedi/qedi.ko] undefined! ERROR: "__uio_register_device" [drivers/scsi/qedi/qedi.ko] undefined! Signed-off-by: Randy Dunlap Cc: QLogic-Storage-Upstream@cavium.com Signed-off-by: Martin K. Petersen --- drivers/scsi/qedi/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/scsi/qedi/Kconfig b/drivers/scsi/qedi/Kconfig index 23ca8a274586..21331453db7b 100644 --- a/drivers/scsi/qedi/Kconfig +++ b/drivers/scsi/qedi/Kconfig @@ -1,6 +1,6 @@ config QEDI tristate "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver Support" - depends on PCI && SCSI + depends on PCI && SCSI && UIO depends on QED select SCSI_ISCSI_ATTRS select QED_LL2 -- cgit v1.2.3 From 7c0a705e0326a7eed2149eb0b7b30e23897becda Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Wed, 14 Dec 2016 14:35:49 +0800 Subject: drm/amdgpu: update golden setting/tiling table of tahiti Signed-off-by: Flora Cui Reviewed-by: Hawking Zhang Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 344 +++++++++++++++++++--------------- drivers/gpu/drm/amd/amdgpu/si.c | 38 ++-- 2 files changed, 221 insertions(+), 161 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 558640aee15a..aa4472343901 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -656,239 +656,291 @@ static void gfx_v6_0_tiling_mode_table_init(struct amdgpu_device *adev) } else if ((adev->asic_type == CHIP_TAHITI) || (adev->asic_type == CHIP_PITCAIRN)) { for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { switch (reg_offset) { - case 0: /* non-AA compressed depth or any compressed stencil */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + case 0: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 1: /* 2xAA/4xAA compressed depth only */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + case 1: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 2: /* 8xAA compressed depth only */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + case 2: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 3: /* 2xAA/4xAA compressed depth with stencil (for depth buffer) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + case 3: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK) | + TILE_SPLIT(split_equal_to_row_size)); break; - case 4: /* Maps w/ a dimension less than the 2D macro-tile dimensions (for mipmapped depth textures) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + case 4: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16)); break; - case 5: /* Uncompressed 16bpp depth - and stencil buffer allocated with it */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + case 5: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); break; - case 6: /* Uncompressed 32bpp depth - and stencil buffer allocated with it */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + case 6: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); break; - case 7: /* Uncompressed 8bpp stencil without depth (drivers typically do not use) */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | + case 7: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); break; - case 8: /* 1D and 1D Array Surfaces */ - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + case 8: + gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED)); break; - case 9: /* Displayable maps. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + case 9: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16)); break; - case 10: /* Display 8bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + case 10: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 11: /* Display 16bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + case 11: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 12: /* Display 32bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + case 12: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 13: /* Thin. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + case 13: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16)); break; - case 14: /* Thin 8 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 14: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 15: /* Thin 16 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 15: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 16: /* Thin 32 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 16: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; - case 17: /* Thin 64 bpp. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 17: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(split_equal_to_row_size) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); + break; + case 18: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16)); + break; + case 19: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_XTHICK) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); break; - case 21: /* 8 bpp PRT. */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 20: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THICK) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + TILE_SPLIT(split_equal_to_row_size)); break; - case 22: /* 16 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 21: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 22: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); break; - case 23: /* 32 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 23: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_8) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); break; - case 24: /* 64 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + case 24: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); break; - case 25: /* 128 bpp PRT */ - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + case 25: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | - NUM_BANKS(ADDR_SURF_8_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); break; - default: - gb_tile_moden = 0; + case 26: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 27: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); break; + case 28: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 29: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 30: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + default: + continue; } adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden; WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden); diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 3ed8ad8725b9..243987502f7e 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -43,13 +43,14 @@ static const u32 tahiti_golden_registers[] = { + 0x17bc, 0x00000030, 0x00000011, 0x2684, 0x00010000, 0x00018208, 0x260c, 0xffffffff, 0x00000000, 0x260d, 0xf00fffff, 0x00000400, 0x260e, 0x0002021c, 0x00020200, 0x031e, 0x00000080, 0x00000000, - 0x340c, 0x000300c0, 0x00800040, - 0x360c, 0x000300c0, 0x00800040, + 0x340c, 0x000000c0, 0x00800040, + 0x360c, 0x000000c0, 0x00800040, 0x16ec, 0x000000f0, 0x00000070, 0x16f0, 0x00200000, 0x50100000, 0x1c0c, 0x31000311, 0x00000011, @@ -60,7 +61,7 @@ static const u32 tahiti_golden_registers[] = 0x22c4, 0x0000ff0f, 0x00000000, 0xa293, 0x07ffffff, 0x4e000000, 0xa0d4, 0x3f3f3fff, 0x2a00126a, - 0x000c, 0x000000ff, 0x0040, + 0x000c, 0xffffffff, 0x0040, 0x000d, 0x00000040, 0x00004040, 0x2440, 0x07ffffff, 0x03000000, 0x23a2, 0x01ff1f3f, 0x00000000, @@ -73,7 +74,11 @@ static const u32 tahiti_golden_registers[] = 0x2234, 0xffffffff, 0x000fff40, 0x2235, 0x0000001f, 0x00000010, 0x0504, 0x20000000, 0x20fffed8, - 0x0570, 0x000c0fc0, 0x000c0400 + 0x0570, 0x000c0fc0, 0x000c0400, + 0x052c, 0x0fffffff, 0xffffffff, + 0x052d, 0x0fffffff, 0x0fffffff, + 0x052e, 0x0fffffff, 0x0fffffff, + 0x052f, 0x0fffffff, 0x0fffffff }; static const u32 tahiti_golden_registers2[] = @@ -83,12 +88,13 @@ static const u32 tahiti_golden_registers2[] = static const u32 tahiti_golden_rlc_registers[] = { + 0x263e, 0xffffffff, 0x12011003, 0x3109, 0xffffffff, 0x00601005, 0x311f, 0xffffffff, 0x10104040, 0x3122, 0xffffffff, 0x0100000a, 0x30c5, 0xffffffff, 0x00000800, 0x30c3, 0xffffffff, 0x800000f4, - 0x3d2a, 0xffffffff, 0x00000000 + 0x3d2a, 0x00000008, 0x00000000 }; static const u32 pitcairn_golden_registers[] = @@ -513,18 +519,18 @@ static const u32 tahiti_mgcg_cgcg_init[] = 0x21c2, 0xffffffff, 0x00900100, 0x311e, 0xffffffff, 0x00000080, 0x3101, 0xffffffff, 0x0020003f, - 0xc, 0xffffffff, 0x0000001c, - 0xd, 0x000f0000, 0x000f0000, - 0x583, 0xffffffff, 0x00000100, - 0x409, 0xffffffff, 0x00000100, - 0x40b, 0x00000101, 0x00000000, - 0x82a, 0xffffffff, 0x00000104, - 0x993, 0x000c0000, 0x000c0000, - 0x992, 0x000c0000, 0x000c0000, + 0x000c, 0xffffffff, 0x0000001c, + 0x000d, 0x000f0000, 0x000f0000, + 0x0583, 0xffffffff, 0x00000100, + 0x0409, 0xffffffff, 0x00000100, + 0x040b, 0x00000101, 0x00000000, + 0x082a, 0xffffffff, 0x00000104, + 0x0993, 0x000c0000, 0x000c0000, + 0x0992, 0x000c0000, 0x000c0000, 0x1579, 0xff000fff, 0x00000100, 0x157a, 0x00000001, 0x00000001, - 0xbd4, 0x00000001, 0x00000001, - 0xc33, 0xc0000fff, 0x00000104, + 0x0bd4, 0x00000001, 0x00000001, + 0x0c33, 0xc0000fff, 0x00000104, 0x3079, 0x00000001, 0x00000001, 0x3430, 0xfffffff0, 0x00000100, 0x3630, 0xfffffff0, 0x00000100 @@ -1179,6 +1185,8 @@ static int si_common_early_init(void *handle) AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_MGCG; adev->pg_flags = 0; + adev->external_rev_id = (adev->rev_id == 0) ? 1 : + (adev->rev_id == 1) ? 5 : 6; break; case CHIP_PITCAIRN: adev->cg_flags = -- cgit v1.2.3 From 1245a694617ebc39342f12d55ed3e6561fcb9f4a Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 15:29:38 +0800 Subject: drm/amdgpu: update golden setting for pitcairn Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 243987502f7e..19b511e984dc 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -99,6 +99,7 @@ static const u32 tahiti_golden_rlc_registers[] = static const u32 pitcairn_golden_registers[] = { + 0x17bc, 0x00000030, 0x00000011, 0x2684, 0x00010000, 0x00018208, 0x260c, 0xffffffff, 0x00000000, 0x260d, 0xf00fffff, 0x00000400, @@ -116,7 +117,7 @@ static const u32 pitcairn_golden_registers[] = 0x22c4, 0x0000ff0f, 0x00000000, 0xa293, 0x07ffffff, 0x4e000000, 0xa0d4, 0x3f3f3fff, 0x2a00126a, - 0x000c, 0x000000ff, 0x0040, + 0x000c, 0xffffffff, 0x0040, 0x000d, 0x00000040, 0x00004040, 0x2440, 0x07ffffff, 0x03000000, 0x2418, 0x0000007f, 0x00000020, @@ -125,11 +126,16 @@ static const u32 pitcairn_golden_registers[] = 0x2b04, 0xffffffff, 0x00000000, 0x2b03, 0xffffffff, 0x32761054, 0x2235, 0x0000001f, 0x00000010, - 0x0570, 0x000c0fc0, 0x000c0400 + 0x0570, 0x000c0fc0, 0x000c0400, + 0x052c, 0x0fffffff, 0xffffffff, + 0x052d, 0x0fffffff, 0x0fffffff, + 0x052e, 0x0fffffff, 0x0fffffff, + 0x052f, 0x0fffffff, 0x0fffffff }; static const u32 pitcairn_golden_rlc_registers[] = { + 0x263e, 0xffffffff, 0x12011003, 0x3109, 0xffffffff, 0x00601004, 0x311f, 0xffffffff, 0x10102020, 0x3122, 0xffffffff, 0x01000020, @@ -618,16 +624,16 @@ static const u32 pitcairn_mgcg_cgcg_init[] = 0x21c2, 0xffffffff, 0x00900100, 0x311e, 0xffffffff, 0x00000080, 0x3101, 0xffffffff, 0x0020003f, - 0xc, 0xffffffff, 0x0000001c, - 0xd, 0x000f0000, 0x000f0000, - 0x583, 0xffffffff, 0x00000100, - 0x409, 0xffffffff, 0x00000100, - 0x40b, 0x00000101, 0x00000000, - 0x82a, 0xffffffff, 0x00000104, + 0x000c, 0xffffffff, 0x0000001c, + 0x000d, 0x000f0000, 0x000f0000, + 0x0583, 0xffffffff, 0x00000100, + 0x0409, 0xffffffff, 0x00000100, + 0x040b, 0x00000101, 0x00000000, + 0x082a, 0xffffffff, 0x00000104, 0x1579, 0xff000fff, 0x00000100, 0x157a, 0x00000001, 0x00000001, - 0xbd4, 0x00000001, 0x00000001, - 0xc33, 0xc0000fff, 0x00000104, + 0x0bd4, 0x00000001, 0x00000001, + 0x0c33, 0xc0000fff, 0x00000104, 0x3079, 0x00000001, 0x00000001, 0x3430, 0xfffffff0, 0x00000100, 0x3630, 0xfffffff0, 0x00000100 -- cgit v1.2.3 From e285a9a64d64e65a10e97c6ae1e9385c9595b563 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 15:29:54 +0800 Subject: drm/amdgpu: update rev id for pitcairn Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 19b511e984dc..cf8a0a104875 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1212,6 +1212,7 @@ static int si_common_early_init(void *handle) AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_MGCG; adev->pg_flags = 0; + adev->external_rev_id = adev->rev_id + 20; break; case CHIP_VERDE: -- cgit v1.2.3 From bd27b678c26ea9f6d6efdbea139f38fba426aaac Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 14:58:12 +0800 Subject: drm/amdgpu: update golden setting for hainan Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index cf8a0a104875..49e0fee28053 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -380,22 +380,27 @@ static const u32 oland_golden_rlc_registers[] = static const u32 hainan_golden_registers[] = { + 0x17bc, 0x00000030, 0x00000011, 0x2684, 0x00010000, 0x00018208, 0x260c, 0xffffffff, 0x00000000, 0x260d, 0xf00fffff, 0x00000400, 0x260e, 0x0002021c, 0x00020200, - 0x4595, 0xff000fff, 0x00000100, + 0x031e, 0x00000080, 0x00000000, + 0x3430, 0xff000fff, 0x00000100, 0x340c, 0x000300c0, 0x00800040, 0x3630, 0xff000fff, 0x00000100, 0x360c, 0x000300c0, 0x00800040, + 0x16ec, 0x000000f0, 0x00000070, + 0x16f0, 0x00200000, 0x50100000, + 0x1c0c, 0x31000311, 0x00000011, 0x0ab9, 0x00073ffe, 0x000022a2, 0x0903, 0x000007ff, 0x00000000, 0x2285, 0xf000001f, 0x00000007, 0x22c9, 0xffffffff, 0x00ffffff, 0x22c4, 0x0000ff0f, 0x00000000, - 0xa393, 0x07ffffff, 0x4e000000, + 0xa293, 0x07ffffff, 0x4e000000, 0xa0d4, 0x3f3f3fff, 0x00000000, - 0x000c, 0x000000ff, 0x0040, + 0x000c, 0xffffffff, 0x0040, 0x000d, 0x00000040, 0x00004040, 0x2440, 0x03e00000, 0x03600000, 0x2418, 0x0000007f, 0x00000020, @@ -404,12 +409,16 @@ static const u32 hainan_golden_registers[] = 0x2b04, 0xffffffff, 0x00000000, 0x2b03, 0xffffffff, 0x00003210, 0x2235, 0x0000001f, 0x00000010, - 0x0570, 0x000c0fc0, 0x000c0400 + 0x0570, 0x000c0fc0, 0x000c0400, + 0x052c, 0x0fffffff, 0xffffffff, + 0x052d, 0x0fffffff, 0x0fffffff, + 0x052e, 0x0fffffff, 0x0fffffff, + 0x052f, 0x0fffffff, 0x0fffffff }; static const u32 hainan_golden_registers2[] = { - 0x263e, 0xffffffff, 0x02010001 + 0x263e, 0xffffffff, 0x2011003 }; static const u32 tahiti_mgcg_cgcg_init[] = @@ -879,15 +888,15 @@ static const u32 hainan_mgcg_cgcg_init[] = 0x21c2, 0xffffffff, 0x00900100, 0x311e, 0xffffffff, 0x00000080, 0x3101, 0xffffffff, 0x0020003f, - 0xc, 0xffffffff, 0x0000001c, - 0xd, 0x000f0000, 0x000f0000, - 0x583, 0xffffffff, 0x00000100, - 0x409, 0xffffffff, 0x00000100, - 0x82a, 0xffffffff, 0x00000104, - 0x993, 0x000c0000, 0x000c0000, - 0x992, 0x000c0000, 0x000c0000, - 0xbd4, 0x00000001, 0x00000001, - 0xc33, 0xc0000fff, 0x00000104, + 0x000c, 0xffffffff, 0x0000001c, + 0x000d, 0x000f0000, 0x000f0000, + 0x0583, 0xffffffff, 0x00000100, + 0x0409, 0xffffffff, 0x00000100, + 0x082a, 0xffffffff, 0x00000104, + 0x0993, 0x000c0000, 0x000c0000, + 0x0992, 0x000c0000, 0x000c0000, + 0x0bd4, 0x00000001, 0x00000001, + 0x0c33, 0xc0000fff, 0x00000104, 0x3079, 0x00000001, 0x00000001, 0x3430, 0xfffffff0, 0x00000100, 0x3630, 0xfffffff0, 0x00000100 -- cgit v1.2.3 From 05319478dad476841282a0eab66a00da425e0914 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 14:58:28 +0800 Subject: drm/amdgpu: update rev id for hainan Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 49e0fee28053..232ee8909d38 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1279,6 +1279,7 @@ static int si_common_early_init(void *handle) AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_MGCG; adev->pg_flags = 0; + adev->external_rev_id = 70; break; default: -- cgit v1.2.3 From 6b7985efc3b56dba3a49221464e7ef65688cda76 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 15:03:43 +0800 Subject: drm/amdgpu: update golden setting for oland Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 232ee8909d38..8e2377b7fcf5 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -340,6 +340,7 @@ static const u32 verde_golden_registers[] = static const u32 oland_golden_registers[] = { + 0x17bc, 0x00000030, 0x00000011, 0x2684, 0x00010000, 0x00018208, 0x260c, 0xffffffff, 0x00000000, 0x260d, 0xf00fffff, 0x00000400, @@ -348,7 +349,7 @@ static const u32 oland_golden_registers[] = 0x340c, 0x000300c0, 0x00800040, 0x360c, 0x000300c0, 0x00800040, 0x16ec, 0x000000f0, 0x00000070, - 0x16f9, 0x00200000, 0x50100000, + 0x16f0, 0x00200000, 0x50100000, 0x1c0c, 0x31000311, 0x00000011, 0x0ab9, 0x00073ffe, 0x000022a2, 0x0903, 0x000007ff, 0x00000000, @@ -357,7 +358,7 @@ static const u32 oland_golden_registers[] = 0x22c4, 0x0000ff0f, 0x00000000, 0xa293, 0x07ffffff, 0x4e000000, 0xa0d4, 0x3f3f3fff, 0x00000082, - 0x000c, 0x000000ff, 0x0040, + 0x000c, 0xffffffff, 0x0040, 0x000d, 0x00000040, 0x00004040, 0x2440, 0x07ffffff, 0x03000000, 0x2418, 0x0000007f, 0x00000020, @@ -366,11 +367,16 @@ static const u32 oland_golden_registers[] = 0x2b04, 0xffffffff, 0x00000000, 0x2b03, 0xffffffff, 0x00003210, 0x2235, 0x0000001f, 0x00000010, - 0x0570, 0x000c0fc0, 0x000c0400 + 0x0570, 0x000c0fc0, 0x000c0400, + 0x052c, 0x0fffffff, 0xffffffff, + 0x052d, 0x0fffffff, 0x0fffffff, + 0x052e, 0x0fffffff, 0x0fffffff, + 0x052f, 0x0fffffff, 0x0fffffff }; static const u32 oland_golden_rlc_registers[] = { + 0x263e, 0xffffffff, 0x02010002, 0x3109, 0xffffffff, 0x00601005, 0x311f, 0xffffffff, 0x10104040, 0x3122, 0xffffffff, 0x0100000a, @@ -809,18 +815,18 @@ static const u32 oland_mgcg_cgcg_init[] = 0x21c2, 0xffffffff, 0x00900100, 0x311e, 0xffffffff, 0x00000080, 0x3101, 0xffffffff, 0x0020003f, - 0xc, 0xffffffff, 0x0000001c, - 0xd, 0x000f0000, 0x000f0000, - 0x583, 0xffffffff, 0x00000100, - 0x409, 0xffffffff, 0x00000100, - 0x40b, 0x00000101, 0x00000000, - 0x82a, 0xffffffff, 0x00000104, - 0x993, 0x000c0000, 0x000c0000, - 0x992, 0x000c0000, 0x000c0000, + 0x000c, 0xffffffff, 0x0000001c, + 0x000d, 0x000f0000, 0x000f0000, + 0x0583, 0xffffffff, 0x00000100, + 0x0409, 0xffffffff, 0x00000100, + 0x040b, 0x00000101, 0x00000000, + 0x082a, 0xffffffff, 0x00000104, + 0x0993, 0x000c0000, 0x000c0000, + 0x0992, 0x000c0000, 0x000c0000, 0x1579, 0xff000fff, 0x00000100, 0x157a, 0x00000001, 0x00000001, - 0xbd4, 0x00000001, 0x00000001, - 0xc33, 0xc0000fff, 0x00000104, + 0x0bd4, 0x00000001, 0x00000001, + 0x0c33, 0xc0000fff, 0x00000104, 0x3079, 0x00000001, 0x00000001, 0x3430, 0xfffffff0, 0x00000100, 0x3630, 0xfffffff0, 0x00000100 -- cgit v1.2.3 From 8fd74cb4a0e563b2025b521accc7a5963f60cdb1 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 15:04:39 +0800 Subject: drm/amdgpu: update rev id for oland Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 8e2377b7fcf5..d353af392a71 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1268,6 +1268,7 @@ static int si_common_early_init(void *handle) AMD_CG_SUPPORT_HDP_LS | AMD_CG_SUPPORT_HDP_MGCG; adev->pg_flags = 0; + adev->external_rev_id = 60; break; case CHIP_HAINAN: adev->cg_flags = -- cgit v1.2.3 From dae5c2985da969074df03b9ff5226432be9e3293 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 15:26:22 +0800 Subject: drm/amdgpu: update golden setting for verde Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 304 +++++++++++++++++++--------------------- 1 file changed, 142 insertions(+), 162 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index d353af392a71..2a99a41553b4 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -145,133 +145,134 @@ static const u32 pitcairn_golden_rlc_registers[] = static const u32 verde_pg_init[] = { - 0xd4f, 0xffffffff, 0x40000, - 0xd4e, 0xffffffff, 0x200010ff, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x7007, - 0xd4e, 0xffffffff, 0x300010ff, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x400000, - 0xd4e, 0xffffffff, 0x100010ff, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x120200, - 0xd4e, 0xffffffff, 0x500010ff, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x1e1e16, - 0xd4e, 0xffffffff, 0x600010ff, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x171f1e, - 0xd4e, 0xffffffff, 0x700010ff, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4f, 0xffffffff, 0x0, - 0xd4e, 0xffffffff, 0x9ff, - 0xd40, 0xffffffff, 0x0, - 0xd41, 0xffffffff, 0x10000800, - 0xd41, 0xffffffff, 0xf, - 0xd41, 0xffffffff, 0xf, - 0xd40, 0xffffffff, 0x4, - 0xd41, 0xffffffff, 0x1000051e, - 0xd41, 0xffffffff, 0xffff, - 0xd41, 0xffffffff, 0xffff, - 0xd40, 0xffffffff, 0x8, - 0xd41, 0xffffffff, 0x80500, - 0xd40, 0xffffffff, 0x12, - 0xd41, 0xffffffff, 0x9050c, - 0xd40, 0xffffffff, 0x1d, - 0xd41, 0xffffffff, 0xb052c, - 0xd40, 0xffffffff, 0x2a, - 0xd41, 0xffffffff, 0x1053e, - 0xd40, 0xffffffff, 0x2d, - 0xd41, 0xffffffff, 0x10546, - 0xd40, 0xffffffff, 0x30, - 0xd41, 0xffffffff, 0xa054e, - 0xd40, 0xffffffff, 0x3c, - 0xd41, 0xffffffff, 0x1055f, - 0xd40, 0xffffffff, 0x3f, - 0xd41, 0xffffffff, 0x10567, - 0xd40, 0xffffffff, 0x42, - 0xd41, 0xffffffff, 0x1056f, - 0xd40, 0xffffffff, 0x45, - 0xd41, 0xffffffff, 0x10572, - 0xd40, 0xffffffff, 0x48, - 0xd41, 0xffffffff, 0x20575, - 0xd40, 0xffffffff, 0x4c, - 0xd41, 0xffffffff, 0x190801, - 0xd40, 0xffffffff, 0x67, - 0xd41, 0xffffffff, 0x1082a, - 0xd40, 0xffffffff, 0x6a, - 0xd41, 0xffffffff, 0x1b082d, - 0xd40, 0xffffffff, 0x87, - 0xd41, 0xffffffff, 0x310851, - 0xd40, 0xffffffff, 0xba, - 0xd41, 0xffffffff, 0x891, - 0xd40, 0xffffffff, 0xbc, - 0xd41, 0xffffffff, 0x893, - 0xd40, 0xffffffff, 0xbe, - 0xd41, 0xffffffff, 0x20895, - 0xd40, 0xffffffff, 0xc2, - 0xd41, 0xffffffff, 0x20899, - 0xd40, 0xffffffff, 0xc6, - 0xd41, 0xffffffff, 0x2089d, - 0xd40, 0xffffffff, 0xca, - 0xd41, 0xffffffff, 0x8a1, - 0xd40, 0xffffffff, 0xcc, - 0xd41, 0xffffffff, 0x8a3, - 0xd40, 0xffffffff, 0xce, - 0xd41, 0xffffffff, 0x308a5, - 0xd40, 0xffffffff, 0xd3, - 0xd41, 0xffffffff, 0x6d08cd, - 0xd40, 0xffffffff, 0x142, - 0xd41, 0xffffffff, 0x2000095a, - 0xd41, 0xffffffff, 0x1, - 0xd40, 0xffffffff, 0x144, - 0xd41, 0xffffffff, 0x301f095b, - 0xd40, 0xffffffff, 0x165, - 0xd41, 0xffffffff, 0xc094d, - 0xd40, 0xffffffff, 0x173, - 0xd41, 0xffffffff, 0xf096d, - 0xd40, 0xffffffff, 0x184, - 0xd41, 0xffffffff, 0x15097f, - 0xd40, 0xffffffff, 0x19b, - 0xd41, 0xffffffff, 0xc0998, - 0xd40, 0xffffffff, 0x1a9, - 0xd41, 0xffffffff, 0x409a7, - 0xd40, 0xffffffff, 0x1af, - 0xd41, 0xffffffff, 0xcdc, - 0xd40, 0xffffffff, 0x1b1, - 0xd41, 0xffffffff, 0x800, - 0xd42, 0xffffffff, 0x6c9b2000, - 0xd44, 0xfc00, 0x2000, - 0xd51, 0xffffffff, 0xfc0, - 0xa35, 0x00000100, 0x100 + 0x0d4f, 0xffffffff, 0x40000, + 0x0d4e, 0xffffffff, 0x200010ff, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x7007, + 0x0d4e, 0xffffffff, 0x300010ff, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x400000, + 0x0d4e, 0xffffffff, 0x100010ff, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x120200, + 0x0d4e, 0xffffffff, 0x500010ff, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x1e1e16, + 0x0d4e, 0xffffffff, 0x600010ff, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x171f1e, + 0x0d4e, 0xffffffff, 0x700010ff, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4f, 0xffffffff, 0x0, + 0x0d4e, 0xffffffff, 0x9ff, + 0x0d40, 0xffffffff, 0x0, + 0x0d41, 0xffffffff, 0x10000800, + 0x0d41, 0xffffffff, 0xf, + 0x0d41, 0xffffffff, 0xf, + 0x0d40, 0xffffffff, 0x4, + 0x0d41, 0xffffffff, 0x1000051e, + 0x0d41, 0xffffffff, 0xffff, + 0x0d41, 0xffffffff, 0xffff, + 0x0d40, 0xffffffff, 0x8, + 0x0d41, 0xffffffff, 0x80500, + 0x0d40, 0xffffffff, 0x12, + 0x0d41, 0xffffffff, 0x9050c, + 0x0d40, 0xffffffff, 0x1d, + 0x0d41, 0xffffffff, 0xb052c, + 0x0d40, 0xffffffff, 0x2a, + 0x0d41, 0xffffffff, 0x1053e, + 0x0d40, 0xffffffff, 0x2d, + 0x0d41, 0xffffffff, 0x10546, + 0x0d40, 0xffffffff, 0x30, + 0x0d41, 0xffffffff, 0xa054e, + 0x0d40, 0xffffffff, 0x3c, + 0x0d41, 0xffffffff, 0x1055f, + 0x0d40, 0xffffffff, 0x3f, + 0x0d41, 0xffffffff, 0x10567, + 0x0d40, 0xffffffff, 0x42, + 0x0d41, 0xffffffff, 0x1056f, + 0x0d40, 0xffffffff, 0x45, + 0x0d41, 0xffffffff, 0x10572, + 0x0d40, 0xffffffff, 0x48, + 0x0d41, 0xffffffff, 0x20575, + 0x0d40, 0xffffffff, 0x4c, + 0x0d41, 0xffffffff, 0x190801, + 0x0d40, 0xffffffff, 0x67, + 0x0d41, 0xffffffff, 0x1082a, + 0x0d40, 0xffffffff, 0x6a, + 0x0d41, 0xffffffff, 0x1b082d, + 0x0d40, 0xffffffff, 0x87, + 0x0d41, 0xffffffff, 0x310851, + 0x0d40, 0xffffffff, 0xba, + 0x0d41, 0xffffffff, 0x891, + 0x0d40, 0xffffffff, 0xbc, + 0x0d41, 0xffffffff, 0x893, + 0x0d40, 0xffffffff, 0xbe, + 0x0d41, 0xffffffff, 0x20895, + 0x0d40, 0xffffffff, 0xc2, + 0x0d41, 0xffffffff, 0x20899, + 0x0d40, 0xffffffff, 0xc6, + 0x0d41, 0xffffffff, 0x2089d, + 0x0d40, 0xffffffff, 0xca, + 0x0d41, 0xffffffff, 0x8a1, + 0x0d40, 0xffffffff, 0xcc, + 0x0d41, 0xffffffff, 0x8a3, + 0x0d40, 0xffffffff, 0xce, + 0x0d41, 0xffffffff, 0x308a5, + 0x0d40, 0xffffffff, 0xd3, + 0x0d41, 0xffffffff, 0x6d08cd, + 0x0d40, 0xffffffff, 0x142, + 0x0d41, 0xffffffff, 0x2000095a, + 0x0d41, 0xffffffff, 0x1, + 0x0d40, 0xffffffff, 0x144, + 0x0d41, 0xffffffff, 0x301f095b, + 0x0d40, 0xffffffff, 0x165, + 0x0d41, 0xffffffff, 0xc094d, + 0x0d40, 0xffffffff, 0x173, + 0x0d41, 0xffffffff, 0xf096d, + 0x0d40, 0xffffffff, 0x184, + 0x0d41, 0xffffffff, 0x15097f, + 0x0d40, 0xffffffff, 0x19b, + 0x0d41, 0xffffffff, 0xc0998, + 0x0d40, 0xffffffff, 0x1a9, + 0x0d41, 0xffffffff, 0x409a7, + 0x0d40, 0xffffffff, 0x1af, + 0x0d41, 0xffffffff, 0xcdc, + 0x0d40, 0xffffffff, 0x1b1, + 0x0d41, 0xffffffff, 0x800, + 0x0d42, 0xffffffff, 0x6c9b2000, + 0x0d44, 0xfc00, 0x2000, + 0x0d51, 0xffffffff, 0xfc0, + 0x0a35, 0x00000100, 0x100 }; static const u32 verde_golden_rlc_registers[] = { + 0x263e, 0xffffffff, 0x02010002, 0x3109, 0xffffffff, 0x033f1005, 0x311f, 0xffffffff, 0x10808020, 0x3122, 0xffffffff, 0x00800008, @@ -281,61 +282,40 @@ static const u32 verde_golden_rlc_registers[] = static const u32 verde_golden_registers[] = { + 0x17bc, 0x00000030, 0x00000011, 0x2684, 0x00010000, 0x00018208, 0x260c, 0xffffffff, 0x00000000, 0x260d, 0xf00fffff, 0x00000400, 0x260e, 0x0002021c, 0x00020200, 0x031e, 0x00000080, 0x00000000, 0x340c, 0x000300c0, 0x00800040, - 0x340c, 0x000300c0, 0x00800040, - 0x360c, 0x000300c0, 0x00800040, 0x360c, 0x000300c0, 0x00800040, 0x16ec, 0x000000f0, 0x00000070, 0x16f0, 0x00200000, 0x50100000, - 0x1c0c, 0x31000311, 0x00000011, 0x0ab9, 0x00073ffe, 0x000022a2, - 0x0ab9, 0x00073ffe, 0x000022a2, - 0x0ab9, 0x00073ffe, 0x000022a2, - 0x0903, 0x000007ff, 0x00000000, - 0x0903, 0x000007ff, 0x00000000, 0x0903, 0x000007ff, 0x00000000, 0x2285, 0xf000001f, 0x00000007, - 0x2285, 0xf000001f, 0x00000007, - 0x2285, 0xf000001f, 0x00000007, - 0x2285, 0xffffffff, 0x00ffffff, + 0x22c9, 0xffffffff, 0x00ffffff, 0x22c4, 0x0000ff0f, 0x00000000, - 0xa293, 0x07ffffff, 0x4e000000, 0xa0d4, 0x3f3f3fff, 0x0000124a, - 0xa0d4, 0x3f3f3fff, 0x0000124a, - 0xa0d4, 0x3f3f3fff, 0x0000124a, - 0x000c, 0x000000ff, 0x0040, + 0x000c, 0xffffffff, 0x0040, 0x000d, 0x00000040, 0x00004040, 0x2440, 0x07ffffff, 0x03000000, - 0x2440, 0x07ffffff, 0x03000000, 0x23a2, 0x01ff1f3f, 0x00000000, - 0x23a3, 0x01ff1f3f, 0x00000000, - 0x23a2, 0x01ff1f3f, 0x00000000, - 0x23a1, 0x01ff1f3f, 0x00000000, - 0x23a1, 0x01ff1f3f, 0x00000000, - 0x23a1, 0x01ff1f3f, 0x00000000, 0x2418, 0x0000007f, 0x00000020, 0x2542, 0x00010000, 0x00010000, - 0x2b01, 0x000003ff, 0x00000003, - 0x2b05, 0x000003ff, 0x00000003, 0x2b05, 0x000003ff, 0x00000003, 0x2b04, 0xffffffff, 0x00000000, - 0x2b04, 0xffffffff, 0x00000000, - 0x2b04, 0xffffffff, 0x00000000, - 0x2b03, 0xffffffff, 0x00001032, 0x2b03, 0xffffffff, 0x00001032, - 0x2b03, 0xffffffff, 0x00001032, - 0x2235, 0x0000001f, 0x00000010, - 0x2235, 0x0000001f, 0x00000010, 0x2235, 0x0000001f, 0x00000010, - 0x0570, 0x000c0fc0, 0x000c0400 + 0x0570, 0x000c0fc0, 0x000c0400, + 0x052c, 0x0fffffff, 0xffffffff, + 0x052d, 0x0fffffff, 0x0fffffff, + 0x052e, 0x0fffffff, 0x0fffffff, + 0x052f, 0x0fffffff, 0x0fffffff }; static const u32 oland_golden_registers[] = @@ -736,18 +716,18 @@ static const u32 verde_mgcg_cgcg_init[] = 0x21c2, 0xffffffff, 0x00900100, 0x311e, 0xffffffff, 0x00000080, 0x3101, 0xffffffff, 0x0020003f, - 0xc, 0xffffffff, 0x0000001c, - 0xd, 0x000f0000, 0x000f0000, - 0x583, 0xffffffff, 0x00000100, - 0x409, 0xffffffff, 0x00000100, - 0x40b, 0x00000101, 0x00000000, - 0x82a, 0xffffffff, 0x00000104, - 0x993, 0x000c0000, 0x000c0000, - 0x992, 0x000c0000, 0x000c0000, + 0x000c, 0xffffffff, 0x0000001c, + 0x000d, 0x000f0000, 0x000f0000, + 0x0583, 0xffffffff, 0x00000100, + 0x0409, 0xffffffff, 0x00000100, + 0x040b, 0x00000101, 0x00000000, + 0x082a, 0xffffffff, 0x00000104, + 0x0993, 0x000c0000, 0x000c0000, + 0x0992, 0x000c0000, 0x000c0000, 0x1579, 0xff000fff, 0x00000100, 0x157a, 0x00000001, 0x00000001, - 0xbd4, 0x00000001, 0x00000001, - 0xc33, 0xc0000fff, 0x00000104, + 0x0bd4, 0x00000001, 0x00000001, + 0x0c33, 0xc0000fff, 0x00000104, 0x3079, 0x00000001, 0x00000001, 0x3430, 0xfffffff0, 0x00000100, 0x3630, 0xfffffff0, 0x00000100 -- cgit v1.2.3 From f815b29cea0968df400f8c9f8b770ec02ec66906 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 15:27:51 +0800 Subject: drm/amdgpu: update rev id for verde Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/si.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/si.c b/drivers/gpu/drm/amd/amdgpu/si.c index 2a99a41553b4..c46b0159007d 100644 --- a/drivers/gpu/drm/amd/amdgpu/si.c +++ b/drivers/gpu/drm/amd/amdgpu/si.c @@ -1229,7 +1229,7 @@ static int si_common_early_init(void *handle) AMD_CG_SUPPORT_HDP_MGCG; adev->pg_flags = 0; //??? - adev->external_rev_id = adev->rev_id + 0x14; + adev->external_rev_id = adev->rev_id + 40; break; case CHIP_OLAND: adev->cg_flags = -- cgit v1.2.3 From 3548f9a829738db1df2643c1db1a134d84b00fc4 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 16:26:58 +0800 Subject: drm/amdgpu: update tile table for verde Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 295 +++++++++++++++++++++++++++++++++- 1 file changed, 293 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index aa4472343901..51bbd6e44dbb 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -411,8 +411,299 @@ static void gfx_v6_0_tiling_mode_table_init(struct amdgpu_device *adev) break; } - if (adev->asic_type == CHIP_VERDE || - adev->asic_type == CHIP_OLAND || + if (adev->asic_type == CHIP_VERDE) { + for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { + switch (reg_offset) { + case 0: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 1: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 2: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 3: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK) | + TILE_SPLIT(split_equal_to_row_size)); + break; + case 4: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16)); + break; + case 5: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 6: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 7: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 8: + gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED)); + break; + case 9: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16)); + break; + case 10: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 11: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 12: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 13: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16)); + break; + case 14: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 15: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 16: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); + break; + case 17: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); + break; + case 18: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P4_8x16)); + break; + case 19: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_XTHICK) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); + break; + case 20: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); + break; + case 21: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 22: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); + break; + case 23: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 24: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 25: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 26: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 27: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 28: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 29: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + case 30: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P4_8x16) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_2_BANK)); + break; + default: + continue; + } + adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden; + WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden); + } + } else if (adev->asic_type == CHIP_OLAND || adev->asic_type == CHIP_HAINAN) { for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { switch (reg_offset) { -- cgit v1.2.3 From f8d9422ef80c5126112284493e69c88753c56ad1 Mon Sep 17 00:00:00 2001 From: Flora Cui Date: Thu, 15 Dec 2016 16:29:31 +0800 Subject: drm/amdgpu: update tile table for oland/hainan Signed-off-by: Flora Cui Reviewed-by: Junwei Zhang Reviewed-by: Alex Deucher Signed-off-by: Alex Deucher Cc: stable@vger.kernel.org --- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 330 ++++++++++++++++++++-------------- 1 file changed, 191 insertions(+), 139 deletions(-) (limited to 'drivers') diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c index 51bbd6e44dbb..b323f5ef64d2 100644 --- a/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +++ b/drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c @@ -708,238 +708,290 @@ static void gfx_v6_0_tiling_mode_table_init(struct amdgpu_device *adev) for (reg_offset = 0; reg_offset < num_tile_mode_states; reg_offset++) { switch (reg_offset) { case 0: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 1: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 2: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 3: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_128B) | - NUM_BANKS(ADDR_SURF_16_BANK) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK) | + TILE_SPLIT(split_equal_to_row_size)); break; case 4: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2)); break; case 5: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); break; case 6: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); break; case 7: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | - NUM_BANKS(ADDR_SURF_16_BANK) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DEPTH_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); break; case 8: - gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + gb_tile_moden = (ARRAY_MODE(ARRAY_LINEAR_ALIGNED)); break; case 9: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2)); break; case 10: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 11: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 12: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_DISPLAY_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 13: - gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(ADDR_SURF_TILE_SPLIT_64B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2)); break; case 14: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 15: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 16: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK)); break; case 17: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P4_8x16) | - TILE_SPLIT(split_equal_to_row_size) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); + break; + case 18: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_1D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P2)); + break; + case 19: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_XTHICK) | + PIPE_CONFIG(ADDR_SURF_P2) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); + break; + case 20: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THICK) | + PIPE_CONFIG(ADDR_SURF_P2) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2) | + NUM_BANKS(ADDR_SURF_16_BANK) | + TILE_SPLIT(split_equal_to_row_size)); break; case 21: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); break; case 22: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | - BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | - BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_4) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_4)); + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_2) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); break; case 23: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_256B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); break; case 24: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_512B) | - NUM_BANKS(ADDR_SURF_16_BANK) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_2)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_8_BANK)); break; case 25: - gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) | - MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | - PIPE_CONFIG(ADDR_SURF_P8_32x32_8x16) | + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | - NUM_BANKS(ADDR_SURF_8_BANK) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 26: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 27: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 28: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 29: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_1KB) | + BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | + BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_2) | + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); + break; + case 30: + gb_tile_moden = (MICRO_TILE_MODE(ADDR_SURF_THIN_MICRO_TILING) | + ARRAY_MODE(ARRAY_2D_TILED_THIN1) | + PIPE_CONFIG(ADDR_SURF_P2) | + TILE_SPLIT(ADDR_SURF_TILE_SPLIT_2KB) | BANK_WIDTH(ADDR_SURF_BANK_WIDTH_1) | BANK_HEIGHT(ADDR_SURF_BANK_HEIGHT_1) | - MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1)); + MACRO_TILE_ASPECT(ADDR_SURF_MACRO_ASPECT_1) | + NUM_BANKS(ADDR_SURF_4_BANK)); break; default: - gb_tile_moden = 0; - break; + continue; } adev->gfx.config.tile_mode_array[reg_offset] = gb_tile_moden; WREG32(mmGB_TILE_MODE0 + reg_offset, gb_tile_moden); -- cgit v1.2.3 From 174cc7187e6f088942c8e74daa7baff7b44b33c9 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Dec 2016 15:04:25 +0800 Subject: ACPICA: Tables: Back port acpi_get_table_with_size() and early_acpi_os_unmap_memory() from Linux kernel ACPICA commit cac6790954d4d752a083e6122220b8a22febcd07 This patch back ports Linux acpi_get_table_with_size() and early_acpi_os_unmap_memory() into ACPICA upstream to reduce divergences. The 2 APIs are used by Linux as table management APIs for long time, it contains a hidden logic that during the early stage, the mapped tables should be unmapped before the early stage ends. During the early stage, tables are handled by the following sequence: acpi_get_table_with_size(); parse the table early_acpi_os_unmap_memory(); During the late stage, tables are handled by the following sequence: acpi_get_table(); parse the table Linux uses acpi_gbl_permanent_mmap to distinguish the early stage and the late stage. The reasoning of introducing acpi_get_table_with_size() is: ACPICA will remember the early mapped pointer in acpi_get_table() and Linux isn't able to prevent ACPICA from using the wrong early mapped pointer during the late stage as there is no API provided from ACPICA to be an inverse of acpi_get_table() to forget the early mapped pointer. But how ACPICA can work with the early/late stage requirement? Inside of ACPICA, tables are ensured to be remained in "INSTALLED" state during the early stage, and they are carefully not transitioned to "VALIDATED" state until the late stage. So the same logic is in fact implemented inside of ACPICA in a different way. The gap is only that the feature is not provided to the OSPMs in an accessible external API style. It then is possible to fix the gap by providing an inverse of acpi_get_table() from ACPICA, so that the two Linux sequences can be combined: acpi_get_table(); parse the table acpi_put_table(); In order to work easier with the current Linux code, acpi_get_table() and acpi_put_table() is implemented in a usage counting based style: 1. When the usage count of the table is increased from 0 to 1, table is mapped and .Pointer is set with the mapping address (VALIDATED); 2. When the usage count of the table is decreased from 1 to 0, .Pointer is unset and the mapping address is unmapped (INVALIDATED). So that we can deploy the new APIs to Linux with minimal effort by just invoking acpi_get_table() in acpi_get_table_with_size() and invoking acpi_put_table() in early_acpi_os_unmap_memory(). Lv Zheng. Link: https://github.com/acpica/acpica/commit/cac67909 Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/actables.h | 6 ++ drivers/acpi/acpica/tbutils.c | 85 +++++++++++++++++++++++++ drivers/acpi/acpica/tbxface.c | 130 ++++++++++++++++++++++++-------------- drivers/acpi/osl.c | 39 +++++++++++- include/acpi/acpixf.h | 12 +++- include/acpi/actbl.h | 1 + include/acpi/platform/aclinuxex.h | 1 - 7 files changed, 220 insertions(+), 54 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h index 7dd527f8ca1d..94be8a8e6c08 100644 --- a/drivers/acpi/acpica/actables.h +++ b/drivers/acpi/acpica/actables.h @@ -166,6 +166,12 @@ acpi_tb_install_table_with_override(struct acpi_table_desc *new_table_desc, acpi_status acpi_tb_parse_root_table(acpi_physical_address rsdp_address); +acpi_status +acpi_tb_get_table(struct acpi_table_desc *table_desc, + struct acpi_table_header **out_table); + +void acpi_tb_put_table(struct acpi_table_desc *table_desc); + /* * tbxfload */ diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c index 51eb07cf9898..86854e846800 100644 --- a/drivers/acpi/acpica/tbutils.c +++ b/drivers/acpi/acpica/tbutils.c @@ -381,3 +381,88 @@ next_table: acpi_os_unmap_memory(table, length); return_ACPI_STATUS(AE_OK); } + +/******************************************************************************* + * + * FUNCTION: acpi_tb_get_table + * + * PARAMETERS: table_desc - Table descriptor + * out_table - Where the pointer to the table is returned + * + * RETURN: Status and pointer to the requested table + * + * DESCRIPTION: Increase a reference to a table descriptor and return the + * validated table pointer. + * If the table descriptor is an entry of the root table list, + * this API must be invoked with ACPI_MTX_TABLES acquired. + * + ******************************************************************************/ + +acpi_status +acpi_tb_get_table(struct acpi_table_desc *table_desc, + struct acpi_table_header **out_table) +{ + acpi_status status; + + ACPI_FUNCTION_TRACE(acpi_tb_get_table); + + if (table_desc->validation_count == 0) { + + /* Table need to be "VALIDATED" */ + + status = acpi_tb_validate_table(table_desc); + if (ACPI_FAILURE(status)) { + return_ACPI_STATUS(status); + } + } + + table_desc->validation_count++; + if (table_desc->validation_count == 0) { + ACPI_ERROR((AE_INFO, + "Table %p, Validation count is zero after increment\n", + table_desc)); + table_desc->validation_count--; + return_ACPI_STATUS(AE_LIMIT); + } + + *out_table = table_desc->pointer; + return_ACPI_STATUS(AE_OK); +} + +/******************************************************************************* + * + * FUNCTION: acpi_tb_put_table + * + * PARAMETERS: table_desc - Table descriptor + * + * RETURN: None + * + * DESCRIPTION: Decrease a reference to a table descriptor and release the + * validated table pointer if no references. + * If the table descriptor is an entry of the root table list, + * this API must be invoked with ACPI_MTX_TABLES acquired. + * + ******************************************************************************/ + +void acpi_tb_put_table(struct acpi_table_desc *table_desc) +{ + + ACPI_FUNCTION_TRACE(acpi_tb_put_table); + + if (table_desc->validation_count == 0) { + ACPI_WARNING((AE_INFO, + "Table %p, Validation count is zero before decrement\n", + table_desc)); + return_VOID; + } + table_desc->validation_count--; + + if (table_desc->validation_count == 0) { + + /* Table need to be "INVALIDATED" */ + + acpi_tb_invalidate_table(table_desc); + } + + return_VOID; +} diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c index d5adb7ac4684..7684707b254b 100644 --- a/drivers/acpi/acpica/tbxface.c +++ b/drivers/acpi/acpica/tbxface.c @@ -282,7 +282,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header) /******************************************************************************* * - * FUNCTION: acpi_get_table_with_size + * FUNCTION: acpi_get_table * * PARAMETERS: signature - ACPI signature of needed table * instance - Which instance (for SSDTs) @@ -292,16 +292,21 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header) * * DESCRIPTION: Finds and verifies an ACPI table. Table must be in the * RSDT/XSDT. + * Note that an early stage acpi_get_table() call must be paired + * with an early stage acpi_put_table() call. otherwise the table + * pointer mapped by the early stage mapping implementation may be + * erroneously unmapped by the late stage unmapping implementation + * in an acpi_put_table() invoked during the late stage. * ******************************************************************************/ acpi_status -acpi_get_table_with_size(char *signature, - u32 instance, struct acpi_table_header **out_table, - acpi_size *tbl_size) +acpi_get_table(char *signature, + u32 instance, struct acpi_table_header ** out_table) { u32 i; u32 j; - acpi_status status; + acpi_status status = AE_NOT_FOUND; + struct acpi_table_desc *table_desc; /* Parameter validation */ @@ -309,13 +314,22 @@ acpi_get_table_with_size(char *signature, return (AE_BAD_PARAMETER); } + /* + * Note that the following line is required by some OSPMs, they only + * check if the returned table is NULL instead of the returned status + * to determined if this function is succeeded. + */ + *out_table = NULL; + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + /* Walk the root table list */ for (i = 0, j = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { - if (!ACPI_COMPARE_NAME - (&(acpi_gbl_root_table_list.tables[i].signature), - signature)) { + table_desc = &acpi_gbl_root_table_list.tables[i]; + + if (!ACPI_COMPARE_NAME(&table_desc->signature, signature)) { continue; } @@ -323,43 +337,65 @@ acpi_get_table_with_size(char *signature, continue; } - status = - acpi_tb_validate_table(&acpi_gbl_root_table_list.tables[i]); - if (ACPI_SUCCESS(status)) { - *out_table = acpi_gbl_root_table_list.tables[i].pointer; - *tbl_size = acpi_gbl_root_table_list.tables[i].length; - } - - if (!acpi_gbl_permanent_mmap) { - acpi_gbl_root_table_list.tables[i].pointer = NULL; - } - - return (status); + status = acpi_tb_get_table(table_desc, out_table); + break; } - return (AE_NOT_FOUND); + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return (status); } -ACPI_EXPORT_SYMBOL(acpi_get_table_with_size) +ACPI_EXPORT_SYMBOL(acpi_get_table) -acpi_status -acpi_get_table(char *signature, - u32 instance, struct acpi_table_header **out_table) +/******************************************************************************* + * + * FUNCTION: acpi_put_table + * + * PARAMETERS: table - The pointer to the table + * + * RETURN: None + * + * DESCRIPTION: Release a table returned by acpi_get_table() and its clones. + * Note that it is not safe if this function was invoked after an + * uninstallation happened to the original table descriptor. + * Currently there is no OSPMs' requirement to handle such + * situations. + * + ******************************************************************************/ +void acpi_put_table(struct acpi_table_header *table) { - acpi_size tbl_size; + u32 i; + struct acpi_table_desc *table_desc; + + ACPI_FUNCTION_TRACE(acpi_put_table); + + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); + + /* Walk the root table list */ + + for (i = 0; i < acpi_gbl_root_table_list.current_table_count; i++) { + table_desc = &acpi_gbl_root_table_list.tables[i]; - return acpi_get_table_with_size(signature, - instance, out_table, &tbl_size); + if (table_desc->pointer != table) { + continue; + } + + acpi_tb_put_table(table_desc); + break; + } + + (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); + return_VOID; } -ACPI_EXPORT_SYMBOL(acpi_get_table) +ACPI_EXPORT_SYMBOL(acpi_put_table) /******************************************************************************* * * FUNCTION: acpi_get_table_by_index * * PARAMETERS: table_index - Table index - * table - Where the pointer to the table is returned + * out_table - Where the pointer to the table is returned * * RETURN: Status and pointer to the requested table * @@ -368,7 +404,7 @@ ACPI_EXPORT_SYMBOL(acpi_get_table) * ******************************************************************************/ acpi_status -acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table) +acpi_get_table_by_index(u32 table_index, struct acpi_table_header **out_table) { acpi_status status; @@ -376,35 +412,33 @@ acpi_get_table_by_index(u32 table_index, struct acpi_table_header **table) /* Parameter validation */ - if (!table) { + if (!out_table) { return_ACPI_STATUS(AE_BAD_PARAMETER); } + /* + * Note that the following line is required by some OSPMs, they only + * check if the returned table is NULL instead of the returned status + * to determined if this function is succeeded. + */ + *out_table = NULL; + (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES); /* Validate index */ if (table_index >= acpi_gbl_root_table_list.current_table_count) { - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(AE_BAD_PARAMETER); + status = AE_BAD_PARAMETER; + goto unlock_and_exit; } - if (!acpi_gbl_root_table_list.tables[table_index].pointer) { - - /* Table is not mapped, map it */ + status = + acpi_tb_get_table(&acpi_gbl_root_table_list.tables[table_index], + out_table); - status = - acpi_tb_validate_table(&acpi_gbl_root_table_list. - tables[table_index]); - if (ACPI_FAILURE(status)) { - (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(status); - } - } - - *table = acpi_gbl_root_table_list.tables[table_index].pointer; +unlock_and_exit: (void)acpi_ut_release_mutex(ACPI_MTX_TABLES); - return_ACPI_STATUS(AE_OK); + return_ACPI_STATUS(status); } ACPI_EXPORT_SYMBOL(acpi_get_table_by_index) diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 416953a42510..9316dfc19cea 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -433,10 +433,45 @@ void __ref acpi_os_unmap_memory(void *virt, acpi_size size) } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); +/******************************************************************************* + * + * acpi_get_table_with_size()/early_acpi_os_unmap_memory(): + * + * These 2 functions are traditionally used by Linux to map/unmap physical + * addressed ACPI tables during the early stage. + * They are deprectated now. Do not use them in the new code, but use + * acpi_get_table()/acpi_put_table() instead. + * + ******************************************************************************/ +acpi_status +acpi_get_table_with_size(char *signature, + u32 instance, struct acpi_table_header **out_table, + acpi_size *tbl_size) +{ + acpi_status status; + + status = acpi_get_table(signature, instance, out_table); + if (ACPI_SUCCESS(status)) { + /* + * "tbl_size" is no longer used by + * early_acpi_os_unmap_memory(), but is still used by the + * ACPI table drivers. So sets it to the length of the + * table when the tbl_size is requested. + * "out_table" is not sanity checked as AE_BAD_PARAMETER + * is returned if it is NULL. + */ + if (tbl_size && *out_table) + *tbl_size = (*out_table)->length; + } + + return (status); +} + +ACPI_EXPORT_SYMBOL(acpi_get_table_with_size) + void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) { - if (!acpi_gbl_permanent_mmap) - __acpi_unmap_table(virt, size); + acpi_put_table(ACPI_CAST_PTR(struct acpi_table_header, virt)); } int acpi_os_map_generic_address(struct acpi_generic_address *gas) diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 5c7356adc10b..33828dd97fc5 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -513,10 +513,12 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_get_table(acpi_string signature, u32 instance, struct acpi_table_header **out_table)) +ACPI_EXTERNAL_RETURN_VOID(void acpi_put_table(struct acpi_table_header *table)) + ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_table_by_index(u32 table_index, - struct acpi_table_header - **out_table)) + acpi_get_table_by_index(u32 table_index, + struct acpi_table_header + **out_table)) ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_install_table_handler(acpi_table_handler handler, void *context)) @@ -974,6 +976,10 @@ ACPI_EXTERNAL_RETURN_STATUS(acpi_status **out_table, acpi_size *tbl_size)) +ACPI_EXTERNAL_RETURN_VOID(void + early_acpi_os_unmap_memory(void __iomem * virt, + acpi_size size)) + ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_get_data_full(acpi_handle object, acpi_object_handler handler, diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h index c19700e2a2fe..da5708caf8a1 100644 --- a/include/acpi/actbl.h +++ b/include/acpi/actbl.h @@ -371,6 +371,7 @@ struct acpi_table_desc { union acpi_name_union signature; acpi_owner_id owner_id; u8 flags; + u16 validation_count; }; /* Masks for Flags field above */ diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h index a5509d87230a..7dbb1141f546 100644 --- a/include/acpi/platform/aclinuxex.h +++ b/include/acpi/platform/aclinuxex.h @@ -142,7 +142,6 @@ static inline void acpi_os_terminate_command_signals(void) /* * OSL interfaces added by Linux */ -void early_acpi_os_unmap_memory(void __iomem * virt, acpi_size size); #endif /* __KERNEL__ */ -- cgit v1.2.3 From 66360faa4333babc53836c7b59a0cff68cb0a9c6 Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Dec 2016 15:04:33 +0800 Subject: ACPICA: Tables: Allow FADT to be customized with virtual address ACPICA commit d98de9ca14891130efc5dcdc871b97eb27b4b0f5 FADT parsing code requires FADT to be installed as ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, using new acpi_tb_get_table()/acpi_tb_put_table(), other address types can also be allowed, thus facilitates FADT customization with virtual address. Lv Zheng. Link: https://github.com/acpica/acpica/commit/d98de9ca Signed-off-by: Lv Zheng Signed-off-by: Bob Moore Signed-off-by: Rafael J. Wysocki --- drivers/acpi/acpica/tbfadt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c index 5fb838e592dc..81473a4880ce 100644 --- a/drivers/acpi/acpica/tbfadt.c +++ b/drivers/acpi/acpica/tbfadt.c @@ -311,6 +311,8 @@ void acpi_tb_parse_fadt(void) { u32 length; struct acpi_table_header *table; + struct acpi_table_desc *fadt_desc; + acpi_status status; /* * The FADT has multiple versions with different lengths, @@ -319,14 +321,12 @@ void acpi_tb_parse_fadt(void) * Get a local copy of the FADT and convert it to a common format * Map entire FADT, assumed to be smaller than one page. */ - length = acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index].length; - - table = - acpi_os_map_memory(acpi_gbl_root_table_list. - tables[acpi_gbl_fadt_index].address, length); - if (!table) { + fadt_desc = &acpi_gbl_root_table_list.tables[acpi_gbl_fadt_index]; + status = acpi_tb_get_table(fadt_desc, &table); + if (ACPI_FAILURE(status)) { return; } + length = fadt_desc->length; /* * Validate the FADT checksum before we copy the table. Ignore @@ -340,7 +340,7 @@ void acpi_tb_parse_fadt(void) /* All done with the real FADT, unmap it */ - acpi_os_unmap_memory(table, length); + acpi_tb_put_table(fadt_desc); /* Obtain the DSDT and FACS tables via their addresses within the FADT */ -- cgit v1.2.3 From 6b11d1d677132816252004426ef220ccd3c92d2f Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Dec 2016 15:04:39 +0800 Subject: ACPI / osl: Remove acpi_get_table_with_size()/early_acpi_os_unmap_memory() users This patch removes the users of the deprectated APIs: acpi_get_table_with_size() early_acpi_os_unmap_memory() The following APIs should be used instead of: acpi_get_table() acpi_put_table() The deprecated APIs are invented to be a replacement of acpi_get_table() during the early stage so that the early mapped pointer will not be stored in ACPICA core and thus the late stage acpi_get_table() won't return a wrong pointer. The mapping size is returned just because it is required by early_acpi_os_unmap_memory() to unmap the pointer during early stage. But as the mapping size equals to the acpi_table_header.length (see acpi_tb_init_table_descriptor() and acpi_tb_validate_table()), when such a convenient result is returned, driver code will start to use it instead of accessing acpi_table_header to obtain the length. Thus this patch cleans up the drivers by replacing returned table size with acpi_table_header.length, and should be a no-op. Reported-by: Dan Williams Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- arch/arm64/kernel/acpi.c | 7 +++---- drivers/acpi/nfit/core.c | 3 ++- drivers/acpi/processor_core.c | 8 +++----- drivers/acpi/spcr.c | 8 +++----- drivers/acpi/tables.c | 17 +++++++---------- drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c | 3 ++- drivers/gpu/drm/radeon/radeon_bios.c | 3 ++- drivers/iommu/amd_iommu_init.c | 10 ++++------ drivers/iommu/dmar.c | 7 ++----- drivers/mailbox/pcc.c | 5 +---- 10 files changed, 29 insertions(+), 42 deletions(-) (limited to 'drivers') diff --git a/arch/arm64/kernel/acpi.c b/arch/arm64/kernel/acpi.c index 252a6d9c1da5..64d9cbd61678 100644 --- a/arch/arm64/kernel/acpi.c +++ b/arch/arm64/kernel/acpi.c @@ -132,14 +132,13 @@ static int __init acpi_fadt_sanity_check(void) struct acpi_table_header *table; struct acpi_table_fadt *fadt; acpi_status status; - acpi_size tbl_size; int ret = 0; /* * FADT is required on arm64; retrieve it to check its presence * and carry out revision and ACPI HW reduced compliancy tests */ - status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size); + status = acpi_get_table(ACPI_SIG_FADT, 0, &table); if (ACPI_FAILURE(status)) { const char *msg = acpi_format_exception(status); @@ -170,10 +169,10 @@ static int __init acpi_fadt_sanity_check(void) out: /* - * acpi_get_table_with_size() creates FADT table mapping that + * acpi_get_table() creates FADT table mapping that * should be released after parsing and before resuming boot */ - early_acpi_os_unmap_memory(table, tbl_size); + acpi_put_table(table); return ret; } diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index 71a7d07c28c9..0efd3fa9a4d8 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2781,12 +2781,13 @@ static int acpi_nfit_add(struct acpi_device *adev) acpi_size sz; int rc = 0; - status = acpi_get_table_with_size(ACPI_SIG_NFIT, 0, &tbl, &sz); + status = acpi_get_table(ACPI_SIG_NFIT, 0, &tbl); if (ACPI_FAILURE(status)) { /* This is ok, we could have an nvdimm hotplugged later */ dev_dbg(dev, "failed to find NFIT at startup\n"); return 0; } + sz = tbl->length; acpi_desc = devm_kzalloc(dev, sizeof(*acpi_desc), GFP_KERNEL); if (!acpi_desc) diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c index 5c78ee1860b0..611a5585a902 100644 --- a/drivers/acpi/processor_core.c +++ b/drivers/acpi/processor_core.c @@ -154,18 +154,16 @@ static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt, phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id) { struct acpi_table_madt *madt = NULL; - acpi_size tbl_size; phys_cpuid_t rv; - acpi_get_table_with_size(ACPI_SIG_MADT, 0, - (struct acpi_table_header **)&madt, - &tbl_size); + acpi_get_table(ACPI_SIG_MADT, 0, + (struct acpi_table_header **)&madt); if (!madt) return PHYS_CPUID_INVALID; rv = map_madt_entry(madt, 1, acpi_id, true); - early_acpi_os_unmap_memory(madt, tbl_size); + acpi_put_table((struct acpi_table_header *)madt); return rv; } diff --git a/drivers/acpi/spcr.c b/drivers/acpi/spcr.c index e8d7bc7d4da8..b8019c4c1d38 100644 --- a/drivers/acpi/spcr.c +++ b/drivers/acpi/spcr.c @@ -33,7 +33,6 @@ int __init parse_spcr(bool earlycon) { static char opts[64]; struct acpi_table_spcr *table; - acpi_size table_size; acpi_status status; char *uart; char *iotype; @@ -43,9 +42,8 @@ int __init parse_spcr(bool earlycon) if (acpi_disabled) return -ENODEV; - status = acpi_get_table_with_size(ACPI_SIG_SPCR, 0, - (struct acpi_table_header **)&table, - &table_size); + status = acpi_get_table(ACPI_SIG_SPCR, 0, + (struct acpi_table_header **)&table); if (ACPI_FAILURE(status)) return -ENOENT; @@ -106,6 +104,6 @@ int __init parse_spcr(bool earlycon) err = add_preferred_console(uart, 0, opts + strlen(uart) + 1); done: - early_acpi_os_unmap_memory((void __iomem *)table, table_size); + acpi_put_table((struct acpi_table_header *)table); return err; } diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index cdd56c4657e0..2604189d6cd1 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -333,7 +333,6 @@ acpi_table_parse_entries_array(char *id, unsigned int max_entries) { struct acpi_table_header *table_header = NULL; - acpi_size tbl_size; int count; u32 instance = 0; @@ -346,7 +345,7 @@ acpi_table_parse_entries_array(char *id, if (!strncmp(id, ACPI_SIG_MADT, 4)) instance = acpi_apic_instance; - acpi_get_table_with_size(id, instance, &table_header, &tbl_size); + acpi_get_table(id, instance, &table_header); if (!table_header) { pr_warn("%4.4s not present\n", id); return -ENODEV; @@ -355,7 +354,7 @@ acpi_table_parse_entries_array(char *id, count = acpi_parse_entries_array(id, table_size, table_header, proc, proc_num, max_entries); - early_acpi_os_unmap_memory((char *)table_header, tbl_size); + acpi_put_table(table_header); return count; } @@ -397,7 +396,6 @@ acpi_table_parse_madt(enum acpi_madt_type id, int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) { struct acpi_table_header *table = NULL; - acpi_size tbl_size; if (acpi_disabled) return -ENODEV; @@ -406,13 +404,13 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) return -EINVAL; if (strncmp(id, ACPI_SIG_MADT, 4) == 0) - acpi_get_table_with_size(id, acpi_apic_instance, &table, &tbl_size); + acpi_get_table(id, acpi_apic_instance, &table); else - acpi_get_table_with_size(id, 0, &table, &tbl_size); + acpi_get_table(id, 0, &table); if (table) { handler(table); - early_acpi_os_unmap_memory(table, tbl_size); + acpi_put_table(table); return 0; } else return -ENODEV; @@ -426,16 +424,15 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) static void __init check_multiple_madt(void) { struct acpi_table_header *table = NULL; - acpi_size tbl_size; - acpi_get_table_with_size(ACPI_SIG_MADT, 2, &table, &tbl_size); + acpi_get_table(ACPI_SIG_MADT, 2, &table); if (table) { pr_warn("BIOS bug: multiple APIC/MADT found, using %d\n", acpi_apic_instance); pr_warn("If \"acpi_apic_instance=%d\" works better, " "notify linux-acpi@vger.kernel.org\n", acpi_apic_instance ? 0 : 2); - early_acpi_os_unmap_memory(table, tbl_size); + acpi_put_table(table); } else acpi_apic_instance = 0; diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c index 2b6afe123f3d..df6bf7379c7c 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_bios.c @@ -300,8 +300,9 @@ static bool amdgpu_acpi_vfct_bios(struct amdgpu_device *adev) GOP_VBIOS_CONTENT *vbios; VFCT_IMAGE_HEADER *vhdr; - if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) + if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) return false; + tbl_size = hdr->length; if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); goto out_unmap; diff --git a/drivers/gpu/drm/radeon/radeon_bios.c b/drivers/gpu/drm/radeon/radeon_bios.c index 21b6732425c5..c829cfb02fc4 100644 --- a/drivers/gpu/drm/radeon/radeon_bios.c +++ b/drivers/gpu/drm/radeon/radeon_bios.c @@ -603,8 +603,9 @@ static bool radeon_acpi_vfct_bios(struct radeon_device *rdev) GOP_VBIOS_CONTENT *vbios; VFCT_IMAGE_HEADER *vhdr; - if (!ACPI_SUCCESS(acpi_get_table_with_size("VFCT", 1, &hdr, &tbl_size))) + if (!ACPI_SUCCESS(acpi_get_table("VFCT", 1, &hdr))) return false; + tbl_size = hdr->length; if (tbl_size < sizeof(UEFI_ACPI_VFCT)) { DRM_ERROR("ACPI VFCT table present but broken (too short #1)\n"); goto out_unmap; diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c index 157e93421fb8..eea3d490e117 100644 --- a/drivers/iommu/amd_iommu_init.c +++ b/drivers/iommu/amd_iommu_init.c @@ -2207,14 +2207,13 @@ static void __init free_dma_resources(void) static int __init early_amd_iommu_init(void) { struct acpi_table_header *ivrs_base; - acpi_size ivrs_size; acpi_status status; int i, remap_cache_sz, ret = 0; if (!amd_iommu_detected) return -ENODEV; - status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size); + status = acpi_get_table("IVRS", 0, &ivrs_base); if (status == AE_NOT_FOUND) return -ENODEV; else if (ACPI_FAILURE(status)) { @@ -2334,7 +2333,7 @@ static int __init early_amd_iommu_init(void) out: /* Don't leak any ACPI memory */ - early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); + acpi_put_table(ivrs_base); ivrs_base = NULL; return ret; @@ -2358,10 +2357,9 @@ out: static bool detect_ivrs(void) { struct acpi_table_header *ivrs_base; - acpi_size ivrs_size; acpi_status status; - status = acpi_get_table_with_size("IVRS", 0, &ivrs_base, &ivrs_size); + status = acpi_get_table("IVRS", 0, &ivrs_base); if (status == AE_NOT_FOUND) return false; else if (ACPI_FAILURE(status)) { @@ -2370,7 +2368,7 @@ static bool detect_ivrs(void) return false; } - early_acpi_os_unmap_memory((char __iomem *)ivrs_base, ivrs_size); + acpi_put_table(ivrs_base); /* Make sure ACS will be enabled during PCI probe */ pci_request_acs(); diff --git a/drivers/iommu/dmar.c b/drivers/iommu/dmar.c index 58470f5ced04..be74545a416a 100644 --- a/drivers/iommu/dmar.c +++ b/drivers/iommu/dmar.c @@ -68,7 +68,6 @@ DECLARE_RWSEM(dmar_global_lock); LIST_HEAD(dmar_drhd_units); struct acpi_table_header * __initdata dmar_tbl; -static acpi_size dmar_tbl_size; static int dmar_dev_scope_status = 1; static unsigned long dmar_seq_ids[BITS_TO_LONGS(DMAR_UNITS_SUPPORTED)]; @@ -541,9 +540,7 @@ static int __init dmar_table_detect(void) acpi_status status = AE_OK; /* if we could find DMAR table, then there are DMAR devices */ - status = acpi_get_table_with_size(ACPI_SIG_DMAR, 0, - (struct acpi_table_header **)&dmar_tbl, - &dmar_tbl_size); + status = acpi_get_table(ACPI_SIG_DMAR, 0, &dmar_tbl); if (ACPI_SUCCESS(status) && !dmar_tbl) { pr_warn("Unable to map DMAR\n"); @@ -904,7 +901,7 @@ int __init detect_intel_iommu(void) x86_init.iommu.iommu_init = intel_iommu_init; #endif - early_acpi_os_unmap_memory((void __iomem *)dmar_tbl, dmar_tbl_size); + acpi_put_table(dmar_tbl); dmar_tbl = NULL; up_write(&dmar_global_lock); diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c index 08c87fadca8c..0661987fdc1a 100644 --- a/drivers/mailbox/pcc.c +++ b/drivers/mailbox/pcc.c @@ -446,7 +446,6 @@ static int pcc_parse_subspace_irq(int id, */ static int __init acpi_pcc_probe(void) { - acpi_size pcct_tbl_header_size; struct acpi_table_header *pcct_tbl; struct acpi_subtable_header *pcct_entry; struct acpi_table_pcct *acpi_pcct_tbl; @@ -455,9 +454,7 @@ static int __init acpi_pcc_probe(void) acpi_status status = AE_OK; /* Search for PCCT */ - status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0, - &pcct_tbl, - &pcct_tbl_header_size); + status = acpi_get_table(ACPI_SIG_PCCT, 0, &pcct_tbl); if (ACPI_FAILURE(status) || !pcct_tbl) { pr_warn("PCCT header not found.\n"); -- cgit v1.2.3 From 8d3523fb3b727478ac528b307cb84460faa1c39e Mon Sep 17 00:00:00 2001 From: Lv Zheng Date: Wed, 14 Dec 2016 15:04:46 +0800 Subject: ACPI / osl: Remove deprecated acpi_get_table_with_size()/early_acpi_os_unmap_memory() Since all users are cleaned up, remove the 2 deprecated APIs due to no users. As a Linux variable rather than an ACPICA variable, acpi_gbl_permanent_mmap is renamed to acpi_permanent_mmap to have a consistent coding style across entire Linux ACPI subsystem. Signed-off-by: Lv Zheng Signed-off-by: Rafael J. Wysocki --- arch/arm64/include/asm/acpi.h | 2 +- drivers/acpi/bus.c | 2 +- drivers/acpi/osl.c | 50 +++++-------------------------------------- include/acpi/acpi_io.h | 2 ++ include/acpi/acpixf.h | 13 ----------- 5 files changed, 9 insertions(+), 60 deletions(-) (limited to 'drivers') diff --git a/arch/arm64/include/asm/acpi.h b/arch/arm64/include/asm/acpi.h index e517088d635f..8957ff8b3dd4 100644 --- a/arch/arm64/include/asm/acpi.h +++ b/arch/arm64/include/asm/acpi.h @@ -28,7 +28,7 @@ /* Basic configuration for ACPI */ #ifdef CONFIG_ACPI -/* ACPI table mapping after acpi_gbl_permanent_mmap is set */ +/* ACPI table mapping after acpi_permanent_mmap is set */ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, acpi_size size) { diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 56190d00fd87..77468be75b3c 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -964,7 +964,7 @@ void __init acpi_early_init(void) if (!acpi_strict) acpi_gbl_enable_interpreter_slack = TRUE; - acpi_gbl_permanent_mmap = 1; + acpi_permanent_mmap = true; /* * If the machine falls into the DMI check table, diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 9316dfc19cea..8a7cab06e271 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -76,6 +76,7 @@ static struct workqueue_struct *kacpi_notify_wq; static struct workqueue_struct *kacpi_hotplug_wq; static bool acpi_os_initialized; unsigned int acpi_sci_irq = INVALID_ACPI_IRQ; +bool acpi_permanent_mmap = false; /* * This list of permanent mappings is for memory that may be accessed from @@ -313,7 +314,7 @@ static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) * virtual address). If not found, map it, add it to that list and return a * pointer to it. * - * During early init (when acpi_gbl_permanent_mmap has not been set yet) this + * During early init (when acpi_permanent_mmap has not been set yet) this * routine simply calls __acpi_map_table() to get the job done. */ void __iomem *__ref @@ -329,7 +330,7 @@ acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) return NULL; } - if (!acpi_gbl_permanent_mmap) + if (!acpi_permanent_mmap) return __acpi_map_table((unsigned long)phys, size); mutex_lock(&acpi_ioremap_lock); @@ -399,7 +400,7 @@ static void acpi_os_map_cleanup(struct acpi_ioremap *map) * mappings, drop a reference to it and unmap it if there are no more active * references to it. * - * During early init (when acpi_gbl_permanent_mmap has not been set yet) this + * During early init (when acpi_permanent_mmap has not been set yet) this * routine simply calls __acpi_unmap_table() to get the job done. Since * __acpi_unmap_table() is an __init function, the __ref annotation is needed * here. @@ -408,7 +409,7 @@ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size) { struct acpi_ioremap *map; - if (!acpi_gbl_permanent_mmap) { + if (!acpi_permanent_mmap) { __acpi_unmap_table(virt, size); return; } @@ -433,47 +434,6 @@ void __ref acpi_os_unmap_memory(void *virt, acpi_size size) } EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); -/******************************************************************************* - * - * acpi_get_table_with_size()/early_acpi_os_unmap_memory(): - * - * These 2 functions are traditionally used by Linux to map/unmap physical - * addressed ACPI tables during the early stage. - * They are deprectated now. Do not use them in the new code, but use - * acpi_get_table()/acpi_put_table() instead. - * - ******************************************************************************/ -acpi_status -acpi_get_table_with_size(char *signature, - u32 instance, struct acpi_table_header **out_table, - acpi_size *tbl_size) -{ - acpi_status status; - - status = acpi_get_table(signature, instance, out_table); - if (ACPI_SUCCESS(status)) { - /* - * "tbl_size" is no longer used by - * early_acpi_os_unmap_memory(), but is still used by the - * ACPI table drivers. So sets it to the length of the - * table when the tbl_size is requested. - * "out_table" is not sanity checked as AE_BAD_PARAMETER - * is returned if it is NULL. - */ - if (tbl_size && *out_table) - *tbl_size = (*out_table)->length; - } - - return (status); -} - -ACPI_EXPORT_SYMBOL(acpi_get_table_with_size) - -void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size) -{ - acpi_put_table(ACPI_CAST_PTR(struct acpi_table_header, virt)); -} - int acpi_os_map_generic_address(struct acpi_generic_address *gas) { u64 addr; diff --git a/include/acpi/acpi_io.h b/include/acpi/acpi_io.h index d7d0f495a34e..303315b9693f 100644 --- a/include/acpi/acpi_io.h +++ b/include/acpi/acpi_io.h @@ -13,6 +13,8 @@ static inline void __iomem *acpi_os_ioremap(acpi_physical_address phys, } #endif +extern bool acpi_permanent_mmap; + void __iomem *__ref acpi_os_map_iomem(acpi_physical_address phys, acpi_size size); void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size); diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h index 33828dd97fc5..f5e10dd8e86b 100644 --- a/include/acpi/acpixf.h +++ b/include/acpi/acpixf.h @@ -967,19 +967,6 @@ void acpi_terminate_debugger(void); /* * Divergences */ -ACPI_GLOBAL(u8, acpi_gbl_permanent_mmap); - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_table_with_size(acpi_string signature, - u32 instance, - struct acpi_table_header - **out_table, - acpi_size *tbl_size)) - -ACPI_EXTERNAL_RETURN_VOID(void - early_acpi_os_unmap_memory(void __iomem * virt, - acpi_size size)) - ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_get_data_full(acpi_handle object, acpi_object_handler handler, -- cgit v1.2.3 From 2a8fa123d9a1d2ca391eefc81fea747108a5081f Mon Sep 17 00:00:00 2001 From: Boris Ostrovsky Date: Thu, 15 Dec 2016 10:00:58 -0500 Subject: cpufreq: Remove CPU hotplug callbacks only if they were initialized Since CPU hotplug callbacks are requested for CPUHP_AP_ONLINE_DYN state, successful callback initialization will result in cpuhp_setup_state() returning a positive value. Therefore acpi_cpufreq_online being zero indicates that callbacks have not been installed. This means that acpi_cpufreq_boost_exit() should only remove them if acpi_cpufreq_online is positive. Trying to call cpuhp_remove_state_nocalls(0) will cause a BUG(). Signed-off-by: Boris Ostrovsky Reviewed-by: Thomas Gleixner Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/acpi-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/acpi-cpufreq.c b/drivers/cpufreq/acpi-cpufreq.c index 3a98702b7445..3a2ca0f79daf 100644 --- a/drivers/cpufreq/acpi-cpufreq.c +++ b/drivers/cpufreq/acpi-cpufreq.c @@ -930,7 +930,7 @@ static void __init acpi_cpufreq_boost_init(void) static void acpi_cpufreq_boost_exit(void) { - if (acpi_cpufreq_online >= 0) + if (acpi_cpufreq_online > 0) cpuhp_remove_state_nocalls(acpi_cpufreq_online); } -- cgit v1.2.3 From adec57c61c2421d9d06c1fa8dd1ff7ed4fd2ca1b Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Fri, 16 Dec 2016 10:06:15 +0100 Subject: cpufreq: s3c64xx: remove incorrect __init annotation s3c64xx_cpufreq_config_regulator is incorrectly annotated as __init, since the caller is also not init: WARNING: vmlinux.o(.text+0x92fe1c): Section mismatch in reference from the function s3c64xx_cpufreq_driver_init() to the function .init.text:s3c64xx_cpufreq_config_regulator() With modern gcc versions, the function gets inline, so we don't see the warning, this only happens with gcc-4.6 and older. Signed-off-by: Arnd Bergmann Reviewed-by: Krzysztof Kozlowski Signed-off-by: Rafael J. Wysocki --- drivers/cpufreq/s3c64xx-cpufreq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/cpufreq/s3c64xx-cpufreq.c b/drivers/cpufreq/s3c64xx-cpufreq.c index 176e84cc3991..0cb9040eca49 100644 --- a/drivers/cpufreq/s3c64xx-cpufreq.c +++ b/drivers/cpufreq/s3c64xx-cpufreq.c @@ -107,7 +107,7 @@ static int s3c64xx_cpufreq_set_target(struct cpufreq_policy *policy, } #ifdef CONFIG_REGULATOR -static void __init s3c64xx_cpufreq_config_regulator(void) +static void s3c64xx_cpufreq_config_regulator(void) { int count, v, i, found; struct cpufreq_frequency_table *freq; -- cgit v1.2.3 From e85baa8868b016513c0f5738362402495b1a66a5 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Fri, 11 Nov 2016 14:22:36 +0000 Subject: mmc: sd: Meet alignment requirements for raw_ssr DMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mmc_read_ssr() function results in DMA to the raw_ssr member of struct mmc_card, which is not guaranteed to be cache line aligned & thus might not meet the requirements set out in Documentation/DMA-API.txt: Warnings: Memory coherency operates at a granularity called the cache line width. In order for memory mapped by this API to operate correctly, the mapped region must begin exactly on a cache line boundary and end exactly on one (to prevent two separately mapped regions from sharing a single cache line). Since the cache line size may not be known at compile time, the API will not enforce this requirement. Therefore, it is recommended that driver writers who don't take special care to determine the cache line size at run time only map virtual regions that begin and end on page boundaries (which are guaranteed also to be cache line boundaries). On some systems where DMA is non-coherent this can lead to us losing data that shares cache lines with the raw_ssr array. Fix this by kmalloc'ing a temporary buffer to perform DMA into. kmalloc will ensure the buffer is suitably aligned, allowing the DMA to be performed without any loss of data. Signed-off-by: Paul Burton Fixes: 5275a652d296 ("mmc: sd: Export SD Status via “ssr” device attribute") Cc: Signed-off-by: Ulf Hansson --- drivers/mmc/core/sd.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index deb90c2ff6b4..a614f37faf27 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -223,6 +223,7 @@ static int mmc_decode_scr(struct mmc_card *card) static int mmc_read_ssr(struct mmc_card *card) { unsigned int au, es, et, eo; + u32 *raw_ssr; int i; if (!(card->csd.cmdclass & CCC_APP_SPEC)) { @@ -231,14 +232,21 @@ static int mmc_read_ssr(struct mmc_card *card) return 0; } - if (mmc_app_sd_status(card, card->raw_ssr)) { + raw_ssr = kmalloc(sizeof(card->raw_ssr), GFP_KERNEL); + if (!raw_ssr) + return -ENOMEM; + + if (mmc_app_sd_status(card, raw_ssr)) { pr_warn("%s: problem reading SD Status register\n", mmc_hostname(card->host)); + kfree(raw_ssr); return 0; } for (i = 0; i < 16; i++) - card->raw_ssr[i] = be32_to_cpu(card->raw_ssr[i]); + card->raw_ssr[i] = be32_to_cpu(raw_ssr[i]); + + kfree(raw_ssr); /* * UNSTUFF_BITS only works with four u32s so we have to offset the -- cgit v1.2.3 From e6282aef7b89a11d26e731060c4409b7aac278bf Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Mon, 19 Dec 2016 11:37:50 -0500 Subject: nvme: simplify stripe quirk Some OEMs believe they own the Identify Controller vendor specific region and will repurpose it with their own values. While not common, we can't rely on the PCI VID:DID to tell use how to decode the field we reserved for this as the stripe size so we need to do something else for the list of devices using this quirk. The field was supposed to allow flexibility on the device's back-end striping, but it turned out that never materialized; the chunk is always the same as MDTS in the products subscribing to this quirk, so this patch removes the stripe_size field and sets the chunk to the max hw transfer size for the devices using this quirk. Signed-off-by: Keith Busch Signed-off-by: Christoph Hellwig --- drivers/nvme/host/core.c | 17 ++--------------- drivers/nvme/host/nvme.h | 1 - 2 files changed, 2 insertions(+), 16 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index b40cfb076f02..2fc86dc7a8df 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -1193,8 +1193,8 @@ static void nvme_set_queue_limits(struct nvme_ctrl *ctrl, blk_queue_max_hw_sectors(q, ctrl->max_hw_sectors); blk_queue_max_segments(q, min_t(u32, max_segments, USHRT_MAX)); } - if (ctrl->stripe_size) - blk_queue_chunk_sectors(q, ctrl->stripe_size >> 9); + if (ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) + blk_queue_chunk_sectors(q, ctrl->max_hw_sectors); blk_queue_virt_boundary(q, ctrl->page_size - 1); if (ctrl->vwc & NVME_CTRL_VWC_PRESENT) vwc = true; @@ -1250,19 +1250,6 @@ int nvme_init_identify(struct nvme_ctrl *ctrl) ctrl->max_hw_sectors = min_not_zero(ctrl->max_hw_sectors, max_hw_sectors); - if ((ctrl->quirks & NVME_QUIRK_STRIPE_SIZE) && id->vs[3]) { - unsigned int max_hw_sectors; - - ctrl->stripe_size = 1 << (id->vs[3] + page_shift); - max_hw_sectors = ctrl->stripe_size >> (page_shift - 9); - if (ctrl->max_hw_sectors) { - ctrl->max_hw_sectors = min(max_hw_sectors, - ctrl->max_hw_sectors); - } else { - ctrl->max_hw_sectors = max_hw_sectors; - } - } - nvme_set_queue_limits(ctrl, ctrl->admin_q); ctrl->sgls = le32_to_cpu(id->sgls); ctrl->kas = le16_to_cpu(id->kas); diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index bd5321441d12..6377e14586dc 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -135,7 +135,6 @@ struct nvme_ctrl { u32 page_size; u32 max_hw_sectors; - u32 stripe_size; u16 oncs; u16 vid; atomic_t abort_limit; -- cgit v1.2.3 From 9fa196e7fc7a0f12329d5346164abb27f026991c Mon Sep 17 00:00:00 2001 From: Max Gurtovoy Date: Mon, 19 Dec 2016 16:18:24 +0200 Subject: nvme/pci: Fix whitespace problem Convert to tabs and remove unneeded whitespaces. Signed-off-by: Max Gurtovoy Signed-off-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 2fd7dc2e8fc4..7d6c87028568 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -50,7 +50,7 @@ #define NVME_AQ_DEPTH 256 #define SQ_SIZE(depth) (depth * sizeof(struct nvme_command)) #define CQ_SIZE(depth) (depth * sizeof(struct nvme_completion)) - + /* * We handle AEN commands ourselves and don't even let the * block layer know about them. @@ -1909,10 +1909,10 @@ static int nvme_dev_map(struct nvme_dev *dev) if (!dev->bar) goto release; - return 0; + return 0; release: - pci_release_mem_regions(pdev); - return -ENODEV; + pci_release_mem_regions(pdev); + return -ENODEV; } static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id) -- cgit v1.2.3 From ff13b39ecf726715a96fcd3c23e50eb792ef6516 Mon Sep 17 00:00:00 2001 From: Keith Busch Date: Fri, 9 Dec 2016 12:08:58 -0500 Subject: nvme/pci: Delete misleading queue-wrap comment It is not theoretically possible for this driver to wrap twice while processing completions. The driver allocates only 'queue_depth - 1' tags, so there can never be more than that to reap when processing a completion queue. Removing this misleading comment makes it a little less likely people with broken controllers will blame the driver for their spurious interrupts. Signed-off-by: Keith Busch Signed-off-by: Christoph Hellwig --- drivers/nvme/host/pci.c | 7 ------- 1 file changed, 7 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c index 7d6c87028568..151ce59f4ffb 100644 --- a/drivers/nvme/host/pci.c +++ b/drivers/nvme/host/pci.c @@ -712,15 +712,8 @@ static void __nvme_process_cq(struct nvme_queue *nvmeq, unsigned int *tag) req = blk_mq_tag_to_rq(*nvmeq->tags, cqe.command_id); nvme_req(req)->result = cqe.result; blk_mq_complete_request(req, le16_to_cpu(cqe.status) >> 1); - } - /* If the controller ignores the cq head doorbell and continuously - * writes to the queue, it is theoretically possible to wrap around - * the queue twice and mistakenly return IRQ_NONE. Linux only - * requires that 0.1% of your interrupts are handled, so this isn't - * a big problem. - */ if (head == nvmeq->cq_head && phase == nvmeq->cq_phase) return; -- cgit v1.2.3 From 2c473a9d02fbe881506d5d43bc7edb776f2f46f5 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 6 Dec 2016 10:14:35 -0800 Subject: nvme/scsi: Remove START STOP emulation Now that the broken power state control is gone, it appears to serve no purpose. Just delete it. NVME devices don't have a concept of started vs stopped anyway. Signed-off-by: Andy Lutomirski Reviewed-by: Keith Busch Signed-off-by: Christoph Hellwig --- drivers/nvme/host/scsi.c | 27 --------------------------- 1 file changed, 27 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/scsi.c b/drivers/nvme/host/scsi.c index b71e95044b43..a5c09e703bd8 100644 --- a/drivers/nvme/host/scsi.c +++ b/drivers/nvme/host/scsi.c @@ -2160,30 +2160,6 @@ static int nvme_trans_synchronize_cache(struct nvme_ns *ns, return nvme_trans_status_code(hdr, nvme_sc); } -static int nvme_trans_start_stop(struct nvme_ns *ns, struct sg_io_hdr *hdr, - u8 *cmd) -{ - u8 immed, no_flush; - - immed = cmd[1] & 0x01; - no_flush = cmd[4] & 0x04; - - if (immed != 0) { - return nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION, - ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB, - SCSI_ASCQ_CAUSE_NOT_REPORTABLE); - } else { - if (no_flush == 0) { - /* Issue NVME FLUSH command prior to START STOP UNIT */ - int res = nvme_trans_synchronize_cache(ns, hdr); - if (res) - return res; - } - - return 0; - } -} - static int nvme_trans_format_unit(struct nvme_ns *ns, struct sg_io_hdr *hdr, u8 *cmd) { @@ -2439,9 +2415,6 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr) case SECURITY_PROTOCOL_OUT: retcode = nvme_trans_security_protocol(ns, hdr, cmd); break; - case START_STOP: - retcode = nvme_trans_start_stop(ns, hdr, cmd); - break; case SYNCHRONIZE_CACHE: retcode = nvme_trans_synchronize_cache(ns, hdr); break; -- cgit v1.2.3 From c703489885218900579279cec4b4ab8e7fce383b Mon Sep 17 00:00:00 2001 From: James Smart Date: Tue, 20 Dec 2016 11:06:08 -0800 Subject: nvme/fc: correct some printk information Dan Carpenters's tool caught a pointer reference - should have been just ptr, not &ptr. Don't bother. Remove the pointer value in the printf. Its irrelevant. Signed-off-by: James Smart Reported-by: Dan Carpenter Signed-off-by: Christoph Hellwig --- drivers/nvme/host/fc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 771e2e761872..827c2b57e5bb 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -2401,8 +2401,8 @@ __nvme_fc_create_ctrl(struct device *dev, struct nvmf_ctrl_options *opts, WARN_ON_ONCE(!changed); dev_info(ctrl->ctrl.device, - "NVME-FC{%d}: new ctrl: NQN \"%s\" (%p)\n", - ctrl->cnum, ctrl->ctrl.opts->subsysnqn, &ctrl); + "NVME-FC{%d}: new ctrl: NQN \"%s\"\n", + ctrl->cnum, ctrl->ctrl.opts->subsysnqn); kref_get(&ctrl->ctrl.kref); -- cgit v1.2.3 From 17a1ec08ce7074f05795e5c32a3e5bc9a797bbf8 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Thu, 15 Dec 2016 14:20:48 +0100 Subject: nvme/fc: simplify error handling of nvme_fc_create_hw_io_queues Simplify the error handling of nvme_fc_create_hw_io_queues(), this saves us one variable and one level of indentation. Signed-off-by: Johannes Thumshirn Reviwed-by: James Smart Signed-off-by: Christoph Hellwig --- drivers/nvme/host/fc.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 827c2b57e5bb..aa0bc60810a7 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -1491,19 +1491,20 @@ static int nvme_fc_create_hw_io_queues(struct nvme_fc_ctrl *ctrl, u16 qsize) { struct nvme_fc_queue *queue = &ctrl->queues[1]; - int i, j, ret; + int i, ret; for (i = 1; i < ctrl->queue_count; i++, queue++) { ret = __nvme_fc_create_hw_queue(ctrl, queue, i, qsize); - if (ret) { - for (j = i-1; j >= 0; j--) - __nvme_fc_delete_hw_queue(ctrl, - &ctrl->queues[j], j); - return ret; - } + if (ret) + goto delete_queues; } return 0; + +delete_queues: + for (; i >= 0; i--) + __nvme_fc_delete_hw_queue(ctrl, &ctrl->queues[i], i); + return ret; } static int -- cgit v1.2.3 From 6c73f949300f17851f53fa80c9d1611ccd6909d3 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Fri, 9 Dec 2016 12:59:46 -0700 Subject: nvmet: fix KATO offset in Set Features The Set Features implementation for Keep Alive Timer was using the wrong structure when retrieving the KATO value; it was treating the Set Features command as a Property Set command. The NVMe spec defines the Keep Alive Timer feature as having one input in CDW11 (4 bytes at offset 44 in the command) whereas the code was reading 8 bytes at offset 48. Since the Linux NVMe over Fabrics host never sets this feature, this code has presumably never been tested. Signed-off-by: Daniel Verkamp Signed-off-by: Christoph Hellwig --- drivers/nvme/target/admin-cmd.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/target/admin-cmd.c b/drivers/nvme/target/admin-cmd.c index ec1ad2aa0a4c..95ae52390478 100644 --- a/drivers/nvme/target/admin-cmd.c +++ b/drivers/nvme/target/admin-cmd.c @@ -382,7 +382,6 @@ static void nvmet_execute_set_features(struct nvmet_req *req) { struct nvmet_subsys *subsys = req->sq->ctrl->subsys; u32 cdw10 = le32_to_cpu(req->cmd->common.cdw10[0]); - u64 val; u32 val32; u16 status = 0; @@ -392,8 +391,7 @@ static void nvmet_execute_set_features(struct nvmet_req *req) (subsys->max_qid - 1) | ((subsys->max_qid - 1) << 16)); break; case NVME_FEAT_KATO: - val = le64_to_cpu(req->cmd->prop_set.value); - val32 = val & 0xffff; + val32 = le32_to_cpu(req->cmd->common.cdw10[1]); req->sq->ctrl->kato = DIV_ROUND_UP(val32, 1000); nvmet_set_result(req, req->sq->ctrl->kato); break; -- cgit v1.2.3 From 7c3a23b85cac5f3caa531f369c1e3a5f1a8b555f Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 9 Dec 2016 14:59:47 +0000 Subject: nvmet/fcloop: remove some logically dead code performing redundant ret checks The check to see if ret is non-zero and return this rather than count is redundant in two occassions. It is redundant because prior to this check, the return code ret is already checked for a non-zero error return value and we return from the function at that point. Signed-off-by: Colin Ian King Reviewed-off-by: James Smart Signed-off-by: Christoph Hellwig --- drivers/nvme/target/fcloop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/nvme/target/fcloop.c b/drivers/nvme/target/fcloop.c index bcb8ebeb01c5..4e8e6a22bce1 100644 --- a/drivers/nvme/target/fcloop.c +++ b/drivers/nvme/target/fcloop.c @@ -845,7 +845,7 @@ fcloop_create_remote_port(struct device *dev, struct device_attribute *attr, rport->lport = nport->lport; nport->rport = rport; - return ret ? ret : count; + return count; } @@ -952,7 +952,7 @@ fcloop_create_target_port(struct device *dev, struct device_attribute *attr, tport->lport = nport->lport; nport->tport = tport; - return ret ? ret : count; + return count; } -- cgit v1.2.3 From d1f1c0e289e1bc46cd6873ba6dd6c627f459e7fa Mon Sep 17 00:00:00 2001 From: Tobias Klausmann Date: Tue, 13 Dec 2016 18:08:07 +0100 Subject: ath9k: do not return early to fix rcu unlocking Starting with commit d94a461d7a7d ("ath9k: use ieee80211_tx_status_noskb where possible") the driver uses rcu_read_lock() && rcu_read_unlock(), yet on returning early in ath_tx_edma_tasklet() the unlock is missing leading to stalls and suspicious RCU usage: =============================== [ INFO: suspicious RCU usage. ] 4.9.0-rc8 #11 Not tainted ------------------------------- kernel/rcu/tree.c:705 Illegal idle entry in RCU read-side critical section.! other info that might help us debug this: RCU used illegally from idle CPU! rcu_scheduler_active = 1, debug_locks = 0 RCU used illegally from extended quiescent state! 1 lock held by swapper/7/0: #0: ( rcu_read_lock ){......} , at: [] ath_tx_edma_tasklet+0x0/0x450 [ath9k] stack backtrace: CPU: 7 PID: 0 Comm: swapper/7 Not tainted 4.9.0-rc8 #11 Hardware name: Acer Aspire V3-571G/VA50_HC_CR, BIOS V2.21 12/16/2013 ffff88025efc3f38 ffffffff8132b1e5 ffff88017ede4540 0000000000000001 ffff88025efc3f68 ffffffff810a25f7 ffff88025efcee60 ffff88017edebdd8 ffff88025eeb5400 0000000000000091 ffff88025efc3f88 ffffffff810c3cd4 Call Trace: [] dump_stack+0x68/0x93 [] lockdep_rcu_suspicious+0xd7/0x110 [] rcu_eqs_enter_common.constprop.85+0x154/0x200 [] rcu_irq_exit+0x44/0xa0 [] irq_exit+0x61/0xd0 [] do_IRQ+0x65/0x110 [] common_interrupt+0x89/0x89 [] ? cpuidle_enter_state+0x151/0x200 [] cpuidle_enter+0x12/0x20 [] call_cpuidle+0x1e/0x40 [] cpu_startup_entry+0x146/0x220 [] start_secondary+0x148/0x170 Signed-off-by: Tobias Klausmann Fixes: d94a461d7a7d ("ath9k: use ieee80211_tx_status_noskb where possible") Cc: # v4.9 Acked-by: Felix Fietkau Acked-by: Paul E. McKenney Tested-by: Gabriel Craciunescu Signed-off-by: Kalle Valo --- drivers/net/wireless/ath/ath9k/xmit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index 486afa98a5b8..4e2f3ac266c3 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -2713,7 +2713,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) fifo_list = &txq->txq_fifo[txq->txq_tailidx]; if (list_empty(fifo_list)) { ath_txq_unlock(sc, txq); - return; + break; } bf = list_first_entry(fifo_list, struct ath_buf, list); -- cgit v1.2.3 From 22b68b93ae2506bd56ee3bf232a51bc8ab955b56 Mon Sep 17 00:00:00 2001 From: Larry Finger Date: Mon, 19 Dec 2016 20:38:12 -0600 Subject: rtlwifi: Fix kernel oops introduced with commit e49656147359 With commit e49656147359 {"rtlwifi: Use dev_kfree_skb_irq instead of kfree_skb"), the method used to free an skb was changed because the kfree_skb() was inside a spinlock. What was forgotten is that kfree_skb() guards against a NULL value for the argument. Routine dev_kfree_skb_irq() does not, and a test is needed to prevent kernel panics. Fixes: e49656147359 ("rtlwifi: Use dev_kfree_skb_irq instead of kfree_skb") Signed-off-by: Larry Finger Cc: Stable # 4.9+ Cc: Wei Yongjun Signed-off-by: Kalle Valo --- drivers/net/wireless/realtek/rtlwifi/core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/wireless/realtek/rtlwifi/core.c b/drivers/net/wireless/realtek/rtlwifi/core.c index 2caa4ad04dba..ded1493fee9c 100644 --- a/drivers/net/wireless/realtek/rtlwifi/core.c +++ b/drivers/net/wireless/realtek/rtlwifi/core.c @@ -1829,7 +1829,8 @@ bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb) spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); pskb = __skb_dequeue(&ring->queue); - dev_kfree_skb_irq(pskb); + if (pskb) + dev_kfree_skb_irq(pskb); /*this is wrong, fill_tx_cmddesc needs update*/ pdesc = &ring->desc[0]; -- cgit v1.2.3 From 76b15923b777aa2660029629179550124c1fc40e Mon Sep 17 00:00:00 2001 From: Kalesh A P Date: Tue, 20 Dec 2016 10:14:30 -0500 Subject: be2net: Increase skb headroom size to 256 bytes The driver currently allocates 128 bytes of skb headroom. This was found to be insufficient with some configurations like Geneve tunnels, which resulted in skb head reallocations. Increase the headroom to 256 bytes to fix this. Signed-off-by: Kalesh A P Signed-off-by: Suresh Reddy Signed-off-by: David S. Miller --- drivers/net/ethernet/emulex/benet/be.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h index 6cfa63a5e9b4..4c30c44b242e 100644 --- a/drivers/net/ethernet/emulex/benet/be.h +++ b/drivers/net/ethernet/emulex/benet/be.h @@ -65,7 +65,7 @@ /* Number of bytes of an RX frame that are copied to skb->data */ #define BE_HDR_LEN ((u16) 64) /* allocate extra space to allow tunneling decapsulation without head reallocation */ -#define BE_RX_SKB_ALLOC_SIZE (BE_HDR_LEN + 64) +#define BE_RX_SKB_ALLOC_SIZE 256 #define BE_MAX_JUMBO_FRAME_SIZE 9018 #define BE_MIN_MTU 256 -- cgit v1.2.3 From f217bfde24077b6684e625dd618e3a522e6f272a Mon Sep 17 00:00:00 2001 From: Heiko Stübner Date: Tue, 20 Dec 2016 17:17:06 +0100 Subject: net: ethernet: stmmac: dwmac-rk: make clk enablement first in powerup Right now the dwmac-rk tries to set up the GRF-specific speed and link options before enabling clocks, phys etc and on previous socs this works because the GRF is supplied on the whole by one clock. On the rk3399 however the GRF (General Register Files) clock-supply has been split into multiple clocks and while there is no specific grf-gmac clock like for other sub-blocks, it seems the mac-specific portions are actually supplied by the general mac clock. This results in hangs on rk3399 boards if the driver is build as module. When built in te problem of course doesn't surface, as the clocks are of course still on at the stage before clock_disable_unused. To solve this, simply move the clock enablement to the first position in the powerup callback. This is also a good idea in general to enable clocks before everything else. Tested on rk3288, rk3368 and rk3399 the dwmac still works on all of them. Signed-off-by: Heiko Stuebner Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c index 77ab0a85f067..fa6e9704c077 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c @@ -864,6 +864,10 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv) int ret; struct device *dev = &bsp_priv->pdev->dev; + ret = gmac_clk_enable(bsp_priv, true); + if (ret) + return ret; + /*rmii or rgmii*/ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) { dev_info(dev, "init for RGMII\n"); @@ -880,10 +884,6 @@ static int rk_gmac_powerup(struct rk_priv_data *bsp_priv) if (ret) return ret; - ret = gmac_clk_enable(bsp_priv, true); - if (ret) - return ret; - pm_runtime_enable(dev); pm_runtime_get_sync(dev); -- cgit v1.2.3 From 8354491c9d5b06709384cea91d13019bf5e61449 Mon Sep 17 00:00:00 2001 From: Thomas Petazzoni Date: Wed, 21 Dec 2016 11:28:49 +0100 Subject: net: mvpp2: fix dma unmapping of TX buffers for fragments Since commit 71ce391dfb784 ("net: mvpp2: enable proper per-CPU TX buffers unmapping"), we are not correctly DMA unmapping TX buffers for fragments. Indeed, the mvpp2_txq_inc_put() function only stores in the txq_cpu->tx_buffs[] array the physical address of the buffer to be DMA-unmapped when skb != NULL. In addition, when DMA-unmapping, we use skb_headlen(skb) to get the size to be unmapped. Both of this works fine for TX descriptors that are associated directly to a SKB, but not the ones that are used for fragments, with a NULL pointer as skb: - We have a NULL physical address when calling DMA unmap - skb_headlen(skb) crashes because skb is NULL This causes random crashes when fragments are used. To solve this problem, we need to: - Store the physical address of the buffer to be unmapped unconditionally, regardless of whether it is tied to a SKB or not. - Store the length of the buffer to be unmapped, which requires a new field. Instead of adding a third array to store the length of the buffer to be unmapped, and as suggested by David Miller, this commit refactors the tx_buffs[] and tx_skb[] arrays of 'struct mvpp2_txq_pcpu' into a separate structure 'mvpp2_txq_pcpu_buf', to which a 'size' field is added. Therefore, instead of having three arrays to allocate/free, we have a single one, which also improve data locality, reducing the impact on the CPU cache. Fixes: 71ce391dfb784 ("net: mvpp2: enable proper per-CPU TX buffers unmapping") Reported-by: Raphael G Cc: Raphael G Cc: stable@vger.kernel.org Signed-off-by: Thomas Petazzoni Signed-off-by: David S. Miller --- drivers/net/ethernet/marvell/mvpp2.c | 59 ++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 29 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c index dabc5418efcc..cda04b3126bc 100644 --- a/drivers/net/ethernet/marvell/mvpp2.c +++ b/drivers/net/ethernet/marvell/mvpp2.c @@ -770,6 +770,17 @@ struct mvpp2_rx_desc { u32 reserved8; }; +struct mvpp2_txq_pcpu_buf { + /* Transmitted SKB */ + struct sk_buff *skb; + + /* Physical address of transmitted buffer */ + dma_addr_t phys; + + /* Size transmitted */ + size_t size; +}; + /* Per-CPU Tx queue control */ struct mvpp2_txq_pcpu { int cpu; @@ -785,11 +796,8 @@ struct mvpp2_txq_pcpu { /* Number of Tx DMA descriptors reserved for each CPU */ int reserved_num; - /* Array of transmitted skb */ - struct sk_buff **tx_skb; - - /* Array of transmitted buffers' physical addresses */ - dma_addr_t *tx_buffs; + /* Infos about transmitted buffers */ + struct mvpp2_txq_pcpu_buf *buffs; /* Index of last TX DMA descriptor that was inserted */ int txq_put_index; @@ -979,10 +987,11 @@ static void mvpp2_txq_inc_put(struct mvpp2_txq_pcpu *txq_pcpu, struct sk_buff *skb, struct mvpp2_tx_desc *tx_desc) { - txq_pcpu->tx_skb[txq_pcpu->txq_put_index] = skb; - if (skb) - txq_pcpu->tx_buffs[txq_pcpu->txq_put_index] = - tx_desc->buf_phys_addr; + struct mvpp2_txq_pcpu_buf *tx_buf = + txq_pcpu->buffs + txq_pcpu->txq_put_index; + tx_buf->skb = skb; + tx_buf->size = tx_desc->data_size; + tx_buf->phys = tx_desc->buf_phys_addr; txq_pcpu->txq_put_index++; if (txq_pcpu->txq_put_index == txq_pcpu->size) txq_pcpu->txq_put_index = 0; @@ -4401,17 +4410,16 @@ static void mvpp2_txq_bufs_free(struct mvpp2_port *port, int i; for (i = 0; i < num; i++) { - dma_addr_t buf_phys_addr = - txq_pcpu->tx_buffs[txq_pcpu->txq_get_index]; - struct sk_buff *skb = txq_pcpu->tx_skb[txq_pcpu->txq_get_index]; + struct mvpp2_txq_pcpu_buf *tx_buf = + txq_pcpu->buffs + txq_pcpu->txq_get_index; mvpp2_txq_inc_get(txq_pcpu); - dma_unmap_single(port->dev->dev.parent, buf_phys_addr, - skb_headlen(skb), DMA_TO_DEVICE); - if (!skb) + dma_unmap_single(port->dev->dev.parent, tx_buf->phys, + tx_buf->size, DMA_TO_DEVICE); + if (!tx_buf->skb) continue; - dev_kfree_skb_any(skb); + dev_kfree_skb_any(tx_buf->skb); } } @@ -4651,15 +4659,10 @@ static int mvpp2_txq_init(struct mvpp2_port *port, for_each_present_cpu(cpu) { txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); txq_pcpu->size = txq->size; - txq_pcpu->tx_skb = kmalloc(txq_pcpu->size * - sizeof(*txq_pcpu->tx_skb), - GFP_KERNEL); - if (!txq_pcpu->tx_skb) - goto error; - - txq_pcpu->tx_buffs = kmalloc(txq_pcpu->size * - sizeof(dma_addr_t), GFP_KERNEL); - if (!txq_pcpu->tx_buffs) + txq_pcpu->buffs = kmalloc(txq_pcpu->size * + sizeof(struct mvpp2_txq_pcpu_buf), + GFP_KERNEL); + if (!txq_pcpu->buffs) goto error; txq_pcpu->count = 0; @@ -4673,8 +4676,7 @@ static int mvpp2_txq_init(struct mvpp2_port *port, error: for_each_present_cpu(cpu) { txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); - kfree(txq_pcpu->tx_skb); - kfree(txq_pcpu->tx_buffs); + kfree(txq_pcpu->buffs); } dma_free_coherent(port->dev->dev.parent, @@ -4693,8 +4695,7 @@ static void mvpp2_txq_deinit(struct mvpp2_port *port, for_each_present_cpu(cpu) { txq_pcpu = per_cpu_ptr(txq->pcpu, cpu); - kfree(txq_pcpu->tx_skb); - kfree(txq_pcpu->tx_buffs); + kfree(txq_pcpu->buffs); } if (txq->descs) -- cgit v1.2.3 From 551cde192343a10c8fbd57c4cc8f0c4b6cd307e4 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Wed, 21 Dec 2016 16:03:23 +0000 Subject: net: fddi: skfp: use %p format specifier for addresses rather than %x Trivial fix: Addresses should be printed using the %p format specifier rather than using %x. Signed-off-by: Colin Ian King Signed-off-by: David S. Miller --- drivers/net/fddi/skfp/hwmtm.c | 12 ++++++------ drivers/net/fddi/skfp/pmf.c | 2 +- drivers/net/fddi/skfp/smt.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/fddi/skfp/hwmtm.c b/drivers/net/fddi/skfp/hwmtm.c index e26398b5a7dc..d0a68bdd5f63 100644 --- a/drivers/net/fddi/skfp/hwmtm.c +++ b/drivers/net/fddi/skfp/hwmtm.c @@ -1483,7 +1483,7 @@ void mac_drv_clear_rx_queue(struct s_smc *smc) r = queue->rx_curr_get ; while (queue->rx_used) { DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORCPU) ; - DB_RX("switch OWN bit of RxD 0x%x ",r,0,5) ; + DB_RX("switch OWN bit of RxD 0x%p ",r,0,5) ; r->rxd_rbctrl &= ~cpu_to_le32(BMU_OWN) ; frag_count = 1 ; DRV_BUF_FLUSH(r,DDI_DMA_SYNC_FORDEV) ; @@ -1645,7 +1645,7 @@ void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len, DB_TX("hwm_tx_frag: len = %d, frame_status = %x ",len,frame_status,2) ; if (frame_status & LAN_TX) { /* '*t' is already defined */ - DB_TX("LAN_TX: TxD = %x, virt = %x ",t,virt,3) ; + DB_TX("LAN_TX: TxD = %p, virt = %p ",t,virt,3) ; t->txd_virt = virt ; t->txd_txdscr = cpu_to_le32(smc->os.hwm.tx_descr) ; t->txd_tbadr = cpu_to_le32(phys) ; @@ -1819,7 +1819,7 @@ void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc) __le32 tbctrl; NDD_TRACE("THSB",mb,fc,0) ; - DB_TX("smt_send_mbuf: mb = 0x%x, fc = 0x%x",mb,fc,4) ; + DB_TX("smt_send_mbuf: mb = 0x%p, fc = 0x%x",mb,fc,4) ; mb->sm_off-- ; /* set to fc */ mb->sm_len++ ; /* + fc */ @@ -1960,7 +1960,7 @@ static void mac_drv_clear_txd(struct s_smc *smc) do { DRV_BUF_FLUSH(t1,DDI_DMA_SYNC_FORCPU) ; - DB_TX("check OWN/EOF bit of TxD 0x%x",t1,0,5) ; + DB_TX("check OWN/EOF bit of TxD 0x%p",t1,0,5) ; tbctrl = le32_to_cpu(CR_READ(t1->txd_tbctrl)); if (tbctrl & BMU_OWN || !queue->tx_used){ @@ -1988,7 +1988,7 @@ static void mac_drv_clear_txd(struct s_smc *smc) } else { #ifndef PASS_1ST_TXD_2_TX_COMP - DB_TX("mac_drv_tx_comp for TxD 0x%x",t2,0,4) ; + DB_TX("mac_drv_tx_comp for TxD 0x%p",t2,0,4) ; mac_drv_tx_complete(smc,t2) ; #else DB_TX("mac_drv_tx_comp for TxD 0x%x", @@ -2052,7 +2052,7 @@ void mac_drv_clear_tx_queue(struct s_smc *smc) tx_used = queue->tx_used ; while (tx_used) { DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORCPU) ; - DB_TX("switch OWN bit of TxD 0x%x ",t,0,5) ; + DB_TX("switch OWN bit of TxD 0x%p ",t,0,5) ; t->txd_tbctrl &= ~cpu_to_le32(BMU_OWN) ; DRV_BUF_FLUSH(t,DDI_DMA_SYNC_FORDEV) ; t = t->txd_next ; diff --git a/drivers/net/fddi/skfp/pmf.c b/drivers/net/fddi/skfp/pmf.c index 441b4dc79450..52fa162a31e0 100644 --- a/drivers/net/fddi/skfp/pmf.c +++ b/drivers/net/fddi/skfp/pmf.c @@ -284,7 +284,7 @@ void smt_pmf_received_pack(struct s_smc *smc, SMbuf *mb, int local) SMbuf *reply ; sm = smtod(mb,struct smt_header *) ; - DB_SMT("SMT: processing PMF frame at %x len %d\n",sm,mb->sm_len) ; + DB_SMT("SMT: processing PMF frame at %p len %d\n",sm,mb->sm_len) ; #ifdef DEBUG dump_smt(smc,sm,"PMF Received") ; #endif diff --git a/drivers/net/fddi/skfp/smt.c b/drivers/net/fddi/skfp/smt.c index cd78b7cacc75..e80a08903fcf 100644 --- a/drivers/net/fddi/skfp/smt.c +++ b/drivers/net/fddi/skfp/smt.c @@ -504,7 +504,7 @@ void smt_received_pack(struct s_smc *smc, SMbuf *mb, int fs) #endif smt_swap_para(sm,(int) mb->sm_len,1) ; - DB_SMT("SMT : received packet [%s] at 0x%x\n", + DB_SMT("SMT : received packet [%s] at 0x%p\n", smt_type_name[m_fc(mb) & 0xf],sm) ; DB_SMT("SMT : version %d, class %s\n",sm->smt_version, smt_class_name[(sm->smt_class>LAST_CLASS)?0 : sm->smt_class]) ; -- cgit v1.2.3 From e2a33c34ddff22ee208d80abdd12b88a98d6cb60 Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Thu, 15 Dec 2016 12:00:27 -0500 Subject: clk: renesas: mstp: Support 8-bit registers for r7s72100 The RZ/A1 is different than the other Renesas SOCs because the MSTP registers are 8-bit instead of 32-bit and if you try writing values as 32-bit nothing happens...meaning this driver never worked for r7s72100. Fixes: b6face404f38 ("ARM: shmobile: r7s72100: add essential clock nodes to dtsi") Signed-off-by: Chris Brandt Reviewed-by: Geert Uytterhoeven Tested-by: Geert Uytterhoeven Acked-by: Kuninori Morimoto Signed-off-by: Stephen Boyd --- drivers/clk/renesas/clk-mstp.c | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 9375777776d9..b533f99550e1 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -37,12 +37,14 @@ * @smstpcr: module stop control register * @mstpsr: module stop status register (optional) * @lock: protects writes to SMSTPCR + * @width_8bit: registers are 8-bit, not 32-bit */ struct mstp_clock_group { struct clk_onecell_data data; void __iomem *smstpcr; void __iomem *mstpsr; spinlock_t lock; + bool width_8bit; }; /** @@ -59,6 +61,18 @@ struct mstp_clock { #define to_mstp_clock(_hw) container_of(_hw, struct mstp_clock, hw) +static inline u32 cpg_mstp_read(struct mstp_clock_group *group, + u32 __iomem *reg) +{ + return group->width_8bit ? readb(reg) : clk_readl(reg); +} + +static inline void cpg_mstp_write(struct mstp_clock_group *group, u32 val, + u32 __iomem *reg) +{ + group->width_8bit ? writeb(val, reg) : clk_writel(val, reg); +} + static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) { struct mstp_clock *clock = to_mstp_clock(hw); @@ -70,12 +84,12 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) spin_lock_irqsave(&group->lock, flags); - value = clk_readl(group->smstpcr); + value = cpg_mstp_read(group, group->smstpcr); if (enable) value &= ~bitmask; else value |= bitmask; - clk_writel(value, group->smstpcr); + cpg_mstp_write(group, value, group->smstpcr); spin_unlock_irqrestore(&group->lock, flags); @@ -83,7 +97,7 @@ static int cpg_mstp_clock_endisable(struct clk_hw *hw, bool enable) return 0; for (i = 1000; i > 0; --i) { - if (!(clk_readl(group->mstpsr) & bitmask)) + if (!(cpg_mstp_read(group, group->mstpsr) & bitmask)) break; cpu_relax(); } @@ -114,9 +128,9 @@ static int cpg_mstp_clock_is_enabled(struct clk_hw *hw) u32 value; if (group->mstpsr) - value = clk_readl(group->mstpsr); + value = cpg_mstp_read(group, group->mstpsr); else - value = clk_readl(group->smstpcr); + value = cpg_mstp_read(group, group->smstpcr); return !(value & BIT(clock->bit_index)); } @@ -188,6 +202,9 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) return; } + if (of_device_is_compatible(np, "renesas,r7s72100-mstp-clocks")) + group->width_8bit = true; + for (i = 0; i < MSTP_MAX_CLOCKS; ++i) clks[i] = ERR_PTR(-ENOENT); -- cgit v1.2.3 From 3868f132cce6abab089fd6b12d6a7333712ade83 Mon Sep 17 00:00:00 2001 From: Gabriel Fernandez Date: Wed, 14 Dec 2016 15:22:28 +0100 Subject: clk: stm32f4: Use CLK_OF_DECLARE_DRIVER initialization method Clock and reset controller use same compatible strings (same IP). Since commit 989eafd0b609 ("clk: core: Avoid double initialization of clocks") the OF core flags clock controllers registered with the CLK_OF_DECLARE() macro as OF_POPULATED, so platform devices with the same compatible string will not be registered. Signed-off-by: Gabriel Fernandez Signed-off-by: Stephen Boyd --- drivers/clk/clk-stm32f4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index 5eb05dbf59b8..fc585f370549 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -768,5 +768,5 @@ fail: kfree(clks); iounmap(base); } -CLK_OF_DECLARE(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); -CLK_OF_DECLARE(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE_DRIVER(stm32f42xx_rcc, "st,stm32f42xx-rcc", stm32f4_rcc_init); +CLK_OF_DECLARE_DRIVER(stm32f46xx_rcc, "st,stm32f469-rcc", stm32f4_rcc_init); -- cgit v1.2.3 From 2f60b28831c7e63759b59113898e6fe4dc90dd43 Mon Sep 17 00:00:00 2001 From: Geliang Tang Date: Tue, 20 Dec 2016 22:02:20 +0800 Subject: xen/evtchn: use rb_entry() To make the code clearer, use rb_entry() instead of container_of() to deal with rbtree. Signed-off-by: Geliang Tang Reviewed-by: Juergen Gross Signed-off-by: Juergen Gross --- drivers/xen/evtchn.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/evtchn.c b/drivers/xen/evtchn.c index e8c7f09d01be..6890897a6f30 100644 --- a/drivers/xen/evtchn.c +++ b/drivers/xen/evtchn.c @@ -125,7 +125,7 @@ static int add_evtchn(struct per_user_data *u, struct user_evtchn *evtchn) while (*new) { struct user_evtchn *this; - this = container_of(*new, struct user_evtchn, node); + this = rb_entry(*new, struct user_evtchn, node); parent = *new; if (this->port < evtchn->port) @@ -157,7 +157,7 @@ static struct user_evtchn *find_evtchn(struct per_user_data *u, unsigned port) while (node) { struct user_evtchn *evtchn; - evtchn = container_of(node, struct user_evtchn, node); + evtchn = rb_entry(node, struct user_evtchn, node); if (evtchn->port < port) node = node->rb_left; -- cgit v1.2.3 From 61f51b7b20f631ef8fe744bc0412d4eb5194b6a9 Mon Sep 17 00:00:00 2001 From: Chien Tin Tung Date: Wed, 21 Dec 2016 08:53:46 -0600 Subject: i40iw: Set 128B as the only supported RQ WQE size RQ WQE size other than 128B is not supported. Correct RQ size calculation to use 128B only. Since this breaks ABI, add additional code to provide compatibility with v4 user provider, libi40iw. Signed-off-by: Chien Tin Tung Signed-off-by: Henry Orosco Signed-off-by: Doug Ledford --- drivers/infiniband/hw/i40iw/i40iw_ctrl.c | 25 ++++++++++++++++++++----- drivers/infiniband/hw/i40iw/i40iw_puda.c | 2 +- drivers/infiniband/hw/i40iw/i40iw_type.h | 4 +++- drivers/infiniband/hw/i40iw/i40iw_ucontext.h | 4 ++-- drivers/infiniband/hw/i40iw/i40iw_uk.c | 17 ++++++++++++----- drivers/infiniband/hw/i40iw/i40iw_user.h | 4 +++- drivers/infiniband/hw/i40iw/i40iw_verbs.c | 21 +++++++++++---------- drivers/infiniband/hw/i40iw/i40iw_verbs.h | 1 + 8 files changed, 53 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c index 392f78384a60..98923a8cf86d 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ctrl.c +++ b/drivers/infiniband/hw/i40iw/i40iw_ctrl.c @@ -358,13 +358,16 @@ void i40iw_qp_add_qos(struct i40iw_sc_qp *qp) * @dev: sc device struct * @pd: sc pd ptr * @pd_id: pd_id for allocated pd + * @abi_ver: ABI version from user context, -1 if not valid */ static void i40iw_sc_pd_init(struct i40iw_sc_dev *dev, struct i40iw_sc_pd *pd, - u16 pd_id) + u16 pd_id, + int abi_ver) { pd->size = sizeof(*pd); pd->pd_id = pd_id; + pd->abi_ver = abi_ver; pd->dev = dev; } @@ -2252,6 +2255,7 @@ static enum i40iw_status_code i40iw_sc_qp_init(struct i40iw_sc_qp *qp, offset); info->qp_uk_init_info.wqe_alloc_reg = wqe_alloc_reg; + info->qp_uk_init_info.abi_ver = qp->pd->abi_ver; ret_code = i40iw_qp_uk_init(&qp->qp_uk, &info->qp_uk_init_info); if (ret_code) return ret_code; @@ -2270,10 +2274,21 @@ static enum i40iw_status_code i40iw_sc_qp_init(struct i40iw_sc_qp *qp, false); i40iw_debug(qp->dev, I40IW_DEBUG_WQE, "%s: hw_sq_size[%04d] sq_ring.size[%04d]\n", __func__, qp->hw_sq_size, qp->qp_uk.sq_ring.size); - ret_code = i40iw_fragcnt_to_wqesize_rq(qp->qp_uk.max_rq_frag_cnt, - &wqe_size); - if (ret_code) - return ret_code; + + switch (qp->pd->abi_ver) { + case 4: + ret_code = i40iw_fragcnt_to_wqesize_rq(qp->qp_uk.max_rq_frag_cnt, + &wqe_size); + if (ret_code) + return ret_code; + break; + case 5: /* fallthrough until next ABI version */ + default: + if (qp->qp_uk.max_rq_frag_cnt > I40IW_MAX_WQ_FRAGMENT_COUNT) + return I40IW_ERR_INVALID_FRAG_COUNT; + wqe_size = I40IW_MAX_WQE_SIZE_RQ; + break; + } qp->hw_rq_size = i40iw_get_encoded_wqe_size(qp->qp_uk.rq_size * (wqe_size / I40IW_QP_WQE_MIN_SIZE), false); i40iw_debug(qp->dev, I40IW_DEBUG_WQE, diff --git a/drivers/infiniband/hw/i40iw/i40iw_puda.c b/drivers/infiniband/hw/i40iw/i40iw_puda.c index 449ba8c81ce7..db41ab40da9c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_puda.c +++ b/drivers/infiniband/hw/i40iw/i40iw_puda.c @@ -930,7 +930,7 @@ enum i40iw_status_code i40iw_puda_create_rsrc(struct i40iw_sc_vsi *vsi, INIT_LIST_HEAD(&rsrc->txpend); rsrc->tx_wqe_avail_cnt = info->sq_size - 1; - dev->iw_pd_ops->pd_init(dev, &rsrc->sc_pd, info->pd_id); + dev->iw_pd_ops->pd_init(dev, &rsrc->sc_pd, info->pd_id, -1); rsrc->qp_id = info->qp_id; rsrc->cq_id = info->cq_id; rsrc->sq_size = info->sq_size; diff --git a/drivers/infiniband/hw/i40iw/i40iw_type.h b/drivers/infiniband/hw/i40iw/i40iw_type.h index f3f8e9cc3c05..7b76259752b0 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_type.h +++ b/drivers/infiniband/hw/i40iw/i40iw_type.h @@ -280,6 +280,7 @@ struct i40iw_sc_pd { u32 size; struct i40iw_sc_dev *dev; u16 pd_id; + int abi_ver; }; struct i40iw_cqp_quanta { @@ -852,6 +853,7 @@ struct i40iw_qp_init_info { u64 host_ctx_pa; u64 q2_pa; u64 shadow_area_pa; + int abi_ver; u8 sq_tph_val; u8 rq_tph_val; u8 type; @@ -1051,7 +1053,7 @@ struct i40iw_aeq_ops { }; struct i40iw_pd_ops { - void (*pd_init)(struct i40iw_sc_dev *, struct i40iw_sc_pd *, u16); + void (*pd_init)(struct i40iw_sc_dev *, struct i40iw_sc_pd *, u16, int); }; struct i40iw_priv_qp_ops { diff --git a/drivers/infiniband/hw/i40iw/i40iw_ucontext.h b/drivers/infiniband/hw/i40iw/i40iw_ucontext.h index 12acd688def4..57d3f1d11ff1 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_ucontext.h +++ b/drivers/infiniband/hw/i40iw/i40iw_ucontext.h @@ -39,8 +39,8 @@ #include -#define I40IW_ABI_USERSPACE_VER 4 -#define I40IW_ABI_KERNEL_VER 4 +#define I40IW_ABI_VER 5 + struct i40iw_alloc_ucontext_req { __u32 reserved32; __u8 userspace_ver; diff --git a/drivers/infiniband/hw/i40iw/i40iw_uk.c b/drivers/infiniband/hw/i40iw/i40iw_uk.c index 4376cd628774..2800f796271c 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_uk.c +++ b/drivers/infiniband/hw/i40iw/i40iw_uk.c @@ -966,10 +966,6 @@ enum i40iw_status_code i40iw_qp_uk_init(struct i40iw_qp_uk *qp, if (ret_code) return ret_code; - ret_code = i40iw_get_wqe_shift(info->rq_size, info->max_rq_frag_cnt, 0, &rqshift); - if (ret_code) - return ret_code; - qp->sq_base = info->sq; qp->rq_base = info->rq; qp->shadow_area = info->shadow_area; @@ -998,8 +994,19 @@ enum i40iw_status_code i40iw_qp_uk_init(struct i40iw_qp_uk *qp, if (!qp->use_srq) { qp->rq_size = info->rq_size; qp->max_rq_frag_cnt = info->max_rq_frag_cnt; - qp->rq_wqe_size = rqshift; I40IW_RING_INIT(qp->rq_ring, qp->rq_size); + switch (info->abi_ver) { + case 4: + ret_code = i40iw_get_wqe_shift(info->rq_size, info->max_rq_frag_cnt, 0, &rqshift); + if (ret_code) + return ret_code; + break; + case 5: /* fallthrough until next ABI version */ + default: + rqshift = I40IW_MAX_RQ_WQE_SHIFT; + break; + } + qp->rq_wqe_size = rqshift; qp->rq_wqe_size_multiplier = 4 << rqshift; } qp->ops = iw_qp_uk_ops; diff --git a/drivers/infiniband/hw/i40iw/i40iw_user.h b/drivers/infiniband/hw/i40iw/i40iw_user.h index 80d9f464f65e..84be6f13b9c5 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_user.h +++ b/drivers/infiniband/hw/i40iw/i40iw_user.h @@ -76,6 +76,7 @@ enum i40iw_device_capabilities_const { I40IW_MAX_ORD_SIZE = 127, I40IW_MAX_WQ_ENTRIES = 2048, I40IW_Q2_BUFFER_SIZE = (248 + 100), + I40IW_MAX_WQE_SIZE_RQ = 128, I40IW_QP_CTX_SIZE = 248, I40IW_MAX_PDS = 32768 }; @@ -97,6 +98,7 @@ enum i40iw_device_capabilities_const { #define i40iw_address_list u64 * #define I40IW_MAX_MR_SIZE 0x10000000000L +#define I40IW_MAX_RQ_WQE_SHIFT 2 struct i40iw_qp_uk; struct i40iw_cq_uk; @@ -405,7 +407,7 @@ struct i40iw_qp_uk_init_info { u32 max_sq_frag_cnt; u32 max_rq_frag_cnt; u32 max_inline_data; - + int abi_ver; }; struct i40iw_cq_uk_init_info { diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.c b/drivers/infiniband/hw/i40iw/i40iw_verbs.c index 7368a50bbdaa..29e97df9e1a7 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.c +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.c @@ -145,9 +145,8 @@ static struct ib_ucontext *i40iw_alloc_ucontext(struct ib_device *ibdev, if (ib_copy_from_udata(&req, udata, sizeof(req))) return ERR_PTR(-EINVAL); - if (req.userspace_ver != I40IW_ABI_USERSPACE_VER) { - i40iw_pr_err("Invalid userspace driver version detected. Detected version %d, should be %d\n", - req.userspace_ver, I40IW_ABI_USERSPACE_VER); + if (req.userspace_ver < 4 || req.userspace_ver > I40IW_ABI_VER) { + i40iw_pr_err("Unsupported provider library version %u.\n", req.userspace_ver); return ERR_PTR(-EINVAL); } @@ -155,13 +154,14 @@ static struct ib_ucontext *i40iw_alloc_ucontext(struct ib_device *ibdev, uresp.max_qps = iwdev->max_qp; uresp.max_pds = iwdev->max_pd; uresp.wq_size = iwdev->max_qp_wr * 2; - uresp.kernel_ver = I40IW_ABI_KERNEL_VER; + uresp.kernel_ver = req.userspace_ver; ucontext = kzalloc(sizeof(*ucontext), GFP_KERNEL); if (!ucontext) return ERR_PTR(-ENOMEM); ucontext->iwdev = iwdev; + ucontext->abi_ver = req.userspace_ver; if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) { kfree(ucontext); @@ -333,6 +333,7 @@ static struct ib_pd *i40iw_alloc_pd(struct ib_device *ibdev, struct i40iw_sc_dev *dev = &iwdev->sc_dev; struct i40iw_alloc_pd_resp uresp; struct i40iw_sc_pd *sc_pd; + struct i40iw_ucontext *ucontext; u32 pd_id = 0; int err; @@ -353,15 +354,18 @@ static struct ib_pd *i40iw_alloc_pd(struct ib_device *ibdev, } sc_pd = &iwpd->sc_pd; - dev->iw_pd_ops->pd_init(dev, sc_pd, pd_id); if (context) { + ucontext = to_ucontext(context); + dev->iw_pd_ops->pd_init(dev, sc_pd, pd_id, ucontext->abi_ver); memset(&uresp, 0, sizeof(uresp)); uresp.pd_id = pd_id; if (ib_copy_to_udata(udata, &uresp, sizeof(uresp))) { err = -EFAULT; goto error; } + } else { + dev->iw_pd_ops->pd_init(dev, sc_pd, pd_id, -1); } i40iw_add_pdusecount(iwpd); @@ -518,7 +522,7 @@ static int i40iw_setup_kmode_qp(struct i40iw_device *iwdev, struct i40iw_dma_mem *mem = &iwqp->kqp.dma_mem; u32 sqdepth, rqdepth; u32 sq_size, rq_size; - u8 sqshift, rqshift; + u8 sqshift; u32 size; enum i40iw_status_code status; struct i40iw_qp_uk_init_info *ukinfo = &info->qp_uk_init_info; @@ -527,14 +531,11 @@ static int i40iw_setup_kmode_qp(struct i40iw_device *iwdev, rq_size = i40iw_qp_roundup(ukinfo->rq_size + 1); status = i40iw_get_wqe_shift(sq_size, ukinfo->max_sq_frag_cnt, ukinfo->max_inline_data, &sqshift); - if (!status) - status = i40iw_get_wqe_shift(rq_size, ukinfo->max_rq_frag_cnt, 0, &rqshift); - if (status) return -ENOMEM; sqdepth = sq_size << sqshift; - rqdepth = rq_size << rqshift; + rqdepth = rq_size << I40IW_MAX_RQ_WQE_SHIFT; size = sqdepth * sizeof(struct i40iw_sq_uk_wr_trk_info) + (rqdepth << 3); iwqp->kqp.wrid_mem = kzalloc(size, GFP_KERNEL); diff --git a/drivers/infiniband/hw/i40iw/i40iw_verbs.h b/drivers/infiniband/hw/i40iw/i40iw_verbs.h index 6549c939500f..07c3fec77de6 100644 --- a/drivers/infiniband/hw/i40iw/i40iw_verbs.h +++ b/drivers/infiniband/hw/i40iw/i40iw_verbs.h @@ -42,6 +42,7 @@ struct i40iw_ucontext { spinlock_t cq_reg_mem_list_lock; /* memory list for cq's */ struct list_head qp_reg_mem_list; spinlock_t qp_reg_mem_list_lock; /* memory list for qp's */ + int abi_ver; }; struct i40iw_pd { -- cgit v1.2.3 From c7eb3bced78fe83119b90d730ab58a572eb80e29 Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:33 +0200 Subject: qedr: configure the number of CQEs on CQ creation Configure ibcq->cqe when a CQ is created. Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 302fb05e6e6f..73df639755fa 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -890,6 +890,8 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, pbl_ptr = cq->q.pbl_tbl->pa; page_cnt = cq->q.pbl_info.num_pbes; + + cq->ibcq.cqe = chain_entries; } else { cq->cq_type = QEDR_CQ_TYPE_KERNEL; @@ -905,6 +907,7 @@ struct ib_cq *qedr_create_cq(struct ib_device *ibdev, page_cnt = qed_chain_get_page_cnt(&cq->pbl); pbl_ptr = qed_chain_get_pbl_phys(&cq->pbl); + cq->ibcq.cqe = cq->pbl.capacity; } qedr_init_cq_params(cq, ctx, dev, vector, chain_entries, page_cnt, -- cgit v1.2.3 From a121135973ca816821f4ff07aed523df82a91b8e Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:34 +0200 Subject: qedr: return error if destroy CQ failed Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 73df639755fa..cbccd7d3ae1e 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -985,8 +985,13 @@ int qedr_destroy_cq(struct ib_cq *ibcq) /* GSIs CQs are handled by driver, so they don't exist in the FW */ if (cq->cq_type != QEDR_CQ_TYPE_GSI) { + int rc; + iparams.icid = cq->icid; - dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, &oparams); + rc = dev->ops->rdma_destroy_cq(dev->rdma_ctx, &iparams, + &oparams); + if (rc) + return rc; dev->ops->common->chain_free(dev->cdev, &cq->pbl); } -- cgit v1.2.3 From d6ebbf29c3015bdccef388a860ac4ef6772531f8 Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:35 +0200 Subject: qedr: return correct value on modify qp Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index cbccd7d3ae1e..5d1980dd6c48 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -1974,7 +1974,7 @@ int qedr_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, if (attr_mask & IB_QP_STATE) { if ((qp->qp_type != IB_QPT_GSI) && (!udata)) - qedr_update_qp_state(dev, qp, qp_params.new_state); + rc = qedr_update_qp_state(dev, qp, qp_params.new_state); qp->state = qp_params.new_state; } -- cgit v1.2.3 From b4c2cc48aa0be767281669bff9f230e81ef27c56 Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:36 +0200 Subject: qedr: modify QP state to error when destroying it Current code didn't modify the QP state to error because it queried the QP state as a bitmap while it isn't. So the code never got executed. This patch fixes this and queries for each QP state respectively and not at once via a bitmask. Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 5d1980dd6c48..0237ff986829 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2078,8 +2078,10 @@ int qedr_destroy_qp(struct ib_qp *ibqp) DP_DEBUG(dev, QEDR_MSG_QP, "destroy qp: destroying %p, qp type=%d\n", qp, qp->qp_type); - if (qp->state != (QED_ROCE_QP_STATE_RESET | QED_ROCE_QP_STATE_ERR | - QED_ROCE_QP_STATE_INIT)) { + if ((qp->state != QED_ROCE_QP_STATE_RESET) && + (qp->state != QED_ROCE_QP_STATE_ERR) && + (qp->state != QED_ROCE_QP_STATE_INIT)) { + attr.qp_state = IB_QPS_ERR; attr_mask |= IB_QP_STATE; -- cgit v1.2.3 From 8b0cabc650a95a4f44de99aae6e8c128d70a40cd Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:37 +0200 Subject: qedr: ignore inline flag in read verbs In the current implementation a read verb with IB_SEND_INLINE may be illegally configured. In this fix we ignore the inline bit in the case of a read verb. Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 0237ff986829..9af2b4f3b62f 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2636,7 +2636,9 @@ static u32 qedr_prepare_sq_rdma_data(struct qedr_dev *dev, rwqe2->r_key = cpu_to_le32(rdma_wr(wr)->rkey); DMA_REGPAIR_LE(rwqe2->remote_va, rdma_wr(wr)->remote_addr); - if (wr->send_flags & IB_SEND_INLINE) { + if (wr->send_flags & IB_SEND_INLINE && + (wr->opcode == IB_WR_RDMA_WRITE_WITH_IMM || + wr->opcode == IB_WR_RDMA_WRITE)) { u8 flags = 0; SET_FIELD2(flags, RDMA_SQ_RDMA_WQE_1ST_INLINE_FLG, 1); -- cgit v1.2.3 From 922d9a40d3baeb30bfecb59b2c083ccec4b349d7 Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:38 +0200 Subject: qedr: post_send/recv according to QP state Enable posting to SQ only in RTS, ERR and SQD QP state. Enable posting to RQ in ERR QP state. Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 9af2b4f3b62f..e31141be5b04 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -2989,8 +2989,9 @@ int qedr_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, spin_lock_irqsave(&qp->q_lock, flags); - if ((qp->state == QED_ROCE_QP_STATE_RESET) || - (qp->state == QED_ROCE_QP_STATE_ERR)) { + if ((qp->state != QED_ROCE_QP_STATE_RTS) && + (qp->state != QED_ROCE_QP_STATE_ERR) && + (qp->state != QED_ROCE_QP_STATE_SQD)) { spin_unlock_irqrestore(&qp->q_lock, flags); *bad_wr = wr; DP_DEBUG(dev, QEDR_MSG_CQ, @@ -3043,8 +3044,7 @@ int qedr_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr, spin_lock_irqsave(&qp->q_lock, flags); - if ((qp->state == QED_ROCE_QP_STATE_RESET) || - (qp->state == QED_ROCE_QP_STATE_ERR)) { + if (qp->state == QED_ROCE_QP_STATE_RESET) { spin_unlock_irqrestore(&qp->q_lock, flags); *bad_wr = wr; return -EINVAL; -- cgit v1.2.3 From 27035a1b37fc284b59a2bca4cf2f910ebf03717f Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:39 +0200 Subject: qedr: clear the vendor error field in the work completion We clear the vendor error field in the work completion so that if a work completion is erroneous the field won't confuse the caller. Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index e31141be5b04..4017315ae734 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -3186,6 +3186,7 @@ static int process_req(struct qedr_dev *dev, struct qedr_qp *qp, /* fill WC */ wc->status = status; + wc->vendor_err = 0; wc->wc_flags = 0; wc->src_qp = qp->id; wc->qp = &qp->ibqp; @@ -3375,6 +3376,7 @@ static void __process_resp_one(struct qedr_dev *dev, struct qedr_qp *qp, /* fill WC */ wc->status = wc_status; + wc->vendor_err = 0; wc->src_qp = qp->id; wc->qp = &qp->ibqp; wc->wr_id = wr_id; @@ -3403,6 +3405,7 @@ static int process_resp_flush(struct qedr_qp *qp, struct qedr_cq *cq, while (num_entries && qp->rq.wqe_cons != hw_cons) { /* fill WC */ wc->status = IB_WC_WR_FLUSH_ERR; + wc->vendor_err = 0; wc->wc_flags = 0; wc->src_qp = qp->id; wc->byte_len = 0; -- cgit v1.2.3 From 74c3875c3d9aad356ae27fc4f4176d4dc89c457b Mon Sep 17 00:00:00 2001 From: "Amrani, Ram" Date: Thu, 22 Dec 2016 14:40:40 +0200 Subject: qedr: Always notify the verb consumer of flushed CQEs Signed-off-by: Ram Amrani Reviewed-by: Michal Kalderon Signed-off-by: Doug Ledford --- drivers/infiniband/hw/qedr/verbs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c index 4017315ae734..57c8de208077 100644 --- a/drivers/infiniband/hw/qedr/verbs.c +++ b/drivers/infiniband/hw/qedr/verbs.c @@ -3238,7 +3238,7 @@ static int qedr_poll_cq_req(struct qedr_dev *dev, "Error: POLL CQ with RDMA_CQE_REQ_STS_WORK_REQUEST_FLUSHED_ERR. CQ icid=0x%x, QP icid=0x%x\n", cq->icid, qp->icid); cnt = process_req(dev, qp, cq, num_entries, wc, req->sq_cons, - IB_WC_WR_FLUSH_ERR, 0); + IB_WC_WR_FLUSH_ERR, 1); break; default: /* process all WQE before the cosumer */ -- cgit v1.2.3 From 37b36193946e4fe7af2c3965e394eb311ab6601d Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Thu, 22 Dec 2016 08:54:36 -0500 Subject: IB/rxe: Use BTH_PSN_MASK when ACKing duplicate sends Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_resp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_resp.c b/drivers/infiniband/sw/rxe/rxe_resp.c index 7a36ec9dbc0c..3435efff8799 100644 --- a/drivers/infiniband/sw/rxe/rxe_resp.c +++ b/drivers/infiniband/sw/rxe/rxe_resp.c @@ -1070,12 +1070,13 @@ static enum resp_states duplicate_request(struct rxe_qp *qp, struct rxe_pkt_info *pkt) { enum resp_states rc; + u32 prev_psn = (qp->resp.psn - 1) & BTH_PSN_MASK; if (pkt->mask & RXE_SEND_MASK || pkt->mask & RXE_WRITE_MASK) { /* SEND. Ack again and cleanup. C9-105. */ if (bth_ack(pkt)) - send_ack(qp, pkt, AETH_ACK_UNLIMITED, qp->resp.psn - 1); + send_ack(qp, pkt, AETH_ACK_UNLIMITED, prev_psn); rc = RESPST_CLEANUP; goto out; } else if (pkt->mask & RXE_READ_MASK) { -- cgit v1.2.3 From cbf1f9a46c9c5903e34b0b110ca40b1e7d4b2ab1 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Thu, 22 Dec 2016 08:54:37 -0500 Subject: IB/rxe: Drop future atomic/read packets rather than retrying If the completer is in the middle of a large read operation, one lost packet can cause havoc. Going to COMPST_ERROR_RETRY will cause the requester to resend the request. After that, any packet from the first attempt still in the receive queue will be interpreted as an error, restarting the error/retry sequence. The transfer will quickly exhaust its retries. This behavior is very noticeable when doing 512KB reads on a QEMU system configured with 1500B MTU. Also, a resent request here will prompt the responder on the other side to immediately start resending, but the resent packets will get stuck in the already-loaded receive queue and will never be processed. Rather than erroring out every time an unexpected future packet arrives, just drop it. Eventually the retry timer will send a duplicate request; the completer will be able to make progress since the queue will start relatively empty. Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_comp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_comp.c b/drivers/infiniband/sw/rxe/rxe_comp.c index cd27cbde7652..d369f24425f9 100644 --- a/drivers/infiniband/sw/rxe/rxe_comp.c +++ b/drivers/infiniband/sw/rxe/rxe_comp.c @@ -224,7 +224,7 @@ static inline enum comp_state check_psn(struct rxe_qp *qp, else return COMPST_DONE; } else if ((diff > 0) && (wqe->mask & WR_ATOMIC_OR_READ_MASK)) { - return COMPST_ERROR_RETRY; + return COMPST_DONE; } else { return COMPST_CHECK_ACK; } -- cgit v1.2.3 From 5cc8fabc5e4c588c75a5ec21423e7c3425f69f48 Mon Sep 17 00:00:00 2001 From: Andrew Boyer Date: Thu, 22 Dec 2016 08:54:38 -0500 Subject: IB/rxe: Don't check for null ptr in send() pkt->qp was already dereferenced earlier in the function. Fixes Smatch complaint: drivers/infiniband/sw/rxe/rxe_net.c:458 send() warn: variable dereferenced before check 'pkt->qp' (see line 441) Signed-off-by: Andrew Boyer Signed-off-by: Doug Ledford --- drivers/infiniband/sw/rxe/rxe_net.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/infiniband/sw/rxe/rxe_net.c b/drivers/infiniband/sw/rxe/rxe_net.c index a576603304f7..10ec699834fa 100644 --- a/drivers/infiniband/sw/rxe/rxe_net.c +++ b/drivers/infiniband/sw/rxe/rxe_net.c @@ -459,8 +459,7 @@ static int send(struct rxe_dev *rxe, struct rxe_pkt_info *pkt, return -EAGAIN; } - if (pkt->qp) - atomic_inc(&pkt->qp->skb_out); + atomic_inc(&pkt->qp->skb_out); kfree_skb(skb); return 0; -- cgit v1.2.3 From 128394eff343fc6d2f32172f03e24829539c5835 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 16 Dec 2016 13:42:06 -0500 Subject: sg_write()/bsg_write() is not fit to be called under KERNEL_DS Both damn things interpret userland pointers embedded into the payload; worse, they are actually traversing those. Leaving aside the bad API design, this is very much _not_ safe to call with KERNEL_DS. Bail out early if that happens. Cc: stable@vger.kernel.org Signed-off-by: Al Viro --- block/bsg.c | 3 +++ drivers/scsi/sg.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'drivers') diff --git a/block/bsg.c b/block/bsg.c index 8a05a404ae70..a57046de2f07 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -655,6 +655,9 @@ bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) dprintk("%s: write %Zd bytes\n", bd->name, count); + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return -EINVAL; + bsg_set_block(bd, file); bytes_written = 0; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 070332eb41f3..dbe5b4b95df0 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -581,6 +581,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) sg_io_hdr_t *hp; unsigned char cmnd[SG_MAX_CDB_SIZE]; + if (unlikely(segment_eq(get_fs(), KERNEL_DS))) + return -EINVAL; + if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))) return -ENXIO; SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, -- cgit v1.2.3 From 567be786597ca24b13906a552ad2159316c6fe7d Mon Sep 17 00:00:00 2001 From: jpinto Date: Fri, 23 Dec 2016 10:15:59 +0000 Subject: stmmac: CSR clock configuration fix When testing stmmac with my QoS reference design I checked a problem in the CSR clock configuration that was impossibilitating the phy discovery, since every read operation returned 0x0000ffff. This patch fixes the issue. Signed-off-by: Joao Pinto Signed-off-by: David S. Miller --- drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c | 2 +- drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c | 2 +- drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c index b21d03fe4f43..be3c91c7f211 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c @@ -539,7 +539,7 @@ struct mac_device_info *dwmac1000_setup(void __iomem *ioaddr, int mcbins, mac->mii.reg_shift = 6; mac->mii.reg_mask = 0x000007C0; mac->mii.clk_csr_shift = 2; - mac->mii.clk_csr_mask = 0xF; + mac->mii.clk_csr_mask = GENMASK(5, 2); /* Get and dump the chip ID */ *synopsys_id = stmmac_get_synopsys_id(hwid); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c index a1d582f47b1a..9dd2987e284d 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_core.c @@ -197,7 +197,7 @@ struct mac_device_info *dwmac100_setup(void __iomem *ioaddr, int *synopsys_id) mac->mii.reg_shift = 6; mac->mii.reg_mask = 0x000007C0; mac->mii.clk_csr_shift = 2; - mac->mii.clk_csr_mask = 0xF; + mac->mii.clk_csr_mask = GENMASK(5, 2); /* Synopsys Id is not available on old chips */ *synopsys_id = 0; diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c index 23322fd9e3ac..fda01f770eff 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c @@ -81,8 +81,8 @@ static int stmmac_mdio_read(struct mii_bus *bus, int phyaddr, int phyreg) value |= (phyaddr << priv->hw->mii.addr_shift) & priv->hw->mii.addr_mask; value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - value |= (priv->clk_csr & priv->hw->mii.clk_csr_mask) - << priv->hw->mii.clk_csr_shift; + value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) + & priv->hw->mii.clk_csr_mask; if (priv->plat->has_gmac4) value |= MII_GMAC4_READ; @@ -122,8 +122,8 @@ static int stmmac_mdio_write(struct mii_bus *bus, int phyaddr, int phyreg, & priv->hw->mii.addr_mask; value |= (phyreg << priv->hw->mii.reg_shift) & priv->hw->mii.reg_mask; - value |= ((priv->clk_csr & priv->hw->mii.clk_csr_mask) - << priv->hw->mii.clk_csr_shift); + value |= (priv->clk_csr << priv->hw->mii.clk_csr_shift) + & priv->hw->mii.clk_csr_mask; if (priv->plat->has_gmac4) value |= MII_GMAC4_WRITE; -- cgit v1.2.3 From 93a87e5e794fb71a51f97fbde6c0010680b62d70 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 23 Dec 2016 09:32:49 +0100 Subject: mlxsw: spectrum_router: Don't reflect dead neighs When a neighbour is considered to be dead, we should remove it from the device's table regardless of its NUD state. Without this patch, after setting a port to be administratively down we get the following errors when we periodically try to update the kernel about neighbours activity: [ 461.947268] mlxsw_spectrum 0000:03:00.0 sw1p3: Failed to find matching neighbour for IP=192.168.100.2 Fixes: a6bf9e933daf ("mlxsw: spectrum_router: Offload neighbours based on NUD state change") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index 53126bf68ea9..a0f9742f62df 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -942,7 +942,7 @@ static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work) char rauht_pl[MLXSW_REG_RAUHT_LEN]; struct net_device *dev; bool entry_connected; - u8 nud_state; + u8 nud_state, dead; bool updating; bool removing; bool adding; @@ -953,10 +953,11 @@ static void mlxsw_sp_router_neigh_update_hw(struct work_struct *work) dip = ntohl(*((__be32 *) n->primary_key)); memcpy(neigh_entry->ha, n->ha, sizeof(neigh_entry->ha)); nud_state = n->nud_state; + dead = n->dead; dev = n->dev; read_unlock_bh(&n->lock); - entry_connected = nud_state & NUD_VALID; + entry_connected = nud_state & NUD_VALID && !dead; adding = (!neigh_entry->offloaded) && entry_connected; updating = neigh_entry->offloaded && entry_connected; removing = neigh_entry->offloaded && !entry_connected; @@ -1351,7 +1352,7 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_neigh_entry *neigh_entry; struct net_device *dev = fib_nh->nh_dev; struct neighbour *n; - u8 nud_state; + u8 nud_state, dead; /* Take a reference of neigh here ensuring that neigh would * not be detructed before the nexthop entry is finished. @@ -1383,8 +1384,9 @@ static int mlxsw_sp_nexthop_init(struct mlxsw_sp *mlxsw_sp, list_add_tail(&nh->neigh_list_node, &neigh_entry->nexthop_list); read_lock_bh(&n->lock); nud_state = n->nud_state; + dead = n->dead; read_unlock_bh(&n->lock); - __mlxsw_sp_nexthop_neigh_update(nh, !(nud_state & NUD_VALID)); + __mlxsw_sp_nexthop_neigh_update(nh, !(nud_state & NUD_VALID && !dead)); return 0; } -- cgit v1.2.3 From 58312125da5806308bd69e075fedae30f8cf7794 Mon Sep 17 00:00:00 2001 From: Ido Schimmel Date: Fri, 23 Dec 2016 09:32:50 +0100 Subject: mlxsw: spectrum_router: Correctly remove nexthop groups At the end of the nexthop initialization process we determine whether the nexthop should be offloaded or not based on the NUD state of the neighbour representing it. After all the nexthops were initialized we refresh the nexthop group and potentially offload it to the device, in case some of the nexthops were resolved. Make the destruction of a nexthop group symmetric with its creation by marking all nexthops as invalid and then refresh the nexthop group to make sure it was removed from the device's tables. Fixes: b2157149b0b0 ("mlxsw: spectrum_router: Add the nexthop neigh activity update") Signed-off-by: Ido Schimmel Signed-off-by: Jiri Pirko Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c index a0f9742f62df..01d0efa9c5c7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c @@ -1396,6 +1396,7 @@ static void mlxsw_sp_nexthop_fini(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_neigh_entry *neigh_entry = nh->neigh_entry; + __mlxsw_sp_nexthop_neigh_update(nh, true); list_del(&nh->neigh_list_node); /* If that is the last nexthop connected to that neigh, remove from @@ -1454,6 +1455,8 @@ mlxsw_sp_nexthop_group_destroy(struct mlxsw_sp *mlxsw_sp, nh = &nh_grp->nexthops[i]; mlxsw_sp_nexthop_fini(mlxsw_sp, nh); } + mlxsw_sp_nexthop_group_refresh(mlxsw_sp, nh_grp); + WARN_ON_ONCE(nh_grp->adj_index_valid); kfree(nh_grp); } -- cgit v1.2.3 From 73b62bd085f4737679ea9afc7867fa5f99ba7d1b Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:24 +0800 Subject: virtio-net: remove the warning before XDP linearizing Since we use EWMA to estimate the size of rx buffer. When rx buffer size is underestimated, it's usual to have a packet with more than one buffers. Consider this is not a bug, remove the warning and correct the comment before XDP linearizing. Cc: John Fastabend Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 08327e005ccc..1067253b98be 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -552,14 +552,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, struct page *xdp_page; u32 act; - /* No known backend devices should send packets with - * more than a single buffer when XDP conditions are - * met. However it is not strictly illegal so the case - * is handled as an exception and a warning is thrown. - */ + /* This happens when rx buffer size is underestimated */ if (unlikely(num_buf > 1)) { - bpf_warn_invalid_xdp_buffer(); - /* linearize data for XDP */ xdp_page = xdp_linearize_page(rq, num_buf, page, offset, &len); -- cgit v1.2.3 From 275be061b33b945cfb120ee8a570f78c3ccafe56 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:25 +0800 Subject: virtio-net: correctly xmit linearized page on XDP_TX After we linearize page, we should xmit this page instead of the page of first buffer which may lead unexpected result. With this patch, we can see correct packet during XDP_TX. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 1067253b98be..fe4562d395e3 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -572,7 +572,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) goto err_xdp; - act = do_xdp_prog(vi, rq, xdp_prog, page, offset, len); + act = do_xdp_prog(vi, rq, xdp_prog, xdp_page, offset, len); switch (act) { case XDP_PASS: if (unlikely(xdp_page != page)) -- cgit v1.2.3 From 56a86f84b8332afe8c6fcb4b09d09d9bf094e2db Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:26 +0800 Subject: virtio-net: fix page miscount during XDP linearizing We don't put page during linearizing, the would cause leaking when xmit through XDP_TX or the packet exceeds PAGE_SIZE. Fix them by put page accordingly. Also decrease the number of buffers during linearizing to make sure caller can free buffers correctly when packet exceeds PAGE_SIZE. With this patch, we won't get OOM after linearize huge number of packets. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index fe4562d395e3..58ad40e17a74 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -483,7 +483,7 @@ xdp_xmit: * anymore. */ static struct page *xdp_linearize_page(struct receive_queue *rq, - u16 num_buf, + u16 *num_buf, struct page *p, int offset, unsigned int *len) @@ -497,7 +497,7 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, memcpy(page_address(page) + page_off, page_address(p) + offset, *len); page_off += *len; - while (--num_buf) { + while (--*num_buf) { unsigned int buflen; unsigned long ctx; void *buf; @@ -507,19 +507,22 @@ static struct page *xdp_linearize_page(struct receive_queue *rq, if (unlikely(!ctx)) goto err_buf; + buf = mergeable_ctx_to_buf_address(ctx); + p = virt_to_head_page(buf); + off = buf - page_address(p); + /* guard against a misconfigured or uncooperative backend that * is sending packet larger than the MTU. */ - if ((page_off + buflen) > PAGE_SIZE) + if ((page_off + buflen) > PAGE_SIZE) { + put_page(p); goto err_buf; - - buf = mergeable_ctx_to_buf_address(ctx); - p = virt_to_head_page(buf); - off = buf - page_address(p); + } memcpy(page_address(page) + page_off, page_address(p) + off, buflen); page_off += buflen; + put_page(p); } *len = page_off; @@ -555,7 +558,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, /* This happens when rx buffer size is underestimated */ if (unlikely(num_buf > 1)) { /* linearize data for XDP */ - xdp_page = xdp_linearize_page(rq, num_buf, + xdp_page = xdp_linearize_page(rq, &num_buf, page, offset, &len); if (!xdp_page) goto err_xdp; -- cgit v1.2.3 From 1830f8935f3b173d229b86e9927b3b6d599aa1f6 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:27 +0800 Subject: virtio-net: correctly handle XDP_PASS for linearized packets When XDP_PASS were determined for linearized packets, we try to get new buffers in the virtqueue and build skbs from them. This is wrong, we should create skbs based on existed buffers instead. Fixing them by creating skb based on xdp_page. With this patch "ping 192.168.100.4 -s 3900 -M do" works for XDP_PASS. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 58ad40e17a74..470293e2b84d 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -578,8 +578,14 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, act = do_xdp_prog(vi, rq, xdp_prog, xdp_page, offset, len); switch (act) { case XDP_PASS: - if (unlikely(xdp_page != page)) - __free_pages(xdp_page, 0); + /* We can only create skb based on xdp_page. */ + if (unlikely(xdp_page != page)) { + rcu_read_unlock(); + put_page(page); + head_skb = page_to_skb(vi, rq, xdp_page, + 0, len, PAGE_SIZE); + return head_skb; + } break; case XDP_TX: if (unlikely(xdp_page != page)) -- cgit v1.2.3 From b00f70b0dacb3d2e009afce860ebc90219072f5c Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:28 +0800 Subject: virtio-net: unbreak csumed packets for XDP_PASS We drop csumed packet when do XDP for packets. This breaks XDP_PASS when GUEST_CSUM is supported. Fix this by allowing csum flag to be set. With this patch, simple TCP works for XDP_PASS. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 470293e2b84d..0778dc88597e 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -440,7 +440,7 @@ static struct sk_buff *receive_big(struct net_device *dev, struct virtio_net_hdr_mrg_rxbuf *hdr = buf; u32 act; - if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) + if (unlikely(hdr->hdr.gso_type)) goto err_xdp; act = do_xdp_prog(vi, rq, xdp_prog, page, 0, len); switch (act) { @@ -572,7 +572,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, * the receive path after XDP is loaded. In practice I * was not able to create this condition. */ - if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) + if (unlikely(hdr->hdr.gso_type)) goto err_xdp; act = do_xdp_prog(vi, rq, xdp_prog, xdp_page, offset, len); -- cgit v1.2.3 From 5c33474d41af09f09c98f1df70f267920587bec0 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:29 +0800 Subject: virtio-net: make rx buf size estimation works for XDP We don't update ewma rx buf size in the case of XDP. This will lead underestimation of rx buf size which causes host to produce more than one buffers. This will greatly increase the possibility of XDP page linearization. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0778dc88597e..77ae358ec630 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -584,10 +584,12 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, put_page(page); head_skb = page_to_skb(vi, rq, xdp_page, 0, len, PAGE_SIZE); + ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len); return head_skb; } break; case XDP_TX: + ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len); if (unlikely(xdp_page != page)) goto err_xdp; rcu_read_unlock(); @@ -596,6 +598,7 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, default: if (unlikely(xdp_page != page)) __free_pages(xdp_page, 0); + ewma_pkt_len_add(&rq->mrg_avg_pkt_len, len); goto err_xdp; } } -- cgit v1.2.3 From 92502fe86c7c9b3f8543f29641a3c71805e82757 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:30 +0800 Subject: virtio-net: forbid XDP when VIRTIO_NET_F_GUEST_UFO is support When VIRTIO_NET_F_GUEST_UFO is negotiated, host could still send UFO packet that exceeds a single page which could not be handled correctly by XDP. So this patch forbids setting XDP when GUEST_UFO is supported. While at it, forbid XDP for ECN (which comes only from GRO) too to prevent user from misconfiguration. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 77ae358ec630..c1f66d8bfb7b 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1684,7 +1684,9 @@ static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog) int i, err; if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO4) || - virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6)) { + virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_TSO6) || + virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_ECN) || + virtio_has_feature(vi->vdev, VIRTIO_NET_F_GUEST_UFO)) { netdev_warn(dev, "can't set XDP while host is implementing LRO, disable LRO first\n"); return -EOPNOTSUPP; } -- cgit v1.2.3 From c47a43d3004ad6ff2a94a670cb3274cd6338d41e Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:31 +0800 Subject: virtio-net: remove big packet XDP codes Now we in fact don't allow XDP for big packets, remove its codes. Cc: John Fastabend Signed-off-by: Jason Wang Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 44 +++----------------------------------------- 1 file changed, 3 insertions(+), 41 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index c1f66d8bfb7b..e53365a86ca3 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -344,11 +344,7 @@ static void virtnet_xdp_xmit(struct virtnet_info *vi, /* Free up any pending old buffers before queueing new ones. */ while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) { struct page *sent_page = virt_to_head_page(xdp_sent); - - if (vi->mergeable_rx_bufs) - put_page(sent_page); - else - give_pages(rq, sent_page); + put_page(sent_page); } /* Zero header and leave csum up to XDP layers */ @@ -360,15 +356,8 @@ static void virtnet_xdp_xmit(struct virtnet_info *vi, err = virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, xdp->data, GFP_ATOMIC); if (unlikely(err)) { - if (vi->mergeable_rx_bufs) - put_page(page); - else - give_pages(rq, page); + put_page(page); return; // On error abort to avoid unnecessary kick - } else if (!vi->mergeable_rx_bufs) { - /* If not mergeable bufs must be big packets so cleanup pages */ - give_pages(rq, (struct page *)page->private); - page->private = 0; } virtqueue_kick(sq->vq); @@ -430,44 +419,17 @@ static struct sk_buff *receive_big(struct net_device *dev, void *buf, unsigned int len) { - struct bpf_prog *xdp_prog; struct page *page = buf; - struct sk_buff *skb; - - rcu_read_lock(); - xdp_prog = rcu_dereference(rq->xdp_prog); - if (xdp_prog) { - struct virtio_net_hdr_mrg_rxbuf *hdr = buf; - u32 act; - - if (unlikely(hdr->hdr.gso_type)) - goto err_xdp; - act = do_xdp_prog(vi, rq, xdp_prog, page, 0, len); - switch (act) { - case XDP_PASS: - break; - case XDP_TX: - rcu_read_unlock(); - goto xdp_xmit; - case XDP_DROP: - default: - goto err_xdp; - } - } - rcu_read_unlock(); + struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE); - skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE); if (unlikely(!skb)) goto err; return skb; -err_xdp: - rcu_read_unlock(); err: dev->stats.rx_dropped++; give_pages(rq, page); -xdp_xmit: return NULL; } -- cgit v1.2.3 From bb91accf27335c6dc460e202991ca140fa21e1b5 Mon Sep 17 00:00:00 2001 From: Jason Wang Date: Fri, 23 Dec 2016 22:37:32 +0800 Subject: virtio-net: XDP support for small buffers Commit f600b6905015 ("virtio_net: Add XDP support") leaves the case of small receive buffer untouched. This will confuse the user who want to set XDP but use small buffers. Other than forbid XDP in small buffer mode, let's make it work. XDP then can only work at skb->data since virtio-net create skbs during refill, this is sub optimal which could be optimized in the future. Cc: John Fastabend Signed-off-by: Jason Wang Acked-by: John Fastabend Signed-off-by: David S. Miller --- drivers/net/virtio_net.c | 112 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 87 insertions(+), 25 deletions(-) (limited to 'drivers') diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index e53365a86ca3..5deeda61d6d3 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -333,9 +333,9 @@ static struct sk_buff *page_to_skb(struct virtnet_info *vi, static void virtnet_xdp_xmit(struct virtnet_info *vi, struct receive_queue *rq, struct send_queue *sq, - struct xdp_buff *xdp) + struct xdp_buff *xdp, + void *data) { - struct page *page = virt_to_head_page(xdp->data); struct virtio_net_hdr_mrg_rxbuf *hdr; unsigned int num_sg, len; void *xdp_sent; @@ -343,20 +343,45 @@ static void virtnet_xdp_xmit(struct virtnet_info *vi, /* Free up any pending old buffers before queueing new ones. */ while ((xdp_sent = virtqueue_get_buf(sq->vq, &len)) != NULL) { - struct page *sent_page = virt_to_head_page(xdp_sent); - put_page(sent_page); + if (vi->mergeable_rx_bufs) { + struct page *sent_page = virt_to_head_page(xdp_sent); + + put_page(sent_page); + } else { /* small buffer */ + struct sk_buff *skb = xdp_sent; + + kfree_skb(skb); + } } - /* Zero header and leave csum up to XDP layers */ - hdr = xdp->data; - memset(hdr, 0, vi->hdr_len); + if (vi->mergeable_rx_bufs) { + /* Zero header and leave csum up to XDP layers */ + hdr = xdp->data; + memset(hdr, 0, vi->hdr_len); + + num_sg = 1; + sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data); + } else { /* small buffer */ + struct sk_buff *skb = data; - num_sg = 1; - sg_init_one(sq->sg, xdp->data, xdp->data_end - xdp->data); + /* Zero header and leave csum up to XDP layers */ + hdr = skb_vnet_hdr(skb); + memset(hdr, 0, vi->hdr_len); + + num_sg = 2; + sg_init_table(sq->sg, 2); + sg_set_buf(sq->sg, hdr, vi->hdr_len); + skb_to_sgvec(skb, sq->sg + 1, 0, skb->len); + } err = virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, - xdp->data, GFP_ATOMIC); + data, GFP_ATOMIC); if (unlikely(err)) { - put_page(page); + if (vi->mergeable_rx_bufs) { + struct page *page = virt_to_head_page(xdp->data); + + put_page(page); + } else /* small buffer */ + kfree_skb(data); return; // On error abort to avoid unnecessary kick } @@ -366,23 +391,26 @@ static void virtnet_xdp_xmit(struct virtnet_info *vi, static u32 do_xdp_prog(struct virtnet_info *vi, struct receive_queue *rq, struct bpf_prog *xdp_prog, - struct page *page, int offset, int len) + void *data, int len) { int hdr_padded_len; struct xdp_buff xdp; + void *buf; unsigned int qp; u32 act; - u8 *buf; - - buf = page_address(page) + offset; - if (vi->mergeable_rx_bufs) + if (vi->mergeable_rx_bufs) { hdr_padded_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); - else - hdr_padded_len = sizeof(struct padded_vnet_hdr); + xdp.data = data + hdr_padded_len; + xdp.data_end = xdp.data + (len - vi->hdr_len); + buf = data; + } else { /* small buffers */ + struct sk_buff *skb = data; - xdp.data = buf + hdr_padded_len; - xdp.data_end = xdp.data + (len - vi->hdr_len); + xdp.data = skb->data; + xdp.data_end = xdp.data + len; + buf = skb->data; + } act = bpf_prog_run_xdp(xdp_prog, &xdp); switch (act) { @@ -392,8 +420,8 @@ static u32 do_xdp_prog(struct virtnet_info *vi, qp = vi->curr_queue_pairs - vi->xdp_queue_pairs + smp_processor_id(); - xdp.data = buf + (vi->mergeable_rx_bufs ? 0 : 4); - virtnet_xdp_xmit(vi, rq, &vi->sq[qp], &xdp); + xdp.data = buf; + virtnet_xdp_xmit(vi, rq, &vi->sq[qp], &xdp, data); return XDP_TX; default: bpf_warn_invalid_xdp_action(act); @@ -403,14 +431,47 @@ static u32 do_xdp_prog(struct virtnet_info *vi, } } -static struct sk_buff *receive_small(struct virtnet_info *vi, void *buf, unsigned int len) +static struct sk_buff *receive_small(struct net_device *dev, + struct virtnet_info *vi, + struct receive_queue *rq, + void *buf, unsigned int len) { struct sk_buff * skb = buf; + struct bpf_prog *xdp_prog; len -= vi->hdr_len; skb_trim(skb, len); + rcu_read_lock(); + xdp_prog = rcu_dereference(rq->xdp_prog); + if (xdp_prog) { + struct virtio_net_hdr_mrg_rxbuf *hdr = buf; + u32 act; + + if (unlikely(hdr->hdr.gso_type || hdr->hdr.flags)) + goto err_xdp; + act = do_xdp_prog(vi, rq, xdp_prog, skb, len); + switch (act) { + case XDP_PASS: + break; + case XDP_TX: + rcu_read_unlock(); + goto xdp_xmit; + case XDP_DROP: + default: + goto err_xdp; + } + } + rcu_read_unlock(); + return skb; + +err_xdp: + rcu_read_unlock(); + dev->stats.rx_dropped++; + kfree_skb(skb); +xdp_xmit: + return NULL; } static struct sk_buff *receive_big(struct net_device *dev, @@ -537,7 +598,8 @@ static struct sk_buff *receive_mergeable(struct net_device *dev, if (unlikely(hdr->hdr.gso_type)) goto err_xdp; - act = do_xdp_prog(vi, rq, xdp_prog, xdp_page, offset, len); + act = do_xdp_prog(vi, rq, xdp_prog, + page_address(xdp_page) + offset, len); switch (act) { case XDP_PASS: /* We can only create skb based on xdp_page. */ @@ -672,7 +734,7 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq, else if (vi->big_packets) skb = receive_big(dev, vi, rq, buf, len); else - skb = receive_small(vi, buf, len); + skb = receive_small(dev, vi, rq, buf, len); if (unlikely(!skb)) return; -- cgit v1.2.3 From 639b08810d6ad74ded2c5f6e233c4fcb9d147168 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 22 Dec 2016 08:19:46 +0100 Subject: xen: xenbus driver must not accept invalid transaction ids When accessing Xenstore in a transaction the user is specifying a transaction id which he normally obtained from Xenstore when starting the transaction. Xenstore is validating a transaction id against all known transaction ids of the connection the request came in. As all requests of a domain not being the one where Xenstore lives share one connection, validation of transaction ids of different users of Xenstore in that domain should be done by the kernel of that domain being the multiplexer between the Xenstore users in that domain and Xenstore. In order to prohibit one Xenstore user "hijacking" a transaction from another user the xenbus driver has to verify a given transaction id against all known transaction ids of the user before forwarding it to Xenstore. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross --- drivers/xen/xenbus/xenbus_dev_frontend.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index 6c0ead4be784..a06828124b70 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -316,7 +316,7 @@ static int xenbus_write_transaction(unsigned msg_type, rc = -ENOMEM; goto out; } - } else if (msg_type == XS_TRANSACTION_END) { + } else if (u->u.msg.tx_id != 0) { list_for_each_entry(trans, &u->transactions, list) if (trans->handle.id == u->u.msg.tx_id) break; -- cgit v1.2.3 From 9a6161fe73bdd3ae4a1e18421b0b20cb7141f680 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 22 Dec 2016 08:19:47 +0100 Subject: xen: return xenstore command failures via response instead of rc When the xenbus driver does some special handling for a Xenstore command any error condition related to the command should be returned via an error response instead of letting the related write operation fail. Otherwise the user land handler might take wrong decisions assuming the connection to Xenstore is broken. While at it try to return the same error values xenstored would return for those cases. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross --- drivers/xen/xenbus/xenbus_dev_frontend.c | 47 ++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c index a06828124b70..79130b310247 100644 --- a/drivers/xen/xenbus/xenbus_dev_frontend.c +++ b/drivers/xen/xenbus/xenbus_dev_frontend.c @@ -302,6 +302,29 @@ static void watch_fired(struct xenbus_watch *watch, mutex_unlock(&adap->dev_data->reply_mutex); } +static int xenbus_command_reply(struct xenbus_file_priv *u, + unsigned int msg_type, const char *reply) +{ + struct { + struct xsd_sockmsg hdr; + const char body[16]; + } msg; + int rc; + + msg.hdr = u->u.msg; + msg.hdr.type = msg_type; + msg.hdr.len = strlen(reply) + 1; + if (msg.hdr.len > sizeof(msg.body)) + return -E2BIG; + + mutex_lock(&u->reply_mutex); + rc = queue_reply(&u->read_buffers, &msg, sizeof(msg.hdr) + msg.hdr.len); + wake_up(&u->read_waitq); + mutex_unlock(&u->reply_mutex); + + return rc; +} + static int xenbus_write_transaction(unsigned msg_type, struct xenbus_file_priv *u) { @@ -321,7 +344,7 @@ static int xenbus_write_transaction(unsigned msg_type, if (trans->handle.id == u->u.msg.tx_id) break; if (&trans->list == &u->transactions) - return -ESRCH; + return xenbus_command_reply(u, XS_ERROR, "ENOENT"); } reply = xenbus_dev_request_and_reply(&u->u.msg); @@ -372,12 +395,12 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) path = u->u.buffer + sizeof(u->u.msg); token = memchr(path, 0, u->u.msg.len); if (token == NULL) { - rc = -EILSEQ; + rc = xenbus_command_reply(u, XS_ERROR, "EINVAL"); goto out; } token++; if (memchr(token, 0, u->u.msg.len - (token - path)) == NULL) { - rc = -EILSEQ; + rc = xenbus_command_reply(u, XS_ERROR, "EINVAL"); goto out; } @@ -411,23 +434,7 @@ static int xenbus_write_watch(unsigned msg_type, struct xenbus_file_priv *u) } /* Success. Synthesize a reply to say all is OK. */ - { - struct { - struct xsd_sockmsg hdr; - char body[3]; - } __packed reply = { - { - .type = msg_type, - .len = sizeof(reply.body) - }, - "OK" - }; - - mutex_lock(&u->reply_mutex); - rc = queue_reply(&u->read_buffers, &reply, sizeof(reply)); - wake_up(&u->read_waitq); - mutex_unlock(&u->reply_mutex); - } + rc = xenbus_command_reply(u, msg_type, "OK"); out: return rc; -- cgit v1.2.3 From 61033e089cde41464f820c8c381ce170d89470f0 Mon Sep 17 00:00:00 2001 From: Juergen Gross Date: Thu, 22 Dec 2016 08:19:48 +0100 Subject: xen: remove stale xs_input_avail() from header In drivers/xen/xenbus/xenbus_comms.h there is a stale declaration of xs_input_avail(). Remove it. Signed-off-by: Juergen Gross Reviewed-by: Boris Ostrovsky Signed-off-by: Juergen Gross --- drivers/xen/xenbus/xenbus_comms.h | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/xen/xenbus/xenbus_comms.h b/drivers/xen/xenbus/xenbus_comms.h index e74f9c1fbd80..867a2e425208 100644 --- a/drivers/xen/xenbus/xenbus_comms.h +++ b/drivers/xen/xenbus/xenbus_comms.h @@ -42,7 +42,6 @@ int xb_write(const void *data, unsigned len); int xb_read(void *data, unsigned len); int xb_data_to_read(void); int xb_wait_for_data_to_read(void); -int xs_input_avail(void); extern struct xenstore_domain_interface *xen_store_interface; extern int xen_store_evtchn; extern enum xenstore_init xen_store_domain_type; -- cgit v1.2.3 From 783dfa6cc41b710b8b0c1979c6100417d0d6c3b2 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Wed, 16 Nov 2016 14:03:38 -0700 Subject: ntb: Adding Skylake Xeon NTB support The Skylake Xeon NTB hardware has made some changes to the register name, offset, and the way doorbells work. Adding driver support for the new hardware. Signed-off-by: Dave Jiang Acked-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.c | 660 +++++++++++++++++++++++++++++++++++- drivers/ntb/hw/intel/ntb_hw_intel.h | 48 +++ 2 files changed, 703 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index 7310a261c858..d2ce28008fee 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -86,7 +86,12 @@ static const struct intel_ntb_xlat_reg xeon_pri_xlat; static const struct intel_ntb_xlat_reg xeon_sec_xlat; static struct intel_b2b_addr xeon_b2b_usd_addr; static struct intel_b2b_addr xeon_b2b_dsd_addr; +static const struct intel_ntb_reg skx_reg; +static const struct intel_ntb_alt_reg skx_pri_reg; +static const struct intel_ntb_alt_reg skx_b2b_reg; +static const struct intel_ntb_xlat_reg skx_sec_xlat; static const struct ntb_dev_ops intel_ntb_ops; +static const struct ntb_dev_ops intel_ntb3_ops; static const struct file_operations intel_ntb_debugfs_info; static struct dentry *debugfs_dir; @@ -145,6 +150,9 @@ module_param_named(xeon_b2b_dsd_bar5_addr32, MODULE_PARM_DESC(xeon_b2b_dsd_bar5_addr32, "XEON B2B DSD split-BAR 5 32-bit address"); +static inline enum ntb_topo xeon_ppd_topo(struct intel_ntb_dev *ndev, u8 ppd); +static int xeon_init_isr(struct intel_ntb_dev *ndev); + #ifndef ioread64 #ifdef readq #define ioread64 readq @@ -206,6 +214,14 @@ static inline int pdev_is_xeon(struct pci_dev *pdev) return 0; } +static inline int pdev_is_skx_xeon(struct pci_dev *pdev) +{ + if (pdev->device == PCI_DEVICE_ID_INTEL_NTB_B2B_SKX) + return 1; + + return 0; +} + static inline void ndev_reset_unsafe_flags(struct intel_ntb_dev *ndev) { ndev->unsafe_flags = 0; @@ -390,6 +406,9 @@ static irqreturn_t ndev_interrupt(struct intel_ntb_dev *ndev, int vec) vec_mask = ndev_vec_mask(ndev, vec); + if ((ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) && (vec == 31)) + vec_mask |= ndev->db_link_mask; + dev_dbg(ndev_dev(ndev), "vec %d vec_mask %llx\n", vec, vec_mask); ndev->last_ts = jiffies; @@ -409,6 +428,9 @@ static irqreturn_t ndev_vec_isr(int irq, void *dev) { struct intel_ntb_vec *nvec = dev; + dev_dbg(ndev_dev(nvec->ndev), "irq: %d nvec->num: %d\n", + irq, nvec->num); + return ndev_interrupt(nvec->ndev, nvec->num); } @@ -465,7 +487,7 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev, goto err_msix_request; } - dev_dbg(ndev_dev(ndev), "Using msix interrupts\n"); + dev_dbg(ndev_dev(ndev), "Using %d msix interrupts\n", msix_count); ndev->db_vec_count = msix_count; ndev->db_vec_shift = msix_shift; return 0; @@ -547,8 +569,171 @@ static void ndev_deinit_isr(struct intel_ntb_dev *ndev) } } -static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, - size_t count, loff_t *offp) +static ssize_t ndev_ntb3_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) +{ + struct intel_ntb_dev *ndev; + void __iomem *mmio; + char *buf; + size_t buf_size; + ssize_t ret, off; + union { u64 v64; u32 v32; u16 v16; } u; + + ndev = filp->private_data; + mmio = ndev->self_mmio; + + buf_size = min(count, 0x800ul); + + buf = kmalloc(buf_size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + off = 0; + + off += scnprintf(buf + off, buf_size - off, + "NTB Device Information:\n"); + + off += scnprintf(buf + off, buf_size - off, + "Connection Topology -\t%s\n", + ntb_topo_string(ndev->ntb.topo)); + + off += scnprintf(buf + off, buf_size - off, + "NTB CTL -\t\t%#06x\n", ndev->ntb_ctl); + off += scnprintf(buf + off, buf_size - off, + "LNK STA -\t\t%#06x\n", ndev->lnk_sta); + + if (!ndev->reg->link_is_up(ndev)) + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tDown\n"); + else { + off += scnprintf(buf + off, buf_size - off, + "Link Status -\t\tUp\n"); + off += scnprintf(buf + off, buf_size - off, + "Link Speed -\t\tPCI-E Gen %u\n", + NTB_LNK_STA_SPEED(ndev->lnk_sta)); + off += scnprintf(buf + off, buf_size - off, + "Link Width -\t\tx%u\n", + NTB_LNK_STA_WIDTH(ndev->lnk_sta)); + } + + off += scnprintf(buf + off, buf_size - off, + "Memory Window Count -\t%u\n", ndev->mw_count); + off += scnprintf(buf + off, buf_size - off, + "Scratchpad Count -\t%u\n", ndev->spad_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Count -\t%u\n", ndev->db_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Count -\t%u\n", ndev->db_vec_count); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Vector Shift -\t%u\n", ndev->db_vec_shift); + + off += scnprintf(buf + off, buf_size - off, + "Doorbell Valid Mask -\t%#llx\n", ndev->db_valid_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Link Mask -\t%#llx\n", ndev->db_link_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask Cached -\t%#llx\n", ndev->db_mask); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_mask); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Mask -\t\t%#llx\n", u.v64); + + u.v64 = ndev_db_read(ndev, mmio + ndev->self_reg->db_bell); + off += scnprintf(buf + off, buf_size - off, + "Doorbell Bell -\t\t%#llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Incoming XLAT:\n"); + + u.v64 = ioread64(mmio + SKX_IMBAR1XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR1XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_IMBAR2XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR2XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR1XLMT -\t\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "IMBAR2XLMT -\t\t\t%#018llx\n", u.v64); + + if (ntb_topo_is_b2b(ndev->ntb.topo)) { + off += scnprintf(buf + off, buf_size - off, + "\nNTB Outgoing B2B XLAT:\n"); + + u.v64 = ioread64(mmio + SKX_EMBAR1XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR1XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_EMBAR2XBASE_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR2XBASE -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_EMBAR1XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR1XLMT -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_EMBAR2XLMT_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR2XLMT -\t\t%#018llx\n", u.v64); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Secondary BAR:\n"); + + u.v64 = ioread64(mmio + SKX_EMBAR0_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR0 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_EMBAR1_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR1 -\t\t%#018llx\n", u.v64); + + u.v64 = ioread64(mmio + SKX_EMBAR2_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "EMBAR2 -\t\t%#018llx\n", u.v64); + } + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Statistics:\n"); + + u.v16 = ioread16(mmio + SKX_USMEMMISS_OFFSET); + off += scnprintf(buf + off, buf_size - off, + "Upstream Memory Miss -\t%u\n", u.v16); + + off += scnprintf(buf + off, buf_size - off, + "\nNTB Hardware Errors:\n"); + + if (!pci_read_config_word(ndev->ntb.pdev, + SKX_DEVSTS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "DEVSTS -\t\t%#06x\n", u.v16); + + if (!pci_read_config_word(ndev->ntb.pdev, + SKX_LINK_STATUS_OFFSET, &u.v16)) + off += scnprintf(buf + off, buf_size - off, + "LNKSTS -\t\t%#06x\n", u.v16); + + if (!pci_read_config_dword(ndev->ntb.pdev, + SKX_UNCERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "UNCERRSTS -\t\t%#06x\n", u.v32); + + if (!pci_read_config_dword(ndev->ntb.pdev, + SKX_CORERRSTS_OFFSET, &u.v32)) + off += scnprintf(buf + off, buf_size - off, + "CORERRSTS -\t\t%#06x\n", u.v32); + + ret = simple_read_from_buffer(ubuf, count, offp, buf, off); + kfree(buf); + return ret; +} + +static ssize_t ndev_ntb_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) { struct intel_ntb_dev *ndev; struct pci_dev *pdev; @@ -813,6 +998,20 @@ static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, return ret; } +static ssize_t ndev_debugfs_read(struct file *filp, char __user *ubuf, + size_t count, loff_t *offp) +{ + struct intel_ntb_dev *ndev = filp->private_data; + + if (pdev_is_xeon(ndev->ntb.pdev) || + pdev_is_atom(ndev->ntb.pdev)) + return ndev_ntb_debugfs_read(filp, ubuf, count, offp); + else if (pdev_is_skx_xeon(ndev->ntb.pdev)) + return ndev_ntb3_debugfs_read(filp, ubuf, count, offp); + + return -ENXIO; +} + static void ndev_init_debugfs(struct intel_ntb_dev *ndev) { if (!debugfs_dir) { @@ -1428,6 +1627,383 @@ static void atom_deinit_dev(struct intel_ntb_dev *ndev) atom_deinit_isr(ndev); } +/* Skylake Xeon NTB */ + +static u64 skx_db_ioread(void __iomem *mmio) +{ + return ioread64(mmio); +} + +static void skx_db_iowrite(u64 bits, void __iomem *mmio) +{ + iowrite64(bits, mmio); +} + +static int skx_init_isr(struct intel_ntb_dev *ndev) +{ + int i; + + /* + * The MSIX vectors and the interrupt status bits are not lined up + * on Skylake. By default the link status bit is bit 32, however it + * is by default MSIX vector0. We need to fixup to line them up. + * The vectors at reset is 1-32,0. We need to reprogram to 0-32. + */ + + for (i = 0; i < SKX_DB_MSIX_VECTOR_COUNT; i++) + iowrite8(i, ndev->self_mmio + SKX_INTVEC_OFFSET + i); + + /* move link status down one as workaround */ + if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) { + iowrite8(SKX_DB_MSIX_VECTOR_COUNT - 2, + ndev->self_mmio + SKX_INTVEC_OFFSET + + (SKX_DB_MSIX_VECTOR_COUNT - 1)); + } + + return ndev_init_isr(ndev, SKX_DB_MSIX_VECTOR_COUNT, + SKX_DB_MSIX_VECTOR_COUNT, + SKX_DB_MSIX_VECTOR_SHIFT, + SKX_DB_TOTAL_SHIFT); +} + +static int skx_setup_b2b_mw(struct intel_ntb_dev *ndev, + const struct intel_b2b_addr *addr, + const struct intel_b2b_addr *peer_addr) +{ + struct pci_dev *pdev; + void __iomem *mmio; + resource_size_t bar_size; + phys_addr_t bar_addr; + int b2b_bar; + u8 bar_sz; + + pdev = ndev_pdev(ndev); + mmio = ndev->self_mmio; + + if (ndev->b2b_idx == UINT_MAX) { + dev_dbg(ndev_dev(ndev), "not using b2b mw\n"); + b2b_bar = 0; + ndev->b2b_off = 0; + } else { + b2b_bar = ndev_mw_to_bar(ndev, ndev->b2b_idx); + if (b2b_bar < 0) + return -EIO; + + dev_dbg(ndev_dev(ndev), "using b2b mw bar %d\n", b2b_bar); + + bar_size = pci_resource_len(ndev->ntb.pdev, b2b_bar); + + dev_dbg(ndev_dev(ndev), "b2b bar size %#llx\n", bar_size); + + if (b2b_mw_share && ((bar_size >> 1) >= XEON_B2B_MIN_SIZE)) { + dev_dbg(ndev_dev(ndev), + "b2b using first half of bar\n"); + ndev->b2b_off = bar_size >> 1; + } else if (bar_size >= XEON_B2B_MIN_SIZE) { + dev_dbg(ndev_dev(ndev), + "b2b using whole bar\n"); + ndev->b2b_off = 0; + --ndev->mw_count; + } else { + dev_dbg(ndev_dev(ndev), + "b2b bar size is too small\n"); + return -EIO; + } + } + + /* + * Reset the secondary bar sizes to match the primary bar sizes, + * except disable or halve the size of the b2b secondary bar. + */ + pci_read_config_byte(pdev, SKX_IMBAR1SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "IMBAR1SZ %#x\n", bar_sz); + if (b2b_bar == 1) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + + pci_write_config_byte(pdev, SKX_EMBAR1SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SKX_EMBAR1SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "EMBAR1SZ %#x\n", bar_sz); + + pci_read_config_byte(pdev, SKX_IMBAR2SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "IMBAR2SZ %#x\n", bar_sz); + if (b2b_bar == 2) { + if (ndev->b2b_off) + bar_sz -= 1; + else + bar_sz = 0; + } + + pci_write_config_byte(pdev, SKX_EMBAR2SZ_OFFSET, bar_sz); + pci_read_config_byte(pdev, SKX_EMBAR2SZ_OFFSET, &bar_sz); + dev_dbg(ndev_dev(ndev), "EMBAR2SZ %#x\n", bar_sz); + + /* SBAR01 hit by first part of the b2b bar */ + if (b2b_bar == 0) + bar_addr = addr->bar0_addr; + else if (b2b_bar == 1) + bar_addr = addr->bar2_addr64; + else if (b2b_bar == 2) + bar_addr = addr->bar4_addr64; + else + return -EIO; + + /* setup incoming bar limits == base addrs (zero length windows) */ + bar_addr = addr->bar2_addr64 + (b2b_bar == 1 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SKX_IMBAR1XLMT_OFFSET); + bar_addr = ioread64(mmio + SKX_IMBAR1XLMT_OFFSET); + dev_dbg(ndev_dev(ndev), "IMBAR1XLMT %#018llx\n", bar_addr); + + bar_addr = addr->bar4_addr64 + (b2b_bar == 2 ? ndev->b2b_off : 0); + iowrite64(bar_addr, mmio + SKX_IMBAR2XLMT_OFFSET); + bar_addr = ioread64(mmio + SKX_IMBAR2XLMT_OFFSET); + dev_dbg(ndev_dev(ndev), "IMBAR2XLMT %#018llx\n", bar_addr); + + /* zero incoming translation addrs */ + iowrite64(0, mmio + SKX_IMBAR1XBASE_OFFSET); + iowrite64(0, mmio + SKX_IMBAR2XBASE_OFFSET); + + ndev->peer_mmio = ndev->self_mmio; + + return 0; +} + +static int skx_init_ntb(struct intel_ntb_dev *ndev) +{ + int rc; + + + ndev->mw_count = XEON_MW_COUNT; + ndev->spad_count = SKX_SPAD_COUNT; + ndev->db_count = SKX_DB_COUNT; + ndev->db_link_mask = SKX_DB_LINK_BIT; + + /* DB fixup for using 31 right now */ + if (ndev->hwerr_flags & NTB_HWERR_MSIX_VECTOR32_BAD) + ndev->db_link_mask |= BIT_ULL(31); + + switch (ndev->ntb.topo) { + case NTB_TOPO_B2B_USD: + case NTB_TOPO_B2B_DSD: + ndev->self_reg = &skx_pri_reg; + ndev->peer_reg = &skx_b2b_reg; + ndev->xlat_reg = &skx_sec_xlat; + + if (ndev->ntb.topo == NTB_TOPO_B2B_USD) { + rc = skx_setup_b2b_mw(ndev, + &xeon_b2b_dsd_addr, + &xeon_b2b_usd_addr); + } else { + rc = skx_setup_b2b_mw(ndev, + &xeon_b2b_usd_addr, + &xeon_b2b_dsd_addr); + } + + if (rc) + return rc; + + /* Enable Bus Master and Memory Space on the secondary side */ + iowrite16(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER, + ndev->self_mmio + SKX_SPCICMD_OFFSET); + + break; + + default: + return -EINVAL; + } + + ndev->db_valid_mask = BIT_ULL(ndev->db_count) - 1; + + ndev->reg->db_iowrite(ndev->db_valid_mask, + ndev->self_mmio + + ndev->self_reg->db_mask); + + return 0; +} + +static int skx_init_dev(struct intel_ntb_dev *ndev) +{ + struct pci_dev *pdev; + u8 ppd; + int rc; + + pdev = ndev_pdev(ndev); + + ndev->reg = &skx_reg; + + rc = pci_read_config_byte(pdev, XEON_PPD_OFFSET, &ppd); + if (rc) + return -EIO; + + ndev->ntb.topo = xeon_ppd_topo(ndev, ppd); + dev_dbg(ndev_dev(ndev), "ppd %#x topo %s\n", ppd, + ntb_topo_string(ndev->ntb.topo)); + if (ndev->ntb.topo == NTB_TOPO_NONE) + return -EINVAL; + + if (pdev_is_skx_xeon(pdev)) + ndev->hwerr_flags |= NTB_HWERR_MSIX_VECTOR32_BAD; + + rc = skx_init_ntb(ndev); + if (rc) + return rc; + + return skx_init_isr(ndev); +} + +static int intel_ntb3_link_enable(struct ntb_dev *ntb, + enum ntb_speed max_speed, + enum ntb_width max_width) +{ + struct intel_ntb_dev *ndev; + u32 ntb_ctl; + + ndev = container_of(ntb, struct intel_ntb_dev, ntb); + + dev_dbg(ndev_dev(ndev), + "Enabling link with max_speed %d max_width %d\n", + max_speed, max_width); + + if (max_speed != NTB_SPEED_AUTO) + dev_dbg(ndev_dev(ndev), "ignoring max_speed %d\n", max_speed); + if (max_width != NTB_WIDTH_AUTO) + dev_dbg(ndev_dev(ndev), "ignoring max_width %d\n", max_width); + + ntb_ctl = ioread32(ndev->self_mmio + ndev->reg->ntb_ctl); + ntb_ctl &= ~(NTB_CTL_DISABLE | NTB_CTL_CFG_LOCK); + ntb_ctl |= NTB_CTL_P2S_BAR2_SNOOP | NTB_CTL_S2P_BAR2_SNOOP; + ntb_ctl |= NTB_CTL_P2S_BAR4_SNOOP | NTB_CTL_S2P_BAR4_SNOOP; + iowrite32(ntb_ctl, ndev->self_mmio + ndev->reg->ntb_ctl); + + return 0; +} +static int intel_ntb3_mw_set_trans(struct ntb_dev *ntb, int idx, + dma_addr_t addr, resource_size_t size) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + unsigned long xlat_reg, limit_reg; + resource_size_t bar_size, mw_size; + void __iomem *mmio; + u64 base, limit, reg_val; + int bar; + + if (idx >= ndev->b2b_idx && !ndev->b2b_off) + idx += 1; + + bar = ndev_mw_to_bar(ndev, idx); + if (bar < 0) + return bar; + + bar_size = pci_resource_len(ndev->ntb.pdev, bar); + + if (idx == ndev->b2b_idx) + mw_size = bar_size - ndev->b2b_off; + else + mw_size = bar_size; + + /* hardware requires that addr is aligned to bar size */ + if (addr & (bar_size - 1)) + return -EINVAL; + + /* make sure the range fits in the usable mw size */ + if (size > mw_size) + return -EINVAL; + + mmio = ndev->self_mmio; + xlat_reg = ndev->xlat_reg->bar2_xlat + (idx * 0x10); + limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10); + base = pci_resource_start(ndev->ntb.pdev, bar); + + /* Set the limit if supported, if size is not mw_size */ + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = base + mw_size; + + /* set and verify setting the translation address */ + iowrite64(addr, mmio + xlat_reg); + reg_val = ioread64(mmio + xlat_reg); + if (reg_val != addr) { + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + dev_dbg(ndev_dev(ndev), "BAR %d IMBARXBASE: %#Lx\n", bar, reg_val); + + /* set and verify setting the limit */ + iowrite64(limit, mmio + limit_reg); + reg_val = ioread64(mmio + limit_reg); + if (reg_val != limit) { + iowrite64(base, mmio + limit_reg); + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + dev_dbg(ndev_dev(ndev), "BAR %d IMBARXLMT: %#Lx\n", bar, reg_val); + + /* setup the EP */ + limit_reg = ndev->xlat_reg->bar2_limit + (idx * 0x10) + 0x4000; + base = ioread64(mmio + SKX_EMBAR1_OFFSET + (8 * idx)); + base &= ~0xf; + + if (limit_reg && size != mw_size) + limit = base + size; + else + limit = base + mw_size; + + /* set and verify setting the limit */ + iowrite64(limit, mmio + limit_reg); + reg_val = ioread64(mmio + limit_reg); + if (reg_val != limit) { + iowrite64(base, mmio + limit_reg); + iowrite64(0, mmio + xlat_reg); + return -EIO; + } + + dev_dbg(ndev_dev(ndev), "BAR %d EMBARXLMT: %#Lx\n", bar, reg_val); + + return 0; +} + +static int intel_ntb3_peer_db_set(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + int bit; + + if (db_bits & ~ndev->db_valid_mask) + return -EINVAL; + + while (db_bits) { + bit = __ffs(db_bits); + iowrite32(1, ndev->peer_mmio + + ndev->peer_reg->db_bell + (bit * 4)); + db_bits &= db_bits - 1; + } + + return 0; +} + +static u64 intel_ntb3_db_read(struct ntb_dev *ntb) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + + return ndev_db_read(ndev, + ndev->self_mmio + + ndev->self_reg->db_clear); +} + +static int intel_ntb3_db_clear(struct ntb_dev *ntb, u64 db_bits) +{ + struct intel_ntb_dev *ndev = ntb_ndev(ntb); + + return ndev_db_write(ndev, db_bits, + ndev->self_mmio + + ndev->self_reg->db_clear); +} + /* XEON */ static u64 xeon_db_ioread(void __iomem *mmio) @@ -2120,6 +2696,24 @@ static int intel_ntb_pci_probe(struct pci_dev *pdev, if (rc) goto err_init_dev; + } else if (pdev_is_skx_xeon(pdev)) { + ndev = kzalloc_node(sizeof(*ndev), GFP_KERNEL, node); + if (!ndev) { + rc = -ENOMEM; + goto err_ndev; + } + + ndev_init_struct(ndev, pdev); + ndev->ntb.ops = &intel_ntb3_ops; + + rc = intel_ntb_init_pci(ndev, pdev); + if (rc) + goto err_init_pci; + + rc = skx_init_dev(ndev); + if (rc) + goto err_init_dev; + } else { rc = -EINVAL; goto err_ndev; @@ -2143,7 +2737,7 @@ err_register: ndev_deinit_debugfs(ndev); if (pdev_is_atom(pdev)) atom_deinit_dev(ndev); - else if (pdev_is_xeon(pdev)) + else if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) xeon_deinit_dev(ndev); err_init_dev: intel_ntb_deinit_pci(ndev); @@ -2161,7 +2755,7 @@ static void intel_ntb_pci_remove(struct pci_dev *pdev) ndev_deinit_debugfs(ndev); if (pdev_is_atom(pdev)) atom_deinit_dev(ndev); - else if (pdev_is_xeon(pdev)) + else if (pdev_is_xeon(pdev) || pdev_is_skx_xeon(pdev)) xeon_deinit_dev(ndev); intel_ntb_deinit_pci(ndev); kfree(ndev); @@ -2257,6 +2851,36 @@ static struct intel_b2b_addr xeon_b2b_dsd_addr = { .bar5_addr32 = XEON_B2B_BAR5_ADDR32, }; +static const struct intel_ntb_reg skx_reg = { + .poll_link = xeon_poll_link, + .link_is_up = xeon_link_is_up, + .db_ioread = skx_db_ioread, + .db_iowrite = skx_db_iowrite, + .db_size = sizeof(u64), + .ntb_ctl = SKX_NTBCNTL_OFFSET, + .mw_bar = {2, 4}, +}; + +static const struct intel_ntb_alt_reg skx_pri_reg = { + .db_bell = SKX_EM_DOORBELL_OFFSET, + .db_clear = SKX_IM_INT_STATUS_OFFSET, + .db_mask = SKX_IM_INT_DISABLE_OFFSET, + .spad = SKX_IM_SPAD_OFFSET, +}; + +static const struct intel_ntb_alt_reg skx_b2b_reg = { + .db_bell = SKX_IM_DOORBELL_OFFSET, + .db_clear = SKX_EM_INT_STATUS_OFFSET, + .db_mask = SKX_EM_INT_DISABLE_OFFSET, + .spad = SKX_B2B_SPAD_OFFSET, +}; + +static const struct intel_ntb_xlat_reg skx_sec_xlat = { +/* .bar0_base = SKX_EMBAR0_OFFSET, */ + .bar2_limit = SKX_IMBAR1XLMT_OFFSET, + .bar2_xlat = SKX_IMBAR1XBASE_OFFSET, +}; + /* operations for primary side of local ntb */ static const struct ntb_dev_ops intel_ntb_ops = { .mw_count = intel_ntb_mw_count, @@ -2284,6 +2908,31 @@ static const struct ntb_dev_ops intel_ntb_ops = { .peer_spad_write = intel_ntb_peer_spad_write, }; +static const struct ntb_dev_ops intel_ntb3_ops = { + .mw_count = intel_ntb_mw_count, + .mw_get_range = intel_ntb_mw_get_range, + .mw_set_trans = intel_ntb3_mw_set_trans, + .link_is_up = intel_ntb_link_is_up, + .link_enable = intel_ntb3_link_enable, + .link_disable = intel_ntb_link_disable, + .db_valid_mask = intel_ntb_db_valid_mask, + .db_vector_count = intel_ntb_db_vector_count, + .db_vector_mask = intel_ntb_db_vector_mask, + .db_read = intel_ntb3_db_read, + .db_clear = intel_ntb3_db_clear, + .db_set_mask = intel_ntb_db_set_mask, + .db_clear_mask = intel_ntb_db_clear_mask, + .peer_db_addr = intel_ntb_peer_db_addr, + .peer_db_set = intel_ntb3_peer_db_set, + .spad_is_unsafe = intel_ntb_spad_is_unsafe, + .spad_count = intel_ntb_spad_count, + .spad_read = intel_ntb_spad_read, + .spad_write = intel_ntb_spad_write, + .peer_spad_addr = intel_ntb_peer_spad_addr, + .peer_spad_read = intel_ntb_peer_spad_read, + .peer_spad_write = intel_ntb_peer_spad_write, +}; + static const struct file_operations intel_ntb_debugfs_info = { .owner = THIS_MODULE, .open = simple_open, @@ -2307,6 +2956,7 @@ static const struct pci_device_id intel_ntb_pci_tbl[] = { {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_IVT)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_HSX)}, {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_SS_BDX)}, + {PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_NTB_B2B_SKX)}, {0} }; MODULE_DEVICE_TABLE(pci, intel_ntb_pci_tbl); diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 3ec149cf6562..6e8c1824eb19 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -70,6 +70,7 @@ #define PCI_DEVICE_ID_INTEL_NTB_B2B_BDX 0x6F0D #define PCI_DEVICE_ID_INTEL_NTB_PS_BDX 0x6F0E #define PCI_DEVICE_ID_INTEL_NTB_SS_BDX 0x6F0F +#define PCI_DEVICE_ID_INTEL_NTB_B2B_SKX 0x201C /* Intel Xeon hardware */ @@ -150,6 +151,51 @@ #define XEON_DB_TOTAL_SHIFT 16 #define XEON_SPAD_COUNT 16 +/* Intel Skylake Xeon hardware */ +#define SKX_IMBAR1SZ_OFFSET 0x00d1 +#define SKX_IMBAR2SZ_OFFSET 0x00d5 +#define SKX_EMBAR1SZ_OFFSET 0x00d3 +#define SKX_EMBAR2SZ_OFFSET 0x00d6 +#define SKX_DEVCTRL_OFFSET 0x0098 +#define SKX_DEVSTS_OFFSET 0x009a +#define SKX_UNCERRSTS_OFFSET 0x014c +#define SKX_CORERRSTS_OFFSET 0x0158 +#define SKX_LINK_STATUS_OFFSET 0x01a2 + +#define SKX_NTBCNTL_OFFSET 0x0000 +#define SKX_IMBAR1XBASE_OFFSET 0x0010 /* SBAR2XLAT */ +#define SKX_IMBAR1XLMT_OFFSET 0x0018 /* SBAR2LMT */ +#define SKX_IMBAR2XBASE_OFFSET 0x0020 /* SBAR4XLAT */ +#define SKX_IMBAR2XLMT_OFFSET 0x0028 /* SBAR4LMT */ +#define SKX_IM_INT_STATUS_OFFSET 0x0040 +#define SKX_IM_INT_DISABLE_OFFSET 0x0048 +#define SKX_IM_SPAD_OFFSET 0x0080 /* SPAD */ +#define SKX_USMEMMISS_OFFSET 0x0070 +#define SKX_INTVEC_OFFSET 0x00d0 +#define SKX_IM_DOORBELL_OFFSET 0x0100 /* SDOORBELL0 */ +#define SKX_B2B_SPAD_OFFSET 0x0180 /* B2B SPAD */ +#define SKX_EMBAR0XBASE_OFFSET 0x4008 /* B2B_XLAT */ +#define SKX_EMBAR1XBASE_OFFSET 0x4010 /* PBAR2XLAT */ +#define SKX_EMBAR1XLMT_OFFSET 0x4018 /* PBAR2LMT */ +#define SKX_EMBAR2XBASE_OFFSET 0x4020 /* PBAR4XLAT */ +#define SKX_EMBAR2XLMT_OFFSET 0x4028 /* PBAR4LMT */ +#define SKX_EM_INT_STATUS_OFFSET 0x4040 +#define SKX_EM_INT_DISABLE_OFFSET 0x4048 +#define SKX_EM_SPAD_OFFSET 0x4080 /* remote SPAD */ +#define SKX_EM_DOORBELL_OFFSET 0x4100 /* PDOORBELL0 */ +#define SKX_SPCICMD_OFFSET 0x4504 /* SPCICMD */ +#define SKX_EMBAR0_OFFSET 0x4510 /* SBAR0BASE */ +#define SKX_EMBAR1_OFFSET 0x4518 /* SBAR23BASE */ +#define SKX_EMBAR2_OFFSET 0x4520 /* SBAR45BASE */ + +#define SKX_DB_COUNT 32 +#define SKX_DB_LINK 32 +#define SKX_DB_LINK_BIT BIT_ULL(SKX_DB_LINK) +#define SKX_DB_MSIX_VECTOR_COUNT 33 +#define SKX_DB_MSIX_VECTOR_SHIFT 1 +#define SKX_DB_TOTAL_SHIFT 33 +#define SKX_SPAD_COUNT 16 + /* Intel Atom hardware */ #define ATOM_SBAR2XLAT_OFFSET 0x0008 @@ -240,6 +286,7 @@ #define NTB_HWERR_SDOORBELL_LOCKUP BIT_ULL(0) #define NTB_HWERR_SB01BASE_LOCKUP BIT_ULL(1) #define NTB_HWERR_B2BDOORBELL_BIT14 BIT_ULL(2) +#define NTB_HWERR_MSIX_VECTOR32_BAD BIT_ULL(3) /* flags to indicate unsafe api */ #define NTB_UNSAFE_DB BIT_ULL(0) @@ -263,6 +310,7 @@ struct intel_ntb_reg { struct intel_ntb_alt_reg { unsigned long db_bell; unsigned long db_mask; + unsigned long db_clear; unsigned long spad; }; -- cgit v1.2.3 From e5b0d2d1ba92a8e424e7395537a96e8a373d0267 Mon Sep 17 00:00:00 2001 From: Xiangliang Yu Date: Fri, 18 Nov 2016 14:51:41 +0530 Subject: NTB: add support for hotplug feature AMD NTB support hotplug under B2B mode. NTB will trigger link up/down interrupt event when doing plug add/remove, this patch implements the two interrupt event to support B2B hotplug function. Signed-off-by: Xiangliang Yu Signed-off-by: Shyam Sundar S K Acked-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/hw/amd/ntb_hw_amd.c | 9 ++++++++- drivers/ntb/hw/amd/ntb_hw_amd.h | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c index 6ccba0d862df..b33f13b5b69d 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.c +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c @@ -199,6 +199,11 @@ static int amd_link_is_up(struct amd_ntb_dev *ndev) if (!ndev->peer_sta) return NTB_LNK_STA_ACTIVE(ndev->cntl_sta); + if (ndev->peer_sta & AMD_LINK_UP_EVENT) { + ndev->peer_sta = 0; + return 1; + } + /* If peer_sta is reset or D0 event, the ISR has * started a timer to check link status of hardware. * So here just clear status bit. And if peer_sta is @@ -207,7 +212,7 @@ static int amd_link_is_up(struct amd_ntb_dev *ndev) */ if (ndev->peer_sta & AMD_PEER_RESET_EVENT) ndev->peer_sta &= ~AMD_PEER_RESET_EVENT; - else if (ndev->peer_sta & AMD_PEER_D0_EVENT) + else if (ndev->peer_sta & (AMD_PEER_D0_EVENT | AMD_LINK_DOWN_EVENT)) ndev->peer_sta = 0; return 0; @@ -491,6 +496,8 @@ static void amd_handle_event(struct amd_ntb_dev *ndev, int vec) break; case AMD_PEER_D3_EVENT: case AMD_PEER_PMETO_EVENT: + case AMD_LINK_UP_EVENT: + case AMD_LINK_DOWN_EVENT: amd_ack_smu(ndev, status); /* link down */ diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.h b/drivers/ntb/hw/amd/ntb_hw_amd.h index 2eac3cd3e646..13d73ed94a52 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.h +++ b/drivers/ntb/hw/amd/ntb_hw_amd.h @@ -148,9 +148,12 @@ enum { AMD_PEER_D3_EVENT = BIT(2), AMD_PEER_PMETO_EVENT = BIT(3), AMD_PEER_D0_EVENT = BIT(4), + AMD_LINK_UP_EVENT = BIT(5), + AMD_LINK_DOWN_EVENT = BIT(6), AMD_EVENT_INTMASK = (AMD_PEER_FLUSH_EVENT | AMD_PEER_RESET_EVENT | AMD_PEER_D3_EVENT | - AMD_PEER_PMETO_EVENT | AMD_PEER_D0_EVENT), + AMD_PEER_PMETO_EVENT | AMD_PEER_D0_EVENT | + AMD_LINK_UP_EVENT | AMD_LINK_DOWN_EVENT), AMD_PMESTAT_OFFSET = 0x480, AMD_PMSGTRIG_OFFSET = 0x490, -- cgit v1.2.3 From 872deb21038e90903a40ab6a29b9d0652a6ebc8d Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Fri, 2 Dec 2016 00:44:28 +0530 Subject: NTB: Register and offset values fix for memory window Due to incorrect limit and translation register values, NTB link was going down when the memory window was setup. Made appropriate changes as per spec. Fix limit register values for BAR1, which was overlapping with the BAR23 address. Signed-off-by: Shyam Sundar S K Acked-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/hw/amd/ntb_hw_amd.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c index b33f13b5b69d..774918ca63d2 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.c +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c @@ -138,11 +138,11 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, base_addr = pci_resource_start(ndev->ntb.pdev, bar); if (bar != 1) { - xlat_reg = AMD_BAR23XLAT_OFFSET + ((bar - 2) << 3); - limit_reg = AMD_BAR23LMT_OFFSET + ((bar - 2) << 3); + xlat_reg = AMD_BAR23XLAT_OFFSET + ((bar - 2) << 2); + limit_reg = AMD_BAR23LMT_OFFSET + ((bar - 2) << 2); /* Set the limit if supported */ - limit = base_addr + size; + limit = size; /* set and verify setting the translation address */ write64(addr, peer_mmio + xlat_reg); @@ -164,14 +164,8 @@ static int amd_ntb_mw_set_trans(struct ntb_dev *ntb, int idx, xlat_reg = AMD_BAR1XLAT_OFFSET; limit_reg = AMD_BAR1LMT_OFFSET; - /* split bar addr range must all be 32 bit */ - if (addr & (~0ull << 32)) - return -EINVAL; - if ((addr + size) & (~0ull << 32)) - return -EINVAL; - /* Set the limit if supported */ - limit = base_addr + size; + limit = size; /* set and verify setting the translation address */ write64(addr, peer_mmio + xlat_reg); -- cgit v1.2.3 From b17faba03fc72091f4d040b879def004316952ec Mon Sep 17 00:00:00 2001 From: Shyam Sundar S K Date: Wed, 7 Dec 2016 22:37:05 +0530 Subject: ntb_transport: Limit memory windows based on available, scratchpads When the underlying NTB H/W driver advertises more memory windows than the number of scratchpads available to setup MW's, it is likely that we may end up filling the remaining memory windows with garbage. So to avoid that, lets limit the memory windows that transport driver can setup based on the available scratchpads. Signed-off-by: Shyam Sundar S K Acked-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 4eb8adb34508..9b791cb33c19 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -66,6 +66,7 @@ #define NTB_TRANSPORT_VER "4" #define NTB_TRANSPORT_NAME "ntb_transport" #define NTB_TRANSPORT_DESC "Software Queue-Pair Transport over NTB" +#define NTB_TRANSPORT_MIN_SPADS (MW0_SZ_HIGH + 2) MODULE_DESCRIPTION(NTB_TRANSPORT_DESC); MODULE_VERSION(NTB_TRANSPORT_VER); @@ -242,9 +243,6 @@ enum { NUM_MWS, MW0_SZ_HIGH, MW0_SZ_LOW, - MW1_SZ_HIGH, - MW1_SZ_LOW, - MAX_SPAD, }; #define dev_client_dev(__dev) \ @@ -811,7 +809,7 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt) { struct ntb_transport_qp *qp; u64 qp_bitmap_alloc; - int i; + unsigned int i, count; qp_bitmap_alloc = nt->qp_bitmap & ~nt->qp_bitmap_free; @@ -831,7 +829,8 @@ static void ntb_transport_link_cleanup(struct ntb_transport_ctx *nt) * goes down, blast them now to give them a sane value the next * time they are accessed */ - for (i = 0; i < MAX_SPAD; i++) + count = ntb_spad_count(nt->ndev); + for (i = 0; i < count; i++) ntb_spad_write(nt->ndev, i, 0); } @@ -1064,17 +1063,12 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) { struct ntb_transport_ctx *nt; struct ntb_transport_mw *mw; - unsigned int mw_count, qp_count; + unsigned int mw_count, qp_count, spad_count, max_mw_count_for_spads; u64 qp_bitmap; int node; int rc, i; mw_count = ntb_mw_count(ndev); - if (ntb_spad_count(ndev) < (NUM_MWS + 1 + mw_count * 2)) { - dev_err(&ndev->dev, "Not enough scratch pad registers for %s", - NTB_TRANSPORT_NAME); - return -EIO; - } if (ntb_db_is_unsafe(ndev)) dev_dbg(&ndev->dev, @@ -1090,8 +1084,18 @@ static int ntb_transport_probe(struct ntb_client *self, struct ntb_dev *ndev) return -ENOMEM; nt->ndev = ndev; + spad_count = ntb_spad_count(ndev); + + /* Limit the MW's based on the availability of scratchpads */ + + if (spad_count < NTB_TRANSPORT_MIN_SPADS) { + nt->mw_count = 0; + rc = -EINVAL; + goto err; + } - nt->mw_count = mw_count; + max_mw_count_for_spads = (spad_count - MW0_SZ_HIGH) / 2; + nt->mw_count = min(mw_count, max_mw_count_for_spads); nt->mw_vec = kzalloc_node(mw_count * sizeof(*nt->mw_vec), GFP_KERNEL, node); -- cgit v1.2.3 From 09e71a6f13445974fe9b70b6d4b68ac362cd68b6 Mon Sep 17 00:00:00 2001 From: Dave Jiang Date: Tue, 13 Dec 2016 09:03:13 -0700 Subject: ntb: fix SKX NTB config space size register offsets The offsets for the SZ registers are wrong. Updated. Signed-off-by: Dave Jiang Reported-by: Sandeep Mann Tested-by: Zachary Ross Signed-off-by: Jon Mason --- drivers/ntb/hw/intel/ntb_hw_intel.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.h b/drivers/ntb/hw/intel/ntb_hw_intel.h index 6e8c1824eb19..f2cf8a783f1e 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.h +++ b/drivers/ntb/hw/intel/ntb_hw_intel.h @@ -152,10 +152,10 @@ #define XEON_SPAD_COUNT 16 /* Intel Skylake Xeon hardware */ -#define SKX_IMBAR1SZ_OFFSET 0x00d1 -#define SKX_IMBAR2SZ_OFFSET 0x00d5 -#define SKX_EMBAR1SZ_OFFSET 0x00d3 -#define SKX_EMBAR2SZ_OFFSET 0x00d6 +#define SKX_IMBAR1SZ_OFFSET 0x00d0 +#define SKX_IMBAR2SZ_OFFSET 0x00d1 +#define SKX_EMBAR1SZ_OFFSET 0x00d2 +#define SKX_EMBAR2SZ_OFFSET 0x00d3 #define SKX_DEVCTRL_OFFSET 0x0098 #define SKX_DEVSTS_OFFSET 0x009a #define SKX_UNCERRSTS_OFFSET 0x014c -- cgit v1.2.3 From 28734e8f69395de4c2aea50fcb74d87720e8537b Mon Sep 17 00:00:00 2001 From: Christophe JAILLET Date: Mon, 19 Dec 2016 06:52:55 +0100 Subject: NTB: Fix 'request_irq()' and 'free_irq()' inconsistancy 'request_irq()' and 'free_irq()' should have the same 'dev_id'. Signed-off-by: Christophe JAILLET Acked-by: Dave Jiang Signed-off-by: Jon Mason --- drivers/ntb/hw/amd/ntb_hw_amd.c | 2 +- drivers/ntb/hw/intel/ntb_hw_intel.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/ntb/hw/amd/ntb_hw_amd.c b/drivers/ntb/hw/amd/ntb_hw_amd.c index 774918ca63d2..019a158e1128 100644 --- a/drivers/ntb/hw/amd/ntb_hw_amd.c +++ b/drivers/ntb/hw/amd/ntb_hw_amd.c @@ -599,7 +599,7 @@ static int ndev_init_isr(struct amd_ntb_dev *ndev, err_msix_request: while (i-- > 0) - free_irq(ndev->msix[i].vector, ndev); + free_irq(ndev->msix[i].vector, &ndev->vec[i]); pci_disable_msix(pdev); err_msix_enable: kfree(ndev->msix); diff --git a/drivers/ntb/hw/intel/ntb_hw_intel.c b/drivers/ntb/hw/intel/ntb_hw_intel.c index d2ce28008fee..eca9688bf9d9 100644 --- a/drivers/ntb/hw/intel/ntb_hw_intel.c +++ b/drivers/ntb/hw/intel/ntb_hw_intel.c @@ -494,7 +494,7 @@ static int ndev_init_isr(struct intel_ntb_dev *ndev, err_msix_request: while (i-- > 0) - free_irq(ndev->msix[i].vector, ndev); + free_irq(ndev->msix[i].vector, &ndev->vec[i]); pci_disable_msix(pdev); err_msix_enable: kfree(ndev->msix); -- cgit v1.2.3 From dfb7d24c5ad5c986f2417f52784738b67cfedd4d Mon Sep 17 00:00:00 2001 From: Steve Wahl Date: Wed, 21 Dec 2016 11:45:22 -0500 Subject: ntb_transport: Remove unnecessary call to ntb_peer_spad_read The results were previously ignored, anyway. Signed-off-by: Steve Wahl Fixes: e26a5843f7f5014ae4460030ca4de029a3ac35d3 Acked-by: Allen Hubbe Signed-off-by: Jon Mason --- drivers/ntb/ntb_transport.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers') diff --git a/drivers/ntb/ntb_transport.c b/drivers/ntb/ntb_transport.c index 9b791cb33c19..f81aa4b18d9f 100644 --- a/drivers/ntb/ntb_transport.c +++ b/drivers/ntb/ntb_transport.c @@ -959,7 +959,6 @@ static void ntb_qp_link_work(struct work_struct *work) ntb_peer_spad_write(nt->ndev, QP_LINKS, val | BIT(qp->qp_num)); /* query remote spad for qp ready bits */ - ntb_peer_spad_read(nt->ndev, QP_LINKS); dev_dbg_ratelimited(&pdev->dev, "Remote QP link status = %x\n", val); /* See if the remote side is up */ -- cgit v1.2.3 From b1227d019fa98c43381ad8827baf7efbe2923ed1 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 21 Dec 2016 18:00:24 -0800 Subject: ipvlan: fix various issues in ipvlan_process_multicast() 1) netif_rx() / dev_forward_skb() should not be called from process context. 2) ipvlan_count_rx() should be called with preemption disabled. 3) We should check if ipvlan->dev is up before feeding packets to netif_rx() 4) We need to prevent device from disappearing if some packets are in the multicast backlog. 5) One kfree_skb() should be a consume_skb() eventually Fixes: ba35f8588f47 ("ipvlan: Defer multicast / broadcast processing to a work-queue") Signed-off-by: Eric Dumazet Cc: Mahesh Bandewar Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan_core.c | 38 +++++++++++++++++++++++++------------- drivers/net/ipvlan/ipvlan_main.c | 7 ++++++- 2 files changed, 31 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index b4e990743e1d..ea6bc1e12cdf 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -207,6 +207,9 @@ void ipvlan_process_multicast(struct work_struct *work) spin_unlock_bh(&port->backlog.lock); while ((skb = __skb_dequeue(&list)) != NULL) { + struct net_device *dev = skb->dev; + bool consumed = false; + ethh = eth_hdr(skb); hlocal = ether_addr_equal(ethh->h_source, port->dev->dev_addr); mac_hash = ipvlan_mac_hash(ethh->h_dest); @@ -219,27 +222,29 @@ void ipvlan_process_multicast(struct work_struct *work) dlocal = false; rcu_read_lock(); list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) { - if (hlocal && (ipvlan->dev == skb->dev)) { + if (hlocal && (ipvlan->dev == dev)) { dlocal = true; continue; } if (!test_bit(mac_hash, ipvlan->mac_filters)) continue; - + if (!(ipvlan->dev->flags & IFF_UP)) + continue; ret = NET_RX_DROP; len = skb->len + ETH_HLEN; nskb = skb_clone(skb, GFP_ATOMIC); - if (!nskb) - goto acct; - - nskb->pkt_type = pkt_type; - nskb->dev = ipvlan->dev; - if (hlocal) - ret = dev_forward_skb(ipvlan->dev, nskb); - else - ret = netif_rx(nskb); -acct: + local_bh_disable(); + if (nskb) { + consumed = true; + nskb->pkt_type = pkt_type; + nskb->dev = ipvlan->dev; + if (hlocal) + ret = dev_forward_skb(ipvlan->dev, nskb); + else + ret = netif_rx(nskb); + } ipvlan_count_rx(ipvlan, len, ret == NET_RX_SUCCESS, true); + local_bh_enable(); } rcu_read_unlock(); @@ -249,8 +254,13 @@ acct: skb->pkt_type = pkt_type; dev_queue_xmit(skb); } else { - kfree_skb(skb); + if (consumed) + consume_skb(skb); + else + kfree_skb(skb); } + if (dev) + dev_put(dev); } } @@ -479,6 +489,8 @@ static void ipvlan_multicast_enqueue(struct ipvl_port *port, spin_lock(&port->backlog.lock); if (skb_queue_len(&port->backlog) < IPVLAN_QBACKLOG_LIMIT) { + if (skb->dev) + dev_hold(skb->dev); __skb_queue_tail(&port->backlog, skb); spin_unlock(&port->backlog.lock); schedule_work(&port->wq); diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c index 693ec5b66222..8b0f99300cbc 100644 --- a/drivers/net/ipvlan/ipvlan_main.c +++ b/drivers/net/ipvlan/ipvlan_main.c @@ -135,6 +135,7 @@ err: static void ipvlan_port_destroy(struct net_device *dev) { struct ipvl_port *port = ipvlan_port_get_rtnl(dev); + struct sk_buff *skb; dev->priv_flags &= ~IFF_IPVLAN_MASTER; if (port->mode == IPVLAN_MODE_L3S) { @@ -144,7 +145,11 @@ static void ipvlan_port_destroy(struct net_device *dev) } netdev_rx_handler_unregister(dev); cancel_work_sync(&port->wq); - __skb_queue_purge(&port->backlog); + while ((skb = __skb_dequeue(&port->backlog)) != NULL) { + if (skb->dev) + dev_put(skb->dev); + kfree_skb(skb); + } kfree(port); } -- cgit v1.2.3 From e252536068efd1578c6e23e7323527c5e6e980bd Mon Sep 17 00:00:00 2001 From: Mahesh Bandewar Date: Wed, 21 Dec 2016 17:30:16 -0800 Subject: ipvlan: fix multicast processing In an IPvlan setup when master is set in loopback mode e.g. ethtool -K eth0 set loopback on where eth0 is master device for IPvlan setup. The failure is caused by the faulty logic that determines if the packet is from TX-path vs. RX-path by just looking at the mac- addresses on the packet while processing multicast packets. In the loopback-mode where this crash was happening, the packets that are sent out are reflected by the NIC and are processed on the RX path, but mac-address check tricks into thinking this packet is from TX path and falsely uses dev_forward_skb() to pass packets to the slave (virtual) devices. This patch records the path while queueing packets and eliminates logic of looking at mac-addresses for the same decision. ------------[ cut here ]------------ kernel BUG at include/linux/skbuff.h:1737! Call Trace: [] dev_forward_skb+0x92/0xd0 [] ipvlan_process_multicast+0x395/0x4c0 [ipvlan] [] ? ipvlan_process_multicast+0xd7/0x4c0 [ipvlan] [] ? process_one_work+0x147/0x660 [] process_one_work+0x1a9/0x660 [] ? process_one_work+0x147/0x660 [] worker_thread+0x11d/0x360 [] ? rescuer_thread+0x350/0x350 [] kthread+0xdb/0xe0 [] ? _raw_spin_unlock_irq+0x30/0x50 [] ? flush_kthread_worker+0xc0/0xc0 [] ret_from_fork+0x9a/0xd0 [] ? flush_kthread_worker+0xc0/0xc0 Fixes: ba35f8588f47 ("ipvlan: Defer multicast / broadcast processing to a work-queue") Signed-off-by: Mahesh Bandewar CC: Eric Dumazet Signed-off-by: David S. Miller --- drivers/net/ipvlan/ipvlan.h | 5 +++++ drivers/net/ipvlan/ipvlan_core.c | 26 +++++++++++++++----------- 2 files changed, 20 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h index 031093e1c25f..dbfbb33ac66c 100644 --- a/drivers/net/ipvlan/ipvlan.h +++ b/drivers/net/ipvlan/ipvlan.h @@ -99,6 +99,11 @@ struct ipvl_port { int count; }; +struct ipvl_skb_cb { + bool tx_pkt; +}; +#define IPVL_SKB_CB(_skb) ((struct ipvl_skb_cb *)&((_skb)->cb[0])) + static inline struct ipvl_port *ipvlan_port_get_rcu(const struct net_device *d) { return rcu_dereference(d->rx_handler_data); diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c index ea6bc1e12cdf..83ce74acf82d 100644 --- a/drivers/net/ipvlan/ipvlan_core.c +++ b/drivers/net/ipvlan/ipvlan_core.c @@ -198,7 +198,7 @@ void ipvlan_process_multicast(struct work_struct *work) unsigned int mac_hash; int ret; u8 pkt_type; - bool hlocal, dlocal; + bool tx_pkt; __skb_queue_head_init(&list); @@ -211,7 +211,7 @@ void ipvlan_process_multicast(struct work_struct *work) bool consumed = false; ethh = eth_hdr(skb); - hlocal = ether_addr_equal(ethh->h_source, port->dev->dev_addr); + tx_pkt = IPVL_SKB_CB(skb)->tx_pkt; mac_hash = ipvlan_mac_hash(ethh->h_dest); if (ether_addr_equal(ethh->h_dest, port->dev->broadcast)) @@ -219,13 +219,10 @@ void ipvlan_process_multicast(struct work_struct *work) else pkt_type = PACKET_MULTICAST; - dlocal = false; rcu_read_lock(); list_for_each_entry_rcu(ipvlan, &port->ipvlans, pnode) { - if (hlocal && (ipvlan->dev == dev)) { - dlocal = true; + if (tx_pkt && (ipvlan->dev == skb->dev)) continue; - } if (!test_bit(mac_hash, ipvlan->mac_filters)) continue; if (!(ipvlan->dev->flags & IFF_UP)) @@ -238,7 +235,7 @@ void ipvlan_process_multicast(struct work_struct *work) consumed = true; nskb->pkt_type = pkt_type; nskb->dev = ipvlan->dev; - if (hlocal) + if (tx_pkt) ret = dev_forward_skb(ipvlan->dev, nskb); else ret = netif_rx(nskb); @@ -248,7 +245,7 @@ void ipvlan_process_multicast(struct work_struct *work) } rcu_read_unlock(); - if (dlocal) { + if (tx_pkt) { /* If the packet originated here, send it out. */ skb->dev = port->dev; skb->pkt_type = pkt_type; @@ -480,13 +477,20 @@ out: } static void ipvlan_multicast_enqueue(struct ipvl_port *port, - struct sk_buff *skb) + struct sk_buff *skb, bool tx_pkt) { if (skb->protocol == htons(ETH_P_PAUSE)) { kfree_skb(skb); return; } + /* Record that the deferred packet is from TX or RX path. By + * looking at mac-addresses on packet will lead to erronus decisions. + * (This would be true for a loopback-mode on master device or a + * hair-pin mode of the switch.) + */ + IPVL_SKB_CB(skb)->tx_pkt = tx_pkt; + spin_lock(&port->backlog.lock); if (skb_queue_len(&port->backlog) < IPVLAN_QBACKLOG_LIMIT) { if (skb->dev) @@ -549,7 +553,7 @@ static int ipvlan_xmit_mode_l2(struct sk_buff *skb, struct net_device *dev) } else if (is_multicast_ether_addr(eth->h_dest)) { ipvlan_skb_crossing_ns(skb, NULL); - ipvlan_multicast_enqueue(ipvlan->port, skb); + ipvlan_multicast_enqueue(ipvlan->port, skb, true); return NET_XMIT_SUCCESS; } @@ -646,7 +650,7 @@ static rx_handler_result_t ipvlan_handle_mode_l2(struct sk_buff **pskb, */ if (nskb) { ipvlan_skb_crossing_ns(nskb, NULL); - ipvlan_multicast_enqueue(port, nskb); + ipvlan_multicast_enqueue(port, nskb, false); } } } else { -- cgit v1.2.3 From eb9def61be7197669cab51f43789b53aa7a69509 Mon Sep 17 00:00:00 2001 From: Tariq Toukan Date: Thu, 22 Dec 2016 14:32:58 +0200 Subject: net/mlx4_en: Fix user prio field in XDP forward The user prio field is wrong (and overflows) in the XDP forward flow. This is a result of a bad value for num_tx_rings_p_up, which should account all XDP TX rings, as they operate for the same user prio. Signed-off-by: Tariq Toukan Reported-by: Martin KaFai Lau Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c index bcd955339058..edbe200ac2fa 100644 --- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c +++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c @@ -1638,7 +1638,8 @@ int mlx4_en_start_port(struct net_device *dev) /* Configure tx cq's and rings */ for (t = 0 ; t < MLX4_EN_NUM_TX_TYPES; t++) { - u8 num_tx_rings_p_up = t == TX ? priv->num_tx_rings_p_up : 1; + u8 num_tx_rings_p_up = t == TX ? + priv->num_tx_rings_p_up : priv->tx_ring_num[t]; for (i = 0; i < priv->tx_ring_num[t]; i++) { /* Configure cq */ -- cgit v1.2.3 From 7c0f6ba682b9c7632072ffbedf8d328c8f3c42ba Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 24 Dec 2016 11:46:01 -0800 Subject: Replace with globally This was entirely automated, using the script by Al: PATT='^[[:blank:]]*#[[:blank:]]*include[[:blank:]]*' sed -i -e "s!$PATT!#include !" \ $(git grep -l "$PATT"|grep -v ^include/linux/uaccess.h) to do the replacement at the end of the merge window. Requested-by: Al Viro Signed-off-by: Linus Torvalds --- arch/alpha/boot/misc.c | 2 +- arch/alpha/kernel/irq.c | 2 +- arch/alpha/kernel/osf_sys.c | 2 +- arch/alpha/kernel/process.c | 2 +- arch/alpha/kernel/ptrace.c | 2 +- arch/alpha/kernel/setup.c | 2 +- arch/alpha/kernel/signal.c | 2 +- arch/alpha/kernel/srm_env.c | 2 +- arch/alpha/kernel/srmcons.c | 2 +- arch/alpha/kernel/time.c | 2 +- arch/alpha/kernel/traps.c | 2 +- arch/alpha/lib/csum_partial_copy.c | 2 +- arch/alpha/math-emu/math.c | 2 +- arch/alpha/mm/init.c | 2 +- arch/arm/common/bL_switcher_dummy_if.c | 2 +- arch/arm/kernel/swp_emulate.c | 2 +- arch/arm/kvm/arm.c | 2 +- arch/arm/kvm/guest.c | 2 +- arch/arm/mach-iop13xx/irq.c | 2 +- arch/arm/mach-ixp4xx/common.c | 2 +- arch/arm/mach-rpc/dma.c | 2 +- arch/arm/plat-iop/time.c | 2 +- arch/arm64/include/asm/word-at-a-time.h | 2 +- arch/arm64/kernel/armv8_deprecated.c | 2 +- arch/arm64/kernel/entry.S | 2 +- arch/arm64/kernel/probes/kprobes.c | 2 +- arch/arm64/kernel/signal32.c | 2 +- arch/arm64/kvm/guest.c | 2 +- arch/arm64/lib/clear_user.S | 2 +- arch/arm64/lib/copy_from_user.S | 2 +- arch/arm64/lib/copy_in_user.S | 2 +- arch/arm64/lib/copy_to_user.S | 2 +- arch/arm64/mm/cache.S | 2 +- arch/arm64/xen/hypercall.S | 2 +- arch/avr32/kernel/avr32_ksyms.c | 2 +- arch/avr32/kernel/ptrace.c | 2 +- arch/avr32/kernel/signal.c | 2 +- arch/avr32/mm/cache.c | 2 +- arch/blackfin/kernel/bfin_dma.c | 2 +- arch/blackfin/kernel/kgdb_test.c | 2 +- arch/blackfin/kernel/module.c | 2 +- arch/c6x/mm/init.c | 2 +- arch/cris/arch-v10/drivers/eeprom.c | 2 +- arch/cris/arch-v10/drivers/sync_serial.c | 2 +- arch/cris/arch-v10/kernel/ptrace.c | 2 +- arch/cris/arch-v10/kernel/signal.c | 2 +- arch/cris/arch-v10/kernel/traps.c | 2 +- arch/cris/arch-v10/lib/usercopy.c | 2 +- arch/cris/arch-v10/mm/fault.c | 2 +- arch/cris/arch-v32/drivers/cryptocop.c | 2 +- arch/cris/arch-v32/kernel/ptrace.c | 2 +- arch/cris/arch-v32/kernel/signal.c | 2 +- arch/cris/arch-v32/kernel/traps.c | 2 +- arch/cris/arch-v32/lib/usercopy.c | 2 +- arch/cris/kernel/crisksyms.c | 2 +- arch/cris/kernel/process.c | 2 +- arch/cris/kernel/profile.c | 2 +- arch/cris/kernel/ptrace.c | 2 +- arch/cris/kernel/sys_cris.c | 2 +- arch/cris/kernel/traps.c | 2 +- arch/frv/include/asm/futex.h | 2 +- arch/frv/kernel/irq.c | 2 +- arch/frv/kernel/pm-mb93093.c | 2 +- arch/frv/kernel/pm.c | 2 +- arch/frv/kernel/process.c | 2 +- arch/frv/kernel/ptrace.c | 2 +- arch/frv/kernel/signal.c | 2 +- arch/frv/kernel/sys_frv.c | 2 +- arch/frv/kernel/sysctl.c | 2 +- arch/frv/kernel/traps.c | 2 +- arch/frv/kernel/uaccess.c | 2 +- arch/frv/mm/dma-alloc.c | 2 +- arch/frv/mm/extable.c | 2 +- arch/h8300/boot/compressed/misc.c | 2 +- arch/h8300/kernel/process.c | 2 +- arch/h8300/kernel/signal.c | 2 +- arch/hexagon/kernel/hexagon_ksyms.c | 2 +- arch/hexagon/kernel/signal.c | 2 +- arch/hexagon/mm/uaccess.c | 2 +- arch/hexagon/mm/vm_fault.c | 2 +- arch/ia64/kernel/brl_emu.c | 2 +- arch/ia64/kernel/crash_dump.c | 2 +- arch/ia64/kernel/init_task.c | 2 +- arch/ia64/kernel/irq.c | 2 +- arch/ia64/kernel/kprobes.c | 2 +- arch/ia64/kernel/perfmon.c | 2 +- arch/ia64/kernel/process.c | 2 +- arch/ia64/kernel/ptrace.c | 2 +- arch/ia64/kernel/salinfo.c | 2 +- arch/ia64/kernel/signal.c | 2 +- arch/ia64/kernel/sys_ia64.c | 2 +- arch/ia64/kernel/traps.c | 2 +- arch/ia64/kernel/unaligned.c | 2 +- arch/ia64/kernel/unwind.c | 2 +- arch/ia64/lib/csum_partial_copy.c | 2 +- arch/ia64/mm/extable.c | 2 +- arch/ia64/mm/init.c | 2 +- arch/ia64/sn/kernel/sn2/sn_hwperf.c | 2 +- arch/ia64/sn/kernel/sn2/sn_proc_fs.c | 2 +- arch/ia64/sn/kernel/tiocx.c | 2 +- arch/m32r/kernel/align.c | 2 +- arch/m32r/kernel/irq.c | 2 +- arch/m32r/kernel/m32r_ksyms.c | 2 +- arch/m32r/kernel/process.c | 2 +- arch/m32r/kernel/ptrace.c | 2 +- arch/m32r/kernel/signal.c | 2 +- arch/m32r/kernel/sys_m32r.c | 2 +- arch/m32r/kernel/traps.c | 2 +- arch/m32r/lib/csum_partial_copy.c | 2 +- arch/m32r/lib/usercopy.c | 2 +- arch/m32r/mm/extable.c | 2 +- arch/m32r/mm/fault-nommu.c | 2 +- arch/m68k/bvme6000/rtc.c | 2 +- arch/m68k/kernel/process.c | 2 +- arch/m68k/kernel/ptrace.c | 2 +- arch/m68k/kernel/signal.c | 2 +- arch/m68k/kernel/sys_m68k.c | 2 +- arch/m68k/kernel/traps.c | 2 +- arch/m68k/lib/uaccess.c | 2 +- arch/m68k/mac/misc.c | 2 +- arch/m68k/mm/init.c | 2 +- arch/m68k/mm/motorola.c | 2 +- arch/m68k/mm/sun3mmu.c | 2 +- arch/m68k/mvme16x/rtc.c | 2 +- arch/m68k/sun3/mmu_emu.c | 2 +- arch/metag/kernel/irq.c | 2 +- arch/mips/alchemy/common/power.c | 2 +- arch/mips/dec/kn01-berr.c | 2 +- arch/mips/include/asm/checksum.h | 2 +- arch/mips/include/asm/compat-signal.h | 2 +- arch/mips/include/asm/r4kcache.h | 2 +- arch/mips/include/asm/termios.h | 2 +- arch/mips/jazz/jazzdma.c | 2 +- arch/mips/kernel/branch.c | 2 +- arch/mips/kernel/cpu-probe.c | 2 +- arch/mips/kernel/crash_dump.c | 2 +- arch/mips/kernel/irq.c | 2 +- arch/mips/kernel/kgdb.c | 2 +- arch/mips/kernel/linux32.c | 2 +- arch/mips/kernel/mips-mt-fpaff.c | 2 +- arch/mips/kernel/mips-r2-to-r6-emul.c | 2 +- arch/mips/kernel/mips_ksyms.c | 2 +- arch/mips/kernel/process.c | 2 +- arch/mips/kernel/ptrace.c | 2 +- arch/mips/kernel/ptrace32.c | 2 +- arch/mips/kernel/signal32.c | 2 +- arch/mips/kernel/signal_n32.c | 2 +- arch/mips/kernel/syscall.c | 2 +- arch/mips/kernel/traps.c | 2 +- arch/mips/kernel/unaligned.c | 2 +- arch/mips/math-emu/cp1emu.c | 2 +- arch/mips/math-emu/dsemul.c | 2 +- arch/mips/mm/extable.c | 2 +- arch/mips/mm/sc-debugfs.c | 2 +- arch/mips/oprofile/op_model_loongson3.c | 2 +- arch/mips/sgi-ip22/ip28-berr.c | 2 +- arch/mips/sgi-ip27/ip27-berr.c | 2 +- arch/mips/sgi-ip32/ip32-berr.c | 2 +- arch/mips/sibyte/common/sb_tbprof.c | 2 +- arch/mn10300/kernel/fpu.c | 2 +- arch/mn10300/kernel/mn10300_ksyms.c | 2 +- arch/mn10300/kernel/process.c | 2 +- arch/mn10300/kernel/ptrace.c | 2 +- arch/mn10300/kernel/setup.c | 2 +- arch/mn10300/kernel/signal.c | 2 +- arch/mn10300/kernel/sys_mn10300.c | 2 +- arch/mn10300/lib/checksum.c | 2 +- arch/mn10300/mm/cache-smp.c | 2 +- arch/mn10300/mm/cache.c | 2 +- arch/mn10300/mm/extable.c | 2 +- arch/mn10300/mm/init.c | 2 +- arch/mn10300/mm/misalignment.c | 2 +- arch/mn10300/proc-mn2ws0050/proc-init.c | 2 +- arch/nios2/kernel/traps.c | 2 +- arch/openrisc/kernel/or32_ksyms.c | 2 +- arch/openrisc/kernel/process.c | 2 +- arch/openrisc/kernel/signal.c | 2 +- arch/openrisc/kernel/traps.c | 2 +- arch/openrisc/mm/fault.c | 2 +- arch/parisc/kernel/asm-offsets.c | 2 +- arch/parisc/kernel/parisc_ksyms.c | 2 +- arch/parisc/kernel/pci-dma.c | 2 +- arch/parisc/kernel/perf.c | 2 +- arch/parisc/kernel/ptrace.c | 2 +- arch/parisc/kernel/signal.c | 2 +- arch/parisc/kernel/signal32.c | 2 +- arch/parisc/kernel/sys_parisc.c | 2 +- arch/parisc/kernel/time.c | 2 +- arch/parisc/kernel/unaligned.c | 2 +- arch/parisc/kernel/unwind.c | 2 +- arch/parisc/lib/checksum.c | 2 +- arch/powerpc/include/asm/asm-prototypes.h | 2 +- arch/powerpc/kernel/align.c | 2 +- arch/powerpc/kernel/crash_dump.c | 2 +- arch/powerpc/kernel/hw_breakpoint.c | 2 +- arch/powerpc/kernel/irq.c | 2 +- arch/powerpc/kernel/kprobes.c | 2 +- arch/powerpc/kernel/module.c | 2 +- arch/powerpc/kernel/nvram_64.c | 2 +- arch/powerpc/kernel/pci_32.c | 2 +- arch/powerpc/kernel/proc_powerpc.c | 2 +- arch/powerpc/kernel/ptrace.c | 2 +- arch/powerpc/kernel/ptrace32.c | 2 +- arch/powerpc/kernel/rtas-proc.c | 2 +- arch/powerpc/kernel/rtas.c | 2 +- arch/powerpc/kernel/rtas_flash.c | 2 +- arch/powerpc/kernel/rtasd.c | 2 +- arch/powerpc/kernel/setup_32.c | 2 +- arch/powerpc/kernel/signal.c | 2 +- arch/powerpc/kernel/signal_32.c | 2 +- arch/powerpc/kernel/signal_64.c | 2 +- arch/powerpc/kernel/sys_ppc32.c | 2 +- arch/powerpc/kernel/syscalls.c | 2 +- arch/powerpc/kernel/time.c | 2 +- arch/powerpc/kernel/traps.c | 2 +- arch/powerpc/kernel/vecemu.c | 2 +- arch/powerpc/kvm/book3s.c | 2 +- arch/powerpc/kvm/book3s_hv.c | 2 +- arch/powerpc/kvm/book3s_pr.c | 2 +- arch/powerpc/kvm/book3s_pr_papr.c | 2 +- arch/powerpc/kvm/book3s_rtas.c | 2 +- arch/powerpc/kvm/book3s_xics.c | 2 +- arch/powerpc/kvm/booke.c | 2 +- arch/powerpc/kvm/mpic.c | 2 +- arch/powerpc/kvm/powerpc.c | 2 +- arch/powerpc/lib/checksum_wrappers.c | 2 +- arch/powerpc/lib/code-patching.c | 2 +- arch/powerpc/lib/sstep.c | 2 +- arch/powerpc/lib/usercopy_64.c | 2 +- arch/powerpc/math-emu/fabs.c | 2 +- arch/powerpc/math-emu/fadd.c | 2 +- arch/powerpc/math-emu/fadds.c | 2 +- arch/powerpc/math-emu/fcmpo.c | 2 +- arch/powerpc/math-emu/fcmpu.c | 2 +- arch/powerpc/math-emu/fctiw.c | 2 +- arch/powerpc/math-emu/fctiwz.c | 2 +- arch/powerpc/math-emu/fdiv.c | 2 +- arch/powerpc/math-emu/fdivs.c | 2 +- arch/powerpc/math-emu/fmadd.c | 2 +- arch/powerpc/math-emu/fmadds.c | 2 +- arch/powerpc/math-emu/fmr.c | 2 +- arch/powerpc/math-emu/fmsub.c | 2 +- arch/powerpc/math-emu/fmsubs.c | 2 +- arch/powerpc/math-emu/fmul.c | 2 +- arch/powerpc/math-emu/fmuls.c | 2 +- arch/powerpc/math-emu/fnabs.c | 2 +- arch/powerpc/math-emu/fneg.c | 2 +- arch/powerpc/math-emu/fnmadd.c | 2 +- arch/powerpc/math-emu/fnmadds.c | 2 +- arch/powerpc/math-emu/fnmsub.c | 2 +- arch/powerpc/math-emu/fnmsubs.c | 2 +- arch/powerpc/math-emu/fre.c | 2 +- arch/powerpc/math-emu/fres.c | 2 +- arch/powerpc/math-emu/frsp.c | 2 +- arch/powerpc/math-emu/frsqrte.c | 2 +- arch/powerpc/math-emu/frsqrtes.c | 2 +- arch/powerpc/math-emu/fsel.c | 2 +- arch/powerpc/math-emu/fsqrt.c | 2 +- arch/powerpc/math-emu/fsqrts.c | 2 +- arch/powerpc/math-emu/fsub.c | 2 +- arch/powerpc/math-emu/fsubs.c | 2 +- arch/powerpc/math-emu/lfd.c | 2 +- arch/powerpc/math-emu/lfs.c | 2 +- arch/powerpc/math-emu/math.c | 2 +- arch/powerpc/math-emu/math_efp.c | 2 +- arch/powerpc/math-emu/mcrfs.c | 2 +- arch/powerpc/math-emu/mffs.c | 2 +- arch/powerpc/math-emu/mtfsb0.c | 2 +- arch/powerpc/math-emu/mtfsb1.c | 2 +- arch/powerpc/math-emu/mtfsf.c | 2 +- arch/powerpc/math-emu/mtfsfi.c | 2 +- arch/powerpc/math-emu/stfd.c | 2 +- arch/powerpc/math-emu/stfiwx.c | 2 +- arch/powerpc/math-emu/stfs.c | 2 +- arch/powerpc/mm/40x_mmu.c | 2 +- arch/powerpc/mm/fsl_booke_mmu.c | 2 +- arch/powerpc/mm/hash_utils_64.c | 2 +- arch/powerpc/mm/init_64.c | 2 +- arch/powerpc/mm/subpage-prot.c | 2 +- arch/powerpc/platforms/cell/spufs/coredump.c | 2 +- arch/powerpc/platforms/cell/spufs/file.c | 2 +- arch/powerpc/platforms/cell/spufs/inode.c | 2 +- arch/powerpc/platforms/cell/spufs/syscalls.c | 2 +- arch/powerpc/platforms/chrp/nvram.c | 2 +- arch/powerpc/platforms/powernv/opal-elog.c | 2 +- arch/powerpc/platforms/powernv/opal-lpc.c | 2 +- arch/powerpc/platforms/powernv/opal-prd.c | 2 +- arch/powerpc/platforms/pseries/cmm.c | 2 +- arch/powerpc/platforms/pseries/dlpar.c | 2 +- arch/powerpc/platforms/pseries/dtl.c | 2 +- arch/powerpc/platforms/pseries/lparcfg.c | 2 +- arch/powerpc/platforms/pseries/nvram.c | 2 +- arch/powerpc/platforms/pseries/reconfig.c | 2 +- arch/powerpc/platforms/pseries/scanlog.c | 2 +- arch/powerpc/sysdev/scom.c | 2 +- arch/powerpc/sysdev/tsi108_pci.c | 2 +- arch/s390/appldata/appldata_base.c | 2 +- arch/s390/boot/compressed/misc.c | 2 +- arch/s390/crypto/prng.c | 2 +- arch/s390/include/asm/checksum.h | 2 +- arch/s390/include/asm/idals.h | 2 +- arch/s390/include/asm/mmu_context.h | 2 +- arch/s390/kernel/compat_linux.c | 2 +- arch/s390/kernel/compat_signal.c | 2 +- arch/s390/kernel/debug.c | 2 +- arch/s390/kernel/dis.c | 2 +- arch/s390/kernel/kprobes.c | 2 +- arch/s390/kernel/ptrace.c | 2 +- arch/s390/kernel/signal.c | 2 +- arch/s390/kernel/sys_s390.c | 2 +- arch/s390/kernel/time.c | 2 +- arch/s390/kernel/traps.c | 2 +- arch/s390/kvm/interrupt.c | 2 +- arch/s390/mm/init.c | 2 +- arch/score/include/asm/checksum.h | 2 +- arch/score/kernel/ptrace.c | 2 +- arch/score/kernel/traps.c | 2 +- arch/score/lib/checksum_copy.c | 2 +- arch/sh/boards/mach-landisk/gio.c | 2 +- arch/sh/boot/compressed/misc.c | 2 +- arch/sh/include/asm/mmu_context.h | 2 +- arch/sh/kernel/cpu/init.c | 2 +- arch/sh/kernel/cpu/shmobile/cpuidle.c | 2 +- arch/sh/kernel/cpu/shmobile/pm.c | 2 +- arch/sh/kernel/crash_dump.c | 2 +- arch/sh/kernel/io_trapped.c | 2 +- arch/sh/kernel/irq.c | 2 +- arch/sh/kernel/kprobes.c | 2 +- arch/sh/kernel/process_32.c | 2 +- arch/sh/kernel/process_64.c | 2 +- arch/sh/kernel/ptrace_32.c | 2 +- arch/sh/kernel/ptrace_64.c | 2 +- arch/sh/kernel/setup.c | 2 +- arch/sh/kernel/sh_ksyms_64.c | 2 +- arch/sh/kernel/signal_32.c | 2 +- arch/sh/kernel/signal_64.c | 2 +- arch/sh/kernel/sys_sh.c | 2 +- arch/sh/kernel/sys_sh32.c | 2 +- arch/sh/kernel/traps_64.c | 2 +- arch/sh/math-emu/math.c | 2 +- arch/sh/mm/cache-debugfs.c | 2 +- arch/sh/mm/cache-sh3.c | 2 +- arch/sh/mm/cache-sh5.c | 2 +- arch/sh/mm/cache-sh7705.c | 2 +- arch/sh/mm/extable_32.c | 2 +- arch/sh/mm/extable_64.c | 2 +- arch/sh/mm/nommu.c | 2 +- arch/sh/mm/pmb.c | 2 +- arch/sh/mm/tlb-sh3.c | 2 +- arch/sh/mm/tlbex_64.c | 2 +- arch/sh/mm/tlbflush_64.c | 2 +- arch/sh/oprofile/backtrace.c | 2 +- arch/sparc/include/asm/checksum_32.h | 2 +- arch/sparc/include/asm/checksum_64.h | 2 +- arch/sparc/kernel/apc.c | 2 +- arch/sparc/kernel/irq_64.c | 2 +- arch/sparc/kernel/kprobes.c | 2 +- arch/sparc/kernel/mdesc.c | 2 +- arch/sparc/kernel/pci.c | 2 +- arch/sparc/kernel/pcic.c | 2 +- arch/sparc/kernel/pmc.c | 2 +- arch/sparc/kernel/process_32.c | 2 +- arch/sparc/kernel/process_64.c | 2 +- arch/sparc/kernel/ptrace_32.c | 2 +- arch/sparc/kernel/ptrace_64.c | 2 +- arch/sparc/kernel/signal32.c | 2 +- arch/sparc/kernel/signal_32.c | 2 +- arch/sparc/kernel/signal_64.c | 2 +- arch/sparc/kernel/smp_64.c | 2 +- arch/sparc/kernel/sys_sparc32.c | 2 +- arch/sparc/kernel/sys_sparc_32.c | 2 +- arch/sparc/kernel/sys_sparc_64.c | 2 +- arch/sparc/kernel/time_64.c | 2 +- arch/sparc/kernel/traps_64.c | 2 +- arch/sparc/kernel/unaligned_32.c | 2 +- arch/sparc/kernel/unaligned_64.c | 2 +- arch/sparc/kernel/uprobes.c | 2 +- arch/sparc/kernel/visemul.c | 2 +- arch/sparc/kernel/windows.c | 2 +- arch/sparc/math-emu/math_32.c | 2 +- arch/sparc/math-emu/math_64.c | 2 +- arch/sparc/mm/extable.c | 2 +- arch/sparc/mm/init_64.c | 2 +- arch/tile/kernel/process.c | 2 +- arch/tile/kernel/single_step.c | 2 +- arch/tile/kernel/unaligned.c | 2 +- arch/um/drivers/harddog_kern.c | 2 +- arch/um/drivers/hostaudio_kern.c | 2 +- arch/um/drivers/mconsole_kern.c | 2 +- arch/um/drivers/mmapper_kern.c | 2 +- arch/um/drivers/random.c | 2 +- arch/um/kernel/exec.c | 2 +- arch/um/kernel/exitcode.c | 2 +- arch/um/kernel/process.c | 2 +- arch/um/kernel/ptrace.c | 2 +- arch/um/kernel/syscall.c | 2 +- arch/x86/entry/common.c | 2 +- arch/x86/ia32/ia32_aout.c | 2 +- arch/x86/ia32/ia32_signal.c | 2 +- arch/x86/ia32/sys_ia32.c | 2 +- arch/x86/include/asm/asm-prototypes.h | 2 +- arch/x86/include/asm/checksum_64.h | 2 +- arch/x86/include/asm/xen/page.h | 2 +- arch/x86/kernel/apm_32.c | 2 +- arch/x86/kernel/cpu/mcheck/mce-severity.c | 2 +- arch/x86/kernel/crash_dump_32.c | 2 +- arch/x86/kernel/doublefault.c | 2 +- arch/x86/kernel/kprobes/core.c | 2 +- arch/x86/kernel/kprobes/opt.c | 2 +- arch/x86/kernel/process.c | 2 +- arch/x86/kernel/ptrace.c | 2 +- arch/x86/kernel/test_nx.c | 2 +- arch/x86/kernel/tls.c | 2 +- arch/x86/kernel/vm86_32.c | 2 +- arch/x86/lib/usercopy_32.c | 2 +- arch/x86/math-emu/errors.c | 2 +- arch/x86/math-emu/fpu_entry.c | 2 +- arch/x86/math-emu/get_address.c | 2 +- arch/x86/math-emu/load_store.c | 2 +- arch/x86/math-emu/reg_ld_str.c | 2 +- arch/x86/mm/extable.c | 2 +- arch/x86/mm/init_32.c | 2 +- arch/x86/mm/init_64.c | 2 +- arch/x86/mm/pageattr.c | 2 +- arch/x86/um/ptrace_32.c | 2 +- arch/x86/um/ptrace_64.c | 2 +- arch/x86/um/signal.c | 2 +- arch/x86/um/tls_32.c | 2 +- arch/x86/xen/p2m.c | 2 +- arch/xtensa/include/asm/checksum.h | 2 +- arch/xtensa/include/asm/segment.h | 2 +- arch/xtensa/kernel/asm-offsets.c | 2 +- arch/xtensa/kernel/irq.c | 2 +- arch/xtensa/kernel/process.c | 2 +- arch/xtensa/kernel/ptrace.c | 2 +- arch/xtensa/kernel/signal.c | 2 +- arch/xtensa/kernel/stacktrace.c | 2 +- arch/xtensa/kernel/syscall.c | 2 +- arch/xtensa/kernel/traps.c | 2 +- arch/xtensa/kernel/xtensa_ksyms.c | 2 +- arch/xtensa/platforms/iss/console.c | 2 +- arch/xtensa/platforms/iss/simdisk.c | 2 +- block/ioctl.c | 2 +- block/partitions/ibm.c | 2 +- block/scsi_ioctl.c | 2 +- drivers/acpi/acpi_video.c | 2 +- drivers/acpi/battery.c | 2 +- drivers/acpi/osl.c | 2 +- drivers/acpi/proc.c | 2 +- drivers/acpi/processor_thermal.c | 2 +- drivers/acpi/processor_throttling.c | 2 +- drivers/acpi/thermal.c | 2 +- drivers/atm/adummy.c | 2 +- drivers/atm/atmtcp.c | 2 +- drivers/atm/eni.c | 2 +- drivers/atm/firestream.c | 2 +- drivers/atm/fore200e.c | 2 +- drivers/atm/he.c | 2 +- drivers/atm/horizon.c | 2 +- drivers/atm/idt77105.c | 2 +- drivers/atm/idt77252.c | 2 +- drivers/atm/iphase.c | 2 +- drivers/atm/nicstar.c | 2 +- drivers/atm/suni.c | 2 +- drivers/atm/uPD98402.c | 2 +- drivers/atm/zatm.c | 2 +- drivers/base/memory.c | 2 +- drivers/block/DAC960.c | 2 +- drivers/block/amiflop.c | 2 +- drivers/block/brd.c | 2 +- drivers/block/cciss.c | 2 +- drivers/block/cryptoloop.c | 2 +- drivers/block/hd.c | 2 +- drivers/block/loop.c | 2 +- drivers/block/nbd.c | 2 +- drivers/block/paride/pcd.c | 2 +- drivers/block/paride/pd.c | 2 +- drivers/block/paride/pf.c | 2 +- drivers/block/paride/pg.c | 2 +- drivers/block/paride/pt.c | 2 +- drivers/block/pktcdvd.c | 2 +- drivers/block/swim3.c | 2 +- drivers/block/sx8.c | 2 +- drivers/block/umem.c | 2 +- drivers/cdrom/cdrom.c | 2 +- drivers/char/agp/compat_ioctl.c | 2 +- drivers/char/agp/frontend.c | 2 +- drivers/char/applicom.c | 2 +- drivers/char/bfin-otp.c | 2 +- drivers/char/ds1620.c | 2 +- drivers/char/dtlk.c | 2 +- drivers/char/generic_nvram.c | 2 +- drivers/char/hangcheck-timer.c | 2 +- drivers/char/hw_random/core.c | 2 +- drivers/char/ipmi/ipmi_watchdog.c | 2 +- drivers/char/lp.c | 2 +- drivers/char/mbcs.c | 2 +- drivers/char/mmtimer.c | 2 +- drivers/char/mwave/3780i.c | 2 +- drivers/char/mwave/mwavedd.h | 2 +- drivers/char/nsc_gpio.c | 2 +- drivers/char/nwbutton.c | 2 +- drivers/char/nwflash.c | 2 +- drivers/char/pc8736x_gpio.c | 2 +- drivers/char/pcmcia/cm4040_cs.c | 2 +- drivers/char/pcmcia/synclink_cs.c | 2 +- drivers/char/random.c | 2 +- drivers/char/raw.c | 2 +- drivers/char/scx200_gpio.c | 2 +- drivers/char/sonypi.c | 2 +- drivers/char/tlclk.c | 2 +- drivers/char/toshiba.c | 2 +- drivers/char/xilinx_hwicap/xilinx_hwicap.c | 2 +- drivers/cpufreq/ia64-acpi-cpufreq.c | 2 +- drivers/cpuidle/governors/ladder.c | 2 +- drivers/dio/dio.c | 2 +- drivers/edac/edac_device.c | 2 +- drivers/edac/edac_mc.c | 2 +- drivers/edac/edac_pci.c | 2 +- drivers/i2c/i2c-core.c | 2 +- drivers/ide/hpt366.c | 2 +- drivers/ide/ide-disk.c | 2 +- drivers/ide/ide-io.c | 2 +- drivers/ide/ide-iops.c | 2 +- drivers/ide/ide-probe.c | 2 +- drivers/ide/ide-proc.c | 2 +- drivers/infiniband/core/ucm.c | 2 +- drivers/infiniband/core/user_mad.c | 2 +- drivers/infiniband/core/uverbs_cmd.c | 2 +- drivers/infiniband/core/uverbs_main.c | 2 +- drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 2 +- drivers/infiniband/ulp/iser/iscsi_iser.c | 2 +- drivers/input/input-compat.c | 2 +- drivers/input/misc/atlas_btns.c | 2 +- drivers/input/mouse/amimouse.c | 2 +- drivers/input/mouse/atarimouse.c | 2 +- drivers/input/mouse/trackpoint.c | 2 +- drivers/input/serio/hp_sdc.c | 2 +- drivers/input/serio/q40kbd.c | 2 +- drivers/input/serio/serport.c | 2 +- drivers/input/tablet/aiptek.c | 2 +- drivers/input/tablet/gtco.c | 2 +- drivers/isdn/capi/kcapi.c | 2 +- drivers/isdn/hardware/avm/b1.c | 2 +- drivers/isdn/hardware/avm/b1dma.c | 2 +- drivers/isdn/hardware/avm/c4.c | 2 +- drivers/isdn/hardware/eicon/capimain.c | 2 +- drivers/isdn/hardware/eicon/divamnt.c | 2 +- drivers/isdn/hardware/eicon/divasi.c | 2 +- drivers/isdn/hardware/eicon/divasmain.c | 2 +- drivers/isdn/hardware/eicon/divasproc.c | 2 +- drivers/isdn/hysdn/hysdn_boot.c | 2 +- drivers/lguest/core.c | 2 +- drivers/lguest/page_tables.c | 2 +- drivers/lguest/x86/core.c | 2 +- drivers/macintosh/ans-lcd.c | 2 +- drivers/macintosh/smu.c | 2 +- drivers/macintosh/via-pmu.c | 2 +- drivers/macintosh/via-pmu68k.c | 2 +- drivers/md/dm-ioctl.c | 2 +- drivers/media/dvb-core/dmxdev.c | 2 +- drivers/media/dvb-core/dvb_demux.c | 2 +- drivers/media/dvb-core/dvb_net.c | 2 +- drivers/media/dvb-core/dvb_ringbuffer.c | 2 +- drivers/media/i2c/adv7170.c | 2 +- drivers/media/i2c/adv7175.c | 2 +- drivers/media/i2c/bt856.c | 2 +- drivers/media/i2c/bt866.c | 2 +- drivers/media/i2c/cs53l32a.c | 2 +- drivers/media/i2c/m52790.c | 2 +- drivers/media/i2c/saa6588.c | 2 +- drivers/media/i2c/saa7110.c | 2 +- drivers/media/i2c/saa7185.c | 2 +- drivers/media/i2c/tlv320aic23b.c | 2 +- drivers/media/i2c/vp27smpx.c | 2 +- drivers/media/i2c/vpx3220.c | 2 +- drivers/media/i2c/wm8739.c | 2 +- drivers/media/i2c/wm8775.c | 2 +- drivers/media/pci/ivtv/ivtv-driver.h | 2 +- drivers/media/pci/meye/meye.c | 2 +- drivers/media/pci/zoran/videocodec.c | 2 +- drivers/media/pci/zoran/zoran_driver.c | 2 +- drivers/media/platform/arv.c | 2 +- drivers/media/usb/pvrusb2/pvrusb2-ioread.c | 2 +- drivers/media/usb/pwc/pwc-ctrl.c | 2 +- drivers/media/v4l2-core/v4l2-common.c | 2 +- drivers/media/v4l2-core/v4l2-dev.c | 2 +- drivers/message/fusion/mptctl.c | 2 +- drivers/message/fusion/mptlan.h | 2 +- drivers/misc/ibmasm/ibmasmfs.c | 2 +- drivers/mmc/core/block.c | 2 +- drivers/mmc/host/android-goldfish.c | 2 +- drivers/mtd/devices/pmc551.c | 2 +- drivers/mtd/devices/slram.c | 2 +- drivers/mtd/ftl.c | 2 +- drivers/mtd/inftlcore.c | 2 +- drivers/mtd/inftlmount.c | 2 +- drivers/mtd/maps/sun_uflash.c | 2 +- drivers/mtd/mtd_blkdevs.c | 2 +- drivers/mtd/mtdchar.c | 2 +- drivers/mtd/nftlcore.c | 2 +- drivers/net/appletalk/ipddp.c | 2 +- drivers/net/eql.c | 2 +- drivers/net/ethernet/3com/3c509.c | 2 +- drivers/net/ethernet/3com/3c515.c | 2 +- drivers/net/ethernet/3com/3c574_cs.c | 2 +- drivers/net/ethernet/3com/3c59x.c | 2 +- drivers/net/ethernet/3com/typhoon.c | 2 +- drivers/net/ethernet/8390/axnet_cs.c | 2 +- drivers/net/ethernet/8390/ne2k-pci.c | 2 +- drivers/net/ethernet/8390/pcnet_cs.c | 2 +- drivers/net/ethernet/adaptec/starfire.c | 2 +- drivers/net/ethernet/alteon/acenic.c | 2 +- drivers/net/ethernet/amd/amd8111e.c | 2 +- drivers/net/ethernet/amd/nmclan_cs.c | 2 +- drivers/net/ethernet/broadcom/b44.c | 2 +- drivers/net/ethernet/chelsio/cxgb/cxgb2.c | 2 +- drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c | 2 +- drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c | 2 +- drivers/net/ethernet/dec/tulip/de2104x.c | 2 +- drivers/net/ethernet/dec/tulip/de4x5.c | 2 +- drivers/net/ethernet/dec/tulip/dmfe.c | 2 +- drivers/net/ethernet/dec/tulip/tulip_core.c | 2 +- drivers/net/ethernet/dec/tulip/uli526x.c | 2 +- drivers/net/ethernet/dec/tulip/winbond-840.c | 2 +- drivers/net/ethernet/dec/tulip/xircom_cb.c | 2 +- drivers/net/ethernet/dlink/dl2k.h | 2 +- drivers/net/ethernet/dlink/sundance.c | 2 +- drivers/net/ethernet/fealnx.c | 2 +- drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c | 2 +- drivers/net/ethernet/freescale/fs_enet/mac-fcc.c | 2 +- drivers/net/ethernet/freescale/fs_enet/mac-fec.c | 2 +- drivers/net/ethernet/freescale/fs_enet/mac-scc.c | 2 +- drivers/net/ethernet/freescale/fs_enet/mii-fec.c | 2 +- drivers/net/ethernet/freescale/gianfar.c | 2 +- drivers/net/ethernet/freescale/gianfar.h | 2 +- drivers/net/ethernet/freescale/gianfar_ethtool.c | 2 +- drivers/net/ethernet/freescale/ucc_geth.c | 2 +- drivers/net/ethernet/freescale/ucc_geth_ethtool.c | 2 +- drivers/net/ethernet/fujitsu/fmvj18x_cs.c | 2 +- drivers/net/ethernet/ibm/emac/core.c | 2 +- drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c | 2 +- drivers/net/ethernet/natsemi/natsemi.c | 2 +- drivers/net/ethernet/natsemi/ns83820.c | 2 +- drivers/net/ethernet/packetengines/hamachi.c | 2 +- drivers/net/ethernet/packetengines/yellowfin.c | 2 +- drivers/net/ethernet/realtek/8139cp.c | 2 +- drivers/net/ethernet/sgi/ioc3-eth.c | 2 +- drivers/net/ethernet/sis/sis900.c | 2 +- drivers/net/ethernet/smsc/epic100.c | 2 +- drivers/net/ethernet/smsc/smc91c92_cs.c | 2 +- drivers/net/ethernet/sun/cassini.c | 2 +- drivers/net/ethernet/sun/sungem.c | 2 +- drivers/net/ethernet/sun/sunhme.c | 2 +- drivers/net/ethernet/via/via-rhine.c | 2 +- drivers/net/ethernet/xircom/xirc2ps_cs.c | 2 +- drivers/net/fddi/skfp/skfddi.c | 2 +- drivers/net/hamradio/6pack.c | 2 +- drivers/net/hamradio/baycom_epp.c | 2 +- drivers/net/hamradio/baycom_par.c | 2 +- drivers/net/hamradio/baycom_ser_fdx.c | 2 +- drivers/net/hamradio/baycom_ser_hdx.c | 2 +- drivers/net/hamradio/bpqether.c | 2 +- drivers/net/hamradio/dmascc.c | 2 +- drivers/net/hamradio/hdlcdrv.c | 2 +- drivers/net/hamradio/mkiss.c | 2 +- drivers/net/hamradio/scc.c | 2 +- drivers/net/hamradio/yam.c | 2 +- drivers/net/hippi/rrunner.c | 2 +- drivers/net/irda/irtty-sir.c | 2 +- drivers/net/irda/kingsun-sir.c | 2 +- drivers/net/irda/ks959-sir.c | 2 +- drivers/net/irda/ksdazzle-sir.c | 2 +- drivers/net/irda/mcs7780.c | 2 +- drivers/net/irda/vlsi_ir.c | 2 +- drivers/net/loopback.c | 2 +- drivers/net/phy/davicom.c | 2 +- drivers/net/phy/icplus.c | 2 +- drivers/net/phy/lxt.c | 2 +- drivers/net/phy/qsemi.c | 2 +- drivers/net/ppp/ppp_async.c | 2 +- drivers/net/ppp/ppp_synctty.c | 2 +- drivers/net/ppp/pppoe.c | 2 +- drivers/net/ppp/pppox.c | 2 +- drivers/net/sb1000.c | 2 +- drivers/net/slip/slhc.c | 2 +- drivers/net/slip/slip.c | 2 +- drivers/net/tun.c | 2 +- drivers/net/usb/catc.c | 2 +- drivers/net/usb/kaweth.c | 2 +- drivers/net/usb/pegasus.c | 2 +- drivers/net/usb/rtl8150.c | 2 +- drivers/net/wan/dlci.c | 2 +- drivers/net/wan/dscc4.c | 2 +- drivers/net/wan/farsync.c | 2 +- drivers/net/wan/hd64570.c | 2 +- drivers/net/wan/hd64572.c | 2 +- drivers/net/wan/lapbether.c | 2 +- drivers/net/wan/lmc/lmc_main.c | 2 +- drivers/net/wan/lmc/lmc_media.c | 2 +- drivers/net/wan/sbni.c | 2 +- drivers/net/wan/sdla.c | 2 +- drivers/net/wireless/atmel/atmel.c | 2 +- drivers/net/wireless/intel/ipw2x00/ipw2100.c | 2 +- drivers/net/wireless/intel/ipw2x00/libipw_geo.c | 2 +- drivers/net/wireless/intel/ipw2x00/libipw_module.c | 2 +- drivers/net/wireless/intel/ipw2x00/libipw_rx.c | 2 +- drivers/net/wireless/intel/ipw2x00/libipw_tx.c | 2 +- drivers/net/wireless/intersil/hostap/hostap_hw.c | 2 +- drivers/net/wireless/intersil/hostap/hostap_main.c | 2 +- drivers/net/wireless/intersil/prism54/isl_38xx.c | 2 +- drivers/net/wireless/intersil/prism54/isl_ioctl.c | 2 +- drivers/net/wireless/ray_cs.c | 2 +- drivers/net/wireless/wl3501_cs.c | 2 +- drivers/nubus/proc.c | 2 +- drivers/oprofile/event_buffer.c | 2 +- drivers/oprofile/oprofilefs.c | 2 +- drivers/parisc/ccio-dma.c | 2 +- drivers/parisc/ccio-rm-dma.c | 2 +- drivers/parisc/eisa_eeprom.c | 2 +- drivers/parisc/eisa_enumerator.c | 2 +- drivers/parisc/led.c | 2 +- drivers/parisc/pdc_stable.c | 2 +- drivers/parport/daisy.c | 2 +- drivers/parport/ieee1284_ops.c | 2 +- drivers/parport/parport_gsc.c | 2 +- drivers/parport/probe.c | 2 +- drivers/parport/procfs.c | 2 +- drivers/pci/hotplug/acpiphp_ibm.c | 2 +- drivers/pci/hotplug/cpqphp_core.c | 2 +- drivers/pci/hotplug/cpqphp_nvram.c | 2 +- drivers/pci/hotplug/pci_hotplug_core.c | 2 +- drivers/pci/proc.c | 2 +- drivers/pci/syscall.c | 2 +- drivers/platform/x86/sony-laptop.c | 2 +- drivers/platform/x86/thinkpad_acpi.c | 2 +- drivers/pnp/interface.c | 2 +- drivers/pnp/pnpbios/proc.c | 2 +- drivers/s390/block/dasd_devmap.c | 2 +- drivers/s390/block/dasd_eckd.c | 2 +- drivers/s390/block/dasd_eer.c | 2 +- drivers/s390/block/dasd_erp.c | 2 +- drivers/s390/block/dasd_genhd.c | 2 +- drivers/s390/block/dasd_ioctl.c | 2 +- drivers/s390/block/dasd_proc.c | 2 +- drivers/s390/block/xpram.c | 2 +- drivers/s390/char/con3215.c | 2 +- drivers/s390/char/keyboard.c | 2 +- drivers/s390/char/monreader.c | 2 +- drivers/s390/char/monwriter.c | 2 +- drivers/s390/char/sclp_rw.c | 2 +- drivers/s390/char/sclp_tty.c | 2 +- drivers/s390/char/sclp_vt220.c | 2 +- drivers/s390/char/tape_char.c | 2 +- drivers/s390/char/tty3270.c | 2 +- drivers/s390/char/vmcp.c | 2 +- drivers/s390/char/vmlogrdr.c | 2 +- drivers/s390/char/vmur.c | 2 +- drivers/s390/char/zcore.c | 2 +- drivers/s390/cio/blacklist.c | 2 +- drivers/s390/crypto/zcrypt_api.c | 2 +- drivers/s390/crypto/zcrypt_cex2a.c | 2 +- drivers/s390/crypto/zcrypt_pcixcc.c | 2 +- drivers/s390/net/netiucv.c | 2 +- drivers/sbus/char/display7seg.c | 2 +- drivers/sbus/char/envctrl.c | 2 +- drivers/sbus/char/flash.c | 2 +- drivers/sbus/char/jsflash.c | 2 +- drivers/sbus/char/openprom.c | 2 +- drivers/scsi/3w-9xxx.c | 2 +- drivers/scsi/3w-sas.c | 2 +- drivers/scsi/3w-xxxx.c | 2 +- drivers/scsi/aacraid/aachba.c | 2 +- drivers/scsi/aacraid/commctrl.c | 2 +- drivers/scsi/arcmsr/arcmsr_hba.c | 2 +- drivers/scsi/bfa/bfad.c | 2 +- drivers/scsi/dpt_i2o.c | 2 +- drivers/scsi/gdth.c | 2 +- drivers/scsi/hptiop.c | 2 +- drivers/scsi/ips.h | 2 +- drivers/scsi/megaraid.c | 2 +- drivers/scsi/megaraid/megaraid_mm.h | 2 +- drivers/scsi/megaraid/megaraid_sas_base.c | 2 +- drivers/scsi/osst.c | 2 +- drivers/scsi/qla2xxx/qla_sup.c | 2 +- drivers/scsi/scsi_ioctl.c | 2 +- drivers/scsi/scsi_proc.c | 2 +- drivers/scsi/sd.c | 2 +- drivers/scsi/sr.c | 2 +- drivers/scsi/sr_ioctl.c | 2 +- drivers/scsi/st.c | 2 +- drivers/tty/amiserial.c | 2 +- drivers/tty/hvc/hvc_console.c | 2 +- drivers/tty/hvc/hvcs.c | 2 +- drivers/tty/hvc/hvsi.c | 2 +- drivers/tty/moxa.c | 2 +- drivers/tty/mxser.c | 2 +- drivers/tty/n_hdlc.c | 2 +- drivers/tty/n_r3964.c | 2 +- drivers/tty/serial/icom.c | 2 +- drivers/tty/serial/serial_core.c | 2 +- drivers/tty/synclink.c | 2 +- drivers/tty/synclink_gt.c | 2 +- drivers/tty/synclinkmp.c | 2 +- drivers/tty/tty_ioctl.c | 2 +- drivers/tty/vt/consolemap.c | 2 +- drivers/tty/vt/selection.c | 2 +- drivers/tty/vt/vc_screen.c | 2 +- drivers/tty/vt/vt_ioctl.c | 2 +- drivers/usb/atm/usbatm.c | 2 +- drivers/usb/core/hub.c | 2 +- drivers/usb/gadget/legacy/inode.c | 2 +- drivers/usb/host/uhci-hcd.c | 2 +- drivers/usb/misc/ftdi-elan.c | 2 +- drivers/usb/misc/idmouse.c | 2 +- drivers/usb/misc/ldusb.c | 2 +- drivers/usb/misc/legousbtower.c | 2 +- drivers/usb/mon/mon_bin.c | 2 +- drivers/usb/mon/mon_stat.c | 2 +- drivers/usb/mon/mon_text.c | 2 +- drivers/usb/musb/musb_debugfs.c | 2 +- drivers/video/console/newport_con.c | 2 +- drivers/video/fbdev/68328fb.c | 2 +- drivers/video/fbdev/hitfb.c | 2 +- drivers/video/fbdev/hpfb.c | 2 +- drivers/video/fbdev/mx3fb.c | 2 +- drivers/video/fbdev/q40fb.c | 2 +- drivers/video/fbdev/sm501fb.c | 2 +- drivers/video/fbdev/stifb.c | 2 +- drivers/video/fbdev/w100fb.c | 2 +- drivers/zorro/proc.c | 2 +- fs/9p/vfs_file.c | 2 +- fs/afs/proc.c | 2 +- fs/aio.c | 2 +- fs/anon_inodes.c | 2 +- fs/bfs/inode.c | 2 +- fs/binfmt_aout.c | 2 +- fs/binfmt_elf.c | 2 +- fs/binfmt_elf_fdpic.c | 2 +- fs/block_dev.c | 2 +- fs/cifs/cifs_debug.c | 2 +- fs/cifs/cifssmb.c | 2 +- fs/cifs/connect.c | 2 +- fs/cifs/transport.c | 2 +- fs/compat.c | 2 +- fs/compat_ioctl.c | 2 +- fs/configfs/file.c | 2 +- fs/coredump.c | 2 +- fs/dcache.c | 2 +- fs/dcookies.c | 2 +- fs/dlm/dlm_internal.h | 2 +- fs/efs/efs.h | 2 +- fs/eventpoll.c | 2 +- fs/exec.c | 2 +- fs/ext2/ioctl.c | 2 +- fs/ext2/super.c | 2 +- fs/ext4/extents.c | 2 +- fs/ext4/ioctl.c | 2 +- fs/ext4/super.c | 2 +- fs/fcntl.c | 2 +- fs/fhandle.c | 2 +- fs/filesystems.c | 2 +- fs/gfs2/file.c | 2 +- fs/gfs2/glock.c | 2 +- fs/gfs2/inode.c | 2 +- fs/gfs2/sys.c | 2 +- fs/gfs2/util.c | 2 +- fs/gfs2/xattr.c | 2 +- fs/hfs/hfs_fs.h | 2 +- fs/hfsplus/ioctl.c | 2 +- fs/hugetlbfs/inode.c | 2 +- fs/jbd2/journal.c | 2 +- fs/jfs/ioctl.c | 2 +- fs/jfs/jfs_debug.c | 2 +- fs/jfs/super.c | 2 +- fs/libfs.c | 2 +- fs/locks.c | 2 +- fs/namei.c | 2 +- fs/ncpfs/dir.c | 2 +- fs/ncpfs/file.c | 2 +- fs/ncpfs/inode.c | 2 +- fs/ncpfs/ioctl.c | 2 +- fs/ncpfs/mmap.c | 2 +- fs/ncpfs/ncplib_kernel.h | 2 +- fs/ncpfs/sock.c | 2 +- fs/ncpfs/symlink.c | 2 +- fs/nfs/direct.c | 2 +- fs/nfs/file.c | 2 +- fs/nfs/getroot.c | 2 +- fs/nfs/inode.c | 2 +- fs/nfs/super.c | 2 +- fs/nfs/write.c | 2 +- fs/nfsd/fault_inject.c | 2 +- fs/nfsd/vfs.c | 2 +- fs/ntfs/file.c | 2 +- fs/ocfs2/cluster/masklog.c | 2 +- fs/ocfs2/cluster/tcp.c | 2 +- fs/ocfs2/dlmfs/dlmfs.c | 2 +- fs/ocfs2/stack_user.c | 2 +- fs/open.c | 2 +- fs/openpromfs/inode.c | 2 +- fs/pipe.c | 2 +- fs/proc/base.c | 2 +- fs/proc/generic.c | 2 +- fs/proc/inode.c | 2 +- fs/proc/kcore.c | 2 +- fs/proc/kmsg.c | 2 +- fs/proc/nommu.c | 2 +- fs/proc/page.c | 2 +- fs/proc/proc_net.c | 2 +- fs/proc/proc_tty.c | 2 +- fs/proc/root.c | 2 +- fs/proc/task_mmu.c | 2 +- fs/proc/vmcore.c | 2 +- fs/ramfs/file-nommu.c | 2 +- fs/ramfs/inode.c | 2 +- fs/read_write.c | 2 +- fs/readdir.c | 2 +- fs/select.c | 2 +- fs/seq_file.c | 2 +- fs/stat.c | 2 +- fs/ufs/inode.c | 2 +- fs/ufs/super.c | 2 +- fs/utimes.c | 2 +- fs/xattr.c | 2 +- fs/xfs/xfs_ioctl32.c | 2 +- fs/xfs/xfs_linux.h | 2 +- include/asm-generic/termios-base.h | 2 +- include/asm-generic/termios.h | 2 +- include/drm/drmP.h | 2 +- include/linux/isdnif.h | 2 +- include/linux/pagemap.h | 2 +- include/linux/poll.h | 2 +- include/net/checksum.h | 2 +- include/net/sctp/sctp.h | 2 +- include/rdma/ib_verbs.h | 2 +- init/init_task.c | 2 +- kernel/capability.c | 2 +- kernel/compat.c | 2 +- kernel/configs.c | 2 +- kernel/cpuset.c | 2 +- kernel/exit.c | 2 +- kernel/extable.c | 2 +- kernel/fork.c | 2 +- kernel/futex_compat.c | 2 +- kernel/groups.c | 2 +- kernel/kmod.c | 2 +- kernel/kprobes.c | 2 +- kernel/locking/lockdep_proc.c | 2 +- kernel/module.c | 2 +- kernel/power/snapshot.c | 2 +- kernel/power/user.c | 2 +- kernel/printk/printk.c | 2 +- kernel/profile.c | 2 +- kernel/signal.c | 2 +- kernel/sys.c | 2 +- kernel/sysctl.c | 2 +- kernel/time/hrtimer.c | 2 +- kernel/time/itimer.c | 2 +- kernel/time/posix-cpu-timers.c | 2 +- kernel/time/posix-timers.c | 2 +- kernel/time/time.c | 2 +- kernel/time/timer.c | 2 +- kernel/time/timer_list.c | 2 +- kernel/time/timer_stats.c | 2 +- kernel/uid16.c | 2 +- lib/extable.c | 2 +- lib/kstrtox.c | 2 +- mm/memcontrol.c | 2 +- mm/memory.c | 2 +- mm/mempolicy.c | 2 +- mm/mincore.c | 2 +- mm/mmap.c | 2 +- mm/mprotect.c | 2 +- mm/nommu.c | 2 +- mm/shmem.c | 2 +- mm/util.c | 2 +- mm/vmalloc.c | 2 +- net/802/fc.c | 2 +- net/802/hippi.c | 2 +- net/8021q/vlan.c | 2 +- net/ax25/af_ax25.c | 2 +- net/ax25/ax25_addr.c | 2 +- net/ax25/ax25_dev.c | 2 +- net/ax25/ax25_ds_in.c | 2 +- net/ax25/ax25_ds_subr.c | 2 +- net/ax25/ax25_ds_timer.c | 2 +- net/ax25/ax25_iface.c | 2 +- net/ax25/ax25_in.c | 2 +- net/ax25/ax25_ip.c | 2 +- net/ax25/ax25_out.c | 2 +- net/ax25/ax25_route.c | 2 +- net/ax25/ax25_std_in.c | 2 +- net/ax25/ax25_std_subr.c | 2 +- net/ax25/ax25_std_timer.c | 2 +- net/ax25/ax25_subr.c | 2 +- net/ax25/ax25_timer.c | 2 +- net/ax25/ax25_uid.c | 2 +- net/bridge/br_device.c | 2 +- net/bridge/br_ioctl.c | 2 +- net/bridge/br_netfilter_hooks.c | 2 +- net/bridge/br_netfilter_ipv6.c | 2 +- net/bridge/netfilter/ebtables.c | 2 +- net/compat.c | 2 +- net/core/datagram.c | 2 +- net/core/dev.c | 2 +- net/core/filter.c | 2 +- net/core/gen_estimator.c | 2 +- net/core/rtnetlink.c | 2 +- net/core/scm.c | 2 +- net/core/skbuff.c | 2 +- net/core/sock.c | 2 +- net/core/utils.c | 2 +- net/decnet/dn_dev.c | 2 +- net/decnet/dn_fib.c | 2 +- net/decnet/dn_table.c | 2 +- net/decnet/sysctl_net_decnet.c | 2 +- net/ipv4/af_inet.c | 2 +- net/ipv4/devinet.c | 2 +- net/ipv4/fib_frontend.c | 2 +- net/ipv4/fib_semantics.c | 2 +- net/ipv4/fib_trie.c | 2 +- net/ipv4/icmp.c | 2 +- net/ipv4/igmp.c | 2 +- net/ipv4/ip_gre.c | 2 +- net/ipv4/ip_options.c | 2 +- net/ipv4/ip_output.c | 2 +- net/ipv4/ip_sockglue.c | 2 +- net/ipv4/ipconfig.c | 2 +- net/ipv4/ipip.c | 2 +- net/ipv4/ipmr.c | 2 +- net/ipv4/netfilter/arp_tables.c | 2 +- net/ipv4/netfilter/ip_tables.c | 2 +- net/ipv4/raw.c | 2 +- net/ipv4/route.c | 2 +- net/ipv4/tcp.c | 2 +- net/ipv4/udp.c | 2 +- net/ipv6/af_inet6.c | 2 +- net/ipv6/datagram.c | 2 +- net/ipv6/icmp.c | 2 +- net/ipv6/ip6_flowlabel.c | 2 +- net/ipv6/ip6_tunnel.c | 2 +- net/ipv6/ip6mr.c | 2 +- net/ipv6/ipv6_sockglue.c | 2 +- net/ipv6/netfilter/ip6_tables.c | 2 +- net/ipv6/route.c | 2 +- net/ipv6/sit.c | 2 +- net/ipv6/udp.c | 2 +- net/ipx/af_ipx.c | 2 +- net/irda/af_irda.c | 2 +- net/irda/ircomm/ircomm_tty.c | 2 +- net/irda/ircomm/ircomm_tty_ioctl.c | 2 +- net/irda/irda_device.c | 2 +- net/irda/irnet/irnet.h | 2 +- net/lapb/lapb_iface.c | 2 +- net/lapb/lapb_in.c | 2 +- net/lapb/lapb_out.c | 2 +- net/lapb/lapb_subr.c | 2 +- net/lapb/lapb_timer.c | 2 +- net/netfilter/ipvs/ip_vs_ctl.c | 2 +- net/netfilter/nfnetlink.c | 2 +- net/netlink/af_netlink.c | 2 +- net/packet/af_packet.c | 2 +- net/rose/af_rose.c | 2 +- net/rose/rose_route.c | 2 +- net/sctp/ipv6.c | 2 +- net/socket.c | 2 +- net/sunrpc/auth_gss/auth_gss.c | 2 +- net/sunrpc/cache.c | 2 +- net/sunrpc/svcsock.c | 2 +- net/sunrpc/sysctl.c | 2 +- net/unix/af_unix.c | 2 +- net/x25/af_x25.c | 2 +- net/x25/x25_link.c | 2 +- net/xfrm/xfrm_state.c | 2 +- net/xfrm/xfrm_user.c | 2 +- security/keys/keyctl.c | 2 +- security/keys/process_keys.c | 2 +- security/keys/request_key_auth.c | 2 +- security/keys/user_defined.c | 2 +- sound/oss/dmasound/dmasound_atari.c | 2 +- sound/oss/dmasound/dmasound_core.c | 2 +- sound/oss/dmasound/dmasound_paula.c | 2 +- sound/oss/dmasound/dmasound_q40.c | 2 +- sound/oss/msnd.c | 2 +- sound/oss/os.h | 2 +- sound/oss/swarm_cs4297a.c | 2 +- virt/kvm/kvm_main.c | 2 +- 1088 files changed, 1088 insertions(+), 1088 deletions(-) (limited to 'drivers') diff --git a/arch/alpha/boot/misc.c b/arch/alpha/boot/misc.c index 3ff9a957a25c..1b568ed74f95 100644 --- a/arch/alpha/boot/misc.c +++ b/arch/alpha/boot/misc.c @@ -21,7 +21,7 @@ #include #include -#include +#include #define memzero(s,n) memset ((s),0,(n)) #define puts srm_printk diff --git a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c index 2d6efcff3bf3..2f26ae74b61a 100644 --- a/arch/alpha/kernel/irq.c +++ b/arch/alpha/kernel/irq.c @@ -26,7 +26,7 @@ #include #include -#include +#include volatile unsigned long irq_err_count; DEFINE_PER_CPU(unsigned long, irq_pmi_count); diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 56e427c7aa3c..54d8616644e2 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index b483156698d5..bca963a4aa48 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c index 04abdec7f496..bc4d2cdcf21d 100644 --- a/arch/alpha/kernel/ptrace.c +++ b/arch/alpha/kernel/ptrace.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 4811e54069fc..491e6a604e82 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -53,7 +53,7 @@ static struct notifier_block alpha_panic_block = { INT_MAX /* try to do it first */ }; -#include +#include #include #include #include diff --git a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c index 8dbfb15f1745..17308f925306 100644 --- a/arch/alpha/kernel/signal.c +++ b/arch/alpha/kernel/signal.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/arch/alpha/kernel/srm_env.c b/arch/alpha/kernel/srm_env.c index ffe996a54fad..705ae12acd15 100644 --- a/arch/alpha/kernel/srm_env.c +++ b/arch/alpha/kernel/srm_env.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #define BASE_DIR "srm_environment" /* Subdir in /proc/ */ diff --git a/arch/alpha/kernel/srmcons.c b/arch/alpha/kernel/srmcons.c index 72b59511e59a..e9c45b65a905 100644 --- a/arch/alpha/kernel/srmcons.c +++ b/arch/alpha/kernel/srmcons.c @@ -18,7 +18,7 @@ #include #include -#include +#include static DEFINE_SPINLOCK(srmcons_callback_lock); diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 5b6202a825ff..992000e3d9e4 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 74aceead06e9..3328af7c2776 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index b4ff3b683bcd..5dfb7975895f 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -11,7 +11,7 @@ #include #include -#include +#include #define ldq_u(x,y) \ diff --git a/arch/alpha/math-emu/math.c b/arch/alpha/math-emu/math.c index 58c2669a1dd4..fa5ae0ad8983 100644 --- a/arch/alpha/math-emu/math.c +++ b/arch/alpha/math-emu/math.c @@ -3,7 +3,7 @@ #include #include -#include +#include #include "sfp-util.h" #include diff --git a/arch/alpha/mm/init.c b/arch/alpha/mm/init.c index a1bea91df56a..0542e973c73d 100644 --- a/arch/alpha/mm/init.c +++ b/arch/alpha/mm/init.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/arm/common/bL_switcher_dummy_if.c b/arch/arm/common/bL_switcher_dummy_if.c index 6053f64c3752..4c10c6452678 100644 --- a/arch/arm/common/bL_switcher_dummy_if.c +++ b/arch/arm/common/bL_switcher_dummy_if.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include static ssize_t bL_switcher_write(struct file *file, const char __user *buf, diff --git a/arch/arm/kernel/swp_emulate.c b/arch/arm/kernel/swp_emulate.c index c3fe769d7558..853221f81104 100644 --- a/arch/arm/kernel/swp_emulate.c +++ b/arch/arm/kernel/swp_emulate.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include /* * Error-checking SWP macros implemented using ldrex{b}/strex{b} diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 8f92efa8460e..11676787ad49 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -33,7 +33,7 @@ #define CREATE_TRACE_POINTS #include "trace.h" -#include +#include #include #include #include diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c index 9aca92074f85..fa6182a40941 100644 --- a/arch/arm/kvm/guest.c +++ b/arch/arm/kvm/guest.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-iop13xx/irq.c b/arch/arm/mach-iop13xx/irq.c index c702cc4092de..bd9b43c8004e 100644 --- a/arch/arm/mach-iop13xx/irq.c +++ b/arch/arm/mach-iop13xx/irq.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c index 26874f608ca9..0f08f611c1a6 100644 --- a/arch/arm/mach-ixp4xx/common.c +++ b/arch/arm/mach-ixp4xx/common.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c index 6d3517dc4772..fb48f3141fb4 100644 --- a/arch/arm/mach-rpc/dma.c +++ b/arch/arm/mach-rpc/dma.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm/plat-iop/time.c b/arch/arm/plat-iop/time.c index 101e8f2c7abe..ed8d129d4bea 100644 --- a/arch/arm/plat-iop/time.c +++ b/arch/arm/plat-iop/time.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm64/include/asm/word-at-a-time.h b/arch/arm64/include/asm/word-at-a-time.h index 2b79b8a89457..b0d708ff7f4e 100644 --- a/arch/arm64/include/asm/word-at-a-time.h +++ b/arch/arm64/include/asm/word-at-a-time.h @@ -16,7 +16,7 @@ #ifndef __ASM_WORD_AT_A_TIME_H #define __ASM_WORD_AT_A_TIME_H -#include +#include #ifndef __AARCH64EB__ diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c index 04de188a36c9..fde04f029ec3 100644 --- a/arch/arm64/kernel/armv8_deprecated.c +++ b/arch/arm64/kernel/armv8_deprecated.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #define CREATE_TRACE_POINTS diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 4f0d76339414..a7504f40d7ee 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include /* diff --git a/arch/arm64/kernel/probes/kprobes.c b/arch/arm64/kernel/probes/kprobes.c index 1decd2b2c730..f0593c92279b 100644 --- a/arch/arm64/kernel/probes/kprobes.c +++ b/arch/arm64/kernel/probes/kprobes.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c index b7063de792f7..c747a0fc5d7d 100644 --- a/arch/arm64/kernel/signal32.c +++ b/arch/arm64/kernel/signal32.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include struct compat_sigcontext { diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c index 3f9e15722473..b37446a8ffdb 100644 --- a/arch/arm64/kvm/guest.c +++ b/arch/arm64/kvm/guest.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/arm64/lib/clear_user.S b/arch/arm64/lib/clear_user.S index d7150e30438a..add4a1334085 100644 --- a/arch/arm64/lib/clear_user.S +++ b/arch/arm64/lib/clear_user.S @@ -17,7 +17,7 @@ */ #include -#include +#include .text diff --git a/arch/arm64/lib/copy_from_user.S b/arch/arm64/lib/copy_from_user.S index cfe13396085b..fd6cd05593f9 100644 --- a/arch/arm64/lib/copy_from_user.S +++ b/arch/arm64/lib/copy_from_user.S @@ -17,7 +17,7 @@ #include #include -#include +#include /* * Copy from user space to a kernel buffer (alignment handled by the hardware) diff --git a/arch/arm64/lib/copy_in_user.S b/arch/arm64/lib/copy_in_user.S index 718b1c4e2f85..d828540ded6f 100644 --- a/arch/arm64/lib/copy_in_user.S +++ b/arch/arm64/lib/copy_in_user.S @@ -19,7 +19,7 @@ #include #include -#include +#include /* * Copy from user space to user space (alignment handled by the hardware) diff --git a/arch/arm64/lib/copy_to_user.S b/arch/arm64/lib/copy_to_user.S index e99e31c9acac..3e6ae2663b82 100644 --- a/arch/arm64/lib/copy_to_user.S +++ b/arch/arm64/lib/copy_to_user.S @@ -17,7 +17,7 @@ #include #include -#include +#include /* * Copy to user space from a kernel buffer (alignment handled by the hardware) diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S index da9576932322..17f422a4dc55 100644 --- a/arch/arm64/mm/cache.S +++ b/arch/arm64/mm/cache.S @@ -23,7 +23,7 @@ #include #include #include -#include +#include /* * flush_icache_range(start,end) diff --git a/arch/arm64/xen/hypercall.S b/arch/arm64/xen/hypercall.S index b41aff25426d..47cf3f9d89ff 100644 --- a/arch/arm64/xen/hypercall.S +++ b/arch/arm64/xen/hypercall.S @@ -49,7 +49,7 @@ #include #include -#include +#include #include diff --git a/arch/avr32/kernel/avr32_ksyms.c b/arch/avr32/kernel/avr32_ksyms.c index 7c6cf14f0985..0d05fd095468 100644 --- a/arch/avr32/kernel/avr32_ksyms.c +++ b/arch/avr32/kernel/avr32_ksyms.c @@ -12,7 +12,7 @@ #include #include -#include +#include /* * GCC functions diff --git a/arch/avr32/kernel/ptrace.c b/arch/avr32/kernel/ptrace.c index 4aedcab7cd4b..a89b893279bb 100644 --- a/arch/avr32/kernel/ptrace.c +++ b/arch/avr32/kernel/ptrace.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/avr32/kernel/signal.c b/arch/avr32/kernel/signal.c index 8f1c63b9b983..b5fcc4914fe4 100644 --- a/arch/avr32/kernel/signal.c +++ b/arch/avr32/kernel/signal.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/arch/avr32/mm/cache.c b/arch/avr32/mm/cache.c index 85d635cd7b28..d9476825fc43 100644 --- a/arch/avr32/mm/cache.c +++ b/arch/avr32/mm/cache.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include /* diff --git a/arch/blackfin/kernel/bfin_dma.c b/arch/blackfin/kernel/bfin_dma.c index 4a32f2dd5ddc..9d3eb0cf8ccc 100644 --- a/arch/blackfin/kernel/bfin_dma.c +++ b/arch/blackfin/kernel/bfin_dma.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include /* diff --git a/arch/blackfin/kernel/kgdb_test.c b/arch/blackfin/kernel/kgdb_test.c index 18ab004aea1c..b8b785dc4e3b 100644 --- a/arch/blackfin/kernel/kgdb_test.c +++ b/arch/blackfin/kernel/kgdb_test.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include diff --git a/arch/blackfin/kernel/module.c b/arch/blackfin/kernel/module.c index 4489efc52883..0188c933b155 100644 --- a/arch/blackfin/kernel/module.c +++ b/arch/blackfin/kernel/module.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include /* Transfer the section to the L1 memory */ int diff --git a/arch/c6x/mm/init.c b/arch/c6x/mm/init.c index 63f5560d6eb2..4cc72b0d1c1d 100644 --- a/arch/c6x/mm/init.c +++ b/arch/c6x/mm/init.c @@ -18,7 +18,7 @@ #include #include -#include +#include /* * ZERO_PAGE is a special page that is used for zero-initialized diff --git a/arch/cris/arch-v10/drivers/eeprom.c b/arch/cris/arch-v10/drivers/eeprom.c index c903a9e53a47..33558d270a53 100644 --- a/arch/cris/arch-v10/drivers/eeprom.c +++ b/arch/cris/arch-v10/drivers/eeprom.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "i2c.h" #define D(x) diff --git a/arch/cris/arch-v10/drivers/sync_serial.c b/arch/cris/arch-v10/drivers/sync_serial.c index 0f3983241e60..9ac75d68f184 100644 --- a/arch/cris/arch-v10/drivers/sync_serial.c +++ b/arch/cris/arch-v10/drivers/sync_serial.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/cris/arch-v10/kernel/ptrace.c b/arch/cris/arch-v10/kernel/ptrace.c index bfddfb99401f..eca94c7d56e7 100644 --- a/arch/cris/arch-v10/kernel/ptrace.c +++ b/arch/cris/arch-v10/kernel/ptrace.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v10/kernel/signal.c b/arch/cris/arch-v10/kernel/signal.c index 7122d9773b13..db30c98e4926 100644 --- a/arch/cris/arch-v10/kernel/signal.c +++ b/arch/cris/arch-v10/kernel/signal.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #define DEBUG_SIG 0 diff --git a/arch/cris/arch-v10/kernel/traps.c b/arch/cris/arch-v10/kernel/traps.c index 7001beda716c..96d004fe9740 100644 --- a/arch/cris/arch-v10/kernel/traps.c +++ b/arch/cris/arch-v10/kernel/traps.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include #include diff --git a/arch/cris/arch-v10/lib/usercopy.c b/arch/cris/arch-v10/lib/usercopy.c index b964c667aced..1ba7cc000dfc 100644 --- a/arch/cris/arch-v10/lib/usercopy.c +++ b/arch/cris/arch-v10/lib/usercopy.c @@ -8,7 +8,7 @@ * Pieces used from memcpy, originally by Kenny Ranerup long time ago. */ -#include +#include /* Asm:s have been tweaked (within the domain of correctness) to give satisfactory results for "gcc version 2.96 20000427 (experimental)". diff --git a/arch/cris/arch-v10/mm/fault.c b/arch/cris/arch-v10/mm/fault.c index ed60588f8467..75210cbe61ce 100644 --- a/arch/cris/arch-v10/mm/fault.c +++ b/arch/cris/arch-v10/mm/fault.c @@ -11,7 +11,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c index 0068fd411a84..ae6903d7fdbe 100644 --- a/arch/cris/arch-v32/drivers/cryptocop.c +++ b/arch/cris/arch-v32/drivers/cryptocop.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/arch/cris/arch-v32/kernel/ptrace.c b/arch/cris/arch-v32/kernel/ptrace.c index fe1f9cf7b391..c366bc05466a 100644 --- a/arch/cris/arch-v32/kernel/ptrace.c +++ b/arch/cris/arch-v32/kernel/ptrace.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v32/kernel/signal.c b/arch/cris/arch-v32/kernel/signal.c index 150d1d76c29d..816bf2ca93ef 100644 --- a/arch/cris/arch-v32/kernel/signal.c +++ b/arch/cris/arch-v32/kernel/signal.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include extern unsigned long cris_signal_return_page; diff --git a/arch/cris/arch-v32/kernel/traps.c b/arch/cris/arch-v32/kernel/traps.c index 8bbe09c93132..d79666aefd71 100644 --- a/arch/cris/arch-v32/kernel/traps.c +++ b/arch/cris/arch-v32/kernel/traps.c @@ -4,7 +4,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/cris/arch-v32/lib/usercopy.c b/arch/cris/arch-v32/lib/usercopy.c index f0f335d8aa79..05e58dab800d 100644 --- a/arch/cris/arch-v32/lib/usercopy.c +++ b/arch/cris/arch-v32/lib/usercopy.c @@ -8,7 +8,7 @@ * Pieces used from memcpy, originally by Kenny Ranerup long time ago. */ -#include +#include /* Asm:s have been tweaked (within the domain of correctness) to give satisfactory results for "gcc version 3.2.1 Axis release R53/1.53-v32". diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c index 31b4bd288cad..3166d1cf2f84 100644 --- a/arch/cris/kernel/crisksyms.c +++ b/arch/cris/kernel/crisksyms.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/cris/kernel/process.c b/arch/cris/kernel/process.c index b78498eb079b..50a7dd451456 100644 --- a/arch/cris/kernel/process.c +++ b/arch/cris/kernel/process.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/cris/kernel/profile.c b/arch/cris/kernel/profile.c index cd9f15b92f8f..ad56b37f8e11 100644 --- a/arch/cris/kernel/profile.c +++ b/arch/cris/kernel/profile.c @@ -5,7 +5,7 @@ #include #include #include -#include +#include #define SAMPLE_BUFFER_SIZE 8192 diff --git a/arch/cris/kernel/ptrace.c b/arch/cris/kernel/ptrace.c index fd3427e563c5..806b764059d5 100644 --- a/arch/cris/kernel/ptrace.c +++ b/arch/cris/kernel/ptrace.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c index 7aa036ec78ff..8febb032fdd7 100644 --- a/arch/cris/kernel/sys_cris.c +++ b/arch/cris/kernel/sys_cris.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include asmlinkage long diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c index da4c72401e27..b2a312a7afc6 100644 --- a/arch/cris/kernel/traps.c +++ b/arch/cris/kernel/traps.c @@ -20,7 +20,7 @@ #endif #include -#include +#include #include extern void arch_enable_nmi(void); diff --git a/arch/frv/include/asm/futex.h b/arch/frv/include/asm/futex.h index 4bea27f50a7a..2e1da71e27a4 100644 --- a/arch/frv/include/asm/futex.h +++ b/arch/frv/include/asm/futex.h @@ -5,7 +5,7 @@ #include #include -#include +#include extern int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr); diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 2239346fa3db..93513e4ccd2b 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/frv/kernel/pm-mb93093.c b/arch/frv/kernel/pm-mb93093.c index eaa7b582ef52..8358e34a3fad 100644 --- a/arch/frv/kernel/pm-mb93093.c +++ b/arch/frv/kernel/pm-mb93093.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include diff --git a/arch/frv/kernel/pm.c b/arch/frv/kernel/pm.c index ac767d94a880..051ccecbf7f1 100644 --- a/arch/frv/kernel/pm.c +++ b/arch/frv/kernel/pm.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include diff --git a/arch/frv/kernel/process.c b/arch/frv/kernel/process.c index 5d40aeb7712e..b306241c4ef2 100644 --- a/arch/frv/kernel/process.c +++ b/arch/frv/kernel/process.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/frv/kernel/ptrace.c b/arch/frv/kernel/ptrace.c index 3987ff88dab0..49768401ce0f 100644 --- a/arch/frv/kernel/ptrace.c +++ b/arch/frv/kernel/ptrace.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c index 82d5e914dc15..bf6e07a7a1b1 100644 --- a/arch/frv/kernel/signal.c +++ b/arch/frv/kernel/signal.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #define DEBUG_SIG 0 diff --git a/arch/frv/kernel/sys_frv.c b/arch/frv/kernel/sys_frv.c index 9c4980825bbb..f80cc8b9bd45 100644 --- a/arch/frv/kernel/sys_frv.c +++ b/arch/frv/kernel/sys_frv.c @@ -25,7 +25,7 @@ #include #include -#include +#include asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, diff --git a/arch/frv/kernel/sysctl.c b/arch/frv/kernel/sysctl.c index f4dfae2c75ad..b54a64971cf1 100644 --- a/arch/frv/kernel/sysctl.c +++ b/arch/frv/kernel/sysctl.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include static const char frv_cache_wback[] = "wback"; static const char frv_cache_wthru[] = "wthru"; diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c index a6d105d61b26..31221fb4348e 100644 --- a/arch/frv/kernel/traps.c +++ b/arch/frv/kernel/traps.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/frv/kernel/uaccess.c b/arch/frv/kernel/uaccess.c index 374f88d6cc00..8b360b4222a5 100644 --- a/arch/frv/kernel/uaccess.c +++ b/arch/frv/kernel/uaccess.c @@ -11,7 +11,7 @@ #include #include -#include +#include /*****************************************************************************/ /* diff --git a/arch/frv/mm/dma-alloc.c b/arch/frv/mm/dma-alloc.c index 7a73aaeae3ac..e701aa9e6a14 100644 --- a/arch/frv/mm/dma-alloc.c +++ b/arch/frv/mm/dma-alloc.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include static int map_page(unsigned long va, unsigned long pa, pgprot_t prot) diff --git a/arch/frv/mm/extable.c b/arch/frv/mm/extable.c index 8863d6c1df6e..9a641c1b085a 100644 --- a/arch/frv/mm/extable.c +++ b/arch/frv/mm/extable.c @@ -4,7 +4,7 @@ #include #include -#include +#include extern const void __memset_end, __memset_user_error_lr, __memset_user_error_handler; extern const void __memcpy_end, __memcpy_user_error_lr, __memcpy_user_error_handler; diff --git a/arch/h8300/boot/compressed/misc.c b/arch/h8300/boot/compressed/misc.c index 9f64fe8f29ff..a947dbb4fd91 100644 --- a/arch/h8300/boot/compressed/misc.c +++ b/arch/h8300/boot/compressed/misc.c @@ -9,7 +9,7 @@ * Adapted for h8300 by Yoshinori Sato 2006 */ -#include +#include /* * gzip declarations diff --git a/arch/h8300/kernel/process.c b/arch/h8300/kernel/process.c index dee41256922c..891974a11704 100644 --- a/arch/h8300/kernel/process.c +++ b/arch/h8300/kernel/process.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c index 7138303cbbf2..d784f7117f9a 100644 --- a/arch/h8300/kernel/signal.c +++ b/arch/h8300/kernel/signal.c @@ -41,7 +41,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/hexagon/kernel/hexagon_ksyms.c b/arch/hexagon/kernel/hexagon_ksyms.c index c041d8ecb1e2..af9dec4c28eb 100644 --- a/arch/hexagon/kernel/hexagon_ksyms.c +++ b/arch/hexagon/kernel/hexagon_ksyms.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include /* Additional functions */ EXPORT_SYMBOL(__clear_user_hexagon); diff --git a/arch/hexagon/kernel/signal.c b/arch/hexagon/kernel/signal.c index b039a624c170..c6b22b9945a7 100644 --- a/arch/hexagon/kernel/signal.c +++ b/arch/hexagon/kernel/signal.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/hexagon/mm/uaccess.c b/arch/hexagon/mm/uaccess.c index 34127261c2b7..ec90afdb3ad0 100644 --- a/arch/hexagon/mm/uaccess.c +++ b/arch/hexagon/mm/uaccess.c @@ -23,7 +23,7 @@ * we implement here as subroutines. */ #include -#include +#include #include /* diff --git a/arch/hexagon/mm/vm_fault.c b/arch/hexagon/mm/vm_fault.c index bd7c251e2bce..de863d6d802b 100644 --- a/arch/hexagon/mm/vm_fault.c +++ b/arch/hexagon/mm/vm_fault.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/ia64/kernel/brl_emu.c b/arch/ia64/kernel/brl_emu.c index 0b286ca164f9..8682df6263d6 100644 --- a/arch/ia64/kernel/brl_emu.c +++ b/arch/ia64/kernel/brl_emu.c @@ -9,7 +9,7 @@ #include #include -#include +#include #include extern char ia64_set_b1, ia64_set_b2, ia64_set_b3, ia64_set_b4, ia64_set_b5; diff --git a/arch/ia64/kernel/crash_dump.c b/arch/ia64/kernel/crash_dump.c index c8c9298666fb..9c12b794e774 100644 --- a/arch/ia64/kernel/crash_dump.c +++ b/arch/ia64/kernel/crash_dump.c @@ -11,7 +11,7 @@ #include #include -#include +#include /** * copy_oldmem_page - copy one page from "oldmem" diff --git a/arch/ia64/kernel/init_task.c b/arch/ia64/kernel/init_task.c index 0eaa89f3defd..fa8ee64adac2 100644 --- a/arch/ia64/kernel/init_task.c +++ b/arch/ia64/kernel/init_task.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include static struct signal_struct init_signals = INIT_SIGNALS(init_signals); diff --git a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c index de4fc00dea98..2ff1df7b14ea 100644 --- a/arch/ia64/kernel/irq.c +++ b/arch/ia64/kernel/irq.c @@ -17,7 +17,7 @@ */ #include -#include +#include #include #include #include diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c index c7c51445c3be..45ff27e9edbb 100644 --- a/arch/ia64/kernel/kprobes.c +++ b/arch/ia64/kernel/kprobes.c @@ -33,7 +33,7 @@ #include #include -#include +#include extern void jprobe_inst_return(void); diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index 2436ad5f92c1..677a86826771 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_PERFMON diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index aae6c4dc7ae7..52deab683ba1 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c index 36f660da8124..0b1153e610ea 100644 --- a/arch/ia64/kernel/ptrace.c +++ b/arch/ia64/kernel/ptrace.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_PERFMON #include diff --git a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c index aaf74f36cfa1..d194d5c83d32 100644 --- a/arch/ia64/kernel/salinfo.c +++ b/arch/ia64/kernel/salinfo.c @@ -48,7 +48,7 @@ #include #include -#include +#include MODULE_AUTHOR("Jesse Barnes "); MODULE_DESCRIPTION("/proc interface to IA-64 SAL features"); diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c index b3a124da71e5..5db52c6813c4 100644 --- a/arch/ia64/kernel/signal.c +++ b/arch/ia64/kernel/signal.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include diff --git a/arch/ia64/kernel/sys_ia64.c b/arch/ia64/kernel/sys_ia64.c index 41e33f84c185..a09c12230bc5 100644 --- a/arch/ia64/kernel/sys_ia64.c +++ b/arch/ia64/kernel/sys_ia64.c @@ -18,7 +18,7 @@ #include #include -#include +#include unsigned long arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len, diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c index 77edd68c5161..095bfaff82d0 100644 --- a/arch/ia64/kernel/traps.c +++ b/arch/ia64/kernel/traps.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include fpswa_interface_t *fpswa_interface; diff --git a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c index 7f0d31656b4d..9cd01c2200ee 100644 --- a/arch/ia64/kernel/unaligned.c +++ b/arch/ia64/kernel/unaligned.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include extern int die_if_kernel(char *str, struct pt_regs *regs, long err); diff --git a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c index 8f66195999e7..9704e2cd9878 100644 --- a/arch/ia64/kernel/unwind.c +++ b/arch/ia64/kernel/unwind.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include "entry.h" #include "unwind_i.h" diff --git a/arch/ia64/lib/csum_partial_copy.c b/arch/ia64/lib/csum_partial_copy.c index 118daf5a0632..42f7678ef6ad 100644 --- a/arch/ia64/lib/csum_partial_copy.c +++ b/arch/ia64/lib/csum_partial_copy.c @@ -11,7 +11,7 @@ #include #include -#include +#include /* * XXX Fixme: those 2 inlines are meant for debugging and will go away diff --git a/arch/ia64/mm/extable.c b/arch/ia64/mm/extable.c index 8f70bb2d0c37..4edb816aba9a 100644 --- a/arch/ia64/mm/extable.c +++ b/arch/ia64/mm/extable.c @@ -5,7 +5,7 @@ * David Mosberger-Tang */ -#include +#include void ia64_handle_exception (struct pt_regs *regs, const struct exception_table_entry *e) diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c index 1841ef69183d..bb4610faca84 100644 --- a/arch/ia64/mm/init.c +++ b/arch/ia64/mm/init.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/ia64/sn/kernel/sn2/sn_hwperf.c b/arch/ia64/sn/kernel/sn2/sn_hwperf.c index b9992571c036..4c3b84d8406a 100644 --- a/arch/ia64/sn/kernel/sn2/sn_hwperf.c +++ b/arch/ia64/sn/kernel/sn2/sn_hwperf.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c index 7aab87f48060..29cf8f8c08e9 100644 --- a/arch/ia64/sn/kernel/sn2/sn_proc_fs.c +++ b/arch/ia64/sn/kernel/sn2/sn_proc_fs.c @@ -9,7 +9,7 @@ #ifdef CONFIG_PROC_FS #include #include -#include +#include #include static int partition_id_show(struct seq_file *s, void *p) diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c index e35f6485c1fd..32d0380eb72e 100644 --- a/arch/ia64/sn/kernel/tiocx.c +++ b/arch/ia64/sn/kernel/tiocx.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/m32r/kernel/align.c b/arch/m32r/kernel/align.c index ab871ccd33f8..ec51e5b34860 100644 --- a/arch/m32r/kernel/align.c +++ b/arch/m32r/kernel/align.c @@ -5,7 +5,7 @@ */ #include -#include +#include static int get_reg(struct pt_regs *regs, int nr) { diff --git a/arch/m32r/kernel/irq.c b/arch/m32r/kernel/irq.c index c7272b894283..5537f7397297 100644 --- a/arch/m32r/kernel/irq.c +++ b/arch/m32r/kernel/irq.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include /* * do_IRQ handles all normal device IRQs (the special diff --git a/arch/m32r/kernel/m32r_ksyms.c b/arch/m32r/kernel/m32r_ksyms.c index 23f26f4adfff..d763f0bd2106 100644 --- a/arch/m32r/kernel/m32r_ksyms.c +++ b/arch/m32r/kernel/m32r_ksyms.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m32r/kernel/process.c b/arch/m32r/kernel/process.c index a88b1f01e91f..e0568bee60c0 100644 --- a/arch/m32r/kernel/process.c +++ b/arch/m32r/kernel/process.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m32r/kernel/ptrace.c b/arch/m32r/kernel/ptrace.c index c145605a981f..a68acb9fa515 100644 --- a/arch/m32r/kernel/ptrace.c +++ b/arch/m32r/kernel/ptrace.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c index 1c81e24fd006..1ed597041fba 100644 --- a/arch/m32r/kernel/signal.c +++ b/arch/m32r/kernel/signal.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #define DEBUG_SIG 0 diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c index c3fdd632fba7..f34957032504 100644 --- a/arch/m32r/kernel/sys_m32r.c +++ b/arch/m32r/kernel/sys_m32r.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m32r/kernel/traps.c b/arch/m32r/kernel/traps.c index a7a424f852e4..c3c5fdfae920 100644 --- a/arch/m32r/kernel/traps.c +++ b/arch/m32r/kernel/traps.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include diff --git a/arch/m32r/lib/csum_partial_copy.c b/arch/m32r/lib/csum_partial_copy.c index 5596f3df833f..b3cd59c12b8e 100644 --- a/arch/m32r/lib/csum_partial_copy.c +++ b/arch/m32r/lib/csum_partial_copy.c @@ -22,7 +22,7 @@ #include #include -#include +#include /* * Copy while checksumming, otherwise like csum_partial diff --git a/arch/m32r/lib/usercopy.c b/arch/m32r/lib/usercopy.c index 82abd159dbef..fd03f2731f20 100644 --- a/arch/m32r/lib/usercopy.c +++ b/arch/m32r/lib/usercopy.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include unsigned long __generic_copy_to_user(void __user *to, const void *from, unsigned long n) diff --git a/arch/m32r/mm/extable.c b/arch/m32r/mm/extable.c index 1743f23d49a3..40ccf80d29cf 100644 --- a/arch/m32r/mm/extable.c +++ b/arch/m32r/mm/extable.c @@ -3,7 +3,7 @@ */ #include -#include +#include int fixup_exception(struct pt_regs *regs) { diff --git a/arch/m32r/mm/fault-nommu.c b/arch/m32r/mm/fault-nommu.c index 80f18cc6f547..e22d5ddae5cb 100644 --- a/arch/m32r/mm/fault-nommu.c +++ b/arch/m32r/mm/fault-nommu.c @@ -22,7 +22,7 @@ #include /* For unblank_screen() */ #include -#include +#include #include #include #include diff --git a/arch/m68k/bvme6000/rtc.c b/arch/m68k/bvme6000/rtc.c index f7984f44ff0f..d53c9b301f84 100644 --- a/arch/m68k/bvme6000/rtc.c +++ b/arch/m68k/bvme6000/rtc.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include /* diff --git a/arch/m68k/kernel/process.c b/arch/m68k/kernel/process.c index 4ba1ae7345c3..aaf28f8e342d 100644 --- a/arch/m68k/kernel/process.c +++ b/arch/m68k/kernel/process.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/kernel/ptrace.c b/arch/m68k/kernel/ptrace.c index 1bc10e62b9af..9cd86d7343a6 100644 --- a/arch/m68k/kernel/ptrace.c +++ b/arch/m68k/kernel/ptrace.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/kernel/signal.c b/arch/m68k/kernel/signal.c index 58507edbdf1d..8ead291a902a 100644 --- a/arch/m68k/kernel/signal.c +++ b/arch/m68k/kernel/signal.c @@ -46,7 +46,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 9aa01adb407f..98a2daaae30c 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index 6c9ca24830e9..558f38402737 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/lib/uaccess.c b/arch/m68k/lib/uaccess.c index 35d1442dee89..a76b73abaf64 100644 --- a/arch/m68k/lib/uaccess.c +++ b/arch/m68k/lib/uaccess.c @@ -5,7 +5,7 @@ */ #include -#include +#include unsigned long __generic_copy_from_user(void *to, const void __user *from, unsigned long n) diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c index 0fb54a90eac2..c6d351f5bd79 100644 --- a/arch/m68k/mac/misc.c +++ b/arch/m68k/mac/misc.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index b09a3cb29b68..9c1e656b1f8f 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/mm/motorola.c b/arch/m68k/mm/motorola.c index 8f37fdd80be9..7cb72dbc2eaa 100644 --- a/arch/m68k/mm/motorola.c +++ b/arch/m68k/mm/motorola.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/mm/sun3mmu.c b/arch/m68k/mm/sun3mmu.c index 269f81158a33..b5b7d53f7283 100644 --- a/arch/m68k/mm/sun3mmu.c +++ b/arch/m68k/mm/sun3mmu.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/m68k/mvme16x/rtc.c b/arch/m68k/mvme16x/rtc.c index 1cdc73268188..8f00847a0e4b 100644 --- a/arch/m68k/mvme16x/rtc.c +++ b/arch/m68k/mvme16x/rtc.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include /* diff --git a/arch/m68k/sun3/mmu_emu.c b/arch/m68k/sun3/mmu_emu.c index 3f258e230ba5..0f95134e9b85 100644 --- a/arch/m68k/sun3/mmu_emu.c +++ b/arch/m68k/sun3/mmu_emu.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/metag/kernel/irq.c b/arch/metag/kernel/irq.c index 3074b64793e6..c9939604a38f 100644 --- a/arch/metag/kernel/irq.c +++ b/arch/metag/kernel/irq.c @@ -13,7 +13,7 @@ #include #include -#include +#include #ifdef CONFIG_4KSTACKS union irq_ctx { diff --git a/arch/mips/alchemy/common/power.c b/arch/mips/alchemy/common/power.c index 921ed30b440c..303257b697c2 100644 --- a/arch/mips/alchemy/common/power.c +++ b/arch/mips/alchemy/common/power.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include /* diff --git a/arch/mips/dec/kn01-berr.c b/arch/mips/dec/kn01-berr.c index 44d8a87a8a68..e9d2db480aeb 100644 --- a/arch/mips/dec/kn01-berr.c +++ b/arch/mips/dec/kn01-berr.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include diff --git a/arch/mips/include/asm/checksum.h b/arch/mips/include/asm/checksum.h index bce1ce53149a..7749daf2a465 100644 --- a/arch/mips/include/asm/checksum.h +++ b/arch/mips/include/asm/checksum.h @@ -18,7 +18,7 @@ #include -#include +#include /* * computes the checksum of a memory block at buff, length len, diff --git a/arch/mips/include/asm/compat-signal.h b/arch/mips/include/asm/compat-signal.h index 64e0b9343b8c..4c6176467146 100644 --- a/arch/mips/include/asm/compat-signal.h +++ b/arch/mips/include/asm/compat-signal.h @@ -8,7 +8,7 @@ #include #include -#include +#include static inline int __copy_conv_sigset_to_user(compat_sigset_t __user *d, const sigset_t *s) diff --git a/arch/mips/include/asm/r4kcache.h b/arch/mips/include/asm/r4kcache.h index 667ca3c467b7..b42b513007a2 100644 --- a/arch/mips/include/asm/r4kcache.h +++ b/arch/mips/include/asm/r4kcache.h @@ -20,7 +20,7 @@ #include #include #include -#include /* for segment_eq() */ +#include /* for segment_eq() */ extern void (*r4k_blast_dcache)(void); extern void (*r4k_blast_icache)(void); diff --git a/arch/mips/include/asm/termios.h b/arch/mips/include/asm/termios.h index 6245b68a69a8..ce2d72e34274 100644 --- a/arch/mips/include/asm/termios.h +++ b/arch/mips/include/asm/termios.h @@ -9,7 +9,7 @@ #ifndef _ASM_TERMIOS_H #define _ASM_TERMIOS_H -#include +#include #include /* diff --git a/arch/mips/jazz/jazzdma.c b/arch/mips/jazz/jazzdma.c index db6f5afff4ff..1900f39588ae 100644 --- a/arch/mips/jazz/jazzdma.c +++ b/arch/mips/jazz/jazzdma.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/kernel/branch.c b/arch/mips/kernel/branch.c index 12c718181e5e..ae037a304ee4 100644 --- a/arch/mips/kernel/branch.c +++ b/arch/mips/kernel/branch.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include /* * Calculate and return exception PC in case of branch delay slot diff --git a/arch/mips/kernel/cpu-probe.c b/arch/mips/kernel/cpu-probe.c index dd3175442c9e..07718bb5fc9d 100644 --- a/arch/mips/kernel/cpu-probe.c +++ b/arch/mips/kernel/cpu-probe.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include /* Hardware capabilities */ unsigned int elf_hwcap __read_mostly; diff --git a/arch/mips/kernel/crash_dump.c b/arch/mips/kernel/crash_dump.c index 6fe7790e5868..77ee99a2d0aa 100644 --- a/arch/mips/kernel/crash_dump.c +++ b/arch/mips/kernel/crash_dump.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include static void *kdump_buf_page; diff --git a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c index f25f7eab7307..f8f5836eb3c1 100644 --- a/arch/mips/kernel/irq.c +++ b/arch/mips/kernel/irq.c @@ -23,7 +23,7 @@ #include #include -#include +#include /* * 'what should we do if we get a hw irq event on an illegal vector'. diff --git a/arch/mips/kernel/kgdb.c b/arch/mips/kernel/kgdb.c index de63d36af895..1f4bd222ba76 100644 --- a/arch/mips/kernel/kgdb.c +++ b/arch/mips/kernel/kgdb.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include static struct hard_trap_info { unsigned char tt; /* Trap type code for MIPS R3xxx and R4xxx */ diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index 50fb62544df7..0352f742d077 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include diff --git a/arch/mips/kernel/mips-mt-fpaff.c b/arch/mips/kernel/mips-mt-fpaff.c index 789d7bf4fef3..a12904ea9f65 100644 --- a/arch/mips/kernel/mips-mt-fpaff.c +++ b/arch/mips/kernel/mips-mt-fpaff.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include /* * CPU mask used to set process affinity for MT VPEs/TCs with FPUs diff --git a/arch/mips/kernel/mips-r2-to-r6-emul.c b/arch/mips/kernel/mips-r2-to-r6-emul.c index bd09853aecdf..ef2ca28a028b 100644 --- a/arch/mips/kernel/mips-r2-to-r6-emul.c +++ b/arch/mips/kernel/mips-r2-to-r6-emul.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #ifdef CONFIG_64BIT #define ADDIU "daddiu " diff --git a/arch/mips/kernel/mips_ksyms.c b/arch/mips/kernel/mips_ksyms.c index e2b6ab74643d..93aeec705a6e 100644 --- a/arch/mips/kernel/mips_ksyms.c +++ b/arch/mips/kernel/mips_ksyms.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/kernel/process.c b/arch/mips/kernel/process.c index 9514e5f2209f..5142b1dfe8a7 100644 --- a/arch/mips/kernel/process.c +++ b/arch/mips/kernel/process.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c index a92994d60e91..c8ba26072132 100644 --- a/arch/mips/kernel/ptrace.c +++ b/arch/mips/kernel/ptrace.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/kernel/ptrace32.c b/arch/mips/kernel/ptrace32.c index 5fcbdcd7abd0..4f0998525626 100644 --- a/arch/mips/kernel/ptrace32.c +++ b/arch/mips/kernel/ptrace32.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include /* diff --git a/arch/mips/kernel/signal32.c b/arch/mips/kernel/signal32.c index 97b7c51b8251..84165f2b31ff 100644 --- a/arch/mips/kernel/signal32.c +++ b/arch/mips/kernel/signal32.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include "signal-common.h" diff --git a/arch/mips/kernel/signal_n32.c b/arch/mips/kernel/signal_n32.c index a7bc38430500..b672cebb4a1a 100644 --- a/arch/mips/kernel/signal_n32.c +++ b/arch/mips/kernel/signal_n32.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c index 53a7ef9a8f32..833f82210528 100644 --- a/arch/mips/kernel/syscall.c +++ b/arch/mips/kernel/syscall.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include /* diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 3905003dfe2b..6c7f9d7e92b3 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c @@ -61,7 +61,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/kernel/unaligned.c b/arch/mips/kernel/unaligned.c index f1c308dbbc4a..7ed98354fe9d 100644 --- a/arch/mips/kernel/unaligned.c +++ b/arch/mips/kernel/unaligned.c @@ -89,7 +89,7 @@ #include #include #include -#include +#include #define STR(x) __STR(x) #define __STR(x) #x diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index f8b7bf836437..a298ac93edcc 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/mips/math-emu/dsemul.c b/arch/mips/math-emu/dsemul.c index 4a094f7acb3d..c4469ff4a996 100644 --- a/arch/mips/math-emu/dsemul.c +++ b/arch/mips/math-emu/dsemul.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include /** * struct emuframe - The 'emulation' frame structure diff --git a/arch/mips/mm/extable.c b/arch/mips/mm/extable.c index e474fa2efed4..81bc8a34a83f 100644 --- a/arch/mips/mm/extable.c +++ b/arch/mips/mm/extable.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include int fixup_exception(struct pt_regs *regs) { diff --git a/arch/mips/mm/sc-debugfs.c b/arch/mips/mm/sc-debugfs.c index 01f1154cdb0c..7e945e310b44 100644 --- a/arch/mips/mm/sc-debugfs.c +++ b/arch/mips/mm/sc-debugfs.c @@ -10,7 +10,7 @@ #include #include -#include +#include #include #include diff --git a/arch/mips/oprofile/op_model_loongson3.c b/arch/mips/oprofile/op_model_loongson3.c index 85f3ee4ab456..40660392006f 100644 --- a/arch/mips/oprofile/op_model_loongson3.c +++ b/arch/mips/oprofile/op_model_loongson3.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include "op_impl.h" diff --git a/arch/mips/sgi-ip22/ip28-berr.c b/arch/mips/sgi-ip22/ip28-berr.c index 712cc0f6a58d..9960a8302eac 100644 --- a/arch/mips/sgi-ip22/ip28-berr.c +++ b/arch/mips/sgi-ip22/ip28-berr.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include static unsigned int count_be_is_fixup; diff --git a/arch/mips/sgi-ip27/ip27-berr.c b/arch/mips/sgi-ip27/ip27-berr.c index 692778da9e76..2e0edb385656 100644 --- a/arch/mips/sgi-ip27/ip27-berr.c +++ b/arch/mips/sgi-ip27/ip27-berr.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include static void dump_hub_information(unsigned long errst0, unsigned long errst1) { diff --git a/arch/mips/sgi-ip32/ip32-berr.c b/arch/mips/sgi-ip32/ip32-berr.c index afc1cadbba37..ba8f46d80ab8 100644 --- a/arch/mips/sgi-ip32/ip32-berr.c +++ b/arch/mips/sgi-ip32/ip32-berr.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mips/sibyte/common/sb_tbprof.c b/arch/mips/sibyte/common/sb_tbprof.c index 059e28c8fd97..99c720be72d2 100644 --- a/arch/mips/sibyte/common/sb_tbprof.c +++ b/arch/mips/sibyte/common/sb_tbprof.c @@ -54,7 +54,7 @@ #define K_INT_PERF_CNT K_BCM1480_INT_PERF_CNT #endif -#include +#include #define SBPROF_TB_MAJOR 240 diff --git a/arch/mn10300/kernel/fpu.c b/arch/mn10300/kernel/fpu.c index 064fa194de2b..2578b7ae7dd5 100644 --- a/arch/mn10300/kernel/fpu.c +++ b/arch/mn10300/kernel/fpu.c @@ -8,7 +8,7 @@ * as published by the Free Software Foundation; either version * 2 of the Licence, or (at your option) any later version. */ -#include +#include #include #include #include diff --git a/arch/mn10300/kernel/mn10300_ksyms.c b/arch/mn10300/kernel/mn10300_ksyms.c index f9eb9753a404..ec6c4f8f93a6 100644 --- a/arch/mn10300/kernel/mn10300_ksyms.c +++ b/arch/mn10300/kernel/mn10300_ksyms.c @@ -9,7 +9,7 @@ * 2 of the Licence, or (at your option) any later version. */ #include -#include +#include #include diff --git a/arch/mn10300/kernel/process.c b/arch/mn10300/kernel/process.c index cbede4e88dee..e5def2217f72 100644 --- a/arch/mn10300/kernel/process.c +++ b/arch/mn10300/kernel/process.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mn10300/kernel/ptrace.c b/arch/mn10300/kernel/ptrace.c index 5bd58514e739..976020f469c1 100644 --- a/arch/mn10300/kernel/ptrace.c +++ b/arch/mn10300/kernel/ptrace.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mn10300/kernel/setup.c b/arch/mn10300/kernel/setup.c index 2ad7f32fa122..1b3d80d8a171 100644 --- a/arch/mn10300/kernel/setup.c +++ b/arch/mn10300/kernel/setup.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mn10300/kernel/signal.c b/arch/mn10300/kernel/signal.c index cd8cb1d1176b..2f3cb5734235 100644 --- a/arch/mn10300/kernel/signal.c +++ b/arch/mn10300/kernel/signal.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include "sigframe.h" diff --git a/arch/mn10300/kernel/sys_mn10300.c b/arch/mn10300/kernel/sys_mn10300.c index 815f1355fad4..f999981e55c0 100644 --- a/arch/mn10300/kernel/sys_mn10300.c +++ b/arch/mn10300/kernel/sys_mn10300.c @@ -21,7 +21,7 @@ #include #include -#include +#include asmlinkage long old_mmap(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, diff --git a/arch/mn10300/lib/checksum.c b/arch/mn10300/lib/checksum.c index b6580f5d89ee..0f569151ef11 100644 --- a/arch/mn10300/lib/checksum.c +++ b/arch/mn10300/lib/checksum.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include "internal.h" diff --git a/arch/mn10300/mm/cache-smp.c b/arch/mn10300/mm/cache-smp.c index 2d23b9eeee62..e80996064d3d 100644 --- a/arch/mn10300/mm/cache-smp.c +++ b/arch/mn10300/mm/cache-smp.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include "cache-smp.h" diff --git a/arch/mn10300/mm/cache.c b/arch/mn10300/mm/cache.c index 0a1f0aa92ebc..0b925cce2b83 100644 --- a/arch/mn10300/mm/cache.c +++ b/arch/mn10300/mm/cache.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include "cache-smp.h" diff --git a/arch/mn10300/mm/extable.c b/arch/mn10300/mm/extable.c index 25e5485ab87d..305de461cb8f 100644 --- a/arch/mn10300/mm/extable.c +++ b/arch/mn10300/mm/extable.c @@ -10,7 +10,7 @@ */ #include #include -#include +#include int fixup_exception(struct pt_regs *regs) { diff --git a/arch/mn10300/mm/init.c b/arch/mn10300/mm/init.c index 97a1ec0beeec..8ce677d5575e 100644 --- a/arch/mn10300/mm/init.c +++ b/arch/mn10300/mm/init.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/mn10300/mm/misalignment.c b/arch/mn10300/mm/misalignment.c index b9920b1edd5a..31d04da85743 100644 --- a/arch/mn10300/mm/misalignment.c +++ b/arch/mn10300/mm/misalignment.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/mn10300/proc-mn2ws0050/proc-init.c b/arch/mn10300/proc-mn2ws0050/proc-init.c index 950cc8dbb284..25b1b453c515 100644 --- a/arch/mn10300/proc-mn2ws0050/proc-init.c +++ b/arch/mn10300/proc-mn2ws0050/proc-init.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/nios2/kernel/traps.c b/arch/nios2/kernel/traps.c index 81f7da7b1d55..72ed30a93c85 100644 --- a/arch/nios2/kernel/traps.c +++ b/arch/nios2/kernel/traps.c @@ -19,7 +19,7 @@ #include #include -#include +#include static DEFINE_SPINLOCK(die_lock); diff --git a/arch/openrisc/kernel/or32_ksyms.c b/arch/openrisc/kernel/or32_ksyms.c index 83ccf7c0c58d..86e31cf1de1d 100644 --- a/arch/openrisc/kernel/or32_ksyms.c +++ b/arch/openrisc/kernel/or32_ksyms.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/openrisc/kernel/process.c b/arch/openrisc/kernel/process.c index 277123bb4bf8..d7990df9025a 100644 --- a/arch/openrisc/kernel/process.c +++ b/arch/openrisc/kernel/process.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/openrisc/kernel/signal.c b/arch/openrisc/kernel/signal.c index c82be69b43c6..265f10fb3930 100644 --- a/arch/openrisc/kernel/signal.c +++ b/arch/openrisc/kernel/signal.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #define DEBUG_SIG 0 diff --git a/arch/openrisc/kernel/traps.c b/arch/openrisc/kernel/traps.c index 3d3f6062f49c..a4574cb4b0fb 100644 --- a/arch/openrisc/kernel/traps.c +++ b/arch/openrisc/kernel/traps.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/openrisc/mm/fault.c b/arch/openrisc/mm/fault.c index e94cd225e816..b1a7435e786a 100644 --- a/arch/openrisc/mm/fault.c +++ b/arch/openrisc/mm/fault.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/arch/parisc/kernel/asm-offsets.c b/arch/parisc/kernel/asm-offsets.c index 78d30d2ea2d8..1c4fe61a592b 100644 --- a/arch/parisc/kernel/asm-offsets.c +++ b/arch/parisc/kernel/asm-offsets.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #ifdef CONFIG_64BIT #define FRAME_SIZE 128 diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c index 3cad8aadc69e..7484b3d11e0d 100644 --- a/arch/parisc/kernel/parisc_ksyms.c +++ b/arch/parisc/kernel/parisc_ksyms.c @@ -43,7 +43,7 @@ EXPORT_SYMBOL(__xchg64); EXPORT_SYMBOL(__cmpxchg_u64); #endif -#include +#include EXPORT_SYMBOL(lclear_user); EXPORT_SYMBOL(lstrnlen_user); diff --git a/arch/parisc/kernel/pci-dma.c b/arch/parisc/kernel/pci-dma.c index b6298a85e8ae..697c53543a4d 100644 --- a/arch/parisc/kernel/pci-dma.c +++ b/arch/parisc/kernel/pci-dma.c @@ -33,7 +33,7 @@ #include #include /* get_order */ #include -#include +#include #include /* for purge_tlb_*() macros */ static struct proc_dir_entry * proc_gsc_root __read_mostly = NULL; diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c index 6eabce62463b..e282a5131d77 100644 --- a/arch/parisc/kernel/perf.c +++ b/arch/parisc/kernel/perf.c @@ -48,7 +48,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c index e02d7b4d2b69..f8b6959d2d97 100644 --- a/arch/parisc/kernel/ptrace.c +++ b/arch/parisc/kernel/ptrace.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c index 2264f68f3c2f..e58925ac64d1 100644 --- a/arch/parisc/kernel/signal.c +++ b/arch/parisc/kernel/signal.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c index c342b2e17492..70aaabb8b3cb 100644 --- a/arch/parisc/kernel/signal32.c +++ b/arch/parisc/kernel/signal32.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include "signal32.h" diff --git a/arch/parisc/kernel/sys_parisc.c b/arch/parisc/kernel/sys_parisc.c index a81e177cac7b..bf3294171230 100644 --- a/arch/parisc/kernel/sys_parisc.c +++ b/arch/parisc/kernel/sys_parisc.c @@ -23,7 +23,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include #include #include #include diff --git a/arch/parisc/kernel/time.c b/arch/parisc/kernel/time.c index 4215f5596c8b..037d81f00520 100644 --- a/arch/parisc/kernel/time.c +++ b/arch/parisc/kernel/time.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index 2b65c0177778..0a21067ac0a3 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/parisc/kernel/unwind.c b/arch/parisc/kernel/unwind.c index e278a87f43cc..1b73690477c5 100644 --- a/arch/parisc/kernel/unwind.c +++ b/arch/parisc/kernel/unwind.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/parisc/lib/checksum.c b/arch/parisc/lib/checksum.c index ae66d31f9ecf..ba6384da6ade 100644 --- a/arch/parisc/lib/checksum.c +++ b/arch/parisc/lib/checksum.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #define addc(_t,_r) \ __asm__ __volatile__ ( \ diff --git a/arch/powerpc/include/asm/asm-prototypes.h b/arch/powerpc/include/asm/asm-prototypes.h index 81592562e0f8..ba47c70712f9 100644 --- a/arch/powerpc/include/asm/asm-prototypes.h +++ b/arch/powerpc/include/asm/asm-prototypes.h @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/kernel/align.c b/arch/powerpc/kernel/align.c index 033f3385fa49..8d58c61908f7 100644 --- a/arch/powerpc/kernel/align.c +++ b/arch/powerpc/kernel/align.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/crash_dump.c b/arch/powerpc/kernel/crash_dump.c index cfa0f81a5bb0..d10ad258d41a 100644 --- a/arch/powerpc/kernel/crash_dump.c +++ b/arch/powerpc/kernel/crash_dump.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #ifdef DEBUG diff --git a/arch/powerpc/kernel/hw_breakpoint.c b/arch/powerpc/kernel/hw_breakpoint.c index 03d089b3ed72..4d3aa05e28be 100644 --- a/arch/powerpc/kernel/hw_breakpoint.c +++ b/arch/powerpc/kernel/hw_breakpoint.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include /* * Stores the breakpoints currently in use on each breakpoint address diff --git a/arch/powerpc/kernel/irq.c b/arch/powerpc/kernel/irq.c index 3c05c311e35e..a018f5cae899 100644 --- a/arch/powerpc/kernel/irq.c +++ b/arch/powerpc/kernel/irq.c @@ -55,7 +55,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c index ad108b842669..735ff3d3f77d 100644 --- a/arch/powerpc/kernel/kprobes.c +++ b/arch/powerpc/kernel/kprobes.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); diff --git a/arch/powerpc/kernel/module.c b/arch/powerpc/kernel/module.c index 30b89d5cbb03..3f7ba0f5bf29 100644 --- a/arch/powerpc/kernel/module.c +++ b/arch/powerpc/kernel/module.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 34d2c595de23..d5e2b8309939 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index 678f87a63645..41c86c6b6e4d 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #undef DEBUG diff --git a/arch/powerpc/kernel/proc_powerpc.c b/arch/powerpc/kernel/proc_powerpc.c index c30612aad68e..56548bf6231f 100644 --- a/arch/powerpc/kernel/proc_powerpc.c +++ b/arch/powerpc/kernel/proc_powerpc.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_PPC64 diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index b1ec62f2cc31..e4744ff38a17 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/ptrace32.c b/arch/powerpc/kernel/ptrace32.c index 1e887f3a61a6..f37eb53de1a1 100644 --- a/arch/powerpc/kernel/ptrace32.c +++ b/arch/powerpc/kernel/ptrace32.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/rtas-proc.c b/arch/powerpc/kernel/rtas-proc.c index c82eed97bd22..df56dfc4b681 100644 --- a/arch/powerpc/kernel/rtas-proc.c +++ b/arch/powerpc/kernel/rtas-proc.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/rtas.c b/arch/powerpc/kernel/rtas.c index 6a3e5de544ce..112cc3b2ee1a 100644 --- a/arch/powerpc/kernel/rtas.c +++ b/arch/powerpc/kernel/rtas.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/rtas_flash.c b/arch/powerpc/kernel/rtas_flash.c index db2b482af658..f6f6a8a5103a 100644 --- a/arch/powerpc/kernel/rtas_flash.c +++ b/arch/powerpc/kernel/rtas_flash.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #define MODULE_VERS "1.0" diff --git a/arch/powerpc/kernel/rtasd.c b/arch/powerpc/kernel/rtasd.c index a26a02006576..2bf1f9b5b34b 100644 --- a/arch/powerpc/kernel/rtasd.c +++ b/arch/powerpc/kernel/rtasd.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c index 5fe79182f0fa..7fcf1f7f01c1 100644 --- a/arch/powerpc/kernel/setup_32.c +++ b/arch/powerpc/kernel/setup_32.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index bbe77aed198d..3a3671172436 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index 27aa913ac91d..97bb1385e771 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -37,7 +37,7 @@ #include #endif -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 96698fdf93b4..c83c115858c1 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c index 8a285876aef8..15f216d022e2 100644 --- a/arch/powerpc/kernel/sys_ppc32.c +++ b/arch/powerpc/kernel/sys_ppc32.c @@ -44,7 +44,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/syscalls.c b/arch/powerpc/kernel/syscalls.c index 644cce3d8dce..de04c9fbb5cd 100644 --- a/arch/powerpc/kernel/syscalls.c +++ b/arch/powerpc/kernel/syscalls.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index be9751f1cb2a..19397e2a8bf5 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 4239aaf74886..e6cc56b61d01 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kernel/vecemu.c b/arch/powerpc/kernel/vecemu.c index c4bfadb2606b..2d8f6d8ccafc 100644 --- a/arch/powerpc/kernel/vecemu.c +++ b/arch/powerpc/kernel/vecemu.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include /* Functions in vector.S */ extern void vaddfp(vector128 *dst, vector128 *a, vector128 *b); diff --git a/arch/powerpc/kvm/book3s.c b/arch/powerpc/kvm/book3s.c index b6952dd23152..019f008775b9 100644 --- a/arch/powerpc/kvm/book3s.c +++ b/arch/powerpc/kvm/book3s.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kvm/book3s_hv.c b/arch/powerpc/kvm/book3s_hv.c index 8dcbe37a4dac..66b2a35be424 100644 --- a/arch/powerpc/kvm/book3s_hv.c +++ b/arch/powerpc/kvm/book3s_hv.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index 826c541a12af..1482961ceb4d 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kvm/book3s_pr_papr.c b/arch/powerpc/kvm/book3s_pr_papr.c index 02176fd52f84..f102616febc7 100644 --- a/arch/powerpc/kvm/book3s_pr_papr.c +++ b/arch/powerpc/kvm/book3s_pr_papr.c @@ -17,7 +17,7 @@ #include -#include +#include #include #include diff --git a/arch/powerpc/kvm/book3s_rtas.c b/arch/powerpc/kvm/book3s_rtas.c index ef27fbd5d9c5..20528701835b 100644 --- a/arch/powerpc/kvm/book3s_rtas.c +++ b/arch/powerpc/kvm/book3s_rtas.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kvm/book3s_xics.c b/arch/powerpc/kvm/book3s_xics.c index 3bdc639157c1..20dff102a06f 100644 --- a/arch/powerpc/kvm/book3s_xics.c +++ b/arch/powerpc/kvm/book3s_xics.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kvm/booke.c b/arch/powerpc/kvm/booke.c index df3f2706d3e5..0514cbd4e533 100644 --- a/arch/powerpc/kvm/booke.c +++ b/arch/powerpc/kvm/booke.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kvm/mpic.c b/arch/powerpc/kvm/mpic.c index ed38f8114118..fe312c160d97 100644 --- a/arch/powerpc/kvm/mpic.c +++ b/arch/powerpc/kvm/mpic.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/kvm/powerpc.c b/arch/powerpc/kvm/powerpc.c index efd1183a6b16..cd892dec7cb6 100644 --- a/arch/powerpc/kvm/powerpc.c +++ b/arch/powerpc/kvm/powerpc.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/lib/checksum_wrappers.c b/arch/powerpc/lib/checksum_wrappers.c index 08e3a3356c40..a0cb63fb76a1 100644 --- a/arch/powerpc/lib/checksum_wrappers.c +++ b/arch/powerpc/lib/checksum_wrappers.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include __wsum csum_and_copy_from_user(const void __user *src, void *dst, int len, __wsum sum, int *err_ptr) diff --git a/arch/powerpc/lib/code-patching.c b/arch/powerpc/lib/code-patching.c index d5edbeb8eb82..c1746df0f88e 100644 --- a/arch/powerpc/lib/code-patching.c +++ b/arch/powerpc/lib/code-patching.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include int patch_instruction(unsigned int *addr, unsigned int instr) diff --git a/arch/powerpc/lib/sstep.c b/arch/powerpc/lib/sstep.c index 9c78a9c102c3..06c7e9b88408 100644 --- a/arch/powerpc/lib/sstep.c +++ b/arch/powerpc/lib/sstep.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/lib/usercopy_64.c b/arch/powerpc/lib/usercopy_64.c index 5eea6f3c1e03..9bd3a3dad78d 100644 --- a/arch/powerpc/lib/usercopy_64.c +++ b/arch/powerpc/lib/usercopy_64.c @@ -7,7 +7,7 @@ * 2 of the License, or (at your option) any later version. */ #include -#include +#include unsigned long copy_from_user(void *to, const void __user *from, unsigned long n) { diff --git a/arch/powerpc/math-emu/fabs.c b/arch/powerpc/math-emu/fabs.c index 549baba5948f..a5e7ad1384ee 100644 --- a/arch/powerpc/math-emu/fabs.c +++ b/arch/powerpc/math-emu/fabs.c @@ -1,6 +1,6 @@ #include #include -#include +#include int fabs(u32 *frD, u32 *frB) diff --git a/arch/powerpc/math-emu/fadd.c b/arch/powerpc/math-emu/fadd.c index 0158a16e2b82..29de37e0e0da 100644 --- a/arch/powerpc/math-emu/fadd.c +++ b/arch/powerpc/math-emu/fadd.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fadds.c b/arch/powerpc/math-emu/fadds.c index 5930f40a8687..7093c5b58002 100644 --- a/arch/powerpc/math-emu/fadds.c +++ b/arch/powerpc/math-emu/fadds.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fcmpo.c b/arch/powerpc/math-emu/fcmpo.c index 5bce011c2aec..5d644467221c 100644 --- a/arch/powerpc/math-emu/fcmpo.c +++ b/arch/powerpc/math-emu/fcmpo.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fcmpu.c b/arch/powerpc/math-emu/fcmpu.c index d4fb1babc6ad..0f9bf4864832 100644 --- a/arch/powerpc/math-emu/fcmpu.c +++ b/arch/powerpc/math-emu/fcmpu.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fctiw.c b/arch/powerpc/math-emu/fctiw.c index f694440ddc00..716d6da7f204 100644 --- a/arch/powerpc/math-emu/fctiw.c +++ b/arch/powerpc/math-emu/fctiw.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fctiwz.c b/arch/powerpc/math-emu/fctiwz.c index 71e782fd4fe3..7212fa7cfd36 100644 --- a/arch/powerpc/math-emu/fctiwz.c +++ b/arch/powerpc/math-emu/fctiwz.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fdiv.c b/arch/powerpc/math-emu/fdiv.c index a29239c05e3e..e1e452069e49 100644 --- a/arch/powerpc/math-emu/fdiv.c +++ b/arch/powerpc/math-emu/fdiv.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fdivs.c b/arch/powerpc/math-emu/fdivs.c index 526bc261275f..5511e2d1c3ad 100644 --- a/arch/powerpc/math-emu/fdivs.c +++ b/arch/powerpc/math-emu/fdivs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fmadd.c b/arch/powerpc/math-emu/fmadd.c index 8c3f20aa5a95..2b6fae0bc8c2 100644 --- a/arch/powerpc/math-emu/fmadd.c +++ b/arch/powerpc/math-emu/fmadd.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fmadds.c b/arch/powerpc/math-emu/fmadds.c index 794fb31e59d1..aff35f24a236 100644 --- a/arch/powerpc/math-emu/fmadds.c +++ b/arch/powerpc/math-emu/fmadds.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fmr.c b/arch/powerpc/math-emu/fmr.c index bd55384b8196..f6347911f6a3 100644 --- a/arch/powerpc/math-emu/fmr.c +++ b/arch/powerpc/math-emu/fmr.c @@ -1,6 +1,6 @@ #include #include -#include +#include int fmr(u32 *frD, u32 *frB) diff --git a/arch/powerpc/math-emu/fmsub.c b/arch/powerpc/math-emu/fmsub.c index 626f6fed84ac..1fb26cebe04e 100644 --- a/arch/powerpc/math-emu/fmsub.c +++ b/arch/powerpc/math-emu/fmsub.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fmsubs.c b/arch/powerpc/math-emu/fmsubs.c index 3425bc899760..f73965453e05 100644 --- a/arch/powerpc/math-emu/fmsubs.c +++ b/arch/powerpc/math-emu/fmsubs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fmul.c b/arch/powerpc/math-emu/fmul.c index 2c1929779892..ffd31b549290 100644 --- a/arch/powerpc/math-emu/fmul.c +++ b/arch/powerpc/math-emu/fmul.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fmuls.c b/arch/powerpc/math-emu/fmuls.c index f5ad5c9c77d0..21aee431ca9d 100644 --- a/arch/powerpc/math-emu/fmuls.c +++ b/arch/powerpc/math-emu/fmuls.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fnabs.c b/arch/powerpc/math-emu/fnabs.c index a7d34f3d9499..af877a53d264 100644 --- a/arch/powerpc/math-emu/fnabs.c +++ b/arch/powerpc/math-emu/fnabs.c @@ -1,6 +1,6 @@ #include #include -#include +#include int fnabs(u32 *frD, u32 *frB) diff --git a/arch/powerpc/math-emu/fneg.c b/arch/powerpc/math-emu/fneg.c index 1e988cd9c6cc..8417d174758c 100644 --- a/arch/powerpc/math-emu/fneg.c +++ b/arch/powerpc/math-emu/fneg.c @@ -1,6 +1,6 @@ #include #include -#include +#include int fneg(u32 *frD, u32 *frB) diff --git a/arch/powerpc/math-emu/fnmadd.c b/arch/powerpc/math-emu/fnmadd.c index e817bc5453ef..6316ef0e0874 100644 --- a/arch/powerpc/math-emu/fnmadd.c +++ b/arch/powerpc/math-emu/fnmadd.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fnmadds.c b/arch/powerpc/math-emu/fnmadds.c index 4db4b7d9ba8d..9ffe037df2b9 100644 --- a/arch/powerpc/math-emu/fnmadds.c +++ b/arch/powerpc/math-emu/fnmadds.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fnmsub.c b/arch/powerpc/math-emu/fnmsub.c index f65979fa770e..f97a9cfb54ea 100644 --- a/arch/powerpc/math-emu/fnmsub.c +++ b/arch/powerpc/math-emu/fnmsub.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fnmsubs.c b/arch/powerpc/math-emu/fnmsubs.c index 9021dacc03b8..7fa1217bd930 100644 --- a/arch/powerpc/math-emu/fnmsubs.c +++ b/arch/powerpc/math-emu/fnmsubs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fre.c b/arch/powerpc/math-emu/fre.c index 49ccf2cc6a5a..b621a790aa67 100644 --- a/arch/powerpc/math-emu/fre.c +++ b/arch/powerpc/math-emu/fre.c @@ -1,6 +1,6 @@ #include #include -#include +#include int fre(void *frD, void *frB) { diff --git a/arch/powerpc/math-emu/fres.c b/arch/powerpc/math-emu/fres.c index 10ecbd08b79e..211c30d0145f 100644 --- a/arch/powerpc/math-emu/fres.c +++ b/arch/powerpc/math-emu/fres.c @@ -1,6 +1,6 @@ #include #include -#include +#include int fres(void *frD, void *frB) diff --git a/arch/powerpc/math-emu/frsp.c b/arch/powerpc/math-emu/frsp.c index ddcc14664b1a..3e3bc73e27ae 100644 --- a/arch/powerpc/math-emu/frsp.c +++ b/arch/powerpc/math-emu/frsp.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/frsqrte.c b/arch/powerpc/math-emu/frsqrte.c index 1d0a3a0fd0e6..7c2ce43750dc 100644 --- a/arch/powerpc/math-emu/frsqrte.c +++ b/arch/powerpc/math-emu/frsqrte.c @@ -1,6 +1,6 @@ #include #include -#include +#include int frsqrte(void *frD, void *frB) diff --git a/arch/powerpc/math-emu/frsqrtes.c b/arch/powerpc/math-emu/frsqrtes.c index 7e838e380314..269951a8c650 100644 --- a/arch/powerpc/math-emu/frsqrtes.c +++ b/arch/powerpc/math-emu/frsqrtes.c @@ -1,6 +1,6 @@ #include #include -#include +#include int frsqrtes(void *frD, void *frB) { diff --git a/arch/powerpc/math-emu/fsel.c b/arch/powerpc/math-emu/fsel.c index 1b0c14498032..32b62c6c7f48 100644 --- a/arch/powerpc/math-emu/fsel.c +++ b/arch/powerpc/math-emu/fsel.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fsqrt.c b/arch/powerpc/math-emu/fsqrt.c index a55fc7d49983..0e2a34b616dc 100644 --- a/arch/powerpc/math-emu/fsqrt.c +++ b/arch/powerpc/math-emu/fsqrt.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fsqrts.c b/arch/powerpc/math-emu/fsqrts.c index 31dccbfc39ff..420cf19b5fd4 100644 --- a/arch/powerpc/math-emu/fsqrts.c +++ b/arch/powerpc/math-emu/fsqrts.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fsub.c b/arch/powerpc/math-emu/fsub.c index 02c5dff458ba..feedd705cf62 100644 --- a/arch/powerpc/math-emu/fsub.c +++ b/arch/powerpc/math-emu/fsub.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/fsubs.c b/arch/powerpc/math-emu/fsubs.c index 5d9b18c35e07..74190514063e 100644 --- a/arch/powerpc/math-emu/fsubs.c +++ b/arch/powerpc/math-emu/fsubs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/lfd.c b/arch/powerpc/math-emu/lfd.c index 79ac76d596c3..d998a50740a0 100644 --- a/arch/powerpc/math-emu/lfd.c +++ b/arch/powerpc/math-emu/lfd.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/lfs.c b/arch/powerpc/math-emu/lfs.c index 434ed27be8db..1ee10b83d7e3 100644 --- a/arch/powerpc/math-emu/lfs.c +++ b/arch/powerpc/math-emu/lfs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/math.c b/arch/powerpc/math-emu/math.c index ab151f040502..76ee2e5dba65 100644 --- a/arch/powerpc/math-emu/math.c +++ b/arch/powerpc/math-emu/math.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/math_efp.c b/arch/powerpc/math-emu/math_efp.c index 28337c9709ae..581f404caa1d 100644 --- a/arch/powerpc/math-emu/math_efp.c +++ b/arch/powerpc/math-emu/math_efp.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #define FP_EX_BOOKE_E500_SPE diff --git a/arch/powerpc/math-emu/mcrfs.c b/arch/powerpc/math-emu/mcrfs.c index e948d5708e2b..8e8e72397ebc 100644 --- a/arch/powerpc/math-emu/mcrfs.c +++ b/arch/powerpc/math-emu/mcrfs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/mffs.c b/arch/powerpc/math-emu/mffs.c index 5526cf96ede5..e00fdc22a0bc 100644 --- a/arch/powerpc/math-emu/mffs.c +++ b/arch/powerpc/math-emu/mffs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/mtfsb0.c b/arch/powerpc/math-emu/mtfsb0.c index bc985585bca8..5ed3e7d5063e 100644 --- a/arch/powerpc/math-emu/mtfsb0.c +++ b/arch/powerpc/math-emu/mtfsb0.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/mtfsb1.c b/arch/powerpc/math-emu/mtfsb1.c index fe6ed5ac85b3..602aa16eda81 100644 --- a/arch/powerpc/math-emu/mtfsb1.c +++ b/arch/powerpc/math-emu/mtfsb1.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/mtfsf.c b/arch/powerpc/math-emu/mtfsf.c index 44b0fc8214f4..b0d5593ad357 100644 --- a/arch/powerpc/math-emu/mtfsf.c +++ b/arch/powerpc/math-emu/mtfsf.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/mtfsfi.c b/arch/powerpc/math-emu/mtfsfi.c index fd2acc26813b..5df30541a784 100644 --- a/arch/powerpc/math-emu/mtfsfi.c +++ b/arch/powerpc/math-emu/mtfsfi.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/math-emu/stfd.c b/arch/powerpc/math-emu/stfd.c index 33a165c8df0f..6baeaec134a2 100644 --- a/arch/powerpc/math-emu/stfd.c +++ b/arch/powerpc/math-emu/stfd.c @@ -1,6 +1,6 @@ #include #include -#include +#include int stfd(void *frS, void *ea) diff --git a/arch/powerpc/math-emu/stfiwx.c b/arch/powerpc/math-emu/stfiwx.c index f15a35f67e2c..9da7c5d1a872 100644 --- a/arch/powerpc/math-emu/stfiwx.c +++ b/arch/powerpc/math-emu/stfiwx.c @@ -1,6 +1,6 @@ #include #include -#include +#include int stfiwx(u32 *frS, void *ea) diff --git a/arch/powerpc/math-emu/stfs.c b/arch/powerpc/math-emu/stfs.c index 6122147356d1..62bd25264fb5 100644 --- a/arch/powerpc/math-emu/stfs.c +++ b/arch/powerpc/math-emu/stfs.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include diff --git a/arch/powerpc/mm/40x_mmu.c b/arch/powerpc/mm/40x_mmu.c index 31a5d42df8c9..61ac468c87c6 100644 --- a/arch/powerpc/mm/40x_mmu.c +++ b/arch/powerpc/mm/40x_mmu.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/mm/fsl_booke_mmu.c b/arch/powerpc/mm/fsl_booke_mmu.c index 139dec421e57..080d49b26c3a 100644 --- a/arch/powerpc/mm/fsl_booke_mmu.c +++ b/arch/powerpc/mm/fsl_booke_mmu.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c index 8410b4bb36ed..80334937e14f 100644 --- a/arch/powerpc/mm/hash_utils_64.c +++ b/arch/powerpc/mm/hash_utils_64.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/mm/init_64.c b/arch/powerpc/mm/init_64.c index a000c3585390..93abf8a9813d 100644 --- a/arch/powerpc/mm/init_64.c +++ b/arch/powerpc/mm/init_64.c @@ -51,7 +51,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c index d5543514c1df..5c096c01e8bd 100644 --- a/arch/powerpc/mm/subpage-prot.c +++ b/arch/powerpc/mm/subpage-prot.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include /* diff --git a/arch/powerpc/platforms/cell/spufs/coredump.c b/arch/powerpc/platforms/cell/spufs/coredump.c index 85c85eb3e245..e5a891ae80ee 100644 --- a/arch/powerpc/platforms/cell/spufs/coredump.c +++ b/arch/powerpc/platforms/cell/spufs/coredump.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include "spufs.h" diff --git a/arch/powerpc/platforms/cell/spufs/file.c b/arch/powerpc/platforms/cell/spufs/file.c index 3a147122bc98..a35e2c29d7ee 100644 --- a/arch/powerpc/platforms/cell/spufs/file.c +++ b/arch/powerpc/platforms/cell/spufs/file.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include "spufs.h" #include "sputrace.h" diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c index 5364d4a54249..d8af9bc0489f 100644 --- a/arch/powerpc/platforms/cell/spufs/inode.c +++ b/arch/powerpc/platforms/cell/spufs/inode.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "spufs.h" diff --git a/arch/powerpc/platforms/cell/spufs/syscalls.c b/arch/powerpc/platforms/cell/spufs/syscalls.c index a87200a535fa..0d290ea83dc1 100644 --- a/arch/powerpc/platforms/cell/spufs/syscalls.c +++ b/arch/powerpc/platforms/cell/spufs/syscalls.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include "spufs.h" diff --git a/arch/powerpc/platforms/chrp/nvram.c b/arch/powerpc/platforms/chrp/nvram.c index 9ef8cc3378d0..c3ede2c365c3 100644 --- a/arch/powerpc/platforms/chrp/nvram.c +++ b/arch/powerpc/platforms/chrp/nvram.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/powernv/opal-elog.c b/arch/powerpc/platforms/powernv/opal-elog.c index f2344cbd2f46..ecd6d9177d13 100644 --- a/arch/powerpc/platforms/powernv/opal-elog.c +++ b/arch/powerpc/platforms/powernv/opal-elog.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include struct elog_obj { diff --git a/arch/powerpc/platforms/powernv/opal-lpc.c b/arch/powerpc/platforms/powernv/opal-lpc.c index e4169d68cb32..4886eb8b6381 100644 --- a/arch/powerpc/platforms/powernv/opal-lpc.c +++ b/arch/powerpc/platforms/powernv/opal-lpc.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include static int opal_lpc_chip_id = -1; diff --git a/arch/powerpc/platforms/powernv/opal-prd.c b/arch/powerpc/platforms/powernv/opal-prd.c index e315e704cca7..2d6ee1c5ad85 100644 --- a/arch/powerpc/platforms/powernv/opal-prd.c +++ b/arch/powerpc/platforms/powernv/opal-prd.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include /** diff --git a/arch/powerpc/platforms/pseries/cmm.c b/arch/powerpc/platforms/pseries/cmm.c index 972328829387..4839db385bb0 100644 --- a/arch/powerpc/platforms/pseries/cmm.c +++ b/arch/powerpc/platforms/pseries/cmm.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index 76caa4a45ccd..5cb2e4beffc5 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include static struct workqueue_struct *pseries_hp_wq; diff --git a/arch/powerpc/platforms/pseries/dtl.c b/arch/powerpc/platforms/pseries/dtl.c index 39049e4884fb..6b04e3f0f982 100644 --- a/arch/powerpc/platforms/pseries/dtl.c +++ b/arch/powerpc/platforms/pseries/dtl.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/lparcfg.c b/arch/powerpc/platforms/pseries/lparcfg.c index e6397976060e..779fc2a1c8f7 100644 --- a/arch/powerpc/platforms/pseries/lparcfg.c +++ b/arch/powerpc/platforms/pseries/lparcfg.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index 79aef8c1c5b3..69cedc1b3b8a 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index cc66c49f07aa..e5bf1e84047f 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include "of_helpers.h" diff --git a/arch/powerpc/platforms/pseries/scanlog.c b/arch/powerpc/platforms/pseries/scanlog.c index 7d28cabf1206..c47585a78b69 100644 --- a/arch/powerpc/platforms/pseries/scanlog.c +++ b/arch/powerpc/platforms/pseries/scanlog.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/powerpc/sysdev/scom.c b/arch/powerpc/sysdev/scom.c index 6f5a8d177c42..d0e9f178a324 100644 --- a/arch/powerpc/sysdev/scom.c +++ b/arch/powerpc/sysdev/scom.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include const struct scom_controller *scom_controller; EXPORT_SYMBOL_GPL(scom_controller); diff --git a/arch/powerpc/sysdev/tsi108_pci.c b/arch/powerpc/sysdev/tsi108_pci.c index 53a16aa4d384..5692dd569b9b 100644 --- a/arch/powerpc/sysdev/tsi108_pci.c +++ b/arch/powerpc/sysdev/tsi108_pci.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/appldata/appldata_base.c b/arch/s390/appldata/appldata_base.c index f587c4811faf..5a8dfa22da7c 100644 --- a/arch/s390/appldata/appldata_base.c +++ b/arch/s390/appldata/appldata_base.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index 4da604ebf6fd..8515dd5a5663 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -6,7 +6,7 @@ * Author(s): Martin Schwidefsky */ -#include +#include #include #include #include diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c index 1113389d0a39..daf9bb063aaa 100644 --- a/arch/s390/crypto/prng.c +++ b/arch/s390/crypto/prng.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/s390/include/asm/checksum.h b/arch/s390/include/asm/checksum.h index d7f100c53f07..12bf4fef2a68 100644 --- a/arch/s390/include/asm/checksum.h +++ b/arch/s390/include/asm/checksum.h @@ -11,7 +11,7 @@ #ifndef _S390_CHECKSUM_H #define _S390_CHECKSUM_H -#include +#include /* * computes the checksum of a memory block at buff, length len, diff --git a/arch/s390/include/asm/idals.h b/arch/s390/include/asm/idals.h index a7b2d7504049..280b60a0bcd4 100644 --- a/arch/s390/include/asm/idals.h +++ b/arch/s390/include/asm/idals.h @@ -17,7 +17,7 @@ #include #include #include -#include +#include #define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */ #define IDA_BLOCK_SIZE (1L< -#include +#include #include #include diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c index 0f9cd90c11af..96df4547377a 100644 --- a/arch/s390/kernel/compat_linux.c +++ b/arch/s390/kernel/compat_linux.c @@ -51,7 +51,7 @@ #include #include -#include +#include #include #include diff --git a/arch/s390/kernel/compat_signal.c b/arch/s390/kernel/compat_signal.c index 6f2a6ab13cb5..362350cc485c 100644 --- a/arch/s390/kernel/compat_signal.c +++ b/arch/s390/kernel/compat_signal.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include "compat_linux.h" diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c index aa12de72fd47..79f8ae933520 100644 --- a/arch/s390/kernel/debug.c +++ b/arch/s390/kernel/debug.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/dis.c b/arch/s390/kernel/dis.c index c74c59236f44..9f017cf417f6 100644 --- a/arch/s390/kernel/dis.c +++ b/arch/s390/kernel/dis.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index fdb40424acfe..84e0557b16fe 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include DEFINE_PER_CPU(struct kprobe *, current_kprobe); diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c index b81ab8882e2e..7447ba509c30 100644 --- a/arch/s390/kernel/ptrace.c +++ b/arch/s390/kernel/ptrace.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include "entry.h" diff --git a/arch/s390/kernel/signal.c b/arch/s390/kernel/signal.c index 9f241d1efeda..62a4c263e887 100644 --- a/arch/s390/kernel/signal.c +++ b/arch/s390/kernel/signal.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include "entry.h" diff --git a/arch/s390/kernel/sys_s390.c b/arch/s390/kernel/sys_s390.c index f145490cce54..b7af452978ca 100644 --- a/arch/s390/kernel/sys_s390.c +++ b/arch/s390/kernel/sys_s390.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "entry.h" /* diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 867d0a057046..ec76315c9ee5 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index d0539f76fd24..283ad7840335 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include "entry.h" diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c index af13f1a135b6..6843dd5a1cba 100644 --- a/arch/s390/kvm/interrupt.c +++ b/arch/s390/kvm/interrupt.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index b3e9d18f2ec6..b67454ad8408 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/score/include/asm/checksum.h b/arch/score/include/asm/checksum.h index 539d9fd45d21..0338927f4826 100644 --- a/arch/score/include/asm/checksum.h +++ b/arch/score/include/asm/checksum.h @@ -2,7 +2,7 @@ #define _ASM_SCORE_CHECKSUM_H #include -#include +#include /* * computes the checksum of a memory block at buff, length len, diff --git a/arch/score/kernel/ptrace.c b/arch/score/kernel/ptrace.c index 4f7314d5f334..8b75e54816c1 100644 --- a/arch/score/kernel/ptrace.c +++ b/arch/score/kernel/ptrace.c @@ -29,7 +29,7 @@ #include #include -#include +#include /* * retrieve the contents of SCORE userspace general registers diff --git a/arch/score/kernel/traps.c b/arch/score/kernel/traps.c index 5cea1e750cec..d948a6818961 100644 --- a/arch/score/kernel/traps.c +++ b/arch/score/kernel/traps.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include unsigned long exception_handlers[32]; diff --git a/arch/score/lib/checksum_copy.c b/arch/score/lib/checksum_copy.c index 9b770b30e8a5..39b99ef61804 100644 --- a/arch/score/lib/checksum_copy.c +++ b/arch/score/lib/checksum_copy.c @@ -25,7 +25,7 @@ #include -#include +#include unsigned int csum_partial_copy(const char *src, char *dst, int len, unsigned int sum) diff --git a/arch/sh/boards/mach-landisk/gio.c b/arch/sh/boards/mach-landisk/gio.c index 8132dff078fb..32c317f5d991 100644 --- a/arch/sh/boards/mach-landisk/gio.c +++ b/arch/sh/boards/mach-landisk/gio.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/boot/compressed/misc.c b/arch/sh/boot/compressed/misc.c index 208a9753ab38..ae1dfdb0013b 100644 --- a/arch/sh/boot/compressed/misc.c +++ b/arch/sh/boot/compressed/misc.c @@ -11,7 +11,7 @@ * Modified to use standard LinuxSH BIOS by Greg Banks 7Jul2000 */ -#include +#include #include #include diff --git a/arch/sh/include/asm/mmu_context.h b/arch/sh/include/asm/mmu_context.h index 9f417feaf6e8..35ffdd081d26 100644 --- a/arch/sh/include/asm/mmu_context.h +++ b/arch/sh/include/asm/mmu_context.h @@ -10,7 +10,7 @@ #ifdef __KERNEL__ #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/cpu/init.c b/arch/sh/kernel/cpu/init.c index c8b3be1b54e6..c4f01c5c8736 100644 --- a/arch/sh/kernel/cpu/init.c +++ b/arch/sh/kernel/cpu/init.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c index 53b8eeb1db20..c32e66079f7c 100644 --- a/arch/sh/kernel/cpu/shmobile/cpuidle.c +++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include static unsigned long cpuidle_mode[] = { SUSP_SH_SLEEP, /* regular sleep mode */ diff --git a/arch/sh/kernel/cpu/shmobile/pm.c b/arch/sh/kernel/cpu/shmobile/pm.c index ac37b7234f85..fba2be5d72e9 100644 --- a/arch/sh/kernel/cpu/shmobile/pm.c +++ b/arch/sh/kernel/cpu/shmobile/pm.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/crash_dump.c b/arch/sh/kernel/crash_dump.c index 569e7b171c01..b33be505361e 100644 --- a/arch/sh/kernel/crash_dump.c +++ b/arch/sh/kernel/crash_dump.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include /** * copy_oldmem_page - copy one page from "oldmem" diff --git a/arch/sh/kernel/io_trapped.c b/arch/sh/kernel/io_trapped.c index f8ce36286cea..4d4e7a2a774b 100644 --- a/arch/sh/kernel/io_trapped.c +++ b/arch/sh/kernel/io_trapped.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c index 6c0378c0b8b5..bc3591125df7 100644 --- a/arch/sh/kernel/irq.c +++ b/arch/sh/kernel/irq.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/kprobes.c b/arch/sh/kernel/kprobes.c index 83acbf3f6de8..1653ff64b103 100644 --- a/arch/sh/kernel/kprobes.c +++ b/arch/sh/kernel/kprobes.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); diff --git a/arch/sh/kernel/process_32.c b/arch/sh/kernel/process_32.c index ee12e9451874..51741850a715 100644 --- a/arch/sh/kernel/process_32.c +++ b/arch/sh/kernel/process_32.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/process_64.c b/arch/sh/kernel/process_64.c index 9d3e9916555d..e0b271bffd6a 100644 --- a/arch/sh/kernel/process_64.c +++ b/arch/sh/kernel/process_64.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/ptrace_32.c b/arch/sh/kernel/ptrace_32.c index c1a6b89bfe70..1aabfd356b35 100644 --- a/arch/sh/kernel/ptrace_32.c +++ b/arch/sh/kernel/ptrace_32.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/ptrace_64.c b/arch/sh/kernel/ptrace_64.c index 5cea973a65b2..c49d0d05a215 100644 --- a/arch/sh/kernel/ptrace_64.c +++ b/arch/sh/kernel/ptrace_64.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/setup.c b/arch/sh/kernel/setup.c index e7b49d81053e..3a44c753b642 100644 --- a/arch/sh/kernel/setup.c +++ b/arch/sh/kernel/setup.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/sh_ksyms_64.c b/arch/sh/kernel/sh_ksyms_64.c index 26a0774f5272..6ee3740e009e 100644 --- a/arch/sh/kernel/sh_ksyms_64.c +++ b/arch/sh/kernel/sh_ksyms_64.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/signal_32.c b/arch/sh/kernel/signal_32.c index f7c3d5c25caf..5128d3001ee5 100644 --- a/arch/sh/kernel/signal_32.c +++ b/arch/sh/kernel/signal_32.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/signal_64.c b/arch/sh/kernel/signal_64.c index d8a3f0d22809..7b77f1812434 100644 --- a/arch/sh/kernel/signal_64.c +++ b/arch/sh/kernel/signal_64.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/sys_sh.c b/arch/sh/kernel/sys_sh.c index 8c6a350df751..6576e5ee1fc3 100644 --- a/arch/sh/kernel/sys_sh.c +++ b/arch/sh/kernel/sys_sh.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/kernel/sys_sh32.c b/arch/sh/kernel/sys_sh32.c index b66d1c62eb19..d5287d76809c 100644 --- a/arch/sh/kernel/sys_sh32.c +++ b/arch/sh/kernel/sys_sh32.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/kernel/traps_64.c b/arch/sh/kernel/traps_64.c index d208c27ccc67..00835edb6e20 100644 --- a/arch/sh/kernel/traps_64.c +++ b/arch/sh/kernel/traps_64.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/math-emu/math.c b/arch/sh/math-emu/math.c index 04aa55fa8c75..5078cb809750 100644 --- a/arch/sh/math-emu/math.c +++ b/arch/sh/math-emu/math.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include #include diff --git a/arch/sh/mm/cache-debugfs.c b/arch/sh/mm/cache-debugfs.c index 777e50f33c00..4eb9d43578b4 100644 --- a/arch/sh/mm/cache-debugfs.c +++ b/arch/sh/mm/cache-debugfs.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/mm/cache-sh3.c b/arch/sh/mm/cache-sh3.c index e37523f65195..031634f273fa 100644 --- a/arch/sh/mm/cache-sh3.c +++ b/arch/sh/mm/cache-sh3.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/mm/cache-sh5.c b/arch/sh/mm/cache-sh5.c index d1bffbcd9d52..d94dadedf74f 100644 --- a/arch/sh/mm/cache-sh5.c +++ b/arch/sh/mm/cache-sh5.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include extern void __weak sh4__flush_region_init(void); diff --git a/arch/sh/mm/cache-sh7705.c b/arch/sh/mm/cache-sh7705.c index 7729cca727eb..6cd2aa395817 100644 --- a/arch/sh/mm/cache-sh7705.c +++ b/arch/sh/mm/cache-sh7705.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/mm/extable_32.c b/arch/sh/mm/extable_32.c index c1cf4463d09d..9cfcbb5848e4 100644 --- a/arch/sh/mm/extable_32.c +++ b/arch/sh/mm/extable_32.c @@ -5,7 +5,7 @@ */ #include -#include +#include int fixup_exception(struct pt_regs *regs) { diff --git a/arch/sh/mm/extable_64.c b/arch/sh/mm/extable_64.c index f05499688d88..96edaff8c983 100644 --- a/arch/sh/mm/extable_64.c +++ b/arch/sh/mm/extable_64.c @@ -12,7 +12,7 @@ */ #include #include -#include +#include extern unsigned long copy_user_memcpy, copy_user_memcpy_end; extern void __copy_user_fixup(void); diff --git a/arch/sh/mm/nommu.c b/arch/sh/mm/nommu.c index 36312d254faf..82f8197b93f6 100644 --- a/arch/sh/mm/nommu.c +++ b/arch/sh/mm/nommu.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include /* * Nothing too terribly exciting here .. diff --git a/arch/sh/mm/pmb.c b/arch/sh/mm/pmb.c index 7160c9fd6fe3..7b2cc490ebb7 100644 --- a/arch/sh/mm/pmb.c +++ b/arch/sh/mm/pmb.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sh/mm/tlb-sh3.c b/arch/sh/mm/tlb-sh3.c index 6554fb439f0e..5c66665bff8b 100644 --- a/arch/sh/mm/tlb-sh3.c +++ b/arch/sh/mm/tlb-sh3.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sh/mm/tlbex_64.c b/arch/sh/mm/tlbex_64.c index 8557548fc53e..8ff966dd0c74 100644 --- a/arch/sh/mm/tlbex_64.c +++ b/arch/sh/mm/tlbex_64.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/mm/tlbflush_64.c b/arch/sh/mm/tlbflush_64.c index f33fdd2558e8..bd0715d5dca4 100644 --- a/arch/sh/mm/tlbflush_64.c +++ b/arch/sh/mm/tlbflush_64.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sh/oprofile/backtrace.c b/arch/sh/oprofile/backtrace.c index 9c88dcd56e86..c7695f99c8c3 100644 --- a/arch/sh/oprofile/backtrace.c +++ b/arch/sh/oprofile/backtrace.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sparc/include/asm/checksum_32.h b/arch/sparc/include/asm/checksum_32.h index eff748c871ec..e25af5fc99fd 100644 --- a/arch/sparc/include/asm/checksum_32.h +++ b/arch/sparc/include/asm/checksum_32.h @@ -16,7 +16,7 @@ */ #include -#include +#include /* computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) diff --git a/arch/sparc/include/asm/checksum_64.h b/arch/sparc/include/asm/checksum_64.h index 0395d75322e9..96a5ed58cea6 100644 --- a/arch/sparc/include/asm/checksum_64.h +++ b/arch/sparc/include/asm/checksum_64.h @@ -16,7 +16,7 @@ */ #include -#include +#include /* computes the checksum of a memory block at buff, length len, * and adds in "sum" (32-bit) diff --git a/arch/sparc/kernel/apc.c b/arch/sparc/kernel/apc.c index 742f6c4436bf..9ebc37e7d64c 100644 --- a/arch/sparc/kernel/apc.c +++ b/arch/sparc/kernel/apc.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/irq_64.c b/arch/sparc/kernel/irq_64.c index 34a7930b76ef..3bebf395252c 100644 --- a/arch/sparc/kernel/irq_64.c +++ b/arch/sparc/kernel/irq_64.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/kprobes.c b/arch/sparc/kernel/kprobes.c index b0377db12d83..2d13a4fc0384 100644 --- a/arch/sparc/kernel/kprobes.c +++ b/arch/sparc/kernel/kprobes.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include /* We do not have hardware single-stepping on sparc64. * So we implement software single-stepping with breakpoint diff --git a/arch/sparc/kernel/mdesc.c b/arch/sparc/kernel/mdesc.c index 8a6982dfd733..c0765bbf60ea 100644 --- a/arch/sparc/kernel/mdesc.c +++ b/arch/sparc/kernel/mdesc.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 9c1878f4fa9f..015e55a7495d 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/pcic.c b/arch/sparc/kernel/pcic.c index 24384e1dc33d..a38787b84322 100644 --- a/arch/sparc/kernel/pcic.c +++ b/arch/sparc/kernel/pcic.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include "kernel.h" diff --git a/arch/sparc/kernel/pmc.c b/arch/sparc/kernel/pmc.c index 97d123107ecb..f12b23f7b515 100644 --- a/arch/sparc/kernel/pmc.c +++ b/arch/sparc/kernel/pmc.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/arch/sparc/kernel/process_32.c b/arch/sparc/kernel/process_32.c index b7780a5bef11..48ffc3e7d1dd 100644 --- a/arch/sparc/kernel/process_32.c +++ b/arch/sparc/kernel/process_32.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/process_64.c b/arch/sparc/kernel/process_64.c index 47ff5588e521..d249ca10b203 100644 --- a/arch/sparc/kernel/process_64.c +++ b/arch/sparc/kernel/process_64.c @@ -33,7 +33,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/ptrace_32.c b/arch/sparc/kernel/ptrace_32.c index a331fdc11a2c..eca3dc76793c 100644 --- a/arch/sparc/kernel/ptrace_32.c +++ b/arch/sparc/kernel/ptrace_32.c @@ -23,7 +23,7 @@ #include #include -#include +#include #include #include "kernel.h" diff --git a/arch/sparc/kernel/ptrace_64.c b/arch/sparc/kernel/ptrace_64.c index 96494b2ef41f..901063c1cf7e 100644 --- a/arch/sparc/kernel/ptrace_64.c +++ b/arch/sparc/kernel/ptrace_64.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/signal32.c b/arch/sparc/kernel/signal32.c index 91cc2f4ae4d9..b4096bb665b2 100644 --- a/arch/sparc/kernel/signal32.c +++ b/arch/sparc/kernel/signal32.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 9c0c8fd0b292..62c3e255ae7c 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/signal_64.c b/arch/sparc/kernel/signal_64.c index c782c9b716db..965d50e833e7 100644 --- a/arch/sparc/kernel/signal_64.c +++ b/arch/sparc/kernel/signal_64.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/smp_64.c b/arch/sparc/kernel/smp_64.c index 8182f7caf5b1..0ce347f8e4cc 100644 --- a/arch/sparc/kernel/smp_64.c +++ b/arch/sparc/kernel/smp_64.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/sys_sparc32.c b/arch/sparc/kernel/sys_sparc32.c index 022c30c72ebd..bca44f3e6b86 100644 --- a/arch/sparc/kernel/sys_sparc32.c +++ b/arch/sparc/kernel/sys_sparc32.c @@ -44,7 +44,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/sys_sparc_32.c b/arch/sparc/kernel/sys_sparc_32.c index 646988d4c1a3..fb7b185ee941 100644 --- a/arch/sparc/kernel/sys_sparc_32.c +++ b/arch/sparc/kernel/sys_sparc_32.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include "systbls.h" diff --git a/arch/sparc/kernel/sys_sparc_64.c b/arch/sparc/kernel/sys_sparc_64.c index fe8b8ee8e660..884c70331345 100644 --- a/arch/sparc/kernel/sys_sparc_64.c +++ b/arch/sparc/kernel/sys_sparc_64.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include diff --git a/arch/sparc/kernel/time_64.c b/arch/sparc/kernel/time_64.c index c69b21e51efc..807f7e2ce014 100644 --- a/arch/sparc/kernel/time_64.c +++ b/arch/sparc/kernel/time_64.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include "entry.h" diff --git a/arch/sparc/kernel/traps_64.c b/arch/sparc/kernel/traps_64.c index 496fa926e1e0..4bc10e44d1ca 100644 --- a/arch/sparc/kernel/traps_64.c +++ b/arch/sparc/kernel/traps_64.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/unaligned_32.c b/arch/sparc/kernel/unaligned_32.c index 32b61d1b6379..d20d4e3fd129 100644 --- a/arch/sparc/kernel/unaligned_32.c +++ b/arch/sparc/kernel/unaligned_32.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/sparc/kernel/unaligned_64.c b/arch/sparc/kernel/unaligned_64.c index 52c00d90d4b4..cda7fd367c4f 100644 --- a/arch/sparc/kernel/unaligned_64.c +++ b/arch/sparc/kernel/unaligned_64.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/sparc/kernel/uprobes.c b/arch/sparc/kernel/uprobes.c index b68314050602..d852ae56ddc1 100644 --- a/arch/sparc/kernel/uprobes.c +++ b/arch/sparc/kernel/uprobes.c @@ -29,7 +29,7 @@ #include #include -#include +#include /* Compute the address of the breakpoint instruction and return it. * diff --git a/arch/sparc/kernel/visemul.c b/arch/sparc/kernel/visemul.c index c096c624ac4d..c4ac58e483a4 100644 --- a/arch/sparc/kernel/visemul.c +++ b/arch/sparc/kernel/visemul.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include /* OPF field of various VIS instructions. */ diff --git a/arch/sparc/kernel/windows.c b/arch/sparc/kernel/windows.c index 87bab0a3857a..435a467b0595 100644 --- a/arch/sparc/kernel/windows.c +++ b/arch/sparc/kernel/windows.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include "kernel.h" diff --git a/arch/sparc/math-emu/math_32.c b/arch/sparc/math-emu/math_32.c index 5ce8f2f64604..4d7e0fff054f 100644 --- a/arch/sparc/math-emu/math_32.c +++ b/arch/sparc/math-emu/math_32.c @@ -68,7 +68,7 @@ #include #include #include -#include +#include #include "sfp-util_32.h" #include diff --git a/arch/sparc/math-emu/math_64.c b/arch/sparc/math-emu/math_64.c index 034aadbff036..9647051853d3 100644 --- a/arch/sparc/math-emu/math_64.c +++ b/arch/sparc/math-emu/math_64.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include "sfp-util_64.h" diff --git a/arch/sparc/mm/extable.c b/arch/sparc/mm/extable.c index a61c349448e1..768a11e6bd4f 100644 --- a/arch/sparc/mm/extable.c +++ b/arch/sparc/mm/extable.c @@ -3,7 +3,7 @@ */ #include -#include +#include void sort_extable(struct exception_table_entry *start, struct exception_table_entry *finish) diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c index 37aa537b3ad8..5d2f91511c60 100644 --- a/arch/sparc/mm/init_64.c +++ b/arch/sparc/mm/init_64.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c index 9f37106ef93a..c84c54a1ac55 100644 --- a/arch/tile/kernel/process.c +++ b/arch/tile/kernel/process.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #ifdef CONFIG_HARDWALL #include #endif diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 862973074bf9..de3eae813e52 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/tile/kernel/unaligned.c b/arch/tile/kernel/unaligned.c index 4fe78c5b8394..f229e979584e 100644 --- a/arch/tile/kernel/unaligned.c +++ b/arch/tile/kernel/unaligned.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/um/drivers/harddog_kern.c b/arch/um/drivers/harddog_kern.c index 3282787bbcfb..6d381279b362 100644 --- a/arch/um/drivers/harddog_kern.c +++ b/arch/um/drivers/harddog_kern.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include "mconsole.h" MODULE_LICENSE("GPL"); diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c index 3a4b58730f5f..12bdb5996bf5 100644 --- a/arch/um/drivers/hostaudio_kern.c +++ b/arch/um/drivers/hostaudio_kern.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c index 8a6b57108ac2..8a4c72af3bc0 100644 --- a/arch/um/drivers/mconsole_kern.c +++ b/arch/um/drivers/mconsole_kern.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c index 62145c276167..3645fcb2a787 100644 --- a/arch/um/drivers/mmapper_kern.c +++ b/arch/um/drivers/mmapper_kern.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include /* These are set in mmapper_init, which is called at boot time */ diff --git a/arch/um/drivers/random.c b/arch/um/drivers/random.c index dd16c902ff70..05523f14d7b2 100644 --- a/arch/um/drivers/random.c +++ b/arch/um/drivers/random.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/um/kernel/exec.c b/arch/um/kernel/exec.c index 0d7103c9eff3..770ec07b6a6a 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c index 41ebbfebb333..546302e3b7fb 100644 --- a/arch/um/kernel/exitcode.c +++ b/arch/um/kernel/exitcode.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include /* * If read and write race, the read will still atomically read a valid diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index 034b42c7ab40..078630d6448c 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 6a826cbb15c4..bc2a516c190f 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include void user_enable_single_step(struct task_struct *child) diff --git a/arch/um/kernel/syscall.c b/arch/um/kernel/syscall.c index c1d0ae069b53..6258676bed85 100644 --- a/arch/um/kernel/syscall.c +++ b/arch/um/kernel/syscall.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include long old_mmap(unsigned long addr, unsigned long len, diff --git a/arch/x86/entry/common.c b/arch/x86/entry/common.c index bdd9cc59d20f..b83c61cfd154 100644 --- a/arch/x86/entry/common.c +++ b/arch/x86/entry/common.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #define CREATE_TRACE_POINTS diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c index cb26f18d43af..7c0a711989d2 100644 --- a/arch/x86/ia32/ia32_aout.c +++ b/arch/x86/ia32/ia32_aout.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/ia32/ia32_signal.c b/arch/x86/ia32/ia32_signal.c index cb13c0564ea7..95c0b4ae09b0 100644 --- a/arch/x86/ia32/ia32_signal.c +++ b/arch/x86/ia32/ia32_signal.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/ia32/sys_ia32.c b/arch/x86/ia32/sys_ia32.c index 719cd702b0a4..47956c6a4fd8 100644 --- a/arch/x86/ia32/sys_ia32.c +++ b/arch/x86/ia32/sys_ia32.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/include/asm/asm-prototypes.h b/arch/x86/include/asm/asm-prototypes.h index 44b8762fa0c7..830b19dbfa31 100644 --- a/arch/x86/include/asm/asm-prototypes.h +++ b/arch/x86/include/asm/asm-prototypes.h @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include diff --git a/arch/x86/include/asm/checksum_64.h b/arch/x86/include/asm/checksum_64.h index c020ee75dce7..08e7efb2c140 100644 --- a/arch/x86/include/asm/checksum_64.h +++ b/arch/x86/include/asm/checksum_64.h @@ -8,7 +8,7 @@ */ #include -#include +#include #include /** diff --git a/arch/x86/include/asm/xen/page.h b/arch/x86/include/asm/xen/page.h index f5fb840b43e8..33cbd3db97b9 100644 --- a/arch/x86/include/asm/xen/page.h +++ b/arch/x86/include/asm/xen/page.h @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 643818a7688b..45d44c173cf9 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c @@ -234,7 +234,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c index c7efbcfbeda6..87cc9ab7a13c 100644 --- a/arch/x86/kernel/cpu/mcheck/mce-severity.c +++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include "mce-internal.h" diff --git a/arch/x86/kernel/crash_dump_32.c b/arch/x86/kernel/crash_dump_32.c index 11891ca7b716..538fedea9b3f 100644 --- a/arch/x86/kernel/crash_dump_32.c +++ b/arch/x86/kernel/crash_dump_32.c @@ -10,7 +10,7 @@ #include #include -#include +#include static void *kdump_buf_page; diff --git a/arch/x86/kernel/doublefault.c b/arch/x86/kernel/doublefault.c index f6dfd9334b67..b2f7207ba86c 100644 --- a/arch/x86/kernel/doublefault.c +++ b/arch/x86/kernel/doublefault.c @@ -3,7 +3,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c index d9d8d16b69db..eb3509338ae0 100644 --- a/arch/x86/kernel/kprobes/core.c +++ b/arch/x86/kernel/kprobes/core.c @@ -56,7 +56,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 3bb4c5f021f6..3d1bee9d6a72 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 37363e46b1f0..b615a1113f58 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 0e63c0267f99..9cc7d5a330ef 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c index 27538f183c3b..a3b875c9e6af 100644 --- a/arch/x86/kernel/test_nx.c +++ b/arch/x86/kernel/test_nx.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include extern int rodata_test_data; diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c index 9692a5e9fdab..6c8934406dc9 100644 --- a/arch/x86/kernel/tls.c +++ b/arch/x86/kernel/tls.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 01f30e56f99e..ec5d7545e6dc 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -47,7 +47,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c index 0b281217c890..1f65ff6540f0 100644 --- a/arch/x86/lib/usercopy_32.c +++ b/arch/x86/lib/usercopy_32.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include diff --git a/arch/x86/math-emu/errors.c b/arch/x86/math-emu/errors.c index 9e6545f269e5..2ccc424a57d9 100644 --- a/arch/x86/math-emu/errors.c +++ b/arch/x86/math-emu/errors.c @@ -19,7 +19,7 @@ #include -#include +#include #include "fpu_emu.h" #include "fpu_system.h" diff --git a/arch/x86/math-emu/fpu_entry.c b/arch/x86/math-emu/fpu_entry.c index e945fedf1de2..0203baefb5c0 100644 --- a/arch/x86/math-emu/fpu_entry.c +++ b/arch/x86/math-emu/fpu_entry.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/math-emu/get_address.c b/arch/x86/math-emu/get_address.c index 8db26591d91a..b8ef9f9d2ffc 100644 --- a/arch/x86/math-emu/get_address.c +++ b/arch/x86/math-emu/get_address.c @@ -19,7 +19,7 @@ #include -#include +#include #include #include "fpu_system.h" diff --git a/arch/x86/math-emu/load_store.c b/arch/x86/math-emu/load_store.c index 95228ff042c0..1643054766eb 100644 --- a/arch/x86/math-emu/load_store.c +++ b/arch/x86/math-emu/load_store.c @@ -18,7 +18,7 @@ | other processes using the emulator while swapping is in progress. | +---------------------------------------------------------------------------*/ -#include +#include #include "fpu_system.h" #include "exception.h" diff --git a/arch/x86/math-emu/reg_ld_str.c b/arch/x86/math-emu/reg_ld_str.c index d597fe7423c9..2c98965a60ba 100644 --- a/arch/x86/math-emu/reg_ld_str.c +++ b/arch/x86/math-emu/reg_ld_str.c @@ -19,7 +19,7 @@ #include "fpu_emu.h" -#include +#include #include "fpu_system.h" #include "exception.h" diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c index fcd06f7526de..61a7e9ea9aa1 100644 --- a/arch/x86/mm/extable.c +++ b/arch/x86/mm/extable.c @@ -1,5 +1,5 @@ #include -#include +#include #include #include diff --git a/arch/x86/mm/init_32.c b/arch/x86/mm/init_32.c index cf8059016ec8..928d657de829 100644 --- a/arch/x86/mm/init_32.c +++ b/arch/x86/mm/init_32.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c index 963895f9af7f..af85b686a7b0 100644 --- a/arch/x86/mm/init_64.c +++ b/arch/x86/mm/init_64.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index e3353c97d086..5a287e523eab 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/um/ptrace_32.c b/arch/x86/um/ptrace_32.c index 60a5a5a85505..2497bac56066 100644 --- a/arch/x86/um/ptrace_32.c +++ b/arch/x86/um/ptrace_32.c @@ -5,7 +5,7 @@ #include #include -#include +#include #include #include diff --git a/arch/x86/um/ptrace_64.c b/arch/x86/um/ptrace_64.c index e30202b1716e..a5c9910d234f 100644 --- a/arch/x86/um/ptrace_64.c +++ b/arch/x86/um/ptrace_64.c @@ -10,7 +10,7 @@ #include #define __FRAME_OFFSETS #include -#include +#include #include /* diff --git a/arch/x86/um/signal.c b/arch/x86/um/signal.c index 49e503697022..727ed442e0a5 100644 --- a/arch/x86/um/signal.c +++ b/arch/x86/um/signal.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/um/tls_32.c b/arch/x86/um/tls_32.c index 48e38584d5c1..5bd949da7a4a 100644 --- a/arch/x86/um/tls_32.c +++ b/arch/x86/um/tls_32.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/x86/xen/p2m.c b/arch/x86/xen/p2m.c index 37129db76d33..276da636dd39 100644 --- a/arch/x86/xen/p2m.c +++ b/arch/x86/xen/p2m.c @@ -71,7 +71,7 @@ #include #include -#include +#include #include #include diff --git a/arch/xtensa/include/asm/checksum.h b/arch/xtensa/include/asm/checksum.h index ec35074fcb03..3ae74d7e074b 100644 --- a/arch/xtensa/include/asm/checksum.h +++ b/arch/xtensa/include/asm/checksum.h @@ -12,7 +12,7 @@ #define _XTENSA_CHECKSUM_H #include -#include +#include #include /* diff --git a/arch/xtensa/include/asm/segment.h b/arch/xtensa/include/asm/segment.h index a2eb547a1a75..98964ad15ca2 100644 --- a/arch/xtensa/include/asm/segment.h +++ b/arch/xtensa/include/asm/segment.h @@ -11,6 +11,6 @@ #ifndef _XTENSA_SEGMENT_H #define _XTENSA_SEGMENT_H -#include +#include #endif /* _XTENSA_SEGEMENT_H */ diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c index 8e10e357ee32..bcb5beb81177 100644 --- a/arch/xtensa/kernel/asm-offsets.c +++ b/arch/xtensa/kernel/asm-offsets.c @@ -24,7 +24,7 @@ #include #include -#include +#include int main(void) { diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c index 4ac3d23161cf..a265edd6ac37 100644 --- a/arch/xtensa/kernel/irq.c +++ b/arch/xtensa/kernel/irq.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include DECLARE_PER_CPU(unsigned long, nmi_count); diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c index e0ded48561db..826d25104846 100644 --- a/arch/xtensa/kernel/process.c +++ b/arch/xtensa/kernel/process.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c index a651f3a628ee..32519b71d914 100644 --- a/arch/xtensa/kernel/ptrace.c +++ b/arch/xtensa/kernel/ptrace.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include void user_enable_single_step(struct task_struct *child) diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c index e87adaa07ff3..c41294745731 100644 --- a/arch/xtensa/kernel/signal.c +++ b/arch/xtensa/kernel/signal.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/xtensa/kernel/stacktrace.c b/arch/xtensa/kernel/stacktrace.c index 7538d802b65a..e7d30ee0fd48 100644 --- a/arch/xtensa/kernel/stacktrace.c +++ b/arch/xtensa/kernel/stacktrace.c @@ -14,7 +14,7 @@ #include #include -#include +#include #if IS_ENABLED(CONFIG_OPROFILE) || IS_ENABLED(CONFIG_PERF_EVENTS) diff --git a/arch/xtensa/kernel/syscall.c b/arch/xtensa/kernel/syscall.c index 83cf49685373..d3fd100dffc9 100644 --- a/arch/xtensa/kernel/syscall.c +++ b/arch/xtensa/kernel/syscall.c @@ -15,7 +15,7 @@ * Kevin Chea * */ -#include +#include #include #include #include diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c index ce37d5b899fe..282bf721a4d6 100644 --- a/arch/xtensa/kernel/traps.c +++ b/arch/xtensa/kernel/traps.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c index 4d2872fd9bb5..d159e9b9c018 100644 --- a/arch/xtensa/kernel/xtensa_ksyms.c +++ b/arch/xtensa/kernel/xtensa_ksyms.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #include #include diff --git a/arch/xtensa/platforms/iss/console.c b/arch/xtensa/platforms/iss/console.c index c68f1e6158aa..0140a22551c8 100644 --- a/arch/xtensa/platforms/iss/console.c +++ b/arch/xtensa/platforms/iss/console.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/arch/xtensa/platforms/iss/simdisk.c b/arch/xtensa/platforms/iss/simdisk.c index ede04cca30dd..02e94bb3ad3e 100644 --- a/arch/xtensa/platforms/iss/simdisk.c +++ b/arch/xtensa/platforms/iss/simdisk.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #define SIMDISK_MAJOR 240 diff --git a/block/ioctl.c b/block/ioctl.c index 656c8c6ed206..be7f4de3eb3c 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) { diff --git a/block/partitions/ibm.c b/block/partitions/ibm.c index 47a61474e795..14b081af8d61 100644 --- a/block/partitions/ibm.c +++ b/block/partitions/ibm.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "check.h" diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c index c6fee7437be4..c2b64923ab66 100644 --- a/block/scsi_ioctl.c +++ b/block/scsi_ioctl.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/acpi/acpi_video.c b/drivers/acpi/acpi_video.c index 201292e67ee8..d00bc0ef87a6 100644 --- a/drivers/acpi/acpi_video.c +++ b/drivers/acpi/acpi_video.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 05fe9ebfb9b5..4ef1e4624b2b 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -36,7 +36,7 @@ #ifdef CONFIG_ACPI_PROCFS_POWER #include #include -#include +#include #endif #include diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index a404ff4d7151..57fb5f468ac2 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include "internal.h" diff --git a/drivers/acpi/proc.c b/drivers/acpi/proc.c index 2a358154b770..a34669cc823b 100644 --- a/drivers/acpi/proc.c +++ b/drivers/acpi/proc.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include "sleep.h" #include "internal.h" diff --git a/drivers/acpi/processor_thermal.c b/drivers/acpi/processor_thermal.c index 1fed84a092c2..59c3a5d1e600 100644 --- a/drivers/acpi/processor_thermal.c +++ b/drivers/acpi/processor_thermal.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/processor_throttling.c b/drivers/acpi/processor_throttling.c index d51ca1c05619..a12f96cc93ff 100644 --- a/drivers/acpi/processor_throttling.c +++ b/drivers/acpi/processor_throttling.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 35e8fbca10ad..1d0417b87cb7 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #define PREFIX "ACPI: " diff --git a/drivers/atm/adummy.c b/drivers/atm/adummy.c index f9b983ae6877..1fd25e872ece 100644 --- a/drivers/atm/adummy.c +++ b/drivers/atm/adummy.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c index 480fa6ffbc09..3ef6253e1cce 100644 --- a/drivers/atm/atmtcp.c +++ b/drivers/atm/atmtcp.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c index 40c2d561417b..c53a9dd1353f 100644 --- a/drivers/atm/eni.c +++ b/drivers/atm/eni.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/atm/firestream.c b/drivers/atm/firestream.c index 85aaf2222587..80c2ddcfa92c 100644 --- a/drivers/atm/firestream.c +++ b/drivers/atm/firestream.c @@ -52,7 +52,7 @@ #include #include #include -#include +#include #include #include "firestream.h" diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c index 81aaa505862c..637c3e6b0f9e 100644 --- a/drivers/atm/fore200e.c +++ b/drivers/atm/fore200e.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_SBUS diff --git a/drivers/atm/he.c b/drivers/atm/he.c index 31b513a23ae0..3617659b9184 100644 --- a/drivers/atm/he.c +++ b/drivers/atm/he.c @@ -71,7 +71,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c index 5fc81e240c24..584aa881882b 100644 --- a/drivers/atm/horizon.c +++ b/drivers/atm/horizon.c @@ -45,7 +45,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/atm/idt77105.c b/drivers/atm/idt77105.c index feb023d7eebd..082aa02abc57 100644 --- a/drivers/atm/idt77105.c +++ b/drivers/atm/idt77105.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "idt77105.h" diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c index 074616b39f4d..471ddfd93ea8 100644 --- a/drivers/atm/idt77252.c +++ b/drivers/atm/idt77252.c @@ -45,7 +45,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c index b2756765950e..8640bafeb471 100644 --- a/drivers/atm/iphase.c +++ b/drivers/atm/iphase.c @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c index c7296b583787..cb28579e8a94 100644 --- a/drivers/atm/nicstar.c +++ b/drivers/atm/nicstar.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include #include "nicstar.h" diff --git a/drivers/atm/suni.c b/drivers/atm/suni.c index 02159345566c..b0363149b2fd 100644 --- a/drivers/atm/suni.c +++ b/drivers/atm/suni.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include "suni.h" diff --git a/drivers/atm/uPD98402.c b/drivers/atm/uPD98402.c index 5120a96b3a89..4fa13a807873 100644 --- a/drivers/atm/uPD98402.c +++ b/drivers/atm/uPD98402.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include "uPD98402.h" diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c index d3dc95484161..292dec18ffb8 100644 --- a/drivers/atm/zatm.c +++ b/drivers/atm/zatm.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "uPD98401.h" #include "uPD98402.h" diff --git a/drivers/base/memory.c b/drivers/base/memory.c index bb69e58c29f3..8ab8ea1253e6 100644 --- a/drivers/base/memory.c +++ b/drivers/base/memory.c @@ -23,7 +23,7 @@ #include #include -#include +#include static DEFINE_MUTEX(mem_sysfs_mutex); diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c index 0809cda93cc0..26a51be77227 100644 --- a/drivers/block/DAC960.c +++ b/drivers/block/DAC960.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include "DAC960.h" #define DAC960_GAM_MINOR 252 diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 5fd50a284168..a328f673adfe 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -70,7 +70,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/block/brd.c b/drivers/block/brd.c index ad793f35632c..3adc32a3153b 100644 --- a/drivers/block/brd.c +++ b/drivers/block/brd.c @@ -23,7 +23,7 @@ #include #endif -#include +#include #define SECTOR_SHIFT 9 #define PAGE_SECTORS_SHIFT (PAGE_SHIFT - SECTOR_SHIFT) diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index db9d6bb6352d..e5c5b8eb14a9 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/block/cryptoloop.c b/drivers/block/cryptoloop.c index 3d31761c0ed0..74e03aa537ad 100644 --- a/drivers/block/cryptoloop.c +++ b/drivers/block/cryptoloop.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include "loop.h" MODULE_LICENSE("GPL"); diff --git a/drivers/block/hd.c b/drivers/block/hd.c index 3abb121825bc..a9b48ed7a3cd 100644 --- a/drivers/block/hd.c +++ b/drivers/block/hd.c @@ -45,7 +45,7 @@ #define REALLY_SLOW_IO #include -#include +#include #ifdef __arm__ #undef HD_IRQ diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 4af818766797..f347285c67ec 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -78,7 +78,7 @@ #include #include "loop.h" -#include +#include static DEFINE_IDR(loop_index_idr); static DEFINE_MUTEX(loop_index_mutex); diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 99c84468f154..38c576f76d36 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c index 93362362aa55..5fd2d0e25567 100644 --- a/drivers/block/paride/pcd.c +++ b/drivers/block/paride/pcd.c @@ -139,7 +139,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include #include #include -#include +#include static DEFINE_MUTEX(pcd_mutex); static DEFINE_SPINLOCK(pcd_lock); diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c index 78a39f736c64..c3ed2fc72daa 100644 --- a/drivers/block/paride/pd.c +++ b/drivers/block/paride/pd.c @@ -155,7 +155,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_GEO, D_SBY, D_DLY, D_SLV}; #include #include #include -#include +#include #include static DEFINE_MUTEX(pd_mutex); diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c index 7a7d977a76c5..ed93e8badf56 100644 --- a/drivers/block/paride/pf.c +++ b/drivers/block/paride/pf.c @@ -155,7 +155,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_LUN, D_DLY}; #include #include #include -#include +#include static DEFINE_MUTEX(pf_mutex); static DEFINE_SPINLOCK(pf_spin_lock); diff --git a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c index bfbd4c852dd9..5db955fe3a94 100644 --- a/drivers/block/paride/pg.c +++ b/drivers/block/paride/pg.c @@ -166,7 +166,7 @@ enum {D_PRT, D_PRO, D_UNI, D_MOD, D_SLV, D_DLY}; #include #include -#include +#include module_param(verbose, int, 0644); module_param(major, int, 0); diff --git a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c index 216a94fed5b4..61fc6824299a 100644 --- a/drivers/block/paride/pt.c +++ b/drivers/block/paride/pt.c @@ -150,7 +150,7 @@ static int (*drives[4])[6] = {&drive0, &drive1, &drive2, &drive3}; #include /* current, TASK_*, schedule_timeout() */ #include -#include +#include module_param(verbose, int, 0); module_param(major, int, 0); diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index 95c98de92971..1b94c1ca5c5f 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -68,7 +68,7 @@ #include #include -#include +#include #define DRIVER_NAME "pktcdvd" diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c index c264f2d284a7..aabd8e9d3035 100644 --- a/drivers/block/swim3.c +++ b/drivers/block/swim3.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c index ba4bfe933276..0e93ad7b8511 100644 --- a/drivers/block/sx8.c +++ b/drivers/block/sx8.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #if 0 #define CARM_DEBUG diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 46f4c719fed9..c141cc3be22b 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -54,7 +54,7 @@ #include "umem.h" -#include +#include #include #define MM_MAXCARDS 4 diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 5d475b3a0b2e..59cca72647a6 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -282,7 +282,7 @@ #include #include -#include +#include /* used to tell the module to turn on full debugging messages */ static bool debug; diff --git a/drivers/char/agp/compat_ioctl.c b/drivers/char/agp/compat_ioctl.c index a48e05b31593..2053f70ef66b 100644 --- a/drivers/char/agp/compat_ioctl.c +++ b/drivers/char/agp/compat_ioctl.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "agp.h" #include "compat_ioctl.h" diff --git a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c index 0f64d149c98d..f6955888e676 100644 --- a/drivers/char/agp/frontend.c +++ b/drivers/char/agp/frontend.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include #include "agp.h" diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c index 14790304b84b..e5c62dcf2c11 100644 --- a/drivers/char/applicom.c +++ b/drivers/char/applicom.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include "applicom.h" diff --git a/drivers/char/bfin-otp.c b/drivers/char/bfin-otp.c index 35d46da754d7..0584025bb0c2 100644 --- a/drivers/char/bfin-otp.c +++ b/drivers/char/bfin-otp.c @@ -20,7 +20,7 @@ #include #include -#include +#include #define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args) #define stampit() stamp("here i am") diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c index 0fae5296e311..eb53cbadb68f 100644 --- a/drivers/char/ds1620.c +++ b/drivers/char/ds1620.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include #ifdef CONFIG_PROC_FS diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c index 65a8d96c0e93..58471394beb9 100644 --- a/drivers/char/dtlk.c +++ b/drivers/char/dtlk.c @@ -59,7 +59,7 @@ #include #include #include /* for inb_p, outb_p, inb, outb, etc. */ -#include /* for get_user, etc. */ +#include /* for get_user, etc. */ #include /* for wait_queue */ #include /* for __init, module_{init,exit} */ #include /* for POLLIN, etc. */ diff --git a/drivers/char/generic_nvram.c b/drivers/char/generic_nvram.c index 073db9558379..14e728fbb8a0 100644 --- a/drivers/char/generic_nvram.c +++ b/drivers/char/generic_nvram.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_PPC_PMAC #include diff --git a/drivers/char/hangcheck-timer.c b/drivers/char/hangcheck-timer.c index a7c5c59675f0..4f337375252e 100644 --- a/drivers/char/hangcheck-timer.c +++ b/drivers/char/hangcheck-timer.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c index f9766415ff10..6ce5ce8be2f2 100644 --- a/drivers/char/hw_random/core.c +++ b/drivers/char/hw_random/core.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #define RNG_MODULE_NAME "hw_random" diff --git a/drivers/char/ipmi/ipmi_watchdog.c b/drivers/char/ipmi/ipmi_watchdog.c index 4facc7517a6a..4035495f3a86 100644 --- a/drivers/char/ipmi/ipmi_watchdog.c +++ b/drivers/char/ipmi/ipmi_watchdog.c @@ -43,7 +43,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/char/lp.c b/drivers/char/lp.c index c4094c4e22c1..5b6742770656 100644 --- a/drivers/char/lp.c +++ b/drivers/char/lp.c @@ -134,7 +134,7 @@ #include #include -#include +#include /* if you have more than 8 printers, remember to increase LP_NO */ #define LP_NO 8 diff --git a/drivers/char/mbcs.c b/drivers/char/mbcs.c index 67d426470e53..8c9216a0f62e 100644 --- a/drivers/char/mbcs.c +++ b/drivers/char/mbcs.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/char/mmtimer.c b/drivers/char/mmtimer.c index 3d6c0671e996..f786b18ac500 100644 --- a/drivers/char/mmtimer.c +++ b/drivers/char/mmtimer.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c index 972c40a19629..4a8937f80570 100644 --- a/drivers/char/mwave/3780i.c +++ b/drivers/char/mwave/3780i.c @@ -54,7 +54,7 @@ #include /* cond_resched() */ #include -#include +#include #include #include "smapi.h" #include "mwavedd.h" diff --git a/drivers/char/mwave/mwavedd.h b/drivers/char/mwave/mwavedd.h index 37e0a4926080..21cb09c7bed7 100644 --- a/drivers/char/mwave/mwavedd.h +++ b/drivers/char/mwave/mwavedd.h @@ -53,7 +53,7 @@ #include "smapi.h" #include "mwavepub.h" #include -#include +#include #include extern int mwave_debug; diff --git a/drivers/char/nsc_gpio.c b/drivers/char/nsc_gpio.c index b07b119ae57f..2a91bf048804 100644 --- a/drivers/char/nsc_gpio.c +++ b/drivers/char/nsc_gpio.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #define NAME "nsc_gpio" diff --git a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c index 0e184426db98..a5b1eb276c0b 100644 --- a/drivers/char/nwbutton.c +++ b/drivers/char/nwbutton.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/char/nwflash.c b/drivers/char/nwflash.c index dbe598de9b74..a284ae25e69a 100644 --- a/drivers/char/nwflash.c +++ b/drivers/char/nwflash.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include /*****************************************************************************/ #include diff --git a/drivers/char/pc8736x_gpio.c b/drivers/char/pc8736x_gpio.c index 3f79a9fb6b1b..5f4be88c0dfc 100644 --- a/drivers/char/pc8736x_gpio.c +++ b/drivers/char/pc8736x_gpio.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #define DEVNAME "pc8736x_gpio" diff --git a/drivers/char/pcmcia/cm4040_cs.c b/drivers/char/pcmcia/cm4040_cs.c index fc061f7c2bd1..d7123259143e 100644 --- a/drivers/char/pcmcia/cm4040_cs.c +++ b/drivers/char/pcmcia/cm4040_cs.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index a7dd5f4f2c5a..d136db1a10f0 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c @@ -84,7 +84,7 @@ #define PUT_USER(error,value,addr) error = put_user(value,addr) #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 -#include +#include static MGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ diff --git a/drivers/char/random.c b/drivers/char/random.c index d6876d506220..1ef26403bcc8 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -265,7 +265,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/char/raw.c b/drivers/char/raw.c index e83b2adc014a..293167c6e254 100644 --- a/drivers/char/raw.c +++ b/drivers/char/raw.c @@ -24,7 +24,7 @@ #include #include -#include +#include struct raw_device_data { struct block_device *binding; diff --git a/drivers/char/scx200_gpio.c b/drivers/char/scx200_gpio.c index 0bc135b9b16f..903761bc41c9 100644 --- a/drivers/char/scx200_gpio.c +++ b/drivers/char/scx200_gpio.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 719c5b4eed39..4fa7fcd8af36 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -52,7 +52,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/char/tlclk.c b/drivers/char/tlclk.c index 100cd1de9939..572a51704e67 100644 --- a/drivers/char/tlclk.c +++ b/drivers/char/tlclk.c @@ -44,7 +44,7 @@ #include #include #include /* inb/outb */ -#include +#include MODULE_AUTHOR("Sebastien Bouchard "); MODULE_LICENSE("GPL"); diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c index f5a45d887a37..5488516da8ea 100644 --- a/drivers/char/toshiba.c +++ b/drivers/char/toshiba.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/char/xilinx_hwicap/xilinx_hwicap.c b/drivers/char/xilinx_hwicap/xilinx_hwicap.c index c07dfe5c4da3..3e6b23c3453c 100644 --- a/drivers/char/xilinx_hwicap/xilinx_hwicap.c +++ b/drivers/char/xilinx_hwicap/xilinx_hwicap.c @@ -88,7 +88,7 @@ #include #include -#include +#include #ifdef CONFIG_OF /* For open firmware. */ diff --git a/drivers/cpufreq/ia64-acpi-cpufreq.c b/drivers/cpufreq/ia64-acpi-cpufreq.c index 759612da4fdc..e28a31a40829 100644 --- a/drivers/cpufreq/ia64-acpi-cpufreq.c +++ b/drivers/cpufreq/ia64-acpi-cpufreq.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c index fe8f08948fcb..ac321f09e717 100644 --- a/drivers/cpuidle/governors/ladder.c +++ b/drivers/cpuidle/governors/ladder.c @@ -19,7 +19,7 @@ #include #include -#include +#include #define PROMOTION_COUNT 4 #define DEMOTION_COUNT 1 diff --git a/drivers/dio/dio.c b/drivers/dio/dio.c index 55dd88d82d6d..830184529109 100644 --- a/drivers/dio/dio.c +++ b/drivers/dio/dio.c @@ -31,7 +31,7 @@ #include #include #include /* kmalloc() */ -#include +#include #include /* readb() */ struct dio_bus dio_bus = { diff --git a/drivers/edac/edac_device.c b/drivers/edac/edac_device.c index de4d5d08af9e..65cf2b9355c4 100644 --- a/drivers/edac/edac_device.c +++ b/drivers/edac/edac_device.c @@ -13,7 +13,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 5f2c717f8053..750891ea07de 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include "edac_mc.h" #include "edac_module.h" diff --git a/drivers/edac/edac_pci.c b/drivers/edac/edac_pci.c index 4e9d5632041a..48c844a72a27 100644 --- a/drivers/edac/edac_pci.c +++ b/drivers/edac/edac_pci.c @@ -10,7 +10,7 @@ * */ #include -#include +#include #include #include #include diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 3de95a29024c..cf9e396d7702 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -30,7 +30,7 @@ #define pr_fmt(fmt) "i2c-core: " fmt #include -#include +#include #include #include #include diff --git a/drivers/ide/hpt366.c b/drivers/ide/hpt366.c index 0ceae5cbd89a..4b5dc0162e67 100644 --- a/drivers/ide/hpt366.c +++ b/drivers/ide/hpt366.c @@ -130,7 +130,7 @@ #include #include -#include +#include #include #define DRV_NAME "hpt366" diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 83679da0c3f0..5ceace542b77 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c index 6360bbd37efe..201e43fcbc94 100644 --- a/drivers/ide/ide-io.c +++ b/drivers/ide/ide-io.c @@ -51,7 +51,7 @@ #include #include -#include +#include #include int ide_end_rq(ide_drive_t *drive, struct request *rq, int error, diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c index 376f2dc410c5..210a0887dd29 100644 --- a/drivers/ide/ide-iops.c +++ b/drivers/ide/ide-iops.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include void SELECT_MASK(ide_drive_t *drive, int mask) diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c index 0b63facd1d87..330e319419e6 100644 --- a/drivers/ide/ide-probe.c +++ b/drivers/ide/ide-probe.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include /** diff --git a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c index 97c070077774..863db44c7916 100644 --- a/drivers/ide/ide-proc.c +++ b/drivers/ide/ide-proc.c @@ -16,7 +16,7 @@ #include -#include +#include #include #include #include diff --git a/drivers/infiniband/core/ucm.c b/drivers/infiniband/core/ucm.c index 579f9a7f6283..e0a995b85a2d 100644 --- a/drivers/infiniband/core/ucm.c +++ b/drivers/infiniband/core/ucm.c @@ -46,7 +46,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 415a3185cde7..249b403b43a4 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c @@ -50,7 +50,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c index 09b649159e6c..700782203483 100644 --- a/drivers/infiniband/core/uverbs_cmd.c +++ b/drivers/infiniband/core/uverbs_cmd.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include "uverbs.h" #include "core_priv.h" diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c index 813593550c4b..b3f95d453fba 100644 --- a/drivers/infiniband/core/uverbs_main.c +++ b/drivers/infiniband/core/uverbs_main.c @@ -46,7 +46,7 @@ #include #include -#include +#include #include diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index a2f9f29c6ab5..fd811115af49 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include "ipoib.h" diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c index 64b3d11dcf1e..9104e6b8cac9 100644 --- a/drivers/infiniband/ulp/iser/iscsi_iser.c +++ b/drivers/infiniband/ulp/iser/iscsi_iser.c @@ -62,7 +62,7 @@ #include -#include +#include #include #include diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c index d84d20b9cec0..2186f71c9fe5 100644 --- a/drivers/input/input-compat.c +++ b/drivers/input/input-compat.c @@ -9,7 +9,7 @@ */ #include -#include +#include #include "input-compat.h" #ifdef CONFIG_COMPAT diff --git a/drivers/input/misc/atlas_btns.c b/drivers/input/misc/atlas_btns.c index 638165c78e75..6423aaccc763 100644 --- a/drivers/input/misc/atlas_btns.c +++ b/drivers/input/misc/atlas_btns.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #define ACPI_ATLAS_NAME "Atlas ACPI" #define ACPI_ATLAS_CLASS "Atlas" diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c index a7fd8f22ba56..a33437c480e3 100644 --- a/drivers/input/mouse/amimouse.c +++ b/drivers/input/mouse/amimouse.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/input/mouse/atarimouse.c b/drivers/input/mouse/atarimouse.c index d1c43236b125..96f2f51604bd 100644 --- a/drivers/input/mouse/atarimouse.c +++ b/drivers/input/mouse/atarimouse.c @@ -47,7 +47,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/input/mouse/trackpoint.c b/drivers/input/mouse/trackpoint.c index 354d47ecd66a..7331084973e1 100644 --- a/drivers/input/mouse/trackpoint.c +++ b/drivers/input/mouse/trackpoint.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "psmouse.h" #include "trackpoint.h" diff --git a/drivers/input/serio/hp_sdc.c b/drivers/input/serio/hp_sdc.c index 852858e5d8d0..559c99ca6592 100644 --- a/drivers/input/serio/hp_sdc.c +++ b/drivers/input/serio/hp_sdc.c @@ -79,7 +79,7 @@ # define sdc_readb(p) gsc_readb(p) # define sdc_writeb(v,p) gsc_writeb((v),(p)) #elif defined(__mc68000__) -# include +#include # define sdc_readb(p) in_8(p) # define sdc_writeb(v,p) out_8((p),(v)) #else diff --git a/drivers/input/serio/q40kbd.c b/drivers/input/serio/q40kbd.c index 5a9d521510bf..d0fccc8ec259 100644 --- a/drivers/input/serio/q40kbd.c +++ b/drivers/input/serio/q40kbd.c @@ -38,7 +38,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c index d189843f3727..f8ead9f9c77e 100644 --- a/drivers/input/serio/serport.c +++ b/drivers/input/serio/serport.c @@ -13,7 +13,7 @@ * the Free Software Foundation. */ -#include +#include #include #include #include diff --git a/drivers/input/tablet/aiptek.c b/drivers/input/tablet/aiptek.c index 4613f0aefd08..d67547bded3e 100644 --- a/drivers/input/tablet/aiptek.c +++ b/drivers/input/tablet/aiptek.c @@ -75,7 +75,7 @@ #include #include #include -#include +#include #include /* diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c index abf09ac42ce4..b796e891e2ee 100644 --- a/drivers/input/tablet/gtco.c +++ b/drivers/input/tablet/gtco.c @@ -56,7 +56,7 @@ Scott Hill shill@gtcocalcomp.com #include #include #include -#include +#include #include #include #include diff --git a/drivers/isdn/capi/kcapi.c b/drivers/isdn/capi/kcapi.c index 823f6985b260..49d0f70c2bae 100644 --- a/drivers/isdn/capi/kcapi.c +++ b/drivers/isdn/capi/kcapi.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #ifdef AVMB1_COMPAT diff --git a/drivers/isdn/hardware/avm/b1.c b/drivers/isdn/hardware/avm/b1.c index 4d9b195547c5..9fdbd99c7547 100644 --- a/drivers/isdn/hardware/avm/b1.c +++ b/drivers/isdn/hardware/avm/b1.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include "avmcard.h" diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c index 19b113faeb7b..818bd8f231db 100644 --- a/drivers/isdn/hardware/avm/b1dma.c +++ b/drivers/isdn/hardware/avm/b1dma.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include "avmcard.h" diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c index 5d00d72fe482..17beb2869dc1 100644 --- a/drivers/isdn/hardware/avm/c4.c +++ b/drivers/isdn/hardware/avm/c4.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/isdn/hardware/eicon/capimain.c b/drivers/isdn/hardware/eicon/capimain.c index 997d46abf5b2..be36d82004d6 100644 --- a/drivers/isdn/hardware/eicon/capimain.c +++ b/drivers/isdn/hardware/eicon/capimain.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c index 0de29b7b712f..72e58bf07577 100644 --- a/drivers/isdn/hardware/eicon/divamnt.c +++ b/drivers/isdn/hardware/eicon/divamnt.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "platform.h" #include "di_defs.h" diff --git a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c index 4103a8c178d7..cb88090f9cea 100644 --- a/drivers/isdn/hardware/eicon/divasi.c +++ b/drivers/isdn/hardware/eicon/divasi.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "platform.h" #include "di_defs.h" diff --git a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c index 32f34511c416..8b7ad4f1ab01 100644 --- a/drivers/isdn/hardware/eicon/divasmain.c +++ b/drivers/isdn/hardware/eicon/divasmain.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/isdn/hardware/eicon/divasproc.c b/drivers/isdn/hardware/eicon/divasproc.c index 56ce98a4e248..b57efd6ad916 100644 --- a/drivers/isdn/hardware/eicon/divasproc.c +++ b/drivers/isdn/hardware/eicon/divasproc.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "platform.h" #include "debuglib.h" diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c index eda4741e3f2f..4a0425378f37 100644 --- a/drivers/isdn/hysdn/hysdn_boot.c +++ b/drivers/isdn/hysdn/hysdn_boot.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "hysdn_defs.h" #include "hysdn_pof.h" diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index 9e385b38debf..ac219045daf7 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include #include "lg.h" diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c index e3abebc912c0..0bc127e9f16a 100644 --- a/drivers/lguest/page_tables.c +++ b/drivers/lguest/page_tables.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "lg.h" /*M:008 diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 743253fc638f..d71f6323ac00 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c @@ -45,7 +45,7 @@ #include #include #include -#include +#include #include #include #include "../lg.h" diff --git a/drivers/macintosh/ans-lcd.c b/drivers/macintosh/ans-lcd.c index cd35079c8c98..281fa9e6fc1f 100644 --- a/drivers/macintosh/ans-lcd.c +++ b/drivers/macintosh/ans-lcd.c @@ -11,7 +11,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/macintosh/smu.c b/drivers/macintosh/smu.c index 08edb2c25b60..227869159ac0 100644 --- a/drivers/macintosh/smu.c +++ b/drivers/macintosh/smu.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #define VERSION "0.7" #define AUTHOR "(c) 2005 Benjamin Herrenschmidt, IBM Corp." diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c index 91081dcdc272..43b8db2b5445 100644 --- a/drivers/macintosh/via-pmu.c +++ b/drivers/macintosh/via-pmu.c @@ -57,7 +57,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c index a00ee41f0573..a411c5cb77a1 100644 --- a/drivers/macintosh/via-pmu68k.c +++ b/drivers/macintosh/via-pmu68k.c @@ -38,7 +38,7 @@ #include #include -#include +#include /* Misc minor number allocated for /dev/pmu */ #define PMU_MINOR 154 diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index c72a77048b73..a5a9b17f0f7f 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -17,7 +17,7 @@ #include #include -#include +#include #define DM_MSG_PREFIX "ioctl" #define DM_DRIVER_EMAIL "dm-devel@redhat.com" diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index efe55a3e80d0..0c44479b556e 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "dmxdev.h" static int debug; diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c index 3ad0b2cd26b1..bbbff72bbb2a 100644 --- a/drivers/media/dvb-core/dvb_demux.c +++ b/drivers/media/dvb-core/dvb_demux.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include "dvb_demux.h" diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c index dfc03a95df71..bc5e8cfe7ca2 100644 --- a/drivers/media/dvb-core/dvb_net.c +++ b/drivers/media/dvb-core/dvb_net.c @@ -62,7 +62,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index 7df7fb3738a0..5c4b5a1f604f 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "dvb_ringbuffer.h" diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c index 05f1dc6c72af..fc9ec0f3679c 100644 --- a/drivers/media/i2c/adv7170.c +++ b/drivers/media/i2c/adv7170.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c index f554809a51e7..72139bdae1ca 100644 --- a/drivers/media/i2c/adv7175.c +++ b/drivers/media/i2c/adv7175.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/bt856.c b/drivers/media/i2c/bt856.c index 48176591a80d..54c627859c8e 100644 --- a/drivers/media/i2c/bt856.c +++ b/drivers/media/i2c/bt856.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/bt866.c b/drivers/media/i2c/bt866.c index bbec70c882a3..0d3f46af2545 100644 --- a/drivers/media/i2c/bt866.c +++ b/drivers/media/i2c/bt866.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/cs53l32a.c b/drivers/media/i2c/cs53l32a.c index e4b3cf49dd38..59c1a98c5a90 100644 --- a/drivers/media/i2c/cs53l32a.c +++ b/drivers/media/i2c/cs53l32a.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/m52790.c b/drivers/media/i2c/m52790.c index 81171d8e1c2c..89c28c36c5bf 100644 --- a/drivers/media/i2c/m52790.c +++ b/drivers/media/i2c/m52790.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/saa6588.c b/drivers/media/i2c/saa6588.c index 89e458c23983..00640233a5e3 100644 --- a/drivers/media/i2c/saa6588.c +++ b/drivers/media/i2c/saa6588.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/i2c/saa7110.c b/drivers/media/i2c/saa7110.c index 6f49886806ee..ad456ce051f9 100644 --- a/drivers/media/i2c/saa7110.c +++ b/drivers/media/i2c/saa7110.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/saa7185.c b/drivers/media/i2c/saa7185.c index eecad2d1edce..119050e1197a 100644 --- a/drivers/media/i2c/saa7185.c +++ b/drivers/media/i2c/saa7185.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/tlv320aic23b.c b/drivers/media/i2c/tlv320aic23b.c index 2e06c06cac9b..cc6104da34ef 100644 --- a/drivers/media/i2c/tlv320aic23b.c +++ b/drivers/media/i2c/tlv320aic23b.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/vp27smpx.c b/drivers/media/i2c/vp27smpx.c index d6c23bdbcd4a..ef0d8b8e3df7 100644 --- a/drivers/media/i2c/vp27smpx.c +++ b/drivers/media/i2c/vp27smpx.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/vpx3220.c b/drivers/media/i2c/vpx3220.c index 90b693f4e2ab..ce9f09370e22 100644 --- a/drivers/media/i2c/vpx3220.c +++ b/drivers/media/i2c/vpx3220.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/wm8739.c b/drivers/media/i2c/wm8739.c index f086e5e6e844..c885def54b15 100644 --- a/drivers/media/i2c/wm8739.c +++ b/drivers/media/i2c/wm8739.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/i2c/wm8775.c b/drivers/media/i2c/wm8775.c index 5581f4db02af..45039d756753 100644 --- a/drivers/media/i2c/wm8775.c +++ b/drivers/media/i2c/wm8775.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/pci/ivtv/ivtv-driver.h b/drivers/media/pci/ivtv/ivtv-driver.h index 10cba305dbd2..6b09a9514d64 100644 --- a/drivers/media/pci/ivtv/ivtv-driver.h +++ b/drivers/media/pci/ivtv/ivtv-driver.h @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c index e825bc93ea7a..24fba633c217 100644 --- a/drivers/media/pci/meye/meye.c +++ b/drivers/media/pci/meye/meye.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/media/pci/zoran/videocodec.c b/drivers/media/pci/zoran/videocodec.c index 13a3c07cd259..3c3cbce0f9cc 100644 --- a/drivers/media/pci/zoran/videocodec.c +++ b/drivers/media/pci/zoran/videocodec.c @@ -40,7 +40,7 @@ #ifdef CONFIG_PROC_FS #include #include -#include +#include #endif #include "videocodec.h" diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c index 2170e174c335..94b9b616df98 100644 --- a/drivers/media/pci/zoran/zoran_driver.c +++ b/drivers/media/pci/zoran/zoran_driver.c @@ -66,7 +66,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/media/platform/arv.c b/drivers/media/platform/arv.c index 03c5098499c4..8fe59bf6cd3f 100644 --- a/drivers/media/platform/arv.c +++ b/drivers/media/platform/arv.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c index 70b8a052eb5b..3c7ca2c2c108 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #define BUFFER_COUNT 32 #define BUFFER_SIZE PAGE_ALIGN(0x4000) diff --git a/drivers/media/usb/pwc/pwc-ctrl.c b/drivers/media/usb/pwc/pwc-ctrl.c index 3a1618580ed6..655cef39eb3d 100644 --- a/drivers/media/usb/pwc/pwc-ctrl.c +++ b/drivers/media/usb/pwc/pwc-ctrl.c @@ -39,7 +39,7 @@ /* Control functions for the cam; brightness, contrast, video mode, etc. */ #ifdef __KERNEL__ -#include +#include #endif #include diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c index 57cfe26a393f..a5ea1f517291 100644 --- a/drivers/media/v4l2-core/v4l2-common.c +++ b/drivers/media/v4l2-core/v4l2-common.c @@ -54,7 +54,7 @@ #if defined(CONFIG_SPI) #include #endif -#include +#include #include #include #include diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c index 8be561ab2615..fa2124cb31bd 100644 --- a/drivers/media/v4l2-core/v4l2-dev.c +++ b/drivers/media/v4l2-core/v4l2-dev.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 02b5f69e1a42..7b3b41368931 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -58,7 +58,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 69e9d5463564..8946e19dbfc8 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -70,7 +70,7 @@ #include #include -#include +#include #include /* Override mptbase.h by pre-defining these! */ diff --git a/drivers/misc/ibmasm/ibmasmfs.c b/drivers/misc/ibmasm/ibmasmfs.c index 520f58439080..e05c3245930a 100644 --- a/drivers/misc/ibmasm/ibmasmfs.c +++ b/drivers/misc/ibmasm/ibmasmfs.c @@ -76,7 +76,7 @@ #include #include #include -#include +#include #include #include "ibmasm.h" #include "remote.h" diff --git a/drivers/mmc/core/block.c b/drivers/mmc/core/block.c index bab3f07b1117..cb1698f268f1 100644 --- a/drivers/mmc/core/block.c +++ b/drivers/mmc/core/block.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include "queue.h" #include "block.h" diff --git a/drivers/mmc/host/android-goldfish.c b/drivers/mmc/host/android-goldfish.c index dca5518b0139..590a8a4522be 100644 --- a/drivers/mmc/host/android-goldfish.c +++ b/drivers/mmc/host/android-goldfish.c @@ -49,7 +49,7 @@ #include #include -#include +#include #define DRIVER_NAME "goldfish_mmc" diff --git a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c index 220f9200fa52..cadea0620cd0 100644 --- a/drivers/mtd/devices/pmc551.c +++ b/drivers/mtd/devices/pmc551.c @@ -82,7 +82,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c index a70eb83e68f1..8087c36dc693 100644 --- a/drivers/mtd/devices/slram.c +++ b/drivers/mtd/devices/slram.c @@ -30,7 +30,7 @@ #include -#include +#include #include #include #include diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c index 9fb3b0dcdac2..664d206a4cbe 100644 --- a/drivers/mtd/ftl.c +++ b/drivers/mtd/ftl.c @@ -70,7 +70,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c index b66b541877f0..8db740d6eb08 100644 --- a/drivers/mtd/inftlcore.c +++ b/drivers/mtd/inftlcore.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c index 1388c8d7f309..8d6bb189ea8e 100644 --- a/drivers/mtd/inftlmount.c +++ b/drivers/mtd/inftlmount.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c index d459aca07881..414956eca0c9 100644 --- a/drivers/mtd/maps/sun_uflash.c +++ b/drivers/mtd/maps/sun_uflash.c @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index 8d58acf33021..df8a5ef334c0 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "mtdcore.h" diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index 2a47a3f0e730..ce5ccc573a9c 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include "mtdcore.h" diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c index 46f27de018c3..e21161353e76 100644 --- a/drivers/mtd/nftlcore.c +++ b/drivers/mtd/nftlcore.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 31f89f1c6123..b8c293373ecc 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include "ipddp.h" /* Our stuff */ diff --git a/drivers/net/eql.c b/drivers/net/eql.c index a10ad74cc8d2..fe13bfea30ac 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -127,7 +127,7 @@ #include #include -#include +#include static int eql_open(struct net_device *dev); static int eql_close(struct net_device *dev); diff --git a/drivers/net/ethernet/3com/3c509.c b/drivers/net/ethernet/3com/3c509.c index a7533780dddc..c7f9f2c77da7 100644 --- a/drivers/net/ethernet/3com/3c509.c +++ b/drivers/net/ethernet/3com/3c509.c @@ -88,7 +88,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/3com/3c515.c b/drivers/net/ethernet/3com/3c515.c index be5b80103bec..e7b1fa56b290 100644 --- a/drivers/net/ethernet/3com/3c515.c +++ b/drivers/net/ethernet/3com/3c515.c @@ -72,7 +72,7 @@ static int max_interrupt_work = 20; #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/3com/3c574_cs.c b/drivers/net/ethernet/3com/3c574_cs.c index 9359a37fedc0..47c844cc9d27 100644 --- a/drivers/net/ethernet/3com/3c574_cs.c +++ b/drivers/net/ethernet/3com/3c574_cs.c @@ -92,7 +92,7 @@ earlier 3Com products. #include #include -#include +#include #include /*====================================================================*/ diff --git a/drivers/net/ethernet/3com/3c59x.c b/drivers/net/ethernet/3com/3c59x.c index b3560a364e53..40196f41768a 100644 --- a/drivers/net/ethernet/3com/3c59x.c +++ b/drivers/net/ethernet/3com/3c59x.c @@ -92,7 +92,7 @@ static int vortex_debug = 1; #include #include /* For nr_irqs only. */ #include -#include +#include /* Kernel compatibility defines, some common to David Hinds' PCMCIA package. This is only in the support-all-kernels source code. */ diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c index a0cacbe846ba..9fe3990319ec 100644 --- a/drivers/net/ethernet/3com/typhoon.c +++ b/drivers/net/ethernet/3com/typhoon.c @@ -119,7 +119,7 @@ static const int multicast_filter_limit = 32; #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/8390/axnet_cs.c b/drivers/net/ethernet/8390/axnet_cs.c index 1d84a0544ace..3da1fc539ef9 100644 --- a/drivers/net/ethernet/8390/axnet_cs.c +++ b/drivers/net/ethernet/8390/axnet_cs.c @@ -46,7 +46,7 @@ #include #include -#include +#include #define AXNET_CMD 0x00 #define AXNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ diff --git a/drivers/net/ethernet/8390/ne2k-pci.c b/drivers/net/ethernet/8390/ne2k-pci.c index 07355302443d..1bdea746926c 100644 --- a/drivers/net/ethernet/8390/ne2k-pci.c +++ b/drivers/net/ethernet/8390/ne2k-pci.c @@ -54,7 +54,7 @@ static int options[MAX_UNITS]; #include #include -#include +#include #include "8390.h" diff --git a/drivers/net/ethernet/8390/pcnet_cs.c b/drivers/net/ethernet/8390/pcnet_cs.c index 63079a6e20d9..bd0a2a14b649 100644 --- a/drivers/net/ethernet/8390/pcnet_cs.c +++ b/drivers/net/ethernet/8390/pcnet_cs.c @@ -49,7 +49,7 @@ #include #include -#include +#include #define PCNET_CMD 0x00 #define PCNET_DATAPORT 0x10 /* NatSemi-defined port window offset. */ diff --git a/drivers/net/ethernet/adaptec/starfire.c b/drivers/net/ethernet/adaptec/starfire.c index 3aaad33cdbc6..c12d2618eebf 100644 --- a/drivers/net/ethernet/adaptec/starfire.c +++ b/drivers/net/ethernet/adaptec/starfire.c @@ -45,7 +45,7 @@ #include #include #include /* Processor type for cache alignment. */ -#include +#include #include /* diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c index 16f0c70266bc..a1a52eb53b14 100644 --- a/drivers/net/ethernet/alteon/acenic.c +++ b/drivers/net/ethernet/alteon/acenic.c @@ -80,7 +80,7 @@ #include #include #include -#include +#include #define DRV_NAME "acenic" diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c index 11cf1e3e0295..9595f1bc535b 100644 --- a/drivers/net/ethernet/amd/amd8111e.c +++ b/drivers/net/ethernet/amd/amd8111e.c @@ -87,7 +87,7 @@ Revision History: #include #include -#include +#include #if IS_ENABLED(CONFIG_VLAN_8021Q) #define AMD8111E_VLAN_TAG_USED 1 diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c index 113a3b3cc50c..b556c926557a 100644 --- a/drivers/net/ethernet/amd/nmclan_cs.c +++ b/drivers/net/ethernet/amd/nmclan_cs.c @@ -151,7 +151,7 @@ Include Files #include #include -#include +#include #include /* ---------------------------------------------------------------------------- diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c index 1df3048a3cdb..48707ed76ffc 100644 --- a/drivers/net/ethernet/broadcom/b44.c +++ b/drivers/net/ethernet/broadcom/b44.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c index 3a05f9098e75..d8aff7a4b3c7 100644 --- a/drivers/net/ethernet/chelsio/cxgb/cxgb2.c +++ b/drivers/net/ethernet/chelsio/cxgb/cxgb2.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include "cpl5_cmd.h" #include "regs.h" diff --git a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c index 7b2224ae72f2..d76491676b51 100644 --- a/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c +++ b/drivers/net/ethernet/chelsio/cxgb3/cxgb3_main.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include "common.h" #include "cxgb3_ioctl.h" diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c index 66c37fac59b2..6f951877430b 100644 --- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c +++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include #include "cxgb4.h" diff --git a/drivers/net/ethernet/dec/tulip/de2104x.c b/drivers/net/ethernet/dec/tulip/de2104x.c index 90c573b8ccaf..57c17e797ae3 100644 --- a/drivers/net/ethernet/dec/tulip/de2104x.c +++ b/drivers/net/ethernet/dec/tulip/de2104x.c @@ -49,7 +49,7 @@ #include #include -#include +#include #include /* These identify the driver base version and may not be removed. */ diff --git a/drivers/net/ethernet/dec/tulip/de4x5.c b/drivers/net/ethernet/dec/tulip/de4x5.c index 51fda3a6b13f..df4a871df633 100644 --- a/drivers/net/ethernet/dec/tulip/de4x5.c +++ b/drivers/net/ethernet/dec/tulip/de4x5.c @@ -472,7 +472,7 @@ #include #include #include -#include +#include #ifdef CONFIG_PPC_PMAC #include #endif /* CONFIG_PPC_PMAC */ diff --git a/drivers/net/ethernet/dec/tulip/dmfe.c b/drivers/net/ethernet/dec/tulip/dmfe.c index df4994919456..07e10a45beaa 100644 --- a/drivers/net/ethernet/dec/tulip/dmfe.c +++ b/drivers/net/ethernet/dec/tulip/dmfe.c @@ -90,7 +90,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_TULIP_DM910X diff --git a/drivers/net/ethernet/dec/tulip/tulip_core.c b/drivers/net/ethernet/dec/tulip/tulip_core.c index 5f1377449b8f..17e566a8b345 100644 --- a/drivers/net/ethernet/dec/tulip/tulip_core.c +++ b/drivers/net/ethernet/dec/tulip/tulip_core.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #ifdef CONFIG_SPARC #include diff --git a/drivers/net/ethernet/dec/tulip/uli526x.c b/drivers/net/ethernet/dec/tulip/uli526x.c index e1c4133b8787..f82ebe5d89ee 100644 --- a/drivers/net/ethernet/dec/tulip/uli526x.c +++ b/drivers/net/ethernet/dec/tulip/uli526x.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #define uw32(reg, val) iowrite32(val, ioaddr + (reg)) #define ur32(reg) ioread32(ioaddr + (reg)) diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c index feda96d585e7..bc9bf88e5831 100644 --- a/drivers/net/ethernet/dec/tulip/winbond-840.c +++ b/drivers/net/ethernet/dec/tulip/winbond-840.c @@ -129,7 +129,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include #include #include -#include +#include #include /* Processor type for cache alignment. */ #include #include diff --git a/drivers/net/ethernet/dec/tulip/xircom_cb.c b/drivers/net/ethernet/dec/tulip/xircom_cb.c index 19e4ea15b504..a8de79355578 100644 --- a/drivers/net/ethernet/dec/tulip/xircom_cb.c +++ b/drivers/net/ethernet/dec/tulip/xircom_cb.c @@ -30,7 +30,7 @@ #include #include -#include +#include #include #ifdef CONFIG_NET_POLL_CONTROLLER #include diff --git a/drivers/net/ethernet/dlink/dl2k.h b/drivers/net/ethernet/dlink/dl2k.h index 8f4f61262d5c..5d8ae5320242 100644 --- a/drivers/net/ethernet/dlink/dl2k.h +++ b/drivers/net/ethernet/dlink/dl2k.h @@ -31,7 +31,7 @@ #include #include /* Processor type for cache alignment. */ #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/dlink/sundance.c b/drivers/net/ethernet/dlink/sundance.c index eab36acfc0d1..2e5b66762e15 100644 --- a/drivers/net/ethernet/dlink/sundance.c +++ b/drivers/net/ethernet/dlink/sundance.c @@ -91,7 +91,7 @@ static char *media[MAX_UNITS]; #include #include #include -#include +#include #include /* Processor type for cache alignment. */ #include #include diff --git a/drivers/net/ethernet/fealnx.c b/drivers/net/ethernet/fealnx.c index 6967b287b6e7..9cb436cb3745 100644 --- a/drivers/net/ethernet/fealnx.c +++ b/drivers/net/ethernet/fealnx.c @@ -88,7 +88,7 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 }; #include /* Processor type for cache alignment. */ #include -#include +#include #include /* These identify the driver base version and may not be removed. */ diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c index d9f3a480ca1b..1f98838f32b7 100644 --- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c +++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c @@ -44,7 +44,7 @@ #include #include #include -#include +#include #include "fs_enet.h" diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c index 120c758f5d01..6e64989f8478 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fcc.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include "fs_enet.h" diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c index 777beffa1e1e..db9c0bcf54cd 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-fec.c @@ -36,7 +36,7 @@ #include #include -#include +#include #ifdef CONFIG_8xx #include diff --git a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c index 15abd37d70e3..96d44cf44fe0 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mac-scc.c +++ b/drivers/net/ethernet/freescale/fs_enet/mac-scc.c @@ -35,7 +35,7 @@ #include #include -#include +#include #ifdef CONFIG_8xx #include diff --git a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c index a89267b94352..1582d82483ec 100644 --- a/drivers/net/ethernet/freescale/fs_enet/mii-fec.c +++ b/drivers/net/ethernet/freescale/fs_enet/mii-fec.c @@ -35,7 +35,7 @@ #include #include -#include +#include #include #include "fs_enet.h" diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 756f7e763d5f..a6e7afa878be 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -93,7 +93,7 @@ #include #endif #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h index 6e8a9c8467b9..5aa814799d70 100644 --- a/drivers/net/ethernet/freescale/gianfar.h +++ b/drivers/net/ethernet/freescale/gianfar.h @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c index 56588f2e1d91..a93e0199c369 100644 --- a/drivers/net/ethernet/freescale/gianfar_ethtool.c +++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/freescale/ucc_geth.c b/drivers/net/ethernet/freescale/ucc_geth.c index 53c5fcf1436c..9d660888510f 100644 --- a/drivers/net/ethernet/freescale/ucc_geth.c +++ b/drivers/net/ethernet/freescale/ucc_geth.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c index 8ba636f61b50..b642990b549c 100644 --- a/drivers/net/ethernet/freescale/ucc_geth_ethtool.c +++ b/drivers/net/ethernet/freescale/ucc_geth_ethtool.c @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include "ucc_geth.h" diff --git a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c index 51c4abc51bf4..a69cd19a55ae 100644 --- a/drivers/net/ethernet/fujitsu/fmvj18x_cs.c +++ b/drivers/net/ethernet/fujitsu/fmvj18x_cs.c @@ -54,7 +54,7 @@ #include #include -#include +#include #include /*====================================================================*/ diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c index 52a69c925965..5909615c27f7 100644 --- a/drivers/net/ethernet/ibm/emac/core.c +++ b/drivers/net/ethernet/ibm/emac/core.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c b/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c index d2b29b490ae0..e5d72559cca9 100644 --- a/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c +++ b/drivers/net/ethernet/intel/ixgb/ixgb_ethtool.c @@ -30,7 +30,7 @@ #include "ixgb.h" -#include +#include #define IXGB_ALL_RAR_ENTRIES 16 diff --git a/drivers/net/ethernet/natsemi/natsemi.c b/drivers/net/ethernet/natsemi/natsemi.c index 22b0821c1da0..90eac63f9606 100644 --- a/drivers/net/ethernet/natsemi/natsemi.c +++ b/drivers/net/ethernet/natsemi/natsemi.c @@ -51,7 +51,7 @@ #include /* Processor type for cache alignment. */ #include #include -#include +#include #define DRV_NAME "natsemi" #define DRV_VERSION "2.1" diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c index 93c4bdc0cdca..f9d2eb9a920a 100644 --- a/drivers/net/ethernet/natsemi/ns83820.c +++ b/drivers/net/ethernet/natsemi/ns83820.c @@ -119,7 +119,7 @@ #include #include -#include +#include #define DRV_NAME "ns83820" diff --git a/drivers/net/ethernet/packetengines/hamachi.c b/drivers/net/ethernet/packetengines/hamachi.c index 2d04679a923a..baff744b560e 100644 --- a/drivers/net/ethernet/packetengines/hamachi.c +++ b/drivers/net/ethernet/packetengines/hamachi.c @@ -160,7 +160,7 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1}; #include #include -#include +#include #include /* Processor type for cache alignment. */ #include #include diff --git a/drivers/net/ethernet/packetengines/yellowfin.c b/drivers/net/ethernet/packetengines/yellowfin.c index 2a2ca5fa0c69..fa7770da6ef8 100644 --- a/drivers/net/ethernet/packetengines/yellowfin.c +++ b/drivers/net/ethernet/packetengines/yellowfin.c @@ -100,7 +100,7 @@ static int gx_fix; #include #include #include -#include +#include #include /* Processor type for cache alignment. */ #include #include diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index b7c89ebcf4a2..0b3cd58093d5 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -76,7 +76,7 @@ #include #include #include -#include +#include /* These identify the driver base version and may not be removed. */ static char version[] = diff --git a/drivers/net/ethernet/sgi/ioc3-eth.c b/drivers/net/ethernet/sgi/ioc3-eth.c index 42051ab98cf0..d390b9663dc3 100644 --- a/drivers/net/ethernet/sgi/ioc3-eth.c +++ b/drivers/net/ethernet/sgi/ioc3-eth.c @@ -60,7 +60,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/ethernet/sis/sis900.c b/drivers/net/ethernet/sis/sis900.c index 39fca6c0b68d..19a458716f1a 100644 --- a/drivers/net/ethernet/sis/sis900.c +++ b/drivers/net/ethernet/sis/sis900.c @@ -74,7 +74,7 @@ #include /* Processor type for cache alignment. */ #include #include -#include /* User space memory access functions */ +#include /* User space memory access functions */ #include "sis900.h" diff --git a/drivers/net/ethernet/smsc/epic100.c b/drivers/net/ethernet/smsc/epic100.c index fe9760ffab51..55a95e1d69d6 100644 --- a/drivers/net/ethernet/smsc/epic100.c +++ b/drivers/net/ethernet/smsc/epic100.c @@ -86,7 +86,7 @@ static int rx_copybreak; #include #include #include -#include +#include #include /* These identify the driver base version and may not be removed. */ diff --git a/drivers/net/ethernet/smsc/smc91c92_cs.c b/drivers/net/ethernet/smsc/smc91c92_cs.c index f1c75e291e55..67154621abcf 100644 --- a/drivers/net/ethernet/smsc/smc91c92_cs.c +++ b/drivers/net/ethernet/smsc/smc91c92_cs.c @@ -52,7 +52,7 @@ #include #include -#include +#include /*====================================================================*/ diff --git a/drivers/net/ethernet/sun/cassini.c b/drivers/net/ethernet/sun/cassini.c index e9e5ef241c6f..0e8e89f17dbb 100644 --- a/drivers/net/ethernet/sun/cassini.c +++ b/drivers/net/ethernet/sun/cassini.c @@ -99,7 +99,7 @@ #include #include #include -#include +#include #define cas_page_map(x) kmap_atomic((x)) #define cas_page_unmap(x) kunmap_atomic((x)) diff --git a/drivers/net/ethernet/sun/sungem.c b/drivers/net/ethernet/sun/sungem.c index 66ecf0fcc330..d277e4107976 100644 --- a/drivers/net/ethernet/sun/sungem.c +++ b/drivers/net/ethernet/sun/sungem.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #ifdef CONFIG_SPARC diff --git a/drivers/net/ethernet/sun/sunhme.c b/drivers/net/ethernet/sun/sunhme.c index ca96408058b0..72ff05cd3ed8 100644 --- a/drivers/net/ethernet/sun/sunhme.c +++ b/drivers/net/ethernet/sun/sunhme.c @@ -49,7 +49,7 @@ #include #include #endif -#include +#include #include #include diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c index ba5c54249055..0a6c4e804eed 100644 --- a/drivers/net/ethernet/via/via-rhine.c +++ b/drivers/net/ethernet/via/via-rhine.c @@ -114,7 +114,7 @@ static const int multicast_filter_limit = 32; #include /* Processor type for cache alignment. */ #include #include -#include +#include #include /* These identify the driver base version and may not be removed. */ diff --git a/drivers/net/ethernet/xircom/xirc2ps_cs.c b/drivers/net/ethernet/xircom/xirc2ps_cs.c index 3b08ec766076..f71883264cc0 100644 --- a/drivers/net/ethernet/xircom/xirc2ps_cs.c +++ b/drivers/net/ethernet/xircom/xirc2ps_cs.c @@ -88,7 +88,7 @@ #include #include -#include +#include #ifndef MANFID_COMPAQ #define MANFID_COMPAQ 0x0138 diff --git a/drivers/net/fddi/skfp/skfddi.c b/drivers/net/fddi/skfp/skfddi.c index 3a639180e4a0..2414f1dc8ddd 100644 --- a/drivers/net/fddi/skfp/skfddi.c +++ b/drivers/net/fddi/skfp/skfddi.c @@ -88,7 +88,7 @@ static const char * const boot_msg = #include #include -#include +#include #include "h/types.h" #undef ADDR // undo Linux definition diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 470b3dcd54e5..922bf440e9f1 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -13,7 +13,7 @@ */ #include -#include +#include #include #include #include diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 78dbc44540f6..7d054697b199 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -55,7 +55,7 @@ #include #include #include -#include +#include /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_par.c b/drivers/net/hamradio/baycom_par.c index 072cddce9264..809dc25909d1 100644 --- a/drivers/net/hamradio/baycom_par.c +++ b/drivers/net/hamradio/baycom_par.c @@ -86,7 +86,7 @@ #include #include -#include +#include /* --------------------------------------------------------------------- */ diff --git a/drivers/net/hamradio/baycom_ser_fdx.c b/drivers/net/hamradio/baycom_ser_fdx.c index 7b916d5b14b9..ebc06822fd4d 100644 --- a/drivers/net/hamradio/baycom_ser_fdx.c +++ b/drivers/net/hamradio/baycom_ser_fdx.c @@ -82,7 +82,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/hamradio/baycom_ser_hdx.c b/drivers/net/hamradio/baycom_ser_hdx.c index f9a8976195ba..60fcf512c208 100644 --- a/drivers/net/hamradio/baycom_ser_hdx.c +++ b/drivers/net/hamradio/baycom_ser_hdx.c @@ -67,7 +67,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 622ab3ab9e93..f62e7f325cf9 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -69,7 +69,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index e4137c1b3df9..2479072981a1 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #include "z8530.h" diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index 4bad0b894e9c..8c3633c1d078 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index 1dfe2304daa7..ece59c54a653 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -17,7 +17,7 @@ */ #include #include -#include +#include #include #include #include diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index b8083161ef46..6754cd01c605 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -178,7 +178,7 @@ #include #include -#include +#include #include "z8530.h" diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index aaff07c10058..b6891ada1d7b 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -68,7 +68,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/hippi/rrunner.c b/drivers/net/hippi/rrunner.c index f5a9728b89f3..dd7fc6659ad4 100644 --- a/drivers/net/hippi/rrunner.c +++ b/drivers/net/hippi/rrunner.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #define rr_if_busy(dev) netif_queue_stopped(dev) #define rr_if_running(dev) netif_running(dev) diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 7a3f990c1935..7a20a9a4663a 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index fb5d162ec7d2..24c0f169a7b1 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -71,7 +71,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index 8e6e0edf2440..3affded3e30d 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -123,7 +123,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 37f23a189b35..741452c7ce35 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -87,7 +87,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index bca6a1e72d1d..6f6ed75b63c9 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -55,7 +55,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index a0849f49bbec..ffedad2a360a 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -45,7 +45,7 @@ MODULE_LICENSE("GPL"); #include #include #include -#include +#include #include #include diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index 6255973e3dda..1e05b7c2d157 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/phy/davicom.c b/drivers/net/phy/davicom.c index 36e3e2033eca..e28913d9ea7e 100644 --- a/drivers/net/phy/davicom.c +++ b/drivers/net/phy/davicom.c @@ -32,7 +32,7 @@ #include #include -#include +#include #define MII_DM9161_SCR 0x10 #define MII_DM9161_SCR_INIT 0x0610 diff --git a/drivers/net/phy/icplus.c b/drivers/net/phy/icplus.c index 22b51f01a94a..567280a72241 100644 --- a/drivers/net/phy/icplus.c +++ b/drivers/net/phy/icplus.c @@ -28,7 +28,7 @@ #include #include -#include +#include MODULE_DESCRIPTION("ICPlus IP175C/IP101A/IP101G/IC1001 PHY drivers"); MODULE_AUTHOR("Michael Barkowski"); diff --git a/drivers/net/phy/lxt.c b/drivers/net/phy/lxt.c index b9fde1bcf0f0..8d198a1f0031 100644 --- a/drivers/net/phy/lxt.c +++ b/drivers/net/phy/lxt.c @@ -32,7 +32,7 @@ #include #include -#include +#include /* The Level one LXT970 is used by many boards */ diff --git a/drivers/net/phy/qsemi.c b/drivers/net/phy/qsemi.c index d470db89e8dd..dbef8002bc28 100644 --- a/drivers/net/phy/qsemi.c +++ b/drivers/net/phy/qsemi.c @@ -32,7 +32,7 @@ #include #include -#include +#include /* ------------------------------------------------------------------------- */ /* The Quality Semiconductor QS6612 is used on the RPX CLLF */ diff --git a/drivers/net/ppp/ppp_async.c b/drivers/net/ppp/ppp_async.c index 9c889e0303dd..feb9569e3345 100644 --- a/drivers/net/ppp/ppp_async.c +++ b/drivers/net/ppp/ppp_async.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #define PPP_VERSION "2.4.2" diff --git a/drivers/net/ppp/ppp_synctty.c b/drivers/net/ppp/ppp_synctty.c index 925d3e295bac..9ae53986cb4a 100644 --- a/drivers/net/ppp/ppp_synctty.c +++ b/drivers/net/ppp/ppp_synctty.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #define PPP_VERSION "2.4.2" diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c index f017c72bb7fd..d7e405268983 100644 --- a/drivers/net/ppp/pppoe.c +++ b/drivers/net/ppp/pppoe.c @@ -83,7 +83,7 @@ #include #include -#include +#include #define PPPOE_HASH_BITS 4 #define PPPOE_HASH_SIZE (1 << PPPOE_HASH_BITS) diff --git a/drivers/net/ppp/pppox.c b/drivers/net/ppp/pppox.c index b9c8be6283d3..c0599b3b23c0 100644 --- a/drivers/net/ppp/pppox.c +++ b/drivers/net/ppp/pppox.c @@ -34,7 +34,7 @@ #include -#include +#include static const struct pppox_proto *pppox_protos[PX_MAX_PROTO + 1]; diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 8b8b53259783..7820fced33f6 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -55,7 +55,7 @@ static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n"; #include #include -#include +#include #ifdef SB1000_DEBUG static int sb1000_debug = SB1000_DEBUG; diff --git a/drivers/net/slip/slhc.c b/drivers/net/slip/slhc.c index 27ed25252aac..5782733959f0 100644 --- a/drivers/net/slip/slhc.c +++ b/drivers/net/slip/slhc.c @@ -75,7 +75,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/slip/slip.c b/drivers/net/slip/slip.c index 7e933d8ff811..9841f3dc0682 100644 --- a/drivers/net/slip/slip.c +++ b/drivers/net/slip/slip.c @@ -64,7 +64,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 57e88b814700..cd8e02c94be0 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -73,7 +73,7 @@ #include #include -#include +#include /* Uncomment to enable debugging */ /* #define TUN_DEBUG 1 */ diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index a1f2f6f1e614..3daa41bdd4ea 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #undef DEBUG diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index 338aed5da14d..876f02f4945e 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -54,7 +54,7 @@ #include #include #include -#include +#include #include #undef DEBUG diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 399f7ee57aea..24e803fe9a53 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include "pegasus.h" /* diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 93a1bda1c1e5..95b7bd0d7abc 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include /* Version Information */ #define DRIVER_VERSION "v0.6.2 (2004/08/27)" diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index ae6ecf401189..65ee2a6f248c 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -52,7 +52,7 @@ #include #include -#include +#include static const char version[] = "DLCI driver v0.35, 4 Jan 1997, mike.mclagan@linux.org"; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 7351e5440ed7..799830ffcae2 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -95,7 +95,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 03696d35ee9c..33265eb50420 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include "farsync.h" diff --git a/drivers/net/wan/hd64570.c b/drivers/net/wan/hd64570.c index dc334c85d966..166696d2c496 100644 --- a/drivers/net/wan/hd64570.c +++ b/drivers/net/wan/hd64570.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include "hd64570.h" #define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c index e92ecf1d3314..7ef49dab6855 100644 --- a/drivers/net/wan/hd64572.c +++ b/drivers/net/wan/hd64572.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include "hd64572.h" #define NAPI_WEIGHT 16 diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 6676607164d6..9df9ed62beff 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index 001b7796740d..4698450c77d1 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -59,7 +59,7 @@ #include /* Processor type for cache alignment. */ #include #include -#include +#include //#include #define DRIVER_MAJOR_VERSION 1 diff --git a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c index ff2e4a5654c7..cffe23bd16e1 100644 --- a/drivers/net/wan/lmc/lmc_media.c +++ b/drivers/net/wan/lmc/lmc_media.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include "lmc.h" #include "lmc_var.h" diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index 3f83be98d469..3ca3419c54a0 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -63,7 +63,7 @@ #include #include #include -#include +#include #include "sbni.h" diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 421ac5f85699..236c62538036 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -56,7 +56,7 @@ #include #include -#include +#include static const char* version = "SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org"; diff --git a/drivers/net/wireless/atmel/atmel.c b/drivers/net/wireless/atmel/atmel.c index eb92d5ab7a27..e12f62356fd1 100644 --- a/drivers/net/wireless/atmel/atmel.c +++ b/drivers/net/wireless/atmel/atmel.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2100.c b/drivers/net/wireless/intel/ipw2x00/ipw2100.c index 64176090b196..356aba9d3d53 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2100.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2100.c @@ -148,7 +148,7 @@ that only one external action is invoked at a time. #include #include #include -#include +#include #include #include #include diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c index 218f2a32de21..ce7eda20a68f 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_geo.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_geo.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #include "libipw.h" diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_module.c b/drivers/net/wireless/intel/ipw2x00/libipw_module.c index 2332075565f2..c58c5b2dcce5 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_module.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_module.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c index 1c1ec7bb9302..6df19f03355a 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_rx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_rx.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c index e8c039879b05..048f1e3ada11 100644 --- a/drivers/net/wireless/intel/ipw2x00/libipw_tx.c +++ b/drivers/net/wireless/intel/ipw2x00/libipw_tx.c @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include "libipw.h" diff --git a/drivers/net/wireless/intersil/hostap/hostap_hw.c b/drivers/net/wireless/intersil/hostap/hostap_hw.c index a8a9bd8e176a..544ef7adde7d 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_hw.c +++ b/drivers/net/wireless/intersil/hostap/hostap_hw.c @@ -32,7 +32,7 @@ #include -#include +#include #include #include diff --git a/drivers/net/wireless/intersil/hostap/hostap_main.c b/drivers/net/wireless/intersil/hostap/hostap_main.c index 1a16b8cb366e..544fc09dcb62 100644 --- a/drivers/net/wireless/intersil/hostap/hostap_main.c +++ b/drivers/net/wireless/intersil/hostap/hostap_main.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "hostap_wlan.h" #include "hostap_80211.h" diff --git a/drivers/net/wireless/intersil/prism54/isl_38xx.c b/drivers/net/wireless/intersil/prism54/isl_38xx.c index 6700387ef9ab..ce9d4db0d9ca 100644 --- a/drivers/net/wireless/intersil/prism54/isl_38xx.c +++ b/drivers/net/wireless/intersil/prism54/isl_38xx.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include "prismcompat.h" diff --git a/drivers/net/wireless/intersil/prism54/isl_ioctl.c b/drivers/net/wireless/intersil/prism54/isl_ioctl.c index 48e8a978a832..334717b0a2be 100644 --- a/drivers/net/wireless/intersil/prism54/isl_ioctl.c +++ b/drivers/net/wireless/intersil/prism54/isl_ioctl.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include "prismcompat.h" #include "isl_ioctl.h" diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 4fdc7223c894..b94479441b0c 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -53,7 +53,7 @@ #include #include -#include +#include /* Warning : these stuff will slow down the driver... */ #define WIRELESS_SPY /* Enable spying addresses */ diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index d9d29ab88184..acec0d9ec422 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -51,7 +51,7 @@ #include #include -#include +#include #include "wl3501.h" diff --git a/drivers/nubus/proc.c b/drivers/nubus/proc.c index 5371b374f1fe..e8f68f5732f1 100644 --- a/drivers/nubus/proc.c +++ b/drivers/nubus/proc.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include static int diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c index c0cc4e7ff023..67935fbbbcab 100644 --- a/drivers/oprofile/event_buffer.c +++ b/drivers/oprofile/event_buffer.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include "oprof.h" #include "event_buffer.h" diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c index 134398e0231b..d77ebbfc67c9 100644 --- a/drivers/oprofile/oprofilefs.c +++ b/drivers/oprofile/oprofilefs.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "oprof.h" diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c index 3ed6238f8f6e..553ef8a5d588 100644 --- a/drivers/parisc/ccio-dma.c +++ b/drivers/parisc/ccio-dma.c @@ -48,7 +48,7 @@ #include #include /* for L1_CACHE_BYTES */ -#include +#include #include #include #include diff --git a/drivers/parisc/ccio-rm-dma.c b/drivers/parisc/ccio-rm-dma.c index f78f6f1aef47..1bf988010855 100644 --- a/drivers/parisc/ccio-rm-dma.c +++ b/drivers/parisc/ccio-rm-dma.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/parisc/eisa_eeprom.c b/drivers/parisc/eisa_eeprom.c index 783906fe659a..4dd9b1308128 100644 --- a/drivers/parisc/eisa_eeprom.c +++ b/drivers/parisc/eisa_eeprom.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #define EISA_EEPROM_MINOR 241 diff --git a/drivers/parisc/eisa_enumerator.c b/drivers/parisc/eisa_enumerator.c index 21905fef2cbf..d9bffe8d29b9 100644 --- a/drivers/parisc/eisa_enumerator.c +++ b/drivers/parisc/eisa_enumerator.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index b48243131993..ff1a332d76e4 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -49,7 +49,7 @@ #include /* HZ */ #include #include -#include +#include /* The control of the LEDs and LCDs on PARISC-machines have to be done completely in software. The necessary calculations are done in a work queue diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c index 3651c3871d5b..055f83fddc18 100644 --- a/drivers/parisc/pdc_stable.c +++ b/drivers/parisc/pdc_stable.c @@ -68,7 +68,7 @@ #include #include -#include +#include #include #define PDCS_VERSION "0.30" diff --git a/drivers/parport/daisy.c b/drivers/parport/daisy.c index 5bed17f68ef4..d998d0ed2bec 100644 --- a/drivers/parport/daisy.c +++ b/drivers/parport/daisy.c @@ -26,7 +26,7 @@ #include #include -#include +#include #undef DEBUG diff --git a/drivers/parport/ieee1284_ops.c b/drivers/parport/ieee1284_ops.c index 2e21af43d91e..c0e7d21c88c2 100644 --- a/drivers/parport/ieee1284_ops.c +++ b/drivers/parport/ieee1284_ops.c @@ -18,7 +18,7 @@ #include #include #include -#include +#include #undef DEBUG /* undef me for production */ diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c index 6e3a60c78873..dd6d4ccb41e4 100644 --- a/drivers/parport/parport_gsc.c +++ b/drivers/parport/parport_gsc.c @@ -34,7 +34,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c index d763bc9e44c1..4d1d6eaf333d 100644 --- a/drivers/parport/probe.c +++ b/drivers/parport/probe.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include static const struct { const char *token; diff --git a/drivers/parport/procfs.c b/drivers/parport/procfs.c index 74ed3e459a3e..8ee44a104ac4 100644 --- a/drivers/parport/procfs.c +++ b/drivers/parport/procfs.c @@ -23,7 +23,7 @@ #include #include -#include +#include #if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) diff --git a/drivers/pci/hotplug/acpiphp_ibm.c b/drivers/pci/hotplug/acpiphp_ibm.c index f6221d739f59..68d105aaf4e2 100644 --- a/drivers/pci/hotplug/acpiphp_ibm.c +++ b/drivers/pci/hotplug/acpiphp_ibm.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include "acpiphp.h" #include "../pci.h" diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c index ec009a7dba20..33d300d12411 100644 --- a/drivers/pci/hotplug/cpqphp_core.c +++ b/drivers/pci/hotplug/cpqphp_core.c @@ -40,7 +40,7 @@ #include #include -#include +#include #include "cpqphp.h" #include "cpqphp_nvram.h" diff --git a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c index c25fc9061059..daae8071a156 100644 --- a/drivers/pci/hotplug/cpqphp_nvram.c +++ b/drivers/pci/hotplug/cpqphp_nvram.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "cpqphp.h" #include "cpqphp_nvram.h" diff --git a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c index 56013d0daf7f..7b0e97be9063 100644 --- a/drivers/pci/hotplug/pci_hotplug_core.c +++ b/drivers/pci/hotplug/pci_hotplug_core.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include "../pci.h" #include "cpci_hotplug.h" diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index 2408abe4ee8c..f82710a8694d 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -11,7 +11,7 @@ #include #include #include -#include +#include #include #include "pci.h" diff --git a/drivers/pci/syscall.c b/drivers/pci/syscall.c index b91c4da68365..9bf993e1f71e 100644 --- a/drivers/pci/syscall.c +++ b/drivers/pci/syscall.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include "pci.h" SYSCALL_DEFINE5(pciconfig_read, unsigned long, bus, unsigned long, dfn, diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c index c890a49587e4..aa2ee51d3547 100644 --- a/drivers/platform/x86/sony-laptop.c +++ b/drivers/platform/x86/sony-laptop.c @@ -68,7 +68,7 @@ #include #include #endif -#include +#include #include #define dprintk(fmt, ...) \ diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c index aa65a857a6b1..cacb43fb1df7 100644 --- a/drivers/platform/x86/thinkpad_acpi.c +++ b/drivers/platform/x86/thinkpad_acpi.c @@ -82,7 +82,7 @@ #include #include #include -#include +#include #include /* ThinkPad CMOS commands */ diff --git a/drivers/pnp/interface.c b/drivers/pnp/interface.c index 4b6808ff0e5d..5c5b3d47b5f6 100644 --- a/drivers/pnp/interface.c +++ b/drivers/pnp/interface.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include "base.h" diff --git a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c index c212db0fc65d..5ee6b2a5f8d5 100644 --- a/drivers/pnp/pnpbios/proc.c +++ b/drivers/pnp/pnpbios/proc.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include "pnpbios.h" diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c index 84ca314c87e3..dd46e96a3034 100644 --- a/drivers/s390/block/dasd_devmap.c +++ b/drivers/s390/block/dasd_devmap.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include /* This is ugly... */ diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c index 67bf50c9946f..ade04216c970 100644 --- a/drivers/s390/block/dasd_eckd.c +++ b/drivers/s390/block/dasd_eckd.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c index 6c5d671304b4..8713fefd794b 100644 --- a/drivers/s390/block/dasd_eer.c +++ b/drivers/s390/block/dasd_eer.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/s390/block/dasd_erp.c b/drivers/s390/block/dasd_erp.c index 113c1c1fa1af..9e3419124264 100644 --- a/drivers/s390/block/dasd_erp.c +++ b/drivers/s390/block/dasd_erp.c @@ -15,7 +15,7 @@ #include #include -#include +#include /* This is ugly... */ #define PRINTK_HEADER "dasd_erp:" diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c index e2fa759bf2ad..8b1341fb2e0d 100644 --- a/drivers/s390/block/dasd_genhd.c +++ b/drivers/s390/block/dasd_genhd.c @@ -16,7 +16,7 @@ #include #include -#include +#include /* This is ugly... */ #define PRINTK_HEADER "dasd_gendisk:" diff --git a/drivers/s390/block/dasd_ioctl.c b/drivers/s390/block/dasd_ioctl.c index 9dfbd972f844..ec65c1e51c2a 100644 --- a/drivers/s390/block/dasd_ioctl.c +++ b/drivers/s390/block/dasd_ioctl.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include /* This is ugly... */ #define PRINTK_HEADER "dasd_ioctl:" diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c index bad7a196bf84..70dc2c4cd3f7 100644 --- a/drivers/s390/block/dasd_proc.c +++ b/drivers/s390/block/dasd_proc.c @@ -20,7 +20,7 @@ #include #include -#include +#include /* This is ugly... */ #define PRINTK_HEADER "dasd_proc:" diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c index 288f59a4147b..b9d7e755c8a3 100644 --- a/drivers/s390/block/xpram.c +++ b/drivers/s390/block/xpram.c @@ -41,7 +41,7 @@ #include #include #include -#include +#include #define XPRAM_NAME "xpram" #define XPRAM_DEVS 1 /* one partition */ diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c index 1b8d825623bd..9ec4ae056158 100644 --- a/drivers/s390/char/con3215.c +++ b/drivers/s390/char/con3215.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/s390/char/keyboard.c b/drivers/s390/char/keyboard.c index 7b9c50aa4cc9..82c913318b73 100644 --- a/drivers/s390/char/keyboard.c +++ b/drivers/s390/char/keyboard.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include "keyboard.h" diff --git a/drivers/s390/char/monreader.c b/drivers/s390/char/monreader.c index ebdeaa53182d..027ac6ae5eea 100644 --- a/drivers/s390/char/monreader.c +++ b/drivers/s390/char/monreader.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/s390/char/monwriter.c b/drivers/s390/char/monwriter.c index 9b5d1138b2e2..571a7e352755 100644 --- a/drivers/s390/char/monwriter.c +++ b/drivers/s390/char/monwriter.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/s390/char/sclp_rw.c b/drivers/s390/char/sclp_rw.c index 6010cd347a08..91b26df5227d 100644 --- a/drivers/s390/char/sclp_rw.c +++ b/drivers/s390/char/sclp_rw.c @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include "sclp.h" #include "sclp_rw.h" diff --git a/drivers/s390/char/sclp_tty.c b/drivers/s390/char/sclp_tty.c index 9259017a1295..236b736ae136 100644 --- a/drivers/s390/char/sclp_tty.c +++ b/drivers/s390/char/sclp_tty.c @@ -15,7 +15,7 @@ #include #include #include -#include +#include #include "ctrlchar.h" #include "sclp.h" diff --git a/drivers/s390/char/sclp_vt220.c b/drivers/s390/char/sclp_vt220.c index 68d6ee7ae504..095481d32236 100644 --- a/drivers/s390/char/sclp_vt220.c +++ b/drivers/s390/char/sclp_vt220.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include "sclp.h" #include "ctrlchar.h" diff --git a/drivers/s390/char/tape_char.c b/drivers/s390/char/tape_char.c index 77f9b9c2f701..46ac1164f242 100644 --- a/drivers/s390/char/tape_char.c +++ b/drivers/s390/char/tape_char.c @@ -18,7 +18,7 @@ #include #include -#include +#include #define TAPE_DBF_AREA tape_core_dbf diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c index 272cb6cd1b2a..e5ebe2fbee23 100644 --- a/drivers/s390/char/tty3270.c +++ b/drivers/s390/char/tty3270.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include "raw3270.h" #include "tty3270.h" diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c index 2a67b496a9e2..65f5a794f26d 100644 --- a/drivers/s390/char/vmcp.c +++ b/drivers/s390/char/vmcp.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "vmcp.h" static debug_info_t *vmcp_debug; diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c index 3167e8581994..57974a1e0e03 100644 --- a/drivers/s390/char/vmlogrdr.c +++ b/drivers/s390/char/vmlogrdr.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/s390/char/vmur.c b/drivers/s390/char/vmur.c index ff18f373af9a..04aceb694d51 100644 --- a/drivers/s390/char/vmur.c +++ b/drivers/s390/char/vmur.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/s390/char/zcore.c b/drivers/s390/char/zcore.c index f771e5e9e26b..d3b51edb056e 100644 --- a/drivers/s390/char/zcore.c +++ b/drivers/s390/char/zcore.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c index 9082476b51db..bf7f5d4c50e1 100644 --- a/drivers/s390/cio/blacklist.c +++ b/drivers/s390/cio/blacklist.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/s390/crypto/zcrypt_api.c b/drivers/s390/crypto/zcrypt_api.c index 854a6e58dfea..51eece9af577 100644 --- a/drivers/s390/crypto/zcrypt_api.c +++ b/drivers/s390/crypto/zcrypt_api.c @@ -36,7 +36,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/s390/crypto/zcrypt_cex2a.c b/drivers/s390/crypto/zcrypt_cex2a.c index c7d48a18199e..b97c5d5ee5a4 100644 --- a/drivers/s390/crypto/zcrypt_cex2a.c +++ b/drivers/s390/crypto/zcrypt_cex2a.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include "ap_bus.h" diff --git a/drivers/s390/crypto/zcrypt_pcixcc.c b/drivers/s390/crypto/zcrypt_pcixcc.c index 26ceaa696765..600604782b65 100644 --- a/drivers/s390/crypto/zcrypt_pcixcc.c +++ b/drivers/s390/crypto/zcrypt_pcixcc.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #include "ap_bus.h" diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c index 2981024a2438..3f85b97ab8d2 100644 --- a/drivers/s390/net/netiucv.c +++ b/drivers/s390/net/netiucv.c @@ -62,7 +62,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/sbus/char/display7seg.c b/drivers/sbus/char/display7seg.c index 33fbe8249fd5..04efed171c88 100644 --- a/drivers/sbus/char/display7seg.c +++ b/drivers/sbus/char/display7seg.c @@ -17,7 +17,7 @@ #include #include #include -#include /* put_/get_user */ +#include /* put_/get_user */ #include #include diff --git a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c index 5609b602c54d..56e962a01493 100644 --- a/drivers/sbus/char/envctrl.c +++ b/drivers/sbus/char/envctrl.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/sbus/char/flash.c b/drivers/sbus/char/flash.c index 206ef4232adf..216f923161d1 100644 --- a/drivers/sbus/char/flash.c +++ b/drivers/sbus/char/flash.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c index a40ee1e37486..6ff61dad5e21 100644 --- a/drivers/sbus/char/jsflash.c +++ b/drivers/sbus/char/jsflash.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/sbus/char/openprom.c b/drivers/sbus/char/openprom.c index 4612691c6619..2c2e6a3b4c7e 100644 --- a/drivers/sbus/char/openprom.c +++ b/drivers/sbus/char/openprom.c @@ -40,7 +40,7 @@ #include #include #include -#include +#include #include #ifdef CONFIG_PCI #include diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 316f87fe3299..00e7968a1d70 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c @@ -92,7 +92,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 970d8fa6bd53..b150e131b2e7 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -64,7 +64,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index aa412ab02765..33261b690774 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -210,7 +210,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 6678d1fd897b..1ee7c654f7b8 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include /* For flush_kernel_dcache_page */ #include diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 5648b715fed9..e1daff230c7d 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -41,7 +41,7 @@ #include /* ssleep prototype */ #include #include -#include +#include #include #include "aacraid.h" diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 9e45749d55ed..af032c46ec0e 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -61,7 +61,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 9d253cb83ee7..d9e15210b110 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include "bfad_drv.h" diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c index 27c0dce22e72..5f75e638ec95 100644 --- a/drivers/scsi/dpt_i2o.c +++ b/drivers/scsi/dpt_i2o.c @@ -37,7 +37,7 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver"); //////////////////////////////////////////////////////////////// #include /* For SCSI-Passthrough */ -#include +#include #include #include /* for kmalloc() */ diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c index 0a767740bf02..d020a13646ae 100644 --- a/drivers/scsi/gdth.c +++ b/drivers/scsi/gdth.c @@ -130,7 +130,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c index a83f705ed8a5..db17ad15b0c1 100644 --- a/drivers/scsi/hptiop.c +++ b/drivers/scsi/hptiop.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h index 45b9566b928e..b782bb60baf0 100644 --- a/drivers/scsi/ips.h +++ b/drivers/scsi/ips.h @@ -51,7 +51,7 @@ #define _IPS_H_ #include - #include +#include #include /* diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 9d05302a3bcd..3c63c292cb92 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h index 55b425c0a654..a30e725f2d5c 100644 --- a/drivers/scsi/megaraid/megaraid_mm.h +++ b/drivers/scsi/megaraid/megaraid_mm.h @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 6484c382f670..d5cf15eb8c5e 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index a2960f5d98ec..e8196c55b633 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -52,7 +52,7 @@ static const char * osst_version = "0.99.4"; #include #include #include -#include +#include #include /* The driver prints some debugging information on the console if DEBUG diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index 9f6012b78e56..b4336e0cd85f 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -9,7 +9,7 @@ #include #include #include -#include +#include /* * NVRAM support routines diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index c4f7b56fa6f6..8b8c814df5c7 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c index 7a74b82e8973..480a597b3877 100644 --- a/drivers/scsi/scsi_proc.c +++ b/drivers/scsi/scsi_proc.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 1622e23138e0..b1933041da39 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -53,7 +53,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index bed2bbd6b923..94352e4df831 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 03054c0e7689..dfffdf63e44c 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 605887d5ee57..5f35b863e1a7 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -41,7 +41,7 @@ static const char *verstr = "20160209"; #include #include -#include +#include #include #include diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c index dfbb974927f2..dea16bb8c46a 100644 --- a/drivers/tty/amiserial.c +++ b/drivers/tty/amiserial.c @@ -127,7 +127,7 @@ static struct serial_state rs_table[1]; #define NR_PORTS ARRAY_SIZE(rs_table) -#include +#include #define serial_isroot() (capable(CAP_SYS_ADMIN)) diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index ce864875330e..9b5c0fb216b5 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include "hvc_console.h" diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 3c4d7c2b4ade..7823d6d998cf 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -81,7 +81,7 @@ #include #include #include -#include +#include #include /* diff --git a/drivers/tty/hvc/hvsi.c b/drivers/tty/hvc/hvsi.c index 96ce6bd1cc6f..2e578d6433af 100644 --- a/drivers/tty/hvc/hvsi.c +++ b/drivers/tty/hvc/hvsi.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 60d37b225589..4caf0c3b1f99 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -47,7 +47,7 @@ #include #include -#include +#include #include "moxa.h" diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 69294ae154be..7b8f383fb090 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -43,7 +43,7 @@ #include #include -#include +#include #include "mxser.h" diff --git a/drivers/tty/n_hdlc.c b/drivers/tty/n_hdlc.c index a7fa016f31eb..eb278832f5ce 100644 --- a/drivers/tty/n_hdlc.c +++ b/drivers/tty/n_hdlc.c @@ -103,7 +103,7 @@ #include #include -#include +#include /* * Buffers for individual HDLC frames diff --git a/drivers/tty/n_r3964.c b/drivers/tty/n_r3964.c index 345111467b85..305b6490d405 100644 --- a/drivers/tty/n_r3964.c +++ b/drivers/tty/n_r3964.c @@ -65,7 +65,7 @@ #include #include #include -#include +#include /*#define DEBUG_QUEUE*/ diff --git a/drivers/tty/serial/icom.c b/drivers/tty/serial/icom.c index c60a8d5e4020..d83783cfbade 100644 --- a/drivers/tty/serial/icom.c +++ b/drivers/tty/serial/icom.c @@ -53,7 +53,7 @@ #include #include -#include +#include #include "icom.h" diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d0847375ea64..9939c3d9912b 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -36,7 +36,7 @@ #include #include -#include +#include /* * This is used to lock changes in serial line configuration. diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 415885c56435..657eed82eeb3 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -107,7 +107,7 @@ #define PUT_USER(error,value,addr) error = put_user(value,addr) #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 -#include +#include #define RCLRVALUE 0xffff diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 8267bcf2405e..31885f20fc15 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -77,7 +77,7 @@ #include #include #include -#include +#include #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE)) #define SYNCLINK_GENERIC_HDLC 1 diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index d66620f7eaa3..51e8846cd68f 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -79,7 +79,7 @@ #define PUT_USER(error,value,addr) error = put_user(value,addr) #define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 -#include +#include static MGSL_PARAMS default_params = { MGSL_MODE_HDLC, /* unsigned long mode */ diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c index bf36ac9aee41..f27fc0f14c11 100644 --- a/drivers/tty/tty_ioctl.c +++ b/drivers/tty/tty_ioctl.c @@ -22,7 +22,7 @@ #include #include -#include +#include #undef TTY_DEBUG_WAIT_UNTIL_SENT diff --git a/drivers/tty/vt/consolemap.c b/drivers/tty/vt/consolemap.c index 71e81406ef71..1f6e17fc3fb0 100644 --- a/drivers/tty/vt/consolemap.c +++ b/drivers/tty/vt/consolemap.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/tty/vt/selection.c b/drivers/tty/vt/selection.c index 368ce1803e8f..36e1b8c7680f 100644 --- a/drivers/tty/vt/selection.c +++ b/drivers/tty/vt/selection.c @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/tty/vt/vc_screen.c b/drivers/tty/vt/vc_screen.c index 14a2b5f11bca..56dcff6059d3 100644 --- a/drivers/tty/vt/vc_screen.c +++ b/drivers/tty/vt/vc_screen.c @@ -39,7 +39,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/tty/vt/vt_ioctl.c b/drivers/tty/vt/vt_ioctl.c index f62c598810ff..a56edf2d58eb 100644 --- a/drivers/tty/vt/vt_ioctl.c +++ b/drivers/tty/vt/vt_ioctl.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 4dec9df8764b..5a59da0dc98a 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -64,7 +64,7 @@ #include "usbatm.h" -#include +#include #include #include #include diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 143454ea385b..1fa5c0f29c64 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include "hub.h" diff --git a/drivers/usb/gadget/legacy/inode.c b/drivers/usb/gadget/legacy/inode.c index 10b2576f8b6a..e8f4102d19df 100644 --- a/drivers/usb/gadget/legacy/inode.c +++ b/drivers/usb/gadget/legacy/inode.c @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c index 5d3d914ab4fb..683098afa93e 100644 --- a/drivers/usb/host/uhci-hcd.c +++ b/drivers/usb/host/uhci-hcd.c @@ -42,7 +42,7 @@ #include #include -#include +#include #include #include diff --git a/drivers/usb/misc/ftdi-elan.c b/drivers/usb/misc/ftdi-elan.c index 9a82f8308ad7..01a9373b7e18 100644 --- a/drivers/usb/misc/ftdi-elan.c +++ b/drivers/usb/misc/ftdi-elan.c @@ -48,7 +48,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c index 2975e80b7a56..debc1fd74b0d 100644 --- a/drivers/usb/misc/idmouse.c +++ b/drivers/usb/misc/idmouse.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include /* image constants */ diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 9ca595632f17..3bc5356832db 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c index c8fbe7b739a0..b10e26c74a90 100644 --- a/drivers/usb/misc/legousbtower.c +++ b/drivers/usb/misc/legousbtower.c @@ -83,7 +83,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c index 1a874a1f3890..91c22276c03b 100644 --- a/drivers/usb/mon/mon_bin.c +++ b/drivers/usb/mon/mon_bin.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include "usb_mon.h" diff --git a/drivers/usb/mon/mon_stat.c b/drivers/usb/mon/mon_stat.c index 5388a339cfb8..5bdf73a57498 100644 --- a/drivers/usb/mon/mon_stat.c +++ b/drivers/usb/mon/mon_stat.c @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "usb_mon.h" diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c index e59334b09c41..db1a4abf2806 100644 --- a/drivers/usb/mon/mon_text.c +++ b/drivers/usb/mon/mon_text.c @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include "usb_mon.h" diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c index 9b22d946c089..4fef50e5c8c1 100644 --- a/drivers/usb/musb/musb_debugfs.c +++ b/drivers/usb/musb/musb_debugfs.c @@ -37,7 +37,7 @@ #include #include -#include +#include #include "musb_core.h" #include "musb_debug.h" diff --git a/drivers/video/console/newport_con.c b/drivers/video/console/newport_con.c index 1e11614322fe..42d02a206059 100644 --- a/drivers/video/console/newport_con.c +++ b/drivers/video/console/newport_con.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/video/fbdev/68328fb.c b/drivers/video/fbdev/68328fb.c index 17f21cedff9b..c0c6b88d3839 100644 --- a/drivers/video/fbdev/68328fb.c +++ b/drivers/video/fbdev/68328fb.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include #include diff --git a/drivers/video/fbdev/hitfb.c b/drivers/video/fbdev/hitfb.c index 9d68dc9ee7bf..abe3e54d4506 100644 --- a/drivers/video/fbdev/hitfb.c +++ b/drivers/video/fbdev/hitfb.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/video/fbdev/hpfb.c b/drivers/video/fbdev/hpfb.c index 9476d196f510..16f16f5e1a4b 100644 --- a/drivers/video/fbdev/hpfb.c +++ b/drivers/video/fbdev/hpfb.c @@ -16,7 +16,7 @@ #include #include -#include +#include static struct fb_info fb_info = { .fix = { diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c index 8778e01cebac..1c3c7ab26a95 100644 --- a/drivers/video/fbdev/mx3fb.c +++ b/drivers/video/fbdev/mx3fb.c @@ -33,7 +33,7 @@ #include #include -#include +#include #define MX3FB_NAME "mx3_sdc_fb" diff --git a/drivers/video/fbdev/q40fb.c b/drivers/video/fbdev/q40fb.c index 7487f76f6275..04ea330ccf5d 100644 --- a/drivers/video/fbdev/q40fb.c +++ b/drivers/video/fbdev/q40fb.c @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c index d0a4e2f79a57..d80bc8a3200f 100644 --- a/drivers/video/fbdev/sm501fb.c +++ b/drivers/video/fbdev/sm501fb.c @@ -31,7 +31,7 @@ #include #include -#include +#include #include #ifdef CONFIG_PM diff --git a/drivers/video/fbdev/stifb.c b/drivers/video/fbdev/stifb.c index 7df4228e25f0..accfef71e984 100644 --- a/drivers/video/fbdev/stifb.c +++ b/drivers/video/fbdev/stifb.c @@ -67,7 +67,7 @@ #include #include /* for HP-UX compatibility */ -#include +#include #include "sticore.h" diff --git a/drivers/video/fbdev/w100fb.c b/drivers/video/fbdev/w100fb.c index 10951c82f6ed..d570e19a2864 100644 --- a/drivers/video/fbdev/w100fb.c +++ b/drivers/video/fbdev/w100fb.c @@ -35,7 +35,7 @@ #include #include #include -#include +#include #include